pax_global_header00006660000000000000000000000064151406613000014506gustar00rootroot0000000000000052 comment=f66a0a1157c5e020e7e67b9ed0289ab53dde1720 trollimage-1.28.0/000077500000000000000000000000001514066130000137355ustar00rootroot00000000000000trollimage-1.28.0/.bumpversion.cfg000066400000000000000000000001521514066130000170430ustar00rootroot00000000000000[bumpversion] current_version = 1.5.7 commit = True tag = True [bumpversion:file:trollimage/version.py] trollimage-1.28.0/.gitattributes000066400000000000000000000000431514066130000166250ustar00rootroot00000000000000trollimage/version.py export-subst trollimage-1.28.0/.gitchangelog.rc000066400000000000000000000143371514066130000170040ustar00rootroot00000000000000## ## Format ## ## ACTION: [AUDIENCE:] COMMIT_MSG [!TAG ...] ## ## Description ## ## ACTION is one of 'chg', 'fix', 'new' ## ## Is WHAT the change is about. ## ## 'chg' is for refactor, small improvement, cosmetic changes... ## 'fix' is for bug fixes ## 'new' is for new features, big improvement ## ## AUDIENCE is optional and one of 'dev', 'usr', 'pkg', 'test', 'doc' ## ## Is WHO is concerned by the change. ## ## 'dev' is for developpers (API changes, refactors...) ## 'usr' is for final users (UI changes) ## 'pkg' is for packagers (packaging changes) ## 'test' is for testers (test only related changes) ## 'doc' is for doc guys (doc only changes) ## ## COMMIT_MSG is ... well ... the commit message itself. ## ## TAGs are additionnal adjective as 'refactor' 'minor' 'cosmetic' ## ## They are preceded with a '!' or a '@' (prefer the former, as the ## latter is wrongly interpreted in github.) Commonly used tags are: ## ## 'refactor' is obviously for refactoring code only ## 'minor' is for a very meaningless change (a typo, adding a comment) ## 'cosmetic' is for cosmetic driven change (re-indentation, 80-col...) ## 'wip' is for partial functionality but complete subfunctionality. ## ## Example: ## ## new: usr: support of bazaar implemented ## chg: re-indentend some lines !cosmetic ## new: dev: updated code to be compatible with last version of killer lib. ## fix: pkg: updated year of licence coverage. ## new: test: added a bunch of test around user usability of feature X. ## fix: typo in spelling my name in comment. !minor ## ## Please note that multi-line commit message are supported, and only the ## first line will be considered as the "summary" of the commit message. So ## tags, and other rules only applies to the summary. The body of the commit ## message will be displayed in the changelog without reformatting. ## ## ``ignore_regexps`` is a line of regexps ## ## Any commit having its full commit message matching any regexp listed here ## will be ignored and won't be reported in the changelog. ## ignore_regexps = [ r'@minor', r'!minor', r'@cosmetic', r'!cosmetic', r'@refactor', r'!refactor', r'@wip', r'!wip', r'^Merge commit .* into HEAD', r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*[p|P]kg:', r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*[d|D]ev:', r'^(.{3,3}\s*:)?\s*[fF]irst commit.?\s*$', ] ## ``section_regexps`` is a list of 2-tuples associating a string label and a ## list of regexp ## ## Commit messages will be classified in sections thanks to this. Section ## titles are the label, and a commit is classified under this section if any ## of the regexps associated is matching. ## section_regexps = [ ('New', [ r'^[nN]ew\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$', ]), ('Changes', [ r'^[cC]hg\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$', ]), ('Fix', [ r'^([Bb]ug)?[fF]ix\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$', ]), ('Other', None ## Match all lines ), ] ## ``body_process`` is a callable ## ## This callable will be given the original body and result will ## be used in the changelog. ## ## Available constructs are: ## ## - any python callable that take one txt argument and return txt argument. ## ## - ReSub(pattern, replacement): will apply regexp substitution. ## ## - Indent(chars=" "): will indent the text with the prefix ## Please remember that template engines gets also to modify the text and ## will usually indent themselves the text if needed. ##git log --pretty=format:"- %s%n%b" --since="$(git show -s --format=%ad `git rev-list --tags --max-count=1`)" ## - Wrap(regexp=r"\n\n"): re-wrap text in separate paragraph to fill 80-Columns ## ## - noop: do nothing ## ## - ucfirst: ensure the first letter is uppercase. ## (usually used in the ``subject_process`` pipeline) ## ## - final_dot: ensure text finishes with a dot ## (usually used in the ``subject_process`` pipeline) ## ## - strip: remove any spaces before or after the content of the string ## ## Additionally, you can `pipe` the provided filters, for instance: #body_process = Wrap(regexp=r'\n(?=\w+\s*:)') | Indent(chars=" ") #body_process = Wrap(regexp=r'\n(?=\w+\s*:)') #body_process = noop body_process = ReSub(r'(?m)\s*^Signed-off-by: .*$\s*', '') ## ``subject_process`` is a callable ## ## This callable will be given the original subject and result will ## be used in the changelog. ## ## Available constructs are those listed in ``body_process`` doc. subject_process = (strip | ReSub(r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n@]*)(@[a-z]+\s+)*$', r'\4') | ucfirst | final_dot) ## ``tag_filter_regexp`` is a regexp ## ## Tags that will be used for the changelog must match this regexp. ## tag_filter_regexp = r'^v[0-9]+\.[0-9]+(\.[0-9]+)?$' ## ``unreleased_version_label`` is a string ## ## This label will be used as the changelog Title of the last set of changes ## between last valid tag and HEAD if any. unreleased_version_label = "%%version%% (unreleased)" ## ``output_engine`` is a callable ## ## This will change the output format of the generated changelog file ## ## Available choices are: ## ## - rest_py ## ## Legacy pure python engine, outputs ReSTructured text. ## This is the default. ## ## - mustache() ## ## Template name could be any of the available templates in ## ``templates/mustache/*.tpl``. ## Requires python package ``pystache``. ## Examples: ## - mustache("markdown") ## - mustache("restructuredtext") ## ## - makotemplate() ## ## Template name could be any of the available templates in ## ``templates/mako/*.tpl``. ## Requires python package ``mako``. ## Examples: ## - makotemplate("restructuredtext") ## output_engine = rest_py #output_engine = mustache("restructuredtext") #output_engine = mustache("markdown") #output_engine = makotemplate("restructuredtext") ## ``include_merges`` is a boolean ## ## This option tells git-log whether to include merge commits in the log. ## The default is to include them. include_merges = False trollimage-1.28.0/.github/000077500000000000000000000000001514066130000152755ustar00rootroot00000000000000trollimage-1.28.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001514066130000174605ustar00rootroot00000000000000trollimage-1.28.0/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000014211514066130000221500ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve labels: bug --- **Describe the bug** A clear and concise description of what the bug is. If you're not sure how, please consider this [article on minimal bug reports](https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports). **To Reproduce** ```python # Your code here ``` **Expected behavior** A clear and concise description of what you expected to happen. **Actual results** Text output of actual results or error messages including full tracebacks if applicable. **Screenshots** If applicable, add screenshots to help explain your problem. **Environment Info:** - OS: [e.g. OSX, Windows, Linux] - Satpy Version: [e.g. 0.9.0] **Additional context** Add any other context about the problem here. trollimage-1.28.0/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000012241514066130000232040ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project labels: enhancement --- ## Feature Request **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe any changes to existing user workflow** Are there any backwards compatibility concerns? Changes to the build process? Additional dependencies? **Additional context** Have you considered any alternative solutions or is there anything else that would help describe your request. trollimage-1.28.0/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000010111514066130000210670ustar00rootroot00000000000000 - [ ] Closes #xxxx (remove if there is no corresponding issue, which should only be the case for minor changes) - [ ] Tests added (for all bug fixes or enhancements) - [ ] Tests passed (for all non-documentation changes) - [ ] Passes ``git diff origin/master **/*py | flake8 --diff`` (remove if you did not edit any Python files) - [ ] Fully documented (remove if this change should not be visible to users, e.g., if it is an internal clean-up, or if this is part of a larger project that will be documented later) trollimage-1.28.0/.github/dependabot.yml000066400000000000000000000010021514066130000201160ustar00rootroot00000000000000# To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "github-actions" # See documentation for possible values directory: "/" # Location of package manifests schedule: interval: "monthly" trollimage-1.28.0/.github/workflows/000077500000000000000000000000001514066130000173325ustar00rootroot00000000000000trollimage-1.28.0/.github/workflows/ci.yaml000066400000000000000000000063101514066130000206110ustar00rootroot00000000000000name: CI on: [push, pull_request] jobs: test: runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.experimental }} strategy: fail-fast: true matrix: os: ["windows-latest", "ubuntu-latest", "macos-latest"] python-version: ["3.11", "3.12", "3.13"] experimental: [false] include: - python-version: "3.13" os: "ubuntu-latest" experimental: true env: PYTHON_VERSION: ${{ matrix.python-version }} OS: ${{ matrix.os }} UNSTABLE: ${{ matrix.experimental }} ACTIONS_ALLOW_UNSECURE_COMMANDS: true steps: - name: Checkout source uses: actions/checkout@v6 - name: Setup Conda Environment uses: conda-incubator/setup-miniconda@v3 with: miniforge-version: latest python-version: ${{ matrix.python-version }} activate-environment: test-environment channels: conda-forge channel-priority: strict conda-remove-defaults: "true" environment-file: continuous_integration/environment.yaml - name: Install unstable dependencies if: matrix.experimental == true shell: bash -l {0} run: | python -m pip install versioneer pkgconfig setuptools-scm; \ conda uninstall --force-remove -y numpy pandas xarray pyresample pykdtree; \ python -m pip install \ -f https://pypi.anaconda.org/scientific-python-nightly-wheels/simple/ \ --trusted-host pypi.anaconda.org \ --no-deps --pre --upgrade \ numpy \ pandas; \ python -m pip install \ --no-deps --upgrade --pre --no-build-isolation \ git+https://github.com/storpipfugl/pykdtree \ git+https://github.com/pytroll/pyresample \ git+https://github.com/dask/dask \ git+https://github.com/dask/distributed \ git+https://github.com/rasterio/rasterio \ git+https://github.com/pydata/bottleneck \ git+https://github.com/pydata/xarray; python -m pip install -e . --no-deps --no-build-isolation; - name: Install trollimage shell: bash -l {0} run: | conda list pip install --no-deps -e . # pip forces non-wheel builds if we provide --cython-coverage as a --build-option # and that's way too slow python setup.py build_ext --inplace --cython-coverage --force - name: Run unit tests shell: bash -l {0} run: | pytest --cov=trollimage trollimage/tests --cov-report=xml --cov-report= - name: Upload unittest coverage to Codecov uses: codecov/codecov-action@v5 with: flags: unittests files: ./coverage.xml env_vars: OS,PYTHON_VERSION,UNSTABLE - name: Coveralls Parallel uses: AndreMiras/coveralls-python-action@develop with: flag-name: run-${{ matrix.test_number }} parallel: true if: runner.os == 'Linux' coveralls: needs: [test] runs-on: ubuntu-latest steps: - name: Coveralls Finished uses: AndreMiras/coveralls-python-action@develop with: parallel-finished: true trollimage-1.28.0/.github/workflows/deploy.yaml000066400000000000000000000050551514066130000215170ustar00rootroot00000000000000name: Build Package on: push: pull_request: release: types: - published jobs: build_sdist: runs-on: ubuntu-latest steps: - name: Checkout source uses: actions/checkout@v6 - name: Create sdist shell: bash -l {0} run: | python -m pip install -q build python -m build -s - name: Upload sdist to build artifacts uses: actions/upload-artifact@v6 with: name: sdist path: dist/*.tar.gz build_wheels: name: "Build wheels on ${{ matrix.os }} ${{ matrix.arch }}" runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: - os: windows-2022 arch: "AMD64" - os: windows-11-arm arch: "ARM64" - os: macos-15-intel arch: "x86_64" - os: macos-14 arch: "arm64" - os: "ubuntu-24.04-arm" arch: "aarch64" - os: "ubuntu-24.04" arch: "x86_64" steps: - uses: actions/checkout@v6 - run: | git fetch --prune --unshallow - name: Build wheels uses: pypa/cibuildwheel@v3.3.1 env: CIBW_ENABLE: cpython-freethreading CIBW_SKIP: "cp39-* cp310-* *-manylinux_i686 *-musllinux_i686 *-musllinux_aarch64 *-win32" CIBW_ARCHS: "${{ matrix.arch }}" CIBW_TEST_SKIP: "*_arm64 *_universal2:arm64" - uses: actions/upload-artifact@v6 with: name: wheels-${{ matrix.os }}-${{ matrix.arch }} path: ./wheelhouse/*.whl upload_to_pypi: needs: [build_sdist, build_wheels] runs-on: ubuntu-latest steps: - name: Download sdist artifact uses: actions/download-artifact@v7 with: name: sdist path: dist - name: Download wheels artifact uses: actions/download-artifact@v7 with: pattern: wheels-* merge-multiple: true path: dist - name: Publish package to Test PyPI if: github.event.action != 'published' && github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') uses: pypa/gh-action-pypi-publish@v1.13.0 with: user: __token__ password: ${{ secrets.test_pypi_password }} repository_url: https://test.pypi.org/legacy/ - name: Publish package to PyPI if: github.event.action == 'published' uses: pypa/gh-action-pypi-publish@v1.13.0 with: user: __token__ password: ${{ secrets.pypi_password }} trollimage-1.28.0/.gitignore000066400000000000000000000006331514066130000157270ustar00rootroot00000000000000*.py[~cod] # emacs *~ # 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 # rope .ropeproject # sphinx doc/_build doc/api/*.rst doc/_static/colormaps/*.pngtrollimage-1.28.0/.pre-commit-config.yaml000066400000000000000000000005511514066130000202170ustar00rootroot00000000000000exclude: '^$' fail_fast: false repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v1.2.3 hooks: - id: flake8 additional_dependencies: [flake8-docstrings, flake8-debugger, flake8-bugbear] ci: # To trigger manually, comment on a pull request with "pre-commit.ci autofix" autofix_prs: false autoupdate_schedule: "monthly"trollimage-1.28.0/.readthedocs.yml000066400000000000000000000005571514066130000170320ustar00rootroot00000000000000version: 2 build: os: "ubuntu-20.04" tools: python: "3.11" jobs: post_checkout: - git fetch --tags pre_install: - git update-index --assume-unchanged rtd_requirements.txt doc/conf.py sphinx: configuration: doc/conf.py fail_on_warning: true python: install: - requirements: rtd_requirements.txt - method: pip path: . trollimage-1.28.0/.stickler.yml000066400000000000000000000000671514066130000163610ustar00rootroot00000000000000linters: flake8: python: 3 config: setup.cfg trollimage-1.28.0/AUTHORS.md000066400000000000000000000016321514066130000154060ustar00rootroot00000000000000# Trollimage developers - [Adam Dybbroe (adybbroe)](https://github.com/adybbroe) - [Andrea Meraner (ameraner)](https://github.com/ameraner) - [Andrew Brooks (howff)](https://github.com/howff) - [Bas Couwenberg (sebastic)](https://github.com/sebastic) - [David Hoese (djhoese)](https://github.com/djhoese) - [Gerrit Holl (gerritholl)](https://github.com/gerritholl) - Deutscher Wetterdienst - [Lars Ørum Rasmussen (loerum)](https://github.com/loerum) - [Kat Kolman (katherinekolman)](https://github.com/katherinekolman) - [Lorenzo Clementi (loreclem)](https://github.com/loreclem) - [Martin Raspaud (mraspaud)](https://github.com/mraspaud) - [Michael Overmeyer (movermeyer)](https://github.com/movermeyer) - [Panu Lahtinen (pnuu)](https://github.com/pnuu) - [Ron Goodson (goodsonr)](https://github.com/goodsonr) - [Sauli Joro (sjoro)](https://github.com/sjoro) - [Yufei Zhu (yufeizhu600)](https://github.com/yufeizhu600) trollimage-1.28.0/CHANGELOG.md000066400000000000000000000503251514066130000155530ustar00rootroot00000000000000## Version 1.28.0 (2026/02/04) ### Issues Closed * [Issue 210](https://github.com/pytroll/trollimage/issues/210) - Relicense to Apache Version 2 ([PR 212](https://github.com/pytroll/trollimage/pull/212) by [@mraspaud](https://github.com/mraspaud)) In this release 1 issue was closed. ### Pull Requests Merged #### Features added * [PR 212](https://github.com/pytroll/trollimage/pull/212) - Relicense to Apache v2.0 ([210](https://github.com/pytroll/trollimage/issues/210)) In this release 1 pull request was closed. ## Version 1.27.0 (2025/09/10) ### Pull Requests Merged #### Bugs fixed * [PR 199](https://github.com/pytroll/trollimage/pull/199) - Update histogram stretch to not use dask delayed * [PR 198](https://github.com/pytroll/trollimage/pull/198) - Optimize linear stretch to work with newer dask * [PR 197](https://github.com/pytroll/trollimage/pull/197) - Update XRImage to create missing 'bands' coordinate when dimension is present #### Features added * [PR 203](https://github.com/pytroll/trollimage/pull/203) - Rewrite XRImage saving to not use Delayed functions * [PR 202](https://github.com/pytroll/trollimage/pull/202) - Enable free-threading compatibility In this release 5 pull requests were closed. ## Version 1.26.0 (2024/10/21) ### Issues Closed * [Issue 180](https://github.com/pytroll/trollimage/issues/180) - fill value not respected when saving palette images while keeping palette ([PR 181](https://github.com/pytroll/trollimage/pull/181) by [@gerritholl](https://github.com/gerritholl)) * [Issue 178](https://github.com/pytroll/trollimage/issues/178) - XRImage.palettize results in image with fill value inconsistent with dtype ([PR 179](https://github.com/pytroll/trollimage/pull/179) by [@gerritholl](https://github.com/gerritholl)) In this release 2 issues were closed. ### Pull Requests Merged #### Bugs fixed * [PR 186](https://github.com/pytroll/trollimage/pull/186) - Fix dtype promotion in channel inversion * [PR 179](https://github.com/pytroll/trollimage/pull/179) - Adapt fill value after palettizing. ([178](https://github.com/pytroll/trollimage/issues/178)) #### Features added * [PR 181](https://github.com/pytroll/trollimage/pull/181) - Respect fill value when saving palette images while keeping the palette. ([180](https://github.com/pytroll/trollimage/issues/180)) In this release 3 pull requests were closed. ## Version 1.25.0 (2024/08/15) ### Issues Closed * [Issue 175](https://github.com/pytroll/trollimage/issues/175) - palettize fails in numpy2 ([PR 176](https://github.com/pytroll/trollimage/pull/176) by [@gerritholl](https://github.com/gerritholl)) In this release 1 issue was closed. ### Pull Requests Merged #### Bugs fixed * [PR 176](https://github.com/pytroll/trollimage/pull/176) - Make palettize work on numpy 2.0. ([175](https://github.com/pytroll/trollimage/issues/175)) #### Features added * [PR 177](https://github.com/pytroll/trollimage/pull/177) - Allow overriding scale and offset values ([2869](https://github.com/pytroll/satpy/issues/2869)) In this release 2 pull requests were closed. ## Version 1.24.0 (2024/06/20) ### Pull Requests Merged #### Bugs fixed * [PR 171](https://github.com/pytroll/trollimage/pull/171) - Fix various numpy 2 and new xarray casting issues #### Features added * [PR 170](https://github.com/pytroll/trollimage/pull/170) - Implement set_alpha_channel in Colorbar In this release 2 pull requests were closed. ## Version 1.23.2 (2024/04/15) ### Pull Requests Merged #### Bugs fixed * [PR 168](https://github.com/pytroll/trollimage/pull/168) - Build against numpy 2.0rc1 In this release 1 pull request was closed. ## Version 1.23.1 (2024/02/14) ### Pull Requests Merged #### Features added * [PR 164](https://github.com/pytroll/trollimage/pull/164) - Build wheels with numpy 2 In this release 1 pull request was closed. ## Version 1.23.0 (2024/02/14) ### Issues Closed * [Issue 162](https://github.com/pytroll/trollimage/issues/162) - Versions above 1.21.0 will not produce IR Images ([PR 163](https://github.com/pytroll/trollimage/pull/163) by [@mraspaud](https://github.com/mraspaud)) In this release 1 issue was closed. ### Pull Requests Merged #### Bugs fixed * [PR 157](https://github.com/pytroll/trollimage/pull/157) - Fix most warnings during tests * [PR 149](https://github.com/pytroll/trollimage/pull/149) - Make sure no cast warning is issued when saving #### Features added * [PR 163](https://github.com/pytroll/trollimage/pull/163) - Allow linear alpha stretching in certain conditions ([162](https://github.com/pytroll/trollimage/issues/162)) In this release 3 pull requests were closed. ## Version 1.22.2 (2023/11/26) ### Pull Requests Merged #### Bugs fixed * [PR 154](https://github.com/pytroll/trollimage/pull/154) - Fix stretch when min/max value it outside input data type In this release 1 pull request was closed. ## Version 1.22.1 (2023/11/24) ### Issues Closed * [Issue 152](https://github.com/pytroll/trollimage/issues/152) - Linear stretch of `uint8` data gives unexpected results ([PR 153](https://github.com/pytroll/trollimage/pull/153) by [@pnuu](https://github.com/pnuu)) In this release 1 issue was closed. ### Pull Requests Merged #### Bugs fixed * [PR 153](https://github.com/pytroll/trollimage/pull/153) - Fix stretching integer data ([152](https://github.com/pytroll/trollimage/issues/152)) In this release 1 pull request was closed. ## Version 1.22.0 (2023/11/23) ### Pull Requests Merged #### Bugs fixed * [PR 145](https://github.com/pytroll/trollimage/pull/145) - Do not apply linear stretch to alpha band #### Features added * [PR 151](https://github.com/pytroll/trollimage/pull/151) - Preserve dtypes in XRImage "enhancements" * [PR 150](https://github.com/pytroll/trollimage/pull/150) - Keep the original dtype of the data when stretching * [PR 141](https://github.com/pytroll/trollimage/pull/141) - Update colorbrew colormaps to be more accurate In this release 4 pull requests were closed. ## Version 1.21.0 (2023/09/04) ### Issues Closed * [Issue 106](https://github.com/pytroll/trollimage/issues/106) - Colorspace conversions are invalid or out of date * [Issue 79](https://github.com/pytroll/trollimage/issues/79) - hcl2rgb bottleneck in colorize methods ([PR 122](https://github.com/pytroll/trollimage/pull/122) by [@djhoese](https://github.com/djhoese)) In this release 3 issues were closed. ### Pull Requests Merged #### Bugs fixed * [PR 124](https://github.com/pytroll/trollimage/pull/124) - Fix the brbg colormap #### Features added * [PR 122](https://github.com/pytroll/trollimage/pull/122) - Switch to new Cython-based RGB to CIE LCH_ab conversion for colorizing ([79](https://github.com/pytroll/trollimage/issues/79), [121](https://github.com/pytroll/trollimage/issues/121)) #### Documentation changes * [PR 137](https://github.com/pytroll/trollimage/pull/137) - Add dynamic colormap generation to docs In this release 3 pull requests were closed. ## Version 1.20.1 (2023/02/03) ### Pull Requests Merged #### Bugs fixed * [PR 123](https://github.com/pytroll/trollimage/pull/123) - Don't scale colormap values if they're ints ([2376](https://github.com/pytroll/satpy/issues/2376)) #### Features added * [PR 120](https://github.com/pytroll/trollimage/pull/120) - [Snyk] Security upgrade setuptools from 39.0.1 to 65.5.1 In this release 2 pull requests were closed. ## Version 1.20.0 (2023/01/11) ### Pull Requests Merged #### Bugs fixed * [PR 118](https://github.com/pytroll/trollimage/pull/118) - Fix image colorization ([26](https://github.com/pytroll/pydecorate/issues/26)) #### Features added * [PR 117](https://github.com/pytroll/trollimage/pull/117) - Refactor colormap creation ([2308](https://github.com/pytroll/satpy/issues/2308)) #### Documentation changes * [PR 110](https://github.com/pytroll/trollimage/pull/110) - Add readthedocs config file to force newer dependencies In this release 3 pull requests were closed. ## Version 1.19.0 (2022/10/21) ### Issues Closed * [Issue 72](https://github.com/pytroll/trollimage/issues/72) - Add install instructions ([PR 105](https://github.com/pytroll/trollimage/pull/105) by [@djhoese](https://github.com/djhoese)) In this release 1 issue was closed. ### Pull Requests Merged #### Bugs fixed * [PR 109](https://github.com/pytroll/trollimage/pull/109) - Fix XRImage.colorize to mask integer data with _FillValue ([545](https://github.com/ssec/polar2grid/issues/545)) * [PR 108](https://github.com/pytroll/trollimage/pull/108) - Fix typo in rasterio AreaDefinition handling #### Features added * [PR 107](https://github.com/pytroll/trollimage/pull/107) - Refactor rasterio usage to improve import time #### Documentation changes * [PR 105](https://github.com/pytroll/trollimage/pull/105) - Add installation instructions ([72](https://github.com/pytroll/trollimage/issues/72)) In this release 4 pull requests were closed. ## Version 1.18.3 (2022/03/07) ### Pull Requests Merged #### Bugs fixed * [PR 104](https://github.com/pytroll/trollimage/pull/104) - Set scale/offset tags to (NaN, NaN) for incompatible enhancements In this release 1 pull request was closed. ## Version 1.18.2 (2022/03/04) ### Pull Requests Merged #### Bugs fixed * [PR 103](https://github.com/pytroll/trollimage/pull/103) - Fix geotiff scale/offset failing for non-linear enhancements In this release 1 pull request was closed. ## Version 1.18.1 (2022/02/28) ### Pull Requests Merged #### Bugs fixed * [PR 102](https://github.com/pytroll/trollimage/pull/102) - Fix enhancement_history not working with keep_palette=True In this release 1 pull request was closed. ## Version 1.18.0 (2022/02/24) ### Pull Requests Merged #### Features added * [PR 101](https://github.com/pytroll/trollimage/pull/101) - Add to_csv/from_csv to Colormap * [PR 100](https://github.com/pytroll/trollimage/pull/100) - Update Colormap.set_range to support flipped values * [PR 99](https://github.com/pytroll/trollimage/pull/99) - Add colorize and palettize to XRImage enhancement_history * [PR 98](https://github.com/pytroll/trollimage/pull/98) - Change tested Python versions to 3.8, 3.9 and 3.10 In this release 4 pull requests were closed. ## Version 1.17.0 (2021/12/07) ### Issues Closed * [Issue 93](https://github.com/pytroll/trollimage/issues/93) - Add support for Cloud Optimized GeoTIFF ([PR 94](https://github.com/pytroll/trollimage/pull/94) by [@howff](https://github.com/howff)) In this release 1 issue was closed. ### Pull Requests Merged #### Features added * [PR 97](https://github.com/pytroll/trollimage/pull/97) - Improve 'log' stretching with static limits and choosing log base * [PR 94](https://github.com/pytroll/trollimage/pull/94) - Use COG driver to write cloud optimized GeoTIFF ([93](https://github.com/pytroll/trollimage/issues/93)) In this release 2 pull requests were closed. ## Version 1.16.1 (2021/11/17) ### Pull Requests Merged #### Bugs fixed * [PR 96](https://github.com/pytroll/trollimage/pull/96) - Fix XRImage reopening geotiff with the incorrect mode * [PR 95](https://github.com/pytroll/trollimage/pull/95) - Fix image format checking in special cases In this release 2 pull requests were closed. ## Version 1.16.0 (2021/10/12) ### Issues Closed * [Issue 87](https://github.com/pytroll/trollimage/issues/87) - ReportError "ValueError: Merged colormap 'values' are not monotonically increasing." ([PR 91](https://github.com/pytroll/trollimage/pull/91) by [@djhoese](https://github.com/djhoese)) * [Issue 84](https://github.com/pytroll/trollimage/issues/84) - allow customization of GDALMetaData tags for scale and offset ([PR 85](https://github.com/pytroll/trollimage/pull/85) by [@gerritholl](https://github.com/gerritholl)) In this release 2 issues were closed. ### Pull Requests Merged #### Bugs fixed * [PR 91](https://github.com/pytroll/trollimage/pull/91) - Fix colormaps not allowing merge points of the same value ([87](https://github.com/pytroll/trollimage/issues/87)) * [PR 83](https://github.com/pytroll/trollimage/pull/83) - Fix palettize dtype for dask arrays #### Features added * [PR 88](https://github.com/pytroll/trollimage/pull/88) - List supported "simple image" formats in docstrings and error message ([86](https://github.com/pytroll/trollimage/issues/86), [1345](https://github.com/pytroll/satpy/issues/1345)) * [PR 85](https://github.com/pytroll/trollimage/pull/85) - Allow customising scale and offset labels ([84](https://github.com/pytroll/trollimage/issues/84)) * [PR 82](https://github.com/pytroll/trollimage/pull/82) - Add 'inplace' keyword argument to Colormap.reverse and Colormap.set_range In this release 5 pull requests were closed. ## Version 1.15.1 (2021/07/20) ### Pull Requests Merged #### Bugs fixed * [PR 81](https://github.com/pytroll/trollimage/pull/81) - Fix Colormap not being able to merge RGB and RGBA colormaps ([1658](https://github.com/pytroll/satpy/issues/1658)) In this release 1 pull request was closed. ## Version 1.15.0 (2021/03/12) ### Issues Closed * [Issue 74](https://github.com/pytroll/trollimage/issues/74) - MNT: Stop using ci-helpers in appveyor.yml In this release 1 issue was closed. ### Pull Requests Merged #### Bugs fixed * [PR 78](https://github.com/pytroll/trollimage/pull/78) - Fix list stretch tags * [PR 77](https://github.com/pytroll/trollimage/pull/77) - Remove defaults channel from ci conda environment and strict priority #### Features added * [PR 76](https://github.com/pytroll/trollimage/pull/76) - Add GitHub Actions for CI tests and sdist deployment * [PR 75](https://github.com/pytroll/trollimage/pull/75) - Change XRImage.save to keep fill_value separate from valid data * [PR 73](https://github.com/pytroll/trollimage/pull/73) - Refactor finalize method in XRImage class In this release 5 pull requests were closed. ## Version 1.14.0 (2020/09/18) ### Pull Requests Merged #### Bugs fixed * [PR 71](https://github.com/pytroll/trollimage/pull/71) - Fix tiff tag writing if start_time is None #### Features added * [PR 70](https://github.com/pytroll/trollimage/pull/70) - Implement colorize for dask arrays In this release 2 pull requests were closed. ## Version 1.13.0 (2020/06/08) ### Issues Closed * [Issue 65](https://github.com/pytroll/trollimage/issues/65) - Writing to file.tiff raises KeyError ([PR 69](https://github.com/pytroll/trollimage/pull/69)) * [Issue 61](https://github.com/pytroll/trollimage/issues/61) - Add rasterio overview resampling argument ([PR 67](https://github.com/pytroll/trollimage/pull/67)) In this release 2 issues were closed. ### Pull Requests Merged #### Bugs fixed * [PR 68](https://github.com/pytroll/trollimage/pull/68) - Add workaround for broken aggdraw.Font usage in satpy/pycoast #### Features added * [PR 69](https://github.com/pytroll/trollimage/pull/69) - Add .tiff as recognized geotiff extension ([65](https://github.com/pytroll/trollimage/issues/65)) * [PR 67](https://github.com/pytroll/trollimage/pull/67) - Add option for geotiff overview resampling and auto-levels ([61](https://github.com/pytroll/trollimage/issues/61)) * [PR 66](https://github.com/pytroll/trollimage/pull/66) - Add more helpful error message when saving JPEG with alpha band In this release 4 pull requests were closed. ## Version 1.12.0 (2020/03/02) ### Pull Requests Merged #### Bugs fixed * [PR 64](https://github.com/pytroll/trollimage/pull/64) - Add long description for display by PyPI * [PR 63](https://github.com/pytroll/trollimage/pull/63) - Fix XRImage producing read-only data arrays and switch to pytest In this release 2 pull requests were closed. ## Version 1.11.0 (2019/10/24) ### Pull Requests Merged #### Bugs fixed * [PR 58](https://github.com/pytroll/trollimage/pull/58) - Make tags containing values to compute use store for saving #### Features added * [PR 60](https://github.com/pytroll/trollimage/pull/60) - Add tests on py 3.7 * [PR 59](https://github.com/pytroll/trollimage/pull/59) - Add scale and offset inclusion utility when rio saving * [PR 57](https://github.com/pytroll/trollimage/pull/57) - Add the `apply_pil` method In this release 4 pull requests were closed. ## Version 1.10.1 (2019/09/26) ### Pull Requests Merged #### Bugs fixed * [PR 56](https://github.com/pytroll/trollimage/pull/56) - Fix WKT version used to convert CRS to GeoTIFF CRS In this release 1 pull request was closed. ## Version 1.10.0 (2019/09/20) ### Pull Requests Merged #### Bugs fixed * [PR 53](https://github.com/pytroll/trollimage/pull/53) - Fix double format passing in saving functions #### Features added * [PR 55](https://github.com/pytroll/trollimage/pull/55) - Add enhancement-history to the image * [PR 54](https://github.com/pytroll/trollimage/pull/54) - Add ability to use AreaDefinitions new "crs" property * [PR 52](https://github.com/pytroll/trollimage/pull/52) - Add 'colors' and 'values' keyword arguments to Colormap In this release 4 pull requests were closed. ## Version 1.9.0 (2019/06/18) ### Pull Requests Merged #### Bugs fixed * [PR 51](https://github.com/pytroll/trollimage/pull/51) - Fix _FillValue not being respected when converting to alpha image #### Features added * [PR 49](https://github.com/pytroll/trollimage/pull/49) - Add a new method for image stacking. In this release 2 pull requests were closed. ## Version 1.8.0 (2019/05/10) ### Issues Closed * [Issue 45](https://github.com/pytroll/trollimage/issues/45) - img.stretch gives TypeError where img.data is xarray.DataArray and img.data.data is a dask.array In this release 1 issue was closed. ### Pull Requests Merged #### Bugs fixed * [PR 47](https://github.com/pytroll/trollimage/pull/47) - Fix xrimage palettize and colorize delaying internal functions #### Features added * [PR 46](https://github.com/pytroll/trollimage/pull/46) - Implement blend method for XRImage class In this release 2 pull requests were closed. ## Version 1.7.0 (2019/02/28) ### Issues Closed * [Issue 27](https://github.com/pytroll/trollimage/issues/27) - Add "overviews" to save options * [Issue 5](https://github.com/pytroll/trollimage/issues/5) - Add alpha channel to Colormaps In this release 2 issues were closed. ### Pull Requests Merged #### Bugs fixed * [PR 42](https://github.com/pytroll/trollimage/pull/42) - Fix stretch_linear to be dask serializable * [PR 41](https://github.com/pytroll/trollimage/pull/41) - Refactor XRImage pil_save to be serializable #### Features added * [PR 44](https://github.com/pytroll/trollimage/pull/44) - Add support for adding overviews to rasterio-managed files * [PR 43](https://github.com/pytroll/trollimage/pull/43) - Add support for jpeg2000 writing * [PR 40](https://github.com/pytroll/trollimage/pull/40) - Modify colorize routine to allow colorizing using colormaps with alpha channel * [PR 39](https://github.com/pytroll/trollimage/pull/39) - Add 'keep_palette' keyword argument 'XRImage.save' to prevent P -> RGB conversion on save * [PR 36](https://github.com/pytroll/trollimage/pull/36) - Add support for saving gcps In this release 7 pull requests were closed. ## Version 1.6.3 (2018/12/20) ### Pull Requests Merged #### Bugs fixed * [PR 38](https://github.com/pytroll/trollimage/pull/38) - Fix casting and scaling float arrays in finalize In this release 1 pull request was closed. ## Version 1.6.2 (2018/12/20) ### Pull Requests Merged #### Bugs fixed * [PR 37](https://github.com/pytroll/trollimage/pull/37) - Fix and cleanup alpha and fill value handling in XRImage finalize * [PR 35](https://github.com/pytroll/trollimage/pull/35) - Fix xrimage alpha creation in finalize In this release 2 pull requests were closed. ## Version 1.6.1 (2018/12/19) ### Pull Requests Merged #### Bugs fixed * [PR 34](https://github.com/pytroll/trollimage/pull/34) - Fix XRImage's finalize method when input data are integers In this release 1 pull request was closed. ## Version 1.6.0 (2018/12/18) ### Issues Closed * [Issue 30](https://github.com/pytroll/trollimage/issues/30) - ReadTheDoc page builds not up to date ([PR 32](https://github.com/pytroll/trollimage/pull/32)) * [Issue 21](https://github.com/pytroll/trollimage/issues/21) - Add 'convert' method to XRImage In this release 2 issues were closed. ### Pull Requests Merged #### Bugs fixed * [PR 33](https://github.com/pytroll/trollimage/pull/33) - Fix crude stretch not calculating min/max per-band #### Features added * [PR 28](https://github.com/pytroll/trollimage/pull/28) - Add convert method of XRImage In this release 2 pull requests were closed. ## Previous Versions See changelog.rst for previous release notes. trollimage-1.28.0/LICENSE.txt000066400000000000000000000261351514066130000155670ustar00rootroot00000000000000 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. trollimage-1.28.0/LICENSE_RIO_COLOR.txt000066400000000000000000000020611514066130000172260ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Mapbox 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. trollimage-1.28.0/MANIFEST.in000066400000000000000000000002631514066130000154740ustar00rootroot00000000000000include LICENSE.txt include LICENSE_RIO_COLOR.txt include README.rst include versioneer.py include trollimage/version.py recursive-include doc * recursive-include trollimage *.pyxtrollimage-1.28.0/README.rst000066400000000000000000000024631514066130000154310ustar00rootroot00000000000000Trollimage ========== .. image:: https://img.shields.io/pypi/v/trollimage.svg :target: https://pypi.python.org/pypi/trollimage/ :alt: Version .. image:: https://anaconda.org/conda-forge/trollimage/badges/version.svg :target: https://anaconda.org/conda-forge/trollimage/ :alt: Conda-forge .. image:: https://github.com/pytroll/trollimage/workflows/CI/badge.svg?branch=main :target: https://github.com/pytroll/trollimage/actions?query=workflow%3A%22CI%22 :alt: GitHub Actions .. image:: https://coveralls.io/repos/pytroll/trollimage/badge.png?branch=main :target: https://coveralls.io/r/pytroll/trollimage?branch=main :alt: Coverage Imaging package for pytroll packages like `SatPy `_. License ======= Copyright 2013 Trollimage developers Licensed under the Apache License, Version 2.0 (the "License"); you may not use these files 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. trollimage-1.28.0/RELEASING.md000066400000000000000000000036011514066130000155700ustar00rootroot00000000000000# Releasing trollimage 1. checkout main branch 2. pull from repo 3. run the unittests 4. run `loghub` and update the `CHANGELOG.md` file: ``` loghub pytroll/trollimage --token $LOGHUB_GITHUB_TOKEN -st $(git tag --sort=-version:refname --list 'v*' | head -n 1) -plg bug "Bugs fixed" -plg enhancement "Features added" -plg documentation "Documentation changes" -plg backwards-incompatibility "Backward incompatible changes" -plg refactor "Refactoring" ``` This uses a `LOGHUB_GITHUB_TOKEN` environment variable. This must be created on GitHub and it is recommended that you add it to your `.bashrc` or `.bash_profile` or equivalent. This command will create a CHANGELOG.temp file which needs to be added to the top of the CHANGLOG.md file. The same content is also printed to terminal, so that can be copy-pasted, too. Remember to update also the version number to the same given in step 5. Don't forget to commit CHANGELOG.md! ``` 5. Create a tag with the new version number, starting with a 'v', eg: ``` git tag -a v0.22.45 -m "Version 0.22.45" ``` For example if the previous tag was `v0.9.0` and the new release is a patch release, do: ``` git tag -a v0.9.1 -m "Version 0.9.1" ``` See [semver.org](http://semver.org/) on how to write a version number. 6. push changes to github `git push --follow-tags` 7. Verify github action unittests passed. 8. Create a "Release" on GitHub by going to https://github.com/pytroll/trollimage/releases and clicking "Draft a new release". On the next page enter the newly created tag in the "Tag version" field, "Version X.Y.Z" in the "Release title" field, and paste the markdown from the changelog (the portion under the version section header) in the "Describe this release" box. Finally click "Publish release". 9. Verify the GitHub actions for deployment succeed and the release is on PyPI. trollimage-1.28.0/changelog.rst000066400000000000000000000342761514066130000164320ustar00rootroot00000000000000Changelog ========= v1.5.7 (2018-08-28) ------------------- - Update changelog. [David Hoese] - Bump version: 1.5.6 → 1.5.7. [David Hoese] - Change default value of `tags` kwarg to `None` (#26) [Panu Lahtinen] - Update to version v1.5.7a0.dev0. [David Hoese] v1.5.6 (2018-08-24) ------------------- - Update changelog. [David Hoese] - Bump version: 1.5.5 → 1.5.6. [David Hoese] - Revert broken change to Colormap. [David Hoese] - Update version to v1.5.6a0.dev0. [David Hoese] v1.5.5 (2018-08-24) ------------------- - Update changelog. [David Hoese] - Bump version: 1.5.4 → 1.5.5. [David Hoese] - Make small code cleanup in Colormap. [David Hoese] - Merge pull request #25 from yufeizhu600/master. [David Hoese] Add support for custom rasterio 'tags' when saving geotiffs - Fix typo in xrimage. [David Hoese] This is what I get for using the github editor - Change TIFFTAG_DATETIME to only overwrite if not specified. [David Hoese] - Add support of customized tags to rasterio image saving. [Yufei Zhu] - Merge pull request #24 from pytroll/bugfix-L-mode. [David Hoese] Fix writing 'L' mode images with extra dimensions - Add tests for saving single band images. [Panu Lahtinen] - Remove extra dimension from the image array. [Panu Lahtinen] - Update version to 1.5.5a0.dev0. [David Hoese] v1.5.4 (2018-07-24) ------------------- - Update changelog. [David Hoese] - Bump version: 1.5.3 → 1.5.4. [David Hoese] - Merge pull request #20 from pytroll/feature-finalize-public. [David Hoese] Feature finalize public - Remove unused imports in show test. [davidh-ssec] - Add test for XRImage.show. [davidh-ssec] - Fix styling issues. [davidh-ssec] - Fixing style errors. [stickler-ci] - Fix sphinx documentation including adding xrimage docs. [davidh-ssec] - Deprecate _finalize in favor of finalize. [davidh-ssec] - Add `_repr_png_` to XRImage. [davidh-ssec] v1.5.3 (2018-05-17) ------------------- - Update changelog. [davidh-ssec] - Bump version: 1.5.2 → 1.5.3. [davidh-ssec] - Fix colorize to work with xarray 0.10.4. [davidh-ssec] - Add LICENSE.txt to source dist manifest. [davidh-ssec] - Fix develop branch usage in PR template. [davidh-ssec] - Update setup.py to include xarray and dask optional dependencies. [davidh-ssec] - Fix badge formatting. [davidh-ssec] - Reorganize readme. [davidh-ssec] - Remove unsupported downloads badge. [davidh-ssec] - Update PR template to not mention develop branch. [davidh-ssec] v1.5.2 (2018-05-16) ------------------- - Update changelog. [davidh-ssec] - Bump version: 1.5.1 → 1.5.2. [davidh-ssec] - Update badges to include appveyor. [davidh-ssec] - Skip bad file permission tests on Windows. [davidh-ssec] - Fix Windows permissions, try again. [davidh-ssec] - Update image saving tests to use permissions that Windows might like. [davidh-ssec] - Fix travis actually loading ci-helpers. [davidh-ssec] - Update travis to use ci-helpers and add appveyor. [davidh-ssec] - Merge pull request #16 from pytroll/bugfix-colorize-alpha. [David Hoese] Fix bug in alpha band handling of xrimage colorize - Fix python 2 incompatible tuple expansion. [davidh-ssec] - Fixing style errors. [stickler-ci] - Fix bug in alpha band handling of xrimage colorize. [davidh-ssec] v1.5.1 (2018-03-19) ------------------- - Update changelog. [Martin Raspaud] - Bump version: 1.5.0 → 1.5.1. [Martin Raspaud] - Adding .stickler.yml (#15) [Stickler Bot] - Fix problems with palettize (#14) [Martin Raspaud] v1.5.0 (2018-03-12) ------------------- - Update changelog. [davidh-ssec] - Bump version: 1.4.0 → 1.5.0. [davidh-ssec] - Merge pull request #13 from pytroll/feature-correct-dims. [David Hoese] Add ability to rename dimensions on 2D arrays passed to XRImage - Add ability to rename dimensions on 2D arrays passed to XRImage. [davidh-ssec] - Merge pull request #12 from pytroll/bugfix-format-kwargs. [David Hoese] Rename format_kw to **format_kwargs in XRImage - Remove unneeded else statement in xrimage. [davidh-ssec] - Fix mismatch signature between save and pil/rio save methods. [davidh- ssec] - Change XRImage format_kw parameter to **format_kwargs. [davidh-ssec] - Added some utilities functions (#2) [lorenzo clementi] Added some utilities functions v1.4.0 (2018-03-12) ------------------- - Update changelog. [davidh-ssec] - Bump version: 1.3.0 → 1.4.0. [davidh-ssec] - Merge pull request #11 from pytroll/bugfix-geotiff-extra. [David Hoese] Add setup.py extra for 'geotiff' so 'rasterio' is installed - Add setup.py extra for 'geotiff' so 'rasterio' is installed. [davidh- ssec] - Merge pull request #10 from pytroll/feature-compute-rio-save. [David Hoese] Add 'compute' keyword to `rio_save` for delayed dask storing - Add __del__ method to RIOFile as a last resort. [davidh-ssec] - Fix RIOFile mode handling and other small fixes. [davidh-ssec] - Update save method documentation in XRImage. [davidh-ssec] - Fix xrimage delaying computation from rio_save. [davidh-ssec] Changes interface to return (source, target) if delayed - Fix linear stretch so it doesn't have to compute input before save. [davidh-ssec] - Add test for saving a geotiff with compute=False (WIP) [davidh-ssec] Required modifying how RIOFile is opened and closed. It is a WIP on how to close the file explicity when compute=False. See https://github.com/dask/dask/issues/3255 - Add 'compute' to PIL save to allow for delayed image saving and test. [davidh-ssec] - Add 'compute' keyword to `rio_save` for delayed dask storing. [davidh- ssec] - Merge pull request #9 from movermeyer/fix_badges. [Martin Raspaud] Switched broken pypip.in badges to shields.io - Switched broken pypip.in badges to shields.io. [Michael Overmeyer] v1.3.0 (2018-03-05) ------------------- - Update changelog. [davidh-ssec] - Bump version: 1.2.1 → 1.3.0. [davidh-ssec] - Merge pull request #8 from pytroll/feature-float-geotiffs. [David Hoese] Feature float geotiffs - Fix xarray warnings about using contains with coords. [davidh-ssec] - Change xrimage to not modify user provided alpha band. [davidh-ssec] - Fix line too long in xrimage. [davidh-ssec] - Add float geotiff writing to rio_save. [davidh-ssec] - Fix left over hack from tests. [davidh-ssec] - Add colorize and palettize to xrimage. [davidh-ssec] - Add dimension checks to XRImage. [davidh-ssec] v1.2.1 (2018-03-02) ------------------- - Update changelog. [Martin Raspaud] - Bump version: 1.2.0 → 1.2.1. [Martin Raspaud] - Add test for bugfix on crude stretch using ints. [Martin Raspaud] - Style cleanup and docstrings for XRImage. [Martin Raspaud] - Bugfix crude stretch when kwargs are ints. [Martin Raspaud] v1.2.0 (2018-03-01) ------------------- - Update changelog. [davidh-ssec] - Bump version: 1.1.0 → 1.2.0. [davidh-ssec] - Merge pull request #4 from pytroll/feature-xarray-support. [David Hoese] Add XArray DataArray support via XRImage - Update logarithmic stretch to work with xarray. [davidh-ssec] - Fix histogram stretch in XRImage. [davidh-ssec] - Clean up XRImage tests. [davidh-ssec] - Do not dump data after linear stretch computation. [Martin Raspaud] - Pass extra format keywords to the underlying writing lib. [Martin Raspaud] - Add compression and nodata to geotiff. [Martin Raspaud] - Clean up. [Martin Raspaud] - Do not keep data in memory after computing a linear stretch. [Martin Raspaud] - Use pillow for saving images other than tif. [Martin Raspaud] - Force copying of xarray structure so original data shouldn't change. [davidh-ssec] Not sure if this applies to numpy arrays but it seems to work for dask. - Add better handling of failing to generate a geotiff geotransform. [davidh-ssec] - Add workaround for rasterio 0.36.0. [davidh-ssec] Color interpretation set is not supported. We will have to depend on the defaults. - Use dimension names to get the shape of the image. [Martin Raspaud] - Fix XRImage to write to the proper band/channel index. [davidh-ssec] - Add toolz to installation in travis. [Martin Raspaud] - Fix rasterio version for travis. [Martin Raspaud] - Add gdal-dev for rasterio installation on travis. [Martin Raspaud] - Add a few dependencies to travis for testing. [Martin Raspaud] - Remove duplicated code. [Martin Raspaud] - Merge branch 'develop' into feature-xarray-support. [Martin Raspaud] - Merge pull request #7 from pytroll/jpeg_does_not_support_transparency. [David Hoese] Check for format=jpeg and set fill_value to zero if not set and print… - Less verbose on debug message when saving to jpeg. [Adam.Dybbroe] - Pep8: Update keyword arguments using "{}.update()" instead of iterating over members. [Adam.Dybbroe] - Combine if statement and only make a debug info when trying to save an LA mode image as jpeg. [Adam.Dybbroe] - Set fill_value to a list of four zeros, so it also works for RGBs! [Adam.Dybbroe] - Make pep8/pylint/flake happy. [Adam.Dybbroe] - Check for format=jpeg and set fill_value to zero if not set and print warning. [Adam.Dybbroe] - Move XRImage to it's own module. [Martin Raspaud] - More work on xarray support. [Martin Raspaud] - Start working on trollimage for xarrays. [Martin Raspaud] v1.1.0 (2017-12-11) ------------------- - Update changelog. [Martin Raspaud] - Bump version: 1.0.2 → 1.1.0. [Martin Raspaud] - Add github templates. [Martin Raspaud] - Merge pull request #3 from pytroll/feature-python3. [Martin Raspaud] Add support for python 3 - Add support for python 3. [Martin Raspaud] - Do not change channels if linear stretch is not possible. [Martin Raspaud] v1.0.2 (2016-10-27) ------------------- - Update changelog. [Martin Raspaud] - Bump version: 1.0.1 → 1.0.2. [Martin Raspaud] - Merge branch 'release-v1.0.1' [Martin Raspaud] - Fix Numpy requirement inconsistency. [Adam.Dybbroe] trollimage now requires Numpy 1.6 or newer. The percentile function which is used was introduced in 1.5.x and not available in 1.4 v1.0.1 (2016-10-27) ------------------- - Update changelog. [Martin Raspaud] - Bump version: 1.0.0 → 1.0.1. [Martin Raspaud] - Add bump and changelog config files. [Martin Raspaud] - Round data instead of truncation when saving to ints. [Martin Raspaud] v1.0.0 (2015-12-14) ------------------- - Update changelog. [Martin Raspaud] - Bump version: 0.4.0 → 1.0.0. [Martin Raspaud] - Change development status to stable. [Martin Raspaud] - Fix version file to just provide one string. [Martin Raspaud] - Adapt to python3. [Martin Raspaud] - Pep8 cleanup. [Martin Raspaud] - Fix image inversion. (don't just negate the values !) [Martin Raspaud] - Cleanup. [Martin Raspaud] - Ipython wants a string... [Martin Raspaud] - Avoid directory creation for image saving unless the filename is a path. [Martin Raspaud] - Bugfix ipython inline display. [Martin Raspaud] - Add support for ipython inline images. [Martin Raspaud] - Add notifications to slack from travis. [Martin Raspaud] - Fix gamma and invert tests. [Martin Raspaud] - Small fixes. [Martin Raspaud] - Allow stretch parameters in the enhance function. [Martin Raspaud] - Fix travis for new repo place and containers. [Martin Raspaud] - Fix unittests hopefully. [Martin Raspaud] - Support alpha in colorize. [Martin Raspaud] - Accept and ignore other kwargs in enhance. [Martin Raspaud] - Add an explicit copy kwarg. [Martin Raspaud] - Fix broken link in documentation. [Martin Raspaud] - Adding setup.cfg for easy rpm generation. [Martin Raspaud] - Add thumbnail capability to saving. [Martin Raspaud] - For PNG files, geo_image.tags will be saved a PNG metadata. [Lars Orum Rasmussen] v0.4.0 (2014-09-30) ------------------- - Bump up version number. [Martin Raspaud] - Ignore sphinx builds. [Martin Raspaud] - Correct unittests for new stretch behaviour. [Martin Raspaud] - More cleanup. [Martin Raspaud] - Cleanup image.py. [Martin Raspaud] - Cleanup. [Martin Raspaud] - Fix stretch, so that alpha channel doesn't get stretched... [Martin Raspaud] - Change the title in README.rst. [Martin Raspaud] - Cleanup. [Martin Raspaud] - Reshape the README. [Martin Raspaud] - Support 16 bits images. [Martin Raspaud] - Use global version number in documentation. [Martin Raspaud] - Cleanup. [Martin Raspaud] v0.3.0 (2013-12-13) ------------------- - Bump up version number. [Martin Raspaud] - Paletize is now spelled palettize. [Martin Raspaud] - Fixed gitignore for emacs backups. [Martin Raspaud] - Added qualitative palettes and a palettebar generator. [Martin Raspaud] - Adding a qualitative colormap and a palette example. [Martin Raspaud] - New badges. [Martin Raspaud] v0.2.0 (2013-12-04) ------------------- - Add travis-ci deploy. [Martin Raspaud] - Bump up version number. [Martin Raspaud] - Added test for inverted set_range (colormap) [Martin Raspaud] - Testing colormap. [Martin Raspaud] - Bugfixes in colormap. [Martin Raspaud] - Cleanup. [Martin Raspaud] - Test for colormap. [Martin Raspaud] - Cleanup. [Martin Raspaud] - Adding badges. [Martin Raspaud] - Add test coverage computation. [Martin Raspaud] - Reorganize tests in a tests directory. [Martin Raspaud] - Do not test build for python 2.4 and 2.5. [Martin Raspaud] - Pillow importing bugfix. [Martin Raspaud] - Add pillow as a dependency. [Martin Raspaud] - Unit tests for image. [Martin Raspaud] - Support for travis-ci. [Martin Raspaud] - Bugfix paletize. [Martin Raspaud] - Added the paletize functionnality. [Martin Raspaud] - More documentation. [Martin Raspaud] - Add an image on the home page. [Martin Raspaud] - Fixed documentation. [Martin Raspaud] - Documentation enhancement. [Martin Raspaud] - Added the set_range method to colormaps and fixed the colorbar function. [Martin Raspaud] - Improved documentation. [Martin Raspaud] - Added the colorbar function. [Martin Raspaud] - Added default colormaps. [Martin Raspaud] - Enhancements to colormap class. [Martin Raspaud] * __add__ * reverse - Added documentation to colormap. [Martin Raspaud] - Unwrap hue when interpolating. [Martin Raspaud] - Change development status to beta. [Martin Raspaud] - Add documentation. [Martin Raspaud] - Add alpha blending to image. [Martin Raspaud] - Add colorization to image. [Martin Raspaud] - Copied over image.py from mpop. [Martin Raspaud] - Fix gitignore. [Martin Raspaud] - Administrative stuff: added setup, __init__ and version. [Martin Raspaud] - Don't show ~ files. [Martin Raspaud] - Split between colorspaces and colormap stuff. [Martin Raspaud] - Initial commit. [Martin Raspaud] - Initial commit. [Martin Raspaud] trollimage-1.28.0/continuous_integration/000077500000000000000000000000001514066130000205465ustar00rootroot00000000000000trollimage-1.28.0/continuous_integration/environment.yaml000066400000000000000000000004551514066130000240020ustar00rootroot00000000000000name: test-environment channels: - conda-forge dependencies: - xarray - dask - distributed - toolz - Cython - sphinx - pillow - coveralls - coverage - codecov - rasterio - libgdal-jp2openjpeg - libtiff - pyproj - pyresample - pytest - pytest-cov - fsspec - pip trollimage-1.28.0/doc/000077500000000000000000000000001514066130000145025ustar00rootroot00000000000000trollimage-1.28.0/doc/Makefile000066400000000000000000000110621514066130000161420ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest 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 " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* -rm -rf api/*.rst -rm -rf _static/colormaps/*.png 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/TrollImage.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/TrollImage.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/TrollImage" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/TrollImage" @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." 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." 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." trollimage-1.28.0/doc/_static/000077500000000000000000000000001514066130000161305ustar00rootroot00000000000000trollimage-1.28.0/doc/_static/colormaps/000077500000000000000000000000001514066130000201275ustar00rootroot00000000000000trollimage-1.28.0/doc/_static/colormaps/.gitkeep000066400000000000000000000000001514066130000215460ustar00rootroot00000000000000trollimage-1.28.0/doc/_static/hayan.png000066400000000000000000021305231514066130000177440ustar00rootroot00000000000000PNG  IHDRxIDATxtMrH!1^MX 8|h;_7L8`dP“Յ"P|/3_}rc$1=Zb{֤1A):bWk!ཧmۼ/WC!R7RJXk/#e/v5Zk1XkicL18N9kW!f>c|Vw188EE)kCk5Ϲ(X.V+a}'@JELu~WUm^L8H_0G{z8J R k-$wF-{RɰC.'⤈W8%vhw2hRrvGZkɳZUU֧֚X,v;f))||>_Tjb`2!a(RJcC)b9t*N90Ơl6m[Mx߾-5Ám6ZF#뭔k!Ƙ$ǰW1F9c 48PJY'l[뚿[H]Xk|W./\Km~BowN-(~YP~3.z.:X.8X׬kɵ2X,}f!t:?rj[f<Zxyy?w#l62NI)/|KO0?7qRĶ{/$)0$ͫg6)Mν90s1. 1,NS bCCb# QJa8t:xR qs;`=Υ1c ,1CQl^(gsWutکvi2TԼm4o8/O0_2K:nYkE15<υR0xd2nPeLaZ"K~6~3 ၬv|ZutJoSHw0P0Ԗ|m6FJE^8*othHni{nDv%dmه4F#wSss!ć,JǏq(1|߇FZM_k݂r(繩jq<$A2"sA鄢(XnKMMӴQt u]CaF5:w jtuDgC?Gr04xf\߷ǷFuA _+%)g «Ժ Wb(lx^\ZkR(V;ǁi]P>LLB&{FB~1Q5Ȳ3)dE!ʲ2>FEB@)e ?4/ ^)S!r~X|n+w%GjtLY-c1_: L$M,$ \.XVPJ5#"LSEsYPJaD:;Qmxl Lwv~'Igp>eY!8_ydpϐ/?PG4 זRg00;9>>>ӼեƝ@{ޢiDQbwdYk-Rl-bRX.0Zk(PUʲ+~>=A|hA"vӶIbo|~f})6$=7d"JT q )  $c N,JDqRlUsTJZ x-E ʷRt:Ȍy<HcdX*r:$@^_:ֿcvIb$VLL.v M$V[ro!2z=JF*GR%cꀢg%yzII]9o z`AEԢ.TۏvA3ն#$FQ `DۇO 'a xi~:T2Йkgv`TU,?Z+NrEYDEm[UUIX˪eңDjtFsZ)~Air9'T:_qzbX;5h;զZ}0$I?:++a4 k2UC2÷+=6BhhN?o{fY΢|}zXqLo+ CdYm#/L8wJ$3nPi鄮p< A,mIx|>#sa<ϱp8\.ZEFu(wE!v9 Av 瑱 \M@,xB8x21^=yyDVwj%!0TWWwkcY5 zV1S-6Z^ eYyX-M0 I$I"rycz\hYb Ju]c0 ˼{G݊]U7IiS/qL#ǁy>) s$phmTt `,`lF7vo8wј*8xy|Յt fZi~=y[SvHt|6ӄ*}NYk{H+Qvlۖ˹>[N[M_ٔߊ)4Msa,tXT?5_/tu'ߒ亮IT2§cWL,Kڰj[ӹcCoM{r$iNMd MZ>9ČP-tP x룝R l_Z9&!Z-f3DQ$p AHꢪmYaߣ,KvL&l6R>!4|~iwȲ Lqtzn'{dbG?_?t\=o0}#. 0 V{ډ%*rDϼ\H 8;|ޝfsSqpYxGcp5XMk12 ǧ@j@kwC7kycQ2]Is>1Q%Bc@k atMt b50'!Y Πm[8ݳ݃)I}t:^kC-t:Q~fx:}PSA74~^XK^Rvoo[Je65Ŗ:ʶ2,ڎsy~/@ksGf2f h{?~Puڶ>)f2 5Y'bJuC5EN_BE=ʲd 2ԩB9W@6`̲s7:j l  \TojcV9[TBcsJg:srݩ?%Ge9Z~h4vE4p8( kN_x}]DpZUkZ4x?SUUͥ!Bﳢ(<&HmKa&-UUfDqTjc5Ȋ{LkHirv ڈ^2ũAhI;HUʗQh}»CGB+U–<%0r s{5z=X1Ȳ 9jI2Sw4/2%~,i$Ln7L&\Z}Xk1]\ds2Γ́Tfֆ2)+ *Ps}HJ2FAN-h:0E$ RjФ7[+⠝&;eY:"*M_)I,KDQ<~zb@\.vXLSLSq()$vEQx~wxN5MY҄tN6'2B! c #InBzK6RQfLT fV%/%;搣DhVD9-Cf6;4G,:unV<4<QrF@۶ً|,؄!va2gP5+<*27Ef[S@. w RH@$F>>ϳHho$2J٨#ꌗfeu=O 9DbU$Izk"O%5iyc4aXt: !CsDAW[ua{,p8^w8ZPUU}u]il6{v;ǘnjcdY(bI &)ErMIͿ\In@,{(\? K-`Sn9 ffzI bRvK}f|O}Bu"!M(4/r (&8|oh1="ti4zmAJ]x VY(5Ϧ79^hEQkg\OH-m&Ms( 4w'.p.s?zyHAϥxU!yM+.U\ǵ,/`r9I.~sBhɰVh@*nơpФN- O%jeXMLry`-s Il^+h1>|g, O6>MSd! ykpLV?iXjX9)x3M»ܽoo467~>:Wk+dYfp:,r;YF0 81x,r>;yY׽ CaL=X]xD$tb _Hի8 D=D$M|>P{<ɋ A003KIJ,S$Vq Q"ߛ 8pįAQcrc[QƔ7 Q]Y B79$xlHD/u$8UycϹh茀iIzɑmy^pL/g뺶<ˬ:{{{GBa[ccP/xDOU:y.}h3.x.n{OJ( ?f4~u7ƾ'].nxÁLVN+svZiHI|n0ES$ fI  `"$ڄ.c&ƭ7d2XbUJv.雊(Da?y8{ ~CEM<~MjI2$H`FFIx,Y4GVvbpom^ʲL0Ę0he$ y [$s3X^, m6wnSʲ̓j'IxJnMsN/Bv[z<;t@Ea!ɬD B ! ^y׽5^'vwUwz&GoKL@N9$Rf(+&a@,>ĈNr5|g5ʣ3#ښ2rc3+m`\:'f 5H@D*5D }G\5}Zwʪi>~D@JQDu)N1H "!-a1{g@R+m] m;$Qc]#g &'JVW>mO]W9G6[7I|"(EEeΣ {sv.G_]m4/Z.iQ˼#_6}~Zmw^p8vs䂺8wEQv%u]|{WE:{>nGrnm{ (>y6r{yot]04*-R,|7ŋ]deSBt덠ϤEsyDZ<î>X(PL2٬wHitMM2GB4Mq:AJMYzu2׶EYR3 tj̆jR?ItȃVU 8:v=qw!л3Q~Be*Q)UlQYfN~óbgRSaV88N{3DѰ>cFu] ="ˌ.k䱿n=̩AͺEQ#!wAoiJy#ꧭ5ˬʂL\3mOP׵Eur/?5[B9z>="7;(O%3>N4wzSĵUGUW龠ލYьތ&t xUL&S,υLSAsTU=,3N!㜳{^|=Pϊbkoe&i>pwML {9ut"「$8UUYܶ>|=D |JSqa =jMd4~Q}<BQ; T~ע(e- XB3qvu2>:s[? 8zRKFLW㗗8Aḟ~ϑЉ5@B&j{Kb}G9?>+b^FSd+:F]YL&1z4_i~e##I<͠aSZ0|m Tw-l6mogHMBIҷrsD4jXvQEZ4MEՠ:GVV+9*Ԁ XP`!l߷"xrN_am Ny>u%9">ixn;n>vX,R{ڍk/%pi> ]S>ARb+ke[v* >c;~^-uχk7\'lX-GD J~0K].<=P ж̳xbaSs4MTon;uT$`85챾;l "w| ނxֈйSYkZ9wTyrהkEsqK s7dA?|>W;2PRWm[vZv\'EQO%a@_!Ma/gf|qJ.CKDh$Lʲz V0,˴DzJ]?v{w܋HTU%EQ4 SF/kYutYiwsd"t]@,_|%GA'x AP%5Vfg!IO{RUDL/MS_/73E|| /q-c A1h8.@:` 5[`G4V 2aT(4lXGR j,ah]w{`-jT9Qco]_ёt4 "|gZy3V5Nj=Q[7Q!~T!x"XWdhYk$3SeB{k 5ġc RWof3הrFd^&k^I8q^Et@}`jۥ {殹g \~#⻠ɼWN9DQk >Σ}c\#:~cX|>xI󈪟Y$n MӠ:}n<ϑ95p~GUU]A|>1D_au/eR'@ c}0pz_)|]j"A=.`0h [A~?$iP&غ(c*fўFeSu n pM8"sq@r$U6Vk|߁x1F[*g> nJkCˏqaC|L$*ȿK7!Wy|nSC,8ɎS%W*yJl^GjGt:\*x&xqsMCy0iXh߹>CP)Wv>rm/ܛ~/qrKiLh3G"E!JLnehfYV\~6^jBcV{0ju:8/"cQ9|z_|~ZNS$IۭܿNF*+8-mG%(Bxs} |"ʫѪg,3HtI6g$o[6aӱ\L 7;ͮUK2pSob4B`9;b8FЧIzv$ҁycl6 f%KRn7wH {t=zu nMRaPT$ct$S#cjQ5ɍ[3%/]+Q6$ B+sl'B2Y6$INZe̠3`<Ksv:P'Թ_!LJp(01j XVX.nv0`2`:8xDfp9ib D$?Ι($Տ11ۂbX Cazp꣞WΙP^P}ĩ#ɰr]^ 2އN]K@,l$2[-$Lnr$"6D|: \M5xcᶛ~z'kwf}U7+D`$He⾆_ˍ18R~$IEE0xt`jDahp[ ӧ6ʲtViBe5uԅ$qs_҉<2&Rݦ ې ["=ۧeì(]iJc*6>pQr<>RX12} <-h<2+?rJw?Ҫhm*D4Ms*=w:wuK}i}#clDHb^u:(SҴ`󦛪А)ėGT"H4qӲ44 p?B!QA~ȺT#m<Xk1 \.q8`jy68U2!If3'p@bt<1ʲD0Ơl뷟} Ȳ ƥ{v; CL&slۚ!> #< CEq,>?wU>WF#iFS3|>ZkGx}?)]Se,-t@ ,   Z W4H7%JgyP1t(HWn&Xl;7sf`$[CjQ(h퐃dݜV`Cq+ SGu uCECBH6 GIaZÊ1t:RS$O9ArMPĸm ?fkXft<, F-z4_ji[x6&b!9r l4 +kNt;z>v-Ių".m@ s9{>%nkA(29p6|n||YU?qg'b s/G)$&b-,s%wJܛDa=Õ[׋>hO&@`'xq30a`-yj%NX>A^dNTEQ<]˲TYi[ ͮzrTQVd2QWǞE844$(җ?'~:r0jX~p$IZln}jîQx|WYu^aJp3yt6d4Qt]K@} !p9A9R g;Y 1 1y7=F*/,MSyv͂.sWꈆ{Ri4F7^g-4ګV֏k^XA3,70 l6g:;9wGX2eŒURp`2%r#!hyd\:+}i>k&l@GQԭ1S4&V\ʋIT.S$~v(uE߻qeᮕWFݫKݶyNt{dx)gb£ڞzE ڽ!joc#h4LwPRɂN'cm <wWp\ L{){ XrAvo~<~y·H=x ooX,ʊr+Vd{/t:zF@&z(P*p>1NQ.Qհ0ϑ)ۭ~Q Z-dWjE9t];@}-{ 6X $ >{nBg%FD # xݮz>&ҘW0 Q׊G#bۈ^K# >C;AA֊;}7=@p(p"0 )qQ} C<iBBڏ;VK<&J 9g:Z_|ўM ۊս@iϫ{haC?yu:Ou YߣλGSZl/nmJ@ZisNHjJ.円>Ϙ. MgYVIaղvn8(ڷg_HL1{pCVFkz<:` AA6e*-fjgY!sa]y%ӣ=ϫ^:b- .<+Ea&6<:tz12)el0I,-1N1˥1bb$㉢H ￸{ѿ#>||>znyX,x,1L$ yǒi(EC+V0` i-FHN i" C6fȞ$]Y]וJ"x2PA(B`h4k?|]K@}x1Bd3>dgJQn3I,Ya AY8SFt7TS^UWѸ Bh\*QB8(=]#1標3G~R9db٤H5zրOS8ο'x41E:jWIw$葆QzUGE.-grO-AAq 5*u-à^'=6(\x6rq[?f{H#zd_~/~CUs:T&H$D$A cUUHӴgL.mɐ__K>#rː̹!O8W%Hc1eQ)3*v 8طQRl9I61Vu~,l]N2Xʞc E\.Ze511p8Du KNs[\:5~{w5Ç`_x? /߿ Iv;DQdEv4M1\ ϟ[L,K @4[r9=xp.abakil6kDQdeS%N9ckHbܥ]׵ce¹t˴x-+|]@}>;&3JNJH)(e!u>TiR!B(vRV$c̛ٙNVӓ(;pF59"2)eLU/ gXVɆ$& &"(4LA@)v }:=ŨdFL̢H#J! d6dȤ>3_$/ue~u9(0e!MQ 8r)h3!AIF\lLse^̮g^tP2;@o]ׅRp (TX@2)F'24,˺`4Ȋj:)K:JCUմ~ ~HUv:("ۂU#X1(bG @@@) \sXH5\,Hma" Cf3 ²,vgI5r4j56bVx )h}>5)rl,YV8wu$ -H7#dIqYA@Q$( 4#&I8"{PrQHx}1 e%!lu4l]nG빩Ʈal;dmK@s^b\9Yl'ﳂc]7˨It<[s}k?W ȭudL]; O\d](y:"Q?ϱV{ΫUsN`nj1u6)MKTyǸpGYCg^I1.zOjN8PVHeHXW6\2 u+g{u]\.3bh4RN69 {HwjRT_{Y( QODAy֝{Թ0O&m HdD߿*A4p " *BEQ(2v;^:ZBϟbBf%^#ɭzj M/өll=Y]uru/|]M@=m)PچKXְ0!dƕB_q&&.`i }G<臋roΆ)3s{gnX^,j РYQU fɚV,ձ6#x=G\p(Ys`s.zy}w3Z}י$._Frq2QGLr9לS0$H d۶>0'"dY&2Uo pqJ>L_ՔlAuq8_%aY MgE~&pi*5j@}h/lDH[:aJcf29`y&y-޹vqjOh^'8|)69>ABQTe$ʼn eY%OS9n<c2 Cqh4MzLjs$Mu.|]@=AVH$)"Y ~_@+:}t4xl@(/?f9soj"8)9GFg }rrup&z)L}b^.v6V3Liv5z^|>G@EeNy)XZION'%O n\c,(oOՒ9q NNQ’D~1rl)EA|%Eu4s~ߞ,cZ^Z]!;nlQ_3z`z3IX}G^04q`TK5=ICgYfnYe9܄X-m1 0}߯~ӓy}:r$y !m{H֓iC.#NٝQ)UV/}}ah"ftyp^Q`#kI MSqdL CmLSi~0 M|0ܻh6ʲNc@aVx{ y |_xmz_ByoXhԺ"cWa @Czan^F 8gZ7>vW-Nj]҂zj(L_h42fxlVaZsw;K1-ͪ;|];AvxxY@B!$;[cao鍿[; ,M Š.b7{xud35N4Mo@偡JMVj’ApU2v.!϶̲1Dz|J#Pe/X)0׆ͦv)g 0_@%΁VK[a< #1%/ GKQM˵7`vf|.dAZ2bBK߿Dj$,a8 ;)I6&RJ[Ua&Ja>k.[E'_Y&Ba.~Ҋ/+3'ǧ18vnL d 8o+ZjNeEE&I"(db73xq>f6isifQD׊g3ӒGnëT*朥b½{13i43x+*#~mò,,Ky5`vϑ3j1Rp]^Nyab>cXp8`4*9v]L& Ck{xGu4 $ \}£ _".x#1) ~XMIl!< ?sh{x |_ ,}V=є>'PID#'8w/nA|W-vA`u]V+Ef3-#vKRV0F♑l]n@=rTUm.l?; !7س$$X lPJhFN7fўͨ^%N3sg;^-hJR | 1& Pf2VM`K9Xnmm R Yшޛ,C&*f"5wZ-$II^|>6<»IҎ‘$$-y#P \*YXz)ɠ*+۽ /WIL*FKs\ 5x-ȇe\m?BʂH BTC\O.Ke{z$oysi/JwHVQhON,,0$P*N4\*)ͦ-9h:Jr1π4d;%KUA/OKoۥ'Dd;Pn} ?cp/Ul iNaK8::B݆ڢcY;Y^Tjpxxݝ Hh4>z8{R4uVlBkhx(eٻ_F|7W _@q fتxH `==u=xlQ<(h(&l]ͮPzJiio@Xuo!`\c|ąƽk|6s7¥?.;w)!崝3gofVJ!5<Hx>p^, KbxDww1!P e!i sM„#MFPF'+u4PrlwcF44hRF4Z|W=0חPs&,EL=No/˹M9Wg#(S҈pW*tz:3l"Vlꎞ7 xŹddJԋ8WJ)rk>ꖔ߶m0,L$G2iP^;H2$'eZtN3cqrz ٹ FiN[tY=OgFn#"u1L4kzF@Asl6^JZEX`0b@@fW~j/cw돍p1N>vV*acy BaAT!,K@<o~sa')>T"ۈd'`皷Bl ۶'_>>~xE;4Il;oA{.$T.("ETQ HP)No@Ckt%"KI "&vEqx7gK}?f0"|"qտcpi-;J2Gib)moo]lk-"AX;p!css`)CϲCd-#Yo<'o7"=kYkFY9Q H{ JO> ?ڃ1sbh'QzWC4=. }c=D='2ruyJԁ (ΓLmW2WKE˨zlЊ IN0ԞZ!0@lq:N}]](Em lNނ劑R%ireZCl'9.ߣ0$"SWD%[syFZ3|]-1 o1`A=Q܄?X:ZǛOz._?fUnHơLfc.T?`d0I*aП?r9/:xx{}=/~d,":x_"52?ģ(BӱV)GyamZvZ%t1yq6l!*9NI!D4-ʲrV&+޲8f!֊kP2 ($ 繉7ChAR qŻR(3)ee,1 *WDE&,XKiUb+BqdV",TX[*ϼ&Ib-QZ_n\ž$#`2;MShRyhS7]4LM8d~;ۤRTt+Zku R [I{K}.;KڐUK:vm8lFaY,Lx0 m1V:eqdƂ Ņ.^BlZc0ilta:b4}UVa2@)W#DQ0|{_7\/05&0υ0v46}FM"gR( {_~! ,XQRQ^+4JMLy% pud"krq2[oJegA'Cjљ 3Cބ1iWW3ۛ RuynfN]ɭ"YOדx$iZ-aYA8C! II " Z)(Bxax߹0 g{}Wk-@$_O}X__{:pxxXv;88ܨy>H<$X@Tͅ-L6`ϹMlxx/yyF~_|G`|r["\x8"onGG1Vs) vtel]=oP=Ic 4NTbBX 02љ?# $Q rqZ+uCHQ<{z]7V5;LFw4MG` 1ru41,_ٯF!'QPqjS8`$I$&\'"4"y q|<,s_CHKjЬj jG52*5 JI.ّle(2sJ̐c_Li4McjmS- @6)AVd2W9p]蓥k}9bbQz\ @e(ʊ39 {k8|f+ީ8@L KN\KShPWrZusf#{#Xjl+.HDႿh$ঃ ؋ϨS]ҹf,XvcevˉEg@雀 u\Jlsz ړ{h_)z^cMͨ75g6@v-s\ߓ= W~>w󶾟uvAB달A>"cc2& dn0 %NRjtл'|@$l4XVVZa 3ӌ18??GR1t`-k]_ m$AE0K cR\^} I rbh4ʈ^ß4MqwZ&C1o}Bs<i0ATcoGxS<ơyRFs_/pl&nTB$Q7Kvf~/?l]RQ]}D\3&DjLnl `1Զ9eR$A h,ߛ)A`gͰhʟL`KV2"I֑y~!cEt\H)c\.}ƃ{k{u[ PCYg N+d)v埦SGz}tN8vۭ~v5N7&d0tKlԏS7*ihtZGs䵜 SQ^2777h4p8s^OǮo_矯%sj{AHQ\v+{*TjUp:MSG|>GD$2@^j`jtoZrXiaR vFŹd<z: \Cd?#Gv .8 ,,1ž\e2&ARspQnh# M5x-c * > t]t:f^(d2<|l]ͮ@*  KW$Lp tOqÂBk1poΌ.wAJs2s~sL{c` %.aǮ汥Q{]9EZ=G[%H(§r{f}$A y˧ i:t8oҠ)x|O,%vήD*\ "yr;'ʜ P$Lbl5Y)tF*rz\_J7ɗ3 MUxs4r,e+tJykS9;JN'O Μ#:R;!2DAOFҹETZ닣f8$@_B\cshl}wߒ%9!z!y%$o]Lq,yO^bd|v-ߵc7Mc$IhX,y!)F- @QSOdAvz;njsJ~!ɵ}xQw;t:PJ!s;2 BIId_r$C'59Ya\( q^?U=4':I|`0nl6s iZ< vl]ͮ@B -P֤as\.M\ \('pJ) h;.wz(Lw|mwo ~[^_ZO<T]ua PKZ+m4:;xyhx,Y=f( I#z>n1FvHg\K3#e[dMMڱe} ,ǧk̥M8JFefť(hG#Hv_&eu]s, M=_:ΏbOz jkԁJ\SRt3E!FI1+^x8tHe96}2sgeR7DeHbkĤ#e?݄ٖUm"MSj%8"IdYWwy$tZl61GQ<1!~QzD?ˇ+ guʢO0 a(`n4M8d%cL&q,Yh7 툵Vt R8zed,M5ƈz=,xxË1#hsB6pT-M 0K =Adqu (o0{[]P΁~ cN'v;)rPW_Yt]K@,c0 <"g5"bp@#2 r0KP$XcEaDti-%.7Qz7'?AG(b( FڶmmHu](@oz1HJex>u-͟R8:!gEjp_6p[91IR!1=ӠF6W*W,K!igrG c iʺ) *~OrskJV}54jm,~\F kIc V. 5BkۊZ,AA=neYֺg4i0k4@e-NlͻOW&{R&q^=R#X! 1)Ѩ6c]ynDt* ].! Cv;$I$Iy!x4l6 ^-Ҕ#=>@a6^\_?>"7V+a]KGR:{;<u|:֢`0AҪh(Y*\u #y餧S!MSFCM $8evG\.w}s =vp/o9~{>Whp8 2qz|fx3x( ӼZE7NA Z _wlt]K@},`KYder(Wr(D &+$V $#,p&06mwWWWzgax/w";i &tX( (y:tFPFŊUBA 5M#/hF8eHrqa^|Fuo5de}bp8g"yY[Y~0ڡOF] wD2bF2_юWհ$dI#_&JsD9yB"`hvPB3V@?)|>kۭ,|!{Ϥr Qì:Me^ Bl,o !t"{D@r4YuqDmۨV*8Λn6j:t]kq~һk4.,.EUqw7WAAp(R2tQphA]qH7oNw~_~$YI~mP BC:B8(?"Ӭx/8Шڶ-Lp6 Asfe*8b" Q6a|ʂ|K.@3hD 9k PhR(h pMH; ''d|-C<"db-^z^<D8w*A֖yjYFc\n@d\n RIB0&37xDITJǩ]GQ$\e9~רͺ[ZVu]a(9Œ%mR~!i{, mX)L,Fav fc2[\L&~/N:bARץ}TU!ٞ: Cxp{x;>}~g- J ԋI2NONFRqX,"Kq*[\Ri#: ŒvP!6 ib~@Y:d2W?pɳC& uaZΰS"ϡSJZM lFp8ww|ca4]WvOBb X &ۓTGA`FCL @Aǂʑϐu]=oP=N]5؉дŠ3213XXX.HH`P*Vb@ ,QI'N嶎qs})#[=>W_ wscN+! Ep/%"Sb` LeZMИqGq}}c2h .˲Pׅ@s wfP5<|>*:wJô#x䫈xigʱp\ fs KjV4E^HF8\eo~kҿru4DNqH>kB_by(@ GC,]83^jA;Žض,*;q\(X,$GJ8<6Sq,o2p\.c !Ųj[`:&^!Moja(\+㦵-4Mp z<:],9RIYr\ו9ʽ=t &kORhm#k2.g[!\mϰ ,Æִƅh *zK$Qʄaq2'zU .ӥ;%%`Þ0뺈Hg [RAa/K򟺬˔  ?˹vq\3Q&,k%Qᏽᒥ+ ÔTaI+i|[,]Gf,)4yA%e-=~=l^wV%5MfX=σְt*y]j򾃋 ݘhFEj{^Z>~~)|xx`q]W?RJFCf0Km#"s! .tֹJ#* +V?dYijO+V_=gfyEc1|>yV PҸa!! n#I!;z=xh$R:yA`<#cqj8;;jwwiY1_èYk#/A=F`8奠;Ll]nQ` 2B1Mx&7}V\ ׸p3hHth*?C`wP;;2s=ע{ $j#)d:DF IBo)p Váw6^3TL. @CJV҉zT TȤ-X?W]JmѾlMylK(Fs u{<K_tA/TFtweKD"!G=y2CBEv4a=*N9e$\ D[tdJ{|kQaoQ|i, j5t:!\`_>!u9tcieN^d?u"< 9̌bр899:- zWWWLuBZuvT*\\\`jp]zv(h6zQ~_Vg`F7~bQri(d2Rt]kAvTZ7Icr)%śz衅޼*z/#Ŀ* z*9҂WkAl-ٽ,h50޾]k2y~|o 2@VT:  lIXYU1),QVEY^[`(IO7h6B.DZVE#nsr;Rh+U9"E]D]RIUa^:@?3vy7R &0&A.؎qxuM*]m8H)zG$*j twFn]ו5_Mjϙ{IQfffp|Tee;KME !P>zbĵ4Oh|UZ I2 9^@e8{0(l!6JF躏x$u4ib!j+gg$u]i%LvIH)F i>kD1 ThtiOO`Ap}<|o6!MSM7v q0a}Ab 6xc ou74+1>Qtڠ7nϘ]oy+6Ϯ(" Iw+=_UlooV JKKKCCt]ayyNa Dtt$B8;;(pr]@^fg(ݝȫ t>:NV0KԿ'C9Z|w:^t]Mk@}rWMj%"M` _@/~@{̡C z(`C.!@"_jǘ m}vgfg̼5 }ݿ^c2RM#!ؓhZAnZxȖ8|ٸ}ߗ/.1.//+U/ާ ( xQ9 P}гg|pq)

HDPǽ=avlu ):xDupnqv:ś篐$珛sM -+Tdv<#Iu]DQO_^pF@wiǷ/sH'P^tF*u*<6=kL0[ 4O|lEX]]#Z-?B|>xS4'c 3!M4v˲r0HijG|3 )* E2;Y8Bk>;\.'-keqd/+휓8Hm4Qa>yA`j$l:RyFX D|˲Zгx\@"F~eFOC, ~N-ٲ|Z%avbz[VS.vvvqk!c>,QǹdGrL=Lf"*J \o?ov牳zpp Sfx,@pb8;;Ct:5كKxV%éH{#e|6nnn(P:^_fY\n.Q(yhd]Mka~ H {̥P<4Жzɥ?Gr)Z@i1!~lH{>݋3Hu?W VlEÆ&TCph0DkKC5J0B*h÷`Vl 8L4'j W:H^\#ߺٍeE䬢.;%DR(n-klrMI -}ʃUs8?4hL&1JYmj1pBX@ G[loorDأJ セ9Q=wY~.<'(u͌JHx p-~q>!岌abT*t:!^]lzn?Mϥ&m۸t:Uyڒ6FpG&|Gd2E2 vwwH$ӗ 8s )x7fq~ݫo6zg=͐f%[u]^Ã>NOOl.1h ё[p]Ǩj( m_Ɔv&J$FZE:Fӑ4DyЀ&}`XNPTN t]MkQ=gu64 n&\nQp{].Y !BBHiڐ2a&5qrnndͼy_{= /f  mDk&$k6P.E͢*lV@N_9c&c"a\w39qr%@L$~}J_&ЦA?zr<4wO{<,]ȘgGㅹ3 4~6y_&QҺz6j/[ޖ6 %hB׷8RqSP&0U~6(=cnNGkIRVa[68^\4YL/euBǐĥ02qlmeJR< PNT8mƒ- qڈ!@Iy`bW%A*`Ќ`.mQ~r9y=sww+++X\\9"ov;­䙩_>(B!Pq||,ҥR kkkT*ISϝN`uuP(l"HabyyY3 0DEAX,bn.Ͽud x8a"L`aaj.^%Ga;;;؀eY*/?Y#ضC @r^jFSr7e]|F;Z4 8vZMue4H xy'&:lIHz/x<t];k`=<-L t@B.RfkBH.IҥPfmBqbK&6$Y ςzC{=~ZR ^uVQ*B}QkH$&9/,,Ȱ ! ӧ69N{9Fli3UE yͦdlPn0xǵAקSiFR*u <"bA Ilz~ ~QD&(9ghߟBj uF &!??{itqw7VEA$d76$ؐA߃n PCbsSk϶G)pHN^"R&Լ*~Sq\W徚r5}dxxY4QVL&Q*0 Dd&D'[[[8::B^eY888P8<<1t]GaqW"L .cggeaFCN]]]EVm Bez.];>o<Tg"1})o" mT />1kυ;&}Fv(h6VNOOj`YTpvvBK7'( 2<,--T*`ooOسP8iHO,j fӆ1x<#4 nWb N|\]oA 4 X6z-1SOăGO=ыAxkbK!&⥇6j%d] eox {&P X~fHf@&N iRlV dh(ϻR(aKeI !_9^ޏcVUi<-C"aӳ#spp ҩ E~u:u?y?C)2 m$Mi\1^n\\1F1Yy(B@HE^ѶmD:~8WqAƈF\74iRڰo\d)XVW xЉtM*7_w d2TqE" _(dl |!J)4`zt8ule)CyLTp&dIVMӔ+Lu!9) 4OP<4M  mRD'$X,⛹W<|D"\&vww`06/4z]rjNj5ZJRAURg Mb5LN:b2TRxz\\.?n<~ bmm mHjxPBՊ3;? 58(Ʒ\Wxt>?e}VNJD/b\8.a%0L^CA//û"`YD"0pzz elnn*t4!՚`psò,%fJ%4MyFq\^N @P \SBߩ zHPH={p4Ғxܗ,]MkQ=ӗ`Ԥ)Sp U  "p!K;)Eq"`BK&2 ۆ$.^Λ*M`f}{=E>/YBT) Ű(2]t-0t‹Dv;~87R ssEzZҢ 2%wcA(@nXzi4ڔ$Ni5?);Eq)D$| ٗ HFt:m`yOvAt lV:DNeax26U2,37.2R4b:@~bƻei ĸt<r˽E/`*18FiIas:(7 T^1rNJɤ}B <4 PޛQ дəLFDȤ$Jie+5糙LfR9%dY,//#h u> *qQ>W}yX[[Cp[8Q~rD7j= |GRG |>o:< z4VV6L&133rݮZ1MʪJhj5(l6Q,eYvmTUcHC;: Z:m/)ܿ`:5lMKQ#ф 1b@E!Uڥ-]].\tU"]?TB,J%-1"ZjUE|7E d&w=9='V,D:#v0EBBvEXXfqB2J+@O*YZi)9>1Ք>{ v JJ9ɨƪԿZrj)%Tf9$|%vw1mDm;_=/]CL_99&NDV"X̔[(ԽMFYS̐'}~WXNnkO.ZNjAyYJnm(V7 1RB1=qI&&jhݖfl178dYӰE2VcgLا}+(V%J: C\ץn|zi鞩B:g&%&j;h^v:=0 t軾^<C$g=;*"E&###,,,0==MP qvvFbeeeJlրAvww}fiFP`'Z9(6&A^gssD""FZF:brspp zqnN9d2Ƶ(gcffjj><>-qC*%S?/H$T*^bOggrʣ}6#~v@_2=x++6}R~~ y.kkkNMMZlll^<;KV鞎9s%1 p*IT # {tJ086WK?g7EQ\*vwweE5DѤ@w !d+T6R׌#[|I\E! Ô1c^SD/Z &3gB@@s(BH/nP3y$AE.(Xi˲ ϝY$q>餗ʚq}ƵީjI&YFG^cii ZMf33PTIw|hf[Wapj͟Ёa;;;Fٰ\FC9xC_ pxx(ErXe_Gͤ`yyRRT|˒dxc&666P*t,˂m[pݢ`qpg\[c[7k\v\pъn`W{03 N0?bq6c oqpp=`mm RB_C)?'޼DݖVZEٔhHbQTFCBٔ8Y~Rߟ5OHOǎb:~U7oNO l]kq|Ormx6b S!եdAEGG蠣:8uR袄R&R֐K+;5)$|{,ZM9!?X%Y㌚al&f)M.l;=i})c/EXfe@" @ʟǦ$*C=_kye 9`+Kvc=u*mT:ɎW5a -ä(?+RiIoPHlAMɨ'Z>r01JX:NO9$FQKיÈ&BAv}@}A "xG뺰mFCb ,r=i?A ;eYFg@' <Iz=1ZykjyLR pNW~PfrѠ6MRxWeimgP. w]F孔H ,DdL@}\eW~?u@4-Q f_Tѷи/J(HpZo:F̰ xqo brGP@&80/aq S#bV}xXbqm/@FB2*j+/`ssS+ZDr"dFy$vwwu_XX٬6)_|jaod;;;(0\{ lFxցgOd<:w`6}@m:miKa葩a`,aoFUYYy!b_Q{m劲cz74:88 AVX䰂 8.:H$4E: xY3e"5NwˎHcЩ˨WC!v"Xn1 ?9ɒj(ǧDkPC޻ O,ȇR>?J0 q1PBX@O6}܋|/kf^'ha #4rC𪪪.h4"M$6c`8}k˹ ֹܩL)8QNG055oc|ϳHxa/_ѯeIdy R(lQ>Ac?{ -#Tܬq}JpjqDýbJ"\V^7ض+쬸/^^ò,R)r9A:QތFBETR)vN B`O* ȏ*l]MkQ=LҴi)I,"`n (bBD@ ] k4 A-)6ifڄҤ a&3sq@?/G2$++~ƛ"}|`bbQ8F<ƆlPr;|=.ZNqסRd5mFt|' lk"d?)@eD؃iPAɭcʜz.V > Z:0 1WE.FE`mmMtTmXT*P($L1^8Dh" c)xv '^D4[ ~NU4 r ۶xfO{|~;EvOPa 2M|_^1w@%'Q];w²,LLLi,--!0 caatx8g4qrϙ@_YDQۯ 3w7gx䒨T*0M~H5_\G&iH&PU>!LP( akk HDUr98Z&6GGGQ.QVEH$.ǃH$2OL~`GG-1APFwi~ds\]MOV=6N$ 0bRTUl:/#*U uWA+2"U F%i1uɹUd%v}{=#=0P֨sw@@:Sw$fffJ ɍ3 GH&Sro].lA:(}e .JIg@cP}x7A e |Zly[:%^Αi}I=06X=R\)b&LÀ#\.'Vٔf&0z[Et:apݨG.77LB`c4uWWWL4 zan+/>a7I\tYLG:bDw'DϑG܎&a{ =asY@;qw[&PP/)9|J)/lJuiJRJpNi69C,K4+L󵢆O`Z(u!m($Oﺮ [m#=!H}D;4aGaӏ=<<`}}Bsss|7aqOI/LDxDxuQ.js(bC\^^ dY!׶mLMMIO{Q ⩧;XFdPTp}}\.3y>4"r#_j:E,|nna$\]MOQ=SXPXW &lH*MW veapANʅdAc70mAfi+!<]vәy{'n$[Z{3K4feK*JQ&J8CU%?mB⿎n\F=ߴHA,Y gim[)Σ!Љt. f*^ڜ4r^w=Y >a'} d 5C5 kHgmߐR |> ׶mDò,f]]]Roa9W iZr>< n.d!5y'U rV*U2@.p~^m$ >0== }zz*O$@ɚeضY>~l]Ki~&aR['I'B+[{^XӞ,H "[ v[ЋGA*`ۀBY;LN'=L\rd,y8+g V(T5fHhU%gijjZr' L8SUpN: a&~\NsfdV?}2*F]}&:i"4|/fӃmqEx&: uNy nYR80 YgˁETG[%"XLDV D<} .(h2sL/8ι}3iH7ju] ""b |똘v0󰵵f 0<u:\ %ٶܐ$9mUxQ,^$,prr";4M ض 0144$zyJ9ܴcggGGGV!bkkkd2 $DefJmrt"yX(Y8rQ4 ܸqbxg;оgy޽} hfff|G=>/DRxtK24qh'xbSX v>Cӿ ҵcOޖDT$l]KLQ=̴-m MH ܐ@ $WcĐp"1c&MC)bm Sv:y6vL;3w߽wW-Oqdw@A"rۊ2g)牮x{qg:泎j&6s_o@+Q)$ƩM8q,{Jf)]2e`N(3SUu ;7qPU*2`-3i3]цza ~ϬEM Na0h4MeY8<<42 BrVVV!n\Y !0[>2Üy,x9/sA$$#]v"ᵑHHr###ERSm4Bhx8"\ׅi=:TUEX؍'3곳3QESUEq ߅Zū{p&NN"SSSNKxp7OAGsX]]ETn\nEHFc ?Yr-̠P(_d2 ۶\5L&j099F˲P*5$ loo gll pX G*X^^m8>>iH"Q|1>>B l@nNຮu9klg,R)qj5 0QVn\.%z-~\KUMj5et:avvq+~8>_Ob[vW?[xXeqru MnM[p:PПPӇK(}ߏ/ۨ—`}}Jidk[W?=G$TKlF­'\;%KJRԩ:Ő)'P 2P-`00" $Iwn{s)lyzc'}BT*V2 TqA3m$T,r677i4ok*kkkerrrjjaO"r4MMN1sѹO>#I˷o :lFSlmmqpp0n9OXYYaccCvvvx}( q\~m|jZ zo(>>%DG(;׿W| 9'7q꽀w:#f+++0M߰E{=27t l{zR$RV0b1Gh4066&˲n5j5LMMPT5Y(#4n2RVUOh{L PE"rylGI] VBIVJ{a0dvMR6:i]QבH$3"d۶c"y-XL~wRn1Ą?==Am?`ncQf/^Fn/< .@!8- 3bhhH.nԳ@qȈ2N(|8 4Md2 KYN{K(*BLƶ-XOFK&red1' ech<8~I,ɂ$5ɤ%$wuf#ˡjJ>0d5;h:*ՙiIxDccddX^zY7ڀ~G9Tʛ:'Hedҁ.;.4\h`4Y H皸hPA`PAmnkADCu$l. t]MOZ=u$McE-2cGTlشR*Zk$WJlW$ @ $h‡ [8gr&s̙mC`o9;*2MgM t0&&䧧t\FESLjHu$ks(khFJ)\qc0I,\וjt̿pyigY7{>۶a IO$)z=`uuN ޖf7Zt㌁Idܯ#Ƅ>?<-=bJjO[}ėߠV*Pױcٚ#~E6J(,z=J%F)2VOҺh$IIY2L?)ԼOj!4Mxrr"[H q&H޹\N Ku?"f1.hTM@'!(Xȩ\ଯ0Wd=5Mi @|?mmbJ"%a(db$=cBR`9v:Z2P,eyx:ZqP*)U푶d,ѹnTޏF+ceeEpw9@ollHYbǨjbv-0 199 qX? ]4MJZb??5qRHwhQvK yhZX__QذP|{̶B+? }cC`KTqt2NdH1AU!)[d0wZgh=,!TR";4{r͐#ϖ3Ϗi/kR dqoLj Ju-ju RJTU4A&>&;}J}Ƌ_I't!Fэ 'Q!@ G&ֶb1pH|;ȟP׌L`'j\.k K"Csb\DN7k}46_ihK(\MbA R&-s LVSu4Mm q2o>8,h";Xd\.M&MmqCj`U&ATBT*nx9vvddxgǣgĨds!;GAKYǏ,} \(AWBi7aqF7{wtt]o`}NR'DiS%iЁj:NDXbfcA, 0?!$. F"uH4!ԭˉw*AYl&O/XU훜~f6)#dhr2}+(!z\y$'/f> Xs }q™mۨT*"È-chTh}-Yuw9(|7By71y$2mfړv0mF.R KKKH$t:ׄ1l?=<x0a(?`Zsڙ~T4tgrݓD(㘛-i/y^$UNXLe,zM1ӓl]MkQ=3IISGu ѪPn .DpS.՟[Ѕ;.*]*R() Zɇ|ts1slK޻{= q+ QiɈj9u!qY, fgN"Hwi1`r*G#2٬N;885Ѐݮdd*\30fyH&(SbD:;3dBI#%k\gHɆ'a"d(zV 34M44pߏ΁R a h%]zZ! X&[!h*IA0^2i Z5qj5,--cll 8. bM{y7㻣Nǰn/ӣ+x~[4>Pc930tRx2#ܓ\.'ā5i41M011!~#˶myT*TUo L# 0 J6풥${3332!gqbee''0YmP( ϣX,AKfgg199=ض ˲#TTr7 Qe)V)ymm $z{4.{kD1(oG,\No6[x]G2pc:\ L}_+Bg"B:2f@!Yvw'L&?\]kg~g%ɮ\R{*JBuBbڡ{!B@:@ AKj0jp2\S;O;I WQt|<|6;z tw:Wqc!0 Hŀn{ޏxxlv iqar^)&+JX/hd/YvjeɆLsy&y,#=0`ktߦI&g{^`ii n}VKGuh~X~eh։Wc{^| q $Gpm~x.6e@]l6E,Ӕmރe=aϣ( \\\%Ft:P,KB8|(`vviJ' LB(u$I($Ϟs\4X+=wƩcm[œDZ*LA)T*y.ceYvx۷HDL`8ƆE0Oh #ܯ1\%j';6f/MMܭ4p5=#AK?7.܊ѩȲL:f5˲ axZM3,9QN 7&%(T`S*TQJ,z+ד`0t(( p넾z]ʲ q܃܌|,ҶmvkkX\\&0wCs4ryq|{V*qpppma|ka+aW' PjMzoә!οZ.07r |VVk5B`AF xz!8jTpa@ M/#d?lu?;gC)uR*ڠHF !"$UV"P.H];D, (2iIp}vcgݙz{gD\S@P c0NhD\-(.AKz=weQdU^Md0srIS3y>΃I pɤ1 # b$_||dr_5ht:9;;}vwwgggG1rHD#%_ɞ}ED2l]IOKJ*HGq8of ʵ.[yNfɃG4onr+Yb:̨rR)P 嬰{`Ri~.e8-"jHmx0d0,C9xMy@ӂחSS 0˩.JEi\U%R 7kxG!Wຮ-El6qVVVX\\$N,˷:?=yf8c+&ՏZ,%|{$}k?M1[~kGd{ԏa}eIh:vj dtW>G2Pp4H$8H24N>x eS5sߨtk#u?34M6MtHn.m"Uauă&7= ^w܃R -TPb ZܥƤngM6d2&sM2{3$xtv'FVV[ xKН8iM9tZ1G&UJV2@>pc@!Yʰ"+܆2ev<܇JZrBp_MiWdTDUE_9Ν$#X_WY(0!m %,(\tR .6uGzw' "ׯP9pާmPq]5|-i6T*: jW۶urܯ65T,NMĖ 722 } T5MU3,]YDmrrRR,ٴ̘zDb15j&㨭wRx<*;;;mY"'S,= `Kp]TV]!1xS!)v I5Aj]*E5W,?QG#?x^z.!sc97хwڴiu;r9z*V~'klnnRHf'<,B4Q2+++8m311iJ%LT$HsI^j06ǿ cvHf2*G]% 8 $LMMV@mDŒ$q##)_DFT|gqqQi0H5Nld 8Qr>FDfض-o_r!΅/?k\~崭|]VZ-YZZbvv]^J1..W:<\t"OQ\eF"몏xuww\.G__KKK* `nnN jq8XH$uBѾ.̶mȉLjr-l+JǕRZm۪Z]~p/Gd28*9ɽhma"$ 3ZMqKLH6 Cѽccc +{8Hɏ?`|%N hვ~J&+8-<7mO$5O1b99 ce .i2::‹ib|l˲Mx:/_fTRݻ˫WZވm[)LNNReyyY%B49==eaafJ{S|kjjd2ɟ_0Χ#M~9 >`OEMaLdR13t,i*7 ZWWp]yNNNr9u_垉 ceC߿z%a,P,9u]9::0 PT*8h4X\\$J\7L*FW/$Hp;Rn(hTYp@AE8UBw)ݻ%RT888i&@DXdssium1ӡ v|>V獨 kDD* fZ5uK. XE"ec-loU?^ziqpl$+i] E` BOꡧr-(AHr,*Ev槳J;.e^"nZZ{{|gNќDrXKt,i t\!^Dq\UZSW Sܒci!y.9Pv2 Lc\VԸdqU+OPO 00뫋 #jp"t4Ґu']u2S(D8 y*Ɇ8$} o7;-mKPpj.iHd2[[[+"|( N[bH*RO>0==zZFNqxxA"QKiPBREY[[S=勒FlVM6 Ð)rQ6*[crz=Nm+eY** è0l6t:ʮt0)%_c%^ͦ899P(8e. č8kèQ{w?8F6u +*:LXC][aKoh8h4T5\3M~O&Hppp*|3SbccL&CXu]d(RTU~ZF6Q"Ao1Ua>o]$V况oSRyiwyWg@V& sS/g<1 ltmf2c ^q~Hԥҹd82hYB1H[>~/d]Oh#ug: dӦ&lK {R Ag/EdaAa=x"C+ PBmnM͘6 [37'9%K}{Iʙ,ŀL)bP:+vwR<TmjHxA]j5O^굆X#`0O+>6H.YAh4@ӆ#&c6¶%^sssrx˨C>Gwvu0 +XWXBu@ṫncQ#KQ< ^y!tSSShLܺi((0 ʫ# I3U9??.ZWAu븺򲘧h4JvQ*( &''g.ɪ7C52赅EVpv 躮X{*fffp||p|*]PBXTPD 6Sr#u}dY  [[[h6D""|(ظPU̒t:L&#|iT*Nu;, 'S`RsR^| &p6vh^`zm0ua5w?pCB!.A\$T?ùFv\]MkW=ч5QHBqL,wEqM)41tE)҆,B J7 +)).`cꍨ?"G,Uq4l=^?/^sdW*cz<6?7u,q!!وp!Pw\ ry}F?@U5ah9zFV y1|G\^ZU|y*9>JKd8l=8ΙSA2i"GBCg=5Ԅ|52ks,\_)ad$ls9G/˲Z"uQB4L^.8"@4nyR җehEQDžqvmuDąm#cte Z f&1Ir4{[ZWժ`L^ݮUUž{ 4M٩T*"vT V bBC ކi$ ###=0IP(0 T*`xxzzhT4"?( r0 QJ$#btt\.|>]133#!l1"Oܣ?C.dvWQ$I4/7u4(aufmncL&#!m{@Ts{{{|(r`uQ:$PySl6yLMMAe躎Cllllp(J8::BP% @88 2&&&È7\"m:@*a0ݯ;!Hem<8;Oxr>D%` W߀:BsH8bw~},>@\vQHCCCBlY0f/MQkWE#&pe- fǵk5\5ŋ*]Ȓk|9L]MkW=XDT*؆bK)ԆB?u ~jux#6: ϲLGb$EM3j7yw&Ќ)|RGJ2!d2t&ul&,agjo)C 40{i\]w:ܒ I`G%H'u]* ʍRNg:̞\^<qڛSBGJRnJA%}&[&φ6FqBDH$~?P9HȞ8 @V ⟨)xƧ#x#kf$Ilbmm-ceY¢|U lHhJ)LLLR 32VD@G {{ s ƔRQjE!3644]u]Tt:b PF+MT**.>DT.!|G.RWh4\fA%8ªɤ p>/+He躎z4h~!kZϧj³<~ u>}ssEض TUqZ_c  (-~=ŋW |}PvƬݑ~} /0u%d~~^*I 49o&x\ 00%l7G5Ҙ+GrG}|lt?WWEǃǨ;#۠7ab#MȲ$D%ldU6"tEA6(,88 3 Ħfh)3 qN1B4M L=D8VV lZMSEi"7#N xY9ś_g_ Njřh۶jMd8I6鴜5uEJǦ>L3)(4Mnτ/3$Id"=zC 32踙Q;H%0AB;aarLX8&&&$Kc/Qo ‹qrP1@@Ղ뺘 <,BZEkMiϣR=D|0^!?8,B2DXwr"_qukkk, oOckk B㈟j_@ tRe]-@.}i4}_Z*MӔ L~/ $J!{quS"=S42j9L/{HJrX ˪hX=5sss2t}} !J066xR0Mt]LMMawwj8$.n#414!HSN0gEض&ޗIw C8`x::.nJ?laii amLOOVrx}w/KxnGKkvD}2n湆%8'O/T]KKa=y811Q!\EMtMBAt.jM@pӍЕ,d#ƨc q4Md.f͗,7;> 'H`b]^G@K!=?5T!#oX&diaPH+udċtZ] Kd@g===arIijtqDgJӒ$Y؋s+۶x1()u@6r*/MXV˛i6)WU  yu_\144qd:Τ1MlBL)JꢛVJ":hTnyW,pZ f{D)Sǹ =IG FQUwhxz~>H3{舰 b@N4MZ 4 BhFFF011^,//0 P()loon\.R+gS.a4MC:ŵZ dWWWGXn2M{{{bG8<:؄8~ux-O?)cGO=:Buf4%XxN0? _x#ڽx'#U10T]K#g~(ڤM\֏!aHZPXBzZ$Cћ[ =ʞvQX K"Y͒MA%Dg5|Cz~&,Ё/?#eݹ+`hBBKOO]~.b^kTp!3!i3> /U!5 Cd 4zgQ0Ȇ(rK=Q øÊ30CT0UNIꗟ_ZZۓ1 w+:Գ-Ŧ9:Cp?+,a@:X[[,B\F.C>j*2@E_YYA8FR۷Xc>N^c%+VzV\.v3$ (8.,B>GE:Fݾt:MK(K&ibll CCCB]9?#!na9 8>#<1֜I|Q(f xah)`۶L`幹9|TPIHTT盛dY+l6Jׯ5<-{qqQH'e4334'*W6tL$?^/>T]K#g~fL8h IJҖZz,B{҅=[ŋ,הں\A%Ԙ0!fIx a~|7} p ? :9pyyy50Dt^57$yxXi0AF阼pvN2%| j|Wfv[tCO -#pmo za[[0zϵWIJ&*D6aMӄiHRxg}. <\ Rc+f##4 WCCQvE8`t]w4MgaYpuuMӰr UUyq^='O6V-,tUUQV:vwwL|]ױ}!@ϣP(`}}ᇿ3qdY/n_Tr0Ŷma||\Ek0>ɟ,JYDh0BiLZ5%f8X,V%Ţ `uV߲٬L,#qk|xK7A ~J4M  HۜCM'''Xkmll''XY tT0`*̌d,$ Xx>FRh4Ø~և4 jZSXYYA^ٶN9##annљ{?ĻϞJy- Pn 0Fqpp~JZqhH$]F~W/OsPij>{n:>/ưOc\]Mh#e~:ۙ4MSn)dlC)ԃB<<'zZ/XEAz%FRʶP$;0IxHYsɐC{yo _.cfsп1pK7@fa`@k 1N$ej+; ,Lx΄VZ4 -Q '(텓#zPC$= ySwo# "Nùſ%* \N χ ~nT ܽ ˲z翣0^hYp7HL༁}Np8D">Cyُ>=F.YFP Z4Olč\|2j*DkZXXXi _,: |Fij|Ce qz9B!d2xrOZ9$IW ,$|8grD d YGU /MPNlZ888T0̓'*D-4M,.."`ll t( ݅BP>ƫp}~DQ*T|T*%P%ۍy\\\R , p8xopd|vEdYbjyTUݔ?~LD<&nuy]T*TOhceKuimHe)X-af* .D ׂ" ⢈(nRpQw  NBhT(TcjʴIh$.׬y}s=)Fll<ԄSӨYMw'ow.|8Wź0dZu]E)jI8r^Uh ~ N|P(ϟ`s4ՠOQ({j%skM;[ l*KUAB7)ը糩Ow4M8<<$ EB#rڃ}{{;]]]lnnՈT"l:)F za)*վ]$*!W犱Yx<~9E,ceeh4Jww7177Ђ_?׏x慥F\ j׭R)BrP{R*14b?j奇uQT,~;0 >z|.S*J|l,g{{) kLds`0b["4M|>LF:r,O,P` yk:<35-Mt[=]o(Όy7tיhOZScj;nrlmmY1աu^y0˴504~nݢ`LFA6qVWWfJ)Ea\&LL.S^/zي?֘T{m:`?.TOLe?i߶tRD`8`2۲yP6.E.d̛$ƃ q/t.Ă@+C{Rk7>|J^D=N' DQ\e9! zB+AK'$mBZȆV"k TM ^:9Z[tptT#$'ìkv+)hyEj]ڞXEPDӊu.`/HF [W@ ]: rkll4MYl6$vּE8fjjJD3edllLỷgErDs^avEͲl'azjbWU4z<"( |IG[x:p٥3`jn^G&%v(377 JL٩M{.]$el k'N[5M# |˲D"DAi/Gt*e֘ro\m_#Dw&4VV~?>+i(64٪2x?PCNJ[ 0x4)fmr:AR*hiiƳO+jlx]h#q?,whVc([l:è~Lv'O9coLP(D>'JSrjmL`Pu=4"PTR ' r _ X*Ph)=wJ)]i]1t]uMS!dR)#VuZI&JCz񿥥% *IR|~;=<✿5Cc 0pyb~KlllT*;n7d2QBXX PٱXE}1S1ۼ:Lv7!?_f˵֘w^T_h[e'ۓ5ٚ_ښ&M)kr1o""+xP{;WAEAPi'5bJHI횤9^_97}}H1 [* \RKC!&JPЌ@@2džM%%@Ƌ6Kn& O??P:k~?͆L=~ӥ˥6Iӱ`l6aŨ' DitQz,H VE"P(NUerQ%drrR"LG$aff|>\̅Ldݥr}Ѻ( ѐ.8Yk2Ąن.ȥKR155E.WZFl/~opepyyٮou?˖w"-J,A4Mc"Uu-be=O`yvM(a1dddD1 bTH$laaA)8r>ɤ4d̵qs\7HDi%v#jB 066F"4Mvvvd2u,x\lllp4'#޽u+3G:A&{aJ|lsyz~ҪUJQ EWW Kc˧55u♠FFc5:ACA½Gs$d2ɽ^u=tڄ&61;hYt#78c25z!EHШ5=21~7Ucd]h&o,1B̽r>PJ*nm,)aHFA`xx]Ujn.%( ߙŏ?Mr9ɤ-9MDŽ_Sdbߏum:.msF=㱉.TX,ĕ3ϓdT*JsA,C.6zҏ|-EʛbkkǏSViیNP-u 4mX,F.cssh4ij0-y_8͛7X>묮VoҧTUPx\kceMڤMl 3-3M-Ttpl:7nn`EFElWQ)Rl-SbLhM36M?Ҧi亸9r9}sOY>:'nب@CƘ1MRI,u^.|Y)(SaJ,JND%fkbH$trBGA{^ *٣-;~eYPWREVkY&iRVYYYQ}4˅_ש6!Aˆ o-A\n7PHmOs6cx [[6466(vFFFfjjJ )+v4MIJS!&H6eE_Z5ܺP_Я08kRmdY::Bʤ$HFS`4M{qO3Pfssa&&&8푸`yَPH.#bl^q[ga<|W_z*mɠ_>1+{:`:_21sss$I|>hFggbrN) Jy,200@2h@-/dҘfpS_ N3M'8e=&rY$|^c?lk3B={X.`>)S[{̫=e FXLu6ol,tL!cf^0 M̻w)oiqt`6`oe0d6 P%y]"yN,Px%.+q[b6[`jNAnـ߁s;X/8 o}{[T*n|+7Fr\/~y5OL|%%h48p7>x7>o .)1 dMu,jt]'+i 4MSnRy'LZF$A4;<^h\(g0f+vIXL`-2uPРstih&F"%u@1'VbݒM\F<GR^1(!"۹f2&MNNP(\.ElV-t]DK$8g l`E(/,Jj7yE\"&ޘƕ;wgC-E|"+ѻ*JbX(G/ |}N `T*n'ѧUNdU Nn\u?q1~ƍ̨󼽽M.cyyYqD%Kcooq8>>&˱~oyϯϓ*_޼-Y[Zwo͛J/,t:,ed(D"es]`\'d2x߻ܫThu]U+l,K`> 2$w0 lllP((5M1ᳯ<\GN_OCa%2+3Ǵz!|i_Y]D5xR';g>w3tވrskw STH$*g4z49ḣ-W2<  $8drzur ܔvM*V_mdYRjDΎpuRⶍa8@PUx=}tteYu2E*KK*I՘`ee9J2ИdzۥZr9ɤ äi27;TJ?sC~OѠ= mў6TkW3hdYYr:QU(TUECZp)]uQJ7ŻR(t]!l>)G\;.Gq)mylzͨ{0 ܹ|w @$xtIEQ%M$1IqlOSɸ&`tH <L8`5 v@V |o'Z U,`+"gzB>miI$yk{mooNy 6(XaA#mɥSW ?u|P u|>/G.TxU o,,,P,%"TU1-iieIJ\ ȃUBQbs&G"(~l6K$`0Hw0H7jRbͻ߲8 Eȑ#:uk~a}}]•ccc6IBVƣοܜ\X,i||C C#iޙΟwxԓٳLMM=*i<~|>m c&$a aJn4D\.ǣuJ_3FoL',  ww_Gx"q&''eeR1N_^`^KϚ KzQb/NB {WaӰUct;5*2!Y}0yht~"]Rxe!<iS5Tm ?Z6 |͛4MμwK(э78dh_>EnOE67ʏdW v*:nMZNR֡{. M2Žݚl mlsAedp5y뻇;y_^8dY>pXrDVWWimOIzs! xG[AdkkKƢ(x\cH) |qaff@ @,Z+#s<(B% {E0^JӜ8q+WPRD4ehhd2)d2XEV4M6\QVuZT*%IR&><<,ʊ,-˒vܢMȈl4;%PUUd4MSM[ڧTKlu?..K mJ[i#jcMƃzÄxA4rA4=Qhu+غ>v?m/Lf~K.f).` Y R ^v[hchwk$ =#x½E]?)ޢE! H!ԅ|>w_u=n#"hXk=ij "ayybCX,*1T,ǡVWZR}HB42]]]ܽ{W鄶pqJŬۀ&T*12rXqhd2 rm7 Z j#3. W#pSBsy' AʼnJSuض́}b*|>Ͼ}$rN~97Wvm=|umbZ{x4(mfyyt:MP```0==7jy"zwŲPv}l~~J Gy5yW?~Vfq}B333OPZ^aJb[YL&D"r[]]VEz]"(q3sջw\UVsΩ&WM(C&oGFܽWlmg``oޢ;Z361|Av`y#tvRKGwl 9S;ï4ٲ}45kP >b:mhlMJ7}! ltwwisxa0\S-5Щ6Fm M&}K-)TEg"rp׫hhRB:69t~--uy_>9|I%J(deeL& <,TJ4x\.G*"W*Ѕin~W(.B`:lF}/#\]aɶ?܅RÚ1>5D6%LH$u/EPȓ BzbR2",RY*"LF.&maa0+, qqzzzHH|P¿K3_U+8o`bbVХ%2 e:;;ijj޽{J %rA%GX>WMhѨB$k<D`>m&!N9f`m̪W?ȍ{LygJ#]'JA4̙3`8paЉq{jU&uw\#\>7P8'rK ^R%P1<ؗc4Rx \2ⲱmSu7>w~ʶz#ޱe]q,GثA}5"b"utT!bYey]AqSW,Nura7-Cq2sss$ ߿Occ#i;.ͳ,S0r~ۿٷŭf߇%> i;mw> (KTWW9ɶm,RI KxÇe?y+i/½}ic .\{ϥx"ۃ\.]xgXU q!qP _cex.iE0Z%G!עD %Ҹ"lOP}$I޽*tww3v#zWb V&133Cgg'G]ZVU&''mۤiXVIEQ Dloo5:kk(cT0 hii{.xxTTMltvi]J&MЄZh !#GnHhC|7 ;`61ViդI[NmUJ׎NI7c۲<&D{E^(q`uwXvooOZ:|_]ez8Iq~DQ8iR)vgmM)l}J(WT} Z(X\\QnDrX* N➅@UU9E|^j\&۴G[ؠ+Qku?kA]q3vE -ƣCbr:r 6I1 4"tGk .LgϒN+V0gn\77j1zZ l."N7n011zqJuT|t֭[lnnʵbjJ̙3dYfffXZZ<9KޤÜ<,on 78C ,Ν;2d{{h4*g??998H!8{۷oJdƶKd2JcccdYzON*5~(Xs%fq٧wHOtꃛ<|YcE2ƴcP#~f{vp-T+MH8:͎ʀ UtJ+ 0#-ZB Dt ^/t( LL{ K_öm9w%%*lLDuhjjQbb۶@dcyyV8#Kt _4}8pܾ/>ŋӘJH$B4euu|>O8QؖeIi2:\|>/\sH;:Gv@k$rS te&h t*At@SN VzjaL3 C~3:RW۶DxT*\"ujR-R>DE8&/I[A[Rj$K>;O -Eܝʴ,"lLdt]WH3 aD,y\&N}do% a*#DQVVV( *0h( (VڭƆZepPU{0jﳾN("jYTU@StUܻwOJAD"_?wjlDL$iiih4i qmmٻAęR`ie9N6YADZmm@__b n߾ѣGRk@ _-67L:;cǎd8pb}DfT0}\"[3155E"`vvX,А:顽\.g,9qd|ˇali/{yAݻU?}rq;͛LOM4Z*!8tuuq]Oؗ300ڶ<0SSS?&o `zzFMIX1r߿>cۀ =Ic{R^%iwdv\w00WԨ7zcVh蠛l&FJAooMgg'b6###wz9aЫM[ܞRj晨eG#u6ӡXiawB5ht0|r !WQ*]7l2\ `5҅k.o~s0^\׋9AR JY\,jڃáwdy4dLx!uY2fҗJ%qؐp$"a\.JITU%˱ٳ$ ù yeHUS,6\* SL'5~ȈlFQt](6C8(jXXX`nn؎D8_f,'ߒrhdWFL&16C6vgG_2sz/"{Eu29r\.ǵkפl d2ǥB^'(4AIRi22Pte>ޠe^;:v K:'\w|l7}VIfM幐j+UǩUflFA§[4LnbZ+*_}n?^G[<2h6Qii[ ~Dmxo7#M}*U'MreJZ v'P(Hrgw(~zN4`aaA|6 mKQΊI1 ٦y^ނUj(fc?<̍7".* p?b>GsL}<ޟ&?Rfh]4)-ā)鯏 ˷4b"Z*mMDWTSsRZ ٲ)7tА"qMKҽTiZ2\+<ˠlIֲ,i& "b5MfdBH;d2q,l~<(`7ֽ(n۶lŚdS՘b||}cc:u|>/T*EٔJO&a,KKK  N,d2'GyJlqظUT_h[e'9Io49-jJus#fPAEP2d⍊^CbM'lcXتlخ֦KJ4i/No@w<4$H'A@z%KT/98%ṟVĿ 6bT*ɤ RE LsA&roQ^oOXnpA3l̛ͦjVR) ~5ʶ]l6Kr{h)Ae$x4#{ss@KdDt+~y&1ۈ 1;;ԵR)}%qFCh%hpRS"1_AZ Yam&K+=)+:x BKWfslչʧ7&5o ѹ\lZ&喗Cz$>"pѲ,4 aFFFXYY!011  ,0 em+߶a$IՂ87ֶxyɃrg,W4~mr3oE~0B__'}x_qܨᡗRژVnԬ2`fX{}^vJĆ#Xt0;;m w?u_~xmU}Tٱt/hcSl{Oe,ϋQÏ>TgTm¹r9'ѣG9|R /i;LOOSVUŸr,FqlVŅשL_}On |qO"lDdj]CzK2x¡ckGխaz  6Q]sx=RzߜRm>!oZ;v%rR)& L$+ bmR7sAbd||l6qRDTb{{@ )w"r'Oj033ӧdjjbǏ1 U=zĉ'htCDObE@iҨ >77G&{(:6\[hSw?䞶iz9MUgulu1pva`C66/ MWU8d i[TLԴi!m69'C[@9{uݪe#8굎g@ /qdsW` JEyڒW[t,D1Ȧ\[[ *0uMהIB(4˩d}}=U(IuuXD,'\DWuPA [b :Iȋ|^|x*X:D7 0@x<ծ'כֿ݆P/r^XYu Cl"QZ&''9z؉U7H$x ˦7)XYyst([:s%['y[,ɒgqpQhd\Ѹc[me$~K6Ϊru):it\B{ 3f:nըz]!~짾wbLF Ua T ---$I%krJUS|һ:?b{972|~?N7/{eR/̱et5W -NBG'j`O~Ƀìgq~i`\.G: lS5v/8d lhY\wKԻ ܎n榈UXu9he^ӝ6@\=_+~EN}4U4jAI$NQ ۽y8fjjJdaɣGذaa(=ip֘BˤY Sj-aY:c6ǎc``T*E{{;:uݻwpmc3)eAl kF,6m"N4gx\oU3̖vZX(-V釐4%F(Z5D pƛbb 1D4xg$I1zAbC>6,F[imvvggf׋9Iy'T%4& 'G h'@D^.AX  J"ۡPHB2ꪉsjn dYdRBt`0O)B6͓߯( `qqe+n [4IӈxfHRW@b]oM"EPfAd,NYY%]]]+ '%>!/PDcvvVFǦ*TUiBmmm|uq pǦ+su PE3'(J$ &''Aww7x|5T6^hҒdwvvlbf#QvߞzOspz)WNfD[֫lRv&|!^/@[266&s0 {d2{{{4t:ͮXL0C\oDehCX$S,pR۩I$<3:I2T9\!1d8ŕŗ,u]bWB6iP=,*REWdc:ETjdD,JEuP *7oī(4^i[&e.%gkhxX\CߍlnΑJn R)J4p}Z[[1 yVV2tttJ$Y]LdjjJd2Ib)ۖ{ڞ8{",&`<!~>Nw/_+%}.l0b. 2t]'Hvn?7j:c0c6ضM,s%rëlv5,*%y\G KOêѕ*ELW:oT{5NXr9ܝ Mŕs3}gp9bXݻjy',Mcχj4n.P.,20`>~ 2ij8)G8o{s>#+>Yi#&raa$IH&DQLcU'fO(|B )Wss3e100 _ rسBT]lSe=tk{nucɀ$fCp("MLԠ$H HM C2Fh$&d&qNɔ] ~lʶvmxqMڤ9}?ܢ 6An!-F3(0(qHAVd|b.^@ L} 9|~]Ȅ-1ibddŸ;VX;39@ ( `0H}} 'JRqɲ,KX~;SO_&8LKxAL$Q &v CshV&u]'\G/7Ei*Ht{$3`YC9ɞ7x%r:VI.o'BGGzFii!ܺumۜL&#t˲W\z.ppe{g>44^`c`U܄\N۫q_:Ófβ,$>ZfY:<<޽{300' u0R&AN]kd:8.a% >_bR)X#]Z˞Psvx422֭[1 t:MkkeJ[,crr0P'y/s6oJ8_]#},?s?p09rt'*}S|Y* lK i (hJ8Aj FEAqwj{ky8; H4J.N>h4au7&go,x)KYW#YPl6˝m7lfu#/Ta߳;36gxUaKhɅμ1z*J;v|B!O/j޻@þ^6@|>Jz͢jbܪ*4!M2bA!`%4A"50q'hh[Iq&c):d^fӤwm& _G(暸1(pT*ִiă6:z`92&@[7ܜDȅʦ茍 >|yrp311A4]h]&΍ܸq#K(Úrw(ϓJBݘB@oo/;w$NsZE4ۀaY.{`~_>\.i&ɤ(TqToTe6ڔӋaTӡ[ h"5bԇb$<>ē QFE#PHjh/S)mtzog9gƇ3s3k)U}re>//fYV h|)~Q.zt@q8|W(ayy/T?z~`<۶j8m6#UTB#3cW TBV5uivKW!{B644:dH$\v7oJ$X:m]OgZC4M`(;ruJ;b1"!3lVZѨ Ћ]hcc#ctNBU! tbȥKԙH`*`6\|qscccLMMJP(m[́vN uٱcz\.dξۭ| ?q"?$b]~|.4/ D({bzTű, ckcpNJ L"`xx%FGGt:M:1M!rStAQ[%H$طo.> [4y<_nMSS˻շ֯ ,|Og_YVJWXs5N1 F0.3j07)鋿SX /m#JQ:0~qh9\ s|srtttڷ8J۷3*;ò,e-AWo _^r"v1sRd6^8H S T9}{pXd2 a"ʕ+|eĩ!޿I9C'JJ ̩az2\j6S31][*5Wq:2`52vXr"uTUXEǤ-D R-Fky8t7&\ۘQ񃭚y`XI-5- "F OiYז9 }9^='ܤX6!(WFҔX,,3>>J5u]oCC7nxxz LNN*A֭[\oU'؃_Ǹ[Z&ʣAT bVb!$P !6"`QD6qC;glga173w;QFGG]x싙ka"!E6y36(  B]  GGqD V=[b hl6E4z;څ.=0@GN/k>GF^m;AQ #-tE Pf ƋC!oB6"!`$jT* |}v,?!M<)ax04m_@#,Lr}Z(KreN<ɝ;wX[[Cw! `hhHRozzΞŲmYꟙa~~$ ?Q-D)9&pu/^dqq-I44k^" 2>>.E4~innlfrrZ&M"6w8O!͒H$wTj9VAMs,,,i˲(J4 Y!3MB#h%Jd2d\.155%G:_%rh|͓㽧;D 00M]y曟v.*wC$B-Rzp"Mb^PQbxCU]|;g\, ˲X]]8p^ŻNIi\{~8C"|>ORall1n߾M%w:9/f+G-A&ٴ h6[E*T(Z->S)M0) ^Q˰Ѣ~pk=HA XJ&HWB%|¶B ^}v&lQc8*S\9s@@%HE:j1n80OiZʳWhjnۂݿ Wu잿DNK?Hĥ.NMpj]/ 7^KeQSMNSmrC k]*-у[?OwUk>{ʉ`ͧSkmCmp>ҺˏQybgF898WU$u-EQflnni\ eD"?wQn޼ʊlK84M )4R1 B_T]h[eIrz6dͺa,8fsNvcwF.Dc7uK?6҄,|y]&${yCϚ}A-_H22!7Bؓꇥeٟ4&u} 2L:ZA 6G/gd۶rf榆-"HhBM$Gf2*۫8A" ]y@F ])^&>ŵXZ)(8;sgh FI._]1#,s]xrmZ1.܈@ @*<߿gJrL6ezzZ&gggY__'ұcK,..x'u]8|^' M RDмevvm~~^߸qC1^(ktd2r90277իW"Lr\Ֆo&=>p]T ZORxf!Bgzf$2bї?5dY,"LjiÇ5iK)E*TϏu?ӟ[]-3mq]G1(4x`D A'HĐ(zU!lX%BHiGhkw5mS3/h>@W x! *d@x񠱐 ?RfQPضM: 4V&C( BQ5MCQ24 !,&E(rMJt+D >' @zqpB&`$"U\k^X,( zkd[}P('+@B h6LOOSVCd2)-)EXu 2?qFR cb) ccyNi)* lEI&TԆaN)D"&&&h4ˮ5Eֺu,8z(Q(}$V& Bf%ܻwOvD)BDKۮsR 0v6l۶ ÐcT پ};CN+7bD.Vo޼㸡'W{7֚±u?s9ҩzu@uwnsNTUտ{gFyl|cܘgeeVqΎ〢PTdilTrXݲ?OP,pr?wgv`Qطɍy|}=Fe-OxudSP9XAui}BdY w59~ƳO8?2\]y `۶)q }ϑi.b<%NQ޽\.XTZfqq3g ]23a2Dv.ppbn1N|_Ox\5Ka2_ms[8wh5-ߠCIxK`P^| ͯfXYjwk!O ٗYHuZim.)dfs 9 Ň ӿ_E]"eBÒeoS?NߡaW)x:Pj09p>7\+X_9jGr-H&chu!M͙BqﷺI( Хit- ØŃV5Q;$Z=fL?~>CΝ;eIL$j50 z مz_h,B4Y̶I=$X]]e||]Iyϑ+J\Koe{<;ڎ\ITi*Q! TdQ]`;X"jWDPZ!6 !4J n4N۸d|/c3=  ,;REw.cV˅I(1|('#pHPJ&ʝ.HJS1cE'd }4V*G5b'<0pG:@HXAReȮ{P^ TD귈O@4 yLZeqq% a O9M 8^”.\OxѣG*=8ʱE4M2 g3J^Đ2&8{#Nx_N)JV*+++Z-<ܻwOu*4McvvZejAڶ7Ƶk<}?~:N6 kB&u{15kooUb~~^AM8sf FV->|Տgr._.YKR)]momѢZv%c[@\f"dRZŧ_m`MՉOJv sJ̝۟Yq"ϳ64d2TYf5ȈX nzSՋ LV[}ВtΝ;G4MR333x=l_NtIK0Uy}@4W>,ru'\s3.Ֆ_sBĵ8hߣwւF Lij!p:L;i;0@fiXjԽ@xbt{'<A4 /k04Am*%װhv9nϳoZazn. DnsYύ1I&vS#5a`T` jŠٱI1Vxx*6˩,fI;aֈhޙPTxeeL.=R+vef5jbQdP߸~3yttT%1kZHpeM>WRXTku?Ki4MSڦkM{) :"b/QaB6⮆^ +/īLW e BWpjma:&ҸٵILI=^<9e_~{~ǔd-^R$]I R{evm|a8A< sqE|z` *JE*E~~ƛakD")^eeȪlH7BP%۶KJ`\.10LH‘HD ϣ@lQR1Xř3grR)ͰKj= ܁򞺈RLb+Ye+Q%-rt:Rj`PV*-SNqUJL$IzuW񨱐C2P۶]Vx%]+aǃgDX ;&(>JQr̺͛7*Г'OI;fJ P lllpmfp)jl%QQRJ%8L!lÅ@kXYY!0d( LOOj@y666WL `?xc_Hܿ۶9f?K⏄l.WrUIpM|\?c{{[ru^a~:rT*E8ƥ8.?M4T*;L&V-Mi $S,1cDu^Y|Z9xʌ?FOwU-bG@/B)331,Zr%G ´o6l44tGO !Ѐ4N~^ ή1htw!Sw MKS7 "Un|yo|ôv $TZ aLmh)ikGh'|+_|Y! > $fNYo6٩whU8aǭmB;;(LiΝ;< ٟU7vaz\0, uzK֬8ojjmqMm,иO:heei666tElNU|V,uԈi333:)hss _4,yC~#6R4FлVER!f&8Qɚf{K[[$v`c|$r~k0t:|>xG2̥nx_ց?'ORjJ.cii 'lrƑI!hD >f/GYsdC3񂚅?{ .9{ ?%\ap[ .{ }_̀9g4P)1κpWƅ21 "SiL6Vy3p&<@AxˀaVvdPF[#`)\yϝtS6}R.@.I{~5~|/~&!2ysx&R3$Re4FT#5_ҭR)Y5M)m^܈ZXDl7~eζm Qe1>>8Įi:O4ۊd,Kp1T\~XQ`n邥H.G m0NlnnRVL&) ,..08w*eMPJj6{.Jj&Nbnn4-UXzkk|8٬,r9tP*pGe=$j q>˵k^c:˚K (Eu/侶Z-yQˋvR?0 ~o(^hiݻK:VHx6155EܼyS,以p˚]%ڱ#G[n\.訂"]ĄT,8}4>h֘n f {xݐlP|$YcGσc\6/Q?^\ƶm|{a:&Տg3KTg_T*|uq\>~󬮬бrLdddD"ʪ E.SSSn4P 97Y4Or}*wKK/3_V;Y~j^!=Z5~91NֹD\j^7rmv J'it&țqZk M!A(a^Ca(xMrٙ|Etd K @w8.HsIKG"Y6Y~p|oW$Gg7DS2%%qv#t cwjx!C\b0ӡMpuuy l ́avӰUC̗Fc]-%L=E2J t4䙧hh)7#6SIx*\~U!,//?fUv)Zӟ+6#xtl?/Ȁ\oU|:pR5\\K"+@|mX/TbbC@,PbQ"+hQ"$6Rڲ !!čLv;3xXۭ-ͼ}{!_<\p+CW )ܲL4%i4+x""d:A6vޠ\-=PW6MV?,.$vǍFCi@" P((C&i`Tb$4Mӈ^#xiŢ- $OBf7 !.*U^Wc1 ^ʊ nC *?IP i6M 3m6?fk^ĕUtP܋|>}-P{{ EMGqOST(lmma6ZMdnJRcU#=cwwW Pn[$K'w+W[! C׹|w̌dlBvjs]WA'\7M~ Pskaa5|WFȮLhknnY6770H`zzZ]~kna!?x7"'K\s /1S.u둴~`0f!n>"\*HD%b:66le]>\? *IjKRW><.yje>PRkYA`]?~\d-Jloo+!G[,r'^N-4WK;,џ.q:}9R? 183 !;r?pYY7vOk,L-(e>sZIԶa$ A OҎCSuX(cI7U{!LpLO7IqoK1 kPNz7t)={xv8lC9>2p}'G0se}lɄ XtܠG$v,&Ɂ K <\bi:;]:c1eZ`4`ILl}$U, s 8zfDmtci⿣f>H7ul::=_}rbT*,..*N"ϳhȁz0Lͦ}W1\ds>T]h[u99gɚ6uhiV:bNQQDLKD:DEم]D](ClHT1ڵ.$m599Njo9!9yy?}CL$ߍtSlvvD[?u \Ф"Sg/055$@G6rYJ(ˬ|5gΜQbw)]q/Emq Bx\rYLj nJ,..$j85 !Tbfll3==-R)%<77bA$>k&;ﳶV# à*Zo4FOOT:p˼2}9lErQ=VHD< }A/=٫)%=gsQ[`6rY |]YZ`E˲Bd|{yVWW<*^YjJu{MԩSj/q!F24M* tMypgg߾sM&vc:u'eA\{KN7 5̄CJ5F! QN xBm>-#T[ď4#ɀn@r7jm+ǰpG9=aimod4~_ X@;0n[v15d/p}N{BO,Fc(Ó3|a'!xY+Y['^G.yK7GH@;=y qI$u/ ..?DOusr ]z s~Z5Tlvi!'ЫzZD70tWce'H{=m0j5Ođ*Guxo-!v_ :T*msEC|7EsS9>8,B3gP.1ښ8E~8RPgff8w,m388H &5[m$p8LwW4"dEK% AYUal֦GGGuORD)(rȑMZ\\ lJfi`YaN}6x<0rʟ5e0f2VWWlwouR]`jE^'''*Wϲ0b^pETUezz{}->U~tghhhc/a7Wq"!(޻dNlN<\X[OnPNGp9, VE* DX#GT47@OC $P.]/TZo_U CoIu JqZ+fHaYZD8aUzy(n.I&dCЮ ,;+omLçk rm8->tB&3aC$dԝė6xr -95=2 kV,..lk&bvpϜ8(ˤRif!>:*{孏Hxx1^:իWYZZ"Q.qh4G=&:M `*͠Vi`a j3DpRXm?JaYΝҥK yogJrb\2`E8Tkm='LxBaQv쐃bMCs:֠YC#DTajiw7sQk$$]'D- zX l܅V7Ɂ8u>ze\ہgV*EA?iXm^E B@ 1ת~ EE2{nA k I5_SvEqp2HiVˣ9F hy45 H8ःzpkc(j#l5 A; ؿ ^²,9YEgbۿbZ=OK0r#RiŒF j=m5H} Fٖi⠆<_qMNp u] I@`{X B%>~+]O\oe?3;3emKlۥ@Fb1Ƅ0 !DcL$xQɓ(HD$RE*lanwvgҸcÖ6@>H7""E/TZOs`'gΜV)4 69C>W-l=|i8ӌdTʚP(ė9qhƮ N˓˕"@F:LA}"]~+++eWr*rׯ_2TA5F# 2 Q2?#2\-"P"+LBWԢAָT*J&NnLSWY]mƁT۲:Zblc790>>Gߥx\q>/H:D\fxxqc˖-J|88HX'H 4L&Γԗ@eߙf(vF-H%-}.^Hi,gOQ,<۷ɮ177Ͷm:::=FZm\Ohu?Ƥ!&F` EiA'/{Bċx=ԫCKbcFKѤm6Lv;;&׭{=3|)\cI, BI .!˱iʀ+b[t]4 +CdAL"K U2,o``r9 %S^uA2ͤ!roԲa6(;;u:uvB /ˎVޛ(aK򝜛M? 9/PxGXT͝1aZmb]qs]rVv_βee \TR(&摳VK_}tzӧO!zVc oe2*jr$CCCj$(reCE6/F! x8buY[[SFLLLE-6773 bULT* 333OET6199͛7uiցt4|»?c.VHK5rV|vuG>x~)* f申Cd)My;1ewϪ لaV{x?sՔ868D H0O~1S8uDmPoײUra{B3clн|6f?܇BHk!ѯX׫ ymڵ5`:͈>>'s L,xipm3gYX|^Aw1wϘ|ߟY6VЊh<ړ#G DikA v;tмa nkD_]4hYF#\!'-# t:tR4lDvئ@sN'Fo[:?o\pٺG1}򒂤{AG^)܏ק6H,b;6](j8u?UnSd?A lŷ۔ mN$ ria)nPu?y>kyP(T*vvv+9|Q>VnwkLP*٦ "A)E'" 2n/ &!MgWV"`bbB`ąOq"叅I\?20S=066Fz0 ɷjDNKt,B6?h ;Q%nkqV蔧|? Xa4g5".aKV-nb! ('GKp$}vt.Lgu LQMvhb;̾Vl}OȦ=| i&GN 4;P0ZXϼLSıL5qCI e9Hrp$~ۍf! l6r;N1оAdkɣ#'Zf(%\U4l#Y:Y k,7WnKO>4 D+X*6x,È$r-A4`BNJIAoptOD i>O_!|"'ɛ7o (q*kkkglS@p۲,\od?N;+MMF h+ځ]&$.q@ qA  ĥӐbc6цumֵ8u]g;Jy}oᗇ,{ق{Y_ a) ٙAO//~yh!;mr###E%<}}<$R)/_C뮋'^>$0# ҥTQa:Vk7ֶm,R:O۶ Z*渔1JFKKKLOOSXXXϫC7*333bwApBBޒs!N9~8eNOh077<]%a8eYd2\U׉DX<jWUiKu\5J%jڻ!A@6Uu4MyWHB>Wso in58I0dtt1|gggu HbJߝy\|%.\ GҥK MNNvw^O9"cǮkIc.DQI3ME_=߱9u>?[bT{{Ɍx:sPlCx::/v 5C]j/e9ZV: 5*L,Y8yCMh.[pNLl1-KeٹKA zVl& pЊODػ_tIS:/.ãbiYMBFg 84.as'rjG]M 0$i*w4}+F<]ruF^bv(EL\zNTF/c= 'ͼʼn+s|9V(7!a7!&5!*vf?]#`$GLa%LYm /^6X]'zd*"t7_9<ߞyx\"K_JD<^;T]h[u#9i>%5YSj2݅ldz3DBx# .v!jBDeMQUhJebhIOҦ9_^ru?>tQlʼn_ u襏l-ɄW~; { K}鴤'< jrrRƜAP`bb]ש똦)jQyE63:ea !^տ3ر@դYImtNMlkE/1::JTb||Wm4MY`Kk0E3!14xt\M.Ҩժ 4 je26F8xjㅇypx]^~٠`%bL=L=Ϧ^iZ022XzNK2dϞ=T*X, IUiΜ.scc];+\H MrX%s,rykӶ7r%˗/HW bL&ùqǹxE+\D"AѸ#)VR)b1r,>iύ ɚTU_,+W8#Ʀiiղ gM*aXaJEv|ճJ|&##NO\زڶ-OE|n48ƏOTL&C"O FFFxM̙3>1e+yލrl_e+i:MjWqzzz8tXL%5&IN}/rOy'Nh&W6:<ļZԚmc5 399)ϖhΝcttt:M.c||\AN˶ٿ?oٷ~wP( Y oϕJE,|b1,brL.B@in;w~zZF>VIN W☦?(R+ra6k.L& GQ&G_lQU2ϼ|/N>FXdzzZ/qq}J  ſc~_.9 2EN}$x=5:gnf`pq2qk.\O_3xg{L*h|={i3wc\;|jplro/(]aܒwjdz zģYBkƄ`7+"E8jqVi*F5@A.΅xv} -,x8ʴ?#ґ+j*ŵj]1LX j-\ 5&G*qpV X?`aR;@Q"c5v?RsGW6AuX4&&&H&^aϧG[i1<5 \ݫ,D[Ԛ[o{}]%bpuNTm1d4UGCAShnU{epz4fKU]񈶍sq bhL6 r\xm$;ǥK0^pXڒ*r׍pl6T]lSe=b鶖A70 C#DF1`B c1h4^oT5jH#12FF;2º>_/޾/WMz4>?B˗<{Y#9dZB)B_(MN.ؖeQ,UƱcYсmD#Sšr94/-Mbӊ7/YEnzC.qT'-En|Nx<Eg`RH8Bd7%WGsK>WYi2006p9% @8I5g MhiiQĥ%4)|bbB$|'8dO:E=W%a~=z#5q6CfvPfQ!Kud] `ӦM74}3gՅmܼyA,lؔ([QdrjRDssִ,_̌>aذaz'O tK4U&[R2ԞNrFCXT#|mmm*ZZn, B0$5,~FFFT,i/&0FTj6+WιL&hc/ϔH$&Dt:ͽd HP uuȶm` g9,HD229JuC$|:<7ZO;{O:WՇ011/IrwDZkaX5aZssM+/8Х#lݺV+ۢ5/ Ν)|ОF_a3菭{D;oj^P x}.c ƪ0ě-q_qc^Nŗ5x|:N{J`c,8wڈ`@ø mL2!ۭk0W\0`;} n cyO!(`qQKv :dJXqFK_G3Xkr/k ͥKx+y>zR\6CioVδxxPgP+/ :z|7;ojQg&(t/EK pmt]"10/maTt@\|U<'>k[|2PHq%G\8m$TnrT*Tk[e?i4mN/Kk&΂_zQ/Y| ^ zE^9c"sk %e]4MN4i4'ŋY'o돊$!׍R v'y9JI!,=RM (|4Ua ͽ=֔0 _hOjuj"A[OIT9*^*7SHO)9vDLlk[t+SF>z5,X,8s\:; <%p(&a;{{IlnnR<66x9x&'2o?L&a/G"1|ҒTD99mdYLT+z?y ߄o9p(JHDKˣ"Q^,awwW T%L&U" WP*p]WdJB,#3>>,iR)ɓ,--F)m1 >AOSUF_=iB!@r[~GpȦ g ]F݈h!AH5Oul{]&6 VVVt~[h[B@.ci_fw?Dv !pW/E.|~{:ӑnAOqAn"\((\Cw~ݥ lOЫ;9[C&?4M8u u՝!g?tR*lll:L>uWToeglǏıc;q(j$ HQU!!@B,;# Alx]U")*"JhJ*%nbqәjV{9e!P@]'JY Λߜ_r]/yql d2$IeFj`&LP(DXTzh9f!j^($. y)4a`Uj+iGBr__|^-!MNN**0 }iI)y H:Լ^Q6Sz 3<>[&I|NPH97F*%IyT_9E]~+++Di*K:jp`(Ľ{h4lmm1;;ݻw$ZN$b]RבHyfffEC2rLL岲u]W%,ߓt:N#9>>&ˡ:VeTg=22B<gssSuTJ=+ E%ScYJo ˲d||\qk&dwà'O0=}S&ٷ=0M9&,//S(biiuLӤX,*p3p\|HR!n]e vvv'L"\.(<Rj&|o h_ a^/ZX)NWgԄ$y*w齵;ܺ+|{;͵ Fl112t td ޠT}Jq7>`y tıVj;|2ӻ$6aF/z7 ZوhTp9fic*!pq5U 4lDL0xvZԎO_' ^rZ/0gѡrԅ 3(uj,0A\xٟ7?=u2FCx{'=+HMaAÆkia|b*Oj)@s)mVԯwZ)~X|%iLTSɝg$#@nܿ $BMbq`:ZS?ܳ{GC w&4&-*S-_*|e:<{afzrΕY(looTkg3i[ ~Bk%Pi6E}WnMB 4B&P5t98H=-yt1?0̋{92c8btet"%E ]yk^*2z0 54-ʳV4,>bDeh4S[D- d$ H([,#r]WET=uKޭ8Y#_:n&ZK X\\Tbؤd,aJ'#ejEqz$?RJ%Z444D>WnS>Wfy@e?y򄡡!:ܾ}f86B94-Jjiׯ_4M) ϥKYXX8)@bh(݃xd2E* EpjjJƆWVVpbeT"9^Pu:XXbo8R(pww rlDMKn4MיfkkJBzzN<׿Syn]R`6BZQTUTLmۊ6=;͐~O}ʕ Q/Rs8.u6 2q턬&8:6:ޥ\.Q R)[̼2 }9Sc$ 93=YcxfGA+\6bW:g$U } 퐑L7{-Z^ ՙъsI>V<`7uR1LHxbBhMqȥCJސ^t0_=sF,vHwHۏB[g#jcĂY~Ţc tI23=n$heB:l^i7ŷ$cpř s#ׯR8"#ŋ8=&cT,CPzjv. ?>aulI4(]% @鸝:~:ϙdۦdS;8O>1`X@&Ɲ[|233s_ wvv NGYr' 4Tke?3;dn6Mvi"mQ5ւŢQ/޽`KO"Mzx0Rilؐפ;f̻aμxtXs]X]]qn߾Qryd'&"n"WB0Tx^|e;\"#'h6<~^T*VΜ!VLLL3H$X]]U,--}eQ,y>EnK&d2_x;r5N]31X?| #6߯x`pgk[{>`~u%dkė2h#Od1ZdC<҉K{:c` YFvKiX:Xz ({1=!Sudqڟ9tߥD2> Og*XXN4 P}zb=DVPC] CיX F,wm3g|CIi>emm7q9ɴ3'j֍|qU%c;o^c$~6$¾:_2'/݀R{|i>tTŞcW~LoP bKb|W2i ߅ɾTcAca3"6zb"cm~'чV F WBc>D#O~ c3/a,Uu߭f<&Pq NX`Ȋ}]י)s||;Й t g|40œ9sUUYZZbxx!.^]u~?.]b(BP`zz[{Dkv/:ݳ,0::gy /AU+ns+vGtrnҩ\N GcqqLm[ 29y)tʕ]F$ 0fR)rX ΂mdQU\BWWMuVcyySX,288Hww7ɤ+[[[Cuf8֭[=%HND"ݻ_d.\<$TvfħbŌ;"xYL\nN>gϞ=yT掶~931ڲ/&7FeO^~\˫AN y|;$6zKrlHUTZ|.߿ R7yO*,'_w9ufG[Q^0@WF7&M?WyO٧ǝ#X{kF+\Xm.rQc̾L$]EX NMdܬk4U7tEE.3kOUc$&S\Cf33(<|D"AOO}}}a,RTou?3ݙvwK LQc/"p ^X ě `H傂6HnH]ی/0>} r, < b4MSd[ڶM2TmD"aJ]UTqkvYeqGK(x$E{ɂ9hPMv2O%j`[U KҚTNI%h:M)ۓ;bɫB%?PFzr_Я ,^01zF9L666b\h0_CWr9Z A* IO9yF,..*cm311)6667j+fSu7&6!nSSSrۅZ]0TJMf&''IRjZ|J133Í7U ?u]diiIM!rQef1MS<ϣ묯.]PG?|0r_KLaϲO|IENR *,b="̝;U2 kllLQ弘8s r,0ŵ/h4pIݛ[ǹt(i1J" JN : ?2Ӫj;cw _M3ɫlnnRG97}oH#!<&@x&Pj分l찿7K뿧Q# FǖxP K1(;><F8C5C'aj03Q!,u70KHpzmA z.J)ezDGR 4C#t&?RyX64-xm%[-rk<8u[1fFGP08ymdI !AA-x:GCh`0λ\-^eq7\S/ėK;w ?шs0=ॽCaф*hVQ`mP yն "<.\XFaiXB'iեl5;zC\9qL&Ã'NU}Tk\U{#gf2664رÔҚ";EB\"*S0 XZڐf&:.nIy'=VOzp衯wH)]bRRJ#Txm||4sif҄2?89unzz[nV icBhv$= [[]Oq={+a`MisvϜ5Y+5(ٛt`5; >RJNh]Uf\u.Lb@v] LO6{G q9y֡| h{dd0?F쩟JY.y Rי7_(?~cQ[[[3]2JYqҜC=y(uJT*&o^<ϣ|JRaaaHD۬ Z ESSS@+4]ǎcffD}MW!vۄɓ'w1;;KVK0ROwΝVQ*V8q\-bnn8|._>d*|mCC::r}2333,..&Un `-|}7Ky^*qQ^˵-slmμߏGYDEk2.:mb HFk6/?Vq﮼h,dϻ՛,?Z&H ,`c|O։ɉDs-\!R#vLΉ(,eD±y'6~QKlxmߦۄ1x>l.P:[箽|qm>9ű\ADމI"V pE a4sZy2bi1ۡ0`ϲ jXlҼsd9N4>";臂N^5} TîMgQ̕78\n:z!䀄##vLe'X@m3Y#|~)rv*)K K .l r=.oϚL'`N2Hg*Ĭǣm#WqDG"NM"Pm)mBEZl&s>Ц Y;D&M_462Blkpť}:L-QD)ETToe<v:MRI^It屏odX*hG47JEĪo}8jT$Ԧl>. ~H,/?!({&ɀRAqD\׍9cq^ƞqK/rFejFVK.~ <0@ hlzCؑi,TJq]tiHP^k]>;t/*/ %15Z[[l>)aIS.T,Vܻw/ Ų,n߾MZ%˱\дOVKi!/ a~~f3@T*8K', 8[T/Wie^O℅EKE\r%z Ijmn{GqS̃:N)@ɲ,^ӧܤ뱴Dgyy4:'"޹q>,%{&n'`~}}0x1D4 wޥZ&gϞM2rޜD6=49q"o W"v<hmbk:9d}D6~0mvF7VJ ?v?aw!ǻ?oqgu `(R1)~q9tE~BeČ&)E32"Ne=r4RZ)E4 ixqBG-FC|΁Lbڮb:0e k>;T֧`ΐ .c)zM Sq.^sR4LmjZ`TPR{~&;<)n31R/qҎpǎyr(Rm; V&Ε#fxNYL%Mc#jYE1_7hy&viOSzP 8^ZY˲MTJSۙ&ع_LgvB]0T9,{l8šA}a4Dlw읨>i"""7guZ\~DYWf,dųjx!bȈ)[11y C76BZb,&ʦFDJ0EBjv1(͔a65!v A^H ~ka]ˤCFO|=bȓut,mt-?j,ہvh7 B ?Ni0dh-8o08S3̌$\8jm_wtJV`Q=H:a"#F,e*|jN~'!cȈ14">suEڂL%Iۏ qBZ%HZ:kj6ӏ$:>k2Bf(Իv7[ 4GD>4;&Ϟyb'4um̏%|p}>2 \OhU?ofgwl'tw` 1RR=H!|H٤X,^{h8涨?6.yڸhؠjF7:CD¤ii2vc/q.3M6O"33Jʪժ$ӦZf]i<ygmrn2پI,lnnJܹsL&9u2,|yo?o Ramm|yM6]+3j5!RFATReq},׏ָs|ޜ-KKK2l[nϟgkkG[:/wWrxcsa>bO ի]RBZ[ $?|}w.BqFʶ۱+(k=K !`q͓} /PɆ=`uv#tb@fwD<IR10-:c\\2ELԐ}?TV eԐ ϡD L"!g 2R>{8ŢW'iY^2XИH#aEp!irT;q PBs!v X"B1 Gї6vŝP2p2WQx(AqCá9orgY< E"菦dD+w6v/JU@9^@p}ͷoKF32][)Ʈf>_᭛X@1=!&, S7rxe^U3z%T蒏E6{6G̸!7"&ۍ`OIs1 BGG?˩0m.1 ]\Ohe3mfKM*-R"H`7/U"xO6pI&oZQX8wJ%^p[(E2p8yNp" m;߿7K=~m^)̎xyW =WޡE<4rr YL4 m 4%,a?  t=Ad[}@4ȏ0䷙J0?H03>`ƚEv=`OJhlghIВ'^j'/Xl̐.(Y p@(-lO X/F . 8nN\v,9" ehzLÈxݗ3 zPN&菞@֙ι"f䅟L# =?Llђ|aȋ+bҗ&(X:&h hl L@8^ 5F@ J-$ٝc?(ڕH/$EZfnR(Evu^=;͋߿ a<qpv̀t q_6{nh2B\ .S>k=n)@2N;$c4EVddKoeo;㱫^EUR6 *M ?;RءJEHtEXAUZQDRqmSfa1F)5s u)s wvW(u3)_uBUyH#D|q67Sa4u)`0q*nYT"DUQAڶ}"E̘îf$)dqӴ3YC83a7 vZ.׾x$I8wKKK\z5+$|M8~8y4 _ΩSjrLza^r<|/f%}T`0^}.]j8q7nt%C)J;v,? 8U`˗/8: M~#ճ"@F* `@\YV_i/rloog&;J%VVV!q&Szc|X[[cVu]Y\\W^xe^<F#Eʜ=7A6jǮ)./o.7|,p#OL@vd‘)Z @ B/R:lԙ7;An'q_5@Zf-2;!"H'D} {:䗭I\7]YK7u ӊbpdǔ8p%Aފ FMI'GG`y3bbFQҗ~2<;bƵq###Od*) 8E:$ dh 7yF"l¤n3D}V;ClPLEO,TPiL!GRs%9`D¦o D^WPǣ$` 6|AL[3qsmF2"g{:?%>bDH-F2aJ82׾'KoP(d[| ߽t8_IṠ7q1>'"N$Й͹T첲ͭKzH7ZHj46֐Rp(cHB$5C[ub G @;fʬd&DE\oUw^؉MS(BtCDiE%JU%eÿ@]b]UvH ذ B,! JD &i]a;?3b|/XhZ|CJͱX2\ .P(iB=鵜fպhU*I$d1-B@j8*fSIdXCޗ+:<%!_9]qH[D/m[5@sX1qvc =K #]O0MS5B*rrP?{=5o.T+z~0 ULLdn7WIӔeݻLOO+uƗv-⧫LQ,}ZTjx qh6uI!utn۬y._L>gyy91fY|c<ʞ&d2$ueE- \.333 KjZDQёRJ%F=y򄝝y绕YZ.):'82i`x:-KOã J;ma3`TO&(&\s mэ:0* '4!*)Nz>% JHa rO|+~2]%O:+BQP'FEn@1H#cĘB0eY%!H.@1:>i#GV(R* mHx♉g 2rGuΝ;Ŷ\lqqm#RX<lo_ ~3iTRycx8ܺr'r$x*qK.a& 94/Ivwwqi)HĵkPU5",Q*J(]رctuuQ,؈#O*fECIK&uOrru \z Z+6NQ,j|S7S 0K>oGB[_oҷ_w7hƦєرz`!Ot{,nԝ-]qꆲ(C 05F#~h۩lW;)<.ҔCȆ4>F͑^#:nG'Dז.wfXSp(qOIc):5[ea҅}2t!ƈXM4 ֪4Ex`!>ƻ<UWAW|p?l2j.:)#z22ҖB{5OU'*tk*`.EHbFչ.7q&+ *Mo8^(k'R>lx'P F2ݯB:e`,nx = {nnwy6ÝSIi2IW'g.гa 1v]c,>V?/%%a^&w5T*QO'y ]3Ѿ"wQ\y,b>K%>nE@u^<I˃9 [iĸ thAPyM,h;IDAT3?-2sҴFlAn97Q/t:] NQAap* ȼqSP 'vZƺu떵iӴIsN^y>?%]dnY:eZn|,>RmIՓʡ3 /9 Xq \ޛP(8]w-IzDCJ ؤU/:xyki0 BMU3e Ce+Bޛ|Ks|&pGm4%ʄ\7;(_6qk"/xգ()|z.<I: {nRBjJ*b׮]keFdz"**frrQb{s_TWVWWRfAUU&&&X^s H077m6(,L&Ν;:{Nshh3e[F<1eD(`z6F7UUeee+.G\*1=="BE~?[m#y=I)1d2kkkѿ 5iqI&a.^HKK W\˲8<8mse ˤ\k}PG/؛yݳsUA^ϔnBd&7oFQ1+Yx0mƎx cUfMܖxNꚆOs] OB{$6H:'Gq|qϼ|~G!) nEG]\jA N=~7見]S0 * TM ԉC(‘C_,AsiR!C'l2DE굩*m>6_jUuTP0K͆bCGQ?^'9Q\3Ureo YjMpDt3q\[:Iz]"zŀ'WRCk,DQ4zCuی++Ji nm:Td ^"դoQ/Pχ=JB{I|=D"EstjLK7IO(eS[!5&Y%fT*QV=i|}|/>w`?Lm,)'>䵗edb:c,kD {KP lꢆfoB[A)|mt T'<՘]_r[u,p,lTKleǯx6vƆ4vJ"RPH !Ԫ!<T,Xc,` $Rł*5ZB@iHƏԱ'~.fxf{=\Ur!>"Ḡ%@9Wa L2<<,@oF|T[*N-Y.uЙ )EANE뺌aos 9 #YOx@4a*cu]G#,Ƀ!qvXhԧQO m$I_fLMe0M4w>,V1diI_<\.¼ds4_?N{83&'>S SA4MsPil-2wJe2 L$榧irm9fr錪R)fggYZZib~$1~f),//ȯWDEyu7nQB8s9~zQ=>y%9Bj^O\ shMe5L: Ni6Hv8OujGh$4lSIGz\rZ*նJiz>J Pk^FK%h{U>SIUBxqp`twm. #zj}-:FX_Nta-WY qy5RߦHGK}~,&Tھ߻muԭ0׮nݿAnVCخ\͈Zݣfc/ 7apz%ĥR#bOp/@3A; SjXN|S篦vXo4 :ngХ+=Q5\\n@AntWQx.$]4O |qd(>tGŲ,,T)4u]ܟW6D#ѿzkɱ82'_AĨ|7{ PV^Ks4˯/IPgy Kp*&Gyq!Ηl6 (Ap˂pO<0C] vQ]Om)~6v|j=R3DfrFal?\ke&M6ibZ4 Z$ۋZPBPU)^UK/ ވ^7bPRRRm栩f=e3;7&}8NСCHD2ÛŤP(dXZZ\0::;Ȍ?wݐHeʚK \.`NFGGec_p.Nw7Hvt`8Afggrv\~rI6{gWxPQΜ9CXdeenߏttt077G$AQrL/ÜxVzja]]r4M~ƣ,,,2׮] Eprrh4࠭eֳYݱt^'|Yy&kkk seǩ?~ׯS(V$ 066F .}Rea%܍,ĺcLL9JǬ;Rkbm/_93x^o"h?ީ)EMK+AL$M#Ut6*n>9DèKW.[Oamr$]11sql4D/y$6$*wc?>‹O~X0]5ID B*L5Ѿ^RK<f@YioAؑY+tfe;l k`8 _45%&)iOTNjap4$$CzM۴nju~a{7Nڪ膄fZa!TxeQ]9MF7$J](Ӎ Պ|OYXP!:dUם2f\_o1bzԏ|:V&pLp䍟qfSu.lv.kxSTn _e̦9HL]h[e9''Ms$]ϥvdt&2(8 u0Po7^VA (FeZ6.g|y׋\''y~3H$177'bxND" .mlTUb($w0Dx-ڞm*KR"n.+^u]gzzXlamuaߪ*9goLӐ--vw A֗4,Pц"T+12jBtDzTJ;eUآe18x)4;bc_)3 U|GЊe+2uGuO<MAQqaX&C1 @rȬUl覥r&͊Ut9qC~*!UtgV=^,S][(,X)\$rᬛ80  :):=&eXT,q̼{yRCUUuCT۱Kgc4 .jOmϘ=i|/+d2 o5I!ӉfsR {ʲ`MJũ(;ώP8Z$j^kjWҷ2moT]h[u+9i,k!&e20D/`KADǨnsCPvkeP6]m0]|'c]4M&&&8[/'v VWk~xP~g۶D"LNNJ|:`KK 333ضMGG/T*?=0:1ut*a}QlPZֆeY޽4fQ22_̲s~2 o_8CWWׯ_GA?cuV9rgI,bj'Kƫ#Y N8EFnPx| l͛7sMyA>| 4ߞ~ӳ8Ie]MaźBp Kb0*Ɏ2lu5/5@V" UӠ)ARM4K䣭pUa@R-(:Z'܂D7aD@!ng}!J_(DM0_tUvDAE4\uB$K.Rih3z^X\\V*!9q.KLi`b(X׸y hb̝Lr۸Dh)+ q;+eo(LqU' A[D"nsxNQq{ \NWqhQ:r;Q$N{ bzPcc#Xnw QVܹJXOzbI"i>t]'")Z(>*nHN5'_yNt:Ma9 D"Ν;Ǘ;vE>lF%PUyc;mYNzo"8'ӴÝ鷷::aص o!5tJ(x*5 i399Ioo8<)N'}<ʐL&fܼi#L&EWSq@dY֭[Df` Il~7epSٹ}{8S*dvvͩi\/:67ⱡƛ ~*;ZZ9t+ϰowl2;2>>.Ȟl.4p8L*⻿Bx=U YCbf"\vX`uĒ;D:ǟ3<&bƣm:SA3C~7ExAG+9M?/E-( ~,J mU0Tiaܨ*naAQXkbq3Q< ["$ Ӌ=qu+diqWռRV,syCi^Ϸa'z>SfI,1XdTQo>BTb?OW9=eSkuL{@b&gtmi.E7Ǧ#ZŬi*ULfHeʦWjH[.n@fhT˔.Hho48{]bbCV"_Id,ۡFԑUBYKF rY/H˙|{rXulk#tn`9ŵ7U|\;qhTE;I6urM{X>C,W,μYPVQ82 lEe&(e-<<̥*bDq5W&%h*qNQET]lSek{ kV&c`BdS&`DfD&.crA4bĄQP .0e\ HW?uesѵ]s]irz>?d!] tvvR(h4*3sHgfqFKy&pXaQxdzy-7ǥ_4 (d2B!1 C4A,už}!m>mp~hC9PF!Nf`L&G37Os^cMs|KdM0s^c׸HMSS,ЂD~˓%mRhd' +lyyl Jd[EUM9',[^0 ".=ܚ^j͡/,!ڎh7Ay]p)RpUp+(Um!*a=XȐxXUsBPe2< IT^?tP?e7{I-Y%^tuW㙵9C>.wT2A[ϖd0TBo;gT}j$K?K=_YEh^9,ls\#/gC"[LqB΀BjJIs(*m?]p-:BLLUa2pݜъ╣pv{DEX/lM8 vK؉: |^Ww N@+of S.N&o n}'gbbB:~\.ɩ)̲@aO$c^LEmbK輖jt]g𺋬 fɔQc}*wY(d uMJ$R99/C^^/mÓv@8Tou?33{ǽ]zp^uPHgQ(H$RD^D/H@_Dhf%R/zQGfrwyݽݙ^wvo~7N4Md2$I<7nVĨZ]@U0&IRȊFK6؈(u/t]18p5<244D6 (DR4P(hmmX,2A6 yQ8_x˲1y* &@X|9Eqt] ]ױLjX [$ح顿IEu.^H"L&C.cvvvqzN$b'_w!ةT Kma$:Veq)ٴo֮ٳg<8 AlΎK%|2onȅBa׷KS,,Tm#Gד9d(n0k%7 j od2PuہqOu D"8$ot<`๰f宮.n߾ͮPfuiN ~e0+Vd۶^o9N.#ۋi wlh4CK8P[ضmg6z.˴w8fff߇2iGr1,:.X0V h4ĺ###q,r-[yGq]~Rij_^*m; F'dՉ+S. sBYpMC$HY)j5(sә{.}{EƎ5h %<\UArWaJAJq*VRkvx(Q^c h̖7$/mjԠ=-GI)H{ \wP\WP(he ϹTb I|5={/pt_CR@"]ɖ&}[dZ)xtN3%+I '؎Gٶ_^rwo*ZS0*TxSSZECbdv7jZM#Bp8>gfmnT1>^)+:8ujl8AL/Vnapy8~|."HeP(ĥK? B)Ҳ,v4MvsntGrh4*Q{:&J'`w9QTU1i={6|k׮InFYt)7ofܹܸqEqp? oK\~k,{zgV®.Ѩ,ZeH&Wٓc!*\xe%O퉰xmʭTayUyi8Ǯ*w}FMn5 Z4j Sڄ OVarjRpՓGזr9Y]͡˥J́֫YX7\xgwG>%GpW.s{h<^?:ȝb0..-a]sS!h49+='Nnj6_iƌYVp 1KNH&+sPu+J2wXwwW1<<잻5\.L[lU3vw^B+hhP1ۃ1! Ę(A}ED""i(ȥUYe.l۽0{Nxdr9;/d2)ɘܐJs NziooVId2h 4A [ ~uU*ׯ_ rb#ziR/l^y\'* $1W!,J,k Dd$ BU֭#Hx>Ν;GPT*111Aww7SSSZ 4e@\t EQR+VH/ ?qv%tzˋhŅ̲`z,={V%v'( LNNdH&tuuJ5׬](!0MZ}=NL"A$gffHR SÿF|ŅOFdYTU |qikk\.se0\JSra0w>|p8h7*B%"JJOT$s#111!ihD/ESٰwo^uO˹ 7,qf߉i߷^:C;opdӽU.d\}sx3M%dQ4U O%V([t)G׿b9^٪́[uVGx"-*մNxHR2y"`6X[dL6IRSnvoԻN~Ag 9/og$^ַ@ s-f*Hb>rQW5JAzQeڴ҃x w-RU7x4:x#Wm:qC{p! Ndk\e3LfI2ӘҡIJh.B1Z#b"^RQ*EB‹B!J) ڤ J,m&6Yf;33KN3?}^Coo˟.b"ﯱeYG@mJ/`yyYl1IPH1 'Nv|J%{%(hmm)@Dt?4lllP,E7J%djjbH4egG%Oe033SS7N|@&!h4c*L BDp8 d0g֐=v4MeK-5P<3;wG Rb_<Ν;ww===M,cuuUI 3pb/KnRω tvvrux5NloO:kMd4'tӶ >L8fii 9#[gggZ9(gD.9imÇtww Dca*FUUvvXEmmmƒt: {n<=F&io?xX\\$qk|={hi)'wlyD_^@y[\׊1;axDI1N_϶Mdꂉ\Hk1{yw6-P,qiBqzA|IdS"/Gh4D[nQRNDSS]]]JY5rsAR~BU2 (jr*1G!kC踿ͩѕ#o_d PwH2 oVf#H&l%Г9B(۲7hzLNNW¿Tou_wkw.kV.(?#ƙ9# E%B(ψD"Q ?FM1 cƖl]kx?oɭ#4p8i}>у܊ V4JX/GkooT*:adG|^^}/5$Iz_~F~|kb9H3yBr93?IEs0˼|#o9ӭ(WÝ89m}qToSu?ֵPO0VF E!ĘaD2hcTD/j-A_I/4D/[T4c@YN,n@[hwz9===hG΋_r^\Gh>>kPQŮh>pбeY>A +nĶ+HtW‡` |x-hkO<UQ :D/ o bKK YFŮO#N0 2c& 7n] MEs]KE~H^ G 5x#A 1S0rQ)(zj7ˇNجpa0Hx],+̱n=HgMOOkh4Jmm-r544P,IRx}>HzQNE$;"Ӝ:K/sx4ywttHP&!*ZB67}&_9WXɶK^Ak8CgHMEi[s.҆]U)0LL T9'uoEKĈOs?+Gym9 `≓FBXS.& OҺL/B +)|5{^vAip] o% p"AS-kab G *fI`E/I0h-gy, ko S^6(c,l٬D[]q3??/o|G< T]RNvݹsG6VWWQo*w#_b7zҲ_) UjQ/н1Nт^ ˪SSS-Nپ};;]KVNMMqdhhYvWr=Z[[ \x E2DXr%׉ \/l[APBC J?[.ϯvI P=@]N}$oŁ_YL0SL<]MLŢ)bOk17uP2 W:PS =ǝL]h[e9'_'I,mŶv-sF7mJ;Bd@Ћ)Lb(9щ0DA ?'tUl)͘0` XkWI5'9M'rrqH{R48#/~B*;V@(b|^+DbDO&aϞ=Rq0\H$"s@HHCm iT*v=Jb(*L%/-EᏀ޳b14McssSXg hB@kk+beЮ]f1 ݻwsN ػw/ns^*qI tuuI͛7P(f@5 h4 @OO]]]ʡ/rMa9ѬTkp0yfbb$RIb}}}AKk 6{9H Pc 6w R.f$Iesftf?i299i{7'=DBV犉]NخT 8k(GiѢTk6>5^κ* xXB[XX`}}۶IDuId~?sss[oNpCҵ:'߹F4F-=zUUijjzR{Y <Ԧ}cެUtIk:[XUmˋgN!oyf~DmϳjT-K|}$>`*a5V$Km}0kkk2B,V ON<w @g$O#ۇnUye*A[PS saNPS*L]ˀ7EAYPZJ*^FM`FFk<~3ak M!B!P;`zpjFtE^ Y)(ZII~ӽmmmI`GuY۶]YшF]8Bxn9<8>5Ͽ+f-Ot5*QQ?G!an!^ ttvru,"f3;;J=77Gcc#۷o'H022i2 Yewߖ`0x!> {%6Q&8Bjz^tsUQyN^oApX$*bOQw/yvFTWYRSUCwWOT]h[e''G4=Y욦]m;"aqƶn 2KEďfcB&(V2uq:fsN:ΎֺM6K4]ӓ/NwpNHy?1 xP@]5_f|P($xbqMcj-ҎbƣqqώOԴP(Dj㡥&2von;_DC+SỾ}033a S[[h\.'e|mmmtttHؘ$NNN҂i$I.ۆh kG]]*{-ub(aiN呅pcc|)3 x'1nܪR~iisPH ^7l给kX,&t:‚4ȑ#299 XW?fV}"CCC9sY\?S"g;uoH]_c"֢%{vVI U0d*c% :3`s0GlG7Y>84)ٙd?++*̭hܿh}/IX  )m|jjjj} #s |*nkZT3ķ)l +؊PVP4+} ,2mj6ܫEˡA.\~Ew^~ٴ~*G4–k^ *jEE3Q*jZͅ*8EY;6R<i쑿O.UEYҝnttTƌ "kP 94lgL8A*Kbxʞؾ%jESU5 ORTWW355E4׮<0v7gOZ:=xH[ljuLR,d 7q="^UU$vχevX, emcȏh6։Fac8֏xp&eB0Z6q-j#0UE6' }@϶^LV#cNpw"U6i ToSe?=i{Y31(^!&%h܌1j //|  !JPkxWdde AӮ'-;/N Nsݾ78g2b;n84ZBD}~~^*=.7C|0MŮ( HƢWn=Ur9S*ko1YP5t]Gu,˒dMӈD"&ΚH$,,(2(ZN !u"۾l6)Nyl`PebbT*ŵ)foI.27.px|^^Ţ$g044id22 2xuIhK2S=›#/_Ǹ4|"v:H\t Hm۬Z EQed2hoogffq@RT*6nHpmu |Ƴc݋ rL C4|=T+VwٝZygyh>3q0K> Il^ζXg f׌ò,I#VO-ڤHr|% ,1PIiy4z:`κ3?l>xNbKDD 4M::+TVx4Pu.aEBMU1J Y^s4'21G(T hdP7Oquz'5I m?Cd :]•*.=NP]LFDV8Z%;+lۖͦiъ fZa͑ϛ(b*eFD@y wv\6{Wnkr9} xreÒ,299)Q,'NyJ'b||l6ΖH$8535zk4".bQvy ]'͒NIR0P.T.:.Fƙ;H$"7n臫/4ۥVMәR_vXd<ò aWt\/)**7MR HyToe;3{niۥj0BhD" 1&&x M1(J  p&iӛ@Ommg;;Y/f/lf}}V$qJ>zUcRR__J򍈽.{,V@ta l\.OHON YʶĄdd8Ya`4 C2D&L3a7SEFH$d2EF@C7ettaD"2k!ԔFt)awUaqq]v'-|o*Xw+ז?|>/XwX#㦦&fff='Iư,nzt' ][1=ʥ=( 뽿X`tuy"@P(k׮YN ]LJ[Mmx'$'{:M^pBys((J8\r9۶4Q4---lߞ]o:9M ?/nH†2MKLgR zA =_%P^%[ 2[ u+aKVj]uq 5҉kaڞqP@ ]ea55 s5mc5%B~x:(%>lXa^fWc۶ HX[T* o Q `xqO,ǣ"jJ]j^WQ^Tp\%Tr 5@ RU*4d H+\.j08jR>~W+:aQSuuutttu⺮=x=;ڲ,|V7n[\0[ S|edYVp9ژnidsaAEȗiB!,/"JI7wilݺdvu,  &DZei39v4Mspl;O+vDF#Q&$l*|VnE$XaC v%չ8樁R1f|y̳q Ų:5zCiPŚ\>ͬggg%!T @LDlȻ6XLVu0JF;o(!F0H$BPwa)lvޒkZhTИr]lbwE0ػw/333,..r!~px{õ5gؓ%\++wm!nܸA?߯^o@CUfd]Z(J#+Ҿ>{izzz$ue`S1/_$}}}CdBtG3 :vܰ 1>>N<❩TJ/M>x+ l_Gr:^p})cJ:G].f>>6-ZssYjVq &cuf}Nf*:)a0h!U 3hh Y=lI>BvɋS÷ETkGvp k}Ge@ @ &qtSYS^-q'$މtL4f9^t54a3ȂSpG\V]l]3o_>۶ QKP؆VJD_ `5Vw(7jTjBcid4H kra<~Y6T* 85l6$>p8,CBLiIh6J5aBNy)nߏLMM"'O핕>:9 sFb1&`v|ks  GZd􏭜<\lll)m{{;b1.EaϞ=̽^/\Nf֚Q[jUi$' >??ȉYP Tqp56d:Qpv*J;][Z{\NQ@݆Wh=]b`9{ߟ ȯq -2@o^!s1 m7W/cnn)._óg: d4 /EQ8|yYjv͡.T3˗X4A/Tm 4RJɇ 01`7M`XIgfjYEڼsO{Д&~c~7mMkVEN9( s4A[B!J- h :E*"r|m;M<޺Jd3fn"AKڰkafIR?<eq(Oi}1=U:;;پ}5+099Iww7dD"A\faaD"A__y24G"T-v4ȲB94[nDMb3d6lR}(AEy!y-6* &zKPּUghl# 5rz@ئAP APutOlB휳΋aTKhu?Mfw$I$v *-ʢUZIۈ* bzPTŃ"IҠD,fMkM>&yxއ3L&)rpp0/&VǶ ֒ UUx*K }peYH4@YFXhEb&ba[-y".Su}[[" ժ8YZH$"Dlq& \N 0\vW|Pwuui7ftB2ots9ƒ ]8eU#_prs }?"; o%ؿ+Wxxٴ*gϞ%044#8vϳ@ַ|3Tٷ1,ۃȅ#-]!bH2 a#ñ rs"S.IRDQ.OXlMZ'Jr+hF6ettT\۶դZ&&& K%Ja`/>ο"Ngg'{19z}|W [y>:WJ]S癛cϓH$x}S'ֆ-|w z7չei X-mP нL(СTPzJ_4Am l/܆pO3NdnE!1Ŵ}>GmEQp\GB_zm3-McػNDb1 D,Y`޾򑼱R%Z*#ssϚBsw e+giLߟaׅNZR{ħggӶbP;lҚAT7X$rU|$.adb&|Ù7(w*hG8[Ԋ"M"? Jy혝: ,-y!lMҩ$,xB=/t.Bg&bEKk@O"@4FFFdF>5'r<gllD"dY7U^+C&jWB 2pMHw8!u`?Ar9u]~ܻ]F [$" #cab f$c?`Q hB]s"\3}oᵷ*6 E )0oZ.>*MMORk@66,>T]h[e'$9Z,Zjq酸VCpns~ E^Ë7REeJ+"5Kw5m4^᜼K̩_;P޺N'|ȶV !t:5G!v'wg/hl%pLON-@# T*l6hyyYZky^J(¶m J큍 FGGjH&QS9@#b6pO^'qQ^;`*KwC|s=Up/:Ͳ_'lhK߽_u1|6C JQ.iD 8' `rӃ]иwtpx^FFF I2dzzZM,,,000$TSf_{w{?Vؔ8X(?܇e8bR7"L/P(µkrjZhR Z1jU7P}ImLEf׼oZ7eiOpz{{4Z"k#ljFc'M`h7g)h ,rݎC"w]u;Jl3ٔÕRu<í- 2|j5L(| r(N@+۶T*]1L*JnTg@4Ŷm%>06?l&o~JyAXE,fI.cll`0"`===$;{M^^Ԕ2͛*}3077}}}^u]וI}vvP(č76nL2 _>᳓4i v.QyY%tdhH}}ႀ ~jGfFi7Ydo|!z;  FC*`!wkVu_g!Z\]lSe=ڵGn'\FD h;;5A4&j ~$D j4 ȅH u]Ӟ֋uzϹ8_d2]xpp=bώTl3q삗ޣ]orbV`fY#=A{OSk\h|ϼ}}T*%]geec\~Dڹr׭GOƍއ$4M:::,|>xD?3>NŢycK=m5L$d/(I3h4J$avvV3 tar9z{{y8lڴ|>yܼyP($đ,"sB˒N߷[;ث꡻Pn,\8^S4ruLR<*jlݘgWX0\@vźZd =w .7 ]XܐzƇYvp BSa\]>btK[Ч*'^xo>)eq0MS5 Q hbd'1(́D'P V R8%,O1j(7(;m4C%ZkR+iD, 3yeU"2bXrlә-paG/Ka>͆<~_"^DH4rK\ynJc RiFWWa,tvvL&QU\.G&K^_?-,MPx maD"aP(BܹsG BaٔcaEQz(U* jm344D" JuV ~k786&ٽ^T5 Taiqť%)Q޾}䵝jaVԠt hy,<#~T cNA/7Bۢ&X δm/z"GToZWɔt m(z(|OjU^\QP-OhР+$Qx8Z%oi,[٪BѢPM&L~ \i: T]h[eI$l|H7eӮiCu] NAo )2j!p*DJaJʘڥi|=ċ5 /۵wP͋T\Tz7Mx[f&C|CXkIU{\tpD"E旷4 Ξ=,m{M( d2Zi$IŢʯp"<4Gb۶{aH!Rbr`l6K*1;Qz---qIvwy߫\& xVHvW^)u޺z[_*ǎ4MJ3}a %3a>fo(ubJEs SSSDp !\K˩Wyf/?rBt: xopJd3B:tH M%ԳH _j Vdr iUR)݉/P., 0[[[|Et=r6L&/0?>|]~ruL!Y6>b}t;;M{ +~4U`^Ǡv;дUP J~Qx5t!SEQZ> tirCKӠPł&|zCA/ט@lɵ+/!)b$DjP~gNx_07 PY_aߺ۷ pȂ v.V2u6#EFyARݻwS*ڲH$T*tuu$O1 ժ4xc!DdYjt4<.]Cu떤9GF )A8ń&\aE+Ƶɘzg Ѫ8^0GaFGg~c~'/^ĶmF$Bw1cA&tެO;8I \D:r0 eppX3?4hxNv`*ek/GIBڶͩP(ЖJamRza S(dKb8FQUFGGFex['N)hF6%QH$(/Iek-E?82?7/.[ZZ~: % .x~,ˢX,rj7N3ؒ$6w\l ߱A Gℽ8*dV )>qr]ڪF tga x@ʡx&K>͑ *[c>swCЈ)Caނ`W*KTZrLcM(^rvT7D^ٞ1! d:h4:o9/㉷ư*NZe߁eƯt tãV҈ljb[&~V㥁unЙZH=zgJ=gF*;PR|LMҼz[>= iOIpRJ"ZRazzZ&^zn:::H$dYz{{Nu,b``9wJfggm[{{8 X]A&25-Zj8!x affV&s9vI39U$LЦ^FOOd|>/Twn"B|>^\.<)Z__ϖ-[x8h6L+_mN#Oo+iM≠||O7ήCA&@&=lб!quxP>JȣilS Q"lMθ)D5XޜiU D{XC#~?ToSe?=]nݺv6Eg6F7@L \yDф JĈ`L kvrzN8}_?pҞs<| ͛io muq*fg!I(EPBS6'r 8NUXaTFRI-"AoŅ(RR`j-Y:::(JR&ԩiǙU .xE0I8&J@(Bu I5l/r.^d``p8 ׯ]ê-"<&{kYtuuW6Mg<-0iձ5Y0Yd8vD";=OsMSDj|>Ϸd(F/dx˗oܹsR-4j#9nKz0{/\gdT>Eq3-y7gv,¯ ~Y\\drrABDj 0j:$LOO3%~॥%q)к}6Xh4*#GNGؿ5C\ Zw='G9y8~FGGLa#3/hzO: i0 xX.l(̪^q*ʓyhTN%]Th TI5mS{[SH!c(d k6d.nUnfn:r@P.aʼn*|p@:b^ydRv^ Ei& ZMd\\rIo eW,4pDsss2Ccffnz94x齿8~hf3W\###GKK L]׉;CTwP(F̫kN m¶m#B tNnXfK(1EO[4V&셶W5ȕls(Ʋ\XBkDgCB:rMX.ΈnFFCs}g*?=Tk[e?''i~4i%iO)vT&k/(:6d2Aؕ^+/!nA9[mӵ+]дMI49Njι8{}>Qmr MX33mXUR߰+>Hd$ =AjNZ\(dkP^(%rt:Y^^P(.뺴gff=:XLZBUPePԷuzej㡻L&C* ]@tRD8&N)OO$ 9mZ,Ոl` B4Oo .=d2.c&}}$iܹ4,/;{8q1m9H+68cs}VVVb$IEe kךv@ @(bppЂqcMeW45r|O&ׯp^dr(󴴴?({5MT#EH'xdɡ bL.>ͻG4PTGapc.䇏8#.|A*޽{<~ FʁcǤlОh"mS {ucc:uN'jYYB\.S(d۝y4^_Npr2lMzf~@бW *nj5bg Q&_GiV8}3DUQJr }zr BgsOb=m"w!TkYn< cl4V)4e9}&$M!ޅL&"044댍I/ 0qLӔ,N766rvdff0NZ Ғ-D\8T mDRsk$-: TU%HwV"M3A4&&&X]]%ɐB!)4ڈb2H-&% +t:)8~,)6GQ)&f,~"P׷x i*׾r{bTwT!3(Vr]$WVXز^rvD}TMLT6wTk΋KļCAvZ?ô\o,T[lSu?[ҍjenjV !(h!>Ho!#AdrŌhvfĢXfOwLJ~Ҝ+T iB)`k;¯ۤPz<Ѩ }((m[: d-. O ZPTI _$aCUo*ttlΝ @ *dYi P9}SF'I-ޅBA k.rX]]LLNh[q0UUnYβ@ tny*.\E:JVX,<"`@ tZ*عs''0:: GoG:1.( =P(H$ʊm۾/}/:咅%&Q #y/trǙP,%,Do]|۷S<XbQg})Nu-n033|!i?~0HZe||͛Sv:Vap FuvkoX0aiѩ~n]@ xb<*vZ"o8~&{*c*T8h2)5*U Q0^{﹝^.+D0{5:v.xfN]vYu`̌Li|jz(oߦ"U~u_O=njm /XJvOĿ֙n&|7-(VO\k3O3{(Ͼ~¶"w.\!_tc[9npx'|C'sLF}@$!ۋ&HNruH5Ąoݺ%I$Jq ajjX,&G۶1 L&#CB*@# նm@,ömڈ 핗WP0H]5M#JɆLdJiLOOJe:#;#P灁9/}}}SEQfB!}8>4߻"U#{;PyNl ţ]~_t[q+UpɒFrZ7˖#=XX,+D;WF5= %E]$3MJT[L[u?sCOR2B ʈL"nn{GMmO&JԘd>oxbLЉc}nƭN9s.ߛctt&Ha+m!N(A n>nIp` `?F _lD4 ǃepp7oL&b/i.ѽ8Hw>r:q-E'900̌z9 0Md2)B˲$K6J=u!HX0 \rwSJUJ$B!0 qBt:z6ŬQHEJU.6}?>י|}==d2f JsaoT& k5W{:'7m R绻YYY  )ah4JW;ǙZY|E&''%G|znHU`~RV0 bT*8@__b΢i |>H&a+:t68 N]|=䯷r)6M>L2$z)thWM~_qiN22D@fF{ܿO*!O;iw*JRot[HZA $rU5dZ'{WgcYʦ][vjЪmqoTQ꺃b߾ '_miAqm1ܻN6շ%ELLjJ8GUYp,+qM`bxUy4^\ՂBJE>w%قoahѭ0wFE̓FLb^N0䔰ȍq7]e&>>7~ ,pi<wlyTEaϞ=Du>'NX_[AeۉD"dY\-x\b"AQ ^BA!pB)$Yi0 H$b$PepK4 RE677QU>~| Hg#E ǎog{Ph4ʡ~aϝ;w䦠\.G$[:R$2RrqpI ߚ^4wX&d P@Wk%mU tF9Jղ͆d~wRSeU>c2+?TMhu?O'O&MM4]NFmt&wL&Nt(z I/^&WQ'Z28ll}$yOC oʁ;;vQ݉vF_UFx/=2بb H&;%)*I_٤VCӶAFD"w캺v 2$ǒDQQ |6eɉvww0i  Ϙ) JB4/~F ̨omY.d2ܸqC2qK:iۼy4={p;u^'ba$Ivb TB'4M.^H  }r2gΜh \(ExgsiOB{]X$Xh4Tk3 s*˒եLMM .]byyr1rJ%:DXDuJ\x#GH8t@&쀇o:&1㙓/`Ln7$,t|۷oS. [W^nTwb&x\NJU F<ɣ͇h T6=Qhl)~+>cvpo n¬:Aҝ,tTquhAmTշpkk:βN𡂫CvyLſ(262Uu,"`Jm?LW~| WU{'?G[.\CmFLQ$-,0eQjjq\[leٝ=NgY%cV9((`0 1!zE0 &&/ $M ڄx#UH{vힷ3]/˹L2|ϫM"yq 9 ~@|nx߳Rٸt8sضm*fnl夊0 Y͋t+ms؃AIIddT:Qդ^X,"dF f&PH޳RG6^ $HзǏG1 N2̜@sL&fYHRtttH*Hl .XȶmnvfZ6ì\ ޠT*сmIk֬X,xRg_صIeM !\jGz>|HcZXDU0۠wМ{phMt*P!PBLo'fZj[VLj#-Zv ղ)z$GQNP[> JBdB 68}mLd[89Sj~vvpUGT̏;UJ"6Bs#^o{mWa۶D<Nwv_hprhsiw+^djzsX  yHP7 2FvR K^zW)XMm>bqOG~O üz.n sX,sh kGAL?{[,š*ZB%r]ǥB2T MOܾ}qK;H$4Hz kYy hF.W۶fv;PHPe͛7) $@@(mD"rJ$!3W&en?BgvwșXEU9NQvv0t]% ]׹wZH$Ylc$ nݺ%G K#&(l2 ̺qVxJ|IR[*U7vЬM궃m;mpŒ0P|JEǦT]hSg''99͇6IMT[smE(1tc v!nݍ fDf7I2iKYYŬNt6䳉'.Nw\>ci7w;{ѵgs^;vqRssN EQ$Nl}WWTL&##AňD"i?6*Oce~~FSIu k@I$\.TUVVVfr[ÇKFerr}Ν;YZZ4M9K2Dd.֛ĸLMMѹcc÷EIEa``GA4޽˥^~|1A_T/Qt.1n_'+pB7^JݺertZu:zW'aZܮX@><+l*͆Tpe]s9Jhrsu~^7uՆ7_^GQ}:"G_{Uej^ڠpPܼz*Unq(n l|>BA^c bwDIEsp[t?tr[A/USe2%T^gV>ʰmP0*l4- LvD"_m;_i=^TlNb}}}q~:رcn޹95tAq YaGn3;;ÇF)nA1%GI=a3,u{L&%p`< dk J jpXR^L5=hYٳ{a+!b!).,,I&REu4#yy=`54M>y~zPA˘,.d2I03Ѵj5V 0x<A Aip3HrD"ex6cB.yZGS[ʿSuql h5ju(UlJ QPS^QOB!]T_L[u? c6Wq1l# ۲=,%\⃉3_cك&˦tFf"j ʂ…R(s&;||*2f1&|>9j"Ee(0H<@FDv%1L@DP(HVI{L  HOE2,|d=1.HD;}}133C:FTn7bHDJpt &zeEJR$iɟcc4!3Nnݺ%"!g駧H&l۶={x4M8uf|=p|DB+*ܹs;+pe''젝Y\gMMd 磾{199^^300 A DQt]&=EQB r+gisE HRԅBwvH|>O/pZ>p?G~c5ݶW/A?87n`Νɽ ǣN>N'mmmܜ<?WˣQ\EߝM(":$MNJu X$_ʱZpHҟZ ?REUV ~U0 0hoog׮]LOOKhXEE~_: ]]]LMM 1ipSHN*yW~% b8^1=ϛ߹iTW(͎dUE(9a8466277G<C_ r%#|GcÃy {g||\R ʆtd2e*W) Ϝ03T^x`l6+q $e$ajֵx>B*re*a6\%]4VK:9N.Zm:0ˑX%ty.^}ͿToSu?-=,-lc/ͺL w& _. 5b 1$8M eԔYJԭiOG{zq9py}QŇ ' vfxxXvE_q̀ӵUUjFk'PQZD~`y)а 2RGGOQ.IӸ\.hvBx<zzzFl߾Z4M#xj~b{attTr9::: BbJdX墷XE L^/D"N8A KmX l.GK|&6^䱌3ifgg%R8dϓNٽ{7n%z*'rr龗ABOoBi r2LFv^b(ypN|۶m7s_9{;9~mmm躎iFފ\EmذA64T,9dϗZ?~M%N.Rp|g}|3% 2 gΜ! B2o2q" ɷ+pӛylۦ+LgHu3\6W$"u~/v=dj7X`,E]BSU'wu585ɪ+ Mj Vp-SmUvilYu&Oɉ|m.β`훦aul!PaXEZ<5B&!͒1 P0.U/nAMKK ,+4+hv$.--qsQ+fuYý~U4i?)%-<=߫:`lv* >^v޸Թ d3guv;gx%:'>;F<P(|=0>177G<Y kRE*baaQ2E3.ZߏeYR1Yȷ-СC2D(BKCW,I&Ը.bz ]vQ֭[s\Ba 0lж玕eBD"ٖ`D" m3<\_lSe=ieXAldٜ&&$@ C0 "0^@ĄDB9Aغkn:F^c\{chmm-?2AUU-kh J@b@o+<*޷\.ysr]F>(HzQ$m$ra%W]]-aX,Fgg'ׯgrrT*АB2GJIz=k׭n\Gn[q/Gk֭[ (  ?ṷd( AI B 7D+Mؼ>u0+l6w^vEWW,0ǏkEbPUU狳(-KpLpoooGQ_.5L&Gk2_\P:͉;МE/]ש@47t:%80w6UquO#o-d%3ޚm80r{idwF|Rκv@%E{7Q[o1::*࡛dL*"_|I:-{hySgVB(&#?S: ;*мjG,&| I6\&j(PL=]4CB,mnc~ YU 鬑Ȝ KYvWyI;Y,T#J>_= J/B}-H#\.M$lJ4條jɓʮ}rԋLOOc6zpxtBߡ6h#"[4}͔Ue B& ;(Kg-`| .UtxvvV6(Ru8 9ҝg~*gϼ,At]gqL&ijj),6l $~ \p~6mji.4::bvJ${$ɤoohhxOvlvH왙~ńjEub oh4*u-e< IU`ݻHl0Hyy9PP($S;::hnnjFjiiKX-uY"?3ld;f^L3kuYT fDȪŧ@iiQZq:l6 R;N$ -a$RF#C2w@k9 ݊(l->O_gܱD\`4汔eZX${ʱm^@S1#?Tk[u?iw6iiIn/ :L^M_@Afݍ:9ss.ft)$jӞŋ8<|X@ @VC4M pt>'S `␅ί( vd(Lz&~x49'X(Ep=Pׂ>۷oFIh&3gggx<<6gK Vd,0Kbcx &|Vxo%v9kX5XxUf=_3lsW(᫯QgSv79mࣉj8uК^Y z#`GI?sy 쭕4- k` 3P(NSLwD蕢(ܻwO+0 CwqtvvvspGV?2_}(7|4Ma7Vc|hF>/dRŠ,˒7n044DRarr5B VVlȈb1?ɣ=\r!N<ɝ;w,,,씛r?o${d+~chmm-8R o44sM8E 2LE1pvYMX] t:д"`r#{ovrh466J㞥k[[C/h4rUm2hii|sM\v>=Jww7{===(3HRREEMMM2Cr:8H&8Njjjx<f֭TWWcyk_J\w#ehJ^쏭y:::l6K={v3::J&IP(D   EMÇ3 _-`0=,\ȡZK81 yfYB\cPUI)g:xI4M' +B ( @@Z 6%f+ٖ 񙁎OwI7@s={|Ux 344$X,qr# fC zA#d!ARC~%8]E(y|x#3 >gė-|1ݦ%,&dֈWq[l戥-(f^ 6+9RSebߦW-:k89K n^ LYb].]Y:c9M) w~>$QV>2s_y8}YYXX LJ_bR)9S>Z=&C&S" 9K)j%}Lmm-tdqnܸ"t`0(l6+B hioow``xxX3|mkAw k˟{x@7,\rYw߳LLL4 Ob~-rjk-?*y!x<(_efM&!J=(x^;~D,O[3Wy8NVVVfǎlڴzJq G8]?+֕{YT[LeG]c0Z6 ,,l&3f 1BcLTc2^EMtfQA,. nFj 0J%0`ma;~:::5Ro)Fraq^FJ?r D׃BaԲ&dEus6J 7p1ҖWDvvvt:eB<R?N4EUU땒]vaYQZ(Ν#޽{ ~`04`Xؾ=XtJvhJjh42Z.ÑP$RB'{9 %c|¢YHTRSSn`2X\\d||n|>^=M"<~n[J 1>>N>>顠*x@ bNxenj8{d7VgO]be*_OYYcccaQ4y4P(u(KIK<gnVdUɽKEE޼™|͕XNuu5DNC+aY Vqeb[C 2?L]h[eI$Muk ֵN(2uon͉ʛx.K,mlZ#ci6mҤ_I8y_@r=?C{{{E<\9i\2YwyOU/ooG@$"߯#^ KKK~`9 bHl6366ŋr i螙P(033C[,B r|Te rL&ɓs.ZW'kVn st+80p;mmmxed||X,FKK >+sڃ+*rQ}n*0Dp8LMM }CÝ|Fi)6?.&"P%(`P((455I\KK 6M&q&qm* _:HZf~U$. Mx{l6` Kcc#VKFͿyW(2۔D-2n>;/WWq8r-CrXM^_6n;Clu_kǖ/m];gL.~/kYJoUϖ ] 0bacӤ'*9#  R/Ψ(|/$BM4OeP%n:Ztʾ 7~#D">8wwl2pSшOTvKCq&'ٮrEjx$}RT/Fdz444`w1£7HRiyg-XRɃP&uuu166f##Gx)r-=$3;;K]]_[[!ڨ1;= 텅y΅PW֖n*+J*buoU~?F4 2QVQحt:ntS*ۉb:beE*^/Hk|>/}gϞbÇ}IRB!mmm4o^])MӸ<9I$|}ufzzɒw"A#R(ع.͜?ȿNchy~yRud:n( t ɼq:F"i4FX,0ZPR u Y.\]h[e$'iѤM54&t+e)tdhsS7D LP'1o Mt:VVPiجK;kM5'^$k48}iJiq?^sq7rFM@1(g6IREQn9 Q<#,yB(J\&+vCr`b;5]"0rITUss2NX&EarrEQhmmȑ#~aF"~^XX#.E_ ~pYο7 Nksr{ZXn/v8 ?ad;gbI.fٽgcYۺDg[pzU䏜>}e侾>#tttH$8NF^m}޺uKGDА={M6 씨H(C-[Im>[IenʋLEzGgGuvL&YXD| m!`S"yf_JIB OlAW'`B4C`qUan K%M5m*e #cB[;E.9Gᯯ2PGԶ TNx 7]kb\(,_)ˬ{b%0T.1/sj>-}&o>]ץxPHPWQU< X"ZvÁ8BAn"tiiInPHrX335ݎf9x/vLMMIyuu ell ÎnQX,ijd)J2PTx=2gmm&S2X8~r X,Q  0 2L=ct&#s@^N"MӘwzBu2 pBDRFI&,"~?VW&x9Z Z\Pǹ8: ~;G*Uy4-h87OGG{Xn] ԔA QaiRh&`&]]]l60 vxFe˘p `RݎV:_vM9{p/"ku]"tqovZi¿t:emZRdy٭( A*+Y/]2ieZ)388H("0WZyJ,hUU^)K-W^E8iDas/0 rGߺ4`_'399)u>n p \"~?555B!X[y^YYf1>>.SBܺuKڏ~?y"Bm'S\]lSeg=>zl3N۵$[AKa03ńI0D D^h$*@5uʅ b\2'gvkumf6M'_ʁ,˲8dWWAz/VAyϋ01"'vKn^({E @Z}麎땿G 1Q+Ė S[[iܹsP(0 N>MJFd<]]]<3>7НMjP˹ӗA_´*ۚRx/kY(8sx7w2χWpgRVύVU1GT_~Z \Όaw1pͲ6 trݍd? ::J:ϒJCEt:v8& ɽ" l6i `0bፃ+vx%m="\_lSU?wmuݺntZ$sloҪ Dh$* Pbh$q!&$DC6& 2$8IvЮ[nkv>d~nx+zrrRzEOݗ--~)r fPx-rhe"XWR楚edY(ek,JtffYX0@Cxz֬Y#䖆50 ZVxDL" \,ý)VXA,#P__ϥKnK l6TU{`Z[`mc|&7gj*el d`^np<ЄfbprjL&;OÅă,Qf0ũS>e•`h"4"orT_'Fy]DF!SFne:3f"c5.Rn_šG3/0끋BCx fU--w&!ɠ,dž8:;PUU g&6`afBHevʮ:qN*ԗEˏoan26o}+*&Oա0d(lh*mniUUUUD");}hnt?8Ic:,TLry.VZ5ʕ+hF8H$BlٲE|pύ7$+@p8tuurJnݺEמq:ݻr0A`j>K<p: \.$\a<`MPKޞ%:h4STEQ1ZA4- ^P,A t@P###u82O[[[IR<at~HDޫ>Ofn݊锏ZPݻzP}5tMX,rȋe~6]t½LLLz95:K:d2)v|>cu]ץfM60d1nBP FޥO7WFum&/rIu]Fӷ3o)fR) T_h[e9iҤ͖.[d٪m0mU(sDu LQ/D˹92bDQ(uصՋINr{ԋcEH9$<.1NS8ȉV6Ň(T?ŀ Â(vR ^W =|>/R'lJe[ ?@djZH;w2dF$Rq) *yALMM144$e֫WR,IRzzzH$LNNNuofnnaνed{uhضyijEa;ߞ_@ߺg19TFP:'y͉[KQ֡=kil5ծrS~u+ jViPV/? nbllLኢ:TQլ:\d2I,ZgI}haH\jLJe %*l*Vn/0za#ߛkKL8JZtZ4BpO`Gm w9tem*Q_'PnՓ-OUmXV̌d䏌pqC*Xqu&ڿ2`,L;LC+<y[$Xf!\Rіp\9j]l va@DHP(sssLLL0>>_9wєQԨI٣~შ\K1 8T6err0uEoʥc4Lr\Jc0ӵ\8"7rN'E~T\4M# t:9uk.X'y{Q`0HT/ao>|>tuuY6%0;;<^$`>ep޽{ٵkx*k_m:hف,//KP2vinjq HrX͋D"{2~?rYz"xnh&WdZ2V0`0@$]&GdS[[ATbdd7n`N&Nt4}>.$\~,|%Suc~;C. 5&K3pv*kSwxxO}N/}=η;z]l qڮ[uzuIUpTϴƦ2 J&lck&|Z p?C>ny* rK%ˑ-ڌ=2U?Ǿ87N)rkr|&S] ^,'p |ul^Wq Pr YXX}9ꙦdLBw7:}$8˲xuI>Z"'9VΝ;GP L3Ǒx>D- ܵd(#yZu:߶yM끟{h}M0;;K]] 4Q:;;fb1i6x\ej'Hx gYLp8CZ9B !M6D"\/ǡPHqd3ZԑNgXn]KQ,*A A,ˢ ~20|Uj6MKY1JFdUmϫd3\D%d2I$!HP]]]V9p8ץ>tZ=rF9ݽ˞vuF/x& ŵ5,..i/w_Oň* بz,+WCpؚSgxY+!N!\Ndh=ŵe+ck244 rV昞?T]lSe=YQ+|l`e0ؖpG0GL 5K 2P0[Qu[vm7X?NEޜ{?yrر* {UkFz BMP_}8@Ką.%E/G"Biu]Ǧl٨TUpy ֆL(ҟ]/5aӬp++7JWWCc&---X,Μ9Õ+W#GJOOp%%rbBۼy&$0<b(/+Cww7#vtr \A*LNNJ :@@ L={H_*"YlJ͆jV󌌌iHJB" H$d6vz444HQi,-- %~刺קqS[&pu`tvvyfE!Ll]h[e'$MIϒ5s`c Z6t8^U `+ěDxr*ۘ2&]HsҮIrrr\}?w'QwvN_C_X5tJ僴,?̈́c kbJ0 bss-iB GSJ"JW;[a9ms]ܹCX[V$*7y&7nʕ+ɡCд2k ih4"FAfggRnLhz" M:us}(A_CX}~>Xw‡rٯ֨; ?Cp_ׅ~/fLݱ$ .q*f~ߍAV!Dt:-3IiDx Pz8-52yUN=^XƞDDt ,/MB0R9d6AoM{kq+~?=s-dhXis/qZri)ț#rm9 sn*elI8Em(k>a+)K ~a{]v( UdjcgT$KD@u`߾}JѠܞ ÐYeXZ j54f3;;K$!T*LLLHyr;'/᳟vwiϹǥ߼@5ѣGS(Hj*"ZR. @@%oQZ^^VRQr9UiF*bvvV"B!ZZZ/ /^IJ,N<8j4 _뾁f )pD"xt:Vd^IGxHSAO>"O)X^b@?G=~.Ht%5jDh.66e*(UnlT +D2ca077\|'x`0͛nSιccp,#$ry$b=<!>-T7inj!y pT,Ϲf|~؟;bCrdp~*[tA<ۣ{apf[]fcڵݨKpVK\N6m?E!ԶmxUIV, ߬iDQ^/###?r~FFF\.K.ƍq>^ pnwL&î]xK^L`Z}4pi*fz~++0$4 0rɭg ڃQ/X+ڋiti⻏l k$ "e=b33 H8"ؑw` q7j&^7;S3-e!35\w8Lg w@ơ|v6j[nyf2w ? hа|s2pgpm6n <‘eh $+y9xF7*,v5Xg}Bgw̵dn3$}ZD:BAsj%(4٤c%q|b1_.ϰ닅T333s9.~?[q9e\p-d_4)-L&%p:ɮ\u [!v&H~R7n܈Kf; `jjJYGQ97Miͦ}fio؀ikuKw^۟bt:Mgg'2 L&#_O%ȩCRsOO,,,H< ƺɮm%}W,~rM4M.*D0B{E %@RpH"G4TfIWW'lNV YVùr<ر\ l B:zsjJ",9QgĒQG?<ݾ,y:3y5/yZ(r N6W9[ ['^x+z6d|nג2Ru=ɪ_`]omm xJg.[ uv6j:<Ǡ9i*'bR)钚ޖyTz8ٔCi0D-y B..xa"PQajKF+OT*E0Qa=Nn:jmŵ]ܺͯ>ȳqx޺$^I۵:h`;G*YEdvN&2B*ב.v<U[[ee";100^9TH` {HRS 6mR!N333yZ1s79o … wȸp]۶)\y4cnnk, 2EzhK4[u*kg$ll;wkJ[w E0Ǹ:/@. tb󯾅l e se"ϴ\.+l<\o|{mF ^9@ka-F\oRߤX:@eC\I(4( ]I›uLnCty)^c2՝&C B%@Ÿg9,SC%`zf\I|a`: e)jms 8(G6}iFTW7 j-^q6ft"5jA?zx*˾@9K{)LB@2V̓'45*PTbcc۶I㪊n,_tpur*+BXڲr>p4ǕiSuF.&6|xUY۷3dYĶmڵk reϞ=槉DZ8^&''Umx<r=Ic˲d2tuuaYt{ ,KU,T'G -qRtw U%ld2<#RV0`mmjJ,J%Iqe4MǶmJlq⛰|`0d~~A1Fw0@& \U`(@s~:e188Ç)xh/CCCC"A:C,#Jؽ[xgN_Fd<Ʒ9|vϽ8*gI[e|9ݜĉc84M[Nz}|<~enR5I((|kK P|OShO*7Y4A"CJ x-w޷UhJ#E!v N88vQ8lFMRdu .`mmjʩSz* VgSPE=w.\P1eѣޤfsssb쳔eGh< pOa>7#ci%>@<^`hA&}[sVXǑuLw4àX +\"ZcuuM&GaO͛|_m~zqsh*Kfc޿Z<;D}c.Eͻ1C|7Fxuuu.ϥ9%$3>/$ B#^`PЧ1gg83Vgo̟íH@n l!B0\˲ VLNN2 \y+ :Rf*n2Hv ֡q\V<+ğI˰!؎ͥNM20djF,Z Pڌ-VB=:h|>O<WCdhp28Ƕm& -B4Hӊf4M)\Gpz~NNqv$͎wiiξ}||w>8< *U(]Kƍ}"Tׯ{FGV(Ju]ed2 B`dY=(`^[fm& 01ȋThK?*@&JFI$E&3ǓiBrD#[ݻx *+Jfݧк5_CF/?cuuUAnxmhssӳYN?bzt-;`&mD"gq]k׮TOle3Be ]$]ISڨ@I*$Fx1!QċxĘI ƃgp 0j8l4KvSvKݝ0~ܿy{=*[t:eA (AR*{K7.,* +++lB>S @ ҽ@NN"pdB \.STbK:F4,SSSy(bTg4UK>'JѸbyLӤP(< ,{GBt:0ҥKXwc8 VIRe)c>sOc{xA4)8 A'x[PI7ެA}}tѦO@ECkl5nsG6{r8y^!됋W <_ wyP@&fH&VYofi:dž^TK} 壣e.ܩf|cL"v f mT6֘F`s{)n"4-qPFҧ>_(뇘qu U|vg+&M\|% smJ "}kSRaaa]8Pk|qܢ=ܥg: ɽW 0L5 2Fׇ*z6 \=`2خL,^L6׾|yLZY44Mrglu9*f-U5^<>63h6>Ee`w:ˍJ]\i3̏;\,X$W/O%>OϜaR`/I2djjD̟dڅ<0Kg1!OHkWczk~J;tde|*jJOߠ2??/˝kXuW'[ŕ 9qw3jgF:@}LU۴O?yoA|a&[Xxmwo_<~F!7g! ZiJA z,yEIR PHaqUe8feeE677) E6;;KVq\ 1>>Kv0 Ǝ$;ښDr"H3BDizb*"(LRDdB@uhr,#E5~viqM~*zNM(i ZL!4MS9r@vmiTAMfضMVn!Σ. qN2N,ަ !AD`0@4O%F,Jm0rxE"f9F5MOp({{{j)(NñcX]]e|L뺼1p!CL&#%B1mqzݿ,&&&m\.eY( rL:&b&VwS$qUUeuu4I$,..r]e||\~gΜ\.KjuJGBOѝ\.\/^ G $\$lvB4=@wS!VEU[P<[BTu}q&vpA`g":VH:ztb={X[[barFySQX8i}T*A9n]%o6sssR28>>(ccc<\; ǎR8~8k,DD"Z-z ]4#81ՋN\HL5MLLtT*hF6 }*B\RD(ԑHDvfiz4M?eoP(:ۭڀgB>hJ2gyM qԈo*t /Vs:LT*9;;K8J>kkۻrDS(}1^-}\Ocei;-C3|cH2,qa ght11̬ԌQW~ 7Y݈ &.&1.L1HFRi)TtBoZ{޷9y* W`x,Q3Yd^W˪MnmpH!AIueY$|| 2mt]qv{</ ]qy6CCUM\.S zD@\NNN$IFFFXYYapp~;bvv 8X 0X]]rL&P&MӘdffiI+g/pi8 p-yif&ut#EG #pu]]::EpwG`Q~M%/@DH? W?/<y[[B}rwvf۩]^;;il]*;dO:6ǵ^^K.pQvU'a>% {Άhtk7cj4bꈻUiVour\-2uް.~ F&5.}AGfC`·b?*>1`8ı!}Z5, ^sa*M:y7ZX^3'S Ze[TꤢVL4U.rV(ᐌ/ 9VέW=BX I$B!xWL ͟x]1pX?9T*$4_goobV4@.kkkj}i ;\8_CB˗jyiiN 5OnvHˡt:VXe)pA)"H$Q| ǃaJ̩Q7@ srӣxEe,ESjg 0 2,J}ҚP>4jΗH *9EuE<ys"RZ3d^̂䂛b|0;wt:M\ZbBcǎ@zz{{P(љoWg8qǏd8lވqq;FHlE6毵CH?Xt Y8t֗a f ؆5xUwWi*;0+JG2cW&lv}z>GrNI<י/( Ͽߞ}Vя~j ) GG^YP?YtgҝýET/-d#m"&Oe6G4Jh E\ƊÁTꀎL5 v3{`vmw9s'+8Xrb&(֚P8 & wR7,B6w9 Vԇ@!SY菡m:59}(IhHDU!}+mD8nw椗J% wk۶+pnollfujLMM#;v?ġt躎LLLƗ<h ȤbvvVzE~Ue46ݣXpXڲ$MOO366k_,՛Cgn߾-+!fYjD(.288iҝl6"h˲ɖiz:|ĢQbiimDz,t]J(0::*211! O_EK[8Jsu\y|ǓNri>Oe}TJ& HLdHu, z : H/C2n}0D%pIf-Fs]h4m7P23YL۶WRD4effFɔ"rPh7;)+@8}}}ngpɉ'p2,b$R)14z)._u_-255EXرc58i^XIaxLta+{x3zOx m7_50ۿRCsoZƫaxzrĥ;mlC"$l:my+g{⣃244ӗػR۴9{VWWyۼz|f1nJs Jݲ05?UWG; Qhi\)ߡ?|0$dD4r?>NΑ&Jx4;hh|ǯ@Gv٨2y6#U)mB].Biݤ Y8L4ľU RIp.0ϼ3փg6e!Apfk݇qT:>ܤ :-?fPϞ$)g99&IU?5Mvb%Am[P!j -r5E2b:&Ia{ SkSn\[2JqS(,Aۧ;\SWR)"Pk۶zz?O<W,z4MSjX,FZEu٬:677M`ׯ+|L&[4,"HJy{{[y(RIV^';00wnnT')Da!hO2THj5Fɸ"3::~\K?ZL0ȑ#X"Q7T\TiXK9 *Is, Z%[IzgZ2{0tBRIc466KKKhZg8@t:ͻ.F"}.3x6sy?s}cˋkg6 U=dopQΜ9cll ׫l2 "\6,?Toe?wg6IcwMX6 HeK$@ B0ԁ1 "*VEA`Q*iNĎ}ؾyI=Z,wz|x*`SBXVl6&+fA /~TޓxJC_~?"gG뀥DT<W!%#G:u+HgϞegg5jyy,RfstTJ6B@R!qT*ܺui*s%!\zup˫]יW뼙EJ|w /}_~sgRp~"v`U7"DܭU]~@|>j\> '<8ԉvwEZ D@b:6Mk BL/yz\.O8}50"} ʼG$} nn1MS1\pGN8A`nnY ߾7ŋcyuBǏnY*8{gfЕT ˲طoJhR*ⅷ~&Ll^̷q;:vQu֨=vWgH? {ƨNGv+T> tu 0=tY rԸ|=M$gg ə7 zݢy9ᡖ56;-X+S[;D01c`@bƮ3 bù#|f\"GN#a_qZ((֮ Y{4A AۧC3{5(EcslmmQTF56z]YV ͦ%d~~qXZZR|^y DžX,'eիWUʝi,,,p/8jwQDp8?.qd_1Z!ZTEŶmVVV0Mx<ѦպP(" rhZ-2JKD~bQ 4ccc강.RXIsANZUq KRabbB3 B?Lr%2LT*wN++)umJ d*c!aD!DiD;Զ@j۶H$}ڶMT$A2{&godbbB*IR$Mh|q=c *}M|-f}Q#.[:FMgOg<1xʃoFCV)PFϟW5R@m2dttvTKhu?d'WnkӇ)lk[z0 JE4Pz(  Rzz"ZA(xgB Z4M&aٙ0ϻ04ܿbK$ ֩S6sXϥ";R.O{ ~]=mw0fn/Xh4av>1t]D>?զɵAr={/Xz#v&FÁHKnCoLݧ:7>odPIjFl 'X\/2h4sd"=Csp}6N ,b+.檋gW*UNu+$j]h,9N/8 J=v me|t-ypU_j5.awallL#w:֭Z2(NRƹpt'߻6?Mrͼ8+mV Lwl6Tl޼E5$u떲 .Q>\[ƽQΜ9JfggiZ Utgd\&($GudR]˔J%4E /:*6(j8C@P>%XLR L2 rC05 ±hd*nb`n'p~*P(,toaB,//+'\bjJ!bt:MRQX,d8n2dYӹb`.n C7=L4MT*(tIšUj,iH$jATohe??iuI[fgutHƜ́AE?/DaE"h8^} \E]l|HڦM{I㋻Y|uH~(J/d-*d7 ̐4Ay fl\)ȫS3Tr2H&˱%tZўRTלLrUfJx/%ETJk a-RRs`c:y:w$ޮᡁ2/]bpp!8C6Ų, h4e.3J؀X,5u_`MTV#$dj i,-?3m@΂BQAJ j?9{ |~wO VO^c6$U*u^bmSZHE looew?lGT*xy?+6< Ν;G?㊪,e)42yŸ5ω`<7ɊpqK0ucdP3 \/NضFPJSI]MvoLy266kܷc'RWdiU#%N) d eB51&ݭFҀ*ϓd8V뺮Z+idNH&8$CJ=dIJ< LӤoVE4`633S/GV6o=?(*!39b~~˲سgZ0Ii ء! ]]];s `& [;-U_CźL-xijn|^"mܸ1()JJ~^6IӶm\KlUIj׏8NdJZDR"Z*AMaQ6 !l`E!@E<&(nJ  Nd8J3}=d,<Y2J$X_f4V i3J_p򀐎z>h+nӄ# S2e.yʊDUYe1>>I @1oW\! Coew)JV_NR,Y}۶#-ݻjz ĉS@G'yg.*>̇9;Ʃz*g#Ez-}dzOgvvB@Vcx4^_n355EdnnNE 3 ,ax!4rf([1vu'hkB -gnKuޙ|RiP<<Jd4V> C f$)0Rf;@`6RVU\bә e|]\.݊۱w^HܹS!Ҽ;NhbٳGAҫrӐ3Gj,6LҦlz$44SBuL] dJY"1T[h[u?99',Ms6mӲ{lUN؃S "22P6{:hŁ6MJNҴIC=$}/Z^K,h#e%R<:w/E^ }Dd[~K[lȃT:!!Sٶ&fff(J^L&|߿F޽{٪VYX\T u RuH$ m6;,o9i2pc5 |_9ܿ .O\/ݥ7\%10-N˩3b,T_w._cox2әW >I(GǺ>?nW" x:ULPw9w7+{ԻƛOnr g.G9z'Gˇ9MgW8 @2bm=f[Y#D$b~Z}6^k7.~+4h@Z38 V.'<z @z2!:-Dkc,iJ~y4MIi~Y_>I^'p_JZ,LRٴ NQ0H h(7˲KZdx#.HA>˱H"@zi2Ymfɻ3JGgr=T훜=޻A9Ipkp5{{q]|}'-ض~N$ Uv_or:|cWO+ f*^qkoyض"Ya;Jq LNd/dvva6f&)ِ&333D[YI_ ҡ!FeCsss%CL>૿Vvb./aaAubt~+3>֘χqBP'QƵ>=pZ)6Y0-+zOV:"ĭk/I[:ϱm6HFb=4w9j I4mv+1y-ܷc;#ӗ!]fs~ ANI*Ĭ+)?u1^i~'[1iŴUP 8f[\|wx0dobIq V7[1$лyHXiPw8:du0M+ cK]u&Y^/)wxYUɢ*W4NΝi-Ҳ,J%>8ϥ'n%0>.1O|XZ<} gT ʑV#׉:Cq:CE^t[˟8$N0TwQضMRRD\Tve&QIJ,PBfcc Ub1ŘuqZge&&*9۶s$yZ熴JhDkʼn'J%)+!QGCrfeq,Kmlj0,P,f"%딸NCX\.+VF/ĂYPqjBU٬fNXQcG \URd2!<㹫W-.=Ns.G8u G)IĶݗE5Gl]h[e'9l mlIV[Z -dEwDpnex)6C\ Q]T\M[&kiҴ=99:Nj}ūy>J__ߑc <\7fy  |o" H޸qG"ƨT*R)$GM4tAa(JӠit:XY[V}͑3||zV>g+{:T+'Lfr yUzeggGzBzzz8m2>½3 bP$jMHAsLb *J+ ^+lcUJQ?8 v50 N%f`7W|goK\T|>F/Ssm)(lNl+WXۣ}/vSOk^:vfܸk8nFf:팛d,L<.s_9ōKVUjVgBqإtiT\Nz*k[N?$aP¬!kߑmj5 .ra #Vd L4W,Z6e6*0T2au)baaU9Bgg(\OqG`&S?R}FoeەN&᣹_lފiTh4J>'pr=>DΗ(qA!B=s8zS"`wwd28J Ɵ<"˲x A/9f HxLӔ}SD";\]lSeo֭68t[٠l3$Y$ pa^ ~ir xcFl\̌MFUvЯӮ9^'sۛy"Z_͂?rd =,^ 2j+e9b?N9h&Zb1`+˸5300@oo/8cJdQe9T*1444Tؾ};gϞ@ (n&&&0M[qՅa?~En!Re5|Wf2nAiej5ÊY!ꊝeEWlyT p.O]cUW|^!0;#8磬Us%˷?0x:j[ y[:xsO%]j#U!%V)m/S[Y]gb ժa *wx}:|/b,S§*PXZl?s$^+= 2RWI2[P˹'Hݸ]&? F2tJnU%(IE8qE&''iQ*}]mF[һ${R%f$[Vd2NF9% 4~=9®w'_]䉄_eY:;;I$N]~HqS5~>s^NR 0JDV_wJ£irg.\%g?2s8eb~H$Bt*VCmL$Ӄ2R οck|> 5AՂbUas(*4,7uq+,+++BTBuZ[[,tqqѹݪJOD"}rjHЛpd XXXp8 RhnST*N[R~.B8 {DGҲlkڄ֬[V7n@Q'($\.G:&ͲN;;Db49z(!wBIiI0 n߾~6T4tttP՜VT^`0H<gqaaI4LdGZZZذartcXM W?ىilj5 ?wt lrL<wp8 n^g9аa\oSu?t+[;1 d q*j \ r1ƈ 1+#A#1`B``43*\&| av.zmgCk}M4q<|VUU_jW'{bjߪ1hZ?B > 2EcArхbf6CCCl޼Y6~RuatTR)TVaAu0T`0H\C"`5ϭaK OC̳Qq#n~qG,Cut]'XZϩx7[`01Do28j E 5Oõ?/ܪB re(?(mv,n'"ʊ@Xs+} ͻxvPBS5%쪍4.^=T?dtF#]|tPX2{5^K)Ca;覆PFu6>7NjSq ߙ d' Rg &ɥ>a2vaF*b0HݢEkgSwXˑ()\Ok*: O Qp3{rQQ_V!r,9X,O^'A,#kbgZaxЪU|efbbd2)CWWI7Hp%neO L&ܺuK^t]X,2;;4x^ Ð`y6 ǛI:fSo LJ}˧gۗ Yn+===6O0lLMDM&Tu̺χC*\]lSe=vtkIkڂ5D@D#K4م1hBx!^EBDcFQ3Eli2 kWN;Zvm9m8}_.i{}s[ G~f5|rK^t]|vu1 no fVu(dug333T*yD"RtX`'^癟e8H&lٲ+W0<V9nt ֺ`JWylL>MZ ^G/aL;`GK$h^MdԆ hRg.N " ݴLـ6Mˆs::gQ\X,f%/,{_;uAH&J,6$B,KZD gIM<gI,,,ЙDQ(Bi)E΄t˗/si>Fg=pA20 ,Wp_b][3Ǐ?d1)DBLL_4[ B\mlu?w}Jkwkn&j4u1DD {/ 1$ab40bF%¦2Xֵ׮zm}n/^Bo;`[d.>SzPAztB8O#\$gdZallP(ihKczzyV8lIᰥNRhF8ʄ2 .]add&,N~(xvwYSaÑQ8p2%ˑJHt.Ѫ @wBc+.ĂZpZؕ**,4i277VJ2Ɯ9[p(LQl<˃himB*6g,p5] '"}87_=55eTp]xsS?.K\ͺD76>|!Rۍ7jP2M&dkjyHXmΘff XBl Ϫl +tyzBبPƬhv,i먎4*;9l* :)n,! 6\*?9o? l/;`0=C9Տfो 4Me{/9q! \w3ǟYaqjʆl`kh]Ehkk#Y00`ea8ǫogF"VB@,1dLj80 e}8Gid2H0߁ȕ lXF ]KUh16tuD^-XYY᛽5ήse3[mw;j]Bi V8UUf (ALX˻RO?!jCl6VXhvNUQ zZج8WM[q{ I$1 0x>*.X3ͷBb2xl0u.݀Xϭ9j$G@mr22m7^PKp+J2Ұ2<5QE346Lǖ%:.6$h4HRJ%NW.p+эi|,'rrW:4p!=#ܜDzPthM-ߠo}Y j®*ä vM{0S pfpM6 J@{k Mí7{ȎL$y L޳OŢ,䚦qGNMibm>i'ԓT*5'\011lVq avDIR.ZQK:q_J8T ӲN"`ݺuҙS~AI& O|ؽf?a077]At#y~y E6e||d2I&alld2($I2LϏuLgNmlBv!euE!1DQcz2Do4z1&5/\ FE#DC%nb:mۖvێk6ίϏ}^m/a/ /x2Mzu4͋kߒ$PG0xx}iq j+W쑘d2iR) ]h7BT*E6ܹ\Nm0 } ޺ljD"fN?##%*LFXb)ܻwOG233<71?ZnE?a|N3{\:3g199)CEAd Pz@5.++>JW/@ѯt8lӳG m(tMg2^0)5}?8, !/UEsgavvt:-C+E~"Ui*bkgk/9=A.c2+xF?8-TYMԠJŽ QM\mCy!d$*Zz ֪F>`60ǫ[+1@mC@à j1rM ㇂I1mɲ2LEu FSv¶f)lڴIZU֣p7\ $7nPJi|N!u͡V~EᩋרnH_/E_ÅJڶm78h7 \a>'22"j֭X,J7 A|:Ȉ, ^y OeK5:Č1F}Aző6 kCPz/%Hބx$cb(&`Pnw]uK&- qPv:H$XXX@UXuJ,\.7ك:,--U@l߾jʆ IZqmٺGPl]יcǎiI4EN^'pU4ibbR ,ݡPx<.mdسg@%*ea&T*6 y~Ӝ8.|SdkU?3foMHm JH$^"E[/$T E|) B-D+Rҗ-Mlv2;s|=' ?09(#~ا,! (I)a0axP!B{2CX!2 / _dfJtҝIB:Nq BTb}=2HhLZرc@GGGPhָy&lnnr Z^ݧKi*=R3HΎz,ˢP(ĸR,W8q QN3_|nbIz]cpdȋ-hףp2$mV܀?u~\pf Zlv{=Zic|ɕZ MRR1r8UO=}NARg/I:B|&cQ+ҿZHj5{w!Ȃl:76A8AS PMJ(~ '|u`NضM.cnn!m lݻ8T)\)ˤR)J Hl6m۪)9*)vIgb&n"ϓH$:"Jnllf9L |W r5d&{zqufiN6++J.kSak*IFhWUξwFfS!׺\JQhYTOhu?3;lg6fmDIb (=ւRP)=+EiQZ"E9ܜ42Afggw2 Z  n S *uY*[FT^О_q6V _׫AA܅hE_Me"v~#Fb}æZUi\4M$)~_(#2o}xT9:)&|?s/ =^zx Pt BahۭLӇgC,qcǧ{/֤~vu:T  lȣ]*j]utuӹ{W:"CiJD)V`Ŋ=mq4McyyY6ALX 9邵<~*?bXX_řJ.HzIſqe~/W>hAa O4w`hF*p6of|1`}y$192+7~&=o%݊ZX0sTUjwGDXTh6(,( DgA}ݴm4v (\ݱ"ECs@ v'4bT" O4lՒ nssSڅEX$H Q(li\N>::*"/I"pl BuA@a'R ˲hS ]wXd7IiCFx;1 F"EB*Kml%6( Z 7A h{m5$ޣӾJ,GfU˘1\aQ BXc!RV8AG& |7~Kyk'^̛ >]R)V\؛"}(G1T.O"Hs/e6=ƶʢ8^+M 9>Cu\~aqJSe:ki6 8i /@ssr+~ڎC9m۲$&\^AOWH:Ă6N='sקJ3mÙj7>rYn|wﺒ$HCb /CZejjV2N)bpm,ڵk*k VKfyD&*Ā:"P7 C;PubB*jw۹}0ܽoR<[><t]T"ՀHr 7Z4:aޏ M(tWD V%(8JHpd1TU,`~18DE;k[V׈\iJvwLKKK:D y8nܸ9R i666X]]Ò]( n\8mf}vKqeg\4MbRvq8(#þH'U#hj6‹F~ttZ~tea _(ūmav^Ǣ =b;t.,z1~\ϟ{A?c.œmV0MJ닿qm0?Y^E?:rU`obh(5{|V:Ib.!ip'!)tzXi-SDJn|&,^]A{D,BADo/1aŢx4M/?>>X!x\U=2 FCH6\t2xբT-}~TrFקf|p'K|fۜ*?9=ǡ$ach"J~-zm<#&)g{,UJHdakIfi g k)&6A\h>PjOOH]bw}a?w! uV TqwTn/]f _ZUU=O*MQhضM&_6^DX7΃BM8ZM&U;wHӤR) aX%C{TU\.? E<_,>rD"lI\ \wb&SSST*&333!CJmvvV"{<j~" hP) 'I֤{똦)V%$aܥ:LUUTke33f6U1] AC[/ Xz!XF+BDJ( P n%lI=MvٝK?`X!$~EW$ ( .%$+JÑ`o467G@hn R4iGAtfI%!fE bŢL R?6eD6Ŷm _R彫 *J,..ך;_ٳ?oʓ9duu!FQT,//8o^9ĵ.PVIRLLLȃJ%v -Wu{lMp (Qhإخ|b+q"t@t; Rb:cc:~ :Xmh/3z,w ވ2z<-I0#z9-Z *TbGD/߾+?qY+9zԦ߱IR_G6lBi$LLƠ F/l 4EԆtB %<ɱ kf{Wg=b:MkP8Gy[59Zc,6dm!) u\ hMķF]Hݴ o\MC9}ry"/ ^,Nf)wNVӧSVyT.K^Fm b@.D) !(x*7]a}Px\1Nfl#av.6T54 SŌ55x@~.F ȇ4 g1'OArZف@617T?|vةV%0eir*ZW#vH>.L>_cQ*Gp]'o8`0X,P}"Wyz'븎% T71<D.$D<.kE=/K,Z\SV uÉ'yeFb1fmFܽ{Y_Gkuy u%J%Tb1O (c%jʰ\.G'HPդsilllp-Ӕ+h1p ⬮j5R4m,vkbՐJ&eeYlmm/]m5M%5z˲ZLoe3=v,nSڴMS/ ĠIAQx띧DI !I B41XHc<`]b˖;ݙY/fߏf}yCΐ6 $) :Ba:ʳ*BB! h4TG8-ݱc|x<VK.199I&QtJVcvv]*J%MGB04 }SS?~E.^J:v񒋋LNN277d$FJLk+ MR&QEuKh,5z.V n =4fi߭Ѯ[h펟m9NBn" hM L{??s4Z}a;v!ƏoR`۶RԊ1ao萄q6!'%s9ƋccW?:/UA^`qƷ^!L6wOtXY7 Yr7Z>F"rt|mm^4tWW8yO?S)6tj"L=OOkj>„v+t7H*uYʊ#b1E>z2<%q*bll|>M-? 4 uZ\R4H!."H_UO~b q[Lm+Zܨl菶}lhy wi֨_L1" -1z L 1hEئg)yKU|0J%XDn^G;Φ]r60|&S4o@JЭiL uxRXT K$5*yddZGtZ>ejqHZ.n5?|ض2S(T+$Lr-BiLj>m>k-J.RjU@(%S.PF-Qr*jJ1I_IF]TM!uCdB!ZZZشidrttt044T_ 7U@uDccct.I0d2<5LeXa~(BR[eQ yqk NЅpxdBt:Mkk+ tuu155eSuhS=c|lYDJ% -/L;K ,JֈŌ7G—K(z"lZʓ%2rDYq&\5]$`'W! ޫm/.s [r/+}Ihx;M$h}q37Q$N,7G19Xտ[^OŎq-dha Ilϰ\-Y` A+áE.L~`ˀl!iJQ4PE>?Ok;O>zkK`w,ˢ)&j7h-!CZ-4tymfRZ7|˖-b1mb* q$|S4\@TQT%+6ʨ QA2_50 ^뾈'\4<00\q*Eq){)A! ya \Ar^PK"Hg wNb @.DlC, 3";sqH|G{%_j[nm[aXY[($H&`֢ }e&6i\qmkRwh< ^"h. Ӕ8&pl=wI& = ꓜizΞ!;eۄ#=n5UJJezE8&G@z*ye@Jl6KTbii8|27o F $ɐ絧GO| 588:ոX,/Tku?3;3;Iڮش$4%PPky6#gr3}/bqq#' /0::ܼy3YpG".LIinnm۸'z9ξ-Ӥ)$MXTan#@"T!*f 39aÇphT-7<@y'hTVlh0vO6+*߽_o -G $Uƿp4^B:P(Ӄ8|pM4SbՊ<m=@} lX %XeV*ΚZ-3rdr zTNHw+7wTwܶ(D֭o9N_ceƆbW蛛9G"0 @ _)dP6u*^XJMكʱ#9aJ'DTb/r ˲fCQUiNb&ccckQ8---S4% db\HD*o VԑWNB*[B.G:챷CJ,ݡ;c^S TUWq~bmdR6@ QFyDlUasx Ռfr[ (-fYe(Fu7XMæ͆ r-j۶XgԸ<#ϡdUkK ?^o#e';WytKϭfUJ*'H ,R ]/ڛ8r_XX}庮7QXd̋:*jwyd|+%VmtwUUU)^*@ `H$*d2l*{{{%-RvwU*@vE*}u6눉[qpX1uvvJ:M؝ eX@2Tw@sffMӰ,;8mm5_ J.~HH .uªeLkuown+qE,3f)QAa?TZH`A!R˾PRELR rkwvݗK?ܽ_?^z_܂q>_ޞ?X ͗uT ,Bڵkilldbbcvy߽TrDz E3ԺFSh:C@J@S l&Qgc5Ի Dz 3N HMyі5&s& 㭩^+e.JPXT8>=˜N8|"ʅ}x<|w#'`}<jϺCu6tdsx}wAg'~dś`2]ahhrVLFu:`AEgh9ij*!n.76g$њq7(\X P(q͕9޽EΊζmjkk@8;ȞߜQu4)1/kf{č}- K`#2p*גEHY~=tڝ HvS(!<0$IՍ.qSwf'#ɏ7[9 NyimmZ+xu6+NMMX,Foo/>-3OE*"dذa U`[6̾ wUMLrv$$Ihemnؠg)Gc1lxyFF)禱Oq˕vD{ .M'Qd-8ku%_{!gi~DD!hAgL}OO?2I9,3Tya)_pB"k!{K N`+7 5[ȮLS)g4Fr9Mh*xES*/߫pn3 f27f=()tG4^`΃,WOXFGGw`j2YFϮ.f&w39ix4Or8u#+3]KbO$-]@l{ PmWGDLu7տd7i693 z9wlUZї.pg9x,&jeh %+K$$IAN!rGR8vV%˔)cD3\).)h~Ż&H/1<Ȇ9n8+QU*.S57X#.4F 4 1C%IDsh:(gHuUh;Q>Ըr)O#lQ☁mKUں?CAefU"&[38`k"eN|N L-xP*a-({IV7.nQ.f%Rª`Y* ~?ҪPX9zzzb.D"A2 H099I$!;bȶ,=y4{.w0P(K^;*)nyuX*raA,D$gOFDWVV{@WEs0Lƭqb'*I T]lSu=ʶv]KB܄q0&Dn >Dׅ^,ި^ T$JB6`iVR:֞Njɸosz?4A ˷F)EADaE1Exl6KXP(q74`JRC$y2L0˱>n\:bwK86mbikwؿA& Rw8w2 ٶm;?b>ΐ|vwCd"rG KVUfsM(4wdZGE ɺM/kM$Jxu)gm> }kqO@~ejly=^g.[l3ʜ,Lfw#:YIUhy1v>o(%"H6e4 nU0W{00ܛdVžI -M&^ Qkخ\ق+xedB"{+ecs:d3q{M -HYxK{9>؁ڶͩwg?˲ p8⺴#MSP_p2Π'QT\X R*[apoa! w c[-nMO#2t:Hgk., 3 ?(@Ӯ( ]'? GaDPW7IG "Do5M z]ץy Qp$l!Uu]fff$B@"``` !!ED!V쳉%RJrp H@ DpH&Tf2ł=:"W|o\`~mcMs0N1gl&Z,bdϏe?3tvm%q0Fc !bI.x0$.&WM4#Ā k f٬]m1t0}&'3=<_vq%\G׍@QCQ]m.f Oزba!pf:F56(ȷz=Dްj,ة)Jt:RsssJ%á eW2|+_Ƌ__ 1f[3 y޹xmPR*( $ 677eEϽD .^9]Џxb15jN9ƭNpS$+> -Z Pkh/A:Ez \a<2+V3l.~|wY]'gyD4`@i,7 ֻ.ɈF?6k{Z LZnN13Wr}r`Qd$jhA^h]xA˗Fy_B@ \.GVv?9 p~T].1btu=~օyR\Kq0<߈0o7=ܫ h;1<fSҨ"d0Jyۏa>Khң0)4zt#f@@DLs2Bd6lhZ`2E"t+AvIH"f^LlL`",]sCTe fW왂h槹J+)1}}V;Q}5z:J3–yO'`-qw>O|SW4>I'6c{,./iEu/ȒAP*]F]Nrirȑ0жm:NInн6@KZj5,ˢX,bfhY p::^2ĩnCq$Ъ( h2LO6ާ Nrӻ,1Q0$GY67 TOed2IɶْݲnVuE,z/^zoJOz)=[PR,R,?[lv$N2<|M$fyy^C׷/|AwZ]갲7ܻ/ /vuKo6MJw`ee%imZ^N._83-sا.1W:FގgG֙%f%dq6mHG>$ 3 %ISR([R>!s7b#]֑#L8!3GMU5X]E8aOq4LL52-ow-^xq/b_ǯH(|@m0|sbV :=xk-)֧>%Nhh R K褔sJIWw(f X vSm@@fEy!<,c w/y֫/ 4s1s]<z{B+ߒ aA;LgX zx'JHDRH4{&P)b=/y1N?zc1]IX5&O%4~2Y DA 3fF u.Lҿ5":0& a& HP$zO QѾaa99 0F+KCP.j:Z@2,@E :(&ڎ۔<H) XVmb:iM$̜g6[Z&S(aWtGv-W$&@qb HpӑG0l v,fffzeŠ1MӤuHX?7"_1GW\xtOl\E!^z 1CȀ6Hm7bFH \] m&.wN 7X}zTVsDzj>~7/~8FU#V;I<iO;8LO}Cp,O.2ӗ8}EIW gxS",ʴ?Vx)dJa!2t]./Wʊ Sd`Dm{"_~ f/+>Y3)j*O"&쀕^_`+Lqb *5 I/A&zǶ4=NͦA.$AOA"67tlx!Kqt$jNZ:Uc,CKMv )#X5 pϞí&`nuҍ&]]DzMI)-ecɚ“#1'A7T^mØeRi+ CW)V932F|>/z.3M'|BW"CMeNY p,2) 6YQƤ(qܼy]e,;44$l)gn ,ˆ>YXX`ddR%y4bQxO(Ejݻw1Mj*Can[na۶l!(Z8CdmՏm>?뺬&G9B'T_hU3ٿIlk"D bR-TB E[> &A"TU)*0R)H&Mn&\fo\s}1]jQy_t̓>ͮۮ% !ID^4FITHjT]ZضM:"x4 cccT*$Dѣ<{Io|J$ lڅY}z>y82tW^>Ѕ6r ٷoxL&q4wvrIG̭[G(x+J@G~՛iEyd=)A--_h6"j'1SY [FJBIqzLȀ[ :N7ѕ8wmf6Pj^]Gh`A, h$,Z{!?i\x0πq qh#Ul:/|t>\&b&165,#K,Gt㘞M[)īkβƤc?V&oa6[)|+ALyY[wBP C(M3QdbwNo.dWW4E5iNV-lV ===133\.T #ߐIZytww355.qi#!^h\;od'X G uQ6Z{DuR^b ACV -@p$‣861/ aM0H5k]ph{<{qmQgCJ1fTRrrt:Pa!r@P`'p4ǛfTy" ݹ@P5FY7$M-ג&jd2LlpbRQe ۫tVS%8jA^:{qqQ1Q$]iZ[[YZZR{)Z9@鞌՗T{oYe* :::bgbbb5T]Tec:ںhKR&B)yWJB7B]EAadMԅF Z`".:˴:q{{ss^ޯ?﯊\~V/"{1Oy4=|l.^ <\HK[_LSR_,(IQ >,ɠ*bd2IRaee)# G|8S<˔6".F\̏|(T.TMhu3Nv#m"jb$"AAbk(V!xbS7im|Ό'0z}y^]e—/hc/FPA "U,d@ m4 s$ )Irom)aj;v UULNN\Ŷm\eG9i]6w(YB01>nu,;_>[Y%i3XFK'8tdßbzzuscTbnn4M8ʼndbbg61110OptRlpBDآeFJ7bk)jf Aa:V/ X^QAd S` 3ge Q{{9>(b-:K5! BA0Ca ~AMv~zmSk_]#|8#iXx;Y( 1 ! [A7 Ә't՘-cUC o.+Li(P57937Sqü v"ζђ`xMw~c P{Qߒ%ͦRH=9l&7I$Ji4a]VV,7ɠ)gHS\. b|i|˼zGFܻ6I Af5P3MTD\CTM$ZdA ,i h@%# `k"cEHaK|ġĹZ2HL$s%"R.LTSJy_JɄȢeكNB.G,Wu.]h\{!ޚpor%%vۨEC)$DAd=x(TV*mY[1Xe[bӠh43mX cnL]b3h%Q0u5:6ӮϚguN8TR?Nٳlll.aܙ xǧϩ[H(t(JjKt8`맍araܽDp- #wG!]Nd@E+VP4J۹칑( Jjf TBoVKY%uPT!G344S&ީSs'UbEEW T]h[e=';mӬ]MF-10&(@ABWӡ^+We~ RWIfi6o޷[.sx-„0tQ0b]_ЭDR3`lVE:GY$cE.,TeT266_J6籺B\%NS*XXX݋b077G.cffD.0fHvx&Yˠw81 >(G_@nGq&_O?ŋT*ضMP;sb9<f^xY\\T*NֳfԔT F'HŤB*! 6IJހ)lL*I˓<כ` .0 X)rYH1yCsy((\>҆>ΰ"H+ֿ~JU.)M;G~32Fh-Br(5#It#>[]8"OF$S^dvb]"~E3X*ZCi@ okCفm9vL"O-u8|~AKewO/|˙7(_ܽZ8x\.g d2y|ߧZZ67hxAu[ f6ka3ɐH&0^;9b`w(FvI120"쐞A>>"%5Dv'Xq̆+GLQe+DrW4&-gJtr+W5J+Z Ve"QP) @BbA,ntdA 1 *LTETʀ(T)v&sw 5ly}O %,mF(z1! h B㈻_ePr"KufY eB!ÊU -%(fH"0 cD܀sB=Djy h u ̥K!R*x_=ms 쌷U3QtO=`=vRhOfGJJmim l]Z`ƮxȄE E;á+oK u3dtAd@RD 'D KGEs ^{ +"t }>f6µ" ]DkS;=!r_f> p?>R@qt#NVfBGܺujiZ2>> !h4 `zZRjRFa잙ѻDP: T*ϓNȤSrLݻܼySUYXXnNyK6|^#jCvxK>fHR0ʉP12 CTO[Uo&$i&vC.Fn,-tQ bܔ"(UnܸRD7.eHv)vf2$&y}&<޽s ŏa`[6Q xoYr7R/y7j!_LLLJTd&L oXfevvVV% uD>N\emmGf\.2 #޸teh}i34mS9T̃V^ןQns]Ldyy^eYzjOx+y{M8}^ Ý䂔~&u4M$hT*)0 mZM 5INSdhGRp~[6ጧs%  űac1uEiƞ#^J!AP..^$ z=ВFW33ᵆͩn >p:_ĭۦ5-G}HAAgx&F 3)DV"tz5x5#&4tVN>VD9]5 <.ܼEvζjj2AG:8 4JGuJSeT/ouдʛW곳t 8w; 6BSJF*8 Oʵ0 󘞚 rOL ,--ɛ7M666O.Q q8^1jNC֭[,,,8d@&ZR*V^IDMRa'vlž*e$jU5!K/)MRIc ꬨ2o@~_)u\oE?xxMHM8J@/T'wD N q q"R{!nIŁpرYz {}]},fv/P=#\L$ OjMRTM |&C(MSEHɥȄL KUkkk\ %V?䏳-^No$s^>6<⋯ony~xqct=8֐'1g:싱K~'*{yet sVP`@q2`BҾ0Hdbp^vnUG=,$FVʠeP+֬M 1C.Ȅ]i!YKVck x1>n0 q:?wx)ූM A{k54lX#N5Bih0^Q)6麮*oB)!Rŧp\P0 Y焽s|OD,R+++T* 2ApttԔ@,Ԣ'VIWkGCB2\B[?(#~c$CSPtRLԼbčbĔj?IfzuB}F5R y:1 NI|gM81L1ZN'CA#aMa#*+~yIDB>B>'ާVp-,_۸5욝iF`\tTwBԥI 4`Bpnz gҳDd+/-,6:^>Fm3z5O55LcwidދIʹhwwWwOI]RgvmV99iHb@W~8alo~):B0 Ն+3Is.#qԡhP.},qQgaaJYGRo#[oNj,&MignꀵntAAw•kYfp!BGP>] ֙vl;&&$s.<_28^ɈTǭ Jڠ$o up 4iZzLSAf*MTy;IKﳱ$p Iz!rYVf7[MNNNۻ~Rq/pwzU!p|ѐZCn6L^X ޸v.Cu]t:6==fi >,OLNNj|ާh!1iH+7J_=1Ck?8}x+-}X?Ct?B Cwz=ƒF&!I8VsC3Bgix>÷_<:$cYMY}(͑:ř[̀J~Ŋt/ՁG <iE(lNXtz7\}V]:Բc2{i/k7h\"|3[֬VYXXk)ƨ=M׮3elC !9;H,\i0fHv', q !AG Lm|@VNvd2=%ρľ\RRt$ʐ@eeV3_?sB6fّJ0C9>3N&z0:c@SޡGf~ ؓ$ȍcg>XY<ЕYXiױ~Piq)e NYïmwE:qV{\Vq>Gw 2M#?,hJ5sU ")_4 *"өQm,//kh{ssSwbQΝ3,4bijZRqQ5hP*Mg&qL>qmS\8::ld2Sruα僡(uft-M)&i((\? _sDt>5{+Kcj Swқ;KlSv(XŹ?U1g^ Ą@UY%?77ᡨ2j}@3g 4Et]׾qhņ "0t:rȬ.Q"+FWx|vĂM$$Aܝ`/ѿԉ/cwzm 0$@ pvrKt^e`ҋ$=aQz]JArb%ʔ}td0?Dd0"9!P#jv$7@)h Փ o%J \Skb%V!h;ȟ~r K%H} 4.'\*K0C0Jvē%Lug8DhJr^TrH#HZ!d'-4\*hN8>-BZ4~۷Qia)$e4]|G8,m2w4 qFڿPPFeE+++➳{&вk׮.333S0>?-ϧvuYZZ jT*\.{+ڙ߃gv{k|rll\_\Me3d;nlՃ+" (H+"GɃ ⡂ =H)<ً i튥.4dMvl23;ﻫ9̼3G*h(^AJߙp^zEm(f;O9N6]`oTc4)1'sUO.O\^z?7ǟk*ogaYj<tq]&qsj5,7n) DQDXR(TqW<5UutRSrd)`8C,s?/#K)S V'0 ՔYaE i7fؗlvaqOi-sf$ARa˟SD #Ak^(_&4FAq<< YDcL'Cb첣QDVD*b$8J>H y W.X-Cڒ}LI>?R)RfLNGcjq@irE~hgc nfةxx!wk̳CfQ尞Zc1$d^ҮXWJ1%?UrSQZ=]U r[XX>JѦVkضMP`mmMyPUHivHuJ}?t:|ye.|??TߋU?w~en~mn neA,BEעOZ k?'a(>o"O>V)EYQvuKVlMl̏;>ܹ1oɐd!sX: 5#Qp=éz4C3h5OTШEqH5͔FAZX,b'L+++0 Sjjf:33e666Ss>RI*R2X]]… |4.EᏞ18clC\ 'M;Ornfyy9FlnnfkkF`~A$nvYVr}M)Ӌd24B=ömJ"ᔞ$b*ٖE]E@Z+< X[[K%|>O^O0j5jAn=r5HYΦllf8<}ZRJ=uýn߾?YX(L MHO8 a1RDz{{{,--ToUw^~̌mi;IQ RŪ*!fł= JH@jibMԱ<ŝ;IfiY==w,)32$m?Tw m39fpjNMO @o Ԉaa>n圔l6KUR( llltr@X˸<Ƚ `eegϞNj3m׮qE:=vx4Oskœc* X{|$Iަhluu5GD?~k"h @0S@*gp=O\eYke/' d3z,'JZuc᫄YQK+`?nUzոNp M9`8S*N +fw냄?)QgH:l!:BąœG_S/,>z~^Oem*a983JK<Hr%~lΕ@r]=17bU$'vE1w_[4ݔ oP)H:x`jOqLsZz\Z˔.ﳱ(#L9in+mf2r}Zf\l99JgFxBᤉVvBK7Ѿ=:ΐ(({dnY~:r9/tvwws>\oUofYy/.o;h,ys= ,4ga4BPt̼V6e\.$ZV G0j=fs_ Gr )S" &BF4I >0؆CEAJ!LFQ4`$>Ju;`l'|OX^c+Y82#.͵LoRBj#DaƣAܻ^0(C0|0r,y2b5o1כ /0\?TZb}ښ&|ommi{_Lke]TAmjp]R{Pby&kkk Q*^OBm5a1ӬnkNj:[;\G}Wb*VEq6[kg,Kun!CY-0܎ &T&_ћ= u3@0p{Q613=+ ⅓K_ cBk7Hko'j0bxkLl{/i"1u0 Q@0Llx=tJe./G̋]t;!gjdfS9fȯ^P)_p?o^㭫%.i[:=oFO^L3ۗiZ\gjﳵv-2HvGjuVVVTѐf\%* NG^Z@p.S dN!L$YlR0L!>Hp>=7Ӕc MGNbbý"`ӏF0}Ogjʝ+w%\UWW+B'wewUs(EBSd?1 Ec8WԌG 2*-q,&hn1L"5~ڍu:HAL;xg1f:xt)q5/V` } `>5p@w8`,vV`G)N~zea͓ň?˓˲+TMoU8ډ$PhA|-MD=[$/@%H )TTj76@Qpi];q{fs]Kx1e͝sMI)M @ۦlλ4?oZV@y<4kŀT3bb0e;k@_SK)aaXᐃr 6}:^-dcgg\.mKRD6N|tOL`6灊NT9Mp2btGA;YL.YɅf-prH~ԓs1Aen:XaKFo.NYe!a77g޷!Ezʐ,fqwH,t)-ˢT*a6T*^6K sx?m3Rr]WW4 677W @D=5cz5jrk%db~Yɕj'sƿF}J`:a&y,B%%$QaJS`l㪀yϓc4p]$ePO"q7;-(/i(X"7+"xȸI`q6qh"#g.~.Kɋg2sG/_H ^$'P#~Tel kA 8Xak\Y9&vL{(ӂG795cY4ӣY.X,Nu]d1I ZI֤L>w,Rv hhplbx¢("HVtNV&  !+hB$1# =ݘͫEQʊeTpy._l ,H)QD&|xt"\?lU?v4P(.E%*TDQ%D%Pԭ X*X:Ub(PQj6(m&qKm眜޽goIg{t3^RF]݌ 5& E Ml.c/hc7FB&''-t>^ST,,..Z`2+++ܺu u6e!@,,,>J):kҒ&zn۴Z-[[[\8{c^+rUz|y Ǒ?|/?n_0 \RhiggG8=8\$`vgJE)l ^,'L'I/a$8sT!K:$*3(18}xPV3ItSaZos'V\}p߽c̫ۜwM<ϧ |b]W,9WVRcENt3>៝_W:AP*R.[!|>RJ=zDPQ1_! "#1g)&Դ Õ1ä;zrxq(23,StaIDAT{4i}A;{:[G'WL޳CSJȞ^ D34̱.yì ɾ9C@nӂUiLDHӉ!N#HEʱ>{jVAvoml9Q5/-<?l 3{ء#UGAǕcRޣihzKW4M6NmԔ5&lz}. ?%4gHȜ*y<8wuuն;gpj3?(V;I)!V6H43Fog:)Sm8Fd8mZAlڹyGhY[66 6D쨔'4*7vf4M d(& EU<?wQ(d= )WRF n=KTfx,E$ t`(ER Ό:B`f*No)+uB$SpBw #d2E"i ]JވjϞr<eAFT'|<%PS!&fjTy}}A @; ڃx' O>ĥ=TbZyû߽7od)%;;;GAV~a|er6rsSL5F GM)h cw>i;fyyY}b䇇xG٤VJ닢:.//n~ͱI 7d@s7s}u.\`'Æ.KKKTU4ji8} Rp'(e#mxX\͋e?LMf,[4Q,-ŋ zRŋ7MEhPmQD,꡻$m&Oсddf=ŔA:ے hdl$iO9۬JHDv~@ 2uLvsNkXl̳=Zrt]Çlmm V2ZRDE@}O]׹~:;;;h&F`@*\tImloo!s2/b\?.'r q<&STfU$fL,V8Slhx5 ҉xuY? I;'*7= Izc h#V0 m}jYla̙rHoaGcW40;#yt<9YcfCж"R?{s } ϛވ bx܊ N[L)HÉrT3e >ňbWCaY4GcLⵕ]ՖO"kT888`"/?=dk'}.M!G'_EaCFWW/^sԸwn~_1U?x,{wC|ߧn+hnFZժJ)ǤZB]MfY7Ѐ`YJYF=z)ki#V9OE1Ju^Z*g. :wwwiݿaU$հIBHMvҀ8݌$EdZFIch%.GL `H$E"(SG+]@s?<.>TG}uq;"[j c8EK* $iu(qT :zOoqj3| &"PX3\n?09[7ŒAAh5k,0b'v|:l2xqyF#KǓN+.'n}Q;k۹ߺ<͟/ B4ۣ\.sM\ڛg&c1MOo>{,RkkkxNj_O^P02\\\w`J1cai)dGƒfCԅ{-q6)o= )h lbBԉ32|įDy/ct#}OgqY=6e,O'9@v^}a6yHI蕒I.eB J "D ?HV+GKˁE kNrBG"T!0ݎ8HTؿKVKcg(*!Ye9ӵQ'{4kk-=W߮p '1*\g#)?tied۶Du]7!dS; d^%HT;{۶a$oHb.\Hj5"7nu DZFo-CQXXX,vwwiہ#O5w|%+O|f}keh١鰺JZEUU~<~>=[g|v̘{W,Wji u\:= ?3(%/T Egj7Q^xvy!3㑿|K̢W|BNd~z-u'g'm8=xi6$Wss}b\ⴇJA'1#F8e(ݿ+#bZ^9l5[MHdiv`UѸ4dlL8n6X%(3q^Rn;)eLZEKXrtd8994M{7߿c|A UU) |Ƿ_͑4 eXj;Aa)Tn1`\ˠ(*&DP5]q(6 IPQ 5LSt1wz.4]HV]me|S"!~H0zl0c<q2t#m̈&u#R /)F_AFŁzH&Ţ@h `>׹`srv+Ѹ!MEp<]'ހ^a{{˲+qTRmBJryFRzK0($|٤^5MR)$et b1oZzMD,,..R=z1⺎(aБBLQPuN#ZZ˲.ܥR)p'T$KOr?\MeLd6RZ q/EAQЃHAR=DϢI*BA UkXOtKl$d3_&&0}?7t]cYPY r^B2K~1Ydu.kC/juUzF=٘:FAp?ASY JӔnP>|U 9Hj:tFά[|Ќt)8|8$b87n ",:iaC9ܹԡYY md qdM !!,d퐍^4Kwa퐸F/ q)׉T_&In7+ˢ>.=Q4|7g柢p& MQQjDBbO2nN2bXh0ov*T%?vmݐ^'N[p{ }ʱos9&)<{ǜuO?IKf0L0M/^˹ϥb}mmm}xL$\vMAm#JpGFAן>ͳ/iB}2 |{ V=֗3:ZKp9\lG@1Wrn*2\^HL H I?R(lzY֖g ~BwP",W .t1nefi0hK5N17hV"Khq+Wy{c-2,(ij)@B=29-Ñm 1I0Y]]%MS\qUef mjJ0 m<ϣH˲T*1+iI$Q(bOy^9z>yHD)4>Y ߵZ-%o,w7Pnl͋#UT]I:I?Aو AtJDdеڝΝA¸A(8t:$tL}{IRw{]hIǙ $ϲt儣iD"Ie!JrG;~M>""F.j5`~nVvvMd>stt+rSV$QOHԭx{޽^eopU-ڛ|KO?|>z?GmyreiJ.WQ`0`}},mBrRK"3̂E%hZ(E"r6m{ },bLu\TrKR ״`2ŗ OabQ zQX`~OÇ.EP# W&mfjOۻ_R D!*/>ɓ@q֥CŅd2e^~`Vb /3W'<[Lv&LZ)/n]O]OU>.ZE<9[[[|ILM^Ocá:A `zcggglPɔNNt:[[|ǠU{hSC 6!WNpӅM!B}FW%&gCAS 4l+y źfb )vS]lcL0'z,i `FHV⛅\ja`D-0:Dx=Bh ƘhiFm+<{:la GfXG9le%t(S,9 аRf`@lvoPn>R$QwT5#'iY#Aԕٶ-']'inKu$a0yPv융5{S*(Y ;>>i4 YV4.f0|rLA kス=...N&"UߚL& t,;?YE,ys!|df=9{\U^6„J@6"v~݌ǡ^jS؆^6!DO$c4[-o4899A Xua6ժjo*n ?`Uoy4Qo|DI0(x#҇3jo%'yM!Zf4 zLΠ#(`1 J/&I,cWhnYyQe^X@fՇjwCQ T)yV|ۨlj1w)n X2[a` N`1 $pC26_:&Fih $J.)yL٤|HbD5Ja*6Nagv-ޡ t o'hh(uJ2~k q& BL& !P|t t:BN}u<qyy tDmYhqԀje ;J8 ^H{\LhO k?i_2$=Nߋ6ݧ_0 G?[0aSYyDk0tZ Yj@T9SxLb3ED8%SP3 oJX[[ 3~A<4 #Z-qJƹ51UUSt;U>qppBu]+∢(bʠX,BuS3:UƆ@_*!9NϤ3h]\fRGmJ2|㣝Fq0dMoUόdw@=I  U PV$ؠn"CvHK6H|,@@DE"! $h'=3w #Y¶s{scL*0R )pP}FPIv*gKR! dGT9qu]tZK@6X\\T:=-lv\N341MBWX__X,b&z]e4 ֨T*\)Í]N/ti: pƀLLJ,x|gW5 Y;ǣ6<\3g^QP2ʻi6ضMRȿgc _>d8A E \9 ,oRQ'i1O c~eX)` 5~k6q.<]cZŘV(4?`嗈Hp}#hq R/^w/s`Dr u{G>ĺiLfnQlaVPـ)l 6=&gb~X}o`&n5c3SfJ.+PáYj4 I;wo7664"055 Qq||LA$qG<Ѽg#G&ϒ15;OmfC>yx3Vw6UߗTכO؂qfrCl[npo4Hg<Mݦj.t]|O ~THW3k`DiHagy:c~*gN9Nah_۬I7Lױ",HT=H&Ͼ%(-,vG35zJ\UcPUA=e$ycL$Ijo}̃$aNbS !tBGf !fAaD1F ]!I Y,,Hҷ?]g"&t݂:]T;|!4L%=WvjZ@T$ek&ſ4ʣRb3%lraw!_06i|>~%]4uvv T!MSqzthWbrhZhy0pttX\ \'ͪY۶YYYaqqNOO%^A0 udggF{EU|Y7!4t9WY_\\h$!ulmma&nW7%`@oppp@4 lKh#u?L2&M%}vܓ=(xro{YuMJ9lˤiB߰C~#2S0 "5 V)h>zE8==e}}]Y^^씓 -AR}ߧVgg/йɓ'<|)Քb\17_3c{BQʽje%yNJ%%hܔzQrc% rU wss h߻t`biS(+BV[%UXrLM68vtNJ, -neȒehSF{t\ Yv0M㟜 ucF#i!/,&5[J@-! t;Df3.LV"!WR{m^w }:x83S2Qh4n>VY<|:k^!I~q133C^0i4jt`Y0 L'ٔPc #bJ&{~u8=@ <0OU8< ]/m$^El߿|%? n r_VFɳ tKv[?@2=>$tLW#/` 0VD+ĈNy *"_ E_*-L3pEMS<08lŹ{❻*ly(b-H"H"=R(*nE^*epJoLK zʧ{b]fSQ%w_RX+ CB8Is8@RCfggG\vͦV2 nU!מI%=z-UQEB]v:%$'0^JQrq(JKR] 3l@2M,<%ldY*#p%ŲV:\MoUƎġi j#,ТRW,`ذ-5A ,EM$dHTQB!q3wލf48XH)Q&yN ?,|$:y'$D"؜4! '$dҊ0H#d1z=9??S})VEPVqpp뛴Z-S7qe8& C"ŖeVWksW~g)uNY;ڴi#ZW vB쏻ery0T F\V1RQ'Wt^v,F7yϒj%4thׅtA\L oΩxOx&(}h >nzhxʲc^p8ha͘:}oP*vQo^ga :F>s׹m@0SjiOO薨ޝ3L?e Nzq텈eDըÆ)n4sfƃռGYtZ#jND8tL&S*T*b>y_Qfܹ}bO6$;_4A(=rȧ:dFDъy"Fױ8ǰ4>Fdϯi`dO.IrĽ' Mt E"!?[,N`_ lB-gay7'AS2Ca=9;ML$(y׽APbώ}47 &`<( Ŧxh"V;lJ^/@fȵb J: Y7!4(XU("-2>t}ȃ{oaN"r(, uV%e> u˳Cii2<Һ`0 i6AVc<DRhI]֖<]6v[Iá0MVEg}}T$}xggGJt.t]qp8f cID@Fj\VVVɐydoT~ďigCCv*!X(b $6l١HK$FAwc FBHTjTmRI;c89;njXAr,:i~qIm w61#w9X(" Ct]X\T*hy\ L&>.^Y[[pi*aH\f0 4 ...,V"akkt!nMToh4鰹W?RP,׷&:RțxY4]1ÜZ{m\VE^nz>o?Gi6%'fə:<Ԣ)RŚ /8WW0_t3,1T'Y"!FNX2X&fnʟ,~ǡ\ d{ew$ @xA0W։z.SFT&^Q$kN"`mv#!j>d2xjO<Xeەd8::JŜ'{{{PTK߇nYJÓ*U+4 P3iDNhBl#nnS0R4+$ϟ; $U)Y o4B/xe K> lXdɂ/ 3+X*RԩԦy;vl&ŻHvZ-F;N<5eZ E] ]%^pLYiDq)JJ9.j:DQVh4qpp@a<n9>>ֈ^&Ph{{[6%8b`U.{{{AёN|>gS+O޻QsJ£ '>_?oyK3kRdGqÐ|ƋJ-`aQЏm"TAfj<IY%\*7R#X J9<Pܓ| ΒyHF5F8")3_s$@(JWs}QŶۅ!P}aܫSD|yqPGǰ(Lu\@RƱ$&%w|0baQ9Ijp1每ZPK*"dIK0 uyeS,/2jΎLnooFrzrBL̈́\z:@d^ZX__V/ggglllh.//ىq<׍' p!`Odk#u?3d2.+͡/ ^g?eq" y)[ɜ]׾C$k~&ё>Q{ߗ'MSQS5~M6='ma%ԯ O~B5}ɃZ 7 iPFElV kEFnh@)XDret2Rبe]+ E2N[kL$C_׫2{2J6+r\VBЗAD\PdA~z *ZJr?4@^^nΠZн=.// h4zB,z=Z'''t:...t0{Z-7| 8<n 9zm0&3e.NJxT0)ZvͶlT| I4'< L rp| z 'dL_0zwc!,bRJ>qf kO,YOXI78XNEfLF\q1Ϊt,wHoזv px;:.ﭮ`e^1+9$1]b\cySԜ1c.ZzF:< Vp6Qqpp5nzmӟ ^\ԫOu2:}>oW2[Y,L"R' }u~gc]61D+;.DV D|O..{NqMԟ[h %+ p*bCyR.OPB~>T(X7BsXPW-9Pp^6 -ިJ5CQc2{"jyq<ǰ[EaɻRnϽmJUr`i4J`adfO&J+h?Ov Ðpt)y427u8 Mͦ^}FAԧSl֜@GqEi_A;;;iUCj!A0 tcSApr ]t }cy>*KeGCEGD$I4G?lOh#U?2d&iiHnP\$"ˊe/zAo<  R Enbf7i4L͌}d!3}ٚ OČ4{Ikz=x3q+aL4NGQCEJ% S(hZf^qNC65H7Z.//Li}aff!{{]Ch,.."`X4lI$}.^/8 ͛7 S=_|EZh^ʶp׳gH8L(WTv@>/\AuBLY:gfG?دVUYsz#=8V739@Aȯ;4Je ,LrIvZ-666L\.g|>OZEJI͏V(\ٗ^ڏ?Tux**JZF.;g/FC(.-a wèÝD c9jR'*`rmRW&o\ot%x*4˃IWSd/ N51#8e^.c|.#A|d{)z WI$4>Qᣞ M jJZ̍F6r'R(V٣ÚV az#T{XШ -?~m G6Bm[M@4TܡPe 0{d,7`h[C@5U&ix]͙6^.~{kkyXiJףl],%ԩC8* N2t$w ?>88\.399I^lrus~V3߸.`&()^k&ft{Vr6F~!a;u>p$# QU狼~3Uާ|2IPjNןf'?sY)˰zcwRH O| HS:37I2wauK?YN6$82# :AaI0)a护^X%#';ۜD5P+zA| XK+:Oz\A"_XObA6BٮG:rSL l,Ԛ# Ӧ ߱1{t&&0gk֗%z~vM% s{{J|۱mM}C.vyh%ak2=$R(Ty˜tm$DӐbz4xO1KiFo\{ Hr?x5CMvLMf\a8 (JT6HFA3it *Ypg)Li!$ & e\qsR3 Ǐban2HHd@d'(NFHHχ sF&6f^#r9m!OLL°L3D:iNsS4+<+0˒,NF#ժ*i}_H$Et//qJyض'D=S}!Uh6St:*gCrlS̢,Ki9P߾}[pRWJ$5c%\a\:5T{- _dMh#eL2|5Gt-[SVP("xœOD^W=UdKuقMk$f̗7@>f 3|GI0 999Qq. e 5g!y`yr3b1Ryb\H,kDEe)+ ຮ+H0m۬Mσ*nCj$ Z*ehZ2`0l2'UVJp8W9O`YH%l^Wd,Άٶŭo_'H[?p_~Bc/KԊ5.qfⵚG$z=GdCWMC(ώaWorѵaGVz,uL. zzn[lل]/ ~0 X^Y{ 2vوKŒg>S$Bu)}@bXRI/k`$H'SWx@d8> D窤2B XJDzag;?ceY ϳ:;;;ʊR2[i>EyPm 0QQVRF#`;\W{ \H՜C~v$ KPd}bD$gx!z.TÖ`+sY<{qDKy0JBLO^T*$A$ ơRr]0fNH cA(DG==?.M u"S7oT%@0MC&;b!d]PTb"3] ߂k?DzcAG !A3FpC0 ( :T6]z=\ץR(滷ٿ1:|ի*>{۶atznn#fggh\ q-EB)n-Ţv lI=@4M_^^f4QvJ /3ui'5MV)P^Qڧ'HaDI|^Xtk#u?4I6&}q-Ukְ n] a*MVŋ'aAOAa{PA,V"eӦ4I$/_f+昐0Ly} 7#L$L*Z $! yLeqTs: H"u]$x4MѨD(JL ͊}F s.\9i4d22 Z-"2S0 uSR),Ra(H$㰾NVcffl6$&|]d#'Dž\n&0|(S-lEzX<~(yzz7_V2A}?\;?|\ amwCڹ.)= ] 軐yLk[/vGc㐌pr+h ] ;zCo7JP qMPbC*ZG 1CԜD/am(`0-nlnxA8GxPJ@ 4A_4,x_|}0oNi1Xxn8ĝVG:"4ip=;OӡP(l6Ķmde%[Wvdn;p2r۶" rH$x]^p xp_r1ݣ~br)@/>0qEׂhu{mSm@i(:.b:HH,қ^}~Z'FS3ɀR}??5G<(`)hQT{ ɞ6a;|(HM,({E3 ]=>FdZ&x(%4?(g"/ ߔU'8R  N4zU'& &5wLܾFƶmJ3X,woS:ŒA~"ժUvlc#'[A4JB$I* B۶#k60 "HP8>>&N3??&ii+2VwubQr@6#<,K)~666T!uu²tt;zCPRQ輌PhTD/--qytMhe33ٍ;;|4%)4KAkx =[APV*xu$~AAJB@A M&&~쎇wDv]xI'9ʲW* ,xS6A@B<~$ьkR8۔ep]˲ݑeL6eeen8;<[& r6uo< eev,"R)*\vɘX8wa)<{A KfsWc|X9r!Z-VK6mY6xoi?sߙ~ }MC iP*`K7Dowsغ CE14ʆ8/v7ugD uiEjJ/ 4 pPA_Gi0ӭap.SrgR}w_']'D9y xYÇ.usR& )G [(R*w+,yqnZS(+ض+|yfV3/sO|3q,IX*ur)[Ԕʳ/}=_ ]V9-dϞΡO;49/U ^W$^k)w4+Yih}IXL;݋|(EQ3*# *ly ]r0D,r`'~zb3M@ܹ݄z(F!n_j"ٱ`&|e3btg;}@'jwı@^#qEMb jmtENzyf4y/|cu4 R(rt5ZbvKnGzɓL&i"y^b5^iyrfH 9D_˲pjyXEU)lk#U?L\&&IlV u׮+,Ȳ‚/"(D]QMP mhKKI4I9MS s}/ɪV4T*(~ 8 jLJH$J^TejoFp|diJ`Z*˲X,fI$T*ViLdooO-l*qjbQp7 kgYXXPNϼhM> >W_O>:bZ|Z|Y(?#*DCI#xwf{A<7`=Kaaw!T// 6] 6Sn_6?zr&#gA.cA&.% $9m/,1*0]UK?aviW~^v}rLHP%ԣϮ>0:YɢW4޾K )h۶+LcIl4dY Hܮ}gGҚ|&m=Oم[0RE3G2+>aiz#v `HS^'qIvvZHh6###[h]POCCCLMM133}Dv'BZ;>-B D#1E7򉢐N Tx?MƋX]]e}}q}_llldtVF"}5dYM ZF,//NV(6 %w%|nK.cssB@^'1::JE__$q @n9~ƥc-Q4Rh$ʦT*199ɵ6xi<ϣhyl5.tMoUɌ?$1u3 &X$.TEQab= b+ *V U0-i$Ǟdŝ{FlKc=;^5MOIRJ%@ |T1r= "/M~Rl48j@JC„Bp}l&"lVc RxrlMTWPfɍO.#_^ .Ysb#S୷g+:qL٤RQoST*1ǝ OP>"kF\mkd znd5^wl<3ɫ7#gܛ>jG¥1~dSX<~8\yE趆O;3y=-ct}5 {g1_=˵˕,;K.Q.Wh6`V1T"0.s?9|;KiZǬs>1~h`l!L/̈pE0p.ڇgSuonvoGGCN00]M*XbOB0@`k:Oؖު0ܵסِ|0)0rH\9Lo9.1bda$hu\J B~ hb'@dg%]8Mi=Nw[w[Cs^ FBAK KT}-<#G.ˢ||BzRgAb`8 Cl!D|oQ ⿾I`ρAɆ|roq o8GMZ&bIǵLI (fahFnLU[WURliSm;ПZeT"J^XXoWbPT$Z8)v*Rj8lllw]zdKT=lewǗs;+MB%JKD 10:  JT DCƉs޽v˒P#9{&G.G!NϺ t.9NhS#бH#SpGSuӱC8^zʇT|3]TgN*YO#z/)My^D(~ u匔Ox+wi_+[i`<Э/frß~Q+D/6{Ө5`'?uGIrNi}i>L~3sdۭT@Kh13(5nyVov X!a&SĶ^ ^O:,FC%sMӸ_`O &+cy.RKZT( RT}TǏSxkkk 66630B>}!xfr`HFqBR˟%VͫضR)̠v]y;8*d]V VfƘ< ]orqaD1q3xP"fZ$ v 9 sc.sĝd'~8] %x 2=_{{A ϸݍ.$^T<ܙ'~ ^/ui5C0p \]fa[ 8x&R|Fr0E?Dl#~#?&`R5#:M,7@N=*5e .cLQgf T36L؄Ъdl LRgHFXGIYtuZ&GNs @F9+:` 1@ Et\;SeɄ9vEH_vߚ6>V,7vcϧ7<{l5jvn+`yOuÛ6x̵4-mcYoe.%e68Nȍ M1O$H$j.h^뀴 /,..e4J%ǑuBP9}%Ο?eYrpp\%Koy{\}E\;Uycg~dw&K"DP!$@@  !4t !$D(h!)Dm lE?x(2xzƷlq=N߿w_\SZ/_ƶmsخqP @Fx̆/h8ƂRvh8ϭj_߻\lEmVc7yuF;Ӈ~w^iEׅrgG0_WkɟN*}<ò,ܹիWsfccrxkkkYz,_G5xxǛ>ge_bKdf׮]xG⣷uݮ{H'4M[ Y([> qXc&>' ;D(li>OIB?DJLQH[RN$<"utJF/p '1iJ| .jQ'/2*5fJS.ǐÉ~>r8qVv [ԉ_k œc% U'&>;_~_!>n421QV "FAuxTr(0d8ַr5ۋ]t[Lrt;}@YxNW`>/4GH~Q9“iFE>Qbadq D!Iq1PkjvA]pMB247yq (_qĿ3~SVC+Dұ:EgCǬRTgwhR6M|gH: YDќU$Ť+:G%(HbhZفpĻ L:\`?I?IWJRL\4X}n4!666x{X#~&oć7ǹr > ١(2>*[[/t|jc@ޣ2.H$h4&IGARaeeE !z]ͦYpĥKhf3FJ\MÓ۬K"+l׸{p]ә~do[U?Gbq$$ Bg$*&_ DH i*i8c;~\_a8Ͳt}ml]5HwI8UҠXF?LL쮆YAL<Ӭ:UP:h&--L3?(H)VWWޞ]=caAav0 y1APשVضM۷88/_>KKKJ%ӤhD4M~W[>mԮ`{wEJ1эOor>,9 %F^pJNƂŢ CAM8yRRaNY\H8? >E5'?kS/Pk#ՏP*ػ@&JfYYO.uͳNh!!iss(TW>NR8ĩ9FUɎUU_x97\ucF9rŦY#A4: ͕H)7fCL]?)HwI "νPUXf '壺1ϟ翵yJ،c Ĥ5Ț,T.RfLCág|3|GJ^nKsO !r1 P/F 4p39ܤK^mynS, u_ S@<J.@nC_OЫx=п4A._¯'tP[* u_9_ 6"Xf[a6&R $`]c # # /SD^c n e­Zxar:wennY^^,J !ٴ `Ћ[Y|Way Yw&WΕ4UedA3a&\Mv?]881k "<gRwbݢTh8UL:vvyC/ht1OwI, iQ>H(mI0P OaSy T;#E+viczBR mDG8B:TAĘY'k}Z.\4b6qL1*w$x )888r_l倷no`/}ks`L)e#JӠ!l<#L1uOH2?㟌Aj YJR|><DgM%"87Wm m!,`ww%,[Xm앰P벵El~e05u\q[;gQ)6TT?ƞ۳ ڰ $"J DI %C@4@ &B EDD)$dfY?兩gRL%[=sc꺁*jőu/gi`Z$@$I~L \eH)rdetAz$kkbu: `ggx^Ð^(]Svy`0 ^:s#q)+fS~n]gX3V;W.Ϙ:ҖS'>`ws8|/|[*.?~/ij9l-M(FAcP1^':X'N Eb4Q(6W#n ~̄_w8rO{e.n^9?S@Uf 9\ M$"mʐiF Ic4Mpk%5M,_tFmNvڱKк`wMxX1 L0N)c1[e`b!L|RY0I+kS mK~jx3X,yfe&8sL4Y B@2_|v ޻;7;䇯0jxsJ$Qbن+ƽheJ :eWAxPhSo8eLlrT.yn^uUDVv?5fvܙNOwFA>ƚrTsI` ^,(%ȱ)5 \03} ) X-dX0(/ԸC]SW@2rP`4սYTW)(@ӖYbK2:j"U0 ȈEZV)d'>-bT3ϝvGOB$e4 N͋2Gn/4 D |ѬHS(GcP1~9 Q ǼʈSǼM_G{TMق<"lf2䠭Li C,?`>hT*6!xW|h4jA~SEFM s# ^T8qbCQk}ϛy^!?_J[)4 2dou?f؎RMQ &EmD%#  ,с uBPJH W4! M؉sgl% w<͛7CE? E#zIWDfeON )I=4JXdBrl6j5:N<4M !ǐl6e>Eaaa!RHQ4"!$ RrJet(NJXYYaooz(r9 w~oN2:ѫ \O`OәQY^ wo_ZFBkii[ݷgH26׸|{Ky6bjR Cb]S$)bjpEW,NR}b4b` Ӊ B8LbpWQ;%0= Jɟw_ʋ4\>PSa'{C TH|ej=p cEwr8wQS(K G@$kG%{c^aIΐ?lv`4w=K^l6)JBvH;X=M._HF[6޻ގNsT=}Wf<^.8tj jkIy>1ش{`;h- Zj8:b1p4̤O>qG'@'WJ'1qhR )OO k b݀5)jc[1rat,t<(jds. #O!Lpc`΋XB̗]:n7ܸwiUF{q6=$kT i|Fژ(zO мkG('`*ȃ3uvjm!/ۿCUy;Y,ӇKQ-n<[a `YsT>NǡVa6EvwwFt:MѠ\.y1ol.i.K7|o(\䣢08{M~ I(8rjK !U1f۶%"_NbddDtWVVqWEMa 7K%hۜ9sFq}|ӲppeyɺNCc||\k:j|\*8p^&6779GrT?\k\U?=LҙLf&R(6 ]P܈Bݸ"BB.݌(hM&ܤ}sRܙ}I7c!+ a AI\Ei=]x'6v&<:廳U _?uN?$IgNe?U f`|O5q՗{|>u-Jvʟ.sՔ'${.I W4M[#D;4s1c9nl|ir7SƼ&aGJ{ԁB v3HճJ[f3+jF&ᾉB>{x@$ʈFw7a0^kfa~ ꁠ]r9C8##mUkm@~\O2 ! 6z.#nBсaYx!|.avvVW,PiUsYrEL g"> QOV.ܡV BL,l& =gmɢ$3Vب|: N3AחMDApHB@r]Aֆ(|@3UW~xhM0) ;…S9j=X1Z?C4dop=F"B4RfR%Ѻ# T(%]Hs 9=+;[P|3MkȒn,(CmND* 2 =r,𬔚gOB-:'Hb"YFtocHM^XGH,nG3Mm07w]N l(fQx}^oZ,..+߲XY.P05fffhz=Z+++z.ի\xӧONLOO/J$GawcjjB.^'Or)y7u.r퓔(qW\}M<! A@P)%()lhrrg ,UXn+?doec=q꺉kRAIP@*P)R6ly,HlY.Yfj PԖP*R*hBGvNσY,٣{瞣?}a1u/xs-:,R" Dծa]K;q0 *xgjjH$B֭[ PuBch9R{R011|tOu|>ubt2M&''|ZV O\&pktbu*{ +OL n~:o_~g_&8HIeZGD*9>UW5O5\~iZTl`F}O^W7{6I5h0{}RЮDM.jh*z]/-YsaltCT#0yc18Ln@Ⱥz AUبE4Mh65v{Ox_݋ vҨojNȨZ'VdTT!pGp\s8^>Ae$s!nn䢊3{,TZ7_Wn$\rvM>덷( dptIiR0 ޾7V'RLCVMyX9C'ehX\|a:kbل S .Eg͡4D{G g5aGűm  _(xX7 9R-WvʑtP!?_LZrBHg:k {8Ž(aBOV֤ F&B$IW7t+L  mBL pR&PmdQ(סp!¬w8B*x p& Zj%bx[Bï6Km}ւDBH|Ne >bu 0-q.h4$;bԓY[[^c׭VKoߦVQr,//K(JTܤh%D,?.mk\SNrk n\@vdDU~[Z"_L$~ز~ǡC*faaR$b!cXK|J\(^BaTke?}IvSY 6T⡡7A XPAzыԓEZQE#&1ikMv7fgfg3ϳw0<|=GC5 5jgI!BHQ뺌F#[#5< TqJb`B!BAy,--iZFz*,,,P(ܥ[1??ZndvlnnR*h49s~/}۶7'wAaTZ|ُ21&ř ML+T"1a{&܎)vO-< YBrqӶ =qϞ?Nd+VOɎ8ӱ*7 LWAOnfs}wWܳLro8݉"Y 9ȁ) rR9 p&pQ^ ` ƾ߱/CI9fM9x:KJ3m'xsj*O-Y@[bl'|*K;6VAL"_!A!d- ;Q&=.;j=8w~x WxU* z?]'({Tk`>W Vm Jj-WԷoߦJ[2Wk%.b1vvv?N+|cW;|n$"ܐE^LOOS*( j5r;(,//T&nC lMe|d$5nMk.xEੈGxbAAPPQZZJ{ҕ&4;$kf23fIWc0??Gto8LH|.&[BLDid9vx˓tz^bH*q Hi6 \Bv ]nmYZZ¶mRDVò$2 $a|qNV#N *쀽Co`0Y]]e}}VE^gggG.nfieYlnnR.c ,ɋ۬| 9^/w):ӘqC pY/F7½Mҙ l;VR!Yݧ?,<}PqbJ^*RvJ Ik?!P 4" BE*R❻ 9N,4PM|{.G/EkR#{~ 5H <ޖJuɰ3Yܛ-R%{6R19E)es-{S1y4(?6JƲԚGULO }t5*ڈ¦3ZDWBr1PS|c}ڥp]v`0qf!h6(BRZF1%4M >\jn/84G,g<]𔒉 ?i{p( WŰYq@L|Y-~7; ǭ cܘ! o¤?T}O9>͔hÞΤq^R6Y?_VF6y'Ճ* éFWMx:bpEjL*Kf$d#zFP2-xd &(/€?'oA$ɴ@hM+bOhB Ƹ}r )%C8Cq[XF<( cpw=NҞi#s\@&x@qfϥhJo4:{z~x\h,9rRij^FQ/8NI n{{;0a7 ZmO鸹\dFjCW%VXUUW^?s['~!aH̰eY.v/$SG/ z AZ嫿mV$dMedffR VzEDI^ER+Bh v˶vl7f|LfÛM1!y'3}pTp]76E+WMbB@Z-dYfbb""e0 IR3 VU!Iٌ۟""0LYx("dD.GkTe׸NX$`A}s.BaqQkΈ'ٹs'+++aϳL$ӷP|aJ|2s`2w8gW2S9S$[:-l%Es+qhKHBKՐ2p}OGp[ B1+I)kwP$$nE =RB )bwX SQu6 |lIH'us/ whU=b]樘x^h!ZFFu8^kRJXb+VFNQo`rf`acY-:%4ؓn+Lnv_.'% ၥiƝ .dg-WsFQFU69ݞ0%D [5T+x^ TaЇe1z~߸=قEA-bLwXk"mM5E9b]P {A.~o#b&n]V|lGӫ\E^6x%>:^ضmo?W_Ŷm* |ui4J8Ƕm8P(q\w0}d aff nmv"{%Hc\vzjl6KX$P.²{L$ ED 8+lpf:A4! dKlUglόۤMI'UBm VnXC +@.;6E J ^RWT!RU!%&M<'ǯaqg)4{Αi[#$N 5,GQ`aC-m'DhsneYuvv,1==K]׍&###ΒJ(lnn~sj\V?SN .! [ccc'QfffvT*9JoY[WuśGprWQS 3sU (>.4Q5TEjJ$ (FV@\>e]&s>gٴ#iɜKϗXjzl=,*A_FW[!-bpRO H_ ]"{V֬08'3}ߖ"gD#fw==/Hp CݎD2`sM` -K'3ׂߋITbdAx Y_Aiﰶ dt¤5hx29Tw} # .޼aXu﮼eY ibbQA@6A2 ii+t*v@䢁'k$>6LƏ7U[SrT"KJ1G(iڞ<^CޣCG!3ݶ{(f?ϕ>s 4r.z΋)Mcm!D?飱}q,o?tL!*M![,̂9m ׯ_۬>~ ~ƫv uG˃>l?B2A=%Հn'3#?EqD DAaM76~ /nM?]шxd-*@"APZb2A!2lW"ЀG퀠yﴝP0PNpTj"ڹH )ɱ2||N\/ǯ?Vjٳg|)h4q…XZ.#ώHs8DV111T^I#d6#|hh(õommlllP_yi8fJe\.ǹs瘙0X^^hf1Mǵ!Y]]V*7n] #\͋e??4 )% QfvFC|gy>̡7h0aJ hB!~}pıiwwopW7珽,ΏGz涠7;Bߐ+UQVH%u7}Ϣi,9Ayh[+ͻ5|-qDgNxDјō2P7C0 %E dG\rK!,I)@xb't/I)W?8=2_ ~b@_72tz:zx^'O KT٩g0*3 ;1i,=t`eHIA [F 9l]. ޵52 rAebhb&@Z»wI?gNK-Xnkl?1C>rYfMh4|AH$Kfyxbw=G*ٜM*i\$*{cj{=]]YYlEFЕtG vjܪ¸=ub#6 Loצշ=q0E agH>>IPI\Au,ЉLbN>(o>T6᷷^@#t͠3l/KP,E:iCցΧR^S)gɇ.'d N z]5~K}L-B*G\;QJ:ms!}2ymrΞ=Z"7.:vv6іi&/^?)%y6ݣnabg*hܺo&aPͱDTBP+ JqikH8ΔnܵO!$^0dke?Mfw'&-%ՂxQAz b`(lnnRThی2n|g"C29|pNGJW.'pi4K-iɽZ- [nㅷW(ykslfo#T 놈ʀ!_픻:ߥ,%@j别C\#Zи˂qz4:)۸f1T+%P1&<tL8P-a"(Pq')'n' zHIT.l10JfYIq̈ <"iix͘ڂJԙ>P)6>Z-1ܸ $Â4ʄCM51!#-*Ɂ1{:@=3G7V_YYܷ8p`usjʑcw#{ pRǬ9X#V„>`}MʣbSQXW FK"e(Z/[X`յ0.0"}c;vB! pұOs( Avx݆ARVd w* d%?ֱ]}0 Lٜ-ZϵV9y\%Ifgg$zK._WuV:!Sr a b2Jvgp$FhʵZ)ؠ D%]6ݺs=[ Ҍxo]\G[=@c/ Q*ml"x%-Z1HT (sще9%4!mэUC^`+8'?>9)D#NDA \0yNCxS= Qӹc_p.Wcu3-nHAjVOtV SW~kor *<],e81 Q Me#0m<h4' CED*I9b X[[Sd2m(~Fof>&F΃p]?~h4Vjs󻇤, 2G$?|˼}7j~߿C|]B$r5GtpcL TyP৾ő_Հz,щ[wHjJY"`ZT::A2E b03Er<:Ŵu(1tK% E?ɇ>ZR$bE\u Noٹ&Q +gzxB?Y}FgjU%y4$'IԛY =(LJ/Q3k`il $g3<ƨ3nLT& N%˗UTZ,a6#L :՘ 9t= />C#[_Ы4.D=,DNQ&jP+y\qgx˂xBc:B˓ "͎8'{@LP!:%@TG]Unº)ցPM+.`)(Nd4V$efA)1n9-\~qSnrɓ'c]Zi+鶒r%9ƅh@M1 1~k| jFA6MfPt<~Ǐc6jsh4u묮.tuB&+>"uq8+y|Wyy4~ dC#T RJH*&dTh<:HOy<[ 'p))=Y)9`,TC. K G]$#"kHc4%cJ Dq_P j8z6D,jE)q]%͹ d4Ca<;jKfy ^%`hNdrJ!qCM@9'&'@2QHJr![]cS Ṿ\|˲xMμvV_eܹ'O3q$t$ezeǿpkt@W1] )_WedGCRl ƾLC^S˨&tyA. fˊ0=DU)V膂2 v1q2i{Oi}2D[U xx{bGNHTs:79R[Q; nֿamm7n$W\\._ڡBA4 1ji 'qNMDgoHCZF#3@kSU}Nm3@J52Jt&,rqG4H?5LO`WX*aڀ#tQNMAg\DUxp)"KJ{‡oE4<_W"e1Wۣn3w^3fΞ=mZ`0`{=4M.^@u"ǎgvvͤlnnBť$J>eqs'Y^^\.j@qOD?d}t/!6x'E_\;l[UkνNL$8N> ̀@C !DԭCG He```F  TT Ht ""%q;ù{ $û\l,6sIΝ;8q?hUx&ІWQDG.ʖP`(' D\O AA,<(_]xt؅Z2]2([&`geuvD iK"8KpC?ϐ~ ae䟩„{lLJQh>S,GL{__ĶmVWWi6t:.qspp۷1BM;wQq{ ZM2qVVV?WTUŒ=exXE83F`||9,u]eK|8f3:=ySچ亠경cToG^{ؖb0 P:***R9ʭ^z@HHUϽPԏS+UC9TQB!(Ԏ%;=:?`h>y3a3]J v0uqZ+++C10L^ }2n繹$կZ~;bgg5F@h$C(B0fR X.>OѣGQXNL $n&е5N:ѣG,//iZ<}n뺴Z-~[ⷯAfaaF$ٝh6#Ssoigd/Q4yA+lnnjd5x7Y~RL"E~X$6fgO7Vvgצt!u9]]EFa쒊B}9lkQ(t])MGs,ԟQSSwHb쿠hT# _cyyT"CpLGq<|@=;IRDo7W|/=afΔ,]*)tM6Ka~1{# ٬Ot8 $ KGPD`$F4=k/@ll4Jl;r}/dK9dm>ffd=zr͌I{ZHv&>]1@(}Dӆl4ˈug&x'I>*#rz7NNTEWB0 X 6ykdkpA/}zv]ܹm咉z˲P/LDO>M6ѣG4M,BUU24 Ν;gz ckj_Tx[YJk<ol6RZFբlB`0Pj2PD\Khu?d71iIJzTZ{^"WA^Ń')RTZRTTZ|4 ibHl^Nfg?3 !($c#(c fN˼m9bpr}e 290$ &{} u]6jU rRĵkhT*j.,//355<~| ym3==i,޺ݻwmfIVKX50e@U`>[?o-l$S%J_gp/r ϟޝh[dȔuƒ"v|aALh R%0u҃1%#!Lt, 3ϊVЊi\(B>MA,@.O<`p7PixI|_hpR9?y@9|A91q'v)6\BWݝ=A0XnnמjΠ⇳b)U7 v$E}sc>K^ko/+qjLMnܸ,K%z8Cj%.}TŲ,, ccqj@yBq\b]0 4~ܴ2 ZC#*R`AIzj{*p(`Q8P])Iϸ{Ԟt2"jj1FgD17"`+++T;3EhT1}.\NfI^m|o߾elRjp]7'Y/ˁX 8ͦ9f]s j'y͘Sv@|*WH<~ M\k[u?%'IN6iHYpEl”c2Rb@zS ý,-26n6mzyywipH/<,+^=n)AUEJAZmdY qm> v8^k`(/h4I& ֪pJ Q[ί^4Mt]VQ(C2Q*XXX`jj suL&EQ(LMMq bw!.G… ,..]Ld~~\. bt}yN8gLCi=҆.FwB4+xznFYM U2]Hr\zEaIPe|_nyt > ^+G&*ۓH]bH@o V* z~p8hr qb 5hB0Iَ1 :XJhTĖ:-x¦j-15щ {(QBRvc__A:c?^%\όS$GӔUmjp-4uݖLFsXnGR=<~_Uy|'3|v|7iY_Om28< țFJ`xh.ouO*;'VUxw@G ʯٖ)n}Qk^U; =I\ǫ6AE7ah@%l`>a/xRc65a4b ǒ߲5e PL]ؾj?jPHQβVSBZj j%$JᕪHBM`"C [: 3D4ۃK?a6vSDtn]HĊa`:OT 7h \&0]~Zt,XtY2Ji4 $UAn} ;'ocmuٺ]xķ|~j?eq3"\|_ǦٳرC*_L3::J44M"m2 JRDPpEarrv2r9de2  =0miR(u=ӯGmq-ATB|Y9z/aKzO>)Jr#~?j77rhwPD"Aڵkr96:L&۷Sw/0 #hJ]hÕƿTKlUvƉ4(iEQDTTתBEl@]ABBEWEtM5I+%Š;fq=,GGWcL-1À!]G Lqy`~j|riIjnnjm@OWUrbQt4wl6U*a^ekkr,Ipi\qLӤVEe֘jY^^VQ.&)t/E3* mcY^OEj5EMܾun'[0ϻdܳ!#pċ:3݀ w֋t927WNչZA'ziB wEֈcp -Z>vρ3iŸQL ھSI(԰$/%eRH 0q-r {d~}R>m-L31 YNfv&7chaӓP(Ęg1ݰA# l>ytjpv #1_xXp:oɷ3\_Y ոcYYnoooPwg) |"AyE^O2Eym˷o7Y!Y=$ΦcrPd͢Y#RߓM* ߣSƠ$pJX¥4 jxB #+`k4-T{*pf2 ? Df.q'$s;>>FOT[gD '$B3 l8a?}< Ig|2R֔M?J$XC5mJ/OhT 0$}|"(H1ؑ_}Mq@.34HtF$X!H')aAff8 Xamgf2 V ֟P~RjvM޽{p5?rX%a/_0 VWW|${%vvvSh|aU>vNi [\\jIRn m#{\aHXTqΝSj8+,--q `cc(qy2w%N4ye.Ԯ= "C/zLlloSe?=g==[f$FD˥;;— Ęh/`)hYӞNjt1h'9yzI A̓Ǿ Qz7 ҳgǷ{^cY'@BA@6MDuZV;ji]i6nRph4_%>Q$XYYI(&LMM%CP`]&&&(Jxm>|?QU:X(Ja>:^h{u]^hGQ74 n.6YvR wM8:Yr#C7Px~WȈ壩`hadRp`:ivS<D 5+Y1Sߦ3񹽡ZDHu!BCIdX%D P( anC5=)'LY&T_+*`;`I5ŐE5- xX|Cѻ$p~0`~~MJ%T*8x2DD1 8r}4M\.'= qٶJL&CVKD1՝d}\ZanYr8unܸmۜ>}3=sDQB\4O~ԡSj4={dMoU;_6u%BiR%Jeb*;6!~+,X,5.A:qc;̰37]v9r91XŹ/YU&0MD" ( `UӖE̱Bl\*j8C.C4RlzLbSUH2 B5CפЙf͞7yctG:v"`57$kOBqA {ǀ =fYZ oD]~?ͨ'Fz}GO % p p mëo7x4pulJڢm@> 񡎥1˅L?}Mkƺt5xvky~k ~l]a' wQRDZ%JQ(ǴZz{+6,mҜNG,oNhy>>/~`>1}rCGZQ`E@"shHσtӢ#Op,38ۏxLyįLx8iix0Jr q|Z%fṈR|AAI+twAGV 3`80H' 8P:AFwd kzu֖ֈc2 yIe'y8xH&9g.a{ /A}ιsuuOXqIR~|pIgC'! 1,Ai|tF!.Ҁyޓ$b4T*E4zN;24`@ZUBﳽM:_eyfr9L ѕzod*̌Dw8C\ʕ+ضJuqGc<~?,A>% ܬt͋[U;d&SPP)~ D qʅ Rt#Э(‚ ]TPZf d&689gFlsᒛ=ORměwʎՕ'л) iljIS̅*KRf^2Ѥ9q2%aZ@sZĦQԯ0SrJeЁ8k V%bRi{]nB3W0חI8 Dg$02ߡ@K.@mKQ}14~:iaBNVc<!kd(wkɗ=$!it֖aHּ}%t:t:vyF#!;;;emۋ4K4vYQY`|zxGKm)}Q>>^|K}!h-/dKh\Us_3W'L3!fhmj +X$-UqQA\(E].ĝ .* bA'֢DLMm2kIg<=^瞛ff1s)u>=ki: Wbt;F 5k#}mtaB6 {D1kPT)36j|/V,--a6BMI$ * eeuBV3==F#0;F٤nSq* 1չÔertū)0 !i;9e[ʩ 6=~^LRI&pJEd@[@) ]RW7=]xif@V{Ct,H&˛vCC.k\Y|.rv['z-LX.^1L{WlaIg4Hg2g}Z@ g$I3mA$d۰`@ (R`HT Ao\6KTaeygQKZs$W|` ]\ ѹ}vݱ0- }WGJ HH(LLyWd*}3ՌˍZ60>>NS'jr$ӯ\˯_|3|;.:!rܓ|v͞Ͳk4X N%B>;=liQ0!F6ʤmH(D3Ѧ^z=hxe %ɂk6 iM +WÜʰ.`-{$MrB HmXqWTZm J$XضÏձ=['iOlAt:m ˽{'-)aZCNaTN‰Ә>]w[繊GRJX}"@lS Rqa'2^{APb)]=Cg[n7i6\v?EZhx9uvKǸx L>͚j5F|Xqh . 4ݺFt5,i Y 84Z}W2!ݪJ{A;#㇯_k徊&lȧÆmcpx]xfÎ' "y4z:n FQttF C$;]uVZ&F\zui[([%U:M4K²y~iUdA5j^k9^i?21Oj{lnНOrsί>QQ(8uIvvv(͑K^'¥o_߹Bda nHz' 5wF=dHTz4$SxSvi+@ɡqN^'_]CYWC;̈&ة ^wGK~2tʅ-G1h3lzE*|!+d2m?-̆U\/)~A@VV>J%Q~t$>D!/0??eo+kZwҋKR|B:faa'NpYfff(ˬQVB0.Fl6yXå.Eߺ(V] lke?3ϼ$nDBBj%&)UPAxҋ"F(xADQꥊA-XlMd&ٝ}xxy{}{_ҥK+TB;`[mҞAav8vLE". yjqrRL!=2Rzz}JV !sssFR)0龋m>Q9QjE]> @ "h}nӧy!de2 T*:brS,/ }"vD 'x_x3EQ l|& Ǡ@Db91p%K;;A˸iهA_‚G#""8hr8OΓ$ o W7޺K:֊\8W٘NdbO N}y-q |q;q ˏg/Gp}w_½{< xє4X^^^Sդ|jy[vjqϪx=;F ~Qff\HI8;Ln@l⋘D%'cDXK5Vea= )C[t"})GI'G dKKfiehoOd֯3d!0y'{*8#GD]ZW9l~.D 0Y @\=`<ɉP{pLYrf@% IFSv.g_Lk/LK~vS.Ⱦ N]jxI:rs¯ϞM[,n7I%W0-MyVv?P IDAT+0J'Vӧڄ Wڢnh4j19&n|' <'R`1 ÐjrtTZ)Z&Qi?u@233}8bqyRFZP%JIw3,+++,,,F.loo[؎*dζmXܹilfF3syakf.ZB# q-@ !LNar& p7 :_ qx[LH͏γyEyiǕLzc )#]:=?/(RM-@XQǔ V* WHnF\8S-Xc`pH<Ye W4«d9jv(Ix I);'FA෥%PaDjo9WA_n0l5^GhF޿A<#|0FG!%aSP۶*zmW8o~U(FI+NFy7E\|z9?PO8E4=9z8G\~X}*/xjWVwL4`.4De'YZZ2Rk+y>)Y\\\.su2=arrJbm:~V1:QdT.fZFVc0$Z^(BdP`ttTe$>Z zepxpv]Y.\@.cwwznaJb4_ddOhU?dvkw)1%Sr x=XKу޼Beժd7 1ckk= (>mٳgy HiӔ)jJ3 9/opk6!)tۼ;+rsVmA?T bN avOX"15Cp0c A {6pt^~3]4DW/QkMJ B.|޴y[#=t$*Z)<Y,.L"A 3RVROYSbb Hbb$RQaO%k$ӉZXl5yTbkPtzD/}v.h86csTj%L^NFPb>~Bòb7LF|DW?V-MֿۛŢ\.^0N.-/c6fqRh4(ZRq0SżqJk%\\H8r)%$v OQy|ljx39 1PQ$RwrwT *W`~V? "/ OlozX (ae? O: fia(\>GQ /- FL,̹Q)!rR@cg ָ96L|s|E0Ő9 i\H^U vB@'%X"B ^F6\?`.T&A*犰v ґM'?0[tH֛s~E>R*K{&(6>K\[[bx`?lHzrJ7YO6ϦXT1߭VN SbVx"s:KKKضMۥnSVuLx·aG;e*c\\Mh#e|c4u[.+Eѣg/޼<.xPEDA-jEv/jm$Ig$}!!0L2=YAUA y|RW(2@eTyGj>SbHEZA jfs2y4Nӡngnz T*ٴ%u):iÄ@(c#r9rfzTBlm]qJ+A!>ex,uz|}E^y+n?`unx}jz.dp# -T@хƊqw$c|8FEU~Ja1U I# ݎ#n^i!Z)u-@܅VBVCl$~J#R  [/S2FFLY40$ %A&!Jr:LR Fn\!>ucM%v:[c`- AX'Iyeꅈ/}'YOiUB$Md+P=˼4ioM>28_=wcZNsݓIY :t4ɬ1hxB=ċAB2ol7ߎ/QhY31>ufj[@S@o -0fbKK JP~dϴd3ŮDCmnL3 `tԚ7L?|yjS 9=р)7$1–p( zFV~$h$'g8`T/^&)7">Âb7$C|Oq8eL45`R.:Ǚ :aį}o/72]\QGʝ+di۶z]7Kl6T*hVa6_Xm:eCNǿPs6d]]$#,B_rF {P)IAޑ4D2X)b9޸x׋ 'Nug;D<K%\F;VN\w/3N#<9pPp>R䆐ME:*枠;:m/qw' c  -g(ZW#y>SJ< txI Ð8i&G][ !888j!G{ z=VM^.?揉n\5 .c"KMHHQNn'0 7R0꫱gUt0m"[kK9r"j4ht")Q5{"x >g|{̵H)5I>qhA-!Պ.zg?1zJn dMR%ĉCu޾8 \GyjzAFYURe[TlP+-d&E_T -.Ѕ0}2|0iXx6VMǶoc8%`s*p y"@H/O2xb7E«<frH괞N)Y_8TrXOrQPɀhc-g,np">U6'` E6Y~8b=́憚 9އrU<,Qz-;?ˁJDKQ³L<". V` ߁VyV,|͸PJ7J{g\ik+lvqgNׯckka,T}677t9fܿߘ>дM3sxxHeyyFp8$Nc]AYeMS\0 :BVZM1, :rV[[[yr%/\'=s,WI(2 F^*_d!nutPe#Wŋ#ZnE Ð0 Uޞmӧ}:m>n}ۄa˗_}1Ʉ^Gǜ2y1~S}Xc'8\n=۠.V e[L9QZ9V⌚! 1/Br.'J;hWxL9 S |#<+<~Oc9;;S**z*Ӧ"WtP> 4M lv*o28::"cBl쌯}Ç F#|ggg۶N_5jv[a͛7i6J긻 \KoUx<ďy9 EŢt.` *|6]Bj7, &XHmhK8c{ϋŝ{`ɏels7 )K{8<\},6P͝%A*P%"s]!?"""\ I}_eͩm4hpUj[[[1/^d~~VǏvc (i*{7ܘS=4U&^U6& ضï/~ƭUFlw؅Q;auH$}X ΄NTm(ZSF/1c,NX 9=pUt} Q>*1,y-Q|L093۬s⯄heO\1¼>bbpl{A^XvW8bhV]3LQgOlZ3BuO8fN98!@f% E%;+0fyz W1:KkęxbuݮXz/ ˅G߮?Uѓ%ujBltK!CAM 6+ez]bYǴla'QCq/Oe|( sV2p^B#C.P{ :dNV Ti =)f/S5S9S%@r>yN'p D 4UY" dm09$ h)FNV%#n'VpynvfBk_u0_ >R ĉ1 K YIrd?c}oKĆAc4V4~jY=S1tV/'r+u,[ly <5gi'4bɕj±W('"xpJ"pǯXqNK{z _ۇ>!_~ N'fۥvah1V#?*0t~3/TKK鎄@CO\Q(OgY L9Pʌo4 ?M357}r,D6:"jw|Kx:}>ݿoafi9I(; t#'C{ gI/Ylb P6*{)oG#:#O^:<'kH++ t2Y$+6tZdH1ΡQ@>RSಷES2>l="= HÄ`:㐆 a'@/3W+w 1 /sdY(N epRA0`Z!H AT(YSm(Fp%VWWܤ^>fTTWmPα=XE(gaa# !B4>LE|ٓU&e['8l?goBo>]\.KuLJ{`)KD5dT-Q"r!b0s,7{ё]dtCga>2;ԵH ᱌*N1{tJSZ G~ʥLҾ^3{\x9 9B&_>쎜xLYƉ0[+$iS 0#yFb7p%M2IcD!},ah}PO+ltM*3e6N[MܗiH5i֩6qx)3pٻyP^B[/ƻ\"|jg3nd9PݗIj-J5jʑ;CmRQ"hlrC=z ΤCd%Qy(cYź(cLs,Ʊ lV:XlA0-xZ# HC1PƏl e͚%{J|`tz {mx#9yG-A9*P40c6&J9 q|!=ы-FM =-Y1Fta&<"+wͫG080 ml I# ~QI'BM\JY-HA,Wˬ\`*tk;}JgdT{>_W>Oktzq|~vmpqr&S'd0p5n^8F~:fïjj5,*jTb-*+ḊX4MKT[cΦl4º(>A3DG|Jicbp9_欐! K/$0kOvp #?xneY Ja\2H on5A 3\F)b7g3N%ijM()P:.ʖ2 C(8ё6j Gv >߯ Nt3"zd(haeLƨc$Jp<&.LY/Q)*x`R򹱓a/׷Tk zZwqHEC$ Ȝ}q_ه2D[9?p$#+TE[ e $KGcϟ$I\L"tt}CW#o cɐBg~狗^^<~Ǭ?ʬP4},,z!VR֖2<֨V,d]=SKo:dR)NNN,K1d\4M>4MUj5jb9fW*$_`yyYmlk#u?LҤI6tw% *Uexċ(*( +"xSxQunlyOf2/3IuSo&my:td2IRB 4R0/ 'gd2XZZu]"H z`cS!;WӲBX,aH$HR8lmmv;%!4FA&vK\u]8zƏX?}xL_^X,jh6lllPpfye͕kw5gc͊#A.Pr^`WCcjۋ>/ƒJɓ;]] vB HGQtpVc|=[5cNQ:DXG?Ʃߍ %SbAS"&;4d1QKږv\=lꕉɔ6}8./=_ Ѻ!}\L= 5K5Pa1]y^Ha:S{<1w䋟M _&lJW+|}߻(ung')[$WP(P"|M] <Λ .{fDZi ՜rM(J/=<*x.kkkf(N3 B۶1MFN?RHH@U!>۶1 #8NЇX,0 d2!!VdB>U A tMoUxflvc;+5R" Ta*X!+v]V,aAŢK~?"JȪ $Sv=|3Sތd#߹U66nE.RRb0 $398 CGQ22I;x6jLƌFO jQ KsCinWmVUs$d?@Ґ]A4yGXd<ۧZR 8.UӤhHdb(K^@uiS|>w_1:Y$*G?|%WMˢP! WDL)Ԑc[j#FTcUe4υ?p*Z@} M9a]pSMhg8Ý?qrD(|)7/ bDQ3Ɍ.CzOf8҂8:4V{={FOŎCÑ\4}gptLt҉D3 ]kܾ%Cǧ:XG(o|!?ͥheDɕ=?~?zOW5Z^(]\Wd@EoFSŜ,bU14\Œ(X*aٙN,AJn>6z2=iO3 =)HR? z1HpJHп«ЛL tV!-,qG#=XԚcH MJʘ(DV3M_$+ P]X7D`b?;U* ]E /SΊsP 5z-2 qfn J1DLQs\K_I6nK!AdR"7ń9Ɯ`` 2WŸ*Ylx|)T~neyrt}O=f?Du>]β;rtZ->eqppm4MOx6nm!FM\\.Gu]ķC'A/^+ JE 6M岸[%5x,%tpE MduuUfz2J"odMhe󵳳;&$MjL EmTPzTăՋ"xPP'C(EbIWM5Fsfvyiyt:j=C=ϣj)W@d#R ,z,J*8B8RKJsyb@aȁm355yEZz'Oniqll Vq=B4}],|:q*} gU.}۪yaa柩0eCaO\f&]='tZcTt!l u&q*q̖&^.³SV^Ocu"ڭz=aҾQ ]7t{N3[>[\sϲɅkAJcp7<ı2A7jy1~X##;(8Ō҄#b`XLaw2 ؽn  N pa)9/|#9 c/9v\;3W 5MW̽&69;̝8ST |x+|wi| +x>?qi^{o<7Ѷ Np:ўA>M$"wmxH,)ES8/QTA'j$<4Ѝإq+- q$d E,΀)nkC^6ڐMRl_Y!rT'ٌR9 $I0D?![ ;++!a&9]iA/EEGmDҟd '>B% f*OȈz' 2l40|v3lHA qAvu`QA enM#Eb='A 9}('<AKS8$mMnX cNȝVKOy=y~ !FOjU|>˻E^  0L T*K%VVVsLxGVSzNZU42yO" TR/!Diff2QX,Ju9?h4Ov@/lKoULiɄn+'VC\ץh$ 3 ١p'O\v \,0{1uRK FY!8Y MU')Q` ;#i\0|G Mx^У2Gܴ#t.S㗏(p8n3h4-ru;Sn\ސ|׷ VaJJtej Rh@ &_xe)]Mn2t1q悖EcΗsvB-,mi1R=MA8//b *1)}~k XD#Ǯ% [ J;s\+dp"lnAÞQV$f?n@Cݑ|+՘NK!zVUW_t$+3,Y Rf+`(Ou yKg$К PcwJaoV N vV|G@خbK)kO/PU1TgWݠfz67KlXn9+(۬Ic25BqhivRLow0*4.bUT3:6? CѫQ@og:G"$p!!o|r_'p0qI oι=oklM,._}~dᡮFuh `_(8F (n{a#MA锞ڵkd2:1񘃃ݮ6MKmu6VK(24tҙ)\͋e?Lf2kdvn)"XTЫQXEC=CUR l۸/Iv&xxy6tN0$a&<}_0 NJ %|~0(pӮV1ѹQlȂBVVVHӔ^gشs\Tt:e4)&j>pniN.+F 09j ժ\p/^h4T*DZ1<  `4Q׍o6Nv4 :Z/#rٽ_ ":+Y* T}D0N$SIB] =v1FQs3#O $L߶H2ɣwu D& "foa͂ g[TB}w<~or|rW3C0N aZNW˂PU=5 (j#j8cUKȂxh-) t _}Ա !]tyWDaCvƓI~Wmݗ\~eN͹h“ 'N6\|{;=^KV{K;|v7Xo^Gu=io|+7Ypf i#DY_yZ Lc-$E/4$|]m qxyuIJWϓue G$AY-lfNdQKRnTf lµ2sHZ 3rZRyRTE%>+_A}g.H)I<Q _={].Z$3( {U[lٍq"ul~5XHNov4ޡ~V.#Ǫ?ɰL0(mZa<'5G|Pmׇ*~Rp4a xT7ٌ/cjRbŔ$O͈wX0^Ǭ8NC\ݽKV3kkkaHݢCICG h vɲ(R'OPFܺqA (XD Z C'Mcқ7u\{n2Y%wq7_S"8yS9(}?=dC uakk+P/Eɣ*54-րr]7g,ˢ3J iu H]X&{{{a0Ƴ6W0I`#VJJ:IdF@e+1lttL=6ScX@1nbⴆt3iӗB/5$WbP7`/\{G>Dբ^sxx˯|F_o^=bj\ XtfNфӡ6 /o͌\vpqAr`䜰8ƨxPr9OFiO:]LY "*wLT72s oL[4H3p,J@N4M3ОrDd Kǚt|LI EW"_eJc_*A4{H#`ZBꔹ cm4ΚM4SSY *ͤ!E|^@RI)8"c OZb5"`F)"aW $iНG1i)-"MƄQ?,~dL UR(X3RCab\-K i.(!+Ӑ$?Ӑ(E;m ˀE'†'XƼ♔cOvQ%R5Pikc&pJLNzOF H`4hfHT΂AӲ7ä1<7sIs.d`˰%{1W}nVfDi Yhɟm y}Nn%%x-;X+d,01q2!Nr*$ 10GWb! )_Yeҟ!m;Dodd>ǡ-V歅3EWCBSlFn݀M&9yZ%R=STl)[]% "ZPewn#Gnb* pqq6Սs6y>QẮU1f n3:J_*X[[cueBf o pP(4Oy*׮Nǜ?l;o#U9sq8 &b7^HdH)ЖtH(H4t $R%Qds8=ř3X%k4-me}iZ=鸓_T,Eu,~4MY%Q%ȲkE8t]VVVBee=5cQ~;;;TUqq1ܤc6^u=Y\\dnn9::hpyy>lѐmj*''Y[,d'{< ![p8KM~ogB;:;'2xA`Э809 ":C3NrHSS]˹I'RhV2Nz}Ͼxj{oE8ǿt2l+)rfK 8 stˡ/%y),@zzo.=^˪4K羴gX9 cvcӠYT 3<* C@iBnMIuWzq8<3y֣KN` ggg2!S~2jq}F9VtIpض]*doT?c׍io2R TAAB0 &VbeRR*J@6M8Mj~1->f} `(^mH!F+[@,Ҵ;!kI0 :Qӡ"@+I4 !|MT,KT5j4Xtrl|uug~~kkDۚy28YoGG8333a&wRa{{!V 4u871sBѠViCjxx?DW6mtxm9ɛJ m,3ga״C$7x"}8gt :sx|sMOSTgk?}CIH^'H y9 \FSRW錇PLOBm asf5Ney"N ]Va8ԅa$;Hb[m_ ,ɽ0 +bQ*`K'o,/u+"TK)XTI6if1kՐ4X/6 sqiJȪp6֥TcF<PI_]:M}6&Nh888P˲X]]e4@ƶmvvv%㘽=Fz:+aH999a8:V3Z[XWjmncN)&dk#e?{:6iڦ6]7TRiKoQ/^AP*RrF'8;=븮<6`kkKK Q|ui4t]0%{lq6_q1SC&f̸Ar:`OYzd5>zOKIOgΟ%~얶`~9~ð<3 &v,%1?}m ꥄ/Ų+.\ &2.ZϋrЮG86HO^-%, W&jV,Ky2g { )CBZV蟯."پVNv`\11I Y'".uZD)SD2701'ֻўdeSNYǡ' #Kq`n4(^njdKx"ཡ G.L}G_ť0$(:ˆX]8mMB^ (_]]essS4MiZZ]|_FQDa̡OTѣe!B^Zj DwՕzcۼ~3lo#U͌퉳qYR*HP!QlE6Q$ Dɖ!J*hj#VDB$ Av>8؞O7Fd=[O{=rccd)tަT*OV#f2,p^*8u=ơz/Bu;ISG7H$rP pDF ;eXPh=l)GAYfyjvYQ+~h>_20D9蟹ŗ;?oNs" +%K%Beμ &T:/L+'!Q2I+ %P }9`A_7C 5 K*YDj߳ W*+R\%@3HYurj*ozOy­/4M>77 s4HzRd,7%Ru#~yq&!ɳAȡlE"!W+ت072T/~_3L6͉S=6cFsҌGcY창9G,%LYx86pj̫UGZ캄GkW]\ң x,G1"Yrj0<0&iN9NlfQkKRGJBBX ,I17Nx:d%[\ 4kuj^?Ʉ[w"nT2pE՛#%Gpp,ybRK ձ2x’e\³i}-|o8.YhE,#˖TSnE }1Vy}>l@ri^#_g_E Kp6$GnY5fX*H(_oyrX??f79Mduu|ʔ ĭ+sXƲO9 >F* 9eL<'z#c 3W%.b 0xy˔%'~1>x~'10ܕЬ0Ш7q)xNѮb/Jn)>Qɿ-g8]6ao)=2's*13RYn|u;o)_ܼͷ}gHQ I`t4OC=hvF#]DN,4ʠP^OT &(ŢFNө*Z .|6amBlKoUxSI"MBlJ}gHaX%J,@l K $iNb;r-–/ќ=vܘWxWInv s||KЃJ4Wf 8Cg\p9l)ށXK`(R;P*)Z-.//7\ZdBuÑ,u]NNNF :یF#: :v̠E>.hq|n7>.ԮGl*gM\0\ǩ伹2FCf,ج'ly]i2~O$ J,k`q>vuea :!; _O}jNJ*tSvZ3'EiF6|lo6RVѣ@JKdrgRn Ѯs3L _^kU7w}E/:unbxej"+g>eza }N|4֌Zvmg4MoECH*4nsfȜJtr(U'e@He~C_@ݜ!% 4[GZ QȂ j #R *PyXTc礘b5S5ê6Z˗, S45W&I yB(Ԡm&>vd5A*dzvm71O?"/(Ы*J5@y'i6v 8ecj6QhvHDĤ"6g/4u]~|@sxŸV%Lz;6X@ b`^PgP~wWx@z4Y[[coo0x)w᣽ozO˗p(Ad;U5MS(ɓ'$3u4(U+!!۪Â.X#~vG !JІCdge$F#ks{qѧ?y { *899!2(, h(x9 V ,CVu>86R8M"Njf.}4jR$ &1s[fjo^g}lf}};jtfBg8cC@ ܿqܒE{^8}pȇ_Uz{;'?tjN 's~ C#sV6XIi%8%ye1%'[ \2N=!=uf W*փaE{n0N\vR8f-5o+Uɚ]5䪤ΒNwT3uf򅄬*kdɏI;GΥU8?(vr~Y8G'"M)NRp9YkݚKaX+BGq+Yu"ٽ!b/ПS- D@,֘>Y͑/tZ.uTp.f?z})f2ƄG'%as]@ ;ܶ9.g/X[hh4͚FX6Pd&PčRHWW3\Ҳ]g3_noU8U ˧{1nzrG_=3_?KJU؈la 1/̈́o GA-_F_2LL.L|wyO都S>u|2pߚ<; Y?x!cooxRhdȃit:n͛8cxlZa0N L#)0sv;88`ww$I N[i[| ~41 xܹslKoe;cǗnpB"T覊Ă.*XudeB,ؕPv_P *HȭV.Ď{x<7`eaiƲU\.ǧ58* 5n|xgHߞ{8>>\.:?YDUU;=S]Kʖm,:cSؔ#uQ𼧢)>̘ˆK,͞ʟ1o[hZD{6Nkabc0)&F]l4M! q[P֜ mxY< y˹!_KypՉqUbB8oo(mJvoAq[6'Lɮ\H3gtTMv/p|c4pmsѽb<*=l#`ȡ>J!b4tAgF>50#z@`5%$*8zH )Z/`(&D!?DIt8O3TH!AaR%xM"ATWĿ%p@O saϗ<3c.dG!ހ%f:~;7XgM&M Gs&&8qoO.@@&FG59nayhHj駡ʎ+.lۈh&nb21U$~}/;a%6i!m`d-aω>M8V*ޤlwuNc ezaC#UfEZ:_R{ol6v6dY>,^N06VOђa%L7߻gEgm^}ﳱAՒ,?I{Jw} SN>O>TOٶ鰺*1Y%k {뺉\>R_YY97tKleyz<쐴E1)BTDH<$l `ϒm@`CBTHAEҸM&x^,~ߌg3s/;>ąK| +5b̻]/.ڇWZ|GJݓ@FJIKpWR\H]9b8aѠ/:9M ; je˪,6F%?",h>3 J3r>\G6 B) @ZI~q XV3 %cCQPA_̕pJ'oV)qQr"cQm,:gi$BKXj\Yח^aVS^\Wos8/ضޞě=j,\W2ٟNPHzW U0ާN" Cj7@͎2sss,KZK:c:AH H {˲h4KՒj fypnןMNN'tod?~vMtiim'VNBC.@?$8pٟ0i4Q4zzeLU1ekIm'<<7,&t:t]'pÛ4PCǤ;3>3(}Z@ 1W^Tv&DXģž}pO&P(dczTcYTh4zLNN"u]jb(mL<8XEVc&aP.}XQZM$PVY\\d}}qp(P(L4 t=fffkw{]YXX QT(wXYϜ1AJ P#"@!=PYEI u/C(T@HXNQ%hz*m_a+s"(,Ls?/5xM?{7ȺyLʁw[>; ]mDSL+'a,2AuoK+u::^bjjWM.#W?Ѹ|A 竜/X x qo/>*f8E·Z-666p'is%)JTUJPFi6R{(6^&a0P׹{nbN477X6JY jQ.iI]Ɇr tMhe3ٝfi6$MBF[,B EśxыD*%ԛM+65Ҵ66Mf·73:a`y_:}t,2r>g9TJDU"Ll* x$Ў %TY.Z| 'O< f3 H~0::F#5@;ry׭ۋ8^TIQ1<Q㿻sACqIPLo9iV)/6#uH#B!HΣt@w;-/9n$%&5ܫs51KUT-5̮f[8mB-TYG!*it H{"ZUx'%$&$Dn!w5.95j~3}?8s\pb0p#/3}CfQܨ+|OZ5G߀Daci9tv :݇88CCC4Vމ .RTRwrrB@6Ų%(/--qvv;HwbuXYYIؽ{7Oox}bl7M4S^?~?ke|3$lM$5MiP(Dh bz%ZQ^wbED B[ڃ jkI7ۜݝٝ/fg  ;3;nߌ1??O4 Vj5d!]4"0==bhy ǎq.],--girC}/9A3H}sp˩ӣDe]Hbj7RQ"$*MebC&#r:?>O%8x*f%ق'T;?qܑ;7ldgi5ޞqw-Oc_,"E~)Fy./A MW2Se겏!v#k3%W5v=nl2p܇PSHc)jxǻs%Bt)#Y$<#4ڤ:D{&G|VLzL&-*v35?{\:=>zV+Te$9d̦,T4-/ӄ@5=*V_`&lUM,[egLa-J&bMR]F₴.1KuA$hN pp<EYvvI 24Y*SN6"kY~0Ζm< l)[{ypo][] s-8  !G"(`<g*4Lצ$$K 'X>B)fffB_/JF#7԰ h6I?e0:)%l6 r#[|Khu?3;;IB4`$Z/X{bW/^A A(8Uڛ A*҇IӤi5kf'8e|X,:†qFFFSW%=|8~wyH+L$Q[+L!SQfs+j$51 (̍Hlb >"8Ĕٖ'1(\aXHj0)&TgcL-nU" En -ϣ>SEI[^f? cIр_/jl<~bǶ?|xdD6HR2R*Qw_(d(q ^mlǑhŬqqɩt:N^geei,ˢnp]ӧO?|KUztFƘE☍#Q0 .g!d+ATD"nq$CIf&q~T[N& {]4spWv^|XdԤ12;;я.S?$` ZOϷxjOҀ3.ύf칐W,..ٳgxWl;|/ddo*0 eǐ>l5k񘹹9J.\)%~R}uTUeCf"h!jB@'N+a L&)JLdTRT"JwyN !c$^' _^.rgcg\2@ ʟ5: iur+_ָ,--)HPp]W.Y6 .5B=ⓓ~]D ey ?|:xS?+7{1P{HM\okX:υ p42`d,!R,#6}+Gjv;!d]Q7x(RKi>;a5M"ψ,:۱/Jw_b!XdQ0`o@D/X$8W1^^|kB0%:&xm}r(~rNrBo`7 )NP@au#bJ҈0 5$6LV ]vS;k`v%+ێ1%q8"j6vdB 7^bh?ORt\LtEmԯWN{lPnkR lZ|NT/& 2䧜NBqz /GX9St?5m3 |v^|KoU\=5E٤VQ8r0cv1Qa&HuQJ%rW/ e\|F˲΁Qb|.R%˖eQVC'*y Ha$I&T&i,?viNcuubC SE5FF4$\. YMxKaDVPh-cimG#|Q38;m>9zz۶rJ% H2JUUeaaVdRˋ^`MMMsznp}NG1f3mʑƵ˭A׋xbφŜ3P׃^xqT֥`v"BV]9><2Ӗ5 {Xw{~:Nq/-4%/s R\=yӥ|P4=R,O_+mk?b08QRXh u{YP|CS9.wpBm&J=(g? 00Ļ},R>؊b]\˾KX)w1VZJZk;[;$'%\FI$p ;fzTI])~K@*V( +D2VY Դvx Į! P<]^8 "zMOmCc"' Te<(\E: ̓,܉cy3af2{q_/HxGOw(݆ۑClU&m ڦ {aL-L~wWܻ1 벾tdkkk8CP n`RIFv:3:: 4ݮMF\p??Mhe3f7i&mBAEz*RDŋ<҃/=x&Z( (XAJ TbMCIlM{fwg}=;0?a:ya]ŋDQfgg) y|GrY<șC.!il~/cu#.ϧfaa5VWWqk}$vT*QTT!Nt(! @B B@u'C_&h~ < #d& Wj00*r%ּt O|{#΀X\Tgq1bKJ$gk4 ,#xB2Xo[m^ Yd AQ(]) _<:jv$ɈB֮G&кcȍe\v&` nBu@n1*lo rT5H(0`T@'[)z^n012!nǦ5-U?[8UȖ6tR[AD6H6d 졣3t8վd5=2Ftf[ctm;qvKw.2iuEq[]"<]nui;izcɗK:=@ہtwK/u0I4ZN=8n&F=*(gҷ4Rq1|¥Ƌ$hSհɧ*Z ~HA,Q-h\^v c1A0mW,Ș=/8w&>IFp)}r0Y6{V D@[`vu]2ͦ>K&aϞ=~lȰ.8p !MhuٝHviYLcA1*J`JŢ E+xxZYE%T"VDE6X!5l~e{<3 i#]p͛agl6C R0\.apIxŵ&gy%><ZFVcff&LA *yWC`<2xTULdbb"Y 7 iFv( B]ש똦, iJ۶h4!!/(*,;wD$b޽,//3_*aZV>MMӘT*q16fM300@^'p>bјDGe3׾=8;' D nW}+~g.Zy^܋цqD/WI4-GfHKTp=o+u _jKoEyÜ~GupߧO2;6S.l+km D0B61ݐyh*aWvsȜ`l6+z*tLl 4mAi@ފ'u]e5A\T*Q,&q_dnnnf yeqȑ]h[e+9m>KlEs beq2+o;?.+/xdUpPQDfumŶkI49'=ie`nr8NrJh}nĄ1 ߶3H jKS{LRܯM\q QHÖATih xzX ^W8&M- N1pNP;R ,߫(eHO[q@~Wa&{16Omp6 =Ga0ƶJ׀ QIZ| x:u"(`<ᵳNDUs 2j"yϪ#,dAc(R:Iq@j=x\s{0m&=08r@|7Axt g"}uRSa`,qNꪉ뷰NX OԜ&MZf'\%/Mgf`[YBl"d@,]Թ\byy/ΕSC]ᒎE`}; yT.7nnH.Bt? Ջ}ж|%D׽Z?0›gwf#?lRUgvЕ?%=ڮ¥Kpo7=ÝJO.0'By^8ޖ-KoUyK.NjL[RHI]J)BBMQ[+mŒRbQ .4iĎ۸qxe.,s ^X9;+MMM*u]tmWk(BG:&166F>'{2eY̐d2˗/}ndYLLT*1;;+?͊@Zi+ B_ZZt:TF!xbS!H(L*8N󙘘<ݻG*P P"i:(ׯ_mdYH$`(> Biȧ^[[C4nY>D9c[I4ks$+Lv#lqQyHF_NDs^T(-עZF&U%FKQ^"s>9,BގtO(#C^Ý% ~)O2odzzSNCRC`݄Aaial9A-b[|g0-׈b;U6.B:_ :RUf+% ف` @]( K^ GnE :"xZѯEl05 s~b&D}șTH*|{),63 BOLZh!  mZEUU* z]߱Xq8vb/s*m2??/>j|Mhe|wMc0VӒH@ڢxP R (-(z$xYRD Z()"%I{Ҵ6馛ٯav&M42/]WɬJR>dB$4ī'(_A=W#xomkֆB&S33SgUb&]*icȘt5 V_tyjG˴g I{T"|ALq⍳>ɾiiIj(d(Y&s= ]Q͸x2̔K.sK1;DvQ\;\QfJ [C*ɰgO:tcc \a;2Q#<|]'UZhjek W|AdCObG~F67#Ѝp?,^.~+)TE l`m?hi`cqX`@QCgvDvCm"c|U=-}>+?%H&{k+:Mr3 l_PkkSByorě!V 1m;&k"6᪔[n(#χi>·K&FL\<]`eb%nGVUke?l&1R]tA,m ŃzEoAAP|HK[Cݶ$I4x}$Ńa<}_h׮]LOOsyfggv=R3ѽ 6E&&&mFCT!! *Νcllg $ 3MB.='XurC 'BAhCJ %|g4V, 0drr(rIVCu߯޽T*QTZ*SSSj5n޼ ,9q%9K)B^='Nêj,G=U21c~_bI\.HuS6Lmv:_]]eqqQOEAXoĥ;_>dq% uYjY ;E,{1f21 hAR3wψ {A lbB0n4(Ps^V2j`=IB}6aqlVYձIAH/pi׶1FZq?s1 |l :'p]~GzOLK'(Nt<`Lxxhinj5ڥccS_,ƜI/W G;i#[hV.Lɐmͼ$V6U"6w@ߏW s_;l-@;D~+m-i#;Ogem5d6gF_Ibğ5MߔH ]m8t&!R¦_kBC/k?mJ!߀ekmDw2 Y[e,3="LMŸKLuR4J%~[w<[,l7 ,{-N]90v+ -4Ht{@B9#{xD.$cy;LUg1 O1ʙ1 DQ@"pi\&e <5^`z߼0 qWޟc-w8Aœ4M]m%'IuU4M٬mT 8JYJxK4G4}L)KbgaqѧT**H陦I\_KlU{cnb;ݦi ZL "Z Xu*@H%[+J,U<[A!!&vl=3a1IcV^XǞs;55ő#G(T*@ԓf#mqqh[T"a\PW^\.366 |P^GZ vB!׮]0 6eow:,4Mr\$J%_y\4M&&&V.P(X!00 #,%@ iLNNvryÔJ%"LOOGFAz=|Сhz ‚8ez$Äc`vy4O@Mj7Mɮ E`$e +dϣJfwSߦ+R4jtTWh4"ӉQ<|x4gO_‰^89;^tx`SPJsSH!K(_v&g1bYqg{H銬`כRh2NWh"J$RH"kIA :jn~X\5`LQmQmҡv ~mfMcR^WR(+dCuU 4c IfPnz8±G7ck)%/pׄͩ.{s6 8'@CI#H|ZC$漤TYhֈ > H%9Ď2'K62^Krrb= &*BOArZANBpX`ڛݰBRqz(n 3_.>E'v$FMgt-ZWlE%6﾿;q[%?`ؐ6htYգĥAn2PJ0jM ` .عY3A}냉Pg{xcǎ{n癛㌾W^_bǛII*s-.hu5BK1rc㷎FHV5\gO]gc;G,̓+O5o3%gOt\ J"ǃ{1͑[s;[J)>z{3(aR*ʋnUJ>^M0w(KKK[ID"/.U ^H8diz8$LS˜}6IR@Ȑ^5*O6 ÷o&1::"9"Ab ZTBlq'6MݻwcYmo1x<+qp_] ,ئ$ࣺusNMMM? AlT$vm5ZIIea*UC‘&g q@Hv1 1 !u*k%6تѴiKJI8{ő$K.EsssضM>WlbHTR1w`>r8V$F}6;Wo6xyR$}>Fo0w~,/|p*9c^K0aT7urK?贱b]^ u怘;.G01ھQ"*`!-GLWkoKPi%G]~Eg!Zܠ\W/l!WDo ikt| 3#Ia{!vZ'm34="V`GS;r_Vz9}`%,g]ve#( LhDHP,H|}IIN}B+ othh`D;ɩ|q6/Hk^ ĪS&#[O~5 v!Bt ąY6ih]M"%$t-jz'3x2 }dsd}tv.Fvs2wZ"E (uFVm_W-KN0H1M${lUbٍXq:Nf>u]&R%+\^0]+ֽywSPNCpq.a1''DL9b=Wx@e8TulۦP(k'#Ƈ:-->|ye?k4_ZOϫ},{%I>|i}()chyO=BOO*f ((PZ%C^'(*/eL&x. UFla yw)e谸1`n(V8q;OU?3LٺlRU"XzhEj)(DEm^Tx"=X)eu-H[!M[Mv'&$z]2. >I~XZz'ժ0uYp5*ӔnEϹ7+ޱi>{^{Aq1IG,9B[Ŷ 08D-4 TתAX_~p-֒&]Ča ZV넽-u^og Yt`,6IXWټmWW|FCP~]HZgr#lԢlb aJ@Ҩ[Y>V7.*q6;ȟ f@.GDC@W/BpѦ&M߇i<L#c9C{&d%/|"*ȊNSEZri*M$5дbuH`ӿ'3Qo:C"ҥ:_*~d!b@"҇ R[?ʹh>Aϕ3wov^]wBVGm Zp  18qQo:5DbP6xnbBi<ϣT*qu\ebb%.w###؋ys@ WVx$ǫ>kpe6 Ֆo9<? \UXL.>Pjɵj>1&Yl .y|x`8'SЬV[!C.lV9ٶ&V*<(yD3H,ᑺ6YR)0F_yCw4^ei+ Cz)~4*- g{o<ʊKhu?l6+nҦ!T-xҪZ<IAi/UjP.P(pEonnRVe(Ї}'.~eY i :'kuT2I4Y]]% eYl|^dC dnnJBTbbppFN4# NE|b1pΝuѠu#@cvQdxãMV*r}!@n]q/_&3==MR! i$I,,,dDq2\.JDc3qZ4>MX4M9z}};*|Vcǧ~!D]zw =,VEO{/^5Kyg'cn*/i}){ ,;To/2Gb/ˢwa4`֫3bŔaV?. 4҆hIltcvk+)VfCbРqbfB"\/ڃ6~1V wZ3E6JX^wY]6ZP R} ЍBn *% [S@7n T@. c0$lA ;y0)k^ g; i~fVPJ2? ?}? Vߦ[킨M7 #ך V:D N͏m\]3Y{p[I˜?KKKjrm]tFHYfTU66낚5M:y.| y_nSY_ej9Ɂƅe/&_yM{{revvVY]ezzZm_N8$}]+ˌ1QH&TCKAvB(\o7JhA[ͩ煀4 ?JR_{,..b8CXDu}_QQ,Ufoξ(%;y|t}Fɛf_iy6ҕy6bvJsFEKjp%S h`j>EGj;Ema7 ?,ށ' 6kD>c3nkzs42LW<鹫\xAclj\pWkZ徣֯ؕeeeEyuI0dbbSzBWYECT?y}`?B% Rhгw_"233#Mx˲v cfnm&|Ap@'1UmFsJig+HjD\on9qkOU?:n邅twkE, 5^dƃ&b<!FBbAHă"Bd]Jvt3͛'&m_:{O}B@^'J|*BXdqq1;y4T*Z-י:={++tS]V˘M (hp8Ie\q„,ft'sfff2ou=#_DQXD$l.V%"%[[[$cHj93b}f%OI[bɣX^^z9v: ]R*vC.r9enqdO4Y4r|y/yf!sss4 jb %_'t:t]狗;߮qxG.2/K)y]{'=|ÇE޲'D2Ya"h4~fE;]~(y@lNMa" T32#P!rbbB%੄Q(WEob KqYG\?byE5Om ruWٷ>#^\1}>(hImB(oPo|F#v[7c;20`'ќOM'i#2K= VE%&& $?vDid鐐.ɋE)\d- t{xT)]8ZB M0N[ 0@qS%: ǔABׁYHϣGB(P0;hQq*z *`=}V 3f,{Z,N]k'ܸq#k LAzNd#)_VqEv4wNf> N"\S] @hę=wpLS.i*ۨeKauu?[379}Ʌ|}d^9(hBDhvc]&)ygTNk|sUZV{tDZyMm_QV1$b.0FS okF,誁بi HEC2A峬a6;干Ƴ\}8]h[e''=9M|촮[RXmm2&/ މ:{Q^(x2ď+'`Eصc] 5Mڝ|59oޓһx<}onnL&9x`x_sҳ,B@*⅋P9e | |\qBhqq!R)J^YY ulU&t:y!6>ȿ]7nG"Տ07j?oPd?ѡH_>v|͝Unl|e2|%].C(ٟd#d:Zzb{?ew]nw1)5 IȘsf W`RRxrTZ0ŻHZaRE06OzD~KtA!>ߓ;Tm( kh)ĝ[6LAWj=>ߒp>W^ ^bB#O+A4/z'A`6\+mA FQNg ]5Ӥ3 JXrL*)5GcѸi>>.jUn\.ǩ~ɣEpVGjPmrLF7)uCLhRi=\O_;U. ʷk:u.ym=le·?q|VlHPY`R+BlHBb@jT X*`AB(Bi&% %q|:}w/뻤LdyxeyCfuTUΣ( o\S%V|2Η_"ϳeYt]fff\.y( vlێLBu]Lӌ`Ny\ ;;;!byܾ}t:eYtTTp]F6L`p8!0#B^Dr† ̐}qȌF D"MB;⇵;6 MӘ@JTFD^1\iLr.oWm,b}}ކQvZF:FUU"iF?J!`ee^+c6BOlnn(=ព(~_"J֜"m"7Nӳ,Bb'B1O z`)bwP*$au7E_eS @1@d?o ?TSUߴlfM^mgDxO4LKm#N09{=Zîɫ} 밯ܐ''qֶ }8suvy"Uh+8&]LZ2Z-GWx>jQ/ @3i9.w)V_KlTU>uo;Bi1PX#A$ƘƅQLHԄ 7 D%эF B!. .LLӺ@LPf;m}.=ѝ;Ŝ}Febb JRW*y+GdY^^V y~~8~^?8[6;rI:mcY{իJH&xdvt:RoYm8lr(벰TZ% C 9۶~[N.}$u]MÐ-LO?Ӡ2q*Ѩ(ϻڊURt8dA!KI1GS hQþmjBWY c "B~y=иӉMr/JNp [}t-r[j\rzKOHF맯핟85}ggii qj9<<+ DBuffF鳤[F3j|` O=7X,h48f}o]^2:+7uj,.| ?yx wcM;H_ݲÐ́Ѭbb"\o]dԘS92ExD1K^~+7rL&lHF)3dCcȈS u Zz> }t QHzZ)Ŷ wOU?3of?lf-Jɡ`AXB=J+x* -PqbۭIvogxxiV/eIBޛ~V8ضMX crr2 %.Ͳ,<)_~<?%odaa,N8iιs瘛cqqb*xGѠT*)nK)C w֭[j:f342m;!$ 6) P`(GfN5Fls4iRVi4Ěŋr0)ˡUdGmral\.GR!PT*d(ˡ“w;v|RXD]HRa,3XE:՗rFfF) 埝L&CF۶ VӍPi$Bo1Qaܰh ,\OyCxY-?qIeOR Poh%IgClXCw-lC6k^WR.-= `*=xk!^vS1v$#r ԇpېqf6喅' >i>wnqYوRH@.>lXTg&Ǣ+zbD}9\hɣDs5=,wzI4pUXQ(}Ϋz߾TtF HOU,C*Ȁ͚<Z1l/ݖ3a?ZVB{tNeROSt:&DѦ3i811a % Andb\nDE|z?_#]5Hf~~4;t+u0d2t]zD"*0 6YɵkBn8q|Rzb*1*/Z̡GC s lst%14ɑgZ45RXBz>n^=#I C_}<)bhCC :Q#Ͼlk9MeHL&nvݏ.m]KV+Dzz.D""~U5V**ݔtN6_3d2&${ yg?ʕ+a8qq0 9:b~OOF;i.w,q\}Y2׮]ö}YYZZoe"\e"ruXYYa||d2N E&IEAut]gzz:`z=n߾@"EhPv]\emmM #6Yhpj@8HADR!=a4dL&&. et:i]E뺤i \.)-y2JL&ă.L5bYΝ#sq@ l2{poG/p/dY#]6;w^&4g)M5kv8*y!]"ԟVKv6|ѤwwwF ˄tP~0l+Ht[J PUM^;]BP uLkth6pL)P-=p$#Xcg'i6<?{]g-٦_U[%;:f:fe#I"ߕ@a1jHʏd.Obvњ%-O2b$vz|*g95SW|y★&lއZ~A cukZ jBN7@N$ke?ξf7i&J4+PNx15}l6G b%b͆Ih?DL\ݥ.<J g #/߉Rpt>i5,fR!{ѭ B>J;xaoG!Pmi+4;D<*` GlL~y f}.Ey:'MPHGL".VH_j-nj,RיhrTi4ʽ$[Js466K.)g<6~(Xm,7vt>:;yr[|z!MנMZDZM_}6ܮՑގwW .v.?kd)szGG:<{噸=0xsn ێ&LeQV~SmS>ύB2}&1G^ݧx*?dp%B0^E;1Ip^"?kN+&qKtIlUxlKNb:%QhBiZAKYj H%WNDG*@H@@jU!& ]u2^uy^Ɯf,e̛o/‚m1šeqy~u xŢ!q,rӳܼybH,cuuUwH رczt]T@(B M$\ehh)fgg>Sb4r!ꎯ:_JӴZ->|\kr1Hp$nE-w"~"'Ja6>hG85dnpLۥX3pyA&ǭs<W(=h=MeJqo\stő*sK]l=yW&d&:~J E[(l$ ="iO#&Ft%oe?\Xh&$RR!!!2@bT$:+1`(KDTuh'Nv||?1p~>_ʝ;wbqׯPV Z&̀Oߗxׯ_n}nKRass4>籸(DlbiZl6ؐB FQ(G e&C`oo676xa1l6+cx>}*E~D_ (Fxكv44 0AK d]qfY<ϓ]2ٶmI t]L&C^Va6GU,rt/8D!cla6LRi Q͆aH@DWz!CK#9 I{V%TNJR;Fy|uJ!FJX)Xf8T՘2q WgsBI;)nʐO>LkOM =a. &}mj e!89And1aĤR\1Eњ$ P_+B>ME{o+)peFZB,jJf$f8J gr2BF񄌖翐jfQʔ&w y="u@Jƚ"1j& w8i%Ľ̐gl/>/ @,}g Bw6kҥZN |6Q].Եϻ∔N`E!|H>(gv| V{χ* Z2JC!|%`'D17N(gh |9^JOޒ#d8tt:RL&Cq X+$?”M@iRz nYnS*ߎt֊Iߺ=a*|]wGUUn?6YKq8XF#( [d0n؝K3Ń!Fn!ˠ&#37 [w?^%}A+ň4c{Se>zizq^ƍS8yZ7)8nzݩ4u_Qڼdd*TQz5=le{N IS A TUB*CƄHg + -* CHE$h()qp} 7dt:s maT*4 n>K߁4kr;A\T*y8ޞo6ua8jꪖ䙦IXd}}D"yT*(JA<ۺ }8fqZtf4MTxKKKlnnRt*jwJ(Cm};G1c?=%8ʂjɡjHlQ귅Bb8SÁF ٬~~M3h4ZjE+++y\% CFATZհ:Lю*}}8Ҩr@"=~ WL )cb;58k$G>m7G?WxhΒ )$cJzALXء8g eh 09i8@p8"k`2 H.B 4 H-0lseFVL](,ytIft FX Ę1^&S1lH}fs}DKỷIg1rW8(JECрQ,%YB$ p|5&vDJL!08H5ҧM\w0S)ޱ=>àyTؕQOV➕7Ծ_XP.MvFzh&{"%~<t#AΊ1Mm{SX3CU~?bwߠ9?2h :~ģKt[I!'{5 hR\\=CQBTÏaܽKZMc~e.:rW5Nza?>0cs>SCLs$*vL\ymZo̥ tfH/ē0ttgxiyK ]~{:v;ipvg֎ 8&e& #f/Vۼɐxڠ ^t3[HN(d;'GDc('{LB*d“ߩ2%8Byyd 1'I3>"oU;38v\qkSi JP$$J( `C%vH,QU ZuQPEq%_ys'1kҽ~s;իWR͚Y)fNlEIDATFEp0 ;?*MA;nlq FHz}2qL>?ҥ>"p$ܟ>mc"=IUԓ=UqݢrrL12`eफ`)/BWoLmN]Ŀ(ڈْjz"+x(Q G>ht|!6WY8d$ƴ> [թZF3"x0ʀDcjᑙJjMizu.qu =fpL70cEۏ0ԙ˯j]gjϯ *g %2~ a rS<="6D&qC000UYb0=RbLC,z' ;a98k@{rSsJRyմ-a9""d DDfBN$th6L^M%e ߑnOuVN?7W?o`ONDy `1+%F y&{>|2~?k9ۣ0 accdǼkxZess3;i0U%rBR/%'k5VVV|2>\+m^;]CcO-5z}/[\|ͅz W{)ۂ 1m(Xl"H=Q s|ddr\1$6E+棛EnߩbLC*9X{`}!?X+pnZY2R'  ű6])ȧ fϢ63iE0k[d!qhzF'#I&bDzu9;88杙6ɤ4үhRhO6"-BO7{IăozIjAA/bVl4n̼y'M渁]=&jJj/ lllp˜\._bAt%<G1??O`cc#H |%"j#GL>… ܹsY^#fujq44MJRʚN{$^z8Z]7'}r֫$)eR7M3Uk?4o[3nqqZ&A4+@Zq-<ԩS!(ϥnçso|t;䴯ZĨ8jVZZ` IkewbV4's&vk>RjUJ$<-oPʆ ]g- =J!-79 dTEuJx .UU鐰O~2TG2|$E_ʈ(=EtB6"fU#@Ug~lҩtFad֖=vŒdl&i!LIp`fۥqtJu>a g6A6Ƴ"rv 7C&ng$*fUvB1Ƿ' )g;l[UiI;Ib(Ҡ"P;  kP"膐X*Jƶm$Mpym`8>7Aݸg˾|O&ן9JiT?ZirƍDs/筷rYQT*˗~uFA&h4( B5A)I̮1M~nn˲essrLf31(ˉ+^M* 1@ h_u(:H y*:w,ׯ_O6j{STa%t: YZ&2ATJ$WK?}vɧkxgW0SVwXltɳ8C٤T*%HKrP0 %c:ͦiU98̀NbFtɨ;T}/tRygh~4vv`߅gD,er$ۓ7s' 赤| %l]OnWWB0᫳g+xnjNn#6Ă{EKVh23Z4+߳J)[U򐯥qK2Ս6J+1ǜ.9h4<oUwfw6}gxQ@("x QDJGh !& jhJRhEp:kww܄z4S=9NWC?tg[\Q.};;; C"f~B>?;Ɔre3VjZF.ш`.]rڸEhNBF&^S*XJS|_trGB)m:uPv/Rܼy|94a~\]p6 YJi|g.q8 ALvfY__7(^G'uђSszbd2`MpuuseNؚN|qLa23:β&AX|R$>cVVV}(岉#RL%^Dz,.3V}<N&P-,mрRsJ8ōK"u<Ĺuٹww2`|=hzXZ#%GIm9 *v5-dSuQ]-f+'J\m3G9t`Wa{ AO _{>a=y #fV)Ap^rpg]7"3 p*lnQEL'N,r jR@?gHBPnSqc_mXGBQ$"eUb&0]&.`]=fZ%7$,;3HtI렟ABbYdoN?_X?f{HYJ0?N!fWbojcg,ؖbJ\'eoj3~WKTq 8;= R)*3d W/Gf<Mc}Wn2i|d@(OME9'?0hc)?<[~(PɈ0"0qvO%r=ۣV՞=7]nG m5MҐHE$*CaMjK|x'8WOo>;BWZBNb8v$^LF!B~5?VƚP[Bz5͚ȉ9urإ4SoLg _=le}|vl'ЦJEI%ĂBS%؅3CG.]hR5 5ĥC{a/eY|߰t(e!4V1>o2M_90<勛8msm._8CVS*ﳸqfv$QmiYXX C<ϣ~vmKgr||LVhPL}ǟLf}}q8<_x~VkzScjEXgZ303F!cL1 |ʲPӄ5vKA_kˡYx2Mhe󹳛&MjƖҘ- Ei/~KAЂ '<{AT{eaaZҒ8ho 2J RC#NL$ XU+\}'#'$Ao=%OVUɀb B9M"탺O.ЉXFR ֻ0,S҉L2$$ZPk)BLnFעJ[0lf`bvb[N&z8fs S70x|vEZa(buujkJ$IEDdqqׯv30Z LJw̙3,~ .v. {|Su/o"$/[L,J08KL% ;LI6G֩!_px~Jxn>ǿ4Q<|9b32)#qA 8ja2*cL]4{k8xvXE^PX Y2^~_ o'2xN=>;oU9gn;]ﮍً` #  $E PPPE Ί HHD%c{;k{ٝř'-9?9OybPw[!sIoXOl`_U+/V~1zˋܸq Ih4vG}cc ISIV0djjfnP}CJ%2\]]ͷ,..bFUxQ侧)u&''q]VpL}h4䄽,Zr|+kaŌy3g8+<΅JB3 :DQ2A]2㰾NߧV111ATʷb|]ekk+rPvweff&f?m\~=r6R3|tS&5J>s]{i(U aE b9/)S;mUaq`ZUJ sz@)5'8<ـҔe :hVj5B|Sb\i*vLA9.0܉4z`i+A;8iZ y@ά4=KYy&\t MXZZ5YzFi={,z|z->W>5LΕ}ʦ/}#X5q ~(F {Qlc1MO]NKC{ uF1Eۡb*}W8S.]2nDmw |s ]RKfvӎ%%1%J IdpD.}^&}iH5akx}"N8MώgOOhU?Lo4MPCjiF^Di'E; d79ZY?3@ Ðuz^ C4|ϋ}QVuJBɟ"zT*Q(Ȓ f cov-r!duu$1LّxH$'nfϟ}kLryfaERbKC& F.JCq('X+g[UVoi( UQDqt2Ia{ m)1Z:CȚV hK{wEwUR,ƙtIt}xd).%T3?ǠT`%eʪ>3{P{m$J0jp=eFf:f >9WN3yd ] g/k\u?5w޹ɤikfbJXR) O⢾ʥ+U7ҽ;7.t#vQE%R"$dL,G䳒&K>PV,$e%,PO侬Y&o:<5l/D1Ħ7K4ĔϐR@>H]Dc6c_??]7 |˥%QD~rgA ||ʢ.W?Cs%S])Q@@u\ץ1@?Vl j5:N:m&vvvU/|-(XsSν8+,Mp#ƕ "5Ɓc-Q3\Hfsnʽ}#綉;aٮahvj6bi>e0hJ$x>en뻋r]@K$3hVG%6KZBɌaѓ`42ژ $4 Y>gaj]t3,nUc;vJ-MU"bݲ` q d B\7P*!Q (,5IƩwΰ83' vx? /f}ёƝWC>n-͋ kT$-YĤg9|>xa2t:ܾ}[OMC_Seq7PHDDBX`0`2h]370 999_Z A:^8իdڂW2|ZW5JzVL$NE̲y.~Y㫗6ٍ=͕dg|{ ! ϣm(fq1o^δTTe,a2T0f̭N;zG>z\su]gqq~E&,--;a(ּ|$/4M8jrҐwh4 ilX`>byy˲ W}^tf=j 43;+muś& rvvvL} yyQۥa?)5f̮VQqFSnw2eYYY!n޼82|GfwhU}λh_eq^Y# #үCT ī/A)c=şIO)F}>MO(2wHMI|P1_ SяeJՠ4Kwwa7iRV13'b1N7 ք;Ppt)eنK1 5cThqDIHHp up8րM_fIʵ)`隠UsGLÔ >1ۼr*AUR6v<~r&x;O`w}Nϳxn_+U ]7eU|(" GI!LƔR ``Ǚ\mzKr?}ϋd?ɛd238;;tuҮ-UZ/ҪRzgoՋ zkѣ=H=bm-Htvf&3&?@nC˛>N8ylllvir~̹s|\ZM0A.Z$ E*BIq=OŋS~(؄eRa#ܙpW.t`} (y՛ϖZeaa$I}5t:znF$A#q$3 ɍz +cǎL@Ç,//cYZygN[s|fn |m.˲h6 4mFQv4McnnMagg#Gn6ilmm@~*m~ݾ}(*bF[sNOOvI6M㰴ėWxx35| !Xa3ҹY!31't)8=_ g?MǯL:Zs>!Q:z.jf Ex]- JV*JJژCI#ő$ ;& W^%o#H I$%A$nF0T@‚CU"[ĬEЪ)6))qw;YO#Ri:^ @tQz,7BMJDz4wC&Acj5&Xfg2͋T` I0kEe'TMM1EIʞ!Rۈ1 #f:v15 xJ3: *B*}$ O"4q"+~]$B?^`dߙ4f@0TzQB,{~E*%Ir]4d pDSQf&`lKHO˪vN:<^p/^ \xV͑u[\x0yf|ȵi75!'~hS^l$$98:\6.Sswq߫^0IYjb_ ۶M^GUUn ,eӔ۶i%zwmm )AK_|^gyyC `0`nn۶q]$IR&&VK.1x<.n_2a+Bbt"cTp)KqymPuVWWr [[[yjvMaH))!3e$h`8q\-8S>hR )y}2H{fS4-ò2T,~N1z4_R S*9 *YV2TtD)Fz.5RPSj$ b/vz/o:_/sǾdԬ$مĉرKCT(#@1PL,QL?AhhϺd'ط߀??>""ԚU3b48geRX D Q"()JEi.?_b=aӟaiYEU4<-ďV=(aa$U-+vofB|"bg@`Ul]40RDN$UP)8#$Q5D2ySػ"jB xi B0IAeЌs{q1Wi>eT`1 #&3AJ<3G듘`M찹2>d;Nbx_k1 I:)㾃ģ7Fp)@ T0rJg11 V+=Na+?:1 YrL=(Z1ݑwL8k=#Ά,hZwD+\NhQ@>̷#O#qU<Đ+,8<|Ao?M݋U|4ilkjw6xVA-AA)Ȋ^xWTMP,+Z R*Jqu7ۦMݙ9s83c{mnC&0s;?[g~!q(\ׯd)(`"u噛ckkvMavv4&qi81dzp|eYx"Uonni|oϟg^q*ǎcuuhDLc4"RJ:3p#r:B~0d{{7'dfffJMBR"@^__4M\UC6cmm~vHBz}R`b%rl- ̼DٗgwGH_`Tpd,A5x8!T NȽ Q6LO~aZD#8 2g 7Psuˈu ,I{rpetu ɈA h6y3J#_1Av|_dgbj 6UՃ@m&p wYF o͆dokG.~#޿KU Ot?43. Q,Z"h.~&g4T6oݫLW?WJџ8|O?@[J5AP0 tK,ϴ͕j5p]rg?.4] C~\tN,VB2pobq{GϰņnQ W_p%rV#I>ф0cHSg:I~+Kߗ6"/u(gJ[/+\x {›L="3 ,^dY0LF޿~w^RΤY D;[f\%ڱmE_=o[U8I (5UhU(bAba f`@XةX#C&v$vr ù\ycm:Qa)EU]zQQVod8r}677}uxj6_H>=7B 7u];wjf?75 ηHh{{lPʓA0 }d21wcQ3cGF_xG1ш~5\__g0PV_p;)[q]5- 湖Ð]NNN(뺆=9 G|zRJZq#QT)1fNy4%C 9 `uzzn⁹"ox~~N$mJ ㊅$Ğ$R2)?FWjc\Ӑ@y_'ggIEdY%p2|}BGvRb 9yM@خNzDn6 4gTЖ :8Vveg183 IEr + 5s!K0&8Oq1n#% -W}#:hr7c1c_a+% qHCCDcnpHQ_cIHmԜ8yV WJ3CyW>),ag %Yd)8T+۪qI`,oN Q)n9E(R$v#X tE.=3%ۭ0̆z`-p|fHbQuKbRK.R48~#*,ܽAۥt|{/pǡQ, K~{G=*#$Z e]RA8@V鰺O hZ|_ݬvoQ*uk5e5/bHAy,pL:F9rxV)[]zu-R& H΂R(*"J<0[8ZuJës\jY4 3V-urƳ_.LS~wy6~@)J,| T]}J ,ݘX duT$w@r$xV.0[N މ> ^' oe?ξImqCEĀ*B(clP,,H "(MQ&cro =OaBt:Y~~}jZک^Tenݺ;a.IKFv{{ǘke>8wosor^ё>BFA… ޳֖N &v{1Pn;w蜼A@VL&\ץja&bQc1q0 vM`= *2Ry~Uj`RP*Q},' Z>q1 CT*z(m>^ak_H k{"5lÒP+ijH!6NhO@8@+?Ɛ3I;Y|tζQ -~ +{ {XtLiZ.8a=`Es :ԛ w<]< P]dH'e"f``.BIӫF@!/&y`|VBPCg.檔f9Hc 4M'HRI/ˎ)KxVT cӐ06e t79\849;?9#0C,=BkB^W]1Zm}?[t ۂ܉h4tqJaNV7UUO\n~RSuѢ$(*FjBnVOs&_|**.]n|V^ Գa!L^fEI|B mG73P鍅 Ԥ3鳜_}Y<)4 ℯq%V '!gAg>IeHO \`P7r^Tb"W6 痆Lc8 Z/Xs۱E a4&i0BCQHrh^G<7d?v;?\WwC u`fSGL !!$ĀXu P+I=;H^&ر ?"~<\zw~ V#ZȵVf6YŋFE^fI"`cc5;;;췱adFE1aڑ}e] 0f1ܷk׮q y||lt {7zt]v(njF#6"M3v]=~W3 ONN-a4MA`5|N57Z^|> 3}tj,ceeN/*@uXniZ sTbQE**a`6#0cª&Ȋ!7)v4kFiO/qv%݈-wlMQ@R&%4frGF5Dmְ:INXSB!=ţ ^z*L\$MpL*dJtEJG8`L#ӌpX).wǂ3 89)*x?U?fNܿɞIH D`Aө;;+K9,RXg.zmp7Lށea}se.W^-x (RJN0:@,(=q  0ރ-sCޙeP =%x ߠ6‹(G"Q2s7mVyps]}=^Vc zn{[h^h&AGw%SsqoySdz緑+ێ gΣ>0LAKʄe );cAMG86a.uOX_;eF?}0RojaEׄ%@#Fek[II L _|}Q(Z}J)^}{e.#4a00 1jܸqh+uA6f֭[lllvfYgL&gBj*ӧ gՊ|8<أdCvB?qor &h&{fM4d$̔fڍI,x>_|X^2|٣kڈJݘ+ۂ?Ǘϼt]ZO>:I]®tՊEE*oF]C;VgC6Lzix̔Ý;);̺fȇk\Us̽LhLIK-R.Iq`BB; EZŀR( 6f'4=wqq ܹ=>4ƍ!Zfu{} àhm CYZZbccClojh<ٳU lllvLy;!fE?~LV#cΟ?Oq)$ Fm=ZPN`!6:fSt:]XD”]ۅuqGiA@Zcq4a<C۶_* ~]atޛWB%}}*>\ӽB///y&Q"0J* aꂯ%?Sמ#lpJ嘕.ƽ]7eCR%ꚀKsd86% fdB|'g?}~DI!`bEaP PcMV a+y*FF9ןn}DK^0N}`fXtQџd(1``yQ⌓^wm@%}j6mYL'd'E!-ܠ8=n ?ɄЦi?&!(Sj3^t;m3Dݍl;g<5=&HQ8oM R}nELA0vk` {C%YfrCɃrBw0l0 o2gD[/k'o~pVE^"MS"^Ru]Y\ NK-J){ g@i#FWc9 R_%3NQL-λ+ln:פMw_<«_q}!j?zn?p+ eZ#Yד~"9Ti ~ :wZc 9K[*5 C)A (;u]ijxI677y$>/~f{#1MTh:-TT#W6l ~g١8OMoU{gc{2iqhBEE!UE(7@bɊ;T@PBltWXTbH׵G"e6s9y^<\.IԈφ!~QzD^Hݦlr1۶mK:u:zVn/R#wmnVlnnh4NtZGRY__7Ɂٷ&\i|Ft:y)8`T" b 5"ܲ,5J%S-BdY@Nf2Vt%a[*XY %ͻ[lCC'\f:q5qUCwi.i6WRaqQ"P@)w.sŜ"N#&GCSH$ MbQ-LiB\}F -M%TPpT+ixh P9sPr!Dװ@kϧ18AL<,'GEr \B?R71tuy%)z7A_曯֭[Ejllllgw ^g`% R(XYc06;;;O@Ji0BV~$Lf0 t_&ͩSB/.a}dqw잯3\|Ydee@rZ*11kkkӌ9L Xetl AٴiwA!a áx^ΐZ9t tA>ƛ@Szקm;nNFGGiZuffft:)]Z]>BgKess'Ovy&SSS!1,H\&" lAG 5^m^sz=󑢧/5'V>ҭ9aʰFhcc?uNJ֞) /d2QPg iF?9++3ЄvU,a[ eFѡ*5w3c ż2,*`t(.*SG!*"b @A]Ǐ)!}-M/ n'xq I}w9$>٥Ts8[k`;i&AlB\ y~h#e[Iz$Vߪr(>NR&@\$AY-$Ӎ8 PIQ(ާπ^SmI$Q[=͋e?3OfI6mlvn]QTzBA"T`-ழըln1nI&7OdP,kr-m;<<)Jz޽˃9>>fccB:qmj5]<~bQ?Hh%H>h4x4JZ.kkk CuCR*y!NGsgMpuuq-.jy8w]W;z~NCZ% }my]BA ~.='8$3G0Ϙ9u(Q FX ,w{}Pt$t8 ]&K?}c+ЪjM°EfAL>rߓSە[:>}3ԦDijZEtRNgē28a)-7$o&o986w;. ejU0Ə{=  V'lTF @ iLhƵo/1LJm5Q[!٬,1irjUU~&OD*pssK)Gw4G^4KӔʕ+j`*- !O&/Uu>o /S r훋\x4$,?$<4鑇3<U)E^a(U#: {MplœRF8|"ׁ3c.DTP^%ORTM`HsqM&f/Hr7g Dx k3A_nҳ)R㿨,2NR"$!KT:0] _KkWJdK"GIdeBh4l WݔE_M tQhEC 5lKp0TW\8d_`yBU6MeJt]0T*AkkkΝX__'MSXXX!P㐤Rܻ CVjuVVV!v*x9z|>"hFXi F#RYZZ""n޼Ǐ" C>}Dy_Bժdk}*^oϴ٠svvx%}azzZ榺q$\.c6iRTHyVWWڢ\.:a(^<|իWjlnnj<QF`8̶)$"7!2a\“d6HY)Ͳ糽# m* /Fg@ :}jԏ"09!ǦWLfa^8 ..c\y8p={Hk17u-BDdFa3ͩTIu>W^o.w16=Qh4c xNaqqZF.cwwWũ<9`6N$? SSuui>A,D{b$&`˲z|t0}0 J⷗2 Y<X$9aLģ*7j&>m#+%hյlU}t-MJ}NXSfocsaO_U%W߿,GiN8;1< ƃaCΖIg sv2G ?d{H>oE?;q6MpT *rVH*¿sā \"Q9!QTVDOᦦmdvz㙔;`xg;a+Y)MЭXfmmmtUg-# ARؕTHW] EIK2m3Grv} /Z"@I[i_Q4M4~g[vA]:  ¯ Brh`d5 {P'QL(޿ ɸ=7vJH @^[!I> za4[ Mx1 _%t#(W羭*mOl"w5j@ ̙ JhEa͞HDpAqB0do~ ^8t[15fQdWdsGHKs؀zv-һO䙟9Ư|f^vq ,}yO^*O(ڶ-O󢺖c5UE1b4UFܙAjF},}Un>ĩ/Fʷ<7m&X* Vyi&y -I؁ŀ>:Le&Dc\`@ uemKwUg}!l)d-M>Bi*Owȧ5q1 c_;s_xBZ"^0 k]8zHeH ]ܠˀ*_'cǸ-͗ }Mu3LfLhn/m,(AyŃ^z=XlYjb i׶tw|d&{/=RQZEse2V ˲stݻw_,RRvDsݻ(4 I$qLՒfҮq,fZ&+ gi_-&d[}AuxKUvtGt cq/s%HXـQESDMN7?Pe@ghsr0SkcY?qYjSxT [(o/3Ƹs9Q*,Aa;ak`fiBU5!ZbWbtH1#N[CK?OLMBqYGZ]LuǞu hۯ p4&MQ nNehEɏ1FYH 4|gAaul~<$˶!jiض-3?:m3 <4U&j*˲85BV>7oRdim)ou{8ߞ!luu&d^IjZf˲ MEL00(,$m=FZOy4"l8CX@zi `:9M}X(u13E&CTAh:n@7F/M\ 3҂]{?bl.|_mWxF8E'gom3UTL1 ?ȄD—rׅDdTHE@ȃA0 UN$C6kdI<рQ h3AFLr]k\Us?fdji:I҈h!`E aBR((]s!((vѕn*tW.j1"hZ)|L3̝{~8?a8=<ǐ H322… q#Ej P kÐ|>Oۥ\.+i FGGui>'|v[nSS"/@Ro߾MT^l6y!Ga6\z,b|x1r\\dz/xIワn+-BXرcͱ@&aff :/^d~~^Y>>333I8m&'_ɓ'dct`ttT褥QF-K΀"ڶ͝;w 2 C  TU \$IHؘjtuh*Ţ J$H)i9<6MSu8qN 56SCF:d@AyC6%nn=l Ƴa** S 2P6R`ȀB HYB|b?\7}CnO~|_΂ IPl)S$^8a,qrs(iH˘$#p$5kŒ8WQQgB'@ڮ  pk,,:`?֡%NG C(" l LMf=*,SAJZpv] /Ț>{8+';DQΎ:k\xʷ Ht>y>fS5bN!tㅣ\RQ}1q_ج{0!mumU *rZv7~0[|ӧOS.3VSf yxk_Stޜ橽ĺ  ,kP U:A 6cU'42J3E̟Tk py"kohzḊ|lvՒM:t2J.ݣmJw)6|gԆ薚s4tRzwRȸ\=Ӊ".[G3 \n ݰH~mI"{ԲB=oe?|=ǎ}qmN֡VR-UR T0"tU` bPU aTCh!j (DMhiqlnkmhyy3,U߀y:X qq/.arL&i6+6ǑUrεZM'OsY?5}U;NPzⱤ6JQVjԾO+qZ/(\#B)(dRyYZZ"dV\x\.Efgg)ٳgG6y;8pBeE$ ڴMT )>p ׮-2==M*annE0 =fdO_u]mn߾RS%/syfVy+q_SJe7 EJrlmme4Muݒj ɕ&R7޿GoVh|,b?tXweYdY.VI  Qȵ;|7 IEu{SP6.OUje bO:Sw?a0G^zobNV =D#}r.V55mWgxD);cyBEL9^tp>wi3hwpmphĢtX{0􀕭( '^w_q׿KoU3[H@Ӥͥ"%*"R?M7ldQk$gT*UI(Iskvgƙ9X,\ok)gTbR.Y[[P(|^A(\Zo%| .AmZzٻRG?^)( ;00@\X,hFڶ6zFlnnr5Z_XZZbzzYΞ=F0MDZwΫ _ `ttD"ǏYYYT*1<<Çի,388adjr9۶} 1A<'Ojw p C |nV8LzN*[Oy-PQN-x>!$>G > yޔ{&~`LSN%eUx%ar۳/OyoOy"Cӻ1heĭHU!6D%0çY+mp!%QŠ&l,Kot-?߄%50C}gw4݈Vۢ/E3vqx+PuGDi.}t&Q.ʆNȆncp]Uݛaf['f!=cPrۼ7| =Z ]Qh~`IolGNb}F~eFKHl gNqoK݋"]_"ycYN"$XhoPfŕ_ꍀ7cH;[醁"E×/.s!s+B6ǝ;s.Y}̜ĩ sss\pAur|^lI,KD5˲:ܸqM(ˬ&œ'O _rdmVO:&N$aY{{{")0L# zG&S܁L&C*" O\vH$µ;\Hyy77NgdD$OlF@ohVh-ӁW%"̞rFv}($>Nb> trC~:8[=j@FƐg_ ٩ΘA@ݯZp< %Q5PdC9ڲ:#ƘO0c;C ]8}Pi= degEZ23Td~`Ň{eh oc0 Q0{u]NоPqb1ҎSTThۢbx{{7ϵ[<~۶1MSjqX\\0>>n kkkmf )GGGKtzo_-JVD"A>N&q%I\I}l^d$M^s\a]gBD1B8X' h/jH8тDd|BUîB|SJ! 5_fP_om7@=ɘǾcMcjIQ᷊ͥq>1&| ETDj︃9D!f/f>Xƭ {KoUq\N&*ESRE!*PvH[!+J JPuRϸK&v3x&=eYfpp$m={bڶgΜA\*ϑWwn{7e&kkk\zeK. uuTUp]}M8Qݻ(Bܺ+$du1FGG0 I$ saFGG/@i}`Y`t:irAǗ7^%0yk6""zX xׯr--R% \I7Dx<fzO|^hv\dr<A?gl28wy('z=bm;{n=TG,y#z4)Lx/X`p_s4翟eU]4TiRmdiCZwtB.\0~Bľ5З(iqsZWWX{J=]lSe糟kueR&2یH#J2QĀW$44hL0(($2–-HX_kwN{Mzs# XV=A} i"֍ {D"i|Ftud2I,T*]N#5k0immu1N׽(,.--tvuQոvG0޻w/D|>dUUٶmCCC4NGG۷og%*uK >|H$B:|"͋Y(k5/Jeg˯M\:>G+LNN277G*B$-Vr*h)ݭC:ܒ K g9VeYh hjjbbbL&C<'0??rS;.\uǪ}'%(F"쌞69)'M_CC eم)=X(y";2W>xx^8WG֏6Q6[eMU*K*bB-;[>6I0jqrUUY׳ÐEH,JFW睻f܈*jш(ۯn@.@0>eJusa{~[e3*U[.ԙB1cϗՐ{,[JHg}AD,VufAoOl ҲGɄY{mA>>˗/355> H( ===̐JPUN>-Α_Itd~I6].J]$^?~#Yu1$*Cۛy@xYja=5αӨ oo oe?;;37]+(DbA4Qo d|΁3? R~sB͢ٵ^d)/Sb^+7 {W$^t&VPD:n[Z~{%>mnVYB0piBN ՓeObIUmb0؁wr2u M ^7ĵa+ڟ Ky*,޴nEcbiK\XQ?.}`5hV?WP%˜Yk$DXm Cz Gʯ6$¾&٪L"H.eCb斄+`b"A\xm;DTmTaJ%GT*N߿gE]ܚ"-94HP, BL;jk{apS~tRTϛfhhȉϮNu˗/sqN-p4I(nZ.f x}}0,Tkȥ{ʡ(<[Lj!\|&Aʰf57.HɰggBSlT25/lgn`Y2v&-Y/"*}VLMOs]( Cl&ԼTٳǸ9/yMV.kYF7zB.m[A P0%DT(woabĜY7!= *ou?3;vۗ-R.,i ) F=$4&FEMЃ^MHHţ&T-Z4%ݴ}}yYL6{/}#9;'+(58*+ɸ ܽ{1<ybKKK@ g.~dLMMQ*~>qS}^wNNɉݕ4GH$BTr@$(xl6 *t2Y]U]˿ZRVB!t]hJ@4ahJX@ Z&'s;eu ge-3( loϜp{W_x//n;|3XfhZzG$eNJ֥9)phQPA<-9zrІ)C6Ulk[a*Hm#r-i4LLLL&9r&;"4O.s}u^8ύY\\tՊŢ+z4xy ߶O }߯yy,^ߛul3"omM9LQ`KK7W9< j6R4C#8,DseJ"?kU3_n$KHClBTDlcZU[VxRPDZPWEA Pі mA eS7fl_9?չ= 9{y~ؘ@ZS@~Z]]tUUT= ;{ňL>LR!3??/+ؠ{Z n?Νd2e(J~ȭVEM0MS,RLf'0>>/9S<;(@粐t3oA#mmS? Ih' ߖVxvΟ?O:ftt x>ogע\-$Q 8M)a62.| |^frHK_ٔLq5;KcY|nŵk) 2 8r HS`3 C׆6;;3R)zzz(E:I-a.)Ѷ4ɡ/oBLt/[. Hu.,R*$!pb,]e`v?\@kGf5ba\%]067>w>VJKvyV#@WM"lYs}Xb`8*.ڦon'&Lf3zNpc9SԍX:k#'p]h¦Y V5|"6X_]ρ:aŧ4\xإ'jLJA >-b`\`B?~HSv\.jUJ+ Xuo a M4x&؞JQ8`[M&q#jidӢp7TbDR;U \e ) Q,XcȁQLf%˱@TZMУ($ ko,//KfHoo/LOOS(bbb_r !",--8|U fSƴq;پ_EQT6U9"I͟}ȍ5Q}4)̮pEBlSKXk#3[U\Nj}>ҦB.Lf<݃* ZʹH3Ri.՝0f8nyR4r{add7~gGGiH>{,/XQt.#خķ^EH4} N^95ș}r9${?;i/?"J-ME*"C̭&SSSFbal=6BE0 Uj?VE>뷢 *91pov O(Qb"Ȓ,d߲DAQ] 2'`>/VHSpT k~u_vCfJ3}~n1@EFT*tHn:{6,Ԇ -{(볨*{YM0vS貦I=$F#g'4X*@$]*mBq7+. FЫSksYzVQS\&[@~l Vqa$g9'zdu^Mrs45 8΍ f IJy {R,IAڕMle[hH)h1F5&p "ƃbFA(F!QbbҖmbGw0 Ƴsy~*y0lL&%6`k`;n7i255p0 Yes5k .'*NaiRIVNʛ`0DӢ(333TWW;@;&ŜH$BKK ?4y}Y\xyL]: EyQ}&'gyqơ͂CWrlq8_{w]N0 2<<pd<*q /c:d29d;#˲#lٲD"ŋ̀].d6OOOKokkC4^ N 'n:99JaMv۵`.^{c& pcJ7py}}}J%ꨪBUUV\&ikצ 2EUUv~$gW &'=,2G$p!c}%/ŨLIVH єy-CɄjADq+>ϋ$)Kz[YZi[!! TKy jUp~o7l#tv=|K6&A((Hp[Ƭ3]-ش*[(RKϫc0sb, [yl= Z[{ >׏4ɸĹr_-RfҬ[KJ27~Jr#!!+ܒ_$䢄ZufE)/7S꘎'_XB6 >!G:?~82=(uϊZcyǭ󯦦#I9ʼnc\C$RVfy9^cߝc}]nfhh  IHX,F*"XYIkk+Ιns $xiZ20 ;v[)qm$D`$ [ն+K(2l+'s?0n9A5&PeKVu^eҋV\x(`mr C-YI :R$ sݿ?aۡK*?ole?wn6YƂeF&F11Q"B2C[K1!1 P _`XMpkX{zz+ط}y~[%I066r{Ӣ{ kU p9hzu7pP]Lop-mg5rl޼S:DǙe2֯_O{{ 3 cΐdT[R\'bK OŨX"ՃϐH$875DPLd||-[b[U03xq_Z!80F]QUջLmVYռ.D/Ix;xu9~P(E5W*FFF<+tхvI\X,:eE$3==Mgg^Q__(0(F[Қ8i QQU[nOseJ"#{TMR5uhQyAZW.¡2MȵT=O|{Kw|L,j +d.i1hS8\N<_`T`Mݒ]f^ma.!.O*XI|dK2{@ujXv@,Qr~$.ϋpIA-92Qyϒk lFYUfecZc3h R-fJ/W=Ѱo 4!p۬jrl7o8g r ?ii -1E%dX\Xe`UkT*\\mM`ȥ\ in{)[EZV}300ej0x<Ų ʖCAx'EfLE/i;ܒDR)Y0vfص?ŵo ٿi H>?5y_,[\qPXd_t8;g=m+ dͷ!VaM$gXa?Ǯߐ^։UL߬#0 ?gXݗ"7*NЕqe?(@]3BXpr9*-/xfh^ϿO[u?/vBX; bU14bhDX.L0]xa4F.&,1p0aѱ}o/Nox{r.O|F-ވq$xhkk# ַ4~^qbZ"$wocf?^`H$ԔٳEQz=1HD.ѽa X@H[5k]^-g#ߌ k[e.:(|"%o 299I(t+WgQUUѬz*|fd32UTmCU}}@ɤ9N:::cK?nn޼I:\d!?ï%H( quKWm3=="˘Ȁ%-a8FuKFN'lV 6fggiۥd2ad<óGeeomnm>GvJ#?IJHk˒B/)xj7_qq蠰M>e*-N&H,fܸˠcpT4Zs,I̧-Q  ( ]6t!É FW>B 2?3 >Ol`2=6+yB9t_- k+SP(3O(CCE-"['ܲ*qWHڬbXH;̧*DwiH5&.mPd~CޗR\M.R b8%ʵ`֘Hh&dթJefg˯bךR$lvtѷ}vX=I,ڵkT]vzaȴhmmeaap8,DȲ1!+P7T* y&eyys/e.,lx"txNwv2[<#DE*↪:A*l.[,.^7]יd||\foL&47n5B;vӃ?`zzͅ H l簪fɍD󌌌`,^t]P,-vP.I$#PM8yg;X/xi/j5 $xlL"KPWVVXZZ^sNa @Qg`0(=prd2dY666_t`>>50 |>϶@4MSREzll ]שj:l7#͢,fD9z,pozr7oÄKFQ/~ tD"!R)2VK.{`|X, }А\yZF7qVۿ oث{lf&&&477(h+1eCjw l/t}}}Fz]vv!N cEQ[i:u Yp8Q__k6K*5+d|>O0b!I ޽{Eb5`&\.***hF|…#hY'vY*qHEQ8tz,&Z?² NrX[zj(O:,_$ lt:-}hpuA͆e2i*/+' 1??O*OrfcYV`xd֣"GKij]nIbs*}49T ':K2pz;LY6xj bҪRDIR~B~\?pB ud<ԎYov099)<+plϼw;V<傘KDL6Uqza63`McsQɭdj.j[9Ș TG١ri$:bj t5+aJ2Y\VIvv:LTs:N'yQ%tUƙ2p61cPcR)4M:]שQYzD"RHD(bxxx|Eq뵌V -]ש͑k|H:f/%~YEڅj80yAfK$CCCcDp8Lɧwu< f۶m444ۋaX8cآ@Ckk+D"vM>gWsM8~t=/`Y I27Ee_<Pym6oL& l[Z?AhFbm2fM4({#YUg.\~)1b+lNCCo}PK;XB]0bܸq%+[nErtY+wϵW\ҵ>r LKG62{@ٺpbIF>O /*l#thu?wK.Mmu ZV:(sTtE (TdDdpVSԉ2V9nڵGzi&r><+YƄR@K ҂.8\\/|ܖDx9v3aɄTN-nd2l,A?ht:$MMM`TTTܒcrB( ]]]d21G ` jkkmihfofi+kkkill،1RE[$t]Y>cŊ-{aam;Y把:D+ X@ȑF":ތ[qTàc6s1ku sIXy>y`;a绖sB k"`Yr(>j$7t]ь(D"k,H$YJ`0hɲ~|>ފ"[ CbC'Cuee;_@8zn7}"tWH|4ohQE6%69P9W+d<29'ܿyE6$T W*)r[aL2dttnct 6ZKJm?w`*\̱.cmP*4̊5g>bˏZ J^F>M$5A*/ \12h ԄD^ŀ Jof.LP,ԯ~Zܵk75ap6{_=s&wS_`GZr8vO,#3;#á(,,UUU\.[C"ׯ355AKK Ӵۂd2ZMQSSi_'_8˩[xEG%k I $Ϗ; 3<OqقL[$NƢ)~_KH&(yzK:VX20M"k T@Md(.*ڞ Ml6AԆ>FGGzB!N}F/E,`ٔ5:z444}K<<YZ`fO4ra8oXL*8N,:cO3>>d9goxk yvŋXVNLɴK]p(ˤib)FGGn,LC.nK8P,RI&>Gz4=z^TP[b1ˆO)ڦ/Kz Z*C PKzγ!D^cVc0\W0`^Z"ll4`],ﲡ8l%qaZٽÔF>]ץh4uQ̷f5RGZ^ Eaxx<.y—#Z&E9hB3gT*ڵkbttÁiRL[ZZhookQ![40<lb3u4^7ȈT6nΫi/rUѨa P EPX pfBh ֭cOr0WLe^`eq iTo]nv]-l|;/.i73ćQNbӲ, *8![|ŀlBd=%㛞<,7F4Íq7/_F4z{{1u^o+*Ǣ&'l}>AVn0,w*KZ$OyA s&sqf7z8I@mT]ba,[znbf)~ndq evyo[8S;> &n3]lSu=-m] $Ä,QԄI0c`ј11 M41zި7*$Fd1& ȅCqLkkwxѝ?,:9>(Z,f ~hyP 4~뷀+:V2`U$ŎJLL1ΥKB8UlX,"u/066VYY8&HQ*4DQYo%W0޴&_a'(-Z=|>/d%Iboo/rW/zmmmmN" ! V]ꪺ}:KI1$ EE֨&ᴋwQL;asBw 2$A`g4k#Z0їer*E -q1n<ʼ/s-dY4MFFFB*N@kb۲*C*@@H7[̙38ѨHP$m۶Q*qN"#BQu"`X,Fgg'!d٪{'|mdppPZ1;;+_*a{_J$YѬp055U~HbSt+훆,+"F*!lkjjp8 n wJtRAw2%f,i`Q&GPCP^Id 4JeF:9 [-)t,<%U9F岝wap!k [bY˯||~b]uX,F4EUUQ,Jx|y >'O9)tAvz000"G^ud2 340Ķrq>zL&Ã!U!&Suؤ^vzzz3uiʕ+LNNfEv8΁+c5e+Vu~_<"r|JWԒLۤZv?uDrqFM[HH`n]P;xT*oŢX Od6(4i%ֻyR:x |.Eិaʸ ^}cE,4W[;ZX8ESwYV_&LY]r"!8m7AvᔫN=c=ŔtTɉbZ81a<϶y_߽Ϧ"5 Mhe;M2I$v]%4ThEAJ?E'ObC(B#h*Mɡdնv'&;~{ɋsa`f`}?F7pg-[V. juv Kۨ=a<> ^Y`ttqԳŸs(v͛QE ;RvnnАpAʕ+߿۷o3??OZtEw.:D<g||!׻i+ ID64rm2a2^[$CUۋ? "2@@{4Mc߇H?Նh\IUui3P <ٝǧXV3 VJ{#VWYj+{{PoHQfL\ŁV>o=*\\h4=T.E~>ׯSՈD"R)a+2HɲCu:$A( PߏaBvhuuu*np8$I  Y[[#H$j4MѨ1 l6K2LI$Aر>fggY__I6<Iip#ÈMY%h~<DK!x{*ir8ArLCds>O:&ɠlNMϼ* oNE+~v,n\&Ɉ6܊"xLPziBYօ8{ffnbp.&&&u2R:t u]p* |7HOO?RG> zgD">Ϲѝ&?+tvv UCӴeRID,-- D͞o|>ihjJ8, K/q~z8273q49'GC!fRwJk+Ih:/+}emGu^Mq?zϦ:,N}yn4 |'o}O S(oyhLb289(1lP9X8ԵTK&8Ӌ'ys/q7/9Kj0d7c\NvIx0%VTyP3ˬZRk§?!ӽ%C'˴N/k[e?9I$I:\BPjA&/& Wc dl*\ z!(C/R(Jgչ Ya뒴[;&K4o"y?swι9Ŷ4&%11`O'IAZ_8i)փ#9[p^~^~dgk?DQb}}}ʕ+Wr$I<hTuz{{YYYa~~X,q2 SNlĻ Lbax`vvVN,ZGflٲEV- O&UeYfпXŞggg'>pi{L$u ކFÂSk%EߝA`mbVɖ-tzLTIU'4&B%٬pi΃*eXK#YңÛch&57馋lN/a >>d)D cو͏Zq~d20UU|p:RmLMMQV蠯EQ㘦Ɂ$ n7rᨴ]p/\`~aA& e(a& 2>>N>gyyUUeիWT:44$'nai=33) Ði*[DKA:KKKrD6 h9uK0$ z,]jNoխ.Uy6Eü6ԡ&)-f5,[Q M;<҈GVVVb.HxاT*+d4VB=at#l*&cDjp)\.<喭x Iʠ>Kmc3r.D",..N[f#EPڵkTU^>r_h40 4MkY;T&[ M={$ oz6c'|T ]yPHJj7fRh4F4ٔ` X,rZ]ʐKMo;5ժb~;Z.jوyaX,3KݭqZ*h6\x﹏7x2'*gҵP(`&ϟOFy?GOV-s*IMIegrTYo_#vb3R:H[9[׬|4 *ٲnW(Hm`ss~*wÇo`Q۩RID$q ke?3;_.&14nbR"lA[l{Z ^HjCzUBJb9$KSeIu̶Lf=L6i}>",.XJH\d+>Z{AF>w])R*c2oFi8GСCyFFZĴM=r,ccc24HQ 鳥|>O$4MrLMMalv(Hi K.A{{;X-o{⺮[[[.K&|)iCTUOO"BS'0#6q6}~X,FPu]IPysnnlS=p<6Dq6VWW kt:>pFz7dY]]]LO{FR"&«FiRԶ'aM@d2d2l/D^^95a ~Cg Y] WGUt 7@MPTYsyρ0!nEŠ vz +, ؋ ^WhYJ$\.KnDjkJe9jrR0p8(jJ$!L'0??OaaᱵEgzzZ[rVByWνs$78g2@̄F(_aiwbb(=RAPśҨIdqI`nkkC46<<%ӵd}c-~n|>N=IP5VVx:JDs ৲QqaGhe >ۙAnݺe dX7wY89zBEe'ݗW>xQWԨN Q*H])E;G'9pl:#g lT#J(S 0qSt|hJ14/r0uF *c: *ܵ\ҡ:1s/k[u?$9Is,iItimS'e.6q7E ܍l ӛ;EoD/;elRmQ:-iKO&^~K |P 'lf^{^Ldtt0q؇ [VȀan#~b"P*(Jrz`ll @)C:gϞVE6EucY__{h4JWWPy$fSPTĕe%f|JBwwpW @4%VGdcA\.,4>2  ,vӓl..DfgvZ-]M؀C{iϼ=NA"2 Xf@{,7lWv/ ?DX70Dø_' '%s^\6"&12|L)t]ih|2Ʊ`Y +++R"ÚJ8t333ٳjʹ/ks`b #SpkYvkeXdȏ\.UA\Fmpy՚ ڽ{7GRvG%T*JHL۷355ET&^Vg,›ǥ0!CCCqc9_49S|M*H\k6ϊHщfӱWr NM7St뛜!//+Lxu]R"R|.:00 CD/ V.(x<\[[CUUb+!L&1DJHlYgE=ͭbM-n n^dzoa.&/|<ϕwGr2HUUܼͩGt:--}gJD\.G0ɝ;m\HܺlR!JIP,c׮]VX,YZZbqqǾ7J|W,D/mr5ܷB܊4Mmv*USe&WW0"o_ vOF9]'0aaa7M>sx̆ioz#.M}8Na,7Li6q\} ^6ɡԸS1Yq/Su6F'Î(͖,a1ɓ6;Xr=5<ځYGS;le2:ca+X;Z$Piنnͽr3Ole?oY߷ﺮe)]݆ &j$zDE1fxLăIDNh&eȂftۺڽmy={GzmU155 * iR.m.Hr]WFHKP; KtH9;z!? OXu]4M_fXE>`||\>uaOlA3hm;vs: ( r9|} /^: acTH&7I$ضM ]aP4/=`j.ih7}t^}׬&~,O6YXe[zHXI|k5`ٻ l4+= 2Wjݮ^~8ImwMBa###q?΅O(dz.Wn0eY9sFn9i癘 S(x9RP(DTy;08)\t+WDޅx('QA2 jUGaLMMHM4-M<qE8cccR)4`P"qXE._,[nEu&''ikkò,3QtVtMB7TRեT8?mj/҂6'f`iXyf6EPlubQ%a95nZW80Cy ÐhfՋ3xiZkmm5Ա1T _ naH!H肨(plL̅uO ׯ_gaaIYdY <öm: L&#Qm۶wVErHdhhȣb|n`|\&_M,/z_sFVQCm CgcO} 3] UB0'::: A9ɠimJ5ػBeT;K](*ZMnD[ָ(xoG pZTN\;]>;'3$WufqW\FsA9Op'J=:8ӢRnMp #S:ݶ7Z揮eNzO9*;s!4_ e'>/FCSꘪh _tj ֚>}<$WId0#W&]#kl4Ypo{[lenݒvH @ $THM&6D^zabȍ(BB Ơ1T@MYLjl1YiZ(mavf;^%\Lf{fff()B@X,&gARI2!RٶX?(+Gq@w/#Ybl_SuuīB2 PέXhD/4b+ODu';>>Ζ-[F444&K*㡭Mo6EuV6܄MUU=5ϝm^*y}6 }#d2CWvhfF(-}diQt-Ew||ͳyn߾-('zbbNUubo (>i RD}}m2i/YHk!\\\2Mr#b(>apeFX% nt  1 rOxӼ RȞ]Yrk׮~摕 ?廄jm;D"E?22s99D"0[̢shiw^\G]WD⥰٦iIR%T㭭.53~ v=MV&b! Ʃe0]KMdģ 3իWQUYLz'&z7A֍LWfISSSSStuu144}%0D"~&"Z&ߏhF0$dPUU_U8֭ˆ*ccca << ]l@@~zsaR[[+hCB! |>^oIg+W{[PV*ԿQԼDˠѱ*ɜFgMnFbYyW*=d XXb>mv\o8`ۥV\Ċzv;dRnDXX0M D7v#-jP}nfffFR&.ȓoKXĹinnNT(466a-ElL̓{ϧ/];~IZ~\ξ=S1{>rzCY{{;p8uxi~?x!&RQm67?ºu!Z[[rܼ9"I4奁(WS,) g8~Mm [T-YL@+)gQj[02KT I2{1VҦ=l]#7xNM/oSe?=Y9[Yml l 7\E I1rEb1D`B&^,Ę8w/a֮N׭y{{srr{}/)j&_$$ܫ$+"d+A'Ч˷ژ$L244$۷%RE P"ȱXT*%)8a9AG`P<'x7qMӨY 뒉߿ERSSC4E}}=t#Hbve"ql,CVQd*+uػ38>;W$鶛ҦvtH4āռu&5v.C.#\WMؿugkR{¢ǮxOYSC-(2`s@D|gdTx]`rrU gEBv?[U)Xͳ]Tg^iҵ :qm*)\,&C?9kLe@m(V(5A&&,jCחWy^ưXL*SjGF\.7[l]" DcddR]?7sI ~)4;;mȯXMQ.6-"(\~_neqZXXp0ݤl0:[Fce`A8Ⱊ~pwVSdoSRWI,fIa9ϸTC^y7% Ð[q^.r瓱dhmm6y zFGG倡iYq.$r~aHȧMhaCnIRH>o"gff䴝fMnG "Wx^BZ&K҂r%7s=0.=]`fC*MaZNիW%&A6l4if4M#KBA B377eU(Ȥ-ynCY#---<~ɣG8u]9nm•7_Pb4a bŮTHd^P5 =E<߇8M5~3(\b'@Z)G Ν 8˼vo-lMYc3) ͕fM[e^ T]Y"0 Jy{n>ݖ!Sw^Ҕ|i޾wՀȠ͡PHj^R74ART*ԃ{GFZ?tkղ ۶ޝehx>$*T|Q@yrק(---!B,֦*2zgmmMRLs'ؠJ܎*혦Iww7ap|g:} wHUܰ0 |X% K-6sL9uLp*FtT0\ettTae%L7K(z|o`|ks-m|%I .piI?/i\-k>˗4+ƀ^lfbbk 1t(kz`Ζ#h/]5da݇R-<fGx O7<1Og U+¦΁hC[ݱ /'nsCV!&n4MZ"nv۽t68/<̜}ߋvod[h4JTstq BZ ^ %UU h Zb`Z>Wn  VP L%8,˒$@ 5۶mò,(h9xsdx@THZYNDvdžϱ\.399 iiia||Eɤ$NLL*N$IFFF&JI T*aܬJ8]F1:ZM6D!F<G4* X|>a$DL&C2$I{[[Ax<Vl޼@ ':4 ى/ UgUμ1χ!M?^?('GMضmGnQ6؜8vݧa(tkԚ6ofCٳL&iŒ4!2/,,{yVvS<pvQ^}*[s4 ZZGG0no.l*,sn4M ul6+2ysz]6p M&VfN>]SUЍ5"(hpyc(O}f-?ʕ+3 ITQzzzd2x^Mp [i kMxC1-9|M㚓A9jK h5Ju;L}ZxZB*dPbOc5 :ζpoE@`=`MgU}$Ԋ&vM-`Nĝou?]ڮ]vڬ 3-E`pㅨd"3MF#^y&3H@b4SeSY-=Z/޽?_`yG'ʞ:|ʄߕJ61jp-J==UI_[ӉW|>X z^tk4Zl6F(P=_;:ÓYM'IOj@H$+acs\.ݷo6^Z-HKkk+zFGGD"AP 3??ρHNmqeq# #-$q?yB*bxxjn7n Cyhhǽ{LNN2q޳ksvH,X8ԉ n߾MUUhL&C  2p&ZZZbtttKQ$L&eeeF\.PC$=3ORۨ5}J‚p/\YM;T}\. ?Vl/Og(.嘝ezzZ 9nHTU\.޹vA^}Uw.u&݄™۳<-8 ĠVTI- OP3Tx!MTd6ix<9N^6ͩSWsU=vsp!9΅r zMK4***?!S%x[g{ьBW+%_L8yi^m9*C6zgU6rQH4mF _;c1<<륷@ K ڵDZZHpx SE<11w=8k8y /g xЬ?)#wOn!|Q6 7J?ȟ_=#0I'ccff1S0h4*x@@d'P"tD0fq:fHp֮]Cee,"z:$t⯏s݋̐*X4cZXX0#kC]}=_ p CmRMc̴>{9+g``xĹnlx<^zDnSSSC`C^hBeA\6٤\7$sQ-LyKn$Wx2J"p7k4qo_/r;T*E2(-UjciA,bW(@>9VcnTdeH-Ĭ*j]5jMyVHmDcEvXP-<V C*Q*2R{.Bc]Ρ4 x?lĝoU1vg~mH)jBDDECHԀDx!$ڪi25BRimvkۥKw:^ 8Ws1drs={B'>h W*oW"WWPFLbB2 C>oW'&&z'p:,g Yħ9La@Duֹ!yB|584#;`ޣ0]QUQ7L&qㆤUI7Qwx+\ۿ4rc,a0d޽Kw. (PI__===cPU`0(?;w~eB.Ockq|ob4]]]$Iz{{{QVVᠿz>c:FlT!<< ߲ աsu7M(dذڠth:ļ‘q4k1 -ptpas166ܹS:0]$i,$KaxCLʿ 0D"_B|>$ݻJEExP(D__DB"srrd"QO&7-!/b)nyy3K/D{iOldmF3\=gNǸʛ.,UGEt8sԟ[&NKK k׮A*++swTŎrkLUU~zc#aPRRNflz|EapT*ObWūx\ND-J] AeȟŁA~̉maI]E<Ѩ/:ze(%GD'- Y 1c7l`֭gjj5rn+- {J4KJhjjeN-s*5GOO333C:muhbI@EEÌP^^Nmm jSId^\ @"׿X;dޞ5orim g:U"U>JKY=9ͨ?65O&*rd|t]k@5vv{{7ŲT($ 1OWm͛,cs!3]8 =+r*s@󰩰t.gMس0fLƲ9Maœc{Jmp;UU|>t]'H޳ir+(?ܱPt0 "HD Ȉ%[ 4JLHYYY2x@vww(;;c|[9?`úr"OɣM )abb34#JMS  $gv,CU-c``@EZDZl.22r\XX#W_bj]]] zarrrhoo'  ihh`ddDLӪbYNHKJJhii[jjj4I=׋i’j'LWv0 j?@u ؈fQWWiDQ9U0^wK>J2+ńy$6F9|SHOqkO w~w]V] GGG \.ul%nݺ%%OUUڃϲ^4>fqvS\R)N̆+Y"?OdgvgN܎iLygY[˭].'yFOOccc2ބXUUldggsm, JX&fQQQ,EEE 1`c55|m&b1rss[0MSN93~x N39H&>Q2˕Y<i=kt}D"=LrQLjwc$016/*TrtSᵟysDŤ"v,A$2==͚5kl=3CAl4IIRk}Ŏ/OT nHmV;AB۬ſ@u~Cvjq ='4qx2c6=e;UvSdΦ 204 7x6Ri6ҋIX(y;?ĝk[e?j5iRӵ5ص cd8e*yl/|3P W .Ա-tNf+$YngIm-ip8<}{1 (Zc Jd 0wT/DCjK1 R)r$ \.sS $ -Dr$I,6/;o83tH)1d2b1HLtZ(Cx$w8xv6smfggVUK$Yp6%07W`ffV -rdJ 5;;(i(v]lK$577 hlldgFxu<+jgŊkQSSjm7k6#6r L&~vl6dWNݢ},I94q|rg7?0/p8.\.(\9t:;G:d"1:C}l(M3^,Xv]1ZfHu1*7oftիWsUGt,eʕ?eGGӷane` B*BmddRc64 U-^:$ q=EQp\]Vif%Z0yC~l[=GRU[+솪f[k|G$NLL.?GHuH$‰YÅ},*"Gw'6:Q *64Ui6'Ŋ>U#SP:xagɀQgcm=n*Q0Ԛ UevւR;qG_}O㶮JZjnD]\k[e?'9IdK6;m  u`sc/a^^ BUPpC&t0IJlm1i%ixqLoxc<144͋ GN'IEQ?GЩ7{qqQ*nf뺬enSSS]tQ("Em$r$ /STp[Mj BK_ߗ 3hX8]eȇa4]v1??OP bۉF-KiJTp8zRWg$sul*A,SP~rNa3ZJ[ߚf;I&,,,06  zZ N><<,//vHRΒL&ee˖Ht}}#GȀrL" IgK("299㡫 륷W"^o޼iR)YE   p:T*zzz$s]$Xh4TJ:;cvv'y8^~NC4͢*_ fMu U/ˑH$:Djntݲ nV_دs|]kp}z2F_dii wi+_R$Ew! qj=E[3AMjXI=RZ%Noϫr :.][! \,l Ð8ۖ2|>###3O͹T*~Me2پ{i/^dqqG({qQ )܎:&&GlZ:::8p|m.kkk$ t]YGF"$ 2==M$i re0LOO&X\}I9|-&>].՚ u;)8ŭlg}W>ŷ=#ɛpP(Yr9d<ji" |Dss3j*Fiv>O^6.7ZV}=P۷oֆnQ8u?S:V=888<(/Mpp14@*NcϞ=v;b۶m$I8 ;4~F"&''1eeIA1v0iE`h4 77WηI8Tx٩c׮]H$p:Ƚ /V7G"jkkZܽ{ov/rQ\\I$ܹ &K/~ٺu+w p:JCCE'}JsO}ms]ZZv˂ټy3ccc|>2 h+_M~5hA,//ˣ't:{lES2D6Ax qY": D(fO'1]dg\z/GBEѓgt"l%̻]q#C2dpp@Zi㑓#?jpC?.+ |^8\0,v,u<4bՐYMPmlM(GаmZqڜ0;`yVR^\ZgQjp&3UjUV(ˉVIRO650,uIt=U-eS~yĝk[e?9iڼ5omgӚS6p)A;a`^tuj:і @C[4`]24i6V/Ngsu.Nnrs{ϯGn3E[WﵢRꎎYq5*~/= yf򯌿>`FR!#b^B-4\.G&ݞ>٢_[[p8LRɓa\.E._?ik;?~q#4FY8@OOxӉKx'r<XMEbxxE<T*L& 9{iy.^z|>O§Wc:^kws/x! ImBXZZ"(XG0D4I4Q| Z ǎX,b9~8LMMq-* w^7oޔ,@u}w8J  `vvVf CCC2E/EhEOMMI:LOO3wm\.#0>>N&s`g><߇b1RDMs~9XUUѨ$9R)C6ütι5H$طo3[\pM~kwl y4 W&xF2rn6t]C>ZM~aHu2QjdY9T*^f3"@u0K%,ve4(_$ᅯr,߿ |xJ(`yłd1bwG2zY]]^V̜fTXDŽbTS(B BNDQE^7@{ՁQu@ |3ҟڊn :M_LeNtqYC4v-6vjvp@KtUńa+4œ'`*XN [x:"~ Lu;k2+ey)dg UAZC =6?Mle?umŽ9l[&+/C 4EOɋxf\"1phbĄ<f6av횭[[u<^{lDΝ; ?%K{@"p\xB{d̞ˇ.|>x'#s}U4е'3ܸq[Z~]מ`0( d"cZqQ*۽RxW/?X$ BLFNbQV;l6XZZB4nף_]gWɋ>#>PёFTUUIPļ^$~(WDz|^G)ώpd_yx<9rDһ@Wo^]NEщ/Ì\ltv3)q&''jݻwzbaiiIBZfgg|R)\]nͅevv-v~?sssת*333ܾ}[J---hۉXMl6322(x:~z]xOE^||ܹP(H$XXX@UU"4f2.uf}} KB!ҙ&H&蠧0ssywd?̝H$)v7N$JXDp\fh&G.H}awr,..XtQ,fb2v O4 %h d*`@ 3.)zXL~tuu p5Z{>n!C{yv;h4Y[[ITĐ@ @$q,>l6LLL@_K@v;bqAa& ^c''V~=-|O<ՖS܄֞}@`{&iuu Jx^JAjjjxlƓ )>@~gG9Ir)ν9k3;\lt C+dv f2 m#jiTO寁(ڎ hi6-&'JYk$ICCN˙6<ςm?V 6hBĝkSg?ɋ9MbRfUUeÌY'ynU8ؔ]`n MfnbJm:Ԍf 5&̤MӚ6Iv>v8xJ D>x+Vh4J}}=6D"!py160>ht2@|G 4 X& b(;;jR-ЩV#xŢ$]mչ7rIw.(Vq Q;UՃ:tlr&'x^F0 2ޯ|qD4%K:\- $й\#G`2| `/<c08N?zDeG4*7nݢT*rr9n߾- r#ٺ:٬LR[YYaTmr}26~9}!be 1`ss3FicttTf3&LnccCoo/ h8/..rU& sssOg2l߾SsZJyٹs'EWWzw%Y/|d+QzZ[z#jZk:*~|UU4#]u5<:.Ma)N^c}Uh`(s3MS*47N^׉tF}o@jV^huhΎ^Rev*+b6:Zj(cSJF-%BF~a~{k?G?yvi_5jдaaMGzYe k[u?Iט6˫mbC%tu-+"86p8cډ xPDe.ƮWd6Qq2ҥF\tK.J$miċ΁}@5=XXXd2&Lass]*~[HoW DzccCtBحrY6.Kuc>NKc.b5=!=p]v=x3hFX$xTti *{rJ%(w'')>WhF8& Ÿr 'OBYKH$Boo4)677I2 twwk*Q"f2xH$ѣv3<<̭[$gnɹ\~P(nȑ#\Yw46# ;HFzܸqC:f37ν%NsjzzX,0/^fXVfggl+TDNXcUUx>%tJebbB7Ȉ4dyV_CVeQ5-Qh(lV4 !YɛPUU6p'!ȑˤR)p\qYx_>^9IpE_s \29Jd3ޯ&|>/$~˗QUUb8cccfdŨViMZ*p8D{W?!>yNnQW,ʙ0; Ӥx(OQ3_%˒) r0Dekk+.oT*̮6XbVϾy %o JBoS)Kǫ[Z+w fc4P;^} kij0ܠWҋ-7/^i"Hm :y9glRb!vl-uRV~q?\ĝoSe?5uRfN۬*u. 1 WBFcLpS]P"DX^st 1H'!ug뺕R֋L_8y>>I3}< 8ЯjRFHZ..z@ Fƀ09j:_2U#np8b1JH$4MB( vz3!\'fhEvrdLhp >& VvIR,,,_/ r7\uM:DXZZIkkkhƥKĉql"cX8x hUUD_i:177G!Gzr9@dYri};RWWzƽ6( 333$IEfY]]b 4w2=="PHp >*$Z!bZI&%zzݻWt:MX$ x8u׮]#/dضmȍy*LaK"HPqMsNك里=hlld444pYF#^W6Ng v1ͼr?܏GfFصk'¸\.f, ォHɻT*H8&*^I*//[zSkk<+[ZΝ;wx"(( ʗNIR$ I Ҵ)rYDF|#G?>Tl6d&89Y[MmmmtttHw0*ZLF>x 9E"`>ϟe{|v@E͙Ъ&#Vbv:;\|`0ȍ7!CljD"ܾ}J"c{v;G H\.䤄Mʅ J& u~8-%&> J0+z~)n38806Ud&;vB@2rtIccc\p~:;;i,Pޯ&Łiݬ >p#s]U\L,M zMeꥭC6ظyG=9NGZiWT7ĝkw_&MsYϤMmb A -ZJ@n2,(n퉣6PDؐWe9psꆥU׭4&I55i q|y?^ uOwԀk{~J+q6]Њl1D'Ei@̈$#HrI^P> ҨEQDu J QQHR6T(vۍf#p]4JKK 0Ld VWWzq:$IrLO?څz<###,"JX,p8H$b4lqZjbjf c>+5  GeYYrrPUÁf;ר{Lum\ W?DP`},;I3'_˭[)v";;p֥82t;[=,㕎g7F 6l }z{{$s]Nee%¬իW300@8fzzl6KCCׯsy***D"޽hllƍ©`0@Vr N&"cjjވ,"Hp7*ԩSTUUaXDt?˲g~ 0zfvtȲLOOVU0k֬! >OdE]]lٺNR{\<gr4'bϼEGhgj2?H dz2:NWWp>(EsY!\EQ0q. %o 8h۷s^EMlc?.!Nfk-\pӧON1066&x}I0xG<[.`cj-4662;;ҥKpwKtfKio-afc95bGoՀ/1UĝO[e?E[2Bi5:ff h2c.F¦K\th7&b^b8dqd 5 Kf"l2^5dQT Eymysy~W/9ѝ?p?߃RN]gfS4+!1 \h JFIT|>fECTr^ qxd2I.cii'Y%eikkA2$JPȶcI&6g& 8U-Ǎ 0.D"fcLW\ّ J[ggDjgxxׯK.:::xLտ8u{r4 E"U~!E!+(4Vp8̭[0RN yn7޽[FP(ĻΑfet:)2s>NJX\\d~~^ _R* S;;;q:D"xLfffz$1c2Bһzt&%~ͱµkd2Q.w MJ$A=-yeTS#IXÏP]{EUU9 &2L… hLL=QUu\S 8 ^ps-WSSSܾ}B79jCqcf}KWQ7GuQp明/ws#+hl)[|'7 Z4r"@*:l`>ǿoM,L:Tcis}H0Љ\YH~}2@HH)QJHP\. !M\T^\.F'۶u]>i,cg A^lJ($`P(`jU ~?DK.caaO$,鴜4<0 Ir( ,--$H477%S2 FvjN%TlZ~?>OJ1U/R*bM8U.>oӥg^.`fzj|}3[{~J;5~x'ޯrG(gL7r9JdRv0uv9L:)l,/TJ>A*nRLdYRرcLMMp8ƶm btE2B6LӔa#^秓\`qq2jwŴ299I[[^ PV1kɱ}Z7F& 4M#HpEl 1MNӴ](#<""/<9.$eV5,D>}㌌UlʼnepkggpqYd2,HCj__LGnҟ(B_xWD^X=Q|o@z~ĨNQƽC',y9 DF_A"{Z8(Ai4 +t4J޶ma oqk$ a,k7%zz8T*6GQ?.xb, ]%FTU% ( tDHD86BE,ϼ:GOP^oii*wbӦM<%:'}fn~817XUH ;ym;Z?R|CiT+itZz#۷o`l6i2,:KO~ww7͛deKUUIMc8&N@__ MT,ߏiR)94Mzs<"@4MJܹX,iܸqEQ~:d_zs7f؄rA_e۶\x'ՙFGG9ve1AoOpb8GR4-4Yظvfff$IV۵ F>\L&z+g6CCCLMM:uyzzz8yt~It]ٳr-( @@bE_zlٲE^۶4k$@ àVX#&`bbHጠ:f3UNH&XsqeZ[[,x<.uC###a#_V[eyyi=Žtv H˲HRttt, d2[Yo SV |}sBZҪ2\[>򻚫e@W;k_ĴtU{>ԭepƇ lv|e>݃k Mg+osiQV+귉x'GPk`8isJ 9Ͷ*.N/G6@ZrqyQN >ͩo PS-{Gc8DqUz[ic@s)*8_̝OSg?m2 e:5ԸɌ,1l.̖lŲxerY6u.]-AgHf8(ƁU2~J9}C ֫sޜ||giܸ8}cb@ΖO*y'n>90 u HWFRpj[+ dkkS555VָXbR^^.͎\ ,,,:tZ`mMMrcFGGikk͛tvvrrL)D"nݺ-!6U( PL:ټy3 ,--ɇhztttB2|Hek@N}3x"w{8u F"퇦aim0_]a/ȔpWAjC#eH]\\\$Yoܹ#o4H^ " Paċv.]vICQjkkI&F9y$CǏUY0%Y 4qUGUU\ 7n`~n^Ā#blsss0 n7Ŵ{,g\|!0M1Zh4J,&⽔$?#p?`W===,//366#JhiiAung߾}܏4MBݻ'۷ұq\7_֧OT4xn{3vd5ťx9Zv Lea:sI1|˗/sv+JE4d)oc"] X{W8?|oOɣ~88Yx}+6NRQ)"OBNqkWTOAkW8Cl^'BCfWxyٌBA$I|>P ^/N" 1==Mmm-In7ٳtڤ]p^(tww#-HDP| Np8i2??O:& J~+ ˭1%|\*Ǐ`jj<<`vvUUymmmA?(*N3?i~[[a+e 7휽CcffFD׳]W$|J ["6 N6.P5Aa|}+śJhooG4v,PQ`дR)N q1 :g8,D&>wL&Ccc*XLnIɤ`b1y*`;FRɦa~F y+ y ̝O[e?zJO[C eBL̄Mٍ ^,bە7/.Lp7s?/ $&lPSڬ iY)Pzqx_ '>N KF155E"ĉ  ÐT*eY9z(333&I8}H1::J$)o?#i봿VbiAڿ}lϦ|Ç#;8B.ƗD"EP(JD..W^=pةSxĞV7gvvbo?ڵ/>)AkkkN{{;LĀrHxx^ /w=p1R677Kc,cyyMKKA#Ex< @@,Bt:qi&RzbWB!BeUmge ﲸ(; b팍IÇ444 GW|>98Nid2()P,)vH466sH QQ>MrrB!.J08>PmNEb[߹O:N.c|u,W1Qjj1 m*( +?<M.`-L1Dռ_UCWQW]74k{UZ=9,uOreH=;5dֈvoRd>m?(unVP ;gׯd MM[<[sڀ=3U\U*U UK*X6*c)e8Tf\ _U[YqQipIĝK[g?&'11DFve(Rnw1)޸6B+lbc7efZJ]VhvjDM̋ɉy38>O_syn΁>N4eff,W4F+BGGX D%IwJ&,//KijC: v¶PеD4~?@>v;l_n#bee.(@'tl``VNbqq,6ݻHiWƛ׈tá*_7wƄ94McffU~_lGN(ݻFz{{T088io{wwWB9O<wD$f1::i,iTUeaa#IkzQ]!_yjRs?R:GL&Bb1fgga"=ҥK Ο?Ǐy%RId22Iocc"sJBdh/=C'qPhs,$I)cOr0a 82;w:&]MMM$ nz###ܼyښ\cl8~lpn7/^b! LEQT䒈|pp ~^fZ\k0]_oi~KwvvEu57)uPzrh<(gИ>H>g[~%ƐB].rL9gQp:ȗT4l*X z]-WXt/̝k[e?'''&&Kbv@,W ajGq+D8P F.aI&nJR.][mҦ??IEܜ~>QQ$XXX5:$;BLR30=z֘^WhRL<:*\0L*ĉ\/p4)TUʕ+,//P&K4Ǐ%2dZE 8~8}}}(tvvf3\.槿*p8L,X,288.$I'Nhhdq1͜>{g' $ b#/$N]aff6&&&uxǃ\叏k LF1 }6ױܸyT*d"144ܹs EWUf6t-qn7J)T Ν;OレoP*m200 /.z^YX\TU%J@yޞD)Dyt:>H$3~"ܔFժ㎎?ujllnbOL E"FGG%-+ az$ brzjeEr~WμvJ;=FTAZdvMfT*b`Üʩo ;s}c__J.#`6Y1ij\ŏoZ<}[17h,3Y\7[Oe4Ei4`40\&JL~ȑ?̝K[w?i$KX*NmR*t`2X.͆71 zQ'UDO[_syn>Q={&'KQ;qKp pqOl'<b~),JV^~@{  ?j_+rU&-b ݄~wVEvx^2 Dblᄌȑ#GhkkC4Rn҃=H$hjjo88Opĸy^YNljbD"۩&055%է~Ea``j2یi :l իdY666JjݙFGGQ"#x@ X}}=GL,=bttMX^^3\n<'Oƍ<|\r?z4466w3DQB,//H$XYY1a7.K. qdYYtݻwr9DQ4M022ή:t]fzt}( i)$^%0G[VY9 2YYYu3~b`/5XYo9$蠫'Nڊ(DZ' qmY]]X,F*"L҂ FJ s);Fww7MS$Μ9'8n{I5o5aUʱ*@ .A 8.`F );J*s5 YXX ȳeV4UإL=xZoǢΏe*.7JMUR477KMߗf,j nvxS#7 BR)^xA" ~*51W_7mz6fpom,YYTZ*1JSE Pʭ)r̝k[e?9ɏ[[,$eM0I!ƨh-p lR0 /z.ĢCV'sG]u?iHz4im1MIHߗI.|~u'G3\ܹ%MqizrNDwggb2MBԭX)S ;1 ;4My-~@ z,|>aN  a)˒ގ߿_R <N0تVd2 166F^2.&z)Q!"{EA ]>*N&d2u3ѥn. ! QV91-]8ax<4Mݻ,,,HDkmr,-ٓp#$I9uAYi~k/,BS?`gD*$755RtJ倧O΃zC{eeo~"az5:lmmDPthUmmoYd( `f32M4v||L&Ӝi PI&4]\.&r8~8!h"J|4DB ]>|HT"935W%0f egpD*sss ruكgrEfffPn::: q5LƒǸ_Ϲ7uGI땠2-m7kNLLF59ŋeB^E۸YKKKp8r#1@8fvvbQ\NsF ԔI1.V{-ˢX,Xx׾[ckTiV^eB[z]ױ,l6K.#vdttbrR D"͛R)jݓC "R)yP AB3 ST*t:-H 2}'9Pа0k%TŎ 3j ߦ{x!P(D6%LҶ ˙9~ʯ'UGu(]]]PTzTjOXJZOP`dd'OuN\.i( 6^ՈFx<ٵkNՑ*ea&H&[~zv%\Q~?Dd?c||۶gϞ=|M KL`0(#t 3ض́tR,ʎ:NΝ;躎WriFR( G_7 IgsfVnqB^wtg5o3^g`6o}zSPUׯ&oPxT*(?fjjT*%M@20`0H,W~Cs4Ⱦ>IZzALdǎ2 0 Y̊Çiii̙3Fye122gG\rUnYA4|>V秵P($E.mi1B*& (r~yfcDP(W jBa\|H$"Css3dnnN9"[l6+ 1`޽tuuKR[E uǃ!-bc}job|7'fҚd-HL6 Ef$I2t ed蔊={xx>:`ppEQHRHg4% 211|`7; 7VٴV~6l cGe~?d|>OTrI:|}5& *iY-ݻH|;Ɖ\7kt%'vlb{d^m$7Q,;Yl!5}QA~rLvHϽKMnQ{(\.K`p8]d45B:Y4(+S֬ VdölMԪ.Zy,]h[eis]$mI15غ /FDؕCA/*LDPAE *~@Ҕm:ښĤ%]mEz^;p{xGzW_+j":Tj`qukOP zZ%@icCm>@;K$+Z|{ 577׌8iZ[[[bP W*, :N=CCC2;;K:xZbR- ͆b63GG/ԍ89(Btbbr,dm6V- :tH{ݵ|D"F#ǏUU_:;ي&'N<*>y1PUΜ9g/T&n( /]d nt;7^m@P#*f贖y_Y=5r)̅?00SWWūJ222B<%EՕ1zHY\dHӬ(KaN>X )"F#| .Z]P }$IbqqQJv;=4 ;wEQFx^JtuuQ(hmmR)D rSޝ39F(bjj`0H.Ce:::XYYaxxXspٌ$H5l97X,AɊqK nJؖ^FHBUUI&b1 Hv"QVE/|rnA׷>hjyy5׉xM ꩩ)%$3wƍ I$G,XV<bd2GQ$똉/>?n^tqRvh!F{S 2z7)ʜd |+wΟIY8pzsm3w -E>c3sۍBT*/+ƳWw~_qqS#~kKz+SU¤OpSLLL`4lH[3}qAXǷ9X*0'͢6N$IxLhm|>yp6͠c^WQ_#]Jfuښp?̝ke?ld_6&%T[6R!b =A+ҋx(AŃ HH{hJą6I+Yt$6;4ټtn4,3s|*v%_4/!/__lB.?q-Jb{+̂gMӔE`-åȢ\--BiRyZE:DwA[<%.,H(GlmmIG30 MD-87nXgѢhvttH'e0"-Jqȑ*DQ4McffFB66]08&2==-)9 ng~!_c֓'3׉Tip?fV,ÉPjy1f7yڧw^q1{;JGJf^tJQ)22~L a#¾w^g~~^ R)9Lgc#U dUUd21dXYY… ryΝ;'{b]__'PWWCuj˼`(dy2AN=_ FI肝ϻu\6/YBQ b HvZ[[ul6KQGsA.m% ޽L{ܵk\s]?FQp(۸<冞p6@Yl.13uu>//,їL2r)JxM22 ZhsMMDqܿox<ܡ,n*Una2+&*WKy%Sa`#nr0No_H[gIN<3.Yb,%st"M(+ n`^j(:V_ݔvw+pPn˂N\-j=jxz&"~vsu8pwyyyQo/ _Ef@WÿֈC\bڹkEPARi4Wv(D yG^ͲeWbUFtiH$B>_)T:===LNNJFeYBaf5VWW) l6n>] !;\TP4M[[[B!'K+'IZ[[Is+({wxj)! #:pmEP"w%raoDHLi'2֮Pߴ=`jJ_6Z=ϺLuXyh {vشۤA[|8A A|r8M@j<Evvv*-ZE2C1<k{+>)؜* Lx=N:::q=2 6i6??O?k:777˸#oǡcn!I_!\ۇM Ua z;u׆(di#7β3J\csѱQFU_ϮxUYuy^Ӳ95v o]k=ӆb5K+) a@ar3"#:̝Ow_}(Rha04$,W#Yy1-\=/KvÖB2%< M/u N0OGim>yvh_e<͓'~ߟ". #&p.Z ^Ob}-A5WS}S'@ě.iBuy!/Y[W*Ba8`I QOOP=+f@2@H^;"}}}\.,Çe'ɓ'lnnRV9uX%X9{J87[]R x  NDрva#g#ꅚ ʨBA$/צNURIuXniΞ=K0IJ,z{{I&TզFbt%>y@ my?ω yp1vvrzɧ/..~:su?zNm.\mpDp:\.sUNߒY<8>>ǏY]]EQ| ݜ9s=`6DQ\ F" 2 ?}?g5:::T-KQ4'N`yyT*E*baa0x'011A:ݻ80ʠZN6e}}]hmm|>O2d~~rvo4M恈033ŋnp󙝕.*6Ѳnt]ɑb #%S%ޠMS1GQ~?/_F4"Hw5"X,F__ 9y$LMM188DhQ稧FmƳ/-]v~vؚ66K݄гQM\ʦ9zR%jv@>q[R |+ϯi6T*%DQBO I?Wğ0`Pk[Ry:{}Fv8,UB0it(dWM* ԰ΕOY=@onρ4U8w.Iv;.k52\v\.ǡCd=zϧ;G$xf455q z=V`yZtiբ {^Yb266&XL;;;rܹs`0HP p-jFGG x<?5ʷ'Vq=Q$Zvuuq]IbnbdXc|m۷su|2ٳj.^Hnwl~E46{ehhHN'lV&e Wq>i'HDPU^]QU/;bL&#_Rm6|n$>;w q饶K:?!XX, ^o2C57r%7-ihh`>}ZbEtJB$\.J:fpp98s cccG?dRpY#+++,,,F%6<>2D KUzQ盯8JeUu(2<3n]8aap8 ?ʕ躎dYhll찳TaVnCͿy9PXQuu *+5۹j\e6{gUlF4|-aL||OJ%#t&B>>~۝4*<(ZQ-&[TIG}Qe [a̝oSe8m׮.mB dqf[\H1 !0b";5m 3DÈ&DݠY78vmYKޞs{}8,YV.A!..)t`]]OVUMS%CN%.`B6 #i p~ע5KZJS(d %Zȕ,-*lXP ?] <bc?>_^z5qJ2DQiŋ dd$¶zfff8p/_ˁKG1"٭[(™3g#055(\.N'dYtuu.QҗlghhH6)˘IKK =77'JJ*LӔ{agp\ʲ`1qb1M+}= 92 '8MSS  eU2 2;;+-[4&# qa7TF9uaܾ}[JLOOIf4e[Y4 [Fxś#-z~O \zVi T Ek YaՖ /ݻC2d|>ZwQuHp0utt'+z6C/Pa6Ňy4ʼn^EQ>B4ᷬ:ld|?_|݅㑏o)JaR)yŴT,톆ݻo׷k 2Ų2Meyac+o̝kSg?'9I[cjlZ055::dX9F/F2:mllcņs̛^ :ejat=l$KtGbcMs} r!y}UWW xO)f^Z1qBX"le7_ W +_}R(' ++apq_N'nbdk 5afx9rLRxavq h 8mmm}211AUUDBWD]Z&55455q?ysWcSl\;ٽEQ띄B!8`K.TjU"JG{lzi.^2tlV z{{) >|HDUUA|Ho`t3謜GBnW;4SGi~?}~e0r.(,'Bn] :T MWОu+W2nO?Eon:;;MÇ?`z Ek]?\# à.y9<@U]^R:Q\yμmrK<gm_qp-\.|uяw0m&kz^X|ZM|Q 4Bw7{ůRۗΚӀr5M1kV@̝k[e?'I4am62M)v*uclQoDx/e^72(ư `lЍ.u[uiviҴ/ӤNj]<\y~Lsĵ;bSfp'ty|ݕj@j5P.*$ 3AByAJ 'rV+6M;8NKdA;uu4ѹJKK̓( Wn[0uɠDP@UumrrrzijjI*T*fV]PS5ڷG01++8N2 \Y}H$$X,J׵Re.=\UU8`Ӝu=iWse:QГg-M+lbpZ5Zm -%mY#/w4zGW5O+:?=CqݲeFFFBAQjs\tvvJkBTSdxI~S ƍ(gccx"bX~:TO0y[FE__(_ p|Dݻq|>~hs8:i䓦{kk֙%CSԞئ9<6<̌"x<vvvX{FTrH-ԫO{C<o}UB6?O?f҅&K7rM4f o|V(ngW-3z̿p\jh4JR㳳x6_Vmd2ICCfiie9$N/YZ:*)L2??Olƛ\S8jTiXauͲT(VZ:+H\̝Ow?m (=HF'#L–MܲŒ-{317K%]H& DI"QRbK׿K.~ B*NbkuNkL?٠wcBqކ@H O0DezHF9+xA"RB=;923x(N'uБnDgHQt]'N{nfff(++cxx08p###N /HUUdY1 jjh4a))-ߏ}l֩jbII4phDQ î%qdMJVe+Y`5kjX2ߠRkJi^d]U.'/^ry'w/g?h4*+O.`0(]v;czzd2I~~>PEQ0z366F$[&T˗Y\\$ r-I߻_a~ag27osp 4X, rTUEUU|e-= )wlhƾ}p\Vmkk Z[[ٺu+ڹsgD"A0ѣRSSömd4M&׾obppPm= JT*ir?rĉʵ Ν;G[[>dtte:::D"D"l' vׇdii&(KF2=v`/ad28Vm64)//' 33^i Lpmm-GǻOɛ6נ0;v099 =Ax9bJ6+**0MOVpt?KKKLOOSYY]]]ߏǖ U,{E-fFnI줹?`BRN:EUUv:tIkfsZoXQ$d5 K |>JYprqlVTtW׭}3lO@~9igjjP(D<q.tt;Q|??@QQv9sv/G)ɠkqbiSSSl˓CbO N!4-9΍O;-|_Xnf5#Kƴᶛv2dޜW_̝k[u?IӤ'K͖/{1[ nD0^l2bn /B6U(lUXV(Q zΜӴ]rExs}<Ut]@.YV˪~Q-8 o]0 V4xӵ؈j#uB.~6(JU#$2˅iyE)ٺ'(P'P&~?~f(><.Putt&Jgzh0p={J򬩩 M0Md2)FX iر#9॥%Y,aPIe/ՉUXXs kj4SSnZh"|6by9l.Nk])_\%wbvBQ,%' +TU]$q8s挔ᙦTRA {<=JuVJ6^l.^w/|7|O5#LvbK`0(ܺu 0Ʃ]\pɑ#GHhƃD"8\2LH$B7;YI~?ܿ9fffuH$»37ywZwbY`nnG"`ppPf CK ||i###={7-rsR,b]BDQc``P(9wMy o ⢴͟ zfb.#*LV BJ\__i^{x[o_^,c>U4VϏ=|X'nUx=\:=l<4mD(ra13==bO 5qBJ:&Lt:S }LLL099)^W.AXRЕ[ur̵H;?yL&8ǏFGGI$ 4MC4H@aF\YVzZ300*333ɥW WH2_MU+`T-\_60_=iwNNy nYmv..pO$A4|>^rYe (۷O0j)%ϳ{n:OsݶmXG1 9$ –y2%Ê͢-ivnt\iW!wo>z#_g`iiIZhEFAe1hjjbӜ/ +Fݵ۷o#\N'PX,k/BbSy}}Rj~~R %@ b1~EQr˄Cкx<n\p|h՝,tW7;ulm'kG?\̝K[g?ljY4b\MZب-qQ+fEY cbɍeMuYZ#1hL/X p $y<@v{B݌\z{{aG4<ʺsw42zttl6˹sx666|erܴ>}J{{;---J%>z|fE0?q/1<$J111g{&Xd2)יLFzmfb1.ɓNGGT 4udA^/T\.';,r먪*YlV6 nv;>UUecww7'LM,}0hnnfxx6*l *lbZ'Wf w ]|/hF,FGCC$eCҸ+%) һsmfff(CB(w.!H*W\&:bs33gp8oTi䚝_V]xTX)d~ϟgssSRTWVVdjzue=v E\29%Mur;;Q]]ͷ=UxnlgB \}WQ.I2R.I>)Á॥%<: 7+`n+ĶUwqFcXݱ1\ɯ_]h[e'I6Kk2Y֬[W D cC@ N{2A}મlݖ1k:̙ixk=9{~KF*ngTG8Z!3=E68O>% lpp.xUUt针V}9$lsc>zqb$I۬9>N*; 6OsM:B<ńVfa1Ok9PMʣo߰5X+D@QzϺYIطoG~>v;x۷o1 SK*"$!HDaqE$S)`z_444h ިUK"+܌+f93"9]q:\pE, ]ⷳJ4 6vf5 VWW샟IV+Ǐp055E>'ӃballD3%<*" 9K\T$N+C!# \Q9t8J-ƥ%dѲ,)~+n)nre977H4M<h@ B,,"!N!|v0d2LNNR]]eYWV& rjjj"HAm۶ P]]`|t:پ};'aCNW}^\>F ne-N C%"\jۺʏsiRxs̶1 B'4Mw2ՏwЀyxMgg'Tq֢:ttt^bpڬu329[׬TP(D6ksnϿ< DQ*ً9q!ɁWSD} ->m} Ewaǎܽ{fN e_===r9P(ܡ95<_0mmmXE,~FN_R\y 94ѻm'cvvV&ccc|>Y\R)^>x<֭[) TTTȵnTUZMӈ㥭uH;f2nALc)"X@j^/PHlddRBISkk+nBB]P%ϱHҙ0hxT$-ڸ\.E$͛i0` ҩ!p5D,ZJܺu"T oky}X5o8y9B6%ɡ²X+kJnbS4XrŤIlj4MgNFF׺YZ\E7,2<<YrOs֒.?~̝k[e?IZ=&&R--%R"Nm7V7؋u w:덂!^T9bJ ml9Mmi_<ϲ>\~k-wVWxU}(عD bH*"H%Sl9*f ` @K ŰxccC‫;j%SQZIu]濯ʑLOOK HٳDŽTIR* RI_PQiJ<'hii˅(r9Rl3 隣`0!LʙѣGyk-ӷX)QNYl%ZcbFX 6__>R(o$D C:=ӗ«<,ikkn. J^aenmme߾ R6:: ^P(2"',K,--I>٤SkN,_lv8ǰZLLL0;;:]]]={O:kV{WN6璘E\. /`- 099I8͛(B4u^dJ59{Dvtt{n c j<'lass<8*6N=>>ؘTOMMhhh,--U,TCM2mZXErf5P(\ ݎaU_ۉF244D\|ʩqZjhv Oo?]ɔHłwxpVy$LBWZ]ut]G44MCUU?n}+DDW&*P!?bP(DP 166fj *9*64M3+tK<ˣu{vQ_SYD==_V1m+vts"HD:>^J<jZ, E0H$Oo9xǏ~ }Ygq9baYPR::,y^ vV:D7n`$%Ioo/===fM};UK4EveFQ΍yd22,4A^̝]h[eG?N&KҦ)4mYVh-[WF6,HQCEd@DAԁx1Ed$n+tXlK-B-֜4MfҞŋxonU2=Mg%};ۓ*! 6W`ZbBEi`ZVY_d98 lS_cΟ?>n"n/XpjEF7H$[_gg'I:&߽A4a;@٫W^*pX6T*SSS\t )q:$ J%@RN~?BAwrs'.K*\rE֍Z[[4ހ<^](xhl6/OD%A\.F)$rs!Ob,.&ysNWW~t:(YZZٳdYHݻq\.`###2dA|A4M޽{d2CF6%J:%tGG###c?~GSm f;V2^NQ֋\ϭAUU|09'rjjj(JKn$jͤR): D8VVV7Wy_房B^%Z5MaF_j>|n1 x?&ah:<&*߼4m92z@bM3sfv?̝oSe?-]_+q(eȄbM$(dK0411pCzAH W.AHF@o4&4hYv[wy>syN͓<}~1=J@{u7__5jp?{TŅ fE*Uņj_TB': qыKZtV|pť^__/f3D\6 )!,t?; TPRd2APdrF]&l Q,9+A"ҲiaXXP"/@䭋$f|Rp611=Lx^FFFt)dP(D0MPS:ok?1 |f1qZˤ  _},bor8Ӭ@"V4NJ]]|ʕ47Pپ/3Luh'Xc-$_ظiIԡ|4 q8L&^9 î5*PH Tm6T WC8f>r9fEUSbX9űy:;;rۡǹz*Hݲ`P1I+W2??OGG~|>5{͝rMmm-p$1\. E#D08NGkk+-rx;HxB&ҥKX,~?333 cy-,,륭RUUn ºEָxOpuDQerrR۶m78~ 63C3EӼ{lGnF&xktl4UErZf?sg>7npMH̩*+*E[V6}sDS$QV"_ƃv8yId#{:*KpD,[h\H̝kU?iӘ5]4 1}ٚ#CƔ8 F^܅w .6a*!L-K֥K'iI'^<=Ǹ:}3cOJz1;R}]d@lVUb"dJЅۓSGY(a("CˆSId>J"ۖsݭr9)S:9^*dVP(HbWEQͻ s l6ce O !'ǾRt:VIfc||۷7bdF,5n,|y cg~8sM e&^dJ+S, f3pxw7 Jx?qv eW ݅(Bw4SLF^k=6'X~Vji$ CM"W>~绷ag3eцTH$B `mmO\{xm1MɎ50::;V! aU㬬,,,ՅjDZ pݻyӣt2AZi|ojj EQ6: Mdz&aΝN X,JOOtM *G4EuQ;w)q #֟n8p@  1<<̵kפbbAssZTxKA?4/vTw5c+(Zי/:t<%M,ņdffBA YRfn8}yOP.Y^^Z )¥Aom-:«5FG7fі-^|Ll#] dtP#U ){D9cȬIY]]Hl,^5aii'V}*5:ZNƺfBQTTc=?̝O[e?-kO_tgH\H YVjz1]fb4v%腉SKdz2c"fc3#aN2Q#zB)Ey^9I~?m[+tQwUwbغo=cĭ_&6:,#jfPXfJBC qH.P,i sEo6%LM{$#R^^Ғ:-}; ռǒU񽪫u]*\MmTT8I&9ŤIv;~*)3uuuRa(Ijj܄B!8^: y{/(')epp,bazz;v7])nwn0rq' #<,F[-bBkm-L?*e<3y:vFGGuv8zk?QHU˪lhh)s ,86->קl6۹80AMm-hF8 &SLF?ij)rb8N%X,Jc:f``}7 ? 0<<̥K?c6+ttt&~*+]<{}tvv277# r_zrs. <.MCQ\B" ֢*455G2J>×1p1E!<-RT>MPgY}J有 ^[ZZ5Z4[yy퉇B2ƍA***,>|9;4^ ZB1# X Ӝ~T*q:Ҝ, G ҕ,DT: 4l+80E #ڐN@ZC{3rb*n[rM&D;NRir@'+gEQ|=z ttR)2 BEQd~~+766"r\*͉-i#6[CCCiENU$/ڨZ)k+ӭe2+t<ɳc +ݼȃkWs_xb/5CcDqH[:55(|^ڲ٬$YXXVPU^XG^r9ٕ 0lD"ݕQ1933#(^2DP($p΅ @ !ŦAaJ0VH$6AD".#NKG x_4^.7E7 Hk3jZʁi4q8)e### 066&ZWQ}·qKt5/k |> Bx<颷!0T(bmm ǃ8l6f^I2ܾy9BbH$" CQ{.fF@ϧ00z^ӪǭV|!e{{x<h҈1:3zw D2F]%&u،U<m8lt:-Iep4I__{{{A/w赖yLS 3x?I[ovL&fáZ)r9 0LR t\gԀ[oĘ}?:n,v{d2(lnnjnΣ?ݼzcNKO[U*twYeKN<ic`ʕ8$/̝MHg:]MP AZ HHk"-MUJKz%Pz BP)9驅JH R)Œ,VKqјUw;3~0om f;C==gb~Q*(Gv49ËGX\J;rŊ@ b 5ިT*@bQNzYz9p옛Ǒ@|;}]%_u%؈eYP(d`,4M R`3!b$AlۦRK(NdutuuA\ l}}mfggRpŦ8kkk9sj*GAZۯ<ÍK/211A>pضM:&LiR&zss|>/t]GUU_jD({}Tz[Bt5y(&P /s|ɛ,..-ѯ74z|>FGGm[MDu^/ɻ.`9`YLӔ~,q2 lVla T@ @<~*bnnD"!d1<< [[[n0K|>ǥ:@ߺuzrrWGuVVVmw.9i(ξJXLRaO$D"~, M_*hoo VV]0o__KKKA9RێÚ цZ"j|c|ŖIrIp^6%H`H}ٜjn:O?#1==M0$T*2ccc ##4cMxt]43ض#㮠* d2,ˢ0H&!q4.J%6QU$N\>:t^l6+) 80ؠ_ mtr~kr+EYrCKeUfѨSC"r(VSx]XPˏ8̶,z{{F477o6]-@CWC"eZ]eNvB+)ST9x8[h[u?Izm'6;CIUa/{t |=z:/"(nk]Fڦӵiґt\O|8["\|o~ 'wq@"8qMcDnmooB}w؃b(2iqY@)@ٿ ڟK S  pbQqv*6vwweoMK-懍V-95 ~ZPV%H V+7d2F@x9x^%rE"́h4lW52So{8⛑0gޏ瘻>~ t:zZ^^ 퍍 '?t ):[(57q\5}) w ͇(=8,daYYYٌq+x1r3T*l܉|>/3L&Arhn[$ VWW"  (^p8L<GQ CXvd2lnnۋiySFJR,..JAɞXZZz" ) >7[[[#K_0d``YrH f&211!5Bb=rBm|1r*CqTbF|T+QOR̭*͉eTU%L>r^?gL4X+zݚgvR)b^H$8pիWKgrDUU.,,Pq:vmBX EruRirAf{&3/^!VvjS6j1\x(rOZ(R|(z6+gp_|:FF>ox.9 v05שl6zzzdK`ffFjOFt-:VKLweu,!l`Z94}VLu*Dwm-9TCn"4ñlbю&lyԝk[e?$mNΚQfn9R+Vtl/2!(CEd^TfW)mIQJbXlm6Iﴉ'ۨ \p~y|ث7ZXeAS}̄Xx+zO [j)bu[]X_qqbTUL&XXh&r2 cP}ȁ+ GK B͉Iy lEBhq%v$ \./hljlVv(J,I[gss4e彼LTb|2NiY!}.--V[p:B!>ooo4[9~.aۙfq%_([@*===Rx1[]flmm1::ʹ#2>GA$_r +Djjj]n42;;a raw4_w+YF酆aF.[YGۋdewuud( B!v;S[[uUUS"ccc( $ rKkkgddDzp8xz]666Zuq]ss3N'6y@>{wRUnXYYaffYѴ-NG,MӰZpʽ>(%&`d2) p455* ^9Oˏ5T^SAhg@:f:::eqqQ*HHcqV+SSSp8XYYcX,\.999A~xX^^Ap8,//c41͒4)LbEUs5>~ ,--166&'''̇t1<|WRvr9)8VoiU}jVrI#g\.?4A.ZݥM:OI$D}UуlmmQ*hooRr(\!rx<2lT*los&''M,XQ8|b1 1;;K$2??O,#cnf424 kggZ][ػۜ5(.9<6;PzSp/DtՇug(N>gaaČ1 6 \pW\uSSS] N__|óR&)Ot?*-Mّε53tidEQdHLӄaٌ}[Wn㙧l(rmJ}YRND"ituut=]GzzY__guu}%~{§oa>&ˎ/ֈFҹT䪤R) \ g0CcqSגdvp۶ϵS+BCP6,XjPlVy g[8f)7 :U9 s_)wY̝MH#g1lkXTD<=fOS?NK.=V(Eu"lZD*hnllsRhҤd&K\{{H 3EȑrY^/C o"#NH@lxցCt:7NP#j4r&?!aq gN's+f#%]B4 y4Mji7'}Xh) Nٵ-BeA'A@KDQEF^8pad!*677E8B4%&)̰N( bH6E4筨c2100(˲nzz60d2Ύu]x<`]N 1MP(ĝ9\b4 K6lW2]dč]~jjwqw^Ir$f E!#qoo8k*|}7_ 7-eZE&="QkpjF `ii=0߃IJͣ(N=)b.j*1JE/.^or*{Z>^I]NH՝dC&}6|?c/M>9Auf׮)q4VLMMe>~:oNrC9>eɤҿ>A j%cyo}Os@W^fQ.J%vww:4J5MS訥#PW`V6xrr篠=Rgo1t7ņ;; NaaJfu`_~Q(ji'\-lj1t*WAAr+ cccjtpp7~TN[~G77]ɭJYRvmyxɳ>̻$"rocD$}mi~K9鸏[^ vn<9V!ĝO#e?}[j(05"xuUb\ E'11^LBlw3MKU"ۓ&a݄4M"i& 4VXDUU&''9>>T,dqK-4Mey0GGGyL$NE"ɓ'r!H:'2 &*TFtIB?//3::*$,hfܺ5-il6jOܴ -2MX,*)˃(JӰpvl6nr1,rϾJ.p$e10UUe>W: ;+1~bcc bibKEQ$633~.kqbͱK tw0 4REGD|+"\q9N(m7-5~],bggS*n'Du2jYYYAU5RӒL&f@Ӝi41MRDX~~]ץ@H`YX $Hmfff( ') حT*<I$pqn7SSS8?/@uaBOxab0###rz<,bUUI$d[֜fd?1O/ ^-3״u5- X w^>OV߿g)u:,e@Et]ѻh4,5czvu3@gw tN0(P~RQd V%n}(kkk>~,u8tuu(l1)2J144$U-PL&tJ$P4Mnю yOJB$_]e%$SQWWWQUh4rݨJ:f}}@ U}-7\7Y^k)l;l29zzzh6xvvv+uM~8ʅ,  \KV*!B"BEj?´+6IPo0yKv_/A.޻S>O6&v+u`!uս&ϵxWO[u?=ѵoi-DJ JR@ Z35,,Yyċ5&/  B6`ZV-=^k+++*8x`ttW]ૉbدZr:c| ʾuqqJB6=*`Y2rNHO0#:::CVL"Kh䥥%rDs,//399tB󬭭)i$T~oYn P6rMӘgzzX,'p8D"LMM1338?<*xL&CPPJj6}JRkQ'@P}B'm, G21S4x;&_~[m8kbZVݮLCCC000}?&Ϥy APh4yLwHD\.Ζaoox>C`T*TFR߼R yI_sE*ghk.D0 CMGeF1 C4Cp8tl5'γ&zt!>vgvfAI/8V9677fkmHiwصAt1'u~z?)7̝OceC[>c[ d\ |qC+nHL4nLHܸ7&f\+¸LXER:W_..b˻xۼ=y‹]-9Du,]7)H6Ir yMa9_zߜ1K@% ,Hb$R|+N6Dft;@ΗeF-K>S2ǗBK\.{.ue sT T. 0<<$qtt^v%1Ak^un"lV/xDfTWMqD?JQXy􈱱1...!n)D$=R(@[vj@Q4'Z-oIKlmmF" X 4Y|t".)]{{oaˢRr rYd)B⳹ p;L'^guuز,izLӉiWw&􉅮ٮ$ ?xw?"K)9[M0 666H&j5\D"y2 `Pcˢ?(Eϋ t:dhh^>Ӷ;n̿]/wڸu]KLce@rB[i{KJI`B"Ht`0qg43c\&6>V2cÂ>Ci҆bE{\U&7}|;1I@pJX+!t\PԢT|>@}1b(^:N^RXHa_YHL y$PxE^ D.wjS9yTAP((_4;Pժ6΢:a rA8+_Qc2L&*J9!@}rl6,fp 'LmlZCH4MⅪǃ- oȢHrzhیd2XYYAZe(JT*8::X (Bp+IcqggpR)Ez]dYR)^ﳳ3cNO auuu𫘟GdR]5MC:aj@TB4A\x<] L\.Ád2X,SDc1jY}d2uHUP(NZƯ EQ;==~QW!<}\.yZ`{*''':Kp/Fj9s" șů6e\ӟٗN K}$GHX.ʸs/gw;/RYycii NDkkkt:zH&4 pn㋏g!}|4 <~+| byyϫ}iWdt###])sI@*J@ Cʌ,ˌ6S 3M/..r PT`w4,(3:n$2V+* :Cz -`3L8%^#xEƒNM7x>L$Iߺg_;ZGF `>w/a<u ʸPo@o*7jhoLꣻ0AғNaXهOa%<B.!6XzW.xݮ{ԝKOcei bO\Lip . !c\r&J3KW.4/ĝeD$I 4]p-e z.Nw~7myUiRr)LCE\:Fm(]'tyʧIڗ0˴ӉJDf4D@&YG ٭.^mt]WgיH(Z]]]]ZmH PhOnnn󬯯dv_x  ivJ\V >A.'ggg[]oz<FF*FLǙ`axxƆ:/crW;>>P( 8R*Tc"3ܥZl0&doW ]Qйd(Eb=߁\.2 X=~fQd ^֖rų,eYJ!I8VlZIɤB$]h4J `ooO%(q(y`Pnf) tww h4jfo8VYX1,?~j`&GGG]l8V^tyt]Gu8bMCCC ٭\ WVV0#i'(k~L"`iiߓO(|k w.exxSOwy"j={F\&G04MRJF#x3==͗eɏti_ 4M>FhCH"$G6ò,T\+ M177Ǜ)]jjB+e}s*Zz$eD"jB4JE)l#z1 Eɚ4M~xCѮRBn{p8LKR}ӛ6Bfv ]tDQ433|8N}4^n?DZXqҼ0tEAksIi9p9hTpW{74u4y5BuYPѪ\ԝk[e?IIl4IK vM2j;t, Eo T^x#xU c}qM m,MJBA6/'ͫ'ϳ8|n朓'L)2(HRA  pXTW*fffr  R]]]f FafggX,\jT*F%Et\.32"CCCXYY^vNevyy)}}BUUիC\]_$ 4M#`sssyYvʂP&rg(_[XL ^6չQãlmAKKK1b1Iiooul6K(n12r/o$9}>4K>'.==  qttښtITz`Cwwzz-ǧw}ݕ VùI8B| 2˲d :vv($D/R)(?v8aa뺎(I&>^<;i<D 5FB*Y޽(*:륾9B)0uuuB!zzzXYYZݴL8lg]#t:Y]]Eu0 D"!!ܻ-~?dz&zss3?FUU 8V+`zz;W.p|2,$ qbv4McffFwҍA,vrNRi,xRdWUUS|U~zyFGG|I *b3\ا( iiiAu~?$.b1dv)//gmmM |~XLtr\yh!ip4;Zy4~+8KϳKqq17>On=pJ@dËD"kbDRe%1 .z??月-/nV199I0$$;o!( x^yS`SxpLvN,FdX sBHĈ$!Y-քhTUeggG"hTֹ9j*V3lnnfW2Gbguu5DB<766 {2$P[[㑿OYYW|w^f+Ǟaa%y<^u?ihɣ.DӊBIia:j1UgH)pyҕ&M%Ovb^`aaGKK !O0425) PP e]G ?ԝk[e?Yv$td%RhMŭҫծCqR] BzJ-s*B/5TlJiי 3iHOO/M'x}yo(RE8[t“,z+җ*%M]PfiX,E.Sz ^qIp7́k$[Ax>a$ 6771Mt]'\h4,hx<Σ=٬<|1Ky/P*X~bl|q.1"BNDXnP ׀5#@eC"9Hw \@uVʭOH+ժ5 y&@&.^ad0MfggT*o΢y477344$/Ah/Ra]{MgozpobzK4Mu]]]x^PErChhhk:D,hTֈ`0(KXdssH$BCCmmmHFt75Yp2*dMHRxxxL&(={p8 tZrtzIrJp_^y]yX?>XizN.R@wsgj%p% fY\\e0`mDgGnߵW}}}$Il6?K\mod&kcPO֞/>ht4X1[Npp٤?]UU&&&d_bq E!Ka\((|>JEy*cx\.G(/X#_kl]Le]n<ޞx666hoo' 2>>n]*~V}Etttҡ*]a2y`K;njse,y6v*ogqaj*AO/rWm{LA jÁЏ~w:q؜U0p!>c%1ᡓti{οIgcĢG/ԝO#e?ӷ)CZ-ey`d$ &4j%l0m6&k↨fOzAdM BnEP҅mE@<ß`O=44=ŵe!a.;^lܪJhPYn_$pgw]*=ncs ހVxb'QUUn̲ĜO`Z]DP+Ńi'U9[/9[4X t%@α\RVR 6bM' Iīus$O'@itww B2t:T*ہ&vh4(*ӌE2O8W.5͗,.44:pUi&JjJޖP($ bl6Kkk+KKK<Q5Mi!(`F0;;r9|>hFoo/H}ccchF2VWaP=̋tH$Bgg'LLLp_l*&\(x5---|8C4~eJdrշGwW3sўOOGG]]]ukӤ:UB( ~OxqIRNP 슗 ,//spp1jbaJu|>܊gRp [[[f–4M bɝZx5x:;7#H>M+Gd;Is6^/7>{CHKş;٦**E>.R3`T'Jr0}>#BMg;bQjѿ^1N3:.Q儓jËrh'SoycStev֠$oziyJmǪfKlU?GNmrmMTj,%JHAJW H]a"$D $PU,X((""/,4% ǩ;=dH΍#f=s8 G: {GSe ZIK+8}ԩSj@4MLrZy `uwvK_$H:e/iۥ$ SЅ !k=ȡu8[]&draڭFpB\*eHĕP  ֠(ٶ#Nf)JGTFC$[ցXɊx@ȌDž 'H(U3BJjS TbG G|2 ccc,--q.[7odrx41m'^7x|ᙟxs`=/n(0P(~*TI֔h68ܿO4s}l6K^GuŢݍFB!I$dYrd۶1 |>P`0T*t]Ok869{3<<Ç\Q63 K/^$ 2t.RAU6FVT+++J(+133iWz$lllPTFL՞L&wP;w(6 H &v'1Ο۫dkX /1==MT"i\trL,#J3znlŸ\.+ q] /,Rw +Wn s:| u/s'Q]&G$Ot˗1Mj >CfLIkj{Nr49NMRyzKgL vMb&zc˅nx mr:T%ҖijkAnn9f;vSX~agQz&sssA:gI6lpQk41_?ĝkcU?7MGCnG&mgj0,g1UDBGGٸPApN]tQFd:80hLm6vtGz0IipƳ9|߇=H(F9ۿb^#$Ku! , ()ۛvH$,Dȍ]w EPBdjlA)K&=ХBt=R5"rV`4M 8&ɂlͅ[ Jg%4R$T!кiԍs+:H{ ҕ}n:::lnn*@ߐgWMIGG8VU(Átvv2==M__Nl6K2$ qm.oZa0+++GKߏiJ[.b :P;wH$DQk*sQ;70}oh[yTDG^~?<\+,Wx؅NKK!NH$|*.[,ea Z'NKKKLNNaq#j<e/H$# RX\\T^˱/ih*[xIW}|2y677;UŘT*tr||,:Z4 UUPe\@:%I<HDNS0(j.;jTZ(HTpJ洿O: b_]^4v K, FKfE}9(O߸IC`Λ!㴵Z4f<&N|a*&u*C.wo^;~ly&kkyQ4u= L?U1&\" ԧYx>~Y8__9 0sUΫ6= X{ Ohe?].ibbHŚaqz:Pp ކ ^Mxap^eZt(LV;LkUy.M<=dޗ[KI>ͿV$Sr뻩})TCwD )MP z]ͤDnDhG ߯6l)Vv$^@(?3̉vdݓn $`GueˑkD~xxh=N;j;I>k P'G=wNv:ftBWNYp8Jhf8C20 ,XUժr8~RC# ?\Un}*osɮ;37Κ)+{TskǙ5),hT*XFAV#iT*dUHnr95**9W֪\.Ύ nW<$I%݅1]Y]]Ui^zN<'N(XXUO@*f2:z`0EXI(q߯l6v KW"6HyC&r16~099<==r nu/,,HzԎj"nRTxϳP*XhiLOO3>>N"r)"x3GL4 {x<DH {ZZ*E,{vѦNHA]"P} KN֣2{㬬P.1 kӴcocZ= Эഁͷgi5xP@! ݲK:A{g1c+ԭ xedmKp{1wHfǪu9տOxF͏Ω3\z_*w7"bP|H: rbRĵ|;::uM@&^Z4\*pzzʿO-\.Ǧ=K@r& N "&سnEQd=7"5ӍFTKĕ",j܂E$!T*aooY `["A&chhI(H4 '''xgB[_h/V1??fv#l'jx{^ag/A^mǗYf(tqqn4j Y,ۮV kkkHӈD"0 Éd%i,s.*`0 "a||+++HREZe0VTJ߇^$2Z䈨u6}j4fd2H$r0 =8::!$I(022֧}3AV׿nGWN|vKiX܃_h uӉfmb1văFlmmazzxL(Çu333Bus 03D"ޣڲÕ~ol>rrrSSSx? EA$zY)d峃*~ Q +3Aǣ;;;( \ \P(gS9MEPl\.s0c~,^v7X,24MZclxb{q E0.=ِ_ 2 7+<CۊYNbw_Aj؋HSu5uc@y J:- Jp8L‰.EV\.OyUH>s)Uud2XV(JЕFA*%NNNT*_\dwoO1==7ܹB4&T*Rub&>033CPP[{Ze``QT(xZr\G"PϣZ ?B&QurjǏ3::b{{{IRΪf>DbycE\z>S b^ʹNnnn HD"t]\KAea!VUT=f3q: ea}=1J>G RrN4ebbL&Ãnl6YϷ}M{xyLwrH\fuuH$+eg<*qYO]_ŀ ,ZMX,޽?okTmۛ3reMF O{;]/b^P}ʶ W(Z%|>.'Bo}ۯ#h!u^-bwg(Zrpp$ ֘}&=^8:ju0_?ԝkcU?In^mMɄm7BS:кҕ qfNAdp!.ą 7E HRH襤$&c6 .{9}j  *n׼Vˋ#0)T,:A lْP6;e%'dȢ,[8V |_ZU0dzz\.~_2@rCP|}82;;ϐ{{fqqHR4M畗hMLJpc #Pnl{xV꿔X*oeSW*%*A8lnn*:D9??'H`dS-`jjJ *wb1.//3?:ԓ$Je2\N-r_ P2xu鴂R%"Yg#F /J)hfu4ͮ24MS7R+lVU)]Aunߞ׻V9@@?1@t:eo-ny^jB?C4M8?[L^ó6GaZ6w[<-XUutkk?Xv1 ~>>;7x)b`0ùK/섇6AwrMkϿ4oOo(_@QQb4.8J(Zkp`mQ֐oYK8l\՜M{~"ͪ "Hm2Z,M7n`7Cxa1NlWw-#{,& oȧ\64ҙ[ųm ð)dINgN$ v,t:;wBo;w[F2iCsP݅てi|'REwth6y. hUZ ͫY"sRnT*D"`0M*9L8$I oVjJHd2'$4MDQd2AUUT*材02P\.nġPcv:Rt]܀H$ BAJed2u<}3n׏$I,*|FA`CaH$|(j<-4LMM1L氼 EQPV199nft^ `ppD  ;u]G?60i=rE$myFTU+G7,YǽOо^/p ¨b!cii a2 `ll a g |vV8>>٬mmlkq8c 50!0 Z8B xR7Bߊ"eƕl/>:\rVYT0==S8$IHl6sAqEZ'r_|*Jh4b|WxKL>/u0L^d_׉?f;Nۧ(9 H:,"LK-vopVS&romh]׹[~z2YyX(7lÓM^e( (@<Y8=?W 7^B / ԝKcw?I^̋I&iRZLMq)]TtM)t_.ҍҍt!B Bb*:[cIE=~=sj###e0op|WWj~9I7BKaj5҅T*թMkn#ݶ1@P}W PoX̤,l 'HZtqy5oThO4ndAz Y]]\.3>>N0(yDQ Ty4Mctt]9::l>.(IlQZͦ.TLgtwwsqqAP?|B_H%^b17~n:tZFՆCaFloo+D:d2I*"*[өTI^|"p"@@y ˹``9<svv- y_q?P?fn+[ƭ?/T͗ZX,A Ԓ3ǣc+{n{7{;hmz7;Zm v\9Fo8Mţ)CA8kQW\zol6# */HK.cppX-who66?lM ?̝KL#u?) H݂AHxGjXC0A1M8=xśD!L )&j6J `+f MΆv Ԃ޼99_ B+i49<<0 W9b(Ur[\@ @TZss=%VU5.W堋 wgggJ~"#,W 8PU|*Ou]ܽgnnNdD"Ri"Ê-uuuLNN̽c}}}$IZzT{pQXj{_]=3Ys}6 C% l p{T1008ؠH$̌!m8,,,ii...٩cEF4744`vE³,MlVo) Mpr\( ^I'eٔ54.ƪUPl68KKK~:Gufgg3DZ,N56_ L>x۶AubtwwSp]j.;/w'#>6GGGa2ݲ,޾+8aʯV4J\o&nH$HR*i3 4 0??O,cttq4MvvvX[[F(s8Y] qrr$$P(֦+++|>[bYݸKYx#8S^JKK !z!YR whhd2 6{{{Jg@9^uv(JB#cN/Gf~|>i*EK[:=(9x(V<|}?Ś=M"d\.8jlVu>e&R~)0j*T0j̩bG}ƧK!*ջ&L۶PL&x Oo%O& ߯X;aJMM v(ަT)Q&3ϿWhG=ԝOce_)miP.Ȃ ,H%1Dqg4\wqa2j8 LD d@@ $BifᣥZ궹{ywLSlF=DR:FIxzMp$Z9P(prr";ioo'RYY@X,F<pR.BPߕF ᰌ # @^Wjނ`6(+J.Zk"&U癝Qa p~~Nċz>Ma-ݭd b1y_$)VUUɍL‡RQQAGG===x~vuuu477Kj&A]*++ioo'Doo/ H#O8?ýw.Z>|._yͳTUUQȗfOR+d2Ef6OZ$SEقp-pUU}d2Iji}+S>V#?$uy+211nM{( ̐JX[[}JD!BK:::P!ǯDhJ/b6BtywQH3uƘx., aVWW:m)c.NSUU6f2᰿PlPuA> ox<^4. D"ԭ>y% N 1u=7esL&ɵ7=W%F Ǔf'yJ*g1(FkN3vBKOۃ,//˕媪g{>%N0) BR]]lQU/Coi#]<|\F/ԝO[W?1}jHXZ"CDJ#);UܡHU;tiJҩQ:DQʪ)ResMy C{|Ϲ|uRn ÐG(jZr` {]^^& {``Cƒ 4^XZZne=00 $3۶EQoV.sR )ށʶWcss0,8 Rx*u>l6+Lbn&ir=x 099IXduuWNߔ&kkkR.q]{csϳ맢6aoxxXAtU@u0וWk&&Qʲ,,ˢlb61ᙘ[b1|>d2yLR*),ѧ "!\)4MLd{{q!ͲZ G2ٳgR):g*z]֪ƍlmm8T/^eRΎD-+u] bΊ{AcO`/XVy)a044$s8SSSTU~E=wv@KK;6__#Ef(wyJEN4?L+O߾:Dž:44?Ex*}1x"H%<[x!\P(DR!L266w6+g5͵m[]eppZFOO0;p:b\uz{unaOOOq]MӸtKKKpND zˏ7@4ewwD"ATRpxx (`0(>0plll`dXhP,&gyy^p˗/3==M `uuU`BeYci< c}l>\(ˢ:{,I V _=Rg;7-ZmMB=o`j.N"q?G|T[ l$ wЇ!;wb|99W#]VN UMS J}EV)54tz$ @OHw?I^4&F_ƾhN\mz`]6e`Aal; zSax;e X1oQ7q{o}y_x>>8TJh`8UtUfY4sVYYSj?}5'TN*fY|'UU$m}zqP˻pR ׋m\*# !ZmIn i N&΅^:::0 C{SSStvv:x\eCLdfff^aqqp8ihh0 2x<rcYluZZZ$MьO-DiYb h*YJOWWP*dI)s`Y}}}pZ7n`aaB@: Py՘AΞ=,..dfTͣ$OuLp8,UXǏWq=4e"43MFEM)f^ܥprX$Rwp}IB@ fkTO' ^?!J111TJJ<'˱7_{^4Ϟ=ceeM$Sr)!woo/w䅟}$o8}%n_|(u `ppl6iض-D"m qFGG~ǃqhƍ70 hCr]d2)w),.. L4eaz||L^P] øY[[#NKF˲VqEaeemRvgV{ ?绺ZràdVUnOʄiϞ=Cuy>;Auzzz{"|=)-^;ktaNbvGip+R I$.m<~l6+T̞O&ͱ2!`n-AUUi9}}Il6B:nL$jf%*ÒWh煗mf޳m `eezhJ(m4M^UU,,,jT*v߃ڤann\l@ʾQk6!kȯj( =0H$P, N@@0DqcarL>LMM!ϓjd{DD 1%-b1AT_<_#?wW:D_ϡ*`1{vww]xX~cqbQ,+V1=Amv o32VI@$4EQ2vwwO\ZZgo/]xA‡w!hbOv@4a}}Ԉ~PFc3gxa Y!2]$R S: #Z-i=0Ћϲ77uizɔFK}pZn `Lmxr`4]p:wUrQxy +'> >1*6.`8|? ө̶U&l6 ͂mJBOO1v$IL,J8WU( 3g2m]MkW=HAeɒH,r]J / uvQJ ٴt+]tdӴ˅-,ZH0lɖQ}4'}v17Oxzsχ A !FE48EUR"=a LBӴwReYC5J}0~09d f}ttM(аB{_Vax@e!biҧ]+,˂,ˈuBX__G(;;;ׅإZfAF!t0`YBa`0@@,c C<wYܾ:g*g2F [e*Bل n7'sW-uH,..򅻿΢ ҕel>-v$j N'VBfp2tf2eavv\`9;<<9TUv\ nS ONNXh[7 RH9Ll}: f<>_NBh@VqU5t:<]]f2&&&Nt:9onC4z=BB8$I§_VVVD"EQ$@"`SQ$9y η_B#I? pszk0 ;os6h}^_$[ ~6/d<=B*//X:& Y*dIcȋh4 )k* TU*"V7=} WMlLӴע]T7a)p/ŮԝK#g?&&M3&Q?ئxP CiK=–ҋPc{*= %=)P=WQ+11I#Dcb0y^?9%B}gy[py/zTGggg\__+c|q5]Nyp#*h4T1vv=>gu<(<,} bffU[vM;X%,+Onu3FXs$.٣#I$ hQ$amm 4n9՝8Q,0 *5M~fBX4aEK<f5!`0H,ZTcM)jpr\&eP(ޞi{d ym*c]4h4JWWB%)x^8dYm4YZZ"b1X SؠV1??&\˲uAqxTItmU$P >)E9vS*8==U<LTT8<ԫ 4@|>@xsY__gbbP(2xT1Λ֨DڸFϟX=`.h.vpwM˂ֺfd2FFFT'{/>Ķm&H$  àP(ݍeYJ\RajӖ"a044S#gggHomd2<>H" :reɗB?!i0uT*z9e_td`Ȝb߂5T^IJj'''R):::ZAdY*D5stt4yX WRFJ#Wm^iW\goD*N޽+O#Uz\RrWyƌ§ho9]spix]tidn@n[^֖gŢWdw\.G̍٦X,RTH&ʏuppϟ灩ԝotǿqԨ`;M)*ڡ '*pb7p$&bj&Y*U"DQ(i9Z8nc~9"eE~}Hh`gJ,˜`FѭE-؍[q0IN"-S97*ÒuNϣEP8%|jh\1I&k||)i>Mx<@ ͐&,fffP(D"Ὸ qX7T5].֐pvvkRǼRbyyNUQxHcNB۶*"R,UUQ@BkP&cv:6JX,ƄB͗iZrJeMp|| ˲OTH1BXDV8x5aeY|cm/ {k|iךweYM18"'IJqsVA]Fд[0M~y _=, p}U~4M~IO& x'x6^ypZ-o^{oXFNZ ^s#jcuuq>|>ضL&/m\__ckk GGGT*ܜ89YK3099܎ulll/spU϶9,--assBg{ŻSji\feYF,6CAp jgH$«44ML1Ɩex*uyxtI#5@NǪhk$h6X\\ޓiEG?#8F܋;Фz婠=jN$ Ճ B ߽Xr1{7!J9 1%@D8 \dxQzz*8Pzz\.#F?>waL~]KOWaDZ6aRl#X,,feJ", # M%,PiAS{dkbďqsp~BW+/=;C ɡG ܽ_YE ;B!G4N'i뺈r';\djie2'T7)3E!C$B!\]]$k㰁뺬;߈aYa;;;t:b(LSe4Mb14 Ȓ p4 \lz899aC(Rjh-T*XYYa=6) |>ׯ`A:f) ]juAoM )<(0b\VQȦ:'RJ%eFlyy+gZEQ`6Rc !4M'J%ңEoP@׻]udxHyD"7#>GCcn\^^> ߾D+?6 "?7=cf dYA7OA%f JJomcfgg!qqqUUH˲pxx x(b*Rj?T;a:F6'Iɫ ƿ;ex(lnnBD"H&K+&B1*~4cmh(" HI&ͪA (a.]h/:k~A`I-=0 }~і`72 DZN7PzOAe\4>H15tEoxg} WDp gvG>; ?\xl6yFȨ_g|YQ(zdqttm^ww&c!HmoQ ԝO#u~L˧m]J?`(TD#YH<ݓG^t^o+x#{}Krq]W*v[+eܗVB4&;I+Z,캟O_-F $$zl< hh~}]0_!Ѡ4j@uw@ůNI&,..2??ObbbBKďH$8<<$Su1 Tt4qL&CբP(h|HrFH$B6eos-bkkaUJ%:EVVVT*C4_y%*|T=Dxz'rpleS|zz$5e FGC0_3>>n]Q0 eADygggZWa6p||YiU/>33?ޗ>-N9h[|6psIRr9bFڭ;$$RIKG~BE* T%VWWu(fCqYX=l[vݛcwwI>eg H_gaa5\ץP(`Y!;w\8ȧ<\HZe}}]#zH:25T%o:x*O=VQѓbHJazzmk' Full,B?ĝOK+gщƉMbdk.$UDpg;oK]eOP(tSb+IQPzA!@HOhbr΍ : 799`0e!9 B&M N޽iurVopTb=:+b1?Pt+ja9<<|lȺLKZ}V.{wϞ}LTRθ ڶMRM,ꪄj4l6Q}Vy_eW 2#%:H$G"L211:i8=8777|'.n߇!CӦϭB@\V!`XĞdiiT*bRJq蘯j .=~1g/>ekk]L$QTDQ"KE\.yo9Hd2٬Ӌ]EB!WVV]ˠQf T*E:f``aGcܴxE)-Jgku4<qC5 equuEP+`!^9::R? Z%R~ZX I$rpp 9 ^gp}PM?D~u ո4K u+ q+6F?t^!0*_g?dEJdpL> grǯ fX,*xKJ0Mu %QLuTD&BeY/ty\ɛN^_/х~ !G%s('( Ol=99av~~4ix,({0Zqzzlmmamm SSSV(JD*bc_]]z=T*yj5! 1%vӸwtP-YJ%r9V o>;H,jFb@T N:+꺎qEDc1@F{#K Y%G:A˲0??V;Dh glZC:ǹ677W0H$I#j\R ,{EdYƲ}+qz2OvUU111+ oгn]ihZ{?F0is4/t&LBEHx<Im}X~ CE {xN/?iÒ&''Qpyyī4]";_2 LC8g{M:aQ<ϣk0=w8,o]GRa7]s:z(an㔍vFwlѐnޔ9yHܻ F+ߵq(Dp7l@ X >w;2y b j4a@-nXYYA"@PGcd2B6E>imp5?ܝK[g?91&y"5(.n[W^mWa1(^l(rƉwtFTg9'EA>BvW>>nّ,avrR hZiooj8eibE^xAT"nhTUOainfɦC2llТBD")3p VFǂBZKzFK,<;u` 5JÅcmeZK [%W Rfna).ksMpL u\:,fctt&iRizC#\ lnn%PxoCKK ^Wׯ_2̹k+ `_v$xUa ;wP*v(=* ϟ?ɓ'A^|А@6(bA8E.Cu "zr~vv&/!lo޼)]J177ui숃 Bںb8I4JLt?7Qݎ"L][[X Tr ìJamm i${6s tLA˴1 i|={ ݎrQYYIfXq$DƐ) ;bvYYYAUU]dR)s>uQo!}aᗕ|V6Kn!kkk:h&ODw|'_Ps aH2pm77Y\\}m,z1D H v;SSSRF4<_J$Ekܸq\.륷H$"9a3t~[{ o3Gb1,i ]G { HYT^4zn B*"\Rn~DPpTh4*赵L/ɠS%P$FM3AʤyTuL(sQ(q?[<r͒<^u^=E SyWdK_Xq;i6:/rD!fx rB"kB_6Ȏrw$GaooYZ[[MɤIlhh%%%TUU(6jkkiOyg%'_q?ĝ_h[e'MjД4]jʺdmX%6(J{voWRP 2P^Z[*Fф4biCh4=iz6'NjC6|;$Ii*H)?^Q.\ZQPg(e룿i[VHG6"ԆG<3jo`x:Qh6zHXYYTAJ$rF(d9g袼^2^L\x4M* թV0M+iccC:Eau/kQ/] @hbqV,{~)@!t:I&ܹsG^D:OPvCvat/ƢCCCKcYR5=|à _,L.,~"ߕy ۟tsrZ-vwwI4 .^$dYv+; *R,F,..R.4 ?Q*X[[tJfh,'&% Q*}>$c&333~KM1kژr܄^;E*bᛦDf)ˬvdll %|߯E^\.,|>/#gS/z"H$/I菸LX$STͦ4]|P([IvCqv8y=N )5/-{ɰ}]Ս~Ful09icױDW: ݞ'M  ]*d2g-EGGGia,1S$76~ۚ 8Pu_oԝO#e?t Mk[Ƃ $%^4bՃ^?уLLhbF8ntS~-mk my;k_}>񌍽ZaNO!HT}j胭\dygOIrM环NUoq 2qA>|\6@ӼXr9:;d2OjY!̸db]]]ʀ#%]눻ƅ<0ЊIw񌺦 ^~~!mJ\^^F:'^z$$k"n!?66F>W1+@qyNd>7i?ՃijP^>tlfnnNkuuu,222B!O Jeq SBxܹ`F$-!i BJ▍B!A,ziDD.c:BVVVT]PPʛn+ˡ ) 2!r #%}}}$ SJcV~dňblnnY]׉F*}"9AXdxxXy9eS}ti:&N+l% tww;ı/˪5q``xيݑ=iAƾs\,5E@u[i|p͜srIfhiQN<'F#R I-{4_q`q]'jKGN?ޫw8'{9rķHhS5947uq?_"4̰59G3ڛwί03RQ'zECn&XNx؁({"з ܿ J!2wS {a+='wErϗn3o+0;Sfk w>9Y\>`vSl91峜OxA*ED(9?;sz; '7il';)x;~SE]w@DOr-N{&8_b αXkS^ߴ,V͛{.ѵeye-7y%Ōcy>TN?ڟ "#Qc rE.4wϗ#'+8%JꋯY_-Kzo^]+1)pN0/?d۶a=|r_fv/.|~sۿV lIoEz;;لD$.qB3sෆ3EgﭺCU8toyӂb!Pad'=Rgxw o0@&R x΢DjTvcI׻@P d%d Jhtد ţ3z0|JoHPLכH*`" yl=f}Wsr^5fCm.&!qUV7H}!wiUVprvvT& :1C x+\D[oC>-𨬀 =:ۭBe$B*=ؑ@RGb]$.RÙ)¥sC={<18d4 I%ױSrD;\oSD\Q<>%Si2 5=He!M}pG3 C?!NF%6k#_\  BP/<bP zlڗ `iVf)OX_&eŠ6;2bE\dBрmmH5CD1h TOniyEit7|zATc{g/_x6~g4C^I#BN C2 JP9!ŤwqVcBH#j&&إ|t3S~ .f*~7û J` (#1uH%Ngԛ6p1+D\# N2cmb}4"j,(N2]wJ@kIBT*%_^x2Po~qe*\*ϟc[oFqk^Lq}GfݠbB|ˎDrUَdHi !,b{ vXi_bl+#DlΩs~HsVmMƎƂFUNW̓AeLdIaQ5kw\'nǻa ڪ,_(m"*/FC.Z2#8k,O97BCnCj `Y{йb ]30g}"Pg'FbHz`/onʔԂQD^gb?OA!G5!&GlL銾~\.s Ν ܬ$-:xb_+T(إ 4wYY]℉DFuggbМ\]_I", ƮAehdYm'{A*2v@[bLst論:3=Q=|A fXʔK3wwk b+og3`_*~;\_ԝp/o2 v௪w|h:~~ϧWdrDnGرqR*ł!x^%/+`A81ϏFfq[L?O{ιibRaCvz`W-#-KQ U)ϫo"%1Z YGS8`W%5 嶦ZNIRq"rܼ\iA0[)d%mpHmsc'X h}IAAo5<$Z ?m/RKњuƛ}~o_vא%~W/no7\,ܼR[ln#E_''L~B $1x^Ď;DIl'mwE3xg]}ֽsėp<>; ~J<2T-حVsLck!̠3j/nGZj!PyI4RIMۘ(r{?!a-ZJEIVl7Už~$-(/P9v?1EhDg#32YGl@pӴi7# lMXԙi<(>_m'lD)O㘙 rh&MM>Y-Ō$+0HgD6hR|F;Xu'7dsz% g }%_zbBHˏi׷^S8ʻpm[&EykD(iVgdqR$!9ݑ8gbމ$cmt֎goCE?id206ޟ19ӳN̦d}6SV&^ sz\[$Sv/M~$=KL1tgW33l7m YRxi:.>8aXcyoݮ!;-~8LM>9Cʯ>=mVop֡RJ^r"Wp,w翖H!ȔgQw.1R[ﶔ|Er+~ozί\vdˎFEO͇3qűa @6,CE#|@vA`'qcF3LQYI jn{?hLC,x]^XasCu[>ciQ C((6044')PuIj 4 DdR9g.UMZ<1V)É0T&+Er9}R츮‰.6\bI4ɶ!_/Hs *tjPН+tc\ۡFʧ/H6^p۵.'j.v KCb|8Tl9j-BYDcdWg,iy94uåH XVT- @M@hc%ohҲk0rn hynRa(?G=np|Bg ߧ$8H FK{w~~H$伏jT}3C[Mh&ok>XJ:[޷^+ʥ%IG.ژ~lcsmxa{"ъpٶu@WO ztmOʜ7o^_v⇧ 6zP54TgDZu*ڬhzͳ5/KKZp1oВSSr>񍿮{@z}ђe.%K mBli*R(`tbg+tT"aӊh)#Zc͞ľnQ:_ECyc%P)mXDq^gr11(R-lj?;ǫ ޢŻG|.O\qΰ]*Eͫ 21-v$ dˎD+vҙNoFi6 kHy)سaАt:bq\e[dY|.圤zXT85h}+\RQ1(ஒ)L;ICTQ^Rw{6x=t4XIX|~#MKDAyӘ+sM[4RRJںÊ9}|6w?DԒtM@Ku؎wpy܌+/4vu;79xGKji ++RV3w_q$nI7tMGs~ԅLH$ 2֩$^ЉŮ4y ڸj;~ZMդ-@BNbE2$.g?QLٹ?Askf(lw-s&Y-<`JMjRSN i""fxtH󜶘[ʘiH oV|k~yj`#d77/8>q?ywn([LJw|{=||[Giݕ5_~,ғkCl?c܊eH[ZB.d\MoH~c{ISJڪbA+N@ĝ?Ÿ@p^ V{JhIeIK8Rfǫw=C)a3)(au2Pd4EQ,d.CE3eR)izJ5% hBB6N@> =^PVzB 1P d˟ tC<4[=ʊ&-y  s8?]+s][e%شGS-&drl[l[fM"K-FSE~Ɛh̎MOȁS΢h/Vm0T<>*cc!m^tn)zÏz"!hF Rw! a'ǫ;o1 ` 82'Y(f3tA{ :Bq$c,0z\1I%k'd^™6vVn@{k*BՄ4XcxCeE?[{C73T(Gwtzt(=jA4]^Yg0Fwq;R_Q&AL(fo:kQخ܀pQTrHh$a1[BIjv~D@3A~X>`j*/..ϟ'BT$o"q!_"wuF࢕æiq !-?WV(L%{/&X_iLJgLB>^?<,+}/+8MTx޼x[|;o/H!`}Īxot[BrUvϟOgӸ'cs}iə/ol\n@=4BH_ÿ)lJ)m&vb{YܙE82{\vkxv\ƘGV%F>5fݮ7FyIIzybb\DP,fb c 0ٗ) C-RF5֐H&NbTxƉhnQd$bEկ* 64Ti y $TTz@]i]y*E!T|PGBvQѣ=&6egv|KS$Yz$A`H]=9J "y*=q̯FvHy?]&u`2/,3=1PbKKfr B%~)7W$<赁L s4 529(VD{}۵ugnhy[-8⸹&cdPghn OɂҎ<##[=E L"N4- 爬 `22uxOhO8;&[d}|qe}6e2ILZs %#7?(l,1\|&0$M^yB!5M@\H$u{v piLCdݯ8M~Q@*[4Ƈϱ4eى›Wx{Y D,G^2Hh躃Lb3 }"q~qBТH/[6~ܢd"0=DI9L7- a blMEύ׎1ɲ A+NWJ(.\`&^;n3GTwU[y⨪EAıۍ\U2&o Dt@%]rm3ݬYtr\tlyQ+EׯJTg&oDLYVw$Ƃ187":5@Vt];9R;]J)K`lC'}ekG̐RGq Oڀ !K `:t\͆FY1plN܇7g:W+%kӚ%A&&p/cT?ӡ5~2: 4|X?nYtYc&m0><ёy1Od{NT?O 't"!"QEB&"4r3qӼeeFk'GlU{ʳe4zg PJqSiNH6I aKq kbz}) 6P8(+`L%y eyO[DDq1,/?e8ؾc--&/"Plߜ$!Վ"ȗr&a0!ΥCs>4Mv5N=YQMKf'Mwdz׋ L^%ʇ;%I'򄸝jZf=;i~v8ܛit낱EYҺ#iܼw25Qp:=DžV|o\s[^~qůW~㫋ˊ*7|lwo+#yU\S޵4c!PQ/4h^zrƆ E6vwɹ"))K<l\ˊG=R11!һO{Y&w^dc!3iRwWu=Vw{@/Uֹ9~G $xmrDiS+DDtc&{M' x=O70|#L[ae Er^,)+MkfS`YQ?ZP|iœ.*`[g^;GhKLj lhM'FwC8:6!&v=whY! d p*] RT+QQ[Ra}HaDO<|XY56US "Toy[h#lynwCןY Hњ`d_wE.ԢZu |`n=|酱]O w#9f-T^rȑCX&&6tQl)1|ؓka$IM՟\RBq|MU-]8x>Ȃ <)6F쎤e}ßd=֐(XdAUѢkޣ x3 %p1L|X= F+.]C_ݠYG{`& dUMe!6NhBXĆ]2i@J|γ"lsPm4,!%2ԫLǦ+  YYvT=7i 8L=߈-K8g(CK=G-Rюmӡwf\A\eJFw| ֹ>rb49H4sMZ\{sy ]jbx8Ka_k}6V7d%[<ߓIyKwMW'A”=Bf ۇtU9!`w(Q~H]k`^=O-$me!KdfVF.?2#k$L߈&9(yfx:~ab ߆F͎Kpu3U_?}cV[s0)8R@.r}fu!%Z5>~X(w}{Ѣu39lVd-Moﰼ9bN.+(8QMp<8b$*-6Nvџ<)gS|]In1}ˮ%)\[ q.5ر,XNMjIHjJ]|<҂hPƨ'«IQ OlFEn}SS.]ںLI3dj;G+jm~ j!& YuGB_8a: =k0L)~mY"[Q=éEa.OP\ä &+H)dcFB"+2CG*sDդ(B.@A{U@Q| z}^{u$*oX@!C_ b-5M:.ؾ^~. *|塆UuleS.=|߾YCkҡ <)7heH Xx ^!,d9i}7}rhl]Ms0}S m(r?7C8qb픡_XejWrL,E۷OрsO^Eyd`j3Y%IA/f<@㬤Hʐf ;?PCܿ /ZPq8KT$01[Q w&pe:3y`AS*G0J(aÏ ]N:60};.?"ETW-8880}G[* A Ro 򼙢8 +9@uZ~*-v±d|e0+fg/]\ʼn }e2 -͟kNܣ8M 903GAJuCx8ƈմ?R^XidP bMBخ0}3a/gsC BIquj8TX$l:mKr,S.S8k`p xKs|T cDtzZƹh& tA#U/lixa)7Zv &-)DMNU t=T#ۓQiR`ԔsH-R:GA%mѯ!RT6Чt p.`ds1H7 {4JA8h NΖ9f|l:{66H% ϭDV(6g$Lț(3|tk\jU/Lqq2UVC+mM0X,KlQvB X&CZ4n/{x}~7'PR_<ǶWծ{(34n#Duxt]K@}2IF>B Xqn 8HHEuud7ݮW「'?Z/W">[i$e lu4Ek$sQC:g1y48U{b΄YcB`G|Q ?Kqtp gM-l( *,=1:|i`*e bR/ڦñ4ۖ`I_].a$r  [YE "喯MNS|Vƅ`RlujgR hp=.c8l}RӠo w׭* A;5 ]eCQ2iAs\@-^C˝#-X}5Z6N>̊pW[|u'[Mds֩S=ٛŎ<- sx]ïY\d]2/9 Gb)W6A qq'U[)\X1>{%>}VHsb#qT /_?t[)n݀ƫϰ#MͦRPvw&!.rtưIQŗNRm(5W)+nJP&fTp5d]nP=olj:ѪBbêB[>g*D6i;}vQ%s=\vp\0LT(C_da:#K`Iy*uNK/#X Z0!09=AFAk *FI,h= gk5)&7]o4p7#D2y }[iflX~y nYRHdy,vBXhv޶A96hx˗(3`YIHÎ;/@G2V@P!ij$rbTfKtܙ`ӣFnSb@m[¢xFņv z6qG!z痆dA_{\ B\ϑf!҉B p63j% mH9{eSyIШ9mX@EdIL @9:ǔ rIŸZ>e>`[Wt^|1)H| . &̏jƑ|{̏/ScQkw{!1⛝(bFdR +c!VW/8<|,) 39L3x_QtJ6r-$a[tzggNs`rq,_,%OGsA?l|gJn2\lqL9ZJCvhSBK5_' cWM{_I!VѴA(j I7i8If$Meg 0vF;O./N.frkeva]H]D~aOi6Ş' ;L`Z+S 4,m} Dލ0?O!eCs(+'K=19[m x;f>8:[svfǦM{c͞m]UdD7] (b `DfNG-gWf h(>Xc3#dEɥB8RDLBZ^ &IIm3JAZŒǛmZcxv¹ymJqξ}Λ]tU$0iίW<}<\ݛ[Q)m>ƴgEb(e|:uYdO?I,ҲU4>Fï|mwo:~~ߋ`˯/y !r Ѷw=;J(.sC }#UkU/ϐڃxԩklR%pJB |]r0=&iif`aao| _@W,طM M⤉c[Y\]Y +oe˺O{0#d/9=,E!s٘qr :֥ ]iM>NLP`y2nFb6;@"-h % U,IcpzM a#uҊdӃ>H|!j\ "=_b_䯭Go78}B˛w7AZ(w )O!0DZ$Xܢ-bJW5#OFs0z,!Å|{2~NFk ,v"_&Rc(:Ǿm|&) Bd[)1=):k~") 0w4MC~"~M]C [XQyat2C2Q.! JAo\a>"F %}8˴%:4b6iYIE `Z;&- bkCa<(A=QAX=3ЍA>IqL!K${R`FA LqQ#OC8K P5_4}hZ @ Q.Z.^ 26=c}4M/(685DfokMR.W ,1f}%V$͋B޾9٢Q4ڝ4NȊعmn t+Qh}g sdEr{"%(m\\]n@=u)I+P[x@ x ߀J5kzXۊeq㵟L`"9Q;XŋV` N[rۢBTT >;B0`I1yM2Fwob=cAnkVp*,*q+ߕbl:#eF+4'S>%QX$3<å$i.`q. a 9hIg yBY‰츸F?ŧW3{|?Ǡˇ_ ArA;L.G^ah9(v[ h)mz؀c۲EЊ|.Xm+9m$E\ˎD?/'ɥ  $<[` !-q fzzC;Xr!RvI\??&ioumTeq&<ִqYIOWꇙtUbj@8C&u]E&m c%@֢^dhrl_6mCKm4&WcF6YP5( 9<c3OOj֚!DS!Q}#&?;>tdA.ISsvuk"عZ᪶7ؠ10CbnwBly{ov(o6!N="e'@ʿCoҩJ7Ct.s\Tǚ g)7wIb%*JV|tճ+J2$pۍ?f 4uRjkN's7"C;lG10JP;z,a{"z ӿkNNMWn \@6 Z"[ՄQ9zHm'ni{QQH:)ju'#zSPͮbQ$X?G+S׿s3}h(( ˜O_ιˆ(ya!(5_ZuW/|.rGy(ypj "ފӫui[/AϷ, V/V:"4Z)kwy%2i!9"_KI 㙬 SMV>#ݸ6(5pw. "E$> oC*l]r@=j%d'v$9 P| ?P 3 $ 8H^Kq d{x/iuB &Z TNwp0~tM|M۴ce G-0 5c#@$e\xJ|S#[B |3<-md*!fw׫Vk&Nr\o ͕!",=h;DsB }kn:<`N;8\+|9Iq/#Cqt9E2&2OkFlya?Z psr=L_? JдEruC]];P B!;F:@BL$F$KUP)%]d>fG$A H4YmkyFN3q, mhT5F92w&bjr|"+I @3LxY{r*J}濗Wﮜe&Pр칷n @ٻ@+u:kk$ * Q5LHluhD#_T eK. HNZ L38 FpWv"ʷ솂TcM4S{O]Ewahڲ.)ߋΥ]}BiZޔ,^ Q mE|A*0嶙#Ԡepc4M#ܩXOfؔR#W^^i'gX-DQuHB;b.<l'S|Jg?6%xi7'xO_+Κ䰕 i"0@x|o?5?Ќbu,{NnpIo?[b?p6ph 9uͺ(^N,}j;lYdKEztM2C%lŽ=-+l/1DBBAB|ϟÏsOIۀP/-W{۔o;+~~ϭ3$ 1ZP}[҅@M繾Ԯ:5ԇ͸^b~W!FexI1%> 36.A<1=l]InA}ճ8dBVl@ I8bXe!A' x衪ů_]d[vOo7&4R0ͭ3m˴@VL d,iב1+; OnaC^)E(;wLvV:ڠ;]!9 tA5KgZbtIj-qɬ Re R@!Uu j0`,OO(!(h vG71= r~f%,aB0J0‡oro2!ǘ!ۤ$Hf(\&=M[o]ʄ[]m+o@|85`Eŵ`A=kH@UKn`!k3iAUјNѬQF>&v+ iiN|t}ft jАi@6!>&r3YO!co$ьsԿI:JQ:WT\ t ҭ{W"|I((Y@~9Q:e>x0ͭ'78wvґ+&B=} ' Mn2 JLKׄ88cRh+Bjsxn t=%<  q^>7g1aEȀB}*pUXwv%Ha}X!j/Aӏf)pR,6 ;y7_\Z ?aǺ FV(ewxqB#+AF*n!"2RRx{Xl|1bXMii*dtA!ɈgTm5U9;m.m:?d]K@}n834`1AH q n5سe@3ld !qlqz=ţ-ᘃ(K4wA 7 6nT5\Y'!nl y Y0M&)Q .gR,TCuA,ޓ`k{P<zJq ` NJ\IgSWj }ABlKa}v6:X=U&o5xY.:Z4ne8lwEF|\*AF^r i RCS7M UUY8t ~ϱ c=Vd;Y,H P7-\nr"5y=d!%fmIb5[#93jWk$p[ҏI}d$-En"Q~H k d^͏RX@ģD/]CE A]dFC^1 qiF }ڮ@}r:L@ȶ@9,o \hyc=l#EB>MQ Gp<`-,Ty@TSu?7lP W! Z$AoBͫxTN'%(XsH!py2Ƴc]ՒŇOwyt/w;|Gyo_c֘ϫަ:!*P+8Tjjc-"3^` ( d#ErǶQ ?}/Pư~zolY(y\ϩ-_JT w3&&?dˎDr t}H`blX#!X!443t&_U,N톬)*?8]&i&l($)p4FJ%5H+a=6 .  W Jt]PxptH۞ǦfGl_1;;Y_o(tq(zɻc%Ҫ.a{`yQRxǶ1tpUd3$F0$O:j[8̀@ лM}$.79W H!;~8iP ]Hd5ȠvtMpz^Q;7"6 FI7X3f?cѦ¼H o™0Vzܤ}?TeEL ']g-#j'i L$վi/avypSvN=bE^5>zÎ'k[6Y'Mv@]ntFXp7ksILuu7EA|;S7e)q $Jl 9OȚ j?]M^q#"s8>N4`Ia#.RhЩ:|e6\s.73^ }oW— H5=iYr޾D|.BW+}ì\./I撿?5Z~+ygEc:>6|Ș+GWH'qOnv^n7|&T2ClE+[s'pafW !?~q6|{ ᴢq(2˪^',2r D;ZhlU=uUYKmeqh,oUw0OGsqp+!^;j{;õ@!wB4m3R (yd]ˮ4|&)H3 iHHHo'QDHg͌:'M8m]V"]7zM`#TwZe7O,X)2i6HC;i+ҠE+JtS0p\QۿBe 3Z@Ѡ]?g}_!!.'aċo?;~GJf)-YKQb9Te)iXxs+ArsW>0<;Uq6*ܰ'e|IVCaiM1jvK5}$ ?s`OH֡$Ь)q(1K꧞.]!F2 Ꞥ9%+ק)pLP5z zwᭅ^wAq@p3d;&qy39!cF}KΌ3W9y.$ְ3)v\]mֵ#ʡMY"b~vJiU-Db 0T c~yRwQC*b7 o=K+ueZ#ys+Bk4g f;9= /SCpʏBH;Ĕ[MoD :;w[ ~wW~-^o|3p8(×;0n#{E`YNOSۇKWYHDsBhbƉW0#dA _>O.D=w[ @r77lZd}qIxv;%v`z=8 /5bJxw^`}V+Pid*fxvHEEԫ#_" c˜iSMjw LHd]#E={fgGk!)9"$'~l?MvZʲc_Uu nUu{UuA?*VØ3IDIERK;@:&Mk:$kI鴎pR$X< %<,cM;zw-#f08I)`4a9H'Ŕ-q:-Jl{+R1IH m⅁DɅs|Ax "D1۩ۏ拏&輳.HO=o"Ɍ5G4(̀Tق(#K᝘$nLX:kShnJQֆgdyՒd9mg,4䦧T0Yb:ub8O 3cGzXie's{Y2 Agl.O h@o$vKqݗV+QYџcH :;y?sҌJ˒LEo\Ւ 2t8^ar>XUpxB*xsL!Jcq3&Ge ljXNgs!*u<; *lvʉspSGƏdvu8Hx LNٓ7 yUMFY^/ٮ|d4~ 9I~ԣ@6p} )T! dՌa VITvpeuemX5x) V1p)&=Q v;>,o~JR4|*~'\yI[h~^_h3ˆV+i<`4J0g&Ӭp ~8ʁeK.w;LAV[d_Qyϑ ЬoA:\23\h8%[YGQ¹ wK͢V,W7},SkXԊºKo+ca/ݏvYhڋ 7:q¸iBR*LJNE `B_\r5?IOm8 ,"*xł9`%ٰ*T==='ŕ4jv=#Ϲb LRZ*2RyVVg&."DmD|e.)K ck jɸ ! %2SwsU$)ʁl.9a#QܸD] n䬕#!^`|hUa{MKj-cnj{1Ց &Ngi>,g:v)t$JImMAsf_,ɨbb:`3 TLf/Q*pyPd%eN aC7֩J9Aߵ;_7(_/T {Gƽ3_8* _į*GY G3-E^|M E f@{Z+Da !Yw؅Vi/A=SZ P- ]`" 8;bVMô'Q\CcR&zIh/-~!U usG[@@Z![e]Zd {h<ښNSQmhJ/IcF anBWX #1?Whont*UɴfͦbWYDQs 6#O4C?6?sjng]N}7e !p5v7~4BL Rރi'I *9g~wǫ7kZw|sJgϏ/` 9ϰD^6{Ҿ H!UO\r#E_I\ 1) .<@<P[Ԃ ڵ-i=3"ROs=v3tQ6ъ}Fmd{ m,)O>DYMWSe8b9MA&+$A3o'd6P6Fc3K]5⣏µהE \2!$K[0qw/qԒ ~ʌJ 1jl6!a(8eY/F[e~֫7SJL)S@J_ ' 0#`uJSfZEyNM.҄lzO}UYtĮ,pيݮߡh6e O D"L`8ٓgD:k:j}kI LSSv)2Q+U*laԈ3HQU#7Yu=0dǩ9Ozg8Űt*]iBI2Y{bv-xG)bdk a?ձ`?A>8gկpXrh7_qǗoi']S;~G.j7/`x%oO:V8ӎk wZ:V=fK9{S774%<'0a g̽ o?&A(dPqOp|措010gBiA8bj>]݊8MNFY-P]2~}? j[|=];RMɻ7˿ޮN%|Ix c'"j:dtd\%dˎES]=d ! $x<;^w@ Ap@#E$cϸvߊE]eMWWs#WOs*3Kzh-AGyAskS /%冬,pH׼!/2{zЏߖ6}TO55.zTn}o±nX:W\!w~!mO.of7) q@ 3Ǝg1`{ !!IS;yIA,"jU]M؇gvK:4E9&В\kX˱r΋14IbDyĖ }`*S!82CjNJ7(m>C Jm -1AD8lBgkȏW:Kh@mUPJo"ǔ$I|:췍7#"8rz{:U~ "_R_D%>tRj#9= 9IzvYNqj5M`>!<_4IY)ZhކR ̫J~ȼ7lȺ+SՏPjCp!=(aN(I>4eFUlxm7uGQ1Z5_=08a2юokat+n-"՚O,xwi >\2%|yuN" n#'*S_Ё wv״;6^?<[> 7}B]#gDЬ)>m6*hn'2~-D!1Kr\$ѝn|}1o?nJxޛq0(bo CO-c"\]InA}U՞:%! G@&\;B,Xb@$&mP,Umz{=uE-AYJ/ aF lDkİ*sƿEzs(WƦ8WeNUЊdUZoY8gg!13kB+ C/ Ugd=) Ec5Z+ 66ȖDZ-rPBH6t0$10)$i<ەloHWAHIJ Siu} ( zU 8>hQex!4TZdmߜ2/RkyckWt; 55 ;8*љ(HG WB}2$Fo1HIύ)tcE m,}O9)\~h6-sxۊU4llV"~hI\^Jƛ0ݐ+f͐^!Fa{-XKޣHcwg)_cƇc46`Og@J+t{x6JyIޢùX Wb$6?pwYU&WX5e4^sHi$VsYDF{ Bn@-"} *E.RdN x/?"q PM) DmLt>`9;|  =lMGEArْNz{6""*C*{ 7A'}Z[ZSZl nalxQxٓ"V Կ EV}&A\]Ɏ#E}UXD1"~qcHg&#q^ X(^ p1%eGʏsIm}G5aRn(#GTf&=HSdMjOL ; 2JK RD/ˠn4" m5O"AvlL4)AMeΙMR1a<07Qbv*?%( Xbًk d1t!ZRDH-sERn'74+R^ .[\<#{/ϩD4zvp^'3vAlpo$>{A]0@ ʑEmj133#Fq|3lr ? xuOqcQkHD5fF`;Dҡh$lwvu?yu w֐`'g݀o>ϱ~+}-ܻkB1@[ lWpf]I%~HRӃ[!dV5EŒT8K}.Lڜ4#ɍHd!EĬK:k{jhi>yt' ?rK" N9-3_1`gmTQXl]ˎD=UmwÄ0*%,3Xl=Y @B <ˮ[UHx-u-W=sœKXP2i.k[)8XBN3׬&CHdR^ Ah+UCuסnez@Ѭ5]eA Ӫaf^0!Lfh}UZ%[a:Xokxq:Xڐ$ڠ @pΓgsbCS(g}4Usk/0geLK1KWp#GS HfGʖoB!A"ь0AVwd dlPz˅@%)[]JT+r$ɖLVR@fu/5(RPPTSaz'i;p}Ȭ'd~Bk" !8E{psKY_. zhQ]SѲ(LUVJrI,9kF.*5Fv:>ӐCsWE?Õ{aíqD+ #V& S^KB>B4A_?9WڻAX+iXP?xkXXoG @u:fkE{tг5Z`^(<T.1$01JQ`1~}qO„d_ed1~WqKRƿ,\KoFG~q@EfUMH)"Ia',63ŝ1^ R=sA*ю~@J+Zwcњ9Zl{$cy]L]uLE4Љb=4W3N}_q*UM>+1Q}ٰ8;e2WEt&Zj_y܉QP_r+-B^b(lB.սIk@%#-\8MwUڷNx,J/)Ǒ $ 7B0b"PI('yr&m}!>=%+1/d% vc U:3%1a "CO!4&1$=)z HB`r\u!ހ,Dղl֊Ǫ{6ޟu:--%rI[#!DJoFd;t-q"* >g`_wě{Wx+Ri_2-M Ot&['`(dq37=ALS\η8MUńgnk%A2MGn~`kt>DjEk|84\KN MS[:ai.)qQ,K|>}F;܁KCZfS7`*L9gV kΰ^fIhS1r ݣ `UN L-'.pmMߨRjO2_Ȯ_c{Nv> )>U`:욞?v!:zln#E_%PjĖ$  H'LW?,nUGb˲{Ngo,pi~8-P Air1I>3*ñs N}4ZS`o1cZ4 @0_Upnؼ$h p-]u[Ҵ'ILt%UpxpKQjp$6%T^xӠTf7`ʆ1I+1BssO+1r?e3@*uD>RN76wڔQ6%vŴG g)lQ<8D;l4$Cx8y5Wg m㗴Cʨ%\Ği}F X:9,qΦonl;ֻm8MJST g%d[)/A8(V-d|ҌO'ʶa8"$̔kXHANCAXxT4Ji B0TݚtHD ٨kM4L2tmJtU-gYlPDcm bWQGji>-E[+Wy.2q/;U,&F u[2⾨;g= #I/iM͟7O|~zxV! \bUp6{0+B%&@]*I0?܋h(h Rc_xY]qTFUg7CՔbt]s_zq`U(| 00ZQK}r >Pз_UAqxO'RD.|=3xOQ gϋJSp(F_{Zq5 ԋCU0vKP݆0Oq(w"<*mWpy[~o~.k(j<;~-?\Ɏ\EEOoFFBB2x >=9xY˪EIz/#č|arAL+]}QHNdїe1({cŦ15-oYߛ}ͫƖ,:bY|Ð^HfG t n^ramy|gueF,,X0:v>Ypxqcw"j۲ny?1O.8.ԏaj܌ecj?+ ?h&23w{A U~N)L矓t I=*#fC Uvb Lq7̽semwi6 S i$8a?m2k&L#}`s <bJeXN^QZF`kTBWM AiqS/[bX#σsa5!&,ye%s$F⨜Tg\E =im*?*)MB܎M'p*g,3 + ATkfc.C˰?NF m0%8ga !c%qÉf#l%T" Σ(/r L j虼\?[1tZr+EPFZ;s~_~|ś[g40izAI&jCoQN0iO#c8Ue0J W1tV)N>88f0JQnvlۚMcxnXWV#a FiySQkŲD#P +#l)&8i5.FQ^c4 mM$M UܶYZMZ\טQw=D#qs, .y/{ޕ{ZAzl JAG$/}1pn[޾;X(⊯_l=JhΚ57zÔttn#Euql%F@1bFG`Ӳb <4枌 SUNO:͖qV:RSZJ2~'#1Mu"m>ݨ] ^ZWYmrTi.vbb69TpP )2-`p$u'x{q=˵DNƑ0Sjw-rUS|JΉ|9[;/2*e?D<281\dړSVTeGy+LTօ\e:Lh R[pz|aK+TKPTH4[<.RŔGw Y2K6MHbu#ւ\ҺBRk #@ֻ@E=5lY:*[6\_Ãlssug}sO+5I!a?CU!SMv;7y?`*!1@R䱮'vfk!݉4'yD8+D" W- Ic154${V1xT 2MK5JUgVuprJV)܎M24QY_VFgv+ ƃ0cL>෿w8gn'b~}'oNϹX9hMS%A9 gxq=r9,f ݁<D:s΀ӌ>r;|lp3IFViC`7GzkXYx9=a5X"UI|YRR SU:׹;aa5%DG_c-#Qx=X+אn fuy5Zy^wWp5XG?/< nF>1^]8d~FcX*} 'VL&ĿTDVwbiflMlDQdUd@ $@D,sYkY&8--tn*I3Fs:$.X acʙ5lZFe;HBSw<}N08c#)ʇud<-~.JOSodtټrq-l UǭbyiF733-4]IXdXF=,!L]sJr!A,V!le% 1/q|ym&)6LiBK/z`$V9k c)-DBp37ā+ע+I2O߶W1%C)S*wߨĤ]ed ?'22'Yx)P'Ub;gMMmA :]U`Β"ۉe,k: er>?;Ij7QV'AnG[Kxţ@| IX<@)IJ45UJi%O(ꄬjYζd%I|x9rfSޘL m+l0Eq)]yپB!?3$2}B &t dH+_YBnKcK4Լȷoϻ1|}wWWԦחȎ5Osx洽* ʗn|@ %"ϲnYA`7,fGx1mSqW<ƝU 4Zv?LX7]Em4O]^T6%$Ul|Kfb$"@3)ǩsȅB #y&:cDuKܣ#hDp @dTӡmͭpI\ =n/^?Q/R?_9(`$tHUxЊ뎡{ե)VO)k13J\n#E?3޵M Np G%O :^\$ۻ޿3ra˖ww}fx`'Ub⧰9}}?jXa1G+Q={gJj:HG'09~'A@kgL!E$fh{LV1t#urEyOxHd4&E0ki:z$@2l1#)ʦ0痢$]&urT̓E-3I<JNSw1!$Aɽ{ =Q(}b@ifFbRw5鹈1L'KiZOÒ} Ł6HDqIkCV R14u ˄0&y6R~"7*Ӽ hk[h%Sad1b3Gy(lU¢W+'3̌Xd.wދHyrPNIz0A -RhOJ==LӍpj0LZ(2LPdڂY`pr(3 C}+M(l&g>۹PoӃ}G}@gSjo/]Ȗ etv:x7ۡ :G^AZoZq0=\U>!`sCSuZy]ǻ4^_Xdim^wݹ\ñ\ ji I[Ŭ( H:jr**Ze˵Cl3ƒQ3XɊr:Y^|A5R yT΋uIߜk`HF i]!xcy]Y{;d3i-k Wڢ5h12e#g8r>$d3ĵc Kw?6X_.j*MR1L/PRDBHMQVCWc L3Ikxp=ӴNȖk} 98 z%Ʈ_iFiG}]?]u aBFz$zm!ݽ-l CЙau!m%*6~\ 9(T10l!HAJ~rT}V+v0m͚ܢ.w,:a=bM!WSGTdO$^dq7FS#-c]&7X5 u#>݉(k~NL.~|;>/n~Ҟ85`V!lKEzӞg(#ePP&K$~?_ "q&~VU%[nwWԹD2Yht_ T (h{jLTREYLjU'B 2@J<1N.\ſ"n v\efh'L- \1bN~*,2WD^g+bý TPOa bo+IePZ,m&͍\ ))ZdO 5BS*HL+hcL4fJ?jK{M85Cre}le)1I)qVĔ@8ǖW>f¸?E^m(GvY+cy<1j)uNėo:+B ((03#ik4~#$]4}'Yǵ4̨VIn^CFVqE&'_wR+f2VӀqf#,'+i*m(9.Nr|4↧ i R;C~X儐s0VT,aifd{̺mSZĬZ\(ܴ)4 ir˻7BFr=f߼x£*YXe Rh 7b٫PXh};xO~<`gax) bE>lSӶa -]5^pUgFch^[쾧r<xc *h*J…4涛0JqYDkHO*PNBXK V1`Y~Lk=cؽCe% 7?rWk>;C? [-_xцv2bt9ȍ{qܜ5QǬ/3_a<~B5lwx<d_|_=^JM:QzuϾ9=s8LbAoTKEz'3F%`bŞ?Xb,H93ݏj=YږVWs=ǞIp:jGNVJ)ͥT k*&0Қ?ʋl&SP]'ܠRX鍡V>#e:F.:_J%$Z&Yi%2&zF6fb2iLXGHHZψ0HdOtО8揼ǓZ (GR; |!GOéȰJ+ 4>.y֥+p7b%^253(mMNtڸ$.*C )O^qB)*4$X14J0};Ga\MaĉɊ7$Ux\z^S!taĥ[)3 d j|܋ۤfFtQ`c %Ҵ}vYi2avNcd\ 3](˶Xm77Jc[)WX#CetEͅw^|87LE?߈+Ӂ1ۮ!RRtǝxtLs~!F`g5C' cd <CsQb˶J^#CO^ Y:ݼaÌM4#Rԉ!Rw\:(>_?'0,N+B5hȝ0/sEwe61t#DxnU]GYYgZ!%-bŻ3 bQѬ~i"5FtX+ Q! fG~$MqآBk:~w?ѫ5zuЭq%Xh0W=㓮a_lZ4x~] nV| O/T֠Ua]vxlځCy^>GeM\k佣qÇYɭvs˛?'wf^s}Uox\W.(\U5y36IT ЊT͋E3;n#Q#1=AA= _ݛ'OU+\1kz|'o5= aAjiK6Z /\nR$Fkycƃ0FH8ἰuW™!/b\L5L&'N;b%n\p l|X`_t "~,RUB붑r5zj_:!B^Z8Dmy61Y,!O^وdKtV;.ӷL40O6÷1 1?x퓞d jm"&K6O)u3]ش=+$$}T Qs,”ÑJ,ęܟ/1%AᩮTqOs \iKkrk3;Pb|W÷pѠ#蛚|6'8uCsszՒ!9Brl7ߜ:}ø #l |%,5a{uo^v% 7 ͶP[c k)>PT6K{gPN>&.NQȡA_tB8=V׮Oy>guOb[%1n=e:cYJS> _ДSv55^!7b؊2>ZLCQi@) iJjV{# MSkwlFR>v̽[r;| G/Xe͟Ϩ2iW?pkjǷdŦSnV8<6 ӌ='EU"ܴ#^y9yrNe { gW)8خQx3[C-.p5~ a~@t+eq~?L;Us3g6,E B DA@| >-BC ]{}P;3ʲ-ڝ98!:R'3B:QCJV)ogSNg+'B #R<{wL_cG9n.c1ݫɲe-׎rbY.PN̩vR0W\#R*QmL'9Մz{@["/mI:@Ĉ'/6nUl%\Nn*W%?F6^ zYUt2$+ FNw}Zj#SLpdʷ0҆o`4=1 NdhN].j=Ϫ1pS N-(N]~3j7KxT{pes)[HhfG]jf2`2[Лbj1ndy?϶IOaI\-*Lkx?A/).Reah$ @ZIRrO Bz_.zܾ"\"[B('ʼn"OCuͭ#!r4уI1\1Ӿ뤙Y)SˊٲXEs!YS&Rk||6!@kP̲ɢ٢ViIE!͢1i;bvXM!b.x8ŞOeϱa쉝C)KVdz.gZv 6<TӅ*B:P/״S\9ŖLǙVbS-8=-oFe 7BWD;C@FdQ>mheiwq-&: QVӸDz_^9j>9;gFesh-usU9J3/Be, 07.}t=1|S޽=g}ph-_7XJ画ihsFp' >xxAŊR?T9Egzݕ X`VHDB!?9D %c^}TU1f F=}~4Yy&Ey3]!/p$) 2s^f\L& ʔ:vjL+s,{ޥqAk=RZ#}v+\SECp 4EK3Nx멣i(ֆ8ϬDw9DUMJFQEa%s%bd.EUӧtD$9]Fd h 'm' D-zwNuzP坫W7@|E^E!4z8Th$dd!yit2ѻ݊Xt)EKF,J1zf؟d ,cV."c=T;#v؎٠ q skULJwzv[dKl8;p,Mzu$<!I$C4%I~߭xU*24լvn<@݋>:̨kQ~: 25]c E9 zQ tc$y֙DAG 5uP"TDf%b[~(wўZI2BYax~eec9^%sj<{?eT=FRiǵc ֬lݧ+޸rۧ8U3` CUbK )F<8ypA 0/t0=c n8 X`j rA7ŶSlQblG=NR.VyO/밦kTg1W([F:U :D#1Gb_/N~qLͽ0}:xn\}yƥ]ʍW|Ͽ |q>w/zq?'kVqt+<^6q&2ϛ;y˗ml*;T"l2tc8.PO{/F-˳&8MFL{˷L;U3̌nAR@E@RPShB E ,@ew}\(s;e˅e3^/XIczO R+c%{S{; \L@.oJ݇X:3p޳9[/șĪ3QR+)\-EL'+\$HO,l]  YŊ_=X6U'Al$A9}t.^PZ,Bvd2ژs+̆͆J>xmkbr?ˊGvfK1;WkG8sŔSAg;K̰Ql)EhZP_h Ƀ {H.׉,y]ߣ!pHHZgc-Ubj ( @)ˆL+&(1K\찠ztl111؞]P]HK8^Meh$R )N̏,"S` BE⼧-u2^_PA.mjh4+q.'կw^,o%.Z.ֿw ^+%׊ipxZPGn Um#[7°9n#B$~ݶ(5!A!ņ$6r=ҽ( L3l)"$yO9-Ft;ϸ[/:Ϫ4siܾ17o9ˋR V޺PaRo˯g| BX>w74kGx)vTڙl@=w?їAPLL9KFuJ(;"eUNEiB14>3hڐy]c.PTBJU2]3#)Lc|נkŧホu<8Y ,&9snP茧ǺoLkhW()ԧܘ;(ʉ2n<鍼s>!n&), i6#dH ][J)I!TJȍD&lt@TrU9 mX.zL6rxd-Y7AJj%4D߹(qKPws QY y)>: 7SLcD3D\?0ݚ9IM[?byiPn3޿>Q @u^B64(PWzI9/hV-ɿ_ǚLeT`<'_}!P% oIAN:AjZ'S}Tm$.Pӌys 2,3B\>ٛyã L1/\/:r㴢3ŭ~L)Mɵf&7XQ!0n=y`Z߁l~g0zp hST2 \ B=Pa>EKi߃ !ߡ<wT6^ϲWg|qs{s2^y;VKIM]3xr. O}w_r^.ܿɺT_,8 ǯNkYLcXh]\\E[u^f3 a< K@HF2H< DDּ2dcAz^Z;꤃usο/}(:Kw*x]q2743[ic,2~X¯WhC!\$'NXm7eSwʖ( M-p|Fet]0EQiwӉr[_n7PmiMyHoVܽcnŒDƏe8qi|x.Bty*5G+cNPqfU#I^A:l奎CPNB'͢r0 t$wsuX3n% r$1G<[v~?ry:֑ uٲsz[dd#8ddA@Zpw| 8j oU}i<ƴ)|H0]c{isu1ݿP ŠŴ5`yupRWN"]r lJe2PY6Ci In6aNfi\Lo[ª(L^TTy`)[BDld^;|C^]Wvւ{}7rN-Z*Ƃ:,`Vs?c#94宪{lE3;>s·q@64tR P*D"@P#sr9߇;Cή/]fy<6\RS1r8e&UƢ=gXnv/]gZ f|p?c9O^d\:9j!( 9-uce4e)<%NB1؎_D6,q8H} U$>\ _:Gmy~,G)a"1Y)ީ][{SήyөbdtJ3LnoqXAJA$H&"9ͧzAkQkE~VЖ9G@G9tn-uԂIR_(4O !Ŵ%M[GUKqZ) ؈K=w fX_G)UYrw`-&~&;^3ZEruy_ţ1u^ APk]+,p,U_Him0:v (Xf u TO`tvm6x_lղ>pmP|=hzӇ/M]xt),1a(N;Q`2t7>roD)J@VƩ*PPFr޺}F}p[S)ϊ[צfa+ nq;ȲlU5OVf _}?o>dӼf46?磜h`DU1u$N5Ӻ䊡Lbͪ|>:(xpΟ vg)3CYd3l[6;A.C۔h}(1\ 0r-5_N4u+d$m1 ([@mko!l9E'oM|Ќ&'1^! M^|oa]qykKnn)\p2h,'%u, {4ރYZKmU4VήGuհ:)>O2FKMgwߩdnEqY痃1xlL(\O6LU6WB$qJ+^N2v+F6dPkm U4ZLz"ZPWtE4P1ћQB)b1MKZӲmHV޹7>_tfUp*FLӂo.f.8I5v6a+y8)keQL⛔?|=:AYCP,1y|dq)L{^ᐷ_9deE<;JP).r$Vu~V1[Li3ϸYtg\*ƅZQ)Xȓr+2S5d;o\Ews_޵;Q  ADB $$)h"hhS@BH@" dػ׻1/3n [VwVseq[Cm8w!XkӕD5ߦy'.Q͞qŞ$:w8`=w>hS(}z߮4.ΊȮ 6b#8-Bjm3 j04c$gY؍"o*Ƶ(BW'yI׉9kn8:+֕ 6@)Ң)iL#K*x{A譵kOopw$%AKRnd"ѥ{zoU Val4(5qZ"ܖ(@GZ$4s✼_MC>CK(US6xcau8$ J.?>MY3<3`9(FJ]֘axvM *.iSD|#bvheYl ppb4.,9:X2ꃇ&\aDR quҖeK L 8v@JEl3EŸOOYW*bk#'#;#rF/G?G&Onb|;~{L_<˼\u"Tj2&) yPʱړ*X|}_|i7I~2`51 E,% i3ÝwԽRe$&$FW-7J3,f z#L$Dʹ>申RBbopz0 X$RMRg-6 DIQ='Pzwp=c QAaES!dd0a< 8Bu0 6`hʎy+iV1-h Br\xqGg!ba`mx*D׷W5n"mGt{Kd-T|0P]KDEK(Ehhmxb\Kwbc<#!@ KOjtF?((q덋8~#ê1(y-0:lK|@M](`,N!븗]ãUDn|9G:-` v'-zc/P-Zm,e >AT88chZ3xOyHݷuLNgF.Zi00iH2Iqg0I7Z"! 􈂂z~"] )Ykovggsgb-3}W H@GHyop/?+Ҿ|$ifWӨ5 GGuޭ).gr+,LԻa<*¬گ=ć[!2 'O 8? 5 <\QV}ZSB쥱/ WyN ꏥ( mvV8 \mIҴ{Ȯ6k:>f 49j6dI>Bz=xIRd:"eTeAd0îgljG-rݙ26ODs}W{Pf~hAAqMLZdLf1/P.8x4mG QlM)n]!qn7^iԹfMN(Q.ˎ =A1yP"N+Y7MR-Wr2[X0H,'[/8;U>[m1Ø|.TOδ{?1ڧ\9x)EmNZ0OceC0J#fJ~v ?KFPزAP5u-G 1&Ѽ"L1_]̵`Ct{|@aNPGv[iLia?}[R~k~JS5&U6!n>9(92|{LrlУ~uã,ad"-hW3r u,%Z]qޔ|/K/dk O / 3ssħg\4B뀳y|^(픿k`w`>+Q nKTpQ~N/m^ŞT[Lo%іMQZbCDX)6MD? l㜆!pVPE\м41OXh7Va{d?g9NzDa@C8 }r7]?Qy+^o쓾ai]"JU!jGs̖"uql!V:ܺTnUg93;ެqI$q @J T4THMBFAIwg~96jY/&$w_wWZI]7Nuǽ((6I!](xGl_lHRiEηD4|^G;ͽy벣x y`y*AlN+b#;Ƥ1U}&4ؙ4]P}R]VN8Hj1źqE”]u΢dFG/{˜þ2#iY({%q6Nʶ)ظNYb |GEώaV''OYm[lqǿI6nu#T44])osՈIc^{%nk|tuќcT$&M yxPTeoFuJʍZ,&hg,/3>a,֌ VZO$=!K cU0U%*ajo[930UY?oϙ*ޒw?uLjoU9,2͋JoO8hYܸ"؇_yp8Ld]V'PD p5 'LhX0q;l.o'T>_*XTˊ\Eu9NwN':PA $;]K7>+p#"!C3L^U.tCOթ.:/RvUG>/,L݇6\ c'dyAйbvc0Ţ-3͐d {.x2W(-Go),FO,. hځvxEU=úĵ5B1GE0Hٞt \`AJt^>q[;F&0Np|Žc󔙞_> {ȧ{d?TF⠐ 6JI]o]jDZȧE1~:vR䣯L> H%:oZLi-r)4G'H &'JImVؘ>bS#~[G:ND?![^B wl/1i0-C6r4BaZ*H#-y&eJ >ޜQylaR2[u,Cb{5t¤)r8?(foӷcFރ1=yok_<<{J^ϘvyVeJLshz+cloYL56b1{Ͽ=L%{w&Tn95ALzyޝ,rS,UswS /`zͶ,ٴL1S}Hc|:7( //nZ6EA;8R *>~oF9hzӍΔΆfsC[ ;EU'i"wgWJG?\KUޏL2#(7,č3 .ݹn$#I't&}8V'.nn(n9=j;/_zL79'^Lޡ-JslbzBWX`htp ]Q쳍u+{A7g%Fs $"Vr6y' pb72ǁ &![>JDhzh|Bj~;9"̻USA _`( qx';YD۵$!bz)*VtAHuQQN&P 8Tuxpz%GaIb@54rƛ q!/y6ވoEZ/ $&5ʹ4P\[DQngb}?N)XD&HT^˂pCn d!A`Ct~LW4uLjxi?&6[;nq틬|8w!qXȘ-MOV+¹-̌q5:i+e<v{~ P )@;h6v|J풒fm tﳵV P+ueHCQō)I>/ܹwăgsnWܽHX㇨Ռ-: X]u2#LY!ǽ@[{D .1wO2n=I噧݈Ŵ@6 ?(^rn}q$YJ'Ѽ֜N &5tbaXE JC.]9G$??>[S%%:r{Գ ${oo/*1D{zI?{\Ak*5Գ8^F!^ , (L_-J<#nְ ˧C~>ۣ1ogKF|xOr4i0^(R݋),bO<XX EkIf3оATnT3q4ICZ5R)W E"XcUBx +Dw  6L:$/0w>Ҝ[0a) .0Ns33Oi? )Mzʚ.) ̓YIe<-hpy`l; TkD[+K~ӂ_ i蒎sE܍ &<=d- dZNtkTX󸦃޶:ں>׷T=(b55\5{OFiܹ.^9nHau.}6N*m3N3Jm**HFS< #EOh)%Y*4 UU#\erM2Q ZB+d'MC{;[x0ѽnlӡ ++Q' U#HP[%!B>683xi yEKnG:"޳2B/-n5&ˠ+$o2~)fj#uԪCSyē6XK*ژ8'K L }#̚C,*Xrr{4Hp =8UByn6W>{is:Q`]T7y*_%GEG~Qk;\>'d[ܿC.vCyB5q%BK.~o:4ٛQINx ӊ3![+\Kf\fg0¨k]Ls` j*&+.lKdzSlS>26&Ɓ#w.L4Dήd:?+k!|E>_^y 8MC1xpwo]ycudՀ',w:މw!{ "PyM>jR?}ͪ;z;B8UMgr{f+Y\bDupba`1s>}UG8pل4/)Ɯ}<n1 Wm6.(rĩՀ;'VSvz ͡Q UlIqoL];o\Ef/;Fr(@X@R ҥADE ttHt  F4PJl@Nr>{f(8V{W3|O\0 2\( `D ҘcKKب͇BF|+bFԥ\0 c0"hD#9nz[NeA!.a *!j0F^MkTz(SQq$)!PF]F)lP#EC~jTeo O:9%0邮n^3ѻB ٘*HjW+-LSv>Y06˛Yfڊ$XY;"٘l!r,WBBj{(GST=|k=bGmk[kRK~*R FBhiw|#mjwȚx0*Lte^^q,*ԐRpaLXFhG!(E[AHĩ S /,D/Dxͷ0>H)DL I7tXN%? X܂ =8+s\`3Vn"_aIۈk~YqNޫs)%ڑ8 pR>@-(eӎ*QO4;'x|-<)mQK!n\9Qld^1a ;YoA*x}lnxs pcЁwXM䕄tST+a%pܾ >AqEE<Vp-?Fx{3O܋J?9~z6~w5 k]SNqgkKGxw~s1#[8XFJE)p>"lGj9p\ qb?OpP4k%Pv s6I\nE2x IP@2D InA8pC<<"\8"Ag*Uc8|qw'NuUqeۥ,.&joR ѻ&GnY8glc;56[(Zv=tM[3Z ?tBr8FQ.%J-JcFi{L'(#hսeiA뇌:uz*kf{CV (�l8ӗP-['%!żFn}IǏ с9M}l*# v}6TEM~h"Y?Ӡ۷Nǹz1V1t$Y8Ah.u]x;!MCjuV t iDV 7p4WRR\v.2$:*\b>ѼwH#pDm;lo_=ӈC5f\^U#*~ԀJDU4(=;,UQS!5 hPơ/zn]JF o2~/vúl4YP)╔֝p8҄VTXf%v󊥕ጨQd5d_=G ],F8s%Isأid^t\c&EWq!`V"xC3~{<>3iIJg ,ma}ԒCY)ٌIcY9/˜mPO76Vq{V`_y)ؼszFBڼt*{#v'9Slsq{xΓѴ $-X6چZ*N. '9Ɂύ=T뮹j 8a bT<!<8]FhpwJkAf ļ \ڈgϦ!T6c8ҙ>{\+'Qd냘ֹ|ϙ$ -&UÊo:ap:u59?eZj~H>`K|~l[Tt9y|~1oA;pq3tTL+sF=|1/^p4]|?FiɊ:+PRY!p+lD%!%n¦)v)ucQ 6S>v|ٴVNS*_TMUU;ӓ1ilTbAqt; ?ApҍRQ$%DI4d3mfg\jusc$⡗`]/J4Ӡ]E(utˀy\̵nh)TCoQa\J f{!ʶ۲^Kcke6e(Hq6+HOcW=Q 8A)ṄgdGیi.隸].BӘJwt<"n#~Ex-u@?N! P˂Nn35mhRҍzċԬMҠ% v/ΙtXLb@e2@o'rp\d]u'%k:#VPi㒮((˃*f \ 8sV ]¹D\_ۙ$Jq=M4/p:6W[lߛ#g &_F9Y%8GӐT~ד`(5Kb2Y$ꋀgyFy,v©@| QX1y^(Q >kZ.E!%IQj8b4MUI3 (\O36zIDAT.GNv 9-Q-)[1; sM?'-ނjc.A^$e' Z()<-ųeΟ=cYNHm[%(LKӬ\Ìy+g=Gx3wqWְʓSX̣_Ν谜,?$JvuGvK._]vyy<4]qpdAq<;盫n Eb)ڬB1MTӡ%hUݶK9LqpIqXi̻ x-yo9CGم;|bwv.<}()Θu=\֙4w׷ gDIk|ue?S8v҂79{k8ű+k\̸=^D|Lqާ9K:@/?ʫ_`z0ץ='?mpas~l''w(+\l}Śr˾bx.hmA$Ei+,̰GP&1eet麇 (ϝor`&16j GչQqWՏyf٬I zLPAЃG!M<](c0,HĘd;3=Pս̡?{M!_p <'?k4Лz]Chwゾa Q}ϔqhx#>;Kcj|M?Mw8 SI7 j :Hb,p®^So'#Ef=3و.;lnMqcжziAR1 09)/@96D+wthhN2iI}<- oZFm쮴]NZ7I'66* mUE5Yt՞ P6ֱҤG6>BXpyLׯ]Fpu~鮞LGT:ZZ4B(UDYV^[#OPR 0s3ԕv4*uRcz'jçW }Oc%F3$g~9J 9SqbVV8ړ?HiZ3S:tnǝ ;3\[`M&cH5uY &eQq _XgsubwFdrW,Jǒ|ߤI΋gS>eXߊraަ,'^b3؝fl '}jiQ[BI*OG ]b@"GYF:9.2"VK AZH+>7Ox*~ٷ[?TOoD{O& mIhSڪ CP/I_/@Bj/āAih*in?aҮWZμ~=vP.6lOuk>_zy8hS$g+2G ^UKwV e`|]Zm r#qxN}+J܀Z7.<) H $ɵ N2id \A54C r(봛qdɀEp" ͡JK/صtWL C̨5Nի?_XMBy#@Јcu.ldr dg3`WZ%Ynxլ-H%v~εJTB(o2pQ~r5έwlUq9?u=/1 l 24z$ƹio_df |QٿWmh=jo|VeI\+ԊsT>ttVʲBto<6U[`Fo%dsf`f*mŞ4~kb6AzǻD݀%M %)a7~OR):-5Pe{\?s/{|A/r'^a=47qɜLg@6)#.+,/qZSFwQ#)ѩ ًȓgO` VQJۯB( >"FOAv%lZVW7Wf  \ˊ0qp"epF< *+iF<6VR57\^ZØ$W\?ƭx,Fnl{|Z BcT63*YCZ =Nx_IC3cut"TNq'OlRL4r~V#dTrr~GeAr'N1{K{ t(S>_/o?LnEꪾMxIlqH!e, <O% @(B(HHJ33*Uj=}9u|rk`mR}oA7"?I¹M]#=(LV2@S;%hDžι;9'u!0Ds=u͌0qS$h-/"Ѥn/&!qC hC5 %1I_kBj{R_B aZSeBrzjj7Ҧ Bȏi^)<'fLJg@1W_p>>%V50 +󗾙H+cٲ&J#iN/ZdD<&-*ڲo}!hT ѸuG*p$;woFUd~Kl+G%@XùHr*?Eq^H/+4c6 fBcdk]t"os&;WfEEлɖ=5|t1h+:OhC4J"=6XIT _{T l&Ys\~+l$1/5Xڴiv嘖0e2lF .5ueQdcdO Aׯn퇜.Kֺ$QUa!s }'f1uل*/CD!m 3w_Of"@Fȵ1P>Zf(V`شVG~u=>>rdˎT>vlg&VɤiA@]҈@HHIذA;6 Gb@Uҙű1C"9WWqm> v(ܽ;捩%iSz"M[hwƖZaUmp۱Ӝ<2!7X\F,Zz ]\jU mjkl,[Y_-~{qP茍My_m"7[tCYQ\k1Xw|E$>so0oi3 `jвڿ 4 aK/~2糃|{ ydhck% P, "Q]+27f>}֫UQ%mu҈];UxS+|Ĺڣ;|>#.+n??9 E Z PÝixm׻yl BwT6_[H].;$V߿=Ч b{5nȥ Ejfi6]bxxV7dPh%; ƻLO%vȺ2l$Ki2c5ϥI0vB:UWvVKso+#-{rϓk3K A*|ppk h u QSo "9şҿ6ZgDܰG8B<*]80xJDUm2sSV3!)B=S0K 6CNe0|"_3OKB_)*CY\pm;dzLCA+ kOĩ,KZk$* \`>˴D Yr=(4A)GG1eƧʗ sSoEn|}1D2ge*F??!<_3gv <:O7d/( ŚUf4J8xyÐc@+I i9g|s eeB$λ-&ސ/S==W$&.81;>+hၬW;}҈+㘝9s߆/>$1Stzڊ"[lW4@ s\P,Έ\ݜn)OWq MpLJ'mP6Bk)"K[TuCD*rR_{9!AUӕLKoUs3㻝4I-BE%Z`XA [lHbCH(B[*v_saqgs޾QF`-ojO׵pFa}m;#ˬgiIݽ;0G**-4A&@2iEᾣt4"KJuZ76r e2hJe`c5z Ty 0!ebE۩@I{p:'7uŎjKbDH虎dHm\mdYIMUʷOo񢽨T֦] 1-5a1V{r'勳e pr%?ҲBMoDo f }8w1ggb99y@1zRpr^74e|)"syɤXm ŽE]Jy.EKD eQ֛jDPnT>OgAu5B}򢝆80v+sLg:tS7!kH֙[5Bb5wUUsY˞!Ux㧋H]9})uU{̥n}9Oʚ+]?UMzOZerdEEgɊI/hSGwdew<)رNj =5 qk/!rr}]գ|ys@GhwjC$HA EN$@hE~ D7'\2jϏX8:YRn41n2)9UťeoyLdoX$Tul312㳷(IRՔU02ʔQ7`Vm/?C˲f iI#+Tw]Xnl(үgN7嶹qO0Jr0Z'vj%ym&/t12%?xƤ#.;|usi\bwDV N n~D©0VeE>;_F+ْl}vi z: (V$ChE;YFr0!T()A4 TnEyf|$ H@b˼oCH쐐XR"a6Ils[u8m ]}q7 'rGV:Zyx` 1hio&m*m1jkɮt6DLEoRԑOh:}"1^Nv+-{ڛdݵ/ƲcIHd4w=.AAUiE[hހbu% @`WwQ*5mI7`0It̍l|s`Ͳhj|>n⭑jlUf_)M]Wtb !N)FÈ޿="Ԛ8>7؟Ĝ^ܓY@!vOJ+„:qؗ/4&M$/K:|[pBF;S|twS8pvMi9-&I%oc|o⷗|O93DHORۚÃ!drUoH?oRPAir&02=0Ukk m&e10IDd(4t0 :]CpyT;LҘ4Y.>M#:N\t5ʅMIOA}h+_dHC` # V"Ww $lMb4H^Be *^L(@NРfk u築#U%DM? 4*LZƻsRgA)( *nk>)I>I[L␽^QZ(k4&=.6۽i0+**/_g4Pj@/fJ( |!Bƈ@j54d&lqᶬRis޽=D4 jYM.*cprG<;ҊQīQӘ@kҬm۸t؏ whxO<=s8MDZ*=Yٴxνj]2D Ļ;}^,3>}k嚽~pDr5gqKঋNѪK VɐgK ߡNWrYKɩ y图lԕb:P6D>0qd{yAZVDuf4LKUn={{401#2qc\֥_``tgĐQ 0t3{ߪqߏ:s*hZm6F$5V,J >dytD&$in`C<4-I#Θ_oU16Ԍġf2/%$ށlʚrU>q&nOXaY-KfG"jOeA^>tBE̱&m,^i[Clj iyުlЋ9>{E{g8~"U%k ~*Du:JRea9<3Yl63D(a*PJ%* _;G53w/L{vn+8cKѐ`-+Xz)Ph $g{s=eXlRd7KY+1'L\xOv6uc9ݍy89ݍ0H֓HYG.KWN0űSVF`F'Po Rfjѹ7%؍_poM(ۮ@7-pʹqeQ@q" 1kRP^c-Uj[OĢ{Z\W:ڎy/JXKuNevqd KXЈ6 ʶL ЬjqdM* nu)M?|}8 eyJ+zÈl{t3FJgG چ$uz L_J\S7PLJ. ޖ5_}~oH |$rk.>dʎfN=gsqs&;Q7nO/ͻgO#V)W>C#Jm|7ї_s' jʯO%xWI2Ōsu&=C+46̦Kv6Ȳ!Ru:$ (&Zjmy&+RɖЉ|Rεm W|F4Brm$E vZMl} c~WoU`&֪a;'8,7&iJ!NF;kRib!JUb2]2e鴤i!-d1U h]55+9AkLr1e}oy=xD<̍QQBt]6n$iBr$$ |Iz#Vdl.KKԾx>Ć{3VM_n">Ӵ`b36,V KNJExQ;ƥ4`2 &W#ÕA&ZN=\}prhĸ]Gv,ܫi-Ӫ?ϢZqZuy.]nEEūg/s8hƫO^?th{j?~fhwl]pxAVM>W|x}aݫ}Vl5V|zc|hSxHEK:Z{B0 b}ǥjXjZ+SӉƧx{H|i@X!z^Lo2hH,) 9LIDWvgzDH$DAQ $*9 !BD d6fPeO[*SWg4gݲjuK4\1㼨M*@1hw[^PPt6aRHWr&8Y,jy1TmAi-r$0kѡvjzBxت(,<$ymِ/)'S^ Bjw4đÛQP*Z ,\s7ژv\qoڳwGrj4*G34h ZפQHJB_2g9I3)mC%`9 1΀T/41xcdx*AlրԳ1(O1G %< YI]V ς@ Et|iY*A7T\v:|`}B}7Ë\ŽCO]kN&#2e "LoUyycDZHIA(- R@EE-BED $( "" {c{;swiv{=~z:UL,e+ib*hR$c͝?%4Xj$93QA,c)qUv .+8!n:|Aڎ-haki5F( Z&8g"7"H"GM*PsaUv43 |Vb,v*E`٦c⡥) X]fa߶,D̘`->qptƀM;DtPچgr+7I@oʲST줟 Fe7I)\ݓaZ&yY0H{`&ü(y14Y o`g7 ]|_oA>[q{9K]lS&T0 deZp0(ʊ4+%Q.BJ`>Ѝ%{o8 ?Z4(h<4qcY&s:84P~HBGZF gKX~gfŭ{͗\nh=]YO|T@ :N4/ N]1c z8ʼn Mo\8Ҡa4|c\CPEԧU4@'(VI6`8.0}4ѝ(TqJ{e3R޽8M;6t7Q e方6뽈݀T&fmNHtaDp6tPP*>»|qksMϷXt/[}B~39]Ƴ Zĺ,)7({3Gi8t|3K)9qUU=ye$+yy˽q]u,׳ׇeFaj2)'[0Ӽ T}ʴjUAMVObd|1.JTT\g:V>݉HAcYFB=Hm3ǚ=f,t|l`p2t= 6%&g] PVy؋xl,pnp."k7*ynqbl>#K:zG:d|%j, NIXr{2 YyPXLKUd^Nh H@T0(F~wʭ;S.$""1G2W=oU]Aw?&PVV;eS"n3Q6e bLSNn3ɒa;SҒm SPTLGAH/^xehZ:~HNV+sLC֨ i/0wmgs()$U#pJuN5ˠUxݰHU[1&,O 䶢(Ʃ:\!]slEx6i$tTgV"dzRفcHX1qjþwGnevm Q)ԴD 7^!e)Ws@WG"a:,њ1`HVTH)}م}Ƒ`}Ɔ|s$l,1/"44(eV._=í Ǣ$o7寯6Hn/dueII~`)BII++fYݚii&Aɝ׏!N? Ґh$&H2jqbBl087]n|{!$N$ j4G-x4\ ?H#əI &Zg&=Xi:8AbpQJV !e$fʑMGotE8.kmٔb7d4g[W=^L,|f(r/~ĸxwSD y/S6' aQa)ggyY˃4 V:M|e\Ƅ (J4&*ͰfqX/CpW ܕeI^ٌ瘼$.un>`o`p8Yj! &\Xkf9/`{?B<ײ cq $u~ i\0Ne(rH̺Y}QLm_;_hԩ+]m92]Za + chg븖4]Z;VeoIc(xe]0a2W5`t> EQBr )"U 1z膁QX5W'4SJ1-FGZ E?TKoU3sgl''MR "bSTRBl+l؃gAbA%@҆4myk<;⌧X{9([{֧ҩ/7s@va\MJ9D.s)AtE"dgӘDR**3Y ' lTS{^_4G]a#&VɀzR ;MLNMcilBydīH(ƪeη̽/Cy1$xmQT4@rF^US-%"bnΧbi&>6²_P]HHZ,-hKfcQ5u``Dyr$!r_hY8ʆ0/D,,+q85pBY ;/S,^QS-UUI IV* :+GƧߦyΥ 82BZӮ\b7Ӫ;f3<Nﷻf p:6u8ޗ ėFBbLcS(O1֎B/qg_vM&"PoT8Mҙ )Яq?D#Oc!Ё65k5IE3 :$u'E~Yq{p"?Dv֮2gǮCTHNB:h+l1{Iӷϱ 4*0o~~OμؾIR£j`UBy4ZYYpْo6ۼV#Tqʏ;|f7Lvƃi!% e=̓1I w{t)]g9F8>d*Wpli̙Zp*YM;}t SUЪz&e[,xJ 4a\Q+P s4! %Sfl_qwĽqbhsabv*^ȷ_Մ!*椼mzZH >qdXXLO을<;=`̕ޯt6C;o]hpـ<`1м "to0(14s,&!t$a><>+Z!OZh̭GRo̓Ш^-Ymn 'KTM)yj#q4rgƣ)Q8Z /,m ^SD;oU^uul'$EI"qR QO !@A(!F)!I{ߙ=sfΡ83?0Z̜u,!y*e]2Y\( Vxu#CPRFM]4g:B&xbq$ѩQ,:LB 25<, J\ږm)AFc6B'  mqc4t>f<3~̲*P+]eh 5oLfDծXb,7I']^. QWsYI|YrLAU׵mѢNaR;j#a!mCV*tUy{ Z1RD)6 *"A*r$/F,0sfc[_hfVC?rE:56XVl6FyQyaBZnG-c[??")_|p]jqBOӻS"e25څplɠSy$EN_sIEF6ˉsEɻ ~(C\ר>i9;Ge^Xj({ң:!k3%Bި1a$bH./pD-%n%ŜOM?5ѓ7iA $]=zhFf\IʛiXyp,.79xA(ӫ7Y~,}.[(V,asaC6y\0/tuzbC&11ɿDIoE{v;^QՉ"CHH$n$pȉ Bp`bl=NX40FPzUQ%IQTBh$ʞSK)kҏVbBUF;`1W*1&XfCRzh,JF"8Z"E$)D±*ٮ *YJlB,FB;Z0䧝 rMW\3ˊw\Z=6|UTq5oT"..6yC+kk|?atE?һ( WgsM$HO}~P{ ( Brr8,JíئĔo5 ioaT()i!93 #=h*AZ/ogL`$tu;ȳL1S,CY_o,LY0$LS7'IkJ fJUd8۝McJ4eݳl\"d"QTrw9o^՛D2),g\^Dl.58B2xTp|. E׷i;Ð 2H򒕖Í~S dk1(1Y!#޽=Ϣe 9if0JץgK|%-8#-JaJ44h{>?YAbݼdXij $#epRfh %h40Ls.<3xzg,6u\e릮Z~˧4LrIzd}ڕ",!-3޾N4aoe!D13&&͖s]ff{钭ȰX\2,n"W wQiyOr/Oco >8g5lLx =(̸6Zli+/q-B!}㡾iUi4v)݃4C iL;U۷, .EYP` UPU&ffFPjR. ݙw5ɦ9?~]us)ɂ@4FZ޲$dUߩ@ iiLkeJr*&ϕ;K28I\IU֔l&YZ2tHvPu8EE)e]Dj2[6WT56P 3b4!IVD5d 0 h1Fרm[yYM(2Y1wWcI 4ˡHLS͋;k(RdPHVpF>\ɴu@5I ƈ.B:BARLKW\ lרΠ2^Xseͷ ,M'5)X*ˋ8hݻN}mmy/L{ʸ2)Ǻ0) MMO<i(m։ӌN=Ф? V688'5pt8Jp ɝ![c>W7 M?yͯycBpS,\k ✻vL6=<m skXm^?b7NYh<ߣYtM]2:Lo-vWisgcTI!ikǔn;\:+o>楮ɞYh*gu0id9ˠeh r2cg^(JjcG &j35m50uqTQƓA\!9Wy2cNL)1?пu]Mf!}7fugЏ*5K\ZE ^\ SNj:'/cGx@Wv]4F_&~t/!.LKUsԵ3 M@eȠ!ƘK΄KKW,nƅ[ĸP!$D ! 3#0tOtWU9_TyT:E!`cK]!M#liaZ\"/M)jBgz8x5bC!;Tׄ&t*zɒ껡"Kjbjca%L {"JH[yξiTgvXIOBhpL}Qh]35yب[[HaTJR0D&wkKjO7 {f8i:Y^A=MQ:Šע,O_YFIKiʙ،B]+uJqTYU%W\Yqi[c`u0+4C]Æ_Xƴq~yNJ䛟"ۜmn@삦K3qӐ˟.%oߞZ"K k^eIx7,ǵ%^`3p MFg'MY4&ģa^=S!t")Ѳ}=3ijry cq`p)b4#3!lp-TK 2)w} )%q=|c|z?ĒWYM`v”QY|d!WnqhsǺkJp [ߓ)ʒ_;Qƻ #Oetۯi?ȹ7ϭ?䥖dc2&aKp \,! dm1S&ӌos|ƋQ-:n0D gRr,p*1f0f]lDIOI)mOvmi Ӝ0 l8 IK['%Ӥ-Üo%/' o-4x{Èܘzm](wpf&Z b/w_l%iM_äclKRi=YS]*I5/"IsQ”NfulisviåYxc"K:~ٞ(ɹ>d`屴`cM$H'`}>򒎧6BoO53G;9fpy\~}&g_qOCdnLS\X!QB?JsmF?5pp/8dCvzdaE+sO~'yxJ0w e8ֱؠTێU]U0}a!b1j &&\\&K_+4H$`0 0@ϩgTUˋJo9E.\itofLm{B3*e dJ#+bjM*ȕI}jy0s)g7DZ\  #j9HQ)h&2lOpq_nw&R9Oh690:>'ȗqhJ&u{cv3c+F(}thz%a3hg$&,X#ń39߲-]<G&[&;05 )L 178Mwm.L3H8t-oAbgk03TtE9|,qI۲8y0!0 {|wQn+~% tTd%+bgE[XtF0YXRaǸNU8MQ@6kYmڐJn)C;Q[@Z(I5V~e⳾=P5G(le<6ܝp.%fQ?>:w6xcy{/P[Ŏ WHGU-1/5yp.!ղf]dЏ~yчJi|vcDqRA*-hx',siJM4A("V)EcA dcwr|H<;8(R )V*vڜbDoiJR`/ԝS`g1qJg \w={1>D:#N5%%eHh$B[}ƉBXz-]WKt&uBN֣Z)l{U5SFAL;җȜdAI:lCڹerǛl Nٜ]qrϭ]G:OWkxV)٪=fGw`AQad{p4>;_Z;tkgrCT>pI-H).̗tr HqKM bgÙH#ʞfS0gGO>|mNo@hfDoUw3;k; r" D i" Zh)(-M (ʠ\QU3x.Q'`[Z 0TD #/b/۞g\A_NWZCKBRQU5!g3%OVJL&JTT5g"%50)jZ6eLSáZݐtR6QH^sp9MF2SlSmBat&/l4vN!c4&' V'ly vkjrXdT2sy~w7G ?!q jNKT坧 de;ȲIB@OK _MFE&gg27rS'|x}lT|SXi6Mk|b3% %o wiYn*ZCV${c ;|l, +Er Jiz!Ia|D%k;)cmam >9%=PosRL/X[Lxœ,_i'H/C=Y^oTK#{-z}CG؜=!"=@mȒhhQkHI^Zҋ<^OyKOLE8{EC&Ox\ `&֘I%h;,>+DZ܃<Uk&e!&xFւCQk,ɸ\o 8:1pC߀I!)U@o@LG0T2IXT .m~O|;HKqy'>ڐCR5t?,[ h.XÓ κ=zm$t)dΨ Ke tU8.,,'f 1mͤTZ<֏N|K [w8 ?Irac~xj\Җ"T ۹575EEZڍh+O@DWM#8`>`r;Nͳ{˄DnU5=m;Nbǎ" R"Qx@,lX` PA@p#Hbc;=< =w[دԬ26!%9I*T0Nz`bZ%UP䩴P<҈&a)IZSM`/BXM4mR'Ϻ*, PI(Mcx:uHbٟnt۹,J SG#0vA'텶kL<|I?6*R%m4L1EP:ԳD*mUJ}2t9.˪u):yg@~õ.͋|} Scg@u$JQĮɃ>Kr$BQ5,ŭd`,-"_*CNdG)bv IIE!L(ru*>IR8|A 0 goP\xQRr}3]aa^>(aВ(!TXnGu\ϽApSD;/ѻ +;3+b o_>{OxEg\Uڢ!Zgȋ|H3\[] sBJHɉK8J_78eY",ΰk&rj!K$nċcJsƒ]@f2zXViӳ.I^%9ݺk1aJ3!= /Ӱu9*h:뼵x|X1J!ll3JJگ'o| ,2w++dሕg<k4$?Cӡ+9LXnxdDy8Y븼4Wm?0&zG(J!Kqay8NFfi$hY\m=0>QMIqia;6hpF C(Lc҇0+ُfL8#8"'rY[ G-=tU!J z;TTʑ:\"wl]eg乼 3,JL]Q<58%Uͻ2-%B.#Sq4_X0u ϔ@ua?Hxum/8gxjE( 7{#,h!q$HY ),zEY䘫ϱҵ> Mc;ttQ G df >xa]&==Go7WCeesujæ4Er0"c]38yyf\}6@56eSF!E8B$!AkLk\U?wg4M[cR MZ|Q ЕJ\ n]p#DJܸ`EP0mڦmL2<[fΜ}fAEAɶ幤Qp|~Dfi^=BI伷fm)T\亮6,U,ͨ]P)BLK5Wi ƪkQTBZwTNPTaM5VvloLm(!54Č"lWm:e0@Fg"WL۹J\]xS\-$)a($|V>Gĩ~4Z,6ZJCdil팈3);d.g`gčs;Ot]YxůYۿ6IsPiQm_ D;o3ugwv5K(UHB?n I7A4TD$ 9P$%rIuvng\?̜.jn[Hx*?]mՓ>Omb3Pܻcbi֨0>sUa[_g9ÑΠ4KϕtTi:A(2?|Ңĕ&uK:@K!)iR8B*0>Vr4 }ѐӤy<LmdF#I955~螊͔rM/,2wq3 (D #e8yU?bx<÷ϨaS ׮ 3*z#N'_H3 Y_[cs1⻝{5+Cx .u+LJ'L#Ods-:XYay/& !lZ12ºQWUtRNR!]ucbq^S~[76xkímn:"OܢC&%& U}G_z^A;r.Pӌ$a0Gk]}DZ+NZӻ!:ܻEExm|mZ#~yvB_:p0`6'o,#UmmY9:ZF8-$L1,t>$\jH+ƳV22"7{V[? }j~;#yqۗ[WM}5";KTy#:76$φ YY $Y =-ǔE¥/͋ Enx)ѣtdBN qקkrk; p !]YIP,8ynVrxd)2g!TNj-|B Mk@7)$53MOIfeMQׄR v%U]p(ǒ`5YjxLwt}ILkbǯFdeE3آx>zҡi=gEEQV /707(2B9K)VZ"Fs=f݊Wq3? q(Vag<>N.=N s«vȅY4R7JxRzZw.^ڣR1A)DO){ȅn$ MO+%NJft>79O䚵t3ULNU_qL?swAJjq|tȔ iC8MM# MIS2. %ub.Pt;>; Քvqp Z*a_iIY*\OTӡW'^(AytBK)kK=N{څ>wS՚X~)J[#}J߱80{Ukh6 nxD" =!,U~(qw(&M Ee;ü6M~͘F[6Nel;G l 1P)(QtIC>;**LO甙D!Q(8r$]m!bU|&An?#hpٴBYK-A qqMG UYo*4tC9 j8slyax`>b³X]=CڏlrִǑ~UZWy"/k";g֘Q|_][)_?!iPbzVj4 BQLJLr0 IMKO8Ja64Xa9\,(ڳ^;vp u%iclAꦷv|H2p&4~I~~ĉ%–VӊpMga3#oDW1r&YیIn1]^6JftuC}ʲ2 +k\a[a7]wa4uZ h.x0I)LܫTDS$:I˵ =m`K1z-f=cuCX5 eəK^K0*>f;W$c5 H;KPYcq{7|U6vSR-#)7n=NECU5i!t}v { ޸]T> N?.S-^PR1V67##ִV+9I+}~7w6xl6:N#1~d|pw} ߶(bk=!?ᄨy]$[6~4dFI $KK drRMLnt,&)ly G A\|)<@^~0`dA,AF)%`H!g齫*jrU?L=:7;U2dC,Za{gJcllY&5-+p^M_Yy V" [쪁5}!O Mw&dq^JmhHTo{)]m ZlpkS͘q/]][\w,_%;> pfmT-KcK+c "a,>u:oו\yQC?pг?qkl]Bb仄#gt֐&o"x5nd䗟?7y|:].S>?lFYJ!k8ڎ+ػ3hNFl \%R\B2сjdIE^'oɤ '+@ȧsR qDZ6"-E9O()IN^b ^`]@I+,GUYfuA ?F+E(aS-h 8j9Cke~hׇ:1&Ũ %p\fN%?|!Y_.1fCȾg}who.W /q{,o os6;i@߅0BsXk{TR3jSKE/Vɲ nr"&+b@U)|~dPYY#Fٲ߈HDf>ıQRjaem6JiyV3&%rJ-5&U련2;p+FX'f7O)G[LIZٓscwm>lBR\LҊ")ۈuXgqQHM` ͠a e[lw>Q֊+Ҥ2Jq|%%UHYK,F;=hLTL[Z0TnU5wWWna! K AB</@ylAH,B$${]5ܺ-7]RKt9q D{!,`acU.K\x9-6?2%/gz_L4zieē?S±M,w]]'E'4enb0Z5=D2K:Gt6ا(+)+4CSJF2+q\s \ӊ}]t?aJč=WfKLa{ 4/%()xS%KK ^9rzY\'( _s!㇦2˝>__;|veܤ b3aAc19~׳)rc zɿ);&?-RZ1YZ.ȆD#n7T[\iF4_PO_ƿbqVgF3˼{qV09wDJpK4K͟%un~)?~:<{;|}Myeo2ȣ #fȽ95a06|97s*i )ބ/8`gob X?QFN YA\:Ri nmG2ޘ0tYyU2xuvM{ۨxӨ\_o<% &Dv od(Q6Rȃ؝.* e%?Z##d).ҸQ 88UpPYmG9 Շro(-Fh^l/, MVip LZö\:D*;CL"4WoT~ێ6ZL۲ $3i3Or^8ՠ=N>?L-TSLoU{;s  @)$:B@G5HR D8vb;y;^}9ߑGaʣ#m@ER$ѴF.<2i|4 @fex;" ]|SöT>lhѪTHG{U빿e-4(+EYSigSa8ɉ(a0}|_:.[Ä'qVpR`KPkT 7Sa qUJ  +ikV qqc^90HĬϯ[#-%ztPUVYt!Θoi =;ϕ퐗pt[^ &I|u㑎&XѠ5gxmB ic}GuoQ~ۦn$(=JMdȋ=RA`K|a =5* կK ^7>]' n >NgW9"+.qooQFB`G}g][2m؈KgK/p6xIJޅ@׬GVf87曛Cf̯{ ?ηy{p|~W>x,Qnz ck&Y{aQD%smJ!6 ]2-Cu6 l ʒva!@]PSaxm17qFU7G}*ϩ B%!iY>Q@)~oWX:W~\\EX3LN">M]߾U#>M|3!WQW&CE`="sa4Y殹yҦ]-Ap2a^ʜQZ,tI~ Ɩ&YIz'gYĬ.t% zb3 ltk\L,D@! ^fuN_ >/EB:!wlN9B̡4%Z*1%vzZhJJeCX' _ƞFNy&To2K-qF} !:lٛt;bt,/|r#Z$_kH%ا E$āQ2L"KE:+p=[ݽF >o;CV KMIgƔp=,tcۋPSIENd+:xU?w]kXbc:/R׈E:dg[7C7 FL344_ߠ{ _gu7ޥ.}lo_7|zr{K iaFj6EtF{6Kŭ͘GU_> ~|oRmȧU 4onqԃiVv+w/'|x<{ЍYǢCUɴ`^I/2gټۋD'I$\{ʮ$QA X[y|;`tMGlB{rίua <ߋi F5r&Vyфz+ Lvy %뭐L*\mmRzcYi~nF3ó9:pVk"w r~~gE`Cƍ*ex_I+'`r` |"ó8p3^hĝu&;W7h#L'K$& ?ݬK6' y՘ZєK݈0te)z6JLog?^ǎة*J) Wn? Sozā[/*U-TUH!҂Bkw>2=H{>_KKj زyT@?3ׅi-EwԒ*j Yίt7i5O3Vz>E3bajG7M*mJj IK .s.w}yt  n[=QpJ.(a{FO>#J;R)uXl`\){ KCR'XV.-1ݙL,+0k{JűIȁ6" &f5i w>Ŵ~!<6ޘ:k~~$JpǵXiڜ~6_,-ֺ^JŜ|JRz6=rMI!baSHIb#p qk8elaЗ%ᇘ {7xIq3p(ΏpU-b! pOx x;?~Dt0Tsm%\`j?pO K6yy[AR3>4DZ?& 'kRMk1K ֚.?9Ex< \rlM޹oѓjSs&|1ɓ/ˊ* ;l)ޣѬq9kX:X\Sو HM ciZr2Zv4'X[.+D}ZmEgexqx2 tiNmv* {2üCE0">%ie'‰(C=Q_V^⬼TwC7F5%Zq8/y ,4 =H?q`spA0:%l)EVnovLO|g2|ٞ6x>Mm()bF=@xAK}ˣ3<)zHԆN2̲`}~3Kڬj ,jo;R£©msy$Aqkb ]iokjФ+MYZ8f$Ċ:VU`FCPszo,@vw QP!̘u D*M;2Vi*IO4xqQV1ޓ#6jyp1lQEL<Ů]Lf'k1۽7g|4'>#NYʒ0-Y*%=`^E2Ɲȸ|yfHlw:!\qxWߍ3MxH[CTuj:+² ;<ޟ$e%{iDm 1XF%1U Zi,hݵgIncdEc-c{= ڗirK; [DE&56B_;8?ޠu>A%!7fO*Nof;Jx_ltUog#៏Hт{?l<ٟ[>Ͽzi`-9DCw!̈́[Mn'@ VΏ)sIvrFd'3үoM_~NM rrUDi7B!Tr#K¬=@6n(,s.r2A8O y =?[j e#\lOpqj 4,.KOzZs)myN*9?l6<* d[ir=PSl Yލ؝攕yT˗؝ȩ{u*7(6hBn`[$Rc[YIaPh/i%}^Vؽ[5J#5c;lѨǧР%+`G-Qr\tХ\k0f͟YJcM|i+h`5b lžf 6/d%.&/fĞVtBAmX.+\ǢXh|TҎ Fg9xw/'ؖ@TI(0f[(ځ)< z mRq8]2l$N9M lgl\0hx|uOz }0W7!Nxlҽ h."ɒ|xPEw͵&?&|.ΊZ> %ntx`|X*9 Z]]-#d~7Ҙz_.yVΆt{G|\Ce6`^1Ui7Y[$EOc[<~vxQ+=tP~˧>:"xS)^M WQeh}IN߱-&7Y#O&ъyoSYB*P5tg3=+Ç}/ɣ 2)|Ʋ5E ><& B>-8/x|Mcl4>?\yu&Ӥop0ys 8e#lbu- ~xogØop:I9_Nm[=,bq6놔qFcm{-)?e!)/Gy'}snpV;䳅cS9—q|Tea.]r`̛ұ@C"5]϶FXIQq 17DX% UoQxMJ) [P(5~>Ix2qn]iVriPbg% ھ*I9pHrC<yvk-rV7ݣ͊rҒ Tr8$V˧ҚqZpteWW zwo޺ûO4%{}rmǢ)^[9?כ#9gsH5FYƼheB.^>E-.e*DKo$W:uԥi&v!((\#EbÂ5Dd?`"+6D2"5&C7T85V*|y5 "b d!6!ێ9Mf k-o*[8jɤtjR.V9biK"rQi`)s}][Ʌ1/wX렮k|O.4.V9zeuV@ v7i|jS2-11O+JB[-qLRh8dVD,l$IiHRJ׮e?$ ?R/B4uN"(;Ö;Y 孖@*yK#F۠nQSKLdNzyRQAkdzfvS{4.9AWͯЧ0tS]M&@ 7_C0F <za]g(W0MKﷷWs@S-\ d]6l?rR,cG? Y\2|:ϟu# L1Y)J<h!Q(9q(QLӒBd?)=%ykoGϦ!u WD-t닳~x<5FpARNǓ>}k;LJ%Q%/1 #\Sſmp%駿'9ߢZgxqH>]"#Нl }LtbOz8A[ڦ1}~&R9pkN28BlF`fvN&8RPa r 1> @8vi8iZa0IO2%p4g" ΛcqfP g}!)]je;1?%;-螏fqA*}u]dR5Z#Asq6َ9"@@4YB9jS {LQ~ SjLa9=A&";aڕ ^PA)ݎ9^RƀuJH pfI7d a*5uIaj < 5^OًVҴ(5gq N,o'_\ b˸'+:WW)4 S~kolє]D7 55cp= Y_mV"|!mǁ0d]U_$%hI?nO= >qRߣ1GqjV-˂w^aSӂ-v<{]~H \/9k{_Oyܙ, $cty'U붱Jsbr5d7@;,+pd,nlǬROcC5ȏ@G83Doݰ8vGSV*b<Ѝtʣ݀F)/\[opQRh%-xD[c^"yY@xM\(rhlq\_IK˄@~+k,O%Z6@?alI9 5#;}OwaYSX*ѽAGŜ~1]Y+z6&?>6I*58dq/&9U^nOZ[fs!huc,JAlyV<5z[dμ?Yax6j왰YP%Zv8N0]6}A>g{o.m¿|}qN-,797<{UFm9[Ϳ1gwLC%{ 2ֶHTQyi֕l|^~|@Q| .#6^QTKo!97b5i Nh6]tQ?. >)(4S0V"9<%͌43 /C#@|wy˟R뱏 aŢ]=z]^xFI8BV9j0K~|U+`!-\EUcvPzC}ek  '8 .5tPOEI5Uv\} P暿?8ft4}>g膊{܊Leߧ[cyƅϑǺ;^p :~pM{0eX80/6 >8_`҈<ѽ1T7(QLb!OF1߹z,Wk?1xg8ƐVqlQpZ%@BpM9ݡ/' w1K ɠI m\s :>6ΘgIjݟ}(ȯ~k36=1W6 Ch4Nlo3)loZ~'BoJm|M|IָB EHSYj^[˟TgQd [$ Z-t!z8CV>U2q~GS1EŊ|r8]ucF6$z$!ӆqnuy $ZQ?жєnɴm6.#^|2_&R72/t޽K79 7'F+گs)Ȭ׵`tR_26/`&Y=h@`ųa-\kF6<*h?]Pa8pz7l)hSfKt:]"N,<Øu+˄Кf!7%*^Vr!>n6u{ 絭7r8NhdO''i޽jCv3ĦʽF狒}Kܾvw^3Ʊe/vOܽ'ZK%ʳ /5ʊ_e+ o 0^ hDيUsjzqff:dbL5[W>*"^xQCd2KftwTrʋS>@Aݜ[>YhHEUl~lGV`iJi(è3s5#,*O;1L%٬4,qmA(t,Uǚ $DZq94=Y)/ 49#tk P39c(VlUDڷPq췜=KiR0Yl:>mntrlTs= %Ȋ"4ewTݶMFǛk^-Mܪ//JY ~E{Ugoepsk<NUsbQR7Y6եI _5G2 S&QH + & q% Eٌgs$)CnڛKí Kbǧ5,fM=x|w==Rgn;=͸ҭ|xm0f1Б{-~{8xͻO-& 4~̧?m%AVpΧ8^xWm)J碢*$&/`soK|nhK٥u.-`0‘GS%{S£!LN#[|}ck/<% 3-:^?'d?ӀWl_tU9|ǻ>>xϒo3S1MA>>@xnS3_^~5zEI|]2젎$q!͹ϴ%ʱj֩F.=eb|POSF {Y8¯u)ɉ"!.Dmw.XbѾNɇ;7ؽ,\<:`0#.tc8Ʒ>mG`KN(z*Jt /A&.^^&|dbCOWD{u+gۼZ7XߚMN0rt:˳wSڨjU_s|DKWu]===O8ɀ G%&BG` Xe#+8I=qeOOSǭbqk&R{9?iPfM[h4%^l}qeՎ44Z?Aaz=d!GS{U8Pɀe~Q/ ?,,$AaW1U7<{&pyrH ze6..F9).X9LVG(aʌlv'P 8p<}abaiT;=V6.8%h4a1O[Ѻ >K&abxܽ%c9T#+Mǎo1xۆ.U"}d ߶%%M %j 12xe&y ~M̍_ )˾ū[}vt3vֿzU߫e+DlSˆF@YH=s5޼'|}F6q!зt7]ػG\< #¨l|UO3pL,/byO~@dS&tn̟!9xpTiԭ4;(N+KqR"OUW^3Ĝ?QMO&ƈ\?¸r ONAh5 ]sUT=:>E]s B2-hm375QqA2+ԨipKHMC錺()Œ|# aȼ"I;^&^ꪠ$*V SV T:"Q;WO@c4V^(BRNl~(H%Dl k{k4.P4 ]Guд?Y7]>_cID-^"Vађxx˟\/qM/N#~xU9[丮ҲKj A)O<|7 %8+b)i0?;;fo%m1,AHq|.||ܑ_ g#K RXlzw=Uš&sKnKKWg:Dq@ ӒuB $*P56s.J cd-؊^3%>x6ws3ʥ{6FN7a!cj3/ cN=_ԪފIvLs$7ڵIZWzh'EnV $+k56yp+:;NH,۴#>P?(n+z0\8,f˘|IutkĿ!w1xLx9:ތbiQѺ#?~J+*(l;;M4NYtk=E! g7 { g~ۧS>#~_7؟[{@&x|9Y %iA#8QYG俤㜏wZ/fu:+^!4(# ъ*Q,p78pЎy?#W':6 =Xv46#{\.)+ǞdҢ%eF|% Z}fRz`Zn^M;Z$z ̭tVЫG'rS1=6 I )OXvB047&O(>F4:P刨og_>U׻":-d{`(`N[{le$s/]!8&hUf8bOC5pŽΙ?~eY5VؼĖg,a C91WOk[mZr+ !N(gsZBXMTojz J!kKV9uE^ͩ7/sc{w0a= G~qɗO{6dgRG&aFo- GLkխ7_Z>ҷx={c3p-rZAT>-W/#?qRiVW$Qj=Uᓿ}ͭ=~ry{φK?u_6&:&~8kJ@*TKoU_؎A  ,Bb~¬nv3," E\ep8qpp'ꪮa񕛙%u9=k Kkҧ-"ÖRR(KEk5`g̫25ya6n9"DC"Q0mfKYW&,1,czˣ78S$+%Ɣh3K 4/iUDrݡY؆ Έ)b9&WktV9)y&b2jZ9khřȈvMq-cq8IZ2rqktqSͳV(hM"†e|Olq`9exƳ8ELFB'xX VC 3b^xx:% l:Mku3L]cȤi\_ 8$ܺ#M W"~E|Qhs",k΍Mg &MFƵ zZQJi'Wm>8DH%7?t1~A@`jQlK?bcݣmps㳟ya+5O<%>}GD|q2Z 8GTĠdcVPh{c56[mfeIbxTxp1l5DM=r2t(% N mߒZx4Ս5e쐟v߹MO(oA.W\ِ äQI V :B l7jUpݰk[E.JL?)Z)k)sLw +ށE6] >tɧnP) (@%C7`p|@2&eE|cyן'1݇}x!|"oalRˤ 8BS_)69_\5D%PUUn~6Gs<0s.C1\EDɎIU${  8>6Ƀd&]6F#1FdDB"KݒnsխVeq,Hֹ~[ll`R^ݪ< ׏5|jݐ{ݎmI 6 Ru¶Q"fv{!b*7+zj%u$x3SܒLJJ0^tUp KTn{،r-5³CAUj˂<+|wrjM7*y=MEr+V􅳝L9HrS)i\v*`;6B{7@/ 'x3ś30I/~0>O?~feĂ P b"81><6GՒH8|q@8Pp*u} 2+]nV'.غb5ϐ8Ny5;$vޤ]mizk:'$`͹M&n 淿fD-U'lzTBvݏ0Z!Y&|ϵyx*yFQ`^$%q: nħH'lB3E\.1^lS7*kʢ5_1󽚗ǝeK&5ű~xFYpɪvߥp( ]ja2㳒#YoipgFvq{Djƪ& =dYԠ]?5UZXG$MɃaJ7 Z;>sa SZeCqY7fz]u%lƪ^78ع) /3I``-SŲIY%dHFef|VѠG61= \Ͽ $^+KAt4%3ػGg%t)Vs,$ >{wϑCT$H't,P^"|e6[Dzɚ iQshvzr@z6fYkcaoʝ1RZLS8k˚๭)!},co;Z-"r)[Lȏg+v^!+7Uhs$` w}Dˎ$̬̌ʩLwO7sc,$ 0Mb`鍅6H`FF鞮ꪬgD"SqNOoc۬o >^ 2vQzA _ y53.&I5:|!ӐhiJs(IQuњp/`+q>oā^$xY*YŽ[xc}qLnPak8s]0p;$Oja$z\boN܅<yRZKHQ׹5n@K뼥Vn9pӝ\M|]Pvy FT=xN p)UZ;Q}vOyc[ÃXֵ,Ŭhx8;ѱ.rǷ~5eN7hM;i^.%?vn*, {1jFڹ!S (T$Z 1qȝ$ˊg|wuAg9]VL4/(V)'ƶ{M^ySdXcyn$i䳵iDOg{iG?)Uڐ`tLpxz/qreor5㳟N|%]4$$wu}flscN;k|}c0/ORb_yQV\zf?[c=Wn%Md'Pnz:sVIlC/ MGhLȣeZFW @bWߒ xDz'({ 葾S`-ʷ(,+ D+A}5V%b8LڸYQ ,/nRDe(\}p^Su|TFOݪ:CΈDm Æ9 8CC h kr83hަk\ؖBB|9Oc 3jLt -UA ͝x]5Cӑw`eJ |U5⼘1˭W5[ E^+Wcfݝi۷HH~LV&7̏0l.G˜oVD p;Iv'K&.ZN̤G^UT P6PHk|oO~h4겳M<畆$T8Lլ00NcVET|u$9sln>zJ,+pNVgwUYZ광ˆХT m{eۂܑe!siZ2U">;j,e29$~ESeq]8ZP_b?Kycg){ng;%Uɤ;9nZeIdUV4U<ľ䅱IEM2wϡwx]%²1/O?gm5|rE~0/O[0j#8ԭI(Zs!ӗn<Ѷ{>] c}I?L"I&/kMٚuv97T>;yL--ӑ GSz=z6L?3W;ܽ_S.ˆ+mV-Pi^s*xc;"U-۾R 3{(@h$%6+wd Ezf~p\c xp2*^G=ߌ#=!\Ƀro!#ZU|4C Zc(GNQMY10$u^ Je FFӔ&h]M8)o^Ǎ "$JeD9(btA,P+頋En-wAc'x"nэ 7BD`I'2Pz} N˶qH:>.1j? ~ސ`LPa)54nE{IڞA&[;mZKZѦ l;K+>X.|9#V܎^Pk xEnͳڶX-Kc}UO/zp^IS|)h+SUkuٚwϼeLiMK ΁g5??x²XV}-S~|S\qრ/@,5[C;+j_=9q(9hHBj1wwrP'-B'oa>[C=s#OZN||új?.z&vT&7P c_[Ui$y-ktoL>W!|>;|??dM(&ꟊn\9(ʢ_=]1FNSv)i/Omo3+'YS AitqQG~>8>g3C<=; fuZLnҕ^f "9գ)Y .?g>ն>C1:.omiy +0{Vz8?k!i?.rN@wd K+~cRYbPld8LV4u mZFi"+Pθϧ!+LcUɥ*kda Ô|]X"/ "2W7Qf~#[~c`I\>sڈϟNzDA#۹x4سÄBj'?|9&6+I/7R^$B_V(u&-QV`¥Zq=7gtʣ*?JYH\W{&Wd4E|wr:p՜|s~?ȕ^/ު'˂N!=inȪP\.אvCzO.5{ik;!jݐW54tB:J/VRi 2.umŢ$ڳU Ch0I$ѣ8I6P֚{;Ex#jƹ"]zn/K7']K{pv}yܟJeIU!؎vX|HBiMýiA/9YIB64󊍮Mon]|fANI$9gc8?aU!x=.Uǐq&qJC{ǹB WflOؗŬh0OBzw8yE])r PꆃDqTG? xh2㸃12ø7ws6"2|K D 0 F'yF(ѥor*C"=c0O4܈`pFkEJ>^lDdj:*P 7L 67zjQP2ԥƋ%բ _2x-:߫~?dvT&\:ZRdwX1u6B5WR]ira=Zi\_Re%^ +o&v8<Dz[LcWn :d 3''!ctNܷt ,Ky4?#!u#d'J Fr]no#7i.F|B'3\(PZPn>:}ebb'%?&4!> ڮ=LahjmxZLmp]z.]O߸ȼ4|o7Q~[0a<]TR][t{Yj-z58$4v?Do#ٝIw'0>pcrMTKAI}>'Q׉NJ=3b~ }zri.IQBY"p\5%L| k ֎"X[tX,M3Fd2"-W&(|YXȣWcNWV!EQsU6ĉOݴypȷϮ;;v]A[pkֆ/OnxyunT$N~McTAz4zk #Kƞ0w~xeY{!-5ϜaO)KFlj7+>K -e}#v|$t4{is|;泧邿kƻ|sbZZ$旫;cH/ ;/p*m<0I|t3 aRCVىkG^ifQODvXya6lۇCVeI(KZJuՠL$j d+ ˼权!v{xf~Wqr~V<G 0H+ELbGk-IxXH`wL>p?ϯnU.Bwu p(sü3=Uݒ'zu!׆`M\o @ ~ ދ {p.Тi-RB]]._"{ rBxgv^}awҚa2T@: {\' )o3[˿=aLqd E=G:iI;1gЯC}Wlj]|OR,Lח{sTMN8 0۟˚1kħ^y]['8 Im*^׿CiukyEC=%ŚfSY`k1Tˌ)wFn8浂 ?;﬒h<@U#D8Nb nSYճ;= F(vrט*Wkndu薼LHBtwV貦^u 7h4hkʛɓ'>u7cO RF,KJKYƐm\m,>PF1fWZcTI/TMoEU]:o88MHBV!@ =3|=XJV@x {KuUu:8_y~f@ 8ArB[C&8quJ2鴾ʃ·bѶ8Хt8+9YOnjuTa0J~w*` E](}aM(YaЮᕝ<ȩ]WV3['FOדB^>رiF^g9mtӾf +5\dkm1.J4o笗{<q,O{[)/Hzp5εޛ}j~  |e {R[/ߜd<ܞxwO}&l×IDATZw~lc"O͵Jeͫcf1ӖP/'?8>rgNqO)l"diܺ9Iy()kI\5%,K3!v~J- â𤼲6 oޞу͠kn^KTx޾yaB i̶iƊ8aLӶb˄,*_;G'daR ,Kò4<,L2xc_ cod+Q\bQp( ɷ9hV&>xA:`F4cˊoǏy8א#J *Wd1faVWo>}YDX_eӒ$}#Ңs^CIA\y%bW?BlBGxGVh$m>%ts"Jp_L)Do/pḲ`+}H.>آ0ȰD%F疭f*),[9C]ze YH79/Pie34ox`ٗiz [dИYI\0$lU{biC*e9وtQ=`- |Iثiۆmi(AswIJxMz庋|I} P!> dF8:FM_AqL={[G5_@8u1H۽>N!?4^AFHfHÛj"LF/PM&ᝃ1ȫDbŵnyzU1LC&PJPkGg[Τ7r Om$z4fh#8?!\7rO. F`9Yk RU9Փ;IGxpVZMl&:C*[G][ t]#RTv*onl1f){C&X0kZwh_C ;"̰Z4bUw\V O ~Em¦7ui,tM*cяocTc2B+Ͻ%AlOPI-uy?/$Jtⵎ-b 6Y>N{Z-szx+Zm0a!Uwcogբ"44b]<8$FX"nʼl9[h)8[x<ㄲx̱df9kbd+EHLq;|w9~Rcf:\䖳ZrŁ/)A#@I-H"^B:G5w M뉌{A;`XB#6? foOzUк6h߼>_$ )ͼ:/[emÔfYs!umpxoQӔWuZT2,*L=n򑦼!hC !xY$v{)M5B tjH!(X0X#MP-[;{Ic2{4@1NRP4EGuIM(x2e}0O L6D*^)O:9C'i ɽC3PtFgRHC[L_@))WxQ3g;{4F?j;qK ,m:ڢ }b;G`0 DY{Oq!D.G&p09ӺlY?IXW-'wϩ:0/_zcn\(uҊDMoUΗ;vMӦm@ T!XaذC X‚_+,Y H tgպMhg3csUMUjXd `jidMK  zU_&nzv-ynix#x^0W+Nm y^ԍ]#GĄJ0 b:RPKkQ˖p?WO1ajJ$$XInyideۦ!|݄Q+௚6dX8T-BH3+q:+8QW蕜Ŋt^9K҅t~ВrHqЅ w)] #1|x] q%ŷ\Q»Wv9.r>sʭi/P2y8ՆX:JAsVEA n_*sS[SfwY 9oZ1]TJnÌ/o˛շ`֞r6:u|u%ν\y 5k|w)2\?Pr?V,kwC~8:Ce'~[da J*V-x.\ɂ"TVo&.5Y 16D 4 6~u2S4"r^@ Qxvbr l \z\o}/0 O?eWܷ YܝGvE~:tV0W{gtRYl]"c7χ^~d]|$)vX>WYM2j\WđGhfc}Y6㐁<8d1 'w]"[fZq^$|[YO{BpnVB8VV|mcIӐ]b}WW;1FY{%D^UDq8/>b%X45m*d*H{ʖ_?:ye e$V˒&wjlz- M'(^. m[+_dŤGٮ,ϟepAk<Ʋ7yֈēN dg_y4{z̆܉e߳rl>}kV{%de?7u3cyW)|/\-Y]xN2{0 {gN8!)[1Mb6gk̸FȍϚ^iP |U`:D`]E!gw<'ECqT)6(.EE].@*Q}e2G.8IM)=i(=z.lw" v%lW݆*\kjlC^Bzfti :9? Z'!xvZHAq*)'!Qkd14/q;#wS # !v5d␓b>zsz?[f3b[lpO^/l[˷LˏT?ڎ8dt^vADK+B%`X ?;VXA-EH*DU N;xY\'t,_s9x^TBӲ,r3M B821mGWnmsms̝UM>َWbk#ˊP+ - Ң䳋t‰ =WzoHc08x^E la2KS('ZЭdk1OlU f& $rX̚MaՑL""AU^)B.Y]Dx~W?&Mk\qtݧcd8>J4ֶ}٢+1'uXz\2'9u--JV\ƳU*T0rί ҖǓKmMNV6 [](}ۦA)UR<{@a8.4.Ҭ Tb:8#\x׿FTsuo^e%gV6ow=>hGl&l}GqnW_|/G ٺ#~fTh֒븠ݰz]ή5c9QULrO[wo5(bidl߱PQ5pZi& 6]}a0M5Ӣ۴J^1=(Iڜg(sɹ~@*+dIMB`< ڶ(OlneHc'qR;瀋:b?L7)TK/$}SD/QNYiʞ7In9(M0+0jcZ^Bї 4ʦ(Ga!_)Ck5I(1\2?@0mL?`xۺM'N"<ZB<eFseqp/b ,Gfp8[oXRVx#+ DŽ,ַu\ޢ{?7سT2x+=D#ytBa6gn! =p,'%vug`. O XF Aa[*C拸?(EU:-&jL2Vt_v&Dz,"m;{R6R5]8?PiDUJ7x8d aP}`O8}tſfU}Y dRYwj XV% Ӷ0D/: 7A_![W9.tahw}Oj!uLZtKt3vG/D͎RHJ#y4HCvjcEP dtQ -rE"ɲh t Em8qcLF҈?!8 x;#ZmZ+o"#e.XBjjN@m94 GbK:g!m)w@$6Bqsp9t@ߵX4f;dmQ_Hۦ,5Ri3_8i!,vB a^L%TVKE~k;/|1_.I.@!Ǹ J[ÏKQf^o¶1HKtßdl]j/"Jfܟgڼ-QOCp~ PoYs왃_-%HMFƐo/wAkWv\ý mq?ubM:d\({p *~s21ҶsE4Qxp[{ }G'$i;GqaBQMOzmNduưIA˄I/f/)o]pg .S.|u<.J>tcBt0 \+[ie2%+[|;_4 9`T.0Z-P͢TLOX@؀p⌴ہUjm-fYTz.RJD vɟ>w'Ru_"!ʿ(Wgt ГD )bg~iģ ݻTFpE(I*UWBrF?rs1~[jfvٝ{|~fܙE>;_yCMGCYK"ucFM1<+Q](jw@]( [ Rmr#,jc,1aY6n,!hƒۑTq-$EaULiʜ:G6O?,)xz <6|XFȽ?c_e2WhlǺD݋$WuTթ鞞ٙ6;d5QDQ]Y4 x/6)F%"ɚuWwٙLOOMWu}Nh8<_V#ˁ@WTEhBo5!IU6YCSfq^_ms:K92'I R)*ͳÍAl.fTW>{_ VZd\jF ]8& ¶ڔf1MMkt;UljH G4㟧%׿EfDWeto0 ,%h&lyEY|r2^`+r͟װj!"oԇ&&Hillt>WQōIֶ,){{/lp0P.4tUrЏ `U؄1qN Qk{tAC=jcO?(5ӻ+|89-%-kı`3;⯋{yLRMU|4!S?8>4NxI,6Y >}|1pk#oS>'*EgܿѣGgc"ϐ&$om2C2+MQUofbSR뚓ي^1M n"JR}cөl Ulonwx'ks^PX8f<9LShHg]#bZ(TְjX$=FFfy<:yj:"y' p_:D_R Nh}-jpJ59{5I<3i$_\==t? B6&9ot#XNw `m4XMѐ(2ڇ7Fħw#!tdeEp ]7<2YPln6ύ?^jɂɳX %ДiHezNaIP)eu&(_\xI U5nP;˕MRjL@QBo_ַ %-<]cE їt`I77D|d#dO_G۫|"(& PڄeXHŒ6u e"(֍nQMGgsOw]I/rMfx2ʍ/i)ku4k.bhq8.qΪ0DMoY{o}WW;NbdzM4"obR0nFc+ʊ^k1nyp`kL ]gu,zoMAk$KR^_&:+)>˴O =Y5gY0ryF6(^S9ST|eEL\j"f2{I\$ ,AUXB,^] BO)_т6Qqk'iY!L9Ӎn'`fӂLWx~?ɂ><$e NWEߓةFz6PrٿLxF&}~7Et]>Es")4xB#lҳiɚH+#w;I ӬjMXr^/dV\s"|%9z;7B"PkKR!'wNNL{pQ0F2׫&W;?>+|G>[,FojUUQSOuRn}{ŧO=E{ҥ> ,bضYƚq:Vumܲv:Y"$fCU8F: DGY!xLZfXvmULrzIJQE%g#p(+ssP9:V3TMyC$,K]tlɕk-*(ڭr%\2^e*~y<i$pKx/H$^j,:H~)NUdXnnlp Z@sbi{jCkfnx8o; eFI^nY<~ᥡv"deEz{?=`x}V4\Ï+_K~f>"t./UO6kh1,ۼً5PK>|c1Ye}kj릓L UTKStx/ؖDY (;Bd{X" YE Nl62nN85RI|}>%feJtMUdTijec.KfB1ׂ2*C*7r _cY.iz?/0hs}E7Т?28Z$gJִeۢx< y6X:'09c13RZo<'>b^cfdbw 4:a*K4I҆ϧ8u,7/lDxE+w4, M!ͻ6~0\^(d氈rCj'SY>7.)}:eHy._oWǼ{~OUn6\ 5u*KbPJi BW|~F}?}"LœE6{MsI\(FQ~"t#*cLCfӄ;$⛟'\mxH21g#.Og6{?xL9%5:Y*-6p\C :=dl}A:ٵm F agnmv.{ %7t|*й$& Ʒɏ`C6{Dǣ*v:tӬq`Vn' #\{}tE-DT&io&A|Gog/7OC?2ʵZ$j!bK,!h ;24 @7T.Aa]T4(T  ( +O1ew VI]1E.KuiTkt= Bz_~J3j*rIw%\|in4hYYsv*VgSbrm_;~DI$GX2rze>G0Gt vNͰˊfYP| ނ tU ozD3E 0AO0ftq݌ CP9GOm }NP]y|Iˋlt.nslС u# pB`:v%uaN7rQa…"iN6oۓ3 dzܟD,m46lņJvliDMoU[>mV@"a d?bÎ+$0bfxL"cwv׽U8ξ*]=}^ $J:}XDǩEu]GV.AKiuUSF|ꥥn ۽a'pr/Ai1Yn;3s.sJ[& c֮ S4ݖ*9"|P 0mR"i-j" rV~:ksi*sB_3Nr!oG"'4mOS5끆7`zx;ט5};wIBTk/͑єwzhӊF<+w4"\݈yڀ/~8ǃ [69K)*?&=/68a/ Wm:-tCqS5 $K) >|}T<>Qq<%7]^~N3J{$A-={uF;Aws}/1y䓱C>ei]~c(Ħ9p| 6}ys@\B6b/D>.Ӭ0 g٢|. 1&KrmVp9(!' ;=|+]Ԝd%[~?bܽcmtǓz2뛼 ݥ>-udl7QǦɞ*HL[.5';Ÿߗ$?CV.+Wp#:_`/ E}t6DE_+9M)?h[Pi z/۷xGw7?IuTT/5ƃ>}g hsw ?P]H}'Z:آl@9JFA|(\,TFO}ۄLv<gGdl<ʓnU~EP9\:-JK5*E4\#%E5{dRJʟr=٩40A DOv6';#'ܣv"kSq*]P[uQ&-"IlozZ8p!Y^[.Jv(%{]p=&b~A:S"+)R:S%ڭ,ȋP5^:9BQ.p|tNPvt'|r{]~;Nl>&|<>]TˎI*]6mcό- 3aX%xH,g b!@e!3qw223"Ed U9;:0|Yo8(Z.݇n{/i9NSnf{0f:(,H7 :_^ͨ[bkIEZFfY[J#ɢ*4 l^bl3J6.A Z_)HCY;@*94lɂyoUJv0uG9Y;>Yu,⃣+|qVQ5If8; Ւ_5(2I 7)?~p[Ǽ- jK9Za[ؗ~軬CX-(>D$ w|k] ]9rc]ywǨ;bF.5 9fMv{F>2hq1 &4mw%b#'|t #ie` }T%22Hl4B)\avlXzDEz}*??.' HH }e5y 7;ƺ:Ե!k Fct!L%;{з2;TCiԮ"A]G*tqKIL}FV y|F\C4ζKR"9!{΅nU#(C ]ƍw~_OW͂,9nNhLnT?{oʮCRI&"P7 #4\HZ43d:餒J\ö\lUIk[eX>^+Ao:$ IGJ ?^"f Zvt/g&BO' H`~H4d-*N' iyqS(1e,%&tF?e\UԥhF K,"v248⋳;1,;NJH4R||(: 0I8JxvW+NwR5m\5LNpn,#kŪm WeMaXk8kWY?ܴؒdZq2I(;{)ea(EIL+ϫRlE)ዚ@p'e0 ]>?caZ?/"lG|x>+ iGRoO4_5G=պc,oyrSk\-FrASCɟ=eMÖn. 7'OoWd;^}I|hn.P bϓojQ|?•k\U%^m^m|_\lA3~H9C%Y'GmA" zH*]VRu\'V {lqkazSQ uc)[)/en~7aNFC]S<-4 <|8ĴN ϖLO,Ӣp׿0O_ԖޒE_|ˉLâIB.?7wo8 $D=ф' ~xxƿ2eý,K Z13pla:r|FjCi%GN9Ǘo3ZpzM爍涶b;|bm挃4dUr{Zo|semI|0pn:VE󜫼⿋AȢhxp8@ F6,_=+⺒49='28''^>!}·`t6/Pa,'KKGo^Օ ŏ$&3 vӺױ[t2 Ί6.oIuWxqH0P-ֻĿf#A-~h=|v}оklJМ%2ZnVxդNá$o }SlLn$D Ĩ1O8B9Uuk@Rj]A'> yq4vA?ZdߞO}:&৶?&ѵdqz=l^|HKY^F>K*t.m[{ĉ7>۷p|ᡊN2;|iefAeY.qe U6P^ ];<tk#ݕv;ܒBV)NjSDad)1k֗v  x׳ $qpC!<֞\{uFUAk†H 'I~]"[HDЄڍu^zsE#?lmUm}j ݄pdC}4w =@\~8h߆6M6)Z6V+7F$ZR-N}<&J^x `9tAb&'w'g,%![9hDpp_3:AԳLnT?{<90IȱmR mU*<S"<kZD EsI4dN63eeK{-GǦ0r @~6ZaI{ RĽ[=a\%z4}Yi~5{kboEYny$\, f9vY T7iZ@7u O,71ǶYZHĮڝ'mfT&t4łX(ԓC_s3n䁺#~SYuU7Mh4>Q> #eB7AS` ×csdg+m+`+F\⁖`Ӭw#Ǒ&{Tc6"W S] #K1:%c.SlV[txrt;;6O7ty~tJLY"/+"!cYp8L-Nfa^T=cY|pœ]N/d%'(Bjf)yq:6G3ZR[XF>Yn7| W|bF 瓌O<;K؎*j6{iax4+I򒿴o ۽W(O2~M?tˢɯlQL2rvI:|ޥ"l>?;,YZ|={I~>|Z+ 'nwTzm^Zp2-ي]05 /rIw滧G,ۏX =[>mO1K"V;fÍ4EwBJ/u#۔؎"ZlF^yjaKn|L~=e/|vv@_B2CZ6blO@eA19AũQ -(nwїK/obGXʑ B)0=_R^Pk zo+MEhԳ]wa4 J8Ng7>IN~k6UiP+hvJv PخKUH$:g2ӅKkY_q.dS,`Sє֚4Y0Ԧ;7P"jyΧ徳2u[!e.4?ߣ*+48:RX5(K Q*_yUcXM|uAg GI^ L@=7ǔ 6$HsQBп׍1gR1BZATnUsq|IMK M+U \q# K .\ Z%i6Iq<aŚXWXZyUKjZ$wBAz8 cF`Օ4 '7ir!rwT5R>cה:Kӏ|NsNRCafy.\s{yZ2/!]b2i֦STirK}͵hZəD&$#\}8dex'Ng8ڢP"k,N#I4 TE2hZ#Jjv(KY)$YY;p>/I%4ntwƲ99$kZL Db?]aq/ڡtvH㘨1q6dlㄣ/3 ݀e%Hڶ]#ÕC0t^sH"#QM=͒n ie#l65$yI< n?-4)-a (ò2\XFSۆ <ϋ^豕썻d0 9`lCnqxâYV5&qrpuC?v冬'yŴlfY8KFxpS/g|[|Meۃu>_3y}l䗃 xOyvq44t/O9_@0_IǗJ+P&cu\I/-xV|P[DaC ꒿|&h=9%/~n쯟ZXMH1Z`M+3+Iqs-X/kE&Xtoy&ݥ7z6qZC4`+.p%MUHLr1Qq"DEMz4^eĻΊ<| 1ȬZU+\/2klUS wk[MLf /V kljךeM_FM,GBKM;4-']x0;QK7`jC,)+`O.PF5e.Q^M *?G#\GE:tFbl!G#s5ؠ)slhB N|]buLdu)UAF =Ah,/_oTIoU^M]m;3( `Ė-Ė$,Q"R)&t{WX%z޻}JJ4c+f[z7bg)'K344ehsRFsi āj?Jw4'?/ nlvf9y^Ry*+x.~hR }˒0% f@R\UUF(uY P&`td؟ڹ kXXvz*WJꂽ}-قf F{}U]wk3!*EB6:2\|&t E0{Nܺe45j\\Ũጏ=;Ot#θu{I=nn ̕+lOgDwM$gwONڀGGNOggobwɻ?#{/3|UoDz$cЍsjb]Vm0!#9اR/j/w"6 <=K9󼠳3X5hE>3|9fw4Co4R U5&thXhy}#ڑ߯'\_jS<|:$}9߉_ < 8 z$1{ÄN;n mKܔ.+I^dF6`["4$YI|Dv+n~@Rn8msK1:l ?@xAt {%e*Zt/RPA;~N$.ɧDŽ8qcb*kYzRDYN,*]^3Q ӈ~ Ѥ41~3 핮bʯҺeJ3{L6I'sY,בCa's~[H$]-x;s rP@/MsFZ-m;MUE4VUID xE6LJIVOE*5HLE˞9sGiGȓx]rE@^2S'(r9:16nj<TGByɨL G w>r❿;̒OƲ&^$Pߠ Z ;bZ f#DIGr*1A BdA2Yl-,Y |W@܀7 -lalAvC55Ed'TH+{{ʉ>*TcJGIOR5n%Cgyf3|p|UYYukM%yduEhI[E XFddqiqBɒ*K_Xg7NVe0œ.$Gj#e#:.\mUUM/TUE*-;~eOJOs)l^:HHpDga92z<:H!ɝV"jԨa-kliSyiw)+:DaaXɁE~~ժTk|sw.}:rgg[|)Ͻ%ƾVKW$Q,espsbӕK_m*.C%2ynyl(yʸǧ"ؚOn+X$.ԸP;"ג疧%#_!kuˍaϛ3V $,[ _sz|sƠc03Ԁ-1DHgQ,cyId^M0mJ^lk^r#⫫c fPcg[3懇/y.yy [qh9._?HlQog '/p,˚8CU$}9yItH6A3uVJ51H_!PS40h֫lODTuF]d/N 5S i6(f".u6}O4'nBV.TwҡxoĭU5UvRR͖'D^T<ӪMIFv3寤vsᢉ\cBEAKCkT)(BpC횳Lsmu :: BjYΦ3( V hʴ"sDMl2{J""1ْb;O c]rS1.JFEUQ .U]mzpZ`Cpװ\Ga|d!1ywM2 qMQAW_';4@!$1CAPH $Dt\U N.gi(l+6 9Gs Z]n SzZwpqiQq!-*zykqkg15>VyVE^"z\ 4|;aӏpIQ2ZTu9+ǵS.n% sewO [Gb䷁UUӭ4TA20쥒ZU\3&_9?[{s`yr~/WG||pƛ  n9cߡ.aì0Y9*cG>^O^xnO9;[bǫ' ʍuf)^_Ü>/O3{v*~7x6Rp9^,Xiφa-ۧϢӔH2M`4h?@%}u}ޣ%@a+rɻF'roW$i BPMSOsxmXKoO`Df{1U.J]>mġ 6EJ~ء5gڨ[P-u$rWFBԮ$?\UÀbҜ0׸=)Hn6`+DzYXaow1^Ė2T.PRtn Z + +(WPO'|Y@G>&dgoI,M"f{L@BUVyC`ZC4~Qqjv@a7YWEϟ(-39G)CUP O1 z}^;t Md9p\\LKk$sN][-Zh.eec`l]!$BF0dHvd$` c<6Ax.j%uW)/Nu;~si[\Waƴ&,钯-05A"g(Ce w&wQ#-^ x䒲6lm${ÐAk+mG%6#J3*Ij7hG*bgY60!fd4-q>dGk[YN[-UjaUlF9KKB;3y8YpcQ60*wRX0Ym|χl)LKZR$3Ңf< 8(dAfIOG /^/y}{y9]ռ_ ӆ>Zw^oh}!>a\pߑ-dİѼҘDIitbIXfe7lN>Aܠ8m67Ad^38!5tivv-%\k_NQyD( ;n8飋) nLjzuJdoh3ġ D] 3a L\e3>nz.sŜbzE6+LGo a 3t^V_T|nuX mYєvjmx謤ZdHh1:/ 6^\[0JeLWlV>(+uN pҜ=;E}Dбc8A_vcAV^66@8~U A1yg"4R" u$v'@&8 Fs={6F}UJ#@dU !m6p7~HȺ[cB>Em<ˣ50f AA8GMsUk  H?䓇JcjۊhL*CSjT TˋU^]]yt&D#&p!kwEt!B f͠Dĸ03yLf&cu^u-}>24窲6N-7hGb(ENA<õ&e1$q=gI\NSH\>w]Cp++㔼䲍ee4q]c  6%t{g sSA*GZh1#ij kX8`w @]Qї?8aNIcgtk.rlcMm0Іi]W iA9$Ll6{Zr;JBiA3'MnH.cl>8.?qwx2J5WOwv4 sͱjP,\>^<d[[lfom)ӧ`5s_G!x͏g3s>r uǬMEwC[$⡵m^{/>& C*}K'XG.dUO^=17*#LscٛdNCbƙ깜 q0$Z3os5.-5XuO5I: bϵ]$SuD[<2H 4'/Y˅߭m$3*s*WN׷Linؠj4ecu@ѹD +|p n1.t"~z֮ӻ>*~YTPeۯz]ڋۼg Yaح R9x%Le'om3;&=*s-'$E6:7E\ lzQ1;/c`Elu# JT ¢0"s TB *!qR6D5Npk FvVI #hML'Xk :sVk8.|O,!Z\&{Nz0RX$&Lz%h7ZdeAOc)qOqz]|\qX~?R\hlx(#Q?*@_Ea-Hv9PXKwonwY}}a-w#'_;Nࣧ)EPς DGMRx"Yn:&$R`Ybci&__!pÇ {4jPL_[QQy%e^-F8aLLxT86htD\.ձX}hiNZAW#;CDneCWuU+v IAAh4 pls\[6H,7H F6`'q;s׹j_٬Zlu}^c;{$yI1p)ڊ d?u(t,Y iWE yV%guܾ*P)6Eu0}D2U%֫]Qp;/sI"O{CLiP+[_]6 J|m[fY,)Ƶ-n2(6aCW-_j?FHLmWnCX1CyVs/Ec|Y??YNs9qSkY^ܶ N{ I q{0m)Rr rƣXoq夒nnoY@5 +5|loD~z|2+p[ܺRP|D)KQ=ㄪnoqLM&PJx!o<&ܼ1Y̖2a86yI>cܟm8:߰C>1pѣ?}^qHZv15g뜲IN7iuQ F֠7{:6AhT61|v#y7a4DbYz\ db{ yJ)ؽޣn^$Jᄴ,S>|sd,@:. Y="#wi;ܹ5 TSӸv'n@v[AnaߠIV_Iz6F]p؝}DAH*>h.>s h xAVe.7ЭP7BB.mO@MNoc=0MOQ^jzHy|ł"ɈvI)N=a9E6\U؝(}L:9gsr-ᵘ2 r8kuvZm+4Ij} EX*e0ec,(Ghs J.3UMYKKe@Zp3NJ<:g3L߇NdΧ,уXHI3Hx ~ܧ3e >OD_o\39v׻Y'qi,BE TT傫E+]?JՊ˪H*$-DIJz9gfYigvyyYĝW/spZ2Vh (m;akx EeHTe7?vuåsL TN7 rVP5)<\/aԖZyP؅:$B{ϓno܍9+kNZuBjH,u[.= u{Cz8[:qxKB)oTh e,@\ќ$02?m޵WWs^9K%1-L*qU#f;$l&9HkzCo5C$6p46˽XN= ؃qzqH?W9{^ _spT!HzJ?d0Tk݄oP[ǭ.w>xhabS.dݥ>Me?1(!hm%Xp8_͵$@~.CVcV8YD3qK!iÊȢ<{O+ь;?f᝭imd}sŽќ[qM|cW^bg{hϽ>]yDM>x`U|v8"]P.AH$ׯA btLXs A1PqJ> a2Ņ=7XT8\|!dSOѓ3,%Augw8]ᴟ$ $9V[Xez\Q!&6ERo ̟֚tXK)rlSE~Y策( ÞM(- *Qu3? 7:?rt4l] m 1ȿ*C맮h&(Mb8B`;9::4q,Ɖfr)ry&UJdep#o`kg-zZ0._ ODAJ|ӧtotz9/l6WPO3TKoU3xbODZ{KoдJj+ Eذ-X@brJJ/IZ'N|a998+_yA-2m8[;hC1r흾L~+BDsSj1esOY0~L2,?l^o2}j&x煣t_\*SOBsŊ0nw(R!6C`^ا;Lw+цn{"}~b9 wd@ \vwD&bXRB0J%H(z6CM3R@!ph2a H\nwyxIK =I<ƃTжW#zeGJ\95@֡R;5P`_*Ye5zxQ8l<~.,ctkzCJ(\z/И z)[;}ݝtmO/pTI>I,SE_tS_续6\).6NJp06|E5V`;˩-{M9t^g3>o*>:3-L3ξmVeWk;8鄩џ6vq!}qF)jx&xy݄©y8ȸU>7:l&!45+!\ Ԃxxµ+Ey:Q2f#jNik$+DUa % r)h g^cJX,||xaNISµ(f`YbJ#MfUsN^<dM( )7$Ǡp ̦޽&C^J!`c ה1tkmYrs7]{v\\^sZi#gn>KE$_,<UV-Ə$U"l;[4NzW2ixs2 O8d57Fluvi/4-d1 q M(Iz}nХ=6ӏ1GWO&sgjC^]-mxݤ|WF1Q^RC5%߹6`8~ 7+m]y,ʆ$4b+=~ш_N{ǔʶ&Rs~ãi_1hដxXs5sF{0aj@JrŸqc񨨹s?{'c|dǗD7&Em-#3G4q/ *^/. _ o>e?͟~LvGw#FNF)2(6|`/!}k_,!u[0gkk.ͭ$Ja׎ҡӿŪtLҚ믢wy].eEaQ~icP9 \_7 9[kV -%(#EPW^@U^ X&\Bij:#E3Q; pb? Q2:oWKhPkD :q/ړ8[')Dsatg >k0W1nߑ`iJ)TZ`:JklUSΤ1[,rdC%sص+ bkTH`˷)}tLtD%gM'`1*N1;}{v@^Uчc۶g=9sTN&$ <\ P칼 YRz)gAAcmh*~D9{=ՒZRS$!Ò  ҆ ٙ`+q @BEN}|6aKaQ%rstLOwu]EtШ鞯y,UsyX@_0j;5Yfzң3-p1UgeN`gR//*n;`]4oфᙿhjmеa4۝]k93>'"ƅ89!4SX@)I dâbVTiC- BDzW!?:L^inR̹:u|i;0VncW U^ =~Z>J9߮'|f4u e^b4ydBݲ~\$QD/rj  /#ShYŨ(!xe5ќWRn|G?} u'xaf~.R7+[ߺ=OĊ~{/%s3 zÕGSj0kYH 2xœ/Qk}k\;߅nX#Ώ2w{C%'L Uchxups']tcI7H~_r`O'LIYS)OG%7~uݧvIrBQǧj/b1 s1pzMԉ[wQ'2H.^CHŋyIlk+̿& }xRhv_ZUħ,Y("\?99tQ_\z54zhhrio,F&.5Vx`٭zr)+Cv]zxFom+ `f9r[v]uRS}Ъ(8lUb+BD&=Z@(6LГs#i&`+2rCx :;2L06ΠI@3CWp΂Jd 3C"GKSUΩcSTr<-g8 C,zm DȬn BYB5:COvKUIAxQRlȑ~d]v@Zj gQvF#;bs3@kO\Pg/\~vs1$9۩>pVRYUTWYg[uq7~@̵Ŕ΢vbDIomzCp$j#d \#r/|0b28dDĖ).áfʡF{Ǔq619Fl 50E t ʂSBϸi0޼9]l@Z˱vqAe+VTPiRb>5y7_4o^!Rscw9E1܅pz*daCYhaCFMuMjD5%NY=ZW+I`u1׎Ҭ+i肒bP N4t22K;kW98)*5˭HI`p0u/[mymK# qrH띄ނK{x6f4L>}'|Eks~s:7X?7o,_z|}-~6}GiRp+;$_y焷v_?v~#?ɻW1W^iJ/{vopl4#(4,m!nIYO\ QO|Ni|y`Q;pd8c)9x1e /w#S-Dc %V>xV 5 Z%}cLXH`JNQU佻,=+VZ&,eIFP|Cu{lG ϸ4̞?zvBG.dG9LՌ'oMQ(eۇ/SX}P Ly0FqԹ^dr N ]|?vcXl\:Qc D@ܣP l%\"ݠMwi uZl5s6iV~T.Ҷ1ϏͿT.r=8OgՋ |q f8@. ꂞpI?ERuya\s xkC؆]|HI /N^3]&3"Z5soұ= HV#%$!!XuVxr .Phk-Z7b7~}F #'x@tӸɝ!bED9ƪyrqmPcbE 52TЧGnIM1O? I5< 9Yg*WJ JC\>M+ko&Ybyg 5#X'Pc&sQ`}3`b`11唃=򐕝#c_RVmLˏ%U?Q{뾪3 ;+4Hܹg31&tw,4M$fA0t}tGOl\֦*J|ͪ$y{.7n϶VH:DYix\FHs/yΦ)V<-9>8^dۿ1 SOЉt Yn~~󯖌&#}Q^sKB=ɤGU~Bwf|HAz{jGxJݾå~;eafjnޟ7fJ*c*Jbe,{ }'7yIhQԆU"[yF%G^zIGdU2sm}W!_o\/T[^e6TzYƬ). a8]<Lv  Ri/}Q[eQ.N?[͍aٚYE?kOr Y7ucȔIyB 2 YInpxqˢKESioKrX^8읮vc5tO,Ҁ~tpi%t(uuAҌz AJ0e]jt{ yQްjxFA=Wm5jNDQ 'Z[-(8.8%/ūDM'cW֕.|o2௏SF[>|8孛c?+XV% kqQsk; oU Eᛵӏ=z_?<ƕ09%YɟӍpy;(ۏ~|5j]s=%$KûWE\0%.k^n }g}H]?ٺ AwV,e S;klqMjc$[?#=c3do^լ䛃qWQHv7a&U85q(y޿E6g17yߏ 飌Q   \v=ՠc_GO_&wa/j,)Qψ6&cջt3>=/F ȿǯCtU.I˷}鿱_:]l]q%2JW :N t&!˧4F0'>o_YdVDnV%.~"4S0 db%W hVsd>l[ R %L0F8ʗsS g*w%'漏 #Vw|! D$8[!M Ɣm_`D .G{_hycH9!FHpBB5mz`$Ѥ՞Yu)⟐**éRrE.vXq$JJ^ϞəL኿~GSD"9:_+ a{w zNJ5<=+ E+'~vE~ /jM(|G96'uú,+M)V-(X˳ N\[i5ȺA;pf\Ɋ =օb4'n xW7hgxg!JS8άWr%+uI(rn:MF$¡|WuhcYi^y< ߜ~nJ ߸R3+oNx<<[7U_sԆ[{oyY/[)u+ɍk?;H)U݇۟!NicIكxyQsɓs0`#woOΙWOW^.lfx>P M)^^r~;˿e-+ytG>$#spxs4+ FF"nV t2k0 ZQZŻ0K~ueh Ìn((#SwlUrӷX<Ɛ1$uZiQx^K2t6p#~ :۟!w;zYM򿯨5זƋDT՚9"*1Ro b2C hB Lo%U'^}q:N[Ѯ^iR!DDÍ:y!>1³ЉlHڵVe6h r3vxCZ0碬Aӳ`r('9F(r\]OY۸n@ׯ;{y ;@cKОtL~''0SwH4@rf]tDm,24Ғ^ G4z\Xc0R!q׏MYrpFiz^N!\4bAxmY\'z#փ1 eN'.xr.037[;5y>a-!WbN$gYۼnزab.Le=}rNXTq[6qp-݋$ehb[SCk^MGq 9)Yb7,83uǬIA]j(:fvA4Unp=jݭ )R. OqPEyn;O&6 =lkh̷wy:F1!`wɊ_c}vv?|> 4s`^PӒÓ|7x%GH^Etnlh߭LFleIls !ִWVB?Ru4Hl>j )} պA!5NB)cJbNr:@o\E=J3ҟ[!xhڅ.g#ԥ5nu}HAudcL8]*BՖ't͖䋋5;>> G䮋rҺ$%7:un5T cR6;8̒ )1tV5 Wl)K#hf-@}jp={KSZ,g'pki%!.fu7dؾ(1t1ƋgNc:~͐Gd:vJӎ ilڽ)cc7Pª#E(n S6EQ}E6Bb,wmLpL:'To}$\Zd,%>$`PGEg3[UWKt}RAnādUO鮵ku6L$'ENܽ5dԲ=yiF-iO8K4u8e(m8Mr拂(TF~'3ו!+,NիJ@blIJ.K&Uy2̈>{wZ^XIZ =?.uB.-W~zF7d(|˽ Fw6:HUBY7ʜmD9[˭nl)h%˂_ntw4}nm{&{8B0jҳľt皲s|r[Wȧ 2<>{ ](dd[ |d'$iCZZ;FߜѠɥ|ίp|Bb2ClD8pgMe,tCϾ_܅\>ݟb-ަZZSU[abaBYuKߵM}T`}|cUVt $* '6?q) IAIƤP4Ku0tRkAmjrŹ'y }@sԵȬ`ْ\6:UwtvE k$'S?G:l6PϾ1˔t<&QڷvۄwY zv1y?btf ;V,hbdSiA0Sd,/y. {;DWIzъ2QϐP 2pKEt~ rptAy-mDWv ] 7GzVv.2]_=Sӿd3p{Cuΐj#"jX*Alaʢ~g7P]Co&OUzcp݈xCVA=eЮKBKQҒ/gtf;#*H;Cd[irzs< l nbran[_dUd8ђǨѽ糊em~ʢ?")*?OybF๼f+CBF{Ok7qFW(pL ŪH $-H E*i{1yْLi\aͧ‰M1*jG1OF(] 4R-uHBq'fUy)œk7z7**`lJ&! T8aLz e8R<7?gygmOQ1DKW:Un3[8EBYE", $"?"KVHQ L2c3׺9)Oyۗ݀BYZ <mtو=yN{KyV.EVJi'ӌUkm?iZ]tR]LSp,GA$U,gk2TR#_D<^ c!()~7">bg;4 9tNos[4;¼ >~n}Q+L|tV7T,!>(]/qqqX5ǑqWDZlCXlLHJw(nyNEvA P%О<(MWQR^}|gL,g*t/ц͕+ ;o1=)B[;]>vo+w@i[uFZHpcrS rmK & vԕ*5*>´Ɋ˜2YItAkWFάxzp{Q~Kc܅hcK^iƱ;S<84_ˆ'I=n92*gU5 צ@ã}s.5ey.{yVd7?/6O)+5w A "GD@">Hϟ}뷆e,#56)jأ'Ԇa( U@W`)va5ۘuYIYB 6̲uL|qj^eUGǿ˔w{\y,wBKU* ;!³()HX(k%%{F1V[2 ÀMɴ%khB/7~ϩNnD)_J; vz<4D%GŌsQ5a30M^"}gf+fKԠBUjvް_yY`'4SxLE] [f"c{.-$x`R|t f|oSB?h}V+oǭEzvL#' vDhjL]9ej m*v} mA`J.~".!t=t=%ew1W "dZj1#b?BGk2q#_K EM %i0(N)[kLώB>Û?U />IJ3;CIW’ֆ9wལFHckœZBݧIS{ٚM|4f+V.2Z9Чn P6aQ5`t[oP+J**iyf?uI^&U2Fȭ!O![I܅Zld 45]ۊxae.yA.DoE?UU=gq6NȆJ+7$Nqe'p\8YS ROlǞGOw׃CRKSU&;o%zD I׍Eiy8++M}Q1K$QjGe='MoUXQH,Y԰2L8ݲ"h-Y6F4Hի,y kk6MyT3MQ(!xz&O|{LdmCxr#Ļ98?CHɕ= BtYBe;L%UϧEd"Q2 ˼ɖkY뒵g\_RYlҋd q;ggH|hUPXrߢ*R)| ={9P'mp\Th%uK'=@W=M),ԴȖNXN"}&M3]уb{ T#E'[MGv#iIDą6PT]_|wrc+'{'Cf92κ݃TR6~%BD7Ikn jҌ >/tgg1FYD.fqpѼx_) .Ox-x6tI2s)ZJDwH  49~X*.ug fH?@^%ؖzw2cۃ3 v U|{4gCd)X֎^\/k1Ai|q?`;ǚ."!^ƯWZ_,>ɣ;p)<P^hINt_%{0[&ݞf2 [{8k 4~<`S߃yd5O 2؟lO;aoaJ_x 9+\ltMz7ȧ>>`!E+⛛ Ph Q2{ rǭGI^_cnzDYkeY5ɩTIXR "4z#_ DPCw*SmR9IΔ=;f{'S"%u,2#HDם̧ uA7$t2jL(Aj8[PВlN3dX0a$bl=umHum^toeղżZU-+~ϯςGJ! 1ź Ci|}dwoU’ TTFԖ{4'!y"hZh, cgJtQ+^om8_T3H5^;'9dSaSOq \x+t|ɗ[~>QrQxb6q ˊ=ŒKT8PZ8gǨgxE$Lr>2L40V@{6Cy[9zMlp&a`'mMwT헟 z, !ߋ9YV\5f0ନI:_?ANBP T/O2Hq)*P"m[2tk:3|Sco`)J4ܶ-Q/5ܒ}47'hdxr0kۀ6] C;7D6Q>ݥXAĝRy `x%9ǮnF;jRVT<]_D)]ˋaQ5L7&0 0`?T|82\p2ŧcD.WBʾc@I@Z mѕ(V4iMjDR'h)`5kϽ~Bh*ܝϊ^ E?!elL#Q l4ywƳ]!`sTauIO 3)ύΘ|#뗔_x~/y6<3+z_uE~s̊yѰ %?y0c]Ηy")bM$nþ#ӊ{y;"GidcMna\Wj]yqmXݱ5Lhe0) I!t.Xs '/ioKΥMZ(VI7DI\sΝn UՃҭm+EPlCI 8`I gx鵳>!`d 1 8hVKj5 ^ۭZ_js.|oUóvn=J´R17YTegx&$?tG+[\*L kÄ06R _x[4 0-j8hz{bY4,UQRp`g3R!jtӈǁ K^' 1'+Pm@,yIJ6{pT١*q:!5"ԍ7b:t/b8ˇL޺N~t!uo,H2 ҡnwop9w/w$a 8O&WDD1'?OߏQƒP TO|rgʼlޔCʸ˼lu0FI?]ssq^zʨ$L-uY"?z|* H ԏ}9gHyٺb3xuCd[݈o+ȓ?D+_#FU;<αư_o"%ԥ?*8xiQ3;}|Yw͑ܞ9ئƘn@P6ӿ~z$|{I9G2}ix0' +׉zFGMVmghIv| knch%A'x,s;Lnt>%zB# Ȑq5m@o`3w0}a3>mj_TIB v f9`H,uAƄ}XW"ew€0VFin@#Ɨ^PG8HgA&\kl®ΑÑ7jj?eb1+$ oS0IH\Q{.5i`V6TQ~ YUC~koY^c#!KϐO::??'Y>+''O~bUd͵RpRUAt;)s,iZ$QJ^8QQ6^̪jL#f9YYWqqlY{W}Q4j)xIM _ $pUYbiKC4O| ƃZhW//D)*BC>jJlNqLx0?^3<ˎ\}9SU]0r;Qd8!b`2c oG`0(I '8CvߪԹ3]tNZB-ѽ/K˖?t79F ] ns wUѲalסoI?OG^ڵ~N.Rybx 5(jgߞu8Ѭb.x7^)uq0Z5ց<|rdP58f2잣`\{y's{v߳_z qkQbVmO)^J ͬ/5/,.jnO)W_ʯ}W.!oN ɂIYT[j3~{:,*?y[W\_N"wМy`Tc5 8W8IA rfӌ'aKsy)YI%?K{kDeǏ cFA9 UO9R>umש&,j\_6o"2z?KpB#M 8Q^Kx2)?1 =4k"\򻯘Sׂ`+.CBw %BǠz-p?VppJ3 !^iZǣ$# j8PIXVҐ,DI³Pxt\(Ik>|ADw|ڿ3<\'<7yi"{PstpF7{~=\m~pTv3q[S>].iSo>!RH0')?Wak`s{򈽋PI6,dt|wRy"ؚf,j&hZ*ӂW7Y ՀhǏ|aݰ}"l2KmJt )eUuGO¯rsG&.6lD}P]Lc.큮*Um[1!oq'':nR%Cz1m7ƔYE?lr%ABe%a89Xswe{-rs=–GzU]P$+"k1~t_~r_?xϞ.觚ut>tz \$:A4=ܮWѻ˳eεوe&7%|9'ۊY` 8Z#R-KO0I?"0˒_ܹʋrՔ~x}bCkI-0vܚYV[ڜl $*+*Zѿ.3B/mܕ:cϮ#&rc7g {˿nu[>"l(UAa,G9L3W[Ϩ_c/>zً07Y5eob17#~Z(?@Azzm͗,wo,:MiT jd\}qe+Gq v/K2vr ݝa!V@A='˰gDJPzZ !YD -veE /S󨪦Y*WHyhmFJ5lX YT4´A rB"ٮf.ǚ!쭃4(B6ˀxUB>a5B'-D[l.ȇP-/o6%vĪ6~5sx uΦI2`U<9Pa,'ƽn8oˣoRlH7dfFDxS0만cM m*%Z!g7~upEu?\+Lc/(#qC'G=}w.t^iV<#9a >e9˪>8ߖ ҈Q:\XZJrmo$ru 7:#}9EM( 0; k!x*eEtF7WXP:q3Pmy| S4QBP ;;XbIm/DeBVK+}U_# *^\UU-Jțr!$EM+&ڎˍ2Zĥ-iڋ]@mmu0sH[?? ,ܮ?z,}_պbf@yxf4)Zkn9J;~oHBinD.N%9YYsz6={dyqq4Y 7Uc}͟26Cē%8@(zrXn?lujr^?`^ԜR. =^h/nq||n{=FrguJ^ۼxQs1+n7~g(}~'9#{Y^!,˚>2N@;4bGrY$#yŸCrPZ9M~-~NOp6oi/_k#FK,+|Z QY҂,zT5-Q{>Hćc>?) _,<'qzCDQ+Kx4YfhRb6'v_ճNȪ Oih~mP-'/[wp렖T)ȭ]a9@Q6ִ~G IJF) qR.FJ#./S#eBd筷8 GHpZ/lj*G94VȦKR4.Ktkjk)Z3EhҹO.)vBA@*"« Y4Ȧd+Kɍ"8;f|x44E.Y+IuAn}P3]f3 \w"w7;gNPT _:;=GXl7pz|7%t"^%{PK? z&?OG4ýxH'?KStΝ'ݹ7S>=k1*gM+N9>׆$f3ri)OdU{<`:3y^gjvk5nrejScN{ҹ8ƌ}(ƶY͞$;GL(ev0}Qvxk}S |H]M;"=@yç9,ICx?VnHے#ͷGpW\>\0NBKѱD`dk}96"Qi>}4T.J|Ww|k|#ePQ9NYχCfe-T@XMkÐEe޽`}jqy+=&y͕$dm|rCO,I$14,~ctċb\]}\LOu6 fWܝ@vu8_kЍ b)M{xaD`t۶Y|1Zm!?"=A]7p9:e2xMn>>씅3\]b S MwY:/0ՑTW<~G.32+1L65^'睳a-Lz' i͝!:{P]r+iѼ>LwFۦ z-XQIV&K:\ |.qQWӌ^7v$;6砏wP?Y߿I(o2'J._W8Yc7nR?S\++ ,P wz`QYՊݯS?z _XV\֌1Ec;r^"~24|w,76ٯ-^'K{ɩasc. 1P5\^HP I3.ĝmed?zPEOQG؝3[ ? _k:?,d̾jKO T4Oz[, Ȑt8`ŗnՆIl]ғ\=qŠmNjVi|'z@Xm=vلݞ+ctv#PKqQ V"L Hd]y)p .| 7X\(@2 ^.v^GvҎA_J"V"@3.AeH{B]|m?3zASop8)Gd90WWk| $@WͻD=wݿq PQiiR6t^M#I?Yege@pPo$}1t@~_7*)dE9eIB:g˂u?%rY$㜶\|k\71GVZ JGkRP;_' A iA{D`pr]jI$g6kNv<;!10 xڣqhF9D]S~ZxL l.tL!3ܣ Fqݹՙfk?fL?e< 61|@}[TF |I&^mO \#nP/^MzuDh7dqGZ$N$Y51^.bMCD?BMcM6u `EL)F ش"x*|lYE*æ=Ȫ%ݬboiM<"6ܪ- Š\ Rh|$⚺\oA>Iu<8)eГHKDm2@s ;m a}9ى9wɔu\:yĺiQgkfaEãi-ulo{:sYwD9Laٷ&9>A/IjP:071EPw}'<1R"뚧muAe,~/ g7qwXYϮ _ b͓'<8os}|i/1j׊e$ߗ7| ?EӴRu'AI87#e~Q߀6٣ݘrN:(Pt?2]t%O:&;Z y:Wx^>*@p^A89h*R4TܐdjvЙKLo\U{C8 "¨H u#]oZdw $Xe1H !el^ٰU|?ow1fҳ!?r{o(qU'ёW[ߚV^ V~4Ӄ\Ҡ"բAk}*֑۔i$&Jp(||_KׄZJQ62pNDiExf`oR2-[ί$|xc~ᄨ뿟XnX.S-wYԆ/}5^Χ7b.@ǝ wwg(`w\+ܞڝres[󚃝 9zk)弦ZAbVQ"S%- }רuD9.JV ;M˱ެa})d^4A^aclS͞ǴܙUxJqX4>: 3!|. [R'!7e#ڙJc vi>yk%>:wi)p}¥f^5t 9xB{^POq WqFo{jt }=IhEӱdJS:kz 30DPEٙ2&?:(Pāc'z߰KZ//H*~S`Z零AuT:TUR\m R<ƠW&+|CO4=~OW,$@Q"3+!L ŘwP83AC/gΩv 3^D*&>y3~|8ac0ZVLr(B/fk9Y(j˱tY+Hk$+T^ޔH8w:ߋ|V吼t$b:5 :Ϊiw*e_+j%kxXh^3 T&.#^Xh9t]<'H%,S8ci-lbx|%eoQQ[˸n9(j*L .f\?rrǸ$bxKt:< Ij9bE HCY/}۟S}Puuv$Q>f6Gs. sNe.*cb@g(!cɘp,mF>'YE^34F 5E2P LB'1Gyś7|)ihխ)/zJ [|C2)`}يx Lҗk+˔t:9kL21x֝d вyib.$_5|{CVfXN5Oe$9/k~{[;1'Rh e4ќxo\_6ь،CL`#DWo2Iu+n&DZтQ;?Yf%Fg'0lCes4" zV eLzfqlO}HzcFq:+@yFrSږE&1}Qg;"#k-'8Xy/PoDTJA#a0M\K5?gpub@jA%!EMBAaZ:OC/KO'iZݺƎʼn5bWzm C /#~(c%Lu`;6ҧ{`y&ynuB:T l0KW5LM4)FQKɈeّX5~lmVҐ;qY{Eed)۞µ|\+N2N#Ԋuh%y~_I{U;*ױ(REk.7Ȳ+FaJױjTuVB7q@+$l͕ӌv 珨=d֟yC&1mO1$"QBa7Riy8 - {!NyFW Fwo7=lŘ?A.:CwGkq(ov=4qcQ2'lƅ`kP75*ޒ2++U>{&BeV<>l[d?LMW{o}wWO|==q+$M@(ʎ+ ~("KX ɂDJ$Erq<=?nf[E=ω&]e鬣]9d ā'Nu,bDiD,&N%bE/9'ӄj:Nu9z?a$iDE_4p!4A*AubݷaQ9o_-Y6vrwx&Ӄbf;+9.cb{kOf շ]~Mzq1l1rOf1ulSMku 硗DtwWgh3Ge ?ۿW$ef'(@zp2"_l-{Ü̵nc;#jDrc\LGacv`Z9;X@hiH]}'MZƵGT`RwxŢ(E}=o"!IY|_>fk!P|FyliHyŒB[>MM\jw4t¯*ak[\qiC5}ihKB-JT3E%`!F74:G,bbLm]љ.QHmo ],6NPDێ\: 8H)Q$G\yGw W!P,6qaӽU\T{ [ֿֿ_epR:8j.f—Jb](ϣA._^vЉˊv9BHt-] EZWT`Z`=auB4!NGN ʦ}?2,⸨ۣ}PƢ$L|5,tq!S뼄J1Ux]Q~^`DcDsF<=f1!<| L6aWԊگy3# 4RR2-|%|ڎq n?;Et8@)מ~B{ԥ-).ݢ6G9w!Y.u{u"-y|ds&=|j ru{Ҹd8Nr6.\ ?$Gd9[N€EG{ܽ: 9 Y2R)MCDdCT=~ݖo)ucZ!=a Z)wYWQ S:߈ctQ/.8BJt!hA{"ng!M%%`-jfOi'tW>FmХʥ!ҫ8o%ҁN#j굄yс^(ȽQJ3d#!{CT>)mM4tk#ko"w` emMLrW|"N1Ź3 {XP1x)ZZ  4Jhh B)"k gs$xn}75vMcBExoYa(ovڎnn\59n y3\$߿Itc-lO?LO E (v^@jtjE%=_!j2ƭ+c`9Q^)mbwΌXU^p7?1MԪؗid䡏g~DKoyst$˲-;8ɮn+EY1:ZVu$vx̰9'2~yM+OzF׭qUBz!˃S:k(NY7ꪠYpEY@B5IU*lb~8q:o1B}^I@qA5+gj_d c;+GRp>;B&=r[h[?2*oW >R ~31 ?A0d).ܰzaI)8"M%k鄠5Xӆ|Ne\|{V~:> clY }O b(+5Ϧ '?U- AϗE> $ݏs$4_ f uv8+yg%5n1-cFau4ϑ1/xϾ$yN17Md?)<ۜciq@S,N]=]4xi52o~A",nA?r+t߲fu!Rl "h5oE]p"h O)_#Ӿ )ND O8~%M'< {8d!ꦂ\3*~:o}CF1mѦz+!$r0v m1wߢsFw![jh] 'V7&ۘ7GmblMw&c׿ (NyB%x:H6خc,l'QCe8,5kQb:Aie{½<9~H{K{_$/U j) cPʹAqA87BS\&4t"/냐úGsIDr$G̬KWW_ݚ%H4 1 `Kcca%8 c yZV߫Y,]oP?|Y/%,2[Ө/,)|U_UfLUj E`jR8K۲FxgtEQ6iSq2 /R뜤o5Wk<%E=)ai9|項$xxxKi*n9AG-a'^e8(e^|6˛}oVO6$m RYƒN<;ӿ`njjrʑm8mmhqkpzC0^h#ֱ]z3z|-W{mBv>? )͟OW;]i)2Sqi0MKW39xP׎:Ru8I翲<$}).IY/'? ͛ktzɠDf(&0ӫ%I=@otX,-q J<-v[m^ӣH @*Fp+7` 6}H~}<>jX.Ȋ4AՇ} ѽsnds\g{vtoL&A8.f ַFФmTZhȀmQu[]R-INU =o55pv6 OA(Gp݌;6)0H 1;2yC BP+[Z6 g5B'%X0&^P 2LphpN!=KAD`|h1 #ȈʣL79-aӨH]/xǻOp4*ngvybЕOQ.Z  .Bn%i:~E邮8l^N-~Ӣ#U>0|nj?jts<xL Tʌ%kPer]_cv!"׆C\ƫUƎoU8+<D6xjv4"~I;Fj :kP!IDATN0za{" "mrA| Ҥv+.g6#R%Rk:+Ni"/)\E)?OgcU<ݺuv;q{H(rM$ٰc $~l ,BH` LӶ{P9TV%}^+_ښa/wl-?L4O%UyE]ѬdU*,3=4 QZ`#k CoirRX5QIE)A \ߢ|R5<:hD#6EcY۔EQ6 BiV:zNҍ8b 38Fqm|.FjƮ7L#>y6ft&<4 I`sr6 lܖ9ֻأcoÏuO>zmӒ %nP~ٜ;x#rȫ|{L;nK7u}~c>xs3Y'7:8fxqW)ӏiԪs%i;|Qp49 6Kd-C` Ďſ3{=.4t~1mmj# vmqȘgyEs<8%jUx6k{1-I𲮹DPG4XD jEZpSN+ܕ`]Ok#j ?c,!Y KԳ ":8BL. }@Sь鳗Zp؁ FmT_ʜzD&e&f!D_{MɠKD]颠ȵP)qmvP0%-XAD]ZC*yI aU5DC@ r琼ZaP;ʿYi<M@.HyWiX@H] 2bz5G[a0.G |3 #\$wwq_=Be+ѿh^lsYH[.h53fY̯Qruڋ1x.[v{!oڶ&Xy)Bc-- ` _VB<͏G]]ٙx#NL`#ȉB \qDQ8p,%'@؇$ c6vc{gwf?C}y~򌼧9 qyuγ]o]66GY.:,HpmTE(EAHA6+7;c|m9;^٨aɒ+_o组k}kF0Y<6]A=x҆nY;+x<_ؽ2x w+{cLIPgĤ{\L <'NI!r88rr YW'Og<*޽{)Rr;8*G'4h E7i$3k'UE{?}/0]V Ҁ_]_L[(_3+h3iut#<pȊ۴Ϸa%F?@kʟ x>N!v.^oGW57McEv?fwG@J(5iC.u laJdD-tƸ8ZST8FjJOQg)SpV<[,mwY @ڇa:7(}m6h+Xm\ {Rt(~a"F#pR(;wOgϙ5;Ø_|u˸ i" F$por:C"#jehfTkڪQ$ٞeF׭QnEΉOwrs7^ oyhk';^DZ p[tA:@_ )[Q0ɚe!7G)r0͹lvFxSk}Wcʭ]xϐ>">zNܶΉjM 0*Ͳ5<>- մpwԬp1*6_x 7/KEuh ft;]B?şe^'c? Su8i;EjSQD3?(Nwzi DKSn]U7=t0(Qd d {?OO 5",@$HHb|g0=sXaURmjQ9~.p{-K:xlYTJQu].KX#Fs|A:[8pK¨` T)} j:n= 8Ns^|7uxef/Oҍmt 2*ŋ:gK1zZp"gS~cw`hը*@q#"@HF8cov;*5؟K-U=o¬|pw h|WC~,B*|gOD Z)×J0bƒmf/\?,JҾvjSۯqq~W9k ?BkɃ#v<f~H o4~ʴ<|deMBU$qx~fѭ->r+QRTǿwý3Le94 7/=Th8=ͯ_sgyƇj@4tz1S٬g7̧wl+e[u@T=a:L[cL2UK6!?Cnj6̶zd(>ߣwW>K# >hKp6HØVL^lh4||™Y}vn+Um術*/P:e/y߶p&V8Z4D vRXSSԻik+.aw*=w{^ *\GPz> cVN q[̆@ZP*qQXXpq fBm D o#\狂޸FBU.G}a ujzơjqȒt H>,e+ ,KEa6|(8}mSmB'+j;N4?Ë$ɄŜ9XO5-ŔN1RjIU[^GPJ,o$-e?Syb&iƵ&2>p=`hQ򃛛'dǏglS)"ywt4־Gc}Sy8o*eR9͍&h9zfp>3e6x<fޒ`TT4+wDԎ*n Q7qoe&)a0JJf8y]4seJ vui/$KZ8/e&%e 6GGx"Ə̪/JK59+auf6"p$jIA7U(TrL;55 (gIvEK\kUŦQhfQΆ=Z߹CSm&wAn0V8Kޤd{ƾux@'uO3MQno7IdiG%;Ll~NHctՇastl@QĩUe?R,]JqXʸȖʬudj6VT*Ҷ Q#UDmB}(BM )rGZVΧ ӲPy(a6M,|Bc\ I{srlKFG PUjz*KlJ/,oYCY"?񭷑^,:R;MJp:S|aVD;(\Arx̽6o8[8'!H p0c#tmaW-gr<8sX j84ݧϘLmPگ]o\Z8su8pnF8zKaY8U  nrkһG=|ٟ⽵M$EE(6w#p)S Gϫ(ep8 kf0JZv#>yzn띐{N .̏('л_V-[U,*A-t#.{+,GzEٻJͨ{Lo\E?ޯz1qXG@4 H E .\p‘? cN\ J!(&d؎޻Z8ԋŽ|,/lN^Dhv!=ڼf>7(xM(Dy@X-Ȣ1pMYlFtS_,w|BJ OVqbc0MK a{ѮyFlx:g/;Vך]#c (uJ'$m<)Ϯ4iUMnr=Ն_n?N? u/آY֞gtVlW+wxfŵ 2l]ojKp#o86؞^<_ NJIxU 4}FI撖ksOF* `&Ŝ8RyErID* [肐{>Mפ%^mGJXA$J,DzK2Nʛ ??|O|!{i+&$\ڝOxE gpx dXɀ{_`nҫ\l+dA똷AW[u Ws5t0r]X~ւֺ }_`ʒ< Q2(9FNįa(]mKC8KQ%W]5m5Gxt`-,!$)L9/#}XJY;<~TJ4+6H&>7^D,l3x\ͨ6ˁQJ`bQ& eD9ٞ$*a&e^/Йd$$$mQ,8Ei@L30G9eƒhBc 5\8wox0y os&9os|)Rwѐޡ{0ǫ,!0Ir>:6c/tv]Q tV}ߑNp`0!LZ0T]꾮'Mnm6?c3Y#i bͷx.hwFsa)i𘪂p5l֯a /\ӟ$)_~uԚ>-8s+5qJo\qX|G9/+|Jᅘ"=L-Se(iQ(7(UFQ-{+u^4 ^Y @i:}j!|)/,< ,}MaoBʽ7[磓 q-Jh{6O1 6|UV]CzSNfZU<>۷%wc{!)5Zi4c3Ž-w3vC[UGYXr-l%8xҏ6߸G<]}6'Ymabos0x[/8|DtfY^y&)>wa<F2ΡԞ p$,L03 Ϣx%čvc8bI6CyJWA'li4$[62 1Cܭ16*"dd:=}C@"ۥ&gIȕM1lDa.a̖(~stJ&9s l\)[8={ 7/UKM,NS$%l&,7<Kr/&)۽t5۫-~]6kl-5l/sOybwj22._嵳Y]į9>f<[\ґvkHak..wx~ttRőױ|eUˡKuQqGH'³;-㭏2Cy!+vx~J :$Z}0Q:Cl 8 ^j]"t<(կ _[';?>.z"' 4|7 dNrmNH6Oݓd{ Je ל* @Htl^KCJU?)iFTJA `IX;@;Q恮ʄPn:C>E-IQiTu!4ԳWB=,*Ӝd%Z3KȔI"e7ƛ P~4Bi*K,nSxs d(:.V:"xRh\7hiM5"DrP`qN:&RoLHZm,'Y^=?J Iݖ\P. v"nȜPZ m^̛$awh% A(q8  {"<qVroi{u̒4esq̃ ߑ<,.Y;)xͣ)7:_><߿0 \6xrtK8Rfkw_N8sn;%j5^iɃ.}-`9ּ)6BoM ºR_qҽA<9hy6Ku(Wlu|R*AZ8 gqD͵Hm^5\ݎR_s<)PA9-d {u!N;$oPD>B,ultc^##=ǟKgUNy; @R~cYrX1zV6BIQIMXUrCmk$J&r<=Kx,, >^ᴠ4g}v[`[xnx|2%{W(>`/GIjrDDL~6{,}=A'eN.ዱҫ^%4E`%єt8T|L}t]^nBYG L3u0OгRۜ(%zQ*[J:omjMTu\ ✪JX u%8$EE.+RV/T0J pJHO;g x:KnLTnMy pâr!ʒ̫RAdWQN,K,ahMJD6zjb F RN"vȑI4gj"hY.l1D" gTreq[=vP|g|+[iL n,+~uKV[|t^╶d 3K.]|,]#͔xKxuť^q-뎙 ^%jlcH't6G&U):( -bJϳ.^Xm,jg}P1O29fd8CvE!Ax'ח.Pq(rhU"gpcɣќW69鈛ϟb:4GU23_]v3q~t_}^8ßvvdc\Y+kNГO|{9FLޔsZ :E ?YIo zd_s'Pz1SK?σ~B)ӜjD%}dyq#~|a`:z:qK3I5gi{3/S ۵4{$YNJ)yiJ3Q?{^بk~%$tGhLDd/Ouv˿dRC$>~ \~t6n@7R;[L-DXz2.㏹rŮ-;PZE2 !^9Bm[Ҕ>)V/<m +wPrrǕ -ȸٻ7-2v XYH%Gx Ic?b yL7bZ)ԇ+4 \a[yTY @둆%: Za2B@1ճd*2Oɥ+TgV]X-3d*\Ms >Y9D- kXjS$~LC$)47D -4ŴJzHTh[3t)(|aA;I'}Z7x k5>9Á]Ğ߾ጭ"Iʽ>~,i}Ew3F:5'cfӌR1n颵aqa)}W79pf E5~ryf ጂ/i>o=]ZR }Is] xq oJ;?Myqz9dj{;'G\RJʰU 8y>hr\?kO/Q뒟{`o^!X(TztJhgb,`XZ Axht`'įn߁2hT >F ^̏~P^R2KxBp*G#UV[\= WD#gI+Zܹ#Wi{)HTCQH(Аb8c/|މ﫽yP۴HfyZ:D Jd1)_Oٍa! <[Ȳ@5N'pFps6ʯJI<˘R$Nr AqXgZRukhY6 KgsH1yǂ)a4YABcu9޿QUqCς6Y2s߮W4x7X5|MN(ʸ5T(ߍ>K㣭c6zM44DMXE;ܧH(TPI$*hJ9w?z\P:pƧhe|vJPҲb1ُRZ@5Jr0_ސ6:*ޒ6WfQb'0H:>nݵ&a/0 `)'#{sl5Ȕ]עT:@9Md2C|F(}¸W%PS]Pc2JMWa{|L"e{5tNiQjW5TiO wG,0ędqzŘKTC$󐤻TB}M=@ѲYPSINVUgZChlզ3 ZQ(èu\KcT&o1$\i)9IszWJ,0WMo yzg0;mڛPIYܗqDe9&/=~QŞ omv1ØWXOwTlRJڎ8ιswJ.&NC{P˓ g:߬aĭ0vBћ>01u]~5͠`\im6-`96-;*4Z+NH['݆;cYXjq(83( Q\4*z@A_ ;_ :, 2ޅe4u?Ϗȧw0K$2]f;6"y;\;-SF+ˠe9ATOtᒵבBǨr1Ȓ_08t,N= nQ6V2l!г k=e1:c'wyӴTˏW[U]]== =vbC)$b˞U$(laH(R b$0~>X֦9:/HznVVVFoK"_>pEń\.LƜ!||ZjQkQr@C7 Vu`%H$pJ3zd1JC?Wo!6j-<9Z|y6?>8e- $%'}a˛?*?s.0/y4yeB _L5RO&1߽ƃn3[g]^Fv>;ݧI)*t/o ot{D]bVsL /{oCjjvڝ3=sWOxd}lYP2g3Ɉy6$R{(@5A'Q^LF/>SmSu3ј{o|oy.-AՒ 7 rd1/dvO]Ouם2ۃ[,}I.*B+EFn}_&7nu->"&h]@:hsxIoWn%7p>H"P-p͂}t8~ukY(츬`9zr54M[#<<-HN ?|&7*#(ݦd9XK2 *AYzUK^ESJ!HlB\5QFD@z7ac%,gT xH#e,0N[YNO<xRp4]'(>䅽MԀ_1B/x`Q6ole1ylns(' Ӑ[o? ICңj is:+*S7"ԕB5lp ŷd y|Qp:H8YVLV.*f UWXhuo /j<:^nzm,yM7|(Z0 yc8`Y)LYT;<iҍ1`^ե7qi׷R_HNzd#hL2PB~Kpw]h Ŕ%MD\T rgw9 Xz=Ʃk6Z1~ h*Ao^4pR<|soH?rNFw`k6M2W`%x%(rC%v3|9D{GHLULKoIUgcyֆYY%>+n9aJZtl vle5k-R5|QF9z巏 b('svǿasO޻J7tV'yŇ6 p4)s^9>spU^vXv9{DQYVUu;b.&W=ҧcrpba3d2/v|G)L:_e,oo#SyyH\ tqwgɇL57;GZYɖ|vC {{8!vM=Ly2G WN1#DS}q"ڻNuE9ADNDuߟa t䗬l?=B_i=;x[OCt25PK (ф*2_JP/onwq3Wqֵ&4.*@Fq#`xj.nǝ p=z=j7H BRGBrnFNw^9?j~2F5ZG(P3Jpz `F9A(OuHP.Ur %`R;I@P.J(-5|+rTCt _C-Z)b_ӼR(kf 7iAHfsߑ<%{þsk-a9l~ݸ!㿧*ɭf,vzzyR;ХӋ9qA]('?t4ʑYEgԕf6-rR<ܻLZ?[mB%(ɫI& /f$ӊra༠$XAi(3Mi,e{@+fqu^\턜J θobRxJCWc6b8ca-D$G[C&+h Xt% z:'TYdjᨄiE >x=~[-'tՍUeD#*5Oa;&Pxa T[o\W>όO2qMV8HP{/p-.+ZR#rI\'=Ϟ}{ŚV>=MEHc [̌\*uX<^|#! LM+*gɦqLn`XWRU8gmumȖ%u:.e2tۂ"7`Y|GH+]gF|/jݎofr#s:t]tAgK t q*J^xeT%'qhz|#:H.gFXwNF9vmZY﬇rB5o [,9qT^7MM,tpEvj0lt0ƏO'@Ol{|Tvz}sWK>ᅤ\CGDi^& hU,8|le?ۺ,e ehP)w`*MXU e\*.55o 9PN nMIʜE4 TB.hTI=C~ucPpAbm|Х7$Ull\u0ClK4G9e"MzdaDŽghPR0j!`%^ܣ^}xݹIHiaj';GWS^C?" 'bHNM4[]]a3C:KG/2"-k Bl.u<~so ǻs~kջނw/q`A\*z;i{69$*vO+J?q{トYI:+ehxw@Ve9jaYö9ӒӔ~ DYIsRkFHBƖ_vR) <ȳ%Q^9xwZ'_ G/:.$){cw$<<ְM\*fIɠeolHNE6eM8U•-IQ, ķ+` #kGm&kx,W |p}/6={R*MV)mgR&[%&-n(uâ5hH*a\p'pskf/dXayy\_e ]ᢽ1Sm LKWSu=}k`&Xp H("e ~K+b"ACll,gӝzz2u:Z}>3.byMvk/0 ŗB7 $UyIB)}X,=h4[0[> Z=_ DZDe%?y"4ao;kM3DzZPT|:F7-}(g=8d!yϿjo]78e^[ y|qpRLҒ݀S+`x^b fluh\EqIFXk_a40q'1MW'N6F|[4]}4b|ƅ5FH {6jgK]DOj".FBFV1k CP.I ~tՎw:6*)X6&#wKOG=nۥJ gG+?WqA~p_?ۣ[G:lp}]))87tZBr wXcVai|s}H?Z-FԎӦvM\5'|AO[!N̐n|_ޠrl5vPr2>ژ>䐥8~sPUF( )kBjRS3\KAU"2OU@!Hˎ9d8]ro3/YRJ"zF4!lTuE99>\*|QYtRhTvZ)U1 hOo%q{$!/ܹ`qIK2=/]c^*6BY,`ӰhxQDaSՖ˝6G笷=擔4.l~D\ÔFW:yk?琋]glJKOģz~Րgs&Q_]f$%rn^s)_!pL0`w{BHi]^!2,*&q<-V$M6B_|hqS4+M 2Oypc`'Syxt-r(k' [8$)trcT4ty4,JJhBVp{'(,\ngRq,")+ڣ혬x&Rh|q E94e%F6)~̟Ck-_GFf)Enp}E(01yIV{tb '_Yn+ca0ÓgS.JJ%w6eg֚eHW[ RPkt>瓌0.~plP ^B qAXG蒴)2NXIJٙΪ?VsڹFZ jm*Z@VIRcPFe"lIXGPV!E*wrSec 2K6NS(FmdqL=#|GuV0 14p#g)#%efpW :-daLփҐ*A8g<[ש)5ՙʀ̰R3z?h} [`<k, f)߃5WyonAG xscNxn/,G ^nМG§Cǯw_F2`\蒩bַZ!e?_Lsz΂;[-CInǵY?iǏܹ/Op:>+ IƓg>L ޼'.)O AJg4BwoyjĕN,-yQQhS+FKڡ0-y(ƭ[MBO{/SmF%29L8%:Yš 8TP|Sq+*ɵSX)QXQHF3=c2Ù6pEFī`bJnL ./KM9Lx3ѨhrdTg+^ie$3lk f\<]4n0- -ߥSXS8!ouyП5DKo$W:un_fd03 D 0baG YE1I!cv:rC{瑗iI#L&QJs, #q3ǔy/O>oNl=E}xٺ(qL1Wt K|kQdkWPW/Eϻ _pzWZe4hE8͐gWcp]jH(*Z vHh!i)0?t`]5PEZRזGO$ア?3:f%bK~#!yF?aFHyU7ܣۜQϯFRM&Q:=aXk_"KR|X +19VF9\,rvwbF-"g~xBw3`mj\Q['հ5ϳA7lbj .o-& MRtWQB]iNfBgwc9h}( I9ӻIJSLgT3c nCt9JZ}#*y?n{1>zv~J_nPa`G,uDh & 7zvHݽ1s;P [EDc{}s-w{R5ڸx_.auwKGm-y@إ2YXDt|#ڰf2&ݥhvɄG4C*l CdJ1D)c rI/I.}Djg|uM$g/:'CAƠyUcᅬP}V7|p0W{l53doxQC~{o5^;U[. 4g0^(ڑDfNXYFYIQ${o^Ѡ{229Õ 61yeU{+2lnI[m_LӒvj+x[߾;䓳$tF4@ ,ҒK"Orw+BkB׼u-j bє"<=71ky$\qo:w/}$w.} }u0vD&QK/Rf&TijKQR1hd_qOc8@n p.ȇ˰6g8OJ%l\?]߃lޠJn:?ax=!Uw;ގ'_nvwH!MaFτ C \%uM^|z6\^6HߢO02@O[m jm ^cBc*%8( yaȳH |z+S(AqbXV A![7 j ĭ$ute\'7FHcZmv` -R Ѧ(#C5ޛe)n6mBe$A|A?)AރTWS4#6AYR&9AC%G/1GlGWlw8d#T|u2)(a*vZ5tI^X \-yy:Yr\ tzeQp߬4ܻ曓9=t_q2* BZްͷ3ND()Pk*Wd%,Ǎ%v~y2|$ MXkPVƊ|}~FTM>gfV xY%{ $$' <dg,W8dtk6gہ]nFL3*g0@X-O([8q'cP0h>~砮2t3Xxm1PCE8~Jxϛ= @k˝]ٮ`['ːP9t\Ueе"uPSI~jUsBv;UeS=>Y\23>;Ν.N4+41LIW:}nclĐU lX!Y'Dl{$AL,"Hd08&jvOwSaq΢JU8{ɟiEYNUd"<^vl~ ~%C4צȍw_yRl<8Uɓbs%L`3[+>8pc1O <+.De^lV‚Un*JU퇬\@/ lw\w?c̱m Ś9KRkY3rdxN˳_hpzA5{w %>]q^ALON.5"N|x<")p>)gAu2Sg1)Mᗗd5nYw( ; ڨbJIq)k8Ċse1[Rk52,o{XҢ*⼦{KN^AW#*îIpXAuO&UDWs=۬OoS#IKmuz׋8t[>?ߥ4&1'ME|F6WMLN[<&<%zy'kv>mߡ;Dd0M ryptEUkqp:,ypTŕ~siI rdaExe5dlZSk/Ui8.d2("H\9v(%TҦ5I>l1%.ي]Hv!N ::qҚ&,I5FqwCD=U+ev{_NX߷N '_/DKWSu]}Ǟۄm@lEX@P$ !$Xd-5D*  Fa<̭ڗsN,N޴W=˨UeP#1M'åè+כj,ZrW3p@P5i'ݣhzNl z Y'seFO,BV7f:@TNH]W7;ܽ%/sJ\K:ud1|]b|1i-;1i'b1ѵA_X5߾;L9yg~u_ͯwhe{` FiuC `ϳ9 j͠ ^RT5(9>P |Ak㜨vS>="y|Jgn,k,jTD{ҘF.HB*pt#Fn-^B&fԉ 7( (cYfl w8$hYA |`M9'?<<3lN S .S&c/  q9}PPٟ0{uH.4"J0k4rB1!<hZr3$Au`S>Wǖn ϹlzɕшwD>K=w1E-,O@K78uո 'XGsn8(jZ:ԍ3}>+k5¢$8& {" / j,>}p4l 0Ė`SwR&5NVVZ!-4LflD3c < X#ʷPAm4` /-ap3 ^!*V'&\P//kFY皋RݎfR)VVRN-'+-JIn$эE7 %D<)2i'iŧZm38tVx Zdp1a2Tt"|!xƐy%\,iv$Lý)ot<' |NrJsY(nvhEBtQhE'{:صU!t*$,lߝ^""c^_c1qtW˼fZtZ1V;m,A$98"s3S1=~_۔o{`CbVk筨& e7zl" mn&.u:ઋnvٝ,LH7fjsDMo$G]U2=37kE9+kAeO!w - sƑK"E!E$(rof]3{UWj%_9gvO5A1#?p,'{m:6yoᄒM/UB;zonxa Ng@\hX5|ɀ3[1ժn"6g痌a'{1e Թ?PX>A(D"@ }tv#AZ2I:8'Uext2ovKc#oCsi-4uqp5)?[IwVոZcdϾF2w靜/=O1a{HFTg7PG czQFYgڟb8K1zaW%wPF6MȀEaUa*Yo [7j<@-8hlA! pv<{h74^W[Y VM:.i]] z&YM0*ŨMȚAKrWWnNJvcoz .?C`wxs;' 3/5P= (cOFd+ Ŕ;@/1ޡ3s5Xf>!Y(:KifOʚ4fV̊fIb`*z=M1ֱ @[K/Y~Ҋ$H+wdY.$d5UIlڑ$ %oux9{n+三:ҹ.a9e'x!.xb#ܺN;7C4D\)[(B[Z7P!QSV,_!D/Wo*΃U'܄[kv8plgO˾*q}, . 8q2C7P-A Y]PH4ŬT ( 6hABOPf,nH AbWɀDYzϓ󿯶%'5üd';m&^lMc9/#xF q+FJ^jMUÃ)q A2(Xj_>?"ro?<_2ìm-9Z11^'\O< OB2ː[St^i!hxp8x /4┟֣nԼZUtvFEcݑyC(.vc>f\H|+G+BF۩D> ͝Y~U'+m?eǏ  fˊ+;;ϧ,a/lwBˊ8edԃyQhc,+S< a-R2)j: vCl%J 1Bpv䯫& *Ü-RbRJRMz:`ֵE@^6# O<{I={J3~qq 3!=nuvb1y^У<:3x>ѝR7R\jt`pL ! Pݍm YI&+%F$mROg' M;Tw"kn/l;LKWS眺tMwL\xǣ p @HdXDl3~ $ &\bl=[Oɾ6:y_4MVuUX x; %JjD1.J _nʕkLlc8qF@-1[7:Za;It W(T_'vo**@3hAq@=<V#YwzDZPֆ$R.6ktǭfiQϧʜPo(Y\CxDj[!6[HU 꿔 AC(E!2 f>q'[?"BjRcqʡ֖R[87 cle(h4B)w}y(-2;T_⯇F-=3>/%o%/r6{!ɿ½EVKmlKBa|{7G|䒓]:#c)aZS1Rz(-RGcHK ק#$Rt{Iړ~=[>t1Rb[ԉl ?pgd!5[wsķ*YÃI0`H@p2ʨb^޽nKҢ`Y*5w74gp^K)Iz_?DKWSTUWUWtOwO=q.dM `%lXH-$ D_F8J|}Uf>-R)ľ } DZK^Pz Gڔ2q$bMƍ}Tcd‹C&}ϏW>62"_|D6xNz9&/` 7 g+w {.z|zմgu#x4K"LZT)z/zujgGHy) <+7enI׆8Aż@HdSHI B]+Ai+$Oi"PUPwq@(]Ӵd,yVF'bSaJ9unچT๰ |͓IQa1=>,hѺp+@ٽ2$AK gxﳸ?xr0:iΩ:Z ؋MCYvɞ+҉}.k2Zd/ )/xrxs>)~I~Dp JrtōNĿM/sNKWu#z !4l9JzYP:oO9|6P">,1F=0hm"=+1seQxWg'糅Cj.owC{dl)c x C:B.P!iC6CE9}D`r܆r8kS$'5u_quvE%ۡq<R)B_HKgYʝ+ b0etCf3~U T[o$Gtx<^qY 'H\\\ $$$E"ڵB{OU\TjUUW}\oF rI3ٌoZxE =b/ĝ^Hs39arGor?"^I8mnnådX° 2ZKY;0N*~" mߥ\ujԙgp [mJG+(qC\ ewc).%~=;{]xrAc;Fxr@c3 'Y]a#z>D93Np[-6j1ev| f'߀g3^n6#%YR*"Op5>yQ!b979:ɘ|5lTOƼP*ߎxzyhiQ48 #NLs ڔ|n.ncO|3h Z>7NGke9f,3/JZ t냘|p]`##ْU3±aKNk: {uCNL8*ۼA$qm4N6E*:hqnYoKR1N ُC.9d{]eEQ)IȋEƪ0qE&2ji$狜MSJTYogϙ؎&TlBEPEBp BBI[ױc%g9{0{c$ *%1kIB]dXRb;olЈ.~"*๾F>YZ>E*Wo"ZXȕwl)j-Su%p}5S iR 2r\Ȃ7 wwt^͚IY8͎ɒVqF a/-+^N29y)\ >~^漱ώ:<5> W8z?6s.S|5⭝6o",נdw *M^̟~8E! -jlC 96ءN`+:$Ü^;(9ibJ*DU#LEFTRl- S 2F4=sA`Su C^&M礏h1?m4kAڃ{,7,{C~ޣxyBuyw(N-zGLJwG|@%EN`^*)y|ƾPϴ%lb.2/0X#A=`v3Kr(CZWc\qbuzX}Bธa X5b>J+ȖA=?c$u:p\eoH0kjo}{`&lZd fB J($)j*hy6ov2!% NT3+FǼ$zooDB?0^jzO%_S.&K6B1ftOQlF6T@ހM ѻT"YJ%kM`x/1!VCP j2$ {S-thk`[E)MȧV d=t)q"4\ϯl|N /&qq6H(fs1J9Et%QZm5RWRCgR-+;>y%HKAӷysiU dEe5˒``YQtm.?:皵N{Ƿ83IKs='lN :M8e8 lLC??pd++^׶v^iwu bnp|tYG￵ex|g_#b~Z*ݟqsg=AP֊㔳Q )E_\/(jaѦA)$e;:rxUH?Z@f{{k[{NL9R8 #@XDZibx7˂C:7kFd*:d+R`mRrF(]g)YJ$uR /82\4_l.Wv*@9.b T]e2'NNtC*]S_n9[Ķ&ĹCn'7lb2yXgUU~W5p%BJǑ|~<:K/efcO)3<9%)%BSZT2I=CڕԮ@Ye('~cWKhH/˚sf%n"[1M9R[ c ȣI)8oqc8N0D_}ͣq^?LoWc>glj$Z! % -nAXWgdžQ,R 7 ucc^{3;gEFifuy@5(-ڷPV/Q4Y_ 4e^cLKih T*|Z:BZMߏ0vh$A?~C\c )M)°1 ،}iɵA@W|Ȉ=A@jڶbUhږQ4Lei4lʺ{"/YVdi%p\kM|t8EB4??ٵӄO.xc< pxX]In>À;}G {̴|yIo*Cuif (O; ;>>Js6ك@&hD޷w ]Mq2|kO?Wdz?%0uW4W  *W9B*I+V1&(!7F4-u@}6ًlε7T -RcTeŠ2h2#8p4805l %Iayf葛%;=vB0Y0);hRe MY# .RUiy?^c*>f|p{"\#'?`2(*yefXӴ?%]<ȍ`hEEiZVj*㰕UU-)T}I~i(Ej{ڪ)YuiZBGUA6̳اln󮛖en>߱x{е{c@V5&N&Xwyg"x2akv6<-=}7IG ZVrVv8q[%9m 1u;8KRSUIvG)?gJKf2|kN~д`U]a 5n[Iy#|qb3[=Ɓc%ݥ5UePRp=ypk&IVs280 <9O\$9|+Ƒf)?O5U+˻GՔ*&į:hFO) νM5ϣKNMHQ^e󴢮쭀FZϧ6'4g+nBD͏_󽳻k0`b98C$O!ErknE9)לBD"9V1z͒Όg?C h>+cwb\Jc_Am; mYe%)ydIO`|Ya| 6 ܛd9+uCS$*ѱz+<ߣ.-aƣ^ȍU-v eYc[7Nxi䆷&=U: Σs DH:R䫊0%pϏy;<>?y1{!/wC>Y!fxm)Ʊ^3?_Mŗsu7-84bJ*lv^YSe6NLaV P5]xw0$KlQ="MN0:ųi= H#DِFi#~+w;NEآ>B gAkjaۯE@q8r@[^D'GH>,Cݍ#M1;g`-vq=v_G aUih.Qo|@a-+#hݠ]ǒ>zyF[O7$Nn ,Bȡ+P p>~ c'`' GQ5qV`yiĚP |m&)GLK+=*k,¸TǴDdm,Hqֆ7#<7;LWħ_~?e'.3FO;^|alӒeV/lCq0<~֥nZm9:: ^j^:X %їT~QWt||dOQ[:γ=)JI@KӜ8`/՜+& |nMMK/u 즚yū|vjbZz|oek<qlsvHn[Jrd I>k0fQBW̋)p |y%Yniq׶ӧOWUQ3NX ~<"E(TtCE$i8]:QW;?CVY8ejNYBf<|h_2]U\k:tQ,woAo_RoGS޿=jNŲ!QaV١K.1e},n:K}BGqnn%c 4ya`фǏy}W˒@ fkf+iwVdM`U:OT͏GwfcEJrH\O \8qAAapP]ggȵjުzH3˗}0 Ifقv7v!m"dpA\ _RNhGۤzAZCZ Q|IU4"wϓe 0ЊlZI|F+ztceJ8d>2jcJw*yq5bV7 ~^Juc1N .~Rҙ g nΞOigшW.h(|o>rq3gճ"/G m3)ߥd4 Yi)g%get-DDblc <c\b j DS+-TGQ~z#}$4u #>rm0fiAzESg0L(2qA93=pW}yyD:n@qЧpmռdt lӐNPQHXz5c3P>a5Ӝ>sez?a}bQ8ꎨ]!,6zU 2B)2i@}h[4}=bEʧ#Ee85֓JF X ` |I V#ᢢhA+p,U6ve,]}.O)uQP5p }LY+YRvɇl|}=!p:3 Y)iG\ =FsI{iihCΡ>K'p[{Dp`\k$fwu>1ZHZJӊ$ =;/uc5B81z)y4Zh&9RB/r=OCYn͗:1-}C?dcS\tBtQE3$T/q鵱$K6R`^[Ѣ61Ӓw<;OٽK*v/pt\r()02/BQ6oqN4%ƾw8ƞAq+!\Kֵuv;;2x8Ȝk1er+yٜw̒֗Gէ}n*ٳLAۿaL6ߑ>C?|5Нh#߻΍!`}9*#vӈ]ākѾ?To\Wq3؎ݘDiRU* `SJlgîk@DET6ZM*Ǎ3s:Ź֛5w>'6u1w1NÄb~P,zbjC {6yS%gSZgӾy{1&s!,H;Zˁt5v'(k|mnk\vz(1l#~u{vasEUmXf+.' -=09(&JA 1wYA~~pD)>;ɒqʏͯoos%Ѽ0iʨÝ>ym٪2twm~ӌn qeaʊra9.7H(Ӝ`d?U-瓜Fd0z fb)KTztJ=6I{}¯'1څ?+2ʽ >R'd'6kz S=Ϗέ~xi27 gTOf3*Ͱ-k gtc?xC4tiGZ1^!=jcR,0YJr/h"_8">g,{DmU3wgYՄ8MУ"s~.a5o؅@KWeN?y_I,xaFA=a6Z%l-2)XQIӺŦ3d*Ak=l@$-dOx ~_]~iFa'̲e:'.^ю<|k?LMo$[u볫?lw3c # D`PD,!K~GI6A& Khff 9]Hğtx}ޠ%md`łc*C%p/)Dck]7%ia_Zu$~!lڥKKw؝gW ̈ De0"2z/E5$2 G';v%T$ ,iәla{.֔ە"B+e~S//Eyܞe<7tP9&=]cW R`KtrͻT%vp<˹qH Ueaev2Bux@4 # ãK.4? 2:27BQɁaK`.4[VqZ 놇+-mך&*Aؔwip\,!o2*o ~lFdJVK\j rZēLb)byt=h1'o"j6Z 6Ma ~YBcQV+29 qUc A\DȣHwS]K00y%eMדӘF27VeMEJK:6]uCҲ6L G6+,aDyEߗʊw\%Zifя"!)xԵ-e%֜J&]9`ӘYHwqs_1|;e`rQ K"c 2Sl|ҲZ槓ÐenktW-ssl=aH52%Uɋ<3Eƪȕ'#X}v:duYܲe/;g r+*L7*E%݃FTYNy5#*bj|p1λb^aڻߟIaunʄ[;X:`uLC0MkVa×e+,Ent|D~{,Q EyZ0 4_3]NR)(ɽ*zwʷ)U1|;ϺZ%=%| f-qxz4ʠ[SdGYE^j+e /6JЦiwRiʝaȸcu'9/rFfkCuuEQ79q^15F!)UmgJj=n 5bhI<-9$IszyZ?Ңfws:I5AEJ˳{ ! xcג'g&)7vȓ+YiJ5 S//NgI^גo٥6 _ܺ쏧)ǍQEN/|rŧq} V<ȓ\%&rXgt\o\t^&:RY(W %0uA@\R,v ΃5GZ< Z .VtȪ_-0v2|ώ\Qs|F!)S.kJWZ6TE8I%sqRFz (h/8U\W<%/,;T}>}%Z} ( =;wt~F)5)_0R˱hʈD1J݋؍]!K w7aJ~~:<>I:s)e%:Y`E v K.bFI3-FiQw!mſV†pi1bw2Jrfs$V/VȷB`8cpHQ&Dv#9+-Z8zl U6# c~zm<nFA IwGt^#X Nx8͸١lv#TIrXOhJj03'gVZlCZߣ7D_._"Xla2Im_iy%~m{AxiTTuBd+hIAbBٛՌbkm#SDKoI]?DZ쮕u^˲+!pCp!$(|n pc`)Y$Xx3GO=\[}-%4kMmD,']"\UkXZb rCCu R, J;@HSsK,wleUR&;)ފ\"$15==b(p!8smF`f[kW:es>[%,Dfc;bp4!0yA}9-K]ȧރp>?yϯ|%95Xo.8Q3T}g$'}zWJB4 qOy5fzxJ2RiàDS$FWElǴ+s4߾eSL󄦮{lT"kF$kȪb%8e|A?}bdeo|g蹑0tVT Ţdq>'a >[?%_X^u pz!VaIP6N#l{*TZJ&VuIiFx|Y6 HWn1*RBw" ,P{[hC4hg٥ߣAW ;T7i,UW"! hw?dj|N=O @h-:ϐ> o} 8K5|EL?5p@p3(kcgpO8zyIg}[LSL5y()a0_Ej xa͆BlDfxWT.xЏ١J9fGZG .\ISKǴ/iбGkk3K5jK rmfhpGڜMRc!˂ݍgWU³TsX-G,]q$_`-pSS1ʑGO$.ؼz4 ǜN3Ni nc|WGt]NƜ1EY86ǣd0kSoj|`$GdžżfijT1[gZ!|6[魮bZZkVz!)*4 e,DI]U7Tݦ*1EF$\tBLğ@~3& .eZIYJ#۞{>qq}w\Nu篥?}c c-|xAjtU@ ^xb=D8[ ,vc`Р Ʊ^@)\/uu4*Glc~eE4ɢà F˒a+fr{'| =Vs6|!_N-0-wo\壣1JNg64ZZ1 w3Nc~kڣxg6OowuLSf!z- wZwv_5Njn3LmbnLp;=|dfOC( w՚H*0))^Sm<7p E _wNH15?z]V'߱h_1ZS\ɜ#oӾ/iu9^w2'YuiCWF(!9![nMNz@K{a3F 6УQFUiB!s[F%?y/Wc)rC$&b1Z$ |8$wPN@/ n1KgqHZvT +n+Zʜd7²Fj Њc;-pO605pF]ckdjaZҌ$$)%ٴX Ja<6g`qסr|TЦt\p*\v2y`(}qʟ~v=ǍQw Nq98D{? yT'G0(u5>Br?Bғ\sms >mF`)$8X E; 0궒W:dc4t jO"+L"dњg v ӛHi=$ Gs9,J4xЪkfwXK8jXTyQk|t:̊񊴦'e (3~ eJq%8OKV|A' ܽ,g@]ϨЭ/NEŦRj͈e!8u:{wvѵknG\6[^ƒKY~7[|dL!/3uxtlIqDE.df{e2~E>~tdyyDTaszvhb ϰ֮NhQ{>gaX?51XAB*-ΗǓJiqWZD)$Sol6mUS c.*PMkgPd8\n" IөxӲ UŴ2dtUkTn:+^ (p{Դ;@5|L[1~Ku QdG4Ctcǟ=y5owY\"f%gHWRQj$|yRK4"+)쑾K9\賗L0}thȨb!"PpJR<gEgGBfe"WPE |v@t|B []jRL(wY6(ZKn\P/lJ, yQW5{G[m5iN+7.Ԝ2z(anqo3di>~p}O`~){PSɁd(_66a(/O4?5zQ${+d+hbl0YJ` W-˚ʪ[Y q{=՜4v}63ʪO^7W}:O7Ř(+'mbP&8ߍ`_%6-W 2]F|.fnD%l6Syj!),L4fYV!/.c1R QNU֌1~oؼ$.t4ll΄x),{MBWlc>]÷E;ԵET/phX [얺6wXYû#񘤵{D\9t}IC G)\^˜Q3K MlIDKop$EIYRdp p c @&lY$de D%C,kU^TF:8RgԶDbJ 4O Lm O/~ҍ!U6*jaĈ^e%I$,(2O Qo#6|r0@7RRXGf~-hpwkϪʞ 2<~z)NvvL[ĞOR>~p˄Q.H9sC)x^$ GFm/^ royN͘jL"*)<1?(xN(ϾZo4KL;xm*+JRf%1J0:Qu3?a/! <.>!ݣ^Ω+wTTlގGo` =DS*2cΪENfwm6gmW*-is0ei[!.\*2g\L nF0Kۏ؜q֛³d%`; dQVeuοV$Řңc;MD>zϖˌhkg?~Hr5N X憪0򘤚- <+-]riǯx[: R@8v+ɳ/O|Ū`,ʫN'@W5_WCOI^O2^-խ!牦kRlYCo <{:{>?Ȫf&qA?+oQ(%{Ap,i*G92 it=Rܿy]DVLɓ0쬵zOSfx-I_13$GtA_Sb@\m|rjZߧTK>ڊG5SE31bXXj1'|po:cx)')U X;{ͫZѺ< PSF޼q2DNB:؂SKI{VtzH*/I' 8em])dd NF+-x뇬ܹ:'+'zyma6mQD6ޠCgk`PwwmO싋%5HFPu eStZfMCݬ6UjPI!:!km!U 30k`mkDS7(iȺYpl]T˪ ޕ>G<:,+;gi)A=oQUDd*%oQ P='ZXȺ1MΓն"St|./1CIU8ˠ}罛t=,;o_Ⱦ! Ӷp-iH%Y.0ZǦI׵ n¢dh3I%w:tM%aQVr6{:'m[Nji0%my VJq4ϸ;QAMayU3I Fma'l ΢́,crYl7_ifo 6>ךq}?|>{ _=Pʊ?b瓖5C x|O L JK1Z7#o [/e7GrWkV"ǵM9L9HH4!%UU7鲯t ¸C6Sҽ~$.zZ|^B.yQQq8KȤeZڰi\j k[OPyj2-qUˬ4-_'R* TdeEX|jK?Do?r}ZSõ(=p[ ȭ@SckzoNAIn Pnv,%riWҮv0+$~[n !:>Ufy ŵMe'*]^)yRU~]e]I_SY~+@IAQn Z48[}eT楡5g +yt$u_rsi<7ќɒ;[7&^-LkKqw&]q1ѥp7?@G,gvx3}7E_N'|ɏ7ۼK޼=^r2)yj^Kg)=x@sɘr Jv *Cp#c\6KG'Tg^Zw~Idlz>cl2gvxJ'tvxCo|Ll'pϐ;x~@|/j ,f $ӣ*2C;=Lka(]P"26tb'<)7x*Y}8o-iniN7%.?)44AEU? {-\ )EtOy"EX0x Da5_[OQϝ\,Ҳ[<_oY:An 2Eh#R JRXKwľefkdoX|')$]Zg'` džGt筚d nh>۫| ҃o>&}.͇_<%>kv<|9I oA?aӷӍɌf??I$d.ScENcʳ}#{_d(U$sKwwJ_9dKr+ 6's@[@OTJvԔ~)k#$Q镞 ȴnS9,rMZbx~o cZ$fԖtBuO|8.FkA# Ti&k>// ) s^id!M HGc|;Kk>wsN.S.+  Z1/'K>y16Ԕ$ ry[9)[x[݈AF;RԔl䟋[[\ZT WjtaHc,O>7tJN ^_oSẏg1qD><`Ty4)hSuJO1?k g"ӎ+rY8( "K5RmY~C =DoR$ETf 8&AŗZ轗G4H%Z1PP IQ@8Q[XӦ,?K0+yo{q;Qٺ\1p589{j *+ ]m &{[pؤĔpmA(]"T`yN:ёoQYjF"e)IkCQ%YMԒ[5>?[uYev# C?!^vD+7Z7wmd9eY2-͝.|sq7ʃ>`LmxkLQ >{t+;ug7 }gEnѱǶƭ7(=v<ȟc횟f:GZ[>I /űNW$ԂtnLIsjۛ4oݢ΢A)ӥ/q#V~c @E]N]bn]AhYkYhV@2Ja@HB֎\B <{{)2Cpuvj(~{T[eM8#ZB( =T=l#Mt(K|5jC8qAͷAv0})MA}ҜR:Pur2yeF LS֑GI-kNY۸^N06RT٢) P(ry67@:l\fBC_ P{O>yoR:=ipw/tEonXk dA";wPذ˙4zvstprި;CM|ˌLg[mkɍ]XrZ'=%Dhyf`!mu| ᠥMmA"+|),ѫ ũ1,,*G v"u%@Tfp\j\MF ބZZL aM~vͅtaʒo_1E$5W]H=J~|8y4Zp}#[ U(1ۣTqn ٭iN#PI4)TdOP-+];D\Ws?{gvfgw$8ċF6T@i( i PPPDB (I2;^sSy! )*_SM SZ}HR;º^p&o}H/Mu p=%S{Y!R 'mSZYIg֣9[aB}*)8[%l5}q2kW:E-" x%NA{I׫qpnYӾt34r{6?|Ay'&Z2f/(>9:-O~ { j~ٿB]Dh{phEq 0#%l65>^+"I. aa>Z.ijOSVn5 DxD' =!4 g'$ K 2%j5 Lԭ]y^}6lqdLm4cߧQA_oyIe)r\eN4.HdL>/֤ ej4yi݃ԇOX^ Liͧ>]z~kJ:Pde?eLu!ĩވ)`:Zg~RȢ~ܮE@b1DKxsk:F!oII(=!-p'ɩS4[>W%_{Әۃ:uɐo2e}( eH?w)ӂh:O9u)(alߺ g稚Kxt?{L~flJgw~Q=Fc(?3I>ZJ SyN0 ;_X.H EvB?\")|#Ah±uqT !Ϋ!-c yԶ*qɵSSRЫ,"ِil ڭV4ՖH|^ư s^p2ihIIAkW6YID$zdm{I6G5nGRhN„a0ιw2nrH^%ZьfSw+|p8x0Z):cRp H 窹ԮӒn7<30^g6?ہ+]\<:q]0l[ p[an4qOǔ1)^2 3%~ "e]"G5N(u(@W[0DKWֽgLό{j6X"8D,B_OV eCAq@Q9焨$JRoi`YZBzzX%"T)ig `H*XQ" 5y0&zT OIF *RIOۗ){<<>•2>nE4VFOo);M E`/5&Y΃H{4Rs?|Q[^{ӷJx~İy=jCus)˄<%N B4".K(veЗYf]gUdn9P!YI$ioz4`2+83>RsK'+L^z_T;$9Mȇ}&ӟl_ß,2p ~Lv~WJޏ8/P6醇 58ZBnh˄(NG""H/_\ET%<-k3f5W7f *puuI!M9!j $"dβѤ( :- (8y"LW K S64QVuxoRj'"LU&x)٬O-q !gE8] ~C][j])!^ip0Kv^Q!pc f<QMzMg)u/G_4vHI] &YoJt~OX}ؚ`5!鐽_Am7(:mz4᷅X0´^;kg5;yxiH- DpLy)CLQs/逶nU8!I3fH bw̏dMYmS5q?(5ih0m-SôP &EC'R/bd~Z?НHox]<;U >Y 1 vN}Ch w~3CDŽeM5[UHEâ1n8 񀟳!ќj"?SM^,AwrV|?'hب2 Àو452@ ~A֣) W% a9ǚ(MX]HEE%?Ҡ"; tVOǐ $>\m1E>9%/F}9/~Ke}u}]bdei"I ewe2wA9Gc`ѴJl%iJ% V %Qrs@fwZY0#޼f,ҍ=ih#Ns~߶* uBʾ1spw {CVgW`1!bM29P^HPuoAK/F+ 0^Byt]XL˚ڏomVc$Mc\+J QlR4(CxG4>8^LvYMrFTgA* ˌ Ee,ZsAW\v mƢ44zC4XM''9 Mg9Ye2"eOxo WIfYŽ~ӓ9OB.?~G͒/NfEMU|+/'+ ;`vJzqBW:t/8MƲ(j.9[||tԑ$X6ɺ-( ⊼E(8Wj7@.|FFmLû,s _W"[w[9P$J2'6JvGGKnlx3K[0͌Q9/òa}k#ڈODCdݼ<' ơ|$91o׸N#@Hd~Ҷu/^,J#WgegH% mcv pTs0.%YF{pk$YK&D >b:C۟ ҂AKZHc<$LQ9bNjSLݢ_<%WQIDx'koX./ZJ0 E"gD[zP!〣m `ju4+T` v&bdyT|J^?9E#Őڈ0qv>98ꚞacJ?)n0[txEc+o Nq&N wHPTA,(jr+׍Ԏ(ӥas;a6D :GzO(=|4Xu.7z:!̩ 8'oqO={Ct٠ˆ>@#]dBtsl!:9'}uDUtBߡxq9oݽų3꼠8|?d#/`6(LzY¶ #XXjap3P+=Y[ %zrkw*A5Ykkg>Mvm/TByP? `~yXo[ky(ja:(a1%A_ /؝8Эwkd0#ΊHIvZׅW=|gYjHqxۣYLg(knRn ca:8+5$?;c_ߝ YO pVlf˺t,؝hc& Ek\4,Tdbyaޱ20#] )6y]6L6$bY7jy⭼_N˖ҟo6Rb)DIȹj, " sao- ' xim$A$Mk fWuMY9FF,!##{B83T@DI?;.+F[DRHIeU~`kfl7pvUAmO)TۂDi=!J;"ِQmάqE5]Ck,8D\bΎOH7u&b#o{!Z_M;vV^ay4⿫/^ol3 y{')f$~^ O;օ" ]wxd>y|{.&Z[l;+p{Yf!9 |iZMI<3y0f-vҤۚ18pqLPEi5}t +l ?@K%+V8i'5sӛϾwKuo~`vv?f ?{Ftxi#]B MХ^l^f\d5OJ48W 1d/ !ڕ fijS0-fĤCd0zyQ!LW՜CJjeyU$DzT6IF*k6n1h`X}Zv0`J"%b̀sa5.2Db]*C J2p5 F([B~(TJ)םR@ʸwm\y!4'Qh֭z m` '3zs9WbM:sQFW72-kuFxC_|^^87Ώ0}SL?x2QηԫńǧxV5{xO -w]a5~y^c>VzX)֒N~J:AʐDIHePڭ էuGXwzBS{iӾn 3[CdWD5I; F 97Yŋ (;2Lb m,ØQ> "><zK|bj4BwY^Q 7F ZօbJV,ҜM# }xt2dY*~]DDzpY?bΔO)MӚ.𗇧4Y/HM˶I<%}/004e^j 0iRXaZlwҀO\#'IpRPT[o$G:uxƂI |ܼV])ŖzT(=jF>.q!":ge|;Y3,}cX6"WwvjMwaѲËiŧ߾b6Pw :x N+F=u8Y\[O3#?({[[C4jţVR!#^A6`wvhVWQr&"H6`ݝ'dUz[_@ך,e2MVS|0[SDS[(wQf$y0c"E8xO(.Ȏ?'_0?z;~0#owxw#>3\eYplxP6B1K[䄆rl%euQ )2 WsdKK0rmh] #SR 70x|9!59M˳+i<>ӠS 1\nk֭L>KHDEM=mIuuc4PM\L ՒXd!LbwzՓgT3Sgv )ïΓT ʘ4 Ki Hrǃ_y5U计\ʊ^,qG ep1Y2}kV@d y)t-nKt@^]"׻O逊x}kq".bIO{}vl֒4!sCL-UL_3́Uj3%ZY ~&5t>H)͑$W7c2-?r>9%p|{ !^Oq!doïs|Uewr7 2-e $G+m>d^S6>Zq:R Ïv׹\5|9i;{wH˹JЍV{|6-\5M(k"'m`o=G/{뚑o&`${=Mh[THH;c_thwƔKQD-JtW㊚iI6>8$ x'>{ob=x e!<ЭLDH5q<"i$EO vRo(M{XaIDAT \ĎMz(=J ""d`&Yv@VawpIJ1EbiF@3!;DdXB8/[R)b'Wl 7)=nP26Do/#B)aȾg v<+q,e;}ʋM|:TJ\'yԙa'G12;:<Ʈ*t9 f|ڀ{u/B"<_mm] `#CՎ s`HKv}]LcEOfYPhMWeB$p}Mdg|# ڎc2>JpStk>D0C<|g՛F>e4gZ7 oxUaٮj=,}YLd|ri ; ޲:N/6vt,Lc-p]4wf$JOpm,|N睃 }z&|p02~?&Qvέ~s{t-F J2Њo%Ղb$, 3ɢ,kTEx@F20=qL&ӂaKfEu6=vW~t߹=c$ŠDHQ,_W찔MHD Cܹ̀]Ţz.^vթֱv(3D𵷱i<5n6%% `5-6yMբy 1O9žLKlkr;!J FMkb֊S$t?l<ڗ|./9ˢa8EB{?T _̹Ւû< 4/_b|c֟}ӷ :K3^_[4! g-ug8>pb^M/Y.y0(V+hm`m|SN cݯ vI޽Ĝ- }0q̅մ6 s`r.Η'D{ceF|xY;x⠒%-0[#pvU`ۆ "|q)"5Cq\'D+kA1Vg_8xM{ ]W%+qxvk8w0JHc]Q%P)x}=GzcM2o}]+;Q@k-a {5IDbQr2 gH4R6jp3n_==aV4,Xq}-0J5aȟ__CM?cȗjpY]ٌ>{'6MH=!%liT{$#;'$&yQayp>뎦5|kQtÄ"E8TU9Ϗw3&aU᫢#2>ӄO(ꎿ~t~}!O%U<.yoy֘O|9E,w&a50#C~{t)f#=iZ|ɻw=*7gURj!ê^ܜ$9pJRX2nVԋPU+ u-hY>:<_mS!X(VO}[Bk|8Ed#~bA8Bam%Tі5 7iY ˧ķn!y8E o[6h} ;54`I_!&eCQ'؆e#لz/',ѻ/R%OoAЖȮGM2v*`XT]B kqʠ|\C!TOwUh})9cd==)^PA>o:^jLñl$놑Q d#~r]>ƛX%HzE+KuI< Y朿g qUP.*U5[ \]pKl9x6uMYs|ɟm(%etF& Y(&d&Pug=bG!])Z eK&v)S$":l0nE{5ޥ6MpJb :PdMBIA`*t%L'o{Sfu ؎ FQG xmQM 2%8GU[C?T#KHk{<.eɒFƘw>g9_=gSFQ'd0qLR8;%z5$'&F}LO @_pPALbCv<^#q hn} :Yy oY5$2$Y1QHgCAKj&67?[>e()#e\Y^fR#w{I\C#ظxJJܵ$as[-n޿Lʚ?W{U?ox]{uz7D"/߿+ zJxӇw!SrAm)voS=FD<)QQ@z2%GKl< {fD(I&bA20x8ݛלq5t&EN$ƏP.UJ=ƫ BljyHc9upQwCb|#kL#C5u<$7LrMj,!rU>uBē1' %=ba݄wh.j֒(Visj-~Es BHW2]b+Y^;931.NCFJu8$??eWIU,YPTRaI,+phF RmWR,k0O]nZң(kӖP8iL+*A?T̊2xϥ b Iѐ }G8@ IXB:_&kΖUƄ-EU)F;C׼Wqxژ&- q8kP7 @ k!ҩ( ӖeQqjGsii ϳ&:8 7Нv<^bk3-dCŭ6} r=Q!=_6uS*ѣO)V,2(l0K-o 4s–rK'D͏GU3;뙵e(QJN\8r@OB n\ I$bc`PK[Vuz o?ytOfu-uLNkZD%8Oi!45xk!7de,z4X2U4Hy&ECO9[^t laY2nnaOx_H3#$VXW !Yh)<$kdǭ[e_5Vsӈ}( 4zb{-عfr}z[EM`lߦ72O7,8;0cY?9dl{mxr=[t8p|Cw&L ‡i o8њx{Ol R@eX"B`)X RAYyJ=ޫq3EJ>!6.u6ɢ21ne"kg7d1ӁmXa q)P.kmic#G9 !_.Mk; eCvc@R'1ة7#[/8zVQYˏUW&,,O㰗q6=u<*Oh/1jzqx*.Pϖtg|zq?凯BIc=G9D};e'h:&'sMm=V(b[hlE*6D \STJN$6ʁÄ,DY4O=- IynyEO{5K $c?E STV0y*룴̚.β 5#h]NzDKWsԭ=Od98$&R%Y$AbX%=[~+vH,,@"!cD.f#\z2]Uu.,NKJ|yU,vW&շ(+ɡZ l\#5^9WڛDT @/(UPSU`-Bk`9֎v7awJ.|uӈc7hnb~)n9 ^Œ||ȭ͈Vϣ13ns^/_i\sϸλ&_c_2p?5NfctA11hp3-#U ٜzx\너D"P8 He P-s(/HBlѕF-5lԷq1IbfKyJ"b9-odۨsݨ PXz$~&>Av,?΋$C*>jkk?!l!ƙo;5O?{u{/l~o%K YKTҾE%*`5x:f.ۉ?~UEFiƗXm`cOl^궐br mѫ.\)3$ Tƃ]&Ag$ʽsZ- YY44—0,2.=#VqKɴSo8dRF+GH@K @*ݭב>s[뼔qb)(t茼I.*lAB`"Fa, }Y=\|MWu&?ΰڲM)^YL z2F͇1f֡,Vt^ϓ\?W,:jePDA"ɔ'̵[݈ﭮ*蕡XjoF? i%M(OOYށwp![l!ik ]rr+hu%S.SJ Jg.BjЖr̪6 ?SIYY: yu@6!`?<-2 J㈤Wq \_uўHAr)B Չx萑MֱI1ټ`G+0eYE+vW,KC/ O<юW6 $JJf6c,K~,Ofj5cNSj5OgܹukP +N ҍ%JQsnɍN̼tJzOAw_KLj0ÿqkE[}!FՀpIXXi<;oV!gȹiQȖN\"X m[l&? eizo)$vNY4ř!SʬX"x=h/:״t>_~.{R}(b=-ehptHAuW m7 L ّfM^^>(JɫG+/HF>7&]?;QJS&}ɟvJ)}Of̲g3mҼb ? ׶0 '_f9d1 .0wߟ[b;O{s~yVKr)L&rȚ'~nd*#&"$?/Ⱥ~tJqg`-xs3=}E5 b]eFJR4*dhk륝hTcibInUx-$LsH|O?2-2(Pz@ L_;Qc`ۘO>5ޤ;}88Aܾs5ɹ2PҨ|RuhT; 9y> Agcs vL5c' nnQ1>bٹBe2Fe*c9eI+CS4Ja8Kk-32N4f84 z,ε TNd$@e4XsmlӠ|q-ᘱbYuCjYI CS5D1iVKVGV+Y[C^}̪F2(PFɜ:h T.нuIY<>'=?E7 0F<>HPZzMǫm !W+U^i[:lZƳ!H+kr*NOyxZȊk-!i'?UT'x;lqJ=u$h *+R~p<:],:G8p}- i`mc%AwKmI^H|VaFѴ!eEQ{} | ?klHZpq+=[q2't\gpƵ}͝Sv_^͝!?Z[W,k u0òP|gjíOUF ݸx0[s};iOӘ8t5O4Z,fdǤAں8,Sp^jœiuH^ӃBn@ײ E ,]EkrMSa a;LIs[~3ISrlYmⲳWɿ"%\8*o<˃lA$zȢp5^߾s΍nf΁$nPiΫ兒H)h"-΂ "hu@-zM|y7ZuQŒ6MоRf`hg?_^q:]\Fd1 nu8Z4ʼb!bX$;ો$b'O?l/9k,wwN}aUw;︿JzJp3&`%:87dJ L=F]).(l2au+{e(Av7 Dot3L [/z6o^1?5: ꗧ36<w?Ã>B'SQw{Y^U<_&;} >_a3c}syF>`5.I)>|SjڲIuYy6)VBpڰ "nJҌGTg k*qcG[,~;bjoӳ*gG҇ %8U%ִX t\`A[-Dwhstn]q􉈮 V4<}>@HA1௲WlOP]NыaF7vn#m7i@Mhf i'ZaU)i]OR߼ɤ<4ڋNE#9PGM}Sp*~zN#Slcc`HslZ9 щQvk~(RϏHvhFY;H%SS7"ၓiXҞv3UJ^¢YgJt\#ue)H"`^isx/=ˆX~>!|/:oȓk*ms`X\ZNActbJ[RBs_i(f D)/!VɪF-^VeVkd/$JF' wie㘶XiL "scs|]̈_Ҏr&]E*I$$iDˎEm8d0 a;$^'5 H! ) RיI2ݞv_,1gK ]%1I D)q 2"̷ANz¨OϜJt2H{^襑V.VvӔ^PPb{-KP܀L/ ?SEcX֎Q.d{}ދ GXݗ{[CKfEɂV$yi7m]VzȓB aQ1H$vġ⨨4:)ђHuˣyE )D2;[ykL (z2d?.tND_ܦ}X_-.nkTˎEmd3D H0@$X o ְ!@a'LU,Q:N*IQU[?Z0", גv?F!IGš'TZ$ SD@J&rqsSTiQM!8* Ր<H&e?QxqnA[3K+.;ͳH5|0H)Os-9_?ұk\.g[>!Sߌqz7g&G2pz8{}k\V $%5G_DT{HkyF>͑: b g-,/n:#5[0Wϰh;QiIoG#T;?;^S+?+TK?5Xn$Ś3W>y- 2II T/"CC8cF* P;@!:\pB`FD뜠.N|gf+hOA fkCV[9/Wڍ$Ö x*yuV2^˓^Do[2@ A$}`?XWYQ>&Nȟ=F ).ϱ1 pWPQ.6"B=ic«WdusՎmߴ7 *Er;"g^8K:jk2MP7^H(ŭK ?RPR*D-0 ':f):j:=e|LkdQ]vn[ǣ)^8*\/O0Y w-dkTE\ ㈪̑ĝ=dRFuqc  q#ոbch!țdtc-|jO9ĆӼ) ")8X͚z(Qtv"U?_RK(d1hu4;N,-&QKAW'u,8Ŕݞ0F]ӔQK3H]]rӏ5m%YU~dUlYc|0hQX˫͜ȀEni5n)5$hOBT"#ZĘQ9V$X0 0~TˏI?ng<~$,%H@$ā'XVdNfn/ 7/m1 }|cgF=Av ć錽-eexQf\]Q~UCD.Y\ee_.|Lo|OE'tDuZ 7|IMw2AMn\R5oR@.}K$#jx1<=`yZ9*d(tu?.%/[̶!8Op{G]>^>QI?rqH%؛vm8:N]`|:N`yuEL=zJnn dLt)ŷZa !j~J~#BNWb m EN3][:|eS˾@59lDۢgkh!kvhGG{N'mXVf̊븸鐓>"Mاv"Rr\hQHE|H1ZH^@ޔ@+ A btl{S3{?X-0k\UGe4%fS%EJ6{I1-9^O!ӍLj )Aѿ&D:aZH!xf^sgR 쾣_]le\sdꭖ@*( M;g|Eեh\t{G9OΕX$tH ַ6QgDWϑ&9YA1J9z2E-j(Jb5!zcd4ӣ> h)j:}e%z~64<!(oыa|~ 炐GCuO__RVc6BHtEm)ʌլ4(M3{64>>0+"2/7;hyHu׍;즡%O^W\dLʔu 29QηN&Jrk[d2{DwgFP9/m t\JsZ_O4DɎU;9$!I'@!bذ!x^-x6H`BIv5┍W%˲lթsw%Cl]<(cQ9tc>^#_)iA  $hG2 M?۟.zuK ֊xy6xQp2/8<7dU;C/2+=??^?9\D޿'͓EA Z[l>o>HX =Qgë4b p!(1S ϽLO| c9|d\}^hKX/mQu'aoq}q2iJQU4 ˞QTjlkOܷc[|i&ql(-Wo3}V<1 RDUf^bIS:G;M(isgihvτ>7YvxX+gך.N2llYs R,5A6hJx\%%F#O5&hcp^4Ʒb`ӝp+_BL>MHR#g )j1hN%fB'=TR-QM΃n M˿eZzN3DF39GC ODLxpqd +l`AHlDŽNLmzGeq^j]=m.U cZ1G"{Vɻ`hOu~XnjN>iau̷c2?Ԩ><<3"&YѽL4a٪5<>dݖ&'NC|vßNyo3X|/^Y+1LGhP?D_KY5G_2çL{6Mʐ*;ǘ_ᓿ,źf^:*f}#7NXZKoh*R"YWRZcz7ʡS8n-Q& xx j\Xaʚ2z1DMA7 ͙ۜ'ȦGKZOy~sKa Ⴧ VW&/|z8Y-E{$h:DYB"NpAi31ܫ9f ?pplr+-E1z߂ YIWlL bW' {$v" Q]iώQX4J֛Zx!Eý8bDKhjl^LRVlOc0McV Pak@ ̖&A9@`7,&hR2i,Wa?5'['gt*FSz{9]Jfa} plS6aPI- (FU@CK2@0/:VØrż`"\t{& t&__6 g 5tLߝO20~tDrx$ָakb#@4:pLk%>=E'{G'zuCNB ? |qND%"&M3B>x6}DK2ľp~g?]-?ݝ7$aߟwEl^/ˢa6lkVA)o9KEIzk}{Xݱez (%ymYk>>oN2 zY1 j%FF-2 K;è*=r[@)| dF5 DoDoE?NҤM!4*A D{_̅ ΈCxJZ6UҼď Y'a/^y=uuKXJ%!2Qo0M(Q: #CsH:(& UoˊXSu(/ >&&bzg#&EFɋ 9o 5y}Afj^^+fe`DG+Szf/F3?q:ܬBh}iF+{ yUqN:64(LTF6 Ik>D#;ۊ⢦E^q35P5B1٨4WoMkCpS?k+I az=B8SVn)ZU34aDD_dc8M7;DF؄Y<;l`GoH%Ld:mcO+-PQD"mEN 6Pؘ֗;$&J[34FψhiH1G<"6x*I2`Mm-N#K~<)InR2Z1ٿt#fB)/MϽu zHq!sD`8p)HY(t}{[X]vW`d?sN ɠ h]Y^07!FD;B6]kݽT_S}tVġ΍:}Fj'1ѱ uQbsao=\̺`_!e.ѕ)&-{`Vy_쮳wqx<ǯi45ܿ OHSC;Q|-~}G=\QB"lt*0h E)]ԴY]{W!β\圌gu.k2N* ;vX0J՝ظeC$HNP,p %~wY9mÖh<+9LKǴLoU13;~$ΣO  H lX#$6aSgUUhҴI8cgg]ud[^9;}zeP>B4W$HL Bu#}يUR1Б ˍm0:GTtj8F9B@;VLÉAڝkwes6)?{[[|51-ͷ&\vc𞓟bMq+@f{/Hֻd~B}c y#57bM ޽jޤ`DW'+VhIG'q%X[tCF_⪚L?ܹ͋'QAkYKmfG9HZOWj9Di_A8Red`އ<,EțbUSwP*Sl8~@_=:`1@$}w0ߦu> [ UcHzd"\|2)j{^Iy -+-Sssp J t: sCJ&Ra*Y^MhW6$deJ;: Qccj8_ R^0yۊ$Tα{2gZӈ~CYN7d,jNSntWRJ'h3B%f<;ObMv^0lcgULn[E=3h;N4A-PKEyT7R=D6Mql{{fvxK-5w{^qfls:8Mb2l'Iʺz_ɍŏU1 8 hDԵ4Go倪6lt" wX6;HX yC]rᔓG/NYʚ_ `B>J b`VP+ ?~wƢE1;7[yF >XYkYA8tg=S-o:mCۘ[x u#%Ut۔)*_6*] }k*E0:wk]\}VzVEB18~JqHk-fiC~35%GE2!H NP5l$ I[<,+K\rkfXc(GRA$+xBO*\=C` JJvm//Pb*K:۹mpՉr:D'ψ:ր3{E?)=gtS89/Id yqU\}ڡQ idymUsËV5^,`h5+؜ W ili K0X Lc<$ƔNNN'=a xR6Ԉe.E%NEMKqNh1F .Hoʟ所Жf=Tbojd\ ~mnWo'wJY(tewBKW "6}hKa,WEZow:So߉H Wݻ㞣ώXϟ/nzw*sT{:9u9@|2"`=ςUp8reR*K'T,h$TҋM(w&94-8,Ma[Hq%]OURc2+46fD^i~zQwdӒV&4/YkfI@E߁3HZ KRf7*@?E /oG,'>ݘãSi2HKM7RDR <f+&oghDۣX]x(xpcqy5TkoDuwMmn*.-* ! HH  pi6zam믖l9=yaw5J~XM Ju%|McBz*؛GRԨuO4p6G yf 3㷝xk N^$ڕ(${')Ϛl28H0θf4kgǵn8Gױ3LF)Jz0%Hz}V4G~e%M',KX=E?V-@>y6B88GT,AYa-2\N  'L'eղpOkYAQRMm T@G:>yedds-| :Q cӗHumn*p ͺ95NW%f)oŊ[C ~n|&Y6Z }E8̎Gĝ%.Bb8`=ѡiF{4,I-\󺗜*9O>F J!Qq"Ff4/ ;% i<&27W\]n*3GW8_ ^ g\X:JZI|LIr~aL?)!<ū5:4GTbW/ydDi[ڄ+*J\$\nd%]UM|~?7%}:RT%1_aQ9؋㌴|:qVD7VLؗk;%ԕo.B)h.~8` R0;'sp9җGS+׏9:~'kW(ZK/=D\ Rx!//*-'(#Fȑ;BIXo:w9bk^?~`9QӊqmGm|{}pFA.S"$veu ܸK U5HcV6Ȭ@\lXmqk8y9O~4 'ɬ +qi5蘍%^ū_]$d!^VOAO&~}R8)ADiZTӝ-& -}c*ƌgݻop݃}7w9{` 1nPfLaZYza"0&[Z>oǴڈB9_NG[Qdq_(z4qUеd./\6y*o6IBbQ1{. D90Qڠ([N^X<'#k\#ejhmupn;"s ʙ 92 S9 ٻ!a#Fw+fI;a5yM+tLIAgN\Q;zN^C|\"+B 8"%ǻvehGctjIYorU 98-ƒ8zxPrD䣤B5{Vm Ǿ+ r1>xJX)﷠t}ilUFu,~8Hk QMCs_ڛ;\V\BRРV-S -UѱXġO46Kkh8~r^?llu @ ɿG|ի;Cw;ۘ,.rS|PmmlIA5ie4s-sPseب"[l6 "@xnΛ!_쬗%~v^O?!Z[>Ƌ7,lݼP x5 8`+:eF{k x/?ý=ñd15&#Q1aN,qoĭGeƎ8砟>i=]?cx9* y3"n;`4j\\G8Qy4i;BLlY@L9v\nE鞱=I,+xނ'd ! "H&NKlϽoucQ=CmGMs?ET^~l xˎKp}hqeE{‡ıұ IQ.wєJEv6XŬ!$i/*)$WXFElPwlak܅aqg8V7ָϾA,44^,z8onew8yk_|sq|w0bDVDQF s InBg\B~k \(i`9#ۄw zyBuZ&tlt}&YHV&L4т@,1(olasOA b|Rct0Ti\`+%K+%uGRuLy˺ U(ItVƎEXaH7@3]6}ׯaho 0eAE1v>&Dyg'KvA[̷v֣%iZp?#n1ESmlVψt$)Q (Bmh9\T]yεhieZ?"HM-ӊXv)h1d2BɐG.\  Hi'ωÝ ńAD ,t*m~%/&$#T!)'m>v!'ƽjo:fUFE,xմW[pk[* ,+ԆqX2NKK/PC/?u^CD2#gͅaLXmm(k&S0=A-ΰN#zT%]]It&]bTo j\ %"D)<=!Pp}Ǵ֨TKS(>Mk=ϦνŬߏH{2 >XPiN{#A@q|{ݷ6WIyS>Z0K8Y6*g@*{uoDDa0] A,U߯%1R6gG vLK| ߿sX0tU K' RjmiL ;{6$F;O6Ibh6֐s(@E s\멀ֆLGsg=$V#Q̀c?Ñ#9r+-$Ε.pԐˀAǐ믨rpm0pvZq8ɊX\=.(~M'0:a$h6(zLp-&S=F&4yg ŭM~=3exTbm#Z|0֢7^D2p?aܴ׹gsѱ-i5Glh-7l޿K;Y3yF~+VՄ16 YZۘST>NolrjҎz[VHh+o|Vn7HOMkiF3<ƹKFoǸҜW4: ~D3fvy:-p#r#u']dble%vn[yFi㎦m}V.:-ЌK6~4Мɶ :~ I/#.2–&K ͌09ɝ6]!90`P:eK B]EmWDd1iqȿaS|h,Zչ(tv`n2? iTixH<}9eAaPe sО?ht;sr65Lkxm=Q A|,wahnחv՞,qfd+]|3#ÖoF#(l_%8K4*qirx.z'Q MY⺥1q N~"i쩿1k^^pG&0jj=~jY 뼻x{4:pį2=bz7s޻jx1`̻PZ!.HziD"՚ g)"ᢒ~;ѦfŐǻ'hucOꤤ_$fڴ8ހH%&""->0fI8F"'v?TIoEU,x H wMrcp31A& q=[]zns)i{ū6c#] |H^@tzE)Rnlcnh {IXIy[-+0`:˭OyCf~ctC5OZac4rbwӊQLkBI?D 4`罭p{Lwz5E>MeɃ=: wX/?BMP?o#_d՜E)Caz^JU͠0PF^!Jΐ6ZD^6,!;1ܢUE[+jix{}#ޤe@bE$!L kkBi1M4^ZSIwZ` U9}p.$$v\q]B2[C:E]|::Qe_]TsAr{L'6}ȺahdZVO $"ZfihS +zJlm$lw'GP׈0F]_`@0&{z ,fDo>Y XrQhT$Ȫ"+>ϞH!葒זJ `AU~1^zAmJk StFscV gܠRS{S5Ѵ--"Bqt'h}7J\ƴͽmoj go{<'.߬+JUuӔJMP8Bkw0dycvk{._ 7cNS>=nqc~|/ޟpm cBdk7tq0/4ݞs^x}svQG˼Ƹà3K+󜪴H"lfVu`Yh7Z>b[#b1@ICkC\Ioe&qt@%ā g#qcU. RK%4@g8<3v%_i,̳*UXr 룐hBAO4I,A?W^uY-Gi$ce6<yHm_NX\ }MP\^~lAǧHDVz|p` }WUh8}u^VlEY3, ~#YB[SFzP5›;>vXPZѽA>Kz"^P5hֆhg$jFC&| v,%{̱oѯxoi*mcc_ݥKBf-rlIe]-&U?QL`^ydb*ʚ}p˺7="nQ*h㼬v:|;$2.t1"..ɽ}w 8kP"8-_'еz;?yeOFW$YqR '`7x8N\KoUs3$N(KZkUbKX[X 6lXTP-TiզIIqsaqƓoFgc>ϫ]OKiA" S})e#:(Fݓv4[-!P #NP#PԖu4=WpCYx1Ixox2I+|<#y3V,LY8Ҹ/skGb\qr{oJ\}|(ѻr5y?bkQSlnPD_elޔ;nrh8dVtP:brFUe(g8XMW)vL,h>gsJgmψ>4Jp!*I02ERw-=:88d"bj8F.&qӹH 2`)NS]&V,U8MYɨakXKAW)p4I̞yUȲBe5(M9ٷ1c@Ɣ_!>u]c($;gj48mEEun󛽤C,>?;+wHa~X__N:j#C|ZQAVx*4dȕvn 㒎&>oeϏ.) %M2 ; .!wVH,M <בedo@D!z*b%Gv*@enȎuHJ (]iPZZr` M đw}W[|0{Vԩn]4֥!'iahG#ݽز߷8n/y8c ܽyg־K^ɳ iY 7|GYb0 kq^bd0Fś=B(>4ʸWS}|6L' Í>W6`2u0U)qD3'Nȥ_?\nUg3g;he/y ޅG! B"U҈8qepqLRF,9|a S7u—rV{B h&ǹ-"Fj)&X{8il06|~{ȳ9E 6rgf)*"FIo݄w]bnxcL9B%G>^nJ~)y 8Aƨ%h04jʥA?'v4H5)mΦz5Et|"8~"!ӱ=MIFu  ÷l*3JCy`*DS+x[%P_;`Q_n0UiQdvlYmRcbM%U޶IyFت&;=G(EWw>B_[yFF.L VR>~_KqyG$K`2l5+@׆%fChJX$T2d)ixdECPBF7U |s 3)2.*C-Kz "mӌt({{)R>ޟp'%+j^_=}0ئqHIjof<5@G#%hyܔ>pz/s"=Yl*u*HEmUGHXʴ \պ.6ʂ:O6sOTIoEu3;L KDBH8pC68%, P ǎb{=KO/U;yNu'6Ԣ?QSZQB+fGd*\#}J)|u/6V,$W@ \aalg|0 %lfReR֬ s?dNh0HC>}u{,5񂲨ys2{[e<;OHBw<ۻ_OXg9A ։`7F۴8 `9o]6|i8cZv)˦%4 bZg~nEҞ &}n ,MxT;_!:X(Jj>{.U¶l*ƦMz%1VoTVo>Ss։VmұUPFuil+Ǭ\ }L\EL"~YlH "gd>e9s)7Ggd׮RS` {poA`)V%v1P:D[jTSs#ٚh: 9[wP* EkAjA*%v-7_jJ#v%BCd4bHC-UD+yx6E-qxᾸNcn_˷%GswQ7+~u0sPqb)Ҙnp4X54d*Hjц79/]v"xz.Of#k-~“bK|- .B%~bKNo><ǟ{ɸC{FoڒqxLڊz~Lh :?;0Ə"uӁ~߆Cv[SEX>DpΖN^-f9覊'3a@ UUK-{*z7$bl,mzAz3E^J1 ټڮ[ Ն$stUxd˟L >~@קPiL<<>%b֯/?:ύ۠|04M.ޠ}nHH/?T<F%%+6.sJÔbyOʋ]goIOx 2ӂÄ%HƱ8ic $χ8riڒ-.A0v &i.N\D4q-ȧmQĩxNvڞC}Rt-kgJqW 0ӧv=׊}7___v%Yh-qQ/YC]6[{kd{ A\ڪ\LLaFšˣp2Hwnץ\3gASKݙ(kgKMum3\ <8{6йM>NjblSSND/;}P 5Hzu.%ɝF≻ RtbTU5)72Q(P@(cKn@yQ1,r~sr9iYF∼6sW>:Y˿'(=:>2%ZOVWsٍ5otzphlA5~4EDRD8ʋ^萨lrxm1N@}ubOR!XN[lCdA_s%:K{`#.Vf" 4jMUkEqC(^YM*|\* `Ҩ,i$Qe^XW+?`fv\7D] vyX2Xo Ѫ&H&$ JJp|109zNwhjz7-{XtFԫmePuT@S'[h!l:Lq  iyG@g wn|~+W,ƖD1L$4Ϧ0QTdzU'o^Ӌv'cVV[G?, G-Bvīy;Xb]LpM-MS&#:>ZPcz>\'뼰=7m[8Zq^&Ls~`7;Nz;,kqJl6cK uвoK)Ptʶ#3)tZpԊ6uQwQ-r:g|6 Me& )A'R-|7$C֝PTlJsA Q{WtD8AhlcW,!fnC@LNGk]Axĵ>A*')Qh^ -[{=nxW36j,`'gEͽ.>]N>Aoخg$1ޥi.e!E̥TdYmVgBŤ婃- Ѝ5]ӍRln/bi;mL+*놲q,{вtd@׎0?\nU9?8q6m %)U7]2č p H* BЀZ5M㤉c{Μg X‹cˋ9|jES+lqpZqsgs6G)IYϫ~~IWb~۟XHB2=)%9+ 8JjO:`mRJEZ5[3`aVØal`k%(N $nè[jld!B2o4q7тٛ;#6R8󏷙">{S:ok~ut//&}s1zJtr),&|._7EC, QdG)qyIFbVI`[Qǯ@amu7 jEyRvXH3i`+MM1؝y6y:5?zٓԽ{f97 Cdzes*?,5ʲ.l ͤ&nPK ]&i 6d9o%B40ADr"uo uY5'C=b [Bx"9V$Oq1ӁkDPnlJ1|5{}Dk]SH <,VGlITjV;YCXIxᱷYh'"!)Q.UiU QuKqU] -Z$]V O[K.9jZx?4R[/ V-g-\N_R%2:8ݳ-":'}ѵåG!"tZvͥ੪F-r^`AUݑ?,&Z&YRR)Iy8Ŵt}!Ȝ͹hӈj⤜ {/[qOOPGxIYt81*bu : dfACD`;Q9P0(\+e{yq)9y*;"G^|jF+pxw~v1Ym]dY~ '?L0Nm%H%kXisqAq}pM={u} 3]I."o( b~̶?LuvƒZ&-X.>V\pR](g&%kq 2mç!W; Wˆ8& N*w_U^ 9b[ ʹYOwR/k$Ep{_S|]".n@Cs+v{y>+S!rezp/=0rPj_- t*c$ Y<_RK,<]2iUQ{[n{M_o;Ks'jgYO*V-Ҭ`!x> UXQ[D nuB6g);F*f)foG~<#T/ #ގgܿSGP'ªoqaRgx'|=sU{jWe;!!2 0CH *jj7%3d p2;{兩we'*53;Jy>~+fHK#4.5OTӭC6łB֬;q>X3]`/3mc< 4OeM(W'!Uý[;X6-lD[~9I$<8)CLk&j(ӊ^Q䳒E^Wq,'%ioaM:J.MT䰛wq=1npillqXQ,* q5釈| HmjBb #4pKgu Υ:9BztS0IXdPi$9fK0L1\-q%S${xG1T֑g-`[޺\Hkn.>vIu-+V2޺L[Ӎܥ&mg4d4Ӥ4>W4HQmf礶$/Kj)%0EMT1/)5=g+6D( M, lK9yÇX9@U-#j+d<8F0Z78A5}/PɶH]= IV5Дb&s!-&4T qNnM!"JCsfugMZjp׃Ӧt9'[Ω\Ӕqk8֡A_ 'LPlaٴ҈T0έmy5}q^K]j6|66A֠>:64Zo#uڛ@ ġ z!2cyASW-4B*0 u Hc0>7SL24AX!K^5R₻ b{P?@"I4,jtaڜ/+/-a,{NOjDε [;T迫ʵA0 4P. TqYipo(4]<`{ؓ )_w/^s]~>xN]{d֖FB+߮ c/)y2P9ǽ%ߙr6(eYԼ:ȭci`|0Ǝg/8(!9>,Ofv2 y,HB^5#֥pZht3e+[bln`߀q,eW s~\v-8 z)-GN\3+%GP c-2y@KS6c/ߑE'd')=@LʕzşÐrv: wzOx3.xȨXcd89 N`7q$eωG)`$r˝0`ΈBAr ߘB& ެ(33zrУCS${{&OSZ>QVů.}g>W'v7׭o3ㅶ oW=[ߍFo[t:g&-tqmѿvoʚ@>i` Sc z7BL^*z`w#‰7.k\y3ۃ 7"t`g3)0E!Do RN5H AfMc,Pfdo? tnji$0,=Eͳ[=ϙ/ew^xolWEeIw[UIf BPXGhDof \nEDZ'8! X oK<BG@"(, l"رcf<מfq&Q5)9/l.BteqF^(eYTM+cn/A(U W@iN䆾*ʲ$K-E:PZA/aF wz4v7!ԚF(%k /l˫ _Jg*͝v7JV WB 1 BM&a]ֻlO1hU#&YKV#: H@АycI"|n)rGib L@CK<-]("Gkb2H&}XL`gA3$o%B,4q_.Akt!/iu Q \YIOYFlI(pbRvgl⏡6"s'K:IW5A;Uaji'/sϝAFdhFtcw֍yoˇ{kLoɽ; +"ЗVJ,DFiQ H@R^x8vAyA2>ݻF'03i[1'x eي8f䃍&sGR@Uq\;Us朹^-dQHhtBH==-*(BD $h$^s=3ʅw}S* M]ժ %sủg$/"A B[W~~ 6P:"4:bjj,R I|cg)ngl1$ۼn( ϔ)*v򘫟Ŭ'ڟ8x@& ]kY6o~W2vϨm~r/Zv3J%#6'Hk~>!u;6~&Z+pD8EδrajqƶA/^vR[Xݿk$!8] {υlԖn$: ¡g?N+ˍBEq@.3z/Ƕ4lm AG: L+U 6.ya_A~-k 2ҝGogQNlk*YD Oj&(=: tf`}Oz|Ԕ."[~S lst@wJXR%8h,W'#FNRݤs{T!ٯ6D*rm(Oz}\`\` [pB "(%BǁQ#^$L:K}Zne Rg5@n ';FB GxLo{L1^I8m-! .~loCڸE ƅ Tc<ɅbxG6{D8wa^ϛK~ITkϚaz2؜'a c C__tTtˆ88+L١rRK( U⟷G3T]^9"N-- ѫݽC!XBWEc)$:,XM#@ف߯d8 d:[x>$EcddkN/8ϏOBQx}+g*fe˃kt. |gUFF7)8o ׹+TIl-NY$ON5\d@_Eġ+Q9L2MKlt?>xɱ3&gr}-jo~z>dx=: Cɍ;ȭ]ӻnd;dk{ BώmeVӄ|tB GSD)sbKůz@Q"NgQ;jC/G`7i?!YK)f<{8lo v ~-v{̏Ƌf>]Mjqcq`°ҍF zv?  OsK&}A6ڄٯT/'T"ukQPE61б=]&1Ʉf_] ct[kv6\R%Yt;^׉cFXf!Ls.bE Ճ8d@!A)_#AҦ`#jQes)Q'E2i=BӬ'y;8aEApV8,hVf e_q/l<@X*U0 o[8|^AxwCfU%ֹF/k*DWS)5:O  Q6:ZDA֕r^(Gn>:DbTMk}"W 5QQAeȞCJ,@dgL"%' ͵6KNjK2,aUZ`m_AQHUU\L}VjVp0s}a-!n_Y$]%%?ٵM_4lIK 3aԅv?7Blc1@H@`j\o(X#0UwR:oK81̖L^BlmD'z; 8 d@ǔTKEv?dkDQ R5Rְeͯ?a 4$((LHxjŭ'^lm٥[wIH5W`%>URV0ZЯtYL~Dкq$gEEي;1wb:@YI~A~D3x3#0af9M֪Χ4J_]Jty^rwKNÀpk1+Nbxd̷̏ح~Ӛ/Z|Ņ: hhg\}Y!f'P 毓H AQVg2(VT l * 8'ZoZQjp3 ԰;=%P닁C ajQp>v[ΞNïo8PJÏc3ݦ)Ow5nRx7J}0#n ^ \D۰VNWl+:?~޹LaqsMgg _"¬'1{Wg>plH ,jՊp-7>}@/B]v\ $f^D.Ίv<~;eIȶ5T QK4TGu|uK"9'Z7` זԋfUf6bEy{(j#;]|'4Z2JJ{`g" t7|q1lDcAvݸw>w9s6M4н:B׎A}xw uOfzA_E("VZ/;& XKLM$ߣ+Гx2 ]hRF,ӵ^~w:&ػF|Kb4µh}8aDZsgOMJFyua=)Ef[HZSxP^j)`Уl,4b7 ۼl8֗9MxxwmjR0+e$on^Jyd񂺔|z?oA%e'w;ϋ5Uٱ;͘x'Ec߮ՒORIjTf V0J ̕H Eh5t^+-։)ܫf1cz^cc-ϞruvA~'_S={\aD`\G4Vh'Eъ"x'DžVY NP#+PPqe nH&{|:it,4xAW5YOVJj\1C:aKU7i"vW5~짆&D]ش'j}EYlg='8жp?X`QS/ґW](}A2IcbAK:fz`V,|s! 1|*;$UT^IM |~~nA;}4º̪W˚u^n9[N*<hV/ G^,j/N@~@ib.Y9 8EIyv# T. r?OaYA5Oڶ`c3==zCO_mCn-_/nu1 cԖ_7Ișߪ-=ru ~f|+5n y3B'tbnr,nwg!K Yq&bFGDC܆`n j[>G^TQ8Q ӻT:"u;ݷї}%}0JI"h"Z6DRqR,\&G#r+FZ_ߣv֓Y- 0jJ~k$ܝ0 ;cQI\R2QT8~$3 "&UMý5eG5;9Up_4I#@(6p[DjdKoE<;!&D(&B$,៰ X"# @@`IH,툑FFs=> (iGI>_HiH$m|._7u;pZS LiAViv)y~eŕِqcBQ rEj^r9zhGEy&HruD'[qȳl̿ ic$`o—'^mo }+Ga.#d%Z^<11#?A8YP})ɷl%1Hww6H0F8Y+òj8qެVާ1utL?R$A4bD[F"N7#T2܊G!aPg^!zY2C͔-PR/רUλǭ_o:d2 Xrc7E&t/*2f&\ߊ,Ek+1%AL m8,!_(ӳΆXb|wi/ljϦ8mk$4[<'C8ڤ9z&;yՆdw`rm {?|k S~@M0k׊:fa>q,IC٫O iˢnQa[ ۻ`gg>b:cW(LT-2t`f8X#;knӲƃuݎEwc}Öw~q|3DRt&>2p! |_7eʃ>t]km;QE/!kO=l,<ws8L{\7QPfMgb^z# }Z8hrE4C )Wԫ8!L?]o#mWź7!W9ͺ'KGi³E)[(p,O7LY*C"E84<^DBΖiȵ4 u0R6b;m-<>Oecx)D_mܾ<1?.x* s!GޔI ƌ.g?h}p;F7ʕaUk|,+m)AW9^0NBם2(̊[i{lT?]ݫiMgq MQ@Q@FHFg!q*cPxl=_J6Eg]Iֹ?i :umcYiV$6LT0"P5ʓȺ7ݾjTqo OZƸ4@@lm>G!TsʐceQ28ͨ۶W9`|e(dQ(a@Kwzέ_ ^0[=gG!?7gp[>{DTX;oEKׇTYB'D!{3ڥWĿ~)WK1ýj%_Z$bHzfJQ`x@CMqZ؎jB?>;SN_(\ˣ8"A:Oخl0eG8˟dֻIS|aPu\T('>Oz??O9{<5m:lb~8#O4^Ɯ=)0gߗdueEj5俑tk#e1JJPyhf!jI.:ZUL6 A9Emdp'v<XU-\ 1(tQR>nK9{A4/pUX0%KG>y{#uQ W dvBRh.]\s02w22|ty#[8.ӥ (7.2@)v.i*F}WJnlxrYnr}g搝gQQw=:::X34iU/\n[Egخ-ITHTؠa !xBݰ@BBE)R^Ա993qأ3| +wNKHFE()8E/ M֊;7ay'9&Cqָe: 'c혍n\f4S,B+Cƒc 8)yksn6w_LƲ;h3Sf%Ӳb1뭘nF&pm`?.xG<=,znQVy\ҳ "Pkz Sjn3C=AbvllO~V,(mgGT25E0y!:>vH#lUچK P ǔ#y.NC>R^#[o3}vD܎S:[^(^NuХ9buʣ)۟)bJÙ] I'ؑǴ!&|yA.I"ay?%ymۡaiCFD#N9ê i7659& U++Wvn`:=DT,T"TE?#3P>d t3I-LF'r |o%OGK`Kc*Ԋ@(m&Dj9xBU1&<R/me6T,J\nբNB'ЬYC h$z~bH\U} z6EO NU84#@'iT+wO4T -[!q+<7 W&ԓrhd |,SDByݦ, tsgD0gZ\!5s)B7"i> }07.46\fTҰƆ Z1`}f[%B`qvùcTekn^=?\tebV~΃ÂQVRD0Ն~sbw9?7Z|3 ,ɰ`Vhz[1PP./:B`I:Q\1*:A"ß/B͋(Jip. y,˼tM$t2XdKDn?潛f % s$8rArE F"@$fyc6xa.֌g,ܮ?g4Z 'I=YF 5~d>UVtLc=҆44Ņ\cT +qmPg˼.󌗆mҼdw -"8+#^?ހ_Gs??3^>øT{8vXƖQۇ>ƻxɍO`c2BEm*a'Se'Bwwpk 'b3EyTvYqL{^7$:wO1 8"}: D8_N66ɚq@2f$~"Gh^fW~$bE$-+F@St!L*r(-aa }4 U)QK1ny կT"\3N+$}Y|=W\g{{'57|WBeũkE ќΊQٰ*>2l/:<$SB@b<_yTjk m~.i~e)-"V~uu-`u5DPi fhJߓh&io-{Xpÿ5[o~̔O bV`C֕Z`YLt˓D2 @f-:&eΏw32[yhqGWw؏D*y€pB׫oB\B&i{^,ýd3>N80LǖQ CuI<{' hWFh0a9:7M") PЉd<tn[U}'.I$@A)   H1x^!  UKNl>}a91dɒ}׿߫JE{VO 8:YD6VFQPTe7VZiEj.Q?.%u4vY+gwgE%zOٰ}WӌI7Cʼ&[V\ы|NW_ߙ3v7ސ,+G/HA) b7v`[+"U(nbr8(3ny }ād^bTYQݻaDɅUr<c0ْObniQJk z(c*mpÄktGx.oug&Ӌ ZNnߗ`^'> &xI؏:38TKTtAʈd\x#p`&Cqdc. Ӝ4!Z-%D7mP>l2RfdJģ.en1T9a#9߿Gz*j[ t;DoS-ZB0N2y4˙fUջttYq}8 <;W >>$3W7VI #T5-%"xVe},ю+K*P9 ۗkU/(**yf[BuA JmQz? ov=^!-ذu 'x! i{ߥM h/ o{ ۠v @1/Bﲪ}>!֙ޓ;[E NI ZZk%6F!Unۥoo_']rKt+=N\6P4ʱJ@7~'yV4L -XTKVJʞO፽>Nj4`;Ak#lI~D! >pɗyIKOy?J %t^11p țWf+FI@s94K^z֨(uDоÿdMT;$e:N[>JZ رd Rۑh+6t2lj\;C>b_s9y^㚖oy .EaW'q4LԅC~k iFtދsBト o+oZyEJd5m-#Q7"o?sUhɜnMF,y' QdUC4᫣/牰9AptѸwYI|_F7} `Ͼ7aO~hz uׂ@GbiJ'^z쓁=@@=$vOnA`!Pߝ~{/m<';X JRIcilyeqiW<}uΙ?Rb%m(/ݒEe0@hBJYcVhsn傕!L8QA5_Wf/bdv>'L%Gӈ;]Ŝay~?o8HkCy(9uxXW#^KP[N>4 ߽?$$6F~39iG?h^f3dQ2шjQ 9ϕ6֓H 78<oᩮB%1B+z}4acz H)xAqyևuFڇt4YIݣ{dm,T'YK5_RL)_= ;9wg苆X{+,ߡ1-*{Zy/C"6+CWIZR"I,*"=15 m7ƻ B6Y=5N{4fF<#`-^knp6JUFu1u/J>;.ym4.bJ]_BZ DY lEx]x yoՉi i §K!=Q+zmY.DGo7wmxmuVco-B)VÆ?p]MTRL|ДwW6_*z DAA n_rR](#Vߎ|8sr n[ejAC!d;X#!ũWDܓ]WR+L4ltoHXʜ9IKmIvc=7 !q8j덢'mUˆiVQ UeJ+m&<>Qdzi@Jh3u΋iNYjxr2淓1th{;kT)pزpzb1.2%Aa!G-ON|`6+eVhFԥl,06Q[OM7Ll *|- HTa0RbtlێD9Ͷخ@Hpxx$Mn>.lJ,Gv7U;cJh TD ll$a.Z=S C#%MmhJi{!ٶd4M#r]3$ "b%ɒGOPkΎ|swΓ7)g5Dqct. TH5L' WY^+ L3Ck O72<[(p:Nؖ~|PI5n^nKnbrAFk 4Իן~9c cy$-,rN\>bBLfϰeͶ C(W[]JS:Kx w,bCr >$}tȯ 'lzsPqHӒ%rK'&/. V3>;vS*N6wzuq7oLV\XbYk䭓`[=. d$HI:]85(dx:Gb /Խu564E:k詀 T5AU˝"Þ"Lgw4hU@p3*CZ d\]_S+RTی H.Vy7oI/~󿿷G6藷{o#kC~/ :t-<[[`O*zQ'GGky+eVMB]>n3Oñ4uՠ .y*\jUQ_uD?Sv@k쿟G:Q1LV THX"–*5_D4[*N\Xx#]W%4EHv_o;LT}kyrM/պ`jLmJŦ*G#&IHV;ػsŚ~~޷I_qhȬA@N]t/z|<֌t)yc-0 [LzJrjI"s0q-dk  lnE3'۱8E T"!A)xxnA Aڒ@{9p1X໕vV+ywo'JbٲBu^5F;@>/NŒ- i`7͆鼠~ApHIT<XajwTDE:VesaO漸0Esz?7TϏ9YV\"Hb$e IZmy~^V|i׆G)ݻSdz|j"ǟO9|>%jl **%/!>:Fޔ~{C^s !H!jv}+β௦g$׿C"+fs)`A*5tX!^Gy m~``tMK6K$'2 dk=‘ͩr7!_Az}c;ù]4 }R+3{Ň/U(=JE w[Ի(zsbRC"\]ah_fǐ@=y9 qu|q43pv UBR H%IIL[,NTػ9s~Gx-#- [8%vU]@!Q֙><YlllAi6{]3l͊'==AK&B9do$KEnťSBeHשxJp(6jSh[68n3x}YdՁ G2hEVܳC@%Tw{/4XCVl͍| l6VY:eWTy%Apk+Eu,>5.f *q:Ȳ_(0Re%Jͻڈ @M3P`403Q֙(K9RRj&ˈa!p/V|~%8_DS#;-$D%w6tݶǃM.)WeEAilK-u2lq˃>yzEk<գ5׼^f՛e/Vqe`9)IY)UXֿTiҵlnU;UUWNb;+ذbņG)x ^H@,L{--QZ{O?߯}DOl8Hr6m vlyɠϑtқV4[/dRXnoEռ`F&),{EϮPz%iimVejC*b%;DO"Mj$jo" wbU~,LnQ,R)ePrˊnH¹(#ߝ]h#DӬ#-,-otw(!z?oE>ӠuSo=s-)7K1u ֘8$9T5zo4>K8]dY$EI0䋣]"]>5 #x+"^x#f8' &:{; &F3 %YEP/~Ō6.^%n9 ,˒:2HN(Eϗ8\dd]GZpU L[g2lwϛ dAߜ 5=K|`lM_@w~.~Qp}z#aP U\k[g8xsn-[*{_*Az"m<+,V>g`]z3qNjĀYl"Z"ctL@-}wak+d<˿yVpYR2 ?<9!%ВqdnWQ?\t/R'wy>؋"-$*#8d%Zyt}0 >bZj+ͧ5ޠY9GQ;M:rk"#nEn}Hۤ$wZ9YloE?3;4ITmJ* P!@ T $Ifn?w${{}nYjQPW*9Ҁ۫."p%MP=ߺ X ǑhJH ۦj Z3.Y CA/pٴZp˚Ղ{׋g]jFd%벦\Dac! "*~YoW <peyq%xF! J.o 'W!OzMq= !Glh%iXVQRƢC& !z~ ̢O}PaZG1ǷS/Ag3raы4V+@n(9?C\)g4So9zMXf$K6n܅Zk!u%'mf!$I@ {Gxݠz=b !M/3:SF%/.xRwzS1qQ fc*cd%]"`(Sn]W ^%(WP n)~$})wt]NJrc(j bJ9&QeW1 <.9'WKc{/PÛeA Ӭ$g7kBbr>p~Og}.I^h+{=+6$˱r6|䀋i1;eui5˜u(a`}tpPdn R! =|)㫦ip _l[oGك6N@@ڪ_^J-mPV Aqa3ӋuԽږ7a(rw@b*"Kox8EJYBH"X97'Ȁ~fg XR(bV2R;%DM}F+VZl^i2ļN䗧o-Pъ9hی'fYnFSKId^(c L ]6J3믃yEHJ0C v)-VZۥg |4vob $bgn]G5[NR* _Q*eoݣ9|z*ZCm1B*6*{$[k輤)& 6S,NR;{a;t+_o-g.8Ppd)5\MI z ώZcqC饋; ^n%d<}FK9E&_5(iC6qbJCqQ,W=ac*hu>GO+pBcF9W'F|xNz-fǏٽ9PwHfHE /6R. /*BЍ%oTa{YųHIH脒;u5 |AQ )1ӧc9AThS9t o/xV.ǻkV?WLk~Uz|ߏ{W+z9m &.<2ՊjY@ )}Cal,ؼ;F/<yԂ&ofKRRN1eJC,m5iI)RܛDs!M}gDz13o/j@1R>+g|.?%Z3`(0B(rv !!tr7CJF}.o G9G9@xt为omԴ* zT׺*p X'U~|aY;vd6J i(jֳ"exi~8:`6zL5Ašʢ#Vm! d0X۱8y<"xDW @ Gך d&X1=%1eL"\kYJQ_f[Hڽ2lrkm-ڋ,]e4:%;uQ X > H %L5*x[") 7o^G#s+_'9DS4>fl-712X{R RX *qܞ$4}Ye(}0 8nyeX68~)N(0~dnF!$KM-)P֞ $@Z"vEqaHIIt@ --5B*ߞ^s3kdQ4m`[ѬtЕ`6!]XWXWG@hW5G{$?Xh`W &yG m G]G1_%|{sujrQ!͙I1 ^ȍaA<`w=#}MGyA] 8X`*躒fO C=5-q<Bwl&++SC)x8aQScyyc;rP?!b@,V D`|;"nK ڗ6aWܾue0~Lphp_{p9}xC j GH9DzLPP%U^3}EW P#knp#o%b2/ۃ緶.yZ&ݘNng<0?tۍypm[Hs5 j6a$MAՏ_?T罖tytN#Vs}/dSDyIn fzbgK[cg]][X]>%ܻ)[;?$ tAdҩ*(:JTH'2#^UnR -a'd6J - rc $ 6[ ժD%{N.{Q?f5Y:2֘(tKQ/+aDQǰUCI|?h8YҾѡ=er8g7gְJR4+Y_s _}{QD1D)V`y_R!{C!~g5=&£*F/^# \(Z cw2X왊25RXZ!ڃ<飥$bf!˺ O Sg>U򊣻|MSlB~*q4a<{uPd 4@.w}kYl*xWxHM>}9WGbg6;Q6- A]6߅Z{X8vUEZ ? _A :팠t21d{}f ԭUn 9Q k~^ǘ#WΘ@> 4̅u|^q l+VJ$YMf!_GCŬgraxZs Z޿ޡ( 7y|sfQ%/Q?dюA9JP1-J6'W,td#nypGKB展t』-nf',?&5˕0/_@xdIoEZzŞqqDFD@N (q6'NLfz.ݞnMw}-j۸i}Wp,1Ik*w4E7֝:/{(P]5u7Sinʉږ֫\IS*I8VDB0J||DK[ iiIҒSNNb&^/Up4M(+gUl9!8H ߦ| An.381`rt5~?xKE~ r\R!MLgԹ.jTb~uKp.j{en!"MՐD\?Y@ʦ x^' :\d^Vp/|kV@ 6KӤf0xw_qn[ݒR:fr|r8br|z(_lݧY- [sZb6u S CtzB'(J)+>Bd ˟GߠE)UA1UH#uO*hw0A!g`s}~N9ڴ.61m_))H~|7g9oNr076C0I搢۞C='ߟPY^fo,\AX Pܛ瓲(^ݻ*PaU+ϓJS&L<܎}TXh+dv(Px5e?kۮ5ϳ~;h87 o|eh)B 괠 1o.1g'>I`a.{i iF2$deiN%"֊H9s/"WφIK>XeA9U0@+u G"- .>o(ZCSL_yu*Mu/N ]S=-Ymz𖱖@InՂ̸7Mg.x}:rwӜZ?EۙQ={ƿ\YoD34AhZV$P>4@B !%DiIIv>ÌVZkeYqNo}j5aZ36, RzO#e` bC[(I@V5U$]eKkz>~F|%샃1Sn K)ʖYx5"O4ڐ_^*)Eݱ5} !|E7?qb,___c./qgkKd3Μ_F:bo@8Gvuն7u jj@h.8r4¶@` $!qDKS{1۝}U)ii< Fkiڍeӷ B 7_$&5me. 7-yxR]UDYM;R[t?/ [cigLUC|U:%R.(dMZ0^U87<bWӓjoJOst*(DehZ֋>:x} m6ElggHq+D}I=xJXlB!N? f tlGo Dr"!(lA#8$܏Ggy5~t_;8Sjcp"xd 侇?w%`?B 덑Ra P޷GWPޢ,} n|M3i:_9Aҷq]t>lCH튁n:4@H{Lӎh8DcT̕[v} @Q{yxth׮%)/vNXnz2,$..4g O7l|~?O~M! |[>91g!Y`eSw3a[9n~nC)AQu|Y]@6 8[$.$T5W+Ƀ4tQUOsC\ I3blo\˒D?Iݺx$F5-a"ѭf}_uv5Gg߰J=G\.6f6 [7dS^sP+㌑ GӤ3ԑ(ι*k-*Jy{[0I9ɸZV4fE~ {knO)͛?@5~ <ϸ(*4 Yg E(}/_!(OHLb2n.V8M~V5XK/ $6 mסg1ܶ҄#AR7%rYHdw.Q'Ur@,k3\:>AQU*R&ދ8gB:o}F" qj 0o4  TvAS2j3D#>-Q@DxJsY(Jm'O=ZHH5ԭei'/Io_ܾEa|;MϦت,U mQ ]c p*C֎ <׃s]/]P[. ؕ킃g8.Q7~O-ykɄu`5C]?z"SN Gܵ r`xh7ur| nLcrXtiK AxqQ4P0/+b5dEeZYkKUƘ"¤&)K< !E愋)ًؕei$}zg]#DLw}2w|&PC Kno|h_myi|ڨVQp274P}|#٬r 5EVaBM׎FX7FY7PIHʹ&<=Dz/N [J1ӞOLbM!|u2uB{뗤GQZ*Zu9P^Pyu^(gz.yI).^|0Iw0,ьw(Q]^o@*AP:?@!M\~HHIU[D8@MSG Nٔs<*6#ؚDoaFu@baBeaYc>ߦE)w,&h!jyْqINj%븨iyqYA䴽}ӍsO`O fdP=ML#3껍d"{ W|=j`\.84 & $gqiYTr|16X&15+T0X ^go@iCÇ~H4 @AEHznǾn]W-oFw&ktE@otɄٵ$nDEZ^@WF]Qaӭ={k :*P޼-0ܩ9onЧ.-bFdhP37u$GQ*Ed\l'mĻ,«Ȯؼ$PG~ c@Jjk)7ix5 R#GlSӤ1rk "R`9Ք)sLaD@zts[7Х/Y]18" =Rϧ|w D0OPE|Fms l\DShJQ7= ޓ^_Fwc{e>$])E$U۪Ʋ,\q1 gkYiu7ˆS &㔻K1aRbj =$%:=@E!zɸqrk")XԊ*'vPS[ m8[s/b<-uM|Z)UIs?sQcKshjGd;|(Co'YWb Ww Ub߀jEo7Co {J޷MsxtbqQH6mD]B"?(ӫlƾؙ"9{d IDAT;:"6sr dMtsy8< C7[ k];^w{Bt\ͪhgiLq}K,EuE64Cm7{Y4ш e 3d9D APRNN=11h/RiM4 O$hD4`4D㗳[~)ܜ}rEܕ =`n.<;KCØe^p2Qk=')Q=E$t}zt0fU)ØyDd]Sk( <8z.7@x,Axu1P  dO $wͧ3gW_1smgvf_vu8?_ȟ B*hĉ~{f8̮fO>z6H|lYJqel;|M|Qcq迼_ӸAՊ$E+JMU4dvŕ!yF>iPEِj^.yvpjF e%zp((ə.}24gXJ B Ӽ潝cY6hë4J OJ_$fw]Tw)2|'|yv Bq Gs;dGQaA C

Ad6>Zĺ#/N#鄅u"ި;~Xc d Qhk^5$>'N5Pk'rX EzC;%m JuސL+AG!ۂݖnߵ# EF( D Po%ں6ǻ&%O F Idegq&YnR@Q3= }5Y:PTcԈ BECZ8wtPg%=j;o z-eeX6vk794Vwj}>(x|9Љs z65݃:WBa!PNړnLo}Z Ʀ;i6[n) NJƥz S %i!%~~L1[axlk,td *6s YcX^Oػ8_kiA4"<`ZT!xXW*7FHH.[d~MSzm9/Zh ydQrD<rīo^yl9Yb%Gm,l N3wBvc"y.Kޤ9Ø.㳧ܤPr\|~6yY,ؗHO0*m)C] sGX> C!i, 5(tY?dˎD?We3sI2 A!׈DH,` ,X^<O (DI4$CLt^bQ%|s t^*Y·k[x~\^u'UEjQg dU3Dlbz]ko4nbKvwTf3܊S86β([75zYѐ*Ig,_ݛ?JȔ$S!HreEe,GaJ'H!I:"~:Zp CvT( fEl⊟ZU4/Kzwu+?<"QGs|* J 9Ge!pG;y~("\V\F!A0:#o HRԏK'ʩD`n奋EYӱ? $EϞR-rRw0vY ?W/l47/iR X`m5B/&a$>K.ٶH`D'% -)JNG|t֛q?6tƁ=[ű/O"QփB;YؗkKM{+5ڮRI$,+or O᭹aσsnH\j!sԫ\#.ή\e!E^q5sr@]$;΂[!Q#S s~Dc0.(8_gƶhQ^t@9+셋A^I[.tJW"=M}NɿǴ'/hO#ݩh' "o;RRdΡw.#g/|qx|^QraS~?ZIA ~yt1!UVJ(O޾2aw7/o588Ap|^ހeͬk:m?}$ĽddImJF*lTv$)G;Xaun˂@tnF)RdKR;N#A u=\j}>EoEOE  lYRD 9= ))lU^xǾ֜r5ajrrzø%ft>WbE\yax! [\3u>76xϘ x;Nk ǧ9Dxy`L$nw9s"βcZD]slF`/p5|rUZqc!<c's~O3b:epɓG'r4<ߵyiQg(һwLjS5MRR+_}37PIU Ի zw074N q{]f>4AM=q8 KJawǷ-}*Ԋ\0 kgZA_s~KڊQp22ήobIU/GQ˅6 myI6nؾ,%&SWjB#ܫGXހqnċi,_^xxY M a&5Q( Vѷp~HOd/{6ao_ :WC()P1]#İ-LUMbȫO&,[Uw޽XY. ,gIu@+lZZ?no7nJT7YQ׍Ocz#_b)юQFZ-@Z-8hJ-cוBR X~{+.1qCxce"&(ZQ2ؾNZtnY$gevD>N'rB9e/52/RLNO^/*젃t1s{{N5Z(޹򷏱6wgԋ>*:ahJﯹz38g\<<[O2Q1Fy6}݈ۃ<;Bf@׹À1<8#.Ʒ-~}yE w&2Ղ`;3)??=绻;cM!vDi7}9as؞CUJyB1dnU}=Nu[*"$$*nynxEny.*wJI'=Þ=\I~G^k߯//®iF~P1}=ٯ{{.%z?\u O3v_.s(3&4Rr]LhJ^Y^Yьy ےơ1J @HZBKǼA A6\5^~KiB<;=a{gNu] B}hN@I+Byx-w.v԰">Jt0ab0t0F(h"Ѭ4{[S;D"Cc0k11ābSuR$l[r|ABZJ+~z-QIuC/Tng$hz7G&x82H9G '17M4 j8wZӄG{oNR);g,D`̮n=Im<:)*UBdYDr3f%dG $??bRH !QI&݋ K?,e|w*a]l;,f|7l0it_k, [EӮuѠ!cU $ d{pkws~zxDiZbُmJTJiFސ^3ec6qR*~pTϲф`z}緷k&? 7dKeofWXHN>EN*.N =Rh4iY7/I[UnX84{ϼĹӔOy<6^2-Y8u_R qQJŚP$f2-(a`=yR#TEW)^h;qNoR 4"!9Ӹs9y?HX^F($:+ ?@y27r\e{~{WϢ3 RKP'703KؠZV _/KpY5R ^F-j߷N?fhYu%8XJN ^Чѵ & (+A.@y~IbIQۻGزdgt.ޗQޖ5̓B"4) #6EGdE78o M"9>70l HNTuW*\Ӫnnsײ/25yc0xpꐲQTpuH^EskA۾x,dt{ = omR<5i ww$' U^)Vx}S3ݻ^We Lr2KQq +J*$`,{+ R״Z+6#&R`UoDZС":.[\^eƶmt0}Ny)Kqi&>q?i(ޤ?G\[g<|= rWH$q *Ja8A`e;|)j'mHS9\)Ef 4ؾD\X**=StPsL+9 EdyL aԽ=:&&aU #hewG WaKb#4陃c$#0j e53|]pz/ ]E?ߵ>yv{vm t~]mߩ:<UR1v5fr`;(.+Ǝu a '|mAu pl{yQ6;Њ:"R*hE49onjwQ2R,Lw)FPP+&.^P_Ǜ֦$9My<ۄ^d>}6{W {m0Ejn>_Q<>kbinNb{ jPU a$m6(w5NRtps`n V f:T߳~*_bdˎEtL$$,Hlx^  VQB4\|תbQm@ZEoJ9?GK)-ވG %<< 0E8gm=(qXXJ8HHZ j)A!R]p#@HIUhI׌wZU-J MB5 8N( 7v:,HA"+>ۋi:rc-g9}K9hfTɎDU.o&CH&ː%&HHHx^g!xDq Q$LO/n/U.e''KV[[ cBy<%7C&v5:R#rk}L_H&!Ys5 -tjk[ wxU?T )4lU SY^/G}(tY ]YiI^~ wN84PN~Nps#abD"K9թEnЌcɪHB<+X{ P%zW/Qlz? afCdZ۹YiG[*mcS(2*kA) TY0NVX` e+awkݶi0^(j;!&ǯ8) %D}gЗڶccbD]V,EY9AI6DgeT&fܲ(+V2 $#=@=a[ ʶLv/Xc~+lJMXZB%_G>9~R.A|Mһ(I@hAI PQ.A w OUuPQ AC&/1kW1k[]aBz8xE3 GL7PY=znp%/5R?WE䦪8ʦn,HӔ vcoG6\ p^Tˢhd#xZjW.{b_lyN?YߏW|y_*¤ cg.;)lKoEFOw==; D D@‚+$ďe`(H$0qw,{< j5{wB67}k TԽ/AJ<' Q'G/dFBD/Fx!ˆ&"l5)S>[kG74!fo QHq:AI-Zgb4r AƈwoP 7=+N:ÓA=CnxvkyDi\7ڐMخ8R_0wE(ZiKgU vnZ-$0umR!jj%'KTV'!фzVһ8o/~ص ]'VIY$SJ@Dx6o`ׯ34?_%)4'T Jʢ!l) cZSq.׹BsBgc[vB0<z:*Mc RY$Exl} ) $J0 oI?\w6cJ!nR:W5u=+X> =EEN|e PC+.L7oc>[T.^I" ^'b>YŽ1eM/9tz!Z[*wp?[5 ֎]Qs^y}8j&sqr d<|1̸2ލu&HI'!ɢ qTj yf|LS+{ԙ.lKD{Υ'=IOTPZ@@@BE]/,ٰBbaTĂRU!XPUi{z==if1$F&^YN=, 2.2Tnl_W+H%XhjSHQ'Ѝ乆AX645,+=< cVa4);'Q|S&ā c<)ȗS?Fl+͜wߪvRAucGӦJ*FIeE$n=+1uFp GJVpr{(ՎTm "nuq2/KM8C`SW7A^YQ3 iD) (`? l^^ g&>^)^C4PӤ F(솈PQ*+Ѭ *($zm$-\;\ڃVZY?65f](Q60nG $vm5,=5yaiCDvJ~5˛wcۢ/>';=bJw#zg" Ϫo:=dZH1B{omouF@ڵo;De$/m00oDË{,NɎyd_fkA(W|VN MۢN5R=e{-g3ӸSmw)U$/5uRsw#=>deQEQEz-XIHߣ+TG0<8N;)yVڱwۢݤ{c݀@62T2g'R:%W#{.y0\;2 %P8?KUe,}P LӐg'G:U\[oE٣vM^!$?[~@Ԗ VIK8>YRYvWBn^;Ο1Z!&!6Ej0]s< laŲN z3>@'2 jH= r2ԥ Yi)F}ߙQ[*@^x3^໓CN~69?=QLP4BP|FIwscV>3%.+c<91jp*~뗐ˮVDw?FDIg4jx;\iu8A{4P9Jf4jEcL(,侥DwT/bNXkDG-K5d޲r&+ ;\j^p9I8>II(yfZ~ly1ϑn'5+ 9yF\ #Er>] ,ASCXCĿS>ohXBX]P+ʩO!=|ްq$/ktH,RepC*[4u/2>@Џu{24ERw^[ׄiJY76C J69雽Eݚ; Nhi=ʍUmc^mԤckơ豝;[/9 Md,ɕQ?qn->J{.zw0,f?aU~u@һN\>gN ̲ !ք%:j9blaŹG[-^ RlUv$?IKg 40! Q:S8슰LLS˕kJاXtŞ{'P!XT{vo Wt^ R8٭]}tV2JFٍkcc4&D$ⅈ9r`grͭ3ad_֘.PM(%y%bZno?n煍3lK[]Ar LcjmvuUU$gxt]ݺ匋%XF zy޴n*Y!]f Q'uxɌW%首a@>>zxɃ#/wыC.c4+9dqqVy39[(4k`ĉD{K0/9Y}dkA2i'MpDL=hA,F#\І7yp9 U=oO-:qlɎT?z(k9$,{ly^@H`N'!P5.^vWGX*UIZTsVn yVݲLkg@,5rs0؉|0G;%d5~` ?PWBjOR /1UXҳ vj)iJ,"qH{|<7:\?0\S\{o|>>o?o>zt;u6TaNG[&._Qs䆩Ǎv(%oW9vͯZ CM. 8 k8a-sܸ PA-2q B0D,0=Gy`%Od8X.{kk++DB4Ʌ4;&B?e0.U- tn )N◚z/sNXfp0V}zK`,'=/630OKB8pr$m #~Iox;b]7fLx=hi ,*Q+@vY06Ä,e;lM^C3ba8k},P څ@jOJ5Sǐ!bs-rx'^RR 9"RYMFQ˽ Rz^zqq` j`9tVU:5>-.kGXJ@cG03aq^n4.V(ZJFM`͒ZT]PxkH}tмB (c=k$3O*|¼Z7KvУKCI8_RmKd& fD6{h1L~Ce8[<뼍gE$Zj|ѢjOc/)!e*qc;w=и/pwStvG*/-(*}1mTd$g6IF6{DJɒlY+G0|Yt^YݽWɅka{w.QQoVMhQkc  51A&~(kloeI+}v7QW(&۵,o[ ky7} U MKN>i`? R[SMk%o.=zF #?p` $4+.ym8o\_cH*G{(p>-|O'ovʤМ T()|+pwHfV ijPqr9#R7،=WVw_=$B[pXJ=o#F O@i- cZQ_MKzli\oU>Ďcb%<4$ 4*(hS(hihh(! @1;;{/ŝ[lsBx6e ]LWd.KqTcx_*@p4\tn!gea{Gts5b/6%DZJADmтq\opI E=QV_-\ǟ]P&{m׌ wm 5z 9$L (\W}T}w\9iف$Z7ZA)ir]TI _XiLW;k-/F$xM|U'߻<4Wa5=+|dhT <$K >9Zkwپ"|,MiZY ǩlD5mKMY:guRPC@)j }"頻֕UDر1 A7edVRPS,Yyыf+I3) C7Ej}j_LӴ,a5jE a~>&6Տɏ:y`I,̥ciAI$%[_8ygI sK3.>DioN V3磥gTBY!<HڨfrְIsK:WCtk"~@f#W{LqΚ(hб-L1̈UG}x}(Mի;U* Y5ΩZI  >7t+~|rćs}l>&I ,i4 R\/JUU.;0eUfLOSMY->x\p<+pmwJ _ -K7h|t981E2xЭ*v?dݎE陝pVXD&ƟsUx\77'D'0®첻3=3[TwϪ}sP]5_}Bt>*Z?[M=t[PiiͰmI)]BO|swiFUU, Ѭ<-AB(P&u\x1Yf%Ovyz9eSE}}KM8E7ԴyƵ+7u8o6-6ٝt=I3|\s{o6kÝ_piIT֤flOSzͥ}ټ@ﱿPۼ|&K 7FxҿnS-TE2QeK7(~CX*e0kşdEj*Ѳ@%tN63esuYe,^.:y962UmO4,KfK7-SJmZ7E-^ӂy h7U ]+ЧRGcZv"4inB)\*P\Jz<3Rm"@C%zgOSicTcֈ2<,1*W42.iؗrHp; B/g$1@pUfwli{1v"Qzڰ_RfeRHI;x6rd=0Je}'<c)Z,0ZB㚋el [/quȮJi;Sڇ|v b.yM҃<Llng< ;I攵=NU+}۴5[`YU%WCp\U-5o7HGCuŢhU)&]~@S&.̗}( Eɩkn5_Uh$9Т:2f\=uޯaKkK zba6$CEz@F}8sqa~Бp,s27j@Lg/h_k|lƁ[%aГ<=H8w%uaG+9IpE4 C8"HR<#+U{aqkӯѿv%P1Xֺ2ຓlKDˏ~=kBĄ!6ElX! L`2Ӯ͢$β,uǔJ͓-pRHsS!YQeO;xfyw$5éS$_ *&s-FUq`nSrT*q65$qVISN8P%<YjZ 405|}{e^`d lu".u#Oo\rL˒WvsßS޾05ROIJXO޾JqͧR5`NS)=y "ڽE'ٷn/t ֐fH}( Naa RkT;A9@ɜt8^pߋA53.ls:BؙYK! 8uWjy1e|qRRnJe@< t3g?=DdP|Ws^nj&ﮢ[ϜZ^wVژ~7' W:yA^tI8Xا._cǰz2??_o\D=k9;VHb%>'R@ |OPe-v2Bo0k--<3uB"/JkKvxhO{:ώNseUEVaPcnRPYXW#0*K+ڔ87ڃ>6:1', >r҉% v뎲)L>F' f8$I[؂Yx$e<˫qڋ½YW#4*= A0g Z7|wk;*N_4s[G&ϭ _3p)$TB*HTIGuݝ0k;ylh?eLU=T0D4~R~rpMRf%jÃtH#R g9W6jyYo|"І# )R tZbb']BXst!CE 6bsn3j l|~' VWxd锇s>?q>Ӊ#nm#W]yLw-$%׻ >yu K"?z 1͈>&b3Tk(f'k_N?<#;9[ZLzx@>Kh # Pj Z#ȭAPkݦmcM dT1r(2M$>Dr'A̖OIlUDO\ vqk,aGUpq%KHPq&խM Yݎ2W7U ƹ]ۊ0q^K&h.nD{%3')~7r-*٣{ArY0 W$z g xJQ&S}ѐ@!}շȇd7}*ڹgS6kPiT-ĐvoQIy֒!FT9!ّYRgI5ȵlaik>z 8 &]dRpztZwpcQAm_/{^n]Xk9>w8u/Ʋt% Vա'4B+:O *-<R$ܬ/%`ޑ14j8dzgKtE@竃r^*@z7PeqtԭW,L^ɫ@,cY2OP$2ɨ^ &"Gާ7)]o&;m*FDFŰ(s>!R *jp7>$SS c)Kciw(Xu JcʤL#|G?;DJE>Lsf-Sg1TtF<s]]DNujV!j 8^R5\ Ei~k*[SB[<:[a 8d{}8[PB6eR-ȴDewZR{Sk>9ѪJÍ"&3g=F9j/Y(d^r;5IYv'#ru6څ>iQx/bsʀǗ>dJG޹z? ΌX68el. ]8ƆkT#m.-q}i"H3.,*v7߳ﶆLqks*8Cs]_Lv!Z TI27gS|2pqZӝ}}77Awcl8iI.JlG"v= pay-LURͦt OZ.SiFNlpt Du= lʦ(zJY >,Lsq#:bg87lb7(+ Yg}ɠPu{K^ELW,|!XlӮG{ ӽ1yִ| m6FH_GܿA!V7/SbT\ĉSWUp$.5:Q^qZŹ*ж @ FO)!G8Rv 7cpeQ9̻ 6t }Ev:,7Ay/j)XW*O } w‚Й͛ zjO' S56 pL!27,zd̍qR˶I$'gLN7 ?mh5HY>4{נ=hflk-La9shnTi1G FCh̎9Zb mEsM59i4Ϣ<-pi,Ye^mMzc^kTI WmP`ڧc?DkゕշC2fXED>|@ϟ"7XʍWىSz 5.c9 !@># g9{qhgBv߆[k`!,K]YQW(WaaB?`ЖX&x.,<NHk@W䕙8HsJK|w颧UiduY4( TnT?oowbidrKߗOc|iAU8J1 lDVb犻[ 0BdSM_A˂ ѱw~8qX~@YauۑT}?0JCUڀ ϭОBPD *-|-|K|xB%2PuqeZ9Nkg?FEu3M9Y$/lTjIm v[t7:ɪ7#-!iA}ܾQ$ZĜ)#Ec4s*͋MCdS$A^ $H2fF rr}m-:^P̞7wB6pkᯣ1CJV%4 L3uO<gXG)*q/~D>Fm6![d( ]K7uAS]@Y/[- PXXBf|A'8l߼%i1s6*jzdU X-qӒԴrُ΢5kE]wLz*]D Gdf۱Z6Vhgfbc4n-#~yD𪿡*97}SxKUM3aLbujBN/X*o$96tdj0.6;WINIO"TМ Y-@%>&Q-aAVmf)??:b0&?yN1 pJ<%Ӛ*ˊ< |seYh?%bW[X<>Zp2eg櫽`cMPIBxRp)mO:7x3}2fH̒y]^׬к]\q1j]dܿr϶6. Mo`Wp/x_HY0ekEA5_ ĴxDo!l"J\[oE=ykv'J _ !\qAi q,=4i$vl=,]Z_|JW?t@tSjjAHAKti#{Dv]W (G\͟;T)b/vГNRc L:{isD:\VWY^'2 F(׎}=R!CtN0^G61 n<%,p-UnpijOB:+PjcYXBu,RTC|nÇK#25p_ \ 5W k"윳5$r;Nh`!;"$qr:mxw\,f6 Tz,l&xA:ﻁX;|uhms=\oNח{熾0Wf8#EwA*Dk!n_xMs M24vcqu/a>w~3hdބߔ]]Sap7`u\T6 G]= nQL_qǟ݈j{6EElw4Uڜz:^^\`MGkX"5dMD+B1>U‰<Ô E8M@Ipkͼ7Sa "I Gzjl͗jíkp[3:dph ,~zsjq0:$BHA8(t>a6˳Ν9ᨇo &H@TyF~~N+W"?Q~:~^Qo(S ޗ,+V'gKQ@ϓOp|AŹ<%;}ik= 'S!rpq=OA'/MbRhbU>:qq qn*S+AX)PwU)`;M0wļO}yt!] B 9xA7ZUmndrYst*.jC~hKAR+TZ7VZ][W4:!5]1DZS kț҂pAe6ϣnD,Yн.N*\%v7 X'&5腒|ATsuW\oU ==eu-w-u` t| Gk@ݮZ-6}!Cul8IB7pLK.+[g4I T=2UE^/ܿcZtPPQ1_)=m5#Z]2dIw9;m6# C~P$~ѓR{8stKoEzttό3qbX !%lYE E"! c=QU͢{ jӫ^CU-"$H$?) I"aWrW8 D$/9o*笫B)$"DR$#IxStM휃aL/N|o/|6~s,ŽQ)aŃq_'3֐v3 8tˊ9綯Jq(・[@!6?{0vByy=|Bq!J&%$RT9˓sO 4*x˦' E  d)BJ:#O7Y I=t'tR+ W[7_t+,& ίV0SA& qMQDo"MgmtE2)$=e*2>o{JqZ<s6"8wp²DJi-S_У|![wfDo('G5Al 2%,+U\U}pv6]:D)Dnkfhɀԭ%h)G\BNՍܹ S*$6Q YfU tf-PlgJ][B[}@Y/m3|7[ woԍvV78j6A/Dut "CwYWg3d T3}5O⭀}p@rg#'S(pSÈ>.&)NPɨ67>Ȉ)heYM[a+'pt! \gbaXzz 5_ćWHuVI͹\<8>uIxͅZͧ;DZRn|p(*q t#27LNU:u8+й寫N(*)Hsog#XOB~8%?lISTd]oTNҦmhFM0@ڦ"MpsKq $Ml.ڦq7.W$}9R heڹFq@9~@ >Z[|_"ca8JQRS T ֮ 5xVP :] I/be2DIK7НM1*I-.k|Z!<5 =±uͥ!Au:$՟BbrW.\6D]D8Q'N8;';脰GZ$JYt0R _)L@<"sDZ!q JSiS+UH\ECC:}ryQPg5E&:IädiXbO.v:?O?:C&_[1`|(|@ApYJs!-ӈXxmtEH߃p'O wsS hIp6oנ:6׋U,_VީJ[39y07hxK[Z:Tߎ߭6~}2zw[w_k4)ۼ~+, ㈌I:~c=EEM|X'?7;4:ShuNUNMҤCfy] ]T=]4;٬]g9" غs?`ȏ/X_OFC lZn= hHZCǗt̟PYiȤa] aל-jz McF79{A-(xݽ9iyfΫY |yx|xI%$secceû1n>&$ސ3Hߺ],)&stEM1i3Bf0ffYXK8Ob 25B@ g\&YrXP#-Q/ulՎjmx::NQ Fw~'H'KE0ѿÇ(Su~l2iƒQ ”ZLgȻ-NPZҸN%HO f&u=}?BqRbnY c3 5D8,LXw$;DaXF`H-QUVum-=<{.y%mtUhĦ2V_Mpˀ^8V p H3!j5Xtͬ0=Ea + W+W|ڼViZNpؚ2ց6*E`a Pi`gp%O{_i=| >%UX)[g"qu!ԦjP^dg.~%C+m!3)8%,z;{EߦcFE[M:%q,L($HM8/ h^ , OgfeK%2sW9O'tw4// [W0X֊8.2nәL}ACXa&&\]oD6M&*\p ρQ@ +ڀmlkfc9뗫N?YEfH5IQc0茦k06y^V:HEVZXrY^g^.+2f',H_wWiM,XYE>>J,j@rp2+c2d%R-|2M#Yvx;}D1Ns~>s0K9z|'ľ$UX~%j_uuD:3YGCos7WM@]lg˜*^k1'ht-\KTq846>PP J,X VlX| CTJ;tZ 3i2?mN2NtseF 08֨@mYjv<ҼD;Ԫ(2^;lݘQ( @yܡꪦ7E' xΌBKnN"7ѳS l g{xRi&:' ~r,3'|:8bg9ݺH9:bդC *&97>Π(g@(ǭ;TKN^QM5* ~-8F9A ԕ ǐ P]!ePܚjfo,z qML@GQ,TQ'+ۘf:\r2;ۈle@@F*ۨʖ *`A8b$̥?U[H5tN7=WfkhRqY1qhØ߸㗨|uE5J ݤ%aVrWCs&ڝ;e3"zwXl 1#pds_ tPOAiP 酘(q,NQWl=T`+V^n m@jLvq\J yɼeX5xvRӦ4^,m!o!_m#Au0ER$xmAϭboiqr$ PH[F[@nsU[vvE]:{]%:3|".0mqAFU8ip@CY^4Ϗ>@jE:kbBÕЁG:KX9;\] {,_-V7@5{=<,߬3} 3惻iH+_pEkgR."P?h[]\הRi^Z sl5F;)?us\]pd{ZrMȏ68b5,7z ;]YNssGw/UJI6iEj*cileiQPc]ÃÄE`㲨q KEog 6Ԏ8u筀a4=NMA5#ԎEf{-s~{rIVZNߦ~A nJ33~gG z20ObN"%x9>pTs $)1+<"m #c .?åK!E)8) l;*te?Fn2\Um->gp$ M{^_HdV2t]p.[LK > }WkcϞP{>>ĥkP !5|L1e;)`Vt<%A*)Թ^- ʅ2*m~ͬ~iUmX5{MHZ\Wv~29?R9wTA2"'+V)u_F[O@i pD` 4B X"V\ 9jKW4,QO:S*YZmR6u@@H ΃o*Vq[ mscg|4U+3 Oܶ |ޥnxw]P>@@]Aw^_] _fG+r||\nx.^sܶK+b|v)–h1R]oS]o\ꮲG?'ZSʚp:~j]st~0``^rdA2 [3:oqĝ-SM5bP,ZNDMXdպ'1X^ $yp^{x;@NrkEٲyeV1sJ iYs{$ۏ&mG)F|~4])̀^EAHKZa0ԼgZ2ڋX.rIÏg%!=Mź! m= )-/%wHLAlMoE;ul() U|>#.p EE"ъ&jIĎ}ٙ0l<%tHVGkm<9YfX)=a]ޟ@ ᳍n蜣iLM&J$Zq1'pxbY*h4IE98^ŒYN ^klk>T˼"OrVe$7D_6ʽZ'ŪɒÓ2g9E")<H#SE$圽)qu$I1}młiý?/p:߰8brq!X14):xs緱[W1i8)0׆Qd "Q7؟kc6{D&}Ol*PzD]T^~kmR;Go uF%% 6N)38 zz-\![R!f65*5t>~)KT%vqm4dJ/(R{ܥ ا pP$kێAQ%w x. rŧi,AQ'u>b?1lS-gsC_3^ Ӣl8^23Cj.ND@(򆨕@4AJ%EY@4y9Ш[gb7 Ac9v6AϾ]w.mP1L2{Wx{q05ECc6<ڒD~ĵKwGyEeRil 4ckҏiӓlb*–\|{k]3-n4^̧7F(x7*{~r7HE)yH a;lˎE۷xbe &A Xx AD!h&cnwWuEe˶RUz\,p%Np@5)ӫ5׺  PIfa'&iyX,Aج]>@ѥ%QY/!_e,Sak:ݘUy!bI,]Jτ{qE|/7Kn Z|xŝ=䐇.d— YArЊ0rҐN'}ԓ>MCr9׻~QA&]/' $i,KcG% Ao&Ȥ+[csBnf2oNa)[EQ .)(6 $"ZdT+ k 3zShw Pl'.i{(f ,Ebhunl 1Q?4ITڋ w`$uZ^DEJST #Use/RMIFj[̶X 2†b)ɔCkjgL͖bt}럻SꌈCdaAL(1A@^VĝYs54B/̜\;׮ ?GƉ.;/TV!46_o˪Q':H`K>ƯA*ǀ\!۸E#ۭԛa]1=,2&m?lm~yZ 6TmO.P6-q7g=uۡ:R:־O#ǽ+˺p\)Ղd^{AqiP. ֗3_=LgXR4bI:!&=)YQ*A *ѤL9xq=:G#3yYJt0BB>wON9 [S( J@ҎaE' gSt@ЎhcZY\ Q T+T<=bnuOcL׼(6ځjMOO>7^ϝmF ਗHA78ҍ<ĖP)p\KE=m;q$3  ) dElXXx0A3ʌxu˛$7 kΧC>9?<+ʇC ŚO'6`d5?^;qFUƲ>9Gψ.ΡZˤa=[]|q ѝӴelh"V`* ]]ߥvE@q[פ'dr8T# /Ry:, &CjUlE)@yG@G;4EM\~<yl~,KXݏ'`qD] {JK[F69iN`<8vB{uć{9;V O<}sv#A܏1H2ǯ)/kVhr'/O BOc- ݋qضgVdXO,Z‫uIV5 >g -J+.9'Iݧ sYB4<9r+HI`<Œ|'HlMoD]'i6} -jCĥ$H|>&!$@(TZҔ$4m<{w[Ҟcgy~#@ "hj 4IqpA:e5j?8NIDqH[Tb):\/$ȦDK:8h(BjʬmL׮ioxUctM \ױ߇Vv#y/ڎ->}oWO]I U#QEvɜ*?pLx9>^|=y̓+S~8,r"8_Q,kۗ,=MqYn IXUO}[cp8|ه\J@==3Q&aB\wHH e^7*s(݉(/>- gS mXrn1%:\-2G K glYrRa_MaRG&Z'N7~:+H:!A 1=4G6<;:2&ttōʯ_2H~~9?|o-ckɄtD|$NL10 w1F-Bss!x|N7o;nZƈ%|qRP9\ɛɻQ䂲[D# DatwjV3LY"@)efkDtHq~__:}Dzc?D2H) pdUS۪_=evJp"?H z BIkg.TTKЍ͊֠%9 ]̴mu/Pp5hY"\V̓$!aWqD>?B)%( V(5&cK"zƏPU\X%]&==#K 5 BPܾD%16ӄCV*'@d]oe Lb6Uc u1Rש|GTT][c{7^?o@@`guYs}s_ovkrApɋ){eJ`۪^CGV݃>ysɱ74ЯkKzC;`:[>A'A( D6{V1n}멃Y[2ӖA WP6]"(%\.y÷,ExDj2Os0P9%(q DtMoU{pn)m)REK+~;`XbCA*Mu8c'-Kd3֜sFhdgDe^^a'Đ@]9HM#2k8M{]5E.KkT Z 9l>) U?ȳ`p 8Ej-SzeU^e(Oe @’W/x 1r^,XõWB^b^*v& _<p,[6jW 'I,V\8EѰlN?,Ń'Ï*^aTzrws,ϥI,=T3١GY6(ƑwWkf^R?0%rԞY#8KlC̱rz_K#(=x݋-opj\QR=z@r&Is;swo)^0oϖ`ATF1ЪqR%; Х!y`pzVbVCyyѸ$hI@"m:rj/cr] ]F2۟cm>ێ5i|lt[.>N?|x7O+=y ׅ:c<#e.~W5_7uQC *CBaF ф{C kVdD a[r^=!:7@ '䉪ȴ1"./Wh@z\*d`cKAgIl|*k~`Ygxbk,( Hs+XBоѧP*_Gݻ7^!?!ݤ|ѣ#O?"r:Ӥ 6?>?f;xyttk-ہd-$i"zBZFw,AfYRa/낥Ҍƍ2!6Znuc_pHՋR3J¶KQDCټ8t$Vl.ö' Fh?R:6m5ltIoEL؎퐍 BP@CRrEpʅ\)HQ8,C ԩFޫ_0ʚ2lWVH "S7r]wW BŕF̬ШưCB\lsց\[Vt؁Xi UUSI@/%{˛=F+_߾$SiZ7fe5^MK^KvGBSiŹ$f-|ق(b66EM+2ݿ*cKe8VI"Xq_ #0S"_FYV*E~ז!p0#hz~atZ)R[\Ԋzq @<DԇZlERG+l |<%}z` E2Y~sbZt1jek[`tCjD1zgM9R$FH*\`+HBYCr2*e"(->.HvэOy+K_8\3фާwhCL6 FPk9ܪ23d=qz̺6ÅdVȵ~.lѦZԬAk1jQRu.aIy#66^J%Ђ3mҗ]g:P͉/z_(SI`}o/;{3Nw ~kTe9ĂN'ozp2ZxsY&ҥN,+seE O"q]ɂT+k`'QxĻ#37-LmuVȳx=[mct٬q%9Dj2T8$q d\u/7n`Fۘń]֚tF;H+m>?9 pT5| 6K@떢YY'yB,GYNӝ,ͧR>;ij~cZh>bL()!%+gxwV٢d7ӡ3љt}oT$N4mfciچ@C$ q_ 64 Vvk;8=ǿsǺL3*a2ֺ6ewOZ=F W/."NDIIiIkCl2Z08+z=Ÿ;?*5iU2}ކ)eG2)\[s#'9G)&^q|vרYj467ZՍe;12Diz?2#}I(Gr ҆ XGxgda᪷I׍/]¥Am&U[+1tQq6 >e}[6@Ю%Im< fp`k+@O}_J׬ſ]2i%-m,TGe'v7TA5pW{;q;g99J:cb} vcO 1yB]*U.I&wl84O/#¬%AS\d%?<=,Ly8h oVIaYNN 6.ci{"p%F4qS|&]MD&L <%Qdf<=fٸR+,8;@mL QUԖsc=dMDxMnڒڪH-PPnk?/q㊸Q emvn^ό=NwK(;#/At2a2WQ@ KqgUEO,U]ˀrp V.x!o 3I$Q 㒽+s0%kmjucHK.;sdClmKjk&k&  7BW?QA' Y: ҡX>_#DŲ=ҩS;&ej0%z.9-uC.&D] С/8| 1˹;˒}7jS?w:dx~K®GKG}xz&FO1Ԧ)}r#|d4uY8/rw&z{r00Fu1yLq&J M'oBjqO/)B $ vuo-zqql}o}?]m_7^cfm,|\V_5GMHl4߅Wl_NZZxwrv[o?}@h SGvQ7TIp&:cn ~/FKV)iybٌ^m. 4Uxo} ®ŦzN2ڨ jl&!}bB\R)T b&Wo~{ާ_a뜲`eiOrkWfCi,J ydՓ}~p1K䧷shRӏ)wJY߽q9iiKK醭fΏ&-/|. c*Os56pAރ?\n[Ug:@C^5bˆ +`Ti %!pX{o\Ζ-Y>Gz:xd,1RH-lr@I@ !4dU|x0cRH %W  ,>,ʼF94.خ2 \H[ٟxDi2._W^&8d6nZT26ƑKY7,MZ8yq|hUB4lX04YY^d%}08Y4Ap} TD22Ԃg'[<A=D8ߣ'vijS HGCSS7YZuߓTqJ ҋ%^2`jpd~6QaקA3TYPC}.*9a5~!%oH.=^|]ƇHΗd5zP_o8ɣ1_~)&8N*{X;?IT%B) ,*r00EeWԫԆ;gdPD. ОnVɳ M@;"01z6JܨvAMwߑڀH^JÍYlrRp-pw窵u}~wuĻ%lǤKgQHOcZrޚ:xwv;-Y׎s^۳p]1(#5m'ɍ4S}oGv$UV&#<f |B8 gEaʨ֙c'?K,)}kFWȴ"ׯ82.l@K>v_θQyUVcŸiL Og+GU͏|1JRC^5ąOE̽[!Ƒ $ ,peԵlHSӇQlɎUOJ 5"!fÂ%a `-;6HQ$bQn:vSUwbq\N+yc]֭3Ox3VjԕeņUJ(yY3#$#/dEe>},13AsjIj tv9?!u#2/KWWxouղ!nqhe1|Q%ikC$ ,$!-RTb;MzY,qPpL,jVQ@>ۣX087 ՚ahJc߹zvBZh^uJ?KXk bH{#w޹O|h0<(0?<Ǐn7(,A>Z%M wH-pkD1a mMgD@cz2CU5IS:T5µ Z2Tmh/9OöEjWa8pՆ=_جҒOps/doْq,+&=ar ϱɤb]HnOzZmY[/ܬBDZ] *HG+4*d@ Pq[tVE&XM\=z/1|Z`UU?Yb >3Rm#3v8q'$cM4yQKp9lԛ5?$(|S9JDmOSL/6˱5JQ9|CjTynxTP;SqH0/v\V_}kQ$*-=mRFnCUHuF~' zo'!&:yW~y:j-,n߽IyyFRZcژEXBl]KM@5FA lElbbiВf,Sc{m-%ڒZ`pP^0 M]r9H `H~et%~dv#qsavkfލy_}f8̳vn~1ĿFJhW7m ܍:n]ExdLzd˘ˇ礫t].&Ky~o9L+KEpQVBM0g!~[7fuMx|eߔv7^v}:@~L < jp69deMhn--RƾK_|8)R]C^\nrJO9;.T|t5N SKu3IYTqpHsEZ"U\h,3IsjdE,Ry WAA)'RlKTGL<´ BB !6{ =Bݠn-]2-j3fر{Y\; ƒeGs9jvzm^Ot?/5 bM9O|O$ J9O<@4։(k S(nw}{v|eps&R sֶ|y2Z ~~8 ﲒ׃ |ե*ʲ<:Ǐrp8&OK8㯃onQp{{)\yϮ=8Lًs%&{q2dw1A EgX2y{~5'k-vMk7#O+6T ՊRT+BEa<[!* B)dqdgU*[sT-;˴` ӥ aH)+Z:>?pPj8hLDi23k{#%' )(k&Gcd 1Y;a7$wR={ygak#,1/W~`"|/:@!K4 d.I$q 3gkkN `?@6 LWAԭd! !O4ߌf3e[x/Ŋ9'M@_L~;OmMA-ήoVUE>Lt"ɏ+V3tH [~q"2;ĿÉaj,OcjWlrֹeY+z|6}A߹ $ Xq )_:AvEa, nY+\_m*I/ia8JFaR:x2,|l_dKsT:v݄5 V|EV,Cv@C$M![ҽW,*<K{94\_\9gW[kneAtlqdcO{TVӫ-{)OLXob+PP*QHpFxKo|u8!]~o\a  #Cx()2Cl%j<wx;&,p}ʬwj=K۞^?ma7apx϶~Ek֫ "vʨ6uu'r\m0J=F MP[Lۃ ޒDMԦgAH<WԦ&;wsrm$Ә`1mjek#ڪPYSVY2.*HtH|2\Y\\5IhMlJ:Go3EoVPΌ ϳ? OXG?Wk]YtQ-)RyI,:ڔ7 XӨuEؼVNևfV#u7=bW&7P^o~пeu3o͇n};b;:X5 b 94OR5 ."A4~R³9ge;)9͉剔˒ސpw@v4"r-)3?K0~󜌩)ZucyӼsRv21jA"w"4@$EF5Fuqb?.6A-1xNC- k!*ixA>$NC9X,UQ(˜o2*CVVYǫvYȁΦخ#k![ `6!lޡ|6[Io]1y#3W/.υXEJ[4y!EWʡpcFS4E@Sg%i22ִTcbTmM떸M$2`QYF=Qo`f1bLGPXQ.?e%:4xb=),uVuC%~ GR]ՐHwR \YO$Mur;ynLjQ*MD_w_Gb]*3X{l2D^ ;헿!(_ŗ#ɛ$hs i:+j~?aԄM$Tbmk<֖뿵pbVUVjo/od1u/T~P^$qy뚁a, N8~T,xL]:|hup壍x=z+N\Nk{>HC'\$ b#~};P?as:Ū&ޔ5lk8q:1േXX;wΙm̎t(ƋtDS'?u>*0irnHWd{3-a[u~:|Q%q͉z+Țo82|n }O?/Bh\S{bIqzyx6kjm ys]Hc7nE^[`cЕgPLc(K-U/EDAQ$χE)"QX;_^L9*+) rv?9e-IUU E㈓AȫMt΀PI~{u|lX%O^mxdF[%dڑiy"'%_gtF2G}IG4"|!ȪD 1:˱ +P֏R1W.15r@ۄ<gq58nCkmFS͈)*զϜ-> W > j2لjV,-nc/Let~昢"{uI Ӈw`moy7Syvw!$<TxssAY 20*2Jia&ث7^(? S.;;6IT \mj#-]CEE0u^i;c!8R9xͯVkk:3؈='Ʊ%WE޵>1x{ Ѝ!u{KtN]5u")QS$gÄ/x_㐛ar=?:VVqvmn|Pw\զ$Jv$wrxp g,SGcJVk =CyN "Z-nQe@$Hkz^#8"j˜$r Q$؆Z0" WoXuCV7l( BPt DJVjYTBtmoWF! i>(e>(Ԯ7!o #UY̓doD?c{lڻ}M#ҢPr8!qā#$@RIMK7l}5u6'KkYޑ}_:BW_d0wOn̬n28 =?ۋf`″y27%eKd_$jWSwbBt x%$u1|h?sZr4V[ 4#&X(xmu"eN`;*q=ߒ=OHEuek^㿉o;otoU `ff俻![}wЦEF7J#<WzA'Y^} y7=tY]d[Onj J~z.ГF:UBƊjn;5vmL$. \o7D>~f 2ĸ)nxYrJ~֮| Y'c0#۔6c]m ((4 [ɡ]sF B ^A- < %og=tMYT@y0zXCQ}x7X"(h2;7tKT;v2)(a*Cb?OaX JP"i;IclOZ;+Ȳw}WS AN  = /ƄyV*,/"kb/.%5IQĽwg!Ia[|\e*sZЈCipJCCL_rNV)*!,댏}*q+CMB:qý#cidX|〳m4xsdݛ?Z8pt2 4AprW]a'gI~xvJ|`ؕb8<^&9xtq}5!S?MS-[T8Wl kE) "94LR(`z:U+l^]RRv+L<*-e4bj mn3 YxIK\C#d!K~tЅ틀5ݸMOQH[劐j:6-,n+B<)z­Z\I]eU"<퉺?OϜlۢ5Mp/ *y!N RQWv|ӔLa]-%U !s $vp,Ev>Bw.Cm7pmtԽh7AAF.{h=j |'``cK(gjpi9|v /p\礛2"rm1 z.^%,x:0qta8' +%h.P%,kR>kTSx!MhCq ^MUP)ٓП| L;F9YUJi;)X+E 5hF#'y,(jKVTlҒqVo7LӁY_,&\gU'˃选o֐iOLaVQqaXG#)ƕB4 g89U`ky#_a?o}ƕ9~Y@kIX- v˜fg ^i)HCZcF-vo n3uJAȯ3;cŖу"ǃV\Sl2gO :[ntK⺿w>UTHZg܈.UО )>dj3RnF-65 ~'+_=AvqP|ZoY|v)SU'`L?6.tIhƈBU"ѾnM[PlcۃjARG#zt5B thʺWT:pϡ:]{u{ 7U;>t׮H;` gAn^;GdAn7UߩWwʈ]UX3Z(}ö+ޛRg&&14 [-h(VÌPC@>Ҕ5Z:.E2RB }B5eRg&A݂]Q5wVrLNEEu(9\''?"% b˯s1UoA気Uaw!O<' O/ƼskCr㍆?߬8C|qoxR:GW.FIlh,R6gV)U*b* 2 %-ị wG>aF tKT/q.tC[R.-!6T=[$~;F$* :e\sỲ)%[b+y{^cIk ({u_E.*F,cB <<᳸_ I U,$(K^WjUS rd((B &Px:hsj^R*~?OO.$9Yy?ڄo?11fbе8|u9Gn m<8f)TܽO]F-Y&(ZCl7IX'g8}mRaT2/P4>8\AdN?^li!uU`=4m(W 4Ɂu#.a9rZ`˘8͓Xd3Ra#t.]YLM-&m'C,ft|\̦Eb,!>9o:lYw܊O,2,'R]Dz=Ac|c&FIX`T?gS4n6zPר$ѪJ }u%1yhfl< Y)d.D{{{׿Mk]m |[Djk  A\WQ>-B]Ÿz۸xQ7'߻k@wB{-_#=잷5/폩 PkCTm\ sdr6Z)wWo<=pxc@mΙ/<7m^A{86ߝ- $0~5mN1T9"Aj޾wxtreI3V\l gt@ Uo1G޳8>߰XHsJڬ^{ OO 8CpR^?s)E^- ~&.}M GڄF_G UE ҂"#sNچ''C;HcKxvxΉ|7y90" 6{J Ӝ3B#hvO6 qnjw"efgowh?<~M(#/NGmiBV ͷ!<14M wx%#`bOjw-ATsYfHM:G;9 A$v@םgT"F {z~l*Q,."vhϛNS~Ӥ%V,)kA<9pm7.x(Y+[CN9:tE;hstr^tiūVqib>v(1AXEEJwp;~cFHa%"96B:8SiDitڠ$G ʌ[ݡ.b>^Ilc6kArj)wxR(Jc{kf-ٚ":In?\8)|Qb w?KWcK){Cȧ, ;YWUȢ0TBቊ{=fY0-y=+=56; 3[2s<\+|Q$tLeq]sstKoT=$I24Ii@ Ć {~GwVA`JJM+:i؞cvUn,/s;~TϞT(O%٬NkCK>5$Iّa^BŎٕ{A P < U%\Kts6tHc(عmM?sN&1}ER)k9b2F1J{ rMNf˜;. 157 ҂w"N)ɨGPgvA?@-嫢b)j4"XB KP)H>D5 u /+ HeRNN UO K^_Tώ=#xzF樦7w}\J/X(Bb-&͖?[um ע/<>M3Bo`2H/Y3ѝh>>*j(Pr>39%6Iz%r*SU9YK"2a*Wr&2A/,2̏?5?^.Uemʾ..IѶ5ǝ h yok͛ ͸u8) dj,׷I}Ǽif_'_'ͩ$iښ]4w@,UYzk##}3X51"BUY 8TD8Vːd_1{VEs/x#sf~0%+ahcϭMQFI „aFJx`xja83b8Yfpu4%"S6˜2Idn˧( "\LkW-xvG[Uz6 \Z Ls6]tFSPm %&F#žHX™NG T$%Of] %k.5.im4k8:F9* 1Ѿ6q::R5RnC6FF#xF%/BIpOs<֨]nQQ1i`Ə>q{78}tW+E2 0 `%JeRǿ)Iφ^м!P] ˙IJ|v3&W"9:YNQYNyәEFz/1=E8nw- ǣTg}f7rJPg5B@"_fc<]1՞=!i~gS O8% X\(EF)p}*+<+^;SjP!SI~ g޺p'~o J k d_g2ںb:;Uit0$tQiombT 2N@8+Ex8ĴfUA6- ކ]^G6O(d3MĮz5AEk;Isv6 &DgZn`CY<^Atbz8m0:!;x hlƧ 嫘VK 1pIf 5c,IO5~xq(U|skwT\#"S>8qL~"ce8Il3X׀'/Q*GZ`sz-KTp0.[D qIDAT' &"V92/{?Φ"7k'mJӤQ[JB .H8@| g.| "5mIe_gv8wSb_38D`5t D=!=?o&+jtJ1rT`+db{nb[|=|w@J묄~ٸs/}k>1<5lI yg$ɱ-Q1f,]6Wh {c5E \i&q0&M$g䛷;\[@kE:x:kzix2pG[+,.;uLcnw ĹvsϵB#(b:ţь1hB5R?LEKExuvNc)C@%F ,r'M7@!!X 1ZFmUk\׾(&Cјg |oT?>I]ӱK ؆`0  !$$$xBH 10ڥm7NuXf}q'w^Zq9Ji{:?vD=.vQ@\"~.:Mq0,VI42=DSMOPcDB/ IJ93 /q€b:kVQ}3}˴|J&3ih"LTGT'VX .>yOCTrL2` 3@ XAUvڔwyXK[dL(U,HGt7/n]o 3'0xu>lN60=%7B5dGse4rQ|6X"Awc%[mo Vv.R&{X鱈.P7ϰdG ?4 "C˅e,:qPe~/`(Df9sqB))ݍ!;ϑYL f{ kl~9哿gJF>2+JR+_ci_s󏌷wj0`YbIpXrs>'Rnl ^p}3hbw#WViY'(^™$5А)cq9¢ ,3ۅ) ZCFK(Wu$hT"J^:CYKOXKů \jdIUE*^o/|OoD{g&l&BHO R/OƉBH%@@8 4lfwwglݮ=<v%1pfa,05ISH [ <⬀3#Q|ɕ=~K=')w |q2 Drm+T ( c% k*t%HO~,+^#|hSZ?*<|-/JEIt9tVZfغqC>>al͝amtihEs-K ,Ha?ۡB+Pxx&u dCo aM-b\>1vLXg9rޭyg3V |׈~MۚEQsQZZJWAzT{Y>G]{z =輂Mkp1 UE|2]PWәÒ:޶*\dP#wnP\,h{m"5fSl_tҜV,Njol= J+^~ }.ۇnB )7pG_[Ng\VuE/|v|A 8 ,]'=gc Xk 9sĆ)N`hȡ6.gr;#r=?#{:vJR\XO,ϯ(.st?9*g.,]SG&rW|+9x9 B pE_reMM,s#͝ `n&vA+؈_viu_Q(FkVeܳ~a?ֱ1dm̂|ј (ߦsx|2%e ¥ ޽G<[n4#M %ݘ7:1ѠGUlQ2M0ƴwhݹD4%ӟ~^70nǣiTls_'pM`#{n2K)~?q*29 ZTR:Q45H`LRyEi2҄BR.Tk%PIXyx gߏg3⽍._pQRRjzXUEP֜ǁ3k di遁58@euIf[AD6Mph&!CD(tct]r+1q1KOh5YLq1+4 pYD~nsg'|7>~ sDg.0%t3D>c)d=.zg32'SKsgyeIWq~0* cI|Nõ_e*L,p[m; "^тrϢLFMOSUV@]/hbPйݦ,(e0a}Q,@.Nhs}BV ]u0Tff?;HyZ<,2+3z,`ݥ_2Rc @DVz;KvX adhYztc Ғ5G7;ŏ6Y}*G)ea{Y A-wwPb:A;mTQߢ9oѹHg,L3u]o%(wt3KnHx娉VU*fr!9p{4V"~$F͵382M1Z[᭮}Q!2L!.sθF?AF{hS"xUhc*FDI*d C3tfdzLzO8i^b'f%P 8WM4<,U KoU3ޙlj&TT %uQtiذbg @jV}4į<wp-˺sr#R%ݖR7dU|}Hr)Ӥೣmo^÷l~] `]soV27Q/󩳔b:wHQ ܽj( }B׸/_GNRX;;*˱yAbڷFښ|W۰#365.l#V>yRif]p4ӽc-g7h"B.N bu?7_ -:_^EW7+)FʶHrT'WCyT|##vwF,JKN~}>G 3v0;GLoH9_ iEJgw k !a/% b_\ ~{6 q=&Oh^B\C "H'Ȗ:y z,ä `gW%wOgz+_˒0Zln7CBe]c*()V{|KoT~{L' I#"m)TjK)U $wK`Ϟς*1Y\V^z};ڷ{7Nh;&q&~JJZ4/ 8+xQΫgV`)r0+dcO HϿcxαn欭vTOF͊4 YOc PhF4O]% EəGsD֍MAʡ',~e䙤u\" Z83 07n9M< &{PH'Ik$19V9=}#2_[/^ULǥL"GxigRp19Ri^ %H L tWNC3>"I?EΎ@(p|fP|%A)"&ifX[&:"+lhؽ"QB: DN<O%b7MTb7-k-* ʀd ]ޖY$V1a6؏%P:kef[{o`_JY?L#3exL!zfҧEfT E,1$)1E#lVL RSj.YMt@ P%2X41ZQg>,60/' ]O)g%׳VtӇlO<P|6HCaSJ U;5]CffáYa n߬AFoC9bD`,A,?P}RF`H2R/uzԏ8H4Kxw10o~L=eմ⬶Xya`iևԏMK1\sFm6Kt">eHw2k|5[ak,~ShZ:y%{Q-* L cce̟'F䈆E"TѐKb~* 4<*Ev&l(%%YQtˎEq2aL& ""X`; O "["HQ Ifx.NV͢^99op0Es0sÎ0L s,Ga;O^뺤f%noG{rVIM.>GU;}osbJHݝ\+=nw|".Mm[[vǵ(rqL-Qbg4,5zb8gr!$q(tYr&$?qo!L^%^`Ĵ{B+}<[!9,y6 ]ڮEdz6.Yk)7k-nE9-Gpsirp +Mpr a3ߊJ1 )QtdL m"Qdt=o#~4R92%Op!NYrA%КvL3`)Y}Zh6K*#*V{M4Aysƌ brRlcp;’LQM S{e..v(WVESN@'yc^tݭX7ђi _cYM3_ECHTj:'LbdjcP!/kcrhW' 2tdXM/ 2xe- 73u%re)`Tjc{Pe7YzrޙT76giu",꿳|ssCF6=f ޷AH-T?W!jR*DהMdʳ ZXKɘH9Y4d$e+&{ss<=Zr͗F8݀h4A'9tI|SxԈ)lW͇dzfd?6N5k7tنBF<ޛwIǻfsg<@l+4'9Wc%z[/qD?=fpSwq/U||u@($+l  d@Ĵ ow+ v2N do6Y2]v%SH3f|KoU3svI UBo۲ H?¯@X%B,P%*+ZҦ(I4Nlc{g1$q^%{IQ #;g2owʓ'D) ý!;>Ez6Eѐ'M޿;r0KĨ`Ѷ ڶ-E5Qy*W$Ŏ:fa㋳ȓ!ɡ ='v1}?!(gpV61;kB`W4^IsgJʻ(FUnCQL16YBwBPNH |_3{8inzVju7TD:2 l\!ȣ6>5y(DskcGSGk7; 鼱m!+iK4I9`&{'ģN9QR25 嚙QrH7/fW-7ܾyuTr|C kf倲 rT*f !uXfd/:F\pF< ɢa0-s ![6ZJK@fC&xh֝Ua8Kk"sqyyَwy{NU~/K']# *TccV<a g7D?uTZj;Kǧ%q^_nC&r{{}aI[}@|<=%:$s]hKˠz|x~̎ǘUYJ,Nģ77gOS Zp Fe|r- >06=}rȏʜr2k_>ɳC=̓@W(R}%9Qfkpn2 ),fPN(URxe m4{O zzJZ*B%2MQ QcljϢyVq%w7Zx\H&{S+,Cp /nELMbC%HH B $vBHy $"!q̭/uaQ=c;+z7(͢Ωs:Awṿ >:0ᜣU"!c=Hb#p&eRYƹj߶)fQ* 0ƒ iW?M+M^%<:o1y'%q8=R暸rp8GKxU'OGyVU 6:<2-&I3zm,ih% )`TUsm _~:mr|teP`4h4f5UcK-DFڍ;Cp4$=ISD)NG2]B(ͽ6|Ogݛ/#Ú%(1h5+b6X%T$dLQތ$J>I`7l [kv@Sd(GSfїFOkp-ф %(@~tirB6S@k3wK3QF&@ .]{R)uRm% )'3K=tvRLe@#?(bChuhynjLh&;Gk+Ymg ,gэIu+4\i3@ ٹk< w7O?اTW~=_gdĽ6#-5a3 av<"'1Io-.XKz ') OmP1s ӏN6q< s[`gojg%X6}u$('m[f "0g<#3֌d?B0ڊ1Q%?)ȖCM)q1Fd]+$XS8n@_En05aEfČ3 Zy~895ä&/M Ablh\нcXzZx38܊|/J'ۀ@ B)腊Żk+>D`v ~|ND΃q)Q]£R <$E1E!Qؠ*exn=:Und gS:ٔ-kzC]2WM D$7I;?K%'wsϲDw(9gS/jUL?;T@O1YOjBH ‘JcQzP 2Rj[s!abKraUHb_Gxo@=پIpx=a|LJ\>ƊH,ux!a R57sF=yA(  @98u} `huElF? #o%";buC(c7'R!Pɷ.*ux๡y }m *! .rqJ tU )njY<QEM^L\b|KoTos4 4-(JEuB’š*!XUVҦt&Ƿsl ey_G1_zVwB\?jՏ!q R^sswS<eePV51{|U~9\2})+1y}i<~<$KtpҒ"-:BֶL_XpHxÅ댏ē f1Np:NqKlF NIFo{'XWw1[]{G<Yq}ύ~kxpZ(!] x1WHrv>T5 2-Q8nsF^@0CΟcG!9>Fe_*K-x L?;~@9?YNcMfgaiL5sFSKEGy,D^ÝZ},j*n8 YuZA͆:{sR/ű\XܔZ=_Xٶ5 FkXMl36ra^SY\4}SHô,T)]^G'Y$u2;v({hRgt4f&] RMtCNqs[w?G|!.Uo@toIW8}6"juUhvDY!z3{[>$}Q\A1Kv7fg|M2TUs+8*i3Vn0 tB+K S8؉8p>,֭I@cVr'QD>НYPo|KoU3sgw<4iKĢ *!'@bAd-XdlB5P_Q<]=w.;X,,W3sc꽫 Lֶ#>nol|:nFT.D]U-ƈ4TLc9ic96n2iW,9{g][]4j+$D( NDJu\SsaH7p4ɔg>i[Mj`} wvGdA}0FU4܃fvfA@"6!V -,Kbm}( 66@)ӽ{R-ݨ?$F8q+ϳ`b@1 Q`!EG5O@ 5>ɫ\OFD :Iŵ,';hUcԒhП5RF_`}-=eXv;YPy=5 uet{tԩh2]:$?O߳0Ѩkˠ<+^ygKi"CasgX>ŭW\|yMGz!tʩJ)WW)-E0=ԐaVy9Hsipв-$^\8pݠfAqe7RgSӎ;kH#DDsCR 0E{` ub%-KoE~Ngb vx8RB0) !!!6 $O@!6(ǎ3ό.=R{s1}Bҹ9MbRYҟi;c|Ϧ[-!Q"9 zz|v<}e B:ͯ;c1ap M5!5ATArs*WXIJXsLg߰m, )錊o<9!SۙӲE7MnqI'+&eTJXF WuN';z"v{l{~||Q&.SdaL~w^ а|[;|QLt{O=^oif:VE,fϵ+?H LOdkcnh0&L:O Zɥag5QڜDm "Yp 0 ^_ p|j{x%!$1myVfZGÊmQ$)fYB4ۘ¦cqQEURp`;Tѳ6l%;$i$TI*ŃfFAշ噠yzOmFT s"A/M8MZQ,ϾxHٻopNeël~9 Ðy+\teiew D< Y(L1mTCdKX)r-4 +{d(#pJȎ>=)S/XZ`@Aژ=̅5]2K#nTos43ͥ-)ъ,@ꦢ`bņ3RTlhUUJQ^4dű^[i|wm3d={C,>R*_Xb LZex|?Ðl3SZTa`Ƴ@SgR{JD/-TJټ\*1QDTʱ\O L4'1ygZ0 sZ= #]m/[Cf&a͎${/`|zܿ+m CzM(c4K2;3|xrt8ga49G.[`tYnxVJ|ŗ2vS yZ"鼅rhR3T#SVqW11X>Nu1HRx4HES kgdӶI)}AMPLw?\BDM6N=W! (2]fcxM$tDEg5 9"Ȃ˷5fjt (}C,#H!kTi74&Gdx|l9 d äވɐg9ʎAJ h+S;_}Mc6p&cD1JK G _j֋ ? I[UKۻC'kxFw.~NImE/Pxhz*ڍ1bdQ0Xj;m % 4pE+,l<0:jiN6)"d!B!qot'~Qf~weINg8H% j+BD9C+AJ̓V4ǝ;[OcR(WxUf^cdEp6ε[oD?wf7IYҖG@n'=V8 DJTU6&i>{8>3O19R~|tJK$  笵g19& .nw'|>B@p"xa/rcjŭ)Lr8#P] <ʗe?{oI14.MLXSD#]I2O Wdq)4~D2UBz5-vISh:kLO&tl+(+/*Ai<{}@0R-'Z RmtZ@YYSD Nm3"G=$rz&^^ 0j>CF{Do/ (2ll\nStNH: UBJzfIMJ}VP|U:TE푯J*tjQ tEO(K+{F_*5FOzߧ\k﫶[۴߭V;m-5BM8A 'Aۊ6k瑋3W uda)pӈFQ6XmO283򼠡\>:+kZutl g3 4/ pA/Qt.s$=z4N@I:e9mx|&￐F&(^ 1E67P~o熍@.~ZK~FnIw6{\=m;(3d]!<ڳMFS>޷J?SgrWClx 5 `.z KoTg_4*iRUʊHH#5` "- 6$xf<v%x]},XOW`8\~HrmtѫӖ&.ךi2 m[\xl]F1ŇJ4OISEc[09^B*hf=kngДt|oϏ$"LC84="hy. hdlp YbXN6\A!,؎K2tURQ4Xlaz 7"Fk+ֶp{J:?;$?G͠33DlH`pP絾+#KvmQF]k(-A{pD g/@~b2 W{87qP3y?MAS l XٯZFyN٨;[Tb|#[hA8K Kl2D|JrlL٫CSYL4YT4t6J_^YԜ󃦸d3ye̻MARe\aQk8DaZa\&偟(0~X6IQ!,AX&X5BL(rm%Qhx7߾kVn k,wv3a!n#~l]N|h#V@kUTp 3t$]NRٲ]Zj-! o]g( 0.R8ͮP(EeA9Pve#Q 0;替 8Ex[pERYx\ZǻR8[G̪ú$*G\c+#pB\/"ia;P_ԤҒ5z˕~p"Nu0Ē5ybY6w?akӀ-5kj3%,f/?l1S3yw7%±wj^o#.ױ/_iӺ:BG$G,Fy+N}-17>`w1S:55h uWpo?q@;e!Z,L!^5}w~UYh<[F8Qnaϩ~XД6mT:5S9!n\(v9=TTAf*N*xBQ晢u ;x*nUCUxH'/B!HHE6ož-– $" iՓ;mgI/յ|GͷҚ5u kdweeYH YF>HmԀǻ+ کb6.}fg"e2XR6To*xs܄G㏫+K#@ǒAJLpQW[r{ Y󚤣7M.| B& L9g@(*dnuu3&8CJȳ&{6";rS)SI:ڬ0OgBFls6.5>οiiȊ (e/!e-Q$=[| D߼ [޻Y)<{u`wlI8"9zD'4FYX2Ö PMei7Y@jDZ>j Ec ~'5Mq:@7g2 sVDK"#2\pjI. 2y9-Zr^[ pS9Ӓ"Ղu}. 3Oydܰ7ֹ8zJ58?Z1Atz5Ҩx܈4`{W "! 000=]]U"{p T-*2SgҚnqDʸnٌ|ک18Za0DG$O좄D$/~cr'qyݵZF3pamlp1ֲ~LbaB[>|kSsnN\8`ZIAI^H|ύΈ@0x((ЕA׆t=e1J|gJ ^m6XL,^kC59ü<+h겣6t* 8CwHѬTxqDcZʢb^(, `V3WNx6ҋCaıOc|3G.ON$jkә#Yo{pn=aX(n?pdT8\$\Zk}o)3x` <=? HXoMLRim\iOЏWUdwk'X]mȪV-xڭUrn?-HgѬNW6ǢidY |xBz15Ec/.ٸr 3Hzkkb O=].hj_c ]ZIOP92ϟED .ՓA"L(EI5zR_;]X2p//%.횭iܷ ܖ5CR[?, 3$n#*g>`-X>/4^߮xb!%6]c2g%Tiww\Fi)R":\\ PgbI=ρƎQ}1VxVpr\0cE:4ק[\ZK8T |8yi-[G_0XkGso\sZ_۝HR~vǏ>ayѻ 9xBF0 ٌswcifGD2x*_~[ 24sW]! at[u(<;ei3y%@`=0+:7Hr'̳G` M[ c'5VTQŌzWger{ė#,jר:zHz/;o\E3g{wud bȅAG  QS(A J$ (h B$D(Qf^m Ŝ];%<:7} spFn甞Ú+8iRjs)v8đ+` k]7in} FnihVlGdUgI\t#i`2x4b$f $/9M ǯqmqޚ^Kͷwh<=C.~ yc(-89֊($7@X Rg~s[1"ӳBh#\iI\BWHd4]=T'd/nP$CIghcغ1>J+jD^n¡滼¬0!˨QE5$kk)=ѬrȓaZ@#f{iq Hb0/w6pF G(mhe/(G?$u1ޟpkzֶy pbg`h"QE;^.`2+\{5Z#Ct|Xe%A3\&bUY|#= Jc+tJSfn,yZ-i4>s@RBpjV aȦ&K5m85޹N`,}`G"kjD!WXUw9w . + ƬPڜH?`$ZF:L6'^r\X0W\ll32Uda D%? Cl: (@eq{mT1ɠ enj]n~ڡ @am __h-+g!2ʱv̽ەhi8D;k,TӨҷ GNu?VpJSvER(ʮ,*uA+l [z/3j=Vb-ޏ#lѾ~у: Ϯ݀O~K%2tX*b>pH B?Ƹ)kџfxLS#JϧN3u)1!mߢ`*n2}pߣcO55Iȗ6pWɽDtT " |֧twO:MEt0ie!55= Cfk31gJbq#j<,ѷ'UJa:UtȠ.HJP+E5 P6HQMG?KT_q2I3ARJX~|n_M ,!AaSh˴f+}5S$x)ν?u'з @ 3l%M_Mʑ0Jd WjD2&]~/~p܀K"QQ]nW&,E>gc|}gjfF@=ߡ,|ֆ!]Obg[l'/:+ak;G|,ypfӜ%%*в֪<] 9.h&v@ /#-aJ֤zgY7V"gHl( !IyoFZ)c3$lLۢ4yzaȹA Q^&x  RcA(U]\`hUPX2SʽG+43zI3-2,_2OXmfa`6e~yJ# MKdԫJ֦3JM~s^q*jC1|,pz $H]s6|.ɑ6 -jlăs`1'v X}pLw[^Dt|Se%N`*EtB Iw?N2}R "w4%?QbDsiМ7oj@62,FC+g^|y`0vv+E8@(븄3IFcVK1R#4)GJnK80"&ԧ*;UF(2D3,i|Ǭ^BɷTa1~|B n\Lϱ.TJ=酂Ǔc cb!@4Lw7\WOٹnvD,tT(KW SNpF;j y,E%^çmݵecGt6Q`xg޺IfW8ɐ?6ϴ*Ph_AQ离nr:u{A+9??I2)i0 V>S;sTt]K؉CBI0Cc`h2C0t0y;vxy$+i:Tν?4f9\ 'xޤўO1"S*e-Tу.ˆHSV%xvy|:|z}~z:w7==.޾ʓIoѹ K5Iup,B_r3]I LbC]22y{PJD piY T(t`UGyj0+sup}sl\tQ᧚Btь/Czbek[|F},(g/a}LE\G+܎2s|ۢt6Kzbx {.YQL ao@#l<QaYYq)p(*HҒQOUIR@\Z9p*ex .*9)[㦈5~Gzz^"S0n { ^i^Kb2!LuKI1:VږDD^·Zk/\!#; D'EHOCz;)yzwx?GW)gq(sb[8Cn^ϷR)yM)Uh.ۺ&m ͊TE}>J"#~1/oW13;35`xA PH$etQI*GTӥJ %HD"01eޝwvlLj9V4gz:w? JV3fNF24h[4"d FyJK!8&q> !xP5сe׵x1B8a0|}"|~9߼' CvbÏostq<%8dkzu͕3}FIA@)4Wy\Yr;.F'CI%%^2lh?"J>BxfDAk2B%2)*ML#P6)}3#lW,EtEx[i9xqN2ўrPQlYa5J<~/>zF(-M [a\ &4 ᬉʊ憴[INGzDhݘO6Y?} Efrb-&ɨ 2UWsܵkqJ^j#Juqu%Z?T`vA6}񸿀 `j&3 ;Vx(ǂwf t$#MS7eV4X T g)Non!fMRhW?!E;rzk""N"BvRقdOM&Lv;m`m*,Ҩ 1^bpj.8 YъIfx:NG/@ $-.;]zYVeu%qf"Γ}>\!+=d1<`QY'x}֞0qtg6IyF},h!/](YeYЋ+]t.Lz7 _ sdOIFmbageuK)uz%gfeINm rDnIHcql,6EHX .<x.\8q% @UBpؘYKAҌÑ>*_2NKNy"<)5E"JY/wx5:{.Ϙ4wg+prjo%t<:$W!/XZ1Nby{g3YɥwX yi'l|qLS썺<4yVcwHJͳq|;,$%OJlPnjvel+p(UGK&#BKd7Nn))4x]bE]V"#8Q.r9xkxsd̗#ʴbZ>>޽5TVᔼ2|ۊNg|AijG:ER2층mhR!* eRLqBP#iTX].0EX –ڟ"m^a|F駚fQ$!*memRSLT/o]QidI 9+=+.= NKk`)V=)( v7K:Jfh*kk!5߾#nGpwR0-8 \P ]Iç7L27Cxcji8 4ԯ307{!, {@=U]+S85 ͺPkAXPڼ (%[roUbڷhvI([低\95QDŲJ[gܾBW滵(8ɑ[m{5`L5dQ;6u4S7t_M#pkMl;"xl"3L ͯf7yp4a|׷dppm#,}EV2jǓVogC/Fݺtܹ&/I/x!D"¾slc޽=q88YoIF/ \y}~?ׄtUk§ /O3Qxs2/yy(bWf ߍ;lɒeIɟRJ;Oɬ |اpcsJt MkhHB}*ڢS tԖ q7Mgo=*V7|s?DID镋,cI>+uȗ6?|8* UJNN4;{[DRp{l^`$z7"!-`l(AAHz8z*֮X+"[䈴1Sak%h['iv&KflN:JQYp:/ȦaIte\ X HX&`3E}fXmQ(ع骍Ja%Vd; ; KtP6l[Q@$MP/RI:1Rj\S嚸PZK/uN8[uh4w=dE^U=x8nev -K)g}ÚVf 2R-/g42ZUVT|@:wcV;ںJ_i;Ĵqe{4jS͠c3=Z(ڞvX2 [ ^{w-InNxlgXK/><#w2AwDʒkK Rɂ{7wx5/6k9BmYzdz( ZQ%!<;X>MW Cԗ+t;br~ 5^O}yHo9A+z%ˣwzۤ7(~ş10ED)vkDžh-2k~o!I}hߥE%Mul^\8B$&@13VVfM>ե"mrifXVLQ#t?oE?{{O_l$DDAǟGII A&@$P$"=vo_K1{emn7uG~@8㝍4go, X׊Ll.}Gy)T.Rr2$fzQ'QƝ?M>Yc-l_Rǧ'dwϭ+=~zxQZ3Gc5w?-ȋ͞OV\p挢A؟[)a{] Oc-ZYqfӧs<"]dָHtUM< u psI UQ ڡ,uIPڥ,-#@iɥ67:}?"JSj2$,e!A^w`R̓4/m^h6BMZlWnx{MjJ.hō~N p%R ǔ4F"ea IeykʏOUSFHA-PTe70jf/?cBUXZa0I A %UG1yɓck.ʗYQ5tRARÁ8N+ )A5mkm׆]&L@ӻ'p=s;Xy^6Z `C@Tv(2x%\pΰ8XCIIr͗Mfk’€lW2\totRڶ']i)fpU4 +{U"@py(a=QKD. Cu@ΛLQ#n (jeZ4͡u-'Z5f=u.e<J];Ssv@]^B HJTּG(ٽ3L-Q2l,tϾh;HՇjзGit؇LGA㈲S,i YFZ?hr(r+.''9$}KypWv?&.ӿ5ÑDr8V@6 ,Gd' WRUiAr:gwdi6zZ*b#t@d$9e"͐Jљhty6"="{J=ſGu۷JEܜ f8cTל2q\uȓZ 0k5]7o0Ԡy)>QB"- #hBcS/pQCyE';bseC|qR Ur,N3eN8$^̏V¤lU͸qb[mj9ICv6ٌotkŢlvc ĩJJ@\Y9c),C VmPLSW+|&ŪK0bm)Q.=:K09pfDk: I Q4'p,Vf Aߥhf4Ñ>Ad\b%Tِj) H(s"=^0Eg3bլŇ2$Y)u2]{ *&R#://pCb1{Ow"_x:nOX&[" jiۃ97l6~ 09΋rf ȉ9PZ J5w7kݰxI ض%+4 x[Dk]!JS*qw}㑀 |Ylu7q`CvADF2%IDPmʳo kx#"ݑ҈؝%$;8ޜSer&$pBƛCi][/ޜ`$YtY)]«d9;+wᦧ#?8X²l:eKVHNcU{NO mI ޑ8'|rl8 teB01>eIE/c)rmoR,bS輐Zl4E)8g-+C|S R{ӎ3NY묐9~IoEZz3v$qHH%9r ~npP$@A(؉؞n3&gK}U.!\ƆV }ͬ[tt?K<tHG_}Chkx-BHx4UCN -]s˛s1ORٔQ绣7 [ypOC./|`UaE8$$agjUϋ?laO&̒{[E\ >ḍ(-WKlrBx[^~G&ȣy0Y+xB` t0ᘳR8ea*GihԾcㅻSU+>Enf Uf"EY.]]?"`q%NC~[SĆ{Mٱ0`3C,)3~mON2zeE2+?6̘qC^/(S)+fm7UQ(LLjk!x8Jdžvi?EPtv~qBv=LR2?[mN5*]c}&GЏ6 vDwq̅5oH{;Y n{_G鮥w$S6*d@8/VN)^PbP^rnnuwhT Hƺ~2 m DR(A@.@z.'h5.Qy݁$ϠЭ] V̨m;ز<ʪ)hv,e.uC;퇞tnyRp(3dI8KRaө&Kin(rCDk_9"!bqTkVW k)(QSnktlBMl4ma *X$I+cɧqޣZ`?{KWϝ)\EW2j[lP-[qY k5IR(F|^KQfn8k[s OoD]{&iӤ PJ%ʁH#@ $ 4mT$zg<0^a=[yA,d) eݲ g[_Jv4$%+ͤ0x8Axp_ӐomxVҴ-O#nd{i8 k˼b*R/.KN+G +ݰ 4R<<ã3l>X~9`,vӀݽUQK*d Fk8xQP0Y5tP>Ag!~ )~1q1/f% Bs4+8 xkypA G솂?y ;^=t+JX?Oޣ81Ck-:c{VmЏ۸BNnp| Sjݔ5 pXcq%F T_ X}i $O]Kdn}O+ǃ` AJna~dE b:}kiu}mrIb!㎧_^p3)v6: mZS R)XئZۢu>xZ4Ĭsl)xBonT4T19AP-,172, [/X*|]'|- ߁1TGx!_TӢCp/\S}s֩VmA,єW\y=6$@u6Ay^ 9~nogtASoEzc7 ) !Z "!nH'RU*$PJi&;a*|]>}/uuSl J\F'P W9GE"dQ54A ~Ikж /qRl;j1rX |`8J ?MrD,1pQBh';螝\zC! 7.f'l3OK^.ygā&)l|HMRwh2ϑ&/1Au{mw;p!E6eMr2\_Ǿ ]t=- ؎۷7vuzLu׭1<:X5%!> -e{JXu#=5jk6N[y EZ,fvuSi8^C奴ENsRףT'xZß@3[\&q28 rZæ-HӚYFRԤeMQi.4lF>i,Q'r.و(O=|/&)'ϒl4-9.m%cKdᘛW#=1MKvZ~wC.̲><~9,lVp|j~iUGU7w]2UjL E7@!{Tjypd7{GԺჭ?lo_Ό#gؒ?N6C5f-0t%aVU0) ߖDNȎV p,AQx}w^P>u5ta^`/X5Q }-Bkn:4Tj6~V16*5:5Ө(gct2AMTxXK>P҈Zԅx|PLf1rKXˑF,ϨYN e'*ލMԹ"%TiIӧەe-fU]*օt $UCF:t <*L1?1x6t,,Ď\ ˜BB[Ad5߹؎wGsт޵dk3> CqRgu,cn7X ʐ+k {A<Y4 3y*hZuW.~o,{noǒ=hniYZ J[t66Rt2Ӹ1_B-}jHyfrT5m֬.Lq.ä1 V4 8EJۻ|hͧ+qYܽ{G~¿xehbًctRnob(3!UVbUs.zI[S#=39?@ B.(M [749y::^hK~Q\\F–IJTrm8JK UQF+{^q lv!AnF"%YKǮ4qI@y}k[C6-͋ɑdqB oC|խ6u)nwDo!CxaiH YԧvZ8lk"Wż:4eFJt*`}킠Kh&%ww۾M 0p5 N} mXV8+OKzO qd"|w6By8]<{([hN ia4n@k֙fpDYUPPR+F!B8}cXDVgʰL| ~I&>&̒'?bq=R |~> =A }IHO`]PJ X%'b(]I|lM;wY%;Gehސ$FE hG% F#+)l5BYjiN&ټyoy²,\ %'Vea{W" @Pݰ]M@^VlIp:K?V+&ל6CEa;uƺ"lُ ڒ rQkQmN.p;ܶOgέcf3U4|'@GvG8u۲{U[),V&`F>w$ﴚITHyݼ7j_UY#@u#h5]< XF-; ~*η*ʂڇ7(*Gf5)5{.^cHX$HE<K$$$%G+2 2:nݑ=hˊ0M~ C$?KKN;s5ҦҦ*b&9wCʅNyk TVծbҢ)K8=Q?` H{;D?=z ukɍ,56iѬpҧ,4:-v`RՄSm:/,t&D,QnE\?͘f,"E'q7[&lq[Yi@fA eW xo!\̦x8iYsK%%nr糃#"+kVȘbm.<:"KKt*.Fx"quQ߾a[>+{ %rw(Y\ #pJ_B]u@(Z ΄:-5Q@vqI&]$qyEZ(f/޿KϟS("5cl{k@~zC^SN9#۸ʈW'd[tb9؈yzp2͸$׭UdՒZdRc*<_r#}4̧9^<|zsďO.9<_r:)xp{]VMxJḿ 4T.g^q9O _enV7lY”|1dʰucdcL5><7,k׸>ywʲ"ā? 2(iwW09_-[]V䇿(ˊl:)\KPdaS*GP9P#DoFD1&BG!~>%ph#UCڮxn'`L1M%T SdN6/Mã)2:z!9|O+=apw Ѹ[ɘ0Q8`}z{PIJ1~۱ҏӹ!gOY&RaYs[ y Bfӓ%8Zք7~nU'1mыTE<cBUB RժmIlLJl.xed{fUQǻ9G+>H Tin QpɀUBeSpޗ C4&sl ] 8B le+EJUF^"p}e uǠ%EU)RJ~>J+ 5e~ u@/UXe4׍-an,fL0М:vF 5D?0Etv2,ܪ:VJb4^dd9F) 7*Ӕ(Cs\+W>렳 硋 +b~ ^*;mcQ7(+9L!Fd+kJtl(n 7TYآBXR>U~3ue[4Ƹ$ JmQ%N4t]M`!6HK^UINg|ǥL6 _QtN'lhuJY[xz^*P;,0/m|/Jكqmz!jeF}L(`Yo⟧0"q7GKR 4:>yY3] EU(ɛٚgk&i;` 1(Ctmh /BaH^Oԏ\%L2++ULb%h;Rso{ u\IKE[ l3ы@H½8OzvA:a6Ԛ|2S/b5M>?FNo|n!٤!Q XlbaD!DWWRpmZ^ƄFvDT)׿ˎE}{I"a0<{(e&"J QƙvU,[j|ȟ$.Q'\ >%"Nd3xv-&CFS̈́ <*WZ~ix]i8o!s.do:0ۍmӕWC_2h#o%1X7d72 㐃ݺ:yr{NQjͳ󔯎@Fͱ+=lhcJPN@;Q'*|QzI6ӯL+<^m'_l6R؋C4^A{%fцregߩm u~o'Uhte(2EenD1Yph֧RQg5=/Y<e=ή7잙&Cq8=];ٮ:b9< qo-P&'{dr?Ngnw}P3 '>o-ķoj\h7%=(I߻$OIޠ}m /ejEu/:-IG4Z#憴[g [}Ѷ bhbjQGh9M]lh0 $iVsdn.^Öixx4:)"~k=8X,懋5҆Px|X̯s"Q9'| |vX됞]O;fUQQmmc%Ui-fLG(X%dK8bc[̵F D3%Rdg>epg͵cP5:M(w7F1f0F!AӐ=QҵmJ!PeݻW5Z8mEu.Fi ɎU6='HG $B ;! >olE(R!4 v[uXNZYn9qO ",4gSt.9قxyxd9ڐ*+pf1ÛOȶo-kø6,gpycYN3ΎST&0J-꺡;Ѻ1P "K'bl3s4ٿҸGQLsN& h\_k Mø }m;_OIU y||uDZj>~xVi8/JGƉj-Hmaz@gSװHv_űQOi-if2$؁U!PQMZNQ奨#t|kk09INT%"~?+И spm D!ɩE]ZD׳|pԢ ?yc + 3C(WaA YۨZh:hg.Ϧ6®^Qik].r 7e)cU4YF!U aP1[o1$8A/r ,r$d>51^+īDSAࡗ"Aq˰/Y\eخI2گ<)bo}IgYE-|e{GR8.p:H]uSh(3tۗ|;;((xSM7p9/fwUEۯ+{)٢$[LIp}F|ھWͳt>pw.ߟӹF{~G9O G׮T89ԒF9kB DĩA/6hM9O7G8QHLfpx@1 |nSJO sC_P[FA_JF8X1Z_z5h2V '[h[Δ{tBጰgonE3qm%Q$El @D$8fk5izFS翨w.q2qọ?Zwod@+W\ZZx`/4* @H >#!Kk q+ 奐'~?hHװ yZJ`23G1Kb:/8qW;f2ELg(OWט MlcNظ aߤcBsgC^qks1iXe/u(  )'jz$kpccTJڅ;9gܼJ\טuwo^*&Dė`yN3DIIY.4KM2ӌ/?6[&f1MK(V# "@.!3l׿(#]jCd{9p*5~*kI&ʺ}K<8y4=SLNm p5CE?3`eE,O^{4Ȧ_T= M߄{>#yR  ji sVjF4B:4 bpx~o.ܺdd8EfN` zwmf\Ίatf%唩q^ڑA/hSOjb]QI <->(n֏ UY V*A*+7<ji ϕTyB qq(U`5'LWtA1OkYs?hcM%c ]! fyI?,gA"f7d8+􋇆<"_q}{WZrHqmҾ3eQ9C@OrnVQpndW8 =*}€lS&>_p N{YSSN|<<m_7*jRH~w zvj4yAk#EYn+[u #.N(N2Dԗ3>nU97iKZRԖ"B.X#+@!i${gƁ=xm<;<pV;~p:˱y)?aOGf%b 2c^ZU(#Y@Y*'7 JfkCӵ&MKj&km(brP'()-xGYs;t;)ew3i`* {Mksܪk.J)P ӠmJ|p\so}[d؈ѲDgK,C+@FoZg4Jz? lAD8 1;,FsBEu<6\W =577C^&M"0 =5@|r^ץT.BO[Tfءs_M sp\xF*f 2+޿.Nhhˣ3*v.ZӂrN$ n7$`|nh4w8j9F8waDt` tBkZLͳ #I؁ 9B")b؁\84'ʮK UUxz|nE\mǷIdH H[&;ބ- $<l(("7رe<=Un#U "ﯴuo@'$2,F(nj_?٦7^=q3G{k'ާtm6q}Q*K+m:w;R;[^`"ku?[ Gcdt!1S A)K9$g8L^UXBC2RS|_N%E0lx2#Pn<96:#&_=\o_1L W9rnKV@`8yu,/rhv#"( UO+Tn eaG,]`NHG .+*&|nSZ1Kdos'ϓ k:Lx|id&YUԕ'9.ڈ`Ajߘ^cV RuZmVNS 3T):PN`tBy]B-2eDL(>hbLL[ޠStw$$u40 eZ0;B4q{G{سcZ)zϴcd1іQOoN_fRdNQdS $R6['K۴ N=%^nE=IrŠ]6d͆ x% )"bǗunVj=/V9ulNiCK#*x3/ieq~]sxs#|x^o{ _=#Гg,FWjDSjm)yy/atZ,ll8={Ƽ5m 5DI_ ~=OkIj)[EI6N"WK0kei}bc$[.d Qa8^€h(V5_z%m%{C~8WL˂e2/LHt@/ 2ny2QgV/ wRNsLgtƚ0V</Ϩe12HΏ@k~:ݢ+{~RI$,gw׏يj訍Rjh'lgz+dU]ƹg "Nѽ YNesخΚ7ߍ=oV.~ڛ1}=/=@AyF)jڼki2?mE݊ *6NS[2t#ڊzjneL8ęfuQy!jeֈaog~0[ 5Ątx>2TTyf)8twH9ih K6>^4ui~O#II9c>I͔ tN:ɼu{o:2?-xPztPt9Ew'~%PVCо#fZd+zBvA cxXC3s@Gd4go5>nKVcZB)h5sp `*=~KKO:$xd8՞8Yf1'Vێ[ۅ9,0R z! *>dI2Xןlrl8Z>ϐ!ç <%9\=2^\dvջSL0xp|"qRst/auxN٣8X3ҝ1jEyyoSW }%{[Oe:%vyEµB%zQ#?d%Pm H&H*Plm rEH#Yl$&$H TVTk XYbEAU(n P !%Yi=âgdg-[SZH3:_EeMz|7ߊa9[4<:g2<޹6Qsk@,a/ bk0(j4xcQ0M _w6)q=IK%CoI.zA!k>\4Ea0s5K71ř50a{ҵ5 '=vZ g)J ޼:;%9bL ۑ)n21oJCYYcv*v CZ`Ip iH=2c1K1Umwcj<:%_ly0J&O"\.JZlx6z,4ǣD>{ x2J PRQ!qtA&OiwV,\%qjqIp7A Z/T 95iLrw%Bt M!3y `{rIpvׯĦw2x#ḾizD/ׄc+d~' "w9i{_!%H- 䋼=olGR%ٹ3.ӌ`ۧ*/o]6&O}ybӿBunbU/9є4`f1jƛ_j8ob~UjlFKB칩 6ң}k {!>"r1S7q!r}n!8A&?”I+kTOeúY_ F zuLT8$F_32:O񷶘冼]hFm\u{Њk<8O_|'!.*9(">87~8zg?*CjY+ӄDV5uG\%?U(8jO"(h [O9 /lgb`^QvʐcNG)2TeK^q:w{ƾPy_3/>zϿyp~|z < $MȳL6#6!sY,+O8̎3T!CצByxW|~vxLw,_m !odYk#D8%OkjYUsz m aۭ$b~A-J6&;w&Ls:Ռ<_EZ##rhٹ~H4IEZY3XWnT5l9te%ƱFa8HRkd+@(e󸦩{i*LUv8UVE!DqNW8}?k+]ר`uyz_[֨>&V}aZ>UK>M^v[7ַv F`Nno_S![6IP8,ϗ=2=!m.O9ě){Of<:*) 2HEF? oĄN_"".J(@wѽ\"|/Ym/ 7Z_[? 9Ȯr;^UMr]g"ZzO[C~"ʖ,q!&\x2;SZ=Nw9Mpzj YyYKZ!1ō=tcPeY)*E޾oJ1Mn)D U ˬm5Sx]"|>]HʚËm؊ͻh#Oc/h:φ[X4e1ӧHzv@[,`DEc҆`wOn˯zP1K;T{=G0&c:SkËe7;DG[{E?B88Y/!. s)s J^&*.MEU]=.$(K'O$OWSx4<ŋ1cH ,Q`Y`eݙj3ٹM2t<=껫imco%aB8ŵ6x6҆\ӲAFW˜ A"s !`TLg'1"urKk~/w}K"@|DkIU4Q֎CkR!UYo[VzϦHlS$'iş;83ɸ)K†xUh[=,(z(Z1]ҾuG)z"n+ĉe`fG!¹5,@D)kLgvT|k--d<-? ld|~qG9MPRp|\wRa0NdDOKb)8n=$IDF ֋5yr/$m5G(&j,^w")%ǕBIx4Ukk3Т[Lpp2ei;`XҵA " Vt:Lyl9/hp 4ȖuH(49P4[óݵP&x3ϟ%RjOXtD^fnI:@D*nܤxձ8UU<>qO\x߸PD:9ܐ@6T#lTlz6V 3-8cRà t{W?Ny}[μ纴F0.;m"ud9Xf}5Nhm~WQPA6 3ʼnB& i$1#4aVyjGK= 'Auб@ /e-(~:}3N099η< 7_P3C)fBkVĩBpM2i- QgFݚkH7LB-a0^+=ajޖZ*lQ-ɜ{;KB3!zf qt% w֗9zm)^+Oޚ!d L\ :MZ"yZ4d'g(6/4nj7Lӥ`[da_^ l0SliHG22EUVw}MoDxz! M@h% Pq |1@B\@U{ Qy;m*-9Lӏ0@dz{;6ZxVfV4$*q" %I #b%+C[h(-Ov~F9b)m6|cal-/A<֮[ŎfkKHCWkyte^(7X%l.,ĉdWHᓶi$1  CI{āO3/Г=Wsy4rmgM+f9'1߬f.6Dȹɡ˫O^qVK 8jdt_WJ}6WOsLb\u+2ƩTQt[m]qO] 9+J6}ڮ3_RL,'8\uxkRE' rnKB#|k@4PҔ9?x<&C"eRiU@yPY.)7JQm!( vvYaK8}~4"Gh^PX+C]6д$$umٽNؼ˝Ōx#?`m`c_obF{eGgwϳ;qO/^!!;O>ji[}ΘhM}zreka h6)kTAm_e.JQxITB*q{Mp>rΧwܐ!} 9 Q]MCTsP)*w8*ڰ-+mI) kt`Lw4N}OƐ\_גMՏ_ .\"C[KlO݆,)=fˊϚ)xDO|G{[dş!|c,'lsɧxs(^O c(gҬi6,^ͨzY" d~r6&ux EPNYo X [Ox ]Tt?E:lQ"Jc&$ӷ hg 5M{/eQ G XPe cnB>voCi>nEU{όǞIb8DHNnH āx+"8 H, FQE2g^Ct~鞪}yK+>XM۷|xG s ;+Nǽsx=8drV?b\<=s6X圵cj QMoRCK]7|/& yz+<|rJҍw$NLs<ٵ0NHov禽tUYObg輴HĤ 7b+iA]Y\[_m7ily2EHIkr<|E#*k BXj1(?>a3YRZYum_BZ [e㭁jQmhؔCjsJ/DGmTYot ӂ~A]+%@fG' *[ {UAqm\%/'9v@HJS{p*?5g`ZwRD*[߿PlZXL"IFv1>ڀ_ N=:GZG\5;&{+}dJm `h'ro{oFIt%]V\Ir%Zmot'iY-Z}p@+MWLG̥=p߱BcZXzd%-՘6&4KD?v?{f2yM Y"b'`ͯBbį@D!Qk==]YIX nU:sd,M3ϯH|0,Ŭ`si~Zqꐻ)?=:bon;. e.~17T3p䣫8U!Yufh-b#!ϏSÒ{PFcnSte*,9MH E8Uu<^|E"\AP 4ԥMLW9w BV_ ʼę #kePJILIWya=jBlͫb?`]nN%]wݝʰ6pypoΠ{@ !ר܅{d%/6B8 ]A$liqc5.h1TcR G ) "FT%L:"z#RxݨPs9“Y(thuH x@Vt>*؊:E~kj %Q=2ularBĖ;o,l:TV_fq0)-sC2MJ\"SVUdaijc]ca5m GxO4IqJs8Õڟf~jcYv]7Y>z<{l WD]k(5+f:$$evBU1G^~ dv 4ʭEV&Іƒ͍.^%>nHW#;Y\ά'ԍK|}fp} 85}c{gqQֶ09ʹf Mt}.o= e Al n=~ďvȔf5K;Q=JZk ü2rX*tp%߲S E1u8">Rۃ7WcdCS :4ٴ% :v0i&c3/wVV_-4fUXnuf%jCi 8, z'PMW"`Hvi ^m!E. Xzҥ*5YÃsQL^\vދr1|ni %oA>;!~76L]NuQRO|w{hR^B](GaH*/EڳQa4gAiŽ2[}82KSI2FgӴE- p]ܤ5U8=W) 1UWjb[X: jE;ş'L٭i1G)4?WdQ@2ə!u."`&G8BUq`wVxf |s!Yկ,wav]J$%a$3E1XdVr\6p}.wyf5a둻q.[DG) Vm+ԺITf ģc!^OZ&DQٶappլXP"| nAz~ȳᅪp.uHf*`˻ 5MOh4 ф$oC9>jRޡ5߆P[9'_?U?g<{7QaV"H@ K X  vV֖. )`Mn}̱8s}vUiTi,{OqK6KBƇ3T!*>yNrօ 8$ĿFQ =sv+c'sʣ]:.u1GG3R1OvzVp:X9qءўO7#"Zk KUsܘa$(cu҅{1qeΕ vąC$&E%3Ls[u׹S,kYs{v|g 5L@gwScF>:5`= ofL|uc"R٘_X BnV@[2eNP`]IlrS7V\l&fOVS}\yloXJkMZ;t)\F>WZUv AE5Gwݸ)~xq'櫼l0ÜϸެA[ J錏ICrvU_W̯K  U./9q}^ ȵy2;,3axaFPiClt3ҢsP SVvg"H=WUZ1նTc*9j<{*Z9ϻb7MДUy]Hnv[G@Qk\E2AlFʤXt6J,,w0 B$]&T3rh[)uߣ]`@!IGik‹#4'cy*w%"(06'B0\gZʑ`(%_8W h&1.X&{`z2dۄhė>#5A5vl3J4L+ؑ1!]3*{߰uIɏINJK 5^/i]=0:.XCb2lqwl"aN !Q>zKPsT?M[ ._;xs5ډTY^ RRh ٿ$(ɎT;خ*NC:J:Q!-k$-!؄ BB,"%LPӽ, K<{s=t)1 v0x晈np8J:7!'K=:,R,GX˰V#5}{o83V>\o@K8mzUEe47Ca˃}zg#>hS+tw֪ŭuXR3ѿ\R+|á 1 B7+edcPF*-E i>q7"j׈ Jݧ  Qem<՟9WVt$ggk;[;VPJ`oHӁCªG/ 'ęϽ!\_iiʣ!7֗/36/2ZDbokwȓ 5*J U%=ƀk?OSVCpy 15<2FMINE BQ Vy.]UE )4EY oHH0Sok!r:ATj v$)e9̴<̣XiqxyS1per^Vٕ?/~}kɦd 0h.$|M0H2ה %~xozҥɧ $i.e-~R.k̎7|TEO3'NGe7tc2C:NvXZ#{H(rsڍ'&',ߺ\`×}Jh>= *4Y) BkWe֜_i;@PAH V^U/Nȃ&iTc)|" 7zcKd4^=(aijnll ]W4ߡlD-LW')`=)-;vӒ$5 R-;!JFkQYa(ek4n|,0I o`jfMf.u e|8v,/ȧvlQ^ěbuAdӌ`HS7/jag1B:^xH6!BJ/}V?9vަH0Ymj'3@4#FR+hEK}~yxQA|:_ EGirU>tLf! b(BRT ]a!;^ oKp5W`BJ")*U$BB d~t:;^vU9}=#wCiQ*0wnK>~gK!77%V8R1˝>QZ%\Z5ΞÉO+pybD'XnKfC}D# :es5 'Y*e h;iWˋMz<\}<%v6q ?&"QPdl\~eaor8yp&(31%hWwLS Z;?9^|ޘ:nv|cQآ$]>nmGblC>\VmcNul7Ez㌯yY9-Ib1q2~c|\h沪l3*:r3,Je6R(*A%PME.rZiqBi*5abv<1w؜0* &zϧ,^X.{Qf lTvgNDWaj]' 2a-Vu>ظB/_]]O*.b>dQnÓ=H`+;6˨m1H$늴[2z1?4H㵅W%0ǎ S|ik' [ȉ<2\Ui"^S{l!mFq0q@ Hm6ru] G9Ul}.[;hF#~3-F9*6CRc[f B9:PRbOOwMO,ijVVf' )+\O6}c&HWa K{ fgT6zMڌlI\S$ÍcdBYX9ҽфz|򮤃#Vl,]= y '8EiiH'^nř$Z'ږ2:x[NIMRnb`}ZǛu+l\p~,Iv{$}?U۴=[f[ ٲed $$@"$$D @HaX0Xcmxfku nua%RU{~px ju1}ũ&gM֙g" qnW]SnJ~CA/Xk2uVg̵B$XC r2>W=]{L#lǼzv47Om, n0L e2 y |I%[֠ge%`PӼiӂu.pݘO8_ h1#XGu(-9wjo<$jj,)О"spAi,YR8p9rk*B+~̻痝'r 젥K+m#WNwX~Zeퟧ+aڭh-y~͍ۻ#߫hD:@g|&'ܿ.:Mlpn3IdZ1EI03iH7!Iځb8Ha\BK2S Hl(Ҩ"ٶ [D 堋\4eAD9`b(ӓp!P7%8 ]gI1ԖS*, 7I sr2('>9I| ^To!㇏4:>s8rmFHߣsjiF=/2U2'gKK>L\ r:@M^\}l0*&I!jx מIDATh+ʾ`B)^6EQu{69xTiݵºs@x!@VѿRwr{EA4~e47\ X,(,;)؋ !7874|0+RII @f}d_}0x(^{DjN[lL|shĨ ;RMev4Rliډfplla6&/h.?[[ 4Axo>kz}\.[EmWK! 4iߙ>\qwc>ԊdcūNyJt$j!ו!q׵bg B˂h$O4¤s/_űv^X>G:~+c>c?Z?JhTll,Ux%LHlӬ:8 LsvN8:AJ<[pu;`e478ݤ=@!7^$pfR~MpI%vCrdE`R,&q%w|cmW~$ GV|3⓳]|qjF++ T]œqshs[:tn ?YmW؜t譣<7&2`qʱN7xsu~6Bh5kuqT`9ә(# vKapW -xE},9j$g[^Γ Ӗ(h i&찟uґdq%|˜{7 ͐EpY?A&nD}ۻ`@QoTf;5gN1qJGi&g>2yvL(n@&ؕ dz=ݛIPԱn@[;ke?&NI$EBBƧ4чW T>?UbXc.fn# [CDrXT^(t "L%׽?ugLҜ-qI6qdd;[ŃH `[ZpP~OǼP`sOEuG]A)5Ph_S6#yĤbPK\:I7*Xpi򠋨5)oC5N0 ܆tGD-u&o04¹R&,<*> ӘLv=:'mC7.\zHo$ `Lsa$"ټclj^" No>q΅9, qzp;7<ƽY^7tZɗ!K5 ;oU٫/k;9BBj@FBZt( T%M0{wvfvg(xczYi4J3s}fn]%8{^ĭ <%9ա(+(Cנ-LCnBC.[q$encp>}~g- иy uFl1SRc2؋ e9_߼,8qκgYȉj[0ʛgƒi.mОsŪX{q2g<Lx?F75> 5 \{Z/dv ll[yJdx6YZ β?-y: dTLiI{&Mam(`1h9 &|)llG,zIAdw ,S=4'J &qJWmĵt ]YѕN&?)l?-h&els¢Sh <-?A:hEpfwj1ZácN8:4<ZU:BX"FJ^:YiΜ%|%+p 5`85Nv,★rFe5]u4e^ǠBnۢ%'^#I"J1\SmwC؈/99>@7 q lQLc5%=M-ն=H!x! ݳ"u<Kx}oMTV++UP%b7>Yln_9/ #M UJ\3h՜a#^QR r^$D4@:$$sl4W(R唸6qĶvu]ҰɞW1Ě@MÄ!e#G4=#gє4/ӬDx>oMR0U~;YA] )Uӷpb5¼bѨ(1d>UrVpЈ NỸZ,ݶF~л5IF!aS@> S)O(oEn4g(K-d`aulKa+]GgXEOD3hOdCNMG ?<lc/TE{#^ gi =;p\u,>9u3fnRQ@T(߀ѥѥ$ 9ds1x?v=dx~= f|y\yik$sC4]\4ώqd06T7بE{pBԝ ψ?z0F>hUx6yW750a<o7 AiNgę;hs4YF~ֹ^*7ꕋxfs8|ɻ[5|g?ƛF5/H5B&dJ+c`T$g6S= ;3>E_{$٬16LKQu4-naC *C?!E,Ỉ`2pJ$90 y+La9j4#1%W b`@>A";mAorC6m(5sO7č\sgcddUM[4fx*h`YUftjBj"-e\m"]}rM*R &@[Š)@"D3Bj꨺+f^~gJeVZgɧcժ`wQHtVv{̓OoOKj J?7ŝ/.{f9ϟ=[}#ylsW$En>M3&YhQucBq=h2dFf*pr+pTɌ-P  ʐ Gl %ғG;'אkԷ<ϙJ_|u U7t_9yyʝr|<5^dUVRe2_~ ?\Ը83 ^y;MS)Ɨ?~͎:OWuMt{<0c1xG (HHI6Y*7 XE$n HDlDQ 91fl]N85\} :WyWtIGWt@ alZ]i CgR$ܬl6KMQD^\+۔>⸍حd 9\b,jOxbw@m F1׏9xJ|tโt~ȋWvxoOc[LV%V%;q݈-YxC=Eh~z@G"##)uxojYTjUIV1?C*_Ƿz:EsP.-&[ZXkr&ǣщ|v;T!1J~2@tBx?&[gwOkCKvSўvW輢6_Յ >Hcou?-7b%_Ql7@|IUh ]Q! v[vI -wy?pFMe8|WPo(sY J\ *PpB =3k"J.ZHe/@f]kXyOcw{*O͓ :vpӭ{ڭ$}B;b4 "V|=xP58 w\MVp\ZU1 #â@Q-_:J0%֐yw Yý!ӆP T8&u.$CIlYW<`7{_]DCFE^{S'f7oFp_A¥9\05ۡ6 (hjY&D>M#P:TxwTix݀/P%K^7 6H)RRS| nEع; @(/ǀ5π $ĆUXD@ &{f<@Zs~e'%~UƖU/c!gպG(_k-z94H]:N(ʒ(enmlƄ kBMAo\7]^4==nNCwºGfbuݮ*_4O_|/VBvai!j7noЪQ U^jLm08Ig.Igry( 7, 6E\Ƨ};QA0cY\=bbmtMzc{%Gk,ݵgM$$FH:#be<<{grc{0ۃ(;#"V4.`.< 9seOzq΀4nΐrHŸNWi0AJpwG%s ) QS6$J{wfIo i*~Dh$uqCVBV4fvo_2t<=@:,=(Ts)rbCεUre( ?F8’ݚU*;ƣ p*|<(N88I %Q?X$'l?.uW7(+J*+uvڅD=+-r<:ְ5n?"tpxs!?="RTECz:Nɒb1{r:ҙ5 P;wB 8~@-ϯL2E9pYj/(Z6VLfǯ"6}RYշk"tn<\zZJ8-II^RQS>]Qs{y֝hi}櫂N )xPdlB6G{!5%FB-/]@CPYP!_EC|%qN׹p7tGJMJox|&pI̲b%Fh@`qsBэ)|Y9 rjSF#D}aT6.3@8 #Ojops!nBey.Yf0SJ+PFVeQPq]K;Iۃ F VGo{w $Z^FvGYӠ0%f9vZjd˭aB:8jxamt| 6!_nCəGb5HY@Md;6@PtS(^4mdW8Kps8 pAy_i`eH!ٌ],(^csR :EAtmd(`tϷ1M^sFCN^nH )?]7 (#ã]byn l5R i:JLw7Ogڔ5tW9ERpoϧnK?" dqwhcьjytTcŚb,zJgJHuy?Pe9w@2: ɝe#iAzW͋$!;smBmIhC!'oR}նxJ<{;{|Ύo3O :->m^l>gQiGbR j":qY€y29.^H)lShq2-w=N]TbUTu*#p-ۜ8'Snu5{µ M;BE ^͠,h6 JyUW`|*1{ܯY4ƬB!45`Q.a Z#*tݬtZ:裊 k!tFیli)놃7hIvҔ: (7;;2gC8M즍-L?HPͯ0L*ͩDl.EvL.UU7qG63 |{}}+wZ'mذ4ki͖nWAA& :Ww iks냑`].BMN׊(I[9,%VCUNR6pYfMA]ۡ'11T +qb5 )2ɯKTq$ŝY}(+YKђ'E=₳+VV㟿ㇷ8x<~ȳ(;.ip7*&c,H4EEOXG)_juKMqBb|>%x_f֘ݶp#&@?|G<*|0]g7 QYpQ @w<d%s*y!ec e#,!岭-5¶>u^!S]>ˎEV֭ݲn.4hh6`6 ^W`;H؍4#̘ь5m]]]ʬKDܤ)9_I%XS\_AkC )(ŠKʪW3ywHLo|rFͺņ< \SuaCfWz֙&,)nb|]rbHWRIGo;u eypQ;芻Z)":M1Goz.Xz1!!Fw1u'FJL6 Y\>f9smd8x?oow:ߺqhm(V;o`1x^껬KIئެMnb0N 8hq؏]n>]0E,YMmS G33*mq2PPצ{tAEJncNW)K8oɓz>R_B!r;@E!Nٌh#Y)4^3`qė$g &?'L\KoU3n8&-M)@۔hX6HlQeǂ 6lXu  4M[b=s9,m,ޒ-sf}ǕT',F͡Rv̎Sc8fR)@ɒ-v{#><3O[]nFkϑ i%׶iPrq?qS+LS4yϰ /2weY"tZC*ĭ >^c&괂Q>"t`̿'@5:+>_{} $|̉'e}481x9Q8Oۜc Z^D4 ZI,((`jJH8Y'E9eQ>;)EZx(r(;#ħ,JzxIDanfv.|1ߊ*5V(EL3&?'6#(~xl ׯ۝3{;D{1y<iQRj#ʤPб芒W$M ڎ1gxBէIHB:B2։E8S U, ;)CM_O0Ʉg!Y<7 s5&fYYF$̌e*s"]#@e9tFH_13s~!d{swOz0ފ8P.@*VXxJ~!q)c$enqqvyG;a:QN35(\>"2S xr9""ǜ!.7X K ˡBIX,^: P< B3݁&ʤ?A&=D3` Yc BPjwcc3 3+0B)b9*&1: io܋)&}IZ a+"r֗XXCV[Wc ;lMDK볪։Lч+Ѥ̆SI?!-q pg@*SӔ&˩_\dڛ4"J2jz 5T搚Shr3_qB*dmqNhW/Q{:^> -IrOq} -@b ՌS7:O׻LW6n!tRiX.C$͝#J>VHg#4C 6/xD7B8'ЭE962<cm ,R=F2/?~O.O!;P&|돲,qIJ;T{?F) v&!IzNGuAu֜DJSvvtEz^d AҤ9;H訋 K\G:UiqƗNLL (?"> ~ + BBbĂ $&{3ӧO>bQvvY?[MC(.jԖ_|@I>|k?<8! Usl =M*[mҺAۣ6Ӓz>P`(ܸIX|}BpfȍKews8D;$_uW>>`omɾ>Z4^k o̟ݻiFx{Pw1 S,Y|3;%QTOcuoC0&3e>ڵ+F9irw݄ΨD?˜keB nB\݄&~KWS>f&8Qbs ;,XlX #"!H dqg.q=Su?UX]-}Ǯ+\!kqbIriM Z%¾I 6lfsM>OJz」̀+/@+pLI+D4ULQƽ GON=[=5jwg~[C4U'v ' ~?)3GB:_L'Eům+~Bw3$]]ۤM!y?N"}sGLn }poĥ!zum[cM:ؖYFQiizxRRc"R, +#| [f? jfIm *pW ,vpnǪ4$JsۤE ]T i;Cc["t$^Fz0Ug)޿90`;BpTD)-ಬx8@Z-UIi.-Ғ\itӠjJKt;N/ydՖE۲[M/Fo4yJ=!Zj5C?*C7ۡ^"<%8)l-rDT'_\Ԫo\}q,QQtO0 D-UQ5&rs6~֛S7v &2.Qhj! *AW1):פ,Yq;m!*θ؛c0Tuž:BZz$e^nx2,)6.6,1\}3= ]t jedv`` KUiv4AU!1VfVB"jA712бp$UCvEJj66c[\R,gf5<[qmL3ebj{=ϏHOsw ~HƇaQ_:yJ3l} ԪF9UPq\mBU^}.OK:k3n=6C$J,"E(R  *RD?- (( r=xC3R_!;'jeOӽ@mx R[bx5&1YLw&xcMx6g/"Gcp⊟=P6VJuafpL"DO&K(g"xNxF2]Q&`$CUT(OVw5nEHMYHZ;]ZiN{<s~PNE6:~΄}^`5n`M\d)S8*;q0!n8NcrrFIܐ440Њ4Қ( E9L7󘿽v7!j*M797AW8T!ݱgw~rs_CWJp];B-w3,wټ([PJ3+r``9z e^q!,CzSV;Y+A$Ea!{S-x`vt0Qe/|}}“wy.nY۷n\Gi>{QBkJ5+Q*gxn?z.=7I9}Nk1Vpv5`ӳqď޺09ެ3n[;Nw'URmX$tp Z@ Ur?Q߾|h.r0tEQŐ,T34Q Y \cթk-Q(,>S*zJzaFHB TS { c&ɕf{ohfĦz"ow`pӉ7"B٪I3 T2E|c򓏓!BӅ-Kl=@}Yߑ5b[oQHau{7q#8-oxYݠD@utOaͬ_X}L ;Cm>N5Jr<4|ؖkrl,I<`2;Ӳ jM  %`Vl?l_'M$&Cۇ+xϞm\ﴲ&lV 12GmւPV1. 3[Ij9A8^¸c] Z! @Y!(7&F:wr9äwd4ȥ7ץ!Nӂ]uKSvshVh1t>FV[dIh7<i S>0)Hi@ ia{;2N ~1]d& M%8B'sgTV7x&*Z_Ȓ +}\)lиk\P9JVgokrs[gLϼ0ߍl&0nS鮂V{)T:_6k/.Y!p,_&K#9UQzH~۹Y(3i;DlD>kݟqG0K}VʢyJج1]*Olsr"+$cd < 1+1noHЪj!]$43ւ|s/M[GWg<0I1Qg)쐢 cU 6Yd(P 'x8~qzv;bebW~WZpĩ9|?[`zH3%ﻌOc=fg-d4Nivgj*kvM.+ ^䑔'OBZs!(GP5?b^1jk[\&7ty/߾NxHƷJE>Ѱ8m'_Fg#0yJc~8,P.R+t}ڱsM:)l3gPPw@5)~F_=nꮾL7C9DdU0@7]Y)9y,  bCe.CrHs{WuՑoЋ:SҼͷ~!Z`@K:߽)+lciKϧhmnіm \D_#V6{}?mJst~ikER5eZINy$[qm9ȧѨi|t\®KU*ai !mČzɹboqpp{3bRh>.<|zR!SnR֚/OXLrkvyAA$~~Z7ltYZ5oC?ͭ+\ɌLGi(jͥȌm v!m3,6_5&nvech*!])U&:R;.4 Q\1A]f6bNq@A aY3r U*ŝ1+4g1+5k!v鎿gH6!2HSKvN?cܷ?Pʢ|tMk⺤ |:;!|}"4E9.+yFnK R䙦ƙ %_EIU,:+-Ta@7rK;8,l-FG*!]dr: H]"&!ډж쵴O7(Ai9LJ&JKвIPTE@[Tua 9+}ᛳ~mü]YEN$?Atbrupɿ<*'dX~ 2> eE~u<#5O lXniF8ԕyD՚m_]p-)W8HAS}oAқ{4eA^WBfsݰ>wipp쫿a}7~ BW9^Y+slCmH۾C:;^J/PstRbxmgo*rϧ&{17&~mqFtw vY~*=9lm~`8OO?(-I ;؝kXV??n%W~9u&Н%!!@J$$E F 2i93$ DB$5ms|||nu7ubxjRZkoInd5} Z]{ t#6y!W 2/|o]Q{#U m ugRiKBUG5"}>M;U mYaW/jIcŷ78+Qb?\5i )&YeMQ*uoJu|19H#|JmY֚n89 ati+swޣc tyMѓK$?: d/vuCv%*//g4"NNz/6P}?G.O1 H)_,֔KVS| }qŘi[]ߴ-ZnB(puBӖ 3[+lZցK`8D/Y3F3}S)2]n{I?Mo7K)Ed[n( =h?JO,K94}SpNWUE"%.יqtfg?DžWqBiW<O,[!RiR Pc7ut!{G$f28?^`MZ`^(Rz(k; iQ.x>)vieV۴}En>{@ 'Y'}ˆ.i*@CEU6*n2Yo/7?Fc-Y/4Ӓ^7ˣKh-i%jiGm~v{5IHB$_ކ˃"M6A!* zJgU ڧJL2w-.f1w!,݁Ԕ&LhّshR{.o5Ö9Po`#Qx-LX\1r{ق;Z>yɒ{;2M H;>ww,K/ ^_dak"% O¯n]S~E3NK,ˆE΢y+bnWU4 ֒PVeeQ#oB kɒlycyq#a_K&RWiͺinXy|=N3hU Njmj c8/j|j".V4^я4sa )Otg gn4yI.6|lV̅zV5R; Cp݉*U*T JUȼv :S'XOb9q(ڠznWcN`lx]|D>>twY3/x{owb| Gu?dg$0^-X|5ł2ͨk­;;itdHMh"'n2Y-֘r| MG]]==Ϭg'`lHxA ! .#%|J.eE0!{z3;;ӯUšzWkJ<޾u)1h`B+1'+ͺwڀcuHK[I I~>#@ik֟:i\;K-Ы!ereo7ɽ-BOv:ݏƴ:~OQkVEMV)~|w䟏'59?x1e-(hOf:JKz_F1sxaB88Z_,+=1[oMt ||ך'I hp2tAKb垇vDNSdD5#Xym*عws5^99)#OLPLSD5 lJxofȳ%x;l q&QD滼 ><߼7Oxk͋YVL {Ji<O[{8g|z?bܹ/q6 '𛽡UavM=lEh% 8-R;!n 58$ Ziuf G\=%\$҄^1J[qnZOWtYXiƓIlUa0\pHc-Y%2YP\)HN0Y e'm(ys0Ӵ!نPKϐn`ftHx;ᡅG8q }Fl8Nm  k8U#BFI`0^L-mrCh|LYҨ1oIǁYy8^:Z4\%# |w/Ej(.dKƞuP|MGUկ>;zmg%$2H/D{.QʉwN!9wH8B#:^g=;骮*5}~y~3̰[d$ [0 VM g`'P#;sd)b鴤1b[cRR|V?*~1NQvGLK͇ <7VWvxOװ kOynX`Ʌy͛~ɀ?OGuZ8 #&"IˆN/w|K|aV?y .1JVEQS0z,jˀՊj\H @ϧzVq΂Rp( ޫJ N2|n>}{봟`ʚY`c_!7?FGd[Ħ=|.N7Mc>E-a#Uq+!$7F<>G:UAo_7\T1-5q&~=Xf;y+aJX,'-d@PBNj\Y@Ʈq\b)1sTh%O=x 0AXP4;z~QC\1<=jqS;GiBQ6α 4v BQ|Cy}Y4 .Wj^29JLFTi`.nbָa6YeHl8A ɘ5RuHkia^$JNJ8ZR[:IL7= uc&[-ޕûumDۼJԹi"{ xw,G `Ni}{I+4Mٿĵ9 vuc,nVϲ()4R\!5!Z^Xo*A4&^"DOpSOԚΓ'9F~g8$A9ѳ/86ŗw9F~<514],5$<.1eY:dƒ7(?8QT:D/ KoUS.]{8q0I FH4_Xeņ=ٌi% Ldvnu;XP9}=vu3Ƹ!s-i[ ¹Β6%F k?pgXBtN2}iAFB|َqomϑ5K3Fv*KC\m&{||1)RBJ[>g].t<y۬nPh_u# hWZL3b/Y"MڸC\LڡJٹk[\_s /ظң;j-\g,${3>4Ɍ[=)45GXTTlsڨ4cY'OeJ tΦFYo452wX۝bSVLf)=\YO _{FLG1NգvcƆ<m\Vln<:iuq3)K>7tq-_ *郯  +[ت4FɄWWJ'Ʉ8%S;xlěkmGwvD)I'L  #6_<>aw@kS==>O#0cG9f}Ms o] (:ʣȭwٗvOb&wBqcW. > 1e1IkƲr]Ұ&ߦp䤅JYL7p֍M{!Y@ w/HF$4!6v'd,ҺLN(9rik=ȣڍ?.]%*4/)RCh&s%T&g63`l ʹ&u.5H ̦tiAŚy"5eQ&-1p&-07YZk\KRToQ30mG#Lq&d{ KFQz7Q|)D ^%aQc$&J·EFpvr|؃oH_$-Cۋ3|)@6$gX?D19Op\,)f 8Uln\n 8(N1)W_VI17kPi.U:Ȋp=#Cf 5+ߑ+EW~8I뼾G :kdvE$ӨR j/ ;OtתS4W6E`mGx8suѓsdwEƻ$d0$Hr^ ~ K 0Df1b$u;?KGӧefαgl ĊM"@BA˚ KD"P X$mg]Wyvj {"YEIKQ<| D6SI0t;"ƳE1x1sm{ZuGKW0xl< ك8FF+? 8']QR:!+`>3`&I}@Sx7HǷ셣޵_s(4b}FH:G_4Zcʌz9cpl)Jقz\~7)adeE5Bn \DeUMk+p; n'{.}>*qL~:o=TR%?܋K\s?ݧ/scIOċHR$b)6l)C@,`?@((,, 1!` 36fgWul8?VG}~\. B.^WXR&f ixu4O$H˪g8`_P3iUUXeKR!v-Eܤ"yFvuF^cpA+$˂$A"1El"~>.t9VDtAuEr~AR(^ [>BpLU&|f=i4:L2͙F!A)tIݱ`#lJ w i"˄kQA* >@/P^EM UEF^{ģhVnӤy쟿YPJeLGd:L$k$_soo~,7A`OAİ]fI{ "ݐsϒ,'19{?qW7xw-؛el4=^o3[]jFAfeVMqVovr$/>iK\1";;D1hd% a]G=;\؛|z8gk0JMvʀ8W/2\[UْfdJryliB6CGwY4Z ^xa5EmQ,_>$'p4(F {-s A߃ &iAW(O/ PеN"AaU)[9L%Tf ̘XR2 W,DV 3E%rBG`K0h$ i6[Tb+\ R?@8)x/={'˜]iō8/lLӒV|re"K]ۦ*HwEl7$ه➿LuP?hk7viXGiNӱxva(U2U+'PߴB aXQ@VhC/ryI^Ω=b_ҹC,M1AQayɱH {G6[4}`qs{*)Hw./޽Z!iuQ~Je8;dhD<f9h}O\&?xwm yШЕιKd1<ƍBRfu]G nMˌ SfQV ~;2{%LokMo$WUx=vwf<A EaF,Ȇ $ Xv" @$Qqfؙꮮ[^ _PRmyxm4/jY71bv66y/W+]Ɲu('t5 c~oo5Q8y-Igs;6#۽{$:R2/$;-ʄ8?Ĕ;mK?}v^A^*TTt2_Cȧ29#❾Ӆs-DV8׬\)OThW0-Jӯ8K#F;9_/Ǘ{woRMޥ np^h[ 61!=kgw ۠x珘mh,q]*T%Yna=,(~T&tN؍֢'EY7+(FkGKKGU]3w;~&!adOG` !lH)"aCwwOwOuLeTUsqZ+Ư*eY j z1! c)CWa SvQh=f-\|o (M\\0|wƤ?|E]ejp lJ9'u1s' c/n бT)4&O) tk)+iԚ!ϓ4#k.J wcD ŝ uGa,*w&&[UXmQ }l RBKdtg/92+)u!&Ok7I1&Def6Bt7`zpLr4tkw|d9OI|]2;O\U;KD`g|_"74ZKZU W;=|_Puk}|K.u N?^]|#lOݍ;?fqU坳MfKCKXS-)w';c~v:n{iyZvƓn S+UEVrmc#pJv#׮`47.r.D}&O!ǓAHj' W^/Ʉ(P$y­v^Xb},cQ5ӡk5\cChQ]`'Lo3|gHߣҪ9=]yq_hܸOnL] ɢ(ݡhWbt=rm8MS#-d<^6`9ڢ]6BH\WDP-k!ڠ%*:y=XBkҽư?v'\S%9'!-t>OC*{>V鋇{cj\=hq< <7xc#f#te{YnIK=֭$32YI[װ&P%( 5?#7H$["dL $<>19I\'J!I5Ks3"%xx8yE"9CLӾ:s ; f;GےDgY'C[wht4cg}K6:孮3%~O^ zk羍dJ?yUFμ!;u62Ek!wI=#Jq=>~Cmw2zސR2]jQEѼc耨"}ɬ-Jf䳔n!7H?;osr/\R$E eb"'SJm)R0"]"R.d $9Ɏ )-:;3;3g&YN}W,9$<.#,fI2Xm |$8`eKҕ$K?PLZD*| #VC uy~ .KRA)LjPKYI?.\n),2RPθ,0YJ<FK(q+hP:ܼ0fp]eY*ݚBJ8x 5%d8&t=z^ zC2mT#)o bK\wSm _RqNYl H@HF?f~4$ c7gdP,r"+䣌ͽM~{CW(qWЕS.VVWZ|g7|v[?Mq)h:+-[@#DjJA`tx|Ȋ.ArbӋ?w⃷:hg'owZn\ϲ\ob̜S'T?ɳEn83/)R)SCwhauk޻zu~O.u̒ ^lۣ?fW-7_~NeQZfrTJcF'QlvZKNi)npQRӻP&q 3RWی(Y,lY@ yܔҒA4l qh STB=aI"E!,Ǹm 5gJA-.yapA\%as8iV $sl5ÃW8Z&qjXd EQՠ?[F8b3[X[uޮ3MItsnD/,|i6Н k?^?IV@bKŒ)IrC|afP tS+ <|g2Uz_v[Qv~u W[>eGGxП-7a|^t4HϽ,۳g\XTj㇧}Qp`d4#34ĥ#h9 bᒿD^IH6CsKx;ѬҮw&qJrYb*r:aœkR5p6Ps] vM>r<7 (rm"8%*ȷ.RqL0Ar#c{wHdtqD6y"Bkr$<莹p|wVו59֚a f.DOo,7h\W]{*uzmZJPgLit9lm`i`N6y#dt}(Lګ Fm`]a*&/<I~U:DEgpɃ/cNx(W磘Mno #ÕUX=:OXf|٧UYm7DF0YEQq(6\.8s4kYqasD1&㛿v;=4 O`8 'l.b.zC= -gKg59&lZ^\vuX4tg(͑Z:әy4)+j~WXK/mSm2\bn}>!?g2IICcIF!Oy]+cz2JH&iNiJ UcV®xVh3/'Э/o?g3}:vlM "@BbvRTU}Un.*A@`#@ I}m3Ź AYskPh@7 a J \eA)4ܚG}n+Tf5 9K %~w#tY*i.T ciP^yBPKiYImN}#SN{h)ЭZAfu݅ %Q>C;P:]S2lQ OǭDZ4x5ngajxNJԝd/l-}盓 vFmz*\x|ASڭij [[_Nf2{(/ ]fxob.{ :asQh_̔Z$j_`4G;_a+~}~towЫ@AT_(a xF :;LgNxU~zajU[3BŰuo^BVqY$ >:=ajK)մΗGl,W9Lk_?ʟ?O.; acl$۔̝OFӔs<e3%+LRI K t⌳5IjϏB^:45jM֚C.o-kgg G8텴"$IX:]E+ &s5G]u #͇0nog*.,iD!et6y+#mQ: FDX*ͧh߇n4֑N9iQɂ%LDŽm:na +h8c%UK %&h{uGþs zd/;x:zc5E$+a=ׄ4.RV4T:MauB7I)G0A%5 p?| SN9oEsC[9Wo)F0b1L Gj|2Tre~uaqRY(o&sڒg^Q:aB\G6xy.^F+tc&kj͒kȒ8O;#vGqreoMHVoBLͫb$4SqL:nx eI{~GοO4o_Nhy\a\ZIteHe3PfTMnI{I`" |FX 22T51\ o"slȬ@7Ubqjh=2xcxֽ oĝKosFrx%JdZX.{Hlh ȶ.;M"ˢ0ZE HZ8$;+I&%Ҽ!>]F!?9>#5g)$Q JRŎ_i:I0K%RQr 28{S B/vh{FF7$7f?T-' ;Z 1 ΗC &ap>rs_vsMtrӒK/, fQ4k ǭ daYϟtY*dc=c_^kНH]#mKa}!wg'/s{&!׷Z?NgZOFncП),J8%[r.'wH[@z!IC||v姘^Y<$֠#.]jۗќ<ޓgkMDG=8e|>1 cR9ǹi2YxN6Z;/(IE . $sd0EDAhId$CJ-Ue {Da 41 H |&YRp4s81Wy0ӽc$\),/hT6_M傅tvN<IgcVN ]~Pb#,,N\Za"c4VO/ȜCsyOxts` O180ڔs:56as4}~h+25&$Jk4I4)Ѥh\pߛ}}%Ӄ!?JewS.LE D*) dr3)\"/ SE9qMo]mιb6QIdI#AA6+XV n[ !U*Ģi H1v~uLsc :zyvZcT)פ*fjlMQ`94.N^8r逹: fdJaށy]st zfxaMฎ PSdO!@')Sҡhŀ$f&ÌR nr!U #TQZqyqɥ9/2#\mqK~PWui.2 >L[v;f%ˈ ՗,eӫsQ!ʫK ,^/NJ¦$vy )5 I$spTo|>jʕkJM\#Ӵ\$!]_` +󿒇U`Mkk88 kz"eA>QcW8Tg.nq{4¢Bw-H0 ]] z~T7M>*{NNb{jΧ$K%~y:5fL*|(ZRrwBd"Y%oww~蒧˯Չ.{7^Z72R.EPZ6sGյi6Qwl=2!5cy>QM؂ZùwҝƲmj;smsXxks(|4qspl"0_&=eRsy!b A1d Zh1.7cD0>,^7OY9pSgtQ=ǔ@QIFt%;1jvwl$ 0L )B S aʭceR%(8sqdSD5$7M˂nO%W/6璛;<ݼ쐍Fg%%ڲ$ >'?⟹F4 H; Rov4_K؛ w.Ѯ\DxXd|q*|c&Di|p@9tx~@i}tGxSko=O@8 {\/8sMF~ֈ8r$($\}"NL$IFo,ϲ n̚;htSM M98a> @= 'I|z>GX8,|Qg2W$4gϑ%VoOˏG?]Uzw=6k!vHd BH )q' $s"$P$$@(Ncwgwg]j }sT}|~)ǜ~ԝe,gJplOAgj)GGW<6+l,' ڞ 1M w0pͯ/wDR-~z>bdȊ/x*oݟq73gp$ ÿvs?t.uC$:2lpk=tH.͟0Z&!yi{cf =n$ϕtJڰ ^KaG}dE盛>,Nsʓ`ߌq㐭lhFKt/c/_S\l1ǏDu,̀t#䋽_@՘tfA\@e1l_r(pBvP.!N> pQ`O AT5!FW9!k]X3+Kfdjg95Y^YjpNf(!Ȗ{8SOD8Y\jlCL+"{)[IFyֽSspv2I:a Wl?bqXo\_B9G*,+8YB68%HNg!?z->ZF쵹YGVNya8WJpɜM|%+Aq# lK!*֫'s:7{6Lf8a![{)^QJ@VVL CW8TQ=DQM_Z#A1١Z07)Zy2EO֓N)!丑 $CN7vA'k*ck$DӹrT)=F.Y OĝnU۬p8Rdhe +Al 9ع |5g|^!#-$nr^zɡF# t׿}V1fip\a[^]m>'iوܴ)[czs^. `˖e+ܲ*^v(bcS/Eo| cdEqhh;`/pޭ~X @ʲi׈~ol *"=Ju8Y?NjCg:M~s},)iNiUeY>-qRǴ`FAAd\oxw..K aJ0K J\xU!+ +t)Md0iV$2ΡA`\:+ tO;0(H9)xEwJV([wʝ.=-`E`y$$%C2&ϰq_9/]ѣI%- *! &sx1iC9p CA8FSҼ HRt^Pe[qHUUurOwNw7 r,[I)ro!WY_:e&PiUx}cV!z~H?Ѭ:]S YyB߽*˗$qJbX/9? Te07^OMjt^֙OwCܨsQo#YgGpj"*!V~@@{d>'4XmzR"<Ï~%P+[ 9S fI5.bvb9:{H( tFU]G#WkEɐ/JV%"d:Gz5kucԩ)$\m]pMq?dvzl"9fXZxP̕?o_dĝKG>g{p;& G '!pB)'b8D !lˏyLOC7KA\}(TPPI4*t])y OQe`^QRKd%<}EjTե)i4Aʢj,1%O*Lq aRzhHdv-d7,|QlBf(%2 ؞栂o1Anaa4Akde(/g&p|^iBft' >'QʣQ4-ovl6\ƋBk =Bk#2-ҢxJ(Ѥ .g95/G,"L%ol4nzl-~6vƳ>j'IS*+~r,$D,N8 _VE7_plu  G9M&U!-2nsztW?L" Tyzx,Š $*d" Yc}lۻ\ݛ]-?;?7.]`Ji֕54Tۏ):802WdB8feLy*+N mx;8mntdܷX E-ROhy YL^%g4w(fxy|rqTX/wOJTVɦgaYAe@wa}w"CD aﰨ7BK؏2m:u4PaЦtl̳!z1GXYG{M5as,9hvM`A˳l:✆g;xrːp!˃zc8ጷ#lFɯcLXn|?aw0'm%t3p~p3-SgɅ?n♂=4EI)aY-FIk-0,2sU#,W_6>㇧ [7ZLŒwuoMx|2:>rۥ4-%̱-H34(V?|e* LL*и،TQ\˅bQ%27j Zh&+('s?NYuD{uZ@Y1YkN%Of1<sO>غǥǷ $4=^$MٹA-aH!`Gy1[-/E)N}ݗ=ctĪ{lQԺ\L(~]&d"-K_ o$yE:h޼n] R_ĝ]oWsfΙ}uc DSQ5"VJHT-/7 H D+U D@RIƻzgvwfg>s5{,CXߒ,xRq8Ob0lo9Dz(( -fo35(9WYnQQT&6.À,-H\{yAq?HO_%cPxN^ n` n?rXh<}x G㟄XDƵ6x%$Lk=% ci`ޣ4y׷q(T% nnl.xya_}l7+3Uθ&d 1 c '|Pouy ,W qolIP=6#* 瓆)ғi0K?hˈ8tuqš=)!v4/; i^"~F}@Ңv>Ǐ|0'5Ui0`en~ϰ X}v8O.:8b0`ǒ)hΛjʢp4xuk?atjܽsL:v4z.iW;iO) E튉=ѭu%9_Yi ~=޹vO#~M}bJm:lYΝKJ)Aؗ^L"ܓc:6YUK +S]$ѽs7xS 0ɕBwBCf簟:E!$uPd dJb$ i%u1H2A&!Ҁj*l[ U&Q»W t 0xe۫&vL~]\er~ƃ !H[W9W&|$&\fԤ@'1: Ikkphl{c`r!h@6a!*g7$Ksuqi,&28|)RaZЩV鸋(Ρ.M1m%ܹuz7vgCu}8fvMQ%1Q,ݠdьp] "O"`XIu{$NgĿz;}ĝo?<3s_}s؎A(I ]HlٰEJvJ]ڪJ&-ք*}̝stq.Vhn30Ym=I<+%cz26R6CضES<JXL$R(#ɔնmKRԗ}sC/vfG/5F`)YejrXSf?bt,ybp~p7mhcQ6 ڍ jdR3$<`<)T.qc~<%lowϲ;`؟skGk,W|"QMzbTTq emKf|7 Fr]oݢXc* |pgF0-s9wϐ^@ Dr(TI+H$j@smaF-I9(VoA1wѻKr:KQ*ljbHJ0,+UFf iPce v5eDzqw8"\=3$/hb?nv>5^Y!wKhRk'f EdžP,un\bķ!1 sb*;~wcsw‚dMQoCa4#;iR4Ԟ "{YTnФ&T}YGyY 38KyHLIIT 7 쓏SLIoW4'k]dQR&GOIA1!~ǯ?\RV|d7D%S  &7IciNew]']4O172 oW?g3wþ8JH]-( I% v JH,T]b!A%DTTE 4M طvkߗwg nl8۳=~?_J /9ҿa;()*C4J PCh:cz 4DQ[SVvP)>԰׳kȴ8E*aL=zy/dFϷh1݃ҫ@YӜNeQnöd fB]C*UGC)Bh;>^xF˧>2 qBRUmLDMdyq05]lל1zg vF UCH^}޼Ku>b %^e:W`Kظv hX?'پG>9!W 3DW(s.W;ؓ#$9ÔŊ~;L.23?lA iмJ7wt1B1TMpUNѰFIgY3 Saȏ qYxaNgXK o>}[J3M0<(_h;D7u|RrRmUYkUWU~Gp\}cʒy>#4A{'ǿ;/uy{4Nq?ƵEOC\F@Ċvŋgg5h}/ߺDAB5&T.gy-M>dAk숏v4=4!q>;IrCgZ>#8N Cis~8 6kA_*1Y^Ta6[!}4RYwxsm;ݢ2薁>sH/12fv<)k.iS 2AE翍P9fcDCHzUst0(xga/@)~'4 {B< ɳYL&H2j.ЊgaB4[mn$[cot0tV;,* O[KWsN]s陞k3c'gP)(ٱmX @!Xf";FxgU]u¢P֢}^C,*qT&I( !A7l/E;<ٰ0 yܰWq{ 2rB`;Fvcc}0,"e+IDsv\ I`ڥd)cw-Hd3 v:$QDӸXer6+XhfT7+\/r^ڵ<<J /vkIbL0,L.=s2 ^?BBDJ%t"C?%NRu̹p3/aV&?|fԾ};o *6a ar[ }\؋d{8b#\=qcn,ɷάU//[C~."3akzm΍llʒȶU0ryf}n.W9ki|%OJ'$belpcmF!"iWh__m"KUaKZcg I0r6Q@);7ĝɏgګqx_ x2LhTXdLT8PT԰y38c f*'ۋF3k`0#TnKu54lÝ-m}VJl"4x" nT6?}/=lH5`9Y8ŨT*ϟ1^D",.nxarc!65.-Vryإv:hM.dQ"υU BeΖt#?_G^sl5Of\w^fn]'Ik+M6N$f1in'0GWQU>_Uq-=!_bZ_tg5 -IF7HQyע4kgtMj:gxG_HbML@$$%4}5׿$Xgrn'.'DiNߏy =y0p)T="{T:3)8H"ae<~op,C?e zgOc:Q${ro1u~'1hUL~gwa*'ABPUt \vLQF6X;$+ ^]c;6Czfs"e-ob^&5Ft3WXW2:0 ˮ[p> d)YZqG= 2L|8:k)XzkB|M˭8=B!(R76R XLfq{:#vdC$DQTTY E0OĝoW~'؎&m$RU@*TMH ,U7,¦PPhhjSLKӏ ~)Q(bn7ٙ0L2:$Q*\=]l  ֐$IBA$M.@+6C?"E͍C2KnO6ȕmj'\ZCFKy=6#Ld;7)8 a(2ID QdL"QsM75Gm09ϻU g4*s=b;5To̠my͍M0;5~1U~ Cns iHh:P5^$Z i0D`!gQ1UP@dHD(h/[$3H IN*3D}m*.AɜOT/DUz1)Ը)E`q!c=~i /$FmfNfiM/WŬ*WO5L.=?~@8 /x#~c7o28yU9~x]*b:|yrb2;r?_g\xaLc01(Z@Z^D9Q1U@ S"M(dcO#2=i.!g"z^~뮠  8r7'&_ٳ׏qb**py MS~/!0v;{G4W.vsލwPm("d]6|6#27w~D&cp{wWk\:x]kX]*RFSE>yC %[^8oolQȭk%aŊjG4$埇}b2Eo,d -ɝp|N=ܹx T"9Y"o Iqgh%"㵷 {h3Vd @HWa}_S;MELu-QGΗPØ}ae.~w5vi"<2%(QtxV% RM'R<"^*:ZJeԾ_buN4T Y=8aA4@^~ [ogoγO)u[(H.*!UBE8  @@↛ )J+!*&Nh؍Il䝝 +'|*bBhY~S,9 N8Zr._霷,eޗ3?ʻM D^2T^VYGsC s3R4X[צ^„8q2C/!qR^dMr>şrݒ,W &!pJs\; >I4,&mV el?xO5D cYi|}Ɵ*_Zp8{O˅zfIgY6*z?7$xE&Ao?χ a')322&azWJX[Gт7Ъ|w{{CVw.!sZqrmlH\eE(V Ɯ**k3-,cԹ?="G ϯ,ҟ"I݅ q5;C  (54\OPyADTY Tw{x~O7.V2XHQ&LŒPQUNG#ypFR{8IƉ˦&Kmي7 E6[uı=ke^4JqV\[(#r|P ;mbF! Wa!޽#7Q5-$A_ܺ;3A)Uw4M&"3,Re4X3Y,鼺Ѡ?e7z/q$Hzܥ0u؜%Xo2[Xt,tCf,2؞-qR\dz5&+9nu!eC#Iaub^EĪJ3} b..rddҠGI+9<)2e|}e &"I0u$rnkg;YM!pF~<5EA<-_DB,]7ex#~|ae&Ey2h5>F`߹EK g/2-ԑ"P5Qxmwa}EdEˍn̿\>ypH &lj.%<ְ_!ZFae3/P{L ׏T|U<tZhyV+% B)D7-!'[jR~*ALڳy>*~+5DcR"ؽI~椼J^Ui,x߉YVDLno?-rKM/G$"=_u 92V1;Ԓ_0|^`?&t|Z* RbT3cY5c FIUIN7^]XcQZp`Y2ÄzPI/ R^DLwow?;];~i;IjFDE(@UU BB RBH-UKV(۴]7_ݙ3G;7|?qBJ4Ө`&C4wx@!3aKFQd1=$)28`p r'>|7]&L&x6þEN˂vbkRZC'_PSLlbPA$p$Ң+TXVT)Tr^绯_\DtIbN&Cr9N ˍf : "UMF2r^">_##'rUcAķԙ֧u%H|auZQ%bz>=l3dԟ{ۜ[񃯭ipa~Wrs30WbSJO∟o? "L"WDii!j QLW+*N3CDr=L7,_^p`p`IxaRzlEb!!ļ7Ƈmv:4UVRΥ.̫1Gg!a1 YJ.-2WD,_f9_ӳ9 aZwCy]dOUUtSH)~eYQPU (XG=P|ՐQ(Nu}$HR7tfNC6[U.A9GxZvZTl8%k\t6G!=Pgm0mqj٢MOl̕h}F_ )Xq89E*LlGgfsh2G$rtrWuv!?v#tM5ʦd 66I8H O,yal2>%1K< R647H!ޭ7筂S}%xne1s} S`Z:KE޽D^9O5P5JaxhT+Iʌc٩ S18_t=а )t%uwBX%!b;IhÝ$Q[MaBh(uG)m/Z18^^- {'.}Fi+?]a|m7 J:re/U- Є)5 g1BJ;-QƓ%4>R/|w}$ym< Q e hF9Dؒl'/ sDn H-1*碏Ѓ*5VT/ ΎLW.>0TXKaQ K[h {L8ptXSRw:Gd89"sVWDn)IpLIlq0 MBDdq%)VͳVw,8&9:@)X(F{?Ko$gvqc'ddȂD@ $H ! $@b &J) `2L&g<vj;bɂJ::GhpsE'=E)Bɓωp UhJ`UMXa!UFv@_tH'\UUB+ M0/nvBE,tAg%::Ǡ\l8T`:&劉Uk2,B nA#TY\*9[ķO h.՘XXʧ'~\g]\MP3U8YR3E /4l,_A?`hLɠU6a8N i");:AG=d*IdqҩNۼRgc8x ;: %$.Xw-\>0\],ՖkV(**hi0e3肌=(XTv>Y"< yM2!hh3QFPxyL;L8"~C ȋ :/O| )R&3|}sPv'/L\gb?RCNǞ9)l${X%kS'* KXs-0 #I4# c8E`%d" dF:c8}}?iVD3 qL3DjĝKo$WuvW_g]UqzO~T/KEBrjOWB]TX׶8JtM<9WR<E!9Oe&Q*Fs0CP=) "9@4CQ*2Ø';d\o3f|e)OS>rmVE;~1sM1y}EUTU_|7X͇pp~4rMnNG뼱Yӓ)q^`{mB݅ώ^j"נ A&+bE%/Ja ED6Bfghe/R c"r2a!ɇSuּw2?:^ eFɋo:8/o1ӋϷV=Da$y.Zx639s<2uҒJ#]E}3`0-=mT$ u=Q(GPHE#QV읆ӶkN h|2vCgatq%jUQxSP 2YiY,y&O_p:JH 52T\n{4᧏6(BDWqhE~Ϲb4Lq%u׶X~%teERb;>X埃91.m:®e-*L'IglUk6HJF2sl (fVX?'α=i8NB\Wр8ԡP)/KIV_F|5pP`Iz4.i{/)q{Qk |S84Bӫa;ux_ƹuR;tl'DsHCWõ]tG):U"'T4EES*eQbwڄG'4,l4m>η_ϨJ0.*ѸAu|1<2ˑYt5a c!iX q*$.Wo3;<v ĝ]ogygkiw8m4A%Q38G P8JA-CKp:v؎`۟9{>s_P `N;3a_u2dzf'PJb2^&cNRP*O͇n43e :af[Ljk:ab0AgV/ҙ@ò4Ȥl R*L:7jt)uۢS+sҩX)#?fE\;_g{2o^m?F q@oYǝ߽މC*z^ġj^Ћ5p+8?sۗL( guxZkUEKJVjE*yꬔ^x2hf/I֤2R `gu;GK2!*u>*:hp,#*/#d# 8 )#{x? ߨb,S=W$-w?l}[X6G|d;Xyq[WL„m֊A7wM>?}_lr] ^^'k),ܸП`m./wV8rE~s2ˤv;_@s%0m<#oO^*x]?}ڔJg/t{aI|[_:U[W[ψ*?zu˃V˅2KΣfFسC3Љy}UC%-;ǡp`p1u9'c~~oZ9ǭk+ }o6n^|p?=Og&snh4:eƧq83*E+]-JW6<hdub[,X:L%y?\w:d znЍs%d68rk|xv^2'$/n[Ͻ{}zqh/ټ/Gog:֪)KY5\0ɛ:uC[rI.-X9i 5t'AT0O?&t≇a m4{$ &Rhq6TJIf.~t#?M?Zc1ng]bԗŬ^"ɀѝ00-çDK *_$wZ-1ʟƈBQȡxSBf#bS,pؤAD<=#  Kp Ӭ` bY.[bĝog?>/ڛn4&@ THAZ q7_'zR H UmS-7I؎wzggwޞYn#}Wd 2x* Y&QCI|kdGxU B7J)Y^+4DX8i&w>W7x"_u޹s@ |s$T>MXiш\]ohν>y^Pl[~ML[Y2 X0̗yn?gm3R&`t#ڞȏ19C3&i"5|^qKuCy1ST)FڹoA8=eqJ694,nl O hg/_Lv1ݑE$"cϏpwdޮ\1xyƓM+wFCW̨MPRy*K#9e[穦C:>a$xky.u [ ~EAowtBJ wh1ИsXE NBsA(4XF/7ŸVX4\]h{/莁f%DdTs.۾5^Dl։EN7K&W<8D748ducFфoV-GS2߹v0k e.KOLO:~HñR6.;Vd E4DFai v!S/ FmojB;@4E~Uǽ]eb(eYZ#!CR,jc!Y&zM ILN>F:QW1x90@ Fh)S*jţV >{@<c+s5&= \dG F f\ت#˜t"7ˏWnuUWuW3;rRD B,رĂ% bHx,@p !vۓxf=ˌc&)}s>Df&߹/W<2i%vz>a'YLP|jT-ö$^U1 ډjrc"odM36KFiX`3*.F$QɆ{: R2賤A#2K`.IX3 on1seĸO=1RQJc{tD0R@(DM%ԱU1Yi\?L=".P:j7O-vCNUu|닏sn!:If\sȽqbUSغuDFHS g}:}Vݮ٥:QJBz(PiwOoM-(̸CǼ>v8;e3}R]ґ . [ KܾܠR3[:q!U ڽ.l%)OL>0Wry(;3$!-PA ,zGRW9=]aYՒ}(aRbTl#g/=͗~:?3~Ȱg.M$N/v zK8p/IiʜNx1AG IyHyCf&a_8%rj .I͟$ =eoXa7|"d~aJ .,i^>hfLw{Da7Į>Oj|71U5z ~؏]/?A\첾7 ʧi8(TuÍMNP0'kQ.@HSԹ%F%(ew=k9~;"ʈjQR'ۨkU 0L[EZj1]9GINx"51&I"$b@rt6܊7Q dsxb{DNs4HV[n6XE@AiB5R?2YBp̝[g9zflf=9Ң$mQ(PR@ₓ8q7\#?@ HV4 ll$k﮽>sfŸۿo>* ="$gp0@m[8INɛaJ*bdEA7Ȩ9ߍ( qƥTiUTTO?yt |f^UBV$)OAii;Ȋ&uC*9UQ+vR`4 0gD6++ mt}b׏ѵ:1o!PQߧqZbD _^gn'V;#/Lh&"zbsD3AOqP #St*sVJ`Mx1Kf"K&}|L0C n30k+uw{/qV8%)/2$At]𓔹Š̕esLIDATw7;W\ v[( FMEL7DKWQvN xQ1,qdriDs-5}0`Ϯq"-Kj9 fDǤIB0t3`Qpn|#z88sٝkvqHI U#UT^z R\q ^B YhJcĵ;vmw{N/ީ1x&\mݣ } ϲ%/BQP4, &zH;4 &#͊ОagR ;@Bi3~]8mW*G߅0Hb!p\C+DM ')lΖh?G)0qM&F&'/49O̻\YʥYv|nuh-=`kiJaV->c~XJk{:Hʌ{USX9Sakw=?<6˧ cN([2W.񓌸~:H8rDŽf5"^~{T!ʠG̡*gI'PFl"Δ Ǽ1SteLE9nrPj $ͨݦ? Ag­QPĞfgqJ U" -r*eGn}P,!GlwjkNQ/it\|/,z+8$k8W^d2s 8$E4T!Tx %~2XRw!'{}<}Ν=<ūxs|'S>R-QٹCm:aRA@6*.pZ[1Kͤ!{Ð〟tQDlrs |1o}~uX!fԝ)R)8 ?)ݾHf:sB?0]?.' ˧w; +@1]<8e`j >l˘ުEM M7jS5!Y\h{ )lJj/hgQ+s;İV!MWx9| xsڳ$0+MF OWhSN]<:Q^ᖈ;;jw C%)KiڥeoKBa,4P<$ɅBslTWYf4FOQU+!Vr%Qի1\rAF5AȎ#'+1g*pTEUg)aWv28e" bU-z&bR?,, fA=S̝[o\W}>qOƧgR !N(T J-EHHTqܢ*w Q$PQPZU*IJ!d7=v왽gfهcO7,i}Z{Q%I}3IE d?Ll_UjT " }$%I"~#O Xw3A*DW ['$gp:O;$NH0$FYUzYQ7UL[VͱX4 Npz'htbGL2";>ˍ_΀Z;'>ݧZ/`,w=D"fD]& )(#k8lݽ><0DN"R<344E"UVkE*ye x2ױ40pa04%bh Ҕ_ b&`Hd87x &}^y%gg d*^Xmo"h{1~ȫW>?/<^fp:JqV ə V$~>?yePFip^f%& 5⹆sE99fcesZXy_{Xk?I05!߽v }}wLbS+|QJBt.I ޾5{8NqyZstlM!$#Mtksq&ZZ]`\cd|-en{e)#MaE}0ZQ; M )֊,;73K[iJ>% uKu*RrIgOdn.ϛ}7N+pu|IRr|p k+U~|cw5N31jnca2q:8JhyA%c ")#RRf&cjPe&`ѱ]zD, kN" G)uGaF9dETo$wON3y Rl')=>e$G*n0UmGʓU}$I4Ȓ*h1+[;b t4A[_GdQ0TjU3訇8REF~+F̚*{IL[?b} g`-C> V pqkK y2!." 0BVY($j7I4g:ia +D,QN$IaP%9;WA.gH&!3;:Wt h9Td`'ģ 3m27Klw?ؙ}y׻kڱ8nҔTV‪HU/P{C8p̭R (*hGZPdq4^{wٝpMZ0/}~ߏ< (7%|(|fPDQT e5EY|u?u-sF xT[5ޏ'D?_hjFcwD1þ "p0Qi_r|ϙTa Tyfa*[4F1b~.I_fxgx.^Xƃv#ZcgO6=(>~\#NADLER9^r6.d]0$RQ&Zԣ0g#xLdl:ObYjkeT&d}*BRSqZݧY71-J"]'`JA  m?%QCqB#dStLx8B4U@%/̦%j,ϭXi: }᧻*:Z:H"LwD,b#Bj@w}ڵ8h2)֦4MDZץi'K)b"l6 3+J8[>[M2 FgѳyO[kPZȲVHr8خl h6l|ueKG>9>?|2n5p51L׷*)rBgI|2 C ̥cx6TxrG!vYLrxr^ey,O%O8bXMs>{mj 96 >|'K.f /iKS󳼠YBi'|QUz%vW2 ._>W$W) GG)P=0QWdŇ{|{Hܮv48h|raw1,76j\}|U2nU^3匆$ q|4-3 (A2<L۰'JNgϟF͚#p\bFk/sx#? yNzvr}f2qF!~k _ȂYa:3t<~y!p~5AˤGd> BΜ+ɌJx=Hrh1lyHwyF)h.7~O;Cx|ѽ_Q p Fs4K|)E*&Q$dcsF,aTbq](Ҫڍđx28W|O.b J;W9rGɜɉ0g\PDS+O:5U Rۏh{'.ojl#ӄ(Xz؆Ɲgkܘv*ss~sq Q xJΕ>} 9{ɯ $I9\i>% FSB󜕦ĉqAז&) (_OIXe6\8OaB8Q`~*v`Ҋm|=BeC|)n@1Fea$c<_Tt0ZT&<21 Y+XrnZ&N Wa{Qq7mGO ܬ`k*cCizC:I'5bd@"e_"ʓh33p )aH RJ0._ccBQJ U2FFp&L\N5O^V64SE{b~qvN`Cd#̝KW:u[mzf;{qQK$H;6?Y8(J,dXNepSf.Dz^c?g})J٦WI9R1Tz?ؕ"J{\<ތاS}2nqzSC*r'UU gX57\8DwFS4!?b͵r&ED9g0Z|90x0({|35l ﬕX%DF4&~ȋtfaBwRæS\r'?ؑumP^mRs³a.<&^ ( h;uL  IyoYoڙ:t\V Z%LpF.X.[|xrcdoXjG( yS;05|%n%dm傄aU$l)V̶x2 y~g8 ?4 ^cv} f -z{e_aBwZ_ 9/(3?|hrC,O>g7bB/חO}ng1 ͤLv_Ϳ| p%;'Xsmn,0T ,ҟWJw0 9O4/GW.V4&+"c ÄeG%_Ҿ RL7pWɟ~fѦ? y\ b:Y.B@g(d{rr4[ Af2EwPa&#b "e`V+d1-c]wfgl^ۻu}K6 mB UJUWU~T#q' RQ iKVmH6fx^3\:`#?y~dIZ@5~D? d&IC-%=/4/]bL LtUhĈ@$ A/YAT|m! /2H8䧯9\ԍ,O,-4yR1Q;|¯< :.ힱ0e2?wU.ow$*G}UdKӡO(6;.Ԛ@r$3^Klwl::w-eΗ j\97E{r($}qC~yޘ/3S],l&]i4A4EnN% #Gи,`kU/hzU3C!1Z{g)fe6OG`׶/V3B-LZQQ#ӷ}TE/(td'vo3P5{#45w/Tibe- V̿Fa4T(}y{#YoTY'klr{uF'EˊP_~? ?^'O`H8 ~Q(*)lX(QyJ\nn:g:Vk*=8d:&ؽCsMYCɱI570$ Iٻ&SĤVU%QZR+RR xNpE(H *Ҧ*hL줎k;Ϗ0K`.s~}>y?Z=")y^IVP|gG!rO 4F֌\z#4>=Y! ]dU?@n+L&Y>4 $I&9W9!lE/t8E+h5#PeNՋ|5bw نaj­1Ib q;T&qR+ "cgc eCecq o[`rw^wh䱰\!M3CfD^H"& En%t.ё$"ldmJZ`^‰YN4ޱ„]hS7u45Ç_2扌7|//C'YVIAI24Q{T)23?<;N( lܠ(K5 K(N:&tJ3fdaYS4q KKD]ԢIfOH\\XQ}9M ^@=.$W} SS@Aω;,NT6Xk3MM,W15a #Ffg4:$RB 3LDњQm>)~m e>d0C~r7N򍮰ٳ ]VO/߳"zƣ1?HC޼.lo离_]9ÿG/Γ "1޷ id0Ε7v9c쓸#Wv@c.oGgǙM|tճMdIVR  o~kϺ6WT wh+Uڝ]=̿۳+5OUx{$[S<P4TZe("Avc2~y}vd5Fk+L: Jo?Ls@ MCa,Kig $DG<F(J\^oVarE^_a/Vh{G X\V 1Tnn~n/U 1ϟkxM0CigT犴&jEO|jK:IYEkN ̵F=yAi$~JhE8)+BtEuBb(Gbc?%JPe~ ڷ~OoKT=ԶqÜڪ^F$al`?~کEaLxf3_8Nx%3w jy%fh̤lb zV5;v\nHt1 _z!j"O&n?v 󽫫cO$qDiaک"VNkZ6381Io4rAAy:BuY]+>n_mZya:}'Ta2gx5嬑A{ŋ,XY0eR Z9az@u拍",ZX$BIv$$a $MhQ( D.dUbOBDBxJbd'D+H4USSe|/<$,.(fY)9ku]y_ϰ\R@S{[>5<>Se:Q}ck!Om?_nϰu_q]|NM>|feb$;C=y˳vqCku^*Ex4 U'NZRsʹ_Y7 /dI@\2QurDs.h?GT/s.k˜u~WJkl4TL%8ϖ;߹LhLf}pCyk_`q\rr>DQC;2LdQ+'0JXA %5ǧT) xt2[Ҩp}zjQGI>:/1.Χ(o\_t$?z.n9dMJڅ9^_%d XV+`HEoi76yW}ƻ ?y"zf>OmH ڂR^r9F'mEm HƩOdܗF$wc ^B }2 E۾bT&3v%z̛?O>iqi"(hF> @8J4]3R]]M l^w|bm"* 9 h&(4I*|zdر :I$~LYjDA7k$C㥷qq9cJ^Ko$W:Uum2c$L " $@"#,"ذ/=H,ـ qa(Ce($Lgl[_^uX+k$su9\P#4LǺlqϦ'MT^XTŗ ")\b@J%Ϡn^ ddG Y ]!yh̦$CЦ@& 2K,9@tD𣏕T8} }daoq.LǤz~89Թthʷ @,&?2 RYM~vي?5wܭh(g')낦SbVb.1۹0UYYS+ń6{&/^2eǧe`$BB =UPI·ѿ~E*%G|6=%4*%N!tKWuJ.4fmS6” "Jr$YsٺE1aϵМ O}{3_'-LAw}+Ymuvz#ti^0R\S'HssBe 2o|->(=ͻu{Zp}kmv/Ջ.T?a1|kq)7$1s0l+ 1##g*E.tNWmX=?m#Rݝ>apm{؎D^0C(@*jʪlu\ ]p38rC4n+h;זNlqsKѷn}A:mG]B7$BER随.MNSa_x 1}M$#ҫo'g#74Ɂ.yw)H6rn ON9-mWpmO ysٖtMI%͍&<9itMcluzaWVTA&/,yqqx? F0F4~quaȌc썹Pe\7)-I 78W)7<,NXNf|;1!:ns# j4?8Mj%)3?ˇֿnT,ֈwM>z}?GA|+KS%⩲6#?~`<4A4E R1?ȥ ˓6WOw)0`08qYE7 ]Qչbc^4{7V%>,ABc*gK!?Nxq%4v7p͕q>_of867GoRۘC*k2I8pmJA_IC,$wNv,I n"HMA% 2[f@X*bJK5{ArG+ !Uj+uUtA[QUTQEH Ipc;vxf<3̹x' G}tqsRLQR@7O]BaοBjse?MRŰ;>;Io (O!8 PT}Z'P)MΚyNc8L!B@6 "EN䓒LDZLCtCʎ,IQc$@4oIaha8Y?ȊLOa2XE\o9rrfeCF)"w 7Q?Zz9JoRVقÍ'?vCy'4[>ϝh v[ JR*3ٽUBE`-_B@/P6P8MH((#y?j`v{[7ΗN2 CS*lSh h~{`W1l.4A >l15~}$\هbNxbq !xbRYt}QLlkYĸ$|r&~28boPUV'A)G aԗMVkElC9 #Η3,d:?! C`}(`}p cǽ鄨X<"eƀA0 CX ";pgEpne\fZw~sa Ґ;f^_CG;v)/*WW=~[d*Im}VX *Sޏ@qW(lt'SW񣄬QY 6b21N Lx(^{f_][Zm?J[\^0pZjB93&-[,siusLL`4_4 g}8D1Syq۠= iC}@wu./tl n n ;$""7Dt̬ju6I#IԷvi1Ol? :&M-~+Kl24n`ibRCSE~xnlN7s`J <3Qbz2%SH3'0&|E]7 IM"k$ ˍ>7Wi^{_1srRkl @{t:Sb /ɦXwyNУ22|^mOyc,ݮ!iZ/~G-#DХdz^Kc/ۈ#qOD{:(}wm.^#>Da14hy )%.gfمYؾK$U1wx|:{H ^uՍ2jJ=:Ri^]=6oO84{>9YeKTOS2@aB:qp5ⷅYN>  BF:Okb)zϴm%Nm"Jt~){ A㾇ߧ'BMW(p6q[DL4"_)kGGpH;3 sAc*c"IIAͅA}1uThXx|akoNR~4QEyG}̝Ko\g̹3{<ƎI mL%@mJn(;>{ XTUEMECPƷx43w7|;:nBtz(L> 0X`$ dZhR,I@L4C ?'ӃR dN I]"uMMJ:= ,T~?*K@e5E%4lOQ!^` BjāMtr8]zgQʭ{CVynw댧jHL)+!J!nX[M,V>BjQ#܂ũy=>ñ.k0SulϜdǍ:\NbY:!Y;^5upE|Ǔk|g# O{T}PSvs4J6B$YD<+Yt@ 1'IcLUi)f\C-If,E8dfJq >`{gWlVf"]jb$C/L$SḤ,ar5C#wHο_Z#Ϯ˻<,# ޸x`rDGgյ;,a/sffoS\lG46Q ƫKǸ93~pn+YylyKIFN9޼E2h5 |]p="gv+x +TGޗ񃄼m7Xp 7uK1|kESK[aPB9R5]O׈V=tOe (Ma;"a_Z O&j%#q0 b.II< T/z@2yRQ͒X@cT1,E" SA2:1S*3!6?`hSX:K7r&r\I|\I5ٚ3S?X:7ɥ2J|'7{&t]K 9؆dÈyJŻALt0=QBdt_~s8/&Xk(Z- E..d g:~|!Ku'&x4 /hLŰsJh Y,ؤ`a`L2U[*Ņ2v(ڂ[;}>\VW8OooR B\!8U ❿yDqC@Ye㙥2o^q~7Nr~'pڻ ֑Yi:4:>}h|qcU!g~񢘊8W}9Oi2n̕ \k2\{4w6Ta04`[ݕ5kgr}=))Ͷe(b޸m03hMg1%0fsOH)YKP#Ma^+~Zϟ4#F1oҩ*'twZDf?a@t aJ=/muIh!֨ou G`TV5,=uVTeUMC3mCTu~jgko8 ,[n²kB]Җ$ ͝m')9ka;`ω}F!iw*s9)Gl\t&1[y(HIÐ0kOֈjAvcX9hiJbdn=P3b@+ vv/Soup*>ޭCFLka8sh$;HR wvm0N$hIB_1s͞z68BNIoXF!k ~&(s)4(*?~ ̝I\Wsj6vrLE Rd%DA@ b* ޱ,@B!EHF1H'rM]֝YrY},<'24 |rK\JC@h<ɲLژ}«y'*qO,;j:$ͲT>ˉ#  $Bd 4􂣺ijB(ML$< 18LA&ɱKCCբIe qjR8C,ccDp1("NUIG)Dݲʜˍ__jp0 u|^2arnΥ C氾k3\h(VOozdBSeXVk PyVDa8 iF:raT!&hZ#vM V2TNWAx6 e슋(.6I' @LVSstcxқ& .ѥN'}<7ϝtGN䍗NsmʲgaElWȤӵ"Ylڂ ʹs0pQQϧ?Ig=4C'alAciTgNUZqoe6>?~p:4ngqg)߿~( 9NXl>m~ ԭvH{a2.ix?G}[Wx[]܊Ršuf9PM$ގJ !N/`< cjjd@Zs"EC#?"IG\ج̺|"^E&ikHݱV~MR aQ qML[WR|%ϢlI?"*{njAr%7H 5zc~t2_Z ottD&ֱM?b.lb4o?`rp 4*isiɒ0 t[Yo[ZDw,I!m#tk̸{7.6X#$4"S6f/^D1irDA ,{ΫSX8eR<ǨѼ gAoAĪNԑX KL'L3FaעMgi10cR0$1 Є?Y-xRROz@~yO]x>A@`CToX:Z6V aj^)}ٖW6T?GeX6o?O.,V} SX&:zX@"%mi4 0 Rl$[plLP9qhMծoMS[#T8mxF\ѥVpH0{5|e'OxO#T >g7/ 7!BN7F^T1 Jq,A=`RcՕ e<;!/2iʋ^ϲ[`0NK%j9FOR+\] #*FM:3VYY.״1M1EI+/„c-_cXa8C1_`#k[w>/1o)l,9փ#,M}] cX2 cTsA?D1բK-wܼ\+U2G=~y?&@&ϛ7V#C[ jj*_|q(Q4:՜Kѳ<_9Xlzex./!w,A)c|U8lPJѿOs=D(ؾ2'<5m11-ϳX2_ؚ1˘:xzʾiM6C O;+j9 ;!Ȯ,!v.mxckR&J,%/c;>d\_@̨C4v4|L ?ra9u^,qu.l61u3H JPhvd%&-%R)T' YQ7$R)seZaֈ~S8ݵ葷Ladc=T!#Tt8|V&e~̝[ogoγ3'{ڱ'i%iRHB"zA%*TJn*B qB\;*" ZJsp8>lbzݙs/MPs=i}GK1r7%rH6_(<˞d@ ҝACX4@_dO:O S{B`9I)g)eH]PP`b9|y ELPDBA*bMa$qG]-`p٠b(-J24Uz"H0H펉 [WiU oxvǵ>qrkRW ߼wouZA_}wUl`Y.,ۓEz`%e0zm<' ^AÕ/o?k54nsA+]L[i.TboG>jB0.WK)6 ֶa2ܑ!Vco-_a,34USC/ڸU*ذqhmOf̕,v/& @}LPN"= Rng(([CTTމ_Y󉒔Qr쨋g*%**HqwvB:~Z^'i [ONo̯?^:ưd?b@AӋ1w7|z{]zgx[{cv}T!c:#TMbPw-g*C5}Je/ goz&ބR: FN8{!PĀ<sn,W)M;|exFfBͿ "C~?l|3/vkw.~J+Zp}=9UIl 4`&ɋgh[,m}AΈ7O6իPZ%)4jRfS@)' 9 ::XWKu~{7kR]9u vG:BPII „;Bxp_#*䊤τ>+WP e5K(') rrzWX,ء~Xn2RIYjq#nFԧ]3S/2:+n G̝Ko\g>37x'IdPўǁ7חZa 7ZxRt8՛LڬեiJ?wk^N]U#iO=+yBZ!z Wӥq8ٖ,@6Y=YdֶHǂqY<.F XbjW5VJ]4 D޳}q@8HdaҘv|}}$.s#9'5SϛDI'xmY@'8Si .eZ^f#JoVRϥسY{r\\g/Wm/HF}Xގ;n7Ż_j/+_w{:?7Ig |LMlvgs2c C%cFC9L%ZtCNmn=z؏x^CS+ct .Y;QAw&cEʰC|Nn,(-r]^;;'f.^g̻W9'(""4  ~0om|k$_{=|b xi~ai*>9z%b)T2F)2Җ@4eM)2 bR|J6[=h=s}*SkWHT -3D"W$n=g2O\6"U\a,tD(`C2"l WB[m*(-R/z|+q _%x)5 lvd]PB3SDqP5<Iicj2h+cj|%L୅Lgub!GD(i٩@N9zGl??̝Yo\o3s3;1;8i( ZV!QU W \t)wH-mEH&*IXqlg޳⌝8::}~Z⅔' /v~O> ),)DܹHw H#+_`8&qTQ740FdT-2Q-yE/\٥𿼉+rÕ%]n~ۿk^hkiId\w/҃MzaЏyrJOc7 M%AS[غB R.γkq fZwCUєbwgbpm/ Ǫ ÄoK݃ye1s-3۷0gkDT8F PU$ƹ9 r-u|' ZxXޥ;HNԋEòe|ci 1WQ%* D P(O.3f<جl(lt<3LE5U꣩2q:\f4][^I9DÑ(@{R J2Yb~5yɰ!m.mydz CY4Kɡ2I!Np~8/:OU)3U$9+ɯ|]-5\Z=L!?irEa~Y(ZA"( A YP A7B~Dp=S" iBaCƒ'K}EFsU4Iq!є/Jc1#?fkBDP]PQt0٢a R5x9RB5?q| O&hBw`n12‘R3ƒq:#?bmrq>+UO5%)xQH|}O挂BFd1clp 6LM]-F%L ew?#TU-g0W1u(֑#ėS(;ɎF>L -˘˫Xu2]EcRS`L|RaT*ifnih2P6fJJg{:~(a I3M0ac!q/\Q8gk1XY%Ys9C.ט4?iE?#;> ?l8(' ?;Sk[X\Q#[gO؝=WXcjXIwZ*rlqcc|Coۻ/GM&U)8|;DIεE[=$cs\?/ oaHIi9W7c/\cw*7\ *Ӄbfg(ET aG7٢9F!N&X%S\?:< WrQ?0L! 0=֯<;ζ2fXb,__Ʌ4.#9ąe>>s?Xs$3&s8w ܌ T4s5]:L5ʑ\[!i@HSpL)0.Wka|1F)k1Sn2՛垮Er&7W0 GX)0!eX:mRiR&|8e[򼺵p±5"#\k|b=ڶ]WjҎ+8ke0wi OgR,V9XjLf MT„-Kpv7{Xi8j=$)i68N4?ٯ?g c.;XS0Blγ%oP]6eIJnsM XTȖ.r:ef mv,<_a2zjgp{ hB#j07_Igzk{Lcc98aq@@r% —C NpHX؃" 6ƞx(1z8Hr_fDyBh8݆*$5%~,ۚ&S'*&R($iKc\TN$`E%J:f0 cP3P tlb [ J1r\_DQ6D.ٜ,KkٚЭ-B!O>ݚM"3Xb*o>c*!l\PH6h|O˔ELN Jhe|7/yU羃 CQHgX1limd  aAdM{< ܸzt,A&r6pwo!'\LgZtLMrk; 9cw]MCBq[p7.`s *~uDdeMMX}Il>Τ>ȀOx:?{k;3,C,Dp?OppbB?}}C?ƌ%B=̓KW-~#74|JQ阜<6~2 %]e7wC^擕O346Y~ߢ[eCZ9<>ߝ`oDdgdA|e&pQh:v2R›Y]śFXεm6Pbfh.Zd a/: vH@UO%?ٝh%Nm}RvonDBb%MЫ&,ogfsQOڢZTw(x3ٞVz Ygc=YvxeciXzQYƥym W Fy.r=VoK&ճ]o9]?.qč}3JIS"ܢ Dd$lNbZeʆcl vzLV?}9&)XX t4cB$)A+XxY~|y^^?,c65:meeddILw@D8a̛:նl(vũA|̝oEg\?b'c!!~jf$H,gÚݰ` $X0F!Cƹ}ݷ}mXԛN,M^)c__q $8<軂Y{T4!Ĥ8 E$i0 $f42jzs$x ;l$2ta;Y.a0M2q˜8G/#Y>є)}#0( ]S M&X1 îBŅMV[e>MbrsPJ"`8PaF 'mT)CkRn˜{Cݟ`.PB\sN)s[[C|\嵋(hJ)=nƅ9|SC*O@t!9Il! )'&F=48-HҸ¨\= wv!ą ~tǤ& 8?Q4cZm6;!u,t)6B7H Zݧt˃ȢUN"%7]Ͳ$ a9Y c83 d4 ȥ)尜lONi<~Iߏu{ZS c|clR+\M7-gcy,.gEZNǖC@d`/թ}E9kV/[Aoҭ_X?qU"b\^~$W\i)ڽ/\ qoD%譮$Wz 0v2 l-!Q\zte0Iql}A_}t펍%Z}itI;//h9] k᫗1UzNQˋ= S I;Y%8Nʾcl ݣ4EG1{dSmdFKo(8ᄊ)kaBͰBKonE\K8NkģA8\^*ϰNd"F2 PU}jEL?ȏmE&?^l4TZ%   2A$a QT! =d`KXAa8Yt<\e".lD1T'%~wE:C1$EΨ6,l|[xWܘIB϶ZzTg{ǯ/p^F @QkTA""FѠ5I/$tlIiv93Xj1ϭ(T=Nϗ+p/ٛH>:%6˨BW.WW NV m|Q0H^f/mxLWp>v[TǷQ@Q G%.Qm./F<&5QBw<۠P͐A.˿RmRfޚ'Ssza1,>³ ^<֐7n? ddq};SgS(ɚeAJ:]{ƭ.ѵaM0JJUw﷉? =aN{+T,gWyA#jҏPE~}ހ[ ,dwͅ˪bEMh RlgK oCCD]^g$oחd/c vwfD0Hr?"o}Q*V8DPm~1jN+r]X(! ?̝ɎTF}=<;T!djB" " b xXlX $& $P@:C$CryY]gu;L=몙c:rys?g`cW5#: c3P aĀ*n0c] +'$PjL7uHZ!8%5qd`74Su2( QϦс*2D!TFQE9 )ru#$ImsЮY,mLEɬq>I:>d/0gPw/Ҵ1u U~;dc=tB˖ 9\Lq} v}ʖ0@Sj-lSb`7Z6i)0a(pMʣa8 t3]Ě?_-߸ڣLL[@s#LU::`KXED~qO{Lĺ ~ðHD-U3ʠR'X萌|olMxQA`O`U_m0E)]B@ /8̃M 5̝QGl5 _t;EEN| E4B( MU|vaS[23VpsR@ ̗L:%$ǡ3$t o||avn 'U\$4mr+)k%~Ys؞|x&]B縶>CMd^Ycecˇpg1Idrau|sj5mwф͝Ƿ tfDP ILe&vw_8ȟ]^jo>2OBc{??Dx x96fӢQ|]J-KnRHx[م*!u[Js 鄇9Ŵ˚^|ɭ^a2QuЄ]x8Pa+7~we6TbX/+G0P1Sʄhr^&#kULvOwi z^H3fm!ƈj˛*vB|7*i`)GeU $%C`iS 5:9L^B0$\MM!yQg3.|a^Ѝ/>.aBwz{O2t޾b@.2 繾;dɒ_>˼k.kǍBNV,Ϝ;Y9Nx kAC`\tGd#8[WYm_"XpqrMFg 4 O/?C7 %!qV#xewowwuՐdYI;COCwpnN3pMR^\kpkrLJLSI -Lb/MSwBų ~{)? slF^At*^]߼B"T:tM>9N,:C|`o*xՈSpvM[GXts#YZe;*zLܿ ,t]`Y;`Xr7dd r')1F&mS$e4%Ỉq)y;(JiIU:ESLx/ ï#ŠtDQ.V+hSg7ɥpH5&񝍯?HxL2oz]CLb_ 7GupNs!l~16ۧm̝n$utUw}m0dxMB",2"DAbϖ*<+He$d1I$Lf33mҷⴛԢ˓ c6|߽xoɁJE.CEU]z*D(NΜPrPu6鸠*sd:F:UY̢ŬOR y< aۘ2"%Pe^Τ 1!G"ʊ8d6]טmNG!EEVV$ӜdQ$1 B D7|#w\ Mo1gTBUI†ҢƢG;txRIٔ/]Uk<"% jte~oDY,l sAoq2X 8&kKh@!{~̴F uv0`5tRM?z'୭.;`{+u8e$M|["$5u Б$ Cb6$XSӴV'tNvL%g-A>0,Y[y?kmqO߬Q8WG%QZW_^"JK:~աN􀴾NeLވW,?i׻_GNS!X9⛋)qOfs! ɧm )+:>θ,[Xmz^bzdUQJ\&yq )ოgi+dw0E7t\Polk/toDU~MS:jO{̭n6p0)fT'\]@ר YSApy|6wqOxmuYƵ0cWGo|Xpl4 8"Le%;G#4=~IS~ jc#pE8!{owimnlC~TBrw)AӥonchzX<fI$]2L2-_XRL y5&dZVs|Cj/ujgi:YDa+~@53=D3 Mζld7)K&+IrAǷ)^`|_>WQbWq[Oɣl>~6i:A& 8ЮpMJ)y6UE?)X B$.Ш躤]hbxeY}ka:|~4·f}BwiaXQeb2H&/N>8QE}薉w}-̝IoU݃m'H0c$D PX , cŚ;6 "&A"f쀍ql_W,0XզTջsr^ jXpie'n@0,vXLN ~GJQ\a N{Uə? C{]47O#mb$d)1ٵ U02s@ӱ{ .z8~8v}V JꞧiSe럯=x=m+dPwL^^F X@ Gc22o{5j/7L)k- 3 M_,G "Ah~B[vs9}V@5y"5K/W.l5rx ڮœh]-;@6x<8g'؜/FĢ\uν2䳥>|<#E ,-fўT{7`- ]n --5w+ٖJ?b4JK%<8w>*%+2?ĪQWǪcc-`\bIrg b'P1=A3!iyˣn%S%a>\f S8{n+m3x Q:ɩw~FǫE I#{.w:q^@O݅Ahpu^R,X]Q(ae-5X}}Y=%) Lu[ SV,sx~80{3=#FK}D!رj."dg%X*j6;u`i:GڵTb8H 4f"~Dx%"Ɇcfh "?9yh&#}:R% D2' 1r{ka ѫʹJ0' _o\W?̽8%(Pł+;$cŚ-**uUR+QWB6$3gXgw|߇) \B&L!u~駿XWzOx&!zpLHMi:R2Q4FH1R@"t 2P 1KBhi)%EaTebCNgߴ aQpbR~wLZ ʍ*cj Ts# RDqJ^;;Ck7w|u^~Y,6˸V?dY{{ܸ8*2B^!97*^N6ܸV-*ƴ]eаL uLgGIQ}Pیi󣄗K_Kķ_C[DM3J(fl9J, V9 /=޻JS W)}[EHIcS)2yQN & Bũ23u;!f+|oc98t9݀,ԹTiQ >3|?ڼ^Dw4lcۏd ]/,QqVo̽#^*~o-њD#=63gSNĵ3}4$I}эExMl5<[mau$EOH®UtOHV8XzWq6xLtُ2Jew_eJk.2q+|Fsn,6yu/dil|٢gt{!$írnK<^btZb>W8&˶$a?L)(Cdy|͡QAiRpmn5׀L(BϔUO:,i}~~ ېtF<[eG h*Yf YppMA LCPerTH>wfp'$z oFc2P94kXYdAf9{  PQ ²AJhT-kD;;M6-"G. eF_?Mk${o}wUwK-iZhd MF`c!»lB @/deM11qlA3+h43jR룫Ւ]ۆsP Q bI5Ay>0\H0sDAսJLD@Cn54AUQ6iدLfBV)t',SrDFAY*ɸޙyN5ʶ=tЅ&+;;:{,QFPvf)e!V%Μ*Zm! RJ,*3j,q03v)rKJ]Ц]% i|4'4Z$'ךoYZJ]ҟOF\c&iR|yҟ ks9Q%1{H÷tBܚ.KSAY;ӽۇ#ME·*~$yQOY9 `QG5/SIZDp76p Ipѿϓg>{g4l[/_mSͻҳ\uL C d^>-cwZ\re S~"$'^{|hqKIX)^rGl[يydspD`v0ɉ2߶pLIse)6}`HqNZh>b*AfiU;৯>ˍ-=S25/KgrpUViRO1d[t#Fk2xIqڍغɊgz j>Rra1:%w?;דYk-ba'G\yځͫ汤`KAѭ}c\4<|\E:/p^ vc~83g.ti& ɘ0a38QtY.Ž"I7qoYY x:= R?7l֛. SD%HPJp"W|k-N'DJ)NpMEV-ݐ *TCͦ!7/6 d:?A wJaQ] (U[dd5$yQA$BRכYWV}*sBz/?D07r9$H!A_u„0-8<w>zl]jk]h.9FcfP&{X~!nSX ̅d(U/QqYWA:% ;'q~o;ewUW{<=bH H 8 Bڈ"ծlswOOtU_,T%UR|(uI+YTL@2cW(= $H U!eQG< GD]<&U3Hc17B&8͆)YN2Jتl8HȒ]N r飙tC~@ ͡n85 СQ<ΡP$`qFBMba,ͧ3,1nB75 Kf.xe<'U@։m? PU8qY>Uen(%qM8egt*Ð/<,.T8YnEeqB015Eg[ܝ㘼a @cb2OW \zC\pxa+4eb;XS+2o$|}>y"1ݚMn1-`fk?/\^ch|''D"CA,1/W%o9ErH8s$JʩóA1'\X)as}{#..x0 9vq-^^asՍf 3sA1}+Ku:.n?Iy~Eɡ[]H$q|?RUvSN[%oa&զ&}69XHA&/.\jtյS(E['|tJeXO\hϣ(b$? ÔBYN3e ]S.oNYP9y xa1מFTJӏ7{>Q{,lNk[K{h3s~t:5¹ l{+s#,TX]np1'Uks^b6x|F (, }|JFE6zcv?MdXM((Hx0NPe蒥'.rr6 2JZC0ئUYT,]eurafL0<7$}je+XNMxU+w DiNnc*?D(̹%NcBqFIDX|cٰ(d1$YeM8݂ɏ)wHz=P4EXmej*}KO̝KoTu~3gڙL+XQBD$uܸ/`Bl4^5* Q  N3sΜ_pr}<'\F54&fiye:C1[/?m.hsQK0LK^tF9 s\poBeDx0 f|gcI z/1IVP~„k`j|&CnmP4=SUoVwbl% '=㕟148˹<nxE x}~~{ݤ׉lqd >nKWi]&}k5\fx;=ni ;5V1_,m:ӍsƞhdUM?:E\2nI[T<0L<PzMsW?D%NJJY]'kJ.#[ix2UD)aGPnucBl^0z$Gi9D׮8y3/ҳt1ټӗEQ얓%ÜU?upCQP{ͫ:& {+习9f*3*ު*\ j:up| UUFs) 1H;8sG(>zc@7WU|c i+؎iz5<HTr![hzYI8QG[ Q\t9-AT7=QN?C-`rN,we(+(ؾݿiLi#Bk͒B1P"tY?} H)2eMgd2\#ߺHSӤ28j+W{1p^.ED:πS"W a02 X"[/J x,W7*2EYy'q\n`("+'0[&dp/-IY\3k3HI!^Pǎ"3TqQԭ5Ŵ9ocS,-m(iNxobBY"WP`!2aC#Ԩ8v3m 91V2ΐ9c3 O d%%y hyc[0e$Sl}f"v*[Ds{}Z/_^LJdäTl.[ /ΆdJC:y#,.9R4癹 }5yq~g_`$/I\iPs[rC/@[9}™:/E~ǻ_<᙮omi{KZ0OaZpt~貸 'tWP~R([Pxwgd")/Z '(Y;ņ kty[M!uo7f(R8] z)~ e87gfO'yt˧z7auOΫ]-pBC{xO+[ 2yU8 -3Kr;fr/-K-<)Xlz ~\lAp[4f #/6 ܞJ`;]Z ?{cYi&w*mBnnguchMk.Xl :Cw ϶{d+}&I :`M40JqLͩ2ɍ~ZEI'u(u3B7gi5t%Ιkvqv,|Ƕ`4<qN0g j<ĒKL3j ؍lGI5:]N(}yTrNc,hΠrx.KhKHpj ZNGRU {Kod=̄IhJ/mJ%  U% _'XTlX-PRJoZڐ6iI&3n?,Y,;>~yG uLcc77F$/߿<29( t"&@1) 21T@>rZ|\OC:ӄ|,4$IcCX®Zz>YF!/ ,KH18mE &t+yEH=EYj4#,c:QiҖ&C4 dd׬´M $4KIIu Nd<%(˥˖6%P&!Fy1QL9% rtJ[s S#34vtShbg[#F$E(d.N^ݐCegw#}RtuJh:~BM?@˻I?:&G;W~ם T%dj;P "(fuIDk|: IҙX:Q0Ђ}"g2רYysυכ\[hDf|rʞ \HeZaG<&Eߝ)Qr`>Y%G( ^ 8&[=/E[͑fǞr,eVM7f 4&wnnpxɩN7w='Z_FtݐLc5 x+;PQDtfs}}EN;Ov V&?nsa͓]\wrnszFe0?P0d'279FvŚjWq>_1v5SF8%]4h.herZ:CT^$uL!CAf|}9OTf$79Pef4qp Q.q }.ןY뎸K8y*ʷ9{r$ ơz 7dܮ$eB4co *1^0_4\˵Bc0_ӜAsV`vC"!@{z;XƩ@pPݐpU"J3Ep*Z4bmpy Kth:,e|i#_EYXyЕ,=_n4lK(>X!Rr3C#GH^E4p1k$ 5MGktke[9 Ȇ=Fxc{DCytVf=zwu>7oe?3ϼkvPŗ @/<xgnEcb< H !/Z vw3ӝyf3&>d{~7C:~_9lmzl+\&_Y.Yd>4lpLrk E LU.Xy3_Q\Hy'ɄNntp'MG :xr*$Ω6C[D'$^q4վWZ"3: BPI@mPBhTJ6@:K6CH3D ܂E9F#b~cGF1#94bͮ~H T/qY׈SL37Z\?Qzۣ凼ml„C9UĘ[ӯQLϝ~c|VP>@]CG[758{ˍ [ 6"SF|=Е,z7׸qt b"/w3%Lj䁄8%zKZ3:^=Zߠ3Ln)Xj+6ҽ.iaL BIZ:e.w<^^ʥ,59-Ʉ;WGi7rd$)pH{(CArƗޣHu*(0f^d0Vq |#N;&UK,$2[& WWqwU1ObVF;hy1ՀVhh&)X %%5Q$ai"L~0?eʮ^V'!̇D}[.orY sȕEVYfT-eK;s{%EFcVd%tz!60FfΎs=F|QfWG=t%M!(0:M@3 {}'GOKɎ/եE 3p0N/HN=JӲ\=4QT&gFaH*j - [[}j@Ɣl5?BVSj!0~;?#4}K #c[Ĭ^̰RبTQ;ցYjjWjDK ^1A:ԝˋE?]ff71 I0HDňAAPz_ЫGTHTD1$"B"f33=3P`C~ߗ0N+GiNƎjZR6A> «높򍊸h4﯏ȅCd6J֓J&:bޗ!G~aJR3_$MY9lTtC2R7;"lg[H;7z1 ]IJ#;ʄd࡛Iv A?)LKPmX7260mA.,G0.cBu]%WB*mE)~_B?!M3Id(Hs&h/; ej*;0%ި62ĝ>#ܶ \~Ɖr2 B8Zk tihq|/Jv>g褒˷Usc8d}y;/2<4Ow'O6L5H&Qa 3VPa7&~$wLLr`̥j $ olIF}pΑ\oY6?ϋ)n(o#Se6(M<>UkkokPB?RB Iem c0d9y4_IIEw 4$H3~0؆+|tyKP:42ІIՍ{ 63E,c'@&>Aq[8UD,"Al,IRI,wyT\ Y'|^(!D&O}=I}|l+aF2-$z(MH=k]$KT jw1lak riݳa3/Kg]3_(cǖ D]"$$V;5H(;*.B"D&q{=tOuUiO(||y^M7EVPU5YR0:8% Ӧc&Xt(r]]A*, TW%*,a><ъe3X\zUh~UCS\|cY]wWA% Hp*- p&=L GU7eDî.PI Q.!/8׶`sGd'/n{k׉{6_>?x`V͖$ʸlش.xϺkr39c,yr,ObӸ$92q 37Vwy(" gIƟÅMٟQ5޺pp4GT3{k<׿x\8ࣸ.' > t2OQtӒ`9خɫ Ey0sW /ǏܥR?;o2F !߸pN[y̷^uEqX2)s=I  Sb5ЅʆkPm]Ћ?x昔Y+1Pc}Ğ=~JgT %9mS3F.=Km:т=(\UEy;*w1 3W?{ԝKo\˞36PBpUEHE %jaWR,XBBB* uLb=s_>8wHN*N_= fFb{e30]4PoSȊ,R$;!'7Z_X!rc4ª#-|U|ϟj=>]%K^<_F,)x0 )=u3">?L24ﴱlB,^#-4?%\ 5{D5]-D&R~^$0dz4рayV09Mg lG@J9/xggy Β %t2PT(R4UؕziJ,Ä )ʠn@pBb:ey(-t} t4]#hxETy.0ˎ2t²*0ekΓ5`4՚B&J{FD5?bjAӷF)Kus5Yr:`V,Cg,se?0t ˫5 Mger yVz{ X9|7"Ugkm2w`ʥ9Oq4"ܸB .U\Wdnx[FpզOhў.7'; Ogc$kz!\ՃKI!XmvBH| wOhXDɤ4ƙս,#( ֹdrC!sAOL* dPm tǩ ::Czn>R盼|vC÷>WcaB?ڭLpeGU>ߣiZ(\v9R\SDQBg1kM__cs3d%:8 ֢;^DN{ :mdR+aa'[U,>?jocmS< %yt@;m&`V|;ܮs[B9!8VML YGu~br//ͭa̟3R.^ 9_=2NH+R+ʹˠ1]ַT (QD!E ө‚Buv`4(r!:A_Tc ?\јG]^^Ϗ{|OVn4XWldg¶k IZX$w\iw$1VQFSX. C6ly8=B yTSxVm@Q`>4az2bx@2α\iwko w dv 14Cs<ӓ>q?$9F10©0ξKo37ER%Y,UQDPQvZ-dUYvmgln) EQ'-"+IJ"9$s;s8v}^@ҋL d>5 蘀YQ[ 4a9o4;#S´&aL<Ի#LIL`"lI0m.!D_jq%DmL!n׷5C5f-l[{Ch_>_/yyUYdiۢȋ(Y$,\KP)Yę|kaW/-\jE~*g`1YPllW \|Xo;G8Iq)b䤹bsp&`mF\(. (cԛ>͊$u.I}_u5\)\V[?G|3sUέ:r>J(.K (aGO?;-}d5ˋe> (0{I?f#Lqҏ3I{PrS qgBZI`fd^" dq/Φ'W|ƜO02Trԛ9_C^}yYljfQKU?t9ElМ/ћ}qP^_{?ު۪r4mUU]_s<^ 2^Z3d{q阛/4OR6UXkIeO6|,|ku(۷Io³`| 1R5QjgYf^&|F;x:䅛5(m8\q䵍<^ovxޛd{G4_moaBe):3Qclszw>?aĩ[ Äe%C bl3LN8;`X#20Ѧe oƀ?}{0+L/" Ha o35 sEٵ8I#\$W?I8Zd^ cRt„1s֚%4Jq>}UHئɺaҘ]Ba$'0fVbJ cV>i.lk}2шbRD:8tJTV?>´N0 Vãg,34yI}{!2yLljr>b ԝKSezzf=Ɩ1%@,D"al$l,bX$+@A$ DpI<=U]S)Ԧ>kNRʲJ+ɀ@q:׫ Xy!QeQLsSjED爏RD@ S} Hy|tV-XݴEt 2QzF%)@R\VS54tPVȐYav D8JU\sg`)\O'L::aJJUXD7l:i*SydOR5i_h:sk5w2k-rQkZln4L0òunu =EI?]7LJ޼?eG DQR9 &~mhpX`NwE՗9֕4KimhXΨW㚈^B 89) fiRp8ރt|\gd[#bYPJ3M)kأma&XJ(EF߯ zԝ[oesٝnn ۂ)DT0nL@cbL;/W~/1W"DPAKmneOs~/fZ _ayR" S6e3x[M}DyLT20  a)w{cd'P  IJfe蚊[6+F c `=" D"]acp{ϱ9a(iAȎt?܁ >\慙*8"SMW9P0?i;H/Lcz n3aU)?6);&2 v"?!d|?Tf9ź2N s\@-/&)l{Q/>ayٲIɄp]ƣ>7z {_ƀ*w,p簧XYdpf.7u?3feU .nqbp_y~^qВu:z i\+E)W mQ$x4g^BST22wbsi cNF^r 6b4}/qt YĤ͘-FEzf>ѪR4>H3λ|a&ahj&;nߴC4^ {Dt^jb[9F|,Ϯ?U+cj/{ObD%f; ]fY:Ի+kì( fZ1lu,YRr$3R5=SuHSԺl_IaǕ[ma^7pL,} `g %ŏ i#2LH춚>i<] UU ᘔE1-N D!p-CgPD c<ʵ 2ХGѼfS=PԷYVZ'9Q ǢԲdZ&a-̹g  Ɯm?V1b\h`g#53]Čz)Aݥ,$/PJ[ޏeϯ?*88âÌ: \- JKAͶ؍3N>ckK8L$QK^(2H2}mxnP|xeYw\ԙE.o%i!y$Q ,q;IsJg4C^^1鱠5,Xm??_Xa1 _[1y.˧hKh`{;"~x ]${_5>n"9&J{dQ*g0X =jb~9agc0$'q!8YPT<~/7vOxiF:Jeh֩Ϯ`ٽOP*ܕs IZV<qyǵ} <|o{УRZy6uOp`H}j0)k6a:tc9h=BE.$'m]خL!h*/)ӌc3jP:*lGq&q|WGOX(ogXE&B4֨h߽nsq;4(](rL/@4wLJAUXvX%ըu(T)QRGB2/)^ xQQV ;}~kJzR2ߢ(&E?C5)IcĴ 087ԝIoUeg>w)嶡#*q!{51q…qCt 8$Ɓ X b H@ÝAMDb`#kin[;Mx'&$E\/ ^o +];9N{bc '`fp״+kD2^$VX$lzm7#셞Hro3{Nw9Z;=@ :lltB;U揧-$]΍h{Y$pFϞXl,7m,Q SS(2)MbpR㝗|{ H K^k]`8B@Zxm/d G%3ʢHQƬ tXR&$&j V[_BGY]%J&XDD-b!VYU5%p$ͷ\b?Ī5ɌQL0Y,oGl%&q|8O>%U[HɣMPhڦ*ľԝGo$*tۡ= c@2` 9(BB,`.#b+YCxfliwtwuUWW) w_I::}W߾$5|[R,2mgc8Hi\1b5PڱzzbZZ{g2GhB hO|.,1ꍊRt$4Z@ .aq&'Ey B eu$tAh PT+|Yq\QbyƩ H1Ugfh ()78}V2-[J C` dYr &J6#Z\+ k);̀gCy\E0R*(FIF%ԗk1JkXkX]Ckynоב|}e5"}JyI n1k_Ռ0z K^O, S0@e1F)ҚOWgPZﺞ7?W\毫g.JK„֏ YNsV|㙳tŒEG)8#5)KgxZqi-+sQ1~oy .0P9|{OQՊw}sx5>lEVf|myRGK.6Tϱ·=յFݟ0UѯӢ嚐JDq$N[.e04yV"]ަPC OOd{h;RBPQo+3WX9XǵMBG[g4qe˗+ /w#j\]'Cn?ra8W;cf|ÔF$wp] d PR>?~< aqk'fm/16#Ιf_`iDo0Lh̸mkV鱵ѵSFeWސMVZoz\Xjrs}"B)JMBBCvN3I`x` g2aRrޢkl9JOW(Ә d1P` ;iHMPE1N61<{F5r5,AMPɈ8s5Swp!xv=`ҏ0Mq5 dc.wYs#\nSw1*bf=R_ ԝKez /  1QnսݻOqgbtф&Dx #"΅nW7X?V:k=;U᭮MS TQO*0_Wք R QE$Sé[z꭮UyMhRzjoM@ RR 82,%)YW$!!jzAd04SqQ%خx`XK'-Un%9~[o(khKS4v, 0uqΓGUVrAv0p:8*9Pva镇uS3/e]9Ҵ EIQ*Dcuc1{9nbvi=d{!dz9c|ե_|d~O;#~%l5W(p+o{qa [DEɝA$BN#];ϗC6k ~Oݯu>8JYx( v~Dnڂ8E1ϱ4) \ژǯi[xe7>aRs9"XX1(b UR$៬f=))ec sQH7 S8~F@)J?&I"TT6vãs2F[`夻[Y1hJ e`::W@un,?AFYԉu0$HnδϾJ jta.Y/A?^dCO̝KoU}c8ҨjZ@!k,`S?@B ĺ+@HJH%j{K82aqK,fs9g}ˏ* F '}o?1,0&Ѣiylib`#2A =I\},^c۪rMtS#2( sU33; A7@NQ~X{N0!)-وLD02FIRaANz)J+&P*deMc]Ea2a Mls$9!嫚_չeq5Lt]*" >V-cj'BbZ:_ZrI^.[e,b.)`Mv=,qYkoAօEn=qEsqx,]%Zݐ^j2Z$ϡ [C%[8z*Ȧ |Kg *m>=nMXdb27o/꫆^/6|>:3|^C959{gK48{kTեY.OuQr rR=n2~'g)&0Q*gr&S0smWZØ0h.q*x I %S 43%h~C>"GC ArHvpTVgԧ ) z8iZho_ӐIO ;%V f=U4o"ӄ͠z4Udut[ٍKq/a[8M3 RIe<"o/CV=ms9{6^SE4ԝnE3'8?$Y-,Y8`B+8\FVH$,9@Hcc{~چ[:*O_I% Tf`ha&yW^GO&`=αR3#bV00E P %Qb2qYp%)j <5-_k2GK5}LӪܽH^BUFI-Slf X}$]Iwc,Vh]aKgKyq:jضrc_ԏLs+TI𞲨.BYCqpVClW\L{5 KoT0?2g54[띀)qlΓ--$F;#e6/u8e &)gxC2)UEƂV+ﯬcY/.pnO)UY|.-GyG$ֹ ".4RXTۡ~F}o=K `U% G{XG9PMOqyG~v@ƂiQx<7GBcfo$gg8p87H[!k,99U|x\{3nͥI^쌯sїlB2&_]+tCIwjK>~͕[ϡ)>nF1yQ \TQ'cvOb>U+' J6"8`Ikfߠ2lgR5 +VF 3I?楕&$K}y{!qfh'';}#vWImA^\fz}Vu,N z7) }Ս$k||)*Qe#,N犬,ihgt]FyA$r9ؼ:VkS3鰸rDZT=DESd29X cn-p}1d^T\lbo =犴=ҳ\4^{u3]➛ `]ƬzuBZ~H6Iny .\COf?=Տ<,lu-(иe +pQ*WG28.bV ^ZE)P9U2Ŏ"-"9!pDss a DD-Jk{i.ZtOlm ҟz렋ل`«~ԝn%W]w:w!FICwh5(JB!9cf xA A tNZ&m_}uݻ*:>G_`HW8J͙TSR.J|S\ˢ٘.-6u eZXKa Rd `HiebI+ˊCނ_JV7Dʉ8zw$@=(_–?JCURm7u?Tt>jRjFSclY򤃧!0TN;ku5Q$K TI~w^ϫ‰7W디L8L^Lfx^1pPZ f>6Z<:T yo (>/g#E nfZrK:hJR?Awǽ!Ӧϝ3lc W [P&7!wIDATcD6 G!=u7_|ϾB~k-89Zn/װB%O.#lQнѦ7yp2&.EgNL  LG 槷ָKthqݺh\,78v@;aC+n! a#:JWM\L3f;[4t^r+C2ISXmYYJb/Sn#8e{\B!W+U]@YP&Kލ-[G1~m ׸Ely,} OUg0EWlH{_cfOԐM?WϷԝre>I$ @ TDب \Zq*^^W`Y KK B) eB3d&3=3=}]-^>g*i$iobT4,I%oY`8$ڮbI~C fj.{Ø:v͚)wtYv?&8` NQnO_oV76;C.7N$"TS);*g9quv@,2.̺(F]n\->{(<5n+, Vӣ20dz.ϡhIo,U\aJ(-c.TH3XԪ>He^nM5AQ:ֺ<R,^Ƃq1' cM+R3pq{soܺbxhFX(5`K<ŵ%tU\A7pkU[!]5!əsiS c8i"!.QwT* [;e2t/ԝOGU]33ӳ3;]wXFv9DH\#CpE@!'PCD0H0Ikc;;;;3=C.uK]zyeJPi;6a m[K^VVum'<0?LFV?$ĺ5 ھȃK^)qg[TXoeU/ %,;iEV8&)sЙY"ez]3'Zmkʋ㡔$r#[ &<8T]\! Y"ݦ"[R}f峫ltƈ$/$ ' 0`Y+q0EB:⫽ئynˣ9r:g H.TDf4x].x,jx S"XmſyKÐ;s޷aCyf `gESpǟb>>Qۉ9 SؽTaϼpw')B%DPr^"ీDdhzM2]{npk4ӫ9Xk]V, f1 l7! 4cs@hz Ys06y(dzYX(0I J In?DuDЦ߯Rsi6Ƒy3#Ló 8E߿ x 3qg r&bnIu2XBs]ּ<D~j+>`-l׮[8e/ԝK:Ե=gc@D!@"D`ώ?*HO$B ``<tOtuwU=S3]-KS:9=::uK/a@Z@&Ok\-K."sx8!,rikrXm\K/p6]8b>$rNB*㖤x>h[cE MnuIw CyEJkuv-M^ y1TL,+zL R=Tr8ij5G9x]ip=7~"$l6xsx3mWWҿNJؤ,Mj-W@Ҝx*lKTyBy2Rrv`FTlH K3ҺQe ;m?~pe+Qgْ8-'Nwjy}>a><}>Eb6ZF4+aJ^tovXX zlAgJ.ԙIn!_ye$ܾKbq`&9Y[&Wl6:U6ݿ0FH)̓],yE^`؟, ]0;5%/?Ip1j6%rwPRS%ڒ'{ +dJ^ WRq4Km !UQ,rӭ "ZzgVNAc^"a\E`/sQg:KGTt)N>Fmm\,[RpVG:۷}l%9O/wЮ \|l_'Kts8(yFcҀӺg[( &E;~[ _>Tp,r4/wx AY:Snm۽ajܽnZLG}nLV1$A̎V4);]˫y~k 7?Kcjsr}{Hҩ[u3MeDI_0I3ڶNK aF9MW#M 4'7ut'n8FgkHa©mħ'E_ϝhs0`oƽOo3ڞඬy~ԝKo]{܇?bRE-41*:iA:!u C@ՂcR+T 6M*@qNع{07?Z_#ֿ?Q7dyZt HmG |?$"KhO}~`ؖ/,K)DC~(Ҡ3Da.^FM1;ܽP$H(t2*Q=,WiA2m CЉBJۘ"`niӘ#DcS"fk=4*8q ɫmCޕ\Kqzw Ä9w:o\\z/nD67G1/jQ5h\\}0RΞY\>$ Ϟ`DGZբ7PJ&5פY1Yr}oHjߏ=DۉzE/H!+p*mp< +uMQ|py[)y5|†d->QR̶=~xWgDN̥@{\ŦK|74\ !a8Uw nbHVg8zaŒgJ0ƽ>}-Lc| S uDiN'`f=?fˤBe ?X Jr?|Nj+M>d%?͵l>db:ßq_^x__'Kóv;U%q1 Pax iSPU65*)t\_;/cV=̓$k/qs0v'`NW>noIv7`r0qZ`*C 3f[8ni$+jH }r0rr]=A>r8+ 3 mOacV莵Ki6y#8 #6hnUFOݚgCm2 D$Be;W@@b`E6 !!Q@!ȉvwUuM gwV|mm`hc/f$mDԂ#) v&iScE¼Ud5e.d/B%$W X}$haj9?S$Nba&/SJ޿"m=  ;!QʜK]L)> SYZ,s%gqja} Qn*|jtAf͒N%TDz0±N YƕKfb4[TUP54|aLG)C38B$1Wl&d, ѠKcڳ$&w98-1;(04p Ų(7I6+)jвf2QQ0jJf87nai*uw8$]&B*zvݑ[ĝIW;vώ#'FB"PXa2 !l6,$e9؆Xݞow[tTҿZu{1kM048Ҡ*T08Yט)|M&dLcy& +uIFsMUUL)׿̓!~B^dp Vgq?jF"˱\RMXv5*yuG/X|4ʂBHtŒyl`y>"0wg{/ X!0ty7.ӗcxwdcnK?g0G)8g1%z4fwp\Dsg и(S8ŵ l$K @ð9爢TuKloC7_]}^ߘz rcXdYf2QF E0V, 'F,|S¨DH^U`ۦ̲7jwK^ocv).$*¢@Oۄ@nczIM+R`uw/t20z~zRVzƜOtJ4Sj'[d_a:igfe)Ѫ 'PRHKzm]˳m [Sߘ<q7P)]g#>r|̀WZ|y`;ݚCɧ[֚|lH1pj(9&j.PާIA`gȅvyMb8-(kZ*])ʊ$' RQb˚M<)IiQr.t(,jMjKeDH)ь sc}j]a! &%^t"EIM -;=uSWˡICT?œ_%_WR>@ ꀆ0I.KK;Sr5<\VkݻM6V(:"E\JlM L (n PݵЗX~Y[KWSt3=#;Q,Xd! EB X# ,"6Q (v8a36]u=Dk{= ^ͦ$Y,UdCV"MIOPm:4 ( 3bnS62 !t>~хO}G9,4i))hv $cLB:tv)Y㩃xv Pk]݊J{#\HJIi&Ͱ<aD!^4㹢8+R8;G>?UչT1h_|J͆ERH$0Hihs1{5ժo>gSf8+xο <>`&jސcBӄ$K1diFܾFfn /qL:50+$Tlb \ӱMF2c7&_E|~7^)'eJV?iAqsm 6{5 ;[LIPt1/%AJ1h8 coc:3+|mIQ%N/m43ʘ,U??/^iK-LK0&%.J(HMp{{aw(+h7~{C>LsR{[*vTm6ɤ ;cE֮khR@A+%nNO"6^#FTsgkȹ\R< O(a! L(c] S+w:i"Y*rB1C% j$3&:Q+ opP^Uvgsp ->0lAN J_5n\`:}?lVxZCLyu?R:ͺMjPFW%?:ں'g1MYBg4\WhB1{{ !%Ìnaĥ?}k58\[p`PA(Hy*=ý*/_np BYs?_j!4!PQκmgd*XFq6% 3uF$4LçHVp(LMGhMu2ACbKzbƂRX3ea(|a솇k+`?{w{ÿQy.+^8v\zz`sxG~x-ӡ^.n~p4IZغN'!M46SEs sԝKW:U.]==a3clٖR@"X!šM"5; ?"CE00Ҟꪮ۩ jjU*TS:1. 1GSqDf /=,Iia < eӼvY£?]n31x6鏦!k "KҦPI]Jx庨(^̆5c>]ylP 5B/FH8\,EQG&* 3^Z=>|8v-~]n,Ɍ%14r9pg}ɡi=p{_\x O>;ԋ .-4[۸p_b@](A0>5ݫ8̵^J8"L]`:oZG\_W8 4!um=ޣ3Od)F]PT7B< Ӯvյ*Y0 +VTqm f:r?Ys-g1A%/m8< ~tcC/&3}_G]78:n:|0]Dvs?g] n M8y4,l6YqH d[ob4fo3[Gtom•JYCy6>Ү#>YwssEN =Fć |=0ϖl9ةo0'5>~S9ɢS^*Ҙnn =e*_#Qint5:d8O<嗯Ri:6D`RոZTc;_?QRpID XvEH\i;l/'蚆 Ÿ2x&ĵ%y/o1 RT^o5 /KQ?IӜq׷|bvU05ע0Ym<xtH]9ӈn=Z:*8;5\[ * }2#4lفRU ]" M͐jF&dO)ʹȓĤATTq9f#ѿѧMif5Y/\GڰyjCY(K x{$ S^z$+x8 ֫s{ n5LIt &i,ˏG?]]ydwfYI: \ 8gEHpGH#$CXAJ]{fvvӯn=rR:Tgq8F>=اӯ1S&ə۴7z)-4𘟍DH&V ӄxڠPj1A%-?W# 6IFe%fwWzN+Kt i1PM$fZ_Ddj[Y-J4nX\|2B:UVS]%MNtc# k\_ejé9"W%x1/v]`Jbʠɝz.G*N|l)\w`g 8F4)c0r,TrgtI`a4۴7U:ɝ^{[+~xiڥvn)*aa`pmK(r2_tr|U]1[7 {5|c "I 6P)ڦv-u'32hΓ9-бM/Cη>.͏=!"VsLKh[{ykK::-IO y>Y>=yXR( k⚒U9[{1!{gѡY@ã6jl.1 m*X SIPXxaF4\MwL-v-@+JE#0i0G1]G8.(ͩb]f JT )B#e$B8|gӜ,OXܼM%Sm^ 'k슉0u][wv'O+q>-⛇cj Cnn(^XUϢ,nP>fyJ Ϸf=q͒$8dOjiFj`7H&a@YX_<)2k#jiw) qRd5 Jgdɲ6.Nm`X688χ# 12 /f|~4F~&0s*o,K~~{LRmaCvσ)YYzDzC, Zib֫;Sn'%},[24 vYi}&% dpH5?2Fט+=A]EyPe4B 4lASzjiRLTZV^9HvTT95$8Ǜ+:;Me㘝˯G#BN9jrR-X&ZZ Nb&?rU=HjK'`HH0Ŋ ر X-X󆂐28lKnfq/qO'ݗoJ^0u ֲA~71mۙpz;<ɞ>50t$#̎MQ`Ko@0@*$;?Q %("?2c (&r~&}_|" ͂Kp7JE@r4!-}Iw5]'TETCEd81_ߢ~C|yˏe#/d↼]I͖"S<\烟yyɛ.F7 lNLC]UI3Gx??v0lVw$iM. 5hzn#b:hRնCh* 6!AJa4NCUt}(,8 8]/q.t';#\XlxA!KUv3eԋ.t*Beu\Q64,Mt`8M%Mlf#y [CKMomP_w4J7Scg0ۄ~GoĵƬxf<8m KJd럳; gU2r;ffw{G74J'_9$%M2.Ɠq4F_k[!($B J,IFC2 cfQ¼m@&€!h[P c>7"$>bU!1y&ֹ'V)5\RT܉iW@HU u\xM__o7Xx6W6.2 drKR# ЧXf: RhJIh.:p~9ZvqB͟NiE%nu1 gyCnyrP E^efD\,czߋpVj,W|v(>US 1%GZA'HRTemCn蚊ɐBͅ_z<.TL4cu~;3o3>}]n>e]i@8!&R9Bוk~'MQ4ZHrCm< V5n_i\B zHǷw8Y+1)p (F90c^2 %˨:8`e\~8drieh>t% eԝKsԭ/3n3-' {6l_d +`E" &J\li􌇞vߪ.8EG (y/ Fkf7?kT 8;xdŜJ7Bʼ G>_⇊iEsZa iƢrSv]"ːʳZYi!,Kp}~_H ?a[. m!et( 7"VEyGXk+jO0U/YͬrmըpA\ J=Z2<_C\%.E1=7ze>O_jJ%5>?ԆWxs·#v/YAyS">qnKj*Ƨc/nr_G\naJY^0X!Va `q0^rh.qVp?lxMRlb $׶.$+KKO.#7Iɬ(\px`Ϲy1"Rgv91g>EN؅ ɻhmxZק-$+ CU!<Óv;HA ]Q@2Ϙ%QօqE/*W.m_p`S#] G9Ȓ78tYʋ7Y%wb:uv[M_,JsT~H0{(!5a&EiJXQ$-ةy4zϪp\aXm<ѭس9K ҊBP].Ci&PV3JrR#WYPgX+ɳ׻׺ :Mߊw6$hxJ2SfZRթ1Zd8B6Bnl6xjZ:C]ܧ pbN`4i2M(_.Š)Ct<Kx*Xf6D*,P VړG"D. ei۟YRQo v~u|²Ѵ`rCt$x_>=cxF?_3Sen ̝kU?GoomM iBTKqVE7Pp@\(BiՅ-6Mk4̽:L{7jVs|u0=[G*ˍ<wD; )s=a9Qu݇bг~ ϑ:GYᔊhgd^j qM3%_ei$pF8ZWu jR$p[*q{? *R Q.JDrsIBP4H&9G!XvF1,s\Dfd= =iPTדyw1E,*W'l}6Yk BݑVUUE?,+1x~ݣ\tY I1z.,s̕:[OP059k;}=W.4QG]0JpS% PhUmTDplM tCS9#SS970TfSSy<"M1U^?pSi0[soO=X`d^/ncvFtz`" Q# q2(cXwj8Щ2Y\*%M. iM[^ }v3EDsMK~]Q{Yw6gbIP &аw0 b` tWMQ2۠n!|7DLM2fPɱuv`tFǃ Hyy C/(/RtVdҜEOə+q~ra2 bX:QSț4J1f }i#Gj7N15*_c֢lQtLo:ϔdpcD4j W^$#nAQH̍b7C_?5SDzS597MW9Wqp BʶAbDL8d,wzyK8 a 8AftAL ӘӪ8\lY?]䏮Dl+2K fQdaUr5 ̙lu;h:Qϕ9"Dg"(Z' Ao$LtT֖3|^WJ glw=#y(\=SbUtA}\5!)P,lєCŠUmE|!a@j(ڬ$\R!0Tx/?ԝnUUϾ"'&>{8pF8& @9=}_k;X+ ;;[߷g__cJ~S5AfX- tob U|EꂛٰmU|Yekz)ay>4q|1(JW*/rҶo>RMSm0kޣHTrThKY T )C%2Rk獦QyE4rďw-<MB`gr(R9Ru F7v-lCgkgk+!뽐w#]9|ӜRYKQ#_QGֻ9u[m42ɢoswOMo$sy@Y feŹ0䣛;}zNO"1\<5[ 9'HYslj}.YRnP.L CT!-9c>MxLJJ-Ei7vxg?ޣ ͱ?EȚ'ÔBC vUg)j iYVB.R-|ǍjRiIDRZvdXAF ` 4(մiY*tä6+C.%G< fQ^1H yEU׈FOJtRL AٶG!$Y%ߟqv)T1Ak{$d;xsrҾp2y:lM!$96˞ÃQʭGcd]ss~9bm΢.Adp~9_bsS| ER-5!J4-ɳ7.a_c._v<} IJB"w;PcP׸kֈOߤ+^<ޓ iSՒl%~~d3k*LK',f<^h%,LC^v?rLve֩:aBZ<Bbh#&aVQZZ:{ȳ|gSu>V,[CijXA B0Jxʏ)*ɩ˧u{v Ag>f i(K8iϡir:B] WO]" hj~?QS4LrDc5 <OdUt߷W zß㔙p88,kjJ(DK$%y N# ŀa],ܝIW:ujuǞoڍFي  Bb"lHৰH !R7iqn}NS,ε ox}\-q _Kj ^\~W`02l&-#]ת?|- \ς>lGɾbn>mjds{'=Arb}iAWީE" +LY]'_($9FY-qDB 'ߺg ɬ@Z2\u/.t#Lӏ}Zk_;IlѬ`x| ffdb0G<<⹂gcn->>:}@|&_ g҆vTe>߹ !ic|WkJK?HŘ^쐕㤤y#^,Z qҢ#]f:t`%=B,sOO\sͥﻼ|G;˓yb3E?^`tzYctY/R~wEZغ<@?NhԖ05šBU-jɟ(RI16v{sc\]~f,_8 q4==W.) JuP.ǣyACN'ZL(7VC)OOzI xO3Ek[LrJp{o8%l>'y6-$%'ӜTUH(r`Zh%$U5{k1˔+mFb4/\Ajr:RWQ@8KXℂLJ!~ԅFwxKL:Dzƕ<lY?\NЦ]& SOS%/V5]1Ram {*p6-.w)6vIӂnw^OR؏腂={k1e ?ܝۏW?s؞=ڻv6&ͪ\RP#PJ}?THU PE (mMM7ɲ7omf?\,/_?{Wp%Nc~> y>ÐwǤyrUJI,Xdyu4(wj&=B287bA2yg!v,XH~pXu1zB8M'ӯxHbH$W/s0^\*>z e -y& ޅ!R.Y{I7pNKsҲ7^bh"s9cUvh&^ k}y·69pi&#rE^h@fC ܟyt,\KQ,ZFH'3lYs;]ɶ(V_9GJ8ko\ \.z6/@xG)6@.W5i=("6PsL^Zo3Y]/+8 ߑ tª:H:bv*3YzS@D a 5Ipu,(F:mG )Q3 %PcLˠiT !IןbN#0xᙀ7u0E aNs_Ü/Ϳ'9 T a.M_ܝ[]g|kg'3ILj'&6czV((j[h)A"7E #*BCk;%il;Lvkf^{u~xwCy7ll[?DU+׷HH ozL=WdH hFJt,I"~Y%ˑk,naK;^^@ݤ>r&W?RmdIN騚DcRpdȲ_dƵ>Z8(aski*ï+ 3 2fT?6~u'rzx(鶀ߗYiY'+$k[2XQ0,Z05vN޸M},GF(9Xw>Ъ[%! dG^"Qk9'f=w-^)~W> ptxj ׮mK(9!\9~',X[lBfk<l "&Y!#U{J "\pD;EI5xUSE1g( -A2[<"Iy܋R 8}KkdNK82nO4;O:_{d ^`̷V Aİ7FT>ۑ{ѻ{ΚS5Tחn!ՆBt>!R0n%f&77r ݃kpᨏ}T*c}^?ݏGd g{'t+RPBu*bg=jn*B=ʒ„ޘqݵE|] !0w MQaJ?LٝN,`!1I$nĹOvs>g*LAmwd"eb.bO0;( IшR7ٕYcO)EOP vڔy QDNpg4Vbͯ2iPT%KԸ$ޜ ?o߼zmb;&/ ҆ T#^(UP! UϜz hTU  CQ7xevއ,G>ϣJ&y۠\0- :KlKeЙp@=ʋ6ƈu7{uI"t'/JKi+<DZ,fTtM"E#Vd~GpuÇMy!fVcJ\wݥI`d5*ATqClj(N w'TlWY.ZM&rM(:"JP$oVg„3wysW#w^~?_FۀOhJ~;ed$EE5 4SEV%rIuKM^~{*Z]٧7tCaw'80:x7W'2CUVӫ|uïWn375n 8y̧7<{d x~LF;\錹g6˭(&+(tIb&負FĤ XLV='͉4KėHbx os%^m Tphqgf#}?>MkLŜ#KYmc3F J z{@ 0e}:'LcY5m 0꺩+񷧎[h xc~ˡk[V :8v(qQΥУʴRh&6AGBso(Z*ʹj[q7X_ǏpPeV;>o)gumKCuL-vQwX." 8@K;ԴMo!g !as5c!nwbȆFFȆF9HD=n;% f"@b +i/CrD}FהsC!*V1ڸ7>K+,gurB%qmiX.@%$S4)\hl&!ɪMxFݦXGW.bs*/y|1_0._"2*yXvzIx_g7+k|0q71GL'! K|pSU[CT8@Vd>T^HGu /Ó`ơa*g8yKUz$_ }?b%a)|[*}rpmc_7zxALLϯfܟqx0=jpa IHDNC"? gǶ!EoWO„pSw`g e[okN)xU$>07iҞDu8IYop j Q3qn܈; O-vdBQ&)A"n.Ka|Kq &F)"l*8ΡUVxқR45K&;.+%6޿ډ湗H΄v,bL.~{=$/ 0)T=O~1CT( "~΄`&SX\9 JS*6߾zq^{H8/>IwDP'$W &_}uOy_<`%eH96*[)r\rvԛ`pyiጵ C~ۻq8؛>*h~벐7xG$Nor"6Ҍ$rs}ow?>뷵mJD)JxQ)Vj{ܐ8q *J*UJ"CKmc'&_;>~0ͣQ$[[9?d(rϖ8ubK O4HR2q|?f,d<1>}j:ѠCNoB")YDiPXhoV,L:〞pӵI )dl|<ߨ01U#HH$N⏉"I;HVYR\e~r2G՗EAr<'Q wgpkFđfH&)͝&nlcỎ"шz3Sx:fFEw0 ?++%\|nAPxRznkY;zأ1wTfۡ X(D"Jt^97G: F´; I5kq|(^NQ #jy`M+tټEhiu 7) ]7&L(55$#7 \H`)ln?q°yΣ '֊BBKāz.݃TLkxN@Kj\TyݶMsg 蓦/Wrj+f硍H4ɥt.,{ ?3'c8n̓!2qRw"G.#?PdnN̻-t.bA7D1->z6c.=n{B6 rSe _%/B4mSy\'ĉ2n}#;[] U汙,l8EXm>0}j|$y{Ћxb!Y*ぇ҄YW8YɰXox/[tV|w:ĹxFh ='`i\)>p)@`*sAsvsN EMZ-Z'>O`a{tTd!Smm.9?V˦Y0#l/)I"K,Og*1 OҼ> ݐn gM/qY,'c?7/(X:w[6@ JbYC!o5 uFx!F1G2&"[{"yAk(r:+R.@}/ {-F*J` ju$LkD 8b`Q)hwĶ߷tTxn.QdH ?E.Lg'_MW]_=_i3dBB+ $,Ȗ=%e Ha%+PPEpx̴񴻧nPRSuyǸqmg=>5]^ye/G|r.&|1G?Un94Vk|M^/<](T>_&hyD@JXGu8{uD 4bG?lmEvadK$2_$LKXuSg5M k"Mg@,[~ԔlD8TUY:(#IS0*Z !dR^q;{|pLCVWp $x2i IȇEҙ mN&%Q@!|t<*~qmvr7w璵ٜ/x!e`86_&G%JU[2Y $^`g%8/$(PdH]h4(+'pΊoq.X,8'skZ<3u+ۘB9^> JaK&Mk,AfbF1{zB7mY+)RݬGNSk 1Y6Q#4CfY0SByaaj<1ưj2wPo ű'b2aO6;W|`ȃǡ>. t@VJˎa_Q3s{/R*vοk#I)2H_WZIENDB`trollimage-1.28.0/doc/_static/my_cm.png000066400000000000000000000006711514066130000177460ustar00rootroot00000000000000PNG  IHDRHK5sBITOqIDATx1nPE ,pV.w ۿ"%tQd=oo߮쪮ʮʮɘz+:q(g9kʩr՜ޜS~yKWRT=ܗy.'Ͻ*Sp* eczyP2#C4Dd>hZޑ[3֌f:_VV>>FmYWGny~GLxbF1Кvӥ[ݞV_ܗnuG):"q;,D`! wXB"q;,D`! wXB"q;,D`! wX9d"sIENDB`trollimage-1.28.0/doc/_static/phayan.png000066400000000000000000004034761514066130000201340ustar00rootroot00000000000000PNG  IHDRxIDATxbӰ?@ X80=Q ? @밢ޣ? &,1aMNS B^0M%52U6RA Á7d#e/B+rdvk?qۦW_.5_x|ax l \[b"ցY =0yKnf?-Š`(}9!%P'"|dՋ ^d*_ ڋv+zR+)o00@* wT3lƨaj`'({[0(acb$v=c uFI/T@` Q03U6`kЪ@DĎGrW@Lר45P#zd*g;a^~2lbg|_2 kL |_?^" ك ;4E?Ԙ whXjC b+D'w<:=bG H-ow@ 8F%7bS( id /bAv$uM,tcg? א=96\aoM1qr;(1w E||i y[ дP ?#W&כg/ro2x=P ll*18Am=80i;|h@)FQ; QԈR3:<> LjH`?55Fw䊍@zb{017 ZG0=۴~؉p-`"3_#_ABzڸFHe.3iù@ʀ Jj 2I*WH3!3 U^H Fl6d/)pud>o!C-s?\=lP?X#6A#b<l jff|)j5 ws 0ZَRyX@!)5˝ئ&i1R6P{z 5-v č2xX'0x]ɰL46Go_]\A ;-dlPЎrh,J'ndU5 )?IX% TgZJ٭^>7&b.ϏPq+(TJ>"|qpdsBi`DL+汱=ɵo0CP#OL~#fmZ\!#Vy2G`o5mc``*~&Lb7ba l cL -a||lM@0=:~jglj{08; &ajM6Vd=#]L#g$q ) +zR#݁^!ۋ+O W*at1vnC7_Y ^ idO75aK\ș_fAo@`+0cyGJCwDE^bҢ? e4^W'^CH?9韘 =`߃Mv)apՀ=^~jd=Sa|E! 6_100001W삙[GI;@հ?bĚCraI+03 0]<1~E7>Bn#et<>;HryRw`-{0oa 8j`‚CH0ncpUjS- 3re+ъby<\j@+ۅ^c B /zZV`<_nN@9N BF@\ S0@b8 ' R@H)I)T񏂡HڢAlj{#uԏ-G@zd@l|  [GI|÷_1@!C{S;}R.?&QK&T": gM{;>}͕D-OoYPy׶_ dLQ+G|ήf$9tD6 C; N2fAL!)@%1dٰ/,&7¼]vD;ubҧ 7T^_/ej,9_xl[oԻgzLk;^og)g"EF!['ղG=*Rqabĸ!W^V@(~Eyl| {/: ;REY bAW@JK'-&'#̨U = fZ@2)VƉ- 5pMK`3spU@Y-s Nj/H WRj9@).3əӃ#El%## _rSUK/{E0VKL5k@R9*JLWm#_jRq> g"Rԓ6|9fq($`xj5j 54ar |-%Ù6BK:em2v31z@qM _ыoa=חbA pzr9ωJ. Eǧfb)BjU@ҹL\S*M:ȩȑk8]u{6-vPWZ1sR30P'#'BBZ8X@NB؂tyHiROn!3Fl|0ѳr'P{(y=Z} -twTTnwTȽpHeu'f܍\7{/1 $ &ǖ7 enz o9-YV 6 3l^)glbCw#!R+F\vSb`(Tȫ)?aY ‡5 +}濅(|~l<%vr d[]bӰ? 2HYpG-@I%K 5&`Pғ%wD \SPcNΣX;*~,sՀ22`|؈u  wTˉ·M?/B1@:o6@J J2n=Q@, 5}S3_XصzF.͠FM?P>6g``7"~000lǭ#}g`@m(b!O[»5peB|f eb|E6jmb)雘iRyR06@lǗIV~%,blp͓30_*ǭ30`1Cy*;A ݈ e6EVClb<r[$hZWQVڣ<R" Ĭ-ȝJI?_ o`C>e`@4pM|ߏ] Zd`D֏p``<# dX@JπА {[ 9|-(5@`b8 f=Cȳ6L(\y05VZ9~ r<·234-d>?0.u@o  ڮ@Z"8oO6Ba 3 F&hU\;F>5b=}<)m@F7P@5U*xl OL10]1 ! yߝ%47Yt*I M:w b5x q s`[9ϤR*lL"1x%bc1n!7 Bii b H $Djkj`!@0`Ďj v@P<1e JZ5z 't? wE!(Un(: v?f  p50lj9`[ `yB O;T6d1|fЂѝpXZ؊]uOl^&v>0Gǥׁ? CulxUmnzG?BUBSn[cz@_(bӰ?+Y)wcF$r%d7s`艙$6G[|d@Z8!3-ԥ}܀P+2q]\^Ik }FWV{q #3O @QRգ5Z -y0:'d.9@7BRq >;zE6 _LL 'g!@`haWbwzѷ:R8lgAn2f GlhVB9a6ZVbڊN-0*ц mu)=O.>f) zǀ C"\+pg`@GRѷa`ێ\ak8dؿ[F-@n4lA"z hZ *v#GW Fr<:2Hy6pu(h >NvWabA*rϟ&ßxA4Y@ m Fb$r $l#1>jZ.P f,>[bMȟ1֣ 0s#|\꩝pGbCt3)2(RK  `=}!8 0G߿[anuV x+~b>?a7-d8{9N #0@(p3={[qJp-y:t@?rq E#llz(:猪W=؆Xm;#g2;1{0yXo_##[^lrȀs `pL ̝0C`4X:plN&fPM YftV˾3z}DkOvT'b< W=?hڀ5|6x'f/}ݻ*xM[^.R v?4H)h]uMEQ \@juzV.F-:$UX5T#e]Ph޽>y{rz w;-v# 6'GK*v7Vzrcj9QHr b bj^㈯׃O2ճ"usZ6tUh*RV:,V 0``^|@-v؆89;plg >J'e6k rNb!Z%~ MBw9S?rR t#V NźZz/6#/Co̩9`gc<ZxA?u,DIi,V;`=z] Zj 1ghf``5C 74#0@jO:jn*\[)RG[6 8o .fDv }t`mza=rw":wX1 tspUk ]5nDn0|@=4# zpQ{%^ɇ?H* UFJ/m0@JIM; GU,$EuyPO0ڬb'dp$Elqmp91ryuBf7 pTW?^UV#\'fb;l#ˡ[ 6-HCF;.HXdO]/ kK"F~3\OB2TSjֳ,R| ű5J}|91j>&45Dʉp +3\ -#f  s\G mw.q R{Sȧ100} b9Xw|=:{9-؎0el ܝQ 0 C{!FU=bT촨1@9XZ%&5 q5JqTtA9w s>|j >d=`-ȣ,ȷ.:j\0i4-d.؂7}[#%1gQ{6Kh6@؆ H;=OhLZ_Ayb }?12l(` |תv탨0OCЂ8 \&fa6! <5YUȧO *qؐ=[aQ}|G=c`D>sQN 4CL?+5Y+ |n%g! 9C7+P2Di|ri[<7#)y]NQ㐰[n a;b]/ j 4]_נ@FC.nzg`2-w00kMcΠ*;"]/ ^~2QEC|}[:"6mw`300|_#b+IJC^-5CĚE @h=1z'5O" V8"~B>y)Ȯ-sj@kX!gБ3Ҭ`eb rw~Q]/ t.gsOgm>E4 '&|؇LG=-T'byR5*nra|zW,ʕ>1ߢ?\L ~lzQKri H5Cd#e0z[Tnw2W8q9avWLw|HyQL ۡ=&_j9r!ci ۴ju@^ߑ08{9 d3|dnY kQ02>ʂ\)#|b;- S=v|jԺ]A0ɷ%O$v ,,mv f?زvo4SًPfr{ZE8g.]0Rtbǵs )wl'9,A5vi3(-pu~X>čܫGlƨt疉]g|^ >|kEabY`l(1 ѧ ?"F; <_0n;9-D;XR 4 Zl AlVZ !Ӄǧ77ԏKT=ĸa@ z餆w^Z$E v])f8j0|[R*5 =f02=q2FʠÆa=y D3?}Hq˟^##7,5J<+VD&8#ߤG̔hci %QI'` [chyej&$rDc;]E400PfE<;b t<킸܀kۨ%# ӫ?NE#(?304}?DvVDZHo~[y *Hn8 fb:4F35֝p 3 9 jņ.C+P,FG)A-s?ÿ3( dl냈!7dA2"v>k(pU k2Pal[V]K @y:gj׶x:9\F :H?$pʚq [YȖ }xa-UͿ۰2`35[~ʦ׻IZ;\@hQ&f*{<b9d30< Co6\f 9Y@% fc' WP;/`mV;,e&]Ȁ0z#D?el1uYOB ^̵ ^1eGяy2zI i[]; 0}IG {#UY,0lFLVQ}VrnTV++p-o]!Zx#uO_A/=h/| c,aN$ 0H2wwAI%e<;kۍzPR=bz ]hy4Ħ }4? u^R {WQ 4S5o^0"Zp(G a:0\Ps*>spUqgmRp8{ _xZ GFE'[e0d>? ކc -v,iR}!zGǶBdllj/JB_z r@?6A|ڝq b[U)LI)O_WQ4*\rC?Xɰ#;BwpG;7S L|[C*U52B (;]Dh> G 0 # ?FCDciz#@̅G | u|^?RYMJ ]ȕ)+=6JC0g` .Lq' ( ?zVI!+pGߣ>O\Q} RvX6HdO91 X8bk*,5Q000i 6w~:V>ud/1@ N#b o{] o[k.ʟBt5ȀZ[ð 2FU - ^>0aPwn<- e$aA*\GXwy@mfئ_wT˱ڋ\A#9.خEv- wTQg8 l9fmbg`J\A 0_Sue-AwR&O{ jӜT_.ML &u(vOh_:[tG @uW~ljao v*3>Ynz!+sEO-3۴W%,90zbp)^\q^8br\ &M +HFK.Q<_|aP]?]ڂT`N|Gh;!+9Ql#!@i>'"|3wE#O!0>E)BW# P]_~#zZ!DnH" i AA(;K|':y-bk" b􂈔'+\=lC=$xRѪ2!C YQF0lgEmͣ| a~@O_ / !r;|5ę%! |'N(9$Ī! 033bHۭo+zA  X ۴0mA_@td07bAtk45+/e|;7pc[˃OawTA<`BFdp d3CZ;+VFl@V"ސ^\i;Z~͓ܝ;0 CsRNX"xCK"R'X5EQUͭStv4~]GoMGyG5GȪFv+X@gj# M p"7#YGRY"Jk:  N!@I@Vs|*8ԝ D;uɑhD5Fb*h6RIdF}؏YU)y* wx"Ĭ?x#l*_4/1*%eQA䏅J+[Hy7Rw#XΜ 6PqwEDLM<k[ϟz5W )tqD@.WHL|V3g0y6ైQӘH@jSbklcJĞ 200`0lrwap5#W>ާ׵( 5q@Jc|^et=r7:d@Ncezo>&(62]A [ = C4 f \J1Rggա[nH7KҢ|G+`kXHs iʟ`p2x%U >\lύJ6( SďkDwv ڷ*ψB/C7*B{r>@kN-lހ(g(C4OTs'Z\BZb"rLo0mlstOB?~Uv'ќ见a;Ս<+zOSJO 9 9‡!]d0uyX| ƺP|!ح|T47!o?+d#_~=DB7ZIzJؠvdpM٠92{_3plWoFKLopYGm%<[&rA RV*$YG* V[jUڣ?l1?f*ۈ3aLZa%J\IYC.@6 y 2NJt?!,L&L>0xa|_G2ĴCJfVfH 6 0ڹSd򁠿q&``lu z09t=LB:lyq҄>L{ #G, *U0p)d8l_h K7wy0lZ[ OG^k67ȩv=:{HQKwnʀd/<̉|k(0r sr;- ^"@\WAl'!dS#bWHF/w5 08j0|[=Ep[䅗,UMؿ3(Bn؜ŰL4Fz]>uO~lBh>~l9HуWHha ?m'(j#`` JGQ|0Yb 5oIRPʚVa|ȵ7nEtʒ㤮Z4S}+! 0DqK3ڒQb"uwϓp\ǟJMjAllDu9@-J~l#mzo 5{[{,℟`;aGwCQ+GX# @^yl72@`0mф*45'7"TXpR4valOCX^-X 6 S##P##aQ'0XL>02L;./ud`K`بp b1U츮%'euQ =-DQ3e'A9>~Lhl;2@Y4ŀ={9AM `nS,F f2@W1v MC.A . Y V Ὠ@G A(͠G6@>< [C~r%VDH 6v\30`? Y0700`O-O=#" WeŶ8;WFFl%;\o7#xŜ!uȽj ?a` JxF(p61yFRVՐwiEa]=q L llX artnyjخ` Bgj XCܩb y*!@dTy_wJ召`~=?܊mQ*r8{9 Uf& ]1@ca|>/Uh|>@*cbkb' Y#9LmTq 0 GׁE}9 m1G^xLnc 3l0ݪJ3qYЫU؎1 >ގ{re!YM }>I@X 2XnH]Ehto?tL`k H_m@0Ňv?d<؛$ ۘFQoO_כ X<Lq=Y9^08 HЮ/c\"D;(gH/bAG"F#eA 2 1 @axBGyۋk*[ 8'eu9Euy`ؼn$eP:#buHd3<2@O QSE[jdwL(\7")ly؟xش Ч`a+,ʟe@0?aՁ~J#rXl5a`@e~<%Tawq-[ [@>P %h00 D2_ j; ܝNP?հԡ1a߁еi'&I!JL:9ٙDZ˅sWAL=s M릛g;Ձ.?SuoIov'$PȢ=oIf@p^fV\s`+9De旦׸*; \xhOs[c"0nWVwNT!Е$[l$)7>`! ؿx}_;j?Vd ox79nU臊$jށ=zA%r n׌V9jj:VB^O9BgSbIR ^!6t;,Jp\4Z%$Y{ AUJzߩ_a_Okl9\D 6oZ \|/>kC_T\ #yuJU We{ zb%F^|ٿ0k!@5& ^X\A<q|&n&-B?|qGJÖ?uySy }WDt0i@blC 3@G_0AnNC_܊P /2BT:)\>HO^}"lЧ +p|k&<0)_`)L:hX<߄NŶWه ] 1 g f`(a(f` /#JDU8ɢ`r?Sاk^{B2D6 W2vuhnedXT,v<B=/DBwT^VӰRpEPyzshTgeS=~>,zcjZ*sVjϽ}7>^ =mH`$RŝnSFBx4町uii !}u]; h(,KG@$GyB@%@^9m1-VR[#F>lGŖp`HqXla z[pbœFl |%52eGg2/kF" vrW22r8q3L vm`P##p/2D/@>6A*m|_?= 9h|U;b!kt$H~N\i}ۥF;dvd GE"lrĀއu'|1'0"at7FNi ] 0&1 0 --dl(XQ$#DBs|8/ED8|7:ʿWu厵ٕ =q.CM9t.SӶ-ǝ]#bFݽ&qyJѴz&p0N>ƦOj|!i!Ija1sI&GAiht<^gŻnնr +u10Ukw+Ϡ8ƀt"(DLOsj50Ϭhӊ̿GE Г[W|ʎ~W)@Vvߙ){9?B]Z =j¦s \ @ <)؀]@&(W'|gY5MV*]TqwrX A@"w4,+㮅%| Y(z^{'%@ V߭il'$}nMINª:?Z k1)+5.D[RN9Omi<ѣdrJPs$@%YqX h2hѣ("v c%~Q޹"\~_Soee zz(T eִH)M5r79Ս@voN)jDo_uЂ;|I˺t^ },}B. I&+g@Ѡ Ui}*_j@,ȕq|] zY"P*4;H<.׋pI4Bkvx-Ew rꃢ|4'"D7#-3-"B܌X4+;>+R5/AiuL!:7Pv3*jtI,3짬+Ӽcҵ }fR>w%ɵ/pR:ts8P)w+d7iS(7.LŷDEkq&ջ&X<-*ah(xܥʩEVŹ .UCMTVj}V9F$ʨ]$wFsCw%8;0 D2%9PNC2'%r=* k 1ؒ,fܥ]UZ8G{ԷcY{~Ao9z*#TOX'~Ӻ[G=:eeRNr43Tԝ=0 30s&NA{N&Ɏ7UJTM翗Z̴HAV( #+WJ5m'#u@2|;z=${u~|Oso94bPѨ߳w'nHa 7kA,`{>n/`)w`]-)WK#w"#cPtDB(E5bύ S2<}W)O0N"N]Fig]A >ճo؉iZV͸mH<@Ži[邏zvNDR7L=۾ t~r售zSĝv|FUsDwFIVt͵@s ]Ɔ'6.A\[ؔpx$#`uO c҇q{b JTiΉwY?a}$Y$o7ٓ8TIw;GQJq]0 KECG0TB$qriG%Ԟ3f_;THr#-mU Nhʙ2|,i;9K[4 ֖4rA6gr8"h~ߦx6;&<[qV\ŵ94|6mNt[{:Q_?eFojzvrJ?&9ٽF~9_5_-..o70 =MfƠ]ii1RP0 kp4TO$ UDy|c 0o$иz?WU*.:1>J߽W'Mt HRJTR݁I͟ہ9fݩ&&}a ˱"(24,+g)*¹i1,2f17OQU?j}:>}(+9ZmYRbtYz[`nM "NLF$2S93;V( 8$gT뉇\  ?%BXARd_rJ$oO׫"z@ |rϒ8{=a\n@Za-\a(%dP{8V0ܳd`@ KQ8!-Qtfrk~0؜bO.!4 {}`l!"L z΢G?ʟ6?qiDdU0TA KpdUV<䚁ÃPYd+abG(= W:vZ۝;\bw] @ gr;q$Wq*%$m| r^G_gj E(t#_Y`Dzn3~,h@ @3G[P;" V׈\>㿙=pemX8PE`8c''*tUջ^vwlF~f:TQ;doPM"XQ7c;lAwQV1 .ۈ.@Έjl/ f`Y|հ;[q䱈^E5?Fh@6R~'zuC˓w  { 9l6<+{θzF0* v :pq ]8^XD7[Cۼ,656"eo0 O1Pf\[c.d`q #" 6"} 7@w7,/d:A (J7]0 t݃.*;w•'W$@+ClCUb7UGwU柹U(M8;e< ՕzUHq* "r}@ X#Ѫ8@NF6 <[ wKmEG9ؓ['w Tɟy/}-EwΚt?\] 0ut AE6(#,, TtA8;`^cQ";k @DZ%\pfjɈJ{b!dkRJ?||,-qYt85 |R^.S[1=(ԊH#l' XAJANF՚}00ބ! z>ͷeAq? ZϷe0CE{3Gfk2rﱇf dG=#Jy+Q{9@yee_yN)>[6" P.b·=\_o9`-#|u{q ^91(-zÃL z6O|:Ra+,"70ZO g\OԃXe o8ݯ'ٺ|%m Y d=d9t!o7m#;W Bn=E7@^,_dm.u0\pknom<Č<^\UVGv5+~l$s|bȕ-z}w aÏ@ +j <אTb&H9 9 03lvru'SI;P&@"6k?Ur_;e>n+HU4:_q- g2T/hR`p \Ci3ԼlCsHŶxf7.}Ev JPFy=` ls`kh`[_{ ҸCV zo.b``/$*p jm6 IE:op6mVRQr{]n7!\G/0 HC̑%B'.[>n u,"v7]1P mtpGc⤳G ą3Q\G2`yS‡/RW]6(lRA1NdZQ}M욷s>]3Ati|~nh`u51™vMǒ/X=kvwmطxv,> 3<3)}u'#V:_dbgrz<mf7>'_Go)H*?E6R?7' zD;@w (нU061@NRVc#^ K6/3@?  $l-b"bk vre>!k(3.|7 ~Q]=y\BZ VD_/wz̈́N.#_\9.`ئ5S;l p7GGU=tȔaZ~^6̴Mkxx}y6/3BHxx)AO+J~ BmZ(@x]u ۙG#÷ v O PH3 V`[O[#yq/1h3LcheBQ>ZLWQO\'thc\7HY HE66er\];0 5l]`fҩ bEb0l 0r 9*uBb2zI X*5Q*MϳmZϿT˷L`Ao,~0T,iY<6o1O} ʚA[ &UgZwѸWOyLA[Y4RGb`B8/G n8Ey놼T Cf'YVOW x"P/x]؁0ޭ>oY3)+U'EHx1`͟2p}kc7Zh?E~RkA|!F}}] @ )X -q_XBB-R&slTws:\"hZA.Bw%@{֑kH0!`uo{N(Gڽ紇z\zle4NLHݹR? (s4*:>K܎[R,]8UmHCݻ2E>L^K:w7%pUç_#2$Lwd "\qD0b;tp"|t>,^8>]@h\Q$<_@q(BHUa i .{tlrs;YBIݗ"' N!lb}|ih;GC(nXv/|%%IJ0y6{| 7VSAfolOv7{orgl)H~s=Fd/NI$BvMeJ١-c0sD/h()ф BbI#,Pr]_aioeHETTK^m Zb +00ɲDf6< ]+n@ɠ$عA/QJANTB뱟f e{;oyT@ϩVm2J;)I}+տz2檾2C5~sj8 ~}ʛPBehel)v~!.3>Ua"cB9e*cPwҦZ~ɷW0"l&\kuC8R[Ч4*Pe{Lcwy?vmm{FV_(Jjn#d^ O5v,*~<%׷,_GMhpRÒbl )&b[%U=1]10 < 0"#O?KXx`7\19u\7q\*ŗ6Z^'XtH_Dx;s,뗠$i*4)bI%u!9WN[47xq]6T] 1 %@P0cP%A1Du?I@D~c*:3 KS2xULՆ1ޣ'z7nV+X=ibY,zz[9#qv`sp.uظ>r=[*BmqSCuدJv6,9Y I5": |{ s.[2,^zv_J:m}]٪0i[7"kP/'zA(K vJVv:yF |akd`߀C>ǟ07o|#oa#GPJɂ5r4QOLd`u;C5p5L`x Zy)Xo ~4F+<@>j҃#fa >|s.b5*bJwRk?Rtb t8Q 0 D9Hm+d̓Ut0I>!kƥ4|o/Dv+~5foR x> TyGM1g"Qs0fJKUYjAZ=OO X\g{h2ukD,l񼆀Ǩ~p~,!M3oV?CI{A|G:O2Cf2 ^ egβo]9@ KTyX*I(>– LUb 6iLkRW*ς*Ld_h"өS6=rPdpf&f$ W$ ,q oOmz?'nYΰ)2& iGpl{1^0vPnWPxv2w't%`g\CFPTUp:s_]I Ox3m{2! tEx i+*Dc]KB4!ޏxrk R=gTs `7,'d^%2>Ϟ[Y^B@4E93neZq fPZg;{&dMiR헮A 3ZXOw 9yV|7-] ˧q/ tN%:A{y't1iAB ۈ8ߊXEYzఀ{OlEވ B>&,9آA@Gw ʢ9.i3 -v|H&p_uy:#6e! 6<Pt@"Rq9a UhB<tE&(z~Gm3 ދg.]dU0X9"WpXB *Y,CG&$4B1\Y L&C.A Pa*t y(<>?r惭)@?y- aFrNltRGp9ȋ=q<^,u1lb_ P0~-s?"Ndy\b[G)ӧqBJ# ߡN nju̚(vl(؉sj PaCJ"zC "9Qĸr_c .HG g/g1yPѢ.茚| Zir@2]Q:﹈H}VOveQLV2I>Ib?}Q+ R%̓҇m$cs?bc ^6lW}H>xy?>,M+J] DۂCtv Bwo 1 pNVߠ[…eYs2z@Br19҃+҈<2EOb+y\T*PW %]10 qFn%bsn^.G>ov5{v\$"+JJR\@7{Gl+Ƿ# rbv}ܒc !po %/|]C7&Α<;*vA&|WPPEcq[P NRP_q&_pzٔ !s1 umݐ@q3\뤓:5: ^X1HIC4I&~޿mG:zi# r0Ukiåx|\syG0Nt>'"n4@/Q"@<8U$, uz~uLkOA9Z*D8segEW$Ҽ ICba`@Vȕ]•.@in=2WE[IR#ty;/ Yp` 0F 8RF2dmq^X4صa7zf02d1xeXe|{ (A憝gQ^Ž0Om )-JcQ/8<XLyi`_&FqRqB!mxkz!,X1srÓw3N j?rp1֝p 5^WC@N'C K* g_OM@O|k\iF!0wx69 U(ln 0 DoB!a _G WU%8$e(JeGTm\hh=:csUwuq(VkzD5.'u]FZ`C'":puG|JڮRKxs,@{(G$O2z~?Ѿ̨>ο }1Vf@fÌ6N;̡'FiXt b1eB#҇]ǶX}HYqGU "3K ;=``sdpdɰ:d7ÿc ^ vO-x2 H-Xegؿ&lE & X٦džMSDj15hQp> vȽU=[/9>F?#Yh[P{1g i`^}UFPQиP10@{.O!Ot@]Y)0ml 0&G-87 =oafVVD#f;n `nbb`\UVnJ's9[5dıYT[pe#ePga lчav.,ȇ )y*̅jsXw<anuy-AB۴7=v?@y^[y] =w!tl!~ -OahdD@ٟE0n5Ldo!ֹvXB>; v/z.(@7s`;B f`ЖClH9ٍyحw0uiZCz^`cvj* `kP{ zJ]0 T˃*#5++@`W&q"ҝ(f "9)n_YgꇪSIJ,_YWx=||Ysqzl?RB܆~ D:&5=2͖? 8,+۹´wa3|;%{QAJ"{ћ5DP xc$1.WqP^iV [jDv0BSo gL(1ۆEJ>sHmz~|}PϖLp_\A0 }#;}oda\[ɱ&B@$ ̢$+-1d9Lga}68gj}Iʅ")rJUx˩{Y!S"̩z@ @̤{O9zdb0!UIN eWL$+1iRds.J]=U\YJ| "Zm|/XÊ es.sϸ0*NL>]0O~tB3)x0 !=g쑕tV3Uq_74;?3tWu:K\ݔ5iy_Jӱg,x'p`w<[ 0Fԉym1s Fxe"Vp@pC*l'iۤυ}޲(3>;Պ\fZߊŬ8"Y%cC`o S.;n]^y~~/'N@5'S]0 %"Sx/C ҤTHvϤt=l. |J"z"Jp=.=CG)Vfz̯`ibo"Rn@r8#k٩$t$}K[d9GaQPܽyp$I"~RGt, ~Mec "y\?gdzZȎhK+@ -O) ρckeDmY4=7 `j/]0 1%AA` J *䧈;Zqtrg-*.J?UT}3`֊R= MZwBߋ @ f~N@.]c,@şևH+؞z Qb `(ˆd4GkE :mPW=Pb&4&^|?lZpW8CԅG^g7d>ʔ<=+@ B1 D$LXI5(B(?ϹYqV^H[" &>0$KEf ! Nl̞VK iʌLzH#z3h/"<'[q~l{=빷&:twe3[(qIC$ʨOk:9z73/QEъ٫Ѻ5P5*yٮψΧ`1c1v}G.] @ tJJT@y/] 0(/<׺]sn{7T"etƙ#xt*o *OEs;<fHtð Ӊۀk8fX_Puξ%G F3g" ;P| a|p gЙ{C:Ȧ @UD:;?|oP Y ]ɖWV8i]I@g =)ƃ#1ΰs?I^ES@y`YJKLJjN |90oNVs 3Pݐ9rc1LƎr`$!ZNt(y6/Y1$cGQT!a\oUAqB?տ0iBL]b&n*ezxnk]ځXU+?i] ]I0}HC =ejI)x\ڹ*L8}8${P byc4P7 &Pg]0lё710;W ] 0 ,{00@IPhA";iҾDW?ġS79$*DM8͏^lV>bQ4.Y!nxԩ ev#1Nkz(; Lp.l$ ;HzS#.Joh*vYo0{{Aᥑ=Q(Iб2WD ,0be'{DQ kC"EEĝK 0 Cc72(BʏѾ ۊjV0o)u&3iAJIڞ1C=r1wm8tkqJ8:d&.n%/fS:{vCyD&~Ԥ9n>nVw0SR r3J=/F@`8oqQ OMkCѫz# ]I0 t}@~7.= ;qB%sHg gx^>+I=lfFskVAKnklyW֚p)4P;mh{D~6^h<Qv1H[gIWggJ3KjT*R;d'`:Vưo:Tgc4ЏmFԎ_tA]0S"0 ;0sQE %I/d 0<0khumt 4cSzbY`mE7)0k(`v3FtJ+a. &xda3d.ō렳J_;Kw܉f0z=pUIk [a$e˞Ɏʢ/1Zuz ];P KܳzwJ,Q:x <11ܮS1"?~@.2#֏^wqQٯ٩?:}󵝘=X@y tP}4P bEg ef Bǫߣ)T7[ JbMlFb\9bp=3ƐS1@wՔ̌ҿ| 0Don :EF]&_(󁱛HN2`p'+z,7һҗ:soxg g_^wmVH~N3D5C,5TMƪ̰;`5jrZcXەc7.O9+#QD:h.Lat(ӭ*CɁ+OPit :`A;YRb4U ʔʎ b"Yl!L ƥ b!a GŇll vr lG\+Z v}geZ2f1e,C_xP6 NNdc++!@ Ўx!N0@0jQ̅-h@lâ|yB qR+t{͍݅06.wtK/8,m MY,=lfئ7-d`|^ ǰta` \-LjCXw M V{) Ƈ3tf]/ wy0lfh[\>\kJЇ葧5HGO0@lC00 D#q F6,l'VMEI}g/c7+W1_ߜh+J*pŽ/^WP/HZT sIb EyP%DhY;RPd%?axq{'6@ )TjeUEdX٘+Z? Y5H{s<$`nnVDv0"8n] 0=. ;]ݜġo 'A.D_ij`wyW@* |5ƬpT>}oטIBZs.)\,Okys'"qmfhPc' %JvM0_yZ^X&sO[>6_|'~X Ac>_.>݃v.2w"X|?8/Nq_<&|GAν6&UbvL9@0=&  )ϣP>c'yR]n0#^6`@g>'Yʏ;gfpүCؕH]؛gW#3Q媕*N2_  @u-ذ8   0 ΍D$ U*h[䌐^"+eGF {IזƷEiܿUDRlG+2WFMv9]$,C$.zt=!8kMS:3%I2U:c 6n??~`\;P([4)]N0}HY:o"u1 V̨S)O ['ۥ)|΋c !9q}grtK?S\<}>;11'vBلP:͗fxC7_c!Nɦl }|>61d\BS Vhp1ERS9B`kg?;E@g*Ǹr(Ov  /Ϩa`oulֶ4槀;n,7] 0{3,+6V,݂8=XKR/DMTEf sD K9bꨛjD(ʎ#F 92Stp^]ƈNbF T|]10 4X ~acF`3b|Չ[JUԑc'3 GhUo8=dq g@׮дp0]ݢ 7vJ ,9^X;O1p8ff)]}+" ;=I`t+骾x9z<~@>Ǡ^<옼Sǜr~@F4=}BJEsHThnl笽7YPʜ<3+,c_!\ZmZ&?y؆+*IYTYrؒ ntDHh0 UA@Tr>I`QKV:J͇4S*`c#@:Yn^kC@XW!W~nE2~0s(MVzsNpDqr!9MVh'A& /bVj%Ls8y~ܿݨ9\)_a*%:=#VˉdC'*sJrq&Z1Q*aPU蟻F]쾿5a{5s7) ] 0 u" fguq_DV; pP=/Z#4lݖy!24þwalnEH|Kݯ&u[N|YݹMoh.֯6HKDaČ̑uuEau18$" Gw8dQ [=dFU3ft];' k=$ 38[ )Ɣ&RsN@O8+;%{̖q;hdU@w(ٛ DȥC @ d 6g@e 0` 9>"%:]lʆTsBN~AlLrvR.qRțKV}YXF\nzC%*iҏZ?7{uy<?rr ^h ߌcj*c=eTz!o?CsduɌ''{r:S=0qex J|yqCkQ>ĝ10 =%>og:``O$qdv'~rtε8I Ђۉ( ^~.4]K o+VA9U%LfB%]&vz@1iOJiuj: d =i0" bRͯb܆'j;wJJe !fCLs3tF@' r҉? wy,f8@ \r(z}ucںo*bD5 _<te )a|A4Ik{@󢎃=;r#tƇ)\(2Ő](Q%oV0,r ͣ7@!WMƩ~!&rqnpBG]?ׇ0`ʒ1r6J՘UP-;oۭA CP- A4pE2GvfaY#qd`^ݱ-MpmR7>}֧] L ʩ:>_lʭ4KO*n(c+I O)8ԲTWyHND([o_j6.P607%uf{7S?O81u jR> 9|(4OIHNC :6uݷ Ĕ)Ԯ]1 1,X++w_7|`!oV$S$$;ZOKr@[#.gV 8K_ݏ_4~'`ey,{@q$>f?Ix/uZ-0L46DBecD#k8:+2 zQ# yڜM g#Rd1]>żh%v߫TYr[DRe#|('@`1ظF#څY#)jl]0 @,p,(l  !9ngG+ds?I<é=pu`Y±@ Uի6a;1; u',}9k+/\ם/ͩuts4꣤M=Lv*WXUa)'_pd#To"PmB8E;UYoķMtΙ2)΂鼳렎jx0{710Er('(vSAqVx.`!Z8 ?cI6?7ǽ1 1b9Kٲ55T}Ϸ&4rwc jbGxۗWZ4m௹` 2I{y@ {BBT-j dl´=&2fS!@N'$~:uG N޶p=`ӢfxNG@X :(1vm^Gyоo9VOۈ7 ¢Mɸ8 Ch G,>52,$n?S~.{:,'2M V\Vk̿ӈoc 4٘ ̔7 ~gT^\; @ Z h'<`a y^A'AsYm Gn&cِ!1Zfk,hXNsuUd=g2!v _j&Qz~*ZKڌ pe ki8Q6/d3ktغGbe3Q)?qG؝EH>dEVXt\0r"˪9Q_89^HS&Ugѷ^qR'\ Ԛ mމ֥3~5 0j,H Urg.&"U :HH{-W}a?];@JB-G Rx[;{97Z=XXcvY 쇙f?Gb{.C(9%SF~[Ne}ՅfGr@Q⸗Otִ={-f b䤼`siuYX]a/y9fţR:x"Qȑҹ1cıSG{P 3`G{B }A'.S*FҨB+FeĶ7ׅGJBlͯ$5,LԵ'q?v&yo֋-3X.-~0DZ *"& BJ?YCc[Zvz~,5'N@`ŽEsH;O[umIMI3V8bMp<G^σwpӧPiPc=&{/ џ nhaf]2SuOu\V.c$ 8kG6V#P}W]ޮᅦ l賔s~w"ud|{ =0 q*l +p.`L 1õqb? =>+fM?EzsTַV xކ+<>ofo<w/Peel݆ih ~ {V+E?'g$Ghӳ+}XY7:9ն3%v̉ZIP.z؞F~Gp<ʯsܴ6B"7^+[iiO=VaFF/z\ ] 0| ;0 ;0EV@L",*QD]l",a~~NAc.Թ+d'FwMӨ](z( z 4 p&>w0L ƌ6F*1Ȕ2 3)??hG[ـIam"@gȌ{]k\X灱}z4+ockxn9t=츋@#d¹N#Ft=n,:!˵=1KBvPJoE٠_]0Q15k0EvұPs:! T;N8v/J|X2>դfT{ X2$"_7)AJ`(/v8C\ؾ>n~_7y[Wv/ ,쬔ؿwIKl8*\6րԙhU$we 1Ī3?[`r,c$X40%ٞsctIzJܬUh99!MƎ߳@_Ԏ_6X@ qlN?68 רvSuPgiGAӦ,TtcTsVnKJ-]V{ODtZ(XjsPRe"w,QnuU7$k#,}~&Ds 9XAolyEǂLpc}{A޸#S=͆0 6Is7ͽ=7ǯ=ilj/^3,uk }ԜDY`4 Q0 C7Uv"|E3ovZm MmtTD*H5h2䄀ʂKL<4%4OvvҸ]LD|]:$w $sgF7~bY] gUʺ41SB2?%)2ags3PUTLL+UU_f>M2Mݱ fRuesU =g>9LíRh<ߏT¤U]Q0 گ sˌ%`G)˥>od7E8LJ#u-Y?B`eݏ2yIZyƪп+Qsw#]10 ؐx# Ob_=8ǵUFJszkL[n#Bj^3nIǀɜL$~.vffv>W'שj%mrV=YOy DJHkt",;y]Hsd. d1|?+.x{E>ݩЍr8 _>4Px GWP *@.I2z/5L2YsgvHy)' X]@ STفEXRQ)QdM|=HtgIn |ek\E98xqʈ@|?8l۱?qK؏ OTu΍y⟃*~i] QP*u(JSLmGTيCWB,}^݉:F/_wN$޳{,Ɂ"+ACWh7!Yv+<I1M4<_5sØo "xyybbG߻ [$[@ l ܭ,r%\QiPH sa@?CWe K,A`TXݽȕ>.@k3B8G,#ˣgji+<) `[vRxiX!xk}d`@ciaӇld70*dy䘏k%"[P[9+G ر0 [lٞk0Fa/r 'IB>b_(nCOWU P =5eZ*֣,DK TNa*ՓDIsi`\=PYvo 5u9i?ٰ*]0V2^J?mCիc J5p=逜~o8zBJsƋSP'swsΙtO YS/N3OFテ')ԓ ߊzkil[\ȵkR3V ]; 1} ,`!Z+x v v)D` 6djcw'!o>yž}zB _h\E." EF=’Slc_9&7?;$T˴϶|yqyNjx5 t&8W/|~}'P>GTpFK7C2״e~V zqp$&0G@ Й=96';olA- 4O|0qk\Xex{/M2<,0 y՟u9Fxe?׮'z^[2p+Zo/] 0ðRgS^VO@DG䜳_Y w|usr `\gzW }T9n~T :e\v-Lvm+E8l񏄳vsh -)[v>DgHCu}.|rr]u`?q\OTn8MntW}_鳵 `OBnLԹc^bjLf g Ns&n6J@7 0 D-$6bfbfa pzc$4M&gT(Sݛ$R}h MF/rݎ2b?~gzɂ'y~S|erqۤE#dJ+}Z"Zwp "#UN\h낮Xa}B!fNxYՑcX?WHlaEbMxkbv8aWᐠ ͹;"ܠ۔*\_\]1@\+}1 &R` ZZ01vVò{ a9h9'd^:cEK5 [J@3betF: 9_"\`{ԎbZ1)Fmᷡc۴rz:no,#:lY\O^$K,2͚~c%N5ڪ\2L@s ,#JzF> ivBNQ1ϣS.ǼTQH !Z7̬? Og~׏(ChWl8]H1j#xs# <\lx% G]32&Ÿ_- k䜼U(#+[o~x8/xT5@ fG FG]=07`Bfl5?3'CLnY=7+* Z}cEsj] 0 <^ 00 /KKU_쳽y<*eOktefR41du*O t  8q'uj갱UǕ u Fv)׿U= Tfl `ȱxvo3^vT4 x+-0qO {eU2?4]Zť)x` A˚~.@CuxT|!|]0 ^Xj}$zqm;Ȏ%o5Yw)(H*f?Ig\*%:IhPz7~;JqӠ1z3]GlL@SJ7FYٺ8`(hԑ<&)=(L2RL؎(tj'UGgX*`1؝Q l62t*ܐ |(J Au㬃erMHPʲ\|^ܜ׋䫑 ]10 <@*B̰2 ;A,`Ć 0"E$,uIM8/=7jnX`tlY ,9h#^u:[?d@AklJ @6I}FjueՁ٣=ܱes?9lB[miRYXr  %="FQϛ9Bh@Yņkh8wrOaU(^`[h{d-Zq?*/U@'+#bLqZZs[nt;yȂt=C>2 wy fjRR:E_L.XaqUL@01:c3P 1u YRFv׵(4dqbUV53|{ƺ6-vVDY ;#P}~>ʹ0ylå0ȋlơ?qz`01l|#4>2Fdž ĭ'v=oVa.`Z`%Uȍ|\~Vjpu:55B`qOi3y3@H @^E  ^Y20`d>t˟F`CaMBDx ?QW\b  [o@#m5LD)a10, l |C¤ f*t35W s6W yؿ0ˇUL&u.0Bȧ̀xc^Q<㫰I9}@LOC\+;\Cݰae_j9ýt;|ll;/< Y@v'|>M KweY8UWx]ԝ @ 5@)3fȌF.|"Eؾ6lBZ0\LJ!"#\CWz|=K &4iuvRc]|,Ju˽t p&'΀n cқ8]c^ASRXsB bg 4g`1!ʪ4 ~!v. <ê]M :-V]x^\ r ? Xs#̝ @e<؃=Y؁x/?&o& 8!$fd9?bitAC-kg>f6>4Kvg' V} ~ U̾9>} Tw>Q%{+ *IT2l 0=6&8xbYݷlX..9m\HԮTW˯X/ޜ{}//s}Ǜ,6Q) drO-lK N)|R)6򉜶] A sl@IAD,K VA4TG%륋,9ρ5#;(NS=̦4mǩ M.nʗzNv}N,Gc2) 06 UݳmeT2p0IoW̒;gߠ0[j{F#\:2Y)NN"Ͻub:.R(H]S WW0P hgĜ 0D]*D9-Ep4yڱ7H#Eq~Ux&PT[S)b˭"-2Vȥg?.; 畘3߮sq9Ku{/J%"+3#p%V#d| 6 ~Q2ܙ8AJ#+aοqDepv`Or+Η`_^`J6@NQu.,ca+|_dрSEF2"#k]A @ |ۇSP\aL#SF N\|;䍸A޴شdK\ ~ g{jy~7NѤW _܆~]@ZlZ+v{Ux[&<(e8óߢuٿ{p?}'&¨TU)cdq3" J|3t4_vCdhѹ;Ow^rۘ?ƏhJW?W%]ޮWGT@IHYae * IRlA<|32=?K\tThp}> A DSb?`cO[H` d_y- {ٹI7mp>3]6a&,`O(b٧ nNwZ7c"@Tc5n:F&-{ZY 7a=uW 0kҋ>NaW6*?}>{[ 8YLdFFSHɬ F.J03FeD|N'`o] 0 L._`P_v ((Nξ!o14WtpPA]mhn${ M [Ɵ }8K#f@j7%LaceD?;f$Uٛ#TL*:g`pu=7pe\)l\'T%U7ZŦyUkY 8 %]h!aYB0w6fYg|Bi~dqQ9oW"l}]1 رNNLODQ$1Qp?>]D;VϘV{μhk߈Y)<׾l,jlXL9N^Ó)lJ7G6nqJSOV1aLA u|'^usd(7ِ%za'kOOŽY ^] @ ~,/WDjykVsqKx "[A~T61?Et6r @}cWNuyv#m$‘O%Ss]"N`aUU@\+ѼV90RϼQgӥ]bR=.Wt57N *șC@]W>@'JԠs٣jΘfT][ O/bQDLPK UnB=3wx5P.<W O׃3P,I qSj؟xN\<8NdاSZK:Bt -UʌN *bvI-EҜ.*`ʐ,p8_O]נ=Gܷ #"ay8ۭ{x {9/ȭg؉_xC諭a =-ȕ528VAw3Iv~SkY ע*rO#t(6uĜ%l ælka)i j zXŅĜoz69b1U`Т:\Fm ?\!BӡCw+FmئqM2 Ŷy(iTf00c#[Lh6l *|L>0d >| ͡R W>|-"t 264+5\Hٹ$Gbz Uk%i.|׮jT O00`׻F'H v.w&N#Me@#Gփ·%?%1za {QĪgwF, ,!#g(lAadyX&m5LraR,!DR-ȗE:o@`|\m!||2]_ t3qXŀ!--`+4D\vtpoUD)/]R-` zlVil*L _CH7|B?k~Pt0#au r^ֵ L&} 1]ˣpG]A0 |SflHvr-x@1M@H}[44Y T@`h) *3kbZƬh*gqy;CUM3;<1 2H<; ;@#bT/AeBF W~%P[+tPL8|] @ ֭=FWщS[,J N D/ٟRm?NBdǷ_@O@@T c\ :Ww\MUD= q꾫 G6GOqJZxyWy'3ݯm]l@@!0O؃ 5;# ] 0 0/&]+0 /^ qVQDŮNfZ=JY!S6vۋ<r*^9ʈC1n\lj~UW_A3lJe5b3zg 0{6֕< QWVhΞBJ!$hWUqG棊0.0>᠞ujL|1؍Qj:KMg{ϩ"uS =+sf1[ v^'/ĝ= @ FzV+Wx@;tf $?Q&hmt.4/mz=}^]$؏MW<1)"EU-/6b;^ߵT]lmjWYW-Rm̸o̫* ;@֑r*@󉚍|Ya~cfcݘYB'j: 2R0є9꬈y=zjdF"Y7F'CPh 3uQBNQPΛq[y%e*TZU`֭пSO:rԝ10WwBd鍝Dc@#_:lvR0l&;QD.Z&wRN֯醀s+3| wnluT (aE'.hbTLկ(\rTgs;G=G}j{/K֋8;Pr G"+uM'.J'ڑz|b7k2 lCߡ  Ƕ' j#5Zk[`0Xy{Qb Ml+a|llt F6 ]X%rõ&](r !R4m C؎ !]CDRfTzNiQe[[e01_\S&iuˀYw:W]\nlgxpaucBay] 0Ce3TLţ#0; Jei#JMHswJyφRϔ8(NAdWNg,+L!ynu*Ɵb~NRPU`:5뱌Cq-nQa2W6@+8<>>*k@\_i;[ǤsVpIVncĮzmx587 %F`+[[aԝ10WH|,H'KK$`E뻽 3)8y}kp=dF෹Ik&|,ImRMV~Ww-9@%v1=h5$HHcFVcS)*8N1acm5Mcl"b3Nek*j@_P%OFM2dza;2br(_z:nFT悜3ԝ 0 D@%2 [=[ Au0'(q]@@ [uFJY<2k)dk+>k,0Y)w|f=QiM*okM2I+<.t=1IRM9FR^׵\@}4-:Zp+_ɻð-US WU.GXZ+h@6hܗ䝱 0 ͢ lBEI(2HA?Rv}ɌoX|@?gy .6Տly? CQPPL0eyj}IO/'`)z7Z㘻[` $C[PhW ԝ 0  hYXH^H%w|Y7\XJ!`Qo$I,}Z>;a^Ei*߫1 V49ۡ+5$C.=KPN{kj|s`VmRoQ(XmOH^["³MƮʼ,s,3ܮ:N$9]O)2ZrG<7ET@c@P٨@JzepuwF%UQ+C `T,9 8T=ԝ 0 C=\؊ј=X+TI+Z ލDK( );#(*3ھ˼NX| q.;#Y8 c̨,7j,-^Z 6\(Y+0H*P\}LouWFa{fk!Ku[\nLW sG%|f\] 0 K0c0o*P"$R4MR-Y-;P2v6=*$vĹف!cYv;A_|2SOe,qQ>'^:xA~Gχꇝ,b[k6-vci(\C>ȹ􋝐pU74BhR*N"  4hC?B@lj[qVlu]/-0+ }>j'>dsI1;t 9#zŏDA\ 5` t\׵(Gck|.C+`Xĉu6pa"JrldKJP)c'χ5@Ryg`9l /0~z,=`8+á_CFʟJp S h3aⴲR-OJ~!g`@=&ǎ|P1'ӒҐ6ސ#`` bB@4q-Dp0%Q.BT\C@].vt*8Y\We"7#n;օ&葊ZJDba x%-5LUydXw\MoQh1~22FW7я427On\=d]c.u0;/S]IQ !\ !0 䝻0 C5[3U8GQp>ЀJ*(ՒJe^7|Ĵc Vjf]{ @fyİL*|O8JՒ ʽK )p:õcO@ ]\^Iߊ'AE :M]lVgx!+K!Aov}@8bVijA )f"_J1rF?f@Fk?f!JY&4Z7"/Z鏮?B7!cD4 7-G]/sL&}g|^pr?caVkJF{FOB;Eʥ;z[|_ +|5"6MH6 F2 Q Cw  O!ML~0U8cQ\]&TŢ|Ϭ?b.c]YFu|"4Y*ɏ"ouW[w/[aSUO3jLU'${)j]k'9Ku* 2ٝp9~Z+߱l 6kժ] 0ljܨ9^M}xOM%8 -1@Tj6:¤@ 5zqIP?ף9;ҽ)rN62dVC`v*^' r #gt&Gi$y6/)s"6,#z6Tm7?ͪA+3.swM֐3}x~XgLز]A 0 7nS lns&H̤:+>&6F.J)JLYiX\1~g*"UE@kIQ%N{HLP ##*n-L:͝MsgoZF}.2IgGy 'K!HJ<)PlCWߎ~f{Y3rkԊm#>~xW*g-# C/*zv[.xH.GJ9P?EܝQ @Du@8} |&},.C/*zȧQ| f8O |W* d\U3/*ԱyY:QN-,Y]phY9a;o(@겡"о¶Z"`g7q;ؕ\b?xU}з2.kQ /=!39mt{IY@̐?B2F$ 1l?ZE!ÎpzGw з.͏@?r8V u2 r@N#ˢG> t9X݂>k4Y^ Y?9e F`` "~>z W - m9]|`q  #WVV>sH-0əc=8[e " F Kxf2r}5ldТ j]5Gj'd).\||{a1iat<_Pq5pM* tH-X[\bӰ?B_ {iuzdLʭ=2َ|:2nw}ȅ>?tpa;}:HO lrFÊI{Ke0|.L|\Ct` |?[а5* ׸"xl~bP\ 6mt:5T@=\zRFգJq <]I o_ g`ߖ.B M$0,߯5zj=vO&ˆBs-Q#> HP%hOmw6\]1@ >Ǹ:\D6&iFi3#3AT ef{&@̈I7p ZV{_0z0z~S]&wE&d7&g*AQ@e\&* Ω3qK%Bk Qp@iVuЮXH|r]@@ {NDv.i3Z .Τe_rY\"-uĚA7Iܲ\{4.Y;YIY]wzQ{=}cY45vl'rŪS!r.Ɔ/n W\'$Q+⢨^3uUJ+`dg8V"N<q2x,℧q6]:mՃ|`FvvL ܹ%ldX'IDATuFL RaXjR!Ts\’@#9%l$)?cRLΘ( x+[ݛK{X9~J=*G[Ԥ('CڣO [_ ,VgNv9ǎLcto猻xUeP=\~Nڟ] K'{K1k03:gٹd݌"`neD)/ Z.BD ./q;5amMKbX26@X(/>QI_]cG; QF2JAh <}#u@/씙}8᭼{TD.X0az?6x2 `6bj>@'Qdwnܝ 0 D b>fc^*KÎ(kPߋOS @ie"`Lt|mbvasUɄՒ}"P;Sr0΄Wkc_&fY 9ZOBO#DPy H`2-E<&T۾Ñ3/i<õ')S;@ xaB[q mi@kJ~lw23lH_t`fJu&{:ǟZrw k xi\ױb!<&8ϡ~`K?F#u VQrENŏ1 f7\?`[݀~fx\kr7&#S& ]@Kߝ]X/fbk}A xC^?0W*K8bQ|uQ,3"qPr*U wY˟kIgFVC#vh~t=<Ǚ!]A 0 'x vMl.n]l-tUĈ(ToՎ:h?w" '9%WYT uq*> n @#f=Ɂ\yU ?&7=կ0Wet)14okU݆pu.d02%Pu\uVა(8k̝ D_NNᚮ%)x_~@L @ۇ4Z:Xi'WxZcʛ2}z^{ ?NmDyFft4c.TקT njc =Vz{GhO #? seXyN<z+7nrkPMZD)b[e_/,P2# o c'v`a}6|B[n!Wb%yɷ x`zD6 3 cv˪P[G92l(ŒaD|#n\^ڕrGw~Fׇ d4|{lW#LBS`bw^ jf@ ?jlHb[M%B @B-U\C*~\+)ӣ` %B&| ~fO t4e `3g:SЁlߍ?6F`9'Ca"F\g!7 p4t[ܕ?ԝ 0 D-GEňвTlBZDNlsuJi7aP4 VyZ3enl-:;";|ᮬ*ggiUQb잸rY捻/̭ǐnJ@UW$0Ћ{\EU@%6/^~?8X8<  717# dׂ@\߭lCzBu&XVt@̚Z7H:e%BV@bw NH9KLTrdʟ1:"bz/6 DM oXg`@ pώF?8{9;L&Pe%\.j-#BZ q@K."e(p~31  K6-ZL eazzEfEy-{9uLŅGa"ޭ0@=0@][ 0 +wg`z}ӯH&:At1z*uS=9˩T񣋌}dR \zP֠*o8a &yF ^z͜foVLU ARo6'|`xf/nzM4s1rڋ)ՅC|/FP^"iwd>tBds0|N\+9#س|lsJG2b;TkM) ՋR@4) up r#V`Y@ۧd CHׯ* BpNyF0, e-m \;bi͢14[p|4zd@̓7".u! U؆R+}bq H,@ 6 ls~[d(l)2@OVV+ )-`HN/ԡml~%v4n|[iå4>W(:(@IO|1c'|dk61 pV5`p"\"'b!աC(" 𤋮T/0e! hfga,18f_ͦ94? ) i5^)CacVo>WI!cYy4za}j mP%oc&m k1g?J #`7f|O7 b MNU`р-)t̝ 0 ;gt0O&i(Jm^ < VKPZS\0g,[@kh?YXM}/P@sһG ~vsx KN{!{&zf uZ5Dz05YieJJy.I#&A&rkJeCY4?"y {OɀCE*':Q ceAIQБ'ﰶ` jV C5̭[ 6* b&ҋ, H/>S C}%tVDZ- pMPH5M W9 RUFL> _hބ5˨-AD|V]|?8!>jx$2T3@\Sf0"i {O6>fM/OCGkceb}%՚a9 N\rpdf`cQrzF~Rc mԺ&.[#^o<#2iB-/!`Mq;]?Krbi>%cǒT$< Y޲ߥUOaATY{Ja3q3@|8hM,̝ 0 C=cKW%~GM'NV%z~dH.8Db-Nm#YFjb0)#x/-I@Di _ɦ(ux-b̘rzͣ-@c&|y}kn4!tܳXx{n*kM4-=Ӎx ڣp]A0_a:'Vq)`/  P`3(7sRTmZ{p_ zo0-cR!@UYN0H8'zΒjX X@pВ@q,(p le@@B: #_sk,0>8(v D^΂GzFl׋> M=m܇5D0>Ǐ~( $3X ;[+" %Xk-1!gˀC6\Kz/D_I̺ z7Gv#)@m`+v@6^k ]G~yt9~ay aS@=d6zw>j" og߭ȕ?2@|;CO۴Q`CXB^\Bv/}8zI]F6H0DhSo&2L E`; _F6Ö^を ``bEDBNl"RVc[^fѪ!s a1lp^b8{9c'ͽ(e9y1o30?܏mh6rVbr]A o%%g艤4HvݕRfoC^+xB`^Wc+~=D Q2-ܮ[h+gEw1){of~^UVAL{):۠WZa- Df>-~?Ce̬'^5eDY'bӰ?1 pӢ@`Ňخ&tU*vl 猪GC(=3z+!5#&Tis  /u3v}XK(/&w0j F W@I 3]A #W8_g7Oťv0HM#cnқUf}Z _[J1@҂9$WTP[8w'yQndFGu?*I t &zN9&[}%<wi͠>73PQ;ؗ_QbٴNv^5?oeW{`I߫x|$+h 2:>a@Ǧ@y=2MR?O @Ff{. Z [;N[叭&vdY=` NuhN@n8"ϧV;ɣki{{*Epq:rC3X']9^̑Bԟ,`~A6@ b琁8M7r!u+ #a³Bui;F@- \)P t5D`v۰@Gכ 6)۰./PP(j rǍNRc[[oyɷ \Eͅȷ1\F]sS x F谍R4de`@>@I G56p#8n6^Cy}z:^qH|y!k)[U.vJ lB @^`VSrl0@Nep2"P1s7XG4Nu@(O\ HwBnC.G#88qv`jduὂV@Bk@w0z V2>e`|^prfp0;F`e"z ڍl[0`>0kn٬<_w`k bpzE^##Ҡ.q ;N V u^ l !B<) B@? FjUBiY^qrl|2 v+6̀l9':| ! vjy |A`r !o-m D>S>t0|vt)Iijm@0!HRbN$׵PV:BNaH)>Z'@v7`+kdp~6;Bc]]/bu'lb`zdºb|_k ]>t9X G `ؼz' +̛2^K rnfÂmO!PcK: ll-$q8kHYK9lVP3{ ˺`Z~m{Xȏ8Ou%?tȋA 5(#ߏ?aP,`ئ5~8sY< ]A މkdqU[pOda0p! n-9.OjV X n^@@ݿ:;DpQM|}YI0."wM;M*0B#OGrѹy/mwt.ԝK 0Cscy)qj -Y+~' y`ҁ`4*: wȠd?zKSy`*s^RPTrʣ*BI??q^v@VeWD_]0YRitBc<&dd=n۲2zg]y8_N2NʫaVĝK0DYx1O]2|S[7@FLּUT>aj{UX]GwD֯+TA{{^c3E 0Q9oգޛF(~:Eo"ٸ`IOvx绯0I3"ֆim޶뱏[-t` L]0)7b> ,z_j9󓦿ΔaܻM۔OqOtuk0˴@'խGP ԝ1 ExY0 i@7!R2f uL@ >XQ) 5X:<;RWR% S4o i~OcVryj2/ Nz9VV&Ove5;WH>4y8W/Kk@` <ܝK0DǫzFgtUC@BYvѰhocցԕ˛_؜%g3.W@R"6v7Uu` d# t9`%Xul OŋYcYa^y`[]A0|D -1a%IKU]f+Տ6o XGaa@Qϯ:&bw( `2@;UٚTt{irU3*r+7@òoox8:Av]0 wl,J̒%>Ha%ֳgW5Bc$BI/Tv@v.jiJ \*I@Wfr nPIz oY4 H@&9(}$}U T #@F0gD ̝ 0 Eé]kt`j@++vBN|_( MK6`4M jM_'TA bG# sAT4z,EpCdyGQk<0hC0h5ie~/&E3ŸoVlW}]oY yz<GE֙](of]P S̑`2UXʠSǡ:$~^Gct#{ яYI[L2N5"x M?-! `m@'`NPjM*$R%7#B~Ͽدd"Qv Q`6EL ~3E+r߰_'@%lje$@ }/1[g, M;tkl& InjS ] 0e\1pPrB)I״ie 4($8wgآdI5_Pi 7_+#:=bϟk{{ >1{w lJ'`uC`v_,ƿ۪3ޞMgl  ƈq6k8B>0] 0 cޒrBGSNA-ZLP4<_ESz) Ğ?FQ;^9P "d.70d#uUudՏ&NKC%z o$wQ^ 1v*[~,[oH3e9pİ?E:y쟑9IexBH dƙ] 0 + LD v|Y/%Np Tv.|`p@ŤV>qN-FI}k4# sR_- MGh16@oo->'#.]WZ II7b'"Ԭ?8? jHc,PG̴5}^?&m2F `-Fgp̝ 0 C3,o8";T\!>kO7k:7ƾhdJV:&#u0N 1ڵ 3] ԑTi2 <-c U_df;  3Ji?L\@v0ѫ zÀJ/ +! 7Lm @r"utB\]A0 _)HHGaLdb&&RjW`1 mO>ۿ,e)JzQlqcq}Ur{K&CoN3Nje#PɀdP,C5 ""|I~'JQkV|Vn WX!L U] @ s錼\Ȳ/VHB8H9z܁>ęOzZ80u*u7 - TفDug?3<863+;0V~Ez5tJS.PAU6?J@6:`b|/?y˓wx-yj9l5𙁭Ab"bBWHb.l@V[[=S`@*t}+fqjbo$ot^ bVSc\e^y ̤lHq2V?2P96=vl';Ab@䅀{ [k!6lQ;Ex 50F̱u5JibU1*Ilc]/ ƺyDxu? X豺ĩ|&Č$bOn B>10>ezBM3Lch9·enX">D0]F_$7]6L.{B?0omkԸYP[G,XK^AŠP#FBE P{,Ց ۴^bƒPҩ~!\#<%FĤS|V/ 2"E.pON-DԱUe61: zqЏ &gE&mKi8೗ӟ@ ( |l:\|5 a PV+(*$U:Fv) "J/I!t6<2j f@Iy 鈉[3lf`|^sr pČ$[;rH,@ #@lu"zGY- cEu'<]A0ßUo=aH-bO&զХvqXMĺ""0^^[a!ٚ7dApDVIg)Zi Lb`* IJ*XxW*5F׳jjg$~ r@ Q-Yp7@@HPs{j nf&ȩ9>L!.B@> Z NbHBWN|n"F;jXDiEkZf20P>k00@*IAd=è轐rjk000C(4gxl 9vbBh0C>ASG쩅2bb`TVj 08*Uu\a/ w lOI2({pу,a&ݮ[P?+/< _xC},lJKDCP{  F}$ĉ-cʠJڽxr*1Gכp (=af.zK0>?wjRj4߭R8fZWgaӟ L&P*Hd##ELZ~ FaX+w; /lF/ Ek\*ae4va]1@@ J5JӫŘ1k c45r7 K6`);_&gqQB55Y7J|ύv?e)IIF?vUSٰ*Kjo\ b#;nᎉ w h <xُ o%G_n*<17+kÈh׵Sk3az8"#|jD0y>*[] 0 3/tC@LDx lSs~#JФcw%/Gcpg B~*j\}E̍Ĩ-An}IephjVcrS*%:$sg-߻V.wEJKҤ~N?=%uWRPP}|k]iΨYJW/pPsft ?]0 1#P[%*S"-=|TNE`9 2VP@.Q5}PEwbk$TMF@_uzfvDM@.>0ճp.&u Rl:0m0t@D|A1f"ƞS/cqH#~"qƢ;N'~@viuv<& 0DjMDVLV_{b[xgOXæT n {bhًE@(1Z I@j _['lI" Z^3I4&bVDF\).h+VY33ynl@ /}Ze?b:Y&/8Kq,ɥlfR%$]/nܝ0C%Nդ^J0:`&*N!F}S֯wx?o0%=p% @ i]UB_M+DDf7t0xLW<7E;3Ǥdƿ'@>|z:c<{V=jݮdЃ+Qpңv}V뿪n? ]A 0 _~OT!Ls!閦Ӻ̛ 8XeO,vvUrdBG3bq!+rO .vא•. Bf ݅>UY_IE) h[k~ a %! 2?@WhaԮblx?5(N\>L ].y|ۨ@6; 3VAlYlh@006:p g䌄o, W){/{* fFz zo#`[^B@/TnwȧZpM uP3pv ! s6@ibA/qCC<}ye_ NpmDG0MCcS #>ŀ|Dq500 *[ʠa9lXE``@p\% ǐ+}Bzau۴vې5 5}`c<>uQ!og%yb|/?>ċk# p]Kվ0@WPykl:\HYoQ o1G3MG Č b]K, W.km#L|7j :F=`=r ׽e;zhSFm8GyQ@t\J!fF'# }$]0 -k #0!/]ESxƒ|g}EnI </IWU3Z_}Q3[ė猟ZzyXWA>H~j,-{AJ;{ pR{̘8iox۱F4P/0CA$@>ZJ#& MK@%>`]KPƕ&2fb\FdZ$bb(yJMkV)37ghh?2vZUW ^XٞU }#NT {G` k ޻~ l 1"'//rW⬾?=%|e* wm= hB5fF<~l*g0ԝ 0 C= p`8YJM>MA!"V_)1D nIs `=x4:D_l?k>\Y [Ϣ2f ߝKTx-pEkX";Ο?卻e<.BB<&0 c :ꓩxTeJy^Gbs ظ!G7`2Q-8pN\ \q %@ Ƿv41=:@5 g` |u1 kK@5(9Rd@̺[I!vл@tFRVD!Z#y\.FpH ,Ŷd@?NE:Y?]91sC5/#JxڒP䘙$_eH˞J )r>nw!ky'g<#c xR} j^`/,*{'v :Re`(ΖXcr*)fz*{ Kœ0Q3;oA&"geQ28)0߹*%IDF̚*,WgfVrc1kr,%=:QT}p*Uϓ~V]A0k| ]=zĨ PU8`yeRÇFZhbQZ06Nz2B## yO#P(RM"w~YW3;'3;3/pz4(qyW`$=6ίɮe' HO -7֯A >Fi{7W I>5Ps]A0 _ CB93tc+(T(rs}^יMku"( .̌.w$@}cN R I@.rM;u9* 8M$۝tz#jĻ1&O_-.LvvO]A0üFg4 e1@0n!0l K\- qGǕm 9@oWVFg@=~` -A8z2LW}^:_lWnrpeJB SSᒻ lS!F/SV@szGJ* t=: v6-vEaʗ[N{~(:tWmbAoa;&p/IMy-s>Lvae2@VaGpGOF000Pp!:@nP`[$G^+̀} Gu5r^`gobg`zl׵8r 1?:ye>@ba V#W1.BGѢ'P$R: \S )UOa"u¤ @P ͆Pg```0 C6,MЙX^cN} ,1 k<}(߭Â7*˝3&?O\@B rleiL{7#E㆖ }eWh;T7D]n:Oݒ֞unY; q8aˀq l`<r# ĝQ0 BIC&Zc2xmDRNabdؔwϹ(\IA'g.LG AK?ϩv ) (`԰vbi#aa;jv_z v}.4YWf+_{P!?*6x Xt0L +:O6}o][0a3aB 6i 02_h^=I B1?gζ;^$hxM$/d~OMVYM8geC& o40 ]5-*LܣL }V1*'u+OK52!nZ=XID ]A0 TCV&AmL ] +!p"n8x*5Ci*X9^sDZ*T{;|Oډǀ% vl~J΀WY1Sٳ3*)KxVj'n@;H`'#Z2%]A0 Pdb<X ^n2Zpd]C̓y|Fd/;L4'C VpAfiVL!:}n?qEʗ~Dz.>XF bUya"C5Z b\WR10X}06jiwSj x]}.SaibO/#em\EKLNl#V[;d8/<n+wo{lßc 1hϏ 2O,&Kkj-Ќly= %y3`=%l7b;l}V+tyR8ķ-ynu,im ] c=.%(fϗB da)e6( v^s,[9t;Y{{yEU%za^W3':O|ղ'ynehL*lrODClCjȟZzٷO FXi3x!V Bq|O?U2f` '؏%'f)#,ķ=LB!' Pb|/?kx"~w _m@^J΍vWAz :WWCk=`r)>V+]0ihrF S{1!zwЪW ȭ/B޺;8v\;)a[- v?z压p@vw ]0 ہX*y'P˷* D= $R,-U9K'~ }$ת5&uNt/chFhP#/%u=( fGnMhqx?@yv|mpw~_}&;] Qк"5%T-T2ˀ7] s9WkirPBچr>$g}]"*$rO"<[ !j) <֬50/$ b',kmr4 `Bs)xxk<$D|X*MD ļ-d6G-*]&ba`@D C\jo{{^~bm$- h+qbk-pD',Rm00`?v 튀\0 >-{؎EȽWY>/W/ 0>e8'<^WҐxm  v8ö No5Ld`e"b0fo̐:hb]A0Ϳ>O̊LU&[2)k;}Y 8. < *LƢSTxt%C036Q5")b%A+ F ?c\M0K˼kԝlE6;;gYL,cNU@LuR5 sͽaFg^ ƮdNb%?lgzC氙jZd72>4MalSԜ@v/1(K+ߢA\ R>ZJȈ~rJH-vD|W"WB 8ۑ[tSr@n` +d8)Бb^Ǖ}R#/r |ǷԕMV B9߼49_\؎u09ĴH+-V@b9sl~ tS >=Pc.@!*9Z0{J!z'BW"BqCjjZ4 m WkH\ I9FBnG|c'{ p_ V0 wd-uR cqG?] 0 3p(+?%FqZƀui[SN[q@. -zp42B4<%@Q0S3FK?3KHd-A7ԁ?}P[9Le_3{<´lU+K[ s*HܰO3}DՈ'܉(.AZGb1|~\$"/< ۴qoT6-vx7֝`; pr;\dLkm>~8]/ 6[tv[nN`P‡0[M"]X@mA-+ Gכp<A+rvAV?onu h]WOqϟPzF_b Ƕ_V`@ x%8pbG7Ij\n>l}rD-0Ћgba`~0VlI-d`@a<|  J|50ŁEz(2:O pyr PO=uL ~䳹GC` >|=}l YLF ϒ˜R0X+} tx } p'z{1 `q LQZ~fCwZ1/ЅqQu'?NHZa`FKoXq >@I>"u: CP7#Wgj^7RbAx c([-exGAZ'"׉R3apV_Ѐ9̀ǭ Wd_01*30lja8W o2T`878bB+ևb*~f`tOGVX? C"It~>Q _1JϷc;:^!@:dvIP T bG*llS0qBiR\X_ ՑZy{& 8d`pudhܤ@TC#q4`ߡ] 0ċUP W x4a_)XYϱܯWt3};GR2<ݩ* zy^ܦ8޽|ٶ8nMahb_03aWZ 0=_?+x'STE(2ufQ[WCe1Y^蹠zP9 mڝOW? `Sx3 95f2C!t!=Yb] @}!͛e`%: A޴`vw.3fgN@B2Le# '+8I̴TY~I%]QO؂0"M|.Ko2ڗ)䈕!IR69+JuKw5t%b5;JjKGSٿh#c v=qRR[D)a9r?})Ҷ|@>;照?ϸm/OCh|/V>g&:>z88W 3fbFSb&()1sG>L%4;),=Ж!l; rŏk lXxa0֝UƺK63؜P##_p [ O쏗?a\{G &K?3BLTv۝Xb1@h[`[ѷht`;?`&F*@:Hl0mI\|ۆ4 0?aVd^ٓRO'VW6=t@ +зcܑIX 9z]Rac@aJS\flK" zp="o FRCw-ԝ;@ Cr5=!"t"D!R#>q^l ¬*YV$)ǽ|%jչu?q=Ԩ^xV@REw$gRC_7),ǚ^9yVz^8@ wg"on ̒i~::1o˘>^C=0bũ NL U .1Npd^U6uc./J:sRe^[|ݎK]=Sg2hG(8Ly"G:ov@b8k*HRG&^!Ik_o6I\3~T5k1T($+&4ByO;eXDkwxt'Nvm]0 ө0dWXb ^uVmGn:Gܘ\`F\~@#mo^2l *{lJZ.S pG"#FD* zb,xv ?ϞI|S:{p~,<,ܷ&Em+f1n]Qo;4ErE<%:(*=M?<]A0 ag2_HiS$sTߡm,'"?Tw#0 @^hǢ@2jͩTa8Y" `oce[B# z2@J=T*f {q5IWcET1:"~$Jw0G)[ICO焀Ui(IfvKzPSWщ6w" X՘]-ޥx ʀ$cQ2+M`mpNݬ #RPձKQEs5GIO)UYJePl~ƎV+}WQ?ƪ+%B7Nߣ? ?;bTT7׾^q@uMwCvVEfܜ:}#"n] 0 8 :8_y_Ubi%&Qw >Uћsg -0[-Cpq6cFLTIx䠅B2J$%jxfShGxwUŗeQ#. YUخ'7qS+u?eW?,1PXWRDcauς\f=A3Zf:Eû ~x:F"OF$.χ[vUڥ>Sf-J}y1x(&˳ p=q3KB( s<^V(HOPgK!^ˀ  (xj}nN X2ruJϸn @@VϜqre3o`^m #ZhJ|#Y M 1 3x^sREp1 >^&[Ii*z~&ʔ9uaV0RΠ8]S[q2hz9Фt1@N+ۼrPjlK5=8"P|uɟkeFQ`+`)̮}"WЧt nFìҟV7y$R._&,6m}:^ Nǡԝ B1Cc!z`.j`*CT-/$PtyYF|Hs@'rKnTPS*\XJř4]u^ Qau'nU#ba W:M]kgxm~GJwwJ^nUWm8I@~|?qu6{$- jᇒ _?;&q13Pkf.[=~a>]90 Џu I Ȥ`@؃m l|ԢZwTkcEjQ\M1J\UW40q)OuQe5DG^9Uq]e2vzI;SU2h 1+Y+ˊ)73xl:T? ft}<,hhذL{?bߞ@AtAauq&Dn+,~]]A0 x(=`'NA&#ZI^p42U;o|ccٸZ \.dSJɚO]@\󘯘"Yέ5 K M:IX:Jo-j}g+q3(w;jCb y'ujCF&<*]N+ zk [f{;9e:NkX ] 0}n ܂ E7q,;;Vq%&u$%)Ir/x5s>vsrn#i:i}ZydEEН;' veC7'Hc4w2kT(}ǰqʁNNjA!պI-*HH/Z°)?7)DHK ST,?]pYINڏ'/O X,Lf1룁d(OO ?;{UAΕy5S`Rc?ТiqmTa2c\#:̢vCbcm,lMҤ?̝@Cߧuҭ)*SN9) ` n[0PͮD;qL*̃09X%&6%N:YeX_^Uk`qؕf:'Z?O $';$ '_ m#+rI-ȓ!%=_*iѲMw^ICߌ^o8mP=e]90 T:> /SZ,O1`l֫t ٫Sj tX#?;adub'|5 -Qho;sQF"*olc`@|_p\!0000܊cf~[ps_<2 ||RvTC̖-XpT]@?@.e`+ FB'aŀ^x#9 Z?6v^Io\ LaHlBl#;ĜO @VP[܏\#v,ԩlWz!mZ gPϰ5Zt20 PabF#W;#46*Y 4B؉0ss^|oX ]D"[OF1?.P14uwc-um|C?axdl F@u2 KnQu@9&6PR(X:20Ʈ"6̍_|D͜ 3 allq^FaTd`@:$VA@÷p h[;ZL\k-"JF?*p]E. PZ F `aiئ}b\m%f9]alBMbPc? w={9R~|ǽ===t'v.-Rv.1z 3000]0胮uPJ>#0~0IۻZKJU,~UugFeAE$ mSQV?rp Tѫ, OʈDQ5zU }xmϿc#wjeWUUT"֙6 `Cl yە}}C-*G>܎YZ.yuw;5IzCxv#o+"B_c.]@ 3-E@T@TՄ6F#9fa+앙ז1<0b2U0TسWFV-gKy.f!o >9bˢXfvO~W㧥=s**Kni"7b|ݣ|+0ȨH];v<1`LT^9M\&^mS`\ j}FTJc;/] ;0D0 p $NDI 7HOE5bp:Sw8̽q V}=>Fר\ۯ;pgoԯ.0&E1e} _Pz\ ;(i@]$[ٖu>foov'X~9m'S ۮBz*ʲ`Mn07/W=ڶ^18UXAY5,'Sǰڿazgeq.$/ZjUVNIKK/js8d!ϕ ~ڡNc'|~yzeы|-z՘I߻/ t6/󚣡CyVFH[B:VNfXbwL@jXE=| /z_x2l O']90܂' Q O!:%< 5!4P &î/!$${l5 JZX>aw{e1NƓYvgo`X_ % 8A>i8h ?Y:YZc(Duf :&wI魇g}!TӍ`ZuYIуdؾfՍuШ^%ʣmAHǾ߻dqwGYT+h5 -Q]qHCZZhDJK2gN,ͯ`S?6eNxjWB8µ S 'xб&lR✒Jyl>^+>] P s؈5X]؀A؁==NRU_qb) ( ƿr-$@N!ť*s h Ltè<[)Cs%< ֡ÐlnmDV6I͸t6):\-8=}ܧMS蠬qMyf]JP"dS[Y\#];%Bbߢ EZ;)8! QJ:pV)ܟswKElwm@# K,DH!Uh󁉕%!.8~NxZ+~~m.IYʲ7ٻy]o4?+g~llUn rt|Ɠ҇;ˮUt~P3:礪3uC}9`=Q`xcR. 4?Q#YbibM~Ɠ9J.:HkĎ5|QJSR?KjX>NLփm஝#i%H;KYۜ38G)EPqj?_GoX8qn fF2o|j'R>᲋^i$K^ hIE f֦Բ*[KP fJ4H-?&W_swKԏ`8]?"ٟGXOɒJל(iӻ! %=;FJ~@.9NKVyjo$/Y.=|1z^k_^r3icoQ~4㓢6@Wv=/ҹpVE]'?dOb;V'K+m>F]n0}bf1d ?`Oe7]Sِ]ygm`@8{<` $|'`"|sHS[7'az6pv]ka^AL}4`@` |6kn͛XzV:bPd"g9vvv\Z%е1C]2(0a}竁- ?[0*IŶvIn媙 旐JcMwO]奖w?osv1$ҍ,}}}(m`abc ]96!rmmbD2k _,:uB^wzk?$\'h |;-_3?/20F} H'HjdBNpQ~G 6ADe3>=t+4{nk F9|s25p` ݯQ~[ð2'RN 0~wT[r*lZfKgGh+}= 'Y;#P̀y=);H1?= nL}[>)8&/tbE,O; "]%z) ! PA gwt濅 vVioP?@$_s&)3 6ԏ]o29F́3000``@/0@1~FJF.HC C `a jxv! Z]ewܣe>w]C. Wŏq-B?b%e%Ta>fŀ( 20 j9%ױ7ua#40ȑ6b+@FU J ߹ȧnEtGLNG@p7 aH!hA_ vEjzx*<_z0D ׎Bk_|52 6-vZ"ruBlɌP03L>0xAwD\p8Ջp%V3h5$@z]!@SE H <P| < QݛBM.mnvfg['+ J9 `u uf5ĵYf$ˢd5mVy8 H)Nb}svG d XX)+5D B%>KW i5N{zzםNrq Cn^'Vb'pDz4?ye3QV2.xA;?baiBo)͍zs @42G_mٚd4s-0e؂SuTO ZLCaK\y;_ }3^p)˞]@q>=>\ ><|I]A:LB`&$ݙNߛ(: B@ϖzK:tzM ӿJ3ˠ3й8 @c,25bdzGK9K%w׉<UvE͢d?kO'fdnQ1$qU=R)C w&Y 56&fWw.9?<#IR廢)5,tInN ODW_eS/| Kܤ̻t3A >. @"pFG4PDZqW~9(Sr`CL`>^TAsv|[àrc?r- -OT~/C+S#[{yVghܤ5^! nx l|lƨa9>Lp` SM20>O Xo}wel6r*;*,`= B0씍aX~f/g6 sY(Б`j 濅(l^%/pMY`O!`Ţo1$ mEG?m=dtwO]9,Gޒ2#GmE)0_}~>C8G|2trـ\n]F`_}$@_Wŏ|EC@ĝ1N@EƩC )rDO| z}RqP!EȂ $J7TΎwi%kƳw@àw w.o4}ڴ ƬXf/?f\EǛoĖ_: 0myѪ^ԽrU3>Dj`CT(w잔0rmÇD~>'-ԁ_x8ײ @daYb sQREi>\c90 qz3##,Z5͌ .+E0"%ևv>!H]~a^x,OǢd qCV-'4}5GBv^ˇk vO9-}* n©b\f2FHω~zwR|]W ]s۶p&(/]jQ\Rbm'Y)BZh]/4WX3,`!7]<{>}{;V.=VE1P U* e $@ý}3s?'zot}=ڤt>&=w[;A??~F%JV5V)ٮh]T,a<g}o@ 9qN +lX^s^/9@*` 'suOGa5Z -1Kg?Tpc=%zQb՛~ 3t;!9Yi5N#\L6O7H0t{{rlz;j'_$PTC% W=&[9e˩U=v]+BA BPH ށp΀ a 7ZA.A ! حJLPzͤg_]MLMi^%dD _}ȎhG82EjTbW/L'AmKDg[x5ג躔{3&nE$_s2up| H7x=vܟl?J_&bBl{9t>9hc?_6!>7l?Zhs2?hDU׋YӪ}Sܦb\ Ci>XK:O?Ql,ZeRkeyKDy 4fD_>O]JA"DN0`#X#A|kmBHXX۝n9,2Ul.{;la]#EYJ bw QRgĺM?-%EŸf*Smݨz{0 'e=ԇ&MwѪv>n1>=$EQ%4+-x~ C&z7X)U\KXW^uBkbjT~FhҢꪖCܥJW|8塌FyWS3{"'Z(a{* % ^+Y5 PsKDeWdqwABјmQ8wA]1 1 W/6N+}/v XM'9-Dܘ\6|oҿwVӤ2[чІ!:㲹(B޹ hR!(GC=29 @Y_1)jNMaqt;M+'A6tB!.IuA:nyVUM'N|t/5xP $3E1m?Rt"R`Gc@+Рb"j'ڮR!AWeтvP)xd*) }47H5E` 'ԝ @ MDf`zf` )%4Ԉ>dBHēloOPa8Ty-"X 3߭;hԏ^\f*@t""s}"2jYVUpeTay.i@`>܅?ick`teϑ>_t|-+5³ !#]j'ETb\ËA4e}hqZgSn֏&ѿ4 S1zT`HM8<:( ^ ^Gyc/MJw5QۺW­k4^Ŀܝ=0 -!6E/a&܀NؘXXK^$4D}&?kG]ܼ4fq\T(ScR*N=Dʱ9::LyQ!&Qm{9i0ofy=Lb-(L˪kf:2ܴujq x"w75$+? ]d\|YHj~)} L4̴׵{|=G,K">pLPd/y}U|Ǥ?|at2- hcx*$0~73{̝ @DBbbBBJpdBH@Bx8 /ko%\`bi>&Ƣ])J͐;Z*d|8$B+'%TIOګRU?@zr.-^5,-}u|kӍTӹzҊ}*2o1 -sG"ޅ_OJBsZYf{[(Z]u{' IQ{XRRjʦ֠붱Ňw{!o`(=ST퇈535I@v/P#gx6@҅-<9 Yk0%+];N@Q IemRqd 8Mn@"ZjH,(X(R =b E^~^9y f f|h-EA#6nZpPiT 3fX0nCdv6Hpt/ %&)DY:Ex%/SIzf+~$Eݺ#J8b*u2Qq9CQhr0CT9~|!KlRǸڎmOq E=\N*QU>]d@E|hd-pFgDeG\6α䛅s, g>Tua\M v(%qY-[QgL|zLK>7}=1Pu^Ka(Ň-+L)3;rou=T~Mm/_6~Q]K4 7In.AgY(&ePjws"?}d)rOY~]_^&y/,Bljt )]_R_oJg:0S'3x4[h.vI #sM@h8b+oCf^1mp̝ @ D}FH)&դzupAp&쬂@fc׻@J.H[׭rb>7N޷^nH'e;Ưq\I8؉oVֲssG3eܲ)f"w5ш8ݷGn odF鲉b39YiiX93sE=ym9CBQPG;ۮ준M̂%`B+ҧ2s[@so]ŏ(_g< yܴq,H<[ J+,[5eoGviM5ц߅a8GحQFXZHb&w[e,g[ p dr66ġk|a=l17"rBD^=S"}% jذVcTq\iᎠ}-v(22iMf]:[9apH)<-/l{cg8}s̃s,ElufQ%4wAY_9o]N0ꖁ ,L0\W1GP oQuSa:@/9;"U^\ﻻ<1A9~nprg]´hq h XN2&/EoxjVM×p,/ l-M1yӄD\UKi/M],mm] 49R1*zcnN=P[Wq#"y/Q֍#!u|(p)i**T~gNWX%)j凴+O),]؂󌆼}O#(3V+?.sgo6򔞤[G M>ָB=/a@ Wk•cKxvO:%̝1AA'%muN!F"D{w̬ 1 !޲kw|osJ[2Vw"C+Dv|ҼdT3sQh竇ERĘ*1jf "G~5lZ^* ~?Р-UI~/3&et̀ҕk3v5ˁ8p›({_~Bc ,!|Ĺq7 baN/5_7ܲ4M @r]קGw>ڢ?LTL?E< _@jH@H""y-#<^A@އ iJ~fx qZUPy)]StqtX. u޹ɒ#)tVֻ򽔍s[85aϿR#KBE]LZdT_S+:tO TAO\ @'K E"(?: dhZ}~Y߁.<̝10 EX{ *.XP'A8`]ාvAq$kal Q??'Ϭ4Q֕)b4b P=@E:ōhD}_2zK;<( н!/ ]^$I/air Feg{_n;6 L3?~v8}uI7=sVnN6tqO#ޓ3;UfȓIpQ%*Sntqb|P}̖=p<2AU@ۡ1GcK"S3Tu|Ydn%H,K'B0 C⌃SԝN0PtDjVBb9yU 1{c(`HqH#pSIzNwF _I0x;_Lu:DU@zv4{~JhXT?:L:d,RP쮀˘ Z?2a(5$Č7_g gч 'Wm@+ gCLv~ܬW ?_ sm%? g `X0#bo(y >Y vi}$KL6+Jg6àΈW/7539#!$h޷upW ilcTV ~xYG1Q>Yʿcohck{2ĄiYKZ\N` Sy:D{PYRthhd]b ]=KA}6Zk iًb`gm߰.o@Dfߎ4̼wDoojF浦"}# ]%R27uj^X]_A h-Z?|Hi WM۩m@Á"ڪ >&*)t`Wc9+Iéj%z!(m9~h^c*\ZBz/̝Q@FoPhJ(ʔ 2gę՞onu-Bf/nM亥FZO? *%j?*fi3_tLo\X9"ʀ@qo.]3t,;(c2En|'onN-bϯC8VϡSR,꼔) ±+=H3ܗ ȗ'rM=lυu_;'yO|ah ں\{1*k|b!A1:ӯ RO]3h4f8ZSoF]N0}Bbc $Vvb 1 ;?AԍHl͈PUl'-ֱ/sq߽{gml[BhMt cf3 #/'F8BreU/K~4$> #* Y]Vږ&ALsM4u؎zK䴆U/5?Mȏ e쏜5$|Ѫ 04Ļk4ҹTQTKRҹ.^XDT}KdI+4s,V?6R]wMp=_yM];pOfZj HȘ'c ^r,`d$jZ03`lͬM Ml4#A8n$;DB]}w$ X|UH1).@]~̝= @ƛx `gcgA 뼻&ߵHrҸ}ԝ1n@EwHE2U(h#\]w")%\ L l{v׻3fobD.{ 6*.O4dQ}wbS&0M9ME;]א.a}xQ2.AFBrͬx}Duwݙk-V{riפ\(~I}=pj>޽$׶Ȇ U0of&8s$W/u-ffӏd%[U۪SJuzVeo\}0 rLтKW/?_5++.+Q!"2}?o̝AJAE AD"d]@ĵp)O xW Byq%.AB~Ϡ 2COUU# T?09~Hwvqc\~6b=itn@9%cc-UUu~whsd:c̩흾4l5}E_P` 1לl-:\icƛTz O5{zZ4U(;fצX=N5舅HL$C0{h/s @.8ǺpUK׹u!hQ)'+6r̝ @E'=؃X`9`IaBnAP<~> !İ3 W/}ٳPxMs /uP5yHԾ߫tdTZ@=q4#~Z* 2xr6hKI%Ezy?quk֕A5Yс!= y@gp+e:-9>hXuxEQǚ' '-뮎;2Dٻo.)Ar6W2Mi.3_"t ǧ<9ƊJ{w=H}. At q_[h)J':Z1 p,R ԝ @ c $*`bV%"!z A CbuЋhWK#wʿ{߼J=HA.4YښnIeSjG86'a-7R/ziRr@~(Cm`v^nTA=xsP\1JȆY<׮_VL%&Fk؝^ѧEmQ  FuY>G!燇h-3v53B*C5 õzZJy:3e|[m `#2Ѕe@:1H!/Q( }8#y覘p@YzR] 0|APSREb faJ Z`0E |M xR~~;OC6˂Fcv7][ ow&R *@J9-^ܟ4{nj]lE+yWcwA@1:|\A,d m]B{ q=%ʆLX7mUY;L> 'E 0r$g0r޽^gh½`Ka,CY;] ζGĊ9=n͟1(\`Y?ƣ\a 5rѭq3݈s(ƁVNŒH~'̝1 @D!` kx=C"^V<Bꭓ'F?3?V>kuM_7#'P`kQ79Ј>/m> R۔TUdJ#XgJM"Z$%E2T$8RzJR_PesAůʨN|xSy_%[U=+ .EZ/K㾕Z"kw͊9@ <:}Ei}Rkŵ5Ga=rw:J ͱ={%>484TZ N>dz>}k@yEInc; ]JA@!,Bz뻀O >WLGni൸1[R̔2'&z~b 셧d}se S,_1*޿r[jXjKb1R1aizlc-UzG|cl2kH߂r6`Ev+;vQX/C$GZ?̯:@~ u98`~AY9"κ_w*!^'+>C ѬTt4'|]-OA}K . *xTq$~ T? ũӕE4! A콝cOzmc/;;ofgmh Q P^]ZC@oUPz40NqzkF))H5ZHd?2¶E517\|7?*՟ ^>;$unqG=>$V{fo)rݟF] 1N`t 0402PF?AIBzh[J饋NlGn;4~FS/$ A]&!J"'Z x Z5 R,rNeǪ֯= w8,@M'Bg9` qھ^jKkw_5zrXVTJZBA7̝1@-j~GR^FWhTs=BV$vxmlW cwҟ}K aTX`Oq\"%Kr{˸VK"=܄:pw*֥Y$S 0-:N:rʤj$H }9BD΂͡~ԼJhIR#e&ϟdDD@[BtZCb qٻ,{os2֯Cb~~[}MJ|m?Y4嗲γ̷[?3boX8 ƈ+fGjCٶQB3 UϟC\1e64'vy]:mwKMxU:)I@žj-<gNM?pn Vfn0"vY=Wܗ }&=ucf%jH%ِKEm=l8$ hܜM7`.uB>(mױO% ߏtegԝ 0E-Z@X=hق)@,P؉;x21=s?%2?ΙTud~o ު'מ(YH8FhbOL$~؄bjgepb5e{$#vuY̝B=;a2!9Kp\nzCվ&q~8@VͭKgxg<,WOi.#u3Fx/U TQn| ';!nDy팾w?'J>i]}-#EGlb*zlr=k?#Fp ck{8P+~1l'l61ZO `s+B &<7U/6 QаFM e/ E769ClX/O8Bf00 5>#e0zI#OwS(wC +X8r Roj0lg@MG gsF7AGNXڅ-Dc`87&&~lG x"pl᏾:@N0}5XZ wc30F݀|Glez93[Qn Au4̝0 Do%2,YRC.់GT0c,tNER*ZF8X#QFt&Tc!%Z2`{33 8$kmXǭ["R0/Ӭ{ YdGzlxB4FǺpSw#Lˤ2?_ԫ0adϩ.DzU k˥`zۘS ׷ קDqrs`'6> n|YVGr㖊?9Lx Q7J2YI&Ĺ7ᔑ'c G2eWDH,|z_̝ @D/A4B`Q "rɏ@l-w~fw&Ly&H}kQ2{v:X(dJgFD&aqTo RbSY?!O*[RIv4& yodR!@MZ*#P!H ]h$8n<4,ݽX,].}!Du%K^ g@ƅՐk$l;vBUH+ci6|N r?Y=sm&4aroNa,hKwKԓ_st:}%*{ZgI3^(q<3NߘOoPcgOᇄZMSMP5(.52!핯PGK߳;^hœsWBEC:{3[*@<_ [ΞubwA:J_\ȅ$de W»VsDø&W? z Spҋnȕ*\jV -OޡE.taÏȫiAVN$ttɰ:$Ú 51l6Ɇȣ P'ZbbyA K^*9>WCMhF0e шסS7-d.,SfE7y6=a FJXA" yv9 >0rHŶ8Lqg:0sIrZFG?P#f?zcy |!R ;Ɏ|Äзjdh6,H9G瘠l;v̝=0 =0 K'6&X w̝P}ri~ }jHs_czm"e)S CWd<3U7m='٫(u3VݔoM3kC 1.jK]y&wZ?NQKiԴ͢+*}]uP6E/мhf߇e㹬iٓ֩tύo2Nj?a<^VS!uԹ2Ą9_6EҦl:g>^Q ڥs \ڱI  D?*xzUG1SDd.)?ԝ 0-Q?Dtec؎eٹoim$8_Ӫںl]@UnO7t8V?&s5<˻ !w \q1^Hڔ} 7mm,3Q~'uwmƻȲwG)YeKҚWKqYq\8H{^_;1!6&5@,d l*_r|ʕ;\( גtd&ugxYzJN?陁O,vӖ҃W*3J ԝ1P C#8\׃p=W\4BB8w]/YաK\PprW w;mDbk՚Y9/P ;bK@Sk:? Waɑ?ݬ&#r0A`gBƐv }'٩@u6os.AOǏŃ~,e_".51(P̃8?Uߡs ﺿW6 /hXx?\eѡ@2r;V-FO;#'(^ԝ1AA s P93Q*@k% J_HF! xyvƟɿVX Z-ҘWշϷ,taj,c #;_2?G@lP3,m4\=ьjϛ~̴4݁c ,XV"Z9I.C vw 2BV,~;tAz$_3֣|&@Q{Ug_ʉ(xL%n]%0}祵2߸1'^if%; \}&=rh֋ygx ܣ5%+]10 +/ X;101ә' tq&LxI֎g'ZQO=g[G£o_)[ʣN 7TB(a6|KwGg"!b"zt~r=(43?OGcqşcVl=A4k_yLOp:9X壺K-j 2(b/WK?_pʯo(d3#%վL"/"]+@ ,,'@b-8ux8҄Ay:}@ #Kݝ7MH tk aB5!IS|'N߷[*uB{E!;֊&kEZOFlLkA(r>R"4不6tޗ(-3k 4 ]#ML+GPxRغɊV")6{m} b$Ȱqd?7җPqHxfUdoxG262;;x_XQ2z,m5Hʱ7i'ԝ P D]R 쒆%v@@T(ps#JĠ׀ӻ:'ߪW).ˢd uhvhoU<% l0_Fϕ@׌{5pIK콷A>-wc̨g|{0ulyaI.^!E{BXaTR-5drJ+<-R q;[?%޾(ݓJ*~' VZ4߭p\3`v֯Ӗ /֬HM;:[!vrUV^{˘'vii3}:^+5j -kƱ|}%4Jb㷋7}U?ykR+߰0v\B4Pܾ"Ly=vM.BȮ*e:k"zUku2$$+Vx{ZX^} #*II-'TIMj𵌛0iN DZ/@x{m"10bB3/;aV2+ M^qGֺρLdl穂T0DGm|~)6ՒuxPv}JS,y4oxz?L=s.M1;@gq'kFd PSsl3I3y N^ṱx{|&$El]1@_XP K_Ll(Lx~@kmkbÝ j4.lo `8fI7i_?$`~|_k$J9]bfֵnG?Zt6,PAɄZ:2qawq 瞽!hݾl,r2L>ճ]A2qݯ1+FXO.uy!sfuhL/wrd(q:.!9P?RҘ;W1cwI'ݸJ ]+@}AjPMz"*#G$`b;~j&]73oj!] ϩ3 a:&]&=οJT${PL *Hrʸ^,z7>r.Z1u1(JixXt8‹-lL#g` - B"욅3/r,}=/꒐vc vf&4\3vy.n5 =/` u ɔ#CAкkci=yҝ 8xR= 35sߊD yd }Ύ[567`14:6 Gy/cB7^$]1@\ cCak-V  :;+* -T#rN%hv>9D> yyH߮EЕc G xvWD\IJlA!zp;6L-!Uo]r@=U`NmTPC` aZ"ӊݳ{f)p\ M69p\ 2spnM)7C̃Dӥco?w߶n<#-/|vD1 8&֨W[~2}Jky*$ I̲ APY+g$0%]RFwv.PfC,}U\0Y~6ݕX4\x4}a=֓u q2'UynLS;V^Z]=,@9r-4Ŵuu^7E@[ŗS*Qֱ RϿ)3RݦA?]1N@+HyE:Z $ " <&u(F6ˢ0s[l+5]O7J!)V>;|߃hD0m\x[}b2Ϟn]ף1 HFj\?ϣEvػ(5^75\!DE`{ޣu~.qg\; X%bZ8Ea5;79O¢tjEXr[+Y#PVqx!y[h$v'Hytw;ڮ F8vYd7Sgۻw沎G፹bԝ?N0J 9CЅbu*ܠ[&DwGSB[TK$*$ޚDvQ)۱wSس!CUt;/? 4K|S"tg0W@s #][J%ցV-H UکJf@BWmM8A !> rA 2rJy2:<uλ5?kx]y{nwk:>oU]$\&?{B?3=ܝ(:iy25̦Ln)sr蹣,ao_n:mv!==_ba` >Qc/L \"'`ro#r&bC`[k]-yE\C  !!㒃-xkT8,eYI ~a"CvD%m},\` j0|Av _穽d!bXeU*e Ff|^ 赡 lӚ׃>5o d)#🡙,UHcFv1߽kE2m*Li |Msaw9 1>e\`͐s@fc[ e?273LB03F sz@&f[.z^Y6=L&j x~\ v];0{cp NJ% sѕ 1僐Ti$3i;\qb?Y:Q𾷵_!ZDɿ#)o{::9̞Wp@rf֩+:XG C`^1!˜eڎϮo?Z4ޗ `0sWov5ЄC_VEM޼LW|=4g4egB<7:ᎈY|5Bgsv}0z@3]@k?,,]U>>AT@l"d25!Y޼yf_f6.HuAM; 7wȕY7fz"Ky xp?:mW@~,yQGŊd@5>3Ze`yQY]j@w~\}~meNqB B(ڿE[SXᎶϑ&lZAXha]u|Np?)$XOn1x(sп#u?dv"6!ϰZտd^xKoo[b5V^88O4C9i?ܝ @ =-5۰0 fH}ы*,!EGdl߻'CMo]눀Z~C)ġ*VsF. n*ڷS?OM9 Z T6`hVK^^z\鑢X(b9>z?{qP_!z*q=1ǘ!J9JUSU/z᳈iͲ 2ԝ @ TP2 0M`"쑖"|c&R(ЫԹ ZTVE!qyݝ +{0jF=jdLY"ݸ/zq[_Ɏ9o" A{qzkzD8zW ENag(VG I A /!v`^+S<0r1Z 1GeC=r߫_42D*xOS_oɑ%(N6N)Wձ>Јi#I= ԩ'Iz]; @}*;؈ Xz ; XHZZoMBp!d8:;q O;|^ob@)XKvF[ |D{X$k~1U_ˀϾoqg_,sRL+tT#Y2heOs~[d`dNX#{iO̝0 Ew `23Pgzc(P;;(3o`2s7 ^j8_L_f jǷ\VCP2vO/it[t965x`GmNP;یJV\\9o] 0= a`' @ ̀ Ц*g=]$9ɾؗ{)0P7ő=a9~aX\6S9Y MtFWY.ψ:ٹUXKTʤra< ǁGzl15IFe|z-8{6yuCnxڇ># _ҵ s[u)aVCY+z󰿽I, l"[gZA2`s}c}]q 0 0 ^MQh&{>t8P=w>oNbA_23F֋[tqR(]OL82!kk@aB.:2ke@RCof`[ ۣ`qf@6;\ pP`|^p i^-||۵c`@x4@dwa^B6 6_W*s;aS#F씿00" #pȇO= `[t;PFl#da0.afYDp ݳP,æ$I( >&$bw];n@})AiB" phR Ptt!"0};;c)5g1{YkX`~:QpzOG$X{K/?W %Nq4^%y[ _.[4a2ءiJl4K-HPե5^{a{,ŵպV_úl8Yap,J&Jd?o}|f6upulkzhX8g"{z.[@0edV&H}0/F7;ݎ)2䵀U&N LHxPTp|`ug N%ryw,w*oԝ @ MO$ D؁@//W'g*ܙ;ӳ T-}[~[-[\{HvJ7L^{2ݪi*7;%!`3j)Y.hd֦w%:@bCrZudFd R3 m`ΞO3o{ {T"4ZG_l]8)KnG.EQ0; pCw`2].6U-Tuňzö~*f>]+rP=CD2*-` ] (bPU6P[[P r^λS#2ɛ{CVU<늈jWiPEx-m{0z}GGjX9T([xsu:F=A cz o_~- Soe5FT^qVtcէD)C(;孱OjTp뵍zw}} aAq^Xvc{q|x0"= %G]0K1#PP{jV"C*|9ǗOzCk+ƠAImsU+q*$p8ߠ8p75R֍k ޛ)2tdtN3s,yʦz_E0MQSӳU+DRx]RеH~V87bDiA֧e0ݛ @꺦HF^7 bq;\dzkG KT.+5R/eZ}*bkA+̹W#KIz(|=R/FZիԝ1 D/鈄J臄Ƞ1PvF]iz`+9|:Q'd^V:v,v_F  Bwv>cR`-s;Ea|>=TJgm&d1庇v(ftM7N$9k}TL&_W*7Ҁy@ݓU^}:PߒF@ԝ @ D1MDA("R M8.KF{?%$|V8 lQGi"^E^[nHJ*8[uԯFC?b%gYeϒ N?_|k3=Ţ9YypB'V*e@D=$Z_Xk bG2iq0s_[g PAHԸ:xo)̳㑮E׭ՏĚwp{pg F%jrET@v$b!*rbR XV#ۋm[]# Fe#1oC^4KVA k'f/ sfCȋH)ıhzo`Ck `)3ԠU` lit5\Cy>tP-yH\ 8Qyϣ [p|\0+U+R |_p7] ںnN`Py/^̀6il=re{l\-)#%1E"!p%a2-:MRpЪu>E;y^? kNAلO "1֝ư F. 00ۗY@Fۛk1:Me%G/*uzXJ "g&aDjD'Fߓq8Dž}A8$t|\-ыA^{]?]_D)U+G@:5 FcO]c"$2S[) _dn;=C\J4V-/K/v=!2WѼ>] @ <*jzX*] zF@HT0A%RⷝGDQr>R`" ]ĭBkք$=OZ֤M&sX^=3aHݪaN`, D#}@X i9gP<Ȇ:ll+Wt!jѦ=l r|?~GBd\68pnRm>; {C@%ö:RbvBy* }rhq1 &Y{d>{x}y$t-7~0?<5"ŀ|g5;d*]1n@SDqm+E:+H/||rXp)p -EV`^ zH.'I盀@L3!|[đ)7۴!)S"&[֞?X~Qͻ"23D@.ỳE \pa^pfCXi?Mz#i%$&8ѱy[exmVғ t#c%ױJ 𤾂<ǐtQ[uٚrk"V^ΐ!;/Ǽ_~X_bcȚ,j^ dibD .̩ె` L ݓ]B }xPװ8vF0͆^`vՀWu:~6Z{M Y}'aG (~!f}q `C*'R+Xtp` /<`$r#l?lX^?>7a[k. |[_@3}ls9kTi8,J?IDAT%|;rA>S<'`3YCXZ v}"7æf^΂W r 36w^b)C/lxddo%D;a f0l_Oa;(M~#2&sX\j<@B޲ KV0lb_Ehv8| \R{ÓsM21cp4Yh1x߉{71lp lot`9V3aj`K0F: [VL g/g{a_ezd BGnNd s zZݦŎv<<,!fU=}ds>OĬAv':]: v>>[GSPs`q;8/ٌv EܝNQ J{%C߀Xh{`3ޣcM" Zٯ@NЗB6/&}fFLe*ӠWyy7ff?]@NZ @"$F:QUp " @LDbӈxqlgfGMӴ)4FLN@fy;$PrQwv<Cj` 9PҭN |QMџuOm"=/xnн=|>%Md EЇ0MkU*Yy4F', B.4N\ȍע>f3. ~@wB1|WEu^9k|N4|NދSt] M~C Vϻ%2 x;ٷT3ăy6=Gz*q01 pzd_[0Rbփ-@ v< 9<8?=/A B-Q! |5Lr*uѲ2 K N]/"l3ʈ5O [ h=Sd@N,(\[We#!7ȡ7Onš$a_#\?|XEƮ [s|yFg`2mZ-(7*a>ߋ׌; y "G=`.`x̀9w[9k vy:h2R4EJb@)=鏔r(a`@`iv* 4-d@% T4-dEj4oD0mS?IENDB`trollimage-1.28.0/doc/api/000077500000000000000000000000001514066130000152535ustar00rootroot00000000000000trollimage-1.28.0/doc/api/.gitkeep000066400000000000000000000000001514066130000166720ustar00rootroot00000000000000trollimage-1.28.0/doc/colormap.rst000066400000000000000000000035641514066130000170600ustar00rootroot00000000000000========== Colormap ========== Example usage ============= A simple example of applying a colormap on data:: from trollimage.colormap import rdbu from trollimage.image import Image img = Image(data, mode="L") rdbu.set_range(-90 + 273.15, 30 + 273.15) img.colorize(rdbu) img.show() .. image:: _static/hayan_simple.png A more complex example, with a colormap build from greyscale on one end, and spectral on the other, like this: .. image:: _static/my_cm.png :: from trollimage.colormap import spectral, greys from trollimage.image import Image img = Image(data, mode="L") greys.set_range(-40 + 273.15, 30 + 273.15) spectral.set_range(-90 + 273.15, -40.00001 + 273.15) my_cm = spectral + greys img.colorize(my_cm) img.show() .. image:: _static/hayan.png Now applying a palette to the data, with sharp edges:: from trollimage.colormap import set3 from trollimage.image import Image img = Image(data, mode="L") set3.set_range(-90 + 273.15, 30 + 273.15) img.palettize(set3) img.show() .. image:: _static/phayan.png API === See the :class:`~trollimage.Colormap` API documentation. Default Colormaps ================= Colors from www.ColorBrewer.org by Cynthia A. Brewer, Geography, Pennsylvania State University. Sequential Colormaps ~~~~~~~~~~~~~~~~~~~~ .. trollimage_colormap:: trollimage.colormap.sequential_colormaps Diverging Colormaps ~~~~~~~~~~~~~~~~~~~ .. trollimage_colormap:: trollimage.colormap.diverging_colormaps Qualitative Colormaps ~~~~~~~~~~~~~~~~~~~~~ .. trollimage_colormap:: trollimage.colormap.qualitative_colormaps :category: Rainbow Colormap ~~~~~~~~~~~~~~~~ Don't use this one ! See here_ and there_ why .. _here: https://www.nature.com/articles/s41467-020-19160-7 .. _there: https://doi.org/10.1109/MCG.2007.323435 .. trollimage_colormap:: trollimage.colormap.rainbow trollimage-1.28.0/doc/conf.py000066400000000000000000000171661514066130000160140ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # TrollImage documentation build configuration file, created by # sphinx-quickstart on Mon Dec 2 09:40:29 2013. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import os import sys from trollimage import __version__ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) sys.path.append(os.path.abspath(os.path.dirname(__file__))) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.napoleon', 'sphinxcontrib.apidoc', "trollimage_colormap"] # API docs apidoc_module_dir = "../trollimage" apidoc_output_dir = "api" apidoc_excluded_paths = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'TrollImage' copyright = u'2018, The Pytroll Team' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. short_version = ".".join(__version__.split(".")[:2]) # The full version, including alpha/beta/rc tags. release = short_version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'TrollImagedoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). latex_paper_size = 'a4' # The font size ('10pt', '11pt' or '12pt'). # latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'TrollImage.tex', u'TrollImage Documentation', u'The Pytroll Team', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Additional stuff for the LaTeX preamble. # latex_preamble = '' # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'trollimage', u'TrollImage Documentation', [u'The Pytroll Team'], 1) ] intersphinx_mapping = { 'python': ('https://docs.python.org/3', None), 'numpy': ('https://numpy.org/doc/stable', None), 'scipy': ('https://docs.scipy.org/doc/scipy/', None), 'xarray': ('https://docs.xarray.dev/en/stable', None), 'dask': ('https://dask.pydata.org/en/latest', None), 'rasterio': ('https://rasterio.readthedocs.io/en/latest', None), } trollimage-1.28.0/doc/examples/000077500000000000000000000000001514066130000163205ustar00rootroot00000000000000trollimage-1.28.0/doc/examples/hrv.rgb000066400000000000000000000064001514066130000176130ustar00rootroot00000000000000 0 0 0 0 0 0 0 0 0 2 2 2 3 3 5 4 5 8 5 7 d 6 8 13 6 a 1b 6 b 26 5 d 33 6 11 3d 6 16 45 7 1b 4c 7 20 51 7 26 56 7 2b 5a 7 31 5c 6 36 5f 6 3c 60 5 42 61 8 44 62 b 46 62 d 49 63 10 4b 63 13 4d 63 16 4f 63 1a 51 63 1d 53 62 20 55 62 24 57 61 27 59 62 2a 5b 63 2d 5d 64 30 5f 64 34 61 65 37 63 65 3a 65 65 3e 67 65 41 69 66 45 6b 66 4a 6d 65 4f 6e 64 55 6f 64 5a 71 63 60 72 62 65 73 61 6b 74 60 71 75 5e 77 77 5d 7d 78 5b 83 79 5b 88 7b 5a 8e 7c 59 93 7d 58 99 7f 57 9f 80 56 a5 81 55 ab 82 54 b1 84 53 b7 85 52 b9 86 54 ba 88 57 bb 8a 59 bc 8c 5c bd 8d 5f be 8f 62 bf 91 65 c1 93 68 c2 95 6b c3 96 6e c4 98 70 c5 9a 73 c6 9c 76 c7 9e 79 c8 a0 7b c8 a3 7e c9 a5 81 ca a7 84 cb a9 87 cc ab 8a cc ac 8b cd ac 8c cd ad 8d ce ae 8e ce ae 8e cf af 8f cf b0 90 d0 b0 91 d0 b1 92 d1 b2 92 d2 b2 93 d2 b3 94 d3 b4 95 d3 b4 96 d4 b5 97 d4 b6 98 d5 b6 98 d5 b7 99 d6 b8 9a d6 b8 9b d7 b9 9c d7 ba 9d d8 bb 9e d8 bb 9e d9 bc 9f d9 bd a0 da bd a1 da be a2 da bf a3 db bf a4 db c0 a5 dc c1 a6 dc c1 a6 dd c2 a7 dd c3 a8 de c3 a9 de c4 aa df c5 ab df c6 ac e0 c6 ad e0 c7 ae e1 c8 af e1 c8 b0 e2 c9 b1 e2 ca b1 e2 ca b2 e3 cb b3 e3 cc b4 e4 cc b5 e4 cd b6 e5 ce b7 e5 cf b8 e6 cf b9 e6 d0 ba e6 d1 bb e7 d1 bc e7 d2 bd e8 d3 be e8 d3 bf e9 d4 c0 e9 d5 c1 e9 d6 c2 ea d6 c3 ea d7 c4 eb d8 c5 eb d8 c6 ec d9 c7 ec da c8 ec da c9 ed db ca ed dc cb ee dd cc ee dd cd ee de ce ef df cf ef df d0 f0 e0 d1 f0 e1 d2 f0 e2 d3 f1 e2 d4 f1 e3 d5 f2 e4 d6 f2 e4 d7 f2 e5 d8 f3 e6 d9 f3 e7 da f3 e7 db f4 e8 dc f4 e9 dd f5 e9 de f5 ea df f5 eb e0 f6 ec e1 f6 ec e2 f6 ed e3 f7 ee e4 f7 ee e6 f7 ef e7 f8 f0 e8 f8 f1 e9 f9 f1 ea f9 f2 eb f9 f3 ec fa f3 ed fa f4 ee fa f5 ef fb f6 f0 fb f6 f2 fb f7 f3 fc f8 f4 fc f9 f5 fc f9 f6 fd fa f7 fd fb f8 fd fb f9 fe fc fb fe fd fc fe fe fd fe fe fe ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff b3 0 0 0 ff 10 a d trollimage-1.28.0/doc/examples/setvak.rgb000066400000000000000000000032201514066130000203060ustar00rootroot00000000000000 51 51 255 54 57 254 57 63 252 60 69 251 63 75 249 66 81 248 69 87 246 72 93 245 75 99 243 78 105 242 81 111 240 84 117 239 87 123 237 90 129 236 93 135 234 96 141 233 99 147 231 102 153 230 105 159 228 108 165 227 111 171 225 114 177 224 117 183 222 120 189 221 123 195 219 126 201 218 129 207 216 132 213 215 135 219 213 138 225 212 141 231 210 144 237 209 147 243 207 150 249 206 153 255 204 149 255 196 145 255 187 140 255 179 136 255 170 132 255 162 128 255 153 123 255 145 119 255 136 115 255 128 111 255 119 106 255 111 102 255 102 119 255 91 136 255 79 153 255 68 170 255 57 187 255 45 204 255 34 221 255 23 238 255 11 255 255 0 255 237 0 255 219 0 255 200 0 255 182 0 255 164 0 255 146 0 255 128 0 255 109 0 255 91 0 255 73 0 255 55 0 255 36 0 255 18 0 255 0 0 248 0 0 241 0 0 234 0 0 227 0 0 220 0 0 213 0 0 206 0 0 199 0 0 192 0 0 185 0 0 178 0 0 171 0 0 164 0 0 157 0 0 trollimage-1.28.0/doc/examples/utilities-examples.py000066400000000000000000000011411514066130000225160ustar00rootroot00000000000000"""Example showing importing colormaps from on-disk files.""" from trollimage import utilities as tu # Examples: importing colormaps filename = 'setvak.rgb' my_cmap = tu.cmap_from_text(filename) print(my_cmap.colors) my_cmap_norm = tu.cmap_from_text(filename, norm=True) print(my_cmap_norm.colors) my_cmap_transp = tu.cmap_from_text(filename, norm=True, transparency=True) print(my_cmap_transp.colors) filename = 'hrv.rgb' my_cmap_hex = tu.cmap_from_text(filename, hex=True) print(my_cmap_hex.colors) # Example: converting PIL to trollimage.Image image = "pifn.png" timage = tu.pilimage2trollimage(image) trollimage-1.28.0/doc/index.rst000066400000000000000000000004721514066130000163460ustar00rootroot00000000000000TrollImage ========== .. image:: _static/hayan.png Get the source code here_ ! .. _here: http://github.com/pytroll/trollimage Contents: .. toctree:: :maxdepth: 2 installation colormap API Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` trollimage-1.28.0/doc/installation.rst000066400000000000000000000056651514066130000177510ustar00rootroot00000000000000============ Installation ============ Trollimage is available from conda-forge (via conda), PyPI (via pip), or from source (via pip+git). The below instructions show how to install stable versions of trollimage or from the source code. Conda-based Installation ======================== Trollimage can be installed into a conda environment by installing the package from the conda-forge channel. If you do not already have access to a conda installation, we recommend installing `miniconda `_ for the smallest and easiest installation. The commands below will use ``-c conda-forge`` to make sure packages are downloaded from the conda-forge channel. Alternatively, you can tell conda to always use conda-forge by running: .. code-block:: bash $ conda config --add channels conda-forge In a new conda environment -------------------------- We recommend creating a separate environment for your work with trollimage. To create a new environment and install trollimage all in one command you can run: .. code-block:: bash $ conda create -c conda-forge -n my_trollimage_env python trollimage You must then activate the environment so any future python or conda commands will use this environment. .. code-block:: $ conda activate my_trollimage_env This method of creating an environment with trollimage (and optionally other packages) installed can generally be created faster than creating an environment and then later installing trollimage and other packages (see the section below). In an existing environment -------------------------- .. note:: It is recommended that when first exploring trollimage, you create a new environment specifically for this rather than modifying one used for other work. If you already have a conda environment, it is activated, and would like to install trollimage into it, run the following: .. code-block:: bash $ conda install -c conda-forge trollimage Pip-based Installation ====================== Trollimage is available from the Python Packaging Index (PyPI). A sandbox environment for ``trollimage`` can be created using `Virtualenv `_. To install the `trollimage` package and the minimum amount of python dependencies: .. code-block:: bash $ pip install trollimage Install from source =================== To install directly from github into an existing environment (pip or conda-based): .. code-block:: bash $ pip install git+https://github.com/pytroll/trollimage.git If you have the ``git`` command installed this will automatically download the source code and install it into the current environment. If you would like to modify a local copy of trollimage and see the effects immediately in your environment use the below command instead. This command should be run from the root your cloned version of the git repository (where the ``setup.py`` is located): .. code-block:: $ pip install -e . trollimage-1.28.0/doc/trollimage_colormap.py000066400000000000000000000053631514066130000211160ustar00rootroot00000000000000"""Custom sphinx directive work with colormap objects. This module must be on the ``sys.path`` and added to the list of extensions in a ``conf.py``. """ import os import importlib from typing import Any from docutils import nodes from docutils.parsers.rst.directives import flag from sphinx.util.docutils import SphinxDirective from trollimage import colormap from trollimage.image import Image def setup(app): """Add custom extension to sphinx.""" app.add_directive("trollimage_colormap", TrollimageColormapDirective) return { "version": "0.1", "parallel_read": True, "parallel_write": True, } class TrollimageColormapDirective(SphinxDirective): """Custom sphinx directive for generating one or more colormap images.""" required_arguments: int = 1 option_spec: dict[str, Any] = { "category": flag, } def run(self) -> list[nodes.Node]: """Import and generate colormap images to be inserted into the document.""" cmap_import_path = self.arguments[0] is_category = "category" in self.options colormap_dict = self._get_colormap_dict(cmap_import_path) image_nodes = [] for cmap_name, cmap_obj in sorted(colormap_dict.items()): image_nodes += self._create_colormap_nodes(cmap_name, cmap_obj, is_category) return image_nodes @staticmethod def _get_colormap_dict(cmap_import_path: str) -> dict[str, colormap.Colormap]: cmap_module_name, cmap_var = cmap_import_path.rsplit(".", 1) cmap_module = importlib.import_module(cmap_module_name) cmap_objects = getattr(cmap_module, cmap_var) if not isinstance(cmap_objects, (list, dict)): cmap_objects = {cmap_var: cmap_objects} if not isinstance(cmap_objects, dict): cmap_names = [] for colormap_object in cmap_objects: cmap_name = [cmap_name for cmap_name, cmap_obj in cmap_module.__dict__.items() if cmap_obj is colormap_object][0] cmap_names.append(cmap_name) cmap_objects = dict(zip(cmap_names, cmap_objects)) return cmap_objects @staticmethod def _create_colormap_nodes(cmap_name: str, cmap_obj: colormap.Colormap, is_category: bool) -> list[nodes.Node]: cmap_fn = os.path.join("_static", "colormaps", f"{cmap_name}.png") if not os.path.exists(cmap_fn): cb = colormap.colorbar(25, 500, cmap_obj, category=is_category) channels = [cb[i, :, :] for i in range(3)] im = Image(channels=channels, mode="RGB") im.save(cmap_fn) paragraph = nodes.paragraph(text=cmap_name) image = nodes.image("", **{"uri": cmap_fn, "alt": cmap_name}) return [paragraph, image] trollimage-1.28.0/load_colorbrewer_colormaps.py000066400000000000000000000065161514066130000217220ustar00rootroot00000000000000"""Helper script to convert colormaps from https://colorbrewer2.org into trollimage Colormap code. The text output by this script should be copied to the ``trollimage/colormap.py``. """ import json import sys import urllib.request JSON_URL = "https://raw.githubusercontent.com/axismaps/colorbrewer/master/export/colorbrewer.json" def main(): """Print python code version of trollimage Colormap objects for each colorbrewer colormap.""" cmap_groups = _load_colormap_info_from_colorbrewer() _print_colormap_group(cmap_groups["seq"], "Sequential", "sequential_colormaps") _print_colormap_group(cmap_groups["div"], "Diverging", "diverging_colormaps") _print_colormap_group(cmap_groups["qual"], "Qualitative", "qualitative_colormaps", normalize_values=False) def _load_colormap_info_from_colorbrewer() -> dict[str, dict[str, list]]: with urllib.request.urlopen(JSON_URL) as json_file: # nosec: B310 colorbrewer_dict = json.load(json_file) cmap_groups: dict[str, dict[str, list]] = {"div": {}, "seq": {}, "qual": {}} for cmap_name, cmap_info in colorbrewer_dict.items(): max_colors = max((num_colors_str for num_colors_str in cmap_info.keys() if num_colors_str != "type"), key=lambda num_color_str: int(num_color_str)) cmap_colors = cmap_info[max_colors] color_tuples = [rgb_color_str.replace("rgb(", "").replace(")", "").split(",") for rgb_color_str in cmap_colors] cmap_groups[cmap_info["type"]][cmap_name.lower()] = color_tuples return cmap_groups def _print_colormap_group(cmap_group: dict[str, list], human_group_name: str, group_var_name: str, normalize_values: bool = True) -> None: print(f"# * {human_group_name} Colormaps *\n") for cmap_name, cmap_colors in sorted(cmap_group.items()): cmap_values, color_human_strings = _color_info_as_human_friendly_strings(cmap_colors, normalize_values) _print_single_colormap(cmap_name, cmap_values, color_human_strings) print(f"{group_var_name} = {{") for cmap_name in sorted(cmap_group.keys()): print(f" \"{cmap_name}\": {cmap_name},") print("}\n") def _color_info_as_human_friendly_strings( cmap_colors: list[tuple[int, int, int]], normalize_values: bool, ) -> tuple[list[str], list[tuple[str, str, str]]]: num_colors = len(cmap_colors) color_human_strings = [ (f"{rgb_color[0]} / 255", f"{rgb_color[1]} / 255", f"{rgb_color[2]} / 255") for rgb_color in cmap_colors ] cmap_values = [str(color_idx) for color_idx in range(num_colors)] if normalize_values: # 0 - 1 normalized values for non-qualitative colormaps cmap_values = [f"{cval} / {num_colors - 1}" for cval in cmap_values] return cmap_values, color_human_strings def _print_single_colormap(cmap_name: str, cmap_values: list[str], cmap_colors: list[tuple[str, str, str]]) -> None: cmap_pairs = [(cval, rgb_color) for cval, rgb_color in zip(cmap_values, cmap_colors)] print(f"{cmap_name} = Colormap(") for cmap_value_str, cmap_color_tuple in cmap_pairs: print(f" ({cmap_value_str}, " f"({cmap_color_tuple[0]}, {cmap_color_tuple[1]}, {cmap_color_tuple[2]})),") print(")\n") if __name__ == "__main__": sys.exit(main()) trollimage-1.28.0/pyproject.toml000066400000000000000000000026201514066130000166510ustar00rootroot00000000000000[build-system] requires = [ "wheel", "numpy>=2.0.0,<3.0", "setuptools>=42", "versioneer[toml]", "Cython>=3.1.0" ] build-backend = "setuptools.build_meta" [tool.coverage.run] relative_files = true plugins = ["Cython.Coverage"] omit = ["trollimage/version.py", "versioneer.py"] [tool.pytest.ini_options] minversion = "6.0" addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"] xfail_strict = true filterwarnings = [ "error", "ignore::rasterio.errors.NotGeoreferencedWarning", # remove when fixed by xarray "ignore:__array_wrap__ must accept context and return_scalar arguments:DeprecationWarning:numpy", # dateutil needs a new release # https://github.com/dateutil/dateutil/issues/1314 'ignore:datetime.datetime.utcfromtimestamp\(\) is deprecated and scheduled for removal:DeprecationWarning:dateutil', # updates incoming in pillow that remove this warning for our use cases # https://github.com/python-pillow/Pillow/pull/9063 "ignore:'mode' parameter is deprecated", # dask deprecated the map_blocks token= kwarg but it is being reverted "ignore:The `token=` keyword to `map_blocks` has been moved to:FutureWarning", ] log_cli_level = "info" testpaths = [ "trollimage/tests", ] [tool.versioneer] VCS = "git" style = "pep440" versionfile_source = "trollimage/version.py" versionfile_build = "trollimage/version.py" tag_prefix = "v" trollimage-1.28.0/rtd_requirements.txt000066400000000000000000000003071514066130000200720ustar00rootroot00000000000000pillow rasterio xarray dask[array] docutils sphinx>=7,<8 sphinx-rtd-theme>=1.2.0,<2.0 sphinxcontrib-apidoc pytest setuptools>=65.5.1 # not directly required, pinned by Snyk to avoid a vulnerability trollimage-1.28.0/setup.cfg000066400000000000000000000001461514066130000155570ustar00rootroot00000000000000[flake8] max-line-length = 120 exclude = doc/conf.py trollimage/version.py versioneer.py trollimage-1.28.0/setup.py000066400000000000000000000062471514066130000154600ustar00rootroot00000000000000"""Setup for trollimage.""" import sys from typing import Any from setuptools import setup, find_packages import versioneer import numpy as np from Cython.Build import build_ext from Cython.Distutils import Extension if sys.platform.startswith("win"): extra_compile_args = [] else: extra_compile_args = ["-O3"] EXTENSIONS = [ Extension( 'trollimage._colorspaces', sources=['trollimage/_colorspaces.pyx'], extra_compile_args=extra_compile_args, include_dirs=[np.get_include()], ), ] cython_directives: dict[str, Any] = { "language_level": "3", "freethreading_compatible": True, } class CythonCoverageBuildExtCommand(build_ext): """Simple command extension to add Cython coverage flag. With this class included in the build we are able to pass ``--cython-coverage`` to compile Cython modules with flags necessary to report test coverage. """ user_options = build_ext.user_options + [ ('cython-coverage', None, None), ] def initialize_options(self): """Initialize command line flag options to default values.""" super().initialize_options() self.cython_coverage = False # noqa def run(self): """Build extensions and handle cython coverage flags.""" define_macros = [("NPY_NO_DEPRECATED_API", "NPY_1_25_API_VERSION")] if self.cython_coverage: print("Enabling directives/macros for Cython coverage support") cython_directives.update({ "linetrace": True, "profile": True, }) define_macros.extend([ ("CYTHON_TRACE", "1"), ("CYTHON_TRACE_NOGIL", "1"), ]) for ext in EXTENSIONS: ext.define_macros = define_macros ext.cython_directives.update(cython_directives) super().run() cmdclass = versioneer.get_cmdclass(cmdclass={"build_ext": CythonCoverageBuildExtCommand}) with open('README.rst', 'r') as readme_file: long_description = readme_file.read() setup(name="trollimage", version=versioneer.get_version(), cmdclass=cmdclass, description='Pytroll imaging library', long_description=long_description, long_description_content_type='text/x-rst', author='Martin Raspaud', author_email='martin.raspaud@smhi.se', classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Science/Research", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Scientific/Engineering", "Programming Language :: Python :: Free Threading :: 1 - Unstable", ], license="Apache-2.0", license_files=["LICENSE.txt", "LICENSE_RIO_COLOR.txt"], url="https://github.com/pytroll/trollimage", packages=find_packages(), zip_safe=False, install_requires=['numpy>=1.25', 'pillow'], python_requires='>=3.11', extras_require={ 'geotiff': ['rasterio>=1.0'], 'xarray': ['xarray', 'dask[array]'], 'tests': ['xarray', 'dask[array]', 'pyproj', 'pyresample', 'pytest'], }, ext_modules=EXTENSIONS, ) trollimage-1.28.0/trollimage/000077500000000000000000000000001514066130000160745ustar00rootroot00000000000000trollimage-1.28.0/trollimage/__init__.py000066400000000000000000000001721514066130000202050ustar00rootroot00000000000000"""The trollimage package.""" from .version import get_versions __version__ = get_versions()['version'] del get_versions trollimage-1.28.0/trollimage/_colorspaces.pyx000066400000000000000000000445661514066130000213310ustar00rootroot00000000000000# cython: language_level=3, boundscheck=False, cdivision=True, wraparound=False, initializedcheck=False, nonecheck=False, cpow=True cimport cython from libc.math cimport cos, sin, atan2 import numpy as np cimport numpy as np ctypedef fused floating: np.float32_t np.float64_t np.import_array() # cdef extern from "numpy/npy_math.h": # np.float32_t NPY_NANF # bint npy_isnan(np.float64_t x) nogil # bint npy_isnan(np.float32_t x) nogil # Function pointer type to allow for generic high-level functions ctypedef void (*CONVERT_FUNC)(floating[:] comp1, floating[:] comp2, floating[:] comp3, floating[:, ::1] out) noexcept nogil cdef: np.float32_t bintercept = 4.0 / 29 # 0.137931 np.float32_t delta = 6.0 / 29 # 0.206896 np.float32_t t0 = delta ** 3 # 0.008856 np.float32_t alpha = (delta ** -2) / 3 # 7.787037 np.float32_t third = 1.0 / 3 np.float32_t kappa = (29.0 / 3) ** 3 # 903.3 np.float32_t gamma = 2.2 np.float32_t xn = 0.95047 np.float32_t yn = 1.0 np.float32_t zn = 1.08883 np.float32_t denom_n = xn + (15 * yn) + (3 * zn) np.float32_t uprime_n = (4 * xn) / denom_n np.float32_t vprime_n = (9 * yn) / denom_n # Compile time option to use # sRGB companding (default, True) or simplified gamma (False) # sRGB companding is slightly slower but is more accurate at # the extreme ends of scale # Unit tests tuned to sRGB companding, change with caution bint SRGB_COMPAND = True def rgb2lch( object rgba_arr, ): """Convert numpy RGB[A] arrays to CIE LCh_ab (Luminance, Chroma, Hue). See :func:`convert_colors` for more information on color spaces. Args: rgba_arr: Numpy array of RGB or RGBA colors. The array can be any shape as long as the channel (band) dimension is the last (-1) dimension. If an Alpha (A) channel is provided it is ignored. Values should be between 0 and 1. Returns: LCH_ab (l, c, h) numpy array where the last dimension represents Hue, Chroma, and Luminance. Hue is in radians from -pi to pi. Chroma is from 0 to 1. Luminance is also from 0 and 1 (usually a maximum of ~0.5). """ return convert_colors(rgba_arr, "rgb", "lch") def lch2rgb(object lch_arr): """Convert an LCH (luminance, chroma, hue) array to RGB. See :func:`convert_colors` for more information on color spaces. Args: lch_arr: Numpy array of HCL values. The array can be any shape as long as the channel (band) dimension is the last (-1) dimension. Hue must be between -pi to pi. Chroma and Luminance should be between 0 and 1. Returns: RGB array where each Red, Green, and Blue channel is between 0 and 1. """ return convert_colors(lch_arr, "lch", "rgb") def convert_colors(object input_colors, str in_space, str out_space): """Convert from one color space to another. Color Spaces ^^^^^^^^^^^^ * **rgb**: Red, Green, and Blue. Each channel should be in a 0 to 1 normalized range. * **lch**: LCh_ab (LCH). The CIELAB Cylindrical Luminance, Chroma, and Hue color space. Luminance values range from about 0 to about 100. Chroma values range from about 0 to 120. Hue is in radians and is from -pi to pi. See the `wikipedia article `_ for more information. * **lab**: CIELAB. The cartesian version of "lch". Luminance is the same value as LCh. The ``a*`` and ``b*`` values range from about -120 to 120. See the `wikipedia article `_ for more info. * **luv**: CIELUV. Luminance and a ``u*`` and ``v*`` start component. The luminance values range from 0 to 100. The u and v values range from about -200 to 200. See the `wikipedia article `_ for more info. * **xyz**: CIE XYZ. Values range from about 0 to 1. See the `wikipedia article `_ for more info. Args: input_colors: Numpy array of input colors in ``in_space`` color space. The array can be of any shape, but the color dimension must be the last dimension. Only the first three elements in the color dimension will be used. So if an Alpha (A) channel is provided it is ignored. in_space: String name of the color space of the input data. Can be one of "rgb", "lch", "lab", "luv", or "xyz". out_space: String name of the color space to convert to. Available options are the same as for ``in_space``. Returns: Numpy array with equal shape to the input, but the last dimension is always length 3 to match the ``out_space`` color space. Notes: This function is called by all the individual ``2`` functions. This function and all color conversion functions are heavily based on or taken from the `rio-color `_ project which is under an MIT license. A copy of this license is available in the ``trollimage`` package and root of the git repository. The majority of changes made to the ``rio-color`` code were to support memory views in a "no GIL" way and allow for 32-bit and 64-bit floating point data. """ cdef object in123_arr = input_colors[..., :3] cdef tuple shape = in123_arr.shape cdef np.ndarray in123_2d = in123_arr.reshape((-1, 3)) cdef np.ndarray out123 if in123_arr.dtype == np.float32: out123 = _call_convert_func[np.float32_t](in123_2d, in_space, out_space) else: out123 = _call_convert_func[np.float64_t](in123_2d, in_space, out_space) return out123.reshape(shape) cdef np.ndarray[floating, ndim=2] _call_convert_func( floating[:, :] in_colors, str in_space, str out_space, ): cdef floating[:] in1_view, in2_view, in3_view cdef CONVERT_FUNC conv_func = NULL if in_space == "rgb": if out_space == "lch": conv_func = _rgb_to_lch[floating] elif out_space == "lab": conv_func = _rgb_to_lab[floating] elif out_space == "luv": conv_func = _rgb_to_luv[floating] elif out_space == "xyz": conv_func = _rgb_to_xyz[floating] elif in_space == "lch": if out_space == "rgb": conv_func = _lch_to_rgb[floating] elif out_space == "lab": conv_func = _lch_to_lab[floating] elif out_space == "luv": conv_func = _lch_to_luv[floating] elif out_space == "xyz": conv_func = _lch_to_xyz[floating] elif in_space == "lab": if out_space == "rgb": conv_func = _lab_to_rgb[floating] elif out_space == "lch": conv_func = _lab_to_lch[floating] elif out_space == "luv": conv_func = _lab_to_luv[floating] elif out_space == "xyz": conv_func = _lab_to_xyz[floating] elif in_space == "luv": if out_space == "rgb": conv_func = _luv_to_rgb[floating] elif out_space == "lch": conv_func = _luv_to_lch[floating] elif out_space == "lab": conv_func = _luv_to_lab[floating] elif out_space == "xyz": conv_func = _luv_to_xyz[floating] elif in_space == "xyz": if out_space == "rgb": conv_func = _xyz_to_rgb[floating] elif out_space == "lch": conv_func = _xyz_to_lch[floating] elif out_space == "lab": conv_func = _xyz_to_lab[floating] elif out_space == "luv": conv_func = _xyz_to_luv[floating] if conv_func is NULL: raise ValueError("Unknown colorspace combination") cdef object dtype if floating is np.float32_t: dtype = np.float32 else: dtype = np.float64 in1_view = in_colors[:, 0] in2_view = in_colors[:, 1] in3_view = in_colors[:, 2] cdef np.ndarray[floating, ndim=2] out_colors = np.empty((in_colors.shape[0], 3), dtype=dtype) cdef floating[:, ::1] out_view = out_colors with nogil: conv_func(in1_view, in2_view, in3_view, out_view) return out_colors cdef void _rgb_to_lab(floating[:] r_arr, floating[:] g_arr, floating[:] b_arr, floating[:, ::1] lab_arr) noexcept nogil: _rgb_to_xyz[floating](r_arr, g_arr, b_arr, lab_arr) _xyz_to_lab[floating](lab_arr[:, 0], lab_arr[:, 1], lab_arr[:, 2], lab_arr) cdef void _rgb_to_lch(floating[:] r_arr, floating[:] g_arr, floating[:] b_arr, floating[:, ::1] lch_arr) noexcept nogil: _rgb_to_xyz(r_arr, g_arr, b_arr, lch_arr) _xyz_to_lab[floating](lch_arr[:, 0], lch_arr[:, 1], lch_arr[:, 2], lch_arr) _lab_to_lch[floating](lch_arr[:, 0], lch_arr[:, 1], lch_arr[:, 2], lch_arr) cdef void _rgb_to_luv(floating[:] r_arr, floating[:] g_arr, floating[:] b_arr, floating[:, ::1] luv_arr) noexcept nogil: _rgb_to_xyz(r_arr, g_arr, b_arr, luv_arr) _xyz_to_luv[floating](luv_arr[:, 0], luv_arr[:, 1], luv_arr[:, 2], luv_arr) cdef void _xyz_to_lch(floating[:] x_arr, floating[:] y_arr, floating[:] z_arr, floating[:, ::1] lch_arr) noexcept nogil: _xyz_to_lab(x_arr, y_arr, z_arr, lch_arr) _lab_to_lch[floating](lch_arr[:, 0], lch_arr[:, 1], lch_arr[:, 2], lch_arr) cdef void _lab_to_rgb(floating[:] l_arr, floating[:] a_arr, floating[:] b_arr, floating[:, ::1] rgb_arr) noexcept nogil: _lab_to_xyz(l_arr, a_arr, b_arr, rgb_arr) _xyz_to_rgb[floating](rgb_arr[:, 0], rgb_arr[:, 1], rgb_arr[:, 2], rgb_arr) cdef void _lab_to_luv(floating[:] l_arr, floating[:] a_arr, floating[:] b_arr, floating[:, ::1] luv_arr) noexcept nogil: _lab_to_xyz(l_arr, a_arr, b_arr, luv_arr) _xyz_to_luv[floating](luv_arr[:, 0], luv_arr[:, 1], luv_arr[:, 2], luv_arr) cdef void _lch_to_xyz(floating[:] l_arr, floating[:] c_arr, floating[:] h_arr, floating[:, ::1] xyz_arr) noexcept nogil: _lch_to_lab(l_arr, c_arr, h_arr, xyz_arr) _lab_to_xyz[floating](xyz_arr[:, 0], xyz_arr[:, 1], xyz_arr[:, 2], xyz_arr) cdef void _lch_to_rgb(floating[:] l_arr, floating[:] c_arr, floating[:] h_arr, floating[:, ::1] rgb_arr) noexcept nogil: _lch_to_lab(l_arr, c_arr, h_arr, rgb_arr) _lab_to_xyz[floating](rgb_arr[:, 0], rgb_arr[:, 1], rgb_arr[:, 2], rgb_arr) _xyz_to_rgb[floating](rgb_arr[:, 0], rgb_arr[:, 1], rgb_arr[:, 2], rgb_arr) cdef void _lch_to_luv(floating[:] l_arr, floating[:] c_arr, floating[:] h_arr, floating[:, ::1] luv_arr) noexcept nogil: _lch_to_lab(l_arr, c_arr, h_arr, luv_arr) _lab_to_xyz[floating](luv_arr[:, 0], luv_arr[:, 1], luv_arr[:, 2], luv_arr) _xyz_to_rgb[floating](luv_arr[:, 0], luv_arr[:, 1], luv_arr[:, 2], luv_arr) cdef void _luv_to_lab(floating[:] l_arr, floating[:] u_arr, floating[:] v_arr, floating[:, ::1] lab_arr) noexcept nogil: _luv_to_xyz(l_arr, u_arr, v_arr, lab_arr) _xyz_to_lab[floating](lab_arr[:, 0], lab_arr[:, 1], lab_arr[:, 2], lab_arr) cdef void _luv_to_rgb(floating[:] l_arr, floating[:] u_arr, floating[:] v_arr, floating[:, ::1] rgb_arr) noexcept nogil: _luv_to_xyz(l_arr, u_arr, v_arr, rgb_arr) _xyz_to_rgb[floating](rgb_arr[:, 0], rgb_arr[:, 1], rgb_arr[:, 2], rgb_arr) cdef void _luv_to_lch(floating[:] l_arr, floating[:] u_arr, floating[:] v_arr, floating[:, ::1] lch_arr) noexcept nogil: _luv_to_xyz(l_arr, u_arr, v_arr, lch_arr) _xyz_to_lab[floating](lch_arr[:, 0], lch_arr[:, 1], lch_arr[:, 2], lch_arr) _lab_to_lch[floating](lch_arr[:, 0], lch_arr[:, 1], lch_arr[:, 2], lch_arr) # Direct colorspace conversions cdef void _rgb_to_xyz(floating[:] red_arr, floating[:] green_arr, floating[:] blue_arr, floating[:, ::1] xyz_arr) noexcept nogil: cdef floating r, g, b, rl, gl, bl, x, y, z cdef Py_ssize_t idx for idx in range(red_arr.shape[0]): r = red_arr[idx] g = green_arr[idx] b = blue_arr[idx] # convert RGB to linear scale rl = _to_linear_rgb(r) gl = _to_linear_rgb(g) bl = _to_linear_rgb(b) # matrix mult for srgb->xyz, # includes adjustment for reference white x = ((rl * 0.4124564) + (gl * 0.3575761) + (bl * 0.1804375)) / xn y = ((rl * 0.2126729) + (gl * 0.7151522) + (bl * 0.0721750)) z = ((rl * 0.0193339) + (gl * 0.1191920) + (bl * 0.9503041)) / zn xyz_arr[idx, 0] = x xyz_arr[idx, 1] = y xyz_arr[idx, 2] = z cdef inline floating _to_linear_rgb(floating rgb_component) noexcept nogil: if SRGB_COMPAND: return _to_linear_srgb_expand(rgb_component) # Use "simplified sRGB" return rgb_component ** gamma cdef inline floating _to_linear_srgb_expand(floating rgb_component) noexcept nogil: if rgb_component <= 0.04045: return rgb_component / 12.92 return ((rgb_component + 0.055) / 1.055) ** 2.4 cdef void _xyz_to_lab(floating[:] x_arr, floating[:] y_arr, floating[:] z_arr, floating[:, ::1] lab) noexcept nogil: cdef floating x, y, z, fx, fy, fz cdef floating L, a, b cdef Py_ssize_t idx for idx in range(x_arr.shape[0]): x = x_arr[idx] y = y_arr[idx] z = z_arr[idx] # convert XYZ to LAB colorspace if x > t0: fx = x ** third else: fx = (alpha * x) + bintercept if y > t0: fy = y ** third else: fy = (alpha * y) + bintercept if z > t0: fz = z ** third else: fz = (alpha * z) + bintercept L = (116 * fy) - 16 a = 500 * (fx - fy) b = 200 * (fy - fz) lab[idx, 0] = L lab[idx, 1] = a lab[idx, 2] = b cdef void _lab_to_lch(floating[:] L_arr, floating[:] a_arr, floating[:] b_arr, floating[:, ::1] lch) noexcept nogil: cdef Py_ssize_t idx cdef floating c, h for idx in range(L_arr.shape[0]): lch[idx, 0] = L_arr[idx] # store temporary results then write output to avoid corruption # if the output array is the same as the input arrays c = ((a_arr[idx] * a_arr[idx]) + (b_arr[idx] * b_arr[idx])) ** 0.5 h = atan2(b_arr[idx], a_arr[idx]) lch[idx, 1] = c lch[idx, 2] = h cdef void _lch_to_lab(floating[:] l_arr, floating[:] c_arr, floating[:] h_arr, floating[:, ::1] lab_arr) noexcept nogil: cdef floating a, b cdef Py_ssize_t idx for idx in range(l_arr.shape[0]): a = c_arr[idx] * cos(h_arr[idx]) b = c_arr[idx] * sin(h_arr[idx]) lab_arr[idx, 0] = l_arr[idx] lab_arr[idx, 1] = a lab_arr[idx, 2] = b cdef void _lab_to_xyz(floating[:] l_arr, floating[:] a_arr, floating[:] b_arr, floating[:, ::1] xyz_arr) noexcept nogil: cdef floating x, y, z, L, a, b, tx, ty, tz cdef Py_ssize_t idx for idx in range(l_arr.shape[0]): L = l_arr[idx] a = a_arr[idx] b = b_arr[idx] tx = ((L + 16) / 116.0) + (a / 500.0) if tx > delta: x = tx ** 3 else: x = 3 * delta * delta * (tx - bintercept) ty = (L + 16) / 116.0 if ty > delta: y = ty ** 3 else: y = 3 * delta * delta * (ty - bintercept) tz = ((L + 16) / 116.0) - (b / 200.0) if tz > delta: z = tz ** 3 else: z = 3 * delta * delta * (tz - bintercept) xyz_arr[idx, 0] = x xyz_arr[idx, 1] = y xyz_arr[idx, 2] = z cdef void _xyz_to_rgb(floating[:] x_arr, floating[:] y_arr, floating[:] z_arr, floating[:, ::1] rgb_arr) noexcept nogil: cdef floating rlin, glin, blin, r, g, b, x, y, z cdef Py_ssize_t idx for idx in range(x_arr.shape[0]): x = x_arr[idx] y = y_arr[idx] z = z_arr[idx] # uses reference white d65 x = x * xn z = z * zn # XYZ to sRGB # expanded matrix multiplication rlin = (x * 3.2404542) + (y * -1.5371385) + (z * -0.4985314) glin = (x * -0.9692660) + (y * 1.8760108) + (z * 0.0415560) blin = (x * 0.0556434) + (y * -0.2040259) + (z * 1.0572252) r = _to_nonlinear_rgb(rlin) g = _to_nonlinear_rgb(glin) b = _to_nonlinear_rgb(blin) # constrain to 0..1 to deal with any float drift if r > 1.0: r = 1.0 elif r < 0.0: r = 0.0 if g > 1.0: g = 1.0 elif g < 0.0: g = 0.0 if b > 1.0: b = 1.0 elif b < 0.0: b = 0.0 rgb_arr[idx, 0] = r rgb_arr[idx, 1] = g rgb_arr[idx, 2] = b cdef inline floating _to_nonlinear_rgb(floating rgb_component) noexcept nogil: if SRGB_COMPAND: return _to_nonlinear_srgb_compand(rgb_component) # Use "simplified sRGB" return rgb_component ** (1 / gamma) cdef inline floating _to_nonlinear_srgb_compand(floating rgb_component) noexcept nogil: if rgb_component <= 0.0031308: return 12.92 * rgb_component return (1.055 * (rgb_component ** (1 / 2.4))) - 0.055 cdef void _xyz_to_luv(floating[:] x_arr, floating[:] y_arr, floating[:] z_arr, floating[:, ::1] luv_arr) noexcept nogil: cdef floating L, u, v, uprime, vprime, denom, x, y, z cdef Py_ssize_t idx for idx in range(x_arr.shape[0]): x = x_arr[idx] y = y_arr[idx] z = z_arr[idx] denom = x + (15 * y) + (3 * z) uprime = (4 * x) / denom vprime = (9 * y) / denom y = y / yn if y <= t0: L = kappa * y else: L = (116 * (y ** third)) - 16 u = 13 * L * (uprime - uprime_n) v = 13 * L * (vprime - vprime_n) luv_arr[idx, 0] = L luv_arr[idx, 1] = u luv_arr[idx, 2] = v cdef void _luv_to_xyz(floating[:] l_arr, floating[:] u_arr, floating[:] v_arr, floating[:, ::1] xyz_arr) noexcept nogil: cdef floating x, y, z, uprime, vprime, L, u, v cdef Py_ssize_t idx for idx in range(l_arr.shape[0]): L = l_arr[idx] u = u_arr[idx] v = v_arr[idx] if L == 0.0: xyz_arr[idx, 0] = 0.0 xyz_arr[idx, 1] = 0.0 xyz_arr[idx, 2] = 0.0 continue uprime = (u / (13 * L)) + uprime_n vprime = (v / (13 * L)) + vprime_n if L <= 8.0: y = L / kappa else: y = ((L + 16) / 116.0) ** 3 x = y * ((9 * uprime) / (4 * vprime)) z = y * ((12 - (3 * uprime) - (20 * vprime)) / (4 * vprime)) xyz_arr[idx, 0] = x xyz_arr[idx, 1] = y xyz_arr[idx, 2] = z trollimage-1.28.0/trollimage/_xrimage_rasterio.py000066400000000000000000000173761514066130000221670ustar00rootroot00000000000000"""RasterIO-specific utilities needed by the XRImage class.""" import logging import threading from contextlib import suppress import dask.array as da import rasterio from rasterio.enums import Resampling from rasterio.windows import Window logger = logging.getLogger(__name__) def get_data_arr_crs_transform_gcps(data_arr): """Convert DataArray's AreaDefinition or SwathDefinition to rasterio geolocation information. If possible, a rasterio geotransform object will be created. If it can't be made then it is assumed the provided geometry object is a SwathDefinition and will be checked for GCP coordinates (``swath_def.lons.attrs['gcps']``). Args: data_arr: Xarray DataArray. Returns: Tuple of (crs, transform, gcps). Each element defaults to ``None`` if it couldn't be calculated. """ crs = None transform = None gcps = None try: area = data_arr.attrs["area"] if rasterio.__gdal_version__ >= '3': wkt_version = 'WKT2_2018' else: wkt_version = 'WKT1_GDAL' if hasattr(area, 'crs'): crs = rasterio.crs.CRS.from_wkt(area.crs.to_wkt(version=wkt_version)) else: crs = rasterio.crs.CRS(area.proj_dict) west, south, east, north = area.area_extent height, width = area.shape transform = rasterio.transform.from_bounds(west, south, east, north, width, height) except KeyError: # No area logger.info("Couldn't create geotransform") except AttributeError: try: gcps = data_arr.attrs["area"].lons.attrs['gcps'] crs = data_arr.attrs["area"].lons.attrs['crs'] except KeyError: logger.info("Couldn't create geotransform") return crs, transform, gcps def split_regular_vs_lazy_tags(tags, r_file): """Split tags into regular vs lazy (dask) tags.""" da_tags = [] for key, val in list(tags.items()): try: if isinstance(val.data, da.Array): da_tags.append((val.data, RIOTag(r_file, key))) tags.pop(key) else: tags[key] = val.item() except AttributeError: continue return tags, da_tags class RIOFile(object): """Rasterio wrapper to allow da.store to do window saving.""" def __init__(self, path, mode='w', **kwargs): """Initialize the object.""" self.path = path self.mode = mode self.kwargs = kwargs self.rfile = None self.lock = threading.Lock() @property def width(self): """Width of the band images.""" return self.kwargs['width'] @property def height(self): """Height of the band images.""" return self.kwargs['height'] @property def closed(self): """Check if the file is closed.""" return self.rfile is None or self.rfile.closed def open(self, mode=None): """Open the file.""" mode = mode or self.mode if self.closed: self.rfile = rasterio.open(self.path, mode, **self.kwargs) def close(self): """Close the file.""" with self.lock: if not self.closed: self.rfile.close() def __enter__(self): """Enter method.""" self.open() return self def __exit__(self, exc_type, exc_value, traceback): """Exit method.""" self.close() def __del__(self): """Delete the instance.""" with suppress(IOError, OSError): self.close() @property def colorinterp(self): """Return the color interpretation of the image.""" return self.rfile.colorinterp @colorinterp.setter def colorinterp(self, val): if rasterio.__version__.startswith("0."): # not supported in older versions, set by PHOTOMETRIC tag logger.warning("Rasterio 1.0+ required for setting colorinterp") else: self.rfile.colorinterp = val def write(self, *args, **kwargs): """Write to the file.""" with self.lock: self.open('r+') return self.rfile.write(*args, **kwargs) def build_overviews(self, *args, **kwargs): """Write overviews.""" with self.lock: self.open('r+') return self.rfile.build_overviews(*args, **kwargs) def update_tags(self, *args, **kwargs): """Update tags.""" with self.lock: self.open('a') return self.rfile.update_tags(*args, **kwargs) class RIOTag: """Rasterio wrapper to allow da.store on tag.""" def __init__(self, rfile, name): """Init the rasterio tag.""" self.rfile = rfile self.name = name def __setitem__(self, key, item): """Put the data in the tag.""" kwargs = {self.name: item.item()} self.rfile.update_tags(**kwargs) def close(self): """Close the file.""" return self.rfile.close() class RIODataset: """A wrapper for a rasterio dataset.""" def __init__(self, rfile, overviews=None, overviews_resampling=None, overviews_minsize=256): """Init the rasterio dataset.""" self.rfile = rfile self.overviews = overviews if overviews_resampling is None: overviews_resampling = 'nearest' self.overviews_resampling = Resampling[overviews_resampling] self.overviews_minsize = overviews_minsize def __setitem__(self, key, item): """Put the data chunk in the image.""" if len(key) == 3: indexes = list(range( key[0].start + 1, key[0].stop + 1, key[0].step or 1 )) y = key[1] x = key[2] else: indexes = 1 y = key[0] x = key[1] chy_off = y.start chy = y.stop - y.start chx_off = x.start chx = x.stop - x.start # band indexes self.rfile.write(item, window=Window(chx_off, chy_off, chx, chy), indexes=indexes) def close(self): """Close the file.""" if self.overviews is not None: overviews = self.overviews # it's an empty list if len(overviews) == 0: from rasterio.rio.overview import get_maximum_overview_level width = self.rfile.width height = self.rfile.height max_level = get_maximum_overview_level( width, height, self.overviews_minsize) overviews = [2 ** j for j in range(1, max_level + 1)] logger.debug('Building overviews %s with %s resampling', str(overviews), self.overviews_resampling.name) self.rfile.build_overviews(overviews, resampling=self.overviews_resampling) return self.rfile.close() def color_interp(data): """Get the color interpretation for this image.""" from rasterio.enums import ColorInterp as ci modes = {'L': [ci.gray], 'LA': [ci.gray, ci.alpha], 'YCbCr': [ci.Y, ci.Cb, ci.Cr], 'YCbCrA': [ci.Y, ci.Cb, ci.Cr, ci.alpha]} try: mode = ''.join(data['bands'].values) return modes[mode] except KeyError: colors = {'R': ci.red, 'G': ci.green, 'B': ci.blue, 'A': ci.alpha, 'C': ci.cyan, 'M': ci.magenta, 'Y': ci.yellow, 'H': ci.hue, 'S': ci.saturation, 'L': ci.lightness, 'K': ci.black, } return [colors[band] for band in data['bands'].values] trollimage-1.28.0/trollimage/colormap.py000066400000000000000000001410151514066130000202640ustar00rootroot00000000000000"""A simple colormap module.""" import contextlib import copy import os from io import StringIO from typing import Optional import warnings from numbers import Number import pathlib import sys import numpy as np from trollimage.colorspaces import rgb2lch, lch2rgb @contextlib.contextmanager def _file_or_stringio(filename_or_none): if filename_or_none is None: yield StringIO() else: with open(filename_or_none, "w") as file_obj: yield file_obj def colorize(arr, colors, values): """Colorize a monochromatic array *arr*, based *colors* given for *values*. Args: arr (numpy array, numpy masked array, dask array): Data to be mapped to the colors in the colors array using values as control points. Data can be any shape, but must represent a single (luminance) band of data (not RGB or any other colorspace). colors (numpy array): Colors to map the data to. Colors can be RGB or RGBA in the 0 to 1 range. The array should be in the shape (N, 3 or 4) where N is the size of the colormap (the number of colors) and the last dimension is the band dimension where each element represents Red (R), Green (G), Blue (B), and optionally Alpha (A). values (numpy array): Control points mapping input data values to the colors to be mapped to. Should be one dimension and the same number of elements as the ``colors`` array has colors (N). Returns: Resulting RGB/A array with the shape (3 or 4, ...) where the first dimension is 3 if the colors array was RGB and 4 if the colors array was RGBA. The remaining shape of the result matches the provided ``data`` input shape. Like ``colors`` the color values will be between 0 and 1. """ if can_be_block_mapped(arr): return _colorize_dask(arr, colors, values) else: return _colorize(arr, colors, values) def can_be_block_mapped(data): """Check if the array can be processed in chunks.""" return hasattr(data, 'map_blocks') def _colorize_dask(dask_array, colors, values): """Colorize a dask array. The channels are stacked on the first dimension. """ return dask_array.map_blocks(_colorize, colors, values, dtype=colors.dtype, new_axis=0, chunks=[colors.shape[1]] + list(dask_array.chunks)) def _colorize(arr, colors, values): """Colorize the array.""" channels = _interpolate_rgb_colors(arr, colors, values) alpha = _interpolate_alpha(arr, colors, values) channels.extend(alpha) channels = _mask_channels(channels, arr) return np.stack(channels, axis=0) def _interpolate_rgb_colors(arr, colors, values): interp_xp_coords = np.array(values) interp_y_coords = rgb2lch(colors) if values[0] > values[-1]: # monotonically decreasing interp_xp_coords = interp_xp_coords[::-1] interp_y_coords = interp_y_coords[::-1] # Make sure hue (radians) are consistently increasing or decreasing interp_lch = np.zeros(arr.shape + (3,), dtype=interp_y_coords.dtype) interp_lch[..., 0] = np.interp(arr, interp_xp_coords, interp_y_coords[..., 0]) interp_lch[..., 1] = np.interp(arr, interp_xp_coords, interp_y_coords[..., 1]) interp_y_coords[..., 2] = np.unwrap(interp_y_coords[..., 2]) interp_lch[..., 2] = np.interp(arr, interp_xp_coords, interp_y_coords[..., 2]) interp_lch[..., 2] = _ununwrap(interp_lch[..., 2]) new_rgb = lch2rgb(interp_lch) return [new_rgb[..., 0], new_rgb[..., 1], new_rgb[..., 2]] def _ununwrap(input_radians): """Undo the operations performed by numpy unwrap. Taken from https://stackoverflow.com/a/15927914/433202 """ return (input_radians + np.pi) % (2 * np.pi) - np.pi def _interpolate_alpha(arr, colors, values): alpha = [np.interp(arr, np.array(values), np.array(colors)[:, i + 3]) for i in range(np.array(colors).shape[1] - 3)] return alpha def _mask_channels(channels, arr): """Mask the channels if arr is a masked array.""" return [_mask_array(channel, arr) for channel in channels] def _mask_array(new_array, arr): """Mask new_array with the mask from array.""" try: return np.ma.array(new_array, mask=arr.mask) except AttributeError: return new_array def palettize(arr, colors, values): """Apply *colors* to *data* from start *values*. Args: arr (numpy array, numpy masked array, dask array): data to be palettized. colors (numpy array): the colors to use (R, G, B) values (numpy array): the values corresponding to the colors in the array """ if can_be_block_mapped(arr): return _palettize_dask(arr, colors, values), tuple(colors) else: return _palettize(arr, values), tuple(colors) def _palettize_dask(darr, colors, values): """Apply a palette to a dask array.""" return darr.map_blocks(_palettize, values, dtype=int) def _palettize(arr, values): """Apply palette to array.""" new_arr = _digitize_array(arr, values) reshaped_array = new_arr.reshape(arr.shape) return _mask_array(reshaped_array, arr) def _digitize_array(arr, values): if values[0] <= values[-1]: # monotonic increasing values outside_range_bin = max(np.nanmax(arr), values.max()) + np.int64(1) right = False else: # monotonic decreasing values outside_range_bin = min(np.nanmin(arr), values.min()) - np.int64(1) right = True bins = np.concatenate((values, [outside_range_bin])) new_arr = np.digitize(arr.ravel(), bins, right=right) new_arr -= 1 new_arr = new_arr.clip(min=0, max=len(values) - 1) return new_arr class Colormap(object): """The colormap object. Args: *args: Series of (value, color) tuples. These positional arguments are only used if the ``values`` and ``colors`` keyword arguments aren't provided. values: One dimensional array-like of control points where each corresponding color is applied. Must be the same number of elements as colors and must be monotonic. colors: Two dimensional array-like of RGB or RGBA colors where each color is applied to a specific control point. Must be the same number of colors as control points (values). Colors should be floating point numbers between 0 and 1. Initialize with tuples of (value, (colors)), like this:: Colormap((-75.0, (1.0, 1.0, 0.0)), (-40.0001, (0.0, 1.0, 1.0)), (-40.0, (1, 1, 1)), (30.0, (0, 0, 0))) You can also concatenate colormaps together, try:: cm = cm1 + cm2 """ def __init__(self, *tuples, **kwargs): """Set up the instance.""" if 'colors' in kwargs and 'values' in kwargs: values = kwargs['values'] colors = kwargs['colors'] elif 'colors' in kwargs or 'values' in kwargs: raise ValueError("Both 'colors' and 'values' must be provided.") else: values = [a for (a, b) in tuples] colors = [b for (a, b) in tuples] self.values = np.array(values) self.colors = self._validate_colors(colors) if self.values.shape[0] != self.colors.shape[0]: raise ValueError("'values' and 'colors' should have the same " "number of elements. Got " f"{self.values.shape[0]} and {self.colors.shape[0]}.") def _validate_colors(self, colors): colors = np.asarray(colors) if colors.ndim != 2 or colors.shape[-1] not in (3, 4): raise ValueError("Colormap 'colors' must be RGB or RGBA. Got unexpected shape: {}".format(colors.shape)) if not np.issubdtype(colors.dtype, np.floating): warnings.warn("Colormap 'colors' should be floating point numbers between 0 and 1.", stacklevel=3) colors = colors.astype(np.float64) return colors def colorize(self, data): """Colorize a monochromatic array *data*, based on the current colormap.""" return colorize(data, self.colors, self.values) def palettize(self, data): """Palettize a monochromatic array *data* based on the current colormap.""" return palettize(data, self.colors, self.values) def to_rgb(self): """Return colormap with RGB colors. If already RGB then the same instance is returned. If an Alpha channel exists in the colormap, it is dropped. """ if self.colors.shape[-1] == 3: return self values = self.values.copy() colors = self.colors.copy() return Colormap( values=values, colors=colors[:, :3] ) def to_rgba(self): """Return colormap with RGBA colors. If already RGBA then the same instance is returned. If not already RGBA, a completely opaque (1.0) color """ if self.colors.shape[-1] == 4: return self values = self.values.copy() colors = np.empty((self.colors.shape[0], 4), dtype=self.colors.dtype) colors[:, :3] = self.colors colors[:, 3] = 1.0 return Colormap( values=values, colors=colors ) def __add__(self, other): """Append colormap together.""" old, other = self._normalize_color_arrays(self, other) values = np.concatenate((old.values, other.values)) if not self._monotonic_one_direction(values): raise ValueError("Merged colormap 'values' are not monotonically " "increasing, monotonically decreasing, or equal.") colors = np.concatenate((old.colors, other.colors)) return Colormap( values=values, colors=colors, ) @staticmethod def _monotonic_one_direction(values): delta = np.diff(values) all_increasing = (delta >= 0).all() all_decreasing = (delta <= 0).all() return all_increasing or all_decreasing @staticmethod def _normalize_color_arrays(cmap1, cmap2): num_bands1 = cmap1.colors.shape[-1] num_bands2 = cmap2.colors.shape[-1] if num_bands1 == num_bands2: return cmap1, cmap2 return cmap1.to_rgba(), cmap2.to_rgba() def reverse(self, inplace=True): """Reverse the current colormap in place. Args: inplace (bool): If True (default), modify the colors of this Colormap inplace. If False, return a new instance. """ colors = np.flipud(self.colors) if not inplace: return Colormap( values=self.values.copy(), colors=colors ) self.colors = colors return self def set_range(self, min_val, max_val, inplace=True): """Set the range of the colormap to [*min_val*, *max_val*]. The Colormap's values will match the range specified even if "min_val" is greater than "max_val". To flip the order of the colors, use :meth:`reversed`. Args: min_val (float): New minimum value for the control points in this colormap. max_val (float): New maximum value for the control points in this colormap. inplace (bool): If True (default), modify the values inplace. If False, return a new Colormap instance. """ cmap = self values = (((cmap.values * 1.0 - cmap.values[0]) / (cmap.values[-1] - cmap.values[0])) * (max_val - min_val) + min_val) if not inplace: return Colormap( values=values, colors=cmap.colors.copy() ) cmap.values = values return cmap def set_alpha_range(self, min_alpha, max_alpha, inplace=True): """Set the colormap alpha channel between two values in linear steps. If the input colormap does not have an alpha channel, it will be added to it. If an alpha channel is already existing, the values will be overwritten. The min and max values shall be between 0 (completely transparent) and 1 (completely opaque). Args: min_alpha (float): Start value of the alpha channel [0-1] max_alpha (float): End value of the alpha channel [0-1] inplace (bool): If True (default), modify the values inplace. If False, return a new Colormap instance. """ if inplace: cmap = self else: cmap = Colormap( values=self.values.copy(), colors=self.colors.copy()) alpha = np.linspace(min_alpha, max_alpha, self.colors.shape[0]) if cmap.colors.shape[1] == 4: cmap.colors[:, 3] = alpha else: cmap.colors = np.column_stack((cmap.colors, alpha)) return cmap def to_rio(self): """Convert the colormap to a rasterio colormap. Note that rasterio requires color tables to have round integer value control points. This method assumes that the range of this Colormap is already in the desired output range and to avoid issues with rasterio will round the values and convert them to unsigned integers. """ colors = (((self.colors * 1.0 - self.colors.min()) / (self.colors.max() - self.colors.min())) * 255) # rasterio doesn't allow non-integer colormap values values = np.round(self.values).astype(np.uint) return dict(zip(values, tuple(map(tuple, colors)))) def to_csv( self, filename: Optional[str] = None, color_scale: Number = 255, ) -> Optional[str]: """Save Colormap to a comma-separated text file or string. The CSV data will have 4 to 5 columns for each row where each each row will contain the value (V), red (R), green (B), blue (B), and if configured alpha (A). The values will remain in whatever range is currently set on the colormap. The colors of the colormap (assumed to be between 0 and 1) will be multiplied by 255 to produce a traditional unsigned 8-bit integer value. Args: filename: The filename of the CSV file to save to. If not provided or None a string is returned with the contents. color_scale: Scale colors by this factor before converting to a CSV. Colors are stored in the Colormap in a 0 to 1 range. Defaults to 255. If not equal to 1 values are converted to integers too. """ with _file_or_stringio(filename) as csv_file: for value, color in zip(self.values, self.colors): scaled_color = [x * color_scale for x in color] if color_scale != 1.0: scaled_color = [int(x) for x in scaled_color] csv_file.write(",".join(["{:0.6f}".format(value)] + [str(x) for x in scaled_color]) + "\n") if isinstance(csv_file, StringIO): return csv_file.getvalue() @classmethod def from_file( cls, filename: str, colormap_mode: Optional[str] = None, color_scale: Number = 255, ): """Create Colormap from a comma-separated or binary file of colormap data. Args: filename: Filename of a binary or CSV file colormap_mode: Force the scheme of the colormap data (ex. RGBA). See information below on other possible values and how they are interpreted. By default this is determined based on the number of columns in the data. color_scale: The maximum possible color value in the colormap data provided. For example, if the colors in the provided data were 8-bit unsigned integers this should be 255 (the default). This value will be used to normalize the colors from 0 to 1. Colormaps can be loaded from ``.npy``, ``.npz``, or comma-separated text files. Numpy (npy/npz) files should be 2D arrays with rows for each color. Comma-separated files should have a row for each color with each column representing a single value/channel. A filename ending with ``.npy`` or ``.npz`` is read as a numpy file with :func:`numpy.load`. All other extensions are read as a comma-separated file. For ``.npz`` files the data must be stored as a positional list where the first element represents the colormap to use. See :func:`numpy.savez` for more information. The colormap is interpreted as 1 of 4 different "colormap modes": ``RGB``, ``RGBA``, ``VRGB``, or ``VRGBA``. The colormap mode can be forced with the ``colormap_mode`` keyword argument. If it is not provided then a default will be chosen based on the number of columns in the array (3: RGB, 4: VRGB, 5: VRGBA). The "V" in the possible colormap modes represents the control value of where that color should be applied. If "V" is not provided in the colormap data it defaults to the row index in the colormap array (0, 1, 2, ...) divided by the total number of colors to produce a number between 0 and 1. See the "Set Range" section below for more information. The remaining elements in the colormap array represent the Red (R), Green (G), and Blue (B) color to be mapped to. See the "Color Scale" section below for more information on the value range of provided numbers. To read from a string containing CSV, use :meth:`~Colormap.from_csv`. To get a named colormap, use :meth:`~Colormap.from_name` or load the colormap directly as a module attribute. To get a colormap from an ndarray, use :meth:`~Colormap.from_ndarray`. **Color Scale** By default colors are expected to be in a 0-255 range. This can be overridden by specifying ``color_scale`` keyword argument. A common alternative to 255 is ``1`` to specify floating point numbers between 0 and 1. The resulting Colormap uses the normalized color values (0-1). """ if _is_actually_a_csv_string(filename): warnings.warn( "Passing a data string to Colormap.from_file is deprecated. " "Please use Colormap.from_string.", category=DeprecationWarning, stacklevel=2, ) return cls.from_string(filename, colormap_mode, color_scale) values, colors = _get_values_colors_from_file(filename, colormap_mode, color_scale) return cls(values=values, colors=colors) @classmethod def from_string(cls, string, *args, **kwargs): """Create colormap from string. Create a colormap from a string that contains comma seperated values (CSV). To read from an external file that contains CSV, use :meth:`from_csv`. Args: string (str): String containing CSV. Must have no less than three and no more than five columns and describe entirely numeric data. colormap_mode (str or None): Optional. Can be None, "RGB", "RGBA", "VRGB", or "VRGBA". If None (default), this is inferred from the dimensions of the data contained in the CSV. Modes starting with V have in the first column the values to which the color relates. color_scale (number): The value that represents white in the numbers describing the colors. Defaults to 255, could also be 1 or something else. """ openfile = StringIO(string) cmap_data = _read_colormap_data_from_file(openfile) return cls.from_ndarray(cmap_data, *args, **kwargs) @classmethod def from_np(cls, path, *args, **kwargs): """Create Colormap from a numpy-file. Create a colormap from a numpy data file ``.npy`` or ``.npz``. The data should contain at least three and at most five columns. Args: path (str or Pathlib.Path): Path to file containing numpy data. colormap_mode (str or None): Optional. Can be None, "RGB", "RGBA", "VRGB", or "VRGBA". If None (default), this is inferred from the dimensions of the data contained in the CSV. Modes starting with V have in the first column the values to which the color relates. color_scale (number): The value that represents white in the numbers describing the colors. Defaults to 255, could also be 1 or something else. """ cmap_data = _read_colormap_data_from_np(path) return cls.from_ndarray(cmap_data, *args, **kwargs) @classmethod def from_csv(cls, path, colormap_mode=None, color_scale=255): """Create Colormap from CSV file. Create a Colormap from a file that contains comma seperated values (CSV). To read from a string that contains CSV, use :meth:`from_string`. Args: string (str or pathlib.Path): Path to file containing CSV. The CSV must have at least three and at most five columns and describe entirely numeric data. colormap_mode (str or None): Optional. Can be None, "RGB", "RGBA", "VRGB", or "VRGBA". If None (default), this is inferred from the dimensions of the data contained in the CSV. Modes starting with V have in the first column the values to which the color relates. color_scale (number): The value that represents white in the numbers describing the colors. Defaults to 255, could also be 1 or something else. """ cmap_data = np.loadtxt(path, delimiter=",") return cls.from_ndarray(cmap_data, colormap_mode, color_scale) @classmethod def from_ndarray(cls, cmap_data, colormap_mode=None, color_scale=255): """Create Colormap from ndarray. Create a colormap from a numpy data array. The data should contain at least three and at most five columns. For historical reasons, this method exists alongside :meth:`from_sequence_of_colors` and :meth:`from_array_with_metadata` despite similar functionality. Args: cmap_data (ndarray): Array describing the colours. Must have at least three and at most five columns and have a numeric dtype. colormap_mode (str or None): Optional. Can be None, "RGB", "RGBA", "VRGB", or "VRGBA". If None (default), this is inferred from the dimensions of the data contained in the CSV. Modes starting with V have in the first column the values to which the color relates. color_scale (number): The value that represents white in the numbers describing the colors. Defaults to 255, could also be 1 or something else. """ values, colors = _get_values_colors_from_ndarray(cmap_data, colormap_mode, color_scale) return cls(values=values, colors=colors) @classmethod def from_name(cls, name): """Return named colormap. Return a colormap by name. Supported colormaps are the ones defined in the module namespace. Args: name (str): Name of colormap. """ cmap = getattr(sys.modules[__name__], name) return copy.copy(cmap) @classmethod def from_sequence_of_colors(cls, colors, values=None, color_scale=255): """Create Colormap from sequence of colors. Create a colormap from a sequence of colors, such as a list of colors. If values is not given, assume values between 0 and 1, linearly spaced according to the total number of colors. For historical reasons, this method exists alongside :meth:`from_ndarray` and :meth:`from_array_with_metadata` despite similar functionality. Args: colors (Sequence): List of colors, where each element must itself be a sequence of 3 or 4 numbers (RGB or RGBA). values (array, optional): Values associated with the colors. If not given, assume linear between 0 and 1. color_scale (number): The value that represents white in the numbers describing the colors. Defaults to 255, could also be 1 or something else. """ # this method was moved from satpy. where it was in # satpy.enhancements.create_colormap # then it was refactored/rewritten color_array = np.array(colors) if values is None: values = np.linspace(0, 1, len(colors)) else: values = np.asarray(values) color_array = np.concatenate((values[:, np.newaxis], color_array), axis=1) return cls.from_ndarray( color_array, "VRGB" if color_array.shape[1] == 4 else "VRGBA", color_scale=color_scale) @classmethod def from_array_with_metadata( cls, palette, dtype, color_scale=255, valid_range=None, scale_factor=1, add_offset=0, remove_last=True): """Create Colormap from an array with metadata. Create a colormap from an array with associated metadata, either in attributes or passed on to the function. For historical reasons, this method exists alongside :meth:`from_ndarray` and :meth:`from_sequence_of_colors` despite similar functionality. If ``palette`` is an xarray dataarray with the attribute ``palette_meanings``, those meanings are interpreted as values associated with the colormap. If no values can be interpreted from the metadata, values will be linearly interpolated between 0 and 255 (if ``dtype`` is ``np.uint8``) or according to ``valid_range``. Args: palette (ndarray or xarray.DataArray) Array describing colors, possibly with metadata. If it has a ``palette_meanings`` attribute, this will be used for color interpretation. dtype dtype for the colormap color_scale (number): The value that represents white in the numbers describing the colors. Defaults to 255, could also be 1 or something else. valid_range valid range for colors, if colormap is not of dtype uint8 scale_factor scale factor to apply to the colormap add_offset add offset to apply to the colormap remove_last Remove the last value if the array has no metadata associated. Defaults to true for historical reasons. """ # this method was moved from satpy, where it was in # satpy.composites.ColormapCompositor.build_colormap # # then it was refactored/rewritten for trollimage squeezed_palette = np.asanyarray(palette).squeeze() set_range = True if hasattr(palette, 'attrs') and 'palette_meanings' in palette.attrs: set_range = False values = np.asarray(palette.attrs['palette_meanings']) else: # remove the last value because monkeys don't like water sprays # on a more serious note, I don't know why we are removing the last # value here, but this behaviour was copied from ancient satpy code values = np.arange(squeezed_palette.shape[0] - remove_last) if remove_last: squeezed_palette = squeezed_palette[:-remove_last, :] color_array = np.concatenate((values[:, np.newaxis], squeezed_palette), axis=1) colormap = cls.from_ndarray( color_array, "VRGB" if color_array.shape[1] == 4 else "VRGBA", color_scale=color_scale) if dtype == np.dtype("uint8"): return colormap if valid_range is not None: if set_range: colormap.set_range( *(np.array(valid_range) * scale_factor + add_offset)) return colormap raise AttributeError("Data need to have either a valid_range or be of type uint8" + " in order to be displayable with an attached color-palette!") def _is_actually_a_csv_string(string): """Try to guess whether this string contains CSV.""" return string.count("\n") > 0 and string.count(",") > 0 def _get_values_colors_from_file(filename, colormap_mode, color_scale): data = _read_colormap_data_from_file(filename) return _get_values_colors_from_ndarray(data, colormap_mode, color_scale) def _get_values_colors_from_ndarray(data, colormap_mode, color_scale): cols = data.shape[1] default_modes = { 3: 'RGB', 4: 'VRGB', 5: 'VRGBA' } default_mode = default_modes.get(cols) if colormap_mode is None: colormap_mode = default_mode if colormap_mode is None or len(colormap_mode) != cols: raise ValueError( "Unexpected colormap shape for mode '{}'".format(colormap_mode)) rows = data.shape[0] if colormap_mode[0] == 'V': colors = data[:, 1:] if color_scale != 1: colors = data[:, 1:] / float(color_scale) values = data[:, 0] else: colors = data if color_scale != 1: colors = colors / float(color_scale) values = np.arange(rows) / float(rows - 1) return values, colors def _read_colormap_data_from_file(filename_or_file_obj): if isinstance(filename_or_file_obj, str): ext = os.path.splitext(filename_or_file_obj)[1] if ext in (".npy", ".npz"): return _read_colormap_data_from_np(filename_or_file_obj) # CSV file or file-like object of CSV string data return np.loadtxt(filename_or_file_obj, delimiter=",") def _read_colormap_data_from_np(path): path = pathlib.Path(path) file_content = np.load(path) if path.suffix == ".npz": # .npz is a collection # assume position list-like and get the first element file_content = file_content["arr_0"] return file_content # matlab jet "#00007F", "blue", "#007FFF", "cyan", "#7FFF7F", "yellow", # "#FF7F00", "red", "#7F0000" rainbow = Colormap((0.000, (0.0, 0.0, 0.5)), (0.125, (0.0, 0.0, 1.0)), (0.250, (0.0, 0.5, 1.0)), (0.375, (0.0, 1.0, 1.0)), (0.500, (0.5, 1.0, 0.5)), (0.625, (1.0, 1.0, 0.0)), (0.750, (1.0, 0.5, 0.0)), (0.875, (1.0, 0.0, 0.0)), (1.000, (0.5, 0.0, 0.0))) # * Colors from www.ColorBrewer.org by Cynthia A. Brewer, Geography, # * Pennsylvania State University. # * Sequential Colormaps * blues = Colormap( (0 / 8, (247 / 255, 251 / 255, 255 / 255)), (1 / 8, (222 / 255, 235 / 255, 247 / 255)), (2 / 8, (198 / 255, 219 / 255, 239 / 255)), (3 / 8, (158 / 255, 202 / 255, 225 / 255)), (4 / 8, (107 / 255, 174 / 255, 214 / 255)), (5 / 8, (66 / 255, 146 / 255, 198 / 255)), (6 / 8, (33 / 255, 113 / 255, 181 / 255)), (7 / 8, (8 / 255, 81 / 255, 156 / 255)), (8 / 8, (8 / 255, 48 / 255, 107 / 255)), ) bugn = Colormap( (0 / 8, (247 / 255, 252 / 255, 253 / 255)), (1 / 8, (229 / 255, 245 / 255, 249 / 255)), (2 / 8, (204 / 255, 236 / 255, 230 / 255)), (3 / 8, (153 / 255, 216 / 255, 201 / 255)), (4 / 8, (102 / 255, 194 / 255, 164 / 255)), (5 / 8, (65 / 255, 174 / 255, 118 / 255)), (6 / 8, (35 / 255, 139 / 255, 69 / 255)), (7 / 8, (0 / 255, 109 / 255, 44 / 255)), (8 / 8, (0 / 255, 68 / 255, 27 / 255)), ) bupu = Colormap( (0 / 8, (247 / 255, 252 / 255, 253 / 255)), (1 / 8, (224 / 255, 236 / 255, 244 / 255)), (2 / 8, (191 / 255, 211 / 255, 230 / 255)), (3 / 8, (158 / 255, 188 / 255, 218 / 255)), (4 / 8, (140 / 255, 150 / 255, 198 / 255)), (5 / 8, (140 / 255, 107 / 255, 177 / 255)), (6 / 8, (136 / 255, 65 / 255, 157 / 255)), (7 / 8, (129 / 255, 15 / 255, 124 / 255)), (8 / 8, (77 / 255, 0 / 255, 75 / 255)), ) gnbu = Colormap( (0 / 8, (247 / 255, 252 / 255, 240 / 255)), (1 / 8, (224 / 255, 243 / 255, 219 / 255)), (2 / 8, (204 / 255, 235 / 255, 197 / 255)), (3 / 8, (168 / 255, 221 / 255, 181 / 255)), (4 / 8, (123 / 255, 204 / 255, 196 / 255)), (5 / 8, (78 / 255, 179 / 255, 211 / 255)), (6 / 8, (43 / 255, 140 / 255, 190 / 255)), (7 / 8, (8 / 255, 104 / 255, 172 / 255)), (8 / 8, (8 / 255, 64 / 255, 129 / 255)), ) greens = Colormap( (0 / 8, (247 / 255, 252 / 255, 245 / 255)), (1 / 8, (229 / 255, 245 / 255, 224 / 255)), (2 / 8, (199 / 255, 233 / 255, 192 / 255)), (3 / 8, (161 / 255, 217 / 255, 155 / 255)), (4 / 8, (116 / 255, 196 / 255, 118 / 255)), (5 / 8, (65 / 255, 171 / 255, 93 / 255)), (6 / 8, (35 / 255, 139 / 255, 69 / 255)), (7 / 8, (0 / 255, 109 / 255, 44 / 255)), (8 / 8, (0 / 255, 68 / 255, 27 / 255)), ) greys = Colormap( (0 / 8, (255 / 255, 255 / 255, 255 / 255)), (1 / 8, (240 / 255, 240 / 255, 240 / 255)), (2 / 8, (217 / 255, 217 / 255, 217 / 255)), (3 / 8, (189 / 255, 189 / 255, 189 / 255)), (4 / 8, (150 / 255, 150 / 255, 150 / 255)), (5 / 8, (115 / 255, 115 / 255, 115 / 255)), (6 / 8, (82 / 255, 82 / 255, 82 / 255)), (7 / 8, (37 / 255, 37 / 255, 37 / 255)), (8 / 8, (0 / 255, 0 / 255, 0 / 255)), ) oranges = Colormap( (0 / 8, (255 / 255, 245 / 255, 235 / 255)), (1 / 8, (254 / 255, 230 / 255, 206 / 255)), (2 / 8, (253 / 255, 208 / 255, 162 / 255)), (3 / 8, (253 / 255, 174 / 255, 107 / 255)), (4 / 8, (253 / 255, 141 / 255, 60 / 255)), (5 / 8, (241 / 255, 105 / 255, 19 / 255)), (6 / 8, (217 / 255, 72 / 255, 1 / 255)), (7 / 8, (166 / 255, 54 / 255, 3 / 255)), (8 / 8, (127 / 255, 39 / 255, 4 / 255)), ) orrd = Colormap( (0 / 8, (255 / 255, 247 / 255, 236 / 255)), (1 / 8, (254 / 255, 232 / 255, 200 / 255)), (2 / 8, (253 / 255, 212 / 255, 158 / 255)), (3 / 8, (253 / 255, 187 / 255, 132 / 255)), (4 / 8, (252 / 255, 141 / 255, 89 / 255)), (5 / 8, (239 / 255, 101 / 255, 72 / 255)), (6 / 8, (215 / 255, 48 / 255, 31 / 255)), (7 / 8, (179 / 255, 0 / 255, 0 / 255)), (8 / 8, (127 / 255, 0 / 255, 0 / 255)), ) pubu = Colormap( (0 / 8, (255 / 255, 247 / 255, 251 / 255)), (1 / 8, (236 / 255, 231 / 255, 242 / 255)), (2 / 8, (208 / 255, 209 / 255, 230 / 255)), (3 / 8, (166 / 255, 189 / 255, 219 / 255)), (4 / 8, (116 / 255, 169 / 255, 207 / 255)), (5 / 8, (54 / 255, 144 / 255, 192 / 255)), (6 / 8, (5 / 255, 112 / 255, 176 / 255)), (7 / 8, (4 / 255, 90 / 255, 141 / 255)), (8 / 8, (2 / 255, 56 / 255, 88 / 255)), ) pubugn = Colormap( (0 / 8, (255 / 255, 247 / 255, 251 / 255)), (1 / 8, (236 / 255, 226 / 255, 240 / 255)), (2 / 8, (208 / 255, 209 / 255, 230 / 255)), (3 / 8, (166 / 255, 189 / 255, 219 / 255)), (4 / 8, (103 / 255, 169 / 255, 207 / 255)), (5 / 8, (54 / 255, 144 / 255, 192 / 255)), (6 / 8, (2 / 255, 129 / 255, 138 / 255)), (7 / 8, (1 / 255, 108 / 255, 89 / 255)), (8 / 8, (1 / 255, 70 / 255, 54 / 255)), ) purd = Colormap( (0 / 8, (247 / 255, 244 / 255, 249 / 255)), (1 / 8, (231 / 255, 225 / 255, 239 / 255)), (2 / 8, (212 / 255, 185 / 255, 218 / 255)), (3 / 8, (201 / 255, 148 / 255, 199 / 255)), (4 / 8, (223 / 255, 101 / 255, 176 / 255)), (5 / 8, (231 / 255, 41 / 255, 138 / 255)), (6 / 8, (206 / 255, 18 / 255, 86 / 255)), (7 / 8, (152 / 255, 0 / 255, 67 / 255)), (8 / 8, (103 / 255, 0 / 255, 31 / 255)), ) purples = Colormap( (0 / 8, (252 / 255, 251 / 255, 253 / 255)), (1 / 8, (239 / 255, 237 / 255, 245 / 255)), (2 / 8, (218 / 255, 218 / 255, 235 / 255)), (3 / 8, (188 / 255, 189 / 255, 220 / 255)), (4 / 8, (158 / 255, 154 / 255, 200 / 255)), (5 / 8, (128 / 255, 125 / 255, 186 / 255)), (6 / 8, (106 / 255, 81 / 255, 163 / 255)), (7 / 8, (84 / 255, 39 / 255, 143 / 255)), (8 / 8, (63 / 255, 0 / 255, 125 / 255)), ) rdpu = Colormap( (0 / 8, (255 / 255, 247 / 255, 243 / 255)), (1 / 8, (253 / 255, 224 / 255, 221 / 255)), (2 / 8, (252 / 255, 197 / 255, 192 / 255)), (3 / 8, (250 / 255, 159 / 255, 181 / 255)), (4 / 8, (247 / 255, 104 / 255, 161 / 255)), (5 / 8, (221 / 255, 52 / 255, 151 / 255)), (6 / 8, (174 / 255, 1 / 255, 126 / 255)), (7 / 8, (122 / 255, 1 / 255, 119 / 255)), (8 / 8, (73 / 255, 0 / 255, 106 / 255)), ) reds = Colormap( (0 / 8, (255 / 255, 245 / 255, 240 / 255)), (1 / 8, (254 / 255, 224 / 255, 210 / 255)), (2 / 8, (252 / 255, 187 / 255, 161 / 255)), (3 / 8, (252 / 255, 146 / 255, 114 / 255)), (4 / 8, (251 / 255, 106 / 255, 74 / 255)), (5 / 8, (239 / 255, 59 / 255, 44 / 255)), (6 / 8, (203 / 255, 24 / 255, 29 / 255)), (7 / 8, (165 / 255, 15 / 255, 21 / 255)), (8 / 8, (103 / 255, 0 / 255, 13 / 255)), ) ylgn = Colormap( (0 / 8, (255 / 255, 255 / 255, 229 / 255)), (1 / 8, (247 / 255, 252 / 255, 185 / 255)), (2 / 8, (217 / 255, 240 / 255, 163 / 255)), (3 / 8, (173 / 255, 221 / 255, 142 / 255)), (4 / 8, (120 / 255, 198 / 255, 121 / 255)), (5 / 8, (65 / 255, 171 / 255, 93 / 255)), (6 / 8, (35 / 255, 132 / 255, 67 / 255)), (7 / 8, (0 / 255, 104 / 255, 55 / 255)), (8 / 8, (0 / 255, 69 / 255, 41 / 255)), ) ylgnbu = Colormap( (0 / 8, (255 / 255, 255 / 255, 217 / 255)), (1 / 8, (237 / 255, 248 / 255, 177 / 255)), (2 / 8, (199 / 255, 233 / 255, 180 / 255)), (3 / 8, (127 / 255, 205 / 255, 187 / 255)), (4 / 8, (65 / 255, 182 / 255, 196 / 255)), (5 / 8, (29 / 255, 145 / 255, 192 / 255)), (6 / 8, (34 / 255, 94 / 255, 168 / 255)), (7 / 8, (37 / 255, 52 / 255, 148 / 255)), (8 / 8, (8 / 255, 29 / 255, 88 / 255)), ) ylorbr = Colormap( (0 / 8, (255 / 255, 255 / 255, 229 / 255)), (1 / 8, (255 / 255, 247 / 255, 188 / 255)), (2 / 8, (254 / 255, 227 / 255, 145 / 255)), (3 / 8, (254 / 255, 196 / 255, 79 / 255)), (4 / 8, (254 / 255, 153 / 255, 41 / 255)), (5 / 8, (236 / 255, 112 / 255, 20 / 255)), (6 / 8, (204 / 255, 76 / 255, 2 / 255)), (7 / 8, (153 / 255, 52 / 255, 4 / 255)), (8 / 8, (102 / 255, 37 / 255, 6 / 255)), ) ylorrd = Colormap( (0 / 7, (255 / 255, 255 / 255, 204 / 255)), (1 / 7, (255 / 255, 237 / 255, 160 / 255)), (2 / 7, (254 / 255, 217 / 255, 118 / 255)), (3 / 7, (254 / 255, 178 / 255, 76 / 255)), (4 / 7, (253 / 255, 141 / 255, 60 / 255)), (5 / 7, (252 / 255, 78 / 255, 42 / 255)), (6 / 7, (227 / 255, 26 / 255, 28 / 255)), (7 / 7, (177 / 255, 0 / 255, 38 / 255)), ) sequential_colormaps = { "blues": blues, "bugn": bugn, "bupu": bupu, "gnbu": gnbu, "greens": greens, "greys": greys, "oranges": oranges, "orrd": orrd, "pubu": pubu, "pubugn": pubugn, "purd": purd, "purples": purples, "rdpu": rdpu, "reds": reds, "ylgn": ylgn, "ylgnbu": ylgnbu, "ylorbr": ylorbr, "ylorrd": ylorrd, } # * Diverging Colormaps * brbg = Colormap( (0 / 10, (84 / 255, 48 / 255, 5 / 255)), (1 / 10, (140 / 255, 81 / 255, 10 / 255)), (2 / 10, (191 / 255, 129 / 255, 45 / 255)), (3 / 10, (223 / 255, 194 / 255, 125 / 255)), (4 / 10, (246 / 255, 232 / 255, 195 / 255)), (5 / 10, (245 / 255, 245 / 255, 245 / 255)), (6 / 10, (199 / 255, 234 / 255, 229 / 255)), (7 / 10, (128 / 255, 205 / 255, 193 / 255)), (8 / 10, (53 / 255, 151 / 255, 143 / 255)), (9 / 10, (1 / 255, 102 / 255, 94 / 255)), (10 / 10, (0 / 255, 60 / 255, 48 / 255)), ) piyg = Colormap( (0 / 10, (142 / 255, 1 / 255, 82 / 255)), (1 / 10, (197 / 255, 27 / 255, 125 / 255)), (2 / 10, (222 / 255, 119 / 255, 174 / 255)), (3 / 10, (241 / 255, 182 / 255, 218 / 255)), (4 / 10, (253 / 255, 224 / 255, 239 / 255)), (5 / 10, (247 / 255, 247 / 255, 247 / 255)), (6 / 10, (230 / 255, 245 / 255, 208 / 255)), (7 / 10, (184 / 255, 225 / 255, 134 / 255)), (8 / 10, (127 / 255, 188 / 255, 65 / 255)), (9 / 10, (77 / 255, 146 / 255, 33 / 255)), (10 / 10, (39 / 255, 100 / 255, 25 / 255)), ) prgn = Colormap( (0 / 10, (64 / 255, 0 / 255, 75 / 255)), (1 / 10, (118 / 255, 42 / 255, 131 / 255)), (2 / 10, (153 / 255, 112 / 255, 171 / 255)), (3 / 10, (194 / 255, 165 / 255, 207 / 255)), (4 / 10, (231 / 255, 212 / 255, 232 / 255)), (5 / 10, (247 / 255, 247 / 255, 247 / 255)), (6 / 10, (217 / 255, 240 / 255, 211 / 255)), (7 / 10, (166 / 255, 219 / 255, 160 / 255)), (8 / 10, (90 / 255, 174 / 255, 97 / 255)), (9 / 10, (27 / 255, 120 / 255, 55 / 255)), (10 / 10, (0 / 255, 68 / 255, 27 / 255)), ) puor = Colormap( (0 / 10, (127 / 255, 59 / 255, 8 / 255)), (1 / 10, (179 / 255, 88 / 255, 6 / 255)), (2 / 10, (224 / 255, 130 / 255, 20 / 255)), (3 / 10, (253 / 255, 184 / 255, 99 / 255)), (4 / 10, (254 / 255, 224 / 255, 182 / 255)), (5 / 10, (247 / 255, 247 / 255, 247 / 255)), (6 / 10, (216 / 255, 218 / 255, 235 / 255)), (7 / 10, (178 / 255, 171 / 255, 210 / 255)), (8 / 10, (128 / 255, 115 / 255, 172 / 255)), (9 / 10, (84 / 255, 39 / 255, 136 / 255)), (10 / 10, (45 / 255, 0 / 255, 75 / 255)), ) rdbu = Colormap( (0 / 10, (103 / 255, 0 / 255, 31 / 255)), (1 / 10, (178 / 255, 24 / 255, 43 / 255)), (2 / 10, (214 / 255, 96 / 255, 77 / 255)), (3 / 10, (244 / 255, 165 / 255, 130 / 255)), (4 / 10, (253 / 255, 219 / 255, 199 / 255)), (5 / 10, (247 / 255, 247 / 255, 247 / 255)), (6 / 10, (209 / 255, 229 / 255, 240 / 255)), (7 / 10, (146 / 255, 197 / 255, 222 / 255)), (8 / 10, (67 / 255, 147 / 255, 195 / 255)), (9 / 10, (33 / 255, 102 / 255, 172 / 255)), (10 / 10, (5 / 255, 48 / 255, 97 / 255)), ) rdgy = Colormap( (0 / 10, (103 / 255, 0 / 255, 31 / 255)), (1 / 10, (178 / 255, 24 / 255, 43 / 255)), (2 / 10, (214 / 255, 96 / 255, 77 / 255)), (3 / 10, (244 / 255, 165 / 255, 130 / 255)), (4 / 10, (253 / 255, 219 / 255, 199 / 255)), (5 / 10, (255 / 255, 255 / 255, 255 / 255)), (6 / 10, (224 / 255, 224 / 255, 224 / 255)), (7 / 10, (186 / 255, 186 / 255, 186 / 255)), (8 / 10, (135 / 255, 135 / 255, 135 / 255)), (9 / 10, (77 / 255, 77 / 255, 77 / 255)), (10 / 10, (26 / 255, 26 / 255, 26 / 255)), ) rdylbu = Colormap( (0 / 10, (165 / 255, 0 / 255, 38 / 255)), (1 / 10, (215 / 255, 48 / 255, 39 / 255)), (2 / 10, (244 / 255, 109 / 255, 67 / 255)), (3 / 10, (253 / 255, 174 / 255, 97 / 255)), (4 / 10, (254 / 255, 224 / 255, 144 / 255)), (5 / 10, (255 / 255, 255 / 255, 191 / 255)), (6 / 10, (224 / 255, 243 / 255, 248 / 255)), (7 / 10, (171 / 255, 217 / 255, 233 / 255)), (8 / 10, (116 / 255, 173 / 255, 209 / 255)), (9 / 10, (69 / 255, 117 / 255, 180 / 255)), (10 / 10, (49 / 255, 54 / 255, 149 / 255)), ) rdylgn = Colormap( (0 / 10, (165 / 255, 0 / 255, 38 / 255)), (1 / 10, (215 / 255, 48 / 255, 39 / 255)), (2 / 10, (244 / 255, 109 / 255, 67 / 255)), (3 / 10, (253 / 255, 174 / 255, 97 / 255)), (4 / 10, (254 / 255, 224 / 255, 139 / 255)), (5 / 10, (255 / 255, 255 / 255, 191 / 255)), (6 / 10, (217 / 255, 239 / 255, 139 / 255)), (7 / 10, (166 / 255, 217 / 255, 106 / 255)), (8 / 10, (102 / 255, 189 / 255, 99 / 255)), (9 / 10, (26 / 255, 152 / 255, 80 / 255)), (10 / 10, (0 / 255, 104 / 255, 55 / 255)), ) spectral = Colormap( (0 / 10, (158 / 255, 1 / 255, 66 / 255)), (1 / 10, (213 / 255, 62 / 255, 79 / 255)), (2 / 10, (244 / 255, 109 / 255, 67 / 255)), (3 / 10, (253 / 255, 174 / 255, 97 / 255)), (4 / 10, (254 / 255, 224 / 255, 139 / 255)), (5 / 10, (255 / 255, 255 / 255, 191 / 255)), (6 / 10, (230 / 255, 245 / 255, 152 / 255)), (7 / 10, (171 / 255, 221 / 255, 164 / 255)), (8 / 10, (102 / 255, 194 / 255, 165 / 255)), (9 / 10, (50 / 255, 136 / 255, 189 / 255)), (10 / 10, (94 / 255, 79 / 255, 162 / 255)), ) diverging_colormaps = { "brbg": brbg, "piyg": piyg, "prgn": prgn, "puor": puor, "rdbu": rdbu, "rdgy": rdgy, "rdylbu": rdylbu, "rdylgn": rdylgn, "spectral": spectral, } # * Qualitative Colormaps * accent = Colormap( (0, (127 / 255, 201 / 255, 127 / 255)), (1, (190 / 255, 174 / 255, 212 / 255)), (2, (253 / 255, 192 / 255, 134 / 255)), (3, (255 / 255, 255 / 255, 153 / 255)), (4, (56 / 255, 108 / 255, 176 / 255)), (5, (240 / 255, 2 / 255, 127 / 255)), (6, (191 / 255, 91 / 255, 23 / 255)), (7, (102 / 255, 102 / 255, 102 / 255)), ) dark2 = Colormap( (0, (27 / 255, 158 / 255, 119 / 255)), (1, (217 / 255, 95 / 255, 2 / 255)), (2, (117 / 255, 112 / 255, 179 / 255)), (3, (231 / 255, 41 / 255, 138 / 255)), (4, (102 / 255, 166 / 255, 30 / 255)), (5, (230 / 255, 171 / 255, 2 / 255)), (6, (166 / 255, 118 / 255, 29 / 255)), (7, (102 / 255, 102 / 255, 102 / 255)), ) paired = Colormap( (0, (166 / 255, 206 / 255, 227 / 255)), (1, (31 / 255, 120 / 255, 180 / 255)), (2, (178 / 255, 223 / 255, 138 / 255)), (3, (51 / 255, 160 / 255, 44 / 255)), (4, (251 / 255, 154 / 255, 153 / 255)), (5, (227 / 255, 26 / 255, 28 / 255)), (6, (253 / 255, 191 / 255, 111 / 255)), (7, (255 / 255, 127 / 255, 0 / 255)), (8, (202 / 255, 178 / 255, 214 / 255)), (9, (106 / 255, 61 / 255, 154 / 255)), (10, (255 / 255, 255 / 255, 153 / 255)), (11, (177 / 255, 89 / 255, 40 / 255)), ) pastel1 = Colormap( (0, (251 / 255, 180 / 255, 174 / 255)), (1, (179 / 255, 205 / 255, 227 / 255)), (2, (204 / 255, 235 / 255, 197 / 255)), (3, (222 / 255, 203 / 255, 228 / 255)), (4, (254 / 255, 217 / 255, 166 / 255)), (5, (255 / 255, 255 / 255, 204 / 255)), (6, (229 / 255, 216 / 255, 189 / 255)), (7, (253 / 255, 218 / 255, 236 / 255)), (8, (242 / 255, 242 / 255, 242 / 255)), ) pastel2 = Colormap( (0, (179 / 255, 226 / 255, 205 / 255)), (1, (253 / 255, 205 / 255, 172 / 255)), (2, (203 / 255, 213 / 255, 232 / 255)), (3, (244 / 255, 202 / 255, 228 / 255)), (4, (230 / 255, 245 / 255, 201 / 255)), (5, (255 / 255, 242 / 255, 174 / 255)), (6, (241 / 255, 226 / 255, 204 / 255)), (7, (204 / 255, 204 / 255, 204 / 255)), ) set1 = Colormap( (0, (228 / 255, 26 / 255, 28 / 255)), (1, (55 / 255, 126 / 255, 184 / 255)), (2, (77 / 255, 175 / 255, 74 / 255)), (3, (152 / 255, 78 / 255, 163 / 255)), (4, (255 / 255, 127 / 255, 0 / 255)), (5, (255 / 255, 255 / 255, 51 / 255)), (6, (166 / 255, 86 / 255, 40 / 255)), (7, (247 / 255, 129 / 255, 191 / 255)), (8, (153 / 255, 153 / 255, 153 / 255)), ) set2 = Colormap( (0, (102 / 255, 194 / 255, 165 / 255)), (1, (252 / 255, 141 / 255, 98 / 255)), (2, (141 / 255, 160 / 255, 203 / 255)), (3, (231 / 255, 138 / 255, 195 / 255)), (4, (166 / 255, 216 / 255, 84 / 255)), (5, (255 / 255, 217 / 255, 47 / 255)), (6, (229 / 255, 196 / 255, 148 / 255)), (7, (179 / 255, 179 / 255, 179 / 255)), ) set3 = Colormap( (0, (141 / 255, 211 / 255, 199 / 255)), (1, (255 / 255, 255 / 255, 179 / 255)), (2, (190 / 255, 186 / 255, 218 / 255)), (3, (251 / 255, 128 / 255, 114 / 255)), (4, (128 / 255, 177 / 255, 211 / 255)), (5, (253 / 255, 180 / 255, 98 / 255)), (6, (179 / 255, 222 / 255, 105 / 255)), (7, (252 / 255, 205 / 255, 229 / 255)), (8, (217 / 255, 217 / 255, 217 / 255)), (9, (188 / 255, 128 / 255, 189 / 255)), (10, (204 / 255, 235 / 255, 197 / 255)), (11, (255 / 255, 237 / 255, 111 / 255)), ) qualitative_colormaps = { "accent": accent, "dark2": dark2, "paired": paired, "pastel1": pastel1, "pastel2": pastel2, "set1": set1, "set2": set2, "set3": set3, } def colorbar(height, length, colormap, category=False): """Return the channels of a colorbar.""" cbar = np.tile(np.arange(length) * 1.0 / (length - 1), (height, 1)) cmin = colormap.values.min() cmax = colormap.values.max() crange = (cmax - cmin) if category: # add an extra buffer around colormap limits to show full category cbar = cbar * (crange + 1) + (cmin - 0.5) cbar = np.round(cbar) else: cbar = (cbar * crange) + colormap.values.min() return colormap.colorize(cbar) def palettebar(height, length, colormap): """Return the channels of a palettebar.""" cbar = np.tile(np.arange(length) * 1.0 / (length - 1), (height, 1)) cbar = (cbar * (colormap.values.max() + 1 - colormap.values.min()) + colormap.values.min()) return colormap.palettize(cbar) trollimage-1.28.0/trollimage/colorspaces.py000066400000000000000000000001651514066130000207650ustar00rootroot00000000000000"""Color spaces using numpy to run on arrays.""" from ._colorspaces import rgb2lch, lch2rgb, convert_colors # noqa trollimage-1.28.0/trollimage/image.py000066400000000000000000001220461514066130000175350ustar00rootroot00000000000000"""The main trollimage Image class. It overlaps largely the PIL library, but has the advantage of using masked arrays as pixel arrays, so that data arrays containing invalid values may be properly handled. """ import logging import os import re from copy import deepcopy from functools import lru_cache import numpy as np from PIL import Image as Pil try: import numexpr as ne except ImportError: ne = None logger = logging.getLogger(__name__) @lru_cache(1) def get_pillow_image_formats(): """Get mapping from file extension to PIL format plugin.""" Pil.init() return Pil.registered_extensions() def _pprint_pil_formats(): """Group format extensions into rows of 12.""" format_exts = list(get_pillow_image_formats().keys()) format_rows = [", ".join(format_exts[idx:idx + 12]) for idx in range(0, len(format_exts), 12)] return ",\n".join(format_rows) def ensure_dir(filename): """Check if the dir of f exists, otherwise create it.""" directory = os.path.dirname(filename) if len(directory) and not os.path.isdir(directory): os.makedirs(directory) class UnknownImageFormat(Exception): """Exception to be raised when image format is unknown to pytroll-image.""" def check_image_format(fformat): """Check that *fformat* is valid. Valid formats are listed in https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html """ fformat = fformat.lower() try: fformat = get_pillow_image_formats()["." + fformat] except KeyError: raise UnknownImageFormat( "Unknown image format '%s'. Supported formats for 'simple_image' writer are:\n%s" % (fformat, _pprint_pil_formats())) return fformat class Image(object): """Generic masked-array based image. This class defines images. As such, it contains data of the different *channels* of the image (red, green, and blue for example). The *mode* tells if the channels define a black and white image ("L"), an rgb image ("RGB"), an YCbCr image ("YCbCr"), or an indexed image ("P"), in which case a *palette* is needed. Each mode has also a corresponding alpha mode, which is the mode with an "A" in the end: for example "RGBA" is rgb with an alpha channel. *fill_value* sets how the image is filled where data is missing, since channels are numpy masked arrays. Setting it to (0,0,0) in RGB mode for example will produce black where data is missing."None" (default) will produce transparency (thus adding an alpha channel) if the file format allows it, black otherwise. The channels are considered to contain floating point values in the range [0.0,1.0]. In order to normalize the input data, the *color_range* parameter defines the original range of the data. The conversion to the classical [0,255] range and byte type is done automagically when saving the image to file. """ modes = ["L", "LA", "RGB", "RGBA", "YCbCr", "YCbCrA", "P", "PA"] def __init__(self, channels=None, mode="L", color_range=None, fill_value=None, palette=None, copy=True): """Initialize basic image metadata and data storage.""" self.channels = None self.mode = None self.width = 0 self.height = 0 self.fill_value = None self.palette = None self.shape = None self.info = {} self._secondary_mode = "RGB" if (channels is not None and not isinstance(channels, (tuple, set, list, np.ndarray, np.ma.core.MaskedArray))): raise TypeError("Image channels should a tuple, set, list, numpy " "array, or masked array.") if (isinstance(channels, (tuple, list)) and len(channels) != len(re.findall("[A-Z]", mode))): errmsg = ("Number of channels (" + "{n}) does not match mode {mode}.".format( n=len(channels), mode=mode)) raise ValueError(errmsg) if copy and channels is not None: channels = deepcopy(channels) if mode not in self.modes: raise ValueError("Unknown mode.") if (color_range is not None and not _is_pair(color_range) and not _is_list_of_pairs(color_range)): raise ValueError("Color_range should be a pair" " or a list/tuple/set of pairs.") if (color_range is not None and _is_list_of_pairs(color_range) and (channels is None or len(color_range) != len(channels))): raise ValueError("Color_range length does not match number of " "channels.") if (color_range is not None and (((mode == "L" or mode == "P") and not _is_pair(color_range)) and (len(color_range) != len(re.findall("[A-Z]", mode))))): raise ValueError("Color_range does not match mode") self.mode = mode if isinstance(fill_value, (tuple, list, set)): self.fill_value = list(fill_value) elif fill_value is not None: self.fill_value = [fill_value] else: self.fill_value = None self.channels = [] self.palette = palette if isinstance(channels, (tuple, list)): if _areinstances(channels, (np.ma.core.MaskedArray, np.ndarray, list, tuple)): for i, chn in enumerate(channels): if color_range is not None: color_min = color_range[i][0] color_max = color_range[i][1] # Add data to image object as a channel # self._add_channel(chn, color_min, color_max) else: color_min = 0.0 color_max = 1.0 # self.channels.append(np.ma.array(chn)) # Add data to image object as a channel self._add_channel(chn, color_min, color_max) self.shape = self.channels[-1].shape if self.shape != self.channels[0].shape: raise ValueError("Image channels must have the same" " shape.") self.height = self.shape[0] try: self.width = self.shape[1] except IndexError: self.width = 0 else: raise ValueError("Image channels must all be arrays tuples.") elif channels is not None: self.height = channels.shape[0] self.width = channels.shape[1] self.shape = channels.shape if color_range is not None: color_min = color_range[0] color_max = color_range[1] else: color_min = 0.0 color_max = 1.0 # Add data to image object as a channel self._add_channel(channels, color_min, color_max) else: self.shape = (0, 0) self.width = 0 self.height = 0 def _add_channel(self, chn, color_min, color_max): """Add a channel to the image object.""" if isinstance(chn, np.ma.core.MaskedArray): chn_data = chn.data chn_mask = chn.mask else: chn_data = np.array(chn) chn_mask = False scaled = ((chn_data - color_min) * 1.0 / (color_max - color_min)) self.channels.append(np.ma.array(scaled, mask=chn_mask)) def _finalize(self, dtype=np.uint8): """Finalize the image. That is, put it in RGB mode, and set the channels in unsigned 8bit format ([0,255] range) (if the *dtype* doesn't say otherwise). """ channels = [] if self.mode == "P": self.convert("RGB") if self.mode == "PA": self.convert("RGBA") for chn in self.channels: if isinstance(chn, np.ma.core.MaskedArray): final_data = chn.data.clip(0, 1) * np.iinfo(dtype).max else: final_data = chn.clip(0, 1) * np.iinfo(dtype).max if np.issubdtype(dtype, np.integer): final_data = np.round(final_data) channels.append(np.ma.array(final_data, dtype, mask=np.ma.getmaskarray(chn))) if self.fill_value is not None: fill_value = [int(col * np.iinfo(dtype).max) for col in self.fill_value] else: fill_value = None return channels, fill_value def is_empty(self): """Check for an empty image.""" if (((self.channels == []) and (not self.shape == (0, 0))) or ((not self.channels == []) and (self.shape == (0, 0)))): raise RuntimeError("Channels-shape mismatch.") return self.channels == [] and self.shape == (0, 0) def show(self): """Display the image on screen.""" self.pil_image().show() def pil_image(self): """Return a PIL image from the current image.""" channels, fill_value = self._finalize() if self.is_empty(): return Pil.new(self.mode, (0, 0)) if self.mode == "L": if fill_value is not None: img = Pil.fromarray(channels[0].filled(fill_value)) else: img = Pil.fromarray(channels[0].filled(0)) alpha = np.zeros(channels[0].shape, np.uint8) mask = np.ma.getmaskarray(channels[0]) alpha = np.where(mask, alpha, 255) pil_alpha = Pil.fromarray(alpha) img = Pil.merge("LA", (img, pil_alpha)) elif self.mode == "LA": if fill_value is not None: img = Pil.fromarray(channels[0].filled(fill_value)) pil_alpha = Pil.fromarray(channels[1]) else: img = Pil.fromarray(channels[0].filled(0)) alpha = np.zeros(channels[0].shape, np.uint8) mask = np.ma.getmaskarray(channels[0]) alpha = np.where(mask, alpha, channels[1]) pil_alpha = Pil.fromarray(alpha) img = Pil.merge("LA", (img, pil_alpha)) elif self.mode == "RGB": # Mask where all channels have missing data (incomplete data will # be shown). mask = (np.ma.getmaskarray(channels[0]) & np.ma.getmaskarray(channels[1]) & np.ma.getmaskarray(channels[2])) if fill_value is not None: pil_r = Pil.fromarray(channels[0].filled(fill_value[0])) pil_g = Pil.fromarray(channels[1].filled(fill_value[1])) pil_b = Pil.fromarray(channels[2].filled(fill_value[2])) img = Pil.merge("RGB", (pil_r, pil_g, pil_b)) else: pil_r = Pil.fromarray(channels[0].filled(0)) pil_g = Pil.fromarray(channels[1].filled(0)) pil_b = Pil.fromarray(channels[2].filled(0)) alpha = np.zeros(channels[0].shape, np.uint8) alpha = np.where(mask, alpha, 255) pil_a = Pil.fromarray(alpha) img = Pil.merge("RGBA", (pil_r, pil_g, pil_b, pil_a)) elif self.mode == "RGBA": # Mask where all channels have missing data (incomplete data will # be shown). mask = (np.ma.getmaskarray(channels[0]) & np.ma.getmaskarray(channels[1]) & np.ma.getmaskarray(channels[2]) & np.ma.getmaskarray(channels[3])) if fill_value is not None: pil_r = Pil.fromarray(channels[0].filled(fill_value[0])) pil_g = Pil.fromarray(channels[1].filled(fill_value[1])) pil_b = Pil.fromarray(channels[2].filled(fill_value[2])) pil_a = Pil.fromarray(channels[3].filled(fill_value[3])) img = Pil.merge("RGBA", (pil_r, pil_g, pil_b, pil_a)) else: pil_r = Pil.fromarray(channels[0].filled(0)) pil_g = Pil.fromarray(channels[1].filled(0)) pil_b = Pil.fromarray(channels[2].filled(0)) alpha = np.where(mask, 0, channels[3]) pil_a = Pil.fromarray(alpha) img = Pil.merge("RGBA", (pil_r, pil_g, pil_b, pil_a)) else: raise TypeError("Does not know how to use mode %s." % (self.mode)) return img def save(self, filename, compression=6, fformat=None, thumbnail_name=None, thumbnail_size=None): """Save the image to the given *filename*. For some formats like jpg and png, the work is delegated to :meth:`pil_save`, which doesn't support the *compression* option. """ self.pil_save(filename, compression, fformat, thumbnail_name, thumbnail_size) def pil_save(self, filename, compression=6, fformat=None, thumbnail_name=None, thumbnail_size=None): """Save the image to the given *filename* using PIL. For now, the compression level [0-9] is ignored, due to PIL's lack of support. See also :meth:`save`. Supported image formats are listed in https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html """ # PIL does not support compression option. del compression if self.is_empty(): raise IOError("Cannot save an empty image") if isinstance(filename, str): ensure_dir(filename) fformat = fformat or os.path.splitext(filename)[1][1:4] fformat = check_image_format(fformat) params = {} if fformat == 'PNG': # Take care of GeoImage.tags (if any). params['pnginfo'] = self._pngmeta() # JPEG images does not support transparency if fformat == 'JPEG' and not self.fill_value: self.fill_value = [0, 0, 0, 0] logger.debug("No fill_value provided, setting it to 0.") img = self.pil_image() img.save(filename, fformat, **params) if thumbnail_name is not None and thumbnail_size is not None: img.thumbnail(thumbnail_size, Pil.ANTIALIAS) img.save(thumbnail_name, fformat, **params) def _pngmeta(self): """Return GeoImage.tags as a PNG metadata object. Inspired by: public domain, Nick Galbreath http://blog.modp.com/2007/08/python-pil-and-png-metadata-take-2.html """ reserved = ('interlace', 'gamma', 'dpi', 'transparency', 'aspect') try: tags = self.tags except AttributeError: tags = {} # Undocumented class from PIL import PngImagePlugin meta = PngImagePlugin.PngInfo() # Copy from tags to new dict for k__, v__ in tags.items(): if k__ not in reserved: meta.add_text(k__, v__, 0) return meta def putalpha(self, alpha): """Add an *alpha* channel to the current image, or replaces it with *alpha* if it already exists.""" alpha = np.ma.array(alpha) if (not (alpha.shape[0] == 0 and self.shape[0] == 0) and alpha.shape != self.shape): raise ValueError("Alpha channel shape should match image shape") if not self.mode.endswith("A"): self.convert(self.mode + "A") if not self.is_empty(): self.channels[-1] = alpha def _rgb2ycbcr(self, mode): """Convert the image from RGB mode to YCbCr.""" self._check_modes(("RGB", "RGBA")) (self.channels[0], self.channels[1], self.channels[2]) = \ rgb2ycbcr(self.channels[0], self.channels[1], self.channels[2]) if self.fill_value is not None: self.fill_value[0:3] = rgb2ycbcr(self.fill_value[0], self.fill_value[1], self.fill_value[2]) self.mode = mode def _ycbcr2rgb(self, mode): """Convert the image from YCbCr mode to RGB.""" self._check_modes(("YCbCr", "YCbCrA")) (self.channels[0], self.channels[1], self.channels[2]) = \ ycbcr2rgb(self.channels[0], self.channels[1], self.channels[2]) if self.fill_value is not None: self.fill_value[0:3] = ycbcr2rgb(self.fill_value[0], self.fill_value[1], self.fill_value[2]) self.mode = mode def _to_p(self, mode): """Convert the image to P or PA mode.""" if self.mode.endswith("A"): chans = self.channels[:-1] alpha = self.channels[-1] self._secondary_mode = self.mode[:-1] else: chans = self.channels alpha = None self._secondary_mode = self.mode palette = [] selfmask = chans[0].mask for chn in chans[1:]: selfmask = np.ma.mask_or(selfmask, chn.mask) new_chn = np.ma.zeros(self.shape, dtype=int) color_nb = 0 for i in range(self.height): for j in range(self.width): current_col = tuple([chn[i, j] for chn in chans]) try: next(idx for idx in range(len(palette)) if palette[idx] == current_col) except StopIteration: idx = color_nb palette.append(current_col) color_nb = color_nb + 1 new_chn[i, j] = idx if self.fill_value is not None: if self.mode.endswith("A"): current_col = tuple(self.fill_value[:-1]) fill_alpha = [self.fill_value[-1]] else: current_col = tuple(self.fill_value) fill_alpha = [] try: next(idx for idx in range(len(palette)) if palette[idx] == current_col) except StopIteration: idx = color_nb palette.append(current_col) color_nb = color_nb + 1 self.fill_value = [idx] + fill_alpha new_chn.mask = selfmask self.palette = palette if alpha is None: self.channels = [new_chn] else: self.channels = [new_chn, alpha] self.mode = mode def _from_p(self, mode): """Convert the image from P or PA mode.""" self._check_modes(("P", "PA")) if self.mode.endswith("A"): alpha = self.channels[-1] else: alpha = None chans = [] cdfs = [] color_chan = self.channels[0] for i in range(len(self.palette[0])): cdfs.append(np.zeros(len(self.palette))) for j in range(len(self.palette)): cdfs[i][j] = self.palette[j][i] new_chn = np.ma.array(np.interp(color_chan, np.arange(len(self.palette)), cdfs[i]), mask=color_chan.mask) chans.append(new_chn) if self.fill_value is not None: if alpha is not None: fill_alpha = self.fill_value[-1] self.fill_value = list(self.palette[int(self.fill_value[0])]) self.fill_value += [fill_alpha] else: self.fill_value = list(self.palette[int(self.fill_value[0])]) self.mode = self._secondary_mode self.channels = chans if alpha is not None: self.channels.append(alpha) self.mode = self.mode + "A" self.convert(mode) def _check_modes(self, modes): """Check that the image is in on of the given *modes*, raise an exception otherwise.""" if not isinstance(modes, (tuple, list, set)): modes = [modes] if self.mode not in modes: raise ValueError("Image not in suitable mode: %s" % modes) def _l2rgb(self, mode): """Convert from L (black and white) to RGB.""" self._check_modes(("L", "LA")) self.channels.append(self.channels[0].copy()) self.channels.append(self.channels[0].copy()) if self.fill_value is not None: self.fill_value = self.fill_value[:1] * 3 + self.fill_value[1:] if self.mode == "LA": self.channels[1], self.channels[3] = \ self.channels[3], self.channels[1] self.mode = mode def _rgb2l(self, mode): """Convert from RGB to monochrome L.""" self._check_modes(("RGB", "RGBA")) kb_ = 0.114 kr_ = 0.299 r__ = self.channels[0] g__ = self.channels[1] b__ = self.channels[2] y__ = kr_ * r__ + (1 - kr_ - kb_) * g__ + kb_ * b__ if self.fill_value is not None: self.fill_value = ([rgb2ycbcr(self.fill_value[0], self.fill_value[1], self.fill_value[2])[0]] + self.fill_value[3:]) self.channels = [y__] + self.channels[3:] self.mode = mode def _ycbcr2l(self, mode): """Convert from YCbCr to L.""" self._check_modes(("YCbCr", "YCbCrA")) self.channels = [self.channels[0]] + self.channels[3:] if self.fill_value is not None: self.fill_value = [self.fill_value[0]] + self.fill_value[3:] self.mode = mode def _l2ycbcr(self, mode): """Convert from L to YCbCr.""" self._check_modes(("L", "LA")) luma = self.channels[0] zeros = np.ma.zeros(luma.shape) zeros.mask = luma.mask self.channels = [luma, zeros, zeros] + self.channels[1:] if self.fill_value is not None: self.fill_value = [self.fill_value[0], 0, 0] + self.fill_value[1:] self.mode = mode def convert(self, mode): """Convert the current image to the given *mode*. See :class:`Image` for a list of available modes. """ if mode == self.mode: return if mode not in ["L", "LA", "RGB", "RGBA", "YCbCr", "YCbCrA", "P", "PA"]: raise ValueError("Mode %s not recognized." % (mode)) if self.is_empty(): self.mode = mode return if mode == self.mode + "A": self.channels.append(np.ma.ones(self.channels[0].shape)) if self.fill_value is not None: self.fill_value += [1] self.mode = mode elif mode + "A" == self.mode: self.channels = self.channels[:-1] if self.fill_value is not None: self.fill_value = self.fill_value[:-1] self.mode = mode elif mode.endswith("A") and not self.mode.endswith("A"): self.convert(self.mode + "A") self.convert(mode) elif self.mode.endswith("A") and not mode.endswith("A"): self.convert(self.mode[:-1]) self.convert(mode) else: cases = { "RGB": {"YCbCr": self._rgb2ycbcr, "L": self._rgb2l, "P": self._to_p}, "RGBA": {"YCbCrA": self._rgb2ycbcr, "LA": self._rgb2l, "PA": self._to_p}, "YCbCr": {"RGB": self._ycbcr2rgb, "L": self._ycbcr2l, "P": self._to_p}, "YCbCrA": {"RGBA": self._ycbcr2rgb, "LA": self._ycbcr2l, "PA": self._to_p}, "L": {"RGB": self._l2rgb, "YCbCr": self._l2ycbcr, "P": self._to_p}, "LA": {"RGBA": self._l2rgb, "YCbCrA": self._l2ycbcr, "PA": self._to_p}, "P": {"RGB": self._from_p, "YCbCr": self._from_p, "L": self._from_p}, "PA": {"RGBA": self._from_p, "YCbCrA": self._from_p, "LA": self._from_p}} try: cases[self.mode][mode](mode) except KeyError: raise ValueError("Conversion from %s to %s not implemented !" % (self.mode, mode)) def clip(self, channels=True): """Limit the values of the array to the default [0,1] range. *channels* says which channels should be clipped. """ if not isinstance(channels, (tuple, list)): channels = [channels] * len(self.channels) for i in range(len(self.channels)): if channels[i]: self.channels[i] = np.ma.clip(self.channels[i], 0.0, 1.0) def resize(self, shape): """Resize the image to the given *shape* tuple, in place. For zooming, nearest neighbour method is used, while for shrinking, decimation is used. Therefore, *shape* must be a multiple or a divisor of the image shape. """ if self.is_empty(): raise ValueError("Cannot resize an empty image") factor = [1, 1] zoom = [True, True] zoom[0] = shape[0] >= self.height zoom[1] = shape[1] >= self.width if zoom[0]: factor[0] = shape[0] * 1.0 / self.height else: factor[0] = self.height * 1.0 / shape[0] if zoom[1]: factor[1] = shape[1] * 1.0 / self.width else: factor[1] = self.width * 1.0 / shape[1] if (int(factor[0]) != factor[0] or int(factor[1]) != factor[1]): raise ValueError("Resize not of integer factor!") factor[0] = int(factor[0]) factor[1] = int(factor[1]) i = 0 for chn in self.channels: if zoom[0]: chn = chn.repeat([factor[0]] * chn.shape[0], axis=0) else: chn = chn[[idx * factor[0] for idx in range(int(self.height / factor[0]))], :] if zoom[1]: self.channels[i] = chn.repeat([factor[1]] * chn.shape[1], axis=1) else: self.channels[i] = chn[:, [idx * factor[1] for idx in range(int(self.width / factor[1]))]] i = i + 1 self.height = self.channels[0].shape[0] self.width = self.channels[0].shape[1] self.shape = self.channels[0].shape def replace_luminance(self, luminance): """Replace the Y channel of the image by the array *luminance*. If the image is not in YCbCr mode, it is converted automatically to and from that mode. """ if self.is_empty(): return if luminance.shape != self.channels[0].shape: if ((luminance.shape[0] * 1.0 / luminance.shape[1]) == (self.channels[0].shape[0] * 1.0 / self.channels[0].shape[1])): if luminance.shape[0] > self.channels[0].shape[0]: self.resize(luminance.shape) else: raise NameError("Luminance smaller than the image !") else: raise NameError("Not the good shape !") mode = self.mode if mode.endswith("A"): self.convert("YCbCrA") self.channels[0] = luminance self.convert(mode) else: self.convert("YCbCr") self.channels[0] = luminance self.convert(mode) def enhance(self, inverse=False, gamma=1.0, stretch="no", stretch_parameters=None, **kwargs): """Image enhancement function. It applies **in this order** inversion, gamma correction, and stretching to the current image, with parameters *inverse* (see :meth:`Image.invert`), *gamma* (see :meth:`Image.gamma`), and *stretch* (see :meth:`Image.stretch`). """ self.invert(inverse) if stretch_parameters is None: stretch_parameters = {} stretch_parameters.update(kwargs) self.stretch(stretch, **stretch_parameters) self.gamma(gamma) def gamma(self, gamma=1.0): """Apply gamma correction to the channels of the image. If *gamma* is a tuple, then it should have as many elements as the channels of the image, and the gamma correction is applied elementwise. If *gamma* is a number, the same gamma correction is applied on every channel, if there are several channels in the image. The behaviour of :func:`gamma` is undefined outside the normal [0,1] range of the channels. """ if (isinstance(gamma, (list, tuple, set)) and len(gamma) != len(self.channels)): raise ValueError("Number of channels and gamma components differ.") if isinstance(gamma, (tuple, list)): gamma_list = list(gamma) else: gamma_list = [gamma] * len(self.channels) for i in range(len(self.channels)): gamma = float(gamma_list[i]) if gamma < 0: raise ValueError("Gamma correction must be a positive number.") logger.debug("Applying gamma %f", gamma) if gamma == 1.0: continue if isinstance(self.channels[i], np.ma.core.MaskedArray): if ne: self.channels[i] = np.ma.array( ne.evaluate("data ** (1.0 / gamma)", local_dict={"data": self.channels[i].data, 'gamma': gamma}), mask=self.channels[i].mask, copy=False) else: self.channels[i] = np.ma.array(self.channels[i].data ** (1.0 / gamma), mask=self.channels[i].mask, copy=False) else: self.channels[i] = np.where(self.channels[i] >= 0, self.channels[i] ** (1.0 / gamma), self.channels[i]) def stretch(self, stretch="crude", **kwargs): """Apply stretching to the current image. The value of *stretch* sets the type of stretching applied. The values "histogram", "linear", "crude" (or "crude-stretch") perform respectively histogram equalization, contrast stretching (with 5% cutoff on both sides), and contrast stretching without cutoff. The value "logarithmic" or "log" will do a logarithmic enhancement towards white. If a tuple or a list of two values is given as input, then a contrast stretching is performed with the values as cutoff. These values should be normalized in the range [0.0,1.0]. """ logger.debug("Applying stretch %s with parameters %s", stretch, str(kwargs)) ch_len = len(self.channels) if self.mode.endswith("A"): ch_len -= 1 if ((isinstance(stretch, tuple) or isinstance(stretch, list))): if len(stretch) == 2: for i in range(ch_len): self.stretch_linear(i, cutoffs=stretch, **kwargs) else: raise ValueError( "Stretch tuple must have exactly two elements") elif stretch == "linear": for i in range(ch_len): self.stretch_linear(i, **kwargs) elif stretch == "histogram": for i in range(ch_len): self.stretch_hist_equalize(i, **kwargs) elif stretch in ["crude", "crude-stretch"]: for i in range(ch_len): self.crude_stretch(i, **kwargs) elif stretch in ["log", "logarithmic"]: for i in range(ch_len): self.stretch_logarithmic(i, **kwargs) elif stretch == "no": return elif isinstance(stretch, str): raise ValueError("Stretching method %s not recognized." % stretch) else: raise TypeError("Stretch parameter must be a string or a tuple.") def invert(self, invert=True): """Inverts all the channels of a image according to *invert*. If invert is a tuple or a list, elementwise invertion is performed, otherwise all channels are inverted if *invert* is true (default). Note: 'Inverting' means that black becomes white, and vice-versa, not that the values are negated! """ if (isinstance(invert, (tuple, list)) and len(self.channels) != len(invert)): raise ValueError( "Number of channels and invert components differ.") logger.debug("Applying invert with parameters %s", str(invert)) if isinstance(invert, (tuple, list)): for i, chn in enumerate(self.channels): if invert[i]: self.channels[i] = 1 - chn elif invert: for i, chn in enumerate(self.channels): self.channels[i] = 1 - chn def stretch_hist_equalize(self, ch_nb): """Stretch the current image's colors by performing histogram equalization on channel *ch_nb*.""" logger.info("Perform a histogram equalized contrast stretch.") if (self.channels[ch_nb].size == np.ma.count_masked(self.channels[ch_nb])): logger.warning("Nothing to stretch !") return arr = self.channels[ch_nb] nwidth = 2048.0 carr = arr.compressed() cdf = np.arange(0.0, 1.0, 1 / nwidth) logger.debug("Make histogram bins having equal amount of data, " + "using numpy percentile function:") bins = np.percentile(carr, list(cdf * 100)) res = np.ma.empty_like(arr) res.mask = np.ma.getmaskarray(arr) res[~res.mask] = np.interp(carr, bins, cdf) self.channels[ch_nb] = res def stretch_logarithmic(self, ch_nb, factor=100.): """Move data into range [1:factor] and do a normalized logarithmic enhancement.""" logger.debug("Perform a logarithmic contrast stretch.") if ((self.channels[ch_nb].size == np.ma.count_masked(self.channels[ch_nb])) or (self.channels[ch_nb].min() == self.channels[ch_nb].max())): logger.warning("Nothing to stretch !") return crange = (0., 1.0) arr = self.channels[ch_nb] b__ = float(crange[1] - crange[0]) / np.log(factor) c__ = float(crange[0]) slope = (factor - 1.) / float(arr.max() - arr.min()) arr = 1. + (arr - arr.min()) * slope arr = c__ + b__ * np.log(arr) self.channels[ch_nb] = arr def stretch_linear(self, ch_nb, cutoffs=(0.005, 0.005)): """Stretch linearly the contrast of the current image for a specific channel. Channel *ch_nb* is the 0-based index. Stretching is based on *cutoffs* fractions for left and right trimming. """ logger.debug("Perform a linear contrast stretch.") if ((self.channels[ch_nb].size == np.ma.count_masked(self.channels[ch_nb])) or self.channels[ch_nb].min() == self.channels[ch_nb].max()): logger.warning("Nothing to stretch !") return arr = self.channels[ch_nb] carr = arr.compressed() logger.debug("Calculate the histogram percentiles: ") logger.debug("Left and right percentiles: " + str(cutoffs[0] * 100) + " " + str(cutoffs[1] * 100)) left, right = np.percentile( carr, [cutoffs[0] * 100, 100. - cutoffs[1] * 100]) delta_x = (right - left) logger.debug("Interval: left=%f, right=%f width=%f", left, right, delta_x) if delta_x > 0.0: self.channels[ch_nb] = np.ma.array((arr - left) / delta_x, mask=arr.mask) else: logger.warning("Unable to make a contrast stretch!") def crude_stretch(self, ch_nb, min_stretch=None, max_stretch=None): """Perform simple linear stretching (without any cutoff) for a specific channel. Channel *ch_nb* is the 0-based index. The image is normalized to the [0,1] range. """ if min_stretch is None: min_stretch = self.channels[ch_nb].min() if max_stretch is None: max_stretch = self.channels[ch_nb].max() if isinstance(min_stretch, (list, tuple)): min_stretch = min_stretch[ch_nb] if isinstance(max_stretch, (list, tuple)): max_stretch = max_stretch[ch_nb] if ((not self.channels[ch_nb].mask.all()) and abs(max_stretch - min_stretch) > 0): stretched = self.channels[ch_nb].data.astype(float) stretched -= min_stretch stretched /= max_stretch - min_stretch self.channels[ch_nb] = np.ma.array(stretched, mask=self.channels[ch_nb].mask, copy=False) else: logger.warning("Nothing to stretch !") def merge(self, img): """Use provided image as a background where the current image has missing data.""" if self.is_empty(): raise ValueError("Cannot merge an empty image.") if self.mode != img.mode: raise ValueError("Cannot merge image of different modes.") selfmask = self.channels[0].mask for chn in self.channels[1:]: selfmask = np.ma.mask_or(selfmask, chn.mask) for i in range(len(self.channels)): self.channels[i] = np.ma.where(selfmask, img.channels[i], self.channels[i]) self.channels[i].mask = np.logical_and(selfmask, img.channels[i].mask) def colorize(self, colormap): """Colorize the current image using *colormap*. Works only on"L" or "LA" images. """ if self.mode not in ("L", "LA"): raise ValueError("Image should be grayscale to colorize") if self.mode == "LA": alpha = self.channels[1] else: alpha = None self.channels = list(colormap.colorize(self.channels[0])) if alpha is not None: self.channels.append(alpha) self.mode = "RGBA" else: self.mode = "RGB" def palettize(self, colormap): """Palettize the current image using *colormap*. Works only on"L" or "LA" images. """ if self.mode not in ("L", "LA"): raise ValueError("Image should be grayscale to colorize") self.channels[0], self.palette = colormap.palettize(self.channels[0]) if self.mode == "L": self.mode = "P" else: self.mode = "PA" def blend(self, other): """Alpha blend *other* on top of the current image.""" if self.mode != "RGBA" or other.mode != "RGBA": raise ValueError("Images must be in RGBA") src = other dst = self outa = src.channels[3] + dst.channels[3] * (1 - src.channels[3]) for i in range(3): dst.channels[i] = (src.channels[i] * src.channels[3] + dst.channels[i] * dst.channels[3] * (1 - src.channels[3])) / outa dst.channels[i][outa == 0] = 0 dst.channels[3] = outa def _repr_png_(self): import io b = io.BytesIO() self.save(b, fformat="png") return b.getvalue() def _areinstances(the_list, types): """Check if all the elements of the list are of given type.""" return all([isinstance(item, types) for item in the_list]) def _is_pair(item): """Check if an item is a pair (tuple of size 2).""" return (isinstance(item, (list, tuple, set)) and len(item) == 2 and not isinstance(item[0], (list, tuple, set)) and not isinstance(item[1], (list, tuple, set))) def _is_list_of_pairs(the_list): """Check if a list contains only pairs.""" return all([_is_pair(item) for item in the_list]) def ycbcr2rgb(y__, cb_, cr_): """Convert the three YCbCr channels to RGB channels.""" kb_ = 0.114 kr_ = 0.299 r__ = 2 * cr_ / (1 - kr_) + y__ b__ = 2 * cb_ / (1 - kb_) + y__ g__ = (y__ - kr_ * r__ - kb_ * b__) / (1 - kr_ - kb_) return r__, g__, b__ def rgb2ycbcr(r__, g__, b__): """Convert the three RGB channels to YCbCr.""" kb_ = 0.114 kr_ = 0.299 y__ = kr_ * r__ + (1 - kr_ - kb_) * g__ + kb_ * b__ cb_ = 1. / (2 * (1 - kb_)) * (b__ - y__) cr_ = 1. / (2 * (1 - kr_)) * (r__ - y__) return y__, cb_, cr_ trollimage-1.28.0/trollimage/py.typed000066400000000000000000000000001514066130000175610ustar00rootroot00000000000000trollimage-1.28.0/trollimage/tests/000077500000000000000000000000001514066130000172365ustar00rootroot00000000000000trollimage-1.28.0/trollimage/tests/__init__.py000066400000000000000000000000311514066130000213410ustar00rootroot00000000000000"""The tests package.""" trollimage-1.28.0/trollimage/tests/test_colormap.py000066400000000000000000000765531514066130000225030ustar00rootroot00000000000000"""Test colormap.py.""" import os import contextlib from trollimage import colormap import numpy as np from tempfile import NamedTemporaryFile import xarray import pytest COLORS_RGB1 = np.array([ [0.0, 0.0, 0.0], [0.2, 0.2, 0.0], [0.0, 0.2, 0.2], [0.0, 0.2, 0.0], ]) COLORS_RGBA1 = np.array([ [0.0, 0.0, 0.0, 1.0], [0.2, 0.2, 0.0, 0.5], [0.0, 0.2, 0.2, 0.0], [0.0, 0.2, 0.0, 1.0], ]) def _mono_inc_colormap(): """Create fake monotonically increasing colormap.""" values = [1, 2, 3, 4] cmap = colormap.Colormap(values=values, colors=_four_rgb_colors()) return cmap def _mono_dec_colormap(): values = [4, 3, 2, 1] cmap = colormap.Colormap(values=values, colors=_four_rgb_colors()) return cmap def _four_rgb_colors(): return [ (1.0, 1.0, 0.0), (0.0, 1.0, 1.0), (1, 1, 1), (0, 0, 0), ] class TestColormap: """Pytest tests for colormap objects.""" def test_invert_set_range(self): """Test inverted set_range.""" cm_ = colormap.Colormap((1, (1.0, 1.0, 0.0)), (2, (0.0, 1.0, 1.0)), (3, (1, 1, 1)), (4, (0, 0, 0))) cm_.set_range(8, 0) assert cm_.values[0] == 8 assert cm_.values[-1] == 0 _assert_monotonic_values(cm_, increasing=False) np.testing.assert_allclose(cm_.colors[0], (1.0, 1.0, 0.0)) np.testing.assert_allclose(cm_.colors[-1], (0.0, 0.0, 0.0)) def test_add(self): """Test adding colormaps.""" cm_ = colormap.Colormap((1, (1.0, 1.0, 0.0)), (2, (0.0, 1.0, 1.0)), (3, (1, 1, 1)), (4, (0, 0, 0))) cm1 = colormap.Colormap((1, (1.0, 1.0, 0.0)), (2, (0.0, 1.0, 1.0))) cm2 = colormap.Colormap((3, (1.0, 1.0, 1.0)), (4, (0.0, 0.0, 0.0))) cm3 = cm1 + cm2 np.testing.assert_allclose(cm3.colors, cm_.colors) np.testing.assert_allclose(cm3.values, cm_.values) @pytest.mark.parametrize("category", [False, True]) def test_colorbar(self, category): """Test colorbar.""" cm_ = colormap.Colormap((1, (1.0, 1.0, 0.0)), (2, (0.0, 1.0, 1.0)), (3, (1.0, 0.0, 1.0)), (4, (1.0, 1.0, 1.0)), (5, (0.0, 0.0, 0.0))) channels = colormap.colorbar(1, 9, cm_, category=category) channels = np.array(channels)[:, 0, :] # number of colors and size of colorbar specifically chosen to have exact # colors of the colormap show in the colorbar assert np.unique(channels, axis=1).shape[1] == (5 if category else 9) for exp_color in cm_.colors: # check that the colormaps colors are actually showing up assert np.isclose(channels, exp_color[:, None], atol=0.01).all(axis=0).any() def test_palettebar(self): """Test colorbar.""" cm_ = colormap.Colormap((1, (1.0, 1.0, 0.0)), (2, (0.0, 1.0, 1.0)), (3, (1.0, 1.0, 1.0)), (4, (0.0, 0.0, 0.0))) channel, palette = colormap.palettebar(1, 4, cm_) np.testing.assert_allclose(channel.ravel(), np.arange(4)) np.testing.assert_allclose(palette, cm_.colors) def test_to_rio(self): """Test conversion to rasterio colormap.""" cm_ = colormap.Colormap((1, (1.0, 1.0, 0.0)), (2, (0.0, 1.0, 1.0)), (3, (1.0, 1.0, 1.0)), (4, (0.0, 0.0, 0.0))) orig_colors = cm_.colors.copy() d = cm_.to_rio() exp = {1: (255, 255, 0), 2: (0, 255, 255), 3: (255, 255, 255), 4: (0, 0, 0)} assert d == exp # assert original colormap information hasn't changed np.testing.assert_allclose(orig_colors, cm_.colors) def test_bad_color_dims(self): """Test passing colors that aren't RGB or RGBA.""" # Nonsense with pytest.raises(ValueError, match=r".*colors.*shape.*"): colormap.Colormap( colors=np.arange(5 * 5, dtype=np.float64).reshape((5, 5)), values=np.linspace(0, 1, 5 * 5), ) # LA with pytest.raises(ValueError, match=r".*colors.*shape.*"): colormap.Colormap( colors=np.arange(5 * 2, dtype=np.float64).reshape((5, 2)), values=np.linspace(0, 1, 5 * 2), ) def test_only_colors_only_values(self): """Test passing only colors or only values keyword arguments.""" with pytest.raises(ValueError, match=r"Both 'colors' and 'values'.*"): colormap.Colormap( colors=np.arange(5 * 3, dtype=np.float64).reshape((5, 3)), ) with pytest.raises(ValueError, match=r"Both 'colors' and 'values'.*"): colormap.Colormap( values=np.linspace(0, 1, 5 * 3), ) def test_diff_colors_values(self): """Test failure when colors and values have different number of elements.""" with pytest.raises(ValueError, match=r".*same number.*"): colormap.Colormap( colors=np.arange(5 * 3, dtype=np.float64).reshape((5, 3)), values=np.linspace(0, 1, 6), ) def test_nonfloat_colors(self): """Pass integer colors to colormap.""" with pytest.warns(UserWarning, match="should be floating point"): colormap.Colormap( colors=np.arange(5 * 3, dtype=np.uint8).reshape((5, 3)), values=np.linspace(0, 1, 5), ) def test_merge_nonmonotonic(self): """Test that merged colormaps must have monotonic values.""" cmap1 = colormap.Colormap( colors=np.arange(5 * 3.0).reshape((5, 3)), values=np.linspace(2, 3, 5), ) cmap2 = colormap.Colormap( colors=np.arange(5 * 3.0).reshape((5, 3)), values=np.linspace(0, 1, 5), ) with pytest.raises(ValueError, match=r".*monotonic.*"): cmap1 + cmap2 # this should succeed cmap2 + cmap1 @pytest.mark.parametrize( 'colors', [ COLORS_RGB1, COLORS_RGBA1 ] ) def test_to_rgb(self, colors): """Test 'to_rgb' method.""" cmap = colormap.Colormap( values=np.linspace(0.2, 0.5, colors.shape[0]), colors=colors.copy(), ) rgb_cmap = cmap.to_rgb() assert rgb_cmap.colors.shape[-1] == 3 if colors.shape[-1] == 3: assert rgb_cmap is cmap else: assert rgb_cmap is not cmap @pytest.mark.parametrize( 'colors', [ COLORS_RGB1, COLORS_RGBA1 ] ) def test_to_rgba(self, colors): """Test 'to_rgba' method.""" cmap = colormap.Colormap( values=np.linspace(0.2, 0.5, colors.shape[0]), colors=colors.copy(), ) rgb_cmap = cmap.to_rgba() assert rgb_cmap.colors.shape[-1] == 4 if colors.shape[-1] == 4: assert rgb_cmap is cmap else: assert rgb_cmap is not cmap @pytest.mark.parametrize( 'colors1', [ COLORS_RGB1, COLORS_RGBA1 ] ) @pytest.mark.parametrize( 'colors2', [ COLORS_RGB1, COLORS_RGBA1 ] ) def test_merge_rgb_rgba(self, colors1, colors2): """Test that two colormaps with RGB or RGBA colors can be merged.""" cmap1 = colormap.Colormap( values=np.linspace(0.2, 0.5, colors1.shape[0]), colors=colors1, ) cmap2 = colormap.Colormap( values=np.linspace(0.51, 0.8, colors2.shape[0]), colors=colors2, ) new_cmap = cmap1 + cmap2 assert new_cmap.values.shape[0] == colors1.shape[0] + colors2.shape[0] def test_merge_equal_values(self): """Test that merged colormaps can have equal values at the merge point.""" cmap1 = colormap.Colormap( colors=np.arange(5 * 3.0).reshape((5, 3)), values=np.linspace(0, 1, 5), ) cmap2 = colormap.Colormap( colors=np.arange(5 * 3.0).reshape((5, 3)), values=np.linspace(1, 2, 5), ) assert cmap1.values[-1] == cmap2.values[0] # this should succeed _ = cmap1 + cmap2 def test_merge_monotonic_decreasing(self): """Test that merged colormaps can be monotonically decreasing.""" cmap1 = colormap.Colormap( colors=np.arange(5 * 3.0).reshape((5, 3)), values=np.linspace(2, 1, 5), ) cmap2 = colormap.Colormap( colors=np.arange(5 * 3.0).reshape((5, 3)), values=np.linspace(1, 0, 5), ) _assert_monotonic_values(cmap1, increasing=False) _assert_monotonic_values(cmap2, increasing=False) # this should succeed _ = cmap1 + cmap2 @pytest.mark.parametrize('inplace', [False, True]) def test_reverse(self, inplace): """Test colormap reverse.""" values = np.linspace(0.2, 0.5, 10) colors = np.repeat(np.linspace(0.2, 0.8, 10)[:, np.newaxis], 3, 1) orig_values = values.copy() orig_colors = colors.copy() cmap = colormap.Colormap(values=values, colors=colors) new_cmap = cmap.reverse(inplace) _assert_inplace_worked(cmap, new_cmap, inplace) _assert_reversed_colors(cmap, new_cmap, inplace, orig_colors) _assert_unchanged_values(cmap, new_cmap, inplace, orig_values) @pytest.mark.parametrize( 'new_range', [ (0.0, 1.0), (1.0, 0.0), (210.0, 300.0), (300.0, 210.0), ]) @pytest.mark.parametrize('inplace', [False, True]) def test_set_range(self, new_range, inplace): """Test 'set_range' method.""" values = np.linspace(0.2, 0.5, 10) colors = np.repeat(np.linspace(0.2, 0.8, 10)[:, np.newaxis], 3, 1) orig_values = values.copy() orig_colors = colors.copy() cmap = colormap.Colormap(values=values, colors=colors) new_cmap = cmap.set_range(*new_range, inplace) flipped_range = new_range[0] > new_range[1] _assert_inplace_worked(cmap, new_cmap, inplace) _assert_monotonic_values(cmap, increasing=not inplace or not flipped_range) _assert_monotonic_values(new_cmap, increasing=not flipped_range) _assert_values_changed(cmap, new_cmap, inplace, orig_values) _assert_unchanged_colors(cmap, new_cmap, orig_colors) @pytest.mark.parametrize( 'new_range', [ (0.0, 1.0), (1.0, 0.0), (0.2, 0.5), (0.8, 0.3), ]) @pytest.mark.parametrize('colors_already_with_alpha', [False, True]) @pytest.mark.parametrize('inplace', [False, True]) def test_set_alpha_range(self, new_range, inplace, colors_already_with_alpha): """Test 'set_alpha_range' method.""" values = np.linspace(0, 1, 11) colors_col_n = 4 if colors_already_with_alpha else 3 colors = np.repeat(np.linspace(0, 1, 11)[:, np.newaxis], colors_col_n, 1) orig_values = values.copy() cmap = colormap.Colormap(values=values, colors=colors) new_cmap = cmap.set_alpha_range(*new_range, inplace) np.testing.assert_equal(new_cmap.colors[0, 3], new_range[0]) np.testing.assert_equal(new_cmap.colors[-1, 3], new_range[1]) _assert_inplace_worked(cmap, new_cmap, inplace) _assert_unchanged_values(cmap, new_cmap, inplace, orig_values) @pytest.mark.parametrize( ("input_cmap_func", "expected_result"), [ (_mono_inc_colormap, (0, 1, 2, 3)), (_mono_dec_colormap, (3, 2, 1, 0)), ] ) def test_palettize_in_range(self, input_cmap_func, expected_result): """Test palettize with values inside the set range.""" data = np.array([1, 2, 3, 4]) cm = input_cmap_func() channels, colors = cm.palettize(data) np.testing.assert_allclose(colors, cm.colors) assert all(channels == expected_result) def test_palettize_mono_inc_out_range(self): """Test palettize with a value outside the colormap values.""" cm = colormap.Colormap(values=[0, 1, 2, 3], colors=_four_rgb_colors()) data = np.arange(-1, 5) channels, colors = cm.palettize(data) np.testing.assert_allclose(colors, cm.colors) assert all(channels == [0, 0, 1, 2, 3, 3]) def test_palettize_mono_inc_nan(self): """Test palettize with monotonic increasing values with a NaN.""" cm = colormap.Colormap(values=[0, 1, 2, 3], colors=_four_rgb_colors()) data = np.arange(-1.0, 5.0) data[-1] = np.nan channels, colors = cm.palettize(data) np.testing.assert_allclose(colors, cm.colors) assert all(channels == [0, 0, 1, 2, 3, 3]) def test_palettize_mono_inc_in_range_dask(self): """Test palettize on a dask array.""" import dask.array as da data = da.from_array(np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]), chunks=2) cm = _mono_inc_colormap() channels, colors = cm.palettize(data) assert isinstance(channels, da.Array) np.testing.assert_allclose(colors, cm.colors) np.testing.assert_allclose(channels.compute(), [[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]) assert channels.dtype == int def test_palettize_edge_of_dtype_range(self): """Test palettize when bins span the entire dtype range.""" from trollimage.colormap import palettize arr = np.linspace(0, 255, 100, dtype=np.uint8).reshape(10, 10) colors = np.linspace(0, 255, 768).reshape(256, 3) values = np.arange(0, 256, dtype=np.uint8) palettize(arr, colors, values) @pytest.mark.parametrize( ("input_cmap_func", "expected_result"), [ (_mono_inc_colormap, _four_rgb_colors()), (_mono_dec_colormap, _four_rgb_colors()[::-1]), ] ) def test_colorize_no_interpolation(self, input_cmap_func, expected_result): """Test colorize.""" data = np.array([1, 2, 3, 4]) cm = input_cmap_func() channels = cm.colorize(data) output_colors = [channels[:, i] for i in range(data.size)] for output_color, expected_color in zip(output_colors, expected_result): np.testing.assert_allclose(output_color, expected_color, atol=0.001) @pytest.mark.parametrize( ("input_cmap_func", "expected_result"), [ (_mono_inc_colormap, np.array([ [0.43301, 1.0, 0.639861], [0.738804, 1.0, 0.926142], [0.466327, 0.466327, 0.466327], [0.0, 0.0, 0.0]])), (_mono_dec_colormap, np.array([ [0.466327, 0.466327, 0.466327], [0.738804, 1.0, 0.926142], [0.43301, 1.0, 0.639861], [1.0, 1.0, 0.0]])), ] ) def test_colorize_with_interpolation(self, input_cmap_func, expected_result): """Test colorize where data values require interpolation between colors.""" data = np.array([1.5, 2.5, 3.5, 4]) cm = input_cmap_func() channels = cm.colorize(data) output_colors = [channels[:, i] for i in range(data.size)] # test each resulting value (each one is an RGB color) np.testing.assert_allclose(output_colors[0], expected_result[0], atol=0.001) np.testing.assert_allclose(output_colors[1], expected_result[1], atol=0.001) np.testing.assert_allclose(output_colors[2], expected_result[2], atol=0.001) np.testing.assert_allclose(output_colors[3], expected_result[3], atol=0.001) def test_colorize_dask_with_interpolation(self): """Test colorize dask arrays.""" import dask.array as da data = da.from_array(np.array([[1.5, 2.5, 3.5, 4], [1.5, 2.5, 3.5, 4], [1.5, 2.5, 3.5, 4]]), chunks=-1) expected_channels = [np.array([[0.43301012, 0.73880362, 0.46632665, 0.], [0.43301012, 0.73880362, 0.46632665, 0.], [0.43301012, 0.73880362, 0.46632665, 0.]]), np.array([[1., 1., 0.46632662, 0.], [1., 1., 0.46632662, 0.], [1., 1., 0.46632662, 0.]]), np.array([[0.63986057, 0.92614193, 0.46632658, 0.], [0.63986057, 0.92614193, 0.46632658, 0.], [0.63986057, 0.92614193, 0.46632658, 0.]])] cm = _mono_inc_colormap() import dask with dask.config.set(scheduler='sync'): channels = cm.colorize(data) assert isinstance(channels, da.Array) channels_np = channels.compute() np.testing.assert_allclose(channels_np[0], expected_channels[0], atol=0.001) np.testing.assert_allclose(channels_np[1], expected_channels[1], atol=0.001) np.testing.assert_allclose(channels_np[2], expected_channels[2], atol=0.001) @pytest.mark.parametrize("reverse", [False, True]) def test_colorize_with_large_hue_jumps(self, reverse): """Test colorize with a colormap that has large hue transitions.""" spectral = colormap.Colormap( (0.0, (158 / 255.0, 1 / 255.0, 66 / 255.0)), (0.1, (213 / 255.0, 62 / 255.0, 79 / 255.0)), (0.2, (244 / 255.0, 109 / 255.0, 67 / 255.0)), (0.3, (253 / 255.0, 174 / 255.0, 97 / 255.0)), (0.4, (254 / 255.0, 224 / 255.0, 139 / 255.0)), (0.5, (255 / 255.0, 255 / 255.0, 191 / 255.0)), (0.6, (230 / 255.0, 245 / 255.0, 152 / 255.0)), (0.7, (171 / 255.0, 221 / 255.0, 164 / 255.0)), (0.8, (102 / 255.0, 194 / 255.0, 165 / 255.0)), (0.9, (50 / 255.0, 136 / 255.0, 189 / 255.0)), (1.0, (94 / 255.0, 79 / 255.0, 162 / 255.0))) data = np.linspace(0.75, 0.95, 10) expected = np.array([[0.53504425, 0.47514295, 0.41509147, 0.28825797, 0.12078193, 0., 0.06763011, 0.19413283, 0.20869236, 0.24952029], [0.8154807, 0.79158862, 0.7670261, 0.73066567, 0.6855056, 0.63483774, 0.57879493, 0.52270084, 0.47846375, 0.43116887], [0.64195795, 0.6437378, 0.64633243, 0.67815406, 0.71676881, 0.74382618, 0.75153729, 0.73985524, 0.73037312, 0.71271801]]) if reverse: spectral = spectral.reverse(inplace=False) data = data - 0.7 expected = expected[..., ::-1] channels = spectral.colorize(data) np.testing.assert_allclose(channels, expected, atol=0.001) @contextlib.contextmanager def closed_named_temp_file(**kwargs): """Named temporary file context manager that closes the file after creation. This helps with Windows systems which can get upset with opening or deleting a file that is already open. """ try: with NamedTemporaryFile(delete=False, **kwargs) as tmp_cmap: yield tmp_cmap.name finally: os.remove(tmp_cmap.name) def _write_cmap_to_file(cmap_filename, cmap_data): ext = os.path.splitext(cmap_filename)[1] if ext in (".npy",): np.save(cmap_filename, cmap_data) elif ext in (".npz",): np.savez(cmap_filename, cmap_data) else: np.savetxt(cmap_filename, cmap_data, delimiter=",") def _generate_cmap_test_data(color_scale, colormap_mode): cmap_data = np.array([ [1, 0, 0], [1, 1, 0], [1, 1, 1], [0, 0, 1], ], dtype=np.float64) if len(colormap_mode) != 3: _cmap_data = cmap_data cmap_data = np.empty((cmap_data.shape[0], len(colormap_mode)), dtype=np.float64) if colormap_mode.startswith("V") or colormap_mode.endswith("A"): cmap_data[:, 0] = np.array([128, 130, 132, 134]) / 255.0 cmap_data[:, -3:] = _cmap_data if colormap_mode.startswith("V") and colormap_mode.endswith("A"): cmap_data[:, 1] = np.array([128, 130, 132, 134]) / 255.0 if color_scale is None or color_scale == 255: cmap_data = (cmap_data * 255).astype(np.uint8) return cmap_data class TestFromFileCreation: """Tests for loading Colormaps from files.""" @pytest.mark.parametrize("csv_filename", [None, "test.cmap"]) @pytest.mark.parametrize("new_range", [None, (25.0, 75.0)]) @pytest.mark.parametrize("color_scale", [1.0, 255, 65535]) def test_csv_roundtrip(self, tmp_path, csv_filename, new_range, color_scale): """Test saving and loading a Colormap from a CSV file.""" orig_cmap = colormap.brbg if new_range is not None: orig_cmap = orig_cmap.set_range(*new_range, inplace=False) if isinstance(csv_filename, str): csv_filename = str(tmp_path / csv_filename) res = orig_cmap.to_csv(csv_filename, color_scale=color_scale) assert res is None new_cmap = colormap.Colormap.from_file(csv_filename, color_scale=color_scale) else: res = orig_cmap.to_csv(None, color_scale=color_scale) assert isinstance(res, str) new_cmap = colormap.Colormap.from_string(res, color_scale=color_scale) np.testing.assert_allclose(orig_cmap.values, new_cmap.values) np.testing.assert_allclose(orig_cmap.colors, new_cmap.colors) @pytest.mark.parametrize("color_scale", [None, 1.0]) @pytest.mark.parametrize("colormap_mode", ["RGB", "VRGB", "VRGBA"]) @pytest.mark.parametrize("filename_suffix", [".npy", ".npz", ".csv"]) def test_cmap_from_file(self, color_scale, colormap_mode, filename_suffix): """Test that colormaps can be loaded from a binary or CSV file.""" # create the colormap file on disk with closed_named_temp_file(suffix=filename_suffix) as cmap_filename: cmap_data = _generate_cmap_test_data(color_scale, colormap_mode) _write_cmap_to_file(cmap_filename, cmap_data) unset_first_value = 128.0 / 255.0 if colormap_mode.startswith("V") else 0.0 unset_last_value = 134.0 / 255.0 if colormap_mode.startswith("V") else 1.0 if (color_scale is None or color_scale == 255) and colormap_mode.startswith("V"): unset_first_value *= 255 unset_last_value *= 255 first_color = [1.0, 0.0, 0.0] if colormap_mode == "VRGBA": first_color = [128.0 / 255.0] + first_color kwargs1 = {} if color_scale is not None: kwargs1["color_scale"] = color_scale cmap = colormap.Colormap.from_file(cmap_filename, **kwargs1) assert cmap.colors.shape[0] == 4 np.testing.assert_equal(cmap.colors[0], first_color) assert cmap.values.shape[0] == 4 assert cmap.values[0] == unset_first_value assert cmap.values[-1] == unset_last_value def test_cmap_vrgb_as_rgba(self): """Test that data created as VRGB still reads as RGBA.""" with closed_named_temp_file(suffix=".npy") as cmap_filename: cmap_data = _generate_cmap_test_data(None, "VRGB") np.save(cmap_filename, cmap_data) cmap = colormap.Colormap.from_file(cmap_filename, colormap_mode="RGBA") assert cmap.colors.shape[0] == 4 assert cmap.colors.shape[1] == 4 # RGBA np.testing.assert_equal(cmap.colors[0], [128 / 255., 1.0, 0, 0]) assert cmap.values.shape[0] == 4 assert cmap.values[0] == 0 assert cmap.values[-1] == 1.0 @pytest.mark.parametrize( ("real_mode", "forced_mode"), [ ("VRGBA", "RGBA"), ("VRGBA", "VRGB"), ("RGBA", "RGB"), ] ) @pytest.mark.parametrize("filename_suffix", [".npy", ".csv"]) def test_cmap_bad_mode(self, real_mode, forced_mode, filename_suffix): """Test that reading colormaps with the wrong mode fails.""" with closed_named_temp_file(suffix=filename_suffix) as cmap_filename: cmap_data = _generate_cmap_test_data(None, real_mode) _write_cmap_to_file(cmap_filename, cmap_data) # Force colormap_mode VRGBA to RGBA and we should see an exception with pytest.raises(ValueError): colormap.Colormap.from_file(cmap_filename, colormap_mode=forced_mode) def test_cmap_from_file_bad_shape(self): """Test that unknown array shape causes an error.""" with closed_named_temp_file(suffix='.npy') as cmap_filename: np.save(cmap_filename, np.array([ [0], [64], [128], [255], ])) with pytest.raises(ValueError): colormap.Colormap.from_file(cmap_filename) @pytest.mark.parametrize("color_scale", [None, 1.0]) def test_cmap_from_np(self, tmp_path, color_scale): """Test creating a colormap from a numpy file.""" cmap_data = _generate_cmap_test_data(color_scale, "RGB") fnp = tmp_path / "test.npy" np.save(fnp, cmap_data) cmap = colormap.Colormap.from_np(fnp, color_scale=color_scale or 255) np.testing.assert_allclose(cmap.values, [0, 0.33333333, 0.6666667, 1]) exp_data = cmap_data if color_scale == 1.0 else cmap_data / 255.0 np.testing.assert_array_equal(cmap.colors, exp_data) @pytest.mark.parametrize("color_scale", [None, 1.0]) def test_cmap_from_csv(self, tmp_path, color_scale): """Test creating a colormap from a CSV file.""" cmap_data = _generate_cmap_test_data(color_scale, "RGB") fnp = tmp_path / "test.csv" np.savetxt(fnp, cmap_data, delimiter=",") cmap = colormap.Colormap.from_csv(fnp, color_scale=color_scale or 255) np.testing.assert_allclose(cmap.values, [0, 0.33333333, 0.66666667, 1]) exp_data = cmap_data if color_scale == 1.0 else cmap_data / 255.0 np.testing.assert_array_equal(cmap.colors, exp_data) def test_cmap_from_string(): """Test creating a colormap from a string.""" s = "0,0,0,0\n1,1,1,1\n2,2,2,2" cmap = colormap.Colormap.from_string(s, color_scale=1) np.testing.assert_array_equal(cmap.values, [0, 1, 2]) np.testing.assert_array_equal(cmap.colors, [[0, 0, 0], [1, 1, 1], [2, 2, 2]]) @pytest.mark.parametrize("color_scale", [None, 255, 1.0]) def test_cmap_from_ndarray(color_scale): """Test creating a colormap from a numpy array.""" cmap_data = _generate_cmap_test_data(color_scale, "RGB") cmap = colormap.Colormap.from_ndarray(cmap_data, color_scale=color_scale or 255) np.testing.assert_allclose(cmap.values, [0, 0.33333333, 0.66666667, 1]) exp_data = cmap_data if color_scale == 1.0 else cmap_data / 255.0 np.testing.assert_array_equal(cmap.colors, exp_data) def test_cmap_from_name(): """Test creating a colormap from a string representing a name.""" cmap = colormap.Colormap.from_name("puor") np.testing.assert_array_equal(cmap.values, colormap.puor.values) np.testing.assert_array_equal(cmap.colors, colormap.puor.colors) def test_cmap_from_sequence_of_colors(): """Test creating a colormap from a sequence of colors.""" colors = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]] cmap = colormap.Colormap.from_sequence_of_colors(colors, color_scale=2) np.testing.assert_allclose(cmap.values, [0, 0.33333333, 0.66666667, 1]) np.testing.assert_array_equal(cmap.colors * 2, colors) vals = [0, 5, 10, 15] cmap = colormap.Colormap.from_sequence_of_colors(colors, values=vals, color_scale=2) np.testing.assert_allclose(cmap.values, [0, 5, 10, 15]) def test_build_colormap_with_int_data_and_without_meanings(): """Test colormap building from uint8 array with metadata.""" palette = np.array([[0, 0, 0], [127, 127, 127], [255, 255, 255]]) cmap = colormap.Colormap.from_array_with_metadata(palette, np.uint8) np.testing.assert_array_equal(cmap.values, [0, 1]) # test that values are respected even if valid_range is passed # see https://github.com/pytroll/satpy/issues/2376 cmap = colormap.Colormap.from_array_with_metadata( palette, np.uint8, valid_range=[0, 100]) np.testing.assert_array_equal(cmap.values, [0, 1]) def test_build_colormap_with_float_data(): """Test colormap building for float data.""" palette = np.array([[0, 0, 0], [127, 127, 127], [255, 255, 255]]) with pytest.raises(AttributeError): colormap.Colormap.from_array_with_metadata(palette / 100, np.float32) cmap = colormap.Colormap.from_array_with_metadata( palette, np.float32, valid_range=[0, 100], scale_factor=2, remove_last=True) np.testing.assert_array_equal(cmap.values, [0, 200]) cmap = colormap.Colormap.from_array_with_metadata( palette, np.float32, valid_range=[0, 100], scale_factor=2, remove_last=False) np.testing.assert_array_equal(cmap.values, [0, 100, 200]) def test_build_colormap_with_int_data_and_with_meanings(): """Test colormap building.""" palette = xarray.DataArray(np.array([[0, 0, 0], [127, 127, 127], [255, 255, 255]]), dims=['value', 'band']) palette.attrs['palette_meanings'] = [2, 3, 4] cmap = colormap.Colormap.from_array_with_metadata(palette, np.uint8) np.testing.assert_array_equal(cmap.values, [2, 3, 4]) def _assert_monotonic_values(cmap, increasing=True): delta = np.diff(cmap.values) np.testing.assert_allclose(delta > 0, increasing) def _assert_unchanged_values(cmap, new_cmap, inplace, orig_values): if inplace: assert cmap is new_cmap np.testing.assert_allclose(cmap.values, orig_values) else: assert cmap is not new_cmap np.testing.assert_allclose(cmap.values, orig_values) np.testing.assert_allclose(new_cmap.values, orig_values) def _assert_unchanged_colors(cmap, new_cmap, orig_colors): np.testing.assert_allclose(cmap.colors, orig_colors) np.testing.assert_allclose(new_cmap.colors, orig_colors) def _assert_reversed_colors(cmap, new_cmap, inplace, orig_colors): if inplace: assert cmap is new_cmap np.testing.assert_allclose(cmap.colors, orig_colors[::-1]) else: assert cmap is not new_cmap np.testing.assert_allclose(cmap.colors, orig_colors) np.testing.assert_allclose(new_cmap.colors, orig_colors[::-1]) def _assert_values_changed(cmap, new_cmap, inplace, orig_values): assert not np.allclose(new_cmap.values, orig_values) if not inplace: np.testing.assert_allclose(cmap.values, orig_values) else: assert not np.allclose(cmap.values, orig_values) def _assert_inplace_worked(cmap, new_cmap, inplace): if not inplace: assert new_cmap is not cmap else: assert new_cmap is cmap trollimage-1.28.0/trollimage/tests/test_image.py000066400000000000000000000635311514066130000217410ustar00rootroot00000000000000"""Module for testing the image module.""" import os import random import sys import tempfile import unittest import numpy as np from trollimage import image from trollimage.colormap import brbg EPSILON = 0.0001 class TestEmptyImage(unittest.TestCase): """Class for testing the mpop.imageo.image module.""" def setUp(self): """Set up the test case.""" self.img = image.Image() self.modes = ["L", "LA", "RGB", "RGBA", "YCbCr", "YCbCrA", "P", "PA"] def test_shape(self): """Shape of an empty image.""" oldmode = self.img.mode for mode in self.modes: self.img.convert(mode) self.assertEqual(self.img.shape, (0, 0)) self.img.convert(oldmode) def test_is_empty(self): """Test if an image is empty.""" self.assertEqual(self.img.is_empty(), True) def test_clip(self): """Clip an empty image.""" oldmode = self.img.mode for mode in self.modes: self.img.convert(mode) self.assertEqual(self.img.channels, []) self.img.convert(oldmode) def test_convert(self): """Convert an empty image.""" for mode1 in self.modes: for mode2 in self.modes: self.img.convert(mode1) self.assertEqual(self.img.mode, mode1) self.assertEqual(self.img.channels, []) self.img.convert(mode2) self.assertEqual(self.img.mode, mode2) self.assertEqual(self.img.channels, []) while True: randstr = random_string(random.choice(range(1, 7))) if randstr not in self.modes: break self.assertRaises(ValueError, self.img.convert, randstr) def test_stretch(self): """Stretch an empty image.""" oldmode = self.img.mode for mode in self.modes: self.img.convert(mode) self.img.stretch() self.assertEqual(self.img.channels, []) self.img.stretch("linear") self.assertEqual(self.img.channels, []) self.img.stretch("histogram") self.assertEqual(self.img.channels, []) self.img.stretch("crude") self.assertEqual(self.img.channels, []) self.img.stretch((0.05, 0.05)) self.assertEqual(self.img.channels, []) self.assertRaises(ValueError, self.img.stretch, (0.05, 0.05, 0.05)) # Generate a random string while True: testmode = random_string(random.choice(range(1, 7))) if testmode not in self.modes: break self.assertRaises(ValueError, self.img.stretch, testmode) self.assertRaises(TypeError, self.img.stretch, 1) self.img.convert(oldmode) def test_gamma(self): """Gamma correction on an empty image.""" oldmode = self.img.mode for mode in self.modes: self.img.convert(mode) # input a single value self.img.gamma() self.assertEqual(self.img.channels, []) self.img.gamma(0.5) self.assertEqual(self.img.channels, []) self.img.gamma(1) self.assertEqual(self.img.channels, []) self.img.gamma(1.5) self.assertEqual(self.img.channels, []) # input a tuple self.assertRaises(ValueError, self.img.gamma, list(range(10))) self.assertRaises(ValueError, self.img.gamma, (0.2, 3.5)) self.img.convert(oldmode) def test_invert(self): """Invert an empty image.""" oldmode = self.img.mode for mode in self.modes: self.img.convert(mode) self.img.invert() self.assertEqual(self.img.channels, []) self.img.invert(True) self.assertEqual(self.img.channels, []) self.assertRaises(ValueError, self.img.invert, [True, False]) self.assertRaises(ValueError, self.img.invert, [True, False, True, False, True, False, True, False]) self.img.convert(oldmode) def test_pil_image(self): """Return an empty PIL image.""" oldmode = self.img.mode for mode in self.modes: self.img.convert(mode) if mode == "YCbCrA": self.assertRaises(ValueError, self.img.pil_image) elif mode == "YCbCr": continue else: pilimg = self.img.pil_image() self.assertEqual(pilimg.size, (0, 0)) self.img.convert(oldmode) def test_putalpha(self): """Add an alpha channel to en empty image.""" # Putting alpha channel to an empty image should not do anything except # change the mode if necessary. oldmode = self.img.mode for mode in self.modes: self.img.convert(mode) self.img.putalpha(np.array([])) self.assertEqual(self.img.channels, []) if mode.endswith("A"): self.assertEqual(self.img.mode, mode) else: self.assertEqual(self.img.mode, mode + "A") self.img.convert(oldmode) self.img.convert(mode) self.assertRaises(ValueError, self.img.putalpha, np.random.rand(3, 2)) self.img.convert(oldmode) def test_save(self): """Save an empty image.""" oldmode = self.img.mode for mode in self.modes: self.img.convert(mode) self.assertRaises(IOError, self.img.save, "test.png") self.img.convert(oldmode) def test_replace_luminance(self): """Replace luminance in an empty image.""" oldmode = self.img.mode for mode in self.modes: self.img.convert(mode) self.img.replace_luminance([]) self.assertEqual(self.img.mode, mode) self.assertEqual(self.img.channels, []) self.assertEqual(self.img.shape, (0, 0)) self.img.convert(oldmode) def test_resize(self): """Resize an empty image.""" self.assertRaises(ValueError, self.img.resize, (10, 10)) def test_merge(self): """Merging of an empty image with another.""" newimg = image.Image() self.assertRaises(ValueError, self.img.merge, newimg) newimg = image.Image(np.array([[1, 2], [3, 4]])) self.assertRaises(ValueError, self.img.merge, newimg) newimg = image.Image(np.array([[1, 2, 3, 4]])) self.assertRaises(ValueError, self.img.merge, newimg) class TestImageCreation(unittest.TestCase): """Class for testing the mpop.imageo.image module.""" def setUp(self): """Set up the test case.""" self.img = {} self.modes = ["L", "LA", "RGB", "RGBA", "YCbCr", "YCbCrA", "P", "PA"] self.modes_len = [1, 2, 3, 4, 3, 4, 1, 2] def test_creation(self): """Test creation of an image.""" self.assertRaises(TypeError, image.Image, channels=random.randint(1, 1000)) self.assertRaises(TypeError, image.Image, channels=random.random()) self.assertRaises(TypeError, image.Image, channels=random_string(random.randint(1, 10))) chs = [np.random.rand(random.randint(1, 10), random.randint(1, 10)), np.random.rand(random.randint(1, 10), random.randint(1, 10)), np.random.rand(random.randint(1, 10), random.randint(1, 10)), np.random.rand(random.randint(1, 10), random.randint(1, 10))] self.assertRaises(ValueError, image.Image, channels=chs) one_channel = np.random.rand(random.randint(1, 10), random.randint(1, 10)) i = 0 for mode in self.modes: # Empty image, no channels self.img[mode] = image.Image(mode=mode) self.assertEqual(self.img[mode].channels, []) # Empty image, no channels, fill value self.img[mode] = image.Image(mode=mode, fill_value=0) self.assertEqual(self.img[mode].channels, []) # Empty image, no channels, fill value, wrong color_range self.assertRaises(ValueError, image.Image, mode=mode, fill_value=0, color_range=((0, (1, 2)))) self.assertRaises(ValueError, image.Image, mode=mode, fill_value=0, color_range=((0, 0), (1, 2), (0, 0), (1, 2), (0, 0), (1, 2))) # Regular image, too many channels self.assertRaises(ValueError, image.Image, channels=([one_channel] * (self.modes_len[i] + 1)), mode=mode) # Regular image, not enough channels self.assertRaises(ValueError, image.Image, channels=([one_channel] * (self.modes_len[i] - 1)), mode=mode) # Regular image, channels self.img[mode] = image.Image(channels=([one_channel] * (self.modes_len[i])), mode=mode) for nb_chan in range(self.modes_len[i]): self.assertTrue(np.all(self.img[mode].channels[nb_chan] == one_channel)) self.assertTrue(isinstance(self.img[mode].channels[nb_chan], np.ma.core.MaskedArray)) i = i + 1 class TestRegularImage(unittest.TestCase): """Class for testing the image module.""" def setUp(self): """Set up the test case.""" one_channel = np.random.rand(random.randint(1, 10), random.randint(1, 10)) self.rand_img = image.Image(channels=[one_channel] * 3, mode="RGB") self.rand_img2 = image.Image(channels=[one_channel] * 3, mode="RGB", fill_value=(0, 0, 0)) two_channel = np.array([[0, 0.5, 0.5], [0.5, 0.25, 0.25]]) self.img = image.Image(channels=[two_channel] * 3, mode="RGB") self.flat_channel = [[1, 1, 1], [1, 1, 1]] self.flat_img = image.Image(channels=[self.flat_channel], mode="L", fill_value=0) self.modes = ["L", "LA", "RGB", "RGBA", "YCbCr", "YCbCrA", "P", "PA"] self.modes_len = [1, 2, 3, 4, 3, 4, 1, 2] # create an unusable directory for permission error checking self.tempdir = tempfile.mkdtemp() os.chmod(self.tempdir, 0o444) def test_shape(self): """Shape of an image.""" oldmode = self.img.mode for mode in self.modes: if mode == "P" or mode == "PA": continue self.img.convert(mode) self.assertEqual(self.img.shape, (2, 3)) self.img.convert(oldmode) def test_is_empty(self): """Test if an image is empty.""" self.assertEqual(self.img.is_empty(), False) def test_clip(self): """Clip an image.""" oldmode = self.img.mode for mode in self.modes: if mode == "P" or mode == "PA": continue self.img.convert(mode) for chn in self.img.channels: self.assertTrue(chn.max() <= 1.0) self.assertTrue(chn.max() >= 0.0) self.img.convert(oldmode) def test_convert(self): """Convert an image.""" i = 0 for mode1 in self.modes: j = 0 for mode2 in self.modes: self.img.convert(mode1) self.assertEqual(self.img.mode, mode1) self.assertEqual(len(self.img.channels), self.modes_len[i]) self.img.convert(mode2) self.assertEqual(self.img.mode, mode2) self.assertEqual(len(self.img.channels), self.modes_len[j]) self.rand_img2.convert(mode1) self.assertEqual(self.rand_img2.mode, mode1) self.assertEqual(len(self.rand_img2.channels), self.modes_len[i]) if mode1 not in ["P", "PA"]: self.assertEqual(len(self.rand_img2.fill_value), self.modes_len[i]) self.rand_img2.convert(mode2) self.assertEqual(self.rand_img2.mode, mode2) self.assertEqual(len(self.rand_img2.channels), self.modes_len[j]) if mode2 not in ["P", "PA"]: self.assertEqual(len(self.rand_img2.fill_value), self.modes_len[j]) j = j + 1 i = i + 1 while True: randstr = random_string(random.choice(range(1, 7))) if randstr not in self.modes: break self.assertRaises(ValueError, self.img.convert, randstr) def test_stretch(self): """Stretch an image.""" oldmode = self.img.mode for mode in "L": self.img.convert(mode) old_channels = [] for chn in self.img.channels: old_channels.append(chn) linear = np.array([[0., 1.00048852, 1.00048852], [1.00048852, 0.50024426, 0.50024426]]) crude = np.array([[0, 1, 1], [1, 0.5, 0.5]]) histo = np.array([[0.0, 0.99951171875, 0.99951171875], [0.99951171875, 0.39990234375, 0.39990234375]]) self.img.stretch() self.assertTrue(np.all((self.img.channels[0] - crude) < EPSILON)) self.img.stretch("linear") self.assertTrue(np.all((self.img.channels[0] - linear) < EPSILON)) self.img.stretch("crude") self.assertTrue(np.all((self.img.channels[0] - crude) < EPSILON)) self.img.stretch("histogram") self.assertTrue( np.all(np.abs(self.img.channels[0] - histo) < EPSILON)) self.img.stretch((0.05, 0.05)) self.assertTrue(np.all((self.img.channels[0] - linear) < EPSILON)) self.assertRaises(ValueError, self.img.stretch, (0.05, 0.05, 0.05)) # Generate a random string while True: testmode = random_string(random.choice(range(1, 7))) if testmode not in self.modes: break self.assertRaises(ValueError, self.img.stretch, testmode) self.assertRaises(TypeError, self.img.stretch, 1) self.img.channels = old_channels self.img.convert(oldmode) def test_gamma(self): """Gamma correction on an image.""" oldmode = self.img.mode for mode in self.modes: if mode == "P" or mode == "PA": continue self.img.convert(mode) old_channels = [] for chn in self.img.channels: old_channels.append(chn) # input a single value self.img.gamma() for i in range(len(self.img.channels)): self.assertTrue(np.all(self.img.channels[i] == old_channels[i])) self.img.gamma(0.5) for i in range(len(self.img.channels)): self.assertTrue(np.all(self.img.channels[i] - old_channels[i] ** 2 < EPSILON)) self.img.gamma(1) for i in range(len(self.img.channels)): self.assertTrue(np.all(self.img.channels[i] - old_channels[i] ** 2 < EPSILON)) # self.img.gamma(2) # for i in range(len(self.img.channels)): # print self.img.channels[i] # print old_channels[i] # self.assertTrue(np.all(np.abs(self.img.channels[i] - # old_channels[i]) < EPSILON)) # input a tuple self.assertRaises(ValueError, self.img.gamma, list(range(10))) self.assertRaises( ValueError, self.img.gamma, (0.2, 3., 8., 1., 9.)) self.img.convert(oldmode) def test_invert(self): """Invert an image.""" oldmode = self.img.mode for mode in self.modes: if mode == "P" or mode == "PA": continue self.img.convert(mode) old_channels = [] for chn in self.img.channels: old_channels.append(chn) self.img.invert() for i in range(len(self.img.channels)): self.assertTrue(np.all(self.img.channels[i] == 1 - old_channels[i])) self.img.invert(True) for i in range(len(self.img.channels)): self.assertTrue(np.all(self.img.channels[i] - old_channels[i] < EPSILON)) self.assertRaises(ValueError, self.img.invert, [True, False, True, False, True, False, True, False]) self.img.convert(oldmode) def test_pil_image(self): """Return an PIL image.""" # FIXME: Should test on palette images oldmode = self.img.mode for mode in self.modes: if (mode == "YCbCr" or mode == "YCbCrA" or mode == "P" or mode == "PA"): continue self.img.convert(mode) pilimg = self.img.pil_image() self.assertEqual(pilimg.size, (3, 2)) self.img.convert(oldmode) def test_putalpha(self): """Add an alpha channel.""" # Putting alpha channel to an image should not do anything except # change the mode if necessary. oldmode = self.img.mode alpha = np.array(np.random.rand(2, 3)) for mode in self.modes: if mode == "P" or mode == "PA": continue self.img.convert(mode) self.img.putalpha(alpha) self.assertTrue(np.all(self.img.channels[-1] == alpha)) if mode.endswith("A"): self.assertEqual(self.img.mode, mode) else: self.assertEqual(self.img.mode, mode + "A") self.img.convert(oldmode) self.img.convert(mode) self.assertRaises(ValueError, self.img.putalpha, np.random.rand(4, 5)) self.img.convert(oldmode) @unittest.skipIf(sys.platform.startswith('win'), "Read-only tmp dir not working under Windows") def test_save(self): """Save an image.""" oldmode = self.img.mode for mode in self.modes: if (mode == "YCbCr" or mode == "YCbCrA" or mode == "P" or mode == "PA"): continue self.img.convert(mode) self.img.save("test.png") self.assertTrue(os.path.exists("test.png")) os.remove("test.png") # permissions self.assertRaises(IOError, self.img.save, os.path.join(self.tempdir, "test.png")) self.img.convert(oldmode) @unittest.skipIf(sys.platform.startswith('win'), "Read-only tmp dir not working under Windows") def test_save_jpeg(self): """Save a jpeg image.""" oldmode = self.img.mode self.img.convert('L') self.img.save("test.jpg") self.assertTrue(os.path.exists("test.jpg")) os.remove("test.jpg") # permissions self.assertRaises(IOError, self.img.save, os.path.join(self.tempdir, "test.jpg")) self.img.convert(oldmode) def test_replace_luminance(self): """Replace luminance in an image.""" oldmode = self.img.mode for mode in self.modes: if (mode == "P" or mode == "PA"): continue self.img.convert(mode) luma = np.ma.array([[0, 0.5, 0.5], [0.5, 0.25, 0.25]]) self.img.replace_luminance(luma) self.assertEqual(self.img.mode, mode) if (self.img.mode.endswith("A")): chans = self.img.channels[:-1] else: chans = self.img.channels for chn in chans: self.assertTrue(np.all(chn - luma < EPSILON)) self.img.convert(oldmode) def test_resize(self): """Resize an image.""" self.img.resize((6, 6)) res = np.array([[0, 0, 0.5, 0.5, 0.5, 0.5], [0, 0, 0.5, 0.5, 0.5, 0.5], [0, 0, 0.5, 0.5, 0.5, 0.5], [0.5, 0.5, 0.25, 0.25, 0.25, 0.25], [0.5, 0.5, 0.25, 0.25, 0.25, 0.25], [0.5, 0.5, 0.25, 0.25, 0.25, 0.25]]) self.assertTrue(np.all(res == self.img.channels[0])) self.img.resize((2, 3)) res = np.array([[0, 0.5, 0.5], [0.5, 0.25, 0.25]]) self.assertTrue(np.all(res == self.img.channels[0])) def test_merge(self): """Merging of an image with another.""" newimg = image.Image() self.assertRaises(ValueError, self.img.merge, newimg) newimg = image.Image(np.array([[1, 2], [3, 4]])) self.assertRaises(ValueError, self.img.merge, newimg) newimg = image.Image(np.array([[1, 2, 3, 4]])) self.assertRaises(ValueError, self.img.merge, newimg) newimg = image.Image(np.ma.array([[1, 2, 3], [4, 5, 6]], mask=[[1, 0, 0], [1, 1, 0]]), mode="L") self.img.convert("L") newimg.merge(self.img) self.assertTrue(np.all(np.abs(newimg.channels[0] - np.array([[0, 2, 3], [0.5, 0.25, 6]])) < EPSILON)) def tearDown(self): """Clean up the mess.""" os.chmod(self.tempdir, 0o777) os.rmdir(self.tempdir) class TestFlatImage(unittest.TestCase): """Test a flat image, ie an image where min == max.""" def setUp(self): """Set up the test case.""" channel = np.ma.array([[0, 0.5, 0.5], [0.5, 0.25, 0.25]], mask=[[1, 1, 1], [1, 1, 0]]) self.img = image.Image(channels=[channel] * 3, mode="RGB") self.modes = ["L", "LA", "RGB", "RGBA", "YCbCr", "YCbCrA", "P", "PA"] def test_stretch(self): """Stretch a flat image.""" self.img.stretch() self.assertTrue(self.img.channels[0].shape == (2, 3) and np.ma.count_masked(self.img.channels[0]) == 5) self.img.stretch("crude") self.assertTrue(self.img.channels[0].shape == (2, 3) and np.ma.count_masked(self.img.channels[0]) == 5) self.img.crude_stretch(1, 2) self.assertTrue(self.img.channels[0].shape == (2, 3) and np.ma.count_masked(self.img.channels[0]) == 5) self.img.stretch("linear") self.assertTrue(self.img.channels[0].shape == (2, 3) and np.ma.count_masked(self.img.channels[0]) == 5) self.img.stretch("histogram") self.assertTrue(self.img.channels[0].shape == (2, 3) and np.ma.count_masked(self.img.channels[0]) == 5) class TestNoDataImage(unittest.TestCase): """Test an image filled with no data.""" def setUp(self): """Set up the test case.""" channel = np.ma.array([[0, 0.5, 0.5], [0.5, 0.25, 0.25]], mask=[[1, 1, 1], [1, 1, 1]]) self.img = image.Image(channels=[channel] * 3, mode="RGB") self.modes = ["L", "LA", "RGB", "RGBA", "YCbCr", "YCbCrA", "P", "PA"] def test_stretch(self): """Stretch a no data image.""" self.img.stretch() self.assertTrue(self.img.channels[0].shape == (2, 3)) self.img.stretch("crude") self.assertTrue(self.img.channels[0].shape == (2, 3)) self.img.crude_stretch(1, 2) self.assertTrue(self.img.channels[0].shape == (2, 3)) self.img.stretch("linear") self.assertTrue(self.img.channels[0].shape == (2, 3)) self.img.stretch("histogram") self.assertTrue(self.img.channels[0].shape == (2, 3)) def random_string(length, choices="abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"): """Generate a random string with elements from *set* of the specified *length*.""" return "".join([random.choice(choices) for dummy in range(length)]) class TestImageColorize: """Test the colorize method of the Image class.""" def test_colorize_la_rgb(self): """Test colorizing an LA image with an RGB colormap.""" from .test_xrimage import TestXRImageColorize arr = np.arange(75).reshape(5, 15) / 74. alpha = arr > (8.0 / 74.0) img = image.Image(channels=[arr.copy(), alpha], mode="LA") img.colorize(brbg) expected = list(TestXRImageColorize._expected[np.float64]) np.testing.assert_allclose(img.channels[0], expected[0]) np.testing.assert_allclose(img.channels[1], expected[1]) np.testing.assert_allclose(img.channels[2], expected[2]) np.testing.assert_allclose(img.channels[3], alpha) trollimage-1.28.0/trollimage/tests/test_xrimage.py000066400000000000000000003042721514066130000223130ustar00rootroot00000000000000"""Module for testing the xrimage module.""" import sys from datetime import timezone, datetime import warnings from unittest import mock from collections import OrderedDict from tempfile import NamedTemporaryFile import dask.array as da import numpy as np import xarray as xr import rasterio as rio import pytest from trollimage import xrimage from trollimage.colormap import Colormap, brbg from trollimage._xrimage_rasterio import RIODataset from .utils import assert_maximum_dask_computes class TestXRImage: """Test XRImage objects.""" def test_init(self): """Test object initialization.""" data = xr.DataArray([[0, 0.5, 0.5], [0.5, 0.25, 0.25]], dims=['y', 'x']) img = xrimage.XRImage(data) assert img.mode == 'L' data = xr.DataArray([[0, 0.5, 0.5], [0.5, 0.25, 0.25]]) img = xrimage.XRImage(data) assert img.mode == 'L' assert img.data.dims == ('bands', 'y', 'x') data = xr.DataArray([[0, 0.5, 0.5], [0.5, 0.25, 0.25]], dims=['x', 'y_2']) img = xrimage.XRImage(data) assert img.mode == 'L' assert img.data.dims == ('bands', 'x', 'y') data = xr.DataArray([[0, 0.5, 0.5], [0.5, 0.25, 0.25]], dims=['x_2', 'y']) img = xrimage.XRImage(data) assert img.mode == 'L' assert img.data.dims == ('bands', 'x', 'y') data = xr.DataArray(np.arange(75).reshape(5, 5, 3), dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) assert img.mode == 'RGB' data = xr.DataArray(np.arange(100).reshape(5, 5, 4), dims=[ 'y', 'x', 'bands'], coords={'bands': ['Y', 'Cb', 'Cr', 'A']}) img = xrimage.XRImage(data) assert img.mode == 'YCbCrA' def test_init_writability(self): """Test data is writable after init. Xarray >0.15 makes data read-only after expand_dims. """ data = xr.DataArray([[0, 0.5, 0.5], [0.5, 0.25, 0.25]], dims=['y', 'x']) img = xrimage.XRImage(data) assert img.mode == 'L' n_arr = np.asarray(img.data) # if this succeeds then its writable n_arr[n_arr == 0.5] = 1 def test_regression_double_format_save(self): """Test that double format information isn't passed to save.""" data = xr.DataArray(np.arange(75).reshape(5, 5, 3) / 74., dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) with mock.patch.object(xrimage.XRImage, 'pil_save') as pil_save: img = xrimage.XRImage(data) img.save(filename='bla.png', fformat='png', format='png') assert 'format' not in pil_save.call_args_list[0][1] @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_rgb_save(self): """Test saving RGB/A data to simple image formats.""" data = xr.DataArray(np.arange(75).reshape(5, 5, 3) / 74., dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) with NamedTemporaryFile(suffix='.png') as tmp: img.save(tmp.name) with rio.open(tmp.name) as f: file_data = f.read() assert file_data.shape == (4, 5, 5) # alpha band added exp = (np.arange(75.).reshape(5, 5, 3) / 74. * 255).round() np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) np.testing.assert_allclose(file_data[3], 255) # completely opaque data = data.where(data > (10 / 74.0)) img = xrimage.XRImage(data) with NamedTemporaryFile(suffix='.png') as tmp: img.save(tmp.name) # dask delayed save with NamedTemporaryFile(suffix='.png') as tmp: delay = img.save(tmp.name, compute=False) assert isinstance(delay, da.Array) delay.compute() @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_single_band_jpeg(self): """Test saving single band to jpeg formats.""" # Single band image data = np.arange(75).reshape(15, 5, 1) / 74. data[-1, -1, 0] = np.nan data = xr.DataArray(data, dims=[ 'y', 'x', 'bands'], coords={'bands': ['L']}) # Single band image to JPEG img = xrimage.XRImage(data) with NamedTemporaryFile(suffix='.jpg') as tmp: img.save(tmp.name, fill_value=0) with rio.open(tmp.name) as f: file_data = f.read() assert file_data.shape == (1, 15, 5) # can't check data accuracy because jpeg compression will # change the values # Jpeg fails without fill value (no alpha handling) with NamedTemporaryFile(suffix='.jpg') as tmp: # make sure fill_value is mentioned in the error message with pytest.raises(OSError, match=r".*fill_value.*"): img.save(tmp.name) @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_single_band_png(self): """Test saving single band images to simple image formats.""" # Single band image data = np.arange(75).reshape(15, 5, 1) / 74. data[-1, -1, 0] = np.nan data = xr.DataArray(data, dims=[ 'y', 'x', 'bands'], coords={'bands': ['L']}) # Single band image to JPEG img = xrimage.XRImage(data) # Single band image to PNG - min fill (check fill value scaling) with NamedTemporaryFile(suffix='.png') as tmp: img.save(tmp.name, fill_value=0) with rio.open(tmp.name) as f: file_data = f.read() assert file_data.shape == (1, 15, 5) exp = (np.arange(75.).reshape(1, 15, 5) / 74. * 254 + 1).round() exp[0, -1, -1] = 0 np.testing.assert_allclose(file_data, exp) # Single band image to PNG - max fill (check fill value scaling) with NamedTemporaryFile(suffix='.png') as tmp: img.save(tmp.name, fill_value=255) with rio.open(tmp.name) as f: file_data = f.read() assert file_data.shape == (1, 15, 5) exp = (np.arange(75.).reshape(1, 15, 5) / 74. * 254).round() exp[0, -1, -1] = 255 np.testing.assert_allclose(file_data, exp) # As PNG that support alpha channel with NamedTemporaryFile(suffix='.png') as tmp: img.save(tmp.name) with rio.open(tmp.name) as f: file_data = f.read() assert file_data.shape == (2, 15, 5) # bad value should be transparent in alpha channel assert file_data[1, -1, -1] == 0 # all other pixels should be opaque assert file_data[1, 0, 0] == 255 @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_palettes(self): """Test saving paletted images to simple image formats.""" # Single band image palettized from trollimage.colormap import brbg, Colormap data = xr.DataArray(np.arange(75).reshape(15, 5, 1) / 74., dims=[ 'y', 'x', 'bands'], coords={'bands': ['L']}) img = xrimage.XRImage(data) img.palettize(brbg) with NamedTemporaryFile(suffix='.png') as tmp: img.save(tmp.name) img = xrimage.XRImage(data) # RGBA colormap bw = Colormap( (0.0, (1.0, 1.0, 1.0, 1.0)), (1.0, (0.0, 0.0, 0.0, 0.5)), ) img.palettize(bw) with NamedTemporaryFile(suffix='.png') as tmp: img.save(tmp.name) def test_save_geotiff_float_numpy_array(self, tmp_path): """Test saving geotiffs when input data is float.""" # numpy array image - scale to 0 to 1 first data = xr.DataArray(np.arange(75).reshape((5, 5, 3)) / 75., dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) filename = tmp_path / "image.tif" img.save(filename) with rio.open(filename) as f: file_data = f.read() assert file_data.shape == (4, 5, 5) # alpha band added exp = (np.arange(75.).reshape(5, 5, 3) / 75. * 255).round() np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) np.testing.assert_allclose(file_data[3], 255) # completely opaque def test_save_geotiff_float_dask_array(self, tmp_path): """Test saving geotiffs when input data is float.""" data = xr.DataArray(da.from_array(np.arange(75.).reshape((5, 5, 3)) / 75., chunks=5), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) filename = tmp_path / "image.tif" img.save(filename) with rio.open(filename) as f: file_data = f.read() assert file_data.shape == (4, 5, 5) # alpha band added exp = (np.arange(75.).reshape(5, 5, 3) / 75. * 255).round() np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) np.testing.assert_allclose(file_data[3], 255) # completely opaque def test_save_geotiff_float_dask_array_with_nans(self, tmp_path): """Test saving geotiffs when input data is float.""" data = xr.DataArray(da.from_array(np.arange(75.).reshape((5, 5, 3)) / 75., chunks=5), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) data = data.where(data > 10. / 75.) img = xrimage.XRImage(data) filename = tmp_path / "image.tif" with warnings.catch_warnings(): warnings.simplefilter("error", RuntimeWarning) img.save(filename) with rio.open(filename) as f: file_data = f.read() assert file_data.shape == (4, 5, 5) # alpha band added exp = np.arange(75.).reshape(5, 5, 3) / 75. exp[exp <= 10. / 75.] = 0 # numpy converts NaNs to 0s exp = (exp * 255).round() np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) is_null = (exp == 0).all(axis=2) np.testing.assert_allclose(file_data[3][~is_null], 255) # completely opaque np.testing.assert_allclose(file_data[3][is_null], 0) # completely transparent def test_save_geotiff_float_dask_array_with_nans_and_fill_value(self, tmp_path): """Test saving geotiffs when input data is float.""" data = xr.DataArray(da.from_array(np.arange(75.).reshape((5, 5, 3)) / 75., chunks=5), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) data = data.where(data > 10. / 75.) img = xrimage.XRImage(data) filename = tmp_path / "image.tif" with pytest.warns(UserWarning, match="fill value will overlap with valid data"): img.save(filename, fill_value=128) with rio.open(filename) as f: file_data = f.read() assert file_data.shape == (3, 5, 5) # no alpha band exp = np.arange(75.).reshape(5, 5, 3) / 75. exp2 = (exp * 255).round() exp2[exp <= 10. / 75.] = 128 np.testing.assert_allclose(file_data[0], exp2[:, :, 0]) np.testing.assert_allclose(file_data[1], exp2[:, :, 1]) np.testing.assert_allclose(file_data[2], exp2[:, :, 2]) def test_save_geotiff_float_dask_array_to_float(self, tmp_path): """Test saving geotiffs when input data is float.""" data = xr.DataArray(da.from_array(np.arange(75.).reshape((5, 5, 3)) / 75., chunks=5), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) data = data.where(data > 10. / 75.) img = xrimage.XRImage(data) filename = tmp_path / "image.tif" img.save(filename, dtype=np.float32) with rio.open(filename) as f: file_data = f.read() assert file_data.shape == (3, 5, 5) # no alpha band exp = np.arange(75.).reshape(5, 5, 3) / 75. # fill value is forced to 0 exp[exp <= 10. / 75.] = 0 np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) def test_save_geotiff_float_dask_array_to_float_with_nans_fill_value(self, tmp_path): """Test saving geotiffs when input data is float.""" data = xr.DataArray(da.from_array(np.arange(75.).reshape((5, 5, 3)) / 75., chunks=5), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) data = data.where(data > 10. / 75.) img = xrimage.XRImage(data) filename = tmp_path / "image.tif" img.save(filename, dtype=np.float32, fill_value=np.nan) with rio.open(filename) as f: file_data = f.read() assert file_data.shape == (3, 5, 5) # no alpha band exp = np.arange(75.).reshape(5, 5, 3) / 75. exp[exp <= 10. / 75.] = np.nan np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) def test_save_geotiff_float_dask_array_to_float_with_numeric_fill_value(self, tmp_path): """Test saving geotiffs when input data is float.""" data = xr.DataArray(da.from_array(np.arange(75.).reshape((5, 5, 3)) / 75., chunks=5), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) data = data.where(data > 10. / 75.) img = xrimage.XRImage(data) filename = tmp_path / "image.tif" img.save(filename, dtype=np.float32, fill_value=128) with rio.open(filename) as f: file_data = f.read() assert file_data.shape == (3, 5, 5) # no alpha band exp = np.arange(75.).reshape(5, 5, 3) / 75. exp[exp <= 10. / 75.] = 128 np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) def test_save_geotiff_float_dask_array_to_signed_int(self, tmp_path): """Test saving geotiffs when input data is float.""" data = xr.DataArray(da.from_array(np.arange(75.).reshape((5, 5, 3)) / 75., chunks=5), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) data = data.where(data > 10. / 75.) img = xrimage.XRImage(data) filename = tmp_path / "image.tif" with pytest.warns(UserWarning, match="fill value will overlap with valid data"): img.save(filename, dtype=np.int16, fill_value=-128) with rio.open(filename) as f: file_data = f.read() assert file_data.shape == (3, 5, 5) # no alpha band exp = np.arange(75.).reshape(5, 5, 3) / 75. exp2 = (exp * (2 ** 16 - 1) - (2 ** 15)).round() exp2[exp <= 10. / 75.] = -128. np.testing.assert_allclose(file_data[0], exp2[:, :, 0]) np.testing.assert_allclose(file_data[1], exp2[:, :, 1]) np.testing.assert_allclose(file_data[2], exp2[:, :, 2]) def test_delayed_save_geotiff_float_dask_array(self, tmp_path): """Test saving geotiffs when input data is float.""" data = xr.DataArray(da.from_array(np.arange(75.).reshape((5, 5, 3)) / 75., chunks=5), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) data = data.where(data > 10. / 75.) img = xrimage.XRImage(data) filename = tmp_path / "image.tif" delay = img.save(filename, compute=False) assert isinstance(delay, tuple) assert isinstance(delay[0], list) assert isinstance(delay[1], list) assert isinstance(delay[0][0], da.Array) assert isinstance(delay[1][0], RIODataset) da.store(*delay) delay[1][0].close() def test_save_geotiff_float_dask_array_with_alpha(self, tmp_path): """Test saving geotiffs when input data is float.""" data = xr.DataArray(da.from_array(np.arange(75.).reshape((5, 5, 3)) / 75., chunks=5), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) data = data.where(data > 10. / 75.) alpha = xr.ones_like(data[:, :, 0]) alpha = alpha.where(data.notnull().all(dim='bands'), 0) alpha['bands'] = 'A' # make a float version of a uint8 RGBA rgb_data = xr.concat((data, alpha), dim='bands') img = xrimage.XRImage(rgb_data) filename = tmp_path / "image.tif" img.save(filename) with rio.open(filename) as f: file_data = f.read() assert file_data.shape == (4, 5, 5) # alpha band already existed exp = np.arange(75.).reshape(5, 5, 3) / 75. exp[exp <= 10. / 75.] = 0 # numpy converts NaNs to 0s exp = (exp * 255.).round() np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) not_null = (alpha != 0).values np.testing.assert_allclose(file_data[3][not_null], 255) # completely opaque np.testing.assert_allclose(file_data[3][~not_null], 0) # completely transparent @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_geotiff_datetime(self): """Test saving geotiffs when start_time is in the attributes.""" data = xr.DataArray(np.arange(75).reshape(5, 5, 3), dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) # "None" as start_time in the attributes data.attrs['start_time'] = None tags = _get_tags_after_writing_to_geotiff(data) assert "TIFFTAG_DATETIME" not in tags # Valid datetime data.attrs['start_time'] = datetime.now(timezone.utc) tags = _get_tags_after_writing_to_geotiff(data) assert "TIFFTAG_DATETIME" in tags @pytest.mark.parametrize("output_ext", [".tif", ".tiff"]) @pytest.mark.parametrize("use_dask", [False, True]) @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_geotiff_int(self, output_ext, use_dask): """Test saving geotiffs when input data is int.""" arr = np.arange(75).reshape(5, 5, 3) if use_dask: arr = da.from_array(arr, chunks=5) data = xr.DataArray(arr, dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) assert np.issubdtype(img.data.dtype, np.integer) with NamedTemporaryFile(suffix=output_ext) as tmp: img.save(tmp.name) with rio.open(tmp.name) as f: file_data = f.read() assert file_data.shape == (4, 5, 5) # alpha band added exp = np.arange(75).reshape(5, 5, 3) np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) np.testing.assert_allclose(file_data[3], 255) @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_geotiff_delayed(self): """Test saving a geotiff but not computing the result immediately.""" data = xr.DataArray(np.arange(75).reshape(5, 5, 3), dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) assert np.issubdtype(img.data.dtype, np.integer) with NamedTemporaryFile(suffix='.tif') as tmp: delay = img.save(tmp.name, compute=False) assert isinstance(delay, tuple) assert isinstance(delay[0], list) assert isinstance(delay[1], list) assert isinstance(delay[0][0], da.Array) assert isinstance(delay[1][0], RIODataset) da.store(*delay) delay[1][0].close() @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_geotiff_int_gcps(self): """Test saving geotiffs when input data is int and has GCPs.""" from rasterio.control import GroundControlPoint from pyresample import SwathDefinition gcps = [GroundControlPoint(1, 1, 100.0, 1000.0, z=0.0), GroundControlPoint(2, 3, 400.0, 2000.0, z=0.0)] crs = 'epsg:4326' lons = xr.DataArray(da.from_array(np.arange(25).reshape(5, 5), chunks=5), dims=['y', 'x'], attrs={ 'gcps': gcps, 'crs': crs }) lats = xr.DataArray(da.from_array(np.arange(25).reshape(5, 5), chunks=5), dims=['y', 'x'], attrs={ 'gcps': gcps, 'crs': crs }) swath_def = SwathDefinition(lons, lats) data = xr.DataArray(da.from_array(np.arange(75).reshape(5, 5, 3), chunks=5), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}, attrs={'area': swath_def}) img = xrimage.XRImage(data) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name) with rio.open(tmp.name) as f: fgcps, fcrs = f.gcps for ref, val in zip(gcps, fgcps): assert ref.col == val.col assert ref.row == val.row assert ref.x == val.x assert ref.y == val.y assert ref.z == val.z assert crs == fcrs @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_geotiff_int_no_gcp_swath(self): """Test saving geotiffs when input data whose SwathDefinition has no GCPs. If shouldn't fail, but it also shouldn't have a non-default transform. """ from pyresample import SwathDefinition lons = xr.DataArray(da.from_array(np.arange(25).reshape(5, 5), chunks=5), dims=['y', 'x'], attrs={}) lats = xr.DataArray(da.from_array(np.arange(25).reshape(5, 5), chunks=5), dims=['y', 'x'], attrs={}) swath_def = SwathDefinition(lons, lats) data = xr.DataArray(da.from_array(np.arange(75).reshape(5, 5, 3), chunks=5), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}, attrs={'area': swath_def}) img = xrimage.XRImage(data) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name) with rio.open(tmp.name) as f: assert f.transform.a == 1.0 assert f.transform.b == 0.0 assert f.transform.c == 0.0 @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_geotiff_int_rio_colormap(self): """Test saving geotiffs when input data is int and a rasterio colormap is provided.""" exp_cmap = {i: (i, 255 - i, i, 255) for i in range(256)} data = xr.DataArray(da.from_array(np.arange(81).reshape(9, 9, 1), chunks=9), dims=['y', 'x', 'bands'], coords={'bands': ['P']}) img = xrimage.XRImage(data) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name, keep_palette=True, cmap=exp_cmap) with rio.open(tmp.name) as f: file_data = f.read() cmap = f.colormap(1) assert file_data.shape == (1, 9, 9) # no alpha band exp = np.arange(81).reshape(9, 9, 1) np.testing.assert_allclose(file_data[0], exp[:, :, 0]) assert cmap == exp_cmap @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_geotiff_int_with_fill(self): """Test saving geotiffs when input data is int and a fill value is specified.""" data = np.arange(75).reshape(5, 5, 3) # second pixel is all bad # pixel [0, 1, 1] is also naturally 5 by arange above data[0, 1, :] = 5 data = xr.DataArray(da.from_array(data, chunks=5), dims=['y', 'x', 'bands'], attrs={'_FillValue': 5}, coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) assert np.issubdtype(img.data.dtype, np.integer) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name, fill_value=128) with rio.open(tmp.name) as f: file_data = f.read() assert file_data.shape == (3, 5, 5) # no alpha band exp = np.arange(75).reshape(5, 5, 3) exp[0, 1, :] = 128 exp[0, 1, 1] = 128 np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_geotiff_int_with_fill_and_alpha(self): """Test saving int geotiffs with a fill value and input alpha band.""" data = np.arange(75).reshape(5, 5, 3) # second pixel is all bad # pixel [0, 1, 1] is also naturally 5 by arange above data[0, 1, :] = 5 data = xr.DataArray(da.from_array(data, chunks=5), dims=['y', 'x', 'bands'], attrs={'_FillValue': 5}, coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) assert np.issubdtype(img.data.dtype, np.integer) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name) with rio.open(tmp.name) as f: file_data = f.read() assert file_data.shape == (4, 5, 5) # no alpha band exp = np.arange(75).reshape(5, 5, 3) exp[0, 1, :] = 5 exp[0, 1, 1] = 5 exp_alpha = np.ones((5, 5)) * 255 exp_alpha[0, 1] = 0 np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) np.testing.assert_allclose(file_data[3], exp_alpha) @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_geotiff_int_with_area_def(self): """Test saving a integer image with an AreaDefinition.""" from pyproj import CRS from pyresample import AreaDefinition crs = CRS.from_user_input(4326) area_def = AreaDefinition( "test", "test", "", crs, 5, 5, [-300, -250, 200, 250], ) data = xr.DataArray(np.arange(75).reshape(5, 5, 3), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}, attrs={"area": area_def}) img = xrimage.XRImage(data) assert np.issubdtype(img.data.dtype, np.integer) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name) with rio.open(tmp.name) as f: file_data = f.read() assert f.crs.to_epsg() == 4326 geotransform = f.transform assert geotransform.a == 100 assert geotransform.c == -300 assert geotransform.e == -100 assert geotransform.f == 250 assert file_data.shape == (4, 5, 5) # alpha band added exp = np.arange(75).reshape(5, 5, 3) np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) np.testing.assert_allclose(file_data[3], 255) @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") @pytest.mark.parametrize( "cmap", [ Colormap(*tuple((i, (i / 20, i / 20, i / 20)) for i in range(20))), Colormap(*tuple((i + 0.00001, (i / 20, i / 20, i / 20)) for i in range(20))), Colormap(*tuple((i if i != 2 else 2.00000001, (i / 20, i / 20, i / 20)) for i in range(20))), ] ) def test_save_geotiff_int_with_cmap(self, cmap): """Test saving integer data to geotiff with a colormap. Rasterio specifically can't handle colormaps that are not round integers. Unfortunately it only warns when it finds a value in the color table that it doesn't expect. For example if an unsigned 8-bit color table is being filled with a trollimage Colormap where due to floating point one of the values is 15.0000001 instead of 15.0, rasterio will issue a warning and then not add a color for that value. This test makes sure the colormap written is the colormap read back. """ exp_cmap = {i: (int(i * 255 / 19), int(i * 255 / 19), int(i * 255 / 19), 255) for i in range(20)} exp_cmap.update({i: (0, 0, 0, 255) for i in range(20, 256)}) data = xr.DataArray(da.from_array(np.arange(81).reshape(9, 9, 1), chunks=9), dims=['y', 'x', 'bands'], coords={'bands': ['P']}) img = xrimage.XRImage(data) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name, keep_palette=True, cmap=cmap) with rio.open(tmp.name) as f: file_data = f.read() cmap = f.colormap(1) assert file_data.shape == (1, 9, 9) # no alpha band exp = np.arange(81).reshape(9, 9, 1) np.testing.assert_allclose(file_data[0], exp[:, :, 0]) assert cmap == exp_cmap @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_geotiff_int_with_bad_cmap(self): """Test saving integer data to geotiff with a bad colormap.""" t_cmap = Colormap(*tuple((i, (i / 20, i / 20, i / 20)) for i in range(20))) bad_cmap = [[i, [i, i, i]] for i in range(256)] data = xr.DataArray(da.from_array(np.arange(81).reshape(9, 9, 1), chunks=9), dims=['y', 'x', 'bands'], coords={'bands': ['P']}) img = xrimage.XRImage(data) with NamedTemporaryFile(suffix='.tif') as tmp: with pytest.raises(ValueError): img.save(tmp.name, keep_palette=True, cmap=bad_cmap) with pytest.raises(ValueError): img.save(tmp.name, keep_palette=True, cmap=t_cmap, dtype='uint16') def test_save_geotiff_with_cmap_and_fill_value(self, tmp_path): """Test saving GeoTIFF with colormap and fill value.""" import rasterio test_file = tmp_path / "test.tif" fv = np.uint8(42) arr = np.ones((1, 5, 5), dtype="uint8") arr[0, 2, 2] = 255 data = xr.DataArray( arr, dims=["bands", 'y', 'x'], attrs={"_FillValue": 255}, coords={"bands": ["P"]}) img = xrimage.XRImage(data) img.save(test_file, keep_palette=True, cmap=brbg, fill_value=fv) with rasterio.open(test_file) as f: cont = f.read() assert cont[0, 2, 2] == fv @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_geotiff_closed_file(self): """Test saving geotiffs when the geotiff file has been closed. This is to mimic a situation where garbage collection would cause the file handler to close the underlying geotiff file that will be written to. """ # numpy array image data = xr.DataArray(np.arange(75).reshape(5, 5, 3), dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) assert np.issubdtype(img.data.dtype, np.integer) with NamedTemporaryFile(suffix='.tif') as tmp: results = img.save(tmp.name, compute=False) results[1][0].close() # mimic garbage collection da.store(results[0], results[1]) results[1][0].close() # required to flush writes to disk with rio.open(tmp.name) as f: file_data = f.read() assert file_data.shape == (4, 5, 5) # alpha band added exp = np.arange(75).reshape(5, 5, 3) np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) np.testing.assert_allclose(file_data[3], 255) @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_jp2_int(self): """Test saving jp2000 when input data is int.""" # numpy array image data = xr.DataArray(np.arange(75).reshape(5, 5, 3), dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) assert np.issubdtype(img.data.dtype, np.integer) with NamedTemporaryFile(suffix='.jp2') as tmp: img.save(tmp.name, quality=100, reversible=True) with rio.open(tmp.name) as f: file_data = f.read() assert file_data.shape == (4, 5, 5) # alpha band added exp = np.arange(75).reshape(5, 5, 3) np.testing.assert_allclose(file_data[0], exp[:, :, 0]) np.testing.assert_allclose(file_data[1], exp[:, :, 1]) np.testing.assert_allclose(file_data[2], exp[:, :, 2]) np.testing.assert_allclose(file_data[3], 255) @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_cloud_optimized_geotiff(self): """Test saving cloud optimized geotiffs.""" # trigger COG driver to create 2 overview levels # COG driver is only available in GDAL 3.1 or later if rio.__gdal_version__ >= '3.1': data = xr.DataArray(np.arange(1200 * 1200 * 3).reshape(1200, 1200, 3), dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) assert np.issubdtype(img.data.dtype, np.integer) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name, tiled=True, overviews=[], driver='COG') with rio.open(tmp.name) as f: # The COG driver should add a tag indicating layout assert (f.tags(ns='IMAGE_STRUCTURE')['LAYOUT'] == 'COG') assert len(f.overviews(1)) == 2 @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_overviews(self): """Test saving geotiffs with overviews.""" # numpy array image data = xr.DataArray(np.arange(75).reshape(5, 5, 3), dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) assert np.issubdtype(img.data.dtype, np.integer) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name, overviews=[2, 4]) with rio.open(tmp.name) as f: assert len(f.overviews(1)) == 2 # auto-levels data = np.zeros(25 * 25 * 3, dtype=np.uint8).reshape(25, 25, 3) data = xr.DataArray(data, dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) assert np.issubdtype(img.data.dtype, np.integer) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name, overviews=[], overviews_minsize=2) with rio.open(tmp.name) as f: assert len(f.overviews(1)) == 4 # auto-levels and resampling data = np.zeros(25 * 25 * 3, dtype=np.uint8).reshape(25, 25, 3) data = xr.DataArray(data, dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) assert np.issubdtype(img.data.dtype, np.integer) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name, overviews=[], overviews_minsize=2, overviews_resampling='average') with rio.open(tmp.name) as f: # no way to check resampling method from the file assert len(f.overviews(1)) == 4 @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_tags(self): """Test saving geotiffs with tags.""" # numpy array image data = xr.DataArray(np.arange(75).reshape(5, 5, 3), dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) tags = {'avg': img.data.mean(), 'current_song': 'disco inferno'} assert np.issubdtype(img.data.dtype, np.integer) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name, tags=tags) tags['avg'] = '37.0' with rio.open(tmp.name) as f: assert f.tags() == tags @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_gamma_single_value(self, dtype): """Test gamma correction for one value for all channels.""" arr = np.arange(75, dtype=dtype).reshape(5, 5, 3) / 75. data = xr.DataArray(arr, dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) img.gamma(.5) assert img.data.dtype == dtype np.testing.assert_allclose(img.data.values, arr ** 2) assert img.data.attrs['enhancement_history'][0] == {'gamma': 0.5} @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) @pytest.mark.parametrize( ("gamma_val"), [ (None), (1.0), ([1.0, 1.0, 1.0]), ([None, None, None]), ] ) def test_gamma_noop(self, gamma_val, dtype): """Test variety of unity gamma corrections.""" arr = np.arange(75, dtype=dtype).reshape(5, 5, 3) / 75. data = xr.DataArray(arr, dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) img.gamma(gamma_val) assert img.data.dtype == dtype np.testing.assert_equal(img.data.values, arr) assert 'enhancement_history' not in img.data.attrs @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_gamma_per_channel(self, dtype): """Test gamma correction with a value for each channel.""" arr = np.arange(75, dtype=dtype).reshape(5, 5, 3) / 75. data = xr.DataArray(arr.copy(), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) img.gamma([2., 2., 2.]) assert img.data.dtype == dtype assert img.data.attrs['enhancement_history'][0] == {'gamma': [2.0, 2.0, 2.0]} np.testing.assert_allclose(img.data.values, arr ** 0.5, atol=1e-7) @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_crude_stretch(self, dtype): """Check crude stretching.""" arr = np.arange(75, dtype=dtype).reshape(5, 5, 3) data = xr.DataArray(arr.copy(), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) img.crude_stretch() red = img.data.sel(bands='R') green = img.data.sel(bands='G') blue = img.data.sel(bands='B') enhs = img.data.attrs['enhancement_history'][0] scale_expected = np.array([0.01388889, 0.01388889, 0.01388889]) offset_expected = np.array([0., -0.01388889, -0.02777778]) assert img.data.dtype == dtype np.testing.assert_allclose(enhs['scale'].values, scale_expected) np.testing.assert_allclose(enhs['offset'].values, offset_expected) expected_red = arr[:, :, 0] / 72. np.testing.assert_allclose(red, expected_red.astype(dtype), rtol=1e-6) expected_green = (arr[:, :, 1] - 1.) / (73. - 1.) np.testing.assert_allclose(green, expected_green.astype(dtype), rtol=1e-6) expected_blue = (arr[:, :, 2] - 2.) / (74. - 2.) np.testing.assert_allclose(blue, expected_blue.astype(dtype), rtol=1e-6) @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_crude_stretch_with_limits(self, dtype): """Test crude stretch with different input dtypes.""" arr = np.arange(75, dtype=dtype).reshape(5, 5, 3) data = xr.DataArray(arr.copy(), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) img.crude_stretch(0, 74) assert img.data.dtype == dtype np.testing.assert_allclose(img.data.values, arr / 74., rtol=1e-6) @pytest.mark.parametrize("dtype", [np.uint8, int]) # include a stretch within 8-bit uint and outside @pytest.mark.parametrize("max_stretch", [74, 74 * 4]) def test_crude_stretch_integer_data(self, dtype, max_stretch): """Test crude stretch with different input integer dtypes.""" arr = np.arange(75, dtype=dtype).reshape(5, 5, 3) data = xr.DataArray(arr.copy(), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) img.crude_stretch(0, max_stretch) assert img.data.dtype == np.float32 np.testing.assert_allclose(img.data.values, arr.astype(np.float32) / max_stretch, rtol=1e-6) @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_invert_single_parameter(self, dtype): """Check inversion of the image for single inversion parameter.""" arr = np.arange(75, dtype=dtype).reshape(5, 5, 3) / 75. data = xr.DataArray(arr.copy(), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) img.invert(True) enhs = img.data.attrs['enhancement_history'][0] assert enhs == {'scale': -1, 'offset': 1} assert img.data.dtype == dtype assert np.allclose(img.data.values, 1 - arr) @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_invert_parameter_for_each_channel(self, dtype): """Check inversion of the image for single inversion parameter.""" arr = np.arange(75, dtype=dtype).reshape(5, 5, 3) / 75. data = xr.DataArray(arr, dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) img.invert([True, False, True]) offset = xr.DataArray(np.array([1, 0, 1]), dims=['bands'], coords={'bands': ['R', 'G', 'B']}) scale = xr.DataArray(np.array([-1, 1, -1]), dims=['bands'], coords={'bands': ['R', 'G', 'B']}) np.testing.assert_allclose(img.data.values, (data * scale + offset).values) assert img.data.dtype == dtype @pytest.mark.parametrize("with_bands", (False, True)) @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_linear_stretch_single_band(self, with_bands, dtype): """Test linear stretching with cutoffs for single band data.""" new_shape = (5, 5) kwargs = {"dims": ("y", "x")} if with_bands: kwargs["dims"] += ("bands",) kwargs["coords"] = {"bands": ["L"]} new_shape += (1,) arr = np.arange(25, dtype=dtype).reshape(*new_shape) / 74. data = xr.DataArray(arr.copy(), **kwargs) img = xrimage.XRImage(data) with assert_maximum_dask_computes(0): img.stretch_linear() assert img.data.dtype == dtype enhs = img.data.attrs['enhancement_history'][0] np.testing.assert_allclose(enhs['scale'].values, np.array([3.114479], dtype=dtype), atol=1e-6) np.testing.assert_allclose(enhs['offset'].values, np.array([-0.00505051], dtype=dtype), atol=1e-8) res = np.array([[ [-0.005051, 0.037037, 0.079125, 0.121212, 0.1633], [0.205387, 0.247475, 0.289562, 0.33165, 0.373737], [0.415825, 0.457913, 0.5, 0.542088, 0.584175], [0.6262627, 0.66835034, 0.71043783, 0.7525254, 0.79461294], [0.83670044, 0.87878805, 0.9208756, 0.9629631, 1.0050505], ]], dtype=dtype) if with_bands: # switch from (1, 5, 5) to (5, 5, 1) res = res.reshape(new_shape) np.testing.assert_allclose(img.data.values, res, atol=1.e-6) @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_linear_stretch(self, dtype): """Test linear stretching with cutoffs.""" arr = np.arange(75, dtype=dtype).reshape(5, 5, 3) / 74. data = xr.DataArray(arr.copy(), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) with assert_maximum_dask_computes(0): img.stretch_linear() assert img.data.dtype == dtype enhs = img.data.attrs['enhancement_history'][0] np.testing.assert_allclose(enhs['scale'].values, np.array([1.03815937, 1.03815937, 1.03815937])) np.testing.assert_allclose(enhs['offset'].values, np.array([-0.00505051, -0.01907969, -0.03310887]), atol=1e-8) res = np.array([[[-0.005051, -0.005051, -0.005051], [0.037037, 0.037037, 0.037037], [0.079125, 0.079125, 0.079125], [0.121212, 0.121212, 0.121212], [0.1633, 0.1633, 0.1633]], [[0.205387, 0.205387, 0.205387], [0.247475, 0.247475, 0.247475], [0.289562, 0.289562, 0.289562], [0.33165, 0.33165, 0.33165], [0.373737, 0.373737, 0.373737]], [[0.415825, 0.415825, 0.415825], [0.457912, 0.457912, 0.457912], [0.5, 0.5, 0.5], [0.542088, 0.542088, 0.542088], [0.584175, 0.584175, 0.584175]], [[0.626263, 0.626263, 0.626263], [0.66835, 0.66835, 0.66835], [0.710438, 0.710438, 0.710438], [0.752525, 0.752525, 0.752525], [0.794613, 0.794613, 0.794613]], [[0.8367, 0.8367, 0.8367], [0.878788, 0.878788, 0.878788], [0.920875, 0.920875, 0.920875], [0.962963, 0.962963, 0.962963], [1.005051, 1.005051, 1.005051]]], dtype=dtype) np.testing.assert_allclose(img.data.values, res, atol=1.e-6) @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_linear_stretch_does_not_affect_alpha(self, dtype): """Test linear stretching with cutoffs.""" arr = np.arange(100, dtype=dtype).reshape(5, 5, 4) / 74. arr[:, :, -1] = 1 # alpha channel, fully opaque data = xr.DataArray(arr.copy(), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B', 'A']}) img = xrimage.XRImage(data) with assert_maximum_dask_computes(0): img.stretch_linear((0.005, 0.005)) assert img.data.dtype == dtype res = np.array([[[-0.005051, -0.005051, -0.005051, 1.], [0.037037, 0.037037, 0.037037, 1.], [0.079125, 0.079125, 0.079125, 1.], [0.121212, 0.121212, 0.121212, 1.], [0.1633, 0.1633, 0.1633, 1.]], [[0.205387, 0.205387, 0.205387, 1.], [0.247475, 0.247475, 0.247475, 1.], [0.289562, 0.289562, 0.289562, 1.], [0.33165, 0.33165, 0.33165, 1.], [0.373737, 0.373737, 0.373737, 1.]], [[0.415825, 0.415825, 0.415825, 1.], [0.457912, 0.457912, 0.457912, 1.], [0.5, 0.5, 0.5, 1.], [0.542088, 0.542088, 0.542088, 1.], [0.584175, 0.584175, 0.584175, 1.]], [[0.626263, 0.626263, 0.626263, 1.], [0.66835, 0.66835, 0.66835, 1.], [0.710438, 0.710438, 0.710438, 1.], [0.752525, 0.752525, 0.752525, 1.], [0.794613, 0.794613, 0.794613, 1.]], [[0.8367, 0.8367, 0.8367, 1.], [0.878788, 0.878788, 0.878788, 1.], [0.920875, 0.920875, 0.920875, 1.], [0.962963, 0.962963, 0.962963, 1.], [1.005051, 1.005051, 1.005051, 1.]]], dtype=dtype) np.testing.assert_allclose(img.data.values, res, atol=1.e-6) @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_linear_stretch_does_not_affect_alpha_with_partial_cutoffs(self, dtype): """Test linear stretching with cutoffs.""" arr = np.arange(100, dtype=dtype).reshape(5, 5, 4) / 74. arr[:, :, -1] = 1 # alpha channel, fully opaque data = xr.DataArray(arr.copy(), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B', 'A']}) img = xrimage.XRImage(data) with assert_maximum_dask_computes(0): img.stretch_linear([(0.005, 0.005), (0.005, 0.005), (0.005, 0.005)]) assert img.data.dtype == dtype res = np.array([[[-0.005051, -0.005051, -0.005051, 1.], [0.037037, 0.037037, 0.037037, 1.], [0.079125, 0.079125, 0.079125, 1.], [0.121212, 0.121212, 0.121212, 1.], [0.1633, 0.1633, 0.1633, 1.]], [[0.205387, 0.205387, 0.205387, 1.], [0.247475, 0.247475, 0.247475, 1.], [0.289562, 0.289562, 0.289562, 1.], [0.33165, 0.33165, 0.33165, 1.], [0.373737, 0.373737, 0.373737, 1.]], [[0.415825, 0.415825, 0.415825, 1.], [0.457912, 0.457912, 0.457912, 1.], [0.5, 0.5, 0.5, 1.], [0.542088, 0.542088, 0.542088, 1.], [0.584175, 0.584175, 0.584175, 1.]], [[0.626263, 0.626263, 0.626263, 1.], [0.66835, 0.66835, 0.66835, 1.], [0.710438, 0.710438, 0.710438, 1.], [0.752525, 0.752525, 0.752525, 1.], [0.794613, 0.794613, 0.794613, 1.]], [[0.8367, 0.8367, 0.8367, 1.], [0.878788, 0.878788, 0.878788, 1.], [0.920875, 0.920875, 0.920875, 1.], [0.962963, 0.962963, 0.962963, 1.], [1.005051, 1.005051, 1.005051, 1.]]], dtype=dtype) np.testing.assert_allclose(img.data.values, res, atol=1.e-6) @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_linear_stretch_does_affect_alpha_with_explicit_cutoffs(self, dtype): """Test linear stretching with full explicit cutoffs.""" arr = np.arange(100, dtype=dtype).reshape(5, 5, 4) / 74. data = xr.DataArray(arr.copy(), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B', 'A']}) img = xrimage.XRImage(data) with assert_maximum_dask_computes(0): img.stretch_linear([(0.005, 0.005), (0.005, 0.005), (0.005, 0.005), (0.005, 0.005)]) assert img.data.dtype == dtype res = np.array([[[-0.005051, -0.005051, -0.005051, -0.005051], [0.037037, 0.037037, 0.037037, 0.037037], [0.079125, 0.079125, 0.079125, 0.079125], [0.121212, 0.121212, 0.121212, 0.121212], [0.1633, 0.1633, 0.1633, 0.1633]], [[0.205387, 0.205387, 0.205387, 0.205387], [0.247475, 0.247475, 0.247475, 0.247475], [0.289562, 0.289562, 0.289562, 0.289562], [0.33165, 0.33165, 0.33165, 0.33165], [0.373737, 0.373737, 0.373737, 0.373737]], [[0.415825, 0.415825, 0.415825, 0.415825], [0.457912, 0.457912, 0.457912, 0.457912], [0.5, 0.5, 0.5, 0.5], [0.542088, 0.542088, 0.542088, 0.542088], [0.584175, 0.584175, 0.584175, 0.584175]], [[0.626263, 0.626263, 0.626263, 0.626263], [0.66835, 0.66835, 0.66835, 0.66835], [0.710438, 0.710438, 0.710438, 0.710438], [0.752525, 0.752525, 0.752525, 0.752525], [0.794613, 0.794613, 0.794613, 0.794613]], [[0.8367, 0.8367, 0.8367, 0.8367], [0.878788, 0.878788, 0.878788, 0.878788], [0.920875, 0.920875, 0.920875, 0.920875], [0.962963, 0.962963, 0.962963, 0.962963], [1.005051, 1.005051, 1.005051, 1.005051]]], dtype=dtype) np.testing.assert_allclose(img.data.values, res, atol=1.e-6) @pytest.mark.parametrize(("dtype", "max_val", "exp_min", "exp_max"), ((np.uint8, 255, -0.005358012691140175, 1.0053772069513798), (np.int8, 127, -0.004926108196377754, 1.0058689523488282), (np.uint16, 65535, -0.005050825305515899, 1.005050893505104), (np.int16, 32767, -0.005052744992717635, 1.0050527782880818), (np.uint32, 4294967295, -0.005050505077517274, 1.0050505395923495), (np.int32, 2147483647, -0.00505050499355784, 1.0050505395923495), (int, 2147483647, -0.00505050499355784, 1.0050505395923495), )) def test_linear_stretch_integers(self, dtype, max_val, exp_min, exp_max): """Test linear stretch with low-bit unsigned integer data.""" arr = np.linspace(0, max_val, num=75, dtype=dtype).reshape(5, 5, 3) data = xr.DataArray(arr.copy(), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) with assert_maximum_dask_computes(0): img.stretch_linear() assert img.data.values.min() == pytest.approx(exp_min) assert img.data.values.max() == pytest.approx(exp_max) @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_histogram_stretch(self, dtype): """Test histogram stretching.""" arr = da.arange(75, dtype=dtype).reshape(5, 5, 3) / 74. arr = arr.rechunk((2, 2, 1)) data = xr.DataArray(arr.copy(), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) with assert_maximum_dask_computes(0): img.stretch('histogram') enhs = img.data.attrs['enhancement_history'][0] assert enhs == {'hist_equalize': True} assert img.data.dtype == dtype assert img.data.chunks == ((2, 2, 1), (2, 2, 1), (1, 1, 1)) res = np.array([[[0., 0., 0.], [0.04166667, 0.04166667, 0.04166667], [0.08333333, 0.08333333, 0.08333333], [0.125, 0.125, 0.125], [0.16666667, 0.16666667, 0.16666667]], [[0.20833333, 0.20833333, 0.20833333], [0.25, 0.25, 0.25], [0.29166667, 0.29166667, 0.29166667], [0.33333333, 0.33333333, 0.33333333], [0.375, 0.375, 0.375]], [[0.41666667, 0.41666667, 0.41666667], [0.45833333, 0.45833333, 0.45833333], [0.5, 0.5, 0.5], [0.54166667, 0.54166667, 0.54166667], [0.58333333, 0.58333333, 0.58333333]], [[0.625, 0.625, 0.625], [0.66666667, 0.66666667, 0.66666667], [0.70833333, 0.70833333, 0.70833333], [0.75, 0.75, 0.75], [0.79166667, 0.79166667, 0.79166667]], [[0.83333333, 0.83333333, 0.83333333], [0.875, 0.875, 0.875], [0.91666667, 0.91666667, 0.91666667], [0.95833333, 0.95833333, 0.95833333], [0.99951172, 0.99951172, 0.99951172]]], dtype=dtype) np.testing.assert_allclose(img.data.values, res, atol=1.e-6) @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) @pytest.mark.parametrize( ("min_stretch", "max_stretch"), [ (None, None), ([0.0, 1.0 / 74.0, 2.0 / 74.0], [72.0 / 74.0, 73.0 / 74.0, 1.0]), ] ) @pytest.mark.parametrize("base", ["e", "10", "2"]) def test_logarithmic_stretch(self, min_stretch, max_stretch, base, dtype): """Test logarithmic strecthing.""" arr = np.arange(75, dtype=dtype).reshape(5, 5, 3) / 74. data = xr.DataArray(arr.copy(), dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) with assert_maximum_dask_computes(0): img = xrimage.XRImage(data) img.stretch(stretch='logarithmic', min_stretch=min_stretch, max_stretch=max_stretch, base=base) enhs = img.data.attrs['enhancement_history'][0] assert enhs == {'log_factor': 100.0} assert img.data.dtype == dtype res = np.array([[[0., 0., 0.], [0.35484693, 0.35484693, 0.35484693], [0.48307087, 0.48307087, 0.48307087], [0.5631469, 0.5631469, 0.5631469], [0.62151902, 0.62151902, 0.62151902]], [[0.66747806, 0.66747806, 0.66747806], [0.70538862, 0.70538862, 0.70538862], [0.73765396, 0.73765396, 0.73765396], [0.76573946, 0.76573946, 0.76573946], [0.79060493, 0.79060493, 0.79060493]], [[0.81291336, 0.81291336, 0.81291336], [0.83314196, 0.83314196, 0.83314196], [0.85164569, 0.85164569, 0.85164569], [0.86869572, 0.86869572, 0.86869572], [0.88450394, 0.88450394, 0.88450394]], [[0.899239, 0.899239, 0.899239], [0.9130374, 0.9130374, 0.9130374], [0.92601114, 0.92601114, 0.92601114], [0.93825325, 0.93825325, 0.93825325], [0.94984187, 0.94984187, 0.94984187]], [[0.96084324, 0.96084324, 0.96084324], [0.97131402, 0.97131402, 0.97131402], [0.98130304, 0.98130304, 0.98130304], [0.99085269, 0.99085269, 0.99085269], [1., 1., 1.]]], dtype=dtype) np.testing.assert_allclose(img.data.values, res, atol=1.e-6) @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_weber_fechner_stretch(self, dtype): """Test applying S=2.3klog10I+C to the data.""" from trollimage import xrimage arr = np.arange(75., dtype=dtype).reshape(5, 5, 3) / 74. data = xr.DataArray(arr.copy() + 0.1, dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) img.stretch_weber_fechner(2.5, 0.2) enhs = img.data.attrs['enhancement_history'][0] assert enhs == {'weber_fechner': (2.5, 0.2)} assert img.data.dtype == dtype res = np.array([ [[0., 0., 0.], [0., 0., 0.], [0., 0., 0.0993509], [0.25663552, 0.40460747, 0.54430866], [0.6766145, 0.8022693, 0.92190945]], [[1.0360844, 1.1452721, 1.2498899], [1.350305, 1.446842, 1.5397894], [1.629405, 1.7159187, 1.7995386], [1.8804514, 1.9588281, 2.0348217], [2.1085734, 2.1802118, 2.2498538]], [[2.3176088, 2.3835757, 2.4478464], [2.5105066, 2.571634, 2.631303], [2.689581, 2.7465308, 2.8022122], [2.8566809, 2.9099874, 2.9621818], [3.013308, 3.0634098, 3.1125278]], [[3.1606987, 3.207959, 3.2543423], [3.299881, 3.344605, 3.3885431], [3.431722, 3.4741676, 3.515905], [3.5569568, 3.597345, 3.6370919], [3.6762161, 3.714738, 3.7526748]], [[3.7900448, 3.826864, 3.863149], [3.8989153, 3.934177, 3.968948], [4.0032415, 4.037072, 4.07045], [4.103389, 4.135899, 4.1679916], [4.199678, 4.2309675, 4.2618704]]], dtype=dtype) np.testing.assert_allclose(img.data.values, res, atol=1.e-6) def test_jpeg_save(self): """Test saving to jpeg.""" pass def test_gtiff_save(self): """Test saving to geotiff.""" pass def test_save_masked(self): """Test saving masked data.""" pass def test_LA_save(self): """Test LA saving.""" pass def test_L_save(self): """Test L saving.""" pass def test_P_save(self): """Test P saving.""" pass def test_PA_save(self): """Test PA saving.""" pass def test_convert_modes(self): """Test modes convertions.""" from trollimage.colormap import brbg, Colormap # RGBA colormap bw = Colormap( (0.0, (1.0, 1.0, 1.0, 1.0)), (1.0, (0.0, 0.0, 0.0, 0.5)), ) arr1 = np.arange(150).reshape(1, 15, 10) / 150. arr2 = np.append(arr1, np.ones(150).reshape(arr1.shape)).reshape(2, 15, 10) arr3 = (np.arange(150).reshape(2, 15, 5) / 15).astype('int64') dataset1 = xr.DataArray(arr1.copy(), dims=['bands', 'y', 'x'], coords={'bands': ['L']}) dataset2 = xr.DataArray(arr2.copy(), dims=['bands', 'x', 'y'], coords={'bands': ['L', 'A']}) dataset3 = xr.DataArray(arr3.copy(), dims=['bands', 'x', 'y'], coords={'bands': ['P', 'A']}) img = xrimage.XRImage(dataset1) new_img = img.convert(img.mode) assert new_img is not None # make sure it is a copy assert new_img is not img assert new_img.data is not img.data # L -> LA (int) with assert_maximum_dask_computes(1): img = xrimage.XRImage((dataset1 * 150).astype(np.uint8)) img.data.attrs['_FillValue'] = 0 # set fill value img = img.convert('LA') assert np.issubdtype(img.data.dtype, np.integer) assert img.mode == 'LA' assert len(img.data.coords['bands']) == 2 # make sure the alpha band is all opaque except the first pixel alpha = img.data.sel(bands='A').values.ravel() np.testing.assert_allclose(alpha[0], 0) np.testing.assert_allclose(alpha[1:], 255) # L -> LA (float) with assert_maximum_dask_computes(1): img = xrimage.XRImage(dataset1) img = img.convert('LA') assert img.mode == 'LA' assert len(img.data.coords['bands']) == 2 # make sure the alpha band is all opaque np.testing.assert_allclose(img.data.sel(bands='A'), 1.) # LA -> L (float) with assert_maximum_dask_computes(0): img = img.convert('L') assert img.mode == 'L' assert len(img.data.coords['bands']) == 1 # L -> RGB (float) with assert_maximum_dask_computes(1): img = img.convert('RGB') assert img.mode == 'RGB' assert len(img.data.coords['bands']) == 3 data = img.data.compute() np.testing.assert_allclose(data.sel(bands=['R']), arr1) np.testing.assert_allclose(data.sel(bands=['G']), arr1) np.testing.assert_allclose(data.sel(bands=['B']), arr1) # RGB -> RGBA (float) with assert_maximum_dask_computes(1): img = img.convert('RGBA') assert img.mode == 'RGBA' assert len(img.data.coords['bands']) == 4 assert np.issubdtype(img.data.dtype, np.floating) data = img.data.compute() np.testing.assert_allclose(data.sel(bands=['R']), arr1) np.testing.assert_allclose(data.sel(bands=['G']), arr1) np.testing.assert_allclose(data.sel(bands=['B']), arr1) # make sure the alpha band is all opaque np.testing.assert_allclose(data.sel(bands='A'), 1.) # RGB -> RGBA (int) with assert_maximum_dask_computes(1): img = xrimage.XRImage((dataset1 * 150).astype(np.uint8)) img = img.convert('RGB') # L -> RGB assert np.issubdtype(img.data.dtype, np.integer) img = img.convert('RGBA') assert img.mode == 'RGBA' assert len(img.data.coords['bands']) == 4 assert np.issubdtype(img.data.dtype, np.integer) data = img.data.compute() np.testing.assert_allclose(data.sel(bands=['R']), (arr1 * 150).astype(np.uint8)) np.testing.assert_allclose(data.sel(bands=['G']), (arr1 * 150).astype(np.uint8)) np.testing.assert_allclose(data.sel(bands=['B']), (arr1 * 150).astype(np.uint8)) # make sure the alpha band is all opaque np.testing.assert_allclose(data.sel(bands='A'), 255) # LA -> RGBA (float) with assert_maximum_dask_computes(0): img = xrimage.XRImage(dataset2) img = img.convert('RGBA') assert img.mode == 'RGBA' assert len(img.data.coords['bands']) == 4 # L -> palettize -> RGBA (float) with assert_maximum_dask_computes(0): img = xrimage.XRImage(dataset1) img.palettize(brbg) pal = img.palette img2 = img.convert('RGBA') assert np.issubdtype(img2.data.dtype, np.floating) assert img2.mode == 'RGBA' assert len(img2.data.coords['bands']) == 4 # PA -> RGB (float) img = xrimage.XRImage(dataset3) img.palette = pal with assert_maximum_dask_computes(0): img = img.convert('RGB') assert np.issubdtype(img.data.dtype, np.floating) assert img.mode == 'RGB' assert len(img.data.coords['bands']) == 3 with pytest.raises(ValueError): img.convert('A') # L -> palettize -> RGBA (float) with RGBA colormap with assert_maximum_dask_computes(0): img = xrimage.XRImage(dataset1) img.palettize(bw) img2 = img.convert('RGBA') assert np.issubdtype(img2.data.dtype, np.floating) assert img2.mode == 'RGBA' assert len(img2.data.coords['bands']) == 4 # convert to RGB, use RGBA from colormap regardless img2 = img.convert('RGB') assert np.issubdtype(img2.data.dtype, np.floating) assert img2.mode == 'RGBA' assert len(img2.data.coords['bands']) == 4 def test_final_mode(self): """Test final_mode.""" from trollimage import xrimage # numpy array image data = xr.DataArray(np.arange(75).reshape(5, 5, 3), dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) assert img.final_mode(None) == 'RGBA' assert img.final_mode(0) == 'RGB' def test_stack(self): """Test stack.""" from trollimage import xrimage # background image arr1 = np.zeros((2, 2), dtype=np.float32) data1 = xr.DataArray(arr1, dims=['y', 'x']) bkg = xrimage.XRImage(data1) # image to be stacked arr2 = np.full((2, 2), np.nan, dtype=np.float32) arr2[0] = 1 data2 = xr.DataArray(arr2, dims=['y', 'x']) img = xrimage.XRImage(data2) # expected result arr3 = arr1.copy() arr3[0] = 1.0 data3 = xr.DataArray(arr3, dims=['y', 'x']) res = xrimage.XRImage(data3) # stack image over the background bkg.stack(img) # check result np.testing.assert_allclose(bkg.data, res.data, rtol=1e-05) def test_merge(self): """Test merge.""" pass @pytest.mark.parametrize("dtype", (np.float32, np.float64, float)) def test_blend(self, dtype): """Test blend.""" from trollimage import xrimage core1 = np.arange(75, dtype=dtype).reshape(5, 5, 3) / 75.0 alpha1 = np.linspace(0, 1, 25, dtype=dtype).reshape(5, 5, 1) arr1 = np.concatenate([core1, alpha1], 2) data1 = xr.DataArray(arr1, dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B', 'A']}) img1 = xrimage.XRImage(data1) core2 = np.arange(75, 0, -1, dtype=dtype).reshape(5, 5, 3) / 75.0 alpha2 = np.linspace(1, 0, 25, dtype=dtype).reshape(5, 5, 1) arr2 = np.concatenate([core2, alpha2], 2) data2 = xr.DataArray(arr2, dims=['y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B', 'A']}) img2 = xrimage.XRImage(data2) img3 = img1.blend(img2) assert img3.data.dtype == dtype np.testing.assert_allclose( (alpha1 + alpha2 * (1 - alpha1)).squeeze(), img3.data.sel(bands="A")) np.testing.assert_allclose( img3.data.sel(bands="R").values, np.array( [[1., 0.95833635, 0.9136842, 0.8666667, 0.8180645], [0.768815, 0.72, 0.6728228, 0.62857145, 0.5885714], [0.55412847, 0.5264665, 0.50666666, 0.495612, 0.49394494], [0.5020408, 0.52, 0.5476586, 0.5846154, 0.63027024], [0.683871, 0.7445614, 0.81142855, 0.8835443, 0.96]], dtype=dtype), rtol=2e-6) with pytest.raises(TypeError): img1.blend("Salekhard") wrongimg = xrimage.XRImage( xr.DataArray(np.zeros((0, 0)), dims=("y", "x"))) with pytest.raises(ValueError): img1.blend(wrongimg) def test_replace_luminance(self): """Test luminance replacement.""" pass def test_putalpha(self): """Test putalpha.""" pass def test_show(self): """Test that the show commands calls PIL.show.""" from trollimage import xrimage data = xr.DataArray(np.arange(75).reshape(5, 5, 3) / 75., dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) img = xrimage.XRImage(data) with mock.patch.object(xrimage.PILImage.Image, 'show', return_value=None) as s: img.show() s.assert_called_once() def test_apply_pil(self): """Test the apply_pil method.""" from trollimage import xrimage np_data = np.arange(75).reshape(5, 5, 3) / 75. data = xr.DataArray(np_data, dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) dummy_args = [(OrderedDict(),), {}] def dummy_fun(pil_obj, *args, **kwargs): dummy_args[0] = args dummy_args[1] = kwargs return pil_obj img = xrimage.XRImage(data) with mock.patch.object(xrimage, "PILImage") as pi: pil_img = mock.MagicMock() pi.fromarray = mock.Mock(wraps=lambda *args, **kwargs: pil_img) res = img.apply_pil(dummy_fun, 'RGB') # check that the pil image generation is delayed pi.fromarray.assert_not_called() # make it happen res.data.data.compute() pil_img.convert.assert_called_with('RGB') img = xrimage.XRImage(data) with mock.patch.object(xrimage, "PILImage") as pi: pil_img = mock.MagicMock() pi.fromarray = mock.Mock(wraps=lambda *args, **kwargs: pil_img) res = img.apply_pil(dummy_fun, 'RGB', fun_args=('Hey', 'Jude'), fun_kwargs={'chorus': "La lala lalalala"}) assert dummy_args == [({},), {}] res.data.data.compute() assert dummy_args == [(OrderedDict(), 'Hey', 'Jude'), {'chorus': "La lala lalalala"}] # Test HACK for _burn_overlay dummy_args = [(OrderedDict(),), {}] def _burn_overlay(pil_obj, *args, **kwargs): dummy_args[0] = args dummy_args[1] = kwargs return pil_obj img = xrimage.XRImage(data) with mock.patch.object(xrimage, "PILImage") as pi: pil_img = mock.MagicMock() pi.fromarray = mock.Mock(wraps=lambda *args, **kwargs: pil_img) res = img.apply_pil(_burn_overlay, 'RGB') # check that the pil image generation is delayed pi.fromarray.assert_not_called() # make it happen res.data.data.compute() pil_img.convert.assert_called_with('RGB') class TestXRImageColorize: """Test the colorize method of the XRImage class.""" _expected = { np.float64: np.array([[ [3.29411723e-01, 3.57655082e-01, 3.86434110e-01, 4.15693606e-01, 4.45354600e-01, 4.75400861e-01, 5.05821366e-01, 5.36605929e-01, 5.65154978e-01, 5.92088497e-01, 6.19067971e-01, 6.46087246e-01, 6.73140324e-01, 7.00221360e-01, 7.27324645e-01], [7.52329770e-01, 7.68885184e-01, 7.85480717e-01, 8.02165033e-01, 8.18991652e-01, 8.36019205e-01, 8.53311577e-01, 8.70937939e-01, 8.84215464e-01, 8.96340860e-01, 9.08470028e-01, 9.20615990e-01, 9.32792728e-01, 9.45015153e-01, 9.57299069e-01], [9.57098327e-01, 9.40960114e-01, 9.29584947e-01, 9.23677290e-01, 9.23753761e-01, 9.30068208e-01, 9.42551542e-01, 9.60784273e-01, 9.41109213e-01, 9.19647970e-01, 8.96571901e-01, 8.72056790e-01, 8.46282229e-01, 8.19431622e-01, 7.91692975e-01], [7.58448192e-01, 7.21741664e-01, 6.84822731e-01, 6.47626513e-01, 6.10070647e-01, 5.72048960e-01, 5.33421992e-01, 4.94570855e-01, 4.57464094e-01, 4.20002632e-01, 3.82018455e-01, 3.43266518e-01, 3.03372572e-01, 2.61727458e-01, 2.17242854e-01], [1.89905753e-01, 1.67063022e-01, 1.43524406e-01, 1.18889110e-01, 9.24115112e-02, 6.24348956e-02, 2.53761173e-02, 4.08181032e-03, 4.27986478e-03, 4.17929690e-03, 3.78662146e-03, 3.12692318e-03, 2.24023940e-03, 1.17807264e-03, 3.21825881e-08]], [[1.88235327e-01, 2.05148705e-01, 2.22246533e-01, 2.39526068e-01, 2.56989487e-01, 2.74629823e-01, 2.92439994e-01, 3.10413422e-01, 3.32343814e-01, 3.57065419e-01, 3.82068278e-01, 4.07348961e-01, 4.32903760e-01, 4.58728817e-01, 4.84820203e-01], [5.12920806e-01, 5.47946930e-01, 5.82732545e-01, 6.17314757e-01, 6.51719365e-01, 6.85963748e-01, 7.20058900e-01, 7.54010901e-01, 7.76938576e-01, 7.97119666e-01, 8.17286145e-01, 8.37436050e-01, 8.57567245e-01, 8.77677444e-01, 8.97764221e-01], [9.14974807e-01, 9.26634684e-01, 9.36490370e-01, 9.44572058e-01, 9.50936890e-01, 9.55671974e-01, 9.58899694e-01, 9.60784377e-01, 9.54533524e-01, 9.48563492e-01, 9.42789228e-01, 9.37126769e-01, 9.31494725e-01, 9.25815456e-01, 9.20015949e-01], [9.08501736e-01, 8.93232137e-01, 8.77927046e-01, 8.62584949e-01, 8.47204357e-01, 8.31783811e-01, 8.16321878e-01, 7.98071154e-01, 7.68921238e-01, 7.39943765e-01, 7.11141597e-01, 6.82517728e-01, 6.54075286e-01, 6.25817541e-01, 5.97747906e-01], [5.70776450e-01, 5.44247780e-01, 5.17943011e-01, 4.91867999e-01, 4.66028940e-01, 4.40432405e-01, 4.15085375e-01, 3.90762603e-01, 3.67819656e-01, 3.45100714e-01, 3.22617398e-01, 3.00381887e-01, 2.78406993e-01, 2.56706267e-01, 2.35294109e-01]], [[1.96078164e-02, 2.42548791e-02, 2.74972980e-02, 2.96227786e-02, 3.17156285e-02, 3.38568546e-02, 3.60498743e-02, 3.82990372e-02, 5.17340107e-02, 7.13424499e-02, 9.00791380e-02, 1.08349520e-01, 1.26372958e-01, 1.44280386e-01, 1.62155431e-01], [1.84723724e-01, 2.25766583e-01, 2.66872651e-01, 3.08395883e-01, 3.50522786e-01, 3.93349758e-01, 4.36919863e-01, 4.81242202e-01, 5.19495725e-01, 5.56210021e-01, 5.93054317e-01, 6.30051817e-01, 6.67218407e-01, 7.04564489e-01, 7.42096284e-01], [7.75703258e-01, 8.04590533e-01, 8.34519408e-01, 8.64314044e-01, 8.92841230e-01, 9.19042335e-01, 9.41963593e-01, 9.60784303e-01, 9.45735072e-01, 9.32649658e-01, 9.21608884e-01, 9.12665692e-01, 9.05844317e-01, 9.01139812e-01, 8.98517976e-01], [8.86846758e-01, 8.68087757e-01, 8.49200397e-01, 8.30188000e-01, 8.11054008e-01, 7.91801982e-01, 7.72435606e-01, 7.51368872e-01, 7.24059052e-01, 6.97016433e-01, 6.70243011e-01, 6.43740898e-01, 6.17512331e-01, 5.91559687e-01, 5.65885492e-01], [5.39262087e-01, 5.12603461e-01, 4.86221750e-01, 4.60123396e-01, 4.34315297e-01, 4.08804859e-01, 3.83600057e-01, 3.58016749e-01, 3.31909003e-01, 3.06406088e-01, 2.81515756e-01, 2.57245695e-01, 2.33603632e-01, 2.10597439e-01, 1.88235281e-01]]], dtype=np.float64), np.float32: np.array([[ [0.32941175, 0.35765505, 0.38643414, 0.4156936, 0.44535455, 0.47540084, 0.5058213, 0.53660583, 0.56515497, 0.5920884, 0.61906797, 0.64608735, 0.67314035, 0.7002214, 0.72732455], [0.7523298, 0.76888514, 0.7854807, 0.8021649, 0.8189918, 0.8360192, 0.8533116, 0.8709379, 0.88421535, 0.8963408, 0.90846986, 0.9206159, 0.9327928, 0.9450152, 0.95729893], [0.9561593, 0.9379867, 0.925193, 0.9186452, 0.9189398, 0.9262958, 0.9404795, 0.96078414, 0.9400202, 0.9179358, 0.89463943, 0.8702369, 0.84483355, 0.8185319, 0.79143286], [0.75844824, 0.7217417, 0.6848227, 0.64762676, 0.61007077, 0.57204896, 0.533422, 0.49457097, 0.4574643, 0.42000294, 0.38201877, 0.34326664, 0.30337277, 0.26172766, 0.21724297], [0.18990554, 0.1670632, 0.14352395, 0.11888929, 0.09241185, 0.06243531, 0.02537645, 0.00408208, 0.0042801, 0.00417955, 0.00378686, 0.00312716, 0.00224016, 0.00117794, 0.]], [[0.18823533, 0.20514871, 0.22224654, 0.23952611, 0.25698954, 0.27462983, 0.2924401, 0.31041354, 0.33234388, 0.35706556, 0.38206834, 0.40734893, 0.4329038, 0.45872888, 0.4848204], [0.51292086, 0.54794705, 0.5827325, 0.6173149, 0.65171933, 0.6859637, 0.720059, 0.754011, 0.7769386, 0.7971198, 0.81728625, 0.8374362, 0.8575672, 0.87767744, 0.8977643], [0.9152645, 0.92748123, 0.93765223, 0.9458176, 0.9520587, 0.95650315, 0.9593312, 0.96078444, 0.9547297, 0.9488435, 0.9430687, 0.9373506, 0.93163645, 0.9258765, 0.92002386], [0.9085018, 0.89323217, 0.8779272, 0.86258495, 0.84720427, 0.83178383, 0.81632185, 0.79807115, 0.7689212, 0.73994386, 0.71114165, 0.68251765, 0.65407526, 0.62581754, 0.597748], [0.5707766, 0.5442478, 0.51794314, 0.49186793, 0.46602884, 0.4404323, 0.4150853, 0.39076254, 0.3678196, 0.34510067, 0.32261738, 0.3003818, 0.27840695, 0.25670624, 0.23529409]], [[0.01960781, 0.02425484, 0.02749731, 0.02962274, 0.03171561, 0.03385685, 0.03604981, 0.03829896, 0.05173399, 0.07134236, 0.0900792, 0.10834952, 0.12637301, 0.14428039, 0.16215537], [0.18472369, 0.22576652, 0.26687256, 0.30839586, 0.35052276, 0.39334968, 0.43691984, 0.48124215, 0.51949567, 0.55621, 0.59305423, 0.6300518, 0.6672183, 0.7045645, 0.7420964], [0.7757837, 0.80522877, 0.83597785, 0.8665506, 0.8955321, 0.9216227, 0.9436848, 0.96078426, 0.94695187, 0.93475634, 0.9242341, 0.9154071, 0.9082816, 0.90284896, 0.8990856], [0.8868469, 0.8680878, 0.8492005, 0.83018804, 0.8110541, 0.791802, 0.7724357, 0.7513689, 0.7240591, 0.69701654, 0.67024314, 0.64374095, 0.6175124, 0.59155977, 0.5658856], [0.53926224, 0.5126035, 0.48622182, 0.4601233, 0.43431523, 0.40880483, 0.3836, 0.35801673, 0.331909, 0.30640608, 0.28151578, 0.25724563, 0.23360366, 0.21059746, 0.18823537]]], dtype=np.float32) } @pytest.mark.parametrize("colormap_tag", [None, "colormap"]) def test_colorize_geotiff_tag(self, tmp_path, colormap_tag): """Test that a colorized colormap can be saved to a geotiff tag.""" new_range = (0.0, 0.5) arr = np.arange(75).reshape(5, 15) / 74. data = xr.DataArray(arr.copy(), dims=['y', 'x']) new_brbg = brbg.set_range(*new_range, inplace=False) img = xrimage.XRImage(data) img.colorize(new_brbg) dst = str(tmp_path / "test.tif") img.save(dst, colormap_tag=colormap_tag) with rio.open(dst, "r") as gtiff_file: metadata = gtiff_file.tags() if colormap_tag is None: assert "colormap" not in metadata else: assert "colormap" in metadata loaded_brbg = Colormap.from_string(metadata["colormap"]) np.testing.assert_allclose(new_brbg.values, loaded_brbg.values) np.testing.assert_allclose(new_brbg.colors, loaded_brbg.colors) @pytest.mark.parametrize( ("new_range", "input_scale", "input_offset", "expected_scale", "expected_offset", "dtype"), [ ((0.0, 1.0), 1.0, 0.0, 1.0, 0.0, np.float32), ((0.0, 0.5), 1.0, 0.0, 2.0, 0.0, np.float32), ((2.0, 4.0), 2.0, 2.0, 0.5, -1.0, np.float32), ((0.0, 1.0), 1.0, 0.0, 1.0, 0.0, np.float64), ((0.0, 0.5), 1.0, 0.0, 2.0, 0.0, np.float64), ((2.0, 4.0), 2.0, 2.0, 0.5, -1.0, np.float64), ], ) def test_colorize_l_rgb(self, new_range, input_scale, input_offset, expected_scale, expected_offset, dtype): """Test colorize with a RGB colormap.""" img = self._get_input_image(dtype, input_scale, input_offset) new_brbg = brbg.set_range(*new_range, inplace=False) img.colorize(new_brbg) values = img.data.compute() assert values.dtype == dtype expected = self._get_expected_colorize_l_rgb(new_range, dtype) np.testing.assert_allclose(values, expected, atol=1e-6) assert "enhancement_history" in img.data.attrs assert img.data.attrs["enhancement_history"][-1]["scale"] == expected_scale assert img.data.attrs["enhancement_history"][-1]["offset"] == expected_offset assert isinstance(img.data.attrs["enhancement_history"][-1]["colormap"], Colormap) @staticmethod def _get_input_image(dtype, input_scale, input_offset): arr = np.arange(75, dtype=dtype).reshape(5, 15) / 74. * input_scale + input_offset data = xr.DataArray(arr, dims=['y', 'x']) return xrimage.XRImage(data) def _get_expected_colorize_l_rgb(self, new_range, dtype): if new_range[1] == 0.5: expected2 = self._expected[dtype].copy().reshape((3, 75)) flat_expected = self._expected[dtype].reshape((3, 75)) expected2[:, :38] = flat_expected[:, ::2] expected2[:, 38:] = flat_expected[:, -1:] expected = expected2.reshape((3, 5, 15)) else: expected = self._expected[dtype] return expected def test_colorize_int_l_rgb_with_fills(self): """Test integer data with _FillValue is masked (NaN) when colorized.""" arr = np.arange(75, dtype=np.uint8).reshape(5, 15) arr[1, :] = 255 data = xr.DataArray(arr.copy(), dims=['y', 'x'], attrs={"_FillValue": 255}) new_brbg = brbg.set_range(5, 20, inplace=False) img = xrimage.XRImage(data) img.colorize(new_brbg) values = img.data.compute() # Integer data inherits dtype from the colormap when colorized assert values.dtype == new_brbg.colors.dtype assert values.shape == (3,) + arr.shape # RGB np.testing.assert_allclose(values[:, 1, :], np.nan) assert np.count_nonzero(np.isnan(values)) == arr.shape[1] * 3 assert "enhancement_history" in img.data.attrs assert img.data.attrs["enhancement_history"][-1]["scale"] == 1 / (20 - 5) assert img.data.attrs["enhancement_history"][-1]["offset"] == -5 / (20 - 5) assert isinstance(img.data.attrs["enhancement_history"][-1]["colormap"], Colormap) def test_colorize_la_rgb(self): """Test colorizing an LA image with an RGB colormap.""" arr = np.arange(75).reshape((5, 15)) / 74. alpha = arr > 40. data = xr.DataArray([arr.copy(), alpha], dims=['bands', 'y', 'x'], coords={'bands': ['L', 'A']}) img = xrimage.XRImage(data) img.colorize(brbg) values = img.data.values expected = np.concatenate((self._expected[np.float64], alpha.reshape((1,) + alpha.shape))) np.testing.assert_allclose(values, expected) assert "enhancement_history" in img.data.attrs assert img.data.attrs["enhancement_history"][-1]["scale"] == 1.0 assert img.data.attrs["enhancement_history"][-1]["offset"] == 0.0 assert isinstance(img.data.attrs["enhancement_history"][-1]["colormap"], Colormap) def test_colorize_rgba(self): """Test colorize with an RGBA colormap.""" from trollimage import xrimage from trollimage.colormap import Colormap # RGBA colormap bw = Colormap( (0.0, (1.0, 1.0, 1.0, 1.0)), (1.0, (0.0, 0.0, 0.0, 0.5)), ) arr = np.arange(75).reshape(5, 15) / 74. data = xr.DataArray(arr.copy(), dims=['y', 'x']) img = xrimage.XRImage(data) img.colorize(bw) values = img.data.compute() assert (4, 5, 15) == values.shape np.testing.assert_allclose(values[:, 0, 0], [1.0, 1.0, 1.0, 1.0], rtol=1e-03) np.testing.assert_allclose(values[:, -1, -1], [0.0, 0.0, 0.0, 0.5]) assert "enhancement_history" in img.data.attrs assert img.data.attrs["enhancement_history"][-1]["scale"] == 1.0 assert img.data.attrs["enhancement_history"][-1]["offset"] == 0.0 assert isinstance(img.data.attrs["enhancement_history"][-1]["colormap"], Colormap) class TestXRImagePalettize: """Test the XRImage palettize method.""" @pytest.mark.parametrize( ("new_range", "input_scale", "input_offset", "expected_scale", "expected_offset"), [ ((0.0, 1.0), 1.0, 0.0, 1.0, 0.0), ((0.0, 0.5), 1.0, 0.0, 2.0, 0.0), ((2.0, 4.0), 2.0, 2.0, 0.5, -1.0), ], ) def test_palettize(self, new_range, input_scale, input_offset, expected_scale, expected_offset): """Test palettize with an RGB colormap.""" arr = np.arange(75).reshape(5, 15) / 74. * input_scale + input_offset data = xr.DataArray(arr.copy(), dims=['y', 'x']) img = xrimage.XRImage(data) new_brbg = brbg.set_range(*new_range, inplace=False) img.palettize(new_brbg) values = img.data.values expected = np.array([[ [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3], [4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5], [6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7], [8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10]]]) if new_range[1] == 0.5: flat_expected = expected.reshape((1, 75)) expected2 = flat_expected.copy() expected2[:, :38] = flat_expected[:, ::2] expected2[:, 38:] = flat_expected[:, -1:] expected = expected2.reshape((1, 5, 15)) assert np.issubdtype(values.dtype, np.integer) np.testing.assert_allclose(values, expected) assert "enhancement_history" in img.data.attrs assert img.data.attrs["enhancement_history"][-1]["scale"] == expected_scale assert img.data.attrs["enhancement_history"][-1]["offset"] == expected_offset def test_palettize_rgba(self): """Test palettize with an RGBA colormap.""" from trollimage import xrimage from trollimage.colormap import Colormap # RGBA colormap bw = Colormap( (0.0, (1.0, 1.0, 1.0, 1.0)), (1.0, (0.0, 0.0, 0.0, 0.5)), ) arr = np.arange(75).reshape(5, 15) / 74. data = xr.DataArray(arr.copy(), dims=['y', 'x']) img = xrimage.XRImage(data) img.palettize(bw) values = img.data.values assert (1, 5, 15) == values.shape assert (2, 4) == bw.colors.shape @pytest.mark.parametrize("colormap_tag", [None, "colormap"]) @pytest.mark.parametrize("keep_palette", [False, True]) def test_palettize_geotiff_tag(self, tmp_path, colormap_tag, keep_palette): """Test that a palettized image can be saved to a geotiff tag.""" new_range = (0.0, 0.5) arr = np.arange(75).reshape(5, 15) / 74. data = xr.DataArray(arr.copy(), dims=['y', 'x']) new_brbg = brbg.set_range(*new_range, inplace=False) img = xrimage.XRImage(data) img.palettize(new_brbg) dst = str(tmp_path / "test.tif") img.save(dst, colormap_tag=colormap_tag, keep_palette=keep_palette) with rio.open(dst, "r") as gtiff_file: metadata = gtiff_file.tags() if colormap_tag is None: assert "colormap" not in metadata else: assert "colormap" in metadata loaded_brbg = Colormap.from_string(metadata["colormap"]) np.testing.assert_allclose(new_brbg.values, loaded_brbg.values) np.testing.assert_allclose(new_brbg.colors, loaded_brbg.colors) def test_palettize_fill_value(self): """Test that fill values are adapted.""" arr = np.arange(25, dtype="float32").reshape(5, 5)/25 arr[2, 2] = np.nan data = xr.DataArray(arr.copy(), dims=['y', 'x'], attrs={"_FillValue": np.nan}) img = xrimage.XRImage(data) img.palettize(brbg) assert img.data[0, 2, 2] == img.data.attrs["_FillValue"] def test_palettize_bad_fill_value(self): """Test that palettize warns with a strange fill value.""" arr = np.arange(25, dtype="uint8").reshape(5, 5) data = xr.DataArray(arr.copy(), dims=['y', 'x'], attrs={"_FillValue": 10}) img = xrimage.XRImage(data) with pytest.warns(UserWarning, match="Palettizing uint8 data with the _FillValue attribute set to 10, " "but palettize is not generally fill value aware"): img.palettize(brbg) class TestXRImageSaveScaleOffset: """Test case for saving an image with scale and offset tags.""" def setup_method(self) -> None: """Set up the test case.""" from trollimage import xrimage data = xr.DataArray(np.arange(25, dtype=np.float32).reshape(5, 5, 1), dims=[ 'y', 'x', 'bands'], coords={'bands': ['L']}) self.img = xrimage.XRImage(data) rgb_data = xr.DataArray(np.arange(3 * 25, dtype=np.float32).reshape(5, 5, 3), dims=[ 'y', 'x', 'bands'], coords={'bands': ['R', 'G', 'B']}) self.rgb_img = xrimage.XRImage(rgb_data) @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_scale_offset(self): """Test saving geotiffs with tags.""" expected_tags = {'scale': 24.0 / 255, 'offset': 0} self.img.stretch() with pytest.warns(DeprecationWarning): self._save_and_check_tags( expected_tags, include_scale_offset_tags=True) def test_gamma_geotiff_scale_offset(self, tmp_path): """Test that saving gamma-enhanced data to a geotiff with scale/offset tags doesn't fail.""" self.img.gamma(.5) out_fn = str(tmp_path / "test.tif") self.img.save(out_fn, scale_offset_tags=("scale", "offset")) with rio.open(out_fn, "r") as ds: assert np.isnan(float(ds.tags()["scale"])) assert np.isnan(float(ds.tags()["offset"])) def test_rgb_geotiff_scale_offset(self, tmp_path): """Test that saving RGB data to a geotiff with scale/offset tags doesn't fail.""" self.rgb_img.stretch( stretch="crude", min_stretch=[-25, -40, 243], max_stretch=[0, 5, 208] ) out_fn = str(tmp_path / "test.tif") self.rgb_img.save(out_fn, scale_offset_tags=("scale", "offset")) with rio.open(out_fn, "r") as ds: assert np.isnan(float(ds.tags()["scale"])) assert np.isnan(float(ds.tags()["offset"])) def _save_and_check_tags(self, expected_tags, **kwargs): with NamedTemporaryFile(suffix='.tif') as tmp: self.img.save(tmp.name, **kwargs) import rasterio as rio with rio.open(tmp.name) as f: ftags = f.tags() for key, val in expected_tags.items(): np.testing.assert_almost_equal(float(ftags[key]), val) @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_scale_offset_from_lists(self): """Test saving geotiffs with tags that come from lists.""" expected_tags = {'scale': 23.0 / 255, 'offset': 1} self.img.crude_stretch([1], [24]) self._save_and_check_tags( expected_tags, scale_offset_tags=("scale", "offset")) @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_scale_offset_custom_labels(self): """Test saving GeoTIFF with different scale/offset tag labels.""" expected_tags = {"gradient": 24.0 / 255, "axis_intercept": 0} self.img.stretch() self._save_and_check_tags( expected_tags, scale_offset_tags=("gradient", "axis_intercept")) @pytest.mark.skipif(sys.platform.startswith('win'), reason="'NamedTemporaryFile' not supported on Windows") def test_save_scale_offset_custom_values(self): """Test saving GeoTIFF overriding the scale/offset values.""" expected_tags = {"gradient": 1, "axis_intercept": 0} self.img.stretch() self._save_and_check_tags( expected_tags, scale_offset_tags={"gradient": 1, "axis_intercept": 0}) def _get_tags_after_writing_to_geotiff(data): import rasterio as rio img = xrimage.XRImage(data) with NamedTemporaryFile(suffix='.tif') as tmp: img.save(tmp.name) with rio.open(tmp.name) as f: return f.tags() @pytest.mark.parametrize("attrs", [{}, {"mode": "XYZ"}]) def test_missing_bands_coord(attrs): """Test that 'bands' dimenisons need a corresponding coordinate.""" data = xr.DataArray( da.zeros((3, 10, 5), dtype=np.float32), dims=("bands", "y", "x"), attrs=attrs, ) with pytest.warns(UserWarning, match="Missing 'bands' coordinate.*"): img = xrimage.XRImage(data) exp_bands = ["R", "G", "B"] if not attrs else ["X", "Y", "Z"] np.testing.assert_array_equal(img.data.coords["bands"], exp_bands) @pytest.mark.parametrize("fill_value", [None, 255]) def test_pil_array(fill_value): """Test 'pil_array' method.""" data = xr.DataArray( da.zeros((10, 5), dtype=np.float32, chunks=2), dims=("y", "x"), ) img = xrimage.XRImage(data) pil_arr, mode = img.pil_array(fill_value) assert isinstance(pil_arr, da.Array) assert mode == ("L" if fill_value is not None else "LA") np_arr = pil_arr.compute() assert isinstance(np_arr, np.ndarray) assert np_arr.dtype == pil_arr.dtype trollimage-1.28.0/trollimage/tests/utils.py000066400000000000000000000021161514066130000207500ustar00rootroot00000000000000"""Helper classes and functions for running and writing tests.""" from contextlib import contextmanager class CustomScheduler: """Scheduler raising an exception if data are computed too many times.""" def __init__(self, max_computes=1): """Set starting and maximum compute counts.""" self.max_computes = max_computes self.total_computes = 0 def __call__(self, dsk, keys, **kwargs): """Compute dask task and keep track of number of times we do so.""" import dask self.total_computes += 1 if self.total_computes > self.max_computes: raise RuntimeError("Too many dask computations were scheduled: " "{}".format(self.total_computes)) return dask.get(dsk, keys, **kwargs) @contextmanager def assert_maximum_dask_computes(max_computes=1): """Context manager to make sure dask computations are not executed more than ``max_computes`` times.""" import dask with dask.config.set(scheduler=CustomScheduler(max_computes=max_computes)) as new_config: yield new_config trollimage-1.28.0/trollimage/utilities.py000066400000000000000000000102661514066130000204660ustar00rootroot00000000000000"""Simple utilities functions to handle colormaps and other use cases.""" from __future__ import division import numpy as np import sys from trollimage.colormap import Colormap from trollimage.image import Image from PIL import Image as Pimage def _hex_to_rgb(value): """Convert a string of 3 hex color values into a tuple of decimal values.""" value = value.lstrip('#') dec = int(value, 16) return dec def _text_to_rgb(value, norm=False, cat=1, tot=1, offset=0.5, hex=False): """Take text line and convert to RGB color. This takes as input a string composed by 3 values in the range [0,255] and returns a tuple of integers. If the parameters cat and tot are given, the function generates a transparency value for this color and returns a tuple of length 4. tot is the total number of colors in the colormap cat is the index of the current colour in the colormap if norm is set to True, the input values are normalized between 0 and 1. """ tokens = value.split() if hex: for i in range(len(tokens)): tokens[i] = _hex_to_rgb(tokens[i]) transparency = float(cat) / float(tot) + offset if transparency > 1.0: transparency = 1.0 if norm: return (float(tokens[0]) / 255.0, float(tokens[1]) / 255.0, float(tokens[2]) / 255.0, transparency) else: return (int(tokens[0]), int(tokens[1]), int(tokens[2]), int(round(transparency * 255.0))) def _make_cmap(colors, position=None, bit=False): """Convert list of tuples into Colormap object. This takes a list of tuples which contain RGB values. The RGB values may either be in 8-bit [0 to 255] (in which bit must be set to True when called) or arithmetic [0 to 1] (default). _make_cmap returns a cmap with equally spaced colors. Arrange your tuples so that the first color is the lowest value for the colorbar and the last is the highest. position contains values from 0 to 1 to dictate the location of each color. """ if position is None: position = np.linspace(0, 1, len(colors)) if len(position) != len(colors): sys.exit("position length must be the same as colors") elif position[0] != 0 or position[-1] != 1: sys.exit("position must start with 0 and end with 1") palette = [(i, (float(r), float(g), float(b), float(a))) for i, (r, g, b, a) in enumerate(colors)] cmap = Colormap(*palette) return cmap def cmap_from_text(filename, norm=False, transparency=False, hex=False): """Convert text file colormap to Colormap object. This takes as input a file that contains a colormap in text format composed by lines with 3 values in the range [0,255] or [00,FF] and returns a tuple of integers. If the parameters cat and tot are given, the function generates a transparency value for this color and returns a tuple of length 4. tot is the total number of colors in the colormap cat is the index of the current colour in the colormap if norm is set to True, the input values are normalized between 0 and 1. """ lines = [line.rstrip('\n') for line in open(filename)] _colors = [] _tot = len(lines) _index = 1 for i in lines: if transparency: _colors.append(_text_to_rgb(i, norm=norm, cat=_index, tot=_tot, hex=hex)) else: _colors.append(_text_to_rgb(i, norm=norm, hex=hex)) _index = _index + 1 return _make_cmap(_colors) def _image2array(filepath): """Extract individual R, G, and B channels from on-disk image file. Utility function that converts an image file in 3 np arrays that can be fed into geo_image.GeoImage in order to generate a PyTROLL GeoImage object. """ im = Pimage.open(filepath).convert('RGB') (width, height) = im.size _r = np.array(list(im.getdata(0))) / 255.0 _g = np.array(list(im.getdata(1))) / 255.0 _b = np.array(list(im.getdata(2))) / 255.0 _r = _r.reshape((height, width)) _g = _g.reshape((height, width)) _b = _b.reshape((height, width)) return _r, _g, _b def pilimage2trollimage(pimage): """Convert PIL Image to trollimage Image.""" (r, g, b) = _image2array(pimage) return Image((r, g, b), mode="RGB") trollimage-1.28.0/trollimage/version.py000066400000000000000000000562031514066130000201410ustar00rootroot00000000000000 # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build # directories (produced by setup.py build) will contain a much shorter file # that just contains the computed version number. # This file is released into the public domain. # Generated by versioneer-0.28 # https://github.com/python-versioneer/python-versioneer """Git implementation of _version.py.""" import errno import os import re import subprocess import sys from typing import Callable, Dict import functools def get_keywords(): """Get the keywords needed to look up the version information.""" # these strings will be replaced by git during git-archive. # setup.py/versioneer.py will grep for the variable names, so they must # each be defined on a line of their own. _version.py will just call # get_keywords(). git_refnames = " (HEAD -> main, tag: v1.28.0)" git_full = "f66a0a1157c5e020e7e67b9ed0289ab53dde1720" git_date = "2026-02-04 09:16:16 -0600" keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} return keywords class VersioneerConfig: """Container for Versioneer configuration parameters.""" def get_config(): """Create, populate and return the VersioneerConfig() object.""" # these strings are filled in when 'setup.py versioneer' creates # _version.py cfg = VersioneerConfig() cfg.VCS = "git" cfg.style = "pep440" cfg.tag_prefix = "v" cfg.parentdir_prefix = "None" cfg.versionfile_source = "trollimage/version.py" cfg.verbose = False return cfg class NotThisMethod(Exception): """Exception raised if a method is not valid for the current scenario.""" LONG_VERSION_PY: Dict[str, str] = {} HANDLERS: Dict[str, Dict[str, Callable]] = {} def register_vcs_handler(vcs, method): # decorator """Create decorator to mark a method as the handler of a VCS.""" def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f return decorate def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) process = None popen_kwargs = {} if sys.platform == "win32": # This hides the console window if pythonw.exe is used startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW popen_kwargs["startupinfo"] = startupinfo for command in commands: try: dispcmd = str([command] + args) # remember shell=False, so use git.cmd on windows, not just git process = subprocess.Popen([command] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None), **popen_kwargs) break except OSError: e = sys.exc_info()[1] if e.errno == errno.ENOENT: continue if verbose: print("unable to run %s" % dispcmd) print(e) return None, None else: if verbose: print("unable to find command, tried %s" % (commands,)) return None, None stdout = process.communicate()[0].strip().decode() if process.returncode != 0: if verbose: print("unable to run %s (error)" % dispcmd) print("stdout was %s" % stdout) return None, process.returncode return stdout, process.returncode def versions_from_parentdir(parentdir_prefix, root, verbose): """Try to determine the version from the parent directory name. Source tarballs conventionally unpack into a directory that includes both the project name and a version string. We will also support searching up two directory levels for an appropriately named parent directory """ rootdirs = [] for _ in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): return {"version": dirname[len(parentdir_prefix):], "full-revisionid": None, "dirty": False, "error": None, "date": None} rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: print("Tried directories %s but none started with prefix %s" % (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @register_vcs_handler("git", "get_keywords") def git_get_keywords(versionfile_abs): """Extract version information from the given file.""" # the code embedded in _version.py can just fetch the value of these # keywords. When used from setup.py, we don't want to import _version.py, # so we do it with a regexp instead. This function is not used from # _version.py. keywords = {} try: with open(versionfile_abs, "r") as fobj: for line in fobj: if line.strip().startswith("git_refnames ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["refnames"] = mo.group(1) if line.strip().startswith("git_full ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["full"] = mo.group(1) if line.strip().startswith("git_date ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["date"] = mo.group(1) except OSError: pass return keywords @register_vcs_handler("git", "keywords") def git_versions_from_keywords(keywords, tag_prefix, verbose): """Get version information from git keywords.""" if "refnames" not in keywords: raise NotThisMethod("Short version file found") date = keywords.get("date") if date is not None: # Use only the last line. Previous lines may contain GPG signature # information. date = date.splitlines()[-1] # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 # -like" string, which we must then edit to make compliant), because # it's been around since git-1.5.3, and it's too difficult to # discover which version we're using, or to work around using an # older one. date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) refnames = keywords["refnames"].strip() if refnames.startswith("$Format"): if verbose: print("keywords are unexpanded, not using") raise NotThisMethod("unexpanded keywords, not a git-archive tarball") refs = {r.strip() for r in refnames.strip("()").split(",")} # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " tags = {r[len(TAG):] for r in refs if r.startswith(TAG)} if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d # expansion behaves like git log --decorate=short and strips out the # refs/heads/ and refs/tags/ prefixes that would let us distinguish # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". tags = {r for r in refs if re.search(r'\d', r)} if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: print("likely tags: %s" % ",".join(sorted(tags))) for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): r = ref[len(tag_prefix):] # Filter out refs that exactly match prefix or that don't start # with a number once the prefix is stripped (mostly a concern # when prefix is '') if not re.match(r'\d', r): continue if verbose: print("picking %s" % r) return {"version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") return {"version": "0+unknown", "full-revisionid": keywords["full"].strip(), "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): """Get version from 'git describe' in the root of the source tree. This only gets called if the git-archive 'subst' keywords were *not* expanded, and _version.py hasn't already been rewritten with a short version string, meaning we're inside a checked out source tree. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] # GIT_DIR can interfere with correct operation of Versioneer. # It may be intended to be passed to the Versioneer-versioned project, # but that should not change where we get our version from. env = os.environ.copy() env.pop("GIT_DIR", None) runner = functools.partial(runner, env=env) _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=not verbose) if rc != 0: if verbose: print("Directory %s not under git control" % root) raise NotThisMethod("'git rev-parse --git-dir' returned error") # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) describe_out, rc = runner(GITS, [ "describe", "--tags", "--dirty", "--always", "--long", "--match", f"{tag_prefix}[[:digit:]]*" ], cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") describe_out = describe_out.strip() full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) if full_out is None: raise NotThisMethod("'git rev-parse' failed") full_out = full_out.strip() pieces = {} pieces["long"] = full_out pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) # --abbrev-ref was added in git-1.6.3 if rc != 0 or branch_name is None: raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") branch_name = branch_name.strip() if branch_name == "HEAD": # If we aren't exactly on a branch, pick a branch which represents # the current commit. If all else fails, we are on a branchless # commit. branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) # --contains was added in git-1.5.4 if rc != 0 or branches is None: raise NotThisMethod("'git branch --contains' returned error") branches = branches.split("\n") # Remove the first line if we're running detached if "(" in branches[0]: branches.pop(0) # Strip off the leading "* " from the list of branches. branches = [branch[2:] for branch in branches] if "master" in branches: branch_name = "master" elif not branches: branch_name = None else: # Pick the first branch that is returned. Good or bad. branch_name = branches[0] pieces["branch"] = branch_name # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] # TAG might have hyphens. git_describe = describe_out # look for -dirty suffix dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparsable. Maybe git-describe is misbehaving? pieces["error"] = ("unable to parse git-describe output: '%s'" % describe_out) return pieces # tag full_tag = mo.group(1) if not full_tag.startswith(tag_prefix): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" % (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) # commit: short hex revision ID pieces["short"] = mo.group(3) else: # HEX: no tags pieces["closest-tag"] = None out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root) pieces["distance"] = len(out.split()) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() date = runner(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() # Use only the last line. Previous lines may contain GPG signature # information. date = date.splitlines()[-1] pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces def plus_or_dot(pieces): """Return a + if we don't already have one, else return a .""" if "+" in pieces.get("closest-tag", ""): return "." return "+" def render_pep440(pieces): """Build up version string, with post-release "local version identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty Exceptions: 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += plus_or_dot(pieces) rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_branch(pieces): """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . The ".dev0" means not master branch. Note that .dev0 sorts backwards (a feature branch will appear "older" than the master branch). Exceptions: 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: if pieces["branch"] != "master": rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0" if pieces["branch"] != "master": rendered += ".dev0" rendered += "+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def pep440_split_post(ver): """Split pep440 version string at the post-release segment. Returns the release segments before the post-release and the post-release version number (or -1 if no post-release segment is present). """ vc = str.split(ver, ".post") return vc[0], int(vc[1] or 0) if len(vc) == 2 else None def render_pep440_pre(pieces): """TAG[.postN.devDISTANCE] -- No -dirty. Exceptions: 1: no tags. 0.post0.devDISTANCE """ if pieces["closest-tag"]: if pieces["distance"]: # update the post release segment tag_version, post_version = pep440_split_post(pieces["closest-tag"]) rendered = tag_version if post_version is not None: rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"]) else: rendered += ".post0.dev%d" % (pieces["distance"]) else: # no commits, use the tag as the version rendered = pieces["closest-tag"] else: # exception #1 rendered = "0.post0.dev%d" % pieces["distance"] return rendered def render_pep440_post(pieces): """TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that .dev0 sorts backwards (a dirty tree will appear "older" than the corresponding clean one), but you shouldn't be releasing software with -dirty anyways. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%s" % pieces["short"] else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += "+g%s" % pieces["short"] return rendered def render_pep440_post_branch(pieces): """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . The ".dev0" means not master branch. Exceptions: 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["branch"] != "master": rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%s" % pieces["short"] if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["branch"] != "master": rendered += ".dev0" rendered += "+g%s" % pieces["short"] if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_old(pieces): """TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" return rendered def render_git_describe(pieces): """TAG[-DISTANCE-gHEX][-dirty]. Like 'git describe --tags --dirty --always'. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render_git_describe_long(pieces): """TAG-DISTANCE-gHEX[-dirty]. Like 'git describe --tags --dirty --always -long'. The distance/hash is unconditional. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: return {"version": "unknown", "full-revisionid": pieces.get("long"), "dirty": None, "error": pieces["error"], "date": None} if not style or style == "default": style = "pep440" # the default if style == "pep440": rendered = render_pep440(pieces) elif style == "pep440-branch": rendered = render_pep440_branch(pieces) elif style == "pep440-pre": rendered = render_pep440_pre(pieces) elif style == "pep440-post": rendered = render_pep440_post(pieces) elif style == "pep440-post-branch": rendered = render_pep440_post_branch(pieces) elif style == "pep440-old": rendered = render_pep440_old(pieces) elif style == "git-describe": rendered = render_git_describe(pieces) elif style == "git-describe-long": rendered = render_git_describe_long(pieces) else: raise ValueError("unknown style '%s'" % style) return {"version": rendered, "full-revisionid": pieces["long"], "dirty": pieces["dirty"], "error": None, "date": pieces.get("date")} def get_versions(): """Get version information or return default if unable to do so.""" # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have # __file__, we can work backwards from there to the root. Some # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which # case we can only use expanded keywords. cfg = get_config() verbose = cfg.verbose try: return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) except NotThisMethod: pass try: root = os.path.realpath(__file__) # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. for _ in cfg.versionfile_source.split('/'): root = os.path.dirname(root) except NameError: return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to find root of source tree", "date": None} try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) return render(pieces, cfg.style) except NotThisMethod: pass try: if cfg.parentdir_prefix: return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) except NotThisMethod: pass return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to compute version", "date": None} trollimage-1.28.0/trollimage/xrimage.py000066400000000000000000002160241514066130000201070ustar00rootroot00000000000000"""This module defines the XRImage class. It overlaps largely with the PIL library, but has the advantage of using :class:`~xarray.DataArray` objects backed by :class:`dask arrays ` as pixel arrays. This allows for invalid values to be tracked, metadata to be assigned, and stretching to be lazy evaluated. With the optional ``rasterio`` library installed dask array chunks can be saved in parallel. """ from __future__ import annotations import logging import numbers import os import pathlib import warnings from collections.abc import Sequence from typing import IO, Callable import dask.array as da import numpy as np import xarray as xr from PIL import Image as PILImage from trollimage.image import check_image_format logger = logging.getLogger(__name__) def combine_scales_offsets(*args): """Combine ``(scale, offset)`` tuples in one, considering they are applied from left to right. For example, if we have our base data called ```orig_data`` and apply to it ``(scale_1, offset_1)``, then ``(scale_2, offset_2)`` such that:: data_1 = orig_data * scale_1 + offset_1 data_2 = data_1 * scale_2 + offset_2 this function will return the tuple ``(scale, offset)`` such that:: data_2 = orig_data * scale + offset given the arguments ``(scale_1, offset_1), (scale_2, offset_2)``. """ cscale = 1 coffset = 0 for scale, offset in args: cscale *= scale coffset = coffset * scale + offset return cscale, coffset def invert_scale_offset(scale, offset): """Invert scale and offset to allow reverse transformation. Ie, it will return ``rscale, roffset`` such that:: orig_data = rscale * data + roffset if:: data = scale * orig_data + offset """ return 1 / scale, -offset / scale def lazy_pil_save( pil_ready_arr: da.Array, mode: str, pathname_or_io: str | os.PathLike | IO[bytes], *args, **kwargs, ) -> da.Array: """Save PIL Image in a dask-friendly way. Special wrapper to handle `fill_value` try/except catch and provide a more useful error message. """ save_res = da.map_blocks( _save_img_arr, pil_ready_arr.rechunk(pil_ready_arr.shape), mode, pathname_or_io, args, kwargs, chunks=((1,),), drop_axis=list(range(pil_ready_arr.ndim))[1:], # drop all but the first axis dtype=object, meta=np.ndarray((), dtype=object), ) return save_res def _save_img_arr( pil_ready_arr: np.ndarray, mode: str, pathname_or_io: str | os.PathLike | IO[bytes], pil_args: tuple, pil_kwargs: dict, ) -> np.ndarray: img = PILImage.fromarray(pil_ready_arr, mode) try: img.save(pathname_or_io, *pil_args, **pil_kwargs) except OSError as e: # ex: cannot write mode LA as JPEG if "A as JPEG" in str(e): new_msg = ("Image mode not supported for this format. Specify " "`fill_value=0` to set invalid values to black.") raise OSError(new_msg) from e raise ret_val = pil_args[0] if isinstance(pil_args[0], (str, os.PathLike)) else None return np.array([ret_val], dtype=object) class XRImage: """Image class using an :class:`xarray.DataArray` as internal storage. It can be saved to a variety of image formats, but if Rasterio is installed, it can save to geotiff and jpeg2000 with geographical information. The enhancements functions are recording some parameters in the image's data attribute called `enhancement_history`. """ def __init__(self, data): """Initialize the image with a :class:`~xarray.DataArray`.""" data = self._correct_dims(data) # 'data' is an XArray, get the data from it as a dask array if not isinstance(data.data, da.Array): logger.debug("Convert image data to dask array") data.data = da.from_array(data.data, chunks=(data.sizes['bands'], 4096, 4096)) self.data = data self.height, self.width = self.data.sizes['y'], self.data.sizes['x'] self.palette = None @staticmethod def _correct_dims(data): """Standardize dimensions to bands, y, and x.""" if not hasattr(data, 'dims'): raise TypeError("Data must have a 'dims' attribute.") if 'y' not in data.dims or 'x' not in data.dims: if data.ndim != 2: raise ValueError("Data must have a 'y' and 'x' dimension") # rename dimensions so we can use them # don't rename 'x' or 'y' if they already exist if 'y' not in data.dims: # find a dimension that isn't 'x' old_dim = [d for d in data.dims if d != 'x'][0] data = data.rename({old_dim: 'y'}) if 'x' not in data.dims: # find a dimension that isn't 'y' old_dim = [d for d in data.dims if d != 'y'][0] data = data.rename({old_dim: 'x'}) if "bands" not in data.dims: if data.ndim <= 2: data = data.expand_dims('bands') data['bands'] = ['L'] else: raise ValueError("No 'bands' dimension provided.") elif "bands" not in data.coords or not np.issubdtype(data.coords["bands"].dtype, str): bands_by_size = {1: "L", 3: "RGB", 4: "RGBA"} if "mode" in data.attrs: mode = data.attrs["mode"] mode_method = "'mode' attribute" else: mode = bands_by_size[data.sizes["bands"]] mode_method = "dimension size" warnings.warn(f"Missing 'bands' coordinate. Assigning bands based on {mode_method}: {mode}", stacklevel=3) data.coords["bands"] = list(mode) # doesn't actually copy the data underneath # we don't want our operations to change the user's data # we do this last in case `expand_dims` made the data read only data = data.copy() return data @property def mode(self): """Mode of the image.""" return ''.join(self.data['bands'].values) @staticmethod def _gtiff_to_cog_kwargs(format_kwargs): """Convert GDAL Geotiff driver options to COG driver options. The COG driver automatically sets some format options but zlevel is called level and blockxsize is called blocksize. Convert kwargs to save() from GTiff driver to COG driver. """ format_kwargs.pop('photometric', None) if 'zlevel' in format_kwargs: format_kwargs['level'] = format_kwargs.pop('zlevel') if 'jpeg_quality' in format_kwargs: format_kwargs['quality'] = format_kwargs.pop('jpeg_quality') format_kwargs.pop('tiled', None) if 'blockxsize' in format_kwargs: format_kwargs['blocksize'] = format_kwargs.pop('blockxsize') format_kwargs.pop('blockysize', None) return format_kwargs def save(self, filename, fformat=None, fill_value=None, compute=True, keep_palette=False, cmap=None, driver=None, **format_kwargs): """Save the image to the given *filename*. Args: filename (str): Output filename fformat (str): File format of output file (optional). Can be one of many image formats supported by the `rasterio` or `PIL` libraries ('jpg', 'png', 'tif'). By default this is determined by the extension of the provided filename. If the format allows, geographical information will be saved to the ouput file, in the form of grid mapping or ground control points. driver (str): can override the choice of rasterio/gdal driver which is normally selected from the filename or fformat. This is an implementation detail normally avoided but can be necessary if you wish to distinguish between GeoTIFF drivers ("GTiff" is the default, but you can specify "COG" to write a Cloud-Optimized GeoTIFF). fill_value (float): Replace invalid data values with this value and do not produce an Alpha band. Default behavior is to create an alpha band. compute (bool): If True (default) write the data to the file immediately. If False the return value is either a `dask.Delayed` object or a tuple of ``(source, target)`` to be passed to `dask.array.store`. keep_palette (bool): Saves the palettized version of the image if set to True. False by default. Warning: this does not automatically write the colormap (palette) to the file. To write the colormap to the file, one should additionally pass the colormap with the ``cmap`` keyword argument. cmap (Colormap or dict): Colormap to be applied to the image when saving with rasterio, used with keep_palette=True. Should be uint8. format_kwargs: Additional format options to pass to `rasterio` or `PIL` saving methods. Any format argument passed at this stage would be superseeded by `fformat`. Returns: Either `None` or the saved filename if `compute` is True or ``(source, target)`` pair to be passed to `dask.array.store`. If compute is False the return value depends on format and how the image backend is used. If ``(source, target)`` is provided then target is an open file-like object that must be closed by the caller. """ kwformat = format_kwargs.pop('format', None) fformat = fformat or kwformat or os.path.splitext(filename)[1][1:] if fformat in ('tif', 'tiff', 'jp2'): try: return self.rio_save(filename, fformat=fformat, driver=driver, fill_value=fill_value, compute=compute, keep_palette=keep_palette, cmap=cmap, **format_kwargs) except ImportError: logger.warning("Missing 'rasterio' dependency to save GeoTIFF " "image. Will try using PIL...") return self.pil_save(filename, fformat, fill_value, compute=compute, **format_kwargs) def rio_save(self, filename, fformat=None, fill_value=None, dtype=np.uint8, compute=True, tags=None, keep_palette=False, cmap=None, overviews=None, overviews_minsize=256, overviews_resampling=None, include_scale_offset_tags=False, scale_offset_tags=None, colormap_tag=None, driver=None, **format_kwargs): """Save the image using rasterio. Args: filename (string): The filename to save to. fformat (string): The format to save to. If not specified (default), it will be infered from the file extension. driver (string): The gdal driver to use. If not specified (default), it will be inferred from the fformat, but you can override the default GeoTIFF driver ("GTiff") with "COG" if you want to create a Cloud_Optimized GeoTIFF (and set `tiled=True,overviews=[]`). fill_value (number): The value to fill the missing data with. Default is ``None``, translating to trying to keep the data transparent. dtype (np.dtype): The type to save the data to. Defaults to np.uint8. compute (bool): Whether (default) or not to compute the lazy data. tags (dict): Tags to include in the file. keep_palette (bool): Whether or not (default) to keep the image in P mode. cmap (colormap): The colormap to use for the data. overviews (list): The reduction factors of the overviews to include in the image, eg:: img.rio_save('myfile.tif', overviews=[2, 4, 8, 16]) If provided as an empty list, then levels will be computed as powers of two until the last level has less pixels than `overviews_minsize`. If driver='COG' then use `overviews=[]` to get a Cloud-Optimized GeoTIFF with a correct set of overviews created automatically. Default is to not add overviews. overviews_minsize (int): Minimum number of pixels for the smallest overview size generated when `overviews` is auto-generated. Defaults to 256. overviews_resampling (str): Resampling method to use when generating overviews. This must be the name of an enum value from :class:`rasterio.enums.Resampling` and only takes effect if the `overviews` keyword argument is provided. Common values include `nearest` (default), `bilinear`, `average`, and many others. See the rasterio documentation for more information. scale_offset_tags (Tuple[str, str] or Dict[str, number] or None): If set to a ``(str, str)`` tuple, scale and offset will be stored in GDALMetaData tags. Those can then be used to retrieve the original data values from pixel values. Scale and offset will be set to (NaN, NaN) for images that had non-linear enhancements applied (ex. gamma) as they can't be represented by a simple scale and offset. Scale and offset are also saved as (NaN, NaN) for multi-band images (ex. RGB) as storing multiple values in a single GDALMetaData tag is not currently supported. If set to a dictionary, automatically determined scale/offset values are overruled by the values provided in the keys. colormap_tag (str or None): If set and the image was colorized or palettized, a tag will be added with this name with the value of a comma-separated version of the Colormap that was used. See :meth:`trollimage.colormap.Colormap.to_csv` for more information. Returns: The filename saved if ``compute`` is ``True``. Otherwise, a two element tuple to be passed to :func:`dask.array.core.store`. The first element represents the source or sources to save and the second element is the target or targets to save to. Sources and targets may be a single object or a list of objects. The targets may be file-like objects that must be closed by the user. """ from ._xrimage_rasterio import RIOFile, RIODataset, split_regular_vs_lazy_tags fformat = fformat or os.path.splitext(filename)[1][1:] drivers = {'jpg': 'JPEG', 'png': 'PNG', 'tif': 'GTiff', 'tiff': 'GTiff', 'jp2': 'JP2OpenJPEG'} # If fformat is specified but not driver then convert it into a driver driver = driver or drivers.get(fformat, fformat) # The COG driver adds overviews so we don't need to create them ourself. # One thing we can't do is prevent any overviews, if we use None then # the COG driver will create automatically, we can't pass OVERVIEWS=NONE. if driver == 'COG' and overviews == []: overviews = None if include_scale_offset_tags: warnings.warn( "include_scale_offset_tags is deprecated, please use " "scale_offset_tags to indicate tag labels", DeprecationWarning, stacklevel=2) scale_offset_tags = scale_offset_tags or ("scale", "offset") if tags is None: tags = {} data, mode = self.finalize(fill_value, dtype=dtype, keep_palette=keep_palette) data = data.transpose('bands', 'y', 'x') crs = None gcps = None transform = None if driver in ['COG', 'GTiff', 'JP2OpenJPEG']: if not np.issubdtype(data.dtype, np.floating): format_kwargs.setdefault('compress', 'DEFLATE') photometric_map = { 'RGB': 'RGB', 'RGBA': 'RGB', 'CMYK': 'CMYK', 'CMYKA': 'CMYK', 'YCBCR': 'YCBCR', 'YCBCRA': 'YCBCR', } if mode.upper() in photometric_map: format_kwargs.setdefault('photometric', photometric_map[mode.upper()]) from ._xrimage_rasterio import get_data_arr_crs_transform_gcps crs, transform, gcps = get_data_arr_crs_transform_gcps(data) stime = data.attrs.get("start_time") if stime: stime_str = stime.strftime("%Y:%m:%d %H:%M:%S") tags.setdefault('TIFFTAG_DATETIME', stime_str) if driver == 'JPEG' and 'A' in mode: raise ValueError('JPEG does not support alpha') enhancement_colormap = self._get_colormap_from_enhancement_history(data) if colormap_tag and enhancement_colormap is not None: tags[colormap_tag] = enhancement_colormap.to_csv() if scale_offset_tags: self._add_scale_offset_to_tags(scale_offset_tags, data, tags) # If we are changing the driver then use appropriate kwargs if driver == 'COG': format_kwargs = self._gtiff_to_cog_kwargs(format_kwargs) # FIXME add metadata r_file = RIOFile(filename, 'w', driver=driver, width=data.sizes['x'], height=data.sizes['y'], count=data.sizes['bands'], dtype=dtype, nodata=fill_value, crs=crs, transform=transform, gcps=gcps, **format_kwargs) r_file.open() if not keep_palette: from ._xrimage_rasterio import color_interp r_file.colorinterp = color_interp(data) if keep_palette and cmap is not None: if data.dtype != 'uint8': raise ValueError('Rasterio only supports 8-bit colormaps') try: from trollimage.colormap import Colormap cmap = cmap.to_rio() if isinstance(cmap, Colormap) else cmap r_file.rfile.write_colormap(1, cmap) except AttributeError: raise ValueError("Colormap is not formatted correctly") tags, da_tags = split_regular_vs_lazy_tags(tags, r_file) r_file.rfile.update_tags(**tags) r_dataset = RIODataset(r_file, overviews, overviews_resampling=overviews_resampling, overviews_minsize=overviews_minsize) to_store = ([data.data], [r_dataset]) if da_tags: to_store[0].extend([tag_pair[0] for tag_pair in da_tags]) to_store[1].extend([tag_pair[1] for tag_pair in da_tags]) if compute: # write data to the file now da.store(*to_store) to_close = to_store[1] for item in to_close: item.close() return filename # provide the data object and the opened file so the caller can # store them when they would like. Caller is responsible for # closing the file return to_store @staticmethod def _get_colormap_from_enhancement_history(data_arr): for enhance_dict in reversed(data_arr.attrs.get('enhancement_history', [])): if "colormap" in enhance_dict: return enhance_dict["colormap"] return None def pil_save( self, filename: str | pathlib.Path, fformat: str | None = None, fill_value: float | int | None = None, compute: bool = True, **format_kwargs, ) -> da.Array | str | pathlib.Path: """Save the image to the given *filename* using PIL. For now, the compression level [0-9] is ignored, due to PIL's lack of support. See also :meth:`save`. """ fformat = fformat or os.path.splitext(filename)[1][1:] fformat = check_image_format(fformat) if fformat == 'png': # Take care of GeoImage.tags (if any). format_kwargs['pnginfo'] = self._pngmeta() pil_ready_arr, mode = self.pil_array(fill_value) filename_arr = lazy_pil_save(pil_ready_arr, mode, filename, fformat, **format_kwargs) if compute: fn_arr = filename_arr.compute() return fn_arr[0] return filename_arr def _add_scale_offset_to_tags(self, scale_offset_tags, data_arr, tags): scale_label, offset_label = scale_offset_tags try: scale = scale_offset_tags[scale_label] offset = scale_offset_tags[offset_label] except TypeError: scale, offset = self.get_scaling_from_history(data_arr.attrs.get('enhancement_history', [])) tags[scale_label], tags[offset_label] = invert_scale_offset(scale, offset) def get_scaling_from_history(self, history=None): """Merge the scales and offsets from the history. If ``history`` isn't provided, the history of the current image will be used. """ if history is None: history = self.data.attrs.get('enhancement_history', []) try: scaling = [(item['scale'], item['offset']) for item in history] except KeyError as err: logger.debug("Can only get combine scaling from a list of linear " f"scaling operations: {err}. Setting scale and offset " "to (NaN, NaN).") return np.nan, np.nan scale, offset = combine_scales_offsets(*scaling) scale_is_not_scalar = not isinstance(scale, numbers.Number) and len(scale) != 1 offset_is_not_scalar = not isinstance(offset, numbers.Number) and len(offset) != 1 if scale_is_not_scalar or offset_is_not_scalar: logger.debug("Multi-band scale/offset tags can't be saved to " "geotiff. Setting scale and offset to (NaN, NaN).") return np.nan, np.nan return scale, offset def apply_pil(self, fun, output_mode, pil_args=None, pil_kwargs=None, fun_args=None, fun_kwargs=None): """Apply a function `fun` on the pillow image corresponding to the instance of the XRImage. The function shall take a pil image as first argument, and is then passed fun_args and fun_kwargs. In addition, the current images's metadata is passed as a keyword argument called `image_metadata`. It is expected to return the modified pil image. This function returns a new XRImage instance with the modified image data. The pil_args and pil_kwargs are passed to the `pil_image` method of the XRImage instance. """ if pil_args is None: pil_args = tuple() if pil_kwargs is None: pil_kwargs = dict() pil_ready_arr, mode = self.pil_array(*pil_args, **pil_kwargs) # HACK: aggdraw.Font objects cause segmentation fault in dask tokenize # Remove this when aggdraw is either updated to allow type(font_obj) # or pycoast is updated to not accept Font objects # See https://github.com/pytroll/pycoast/issues/43 # The last positional argument to the _burn_overlay function in Satpy # is the 'overlay' dict. This could include aggdraw.Font objects so we # completely remove it. mapblocks_kwargs = {} if fun.__name__ == "_burn_overlay": from dask.base import tokenize from dask.utils import funcname func = _delayed_apply_pil if fun_args is None: fun_args = tuple() if fun_kwargs is None: fun_kwargs = dict() tokenize_args = (pil_ready_arr, mode, fun, fun_args[:-1], fun_kwargs, self.data.attrs, self.data.dtype, output_mode) dask_key_name = "%s-%s" % ( funcname(func), tokenize(*tokenize_args, pure=True), ) mapblocks_kwargs["token"] = dask_key_name new_img_data = da.map_blocks( _delayed_apply_pil, pil_ready_arr.rechunk(pil_ready_arr.shape), mode, fun, fun_args, fun_kwargs, self.data.dtype, output_mode=output_mode, image_metadata=self.data.attrs, dtype=self.data.dtype, meta=np.ndarray((), dtype=self.data.dtype), chunks=((self.data.sizes["y"],), (self.data.sizes["x"],), (len(output_mode),)), **mapblocks_kwargs, ) # new_array = self._delayed_apply_pil(fun, img_arr, fun_args, fun_kwargs, # self.data.attrs, output_mode, # **mapblocks_kwargs) new_data = xr.DataArray(new_img_data, dims=['y', 'x', 'bands'], coords={'y': self.data.coords['y'], 'x': self.data.coords['x'], 'bands': list(output_mode)}, attrs=self.data.attrs) return XRImage(new_data) def _pngmeta(self): """Return GeoImage.tags as a PNG metadata object. Inspired by: public domain, Nick Galbreath http://blog.modp.com/2007/08/python-pil-and-png-metadata-take-2.html """ reserved = ('interlace', 'gamma', 'dpi', 'transparency', 'aspect') try: tags = self.tags except AttributeError: tags = {} # Undocumented class from PIL import PngImagePlugin meta = PngImagePlugin.PngInfo() # Copy from tags to new dict for k__, v__ in tags.items(): if k__ not in reserved: meta.add_text(k__, v__, 0) return meta def _create_alpha(self, data, fill_value=None): """Create an alpha band DataArray object. If `fill_value` is provided and input data is an integer type then it is used to determine invalid "null" pixels instead of xarray's `isnull` and `notnull` methods. The returned array is 1 where data is valid, 0 where invalid. """ not_alpha = [b for b in data.coords['bands'].values if b != 'A'] null_mask = data.sel(bands=not_alpha) if np.issubdtype(data.dtype, np.integer) and fill_value is not None: null_mask = null_mask != fill_value else: null_mask = null_mask.notnull() # if any of the bands are valid, we don't want transparency null_mask = null_mask.any(dim='bands') null_mask = null_mask.expand_dims('bands') null_mask['bands'] = ['A'] # changes to null_mask attrs should not effect the original attrs # XRImage never uses them either null_mask.attrs = {} return null_mask def _add_alpha(self, data, alpha=None): """Create an alpha channel and concatenate it to the provided data. If ``data`` is an integer type then the alpha band will be scaled to use the smallest (min) value as fully transparent and the largest (max) value as fully opaque. If a `_FillValue` attribute is found for integer type data then it is used to identify null values in the data. Otherwise xarray's `isnull` is used. For float types the alpha band spans 0 to 1. """ fill_value = data.attrs.get('_FillValue', None) # integer fill value null_mask = alpha if alpha is not None else self._create_alpha(data, fill_value) # if we are using integer data, then alpha needs to be min-int to max-int # otherwise for floats we want 0 to 1 if np.issubdtype(data.dtype, np.integer): # xarray sometimes upcasts this calculation, so cast again null_mask = self._scale_to_dtype(null_mask, data.dtype).astype(data.dtype) attrs = data.attrs.copy() data = xr.concat([data, null_mask], dim="bands") data.attrs = attrs return data def _get_dtype_scale_offset(self, dtype, fill_value): dinfo = np.iinfo(dtype) scale = dinfo.max - dinfo.min offset = dinfo.min if fill_value is not None: if fill_value == dinfo.min: # leave the lowest value for fill value only offset = offset + 1 scale = scale - 1 elif fill_value == dinfo.max: # leave the top value for fill value only scale = scale - 1 else: warnings.warn( "Specified fill value will overlap with valid " "data. To avoid this warning specify a fill_value " "that is the minimum or maximum for the data type " "being saved to.", stacklevel=3) return scale, offset def _scale_to_dtype(self, data, dtype, fill_value=None): """Scale provided data to dtype range assuming a 0-1 range. Float input data is assumed to be normalized to a 0 to 1 range. Integer input data is not scaled, only clipped. A float output type is not scaled since both outputs and inputs are assumed to be in the 0-1 range already. """ attrs = data.attrs.copy() if np.issubdtype(dtype, np.integer): if np.issubdtype(data, np.bool_): # convert boolean masks to floats so they can be scaled to the output integer dtype data = data.astype(np.float64) if np.issubdtype(data, np.integer): # preserve integer data type data = data.clip(np.iinfo(dtype).min, np.iinfo(dtype).max) else: # scale float data (assumed to be 0 to 1) to full integer space # leave room for fill value if needed scale, offset = self._get_dtype_scale_offset(dtype, fill_value) data = data.clip(0, 1) * scale + offset attrs.setdefault('enhancement_history', list()).append({'scale': scale, 'offset': offset}) data = data.round() if fill_value is None: data = data.fillna(np.iinfo(dtype).min) data.attrs = attrs return data def _check_modes(self, modes): """Check that the image is in one of the given *modes*, raise an exception otherwise.""" if not isinstance(modes, (tuple, list, set)): modes = [modes] if self.mode not in modes: raise ValueError("Image not in suitable mode, expected: %s, got: %s" % (modes, self.mode)) def _from_p(self, mode): """Convert the image from P or PA to RGB or RGBA.""" self._check_modes(("P", "PA")) if not self.palette: raise RuntimeError("Can't convert palettized image, missing palette.") pal = np.array(self.palette) pal = da.from_array(pal, chunks=pal.shape) if pal.shape[1] == 4: # colormap's alpha overrides data alpha mode = "RGBA" alpha = None elif self.mode.endswith("A"): # add a new/fake 'bands' dimension to the end alpha = self.data.sel(bands="A").data[..., None] mode = mode + "A" if not mode.endswith("A") else mode else: alpha = None flat_indexes = self.data.sel(bands='P').data.ravel().astype('int64') dim_sizes = ((key, val) for key, val in self.data.sizes.items() if key != 'bands') dims, new_shape = zip(*dim_sizes) dims = dims + ('bands',) new_shape = new_shape + (pal.shape[1],) new_data = pal[flat_indexes].reshape(new_shape) coords = dict(self.data.coords) coords["bands"] = list(mode) if alpha is not None: new_arr = da.concatenate((new_data, alpha), axis=-1) data = xr.DataArray(new_arr, coords=coords, attrs=self.data.attrs, dims=dims) else: data = xr.DataArray(new_data, coords=coords, attrs=self.data.attrs, dims=dims) return data def _l2rgb(self, mode): """Convert from L (black and white) to RGB.""" self._check_modes(("L", "LA")) bands = ["L"] * 3 if mode[-1] == "A": bands.append("A") data = self.data.sel(bands=bands) data["bands"] = list(mode) return data def convert(self, mode): """Convert image to *mode*.""" if mode == self.mode: return self.__class__(self.data) if mode not in ["P", "PA", "L", "LA", "RGB", "RGBA"]: raise ValueError("Mode %s not recognized." % (mode)) if mode == self.mode + "A": data = self._add_alpha(self.data).data coords = dict(self.data.coords) coords["bands"] = list(mode) data = xr.DataArray(data, coords=coords, attrs=self.data.attrs, dims=self.data.dims) new_img = XRImage(data) elif mode + "A" == self.mode: # Remove the alpha band from our current image no_alpha = self.data.sel(bands=[b for b in self.data.coords["bands"].data if b != "A"]).data coords = dict(self.data.coords) coords["bands"] = list(mode) data = xr.DataArray(no_alpha, coords=coords, attrs=self.data.attrs, dims=self.data.dims) new_img = XRImage(data) elif mode.endswith("A") and not self.mode.endswith("A"): img = self.convert(self.mode + "A") new_img = img.convert(mode) elif self.mode.endswith("A") and not mode.endswith("A"): img = self.convert(self.mode[:-1]) new_img = img.convert(mode) else: cases = { "P": {"RGB": self._from_p}, "PA": {"RGBA": self._from_p}, "L": {"RGB": self._l2rgb}, "LA": {"RGBA": self._l2rgb} } try: data = cases[self.mode][mode](mode) new_img = XRImage(data) except KeyError: raise ValueError("Conversion from %s to %s not implemented !" % (self.mode, mode)) if self.mode.startswith('P') and new_img.mode.startswith('P'): # need to copy the palette new_img.palette = self.palette return new_img def final_mode(self, fill_value=None): """Get the mode of the finalized image when provided this fill_value.""" if fill_value is None and not self.mode.endswith('A'): return self.mode + 'A' return self.mode def _add_alpha_and_scale(self, data, ifill, dtype): alpha = self._create_alpha(data, fill_value=ifill) data = self._scale_to_dtype(data, dtype) data = data.astype(dtype) data = self._add_alpha(data, alpha=alpha) return data def _replace_fill_value(self, data, ifill, fill_value, dtype): # Add fill_value after all other calculations have been done to # make sure it is not scaled for the data type if ifill is not None and fill_value is not None: # cast fill value to output type so we don't change data type fill_value = dtype(fill_value) # integer fields have special fill values data = data.where(data != ifill, dtype(fill_value)) elif fill_value is not None: data = data.fillna(dtype(fill_value)) return data def _get_input_fill_value(self, data): # if the data are integers then this fill value will be used to check for invalid values if np.issubdtype(data, np.integer): return data.attrs.get('_FillValue') return None def _scale_and_replace_fill_value(self, data, input_fill_value, fill_value, dtype, scale, replace_fill_value): # scale float data to the proper dtype # this method doesn't cast yet so that we can keep track of NULL values if scale: data = self._scale_to_dtype(data, dtype, fill_value) if replace_fill_value: data = self._replace_fill_value(data, input_fill_value, fill_value, dtype) return data def _scale_alpha_or_fill_data(self, data, fill_value, dtype, scale, alpha, replace_fill_value): input_fill_value = self._get_input_fill_value(data) needs_alpha = alpha and fill_value is None and not self.mode.endswith('A') if needs_alpha: # We don't have a fill value or an alpha, let's add an alpha return self._add_alpha_and_scale(data, input_fill_value, dtype) return self._scale_and_replace_fill_value(data, input_fill_value, fill_value, dtype, scale, replace_fill_value) def finalize(self, fill_value=None, dtype=np.uint8, keep_palette=False): """Finalize the image to be written to an output file. This adds an alpha band or fills data with a fill_value (if specified). It also scales float data to the output range of the data type (0-255 for uint8, default). For integer input data this method assumes the data is already scaled to the proper desired range. It will still fill in invalid values and add an alpha band if needed. Integer input data's fill value is determined by a special ``_FillValue`` attribute in the ``DataArray`` ``.attrs`` dictionary. Args: fill_value (int or float or None): Output value to use to represent invalid or missing pixels. By default this is `None` meaning an Alpha channel will be used to represent the invalid values; transparent for invalid, opaque otherwise. Some output formats do not support alpha channels so a ``fill_value`` must be provided. This is determined by the underlying library doing the writing (pillow or rasterio). If specified, it should be the minimum or maximum of the ``dtype`` (ex. 0 or 255 for uint8). Floating point image data is then scaled to fit the remainder of the data type space. Integer image data will **not** be scaled. For example, a ``dtype`` of ``numpy.uint8`` and a ``fill_value`` of 0 will result in floating-point data being scaled linearly from 1 to 255. dtype (numpy.dtype): Output data type to convert the current image data to. Default is unsigned 8-bit integer (:class:`numpy.uint8`). keep_palette (bool): Whether to convert a paletted image to RGB/A or not. If ``False`` (default) then ``P`` mode images will be converted to ``RGB`` and ``PA`` will be converted to ``RGBA``. If ``True``, images with mode ``P`` or ``PA`` are kept as is and will not be scaled in order for their index values into a palette to be maintained. This flag should always be ``False`` for non-paletted images. """ if keep_palette and not self.mode.startswith('P'): keep_palette = False if not keep_palette: finalize_kwargs = dict( fill_value=fill_value, dtype=dtype, keep_palette=keep_palette, ) if self.mode == "P": return self.convert("RGB").finalize(**finalize_kwargs) if self.mode == "PA": return self.convert("RGBA").finalize(**finalize_kwargs) if np.issubdtype(dtype, np.floating) and fill_value is None: logger.warning("Image with floats cannot be transparent, so " "setting fill_value to 0") fill_value = 0 final_data = self.data.copy() try: final_data.attrs['enhancement_history'] = list(self.data.attrs['enhancement_history']) except KeyError: pass with xr.set_options(keep_attrs=True): attrs = final_data.attrs final_data = self._scale_alpha_or_fill_data( final_data, fill_value, dtype, scale=not keep_palette, alpha=not keep_palette, replace_fill_value=True) final_data = final_data.astype(dtype) final_data.attrs = attrs return final_data, ''.join(final_data['bands'].values) def pil_image( self, fill_value: int | float | None = None, compute: bool = True, ) -> PILImage.Image: """Return a PIL image from the current image. Args: fill_value (int or float): Value to use for NaN null values. See :meth:`~trollimage.xrimage.XRImage.finalize` for more info. compute (bool): Deprecated. The ``False`` case is no longer supported, use :meth:`pil_array` instead. Returns: A ``PILImage.Image`` if ``compute`` is ``True`` (default). The ``compute=False`` case is no longer supported. """ pil_ready_arr, mode = self.pil_array(fill_value) if not compute: raise RuntimeError("Delayed PIL Image creation is no longer supported. Set 'compute=True' (default) " "to get a PIL Image object back or use the 'pil_array' method to get a dask " "array and image mode that are ready to be passed to 'PILImage.fromarray' " "in a later dask function.") return PILImage.fromarray(pil_ready_arr.compute(), mode=mode) def pil_array( self, fill_value: int | float | None = None, ) -> tuple[da.Array, str]: """Return a PIL-ready array wrapped in a dask Array and the associated image mode. The underlying array is a numpy array of this image's data that has been finalized and squeezed to remove dimensions of size 1. The second return value is the expected image mode of the data as a string (ex. "RGB") that can be passed to ``PIL.Image.fromarray``. This method exists to avoid using dask Delayed functions which at the time of writing result in duplicate computation of Array tasks that are used as input to the Delayed function. This method should be used when wanting to perform a lazy evaluated dask operation on a PIL Image object. The lazy operation (ex. a function called from dask's ``map_blocks``) is expected to do ``PIL.Image.fromarray(pil_array, mode=mode)`` with the input ``pil_array``. The dask Array will have whatever chunking this `XRImage`'s data has and is not guaranteed to be one large chunk. One chunk may be needed to process the data as one single PIL Image. To rechunk the data for a call to dask's ``map_blocks`` pass the rechunked version of the data with ``pil_ready_arr.rechunk(pil_ready_arr.shape)``. Args: fill_value (int or float): Value to use for NaN null values. See :meth:`~trollimage.xrimage.XRImage.finalize` for more info. Returns: Dask array wrapping a finalized image numpy array and the image mode as a string (ex. "RGB"). """ channels, mode = self.finalize(fill_value) pil_ready_arr = np.squeeze(channels.transpose('y', 'x', 'bands').data) return pil_ready_arr, mode def xrify_tuples(self, tup): """Make xarray.DataArray from tuple.""" return xr.DataArray(tup, dims=['bands'], coords={'bands': self.data['bands']}) def gamma(self, gamma=None): """Apply gamma correction to the channels of the image. If *gamma* is a tuple, then it should have as many elements as the channels of the image, and the gamma correction is applied elementwise. If *gamma* is a number, the same gamma correction is applied on every channel, if there are several channels in the image. The behaviour of :func:`gamma` is undefined outside the normal [0,1] range of the channels. """ if _is_unity_or_none(gamma): return inverse_gamma = self._get_inverse_gamma(gamma) logger.debug("Applying gamma %s", str(gamma)) attrs = self.data.attrs self.data = self.data.clip(min=0) self.data **= inverse_gamma self.data.attrs = attrs self.data.attrs.setdefault('enhancement_history', []).append({'gamma': gamma}) def _get_inverse_gamma(self, gamma): if np.issubdtype(self.data.dtype, np.floating): dtype = self.data.dtype else: dtype = np.float32 if isinstance(gamma, (list, tuple)): gamma = self.xrify_tuples(gamma).astype(dtype) else: gamma = np.array(gamma, dtype=dtype) return 1.0 / gamma def stretch(self, stretch="crude", **kwargs): """Apply stretching to the current image. The value of *stretch* sets the type of stretching applied. The values "histogram", "linear", "crude" (or "crude-stretch") perform respectively histogram equalization, contrast stretching (with 5% cutoff on both sides), and contrast stretching without cutoff. The value "logarithmic" or "log" will do a logarithmic enhancement towards white. If a tuple or a list of two values is given as input, then a contrast stretching is performed with the values as cutoff. These values should be normalized in the range [0.0,1.0]. """ logger.debug("Applying stretch %s with parameters %s", stretch, str(kwargs)) # FIXME: do not apply stretch to alpha channel if isinstance(stretch, (tuple, list)): if len(stretch) == 2: self.stretch_linear(cutoffs=stretch) else: raise ValueError( "Stretch tuple must have exactly two elements") elif stretch == "linear": self.stretch_linear(**kwargs) elif stretch == "histogram": self.stretch_hist_equalize(**kwargs) elif stretch in ["crude", "crude-stretch"]: self.crude_stretch(**kwargs) elif stretch in ["log", "logarithmic"]: self.stretch_logarithmic(**kwargs) elif stretch == "no": return elif isinstance(stretch, str): raise ValueError("Stretching method %s not recognized." % stretch) else: raise TypeError("Stretch parameter must be a string or a tuple.") def stretch_linear(self, cutoffs=(0.005, 0.005)): """Stretch linearly the contrast of the current image. Use *cutoffs* for left and right trimming. If the cutoffs are just a tuple or list of two scalars, all the channels except the alpha channel will be stretched with the cutoffs. If the cutoffs are a sequence of tuples/lists of two scalars then: - if there are the same number of tuples/lists as channels, each channel will be stretched with the respective cutoff. - if there is one less tuple/list as channels, the same applies, except for the alpha channel which will not be stretched. """ logger.debug("Perform a linear contrast stretch.") left, right = self._get_left_and_right_quantiles_for_linear_stretch(cutoffs) self.crude_stretch(left, right) def _get_left_and_right_quantiles_for_linear_stretch(self, cutoffs): logger.debug("Calculate the histogram quantiles: ") logger.debug("Left and right quantiles: " + str(cutoffs[0]) + " " + str(cutoffs[1])) data = self.data nb_bands = len(data.coords["bands"]) dont_stretch_alpha = ('A' in self.data.coords['bands'].values and (np.isscalar(cutoffs[0]) or len(cutoffs) == nb_bands - 1)) if np.isscalar(cutoffs[0]): cutoffs = [cutoffs] * nb_bands if dont_stretch_alpha: data = self.data.sel(bands=self.data.coords['bands'].values[:-1]) left_data, right_data = self._get_left_and_right_quantiles_without_alpha(data, cutoffs) if dont_stretch_alpha: left_data = left_data + [da.zeros_like(left_data[0])] right_data = right_data + [da.ones_like(right_data[0])] left = xr.DataArray(da.stack(left_data), dims=('bands',), coords={'bands': self.data['bands']}) right = xr.DataArray(da.stack(right_data), dims=('bands',), coords={'bands': self.data['bands']}) return left, right @staticmethod def _get_left_and_right_quantiles_without_alpha( data_arr: xr.DataArray, cutoffs: Sequence[Sequence[float]], # two-element sequences [left_cutoff, right_cutoff] ) -> tuple[list[da.Array], list[da.Array]]: left = [] right = [] for i in range(data_arr.sizes["bands"]): left_i, right_i = data_arr.isel(bands=i).quantile([cutoffs[i][0], 1-cutoffs[i][1]], dim=("y", "x")) left.append(left_i.data) right.append(right_i.data) return left, right def crude_stretch(self, min_stretch=None, max_stretch=None): """Perform simple linear stretching. This is done without any cutoff on the current image and normalizes to the [0,1] range. """ min_stretch = self._check_stretch_value(min_stretch, kind='min') max_stretch = self._check_stretch_value(max_stretch, kind='max') scale_factor = self._get_scale_factor(min_stretch, max_stretch) attrs = self.data.attrs offset = -min_stretch * scale_factor try: offset = offset.astype(scale_factor.dtype) except AttributeError: offset = scale_factor.dtype.type(offset) self.data = np.multiply(self.data, scale_factor, dtype=scale_factor.dtype) + offset self.data.attrs = attrs self.data.attrs.setdefault('enhancement_history', []).append({'scale': scale_factor, 'offset': offset}) def _check_stretch_value(self, val, kind='min'): if val is None: non_band_dims = tuple(x for x in self.data.dims if x != 'bands') val = getattr(self.data, kind)(dim=non_band_dims) if isinstance(val, (list, tuple)): val = self.xrify_tuples(val) dtype = self.data.dtype if dtype in (np.uint8, np.int8, np.uint16, np.int16): dtype = np.dtype(np.float32) elif np.issubdtype(dtype, np.integer) or isinstance(dtype, int): dtype = np.dtype(np.float64) try: val = val.astype(dtype) except AttributeError: val = dtype.type(val) return val def _get_scale_factor(self, min_stretch, max_stretch): delta = (max_stretch - min_stretch) dtype = self._infer_scale_factor_dtype() if isinstance(delta, xr.DataArray): # fillna if delta is NaN scale_factor = (1.0 / delta).fillna(0).astype(dtype) else: scale_factor = np.array(1.0 / delta, dtype=dtype) return scale_factor def _infer_scale_factor_dtype(self): if np.issubdtype(self.data.dtype, np.integer): return np.float32 return self.data.dtype def stretch_hist_equalize(self, approximate=False): """Stretch the current image's colors through histogram equalization. Args: approximate (bool): Deprecated. """ logger.info("Perform a histogram equalized contrast stretch.") if approximate: warnings.warn("The 'approximate' keyword is deprecated.", stacklevel=2) nwidth = 2048. cdf = np.arange(0., 1., 1. / nwidth) def _band_hist(band_data: da.Array) -> da.Array: one_chunk_data = band_data.rechunk((-1,) * band_data.ndim) # FUTURE: 2025-06-24 - The next release of dask should fix the need for the `axis` keyword argument here # See https://github.com/dask/dask/pull/11988 # Without the single chunk of data above, `axis` is needed, but we use the single chunk # during the call to `interp` so we do it here instead of letting dask do it for us bins = da.nanpercentile(one_chunk_data, cdf * 100.0, axis=tuple(range(band_data.ndim))) res = da.map_blocks( np.interp, one_chunk_data, bins, cdf, chunks=one_chunk_data.chunks, meta=np.array((), dtype=one_chunk_data.dtype), dtype=one_chunk_data.dtype, ) return res.rechunk(band_data.chunks) band_results = [] for band in self.data['bands'].values: if band == 'A': continue band_data = self.data.sel(bands=band) res = _band_hist(band_data.data) band_results.append(res) if 'A' in self.data.coords['bands'].values: band_results.append(self.data.sel(bands='A')) self.data.data = da.stack(band_results, axis=self.data.dims.index('bands')) self.data.attrs.setdefault('enhancement_history', []).append({'hist_equalize': True}) def stretch_logarithmic(self, factor=100., base="e", min_stretch=None, max_stretch=None): """Move data into range [1:factor] through normalized logarithm. Args: factor (float): Maximum of the range data will be scaled to before applying the log function. Image data will be scaled to a 1 to ``factor`` range. base (str): Type of log to use. Defaults to natural log ("e"), but can also be "10" for base 10 log or "2" for base 2 log. min_stretch (float or list): Minimum input value to scale from. Data will be clipped to this value before being scaled to the 1:factor range. By default (None), the limits are computed on the fly but with a performance penalty. May also be a list for multi-band images. max_stretch (float or list): Maximum input value to scale from. Data will be clipped to this value before being scaled to the 1:factor range. By default (None), the limits are computed on the fly but with a performance penalty. May also be a list for multi-band images. """ logger.debug("Perform a logarithmic contrast stretch.") crange = (0., 1.0) log_func = np.log if base == "e" else getattr(np, "log" + base) min_stretch, max_stretch = self._convert_log_minmax_stretch(min_stretch, max_stretch) b__ = float(crange[1] - crange[0]) / self.data.dtype.type(log_func(factor)) c__ = float(crange[0]) def _band_log(arr, min_input, max_input): slope = (factor - 1.) / (max_input - min_input) arr = np.clip(arr, min_input, max_input) arr = 1. + (arr - min_input) * slope arr = c__ + b__ * log_func(arr) return arr band_results = [] for band_idx, band in enumerate(self.data['bands'].values): if band == 'A': continue band_data = self.data.sel(bands=band) res = _band_log(band_data.data, min_stretch[band_idx], max_stretch[band_idx]) band_results.append(res) if 'A' in self.data.coords['bands'].values: band_results.append(self.data.sel(bands='A')) self.data.data = da.stack(band_results, axis=self.data.dims.index('bands')) self.data.attrs.setdefault('enhancement_history', []).append({'log_factor': factor}) def _convert_log_minmax_stretch(self, min_stretch, max_stretch): non_band_dims = tuple(x for x in self.data.dims if x != 'bands') if min_stretch is None: min_stretch = [m.data for m in self.data.min(dim=non_band_dims)] if max_stretch is None: max_stretch = [m.data for m in self.data.max(dim=non_band_dims)] if not isinstance(min_stretch, (list, tuple)): min_stretch = [min_stretch] * self.data.sizes.get("bands", 1) if not isinstance(max_stretch, (list, tuple)): max_stretch = [max_stretch] * self.data.sizes.get("bands", 1) return min_stretch, max_stretch def stretch_weber_fechner(self, k, s0): """Stretch according to the Weber-Fechner law. p = k.ln(S/S0) p is perception, S is the stimulus, S0 is the stimulus threshold (the highest unperceived stimulus), and k is the factor. """ attrs = self.data.attrs clipped_stimuli = np.clip(self.data, s0, None) self.data = k * np.log(clipped_stimuli / s0) self.data.attrs = attrs self.data.attrs.setdefault('enhancement_history', []).append({'weber_fechner': (k, s0)}) def invert(self, invert=True): """Inverts all the channels of a image according to *invert*. If invert is a tuple or a list, elementwise invertion is performed, otherwise all channels are inverted if *invert* is true (default). Note: 'Inverting' means that black becomes white, and vice-versa, not that the values are negated ! """ logger.debug("Applying invert with parameters %s", str(invert)) if isinstance(invert, (tuple, list)): invert = self.xrify_tuples(invert) offset = invert.astype(self.data.dtype) scale = (-1) ** offset elif invert: offset = 1 scale = -1 attrs = self.data.attrs self.data = self.data * scale + offset self.data.attrs = attrs self.data.attrs.setdefault('enhancement_history', []).append({'scale': scale, 'offset': offset}) def stack(self, img): """Stack the provided image on top of the current image.""" # TODO: Conversions between different modes with notification # to the user, i.e. proper logging if self.mode != img.mode: raise NotImplementedError("Cannot stack images of different modes.") self.data = self.data.where(img.data.isnull(), img.data) def merge(self, img): """Use the provided image as background for the current *img* image. That is if the current image has missing data. """ raise NotImplementedError("This method has not be implemented for " "xarray support.") if self.is_empty(): raise ValueError("Cannot merge an empty image.") if self.mode != img.mode: raise ValueError("Cannot merge image of different modes.") selfmask = self.channels[0].mask for chn in self.channels[1:]: selfmask = np.ma.mask_or(selfmask, chn.mask) for i in range(len(self.channels)): self.channels[i] = np.ma.where(selfmask, img.channels[i], self.channels[i]) self.channels[i].mask = np.logical_and(selfmask, img.channels[i].mask) def colorize(self, colormap): """Colorize the current image using ``colormap``. Convert a greyscale image (mode "L" or "LA") to a color image (mode "RGB" or "RGBA") by applying a colormap. If floating point data being colorized contains NaNs then the result will also contain NaNs instead of a color from the colormap. Integer data that includes a ``.attrs['_FillValue']`` will be converted to a floating point array and values equal to ``_FillValue`` replaced with NaN before being colorized. To create a color image in mode "P" or "PA", use :meth:`~XRImage.palettize`. Args: colormap (:class:`~trollimage.colormap.Colormap`): Colormap to be applied to the image. .. note:: Works only on "L" or "LA" images. """ if self.mode not in ("L", "LA"): raise ValueError("Image should be grayscale to colorize") colormap = self._adjust_colormap_dtype(colormap) l_data = self._get_masked_floating_luminance_data() alpha = self.data.sel(bands=['A']) if self.mode == "LA" else None new_data = colormap.colorize(l_data.data) if colormap.colors.shape[1] == 4: mode = "RGBA" elif alpha is not None: new_data = da.concatenate([new_data, alpha.data], axis=0) mode = "RGBA" else: mode = "RGB" # copy the coordinates so we don't affect the original coords = dict(self.data.coords) coords['bands'] = list(mode) attrs = self.data.attrs dims = self.data.dims self.data = xr.DataArray(new_data, coords=coords, attrs=attrs, dims=dims) scale_factor, offset = self._get_colormap_scale_offset(colormap) self.data.attrs.setdefault('enhancement_history', []).append({ 'scale': scale_factor, 'offset': offset, 'colormap': colormap, }) def _adjust_colormap_dtype(self, colormap): if np.issubdtype(self.data.dtype, np.floating) and colormap.colors.dtype != self.data.dtype: colormap.colors = colormap.colors.astype(self.data.dtype) colormap.values = colormap.values.astype(self.data.dtype) return colormap def _get_masked_floating_luminance_data(self): l_data = self.data.sel(bands='L') # mask any integer fields with _FillValue # assume NaN is used otherwise if self.mode == "L" and np.issubdtype(self.data.dtype, np.integer): fill_value = self._get_input_fill_value(self.data) if fill_value is not None: l_data = l_data.where(l_data != fill_value) return l_data def palettize(self, colormap): """Palettize the current image using ``colormap``. Convert a mode "L" (or "LA") grayscale image to a mode "P" (or "PA") palette image and store the palette in the ``palette`` attribute. To store this image in mode "P", call :meth:`~XRImage.save` with ``keep_palette=True``. To include color information in the output format (if supported), call :meth:`~XRImage.save` with ``keep_palette=True`` *and* ``cmap=colormap``. To (directly) get an image in mode "RGB" or "RGBA", use :meth:`~XRImage.colorize`. Invalid data (NaN) are sorted into the final bin and the ``_FillValue`` attributed for the resulting image is set to the corresponding value. Args: colormap (:class:`~trollimage.colormap.Colormap`): Colormap to be applied to the image. Notes: Works only on "L" or "LA" images. Similar to other enhancement methods (colorize, stretch, etc) this method adds an ``enhancement_history`` list to the metadata stored in the image ``DataArray``'s metadata (``.attrs``). In other methods, however, the metadata directly translates to the linear operations performed in that enhancement. The palettize operation converts data values to indices into a colormap. This result is based on the range of values defined in the Colormap (``cmap.values``). To be most useful, the enhancement history scale and offset values represent the range of the colormap as if scaling the data to a 0-1 range. This means that once the data is saved to a format as an RGB (the palette colors are applied) the scale and offset can be used to determine the original range of the data based on the min/max of the data type of the format (ex. uint8). For example: .. code-block:: python dtype_min = 0 dtype_max = 255 scale = ... # scale from geotiff offset = ... # offset from geotiff data_min = offset data_max = (dtype_max - dtype_min) * scale + offset If a geotiff is saved with ``keep_palette=True`` then the data saved to the geotiff are the palette indices and will not be scaled to the data type of the format. There will also be a standard geotiff color table in the geotiff to identify that these are indices rather than some other type of image data. This means in this case the scale and offset can be used to determine the original range of the data starting from a 0-1 range (``dtype_min`` is 0 and ``dtype_max`` is 1 in the code above). """ if self.mode not in ("L", "LA"): raise ValueError("Image should be grayscale to colorize") l_data = self.data.sel(bands=['L']) new_data, self.palette = colormap.palettize(l_data.data) if self.mode == "L": mode = "P" else: mode = "PA" new_data = da.concatenate([new_data, self.data.sel(bands=['A'])], axis=0) old_dtype = self.data.dtype self.data.data = new_data self.data.coords['bands'] = list(mode) self._set_new_fill_value_after_palettize(colormap, old_dtype) # See docstring notes above for how scale/offset should be used scale_factor, offset = self._get_colormap_scale_offset(colormap) self.data.attrs.setdefault('enhancement_history', []).append({ 'scale': scale_factor, 'offset': offset, 'colormap': colormap, }) @staticmethod def _get_colormap_scale_offset(colormap): cmap_min = colormap.values[0] cmap_max = colormap.values[-1] scale_factor = 1.0 / (cmap_max - cmap_min) offset = -cmap_min * scale_factor return scale_factor, offset def _set_new_fill_value_after_palettize(self, colormap, old_dtype): """Set new fill value after palettizing.""" # OK: float without fill value or fill value nan # OK: int without fill value or fill value to max value if ((np.issubdtype(old_dtype, np.inexact) and np.isnan(self.data.attrs.get("_FillValue", np.nan))) or (np.issubdtype(old_dtype, np.integer) and self.data.attrs.get("_FillValue", np.iinfo(old_dtype).max) == np.iinfo(old_dtype).max)): self.data.attrs["_FillValue"] = colormap.values.shape[0]-1 # not OK: float or int with different fill value elif "_FillValue" in self.data.attrs: warnings.warn( f"Palettizing {old_dtype.name:s} data with the _FillValue attribute set to " f"{self.data.attrs['_FillValue']!s}, " "but palettize is not generally fill value aware (masked data " "will be correctly palettized only for float with NaN or for " "ints with fill value set to dtype max.", UserWarning, stacklevel=3) # else: non-numeric data, probably doesn't work at all and will fail # elsewhere anyway def blend(self, src): r"""Alpha blend *src* on top of the current image. Perform `alpha blending`_ of *src* on top of the current image. Alpha blending is defined as: .. math:: \begin{cases} \mathrm{out}_A = \mathrm{src}_A + \mathrm{dst}_A (1 - \mathrm{src}_A) \\ \mathrm{out}_{RGB} = \bigl(\mathrm{src}_{RGB}\mathrm{src}_A + \mathrm{dst}_{RGB} \mathrm{dst}_A \left(1 - \mathrm{src}_A \right) \bigr) \div \mathrm{out}_A \\ \mathrm{out}_A = 0 \Rightarrow \mathrm{out}_{RGB} = 0 \end{cases} Both images must have mode ``"RGBA"``. Args: src (:class:`XRImage` with mode ``"RGBA"``) Image to be blended on top of current image. .. _alpha blending: https://en.wikipedia.org/w/index.php?title=Alpha_compositing&oldid=891033105#Alpha_blending Returns XRImage with mode "RGBA", blended as described above """ # NB: docstring maths copy-pasta from enwiki if self.mode != "RGBA": raise ValueError( "Expected self.mode='RGBA', got {md!s}".format( md=self.mode)) if not isinstance(src, XRImage): raise TypeError("Expected XRImage, got {tp!s}".format( tp=type(src))) if src.mode != "RGBA": raise ValueError("Expected src.mode='RGBA', got {sm!s}".format( sm=src.mode)) srca = src.data.sel(bands="A") dsta = self.data.sel(bands="A") outa = srca + dsta * (1-srca) bi = {"bands": ["R", "G", "B"]} rgb = ((src.data.loc[bi] * srca + self.data.loc[bi] * dsta * (1-srca)) / outa).where(outa != 0, 0) return self.__class__( xr.concat( [rgb, outa.expand_dims("bands")], dim="bands")) def show(self): """Display the image on screen.""" self.pil_image().show() def _repr_png_(self): import io b = io.BytesIO() self.pil_image().save(b, format='png') return b.getvalue() def _delayed_apply_pil( pil_ready_array: np.ndarray, mode: str, fun: Callable, fun_args: tuple | None, fun_kwargs: dict | None, dtype: np.dtype, image_metadata: dict | None = None, output_mode: str | None = None, ) -> np.ndarray: if fun_args is None: fun_args = tuple() if fun_kwargs is None: fun_kwargs = dict() if image_metadata is None: image_metadata = dict() pil_image = PILImage.fromarray(pil_ready_array, mode=mode) new_img = fun(pil_image, image_metadata, *fun_args, **fun_kwargs) if output_mode is not None: new_img = new_img.convert(output_mode) return np.array(new_img) / dtype.type(255.0) def _is_unity_or_none(gamma): if gamma is None or gamma == 1.0: return True if not hasattr(gamma, "__iter__"): return False return all(g == 1.0 for g in gamma) or all(g is None for g in gamma) trollimage-1.28.0/versioneer.py000066400000000000000000002432271514066130000165020ustar00rootroot00000000000000 # Version: 0.28 """The Versioneer - like a rocketeer, but for versions. The Versioneer ============== * like a rocketeer, but for versions! * https://github.com/python-versioneer/python-versioneer * Brian Warner * License: Public Domain (Unlicense) * Compatible with: Python 3.7, 3.8, 3.9, 3.10 and pypy3 * [![Latest Version][pypi-image]][pypi-url] * [![Build Status][travis-image]][travis-url] This is a tool for managing a recorded version number in setuptools-based python projects. The goal is to remove the tedious and error-prone "update the embedded version string" step from your release process. Making a new release should be as easy as recording a new tag in your version-control system, and maybe making new tarballs. ## Quick Install Versioneer provides two installation modes. The "classic" vendored mode installs a copy of versioneer into your repository. The experimental build-time dependency mode is intended to allow you to skip this step and simplify the process of upgrading. ### Vendored mode * `pip install versioneer` to somewhere in your $PATH * A [conda-forge recipe](https://github.com/conda-forge/versioneer-feedstock) is available, so you can also use `conda install -c conda-forge versioneer` * add a `[tool.versioneer]` section to your `pyproject.toml` or a `[versioneer]` section to your `setup.cfg` (see [Install](INSTALL.md)) * Note that you will need to add `tomli; python_version < "3.11"` to your build-time dependencies if you use `pyproject.toml` * run `versioneer install --vendor` in your source tree, commit the results * verify version information with `python setup.py version` ### Build-time dependency mode * `pip install versioneer` to somewhere in your $PATH * A [conda-forge recipe](https://github.com/conda-forge/versioneer-feedstock) is available, so you can also use `conda install -c conda-forge versioneer` * add a `[tool.versioneer]` section to your `pyproject.toml` or a `[versioneer]` section to your `setup.cfg` (see [Install](INSTALL.md)) * add `versioneer` (with `[toml]` extra, if configuring in `pyproject.toml`) to the `requires` key of the `build-system` table in `pyproject.toml`: ```toml [build-system] requires = ["setuptools", "versioneer[toml]"] build-backend = "setuptools.build_meta" ``` * run `versioneer install --no-vendor` in your source tree, commit the results * verify version information with `python setup.py version` ## Version Identifiers Source trees come from a variety of places: * a version-control system checkout (mostly used by developers) * a nightly tarball, produced by build automation * a snapshot tarball, produced by a web-based VCS browser, like github's "tarball from tag" feature * a release tarball, produced by "setup.py sdist", distributed through PyPI Within each source tree, the version identifier (either a string or a number, this tool is format-agnostic) can come from a variety of places: * ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows about recent "tags" and an absolute revision-id * the name of the directory into which the tarball was unpacked * an expanded VCS keyword ($Id$, etc) * a `_version.py` created by some earlier build step For released software, the version identifier is closely related to a VCS tag. Some projects use tag names that include more than just the version string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool needs to strip the tag prefix to extract the version identifier. For unreleased software (between tags), the version identifier should provide enough information to help developers recreate the same tree, while also giving them an idea of roughly how old the tree is (after version 1.2, before version 1.3). Many VCS systems can report a description that captures this, for example `git describe --tags --dirty --always` reports things like "0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the 0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has uncommitted changes). The version identifier is used for multiple purposes: * to allow the module to self-identify its version: `myproject.__version__` * to choose a name and prefix for a 'setup.py sdist' tarball ## Theory of Operation Versioneer works by adding a special `_version.py` file into your source tree, where your `__init__.py` can import it. This `_version.py` knows how to dynamically ask the VCS tool for version information at import time. `_version.py` also contains `$Revision$` markers, and the installation process marks `_version.py` to have this marker rewritten with a tag name during the `git archive` command. As a result, generated tarballs will contain enough information to get the proper version. To allow `setup.py` to compute a version too, a `versioneer.py` is added to the top level of your source tree, next to `setup.py` and the `setup.cfg` that configures it. This overrides several distutils/setuptools commands to compute the version when invoked, and changes `setup.py build` and `setup.py sdist` to replace `_version.py` with a small static file that contains just the generated version data. ## Installation See [INSTALL.md](./INSTALL.md) for detailed installation instructions. ## Version-String Flavors Code which uses Versioneer can learn about its version string at runtime by importing `_version` from your main `__init__.py` file and running the `get_versions()` function. From the "outside" (e.g. in `setup.py`), you can import the top-level `versioneer.py` and run `get_versions()`. Both functions return a dictionary with different flavors of version information: * `['version']`: A condensed version string, rendered using the selected style. This is the most commonly used value for the project's version string. The default "pep440" style yields strings like `0.11`, `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section below for alternative styles. * `['full-revisionid']`: detailed revision identifier. For Git, this is the full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac". * `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the commit date in ISO 8601 format. This will be None if the date is not available. * `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that this is only accurate if run in a VCS checkout, otherwise it is likely to be False or None * `['error']`: if the version string could not be computed, this will be set to a string describing the problem, otherwise it will be None. It may be useful to throw an exception in setup.py if this is set, to avoid e.g. creating tarballs with a version string of "unknown". Some variants are more useful than others. Including `full-revisionid` in a bug report should allow developers to reconstruct the exact code being tested (or indicate the presence of local changes that should be shared with the developers). `version` is suitable for display in an "about" box or a CLI `--version` output: it can be easily compared against release notes and lists of bugs fixed in various releases. The installer adds the following text to your `__init__.py` to place a basic version in `YOURPROJECT.__version__`: from ._version import get_versions __version__ = get_versions()['version'] del get_versions ## Styles The setup.cfg `style=` configuration controls how the VCS information is rendered into a version string. The default style, "pep440", produces a PEP440-compliant string, equal to the un-prefixed tag name for actual releases, and containing an additional "local version" section with more detail for in-between builds. For Git, this is TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags --dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and that this commit is two revisions ("+2") beyond the "0.11" tag. For released software (exactly equal to a known tag), the identifier will only contain the stripped tag, e.g. "0.11". Other styles are available. See [details.md](details.md) in the Versioneer source tree for descriptions. ## Debugging Versioneer tries to avoid fatal errors: if something goes wrong, it will tend to return a version of "0+unknown". To investigate the problem, run `setup.py version`, which will run the version-lookup code in a verbose mode, and will display the full contents of `get_versions()` (including the `error` string, which may help identify what went wrong). ## Known Limitations Some situations are known to cause problems for Versioneer. This details the most significant ones. More can be found on Github [issues page](https://github.com/python-versioneer/python-versioneer/issues). ### Subprojects Versioneer has limited support for source trees in which `setup.py` is not in the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are two common reasons why `setup.py` might not be in the root: * Source trees which contain multiple subprojects, such as [Buildbot](https://github.com/buildbot/buildbot), which contains both "master" and "slave" subprojects, each with their own `setup.py`, `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI distributions (and upload multiple independently-installable tarballs). * Source trees whose main purpose is to contain a C library, but which also provide bindings to Python (and perhaps other languages) in subdirectories. Versioneer will look for `.git` in parent directories, and most operations should get the right version string. However `pip` and `setuptools` have bugs and implementation details which frequently cause `pip install .` from a subproject directory to fail to find a correct version string (so it usually defaults to `0+unknown`). `pip install --editable .` should work correctly. `setup.py install` might work too. Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in some later version. [Bug #38](https://github.com/python-versioneer/python-versioneer/issues/38) is tracking this issue. The discussion in [PR #61](https://github.com/python-versioneer/python-versioneer/pull/61) describes the issue from the Versioneer side in more detail. [pip PR#3176](https://github.com/pypa/pip/pull/3176) and [pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve pip to let Versioneer work correctly. Versioneer-0.16 and earlier only looked for a `.git` directory next to the `setup.cfg`, so subprojects were completely unsupported with those releases. ### Editable installs with setuptools <= 18.5 `setup.py develop` and `pip install --editable .` allow you to install a project into a virtualenv once, then continue editing the source code (and test) without re-installing after every change. "Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a convenient way to specify executable scripts that should be installed along with the python package. These both work as expected when using modern setuptools. When using setuptools-18.5 or earlier, however, certain operations will cause `pkg_resources.DistributionNotFound` errors when running the entrypoint script, which must be resolved by re-installing the package. This happens when the install happens with one version, then the egg_info data is regenerated while a different version is checked out. Many setup.py commands cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into a different virtualenv), so this can be surprising. [Bug #83](https://github.com/python-versioneer/python-versioneer/issues/83) describes this one, but upgrading to a newer version of setuptools should probably resolve it. ## Updating Versioneer To upgrade your project to a new release of Versioneer, do the following: * install the new Versioneer (`pip install -U versioneer` or equivalent) * edit `setup.cfg` and `pyproject.toml`, if necessary, to include any new configuration settings indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details. * re-run `versioneer install --[no-]vendor` in your source tree, to replace `SRC/_version.py` * commit any changed files ## Future Directions This tool is designed to make it easily extended to other version-control systems: all VCS-specific components are in separate directories like src/git/ . The top-level `versioneer.py` script is assembled from these components by running make-versioneer.py . In the future, make-versioneer.py will take a VCS name as an argument, and will construct a version of `versioneer.py` that is specific to the given VCS. It might also take the configuration arguments that are currently provided manually during installation by editing setup.py . Alternatively, it might go the other direction and include code from all supported VCS systems, reducing the number of intermediate scripts. ## Similar projects * [setuptools_scm](https://github.com/pypa/setuptools_scm/) - a non-vendored build-time dependency * [minver](https://github.com/jbweston/miniver) - a lightweight reimplementation of versioneer * [versioningit](https://github.com/jwodder/versioningit) - a PEP 518-based setuptools plugin ## License To make Versioneer easier to embed, all its code is dedicated to the public domain. The `_version.py` that it creates is also in the public domain. Specifically, both are released under the "Unlicense", as described in https://unlicense.org/. [pypi-image]: https://img.shields.io/pypi/v/versioneer.svg [pypi-url]: https://pypi.python.org/pypi/versioneer/ [travis-image]: https://img.shields.io/travis/com/python-versioneer/python-versioneer.svg [travis-url]: https://travis-ci.com/github/python-versioneer/python-versioneer """ # pylint:disable=invalid-name,import-outside-toplevel,missing-function-docstring # pylint:disable=missing-class-docstring,too-many-branches,too-many-statements # pylint:disable=raise-missing-from,too-many-lines,too-many-locals,import-error # pylint:disable=too-few-public-methods,redefined-outer-name,consider-using-with # pylint:disable=attribute-defined-outside-init,too-many-arguments import configparser import errno import json import os import re import subprocess import sys from pathlib import Path from typing import Callable, Dict import functools have_tomllib = True if sys.version_info >= (3, 11): import tomllib else: try: import tomli as tomllib except ImportError: have_tomllib = False class VersioneerConfig: """Container for Versioneer configuration parameters.""" def get_root(): """Get the project root directory. We require that all commands are run from the project root, i.e. the directory that contains setup.py, setup.cfg, and versioneer.py . """ root = os.path.realpath(os.path.abspath(os.getcwd())) setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): # allow 'python path/to/setup.py COMMAND' root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): err = ("Versioneer was unable to run the project root directory. " "Versioneer requires setup.py to be executed from " "its immediate directory (like 'python setup.py COMMAND'), " "or in a way that lets it use sys.argv[0] to find the root " "(like 'python path/to/setup.py COMMAND').") raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools # tree) execute all dependencies in a single python process, so # "versioneer" may be imported multiple times, and python's shared # module-import table will cache the first one. So we can't use # os.path.dirname(__file__), as that will find whichever # versioneer.py was first imported, even in later projects. my_path = os.path.realpath(os.path.abspath(__file__)) me_dir = os.path.normcase(os.path.splitext(my_path)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir and "VERSIONEER_PEP518" not in globals(): print("Warning: build in %s is using versioneer.py from %s" % (os.path.dirname(my_path), versioneer_py)) except NameError: pass return root def get_config_from_root(root): """Read the project setup.cfg file to determine Versioneer config.""" # This might raise OSError (if setup.cfg is missing), or # configparser.NoSectionError (if it lacks a [versioneer] section), or # configparser.NoOptionError (if it lacks "VCS="). See the docstring at # the top of versioneer.py for instructions on writing your setup.cfg . root = Path(root) pyproject_toml = root / "pyproject.toml" setup_cfg = root / "setup.cfg" section = None if pyproject_toml.exists() and have_tomllib: try: with open(pyproject_toml, 'rb') as fobj: pp = tomllib.load(fobj) section = pp['tool']['versioneer'] except (tomllib.TOMLDecodeError, KeyError): pass if not section: parser = configparser.ConfigParser() with open(setup_cfg) as cfg_file: parser.read_file(cfg_file) parser.get("versioneer", "VCS") # raise error if missing section = parser["versioneer"] cfg = VersioneerConfig() cfg.VCS = section['VCS'] cfg.style = section.get("style", "") cfg.versionfile_source = section.get("versionfile_source") cfg.versionfile_build = section.get("versionfile_build") cfg.tag_prefix = section.get("tag_prefix") if cfg.tag_prefix in ("''", '""', None): cfg.tag_prefix = "" cfg.parentdir_prefix = section.get("parentdir_prefix") cfg.verbose = section.get("verbose") return cfg class NotThisMethod(Exception): """Exception raised if a method is not valid for the current scenario.""" # these dictionaries contain VCS-specific tools LONG_VERSION_PY: Dict[str, str] = {} HANDLERS: Dict[str, Dict[str, Callable]] = {} def register_vcs_handler(vcs, method): # decorator """Create decorator to mark a method as the handler of a VCS.""" def decorate(f): """Store f in HANDLERS[vcs][method].""" HANDLERS.setdefault(vcs, {})[method] = f return f return decorate def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) process = None popen_kwargs = {} if sys.platform == "win32": # This hides the console window if pythonw.exe is used startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW popen_kwargs["startupinfo"] = startupinfo for command in commands: try: dispcmd = str([command] + args) # remember shell=False, so use git.cmd on windows, not just git process = subprocess.Popen([command] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None), **popen_kwargs) break except OSError: e = sys.exc_info()[1] if e.errno == errno.ENOENT: continue if verbose: print("unable to run %s" % dispcmd) print(e) return None, None else: if verbose: print("unable to find command, tried %s" % (commands,)) return None, None stdout = process.communicate()[0].strip().decode() if process.returncode != 0: if verbose: print("unable to run %s (error)" % dispcmd) print("stdout was %s" % stdout) return None, process.returncode return stdout, process.returncode LONG_VERSION_PY['git'] = r''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build # directories (produced by setup.py build) will contain a much shorter file # that just contains the computed version number. # This file is released into the public domain. # Generated by versioneer-0.28 # https://github.com/python-versioneer/python-versioneer """Git implementation of _version.py.""" import errno import os import re import subprocess import sys from typing import Callable, Dict import functools def get_keywords(): """Get the keywords needed to look up the version information.""" # these strings will be replaced by git during git-archive. # setup.py/versioneer.py will grep for the variable names, so they must # each be defined on a line of their own. _version.py will just call # get_keywords(). git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s" keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} return keywords class VersioneerConfig: """Container for Versioneer configuration parameters.""" def get_config(): """Create, populate and return the VersioneerConfig() object.""" # these strings are filled in when 'setup.py versioneer' creates # _version.py cfg = VersioneerConfig() cfg.VCS = "git" cfg.style = "%(STYLE)s" cfg.tag_prefix = "%(TAG_PREFIX)s" cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" cfg.verbose = False return cfg class NotThisMethod(Exception): """Exception raised if a method is not valid for the current scenario.""" LONG_VERSION_PY: Dict[str, str] = {} HANDLERS: Dict[str, Dict[str, Callable]] = {} def register_vcs_handler(vcs, method): # decorator """Create decorator to mark a method as the handler of a VCS.""" def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f return decorate def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) process = None popen_kwargs = {} if sys.platform == "win32": # This hides the console window if pythonw.exe is used startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW popen_kwargs["startupinfo"] = startupinfo for command in commands: try: dispcmd = str([command] + args) # remember shell=False, so use git.cmd on windows, not just git process = subprocess.Popen([command] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None), **popen_kwargs) break except OSError: e = sys.exc_info()[1] if e.errno == errno.ENOENT: continue if verbose: print("unable to run %%s" %% dispcmd) print(e) return None, None else: if verbose: print("unable to find command, tried %%s" %% (commands,)) return None, None stdout = process.communicate()[0].strip().decode() if process.returncode != 0: if verbose: print("unable to run %%s (error)" %% dispcmd) print("stdout was %%s" %% stdout) return None, process.returncode return stdout, process.returncode def versions_from_parentdir(parentdir_prefix, root, verbose): """Try to determine the version from the parent directory name. Source tarballs conventionally unpack into a directory that includes both the project name and a version string. We will also support searching up two directory levels for an appropriately named parent directory """ rootdirs = [] for _ in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): return {"version": dirname[len(parentdir_prefix):], "full-revisionid": None, "dirty": False, "error": None, "date": None} rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: print("Tried directories %%s but none started with prefix %%s" %% (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @register_vcs_handler("git", "get_keywords") def git_get_keywords(versionfile_abs): """Extract version information from the given file.""" # the code embedded in _version.py can just fetch the value of these # keywords. When used from setup.py, we don't want to import _version.py, # so we do it with a regexp instead. This function is not used from # _version.py. keywords = {} try: with open(versionfile_abs, "r") as fobj: for line in fobj: if line.strip().startswith("git_refnames ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["refnames"] = mo.group(1) if line.strip().startswith("git_full ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["full"] = mo.group(1) if line.strip().startswith("git_date ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["date"] = mo.group(1) except OSError: pass return keywords @register_vcs_handler("git", "keywords") def git_versions_from_keywords(keywords, tag_prefix, verbose): """Get version information from git keywords.""" if "refnames" not in keywords: raise NotThisMethod("Short version file found") date = keywords.get("date") if date is not None: # Use only the last line. Previous lines may contain GPG signature # information. date = date.splitlines()[-1] # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601 # -like" string, which we must then edit to make compliant), because # it's been around since git-1.5.3, and it's too difficult to # discover which version we're using, or to work around using an # older one. date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) refnames = keywords["refnames"].strip() if refnames.startswith("$Format"): if verbose: print("keywords are unexpanded, not using") raise NotThisMethod("unexpanded keywords, not a git-archive tarball") refs = {r.strip() for r in refnames.strip("()").split(",")} # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " tags = {r[len(TAG):] for r in refs if r.startswith(TAG)} if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %%d # expansion behaves like git log --decorate=short and strips out the # refs/heads/ and refs/tags/ prefixes that would let us distinguish # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". tags = {r for r in refs if re.search(r'\d', r)} if verbose: print("discarding '%%s', no digits" %% ",".join(refs - tags)) if verbose: print("likely tags: %%s" %% ",".join(sorted(tags))) for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): r = ref[len(tag_prefix):] # Filter out refs that exactly match prefix or that don't start # with a number once the prefix is stripped (mostly a concern # when prefix is '') if not re.match(r'\d', r): continue if verbose: print("picking %%s" %% r) return {"version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") return {"version": "0+unknown", "full-revisionid": keywords["full"].strip(), "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): """Get version from 'git describe' in the root of the source tree. This only gets called if the git-archive 'subst' keywords were *not* expanded, and _version.py hasn't already been rewritten with a short version string, meaning we're inside a checked out source tree. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] # GIT_DIR can interfere with correct operation of Versioneer. # It may be intended to be passed to the Versioneer-versioned project, # but that should not change where we get our version from. env = os.environ.copy() env.pop("GIT_DIR", None) runner = functools.partial(runner, env=env) _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=not verbose) if rc != 0: if verbose: print("Directory %%s not under git control" %% root) raise NotThisMethod("'git rev-parse --git-dir' returned error") # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) describe_out, rc = runner(GITS, [ "describe", "--tags", "--dirty", "--always", "--long", "--match", f"{tag_prefix}[[:digit:]]*" ], cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") describe_out = describe_out.strip() full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) if full_out is None: raise NotThisMethod("'git rev-parse' failed") full_out = full_out.strip() pieces = {} pieces["long"] = full_out pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) # --abbrev-ref was added in git-1.6.3 if rc != 0 or branch_name is None: raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") branch_name = branch_name.strip() if branch_name == "HEAD": # If we aren't exactly on a branch, pick a branch which represents # the current commit. If all else fails, we are on a branchless # commit. branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) # --contains was added in git-1.5.4 if rc != 0 or branches is None: raise NotThisMethod("'git branch --contains' returned error") branches = branches.split("\n") # Remove the first line if we're running detached if "(" in branches[0]: branches.pop(0) # Strip off the leading "* " from the list of branches. branches = [branch[2:] for branch in branches] if "master" in branches: branch_name = "master" elif not branches: branch_name = None else: # Pick the first branch that is returned. Good or bad. branch_name = branches[0] pieces["branch"] = branch_name # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] # TAG might have hyphens. git_describe = describe_out # look for -dirty suffix dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparsable. Maybe git-describe is misbehaving? pieces["error"] = ("unable to parse git-describe output: '%%s'" %% describe_out) return pieces # tag full_tag = mo.group(1) if not full_tag.startswith(tag_prefix): if verbose: fmt = "tag '%%s' doesn't start with prefix '%%s'" print(fmt %% (full_tag, tag_prefix)) pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'" %% (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) # commit: short hex revision ID pieces["short"] = mo.group(3) else: # HEX: no tags pieces["closest-tag"] = None out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root) pieces["distance"] = len(out.split()) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() date = runner(GITS, ["show", "-s", "--format=%%ci", "HEAD"], cwd=root)[0].strip() # Use only the last line. Previous lines may contain GPG signature # information. date = date.splitlines()[-1] pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces def plus_or_dot(pieces): """Return a + if we don't already have one, else return a .""" if "+" in pieces.get("closest-tag", ""): return "." return "+" def render_pep440(pieces): """Build up version string, with post-release "local version identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty Exceptions: 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += plus_or_dot(pieces) rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_branch(pieces): """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . The ".dev0" means not master branch. Note that .dev0 sorts backwards (a feature branch will appear "older" than the master branch). Exceptions: 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: if pieces["branch"] != "master": rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0" if pieces["branch"] != "master": rendered += ".dev0" rendered += "+untagged.%%d.g%%s" %% (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def pep440_split_post(ver): """Split pep440 version string at the post-release segment. Returns the release segments before the post-release and the post-release version number (or -1 if no post-release segment is present). """ vc = str.split(ver, ".post") return vc[0], int(vc[1] or 0) if len(vc) == 2 else None def render_pep440_pre(pieces): """TAG[.postN.devDISTANCE] -- No -dirty. Exceptions: 1: no tags. 0.post0.devDISTANCE """ if pieces["closest-tag"]: if pieces["distance"]: # update the post release segment tag_version, post_version = pep440_split_post(pieces["closest-tag"]) rendered = tag_version if post_version is not None: rendered += ".post%%d.dev%%d" %% (post_version + 1, pieces["distance"]) else: rendered += ".post0.dev%%d" %% (pieces["distance"]) else: # no commits, use the tag as the version rendered = pieces["closest-tag"] else: # exception #1 rendered = "0.post0.dev%%d" %% pieces["distance"] return rendered def render_pep440_post(pieces): """TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that .dev0 sorts backwards (a dirty tree will appear "older" than the corresponding clean one), but you shouldn't be releasing software with -dirty anyways. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%%s" %% pieces["short"] else: # exception #1 rendered = "0.post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += "+g%%s" %% pieces["short"] return rendered def render_pep440_post_branch(pieces): """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . The ".dev0" means not master branch. Exceptions: 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%%d" %% pieces["distance"] if pieces["branch"] != "master": rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%%s" %% pieces["short"] if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0.post%%d" %% pieces["distance"] if pieces["branch"] != "master": rendered += ".dev0" rendered += "+g%%s" %% pieces["short"] if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_old(pieces): """TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" else: # exception #1 rendered = "0.post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" return rendered def render_git_describe(pieces): """TAG[-DISTANCE-gHEX][-dirty]. Like 'git describe --tags --dirty --always'. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render_git_describe_long(pieces): """TAG-DISTANCE-gHEX[-dirty]. Like 'git describe --tags --dirty --always -long'. The distance/hash is unconditional. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: return {"version": "unknown", "full-revisionid": pieces.get("long"), "dirty": None, "error": pieces["error"], "date": None} if not style or style == "default": style = "pep440" # the default if style == "pep440": rendered = render_pep440(pieces) elif style == "pep440-branch": rendered = render_pep440_branch(pieces) elif style == "pep440-pre": rendered = render_pep440_pre(pieces) elif style == "pep440-post": rendered = render_pep440_post(pieces) elif style == "pep440-post-branch": rendered = render_pep440_post_branch(pieces) elif style == "pep440-old": rendered = render_pep440_old(pieces) elif style == "git-describe": rendered = render_git_describe(pieces) elif style == "git-describe-long": rendered = render_git_describe_long(pieces) else: raise ValueError("unknown style '%%s'" %% style) return {"version": rendered, "full-revisionid": pieces["long"], "dirty": pieces["dirty"], "error": None, "date": pieces.get("date")} def get_versions(): """Get version information or return default if unable to do so.""" # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have # __file__, we can work backwards from there to the root. Some # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which # case we can only use expanded keywords. cfg = get_config() verbose = cfg.verbose try: return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) except NotThisMethod: pass try: root = os.path.realpath(__file__) # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. for _ in cfg.versionfile_source.split('/'): root = os.path.dirname(root) except NameError: return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to find root of source tree", "date": None} try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) return render(pieces, cfg.style) except NotThisMethod: pass try: if cfg.parentdir_prefix: return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) except NotThisMethod: pass return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to compute version", "date": None} ''' @register_vcs_handler("git", "get_keywords") def git_get_keywords(versionfile_abs): """Extract version information from the given file.""" # the code embedded in _version.py can just fetch the value of these # keywords. When used from setup.py, we don't want to import _version.py, # so we do it with a regexp instead. This function is not used from # _version.py. keywords = {} try: with open(versionfile_abs, "r") as fobj: for line in fobj: if line.strip().startswith("git_refnames ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["refnames"] = mo.group(1) if line.strip().startswith("git_full ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["full"] = mo.group(1) if line.strip().startswith("git_date ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["date"] = mo.group(1) except OSError: pass return keywords @register_vcs_handler("git", "keywords") def git_versions_from_keywords(keywords, tag_prefix, verbose): """Get version information from git keywords.""" if "refnames" not in keywords: raise NotThisMethod("Short version file found") date = keywords.get("date") if date is not None: # Use only the last line. Previous lines may contain GPG signature # information. date = date.splitlines()[-1] # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 # -like" string, which we must then edit to make compliant), because # it's been around since git-1.5.3, and it's too difficult to # discover which version we're using, or to work around using an # older one. date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) refnames = keywords["refnames"].strip() if refnames.startswith("$Format"): if verbose: print("keywords are unexpanded, not using") raise NotThisMethod("unexpanded keywords, not a git-archive tarball") refs = {r.strip() for r in refnames.strip("()").split(",")} # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " tags = {r[len(TAG):] for r in refs if r.startswith(TAG)} if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d # expansion behaves like git log --decorate=short and strips out the # refs/heads/ and refs/tags/ prefixes that would let us distinguish # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". tags = {r for r in refs if re.search(r'\d', r)} if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: print("likely tags: %s" % ",".join(sorted(tags))) for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): r = ref[len(tag_prefix):] # Filter out refs that exactly match prefix or that don't start # with a number once the prefix is stripped (mostly a concern # when prefix is '') if not re.match(r'\d', r): continue if verbose: print("picking %s" % r) return {"version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") return {"version": "0+unknown", "full-revisionid": keywords["full"].strip(), "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): """Get version from 'git describe' in the root of the source tree. This only gets called if the git-archive 'subst' keywords were *not* expanded, and _version.py hasn't already been rewritten with a short version string, meaning we're inside a checked out source tree. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] # GIT_DIR can interfere with correct operation of Versioneer. # It may be intended to be passed to the Versioneer-versioned project, # but that should not change where we get our version from. env = os.environ.copy() env.pop("GIT_DIR", None) runner = functools.partial(runner, env=env) _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=not verbose) if rc != 0: if verbose: print("Directory %s not under git control" % root) raise NotThisMethod("'git rev-parse --git-dir' returned error") # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) describe_out, rc = runner(GITS, [ "describe", "--tags", "--dirty", "--always", "--long", "--match", f"{tag_prefix}[[:digit:]]*" ], cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") describe_out = describe_out.strip() full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) if full_out is None: raise NotThisMethod("'git rev-parse' failed") full_out = full_out.strip() pieces = {} pieces["long"] = full_out pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) # --abbrev-ref was added in git-1.6.3 if rc != 0 or branch_name is None: raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") branch_name = branch_name.strip() if branch_name == "HEAD": # If we aren't exactly on a branch, pick a branch which represents # the current commit. If all else fails, we are on a branchless # commit. branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) # --contains was added in git-1.5.4 if rc != 0 or branches is None: raise NotThisMethod("'git branch --contains' returned error") branches = branches.split("\n") # Remove the first line if we're running detached if "(" in branches[0]: branches.pop(0) # Strip off the leading "* " from the list of branches. branches = [branch[2:] for branch in branches] if "master" in branches: branch_name = "master" elif not branches: branch_name = None else: # Pick the first branch that is returned. Good or bad. branch_name = branches[0] pieces["branch"] = branch_name # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] # TAG might have hyphens. git_describe = describe_out # look for -dirty suffix dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparsable. Maybe git-describe is misbehaving? pieces["error"] = ("unable to parse git-describe output: '%s'" % describe_out) return pieces # tag full_tag = mo.group(1) if not full_tag.startswith(tag_prefix): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" % (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) # commit: short hex revision ID pieces["short"] = mo.group(3) else: # HEX: no tags pieces["closest-tag"] = None out, rc = runner(GITS, ["rev-list", "HEAD", "--left-right"], cwd=root) pieces["distance"] = len(out.split()) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() date = runner(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() # Use only the last line. Previous lines may contain GPG signature # information. date = date.splitlines()[-1] pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces def do_vcs_install(versionfile_source, ipy): """Git-specific installation logic for Versioneer. For Git, this means creating/changing .gitattributes to mark _version.py for export-subst keyword substitution. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] files = [versionfile_source] if ipy: files.append(ipy) if "VERSIONEER_PEP518" not in globals(): try: my_path = __file__ if my_path.endswith((".pyc", ".pyo")): my_path = os.path.splitext(my_path)[0] + ".py" versioneer_file = os.path.relpath(my_path) except NameError: versioneer_file = "versioneer.py" files.append(versioneer_file) present = False try: with open(".gitattributes", "r") as fobj: for line in fobj: if line.strip().startswith(versionfile_source): if "export-subst" in line.strip().split()[1:]: present = True break except OSError: pass if not present: with open(".gitattributes", "a+") as fobj: fobj.write(f"{versionfile_source} export-subst\n") files.append(".gitattributes") run_command(GITS, ["add", "--"] + files) def versions_from_parentdir(parentdir_prefix, root, verbose): """Try to determine the version from the parent directory name. Source tarballs conventionally unpack into a directory that includes both the project name and a version string. We will also support searching up two directory levels for an appropriately named parent directory """ rootdirs = [] for _ in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): return {"version": dirname[len(parentdir_prefix):], "full-revisionid": None, "dirty": False, "error": None, "date": None} rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: print("Tried directories %s but none started with prefix %s" % (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") SHORT_VERSION_PY = """ # This file was generated by 'versioneer.py' (0.28) from # revision-control system data, or from the parent directory name of an # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. import json version_json = ''' %s ''' # END VERSION_JSON def get_versions(): return json.loads(version_json) """ def versions_from_file(filename): """Try to determine the version from _version.py if present.""" try: with open(filename) as f: contents = f.read() except OSError: raise NotThisMethod("unable to read _version.py") mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) contents = json.dumps(versions, sort_keys=True, indent=1, separators=(",", ": ")) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) print("set %s to '%s'" % (filename, versions["version"])) def plus_or_dot(pieces): """Return a + if we don't already have one, else return a .""" if "+" in pieces.get("closest-tag", ""): return "." return "+" def render_pep440(pieces): """Build up version string, with post-release "local version identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty Exceptions: 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += plus_or_dot(pieces) rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_branch(pieces): """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . The ".dev0" means not master branch. Note that .dev0 sorts backwards (a feature branch will appear "older" than the master branch). Exceptions: 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: if pieces["branch"] != "master": rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0" if pieces["branch"] != "master": rendered += ".dev0" rendered += "+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def pep440_split_post(ver): """Split pep440 version string at the post-release segment. Returns the release segments before the post-release and the post-release version number (or -1 if no post-release segment is present). """ vc = str.split(ver, ".post") return vc[0], int(vc[1] or 0) if len(vc) == 2 else None def render_pep440_pre(pieces): """TAG[.postN.devDISTANCE] -- No -dirty. Exceptions: 1: no tags. 0.post0.devDISTANCE """ if pieces["closest-tag"]: if pieces["distance"]: # update the post release segment tag_version, post_version = pep440_split_post(pieces["closest-tag"]) rendered = tag_version if post_version is not None: rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"]) else: rendered += ".post0.dev%d" % (pieces["distance"]) else: # no commits, use the tag as the version rendered = pieces["closest-tag"] else: # exception #1 rendered = "0.post0.dev%d" % pieces["distance"] return rendered def render_pep440_post(pieces): """TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that .dev0 sorts backwards (a dirty tree will appear "older" than the corresponding clean one), but you shouldn't be releasing software with -dirty anyways. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%s" % pieces["short"] else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += "+g%s" % pieces["short"] return rendered def render_pep440_post_branch(pieces): """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . The ".dev0" means not master branch. Exceptions: 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["branch"] != "master": rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%s" % pieces["short"] if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["branch"] != "master": rendered += ".dev0" rendered += "+g%s" % pieces["short"] if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_old(pieces): """TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" return rendered def render_git_describe(pieces): """TAG[-DISTANCE-gHEX][-dirty]. Like 'git describe --tags --dirty --always'. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render_git_describe_long(pieces): """TAG-DISTANCE-gHEX[-dirty]. Like 'git describe --tags --dirty --always -long'. The distance/hash is unconditional. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: return {"version": "unknown", "full-revisionid": pieces.get("long"), "dirty": None, "error": pieces["error"], "date": None} if not style or style == "default": style = "pep440" # the default if style == "pep440": rendered = render_pep440(pieces) elif style == "pep440-branch": rendered = render_pep440_branch(pieces) elif style == "pep440-pre": rendered = render_pep440_pre(pieces) elif style == "pep440-post": rendered = render_pep440_post(pieces) elif style == "pep440-post-branch": rendered = render_pep440_post_branch(pieces) elif style == "pep440-old": rendered = render_pep440_old(pieces) elif style == "git-describe": rendered = render_git_describe(pieces) elif style == "git-describe-long": rendered = render_git_describe_long(pieces) else: raise ValueError("unknown style '%s'" % style) return {"version": rendered, "full-revisionid": pieces["long"], "dirty": pieces["dirty"], "error": None, "date": pieces.get("date")} class VersioneerBadRootError(Exception): """The project root directory is unknown or missing key files.""" def get_versions(verbose=False): """Get the project version from whatever source is available. Returns dict with two keys: 'version' and 'full'. """ if "versioneer" in sys.modules: # see the discussion in cmdclass.py:get_cmdclass() del sys.modules["versioneer"] root = get_root() cfg = get_config_from_root(root) assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg" handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or cfg.verbose assert cfg.versionfile_source is not None, \ "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) # extract version from first of: _version.py, VCS command (e.g. 'git # describe'), parentdir. This is meant to work for developers using a # source checkout, for users of a tarball created by 'setup.py sdist', # and for users of a tarball/zipball created by 'git archive' or github's # download-from-tag feature or the equivalent in other VCSes. get_keywords_f = handlers.get("get_keywords") from_keywords_f = handlers.get("keywords") if get_keywords_f and from_keywords_f: try: keywords = get_keywords_f(versionfile_abs) ver = from_keywords_f(keywords, cfg.tag_prefix, verbose) if verbose: print("got version from expanded keyword %s" % ver) return ver except NotThisMethod: pass try: ver = versions_from_file(versionfile_abs) if verbose: print("got version from file %s %s" % (versionfile_abs, ver)) return ver except NotThisMethod: pass from_vcs_f = handlers.get("pieces_from_vcs") if from_vcs_f: try: pieces = from_vcs_f(cfg.tag_prefix, root, verbose) ver = render(pieces, cfg.style) if verbose: print("got version from VCS %s" % ver) return ver except NotThisMethod: pass try: if cfg.parentdir_prefix: ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose) if verbose: print("got version from parentdir %s" % ver) return ver except NotThisMethod: pass if verbose: print("unable to compute version") return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to compute version", "date": None} def get_version(): """Get the short version string for this project.""" return get_versions()["version"] def get_cmdclass(cmdclass=None): """Get the custom setuptools subclasses used by Versioneer. If the package uses a different cmdclass (e.g. one from numpy), it should be provide as an argument. """ if "versioneer" in sys.modules: del sys.modules["versioneer"] # this fixes the "python setup.py develop" case (also 'install' and # 'easy_install .'), in which subdependencies of the main project are # built (using setup.py bdist_egg) in the same python process. Assume # a main project A and a dependency B, which use different versions # of Versioneer. A's setup.py imports A's Versioneer, leaving it in # sys.modules by the time B's setup.py is executed, causing B to run # with the wrong versioneer. Setuptools wraps the sub-dep builds in a # sandbox that restores sys.modules to it's pre-build state, so the # parent is protected against the child's "import versioneer". By # removing ourselves from sys.modules here, before the child build # happens, we protect the child from the parent's versioneer too. # Also see https://github.com/python-versioneer/python-versioneer/issues/52 cmds = {} if cmdclass is None else cmdclass.copy() # we add "version" to setuptools from setuptools import Command class cmd_version(Command): description = "report generated version string" user_options = [] boolean_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): vers = get_versions(verbose=True) print("Version: %s" % vers["version"]) print(" full-revisionid: %s" % vers.get("full-revisionid")) print(" dirty: %s" % vers.get("dirty")) print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) cmds["version"] = cmd_version # we override "build_py" in setuptools # # most invocation pathways end up running build_py: # distutils/build -> build_py # distutils/install -> distutils/build ->.. # setuptools/bdist_wheel -> distutils/install ->.. # setuptools/bdist_egg -> distutils/install_lib -> build_py # setuptools/install -> bdist_egg ->.. # setuptools/develop -> ? # pip install: # copies source tree to a tempdir before running egg_info/etc # if .git isn't copied too, 'git describe' will fail # then does setup.py bdist_wheel, or sometimes setup.py install # setup.py egg_info -> ? # pip install -e . and setuptool/editable_wheel will invoke build_py # but the build_py command is not expected to copy any files. # we override different "build_py" commands for both environments if 'build_py' in cmds: _build_py = cmds['build_py'] else: from setuptools.command.build_py import build_py as _build_py class cmd_build_py(_build_py): def run(self): root = get_root() cfg = get_config_from_root(root) versions = get_versions() _build_py.run(self) if getattr(self, "editable_mode", False): # During editable installs `.py` and data files are # not copied to build_lib return # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) cmds["build_py"] = cmd_build_py if 'build_ext' in cmds: _build_ext = cmds['build_ext'] else: from setuptools.command.build_ext import build_ext as _build_ext class cmd_build_ext(_build_ext): def run(self): root = get_root() cfg = get_config_from_root(root) versions = get_versions() _build_ext.run(self) if self.inplace: # build_ext --inplace will only build extensions in # build/lib<..> dir with no _version.py to write to. # As in place builds will already have a _version.py # in the module dir, we do not need to write one. return # now locate _version.py in the new build/ directory and replace # it with an updated value if not cfg.versionfile_build: return target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) if not os.path.exists(target_versionfile): print(f"Warning: {target_versionfile} does not exist, skipping " "version update. This can happen if you are running build_ext " "without first running build_py.") return print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) cmds["build_ext"] = cmd_build_ext if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION # "product_version": versioneer.get_version(), # ... class cmd_build_exe(_build_exe): def run(self): root = get_root() cfg = get_config_from_root(root) versions = get_versions() target_versionfile = cfg.versionfile_source print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) _build_exe.run(self) os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] f.write(LONG % {"DOLLAR": "$", "STYLE": cfg.style, "TAG_PREFIX": cfg.tag_prefix, "PARENTDIR_PREFIX": cfg.parentdir_prefix, "VERSIONFILE_SOURCE": cfg.versionfile_source, }) cmds["build_exe"] = cmd_build_exe del cmds["build_py"] if 'py2exe' in sys.modules: # py2exe enabled? try: from py2exe.setuptools_buildexe import py2exe as _py2exe except ImportError: from py2exe.distutils_buildexe import py2exe as _py2exe class cmd_py2exe(_py2exe): def run(self): root = get_root() cfg = get_config_from_root(root) versions = get_versions() target_versionfile = cfg.versionfile_source print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) _py2exe.run(self) os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] f.write(LONG % {"DOLLAR": "$", "STYLE": cfg.style, "TAG_PREFIX": cfg.tag_prefix, "PARENTDIR_PREFIX": cfg.parentdir_prefix, "VERSIONFILE_SOURCE": cfg.versionfile_source, }) cmds["py2exe"] = cmd_py2exe # sdist farms its file list building out to egg_info if 'egg_info' in cmds: _egg_info = cmds['egg_info'] else: from setuptools.command.egg_info import egg_info as _egg_info class cmd_egg_info(_egg_info): def find_sources(self): # egg_info.find_sources builds the manifest list and writes it # in one shot super().find_sources() # Modify the filelist and normalize it root = get_root() cfg = get_config_from_root(root) self.filelist.append('versioneer.py') if cfg.versionfile_source: # There are rare cases where versionfile_source might not be # included by default, so we must be explicit self.filelist.append(cfg.versionfile_source) self.filelist.sort() self.filelist.remove_duplicates() # The write method is hidden in the manifest_maker instance that # generated the filelist and was thrown away # We will instead replicate their final normalization (to unicode, # and POSIX-style paths) from setuptools import unicode_utils normalized = [unicode_utils.filesys_decode(f).replace(os.sep, '/') for f in self.filelist.files] manifest_filename = os.path.join(self.egg_info, 'SOURCES.txt') with open(manifest_filename, 'w') as fobj: fobj.write('\n'.join(normalized)) cmds['egg_info'] = cmd_egg_info # we override different "sdist" commands for both environments if 'sdist' in cmds: _sdist = cmds['sdist'] else: from setuptools.command.sdist import sdist as _sdist class cmd_sdist(_sdist): def run(self): versions = get_versions() self._versioneer_generated_versions = versions # unless we update this, the command will keep using the old # version self.distribution.metadata.version = versions["version"] return _sdist.run(self) def make_release_tree(self, base_dir, files): root = get_root() cfg = get_config_from_root(root) _sdist.make_release_tree(self, base_dir, files) # now locate _version.py in the new base_dir directory # (remembering that it may be a hardlink) and replace it with an # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, self._versioneer_generated_versions) cmds["sdist"] = cmd_sdist return cmds CONFIG_ERROR = """ setup.cfg is missing the necessary Versioneer configuration. You need a section like: [versioneer] VCS = git style = pep440 versionfile_source = src/myproject/_version.py versionfile_build = myproject/_version.py tag_prefix = parentdir_prefix = myproject- You will also need to edit your setup.py to use the results: import versioneer setup(version=versioneer.get_version(), cmdclass=versioneer.get_cmdclass(), ...) Please read the docstring in ./versioneer.py for configuration instructions, edit setup.cfg, and re-run the installer or 'python versioneer.py setup'. """ SAMPLE_CONFIG = """ # See the docstring in versioneer.py for instructions. Note that you must # re-run 'versioneer.py setup' after changing this section, and commit the # resulting files. [versioneer] #VCS = git #style = pep440 #versionfile_source = #versionfile_build = #tag_prefix = #parentdir_prefix = """ OLD_SNIPPET = """ from ._version import get_versions __version__ = get_versions()['version'] del get_versions """ INIT_PY_SNIPPET = """ from . import {0} __version__ = {0}.get_versions()['version'] """ def do_setup(): """Do main VCS-independent setup function for installing Versioneer.""" root = get_root() try: cfg = get_config_from_root(root) except (OSError, configparser.NoSectionError, configparser.NoOptionError) as e: if isinstance(e, (OSError, configparser.NoSectionError)): print("Adding sample versioneer config to setup.cfg", file=sys.stderr) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) return 1 print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] f.write(LONG % {"DOLLAR": "$", "STYLE": cfg.style, "TAG_PREFIX": cfg.tag_prefix, "PARENTDIR_PREFIX": cfg.parentdir_prefix, "VERSIONFILE_SOURCE": cfg.versionfile_source, }) ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: old = f.read() except OSError: old = "" module = os.path.splitext(os.path.basename(cfg.versionfile_source))[0] snippet = INIT_PY_SNIPPET.format(module) if OLD_SNIPPET in old: print(" replacing boilerplate in %s" % ipy) with open(ipy, "w") as f: f.write(old.replace(OLD_SNIPPET, snippet)) elif snippet not in old: print(" appending to %s" % ipy) with open(ipy, "a") as f: f.write(snippet) else: print(" %s unmodified" % ipy) else: print(" %s doesn't exist, ok" % ipy) ipy = None # Make VCS-specific changes. For git, this means creating/changing # .gitattributes to mark _version.py for export-subst keyword # substitution. do_vcs_install(cfg.versionfile_source, ipy) return 0 def scan_setup_py(): """Validate the contents of setup.py against Versioneer's expectations.""" found = set() setters = False errors = 0 with open("setup.py", "r") as f: for line in f.readlines(): if "import versioneer" in line: found.add("import") if "versioneer.get_cmdclass()" in line: found.add("cmdclass") if "versioneer.get_version()" in line: found.add("get_version") if "versioneer.VCS" in line: setters = True if "versioneer.versionfile_source" in line: setters = True if len(found) != 3: print("") print("Your setup.py appears to be missing some important items") print("(but I might be wrong). Please make sure it has something") print("roughly like the following:") print("") print(" import versioneer") print(" setup( version=versioneer.get_version(),") print(" cmdclass=versioneer.get_cmdclass(), ...)") print("") errors += 1 if setters: print("You should remove lines like 'versioneer.VCS = ' and") print("'versioneer.versionfile_source = ' . This configuration") print("now lives in setup.cfg, and should be removed from setup.py") print("") errors += 1 return errors def setup_command(): """Set up Versioneer and exit with appropriate error code.""" errors = do_setup() errors += scan_setup_py() sys.exit(1 if errors else 0) if __name__ == "__main__": cmd = sys.argv[1] if cmd == "setup": setup_command()