pax_global_header00006660000000000000000000000064146752616340014530gustar00rootroot0000000000000052 comment=c15aec2c7dbbcaf5b9790b980f699bf295baa7d9 opt_einsum-3.4.0/000077500000000000000000000000001467526163400137165ustar00rootroot00000000000000opt_einsum-3.4.0/.codecov.yml000066400000000000000000000004331467526163400161410ustar00rootroot00000000000000coverage: ignore: - test/.* - compare/.* - test_helper.py - setup.py status: patch: false project: default: threshold: 80% comment: layout: "header" require_changes: false branches: null behavior: default flags: null paths: null opt_einsum-3.4.0/.github/000077500000000000000000000000001467526163400152565ustar00rootroot00000000000000opt_einsum-3.4.0/.github/CONTRIBUTING.md000066400000000000000000000125401467526163400175110ustar00rootroot00000000000000# How to contribute We welcome contributions from external contributors, and this document describes how to merge code changes into this `opt_einsum`. ## Getting Started * Make sure you have a [GitHub account](https://github.com/signup/free). * [Fork](https://help.github.com/articles/fork-a-repo/) this repository on GitHub. * On your local machine, [clone](https://help.github.com/articles/cloning-a-repository/) your fork of the repository. ## Making Changes * Add some really awesome code to your local fork. It's usually a [good idea](http://blog.jasonmeridth.com/posts/do-not-issue-pull-requests-from-your-master-branch/) to make changes on a [branch](https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/) with the branch name relating to the feature you are going to add. * When you are ready for others to examine and comment on your new feature, navigate to your fork of `opt_einsum` on GitHub and open a [pull request](https://help.github.com/articles/using-pull-requests/) (PR). Note that after you launch a PR from one of your fork's branches, all subsequent commits to that branch will be added to the open pull request automatically. Each commit added to the PR will be validated for mergability, compilation and test suite compliance; the results of these tests will be visible on the PR page. * If you're providing a new feature, you must add test cases and documentation. * When the code is ready to go, make sure you run the test suite using pytest. * When you're ready to be considered for merging, check the "Ready to go" box on the PR page to let the `opt_einsum` devs know that the changes are complete. The code will not be merged until this box is checked, the continuous integration returns checkmarks, and multiple core developers give "Approved" reviews. ## Additional Resources * [General GitHub documentation](https://help.github.com/) * [PR best practices](http://codeinthehole.com/writing/pull-requests-and-other-good-practices-for-teams-using-github/) * [A guide to contributing to software packages](http://www.contribution-guide.org) * [Thinkful PR example](http://www.thinkful.com/learn/github-pull-request-tutorial/#Time-to-Submit-Your-First-PR) ## Code of Conduct ### Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ### Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ### Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ### Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ### Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [dgasmith@vt.edu]. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ### Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ opt_einsum-3.4.0/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000003401467526163400210540ustar00rootroot00000000000000## Description Provide a brief description of the PR's purpose here. ## Todos Notable points that this PR has either accomplished or will accomplish. - [ ] TODO 1 ## Questions - [ ] Question1 ## Status - [ ] Ready to goopt_einsum-3.4.0/.github/workflows/000077500000000000000000000000001467526163400173135ustar00rootroot00000000000000opt_einsum-3.4.0/.github/workflows/Docs.yaml000066400000000000000000000010661467526163400210720ustar00rootroot00000000000000name: Docs on: push: branches: - main pull_request: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v5 with: python-version: 3.x - name: Install run: | pip install -r docs/requirements.yml pip install -e . - name: Build Docs run: mkdocs build # Only deploy if main, otherwise just build for testing - name: Deploy if: endsWith(github.ref, '/main') run: mkdocs gh-deploy --force opt_einsum-3.4.0/.github/workflows/Linting.yml000066400000000000000000000033051467526163400214430ustar00rootroot00000000000000name: Linting on: push: branches: main pull_request: branches: main jobs: mypy: name: MyPy strategy: fail-fast: false matrix: python-version: [3.12] environment: ["min-deps"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: conda-incubator/setup-miniconda@v3 with: python-version: ${{ matrix.python-version }} mamba-version: "*" channel-priority: true activate-environment: test environment-file: devtools/conda-envs/${{ matrix.environment }}-environment.yaml - name: Environment Information shell: bash -l {0} run: | conda info conda list conda config --show-sources conda config --show - name: Install shell: bash -l {0} run: | python -m pip install . --no-deps - name: MyPy shell: bash -l {0} run: | mypy opt_einsum ruff: name: Ruff strategy: fail-fast: false matrix: python-version: [3.12] environment: ["min-deps"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: conda-incubator/setup-miniconda@v3 with: python-version: ${{ matrix.python-version }} mamba-version: "*" channel-priority: true activate-environment: test environment-file: devtools/conda-envs/${{ matrix.environment }}-environment.yaml - name: Environment Information shell: bash -l {0} run: | conda info conda list conda config --show-sources conda config --show - name: Lint shell: bash -l {0} run: | set -e make format-check opt_einsum-3.4.0/.github/workflows/Tests.yml000066400000000000000000000031711467526163400211420ustar00rootroot00000000000000name: Tests on: push: branches: main pull_request: branches: main jobs: miniconda-setup: name: Env strategy: fail-fast: false matrix: include: - python-version: 3.8 environment: "min-deps" - python-version: 3.12 environment: "min-deps" - python-version: 3.9 environment: "min-ver" - python-version: 3.11 environment: "full" - python-version: 3.12 environment: "torch-only" runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: conda-incubator/setup-miniconda@v3 with: python-version: ${{ matrix.python-version }} mamba-version: "*" channel-priority: true activate-environment: test environment-file: devtools/conda-envs/${{ matrix.environment }}-environment.yaml - name: Environment Information shell: bash -l {0} run: | conda info conda list conda config --show-sources conda config --show - name: Check no NumPy for torch-only environment if: matrix.environment == 'torch-only' run: | python devtools/ci_scripts/check_no_numpy.py - name: Install shell: bash -l {0} run: | python -m pip install . --no-deps - name: Test shell: bash -l {0} run: | pytest -v --cov=opt_einsum opt_einsum/ --cov-report=xml - name: Coverage shell: bash -l {0} run: | coverage report - uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage.xml opt_einsum-3.4.0/.gitignore000066400000000000000000000014761467526163400157160ustar00rootroot00000000000000# Hatch replaces this file opt_einsum/_version.py # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] # C extensions *.so # Vim scratch files .swp # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .cache nosetests.xml coverage.xml # Translations *.mo *.pot *.swp # Django stuff: *.log # PyCharm junk .idea # Sphinx documentation docs/_build/ # PyBuilder target/ \.pytest_cache/ docs/source/autosummary/ site/ opt_einsum-3.4.0/CITATION.cff000066400000000000000000000007621467526163400156150ustar00rootroot00000000000000cff-version: 1.1.0 message: "If you use this software, please cite it as below." authors: - family-names: Smith given-names: Daniel orcid: https://orcid.org/0000-0001-8626-0900 - family-names: Gray given-names: Johnnie orcid: https://orcid.org/0000-0001-9461-3024 title: "`opt_einsum` - A Python package for optimizing contraction order for einsum-like expressions" version: 3.3.0 doi: 10.21105/joss.00753 date-released: 2019-06-28 url: "https://github.com/dgasmith/opt_einsum" opt_einsum-3.4.0/LICENSE000066400000000000000000000020701467526163400147220ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2014 Daniel Smith 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. opt_einsum-3.4.0/Makefile000066400000000000000000000005411467526163400153560ustar00rootroot00000000000000.DEFAULT_GOAL := all .PHONY: install install: pip install -e . .PHONY: format format: ruff check opt_einsum --fix ruff format opt_einsum .PHONY: format-check format-check: ruff check opt_einsum ruff format --check opt_einsum .PHONY: mypy mypy: mypy opt_einsum .PHONY: test test: pytest -v --cov=opt_einsum/ .PHONY: docs docs: mkdocs build opt_einsum-3.4.0/README.md000066400000000000000000000122241467526163400151760ustar00rootroot00000000000000# Optimized Einsum [![Tests](https://github.com/dgasmith/opt_einsum/actions/workflows/Tests.yml/badge.svg)](https://github.com/dgasmith/opt_einsum/actions/workflows/Tests.yml) [![codecov](https://codecov.io/gh/dgasmith/opt_einsum/branch/master/graph/badge.svg)](https://codecov.io/gh/dgasmith/opt_einsum) [![Anaconda-Server Badge](https://anaconda.org/conda-forge/opt_einsum/badges/version.svg)](https://anaconda.org/conda-forge/opt_einsum) [![PyPI](https://img.shields.io/pypi/v/opt_einsum.svg)](https://pypi.org/project/opt-einsum/#description) [![PyPIStats](https://img.shields.io/pypi/dm/opt_einsum)](https://pypistats.org/packages/opt-einsum) [![Documentation Status](https://github.com/dgasmith/opt_einsum/actions/workflows/Docs.yaml/badge.svg)](https://dgasmith.github.io/opt_einsum/) [![DOI](https://joss.theoj.org/papers/10.21105/joss.00753/status.svg)](https://doi.org/10.21105/joss.00753) ## Optimized Einsum: A tensor contraction order optimizer Optimized einsum can significantly reduce the overall execution time of einsum-like expressions (e.g., [`np.einsum`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.einsum.html), [`dask.array.einsum`](https://docs.dask.org/en/latest/array-api.html#dask.array.einsum), [`pytorch.einsum`](https://pytorch.org/docs/stable/torch.html#torch.einsum), [`tensorflow.einsum`](https://www.tensorflow.org/api_docs/python/tf/einsum), ) by optimizing the expression's contraction order and dispatching many operations to canonical BLAS, cuBLAS, or other specialized routines. Optimized einsum is agnostic to the backend and can handle NumPy, Dask, PyTorch, Tensorflow, CuPy, Sparse, Theano, JAX, and Autograd arrays as well as potentially any library which conforms to a standard API. See the [**documentation**](https://dgasmith.github.io/opt_einsum/) for more information. ## Example usage The [`opt_einsum.contract`](https://dgasmith.github.io/opt_einsum/api_reference#opt_einsumcontract) function can often act as a drop-in replacement for `einsum` functions without further changes to the code while providing superior performance. Here, a tensor contraction is performed with and without optimization: ```python import numpy as np from opt_einsum import contract N = 10 C = np.random.rand(N, N) I = np.random.rand(N, N, N, N) %timeit np.einsum('pi,qj,ijkl,rk,sl->pqrs', C, C, I, C, C) 1 loops, best of 3: 934 ms per loop %timeit contract('pi,qj,ijkl,rk,sl->pqrs', C, C, I, C, C) 1000 loops, best of 3: 324 us per loop ``` In this particular example, we see a ~3000x performance improvement which is not uncommon when compared against unoptimized contractions. See the [backend examples](https://dgasmith.github.io/opt_einsum/getting_started/backends) for more information on using other backends. ## Features The algorithms found in this repository often power the `einsum` optimizations in many of the above projects. For example, the optimization of `np.einsum` has been passed upstream and most of the same features that can be found in this repository can be enabled with `np.einsum(..., optimize=True)`. However, this repository often has more up to date algorithms for complex contractions. The following capabilities are enabled by `opt_einsum`: * Inspect [detailed information](https://dgasmith.github.io/opt_einsum/paths/introduction) about the path chosen. * Perform contractions with [numerous backends](https://dgasmith.github.io/opt_einsum/getting_started/backends), including on the GPU and with libraries such as [TensorFlow](https://www.tensorflow.org) and [PyTorch](https://pytorch.org). * Generate [reusable expressions](https://dgasmith.github.io/opt_einsum/getting_started/reusing_paths), potentially with [constant tensors](https://dgasmith.github.io/opt_einsum/getting_started/reusing_paths#specifying-constants), that can be compiled for greater performance. * Use an arbitrary number of indices to find contractions for [hundreds or even thousands of tensors](https://dgasmith.github.io/opt_einsum/examples/large_expr_with_greedy). * Share [intermediate computations](https://dgasmith.github.io/opt_einsum/getting_started/sharing_intermediates) among multiple contractions. * Compute gradients of tensor contractions using [autograd](https://github.com/HIPS/autograd) or [jax](https://github.com/google/jax) Please see the [documentation](https://dgasmith.github.io/opt_einsum/index) for more features! ## Installation `opt_einsum` can either be installed via `pip install opt_einsum` or from conda `conda install opt_einsum -c conda-forge`. See the installation [documentation](https://dgasmith.github.io/opt_einsum/getting_started/install) for further methods. ## Citation If this code has benefited your research, please support us by citing: Daniel G. A. Smith and Johnnie Gray, opt_einsum - A Python package for optimizing contraction order for einsum-like expressions. *Journal of Open Source Software*, **2018**, 3(26), 753 DOI: ## Contributing All contributions, bug reports, bug fixes, documentation improvements, enhancements, and ideas are welcome. A detailed overview on how to contribute can be found in the [contributing guide](https://github.com/dgasmith/opt_einsum/blob/master/.github/CONTRIBUTING.md). opt_einsum-3.4.0/devtools/000077500000000000000000000000001467526163400155555ustar00rootroot00000000000000opt_einsum-3.4.0/devtools/RELEASE.md000066400000000000000000000006231467526163400171600ustar00rootroot00000000000000# Release Checklist ## Lint Static Scan Check for flake8 issues and spelling. ```shell pip install flake8-spellcheck flake8 --whitelist ./devtools/allowlist.txt ``` ## PyPI Source and Wheel ```shell conda update setuptools wheel python setup.py sdist bdist_wheel twine upload --repository-url https://test.pypi.org/legacy/ dist/ ``` ## Update conda-forge ```plaintext - Version - Zip Hash ``` opt_einsum-3.4.0/devtools/allowlist.txt000066400000000000000000000023411467526163400203300ustar00rootroot000000000000000b100101 0rc1 10pt 11pt 12pt 16x16 32x32 a4paper abap allclose astype autodoc autogenerated autograd Backends backendseq bbfreeze bdist blas borland bw C0301 caes cba cfg cmd cmdclass cmin conda const consts crossref cupy cx datestamp DDOT Deduplicate dep dereference detailmenu df dirname documentclass dtype ein einsum eq execfile expr favicon fi FILEVERSION fmt fn fs func GEMM GEMV gh gitattributes githubs hadamard Hadamard hardlink hashable hashtable howto htaccess htbp https ico idx iij ij ik inds isort ja ja jax jieba jk jkk js letterpaper lgtm lhs libs loc lru manni mem method1 method2 modindex moduleauthor monokai nczeczulin ndim nl no NUM numpy numpytensordot opensearch outputless pagerefs papersize paraiso parentdir pep440 perldoc pointsize prepended prodcuts PRODUCTVERSION py2exe Pygments pylint quickstart recurse ret refnames rhs ro rrt rsrc rst runtime s1 s2 sdist sectionauthor Ses setrlimit sig skipif sourcedist sourcelink sparsify sphinxstrong sphinxtitleref subdependencies subgraph subgraphs subst sv TDOT tempdir tensordot Tensordot test5 texinfo Texinfo tf TF theano timeit titleref tmp toctree toplevel trac transpose uncomparable undoc unparsable v0 VCS Vectordot versioneer versionfile x3 xcode xhtml zh zh zipball opt_einsum-3.4.0/devtools/ci_scripts/000077500000000000000000000000001467526163400177175ustar00rootroot00000000000000opt_einsum-3.4.0/devtools/ci_scripts/check_no_numpy.py000066400000000000000000000001111467526163400232630ustar00rootroot00000000000000try: import numpy exit(1) except ModuleNotFoundError: exit(0)opt_einsum-3.4.0/devtools/conda-envs/000077500000000000000000000000001467526163400176125ustar00rootroot00000000000000opt_einsum-3.4.0/devtools/conda-envs/full-environment.yaml000066400000000000000000000004301467526163400237770ustar00rootroot00000000000000name: test channels: - conda-forge dependencies: # Base depends - python >=3.8 - numpy >=1.23 - nomkl # Backends - tensorflow-cpu - dask - sparse - pytorch-cpu - jax # Testing - codecov - mypy ==1.11* - pytest - pytest-cov - ruff ==0.5.* opt_einsum-3.4.0/devtools/conda-envs/min-deps-environment.yaml000066400000000000000000000002561467526163400245570ustar00rootroot00000000000000name: test channels: - conda-forge dependencies: # Base depends - python >=3.8 # Testing - codecov - mypy ==1.11* - pytest - pytest-cov - ruff ==0.6.* opt_einsum-3.4.0/devtools/conda-envs/min-ver-environment.yaml000066400000000000000000000004071467526163400244160ustar00rootroot00000000000000name: test channels: - conda-forge dependencies: # Base depends - python >=3.8 - numpy >=1.23 - nomkl # Backends - tensorflow-cpu ==2.10.* - dask ==2021.* # Testing - codecov - mypy ==1.11* - pytest - pytest-cov - ruff ==0.5.* opt_einsum-3.4.0/devtools/conda-envs/torch-only-environment.yaml000066400000000000000000000003721467526163400251400ustar00rootroot00000000000000name: test channels: - pytorch - conda-forge dependencies: # Base depends - python >=3.8 - pytorch::pytorch >=2.0,<3.0.0a - pytorch::cpuonly - mkl # Testing - codecov - mypy ==1.11* - pytest - pytest-cov - ruff ==0.5.* opt_einsum-3.4.0/devtools/conda-recipe/000077500000000000000000000000001467526163400201065ustar00rootroot00000000000000opt_einsum-3.4.0/devtools/conda-recipe/meta.yaml000066400000000000000000000057011467526163400217230ustar00rootroot00000000000000{% set name = "opt_einsum" %} {% set version = "2.0.0" %} package: name: {{ name|lower }} version: {{ version }} source: path: ../.. build: number: 0 script: python setup.py install --single-version-externally-managed --record record.txt requirements: build: - python - setuptools run: - python - numpy test: requires: - python - pytest commands: - py.test --pyargs opt_einsum about: home: http://github.com/dgasmith/opt_einsum license: MIT license_family: MIT license_file: LICENSE summary: 'A contraction optimizer for the NumPy Einsum function.' description: > Einsum is a very powerful function for contracting tensors of arbitrary dimension and index. However, it is only optimized to contract two terms at a time resulting in non-optimal scaling. For example, let us examine the following index transformation: `M_{pqrs} = C_{pi} C_{qj} I_{ijkl} C_{rk} C_{sl}` We can then develop two separate implementations that produce the same result: ```python N = 10 C = np.random.rand(N, N) I = np.random.rand(N, N, N, N) def naive(I, C): # N^8 scaling return np.einsum('pi,qj,ijkl,rk,sl->pqrs', C, C, I, C, C) def optimized(I, C): # N^5 scaling K = np.einsum('pi,ijkl->pjkl', C, I) K = np.einsum('qj,pjkl->pqkl', C, K) K = np.einsum('rk,pqkl->pqrl', C, K) K = np.einsum('sl,pqrl->pqrs', C, K) return K ``` The einsum function does not consider building intermediate arrays; therefore, helping einsum out by building these intermediate arrays can result in a considerable cost savings even for small N (N=10): ```python np.allclose(naive(I, C), optimized(I, C)) True %timeit naive(I, C) 1 loops, best of 3: 934 ms per loop %timeit optimized(I, C) 1000 loops, best of 3: 527 µs per loop ``` A 2000 fold speed up for 4 extra lines of code! This contraction can be further complicated by considering that the shape of the C matrices need not be the same, in this case the ordering in which the indices are transformed matters greatly. Logic can be built that optimizes the ordering; however, this is a lot of time and effort for a single expression. The opt_einsum package is a drop in replacement for the np.einsum function and can handle all of this logic for you: ```python from opt_einsum import contract %timeit contract('pi,qj,ijkl,rk,sl->pqrs', C, C, I, C, C) 1000 loops, best of 3: 324 µs per loop ``` The above will automatically find the optimal contraction order, in this case identical to that of the optimized function above, and compute the products for you. In this case, it even uses `np.dot` under the hood to exploit any vendor BLAS functionality that your NumPy build has! dev_url: https://github.com/dgasmith/opt_einsum extra: recipe-maintainers: - dgasmith - loriab opt_einsum-3.4.0/docs/000077500000000000000000000000001467526163400146465ustar00rootroot00000000000000opt_einsum-3.4.0/docs/api_reference.md000066400000000000000000000031251467526163400177600ustar00rootroot00000000000000--- toc_depth: 1 --- # API Documentation ### `opt_einsum.contract` ::: opt_einsum.contract.contract ### `opt_einsum.contract_path` ::: opt_einsum.contract.contract_path ### `opt_einsum.contract_expression` ::: opt_einsum.contract.contract_expression ### `opt_einsum.contract.ContractExpression` ::: opt_einsum.contract.ContractExpression ### `opt_einsum.contract.PathInfo` ::: opt_einsum.contract.PathInfo ### `opt_einsum.get_symbol` ::: opt_einsum.parser.get_symbol ### `opt_einsum.shared_intermediates` ::: opt_einsum.sharing.shared_intermediates ### `opt_einsum.paths.optimal` ::: opt_einsum.paths.optimal ### `opt_einsum.paths.greedy` ::: opt_einsum.paths.greedy ### `opt_einsum.paths.branch` ::: opt_einsum.paths.branch ### `opt_einsum.paths.PathOptimizer` ::: opt_einsum.paths.PathOptimizer ### `opt_einsum.paths.BranchBound` ::: opt_einsum.paths.BranchBound ### `opt_einsum.path_random.RandomOptimizer` ::: opt_einsum.path_random.RandomOptimizer ### `opt_einsum.path_random.RandomGreedy` ::: opt_einsum.path_random.RandomGreedy ### `opt_einsum.paths.DynamicProgramming` ::: opt_einsum.paths.DynamicProgramming opt_einsum-3.4.0/docs/changelog.md000066400000000000000000000263661467526163400171340ustar00rootroot00000000000000Changelog ========= ## 3.4.0 / 2024-09-XX NumPy has been removed from `opt_einsum` as a dependency allowing for more flexible installs. **New Features** - [\#160](https://github.com/dgasmith/opt_einsum/pull/160) Migrates docs to MkDocs Material and GitHub pages hosting. - [\#161](https://github.com/dgasmith/opt_einsum/pull/161) Adds Python type annotations to the code base. - [\#204](https://github.com/dgasmith/opt_einsum/pull/204) Removes NumPy as a hard dependency. **Enhancements** - [\#154](https://github.com/dgasmith/opt_einsum/pull/154) Prevents an infinite recursion error when the `memory_limit` was set very low for the `dp` algorithm. - [\#155](https://github.com/dgasmith/opt_einsum/pull/155) Adds flake8 spell check to the doc strings - [\#159](https://github.com/dgasmith/opt_einsum/pull/159) Migrates to GitHub actions for CI. - [\#174](https://github.com/dgasmith/opt_einsum/pull/174) Prevents double contracts of floats in dynamic paths. - [\#196](https://github.com/dgasmith/opt_einsum/pull/196) Allows `backend=None` which is equivalent to `backend='auto'` - [\#208](https://github.com/dgasmith/opt_einsum/pull/208) Switches to `ConfigParser` insetad of `SafeConfigParser` for Python 3.12 compatability. - [\#228](https://github.com/dgasmith/opt_einsum/pull/228) `backend='jaxlib'` is now an alias for the `jax` library - [\#237](https://github.com/dgasmith/opt_einsum/pull/237) Switches to `ruff` for formatting and linting. - [\#238](https://github.com/dgasmith/opt_einsum/pull/238) Removes `numpy`-specific keyword args from being explicitly defined in `contract` and uses `**kwargs` instead. **Bug Fixes** - [\#195](https://github.com/dgasmith/opt_einsum/pull/195) Fixes a bug where `dp` would not work for scalar-only contractions. - [\#200](https://github.com/dgasmith/opt_einsum/pull/200) Fixes a bug where `parse_einsum_input` would not correctly respect shape-only contractions. - [\#222](https://github.com/dgasmith/opt_einsum/pull/222) Fixes an erorr in `parse_einsum_input` where an output subscript specified multiple times was not correctly caught. - [\#229](https://github.com/dgasmith/opt_einsum/pull/229) Fixes a bug where empty contraction lists in `PathInfo` would cause an error. ## 3.3.0 / 2020-07-19 Adds a `object` backend for optimized contractions on arbitrary Python objects. **New Features** - [\#145](https://github.com/dgasmith/opt_einsum/pull/145) Adds a `object` based backend so that `contract(backend='object')` can be used on arbitrary objects such as SymPy symbols. **Enhancements** - [\#140](https://github.com/dgasmith/opt_einsum/pull/140) Better error messages when the requested `contract` backend cannot be found. - [\#141](https://github.com/dgasmith/opt_einsum/pull/141) Adds a check with RandomOptimizers to ensure the objects are not accidentally reused for different contractions. - [\#149](https://github.com/dgasmith/opt_einsum/pull/149) Limits the `remaining` category for the `contract_path` output to only show up to 20 tensors to prevent issues with the quadratically scaling memory requirements and the number of print lines for large contractions. ## 3.2.0 / 2020-03-01 Small fixes for the `dp` path and support for a new mars backend. **New Features** - [\#109](https://github.com/dgasmith/opt_einsum/pull/109) Adds mars backend support. **Enhancements** - [\#110](https://github.com/dgasmith/opt_einsum/pull/110) New `auto-hq` and `'random-greedy-128'` paths. - [\#119](https://github.com/dgasmith/opt_einsum/pull/119) Fixes several edge cases in the `dp` path. **Bug fixes** - [\#127](https://github.com/dgasmith/opt_einsum/pull/127) Fixes an issue where Python 3.6 features are required while Python 3.5 is `opt_einsum`'s stated minimum version. ## 3.1.0 / 2019-09-30 Adds a new dynamic programming algorithm to the suite of paths. **New Features** - [\#102](https://github.com/dgasmith/opt_einsum/pull/102) Adds new `dp` path. ## 3.0.0 / 2019-08-10 This release moves `opt_einsum` to be backend agnostic while adding support additional backends such as Jax and Autograd. Support for Python 2.7 has been dropped and Python 3.5 will become the new minimum version, a Python deprecation policy equivalent to NumPy's has been adopted. **New Features** - [\#78](https://github.com/dgasmith/opt_einsum/pull/78) A new random-optimizer has been implemented which uses Boltzmann weighting to explore alternative near-minimum paths using greedy-like schemes. This provides a fairly large path performance enhancements with a linear path time overhead. - [\#78](https://github.com/dgasmith/opt_einsum/pull/78) A new PathOptimizer class has been implemented to provide a framework for building new optimizers. An example is that now custom cost functions can now be provided in the greedy formalism for building custom optimizers without a large amount of additional code. - [\#81](https://github.com/dgasmith/opt_einsum/pull/81) The `backend="auto"` keyword has been implemented for `contract` allowing automatic detection of the correct backend to use based off provided tensors in the contraction. - [\#88](https://github.com/dgasmith/opt_einsum/pull/88) Autograd and Jax support have been implemented. - [\#96](https://github.com/dgasmith/opt_einsum/pull/96) Deprecates Python 2 functionality and devops improvements. **Enhancements** - [\#84](https://github.com/dgasmith/opt_einsum/pull/84) The `contract_path` function can now accept shape tuples rather than full tensors. - [\#84](https://github.com/dgasmith/opt_einsum/pull/84) The `contract_path` automated path algorithm decision technology has been refactored to a standalone function. ## 2.3.0 / 2018-12-01 This release primarily focuses on expanding the suite of available path technologies to provide better optimization characistics for 4-20 tensors while decreasing the time to find paths for 50-200+ tensors. See `Path Overview `_ for more information. **New Features** - [\#60](https://github.com/dgasmith/opt_einsum/pull/60) A new `greedy` implementation has been added which is up to two orders of magnitude faster for 200 tensors. - [\#73](https://github.com/dgasmith/opt_einsum/pull/73) Adds a new `branch` path that uses `greedy` ideas to prune the `optimal` exploration space to provide a better path than `greedy` at sub `optimal` cost. - [\#73](https://github.com/dgasmith/opt_einsum/pull/73) Adds a new `auto` keyword to the `opt_einsum.contract` `path` option. This keyword automatically chooses the best path technology that takes under 1ms to execute. **Enhancements** - [\#61](https://github.com/dgasmith/opt_einsum/pull/61) The `opt_einsum.contract` `path` keyword has been changed to `optimize` to more closely match NumPy. `path` will be deprecated in the future. - [\#61](https://github.com/dgasmith/opt_einsum/pull/61) The `opt_einsum.contract_path` now returns a `opt_einsum.contract.PathInfo` object that can be queried for the scaling, flops, and intermediates of the path. The print representation of this object is identical to before. - [\#61](https://github.com/dgasmith/opt_einsum/pull/61) The default `memory_limit` is now unlimited by default based on community feedback. - [\#66](https://github.com/dgasmith/opt_einsum/pull/66) The Torch backend will now use `tensordot` when using a version of Torch which includes this functionality. - [\#68](https://github.com/dgasmith/opt_einsum/pull/68) Indices can now be any hashable object when provided in the `"Interleaved Input" `_ syntax. - [\#74](https://github.com/dgasmith/opt_einsum/pull/74) Allows the default `transpose` operation to be overridden to take advantage of more advanced tensor transpose libraries. - [\#73](https://github.com/dgasmith/opt_einsum/pull/73) The `optimal` path is now significantly faster. - [\#81](https://github.com/dgasmith/opt_einsum/pull/81) A documentation pass for v3.0. **Bug fixes** - [\#72](https://github.com/dgasmith/opt_einsum/pull/72) Fixes the `"Interleaved Input" `_ syntax and adds documentation. ## 2.2.0 / 2018-07-29 **New Features** - [\#48](https://github.com/dgasmith/opt_einsum/pull/48) Intermediates can now be shared between contractions, see here for more details. - [\#53](https://github.com/dgasmith/opt_einsum/pull/53) Intermediate caching is thread safe. **Enhancements** - [\#48](https://github.com/dgasmith/opt_einsum/pull/48) Expressions are now mapped to non-unicode index set so that unicode input is support for all backends. - [\#54](https://github.com/dgasmith/opt_einsum/pull/54) General documentation update. **Bug fixes** - [\#41](https://github.com/dgasmith/opt_einsum/pull/41) PyTorch indices are mapped back to a small a-z subset valid for PyTorch's einsum implementation. ## 2.1.3 / 2018-8-23 **Bug fixes** - Fixes unicode issue for large numbers of tensors in Python 2.7. - Fixes unicode install bug in README.md. ## 2.1.2 / 2018-8-16 **Bug fixes** - Ensures `versioneer.py` is in MANIFEST.in for a clean pip install. ## 2.1.1 / 2018-8-15 **Bug fixes** - Corrected Markdown display on PyPi. ## 2.1.0 / 2018-8-15 `opt_einsum` continues to improve its support for additional backends beyond NumPy with PyTorch. We have also published the opt_einsum package in the Journal of Open Source Software. If you use this package in your work, please consider citing us! **New features** - PyTorch backend support - Tensorflow eager-mode execution backend support **Enhancements** - Intermediate tensordot-like expressions are now ordered to avoid transposes. - CI now uses conda backend to better support GPU and tensor libraries. - Now accepts arbitrary unicode indices rather than a subset. - New auto path option which switches between optimal and greedy at four tensors. **Bug fixes** - Fixed issue where broadcast indices were incorrectly locked out of tensordot-like evaluations even after their dimension was broadcast. ## 2.0.1 / 2018-6-28 **New Features** - Allows unlimited Unicode indices. - Adds a Journal of Open-Source Software paper. - Minor documentation improvements. ## 2.0.0 / 2018-5-17 `opt_einsum` is a powerful tensor contraction order optimizer for NumPy and related ecosystems. **New Features** - Expressions can be precompiled so that the expression optimization need not happen multiple times. - The greedy order optimization algorithm has been tuned to be able to handle hundreds of tensors in several seconds. - Input indices can now be unicode so that expressions can have many thousands of indices. - GPU and distributed computing backends have been added such as Dask, TensorFlow, CUPy, Theano, and Sparse. **Bug Fixes** - An error affecting cases where opt_einsum mistook broadcasting operations for matrix multiply has been fixed. - Most error messages are now more expressive. ## 1.0.0 / 2016-10-14 Einsum is a very powerful function for contracting tensors of arbitrary dimension and index. However, it is only optimized to contract two terms at a time resulting in non-optimal scaling for contractions with many terms. Opt_einsum aims to fix this by optimizing the contraction order which can lead to arbitrarily large speed ups at the cost of additional intermediate tensors. Opt_einsum is also implemented into the np.einsum function as of NumPy v1.12. **New Features** - Tensor contraction order optimizer. - `opt_einsum.contract` as a drop-in replacement for `numpy.einsum`. opt_einsum-3.4.0/docs/css/000077500000000000000000000000001467526163400154365ustar00rootroot00000000000000opt_einsum-3.4.0/docs/css/custom.css000066400000000000000000000002731467526163400174640ustar00rootroot00000000000000div.autodoc-docstring { padding-left: 20px; margin-bottom: 30px; border-left: 5px solid rgba(230, 230, 230); } div.autodoc-members { padding-left: 20px; margin-bottom: 15px; } opt_einsum-3.4.0/docs/examples/000077500000000000000000000000001467526163400164645ustar00rootroot00000000000000opt_einsum-3.4.0/docs/examples/dask_reusing_intermediaries.md000066400000000000000000000064321467526163400245550ustar00rootroot00000000000000# Reusing Intermediaries with Dask [Dask](https://dask.pydata.org/) provides a computational framework where arrays and the computations on them are built up into a 'task graph' before computation. Since :mod:`opt_einsum` is compatible with `dask` arrays this means that multiple contractions can be built into the same task graph, which then automatically reuses any shared arrays and contractions. For example, imagine the two expressions: ```python contraction1 = 'ab,dca,eb,cde' contraction2 = 'ab,cda,eb,cde' sizes = {l: 10 for l in 'abcde'} ``` The contraction `'ab,eb'` is shared between them and could only be done once. First, let's set up some `numpy` arrays: ```python terms1, terms2 = contraction1.split(','), contraction2.split(',') terms = set((*terms1, *terms2)) terms #> {'ab', 'cda', 'cde', 'dca', 'eb'} import numpy as np np_arrays = {s: np.random.randn(*(sizes[c] for c in s)) for s in terms} # filter the arrays needed for each expression np_ops1 = [np_arrays[s] for s in terms1] np_ops2 = [np_arrays[s] for s in terms2] ``` Typically we would compute these expressions separately: ```python oe.contract(contraction1, *np_ops1) #> array(114.78314052) oe.contract(contraction2, *np_ops2) #> array(-75.55902751) ``` However, if we use dask arrays we can combine the two operations, so let's set those up: ```python import dask.array as da da_arrays = {s: da.from_array(np_arrays[s], chunks=1000, name=s) for s in inputs} da_arrays #> {'ab': dask.array, #> 'cda': dask.array, #> 'cde': dask.array, #> 'dca': dask.array, #> 'eb': dask.array} da_ops1 = [da_arrays[s] for s in terms1] da_ops2 = [da_arrays[s] for s in terms2] ``` Note `chunks` is a required argument relating to how the arrays are stored (see [array-creation](http://dask.pydata.org/en/latest/array-creation.html)). Now we can perform the contraction: ```python # these won't be immediately evaluated dy1 = oe.contract(contraction1, *da_ops1, backend='dask') dy2 = oe.contract(contraction2, *da_ops2, backend='dask') # wrap them in delayed to combine them into the same computation from dask import delayed dy = delayed([dy1, dy2]) dy #> Delayed('list-3af82335-b75e-47d6-b800-68490fc865fd') ``` As suggested by the name `Delayed`, we have a placeholder for the result so far. When we want to *perform* the computation we can call: ```python dy.compute() #> [114.78314052155015, -75.55902750513113] ``` The above matches the canonical numpy result. The computation can even be handled by various schedulers - see [scheduling](http://dask.pydata.org/en/latest/scheduling.html). Finally, to check we are reusing intermediaries, we can view the task graph generated for the computation: ```python dy.visualize(optimize_graph=True) ``` ![Dask Reuse Graph](../img/ex_dask_reuse_graph.png) !!! note For sharing intermediates with other backends see [Sharing Intermediates](../getting_started/sharing_intermediates.md). Dask graphs are particularly useful for reusing intermediates beyond just contractions and can allow additional parallelization. opt_einsum-3.4.0/docs/examples/large_expr_with_greedy.md000066400000000000000000000273451467526163400235430ustar00rootroot00000000000000# Large Expressions with Greedy Using the greedy method allows the contraction of hundreds of tensors. Here's an example from quantum of computing the inner product between two ['Matrix Product States'](https://en.wikipedia.org/wiki/Matrix_product_state). Graphically, if we represent each tensor as an `O`, give it the same number of 'legs' as it has indices, and join those legs when that index is summed with another tensor, we get an expression for `n` particles that looks like: ```console O-O-O-O-O-O- -O-O-O-O-O-O | | | | | | ... | | | | | | O-O-O-O-O-O- -O-O-O-O-O-O 0 1 2 3 4 5 ........... n-2 n-1 ``` The meaning of this is not that important other than its a large, useful contraction. For `n=100` it involves 200 different tensors and about 300 unique indices. With this many indices it can be useful to generate them with the function `opt_einsum.parser.get_symbol`. ### Setup the string ```python import numpy as np import opt_einsum as oe n = 100 phys_dim = 3 bond_dim = 10 # start with first site # O-- # | # O-- einsum_str = "ab,ac," for i in range(1, n - 1): # set the upper left/right, middle and lower left/right indices # --O-- # | # --O-- j = 3 * i ul, ur, m, ll, lr = (oe.get_symbol(i) for i in (j - 1, j + 2, j, j - 2, j + 1)) einsum_str += "{}{}{},{}{}{},".format(m, ul, ur, m, ll, lr) # finish with last site # --O # | # --O i = n - 1 j = 3 * i ul, m, ll, = (oe.get_symbol(i) for i in (j - 1, j, j - 2)) einsum_str += "{}{},{}{}".format(m, ul, m, ll) ``` ### Generate the shapes ```python def gen_shapes(): yield (phys_dim, bond_dim) yield (phys_dim, bond_dim) for i in range(1, n - 1): yield(phys_dim, bond_dim, bond_dim) yield(phys_dim, bond_dim, bond_dim) yield (phys_dim, bond_dim) yield (phys_dim, bond_dim) shapes = tuple(gen_shapes()) ``` Let's time how long it takes to generate the expression (`'greedy'` is used by default, and we turn off the `memory_limit`): ```python %timeit expr = oe.contract_expression(einsum_str, *shapes, memory_limit=-1) #> 76.2 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) ``` This is pretty manageable, though we might want to think about splitting the expression up if we go a lot bigger. Importantly, we can then use this repeatedly with any set of matching arrays: ```python arrays = [np.random.randn(*shp) / 4 for shp in shapes] expr(*arrays) #> array(23.23628116) arrays = [np.random.randn(*shp) / 4 for shp in shapes] expr(*arrays) #> array(-12.21091879) ``` ### Full path And if we **really** want we can generate the full contraction path info: ```python print(oe.contract_path(einsum_str, *arrays, memory_limit=-1)[1]) #> Complete contraction: ab,ac,dcf,dbe,gfi,geh,jil,jhk,mlo,mkn,por,pnq,sru,sqt,vux,vtw,yxA,ywz,BAD,BzC,EDG,ECF,HGJ,HFI,KJM,KIL,NMP,NLO,QPS,QOR,TSV,TRU,WVY,WUX,ZYÂ,ZXÁ,ÃÂÅ,ÃÁÄ,ÆÅÈ,ÆÄÇ,ÉÈË,ÉÇÊ,ÌËÎ,ÌÊÍ,ÏÎÑ,ÏÍÐ,ÒÑÔ,ÒÐÓ,ÕÔ×,ÕÓÖ,Ø×Ú,ØÖÙ,ÛÚÝ,ÛÙÜ,ÞÝà,ÞÜß,áàã,áßâ,äãæ,äâå,çæé,çåè,êéì,êèë,íìï,íëî,ðïò,ðîñ,óòõ,óñô,öõø,öô÷,ùøû,ù÷ú,üûþ,üúý,ÿþā,ÿýĀ,ĂāĄ,ĂĀă,ąĄć,ąăĆ,ĈćĊ,ĈĆĉ,ċĊč,ċĉČ,ĎčĐ,ĎČď,đĐē,đďĒ,ĔēĖ,ĔĒĕ,ėĖę,ėĕĘ,ĚęĜ,ĚĘě,ĝĜğ,ĝěĞ,ĠğĢ,ĠĞġ,ģĢĥ,ģġĤ,ĦĥĨ,ĦĤħ,ĩĨī,ĩħĪ,ĬīĮ,ĬĪĭ,įĮı,įĭİ,IJıĴ,IJİij,ĵĴķ,ĵijĶ,ĸķĺ,ĸĶĹ,ĻĺĽ,ĻĹļ,ľĽŀ,ľļĿ,ŁŀŃ,ŁĿł,ńŃņ,ńłŅ,Ňņʼn,ŇŅň,ŊʼnŌ,Ŋňŋ,ōŌŏ,ōŋŎ,ŐŏŒ,ŐŎő,œŒŕ,œőŔ,ŖŕŘ,ŖŔŗ,řŘś,řŗŚ,ŜśŞ,ŜŚŝ,şŞš,şŝŠ,ŢšŤ,ŢŠţ,ťŤŧ,ťţŦ,ŨŧŪ,ŨŦũ,ūŪŭ,ūũŬ,ŮŭŰ,ŮŬů,űŰų,űůŲ,ŴųŶ,ŴŲŵ,ŷŶŹ,ŷŵŸ,źŹż,źŸŻ,Žżſ,ŽŻž,ƀſƂ,ƀžƁ,ƃƂƅ,ƃƁƄ,Ɔƅƈ,ƆƄƇ,ƉƈƋ,ƉƇƊ,ƌƋƎ,ƌƊƍ,ƏƎƑ,ƏƍƐ,ƒƑƔ,ƒƐƓ,ƕƔƗ,ƕƓƖ,ƘƗƚ,ƘƖƙ,ƛƚƝ,ƛƙƜ,ƞƝƠ,ƞƜƟ,ơƠƣ,ơƟƢ,ƤƣƦ,ƤƢƥ,ƧƦƩ,Ƨƥƨ,ƪƩƬ,ƪƨƫ,ƭƬƯ,ƭƫƮ,ưƯƲ,ưƮƱ,ƳƲƵ,ƳƱƴ,ƶƵ,ƶƴ-> #> Naive scaling: 298 #> Optimized scaling: 5 #> Naive FLOP count: 1.031e+248 #> Optimized FLOP count: 1.168e+06 #> Theoretical speedup: 88264689284468460017580864156865782413140936705854966013600065426858041248009637246968036807489558012989638169986640870276510490846199301907401763236976204166215471281505344088317454144870323271826022036197984172898402324699098341524952317952.000 #> Largest intermediate: 3.000e+02 elements #> -------------------------------------------------------------------------------- #> scaling BLAS current remaining #> -------------------------------------------------------------------------------- #> 4 TDOT dbe,ab->ade ac,dcf,gfi,geh,jil,jhk,mlo,mkn,por,pnq,sru,sqt,vux,vtw,yxA,ywz,BAD,BzC,EDG,ECF,HGJ,HFI,KJM,KIL,NMP,NLO,QPS,QOR,TSV,TRU,WVY,WUX,ZYÂ,ZXÁ,ÃÂÅ,ÃÁÄ,ÆÅÈ,ÆÄÇ,ÉÈË,ÉÇÊ,ÌËÎ,ÌÊÍ,ÏÎÑ,ÏÍÐ,ÒÑÔ,ÒÐÓ,ÕÔ×,ÕÓÖ,Ø×Ú,ØÖÙ,ÛÚÝ,ÛÙÜ,ÞÝà,ÞÜß,áàã,áßâ,äãæ,äâå,çæé,çåè,êéì,êèë,íìï,íëî,ðïò,ðîñ,óòõ,óñô,öõø,öô÷,ùøû,ù÷ú,üûþ,üúý,ÿþā,ÿýĀ,ĂāĄ,ĂĀă,ąĄć,ąăĆ,ĈćĊ,ĈĆĉ,ċĊč,ċĉČ,ĎčĐ,ĎČď,đĐē,đďĒ,ĔēĖ,ĔĒĕ,ėĖę,ėĕĘ,ĚęĜ,ĚĘě,ĝĜğ,ĝěĞ,ĠğĢ,ĠĞġ,ģĢĥ,ģġĤ,ĦĥĨ,ĦĤħ,ĩĨī,ĩħĪ,ĬīĮ,ĬĪĭ,įĮı,įĭİ,IJıĴ,IJİij,ĵĴķ,ĵijĶ,ĸķĺ,ĸĶĹ,ĻĺĽ,ĻĹļ,ľĽŀ,ľļĿ,ŁŀŃ,ŁĿł,ńŃņ,ńłŅ,Ňņʼn,ŇŅň,ŊʼnŌ,Ŋňŋ,ōŌŏ,ōŋŎ,ŐŏŒ,ŐŎő,œŒŕ,œőŔ,ŖŕŘ,ŖŔŗ,řŘś,řŗŚ,ŜśŞ,ŜŚŝ,şŞš,şŝŠ,ŢšŤ,ŢŠţ,ťŤŧ,ťţŦ,ŨŧŪ,ŨŦũ,ūŪŭ,ūũŬ,ŮŭŰ,ŮŬů,űŰų,űůŲ,ŴųŶ,ŴŲŵ,ŷŶŹ,ŷŵŸ,źŹż,źŸŻ,Žżſ,ŽŻž,ƀſƂ,ƀžƁ,ƃƂƅ,ƃƁƄ,Ɔƅƈ,ƆƄƇ,ƉƈƋ,ƉƇƊ,ƌƋƎ,ƌƊƍ,ƏƎƑ,ƏƍƐ,ƒƑƔ,ƒƐƓ,ƕƔƗ,ƕƓƖ,ƘƗƚ,ƘƖƙ,ƛƚƝ,ƛƙƜ,ƞƝƠ,ƞƜƟ,ơƠƣ,ơƟƢ,ƤƣƦ,ƤƢƥ,ƧƦƩ,Ƨƥƨ,ƪƩƬ,ƪƨƫ,ƭƬƯ,ƭƫƮ,ưƯƲ,ưƮƱ,ƳƲƵ,ƳƱƴ,ƶƵ,ƶƴ,ade-> #> 4 TDOT dcf,ac->adf gfi,geh,jil,jhk,mlo,mkn,por,pnq,sru,sqt,vux,vtw,yxA,ywz,BAD,BzC,EDG,ECF,HGJ,HFI,KJM,KIL,NMP,NLO,QPS,QOR,TSV,TRU,WVY,WUX,ZYÂ,ZXÁ,ÃÂÅ,ÃÁÄ,ÆÅÈ,ÆÄÇ,ÉÈË,ÉÇÊ,ÌËÎ,ÌÊÍ,ÏÎÑ,ÏÍÐ,ÒÑÔ,ÒÐÓ,ÕÔ×,ÕÓÖ,Ø×Ú,ØÖÙ,ÛÚÝ,ÛÙÜ,ÞÝà,ÞÜß,áàã,áßâ,äãæ,äâå,çæé,çåè,êéì,êèë,íìï,íëî,ðïò,ðîñ,óòõ,óñô,öõø,öô÷,ùøû,ù÷ú,üûþ,üúý,ÿþā,ÿýĀ,ĂāĄ,ĂĀă,ąĄć,ąăĆ,ĈćĊ,ĈĆĉ,ċĊč,ċĉČ,ĎčĐ,ĎČď,đĐē,đďĒ,ĔēĖ,ĔĒĕ,ėĖę,ėĕĘ,ĚęĜ,ĚĘě,ĝĜğ,ĝěĞ,ĠğĢ,ĠĞġ,ģĢĥ,ģġĤ,ĦĥĨ,ĦĤħ,ĩĨī,ĩħĪ,ĬīĮ,ĬĪĭ,įĮı,įĭİ,IJıĴ,IJİij,ĵĴķ,ĵijĶ,ĸķĺ,ĸĶĹ,ĻĺĽ,ĻĹļ,ľĽŀ,ľļĿ,ŁŀŃ,ŁĿł,ńŃņ,ńłŅ,Ňņʼn,ŇŅň,ŊʼnŌ,Ŋňŋ,ōŌŏ,ōŋŎ,ŐŏŒ,ŐŎő,œŒŕ,œőŔ,ŖŕŘ,ŖŔŗ,řŘś,řŗŚ,ŜśŞ,ŜŚŝ,şŞš,şŝŠ,ŢšŤ,ŢŠţ,ťŤŧ,ťţŦ,ŨŧŪ,ŨŦũ,ūŪŭ,ūũŬ,ŮŭŰ,ŮŬů,űŰų,űůŲ,ŴųŶ,ŴŲŵ,ŷŶŹ,ŷŵŸ,źŹż,źŸŻ,Žżſ,ŽŻž,ƀſƂ,ƀžƁ,ƃƂƅ,ƃƁƄ,Ɔƅƈ,ƆƄƇ,ƉƈƋ,ƉƇƊ,ƌƋƎ,ƌƊƍ,ƏƎƑ,ƏƍƐ,ƒƑƔ,ƒƐƓ,ƕƔƗ,ƕƓƖ,ƘƗƚ,ƘƖƙ,ƛƚƝ,ƛƙƜ,ƞƝƠ,ƞƜƟ,ơƠƣ,ơƟƢ,ƤƣƦ,ƤƢƥ,ƧƦƩ,Ƨƥƨ,ƪƩƬ,ƪƨƫ,ƭƬƯ,ƭƫƮ,ưƯƲ,ưƮƱ,ƳƲƵ,ƳƱƴ,ƶƵ,ƶƴ,ade,adf-> #> 4 GEMM ƶƵ,ƳƲƵ->ƳƶƲ gfi,geh,jil,jhk,mlo,mkn,por,pnq,sru,sqt,vux,vtw,yxA,ywz,BAD,BzC,EDG,ECF,HGJ,HFI,KJM,KIL,NMP,NLO,QPS,QOR,TSV,TRU,WVY,WUX,ZYÂ,ZXÁ,ÃÂÅ,ÃÁÄ,ÆÅÈ,ÆÄÇ,ÉÈË,ÉÇÊ,ÌËÎ,ÌÊÍ,ÏÎÑ,ÏÍÐ,ÒÑÔ,ÒÐÓ,ÕÔ×,ÕÓÖ,Ø×Ú,ØÖÙ,ÛÚÝ,ÛÙÜ,ÞÝà,ÞÜß,áàã,áßâ,äãæ,äâå,çæé,çåè,êéì,êèë,íìï,íëî,ðïò,ðîñ,óòõ,óñô,öõø,öô÷,ùøû,ù÷ú,üûþ,üúý,ÿþā,ÿýĀ,ĂāĄ,ĂĀă,ąĄć,ąăĆ,ĈćĊ,ĈĆĉ,ċĊč,ċĉČ,ĎčĐ,ĎČď,đĐē,đďĒ,ĔēĖ,ĔĒĕ,ėĖę,ėĕĘ,ĚęĜ,ĚĘě,ĝĜğ,ĝěĞ,ĠğĢ,ĠĞġ,ģĢĥ,ģġĤ,ĦĥĨ,ĦĤħ,ĩĨī,ĩħĪ,ĬīĮ,ĬĪĭ,įĮı,įĭİ,IJıĴ,IJİij,ĵĴķ,ĵijĶ,ĸķĺ,ĸĶĹ,ĻĺĽ,ĻĹļ,ľĽŀ,ľļĿ,ŁŀŃ,ŁĿł,ńŃņ,ńłŅ,Ňņʼn,ŇŅň,ŊʼnŌ,Ŋňŋ,ōŌŏ,ōŋŎ,ŐŏŒ,ŐŎő,œŒŕ,œőŔ,ŖŕŘ,ŖŔŗ,řŘś,řŗŚ,ŜśŞ,ŜŚŝ,şŞš,şŝŠ,ŢšŤ,ŢŠţ,ťŤŧ,ťţŦ,ŨŧŪ,ŨŦũ,ūŪŭ,ūũŬ,ŮŭŰ,ŮŬů,űŰų,űůŲ,ŴųŶ,ŴŲŵ,ŷŶŹ,ŷŵŸ,źŹż,źŸŻ,Žżſ,ŽŻž,ƀſƂ,ƀžƁ,ƃƂƅ,ƃƁƄ,Ɔƅƈ,ƆƄƇ,ƉƈƋ,ƉƇƊ,ƌƋƎ,ƌƊƍ,ƏƎƑ,ƏƍƐ,ƒƑƔ,ƒƐƓ,ƕƔƗ,ƕƓƖ,ƘƗƚ,ƘƖƙ,ƛƚƝ,ƛƙƜ,ƞƝƠ,ƞƜƟ,ơƠƣ,ơƟƢ,ƤƣƦ,ƤƢƥ,ƧƦƩ,Ƨƥƨ,ƪƩƬ,ƪƨƫ,ƭƬƯ,ƭƫƮ,ưƯƲ,ưƮƱ,ƳƱƴ,ƶƴ,ade,adf,ƳƶƲ-> #> 4 GEMM ƶƴ,ƳƱƴ->ƳƶƱ gfi,geh,jil,jhk,mlo,mkn,por,pnq,sru,sqt,vux,vtw,yxA,ywz,BAD,BzC,EDG,ECF,HGJ,HFI,KJM,KIL,NMP,NLO,QPS,QOR,TSV,TRU,WVY,WUX,ZYÂ,ZXÁ,ÃÂÅ,ÃÁÄ,ÆÅÈ,ÆÄÇ,ÉÈË,ÉÇÊ,ÌËÎ,ÌÊÍ,ÏÎÑ,ÏÍÐ,ÒÑÔ,ÒÐÓ,ÕÔ×,ÕÓÖ,Ø×Ú,ØÖÙ,ÛÚÝ,ÛÙÜ,ÞÝà,ÞÜß,áàã,áßâ,äãæ,äâå,çæé,çåè,êéì,êèë,íìï,íëî,ðïò,ðîñ,óòõ,óñô,öõø,öô÷,ùøû,ù÷ú,üûþ,üúý,ÿþā,ÿýĀ,ĂāĄ,ĂĀă,ąĄć,ąăĆ,ĈćĊ,ĈĆĉ,ċĊč,ċĉČ,ĎčĐ,ĎČď,đĐē,đďĒ,ĔēĖ,ĔĒĕ,ėĖę,ėĕĘ,ĚęĜ,ĚĘě,ĝĜğ,ĝěĞ,ĠğĢ,ĠĞġ,ģĢĥ,ģġĤ,ĦĥĨ,ĦĤħ,ĩĨī,ĩħĪ,ĬīĮ,ĬĪĭ,įĮı,įĭİ,IJıĴ,IJİij,ĵĴķ,ĵijĶ,ĸķĺ,ĸĶĹ,ĻĺĽ,ĻĹļ,ľĽŀ,ľļĿ,ŁŀŃ,ŁĿł,ńŃņ,ńłŅ,Ňņʼn,ŇŅň,ŊʼnŌ,Ŋňŋ,ōŌŏ,ōŋŎ,ŐŏŒ,ŐŎő,œŒŕ,œőŔ,ŖŕŘ,ŖŔŗ,řŘś,řŗŚ,ŜśŞ,ŜŚŝ,şŞš,şŝŠ,ŢšŤ,ŢŠţ,ťŤŧ,ťţŦ,ŨŧŪ,ŨŦũ,ūŪŭ,ūũŬ,ŮŭŰ,ŮŬů,űŰų,űůŲ,ŴųŶ,ŴŲŵ,ŷŶŹ,ŷŵŸ,źŹż,źŸŻ,Žżſ,ŽŻž,ƀſƂ,ƀžƁ,ƃƂƅ,ƃƁƄ,Ɔƅƈ,ƆƄƇ,ƉƈƋ,ƉƇƊ,ƌƋƎ,ƌƊƍ,ƏƎƑ,ƏƍƐ,ƒƑƔ,ƒƐƓ,ƕƔƗ,ƕƓƖ,ƘƗƚ,ƘƖƙ,ƛƚƝ,ƛƙƜ,ƞƝƠ,ƞƜƟ,ơƠƣ,ơƟƢ,ƤƣƦ,ƤƢƥ,ƧƦƩ,Ƨƥƨ,ƪƩƬ,ƪƨƫ,ƭƬƯ,ƭƫƮ,ưƯƲ,ưƮƱ,ade,adf,ƳƶƲ,ƳƶƱ-> #> 5 TDOT ade,geh->adgh gfi,jil,jhk,mlo,mkn,por,pnq,sru,sqt,vux,vtw,yxA,ywz,BAD,BzC,EDG,ECF,HGJ,HFI,KJM,KIL,NMP,NLO,QPS,QOR,TSV,TRU,WVY,WUX,ZYÂ,ZXÁ,ÃÂÅ,ÃÁÄ,ÆÅÈ,ÆÄÇ,ÉÈË,ÉÇÊ,ÌËÎ,ÌÊÍ,ÏÎÑ,ÏÍÐ,ÒÑÔ,ÒÐÓ,ÕÔ×,ÕÓÖ,Ø×Ú,ØÖÙ,ÛÚÝ,ÛÙÜ,ÞÝà,ÞÜß,áàã,áßâ,äãæ,äâå,çæé,çåè,êéì,êèë,íìï,íëî,ðïò,ðîñ,óòõ,óñô,öõø,öô÷,ùøû,ù÷ú,üûþ,üúý,ÿþā,ÿýĀ,ĂāĄ,ĂĀă,ąĄć,ąăĆ,ĈćĊ,ĈĆĉ,ċĊč,ċĉČ,ĎčĐ,ĎČď,đĐē,đďĒ,ĔēĖ,ĔĒĕ,ėĖę,ėĕĘ,ĚęĜ,ĚĘě,ĝĜğ,ĝěĞ,ĠğĢ,ĠĞġ,ģĢĥ,ģġĤ,ĦĥĨ,ĦĤħ,ĩĨī,ĩħĪ,ĬīĮ,ĬĪĭ,įĮı,įĭİ,IJıĴ,IJİij,ĵĴķ,ĵijĶ,ĸķĺ,ĸĶĹ,ĻĺĽ,ĻĹļ,ľĽŀ,ľļĿ,ŁŀŃ,ŁĿł,ńŃņ,ńłŅ,Ňņʼn,ŇŅň,ŊʼnŌ,Ŋňŋ,ōŌŏ,ōŋŎ,ŐŏŒ,ŐŎő,œŒŕ,œőŔ,ŖŕŘ,ŖŔŗ,řŘś,řŗŚ,ŜśŞ,ŜŚŝ,şŞš,şŝŠ,ŢšŤ,ŢŠţ,ťŤŧ,ťţŦ,ŨŧŪ,ŨŦũ,ūŪŭ,ūũŬ,ŮŭŰ,ŮŬů,űŰų,űůŲ,ŴųŶ,ŴŲŵ,ŷŶŹ,ŷŵŸ,źŹż,źŸŻ,Žżſ,ŽŻž,ƀſƂ,ƀžƁ,ƃƂƅ,ƃƁƄ,Ɔƅƈ,ƆƄƇ,ƉƈƋ,ƉƇƊ,ƌƋƎ,ƌƊƍ,ƏƎƑ,ƏƍƐ,ƒƑƔ,ƒƐƓ,ƕƔƗ,ƕƓƖ,ƘƗƚ,ƘƖƙ,ƛƚƝ,ƛƙƜ,ƞƝƠ,ƞƜƟ,ơƠƣ,ơƟƢ,ƤƣƦ,ƤƢƥ,ƧƦƩ,Ƨƥƨ,ƪƩƬ,ƪƨƫ,ƭƬƯ,ƭƫƮ,ưƯƲ,ưƮƱ,adf,ƳƶƲ,ƳƶƱ,adgh-> #> #> ... #> #> 4 TDOT Ğğ,ĠğĢ->ĠĞĢ ĠĞġ,ģĢĥ,ģġĤ,Ĥĥ,ĠĞĢ-> #> 4 GEMM ĠĞĢ,ĠĞġ->ġĢ ģĢĥ,ģġĤ,Ĥĥ,ġĢ-> #> 4 GEMM Ĥĥ,ģĢĥ->ģĢĤ ģġĤ,ġĢ,ģĢĤ-> #> 4 TDOT ģĢĤ,ģġĤ->ġĢ ġĢ,ġĢ-> #> 2 DOT ġĢ,ġĢ-> -> ``` Where we can see the speedup over a naive einsum is about `10^241`, not bad! opt_einsum-3.4.0/docs/getting_started/000077500000000000000000000000001467526163400200355ustar00rootroot00000000000000opt_einsum-3.4.0/docs/getting_started/backends.md000066400000000000000000000312571467526163400221410ustar00rootroot00000000000000# Backends & GPU Support `opt_einsum` is largely agnostic to the type of n-dimensional arrays (tensors) it uses, since finding the contraction path only relies on getting the shape attribute of each array supplied. It can perform the underlying tensor contractions with various libraries. In fact, any library that provides a `numpy.tensordot` and `numpy.transpose` implementation can perform most normal contractions. However, certain special functionalities such as axes reduction are reliant on a `numpy.einsum` implementation. The following is a brief overview of libraries which have been tested with `opt_einsum`: - [tensorflow](https://www.tensorflow.org/): compiled tensor expressions that can run on GPU. - [theano](http://deeplearning.net/software/theano/): compiled tensor expressions that can run on GPU. - [cupy](https://cupy.chainer.org/): numpy-like api for GPU tensors. - [dask](https://dask.pydata.org/): larger-than-memory tensor computations, distributed scheduling, and potential reuse of intermediaries. - [sparse](https://sparse.pydata.org/): sparse tensors. - [pytorch](https://pytorch.org): numpy-like api for GPU tensors. - [autograd](https://github.com/HIPS/autograd): automatic derivative computation for tensor expressions - [jax](https://github.com/google/jax): compiled GPU tensor expressions including `autograd`-like functionality !!! note For a contraction to be possible without using a backend einsum, it must satisfy the following rule: in the full expression (*including* output indices) each index must appear twice. In other words, each dimension must be either contracted with one other dimension or left alone. ## Backend agnostic contractions The automatic backend detection will be detected based on the first supplied array (default), this can be overridden by specifying the correct `backend` argument for the type of arrays supplied when calling [`opt_einsum.contract`](../api_reference.md#opt_einsum.contract.contract). For example, if you had a library installed called `'foo'` which provided an `numpy.ndarray` like object with a `.shape` attribute as well as `foo.tensordot` and `foo.transpose` then you could contract them with something like: ```python contract(einsum_str, *foo_arrays, backend='foo') ``` Behind the scenes `opt_einsum` will find the contraction path, perform pairwise contractions using e.g. `foo.tensordot` and finally return the canonical type those functions return. ### Dask [dask](https://dask.pydata.org/) is an example of a library which satisfies these requirements. For example: ```python import opt_einsum as oe import dask.array as da shapes = (3, 200), (200, 300), (300, 4) dxs = [da.random.normal(0, 1, shp, chunks=(100, 100)) for shp in shapes] dxs #> [dask.array, #> dask.array, #> dask.array] dy = oe.contract("ab,bc,cd", *dxs) # will infer backend='dask' dy #> dask.array dy.compute() #> array([[ 470.71404665, 2.44931372, -28.47577265, 424.37716615], #> [ 64.38328345, -287.40753131, 144.46515642, 324.88169821], #> [-142.07153553, -180.41739259, 125.0973783 , -239.16754541]]) ``` In this case, dask arrays in = dask array out, since dask arrays have a shape attribute, and `opt_einsum` can find `dask.array.tensordot` and `dask.array.transpose`. ### Sparse The [sparse](https://sparse.pydata.org/) library also fits the requirements and is supported. An example: ```python import sparse as sp shapes = (3, 200), (200, 300), (300, 4) sxs = [sp.random(shp) for shp in shapes] sxs #> [, #> , #> ] oe.contract("ab,bc,cd", *sxs) #> ``` ### Autograd The [autograd](https://github.com/HIPS/autograd) library is a drop-in for `numpy` that can automatically compute the gradients of array expressions. `opt_einsum` automatically dispatches the `autograd` arrays correctly, enabling a simple way to compute gradients of tensor contractions: ```python import numpy as np import autograd shapes = [(2, 3), (3, 4), (4, 2)] x, y, z = [np.random.rand(*s) for s in shapes] # make single arg function as autograd takes derivative of first arg def foo(xyz): return oe.contract('ij,jk,ki->', *xyz) foo([x, y, z]) #> array(4.90422159) # wrap foo with autograd to compute gradients instead dfoo = autograd.grad(foo) dx, dy, dz = dfoo(arrays) dx, dy, dz #> (array([[1.10056194, 1.25078356, 1.48211494], #> [1.38945961, 1.5572077 , 1.65234003]]), #> array([[0.41710717, 0.63202881, 0.84573502, 0.95069975], #> [0.42706777, 0.73630994, 0.99328938, 0.77415267], #> [0.40773334, 0.61693475, 0.82545726, 0.93132302]]), #> array([[0.78747828, 1.28979012], #> [1.26051133, 1.48835538], #> [0.46896666, 0.55003072], #> [1.10840828, 1.16722494]])) ``` ### Jax [jax](https://github.com/google/jax) is itself a drop-in for `autograd`, that additionally uses [XLA](https://www.tensorflow.org/xla) to compile the expressions, particularly for the GPU. Using it with `opt_einsum` is very simple: ```python import jax # generate a compiled version of the above function jit_foo = jax.jit(foo) jit_foo([x, y, z]) #> DeviceArray(4.9042215, dtype=float32) # generate a compiled version of the gradient function jit_dfoo = jax.jit(jax.grad(foo)) jit_dfoo([x, y, z]) #> [DeviceArray([[1.10056198, 1.25078356, 1.48211491], #> [1.38945973, 1.5572077, 1.65234005]], dtype=float32), #> DeviceArray([[0.41710716, 0.63202882, 0.84573501, 0.95069975], #> [0.42706776, 0.73630995, 0.99328935, 0.7741527 ], #> [0.40773335, 0.61693472, 0.82545722, 0.93132305]], #> dtype=float32), #> DeviceArray([[0.78747827, 1.28979015], #> [1.2605114 , 1.4883554 ], #> [0.46896666, 0.55003077], #> [1.10840821, 1.16722488]], dtype=float32)] ``` !!! note `jax` defaults to converting all arrays to single precision. This behaviour can be changed by running `from jax.config import config; config.update("jax_enable_x64", True)` **before** it has been imported and used at all. ## Special (GPU) backends for numpy arrays A particular case is if numpy arrays are required for the input and output, however, a more performant backend is required such as performing the contraction on a GPU. Unless the specified backend works on numpy arrays, this requires converting to and from the backend array type. Currently `opt_einsum` can handle this automatically for: - [tensorflow](https://www.tensorflow.org/) - [theano](http://deeplearning.net/software/theano/) - [cupy](https://cupy.chainer.org/) - [pytorch](https://pytorch.org) - [jax](https://github.com/google/jax) all of which offer GPU support. Since `tensorflow` and `theano` both require compiling the expression, this functionality is encapsulated in generating a [`opt_einsum.ContractExpression`](../api_reference.md#opt_einsum.contract.contract_expression) using [`opt_einsum.contract_expression`](../api_reference.md#opt_einsumcontract_expression), which can then be called using numpy arrays whilst specifying `backend='tensorflow'` etc. Additionally, if arrays are marked as `constant` (see [`constants-section`](./reusing_paths.md#specifying-constants)), then these arrays will be kept on the device for optimal performance. ### Theano If `theano` is installed, using it as backend is as simple as specifying `backend='theano'`: ```python shapes = (3, 200), (200, 300), (300, 4) expr = oe.contract_expression("ab,bc,cd", *shapes) expr #> import numpy as np # GPU advantage mainly for low precision numbers xs = [np.random.randn(*shp).astype(np.float32) for shp in shapes] expr(*xs, backend='theano') # might see some fluff on first run #> array([[ 129.28352 , -128.00702 , -164.62917 , -335.11682 ], #> [-462.52344 , -121.12657 , -67.847626 , 624.5457 ], #> [ 5.2838974, 36.441578 , 81.62851 , 703.1576 ]], #> dtype=float32) ``` Note that you can still supply `theano.tensor.TensorType` directly to `opt_einsum` (with `backend='theano'`), and it will return the relevant `theano` type. ### Tensorflow To run the expression with **tensorflow**, you need to register a default session: ```python import tensorflow as tf sess = tf.Session() with sess.as_default(): out = expr(*xs, backend='tensorflow') out #> array([[ 129.28357 , -128.00684 , -164.62903 , -335.1167 ], #> [-462.52362 , -121.12659 , -67.84769 , 624.5455 ], #> [ 5.2839584, 36.44155 , 81.62852 , 703.15784 ]], #> dtype=float32) ``` Note that you can still supply this expression with, for example, a `tensorflow.placeholder` using `backend='tensorflow'`, and then no conversion would take place, instead you'd get a `tensorflow.Tensor` back. Version 1.9 of tensorflow also added support for eager execution of computations. If compilation of the contraction expression tensorflow graph is taking a substantial amount of time up then it can be advantageous to use this, especially since tensor contractions are quite compute-bound. This is achieved by running the following snippet: ```python import tensorflow as tf tf.enable_eager_execution() ``` After which `opt_einsum` will automatically detect eager mode if `backend='tensorflow'` is supplied to a [`opt_einsum.ContractExpression`](../api_reference.md#opt_einsum.contract.contract_expression). ### Pytorch & Cupy Both [pytorch](https://pytorch.org) and [cupy](https://cupy.chainer.org/) offer numpy-like, GPU-enabled arrays which execute eagerly rather than requiring any compilation. If they are installed, no steps are required to utilize them other than specifying the `backend` keyword: ```python expr(*xs, backend='torch') #> array([[ 129.28357 , -128.00684 , -164.62903 , -335.1167 ], #> [-462.52362 , -121.12659 , -67.84769 , 624.5455 ], #> [ 5.2839584, 36.44155 , 81.62852 , 703.15784 ]], #> dtype=float32) expr(*xs, backend='cupy') #> array([[ 129.28357 , -128.00684 , -164.62903 , -335.1167 ], #> [-462.52362 , -121.12659 , -67.84769 , 624.5455 ], #> [ 5.2839584, 36.44155 , 81.62852 , 703.15784 ]], #> dtype=float32) ``` And as with the other GPU backends, if raw `cupy` or `pytorch` arrays are supplied the returned array will be of the same type, with no conversion to or from `numpy` arrays. ### Jax [jax](https://github.com/google/jax), as introduced above, can compile tensor functions, in doing so often achieving better performance. `opt_einsum` expressions can handle this behind the scenes, so again just the `backend` keyword needs to be supplied: ```python expr(*xs, backend='jax') #> array([[ 129.28357 , -128.00684 , -164.62903 , -335.1167 ], #> [-462.52362 , -121.12659 , -67.84769 , 624.5455 ], #> [ 5.2839584, 36.44155 , 81.62852 , 703.15784 ]], #> dtype=float32) ``` ## Contracting arbitrary objects There is one more explicit backend that can handle arbitrary arrays of objects, so long the *objects themselves* just support multiplication and addition ( `__mul__` and `__add__` dunder methods respectively). Use it by supplying `backend='object'`. For example, imagine we want to perform a contraction of arrays made up of [sympy](https://www.sympy.org) symbols: ```python import opt_einsum as oe import numpy as np import sympy # define the symbols a, b, c, d, e, f, g, h, i, j, k, l = [sympy.symbols(oe.get_symbol(i)) for i in range(12)] a * b + c * d 𝑑 # define the tensors (you might explicitly specify `dtype=object`) X = np.array([[a, b], [c, d]]) Y = np.array([[e, f], [g, h]]) Z = np.array([[i, j], [k, l]]) # contract the tensors! oe.contract('uv,vw,wu->u', X, Y, Z, backend='object') # array([i*(a*e + b*g) + k*(a*f + b*h), j*(c*e + d*g) + l*(c*f + d*h)], # dtype=object) ``` There are a few things to note here: - The returned array is a `numpy.ndarray` but since it has `dtype=object` it can really hold *any* python objects - We had to explicitly use `backend='object'`, since `numpy.einsum` would have otherwise been dispatched to, which can't handle `dtype=object` (though `numpy.tensordot` in fact can) - Although an optimized pairwise contraction order is used, the looping in each single contraction is **performed in python so performance will be drastically lower than for numeric dtypes!** opt_einsum-3.4.0/docs/getting_started/input_format.md000066400000000000000000000057421467526163400230760ustar00rootroot00000000000000# Input Format The `opt_einsum` package was originally designed as a drop-in replacement for the `np.einsum` function and supports all input formats that `np.einsum` supports. There are two styles of input accepted, a basic introduction to which can be found in the documentation for `numpy.einsum`. In addition to this, `opt_einsum` extends the allowed index labels to unicode or arbitrary hashable, comparable objects in order to handle large contractions with many indices. ## 'Equation' Input As with `numpy.einsum`, here you specify an equation as a string, followed by the array arguments: ```python import opt_einsum as oe eq = 'ijk,jkl->li' x, y = np.random.rand(2, 3, 4), np.random.rand(3, 4, 5) z = oe.contract(eq, x, y) z.shape #> (5, 2) ``` However, in addition to the standard alphabet, `opt_einsum` also supports unicode characters: ```python eq = "αβγ,βγδ->δα" oe.contract(eq, x, y).shape #> (5, 2) ``` This enables access to thousands of possible index labels. One way to access these programmatically is through the function [`get_symbols`](../api_reference.md#opt_einsumget_symbol): ```python oe.get_symbol(805) #> 'α' ``` which maps an `int` to a unicode characater. Note that as with `numpy.einsum` if the output is not specified with `->` it will default to the sorted order of all indices appearing once: ```python eq = "αβγ,βγδ" # "->αδ" is implicit oe.contract(eq, x, y).shape #> (2, 5) ``` ## 'Interleaved' Input The other input format is to 'interleave' the array arguments with their index labels ('subscripts') in pairs, optionally specifying the output indices as a final argument. As with `numpy.einsum`, integers are allowed as these index labels: ```python oe.contract(x, [1, 2, 3], y, [2, 3, 4], [4, 1]).shape #> (5, 2) ``` with the default output order again specified by the sorted order of indices appearing once. However, unlike `numpy.einsum`, in `opt_einsum` you can also put *anything* hashable and comparable such as `str` in the subscript list. A simple example of this syntax is: ```python x, y, z = np.ones((1, 2)), np.ones((2, 2)), np.ones((2, 1)) oe.contract(x, ('left', 'bond1'), y, ('bond1', 'bond2'), z, ('bond2', 'right'), ('left', 'right')) #> array([[4.]]) ``` The subscripts need to be hashable so that `opt_einsum` can efficiently process them, and they should also be comparable so as to allow a default sorted output. For example: ```python x = np.array([[0, 1], [2, 0]]) # original matrix oe.contract(x, (0, 1)) #> array([[0, 1], #> [2, 0]]) # the transpose oe.contract(x, (1, 0)) #> array([[0, 2], #> [1, 0]]) # original matrix, consistent behavior oe.contract(x, ('a', 'b')) #> array([[0, 1], #> [2, 0]]) # the transpose, consistent behavior >>> oe.contract(x, ('b', 'a')) #> array([[0, 2], #> [1, 0]]) # relative sequence undefined, can't determine output >>> oe.contract(x, (0, 'a')) #> TypeError: For this input type lists must contain either Ellipsis #> or hashable and comparable object (e.g. int, str) ``` opt_einsum-3.4.0/docs/getting_started/install.md000066400000000000000000000017441467526163400220330ustar00rootroot00000000000000# Install opt_einsum You can install `opt_einsum` with `conda`, with `pip`, or by installing from source. ## Conda You can update `opt_einsum` using [`conda`](https://www.anaconda.com/download/): ```bash conda install opt_einsum -c conda-forge ``` This installs `opt_einsum` and the NumPy dependency. The `opt_einsum` package is maintained on the [conda-forge channel](https://conda-forge.github.io/). ## Pip To install `opt_einsum` with `pip` there are a few options, depending on which dependencies you would like to keep up to date: * `pip install opt_einsum` ## Install from Source To install opt_einsum from source, clone the repository from [github](https://github.com/dgasmith/opt_einsum): ```bash git clone https://github.com/dgasmith/opt_einsum.git cd opt_einsum python setup.py install ``` or use `pip` locally if you want to install all dependencies as well:: ```bash pip install -e . ``` ## Test Test `opt_einsum` with `py.test`: ```bash cd opt_einsum pytest ``` opt_einsum-3.4.0/docs/getting_started/reusing_paths.md000066400000000000000000000113341467526163400232340ustar00rootroot00000000000000# Reusing Paths If you expect to use a particular contraction repeatedly, it can make things simpler and more efficient not to compute the path each time. Instead, supplying [`opt_einsum.contract_expression`](../api_reference.md#opt_einsumcontract_expression) with the contraction string and the shapes of the tensors generates a [`opt_einsum.ContractExpression`](../api_reference.md#opt_einsumcontractcontractexpression) which can then be repeatedly called with any matching set of arrays. For example: ```python my_expr = oe.contract_expression("abc,cd,dbe->ea", (2, 3, 4), (4, 5), (5, 3, 6)) print(my_expr) #> ea')> #> 1. 'dbe,cd->bce' [GEMM] #> 2. 'bce,abc->ea' [GEMM] ``` The `ContractExpression` can be called with 3 arrays that match the original shapes without having to recompute the path: ```python x, y, z = (np.random.rand(*s) for s in [(2, 3, 4), (4, 5), (5, 3, 6)]) my_expr(x, y, z) #> array([[ 3.08331541, 4.13708916], #> [ 2.92793729, 4.57945185], #> [ 3.55679457, 5.56304115], #> [ 2.6208398 , 4.39024187], #> [ 3.66736543, 5.41450334], #> [ 3.67772272, 5.46727192]]) ``` Note that few checks are performed when calling the expression, and while it will work for a set of arrays with the same ranks as the original shapes but differing sizes, it might no longer be optimal. ## Specifying Constants Often one generates contraction expressions where some of the tensor arguments will remain *constant* across many calls. [`opt_einsum.contract_expression`](../api_reference.md#opt_einsumcontract_expression) allows you to specify the indices of these constant arguments, allowing `opt_einsum` to build and then reuse as many constant contractions as possible. Take for example the equation: ```python eq = "ij,jk,kl,lm,mn->ni" ``` where we know that *only* the first and last tensors will vary between calls. We can specify this by marking the middle three as constant - we then need to supply the actual arrays rather than just the shapes to [`opt_einsum.contract_expression`](../api_reference.md#opt_einsumcontract_expression): ```python # A B C D E shapes = [(9, 5), (5, 5), (5, 5), (5, 5), (5, 8)] # mark the middle three arrays as constant constants = [1, 2, 3] # generate the constant arrays B, C, D = [np.random.randn(*shapes[i]) for i in constants] # supplied ops are now mix of shapes and arrays ops = (9, 5), B, C, D, (5, 8) expr = oe.contract_expression(eq, *ops, constants=constants) expr #> ni', constants=[1, 2, 3])> ``` The expression now only takes the remaining two arrays as arguments (the tensors with `'ij'` and `'mn'` indices), and will store as many reusable constant contractions as possible. .. code:: python ```python A1, E1 = np.random.rand(*shapes[0]), np.random.rand(*shapes[-1]) out1 = expr(A1, E1) out1.shap #> (8, 9) A2, E2 = np.random.rand(*shapes[0]), np.random.rand(*shapes[-1]) out2 = expr(A2, E2) out2.shape #> (8, 9) np.allclose(out1, out2) #> False print(expr) #> ni', constants=[1, 2, 3])> #> 1. 'jm,mn->jn' [GEMM] #> 2. 'jn,ij->ni' [GEMM] ``` Where we can see that the expression now only has to perform two contractions to compute the output. !!! note The constant part of an expression is lazily generated upon the first call (specific to each backend), though it can also be explicitly built by calling [`opt_einsum.contract.ContractExpression.evaluate_constants`](../api_reference.md#opt_einsumcontractcontractexpression). We can confirm the advantage of using expressions and constants by timing the following scenarios, first setting `A = np.random.rand(*shapes[0])` and `E = np.random.rand(*shapes[-1])`. ### Contract from scratch ```python %timeit oe.contract(eq, A, B, C, D, E) #> 239 µs ± 5.06 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) ``` ### Contraction with an expression but no constants ```python expr_no_consts = oe.contract_expression(eq, *shapes) %timeit expr_no_consts(A, B, C, D, E) #> 76.7 µs ± 2.47 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) ``` ### Contraction with an expression and constants marked ```python %timeit expr(A, E) #> 40.8 µs ± 1.22 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) ``` Although this gives us a rough idea, of course the efficiency savings are hugely dependent on the size of the contraction and number of possible constant contractions. We also note that even if there are *no* constant contractions to perform, it can be very advantageous to specify constant tensors for particular backends. For instance, if a GPU backend is used, the constant tensors will be kept on the device rather than being transferred each time. opt_einsum-3.4.0/docs/getting_started/sharing_intermediates.md000066400000000000000000000033071467526163400247320ustar00rootroot00000000000000# Sharing Intermediates If you want to compute multiple similar contractions with common terms, you can embed them in a [`opt_einsum.shared_intermediates`](../api_reference.md#opt_einsumshared_intermediates) context. Computations of subexpressions in this context will be memoized, and will be garbage collected when the contexts exits. For example, suppose we want to compute marginals at each point in a factor chain: ```python inputs = 'ab,bc,cd,de,ef' factors = [np.random.rand(1000, 1000) for _ in range(5)] %%timeit marginals = {output: contract('{}->{}'.format(inputs, output), *factors) for output in 'abcdef'} #> 1 loop, best of 3: 5.82 s per loop ``` To share this computation, we can perform all contractions in a shared context: ```python %%timeit with shared_intermediates(): marginals = {output: contract('{}->{}'.format(inputs, output), *factors) for output in 'abcdef'} #> 1 loop, best of 3: 1.55 s per loop ``` If it is difficult to fit your code into a context, you can instead save the sharing cache for later reuse. ```python with shared_intermediates() as cache: # create a cache pass marginals = {} for output in 'abcdef': with shared_intermediates(cache): # reuse a common cache marginals[output] = contract('{}->{}'.format(inputs, output), *factors) del cache # garbage collect intermediates ``` Note that sharing contexts can be nested, so it is safe to to use [`opt_einsum.shared_intermediates`](../api_reference.md#opt_einsumshared_intermediates) in library code without leaking intermediates into user caches. !!! note By default a cache is thread safe, to share intermediates between threads explicitly pass the same cache to each thread. opt_einsum-3.4.0/docs/img/000077500000000000000000000000001467526163400154225ustar00rootroot00000000000000opt_einsum-3.4.0/docs/img/ex_dask_reuse_graph.png000066400000000000000000003042611467526163400221400ustar00rootroot00000000000000PNG  IHDR%bKGD IDATxy\T.\nhj {{˥r75vy7rEqɒ(;=y== 3=}9fY%*\DةP^%%%i۶mc/MGpBCCMG_tM52bpq 2-ql6!!!|H@ c\eN@ 8&ʜ9;Qv\D؉r `'5Nk(;Qv\D؉r `'5p`NRXXNj: 8PP(|G?~ԣGǫK.;vl#66V'OV``W=zᅲ$ZJ~~~/'jȑZpaexC.}l6[YEWlfΜ^{Mаa→iӦ\rWӦM|}%+9xZh!IJHHP͋{뭷_T͚5:(99Y/BeCk.?rC%O>QÆ 5jhɒ%T*<<<.,geffɓjڴz-Mỏuɓ~Xo^JJJR:u]E,s]chJJ>3KWNrxyyɓEnjL͞=[)))U^^5U^x%''kʕT$iΝjӦeJjmuӧ믿j>}233VZz=ٳ \k5Є=3/z\nn$)..Nj֬5P(۹s4{l=ZϷ/_`;[9sFRժU=P*TPLLE3;;[ժUS||T7xCYYY-I9s$رcʵǏKwn+q1J* c}}}բE /v&P2X СCK@OO?]W^)ھw^*++K^h֬Y}ރQFRJ-Z?dլYSaUTI=]ٲ,ؗ$ɲ,5 f@ :Ȑ$mɹ钤|UXQǏWZZÕTIA]u}=3ܹsVuѢE4i5kɓ'+))IzRLLvءŋ_ǧ5lذ^^^zW5g=STzz>SM8񂫈pmP%d0a$Ú-_\/N:Zj};0l޼y;vƏѣGkĉ>|^ypC@g,2ʣPa|8ͦ1s `'5Nk(;Qv\D؉r `'5Nk(;Qv\D؉r \eY#b St(BCCMG.eiڵ߿(e#3j* 0@6tP,> UPP l2 Q``80%ʲ,=z$)22x8L%)I=z,%E@ɣ\' HRWch~~4<\'n:J-ZsN#//O!!!TN#5pb ,$)##C֭3ǚ5k&Irwwg0(5pR999Zl$Innn?T8ϟ_E^^,Y,é@yCNoUvvv|-[LScԊ+>bʕSr ԼyVl[^^;CqXBŶi޼yr PZZ֬Ysl6 q(z HkTXXx[NgΜ1 ٳg~TXXKH+5pBWdɒ2J'44Te]~f?\'s m޼Y߲,͝;SdVPPM6رce WkdBBBT¥Bm۶MIIIe ñcǴm۶.?M/.T<\'|YkY2Jc…]*qaf*(9ǏWJJ4hP-??_999,۷o/xPm߾] 6,-##C+WVŊ))):~uDPج+}4ph L l6(00tP,`'5Nk(;Qv\D؉r `'5Nk(;Qv\D؉r `'5Nk(;Qv\D؉r `'5Nk(;Qv\Tt@֑#GTeddh˖-0yzzS7p֭ pj( t1%''+33SȐ$mٲET͚5&MJ*SleYCMaa٣۷+&&F񊏏ב#GabŊTjjᡖ-[G޺uwaÆeR$mڴI?*77Y222_lfS&M-jJ]tQU Dpak bbbHmڴIgϞUZԪUr[M6UUfMp (zNWTܹsջwoծ]+wiEDD(22R_!__ߢG-ZPݺufVV9rss]iii:tP366V)))Uz)G_9(ekPhŚ;wn*OOOuE{V޽աChmݺURAA5d=#,0rssn:kŊ*((PP??_^)))jݺ\/(,K}jڵT`` nݺ9Ҵb ͝;W6lP͚55p@ )p-bcc5sL-ZHiiiի ￿LVPP[jܹZx233շo_=3{d, (5kP^(44T߯߯ʕ+$͟?__~<~X&L-b:H~GM:UK.U˖-5l0 4\G2;;[+V7|kתm۶zWpla% _UV2dڶm}iժU *Ś$5jHƍSLL-ZxuAw~Ghs=رhرX*UhZzݫoYVV4w .F?O#GTϞ=M6]R #ht)uI/~wgg߮\R?QgmV ,PLLwÇ{ڻwh_~wԩ*Vݻw>S-LGj6Mw}o߮/R!!!e2VZ)$$D|nݪ8yZl/Bђ[oUO? 'ׂr XddZn ?WTTڶmk:l6X=z'u]wԩSpB'OT>}裏SO9TWڵӖ-[駟jҥjݺ6md:JkPF oO>֭bccO8yyyS88P֯_СCھ}f͚5kU"l6X~իLBP@8u.;6mTV-ӱJE.]gqի&Mӱ8B{ׯv;wSNcڵkkҥ={L޽{c˰YJտURE!!![MG*3}^yu]Z`A)Ǒ kڴi=zHe&::ZAAA:w֬Y֭[.Fh۶m{Զm[Xi/][{Uvb ըQt$"55U{8^]v5̝={VwKsa, R~{ZfKk-[(11Q~~~:zH'﯄EFFl奈wZrH/(,]Twul2URt$Zn͛7+??_={ԱcLGP;vL~~~?kt$<<ϟݻwYfj(zO'NЎ;a:ڵktO?TÆ 3@4zhر^^uI7֪ULpAWhh5sLtmgرcuiqM0A/u\>YFK.55CzzZj?7)UV{5gq#FhʕU5Lq ?"##u.@a7TNN}]QF>Ν;MPo߮J3f̠X+A|2224eQp)\kt15kLӧOѣMq*egϞR֮]k:RҫW/*22t3sL?^_8f6mjժʼnKf믿u1{ pR?6lؠ_8zJ^^^MGe0s 3gtM7魷K/d:Sݺu|rQ{WOMGqZ||M>|Xu1g5#FƍoV?(J޽{rJ릣8ѣGJ*5k(5J={^z%V^iӆeMծ]; 0tv 7׬Yk:Nr w}T=䓦8=ͦÇkɒ%2@ ҥK5rHl6qÕUVӣ\4w\W 64%p10] @\ˈ4iR裏4~xGW.]4vGll&O@U|||teggdff*))?` MÃ)(%kpT-Vj9s&L~[˖-Sݺu→iӦ\rWӦM}%B%$$$$$Ȳ,lٲzennnj֬3(%Y.#%%Eu)}|'jذTF -YDpߗEƾJٳg 'p-RRR$Iu-}0^ڵk3PJjժ>~7lR݇;3HOO7ȐRGCNjC(%kpY\RFRff"; IDATN8QFiԨQJOOWXXx S駟Vƍ'xBuQ۶m]y?^CU=O?]2CaaZji3fƌM;w$׈#ԩS'G/IV*777t8tUXTL2^իSPZ,%9rdC[lۑ#GmOJJ<==-Iomּy,IVΝײeKyeYV^^UfMM6_oM45kXqm9ro߾Vz};.F֧~Zjj֬Y` :#FSj e\Fff<==|7.vaÆjذ$i„ jҤ ziϞ=E7j(M2E']}iܸqT >\m۶ɓ%I;vg}&___l6l6[N'OTTT`Ix222Cz~.(Y\.]Ν3C.zN!///~Z]v+R}޽UVV{bѬYyyyp0ժUSvvMG*:JRZZPPJX QZ5>|ԞٳtޟsWŊuq)<<\JMM9~4hڵk_\3lI/4jԨ/C,ooo۷:`,2ʫ?zwu Q\Zddtqf^ѣjԨ6mڤ=z֭7xC?(80ι㣓'O- Q`4hjժ)>>tӧOt\ ͊fS˖-g:K;SP:(2n&U\C8(caqqqR7nl: Nr .B jѢ8`:K\bbbLpi111jٲ*TtE[l1e=zTڵ(ХK];v(m={ON\ciÆ ڳgׯo: S``ϟ{te,44TŋCpN<:{ 5WIJP^رnFt$;j5k8 yh5ktQXX+11Qќ3($ܹSݻw믿'rrr'˲m6ηluEڼy3W J&Mһᆱm۶[o5W9$tIӦMo BAA}Q:tH!!!kRBCCAtroܹ;0@9ҵkW-ZH=ׯI&TܹS>o5(Q6Ms̑>رtrwє)S駟rU@ujٚg:1}ݧzH˖-S*ULGBM}^|E1BSNuNҀrJ^ZAAA#p >[}uiӑTaaz- :Tcƌ7|#wwwӱ_,W;f̘W^yEzܹsUn]ӑJƍ5h yxxhҥj߾HTtt@ ,p:uJC ƍ5}t @5(/mۦxuA7o6X3fo߾ԩ)\;j޽ڵ5i$Uj6mڤ:(66V7nX\2rmi׮]ԩ4vXeddU~gSƍӴiӴ|ryyy ԨQC!!!;wފ5D_V^ԥKBokPtR͚5KZn%Ku2224vXuAھ}yӱ8ͦ1ch۶mu-W_UVVh-44TZ_9shɒ%YX*P@lz^zGр~ѮYaa-Z֭[?׌3?Cpb;vԎ;4}t͙3G[VhhC.駟Էo_ 8PS\\Fa:k`HݺuW_)**J'NPvj׮]]Q~~ΝoY *Z5j(UM>bccճgO=j۶o:ܹSrss3 o;Ԅ ԧO#y@ \r*&&F7o~7uQsԹsgyxxھ 6h:u4drmٳg`m۶M<y睥277Wa}ڽ{4iRao95( qF-\P:|V*???C[Zhq-&&3RRR8ٳG6lO?$777vm0`f͚RyiժUeYj۶վ}{[^^^}\/ׁ[*++KM6U޽cGDСCڰa"##uV9rDrssӍ7ިoQkז<==eٴj*=:{2223g(..NO$U\Y[VϞ==zz_-4mڴI6lPTT8I\hۻ奰0u] +%%E~WB խ[7( 5pt999/:rHQC)))IڵSݺujժK-Z|||ԤIfUp9_fC^jղG_l[``ƌ]۞ʕ+e<P,˲LPc@Q@ƲPNk(;Qv\D؉r `'5Nk(;Qv\D؉r `'5Nk(;Qv\D؉r `'5Nk(;Qv\D؉r Ͳ,tm߾} 6i%''+&&F=z0ũ}#+#8(jJu5i 2Dڵ3{Q0.44TAAALGٳg $ͦ͛tڵK!!! 4{U4۹s5;_M:rfuk(;Qv\D؉r `'5Nk(;Qv\D؉r b|XCUTTT<_ffNjY{=7N}տ/>|wqUߗEsAr-~Z%VKbSce3jVژ5&H Ը4`[|4+pz>so @h(,Y;wGɶbǎС c])))={\\\d$IIII:ujm րԱcGM6_6oެ([իWWӦM/+CԷo_3Fܹݛm̌34h nvٰaF (&&F]t]wݥ]|Y} Oݻw׾} ~^j:}t fΜ)ͦ-[ĉ K.ՠAdCgVtttJ+j(5fѣѣ:t蠭[j\y, 1-Gl$U˗I~?6f׮]FҥKr}ݦQFcҌi֬ӧWWWg1fҤIF5jT\rlٲTXH2&M2k֬1C 1_4L͚5ŋAɶ7[7'3&99ٔ+WĘ˗/.sҤI~#_I2!!!O ^_C̈́ d\΍#5Ԙ(aB9`9G7y^dMf233;}">>>7Ӷr֭{Ø5j4KSc~?lԨqww?ޫW/b^j1f߾}FСC4iH2m۶m3rlٲ|}}{uҷo_W_c4uu6bbb$c94P9A /4L6mn:\z|RӪ]vcf͚?1b4c yxxҺ9=Kٶ5mq9rRRR+>>^W\QZZ}Lݵd-_\umIuV1YUV;mjr IDAT P]+?slus~q:?[jԩJIIQ||6m޽{kĉOOOIҙ3g u^RCsC ѫ\ 5PV\P**###1O=Zn\R={\"""rܾ}v_aÆB zyf:tHǏo]19SttRSSUbleff%_slY7ץKᡨ(UPAcǎUjj>^ZÇ7ͦÇ^zPΝ;{ … Zj@I@ &&&F111 s\NR?O%''r9O4rHyzzO>z饗Tn]IDDDl2]rErJu]W^$csf]s/_3/j:w$I?ԩ9shҥj޼UJqjذ\]]%I'N阬L)))T$'TÆ 5~xoz衇Y-7ۇF)66V'Oԝwޙus&Mؿ>|^tInz6Δ)SS~l?^ԩS<J;j(5TƏ8˗/ƌPr`=oذH2Vu{C?<7G5eڷoo*UdLTT5 2 ,0'O4dʗ/o֬YcV\iÇ83}tcٌ$G{̙jժ]v&<2wq΀b֭{cf2ȑ#7͖4@IJ 5Ƙ9sVZJ*,Y$9 JP19,gϞ֧~ZDɊߜ9sty=Zgr(,,LΜ91E3ómիjժ*s9 fSHHPC**9YeJ9sWcƌQ͚5s&O1c(..ξESNTn|)AjjO:m۶)**7541E3pol%X5xb9RVǹe6m$}vܩ1ch޼yS;hM8Q͚5oՄ fyxxX(>Pj#܈BXV/;z-Zd ￯˗+&&FmڴQݺu=_cr}g)S( B. EIp+QCVkeRo!59Ҍ/J(xJ\ 8 kh8 kh8 khe@jjԢY=N)##C?tbutA#yiVpJ֭Ӄ>(WWWyyym۶Z~QRBB=LprQh۶PƵmV:ԯ/8Nm۶:c!EO>Zx-Zz8P,ZH}U>}pBg!0KJJҲe$~`eٴtR%%%Y@4JKK$-_\'ŋeQZZ[ @4͛7O6M -Nŋ.Il rDs vZeddطYJ (222f={TN*444Z~Μ9cQ"(=Ξ= 6dfŋ-LJ"kंtBthrqrff-JJ* PArss9͓[iܹŜd\ N&22RM6sLƍuСbJ<{)DPp6}saݻ@gϞ6RL@IGs ܹsvq\ 7Z`MǤo-0TfR)66V۷WNҐ!Ct}{ڷo}?;TBB{9qj޼y5sWIx|M[5jzQF)!!AڰaF (&&F]t]wݥ]tIF_{zov^߹)i=1c_;w޽{1c vm1yyG~^{373gΔfS˖-u {KjРAlڟCgVttt5J -5ѣѣ:t蠭[jlsQC(cS<3f\x{{///7gϞ5ӨQ#s}v[ff9|dVj/_n8`$뛏?$&&]vIK.-d/H~~~f͚ŋ~3+W6̄ ͼy$Ӿ}kRR6goooӰaCsYeSbE#L4ɬY 2$&&ۛ_|#G777f'$$߹)wm5jd1&--xzzf͚>}quu5qqqc&Md$QFk̕+Wr}|wCAߛIOO7/_6 0/_6ɦ\r&&&\|sҤIz$%EHH ?7C fh&L`_}׹ΝGk#JPk@)/g7y^dMf233;}pӶY[ cjԨq,ͷm6#)˖-3ӤI֬Y)_Mw1LlllI7ȶF||}̌3$< %u:u?1Fwwwz2...իcg$:hLNC~#f{3/}5_}1ƘHSN\js-&&H2=XWkPjhjh鯡_IM67zPkP&rY(N>jժ9f֬YЈ#Ԯ];%''^^^w4m9پ}5k&c z)I.RZ5]runyswYe˖lk\=]j$~ٞs$n#GO$5SyfG -Ђ[5E^^^O -j( /8ڵk7N 6Ԋ+4|wߕ_$^*I2(11hCwt>>>JMMɓЌ3=onuC_㳜??{OG30ߛVzTBE .\$ժUp6쨡Eq(&&F}s\N< #xf3IIIXp1WZ~޽{I32~2̊+LFFt钑d4ib3׮[~}#ddd4wƍMJ̉'1\|4lH2? 6#'kke&fkjji֬W^{1t5cvmnVXaRSSͺuL*U$s|~$nUV56ͬZ5jIf۶mɓfQFo1+V0[l1QQQ&==>G~:=o7sh"g3Wqljjd3W65kּիWs^c|zlo}oeĉW^]Z5}ø03tP#ɸ>޽;9[ ͚5˸#G4۵rsJ :gӪU+SR%3`ϛ%K9gQPkP&ڌ1&s$Y0,\@ٳ駟E, ̙kђ~\(&&Faaazu̙|)ATTm{^TV-}Wf)$$D+̘.44TWA®(U3g|}}5f͟6yd3Fqqqm...W:uꤺukLQ RSS5}t}ٶo۶MQQQ78nD EI@ -P@ըQC/ȑ#juQ6m$}vܩ1ch޼yS;hM8Q͚5oՄ fyxxXt$j(Q\ zYѣGh"@q￯˗+&&FmڴQݺu=_cr}g)S( ²~Yhj(D FaP. 2a!53V7(rY( kh8 kh8 kh8 VGR fug=(e&???+WTnnu2{Q-(b4׀Rq:v֯_ou2:v (mKm۶233~8W*UԸqccc(:zҥKXJ` 8PO<,YbuP,pb.\Њ+ddu(ueٴb ]p8Nl̔1FWV\\ՑԈիeQffY @4]ڢE,JOhhb `#kbcci&eddH000TPzٛkڸqN:eq*P\'`l[~0111ںu233\]]pB S8@YkYܴ`@,WWl2224w\fu8#G%fYfڳgEth޼C(}%B\'wݻW ڷo_5wwwX T4 )---Z̉?s|,--Ms)D$Pp2wV֭?AǏ/DP4lPGsݻղebJJ0. gYN8;vS"(=o~ƚϟ_L@IGs 1FSFFs'CA'*UC322=@sݮӧg;wgϞٶWR8@PJ :4۶˗M6]vOa({8Pߟ3,A6M ‚ IDAT!!!ׯQ@=G\Ds p5A4\Ds p5A4\Ds p5A4\Ds p5A4\Ds p5A4\Ds p5A4\Ds p5A4\Ds p#))IQQQUJJ]vS&MRJTreyxxSW ʶtEGGJHHPRR"OOO-YD'OVʕ+VZjҤ*Wlu|`!1XP0ڰa~WEEE:uq&OOOyxxRJXd%''ǺQF񑷷ڵk.]obȝ?^ׯEGG+-->&~VTIJMMτ]+tz&Me˖zcŮⷐ'NЪU0ƪJ*jݺ-5iDuUŊo:g||=(EFF:x+c7o][nz衇5'D)))Zv֭[0ݻW...j޼v6iDjРn:gjjN:eYصkTvmuM]vbS`kPR]tI˖-W_}kתB zԱcGuI;wVr }dk͚5ZfvڥנAcյ”-[(((HWRR6l~ZjnFFvޭ5khӦMڸqu_<<<< }]`kPlܸQ_~{cO_~~~ELg*$$Dڱc?hРA P:u=~ӬY'O]v4hի{WjŊ Բe޽{륗^RN=(t4Xb&LM6տyzzZ R``s7T ;r&Oszم s*<<\;wo=zX 8n ,3׽ޫG}Tڴil٢/%&Is&Mh}gZzH("""4p@hݺu9s5qXjժ饗^֭[qFUXQ<>V9tyGu?Q;v:M/_^CաCw_~Q5b%%%Y@_Zݻ7(22RC ޽[M6U>}ԥK߿hh@1: l޼Ν;͛7kҥV`...۷ݫoF}|||hu4Nlҥjڴ>3}G_/777X˖-Y.]R֭5b%''[ 5(FWN:U;vPu\\\{zԳgO>}hHLL}Q=z#F8'iF[lԩSf͚iڵV@s Azz}]=#z8WQ[mܸQRV88P(VZ֭[ѣڴiqV*T6l"##ծ];iܸqȰ:ȃs@ t=裚2eNFV*R:u/nݺ{1bҬ￯G}Tڶmxc5k*44Ts'|zH111Vc!Y_^BCCբE #/B#GTxbyyyY @)qyOҎ;giȐ!VG*vwVEH EdzGjǎe&I/nݪhɓVGP 8q^3mV&kԪU+رC;v~#\"駟 /U\Hjժ:hϞ=VGP8p@:u~'5oH… sϩO>/As 7=z4sLGծ][aaajРup#(l"___կ__6mRzT"j֬Yzw/k„ VG=}zw4sLKV).]~駟~ժU+#(!vڥ.]K.Z`*T`ui֬Y6l&M7x8u i@! 5uTV)Ѯ^^ziΝڴibGQNt=T孎T}6lfϞ^x8e40,]Tӟo>:N]… ڼyjժeu$9w:u*U(,,ߧ2yMvmVqZ6mRΝxb8 Ihh~i:Ӻt钚5k:(8888;k_?ڷoe˖gϞVqz Ҷm}'&MsΚ3gq޿oԎ;tZgFs 'ӧm6 GO[-7o{9EFFqV)>ŋ3q5o\?x  Я{ŅJ+cZh֭[+008eƿ/G{Qfͬ1`ٳG{SzeucfVdu5hy{{k޼y\h޽{ںuQ8}W'Z Xg/&[ժUK}:Jꫯ*<<\: ٳG?^}UIS5w\h@1 JtY 4мy_:udu2M<+ k 6(::Z>Q,ͦ(((HVPm6qʬAѣڲeQpJ4 AAAjӦ7onu2m:u֯_ouj*jVG)Zj-Zk4-ZH :Jww]v﬎,Xx@VG)P[Cs rm6]xQ?Q ի֮]K -!z .hΝVG\\;TƍIݺuɓ'uȇH:uJݺu: $s=S֭[gu5EXX%HUre R",,LjӦQ_]tQXX1p:4 /_VxxvjuWrԩS' R",,L;wQ_ݺuӦMtTh@o߮K.K.VG5v'ƍ%Lnݔ;vXBs r~yzzꮻ: ѢE *>>(3gΨe˖VG54h*UVG\\G-tkҤ|;t54ǎSZZZ@YAs seddf͚VG)2~UVMƍS^R sWF ?HpkΝ;G -⮡JHH(u(Khu$I') 8PUhhB5ѣ mΜTR(T\54uPxhu8*W\dkرC:tаa4vX+%%Egϖl6=ԩSmKMMUpp ;*<<\mڴQyfEEEwު^6m_~%K,Ν;#~CgVtttϝÃBKNN:8jh*U$I/^,5(khu%k>:3fhzꩧ_|Q 6km[ ԡC͟?_W||uq 8PK,ܹszjEFF_϶vHHl6ڶm[u+==]>w \:3(|4:qY >L{$)\fQFڵkSӦMUn];vLTVZFڽ{wnݪUͭ+K?Sϝ3׀kP\\dddH\\DΚ5K1bڵk[>^^^7ܴӪV-OOOIҙ3gd~OzLPW "[\'+ТSOiѣv!___͝;ֻVQ6iTF逳\25UC{ :kpp%3ƍSÆ b ͟?_iiizw%ի~dB[v7%n~TKjժu 󖔔A!PP9'b`kp8sO>GUVUݺu%I>>>:|M+WHV\L]|YYnȝ5.33ӾTRR 7qDU^]Ǐ/,ϟ$uԩ@ߏ5+3ר@H@᡹)=ꡇɓsW ,$M>^3f̰o2e$I2h֭2UXQUTvn˲yf_~ŋ4׀\:3(|6sJIIQʕd=V)={>BW^UBZYK.-5ܚ={;(\CwJIIQ lʐשTjժÇ[̙3G?c~"ݶm)Sڜ9Rƍt QF:t1LiR:uhPh@|||tAc5jh9rRSSoyXM0Ak֬)KԤI"]iҤ 5Ynzmu 5E׮]5e9sF5kִ:NV\9͘1C+fM.. eff|[^!n:k%@ll"##:B rssիR+WNʕSΝUvm)--MW\ѕ+Wkcf{W16WWWjʕVG+V|رQp:4 ޝ՘VEoc,26F 0d4>}FFc Š:**}ڴ]?|5Ҧu꼞Gytu:s޽62B=i&Q4ޣG#GҥK@WW={,D 777ٳ?Emܸ| eG!""*sX\#"àAo>ܽ{Wv+Vƍm6AOO/禧J*xꕊk}n*;F{.:AɎBDDT&FD^zr E-GDž;Ξ= kkkk1007V WWW,_qqqMʗ/O?hIv""25"< ׯEc]xv\ԯ_GEсN:رc, bq:v *`ݲh ,wۧ`ܸqXr%ox#TZ5}ݻ Cbb"899B ;i_~'ND\\jժ%;F֭222pQ*׈ bϞ=prrBtt4d&L?```P煆? Dll,]mDg޼y;w.Qreq4B^;vLv""5" N:-ZȎSM6 +V@||ZjsuuEfd$R[/^ ƌ___qʼ'O۷oGϞ=e!""*X\#"*lm8p Heaaa~ƍ'W=ž={֣GɎIVϟ3g011BCBDDWDDD%5"ˆ-֯_ʎSf >>'O8bWQUVhҤ o.;Nn:|嗈F֭e!""*X\#"*,ooot*U$;N}bH=zC!$$!!!j#zÇaoo;vUv2ٳg077G~lGLF IDAT';&`q^pqwwǯ*;Nf͚6lXզ;;;eRvL"sPv2嫯Ž;p%ˎCDD X\#"*M6 prr}`͚5!!!ի);`q8q 4[nQwcWiݻwׯ8۷ѦMՋK"""bqacc+åb}uuy믿ƼydǑ&!!fjj GGGvQ4n8\hڴ8Vff&푘ǏR["""bq};w6663fFGRRlmmQR%:t:::#]m ADDڨ@H/_^vRiXb?;kDD+Ve)U222ꊓ'O"&&ՓImֽ{wTXQvLB5lll}vv 6`РAi"׈Ì30k,lٲnnn B|?qva"##[[[Jht={D@@dG*v؁}bƌ:u8DDD5"+V`׮]pppG7K,AHHw.;NfWۮ]SvQ~8;;/Ē%KdQ{ ,[Lv"""MQqB~={m۶#3gbƌؼy3<==e)SF͛1h モGmEFF ݻwG`` ;bq8z nnn8p$;ZΆ/_˗/˭ݺucW+VG?ڵ ڵ+/;cqeee᫯rJ 2Dv$?H]mTZcpvvƦMP\9ّB@@c͚5z`q$!0i$,X?#Ə/;T۷/bcc}vˎD?~ <<;wăFjF>}жm[˗[X*###,^SLI0{l( ш_,Ea„ ӧ֬YcccّT.::xvڅVZɎDɓ'jkӦ ?ГJ)))3fȎrqqqhݺ5^|cƌr "DD%-["**Jv$Zj`jjXԘ,--1qD?x!6oތ͛cŰB:u兠 <\vd*8s RSSwX8::"55ٸp="""5Q lj'иqcٲc|ZjɎEPZ5cʕ{.bbb7ƍׯU;;;̟?UwutC˗/ѣGL:ƍ3f`ĉHNNFjՐ---dgg Vu興 / %"R---L:ΝCJ`cc///<~XvbqIa8p Ο?ZfW۝;wc0`ڨHN> kkkCZZ222:::pqqo'˗1zhx{{Ǐ$&&ڵ!N<ɓ'CKK FFFѣttt077׈nh"""u5i{o>4o .DRRhEr|.N< ???ɎF*Zmaaar6???XYYv\)55ӧO%Ν;P]k h+W1k׮Ɉޒ`4n۶mÆ pA4o_̚5 qqqɓaaaQ[bb"~/HOOȑ#1eʔw^RU"--";;Ǐ̙3W񉈈FD۷oW^2_hܸ1֭[mwt"""kDD jԨGUVBm3::زe }zq'""FD.,X &R)@PPЮ];t]t-K,KBB82~:1p@ 8 4(}fz-44cW[cbBBѳg"'>>7nD@@\ƍ+Ν;ZjE+DEEaؿ?"##addwwwxyy}E*jժHIIy6:::077Ν;ajj> kDD CѬY3~ ={p۷4isss|ᇨ\r+[pe\r.\ѣGqYhkk ]tA^`ccS7Qnv!dggٴi\[P?~\,H8vv؁#66YYY裏о}{4m~!4iӧOq\t /_FLL =Tsprr'|rʽ2h lݺ5KC 5kEDDDl!!!ӧOˣݻڵk}\\ܹs|rի^z022B PBCWWx%/_HMMTV 氶F.]ЩS'Bn]m5j@Vʝ>}xyb.>3[ :tqe<~k5jH9ϑCoݺM4A-йsgt&&&Ş׮]pqqKAg̘iӦ>(O,t!t V>Vnle˗q=|Rŋx QbE+ offfʮ,MΟ?Pv!!!ݻ7ZjSNكݻ$Ǔ'Op\xqqqxRRR+*O###|9Tqc TV /^bŊHOOG>}~@DDD9FD$˙3g`gg]kʕSvQޞ>}صk޽5jSNpqqAϞ=զ]kkkb?X"+9z6lfkk?gΜ,Y#G HDDYX\#"h۶-Zkf͚xdDJToBDDDl @j*)Wxx87`̜9?;;;)4kDDv=Ç.Hmnn/JHFTZ蛀PhyU$''UVҩLzoBo߾Dll,ԩ#)!FaqH?ʕ+GQq2]ma7nvޭ54Ibb"QF |}}1i$)5vѣGcÆ Beڵ+߿h5JkDDؠjժU6o !l21Bv<" o8p lq4Çaii6m`ǎ,?׈d@v!!!WƯ ???ˎHDfWÇ?Ҝ9sڵ7~Gq4Vdd$1}tL2Ev""5""뇫W"666HMMEŊ%%#JNN*UȎ2Ϟ=5ׯ}AGGGv$d|7 8DDDe kDDv=`ڵ4h8DTBnܸj\W[vv6\]]qYĠF#/;wDtt4d!""*+X\#"RiӦaոy&ʕ+';]mn߾jժsppp@Ϟ=QV-11w\8p۷T!++ 044,`qH^z ૯8D$IYj۷ol2 >\vxXYY ,Һu0b>@Yj{]qvv8aaaprrҥKywj""*Y[[ܜDNjD֭վ%وH___̙3?׈Tȑ#ر#;qȯkז-SSSq(ٳ'N8XwDDDT FD*s"##eG!RJ]ږ,YovB=T*gϞǾ}#;Qi*ܽ{X~=  ;ɈDHHoߎ[nIj=O)Sx9sڵ7~GqJ#׈Taذa㡧';Aov9rʮ6{gÇaii6m`ǎP(:>͛1p@lٲ6,TԫWcƌ/;iDDDjZ*tRl]mڵ+߿hSzaذaмysqJ׈Jښ5k퍛7oVZ*6]QQQ(*ڵ+>|ǏXJDDTp,VZe˖ذa(DD9v؁7ojsqqA:u#00}驢T|Gv"|ֱcGF8x tuueGxb7wFe!""Rw,[naÆظq#/"R]m^F޽{SN,Q9BCCSSSqkDD%e„ شiᓈJC޽]ڨHMME!@DD dG"""RWAZE)))0j(ֈ ܹs/ ((~:̙T3|7oI&!<<c{000m#FȎCDDعFDTV\ ܼy5k֔n޼ +++t7nu7j۹s'QJtO89P +Wİad!""RG,$ldG!"*4!33044,r[Yfpuuj+e;,XGᝯQqhXYYɎCDTdC 33"-<<;vKVdggΝCll,W.;:aqO>ÇeG!"*Kb̘1 SfW[xx8V <{ VVV011޽{#;`q8ݼy 6Ė-[&;QDEESN0mڴOjj*=pܹ/^D `ooWWW8;;nݺ%*ӧO?_yɎCDD.X\#"*NǏǖ-[ "*>|KKKn;v쀖n.Ϯ6i& 4[n8DDD5"⒒zoŤId!"*L888ݻFJeaW5jp14kLv"""X\#"*.˖-qmTZUv"B;v,V\Guֲ-<<rtuzzzcj t 8~8*V(;L,-Zm۶Xz(DDe6l8yʭ|ܹ3ThӦ lll B!;,,}{8uZl);Q\t 666:t(~gq -6333Օ]m%$""={6[qdaq8")) P^| [[[T\(E7BBBp…]mNNNWeƢE0a޽ݺuH׈ѤIӧ8DD&""":uȎTVpDv"""Ucq};~:e!"*~3g:ȎSV2Ѷm[חHX\#"zIII[.NfT G=oooqxmϞ=x%ڊի'V\);*FD>~WL8nBժUe!"*[nݺuæMdQ ov#66]m^za:t8DDDQQ !ЬY3t +V@СC#22#%vԩSh"9rVVVkDDE_OG}$;Q :FÆ e)?֮];O>_j!;;...8-;EvdG -[|qp!_믿pEԩS1$->|gϞ0003{cq4S(hԨT"; ;=}׮]O7e;ߏFɎBǏc֭(oܸ F011) DD&HGv"z?g.De۶mTK. (O 633,YgRk/\8Y IDAT{Zj^:{<<<0m4| ,XYYY4i޽[ Ro^/_믿#>#|hԨ%5xw][Zju)〈 kDСCXj֯_!ܹܹuJLXz\vMqu4lP/bڴiKB,ETTTch¼TgIuܾ}[|g9߻w 5j|L6^JA8p TRExfШQ#ܽ{...HHH~:֭ }}}7re|̘1000L :T׾6n܈ t5]tAJJ ֮]["c}Ghذ!OTW~Rhh(vލݻ618/qpM,\0ݺuC#c<0X\# ;wĉ'УG{{{C__ׯ98tƎ SSSܻwhРqUcҤIBǎqYFz!11FjТE *mbdDEEa055Ç憪UE?&Nɓ'cܸq޽;ƍ|iii1l0X[[Νu\t) Zl[nAP@P $$ B'Ozŋco?[իWp{Xz5nܸQ}j 6ׯN:صk[}Aq^z<Twf͚o=7==:tx/(DDNr B!222\!īWDDD044ܹsExx6lHJJ7 6B%B!ܹ#*T ٳg7o7 V&M*U(<@_8|ؼy022ѣG˗/E&Mr\#ѤIaff&߹G !/ťK?֭Yx;_L&;1j(&w2ׂEǎajj*֬YαӪU+@x<%%Eڵ+N>>ARRZZNQ{ z*= _ر# """}DGGB>@ӦMС6mP̜9M6#>}Mbʔ)9TT M67V\ υ9丬={SNUR%Ç (oT;/ժU 9up|^q^z<䜟`ƌڵ+DD5" b/::-ZM *z}ԩS޽;bbbСC@y^z79yqx nܸ x[_G'+Wŋ}:̰g"##ӦM{o q۷sss`9Eyv֭k tWo67 BJp߿zzz0`@/j*Rvp^R4`ԩS?~ swx;w`ĉ9swq@D$\JD\eСBP/_sFˋ[n){vRRRmB6m5jıc۷{| (m644Ϟ=B貱rAesss@dff*aaii)222DJJuͱh߾}HKKfff2dشi6m֭[ & !.uZfѢEbڵʅD޽~k̟~I4k,u_ϟ/7n Ѹqc1s3gpdSQ\㼤y)33SXXX(_EZyTVž? g>E.]įZd;v6m[cg"bf}~!@۷L;;QIS(駟0w|MOOǨQTO?Ty<B::l%"JHHs 1ĉl2(\נс)f͚p M,QY&vܙ ttt0e|G*JFDނr|C9ttt޺[pff&<==q58::7oFzzDD5"*Qm۶ł Y`F1e'#"R_om۶IJDD2{Arrtׯ_gƉ'?F1i$ܽ{Wbj""}z~gذaʕ+'!u?/)ҥK߿˗.ttt0vXe7%qM|WXv-H鉈4kDT/n5j@zrUGG_5$&$"R/1BX\vMB*"R.UvmΝ;Xz5._?VVVw[""*:׈D!0|G޽{B---ԨQgϖH縑tuuyi(j֬;ٳg OƑ#G`ffC~ǏUH3( "zOO<q̟?>>>ʟmݺB={Э[7I˥Kдi+W077󑘘(;"T,QZ vvvhѢN< kkkّH޼dҥKpvvƬYP~}1/^H ׈(OIIIׯFɓ'cǎ\XDDDD$Q&MΚ5 {»Faqh׮o_ """"1|||p l߾гgOɒ<~J&\m߾(Wbbb(;)---",, 'O=L:u#׈(LL4 }􁧧'= ȎEDDDDDVrJcʔ)ؾ};6lWWWQ"*sX\#"wK.E`` V\ ===ٱ^:&Nd4-- hڴ)";"Q`q~ɎDDDDDeXt 'O|ܺuKvD"Baaa!;Amڴʕ+I&?Q"҈5" c5kall,;q5kĉqulٲO>#ڴiUV!55UvD"cqHC>}8r݋'BPȎEDDDDDOO8z(bbb`aaѣG&M;wdG$"kDhƍQN:u ]t4%q-96l=zTv<"wbqHz >>>°aڵkˎEDDDDTV-ظq#n߾ ;;;XYYaժUHKK(׈4۷ѩS'[۶mtuue"""""ʕ>4k 055ŤIp]F+++xǎHDDDDDћ7obĈXf ၨ(HñFT !0|8::hڴXDDDDDERNݻXz5.]v Ȑ4kDeԓ'OӧcѢEظq#ʗ//;{ׇΜ9#G CE ǏˎHD52ĉƹspAȎDDDDDT"m6\|^^^Xd ֭,4׈111h۶HDDDDD% ͛7/ĉhٲ%LbqHKKða0x`3aaaYXDDDDD*UB >ΝÑ#GPNM4Saq vlmm]va޼yyXe>sXݐL@%\@s!7 qK,5|25G3+fVJ.h(& "0ܿ?1Qa`~pãa~3 \KKٱzѡCbpqq1c'; ׈L\xx8|}}aii#Go߾#)Jƍѣ2hdG$"h4Xp!^~e 0H촇ݻ6l5k˗#--MvD"2A˗/7| 6jժc ;wѿ,^5„ /;"׈L̑#G .x뭷dG"""""2YM6Epp0n޼ŋc޽?v !Dpo]t7bcc#;YY&MK.aϞ=R ^~e4k ̔5"ÇcҤI={6~78::ʎEDDDDdvLu֡M6 /^J߇SD7bȑѣG"77WXZZ۷DEel>NNNzΕykdlgϞBG~/>>^ >^kر&L@Æ _jՂwQq |ٳgcƌ3_߇bƌ0a͛9sh-P%=o]^+kw!{pwwǝ;w0d8;;?Ͽ>UVARuָ~sN=* 良<#͛'&M$rrrDff7o]_~~~~pwwk׮gQ^xA>,t{vv ^|EUPu4PaAAAA%v҃b q-q!ѰaCRĿi؃xX(PIEGGUǏ(!sM888xڵk "88X狸8㬋_"gSNR(9.6o,xܴ7n,8p=B';>͚5Ľ{>|X(_xxk~tnqY?nݺVuq?Pn* 6b̙ž!!!<==yt]_߆R|B+ks/u~m<%! ~BsΉ y4/BBB~(u nZ>Dv ͛7ѯ_2e5\cbbb*`=J*~n+`7jԨR/) %؇؇؇؇ szR^^x饗Lko߆cYz50m4"33vvvnQwrr*$hJ4}t⫯’%K Z}?TRrݖ9r^^^B<:]sx.-g'w/\Ž7 ?Ç/uօY2LUzusϕz kkkeDǙRW]vصk '''{_~Y,ZH>EOTV$FyҞӯ->k3*ѣG+L_zڵč7ݶ?KR}{O+kW}srr1h q({);;[XZZj:o޼B'##C})E ٝرcX|/BB(o5 'kUT)t[nn J\8؃Г̵عsXlY\_3-Xؽ{76o Zs GIqfrƌZ=!j~~~k4СCO믿b޼y,}Ҽysdggcn?{,BBBt^RW"zRqk<'DŽ7puu-t,iDΝ/=qℰb";;[߿_ԬYSW\ywY^ QϮ<ך'/ׯڵjZ_6^駟D޽_{.֭[=hNN4h6lf>Llٲs,_\4mT[7222DӦMŢE VSN /hTzP^^#G"ի$sAJs}}}}2ѣGrJ1}t1wg4>d DFF ?,>D۶mŲeī*  \"… Czw… k׮bb˖-"11QbϞ=+;"55U\RT*@|'ݻ%VbUV {{{+:$xEjjػw[ vbBQ}BCCŢE?^jU1p@$ի'Ə/RRRe=ٳgkvSֵVZGkO" @̚5K? Ž7wbٲe.Ͽm^ԩS_;::˗/… E&M8q6m(vI& R׭['F->B'5ZV^-,--EBBBk>Ii5 Ѓx|AcNJ1cƈsQF=sUsAJ{z*OSTErsC !D~2?|kF#ņ D:ut!OT?幕B6\=X؃Ȕ)g-!AJ >d,Cd؇! ܹ#<==۷XͲe._,ڴi} }T%L"N>СCYf"^%؃ =L{2|=H5!c"S>пPNl߾ӧOGvvvE-KO|1k,:ǐ'*IVVV˗/?ֺu,Yg.m؃ =L{22:!ee>TIN._\hWY8bԩCTREtI5kֈG|Cn(bΜ9ǎ+ٱ*%Z--[= {* 娈= *!(o*i5B<9lۺu+ n&""aaa:tIODD+((m6\LW mvX(Qe8\#""""""""kDDDDDDDDDzpHO5"""""""""=qFDDDDDDDD'׈8\#""""""""kDDDDDDDDDzp dG ""3qMdddȎADDTLUqߘ1c1spKRhh(>,;,--`qĬX95k֔h׮]ѣGVVVزeDD4 :!4 ?ȎEDD&",, ~%!""*ƍaejׯH8\#'CVVVXxDDDd*8ѣG?s4DDD۰aj3g >>^b""epHڿ@^^߯U(qqq FאRTprrhO fmm0I5"xºXdDDDt7n܀?rrrY+`iiBH6o kkBj||&"8\#h ݦVo̙3RRݻwݻwGjj*/h@DD#@hhhCB $&&bpFT˗/#99YYYaFNDDDJC׮]+ P׈HiܸqY[[cFNDd8\#*ETT,,UQشi^jPDDH#GġC pCB j>sDqFT/f4 |gFLDDDJ%ȑ#ѥKMpE`ӦM%qݻ4b*"Q)/ZժU1|pQ8\#ғ  %""c͚5;v,U&;kDzruupk׮a„ ՕV^ xzzʎBDDDDpF'׈*矘8q(DDDD$ kDzrqq͛7!$ȎBDDDDpF'WWW 55Uv"" 77ׯaee%;I\]]UR[lAzz:Ǝ+; I8\#"V^W^y 4$pHOիW=dG!""#;q> kDQ%-ZOv""""5rpuuaDDLzz:lقɓ'CRɎCDDDDqFT...U2=T*F-; )kDB*!=5k֔Jv"S=׈*?[n{+222QV^]UVBpFT...׈*7o"<<'N5rpuuwoW^yEv""""RBAdܹW <<||ܿǎ4h*UJsQV-4jpssCe?="qFTL=z'OĩSp)#;;`aaZj~pvvFڵaooY&,--#%%EnݺXzuh[7Zn 6*"2yS+++ԫWΊ[nň#77 x5 /)) /N:ӧOɓr劶WVZ 4@Zjժ=rrr`mmG!''yyyq))){C IDATv{uօ7Zjooom^^^Asd8\#zZzz:"""pAɓCڵѪU+j ?<<<<憆 ʪ|UHLLիWqe9sF޽ +++ ԩЫW/N""2zڽ{wԬY[ҥK"::Ѹv,,,cS+t/L\zW\ŋSN̙3A͚5/SNٳ':vp믿b׮]8th۶-:uΝ;SNڋۍ7h 66* :uB߾}1h 4o\J6"c=={,yӧDDDE]vҥKY&:w_|;w/jԨalqqqھk׮ׯGGGg#`QuE!,, qqqW>}_E޽{ػw/vڅݻwΝ;hժÇqƲ#Q%ctԩصk.\ZH|8paaaq] ӧN:{OpC9FFF"??:t( 5kʎHרrŎ;b߾}prrB~}* '??111ضmn݊۷o]v?~9s?<;ٱȈXO+)"##ocGر#9 ⣏>N>-;UR &r] <o6~mN|}} \#~5 ذaw6c̘1M66b=5S""|,^/F>}n:ԭ[Wv,hcѢEٳ'BCCQvmٱr9HOΝ;ɓ h@=zSマ={/*qѽ{0`,]_~%vXZZb޼y… Ю];￲cQ%)Zff&9s`ҥغu+d2{NNN矱xb1bd"r`=:y<`2e T*XfC8z(Zl ???YFv$xX()͛7D{#UJ1bܰsN*)Q`ذah߾=PNّ*|̟?1OO? CaLqqqxh~W^8|0233Ѿ}{8qBv$"*S`=%"֮]_~C $裏uV|W2de"3).]FӦMeG<<<wwwtѲ#XOȼ͝;ǏZvJoȐ!سg"##tّ qFw^zž={$;nݺ! Jz\DDGӧcٲe0o<ّ ~~~ѣGȎDf5Rp 8Ɩ-[`kk+;=۶m/ <<\v$"*|Xj6mڄ_]v$*BqAܿݺuí[dG"3)ݻ1d=ׯHT +++W_bMDzj:XOLSL}v :Tv$*;<F={r60Z(I?+!ƍM6a׮]x饗dG"XOM)5k>3l޼AAA㐎5j௿3qFR9r={D߾}i&XZZʎDeh0l0ݻڶm+;QzjXOLϢEh"bĈP]r~~~xUʎD5իر#ڶm~W1Q=B`` N>C瞓a=5DDcx7_c㐞Ν;.]ॗ^¶m۸?5###]tQQQڵ+j5 ;Qzj^XO/22xwˎCL<}8dq,KFh+ -- wA3`gg;w"==ÇFR`=5?DDvE 4 ’%Kdǡ ХK|wϱfqDqFF7g~8TA6l_X`8Dyb=%"RL+hҤ ~T*ّ1sԩSqaqP2_ ֮]cʎC^{ ۶mqc=%"RaÆ!""G8TX;v חLϹFƓ6m`Xj8d@Ǐ֭[q ɎCdvXO+S""e _ٳ={ ޽{Aƍ{n^tG^^9rUT (77Cdd$,--eG"2 )|h߾=fΜ ʎCv1t K.Ż+;^ЀcňŦMAŦMpq^AV.DDrW_>CqڵkcΜ98q8d"ܑ#GЩS'|嗘q]qHaU|l;wƺud!3f ?ӧOCRɎC8+S"mb*++ nnn4iɎC=רℇ… 1c(p3gD|| ^{5deeHXOI_DDYv-zFɎB&fܸq駟&; )kTn?# ZjɎB&nݺׯ~GQzJDTvػw/x Q"5*DFF䟤aÆa߾}HIIH*S*/S"駟`ccˎB&f͚۷/n*; )kT.۶m-+; (DRRy֭[1p@T^]v2QC,; IȆDz^:틟~Iv"XOXOt(ɎB&l;dG!8\#=xQQQ L܀LQ`=zJDݻw{LXѽ{wڵKv5[DDЫW/QѣGH S(DDٵkPF QPղDvԩSGv2qC6mXON`޽<)U~!##111Dݨ`߾}cIzJd'ODjj*{/Uwww4i҄pr$$$k׮ҥ Ο?Q*)Qɢ舖-[ʎBfK.$pKKKʎBfSNPTܝ*ShDD%AN`aT1:wÇѣG$&^^^̄ZlT鰞REc=%"*?_|Qv 2#;wFvv6N<); Ǐ/?.;Q!-%%ׯ_g ռysԬYpr)jJv 23kU:dDDE+[̉JN>-; Iٍ7TἽ;wȎBdd(DDE;uj׮uʎBfN$p,..AT SUd(DDE;s E;|8\2KHH3dG!3SN˲) )Q);M"-- iiiQ]znnncrssÕ+Wd 2 S2$S"g]r5̐;VRQ ;UdHDDj$%%i DQF`ﭤ8\2~:Ck׮ɎAddHDD%%%AѰAؠ~콕kTfɼ\x+V(fBRRRO:u"5*)*K5*T8;;K7lW"##pB;Z|y2;;;#55UTYXO[AMdUs뽵jbﭤ8\2QDZWbȑF߮={cƌʕ+amm]` 8YYYjժ#//OTYXO_jj*lll`gggm>{/UyqFe!ݤ$ 0>AQF7ހS۪U+4n~YB ==]T9XO*t8::}2ޛ&e$kT&*Uu?Μ9۷ocĉGdd$OwwwܼyݺuCF/"((f˜1cӧOv؁ &aÆHOO믿Zjǎnѣر#LYYY8t{=Ν;2d퍟Y |={6f̘̘1Ї999O[o>vǎ8~8Sw@@֬Y˗/Wڥ)xo׈)멡c Vޛc2x ?nm͛7B+bbbDjtR!z-)6m*7n,BV %ƍFXdvѡC<==aÆ۷opQjU@L:U\|uVmlذA3g,q.M888Z͛ׯA/ӧom)멡`K6{oϗ#P*F1JϜ;a W_}%K 77j=ѱС3WM___dffjO~jaWZj8KIGGG3'KĔ#G Bgpm3Pw1%)xo="2GzJDTX^^,--eb5kmm URQ\E~x{{sE5ʼ8q8z(v{ 6lmXW^-tuKFjj*._g >WgyB+DƍKܫ`ƌѱs ;;;@L2EDDDs gg{%L:U( Eڵŕ+W*S'OvД@ܸqC&%SSmc=%"*)00P4iDʹ9s*K[mF5>\.^]`1w\hsAڵ`Z͟?8;GժUOOOl޼3g{L8B߿D&KKKX[[Sy{*55fffVjz饗t~n"]b=e=6S",--̻^S{?~yD)Bv2* RE֭q9gȐ!xW?h_>/_ǚ5k0qDH_T{XOJƘ1cPPPW^9r$,,,f5*UVZ'V\8sA\p;fEdeeN:|#HFT?Tt;wFʹI.6רlllL`NNNnݺذa>,qy&ϟ;w>pB"SzzMDD%={9jKVV^UXzpM19swʙ>}:8 5ϟJɓ' CDD7ntwmԭ[WtTXOJzZ9rՖ[nq5QU޽[ʎBF 4ʕ+eG!:S&S"Dpp0&M$;psst\k޼9e #͛ˎAMDD%) 4mڴxM"Mzsibs*YfreT*\z͚5H'XOI[XOJH[Ӌdz\ {WWʎBFʕ+˃(D:zJzJDT:{{{;wNv 2BΝCF`ii); IUXvP(&; 'OBPAv"`=%ma=%"*]q)T*QȜ|;wHﱞi̙3/Jv#&LÇqi(JqHF1rH={'N8 N:aݺu S'S""s;`㐞8x z쉨(xyyɎCvEzz:.]*; EڵkȠ?i- 3g΄#F);)\#={6-[ .Vvx0}t|ײSzH Ѯ];m6l$_#Gcǎ~BI{>|6mڠ_~_e!ƎӨ^8Db=%"ҍ;2Cv$++ mڴȑ#-z~-FFxx8n*;Im6]K,A"5zJDK[o޽{$3g΄,X ; 9\#ÇwLÇGGGDFFʎCdXOM)ݹs[7d!۹s'a >\vo\FڷxbxyyaڵkT*eG"霗f͚޽[vkkkXJطoHDF8ܹ̙aÆɎCDDGP 44 4!Cp}ّHC}ڵ ׯAsB`„ غu+RSS ;U™3g&M -- UTJBf0m4qƲcӔk׮cSgggYUsP""}s vvvHHHO >7n8dɓ͛ػw/w3Pprr+8t(**(J{Qzuɩ˟ݻڵk5kˎDj{=ݹs'V*;=ѧO 6 V!*::cƌ… ˎC5Ν;۷/ؽ{7?}RĞ={`cc <皙AjժaĈ4iȭ̉* /(Jl{a=50S""o Ĕ)S׵&..Ç?/^,;6Jr")) *  BvvHTN߇+PF077/"T*bݺu4h7n J֭[ouXlrrrBS""oXv-BBBʎC ooo;?8dr•+WЧOԭ[񰵵^Ν;>vvv#\t vM(ѪU+\zfffcǸ?!&&?#aaaܕJݺuCjjjYO[E)M6aر=z4VXmRHb&I\FqسgjԨ={#ٿ?zڵkcϞ=eZ*/^\jcMP |CIT۷ {~ź[lƍˎDgᅬe˖FEz^zسgvcƍ#h 8={ݻ/yxxťOT*֮]"M%2xnnnXt)Z\nnnaÆGT[O0 <8s !;I+,,ěo/?[5KVVVزe &O ///|嗼wEEE3gF ???lܸիW1~R ""K.;?#*?͛EEE? z4QO0t B@׮]$;Iy&uaxwdG"#-333,]V_#;;[v,!C 00˖-âEԺg-0k,(J(J7f͂7vڅǏ Z- ۗ_~ R`nn???nݺ㰞ʥzJDDI&طoggg"4'55;w͛7o>ˎDFA8x T*^zɎdԒذatRW_-TժUvu :W\ зoJȘ9s...hذ!=ZbP \t 71YOuK ={6 +VVv,R9\]]5kʎEƏa޽;=6mڠo߾7o^7;w. ;ѣy#hii0Ĕh@FgXjUGd :}aÆشi R Bg͚Uz+ڪDDdX >#$&&رcСv!;QzS_|cl"RĒ%KK/$w.N:%;8qڵ?ϯRė_~) >}(**y"}cQF !rssB}׿JݑP={ȑ#077G.],;V !0o=-[&={_~x7`mmCahذhD\#bff)S… qFaҤI8yx:wqEŋqyL<`tPۛ(ܻw BRR&;R %C=%""/~L>͚5 ]>AAA &N &Ci?#,, wޅ+{=8;;?Dvv66oތnݺɎDT!O@||5YOax~|wD6m;`ԨQ[x۷cժUxzzG-d#*6\v +W/+WUVȑ# bߝ8qׯGTT.\;;;5Ok>|#!!+V dG"*G M6Ell,^~eّ*H79޽{#//ވǏѿx{{cСhCRReUP*hԨ>l豹FTI 55GA~~>Ѻuki-Z@fмys4i666yXIIIP(߿3?BVV233t\|OƹsPXXUK.prr#nl)))1b5j4iDv$bAAA>}:}]&’H=رcP7Nv$2QEEEx~~~#S""|WꫯϷuAVVF\~n*^|"?? j*N:+͛5kUe 4[J6lq"qyyyUΝ;ϝ,Hv oookشiׯ/;۷o7oĶmбcGّ)sΡ[nEQQQԩ;dշo_$''3BR]vQɈ+׈eӦM((((saa!l"1y7p!ܻw]tѣGeG"#޽{ػw/kzJDD?A ij֬ܟ !R0d\pA^5"- /B*1ijٲ%ۇVZo߾شiHddN:޽{G˖-eG2:DDd{\~ªmkk ZJ)))/(L-H233ѴiR HOO-]xALL :u$;̞=| .\(;Qc=%""Stec-␗QFIN]Ɂ'ǏGN޽{KNH Jik׮}T*DT{{{۷ӧw2 !GaΜ9Xt)k:zJDD($$Ճkcfff0`ȑō5ر#tM HoFaaaa/>ɓ'*S0i$ >s`Xd "##[oɎdXO<|M(Jq􊿿?֯_?SvgFAΝéS&/iii8w(JO1uTȎEz$''Co~ ޲#S""2E111uL";7n,--%‰4СCwԮ]13338pZyF*ݴiдiS=ϟƍQn]ٱHlسg^uّL) 4͚5EXZZbܸqBPȎDTiU.QQQPy:u P(A۶meG"I2220x`cxWeG2yDDd233Ѽys[#GG/9sm۶Ν;1p@qDDÇI&ٳ'~7ّH3gΠwP*HIIac.$$Eoizw\#"$$$`ȑ>|8dG":x ͛#555\QQV^ɓ'%͛7ƍcsXr%gcmݺ @^5kʎDDDD&`۶mԩSeG{ްիeG!* ̘1[nETT Xxx8FQFaÆ x饗dG""""^vWZ5L8%6>"5"2"%%׮]CϞ=qYّH-ZI&?ʕ+Tr3m"""ҍ7o"..~~~ dff"!!Av"lKvpa4jݻwGllHB| r[w"""ҩPԬYÆ `k۷/76 Q9"!!ÇСCс+**>Hv$"""21BZ &MBjd1(غu+^*; kDDQjU^xnt`rss1tP]111LPBB.]č 0bbʕFD3f ::pssݻweGr{.#!!# ڴi#;ɓb }wHDDDDϸ>֯_zKv`ƍasHw#Gjժڵ+#;AKOOG>}ݻ:tT+;v(F~slXFgXjH)-- NNNY&ߏ-ZȎDDDD\3f jժ%;QGrr2N:%; 6׈$^:6l؀ٳgcʔ)1cT*Xcݻ7ZjD˲#=סCpqnd =76 bsHBy!22xȎ6o WWW 0BBBкukSvP(0uT!77Wv2lI6f$&&رcprrBFFHzkʕ5jNףZj#УGn:ndCSNǏ%; 6׈@Ϟ=qK.HNNI`ʔ)9s&~'T)_dd$ 1aQL-΍ Hg΄HO4n{쁣#&;^B`̙3gpBّ-$$^^^S(&cdG!¦M駟bҤI&AAAƍ Y#ɓ'qnd A~ЦMnl@:F˗/7rrrdҹxzzb֭0j(ّ*$88*z-;Iz7MH\#"ScǎEbb" GGG\zUv$oǏ#99 B?~5k Bv JkʎBF5""=֫W/߿O>cիlll4r, 1w\a͚5jձ駟j<,sc;CC""CVyݻ ,C}n5kk֭۽{7n(((Llذ>~XԩSGhjxuEfݻwBܽ{W4kL,Zt}l1bq _!֭[Kxyyw+2Rqq\q+]E=- !)t=g2y2s׶r׶2SҢjtJI̙3W^YYYŏۋSN=jJFYW sssΝ;z'Nѣr)c~38.KE9qcsơ1S"2m2Y2O;ks׶ז5PkBL0SNmڴA˖-u Gaa!X 77zۣE}|*1DZ>88$"2d e2x)Q@"1118vJ>>BR !Xr ~7!_K[hQZj ~G!ر ?~\\@ OxfrYkL,.k5F3΅O;w΢^z+]t=8d=e=%"*McBZW}cl2Qzuaff&N~-<׶ZdQ\FzmY&҇jpp0SO\PP`ǪW`޽O}*q\-8?tBBB񓓓1dȐ 86.)!v5U_5jkی3Xb+/-Wֵזd=Hݺu k~͚5+x*h޽@%fffdGjԨaz ƍk =qcq?ǡqHDy8^[S7o?Xv T*1k,1DZnpǡnpi)c>5v\FDDDDDDDD&6׈\#""""""""RkDDDDDDDDDjbsHMl5"""""""""5FDDDDDDDD&6׈\#"2 !dG """"*%u)e SXX<1tȑ#P(ܹ(:SXX(;VT*B,_??cDd u3HW!^WXt)~m( Q*LRJE!ؚ%2"E32j(_^v ґu[vRcDd8ɥy%** Gʱl^^^EsԖ-[dG)JI&V^OY#;N-_X`ڶm+;NuEvb=e=%"2d:q>z1'''Og}!C`ڴi㨥aÆ#,\#Ң$ 8HNDT1O2^077*ǒS!asHK"""J|Ǒ 2([nEnnn qFHLE#㔛M6 ?F\\Tdh\#҂lݺD~ bbbJ|EaffV|lݺUR"2EDL>~%! #1 P 0$DQJŊ32#2BGJnB yG^Zrrg- '} W@?\ٳg/xOӦMPK=//O~D@dffjϿu___4PW@?\ӦM|-\PN PM&^a0W_]4X-Y @Y\3>>ꫯ) PrZje41:uj97\s]ixVPP9r]1\,&&FƘ\ڬY.{֚>f8pSQO~:kתUlll9b8QZZX rL_LLO?jA=/84~;{)DSPP( ׂ4o>^VӧUjբfڨQ#ծ][UVUժU$I:}5TeggZjj߾"""ԥK5mS?~\-R\\o>UPA SxxիWV^]>>>:w ܹh .???lRر"""8QO~+V(>>^[lQAABBBe7|U^]UVU@@ uԩwޢ/ݫ*""BTF ۫ q͘1CSNնmtuשCE5<UXщk7+ಶlbza*T`OUV2B`gUf*T`zimVf u13|pSF g:wlbbbLVVV~ݻͨQ7l$͛3g2\.)Џ>>m۶f޼ye-VI^DFFI&**믶#?&((Ȅ#FSNَel_|TT4j,]v$!)Џ<ʕ+MӦMMŊMttINNcLVVcnSJ3bs9۱P6;vViРY`H5o<jp\4kT\ٌ9ʷűs΢oÇmGQO~:dqc~{nۑ.)''0*U2rYzH(; ׀4Ӯ];o^|23#FӪU+gۑ`Q^^1b5&))vb7oW 6 .N@=ZlY̔)Sl);w]/r{4,X͛ĉںu>UZv\|MmܸQEَ ~Wo^>3XTO*O~g{jСCo;D=gӫ{G{RRRԷo_۱aÆZh>SM4IJKK Np ^7xCݻw߯7iӦc-ܢ7k׮҈#d $>>^-ZPff6lؠ'xv TLL&M+22R'N %@=:v:t蠏>H_|&OSO)11Q'NP-rJۑL6ϛl7O=P4i8N' *gy4x9s昀ӳgOm;S㏦^zI&MPO~gMhhپ}8Ne~aSR%_ێcUΝ;>}hѢE={uf;S͟?_{VN_rʶ# Lk;p ~iZ|NۑԦMݻ+&&ƣlfs?#G_LsJKKڵkUn]ۑSp#GT۶m+V(00v25rH5Jf#s=39szi;N1c/B_lǁۧo]sOT}M65o<؎ըSp#GEEE駟~+ ԫW/%$$h֭^Bٶo߮VZiРA=z8V裏a5ivP~~neff*11QUT%&&ꮻ[oW^yvE=+yn?3fޕdggUV իz|X4hFi;נ^z ~t1OGÆ ĉڵkێw^mݺիnBy զMkժUc_ޫnz-? ؎2ƎCTXX8zziS(_K~[oUh;صk5k2d8:. 4il٢?;>>>7nnݪɓ'ێ+ؿ_g?pKxQO|я.рԤI jС9r:d;3Qt7+**J&L%=ZtRSSUBqp  7|;v( vb uIZnm;Ǣ^ܵ]VڵS||:t`;9{6l޽{޳Wƙk,ӦMꫯڎⲆ k̙;>L*رڶmѣGێѨWG=G?:wG׿tw2XJ*W^'|Gڎ5xB5iDm۶g}f;K_ 6hnyoO6l0}gڳgGwG?ZhE{e(44T=ڎ5x jǎn;{הS(]̙3gG饗^bvݺuӭުqَ⑨G=C?*>wG7o.]؎ҪTAiĉ:{8kSLQԨQ#Q\^xx.؎ߙ;wOڎ|||OkΜ9ʲPOz e~T|ԏ7gЯ_?effj #QɹK?߯5j؎6h"9rv\5xs***JAAAjժk׮omGbŊ޽(nGՊ+i;Ǡ~TrЏN<+Ww޶zH*Tp{y#kp{yyyZf:ud;رVZ>^vmGq;Zb kp{[6lh;  7ܠ8QZrr8pANB=u~8WGqqq MhǎmڴIm۶mmV7nëmڴIjٲ(nm۶u9Qtq~tm߾]wy(nUVXKn[0\HNNVxxn+,,L)))cxdtMP(n)<<\ڹs(nzZ:SpQj?ڱc ոqcQܒ4h gَrI/k6i׮]Ϸk>,~|7ϏRJ~TzڏRRR粗˶51\[۵k\ݻW=U_-,,Lڳg(^˕kWTIuUrr(nzZzS(=Qj?JNNVhhlG;m[kkP^=I.tEEEPIRZZnfaTZZZvp%ׯ__iiic5iQOGhR믿ڎK5LIRj՜ &(::Z/*U$?tYz?Q;w?,I}ݻ;myވzS(sb?2}uriΝ;H2gϞu2M0\wuN_nݍ5?IucKY`1x8 3̉''qyG1LBBӗMqMDDD,[POz C?rWGw}y\oڶFIOO/a,nܹserCΝ;P . %)22RqF5kLƘt֭؟S?3W*UٳglsIq)UTIgΜ)e{ sPOtGm[zն-x\*U0@+WSO=kjǎ5j &I:~vޭUR[XX(_ͭR```|.t~ggg;}޴9tGjժlRʒ$۶pseuCǂZ~y}>|$Iј1c.wIII0a߾ϿZqSTn|t&oڏO>>\JS砞@ЏQ`` ۶\[ R^^O1=zϟ[nEwVj OKx IDAT<4hQFiرa͙3G԰aC:tHiii[%_+rΟ򛝝U:m;s]z+bŊerMӧziQOG(((HNrri۞>}Z+WӗRr]܀򔐐`$C9u˖-35kּF]wꫯ1ݻt\{VZg5G-Zkf_-';;ی5賟}YuV18pH2VrQS;줥oիծ];-/бcꫯJ*>>^C ё#GY\R:tЁTvmqҝwީVZ>pri? 믿AَⶨG=ң_:zӶ0`mۦ5k؎ rY(Z:u51chС:~xkSڵkn)*RRR믿v.ӛ㌌ =zTᶣ5iQOG(<<\VFFWez  |||ԨQ#& _Pl٢CjڴiN,WFp͛dI@G=ңj;vp2qr텇kN[ޔ)S4p@}gSڶm={j˖-6m4ir۷o@[ָqcN}7۷oW*Ut7ڎC=PU\Y?ӖMԩSڿ?Wk(7qD:~xQ|vd]s5h;Ǡ:z E?r?O dۖЁO?cǎ2#SVҞ={lGq{պuԫW/Q K. Ҍ3lGq+ӦMӟgUPvA=-9)8ܡUXQ==ųM>]\s:ud; .<}ݧ%0uT]wu.͖7Tz衘QFRR6mڤhQ< 䨧|s~+99v1m4[2#TPAzҔ)SlGq3f??.$::Z۶mӏ?h;[ 7ܠvB=-9)8ܥuQumGq ۶mO?.<ƓO>;vhҥ%K(55UO<(vکQF0a(./''G}'__ZQOz e~T|ԏ|}}շo_M4IgΜ?^jݺ(cp.]ܹsJHHťu]V.\h; ǤI /hΝmqY| ={($$vD=-)-Q[?:rׯwyG_mqYiii馛'ԋu?<믿+Wj͚5YF(/]}Q\V^^}= ꨧPGWf͚zꩧ4fڎƌ5kWk8۷W@@-[f;K$[N?~;vvڶ㸜?P֮]t 7؎ѨWF=A?2wG?~}Yq\NZZ5j{O/82\=zVXv3k,ZJGWOVZ| `PO/z ~ty܏֭_mq9/ԩzvg#=Z|h;K8}7n]O?Ww{բEԵkWq\F~d%%%k+PO/F=G?'Э[7}'㸌KK.Zp>qpu =pO8.a:ul;~ ǺkꮻҬYԣGqbS(yJ?9s飵kDLIgϞ-ܢ͛+66v3]wu3f}َcݲewqm\*)##C}U׮]3酨`Bԏ}QuY}ѩSlDZ^ұc4vXQPkڶmzq8r䈚7ok֬Y㠄̙=zh^~Xk׮նmTV-qz ~(==]͛7W۶mlٳgwޚ3g?ێPxSNe˖ w}'???ۑUAA:u꤃jӦM  x4c m޼Y 6܍7N֊+twێ㵨Sp#GqqqܹƏOܱcZl'xBƍ%el\sf͚kj㔻kÆ ={G5^oaÆ֭;f;NZh QF1XzJ=W@?~z饗dqѣGխ[7sOA7p e˖={&M7|vr3|p}6mn6qP *UŋUXX]*++vraS{kf;D=kyn??h=Zn8"''G< 4o<djڵkkȐ! VVlG*S'NkO?ԫIV{WcǎիգGUPv2/SNj߾f̘u|2)Џ|v$8 GСCs<#]QAAO̵^kԩclGBPOol٢O_W9rv>|XW֭m۶i?eoױcG%%%O>߿ڵkD۱.O>DZpM%Kf͚ W@?\jw}SoUxx&M<.߫M6_'xB"""lBY=\IaaM:U֝wީ>}k׮eTL/ܹseQ/uNIRz.YzzuViʕTzԧOEGG+,, ɓԩSn:;PddN5nX<\j%VTZrgUZU=N:9@z p#TPP˗+&&F~ՠAEDDCjڴ5jU^o/w̛{*99Y֭S\\6mڤBmV}U=TzXEk#~+..N :q$z SZ@%''KÕ,:tHȐ$ըQC:tPDD"##ոqckpQ%$$(..NqqqJMM$UXQ7tBCCի@ .T=tٳGkѿkժ:v쨈nZ6Wnz p#t9_711QyyyQݺuU~}mXuU:y򤲲o>ܹS0EFF 뮻:k p p(%%E)))JMMUzzzQ]n$M6EE;$$DaaajԨUvmkoY'''RFF~lٲ#88X Sxx4he p )ЏGjͪSUzuVՀa$5iDO?Yf%רQ#رC#FЛoi; G7ȑ#ՠAڵvX_ O6}t__~8@ڱc$iԩQO~޽[?4p7 ׀2]Wn?~9%7\s͛7OΝ{|}}XN7Fﹹo!P2TPPpcx<9 Gk̙- w)##R]@Ҕ~kC$խ[ܲő ^[l^{5mڴu뭷gE=ܗ 4`ۢĸ,p5A 1\p p5A 1\p p5A 1\p p5A 1\p p5A 1\p p5A 1\p p5A 1\p p5A c3}ںuEo.Ijڴ$_-ԯ_?1p[nn;Ftm߾]\`#x>>Eֱc.:kS:u䵽4k@ (""BzJmj;'??_QQQ[N*M6l(uMU~~:=c駟l@IDATѮ]^u?_|Q$I]tQNcz8k?8'Nԋ/( Ӌj*u֭WnD=8WIqFU4l;{ {Rmԭ[N<'Nhܸq8p^Hm#???%''s ޽{\ٳg5o<%&&:.`ҥK%I ISNk~~~z'/+;;[~N8s)//rw}8ƍլY3ÜJSsg=EO*q۶>#=4hbbb4a„+^Ҹq^ ֱcǴo>}z'Nqz衇4z … u7^ryeo{$?~9r䈤߮翜7[nQ o(00йA+>Zڽ{rrr.YaaR9c?rf͚o̲9n`:ֶmԥKmڴIwuLr'%%]gڲerss$=_ko>#ejak.\xvm_2o>-^XԷo_{0jhqph̘1 &Ajxg\㤥I4JǑcF hɒ%9soHZΝ;UNU\7t%ߛ $. JW_լY4l0իWO۷uAI޽{5tPM>]:~~a>|XE7l}Z999رƌ'xBwuKIR=TZ5mܸyZÆ /~Jy>aH&~?oի(ϗP/핹GfRϞ=mGqIee%r kb8 kb8 kb8 kb8s@@)-X(`Z& H4(JPX.`}i\>[+Z0 c-"7IlްODPDDdQD/"ӰQD^E""yy|QDGDv?""O[D)"k ""ߓi|HD.$kD޴ϊ=v5d%ѦT5PwW]a&mooH>".ME>k"w"rͺ2?CC"}a#<'"s"J*{T]ˁPƮi1ɯ[iY0n> ,a[7>JHXxi>_KBX<-kON?sY-mfӰOmyw"vfLM0gw 0}~ 8w4+ |d Bv̥qN^m}>_UVub`ncoۀCc<=˴K"Rࣛݪ/7g%q`?zg_7jKDG2(~<#3׫{;K2=m ~iSkSrMlmmzBC9UyaP՟o'_t%<]?Ce`TO7HJwi~4?7`q8o!BDXFG] ɝXU"aA){*1R`Q@:~SH ]T^D6WNaS*"wKp[[HWnUH_8:~zӦM] 2Doc͓wHV_!"?UwwKSE}$-2uQ0Ǚ~ pk&}mO;d.}=eʨhօ "GI~Ad<$]HU8V ܉9v^I] LZǰ)CWbއօƺ II_sm.$+r(`ЃuퟫǶ5bd =L$8Oo~xOt pyeή+kT>R]601mʰCv =< '9q~eD`(m'NZ1V^Do~ȧam"TyH^XDMixfK醾2ȷ"Y E=5}T'Ol>SD^!SD2syÎs[RiS$WWs1岃I~t=dwiI~3I5jdi)0 %oWDm<xXD>|d)s$qD"YҰoKM<iگ]PGo\D$"x9xm7ynv=K% |0\mJD^)"7H{ӰgQa(h%q"EO|\D;VT z"9ydE3Sy"ii%Y\G%HTh$TgH~!~Ē+T< 19JbUn\EMl<̥Ҧ'q򎰗KOH rẠgIɟEF>$e$?"Y z[ʽo(mbD&W՛+`0 GBy?iD!Q "JπR:s`0 { $6 Hm$E}\Mo{Q"7 `U}IE$ԃI܀} x޾-r`0 CL`0 C`0 )F4 `0dQ0 `0 bL`0 C`0 )F4 `0dQ0 `0 bLÞ!"E>9%"ܛDDE^9uuSe"Tw[1lȱ,(LWDuepTZDdJD~7]"-`0F4_(ppXU 6"ro_nZD èaLCr}KzGŰq"zU}>g?F-0a0 $aEdADBD D"w"Y)q IMK?_}#"MD\@DȇE&"N"k"4#<=f,Ȣ_Da͙7ȫ3[TD$/"/|^xwԴ]5EyzAD{8TFDMU5RQvUzfi ;Dm"vnG[)ye:.4qʙȼ,{QEi'EEd|]E:DAyE]8yZD~};?D䈈$G2PESi("?-"gSyHDnM9Q]Wv||Mң!K}[4K{^a j.?(V i[Ұ8|haJ|nNkw,},}4o%YazdYrMvI;ܔz?;s6x_>~H&Fndw~_.?nKZߜ~V'4S]<Ҵ6$s;g4^J9cBNw:4E2L;P׎{;J% E!|#{_1-d7vӎrrGmddxG_KdۖM5 xm~ gx3L.Mv}u#?|9u"Up39Um? o"rD19O࿦e}WH`ު_Me~p+c$go\F_L-yɄ]VIܹ^!TUU'O'LU(7ޑU3BU]'9TTۀ' MfށmS?6x٪inߵ;Ƈk"=ydWۙ*p/V/HSHwJ%UM)(\e]K?&xU %n#೪?x~,I>SUI$"?O|80[y)v|!9.Y s{" ҁ_I̗uj7k':vezVDΒE,4%"K2TDdv+6vϨj VsKH&q:UuEE$ cX`K_UDLබr]\ܪߑ p8)"%wUӝ Oܤ^0m%ޥ_NuHNOUO\yl MyUB!"~dҴ%OD#Q0onqTD[;3Hh QHHMm2$mo2 wbqD$OGot&2>kD-$߫9Ko!Fg./t+| 9-ϑ(S6[ujSy1 xd+Slb.}=<.l9 xɄy$V~ۊ;TUwG;ݼNc$/-Uե!ܦִ]me&}=qcu'}~reT$gd"NzlT]WJ25ѧg a6^u'"%57Knm'{"Ʋc\ $+!Oo%2|O2y mi' T؅>C$ln =軧׋/hu>U ed>Tu»p^Yy6m!y'Ӏ%!cE~ n-~FϦ\i$ h۷B_֚ԋ7YQDIη$V<5}TOl=SD^!Scr7CǑ\ΰ7ln4I;~<'Wސ~׊ӏ_V՟ă\BpEDryyDuw'9vJn>0Q0/]~d}|)=XP̺%8=CY""Mgͽ@<"Cug9$qYҰϷmA{4&M-}iى$n>cӿW n.#GD>M:H2$+NW%9[|{]]|$.n.c\UC19~OM QfqbV|AD~b|3Ir47tQ0/QRx"p%$Vw&"O&_ߑqU({U$nLEI' |D~Qr('Er>uHZ$+?.VU< QX<;xa$ۯ"i/OϠ &n7?GI fn$M*{@Uݔ>NcF6$@ $Yi I_x.p7y$O#9'\>aǴ HxQz`0 @D~"{0D0p>"^y7vϩz+{a[3j`0dOWXO*Rߔd5$;_ ÌQ0 `Ȟ?&Q2PIn/vA/oTz1 1f`0 )`0 )F4 `0dQ0 `0 bL`0 C`0 )F4 `0dQ0 `0 bL`0 C\ ZD>+"*"-`0 ðs+$by`0 aTZS!"lz祈XDnWD\U|'BgD"R,R|cv>w cTrh".3"p#0 ^UUW{+y68Lr3al0ZC <- ^" `0\z A>OhN< #Q `0.)r`p{Tx1xWrrqU̅2Ms7C/F%}}4zXn?y/0.eW];=Uݵ(+SҺuD|[/"re-@9T}pz {dJy8[Nc-H^P_Hׄ6ĭ"*q#&5yXyd ATND="NLaIqs)Ki"1 =#`1;.yٞe]xX=?Vo>~믿~BvyB>BraH.s9♳yu~'rpLր8b̿5clהD^aM=Rq**5Ƽ?bH.cu(+sԺutxEdniO{Z7Yv M qcYVO&9KwWw. $g"'"%Um_ݘޕeaJ/]>*VjuIrO♳yu~Ge4WYTo@]T5\UiMA_Nj%"O"Q$s:Z^Hvm|hPT>|'[[Y?s6no;WG"RlK7Ч:U Ud$~3d,Mnr-8$OC3aSUd#QUj۶W>^AÌ#٤9hW]~_xUY?[O^."<8\Ve'"Nfv_]ON/؋gRmmW~O!M)aF.vlQUVb5O#l L'mtp7c^D>gQwHnbN$f&ݠA@?rZSUonFϒ(# ʏmN9 {YʿۼMtՃt'j@$18qvJ4&aYkϼ?{Xb==%Asvʼn:a2Dc[`FQD|Yxa87P.LsxˏmbafǖZԛ>eG>&rF]I_,x;f|#K76Y#SX8Cӑ_ 72[e|Afd9\hz\~ nNij*1aƑl 4 #Ö#s8?ȧ2'H>C<&t%kUō\|"kE\/K>}fUp#|ʍ1E$ IDAT4f>sg|&L|q,98%Qe*,-## q398MAFQ41[C̠ 6kύ| 7Sf ߘ"B)W`(Jɍ>~ ċGj҃UJ)WTpl*yvlkeyxQL9qqWVF=C @L'.qAFQK'YQiShJfq2&cssi}NO#0s+Vd6rz-^e  }p]i'<X}Dd%508s(`| k0F>g7{p Gb㻉s0ui ^2EB*m*˭e!Bj,'ORsk?0!ARBɋ2V)ຫ(_Z5?O|aǎON# 3F>M1F>p~Vy|w ny;w?金_Ǟ ʼn]`Q@+lQʕplgq<^q3{y+UWq}Y-u7G4]9<=X1^r(WWGFuհeግ}qt2ǰ%"==P?VJ 488q|.OaYg"?A1Wċ=f 3ZI3Lc!q`*XXؾO<>Nˑh`L0F>YqɌ# 4 Q0A9lgמ[|z%] A#KǍ\ Vred+lF>FT*qnql 93ߢ`b8^6MF|&'ßO6\2H2X÷t`Xj[ x؋gRmmwq}q\®l:8} qv(+qUe[f!X+1]Pi8W/ۜ]jqe8& `U"<ѹD zŒ#嵧H2Xf3#aE^TSz/9KwW鷝.tZFCTUZaH#[KZ2SI\}]N.č\Wk̒sA& #0AK5oϭ*R.a1,9}$"8;(rq$t2KcE> yy۳rfVV+=skuX1 @\ l-WyE$".2L#c;4&/ev  j4PYכ- fc 8PX{U4{hi0 oi waU^(}<^Wz)K76́֯X8"oZJqT)G8Ϭ9KwW]&B'/)l+{l9k2n+㘩ӥ_c57|s#G82vʼnZ\hx,4٥[b\T̳Zte6y?Z'O"W]嗓sJ}]e98MAF~ե"aIv'Νz&^BmDy"ऺD1Hvy8AFQK94Ip/؋gRmmK |\-|29 T%wog]b[&씩|$W񂈆QW DaZ.0SŠ6JhCU b q[hՕ^f.=G:9hź4+7Em0]~܋dYʿۼMtK'WwÏ>uk/C L١k(P'uI:Y[l8d(ba|.iCם\!Gq<*BƋGTT5&n6^CE(1\^'zE3dnPQ_ui (নo @u's7Eqgmۻ[YS? "wٖ6k\= Va팪ƒq9Dˋ=kMc~9qH-t|^LنjzRxb . eXXR }˲zh/NK/e\8?ܸ֯)p馨^Sna9#9<ϣP{cx,m^ݦv߼iΡij?wT N⦨[gc& \5ySũ w>' 9^w8\>́u7GT6"݀};N,"IǸr_u3azAYr2 rs߅AÌ#٤9hW]7ECB?\5c;wjBx,m^ݦhЃ\TEf#SG!_Xw1"ζβ/j;ʉ7ض{y)#^صm[+8]dXB*k$Tm6хEp=\FEre98MAF~ԥqSd r(.=;ˡq!xP; AZAwukY WsL\`5V.Njr_^բC뮌| 1 93 ˜oK" X1A (1ɆKbYǠA(֥Q0۶/^q$Mt2Xf|q^c/9Kw׎ӧv[\! _XW[^q5b](rVqk|eF3o €SSseJN'mDYtlJQ Gg**q7h% y?&jp~mP&63dWwnPQ`Ҭ`1]^;N:r#O_M|⚨;'"BNra@D,{8CYV\(`0LiL"-Q|R-:(ďuÖ7LU$Eq*:|bǑ. 4 b]sqz˂bix+QHTI r]D 59q̜;yDq-!'j>UK3ߚ_gql Ƕ`y-Z#s Z)KVĹ2"M>0HeF.yFzѠR\rO>nf♳yu^cԫ/lqҩ'z 4Q9d)V]$cاQ +C+˹2K稹5院['m(Əbyw)E(ސ 0 KKh.E!qA<쿃"GI7(s(Я4h}5=0\˲Ѻzc enC c;ØU #s\3~ U{xᕾ3ɇL*mH0$]-\D颍D,5Zk%}# l4MM>==MEKK+/{0;Zmz7GzG뻤0$ArUYY?s6ҧ+qeoQ/o?h  \r$:52@Fn}}oXW\M0M?ǖym%_p,˧X=SD䮾ReXnf&ݠA@8Zlu]޹0M {Yʿۼv^l(zڠw1^92nm1 *ۆ>XB`,|G 6gqCJ;/vh4%&͌stfFeKp ֙3p8[e98MAF~ԥqn r(.ħfλO?vh%X|tc+.k^ ۲QUvAUyxa! EfukD1 F&3<"==*Q;(1ɆGOź4 3(  Eg7*.&.4Cm[_8P8La(ث Ya˪w9(֥Q0Aon. \.1ֱW>v^9~8^_pTO+lF؉ ԃ: '-GY{t(MI9W&bV/zlyAb+`upݱ-f X*m᪩G* ;T`j\C>Nn||`A8]^&c(C̠x77pdWW L,7qc|(P;fטt#7J<"\ib6q,8)0U"Ku`/'Ԑ0 (LPʗ6s/)86ʲPw0ufrmj{gh9{7iPĮ ->`nɊGH7(s(0ui!fPUz(π\;w`z5T5(-r+(\؊ۡNg[Ķla1ίJvU3(J1G^e,{/. !,Gl1ɊGH7(s(0ui!fP'g0s|F~Phṉ5Jf+nRyswϯ8mn[r%l,^!SũۖJǜpjl`>/Yz{kd#lqdeF.̌Uuy87PuH?83 E-<6[JB5_e2d8ô^q(wR_pvo8_^(G>ޒeB=!8+a?x~hb{E3dnPQ_uiPUa@ugmwWE5 į/^ܥYįcAi \i0 K ~^U6SShL)S&c\xX6rtzT@c1vK]ms4x qE ҪhkSUBǡu BE/Dx`eP'UY^ٍ,HsUd֘.Qwl_ W:*LDp]wONX{YRשVuneYf5[<[ ceQ+]`ro|N_۬`绪?z/pa>G]ڪWpE ;Xm2~94CUPMgvI6P,,_'pLsϱZ^oywI.!&KL]#2cyo-)/)7%ۿ:šk"wP0H6eQHCp~vyu^cՏ[sJS8OÙJnr}AvvS.r%3UZ9 pdȊy*2]T{6zAs n?]'Xj`۾0[yVW/C<(mގ߸+a>fs`ή#lqt2XFbm ]^;JljR4on}Oa~b BqSk˒c5[䓹Io,~Gaҙ+> w,X 8Nr{u Gk4pLW'')=ؕ2 ЊϠ>q$M>(֥Q0Aon.o+m[/o}S8w'`DI-m YLy+Ǯ@!! ͠` ~cEk3ަmD])q̌8bclNrA% &-wappM|ԁr[3>LOA8]^&c(C̠x77pd׎RQc4' ɖOULZhcz.ry)qؕ/T( xDz cW0^qn#\u3Q-Tw|Om+&K'L liwnk_ |}~u+x,;Guո֕z6&gƎ(J}(pZ$>(J1ɆGvnPQ`Ҭ`1rv.,ȏA!ep{u59aeIsȧ& h-Jc EHB0N`%UW̵Xn.\6v*z~nˢSoL(s;R0U9L^5$VGUWҖ-(P,7ecU}?ۘq$1uiV0A9lg׎ \l;G5UCu. ?9!WO>dsk^|P>g_iӅifɹwV/\i(\5ƒ!ȋ +V,IKV7֖8U8a]cJP,&hP&63d1>F.9 ʡ`s8?v>&$ZV }:-ǎ.,=Z!_j/(X4V܅EEdqK-%*Na"?3gբ%M+:` umwG"]us̭޷5"x.9KEP*1ɆGL7(s(0uiȇA9lg׎['(7fu_:s4穖go%J߄MwlgQO'g0k^,9+G!WL W_I9W䔘*N1 IDATW( Ҩgm1QG1~' f2Sջs Jcry("mhz[&n6A,R&'+2F>0HeF. 3(v8N zߏߪoө`NO^ 8f^(EUTg0 " 9"M)?F>g0(vH"9l}g:LTe QaCuԒ&+y#]Yn3N0==En>jn0'reAFQK`1rv.mosNXx9"">_W1/\}_֓NxGϤ3|~lJͯ1לl,5bs"7weAy˅m*_1U3U[`l,Sb&RDMyCĊu%\0F>Y1. 4 b]-h/ey\eY=c/9Kw׎;HV%?哴 ,Qp-O[<ybbE>~x@CfФX_O> $D58<ǣˏRjԼ;cqLoЌ(%Y)o/Y,.8_w6%RJa{mJU҉O.r Y#OLSҊoͼŏ#Oszl_4W,5c$#ך!##/7?+ǧF%S|+Qn1Μaszot+9syj0|\7_1XGz#/q"l4qK`[+{_g|\kz{{1Z> $Im2^v$/-[I`븐K3\)GDtn4.Kޢ?rBf!alYQkMb!y`<1Ӟ`VHZTC GLՒY7};)-aLr\djSǭ⇋ON4?HhSLiC/ 9>s ]l EhiB0aocF_AjH"OS/Aڑ|A "i, 'YL~\~vQ~@3ߒ)3./_&CZix (/YnL ;Ô2Zk"ݦY 4xǡz/10yp4Q},l3Bnbun gFb ֑| Lƴm yFdT蝮ɷ抿 "sh}-L"9B.h֘ gXt7?Q9A%D.Q+Yȍ nnJZ; 6Iz!v1׈b4G)]\k͋e85%, /pgH|WOG ʟ薛tc8xm؆#|kgz:9-4߶ b3BvB3qaLL>q=eb QSfo.J%Is@Wx.b|zB_AZk,- V܇_2*pN׎ʓК ȃiy&hnؚE5Q4+$#li3`,nD7XWOVO^7QS5-)o !$eݭm(Y0fu05oK~m'F}t/,`,0֪^ȕg[{B16|zB_A*ȒiYUn_2*pN׎8$ϋ>"RP9 YrJAcQ,ÆhKS:[tNU,EK,'hqƗiFE,1p|t]Z#57[7yK:gFto[mowؕB | ի}S_:;]OC)EɏF#gOqG-~ N׶;In>[SZAq862m@b$!o2 \>ZhjqKY hқdj*J͓Փ4&/qyk;2W+0-ktgyH$aV07TFE,,%KQaI qC3me FSVwAg|;^4WhZDe,*}sMES'L}J=1QF HQbQFE >(y`N׀ߐ)LݗKҎ8|a~C FX{kGYDiV] !1vx('yT`;n߬ `_ӵ#y+(H>@ڮ|=VCx ʇ`\4O7oui$N]ƕn`@A`L'xpA¼~V`jӑG+G9Y>ɰ;L2[bcILCf,l'Zϳ 3r^sP CҥU' !*>Cl5 O dH$#wAErʸ@_ӵ#y( qPzܙ JS- cOqH>ifaנIQg6%-V۰`r(VGXʖh&M+ش~'tjkw+4 lS N[kyi,;&9\AA MT0 /q0}xu+W0gB?[Oop`ב];~x/~ N׎3Z ;yX! ֓|:^4e010Kmk fd5rLaf:b֚frrm4Myu)ZJ QQq*x;(bFJdž/3h1[y6oS'G0Oedub}-F<ɵ$ fou H>^GR_A=f'0 ~N׎5"OtZ-DQӃ*C`Pr t hep˰;gz[nig*ښ·-Zkx{m.7.sqYf4Ehu{V!lɐocJFr;mu+=8iF.~MFcd040_2XGzk@98#>+ @_ӵca(O } М-mL[!*a iJ$AٽZco` !~JC!DK;B^iAp~tH^>|4 aȊqbtU6.hEKrH>EKo̽[oъ[<ZkeeBTʺBvȳ<lrek[,pǒvqr;7!Ek_]LUhߘ!2*Y~-=@ZkX @1FN\|zB_AeYR FG{ԿZ#%~2_yƴKP 8wv$߭G!ND GǫRA) JÇv (}pݩB!"eLxxiK0 !lB0b EN\_/g1Uʘ3iXR9dh>TFi Z@`IY~Df, 'GjZ&nӮ-}:;NS_xYZkCkbH>]Gv!/CZ[Mt26}90~b̿< ޻(pVM!Ė!g !"!B__sZݎi/փڑATAR7z|3 t@6CSՊ4E[A#>X00"&hE agag5B m-zT'J"E4"U{w9I&QFl#"8N$@#wAӲ|AA~H"ZGXkZ,]~_e?픮k#X ǘ 5A8 5m8{9ڑ|\>VJa7n?@&Q1tÓhCfHl62M$0jQVbJV 0y0-â||qǵ֘kDyD3yNe=NHsBHXђim.SfCfiё :_>{jdn<߃803Cc~&/PX2R("{2s8HotPa9KKKT*]?mҲydiZS1"gvݴEQ7ȷ74wqu_j5O$Z_z' Zk9yyOiMWk?E=~Wyɭ-քawhIYV׎嗯AB7gI/bMuiںF8{/k!FD Nl|4O3jLSLU|:}_d=m|/|G=JΙmrq\7 CӟwB;Xl0Y~f] 5K&趜 IDAT cIg>ɟ w޽B}dmߓ~74}^\s/ǿ[];w"1YՔ!zHJ3 L- !Le 78di;>!0 ag8Ym0B`K8\L[qø;"8>fmY{+vma`HˑgwC{Rn6^yh#O2ZXƱ }a.j~lF {>o;/#wA֚ o_=#ƎwsM_-uv vc`,pUk%!>Az_jJۯyć@< ֝hV݋0 y[5IK佸^v,o ZFϼK!B6_uhPǠTxnMälk,D X"ʢ"e..CQT%"MQ1QRMqov&Ncls{8$YNۙsid98Ba0,!r+̆7,&(,6Ǩj@9"ɥR⥼_1XGz#//v/_ZźO; Z딂}h}+Wpxi7!xN[(HӴv:q6VmR}7$iBsgWX5˯8n(&M! In,mZmGE\k\ߧI] RynZijQzX7I?<ãUXbbss E`Kn֚,"!0R6(eb64qmw-S"\OMSR)b %XBWj wd,#5M0yXnު-I,"˲vv_~n,>Y_?7?θ泿ȣnG%v<(8B{7i_IY?RKB_^JZ9ymҊ'`Z^ !hZضnlZ[_5V`}ۋ>: X%I6/aK/~Ռ]rfYsb [ZTF" smeqs&s0!&,ڍl5{ծb60%ԍTJQvˌx#-Ld2ũS+u4$7i bK6muKY#WL0 ,E96Ϯeټ|q !r7UsG(OO|}"~H;9W!R ĉ"t%^۵ٶne{vvo_ϱγ8ή-lyk_o!QcM! gx_OCia q[}lnb7€(ړS“7u?B=D`v| { *L2&6%UZ+!4iYitwr'KIo^ǬV %<oWjvJ#J"Vq2:~y#?Y/s|◾#E!rڍO>3?OuPXQa_)҄\:#%][v bZy$gGdV0:?J˲hkdQH'ȑ 0}~!mE [Q<F H>^ڶ]5hB{9=%{PBb!4҂ NyaPq*:gǐwjccZh8nQ3 K-ŴM2˸},kkьR%tdFaqeF3=`rSRL.ޡ1Khi0ؔ-cM S $^@#@Adi֟~Ws뎍9SRss ȑQZ0 vK95)!oS]_o}7Dz>EN?ɍȳ"Kssk3O?ãO'Ί;y*N !ztusg_ i4_Í:]٢OXܠ2rLp+;W)E=ӈ,FYL~a@,K ghMz\'00ߚ'B<1VCd"&Ĺ[%MrEg?ThQ,Wta%4yp<ؤa3OdUF')zPJ"|Auss8i]0 ig)zp,}+֩>Ehm@kM7^ܷNh܀q,{^be;Zw 1 H>M, CTNklfvYGgҐv(κ>4ebee7Jkb> ٸl{QgENVN>2Aƌ9cc\Y*`fWml,RTqdoKV)P9*ɕ:T7߿@c%[M{auqZ3 ߫y+˹Vjoy>AefW*#T ` o3e0`ɢfE>0 Qj$$8CKuE<,E*#͕nw,3g>lNAPr@1LE%Ԣ3ur /_Z̩McJJ\F<0׿n40f)7ZZY74A)taJ;iޮm@9$uoLITsnn/ƫi<ٟ T;v7,ˤ2vPPI9 g;`@B׎  8ؙI>JlkLRI"R? $Ҋ[\i_!S0 uǷ/Xt|4"#tUH$%U|<-G#jPq*@wBt"ӚzԌ9THMr;⽛ˤR&e|ئ{;GT? |94=:J;s,ML[&ŭV6F!<%+$#;+ VcXZZ>q0cZ)ο |6rKe?9Jg}JӢ44OApOop` ZsXn6B\q<6L&ONwy!24M$V׎ރ+Q٩C^>|EVP5aئ+eUʄ5\22,x\\=7ͨI#j0O") 4/q} S,%K4&[~;\KC%N* ,4plTA3^"=@U3xi`Jy\0U{gRkjQyE&e8BMs/#KA'W4[M5S=>B`J#Iueϕc ylf7:A1^v$V+a_&@[~DݘdyR{v3=,,lic T(y0OVOb()Xnz"KZL{X¢PBqZƑt'4m)eRC+ )93Y\^ C4)Fx0.<fƐ5:7o߸^ 9eurr?;EoMyO9n.)n6X٠݈ {Ϸx]Xq=g&Ia"O˲z"qz"`2 1C^B_AɖC؎YHpN.`~du,&?G؆M,!,eٺEO=K7^" Zhtױ15G8Fjr[Lp I;Ji')QXlFT\- y[8$MZs}H`敥5ɇA/Xly{vYRnL^;)Fz"7Mg,|,mŶ-c\{pX~HwUVI 0M}($d:Dt= u%4TCaQ)0Cfzl: {<:(CIAu$Z 04e³ 0 J[s:fi޸R0J6Lo_~.?I*%6ENf$O>Fi| mml:DVCy7=vj{6.MuJe{vvo_dzcnTj7.QIӏ?=mܥ {TC<ɟ_+=Z\G].j|b+..cXώ۶^0;ֽc{qͽnum[2񓗾mb+.L iܠ]Z8vanR2 3'(%"ac,h4E`Q,Ŕ&xS<6m (/iKCG1-?S#ʶfQr*CcH۔zuRV\958/-1 28_p9¢OCGƒ&0%Mڈ<)?kZ T*lqv70L3ۚ֬Zh,ިN#pMa(𵿭Βio`T}g!ܒ$c"}C("|B#Gv<#c8yE0Z-rQ0DA|zPN /pGovKWrѱ}@Z)ο2/wqur'~s<+W}l[!Ir-_ѬGT{]BO,Ck2i/߭S#[0n/O:ǥ@13PZk,*r z\t `T(e.6./* `Kf5`{ӛ 7+1[3OwnMP)F&qm|폮K 2P#]x% ֑^[;Ҥ4~ܐFG0&K}50,9|,^Xyg?Wx3qOR 0oSݰAװ L!ħ? 7S5Tecy4T8ϭx/7hBDžc4*UUbӥ&o6I._{ Kws_ZkWo@7E$ER$A R#<GxơE82ƣyB AA74 bkl ^]յ=?UUҵ~ @W]N{|i !e*un~co^=-2v˭ 88Nexf5s+v''BN5 r[ryxcU ^Nߟ8;$Vwha]oȿ|wHu()MN/hh_vܖGwIzKuҍ֦AG3$@% @(5(z8�@ 0JY,[o3V33*"(vC5K<,b38p7Zh(؆B'R<Zfۧtˆ0QUセ8e=tb&+6;T}dY7݌un 9ۤTJEWq#c0BihGeͯ]o UUI䆜;;עm[6o˟`frb¡;t (3TC9NS r?#5ܥqcx{g:%!;S) 2y5s ASQ;MSn) =)Z4Eabi6l Pt+)"BPFjY)mul ^ZNf$!!A0VCUUη rWwUft]g0J*3Q+FNS>2ٛI*crݫj}e^l`UƱu 6 H ̵љE2nKy|*>H'N3b 'hj'  4͑͡V*}CS[wc /ܹݱ}i-v ;r(Vk9ۢxG_j_`az#mXd^is4S/."Nn)zxBaK)߳[ 4 wÎ^ڿݶ6\?r^HB? P-na*m%$)E+j2љ`4;3@*rt{݋eX,$5R8, *P5F+5k0̶BNOw-<\XцD랏Vi(*sS.4M]֖Ch4Lb1g^OopCǝ6 sr. oNs8$Sز)<# +B6 ۭXz=/ɝ^ڿݶ6\( x08<~ck6ҩ/Yr),c֟B͸d Ws98-7^J ;iFTg ֳhO+lai%Ġ;Ȱ;$Y\) ?i'1A;Ï eB5,nܽ%/^2;KXwމZ*-khdCU,En cU>Ni$ȹhCCrw<˶Z0930L\E3DI̩_}ΕGx3_tqܚAkmr>n Vb!.zc7ݝ^ڿݶ6T!)SY 4Yƍ)O|4@)i"rJ(@ݕͥBΠY"!AA!#CZ|s S5 HLܡKKLSL`jSغMWL]E ,%d$tiFˏvǏ\n_./2/]BI|t1l Ł25!)%YǛʡ*jW4E7hfEP,pM=ӑ|#]vn~ cBfzC쨂na;\h]v {J> w wefs%Bl-_bXd(aHRe%ɹ)Mց[gj^f)EaA.z 86pccK% A%ԣ:7UokQv/QW-ٜmqvD!0Nu"T:+.t}ty!RE!.Mk:-B(hȡE~žOop#[evsog1->R}x:?g;e~5$+PuC*LQUU?avȏЎ=l { lkCu7_Ŵ \2~ F^YEQJ;H6C( 5_;`.lV<XƘIQ+Pz9{sۓX@=j1NT3@SNl+୩6u뚺mVK/2_ ]yE!!*PD;rkX BN@J^J>RJ8ݨOWЬϟU8x]:IN>~oH:У!/v#[&1~I}rɳg8И&:+g~7\J5q/}6!ruIgE5iT2ˑ28ZDbN`n{DD n+DB#Zo]@ᳪD.b!!7c,Yu:aZX78^=Έ=¬7l;iU,PJI)) 4D@T zUƏ|\| #W8Nub\CS*h"[h= CAKakryP^$t_pydl ],)Y.lCV'fۄQ$7E72v~ַjzI`Z::Qi_y=eοeeu➏>}w۱ fֿ8γdY.8zQTsdmgu:_#Oi/ 2Zw5=DIiZO U "~EBaPD2$qTgrYR jDYD+nq}Vv}|,hMbbP K CT*@|j8dEuFZacGFY)4 <b[;$I;^ڿݶ6\(@}1&u aкC׋<,ޘD+QT$2`\\D| w0E f?QQ)[eAlѝ#ФE&"mZ9y2 Qؚ-mYx_EpPd]_ +qp{UTU͠hƒrhYu{L@@vs{UFF9v}4k3Ӡr+So䏨O^^V4wf&gordA1͹U}K.0k8>)em%7dp,( Cy?B,4iQRrġ%+~*G GDiD#n0Ow/#`8W?iiS5)eT;\Ҍ'ǓL!shǴSW92XU0EYgB8u\hA>11f+HvBtL.8=X#`d#U&'SC:ܒ,OXr| ܍g|zrB=qQ(h4L ~Cl6>|5n}(}Bu5#o_{4xX+-# DtWǴh;+-sgoJ)n|OosF{ {J> qeQ'SFW-.jKz ceY&QDDD((u z GJGH|P׸GihM $>\\diFFƬ7˩8WXR2јS?w08P<;i̲(PU(bHA6$ PuM_ՉI*p W/S{u"ƫթLctSW ^G9r;|#! Oq]LJVA**8c.C.S- o]w}aC% ן|aߺYʝȊeh]&=2EsYTx}u8;Oͤh$YhBQQFL]:zp͑;e\k2\q?;yQo2]Uh.t_ )%qMѡ(iƠc00Xa`j&;!±Qȥ# \<˶;k_^^Ǟ} kjas:V4}×?ą~вa?txU: n-~Co|_;/]*?# ߮{X$ޠoeFԮc* 2l FEG"Mc Vj+ 4O| xWUpLUU9T8ds4M\Ĝ69X8Ai{2Q̴O \.E^7Zӌ-^qnE2dM'R}qW1"QnhNGK}ߚ6!5T4}0$TLv6/ZEQmq'w^Oo7{?{o_E>t'[!E%2BEf#6.>7Nj:GwreM2emK6j ="]񟒯Lbo[[Rz`oBݗ\ սX7؉kmK[ Fm~JZ~\c.aZl j"TuRJأsŋNxi[TML-b v14/~NTHec'.}.zak"U ,4 y 超ZmI#k#24TǡfhufA=Q:չ0`}1n_x#__+^޷H(ﺗ{G$;4҈T MR5F#/`7!]q9fQuMeYw5ĠM H%4t;w.iw R~Iq 69&@|RʗO?bO*rQj5H]Z*RӴKE.YX#l8^K66 nLXhA"4[HTC,#tsgR-.7.sſB=e}Ǭu#q(@ -E' d.jl҈ڔ*V0Vx?\S"eFP5VKҌ??)>]B IXJFy~u u]z1cV'a؅1h{RA$$QYlYzǢ(BUZ*r;cR7xO?EO2xH " <ڏh;4Ґ,KؿT UBqw5"'o-Yל:Sg{cȏ>X*e;~}/92B8ƢTi)ӿ @*2)^o髥;-n) =\Rav06TWf(YDY@Q5k)\GjFa=y Da0W+J4M#2FIUˀ;@=Sq*t/OC18\9˵\p|8E,@Wt MS4ʶM& Te ^Ҭ*^8>RvU4|w(RZ.AP_}]1*ZrS_}J8} ;~RJ4A(oF$y3_f҅eer{{>|\jfiBĨJ4xiJP*]U>}~<6O+|7oQ3$Z['/0J=>wZr4hl[=\%58_ws տrC*(&1Uݩ:E\:iRڳB<˘g\|UHHS1 f]F ruR%%HjQ$ *Hcs , MvNl'b` Pp0:ϝ``𡛪 *2F F|ތF߿(9|Z%P[3MR!n.k~^INٗo[e$bf.\\3Wۻ s u0{s)7/cVF* Ŀ2jӁT(.XPY+f%E}q)DTUe7iMvS79b" nAYrbW>#eSW[/\T~H#jgf Vj8!}n#t0%!?Gbp( 0.|z5H)9 a&R8slPhiwB.|s0VqV*Jq~p.awR&1mݞG$}O?3Y"}3k~!fnyaF߄e;}|o^ H.16In4+a񗰋I>Bc>|=^OoЏbaa=aPΒXOdC %UmKף:t4Q;wH,hM&ۓ%#X}V뤔4jS;\.j6*~))@a,TTE0/Swy=ejDF]?:{dee5f"=ktba6bQ7o[x$bOŔ+[H{ogJkvzٹ>q>k]Psq,*Ut]lK)y;_.W9|PN`l|+4]U@8[crز)6F9 x8 <;ӻY?h@gwf$B$$_RJTcDdi}6y&2fV[cX7RQ*fZP9>K&T*ͨeX˜N_( 6 Nk;>Ġduǿ^g?q~C#JRB=0Hbb ;:'Nl|rm| *kAJI܈#[x/!y=7Ͽ4/ βsOr!wzPun78{ ^d#w+vo K!JU3\4g (p@/a{+aZR&Bv6$ޠjV\[|xTٟfn +M).. tNU$3IA+,?P8k#H622pup)[J ]rSQaR-Pݍ}r0[fNM*?aOQGH/Ocz I(F/aGGtMT$u4}vVS̅s|˼˳o~'nsY\VmH=!e#UT!(ii7i|~w8g^8윪iKC<ԖS5q̶0 MQ#krpOl<}P4@SlzWZ.ņL!ćW-\ Fy úKKY[A_'(i@g@A'a&O|,,U+/AoF5SUKBGQm.GGl0ש6k<4Vpfuԃӓm4q=l"q*ؚajdZ]㹏> j:ڱc!Rڝ_HgKy;49W[6Y:i$vgiʛ?!'2So}_y{Bu$ڲzBTUöL4Cڹ|)F:O^<ۛ#O.}Klfqձ[gM `/ɧ7$'BhOCqߪrn]MЎ^qM9=o?lXDtu+DaȤY P $_MɧV-⽐#$2Zs3M\B5Ll@ z 5?_Ѹ2\qh?9`K0٪-1zbGfe|~L}7?kE{8x  _=`xv' ; %vj/ɧGm6v ʣk=vLw+$LN>pd]H`UC)%q\q.\tƢ4u(o{ǥ$?x+Y M뢒u,˘fx}3C+Hec*>AٱOrvpo0I*>u>*U/IEHHױoݾ"2F ݢ4$N i]ܣް#MbfI}0JYDjgbר7AMxIPEm^n$a$ICAjqCnG~sUν{r{~y~jo0!oK)k' Ѱ@?ivWF(+v5%#8|(:K:ٷ, ,>2jȶ N5Oҝ[q(LkRؚMŬ0`IUS1ISYcBj*V@SSxk| * Ahdbbµ ؆\'""f[!S`{,ë5|evaxm$ϲUղ6I)5cJ:ע'ʀيyb 6viJcnK!$S:4N$Y-w.O}Wmx9{=~~nl^n^eYG1V)WLY&?>cI>[5KK!?eI&}NH)1 cGA@P~4(P4w,˺[8Cu04\3z-8[p a$EdyFrd7 =/HB$"qjjq\g]qG݆!Jf i*fGuPJrQKlK# C,E(0n!RGHdB;Luڔ,wC>IA.(Y :ӝu|`#eA@iS}:q@!Z̊|(6l3DgAcPU egC0 (XwcQuw,M<7 ʓfϸrDU?9}>U#O2p0q#y(cl۾v0$I]vQ8c4ŷD"yGq&Ifx'rV^cO9.ׅ? J)O_) x,H/~ܩcBn{1)%emf-8 1}CJm$K(j6m̐a4BA]Pn #2|4 EӐ}О8"Pdfy~,-TC1`Jo1g8<5T2PԊFrp-)%^?4= *T2(ײQUuC>~9!T$|sf+\NFT`=0;q[n/ֹ>ļFs˲;ĚVt_21Uz'f(*]{n-[xzG0 :EKxbVlǾr駘x5Bl'y'( Y;a˵)W4de1.tM_cRJ^K}uӿsaw&C/6!~OJ}xHqrr;BPZXU ;v{iۊ<(^ E -gA4F ݒ%F;(B3 VEJd;w8YBb&T*2vh1ՐC cݭܯ0N034Eb:a&۷fPC+UU%.N 'Wd3]=r(֥B*-IYI3ϧ+Oz١j:[vEq(5;I^P*#wIq3EmⲲnu{{>),webvV_%Y?VX^g=qwyG.ȑ{ߺgxt_۹QOOgoW_|zЖBF$, <]T"g[e0VOiߙ&#`0*LHTsĪ7=VDI,\JL{$XE(xG$ :KegYP$ &I1Ӊ>>X^QOQ}c2(Nm1  Vexm=e)Iʟ͠_MC ˢ<["e#zE`ns7kԗynGUqE-ԓ$ 0v^]*#Ͱ::sc<}E /^b;_?!g9=ŞOoJ>Zj]f1(B"T6/:~*V%tf@tM.ZiL'N,%U艒IFԠd( Јqn8CQw0RAݖ(G3d.؏kZ]Prmn?nuh'9:RJtνw ~.{~/fTZ S~(0!ˋm'PuM)Kc﹗;a f{n_|i^_Zq'7 bvN(H 3 oDQJlCb *amO:wrG۹lJ؎9;VOo7J>@q3_T + 僀{%f3UT|^"]iHTe;Rdae~)ư4 C5A( E&4T)qш8hLm ĢC'hF~⣫^44CEl`p~+yPcZOJP _i!V0$ů7 [m!oN Gj"[\X.=#3tdp^0oZLs~7D!nyxI;6=쀒{ˮsn*WĜHDΐF X{mZA ,l`ax]xu6  °ɣɚajMvsW|pǭzU]UU=S_ν'}?U 4pfi5g,Dw@3n=ꟜX!|}ۿfo&6b`^ !l)IB 8̯u.n ;Eu7e nwK Cٷ&vv7t/绛`* Uy)q΢!sAXԋ4R P[2bs=G?/c_IjV2Gw-pO?)i5L%׼YKWj$wϑf?]G(@Xz$)77qJ/HRв97Ta9\x4'?O[K3yd 2E`Yi$ RtU'Nbzs;GTINʗWx?} NY710_$:Pr}bL>VA'Kq +C8 a9&?KнBTC#Ps_)n EcD,U,n]RuLLN4O Aͬ 44!kM]zqCA'q%WT qvxQ`}}A<y+|X^'Ld'Ǩ(F"",CkۤMJ& \xwtE;,fӐGaW IDATn(fPBŲoNĜ7 VKe~8{ lZlU&0yyf22>nދ11)Oxor~ֽ#|͝o&6b` % R/B<Ss@ˍ tbN|683i\^Av;H&%bp^wx,#IsN)eخysϚ]ӣ$;\X4k3{՛ 7J9;5O{|Bb+`f L"{ m2TTA)J1f#eD yۅ2Geġ[1}4APX$vB蹼 EWѧ?џ0vasX;{3Wh9Ex}݇PoMjO{|^_!st ӱSFt0 !>!CVw-qI)__]vJP.g vQ@fy6X ?fcCG);Lp7 .аefWQakx@ع%yQ+C7V0Ȼa)w/K(e<''{ 38 ┢Q'se `mM|L]ŋ:nε{xbUzܥ\*F A\hj8(`qJJAj%Tj+22C~vʢSGx.it繨HƎuݺ9~__$Ə"PȮG['v"ȳd Kg9'.ipǨ6N?ߜxzA~]vzؐ%!# "KJ)fCŪ)A$ e c`.\KټjӪL"?%j]œz=4yȫ tr3Q,a4pݠL$%4 !(#^ or.ݨ$]Ux/8;u,Mck֑R>03 @QB>ZCSKkL6۠<4|q!= ;e+$=m0 V#aa3fLq 3DC`gY8vgɻxRG6Ib9ʽ˳4gf84o|5Daxo&60*<=!@xWJ\.6K`[ aPts|aTu(c.*p]B)Vƹ]b+d ;Qk{+{15V"CLDA(QllKC6+2誂*$\"BJ*",!3ε|҅GT8B {`/vuՠ R Bݢ8>B=NkaV&e1jdi*Y(U(ܥ} ZO.r3V҈cV] IN䣨!WAl<"3"ԕ<"~C(϶#PF!Jc$4) #8%Ӷl'?i ^_O{.|3qOb pkȀub|6ؖ仕Eoa +u,\YFܙBύUXY [t(BSSB'>RDo!MIFF'pvmaIP(R/VHEI u!dm1R*Q2tbvcPfiWޞ=…G҉sK)kϩP!A"cl]ZPԉ+-zӼKrBD| S ?u l~ǟE-_mG6TQLXXq{z(dqW_^&~S׃o&6y7p ߀)󍿲p8G?R*)$Mh+ˠyf "_a`.8bJ $&@WBݦ씩;u ŠQhP0Vq|NP0rf(٥.ble*iPVF4 Q8h6H2:B(BdhQ1/u91,dCehQ/^{݅]ݠ):$ʞq m bdNXmP,שk`$H)҄8\M62q؊y$MbN};s\9ub1(zgeFB['v<7'ݰ(Tj$iLI4,1b79Rý#tlNj;e=Ll| 'gD>_@_Jœ#B|YJyzvq )A$ & Qu0 yNwFq(,?j7BF^ͣlJziFJI'pT &&ID ZLٗIюjF* ;Y05Db? 0tnYLywwH$۸w@B0O{YgƟLFN.S2Rť59o+5Q()c.f+MDOfI%u ̢w2v$Q&׌KE QJ$s[H'%UA>a)=;BQA;vnZ7c{(;'x9oɊɽ( )inZ#P$E`*1PDnjl˪BIDܞbEmR’{| ^,OBywTMI&4JF0 190.N6O?Z>" ]^NaLI)h"bzqftE ;̻}=VJϽ}t4 qAUYves%}׆YuK,2)J& CSz^D1SQ5 &uf{=۸w7?k/׿"~U*?C g=si0@T6lk2iw/vG8Bccq|NpK0~)|3; B7% 8 2y^76-$y,K٬$a^g\=9)fCy2_.EqTVYWl-c1fz3ԬZyU 8=Lof?Q1'y̦̹-.A4 иRy^t|`X&c ho{yI((A0M"@_1I))W|-U%Fv@PT0DHI$Qͼ;RJ.}W_|w~]UG摧|mY,aĤIU=K9McA a3la&<݀KFH٥:LrMe7y̹ޠwxzS-R !%{h7~bٜsX,Rè(:Cw =~]bH7ҌvQR ]X0#NR(bzjB";b{u-4ehr޹zN_gU|Gzcwj(FQD5O9ԙwi]Y.{yvܸ0#PfeI \ݘbҜ#-ɧ￁L<~/wg;e=Lltc-!|Mq?^ gRʩX~x/O!D* SwI>lKsd^sS: M!+ǡ4ͮ٫j`CVآHeB^gΟ_OY/Йf99GݬSsIآ'/R+!lFS򝡆]hj('3L#"-.^<0ls2IN^NMW_8|Ͷɲ'~HηOPMuOaO{O7H(*C11Y$)R(WuNYLꗾ~8T<'>Cv}i3u$Ny۳_@R-vU$4wC:s^'&hBEOʭ`'饺g r;e=LlDh$vLJy\'s3q?/k.7仨d&g<ۊK`[za>ZSCZ L ȅ,DL:0(u8fWq;)dy! ݵ/iBݸYi0u,SPp+eLm}ŽT 1YO(ZY&0ghS+RFsH2IbZDVJ'ъEӤ'Zau78wVPTBߣyeT j6xW_z?>.b]<ԳS;֒Ac{4&'q5wHY$7h.; 97Ҍi^A*Oإ $YW$a#ߨ%Mu l*8*$g]sZ-c UB;%(xb7'⠏9~w^(KPv ;!Ҙu3 X3Ot.yD2b2N1usH))*UPԋEf`*IʐYoUd.'`8Bh!]RH:.s s`08Ii6H#2Gㅟ9@tDT1ܔk|9$-25B'bv!,Ernͭ@&K$($iJJ$Fӷgqw]Nۼ4/_\qL4Gxg;|׍`N"<9v |Wt3}ل׫'RI&S:EӐt`&7Ͽ$[cJHRG7/ǵ2EۉÀR. }WJMB C+ G\ϝ`.  P(>ae[7sܖ0wٟdh.` @VjF<β4 !4F wќ~ؼ#"UPk00GQO|,5LҰZnHijۤ]¤*TMIJ^D^ET6P2s㟺gg#i2̃((@0ﻏhv.қ؏XOhQ({fh HALHRɌ,MѲlFf"IZ3ZM4%xJJXu| ފc}3o>z~K࿾PJIöm8&MS ~Kʢ(}jږq3ee>B$Z;)}8CӡX,$Ɇgao|FjpNS $B6}ba: L1HiEy=D,ΨulFtRbcSJ~LаELU2O.^ g8 B|M05ߦϠX¡]TT ˦ݴo |\5Wp;! ;ӫ=Ͽv s!ZWf1T+!JHHKd^nrҏq;&BJb'c(؍M^GC$H@Ljc5$_it}JA&bYg~3'y?dvi(i*A {']RǙfƟKXE' wreZ~e^ $֣) `}; r6xxN02M}OU# IDAT*䚗UwC7׭-]֭*[^]&IJ,t]H)}ݩ⮨i+;ou|qS*?rOREWe)J.&M%h1Bov(Xkmۤi^NOS1* y fiY^"ry?E rSr7jDjJەcB!>y,&*LFi')pw kuqo\s!L~}s!zG7FR|ߩo~kV')&Z{>PHcɈfҨT:\=UPIcc\ 趈.vH9ih(YınS ~to0呧axAVí)gٳ)Jl !Se$_U*|zca"q靫cЅGC(+-|/ Vd[)e2A%euE֣),GX¦H7nsB[rR#Um'g(+>]A(6bMKU vYC4"qyT; 4a8I+hq}fք)}@E=I)2L \LJ=3ODxMdH"5UemD6X2@>sABSlu4baȃG.8XfXoA[ZzMI7{dD[M xGد䋧@X  1?,ÕRvw`#w8-,my#B[J<-{[b0}v,)%QV|ڒH#Q\~x%yy{DZ4IQ/!ҪbƸ@`+6ar{npQ8t4hM(`ޝ'E9x楒ph}MPu!a Ą$ID?ZA KVY&{\W9`4 cdNCJȃ'I.q\7"mbQ\Ax}s]݀fRPTL$PlqLQ.! PF)^}y.$v ȲagP @n{Ii™ٷ9>6y ~~xJFۦI,-Z^4JP+~$M3f",\i#T4];ڥ>S<>G(h)Sop[5rɡ QsC/# 4d A`+lcض}\[.ui) 2M@]V7d >1䶾eq!Te!fϞ,:ۼ9՗ͮ7u>#O=Cel)%xNA"K B!M(z([sr~8p8po[׬+p/mn cxPĶ[;,"P) q`8mwװUH&_qBHw?8yPgSU WR.6 RR;1[U&u] ø^]&[ݯu)c(+4nu|05 {T@uJ>Q5Qj{QUuJAֶ"#J(V%5Zևaf7K+h̫XDi==X;wt4m5zYX6Z[$scTM;g'1ɬ?K9tv[_8d>D+Thx}x4T!(Xco-_V?w/]¹x7R1 FsPmHHE3R*_s1 ,)eڼﯦiCLGv.VD6Fp>:/K_ķAӫM'>\aƊwg+*G: C)kQܨ_`:dR7s Ç>d`pS|>Ika|d~cie*n*c;~ Q UeW)Bt R?mG,;"SQ6Λ9[j0s(\BTehed!xfWvaUWR GshM:I(c]YGuF9<Ő]MըA bA3n3k{ ,C``c(:^ߡO^Ўr+$/ϕ MSJ'޿̻H.\M"#x=wŚǎa3cw0f4[sT'Ɖ !wτEff:xD/UWim,cJ$ak. !'sRAmb  %3Z}]n$ʋs[Ww呧 nyDAĄ*d#PFTSXr[g9Ir C;i^x*?=Ad8EsL4[CQ۶ou?Gi)?y`JJkŽy 7.ⱛgs8 <8:˯eëVQ? T]3? kL!fS L&8d[ڋ(L{tf_kv);TdcHߧo (~I ~` 0%t4j̶9ꪂ~ [anudYFX)޷ )% PSQ/@\qt 'xSOSqm<*Bq@T۬E'=@as" \:s WN/h$?A! ]*yLR͝rN2BD.gsKmEܐL"dUaF|kk-ŠC4Z%!eݰLT&pt8y{yw1.ӈ( QNFt Ԓ9E3hb4@ebi &G1lOs?Ov!k_[Wq"'dBAi +?ѥwRp0-#UM#K%a+xe$Q]PS oCG!^-,;&1qfhMKhwNKs{MzUVc^bX}x;,MJn`7 amG6 I>IFk[جhaWY DScAۻXRJ2$S zdMa!9 7$]Ϧk6"QeL5x9~ebӃ{y 5h ôVswq1 ~ʕW!T"3٘^70b!uD2kP, 4un Jv;TK~D'1 EqKWС*RJvN'=q!E! .NJ~wbUXЩVN%Z d 7}^$"q996C%s@$Pu!Ķ $AT d9:WHℑ :vK3sf)661#wai͎oJOYg~&DIv#A$? tx囫+-VAӿq#K~~?@4$a|_U<,Tk{W?].gR10 iEG$eѻa% ]ڻD'ͨTgPjikѤVj>1w۴qL,8_ܼo>G9;XyZ`8A*Q U#STUP-B9$2 @WOJIRQp)S+dA7OrcwP+9}fGIG!\vaLDt:(dA8 T,Cھ{^( U,Jiy&s" ?d~-AUD2O CG BsFʲ$;?st._+}Cf)ak×_iV}򳔇GViāGtˡ6#EM_w{e? $SE?S߳r?iI4;L3H!Mf*Zm,; )?Osz| .gsm h2waKKGYEMP.*ɺﻪ2#`m)kPAQT]Ǵm74$^ɍKfp;M,҉79/C>pGz?쭚GyX@u;nE٭qqcpo<׫'t2j룟4Z5NgH/E)|N"<9z+k/.Rk[.gs+hp\(@k!UqmivMa%rneY""K=b"GjG b7s1 2$(?n$*:/!)D&).~)1]r6'bL8@7s1TkXw {"4Z秱._ >, Cհt!%$)8{!T喉tPn uն8mw} Q(4M\TM.ѬrA*._\q}xg-[j҄ <^s,I (jMz P*3rTg$TJl6Id! MW2Jɒ E E% `!ޒR>ӰK%r[2O%D˘Ƒe,w 6R&D8*'NcG }ugܿ\؋vj1dם#ޖ/ګz%[s fF 1`H1$Ȗ5єHliNvꮽ*|{q?Dʬ\ 7xqO( ^o]ًy̱*neZ*jW44aZ {K 0dY&W)QPFDӉ"2ӉV?J)n$JH{doGR'hP[7e DFd%ҩ)F6QV׹ 3{^biMQq"w7+Kbpf" u*rД~H|qOSm~섽;G4\-I2玓K訋U+@E̕ŧѓM3, F1iҥX?^\o&ݨK/aa9ݰ p%Y]?Y;.4V«WgN'9&YXUG2R3*yfqwCtdN_5U@n.yWϬ񙇧M40$^b IL^XejBBcBLz) 8:I^( S_1S,I) )!6Hp\ /2nً?r=!̾*2唋'OO|{^ IMvڷ$˲H]Z s̞xb&RP/gI>+1+?\'nyӘLq>”wnf D4'\S 2CTZh; yaO̾[J912WG05m͓',1z3ϣ3O+UJbKfDED4`Ld?08pi8#i>5y^iB3VkJ(,m!bA\, XLSzmDix岬`1Xk$\ץ(!_ʥ4>q.i`Ph$t1[v/dex%i I,N_ [KX ğiSe2Sy{unط$43 ~n˚\+'?3?% 6*f.wPXB95Comˠ? 7"wҖ䳏`OsP$]U)C >, dSECrq!ӱ& I9/.˭N7OcMIQ4."L$8egI%yjIWRXT\D vwSI|^R~MI\kk <&}lS z)<j0Юh@Q5IGۏ&&Hv}DqS]_ 1Cfμ̥^ix>܋BYzg /|I(\NpG8~G] #YӞLkn(«kmf$9eZ>.y'{4Dq2 I>7V"HBT+<'7r A2%aq7|6@>&ՂZvOYr?;K?ѺJXBC=ug&y[Z6[++6ݤg\eݦ)N˰pM<a+6ZK0 8Y*z4a~X.H݌:QF֚<;=oټkTmH2pOWJciRBPWJn#+RHIcU5J)~(>vEid07'd)R{F1\}!y>^_dl~GvJaL:B?@efT?$m^](V^>˲]!\v@҃ڈIY""oTv=_wlõ !ЮC$I) `#Zk^gI:~ #Xj1L .IV^Ga뤈bPP(gP{m`._|g* IDATٙuLGCisW| 6:&~;S~Dkh>FE ǶubO6ϲty_`jS4*WE."ZP3N=oZiVBяCGiۆ;n`?GJ_I<=g$ ;qim˩@e^ te\FSG^PXEmWV Zߕt tqQdྑVsR$Rcq1O!5En. V^rfqC mR``Rd=p#aRc˳iCXpRD(AB6R3E9rln5paz$Pݘ^LưJ4 (jaasO~+/=G}Q8e9e ߰/rQecZak\WOFB161FvjYtueYyf!M~WgVW.G3z$UaDo1\i+ak혰=giۈ ™6هQ9:,r`XU .`ԃkaȝfE-L͵,r4Eߒ} Q3XbRqۤT0o ~bքEL< 8XdX$+2'KBj$”9<( 2ؖm&TM\2XT1Δ/f`{F1 z]eѰ݆Z"?+u#mZ\IgZ) <d>9.^F)rpq,%8ʷx핊={Ci\>1gh:m;!ȒR^YLxCc|]a^"ϲlXZt,CN]\Kh%Ѕƴ-׻~o{_Ƿ,-y3o__}l.ECZ0\ɔr Jwsnٖ)&Ɠgm!Ĉֺ]Ql@kY+/ݰc'y;s)Mn;ŪÛ2WQ4t(&Okʥkr˄ C>ZAܹˑʑ5vP4$6ᐉV>M/ p=$<'  !V]L`;iS&xi:'ӧZ'MZk,A{g%p^F]7eg&MiIr ͭЍ @9s.rYs` FqThL]4]+Tư[cϼ~׼(y9x=Yp͠U(^4)4EK^4vҏzT q YbHlO.l%G/ )=<JCҘrg󍹖V\F jn @83f?O/=VOir~+I>`7Pio&/"`e.4^q \AݭsT%Nl\C8Ra[d"B+Q YeJ) Nsz="b*1 ^ar% EruqBK^ [6Z^'`jwzdnk9|ذ el(8cGI6k zKԱgK aPs> l CiQiR x4']w^yqG^YSN1}s{-,a" Sٍ&E!^~e7aHܠAŌUxr7G+umZ/.iBwiC2X ]]G&,{?1.M{G,sli ltץ6Ro۾d奷2vv_4Ea/Fbz6B޹/mB;eb'y0o12VuPJg^?%'T&ZFnVD9f)diZ M[f B@h\Jג[aN\v`PJʊ{*>78Z9fQWo*u:_sI抰\l H9>Gp0 ԟTQLu[(pdɐM mZI*KoPJzi)z`Q;0!oLhIrd⪔d8vc-,"G9ztcl,[g!)v MW~}L{Mm"G p|4K{KvÏh(?o5SW_A˚A?VvLk(]Gt:1Mtq}k?s H5Pu151ݙeBR8f9zNF|{/ ;a~fv`S"Enȅ.foDn.1# W m5ҫ>NdNC&aQ[Tk1WwÏ@) T+Z7{J8g3y0a7W+Mf,\ns\D;׵q [ȷaJgmI.F]c.RӸB0{GB_Z;kvIw/;qimK rD]i5QBv.ҒzUopp(02'yϑ\_U,c75Ng^"4s"\h-qrt4pj*y|Qbb܋VY4l c}ۨ5"GJ R9ހArxÀLj[x )X3+}c=`HcnAk*JbFĠ4٠G/KZnM-?"qm_S?i_!d|MZn_+Z}mN1~%UP Zp!闢PcFuX"}o=B.5qu[8èđΆ,S} =d85YI9@s+ѨN. *sjҫknʙATaĕ֚֠ E(wL$(՚A@)SՒ{+nևݨ`6yk[P 7 y_*uꘫ$ ,(b$Ĵ-~/7J_am=^jc&1KWYt8N0,%j v^ET B% Ư[?W{69|Ab,K&]}Ks ͛$pr .BH Ǭ{+`N/h&Z'˄Z`0 n u'-N\ٟLܴ®6A`!8j?,Axdn\i1I d0]wRШDi2Kmc8 'W5N|d W6-h@si6\j EBYslSͤs*o^ 7_ zODLkq=Žq5hQJTÁc8Qyvñ۝g_} l -P?Αw/R:Rda HRQ Ԯ="'r^e4a}sCm?)Ķ,En[=k?ɒRZȴ%d+ofJC7m˙&X[oJHI8zS,(LA֊PaXvH}w; 0gBKk}B8|BB+i7֥wкQI[/ͰE12⏇DY5tVPhݗ.68iU`r4ZDˣ$ekK<&t&i. 6Wp} R!eF.rdz/W^~3?_w'xۧoq+U8&2Uϡ- 0LjZݧXj$ ҠXy!)z]\f~ ic qm5cKۉ#Z&Jc*F0eLcu?_$ Y'Ô|rvgqHǨiwB&'NۓvfJ Du7D-%*x k/ !lrZoKm?I>ۃH´q%T."lQ2oԦ$!sj8\D"lzMeHצ_ҷ4%&ulLY̫0afSg<6).Q݄sJ?8 Im3Ue O>7n;~%VH{~LzlTA&qVQ OZk:I1baȰ.01,L5g38tɱ(\[(MU[b~ߵ߿svq"{ E.> afk},eUW £n.UŤy0_ r$#LR!En௳CJe;ωGނ[ p+5F]7+ȳ@IbI8W٬naL@2nλ~KK|߼H+R){yGߴ۵VISTL &T4_pu*7Ӷ^:›m~%WZEU6xiYl 0Ԝ:[%{p `l\:.WF)("2z9 E.1ݿ@iHtD=*1Ԯ4, d@N0nF1;S@,őh~[0H4T {[@;1>b^,A]&Jn*X>,4XT=?wsϵ1%hA$H6(0}FhbՑ'_(p*uNKfB3~Gc7)J.,(4YZ`r[ɷ~4%~7"aټvr+%ql) CT:қ y++ ~:Ng0WG&[ 0[k}WgZoþ}|{V hi6՗)>iMiJ̙*!XvBv!**‚ĪxB B yϺyΗ e4_;j W Ĩ,g{fc[?)>xK.e♚$ h0\VrToMJaH6Gku߳GZish H)˺)?&30C\+QCz5eݔojQyvmvaf&ZH|ST WL<+4>A\ۍ-B*pp՛> v!ģ7eǭnȿ};2̡GM]tJ?5ǰ=b5tHu6iGm~4#RUiuHrL HlN4&0Vl"+KUϰ29zBċ%gJ]\{)?)+UiABa~@em .zۃ_kMg䅺5&Ja^\R\T4L;Y= Bj0qG6HH)9YMl \gx7 vVW4gg[cEVFb#C'2# QZ%KQʱE<. 9D\cRNBVi:ކ`+zҳ;߉s+tb/S8/l_qFaHΝBapm5K x4N=q4 Dbm>V4*j}oH>v=F=0(rTQͬZk(*::=گo^G_>; j-V&[N+rmD֛fYN M<]'} F`3rTƶ`-7qV~+VY3$A ַgΠh;@)]BhݴTd,KED*%=m0,&z|9Ԉ_Ė2)A:7|'ڥk~sBׁw4[w"/KE7M*u[S*X y螲"DR8F{xEBwŜU"K-]:~Q,xqE<|(55rGr5UI͐ F[a.rP8"b4\^@PKᇏEVGA4hk?8?NȤ !r #c?EcbdBP>orpI^RS͕,esiNpdiBŗ}Qn\%qÐ13sc^ZAWE+R}TJT블Vc!ghcCc<Hqv^L¿~ecO}:[K6\#9,J:BhA$Ï[JfKVz-vQz9~x#eEq73D"$xKsV^Z3z3`o4MtJEO k^GmHi[Rk#RWY0VjȽ@ F: Z^"_1ü v_|c&G}݌?&@sp=W:(e(MNqk1pͥ^ߩWOvʍc?v4_]:.}4wvtq+IEB4k}y Bpϰ;!fhT䚖͘^nG}].jii,.EktESoJcŸ!9/",u7<B_1o]$2qDLA 5l砋gWP1)%0xdyٹ K8 IBOHJAhA07w92_ڴ4Μ75m}_`M{^V9%X]¡%zh_tS{.I+B(6,e]^t:juYnYCU;?0DQa$fbUx |% V]K2?0:6{C'F~[ 0bK r"s]O'ya R=2MmN+b}A8ꦽo%<7IF6n-KZz'7%si´V &6_EA4ypIVW8^|b|8GiJK^u]P+y$vsZ8?40:dͣPNn\9.0 ] WhX ҋ?GiPI:Bw 3=ukL]#ZLA`phCVTaxGX5V11%i^K83aiwy_{~Ɨġ#._cQڝ*2$"@cm82Y~JXp@JԔCx|ҋ}h,_p؈} $.&n(%"avGO4'y \z%tihCU%^YRRJ " |#1;;5.hQ@%إKtIt#tr0HSjU&Xv/#_ĵX#\7fu ~}O|Vٯة󑟽ǽ!wb/| KɄ"S ݜ.ElQt;VL8wؼvs~A`2y2 QV%? <L [ie+q+_/mIO>$"Ľ>ه @la\ZkI>`H]%i֥cMOALr,!yFHQSĜҥ.~40 h ťڽ:0sd >Z5'V.ŷJc9rg~9Uୗ*Dï_վF3Ky@ IDAT>A8;20.R./%@%E|zyaӘ"XǚxA!_͞ǚkeENgB? eZbw!3sp O_L/?LE>X4b6aX7{CI_ZXPaܙR P^\d`PDx U`ur;ĭ;u3_ukZKR.q90^!([=2Avg\$_Dz\q}ңpB,E2}9ggÕI{L 4)sy:B@k V9o*vP YRpiEwu^q=x|kCYujp_ mhK~aFvz&AF]c1Д2ʷC>/m'pa,!4'hLϐ5qL=]4]^0$6>P>Z, T$7r_Y|;:vfz?{V.R.jqmqI4sT>[cI_^ov6|&|E?|[ϾA.Lr٢<\Ș[~cw0­Rs3 :gk) [DkPJ.jxچJUp⛔g&KKܲ ltBz13A?CYWXZLNς`[#\R(HetM!%AJ.aFrGj/WY_\P\Nt_@q/E{~+{~C?裱nDMC| iE!Cn!XZA8 |St;, <CZӇv\8F%X!5 Q׏,H!1"ۋuDB WZ`L,_#\O5>3[䋿yRĕ+yoǃ:x]ޭ\c+}%hI҆7[@ɆdãO"7+ȸё`1n"Y$[FdkAKܬ]'C%(De8l?,kqT"UJh@֩FcQ*_nHX&ɑ'oG pZ>O&W^4S bף49Ҙ-wg8ӄj*’ ._| }+w9?aJHt-p82M38y3g~ǯ8߼4&óOIѬyDcL9\ "KRZKX ъL = ˆJ2~%V)mG"&K:.ґBs؋ud1k';}H Pp@J\W%ֆoiQ!G1uש[GH) :+!3Xa<LR%z_>sDԟ:BMYy f)z1nKEyQ;J UUZ)v6c\tl ~慫RY5^#ґđK =7825T[Muw?6͏n0V.ƒ (滐 :(WE.r;A}oaUՠۆJjvކ۷^j1ME>kl$5/ɲ I* Q㔝%3Xr Y0( ǿ/mOqpjs5/j-8C9Ki_ '?%sDx(t?p>Ap()E!Abu yI^Z8(RJč5{zHS^Wgy W# GJ˼ %rJq {XcKCIi&tz@,OP-[/."i"JOяf[gQj 5/RB^ n}<.nlcWno6dP;ڤwnVoߪc`x7H i^?11ڕn7z"j3șS8׾Ȓ{riTӟFkYk1>L.Id# Vٴtn9{q4 ] SL=[G[lY# ra%nB։н=vQ~s֒iW᯼ďPܩ[GR>Q`PLڱ&r^`WwX{Zǹcn5)CHr]%$?,XI3T;$_q#j!Ci~*uOW)4> o,%7؃NΟJktC|?{?r{tzo]KT;~NI)X~<ކDPADի5}ߗaKp~CMx]Dn\zmB cYk BT#,p]Xj>cy=WkC$ay7ܟ1LI:Hq=]81M\_G!7G0̵ j(q\3.t[*B# '{Cx=7^b XR1ʲ$WW9ŋwߍ-Z#8ܼ)KK(_ 蕍R~pSP"\(nucpȊsy"j&̹,~z0͋kw1s98{uLA{:vYkG5{=W\Oe30PNnw <ö.BWⳣc];Xv["l.ewq-$C"VOs-'Crn8q]c4闸x?":עuqZ:mp bHS.VDn q8 :#+<7; Юā1&M^~Pǖ04*ϱAi0ɥ 8?@> EAiv PIѸJF13 rņ֒)^c {?W;>owc ee9-ޥMhƜ+k,|{cD?Oq1MB^۝!\v5Ʊw"WHd 9?~WޢK~zcjO&|x 1NٻƱcEq~1 v{8 46f1*9FXX+B𽞇r\AXy2 IU.xf%(XA#|< o8()C*yqfD1nbkU܈yg?p%-G>!ú K[ /i^ʗT:>:EWNN׸PT;S Y<{{DJOr=40'>}ZHxln|C W(]rgPḒ(:emL]dhڐf$ LNoY8.^䃑HGVyZcJ tc^#VeronO+z7_;8WomvBtYt 0{K[UE3sbc;낱m)ݓzm+ L!'ު ^$`s|M* R |HUd:y>~Yl/cPz M1~P9]bSֻej(<4_n{&+5Fm?1,?7A…+:ZtI:woK>J0T105q8UEYtBO(& _V/)&d#%JAW/xenتujg9YWJh\9T0 0@`,‘jYckINTs/xv[ƴNEH.cL ¯~'Nqז 9[YELv7/>}E6 ;M#xIFae绉Tyw7*AE˷;5q¦݂r\F(xy 8^9.fD6eY`ʒS@b@MǴ*7' ѥKj&iVʳC3?#sBXxuK8taH<_1 5O{8vjVUR Pw*9{_zXk^o}bQd!^~ƺM*ze7۳q.ɓAӆ]w-?IkUB;ZOқ,# %G (2:K>YmEuA})<8G6Fl|穀0cO1p.2]wsc=B8wjqeo?{.,Ҳ /R0rR+#i-ӺF'uP P٥9:;]g[zaGМf!,؝fJHR:#ͰȜ}6X[@i$quN{&I}*)|ϢCOԐJ'%/s;gO6/6~mcf7*WֈN [ńN`uCV[K+eP!BŷDn#IjA !]n`=BZ{%F.lb75AnK A9#ZJCIR.eQRT]蒴'+C1i=hah#kLȬC#)̟J8zƮqe R5 {,,/_}~}~?p{z3O?=LAT8此]S1zhcKrAzT{`-UZtT 9>Gkt Kʃ? "uFИ9Dhj$5i^R wFJR `rm]fW/pХaܯ6 >s핒5A/U7DYvοiT?cGgF]ûݜ#\7b1#4BNOGu3^@nW=6 Z J}[LM_՗;wp} [c R*,%B:6qa=kF17K xc"e&pI6r\1.+@ם`1 5~N@D$RMskC$%4 T+q/,+(Il֘h4*+Ls='FW;9~Fq8"_UhCVhUIyR2L-$$bc.>sk>0,FV93%cI%v2^cu>ќyP0X7ֻ88zy-@"<r<ټ=+¯0~MKt'ER%!g>֮пuco(evm<ʰQZ*k e9NOW^Ylւ~֋ɓ~We :,_,Wg{\ZjŋLQT%.='ׇ#qb""I/,Jp[*( .أ.3ߺW'RM,KFKaL7=R@8; |H:{dO?<5DZpt,#t{}瓌QlUB|y7Ccy3 O?1ǭk,:-Э^oDs?"ƀZzwp#0$ܪe͂GJvq۳PdPr .BT"NPf9Y& NU?>pZQ<4j6xWҟ7h!?/,.\A3?:'kG>EXL)J/zyYsqUe\N@FW=XQt#or\&cjM=  #%P j葽D88JC*/9~}r~>|ړ*dAAYCͮf8`!bW ]2o%y7WZQN#,JRqYkeF`en!/qq! ZNY h>xE]4gIFmAbǕ!׮D{iR1q,\b% mh(S뼗[_ 41nLf%/WAJ 4{:UC)>-) >\ \6zm'K֙ 􋬪ǧ,LM֡fG^̵~9YaEWOZ2s,X~z),Ә #r{l඄lR7Gn(򱅡褤pzJOЧ3awA#N+wk,&kŦnܐ5 8cI~|~;Ta3ƽ5-”BȠD93I IEJ5;蒢JdI~Š$ 83bby( /<"_ӧ69ũ>ϟ?ŵ݉9NOv],͞dg̓49g0(*mZ"QX?r*'U+]ٜTʱJ% MRD"Y$+$YYo9'ܯggzfzzHOTg{} I)بA<"rz<z++bjfo(Ř"AFyTr5U8t澜s _ FE$I OZ]CxSr(QZh;$E )iE.Znn}y򐙖O;~?H%'^L]40TOuUgoH:ښ,& 0}8G]~H>:2XO Zޚc<ш^aݾ .MmTZAgGI]%cH2ɠ೿kc6jrwuhN5ē@FW'Z?ywro` ,`sEj44~ L{ZE n7'0* bRܱPy E^=72O,/3\]EHmTy7!˜4ӻt Ggh3/| _0.<'~L$1lڬNGLum%RE¹>&HC5Q9Az G<U8)4aXW <МY 9Њ]rc%5uEw^6ӻFWXc񣘠5MܜG('זFə&SuAkZO ƚl̴9_=Jʐ rҬđn~I>Z^e>;/7 oOɟ8)Ξx^$k->W`g@Oğw7p%үS̄{ }ҖӸ{7 'iFoȲPKU[R.(HGcV (`سT yWpCd=#5Es <ܷ'~1'xSUa`MguOR$á+dP45i :wJm_o׈MYn6H>Y`0qlA8yoXh,Tha*wie, ܠb%h8 Sxa#j&4Yyu0gyq~uSvd"G \W.J_/0Xr0h#э?{$ .C *ZKh Z0;[km&YDJ -(B(BO}C j.`ň]ckJ 'pROR`g^wV6¦˓=z`"dW$0'u`^H>&q30㭹ޱf-~<\LIFC|FM¤E/%]P^0g,=¿c  {o//]Ս8=|y{  lxfnUY$YJ#n ЕFW0ɳLEQd1ܮ e5K^a0] YɹoW/=Z?c?K|绸ܳ^>ejsvf ̶S2Ij }3 ҳۖBK,A@C|ҫ]`:% PH4①)l&k-vا 4ժ.V4_z} Խ4 VUE2{ʚJNJHA^Yּ 4ҡ)޺K0-2z n!5+W{# v4T73jĸ[@B T7bHk#ÂОp`k-/|q+M:r?ac{o(4.k/ I]V~NȞ][h(=m,0 b$( `,zF<7۩E~V7?B?EkuW.E]}B|Z{}[Z*סnݸƄr@W%&C{soE:3ঐϳܛ')ǿi_ySɋ@(p);~@tHOoz?#<%Bro\=ZW o0#iYar?h7as$qB?cqsNKM-ii45rx:clX_:wA.m-eVQr5٭1ܕPn jg>}wu-ly?zSon, Qg]ȥG S.& ?{u:oQWDIjP uy7kXc1Xai\B}AaHaB,SoL]6 <'-mdgLY!?64o L+tYyqB{k-e)q:vRA`d4AYknc2/HC!kk$8]]}c=*xVac<+?-_Y=.' f?BS^O)Dn*Y ̉X5ZdY[I،x rr+~˯Пx>qƶIEk!1mx3]֟}!1?]ky5;KUFb4@ZCY u R:;(9$ 'Ʋ<ʙm740\+Czy黊RdeI^Tzgn c-w5 @VV+1"c_b廟+٦wxC?+Q;p]h]a'S2ylt$h>qgHQ-^ad"LF![h4@_JsWh $?xm x6<_BmW7(НEcnYy.*q.ݭ@HrV~[t4EVGCηgjvƃ0aWѥ3 VWyl5_xtFU)""Pn<Ǹ)Q\kD&Ԇ$ hD1NiT/VTcN/-/ H'Nڋ+FG؈H`tpxxBi8uLJZ?:(SbODfNK (\_6: :y%S7zn@mdyNRT$Τ;klmԉqweHLeХE9hQ@i<]x#c鏼6]=qANucJA8Lϵ9|w qo҃}cZKrgΓ*.E9Z?~g-=zXA`F2t~7vf1#sZz"? ^~ #j_~Xq/=Bdlǰ[XkspXgWeP}z@9c#Y)2hHb*fcCV.qMǤA!_YbQ<gg^/<4Iom>p,kőGP5!|K f{l6>Mˆ0X\PaBZKoS~3cfb-5mƙ i>uNk֍EzA?qүB[Gt3)'Qmty/XkL.d+w? t k텝&Wށ1lo4tURh4 T2vB๊26{,|y(KQ|K:ɧLS_;=i$8Q+`ȋ|,K\3T'у ,/)fa=mYQU@J|=n' +m¢¹*ge,3=:.+V%'p}/6HQP^_ľêX/@i J+(~;D-,'YWSd`4b&O$K PґHB8:@*C{͡מ_)FUAVjNvL7[f])d ZF50k;]i@u!;XGP -%yR24Y IDAT+F0ӗ*6sZC/܇:|\_B턜(rfޖѿ8;GK>K:G4{kuuyme B8yܒ2#XOq"¢BYk`?j B+Yù6ߦMaW!g߱OڎdnM`jU'_P'_N^gZi C0,Kqh4ӶqI2X]ea!Qywjs];r !x_%mf(1Y~Ks) sR9xw>r]{'~H}?gyy LgmGh㢫f#Nŭ +OpFQDgXU? EkCNH8񉍾@{qyFk;iV{}V>ŌkUMhF?vn S 8 XY|h:ў{U~ hHJħbf$1M !/- FKy MJN$Oy˳RbrR9kEFռk( VƤD!=:bK|17ATr_@KƽȐf Z(Gbs3-*]d8U|ߜaf>sN1wo/P|:Eњ$MuiUyy( jt|uLʯ5ï_.gq2y'%e`a*x8"s+Z6|{mI:!y]n+%6W+ kփ4\"p-9S^fk)Pkgmg4uq6wsZUY`d!iywjʂ(VsgA%7#<#[nsc+,vf|8ܗ?oa͵σ??4uΤ}s4}1nA7?Om2=թ+/ L! 8`Mǹ=ns4渨kh= Rqp(ɼLLS`<\}lxF1HrV/%Rx .cp'hJK#2^[݊tZހl]9J: YMI`>{CdtJm!Y6bJ(ѕuy "0po ,-8!Go+:+ cǑޣWیoaHA4-soki3r+=Gg}'#? /9Tid4H2MQ@d $ :Zʲl"㢔q&agI[fhӚC 6>%N/"N\yM> :eR >gWP4ע巶$k,!.lAuZo$Lu[e`*Rz.B}w4ȳ!p q$tGq~|~sʫ&WBy>Qq{}oBygjoOS&+.Μ::UE:R,qHaiOMs!\??ZwKE#0cډ4Dg}(i{m*dk2t]~Wե*BV4\TI%v]|Wўx^; |]w3FnKT @X*59k{-,' |Nhqz)a(VLgKkxfPR!cqdk M ;M <ץ-. "sJ>B}=%H.QhY:GjzRl}֢k:>ySwwXW{$=!Zu!B Ii`S V]9ogBhJ-5UjHuM!wr+kzӣVU)zc@ٟwMx<}͌C[04׺烙Xk- \/S9.)r<$O8s0Ty^Vǡ038B>BHHͿ"8gfpaq鵳@x.rD"q0D1D3p)1ؔ$ 09|)9{`F4 QX\1,oRg>>MuX]RneI5)W3(PF4㴃6"qqoֆNd+ˤeo~rmB vH MV)Z̀bu\1Սi]`2{[VxüϝxzeBL1$""7#k }, =nȨ௺Yx+\0/?=^Zv"~$cC(beҳ%qK_{u//W~"fSG 2mzŭF^ !Rw3f精Vjڿ]ld-KW˜mʊd'j\FRde!kozz/P]EIEuBe/yg~s>/(G#s/Lv*кcpdʯ}vmOjEǤ4+%Wshf߻Vg?߭a Sf!k+R >quW g5(6BV7 Od@eWYPX 8!䧐EȀL{qFҸB2;wJ[/4".DPȀ4Hk`"ҜaV!9"/ nGNXK-t`.Z .{#]ֵcYc1RD V5rWHG.B:Ox7TƤ{~+ó*~F%!?u|-wp3bQb *%K':5}^_ ƟHl5סQ:}>ZnO^7f܍am)R֚z=Jf{iPZ\*I+dQ?d\0A!A8gƮ`):zy3vqz+Z<{/~9֔_'߇T"Ϙ:z/dx(CYUxU;w!)zSM=!B*`fbPɖ'5" zD~Q>89t1UZxHt:m4l6Ze}8x,jQYVt 1E<[ D2786ͪd0LȊ 庴}\+!'Pe-d3#}KmK*N6PFCίhS3a[qNĞD]E4ƒgUV1VStapBEբϳڐ%k1Õx =`Pnqt~_cfԡ͇;zKv(9P+{ ꗟ*!%$z]X2E_ꊵ3Fc֢@9l3\_^z\|EGW<5gxx/asHY {d)ɨ&CRT7&:-!rCѿ±`T6 $jV+_?=~Xr'O;1ݣaak&z(e) ω7/'mmpx;f(!Z0ƠU .U$C ZC?ew%`Z1JXZ&6M | H>Y+tk0)±L:htRXAX.pDP^#eyN2H(;{ySPf%U4xחXN&Ȓ,-IV2tQ$UuO|O_[qKeʍl:!z[&h jQdKKYBz#oqI>ť3IsԐiZOCLm~0ɵ܈.ZtHgM bđ&%zI{݆<1(ȀK(G']v܀OV7Gb7bDTm󉑹NLc񝺖66f/ xGq /o[$xׁZòp5h7$k,XU~'LYD~o{H] d8@)B6`Z0:K-/hhvp'Zp6$>o^ڗhLS]_4s^S]-p:3S>|K”18ym0lxi-D=aH)E+SEO\S0nhxu*ϯ<=LcY8$"yq!o_9#-Jb%k#OD[yj5hmK Y^RRo&v9&q]iGf*FcaYJ/aJ9SFj%h6|% (qjmC"랣p4F[DiX-Fj ޔafqh*"O)Y $B(Iќd'"˜рJAјpo XRwokGI[X;a/I2RZERZDZIQ|mfX0y .?vX։w䃱H (E(d0;y= 0* Te8. ~"_Y 7H)-7 !yP6 %l.LEyl&v֢L-.QeQck-1F()Y\9 c52p_Ec*W0j՞q|}6ؑ'k$6IGj7p#jox,޺k #aRKخ8SSte YDX8'gw>aŧYQL4uhG>RR S }ʠKjmy٣d2< d}:ٵ ^@\)vp IDAT\R[K,<5pzXz]arlc*5u֐50R } jckUݐsB أʋ+/vB[ 2ueg_ڞT}fJ]:Y\3s ^28a:!Gчs>3Z@pu1mI+j>EԐڮ߱$)\m1JP0R 7H> 4?H>IZ#e3cʻ& G *3h+RGYVp6EFyIn""ι#qsØ0NU', $lY`o>98x?噯ͦ6Va~jMknӦV/Pts)P3s°'<t_Gdʄ44σ cbza<ƒ(xϡ2'q%)rtk7ar n;c6(j:aB*IpwWpe|?1i"ǎR<4 (1_7/X!Um E(D> -:plcrj#9o% .M2Bx(ӐRzI{' ^"l6郼3wdv.]j_\ J(H0"tNP>ʍ$,# KX\3&=\iT7pa sUWxA纒{`lTf)Updm>V ؕ_uUW#~3ǟ۱O-oyx//G "i"^"G֑/"l)nw(JǡNE4h14qgLW9>r+cVQf'VX㱵8K`{t4M"k0| V' ==ws+Xpqe*D%Љ}%rAv#HSBnF%/|~1R1I #c}S+kP-6LsA&[ D(֑xK30ŒKUĩjƄ3’(ɼcV{S EiQm H%V.0Ir s&r/O*ZT`/udjl]ؔQ,繣Q9[۔/y'n2gbpŜPGx!] 9c&_z}"ޱD=z{ϥX\KL<<⏛$(_ Fנi|ЈWLGjcpΣ4FX!woz~_|;?q7qyOhUIZ) L*g 6JhuB`v(Ҍ0/ [SZ@mTܻh-JW "?#bI)uK-WH,mF& OJ3)9W#^Ūu%<Y , 8u[ 3DwM H'S|'~ D.1Iv{FY1; ;=8" 9AnE$uL&%YV rL bOQYR3`1HE5QmgeeW[sdKYX6뛠j̿,h4!)O1Yߞ\]RYu}I>GHCؾɅଣxrɗ^::lyu}KŕM;g2b:P鵌 iIZjGPXk0uW^-R_zr: ~Dhљ%EAH&9iH7 mbB5 :aJa&%6wH0aAZLġ T.bEcAGGP|뚗u [欭dum4VeJ]a"u5~'Ƅ lLGP7U#f=E7RKsGS8ƭ֢VcL8RNQ`'cLpiIjzp|9qm.a}Zs&ωKEHoP^ԥ%$°~fJ~ތOYH'0 ҩf2lTZHKyTپW6$8zO/خN(3b/euv:5)oYUUѧ5O)jL}R ޅKzN1__vJ y ɻG( ܷu]?7q-VEI2\-0i)H#o㶲,iZ"=Ea }Fד>~i3)$J*x No>O|ThWBSqw~ZpI0Gޖ^ͧxJ()'B~㿷rgq/aR*f ,#<_m0+$1NuO xح>~r.eZ%k چQR?:lEʄ6㊵Xym!|R ;m^NڿTSⱮkEʂ9T;&w&ZK)g6qXz +ueNT5ifFJkqVP /R,Ew{ qJ@{NӍC?,4q+',AѝkyMJn^ub31Cyo|ϡ3|Wۿ &k]M~S |I #XֵүfӸÛt~3͕}O1,])J|٭]Gf h_zroэm;ǾMoҸ/f:nUU#b{gǗc[xWbvvF(ŋ}G?/<~>ou[A+l33w"g^<1~O'[\ R' $ ŝ=[mdfU<I ‰%/a&:DamHz?_dndpN osSwn㜃tLl1,a8'|xr[Ǔ=#7χ^;h>γYT_ 6HEaqi lcHgj?V̑z,[@R@w,YF+f^, ^ЎmEs&1tQ ( \`?cP&] -jUS'B#xv̜̀]L0wI%AR͔ dJ;>[#Z{Sl_7ۈӓZ^Hlٕ}PI_z?0Hf_ltw.RK2x666$Gج9V fjiFL̨lW_eцrZ6PIF)V-7.+,>Piuڙ)bnN&rU(JAT:* kByY9(l|vlMrII>(Z 顄\s|gwwFKK\f4 t$w`W\SJ&6젤~jLj6$ya%{ ;XbE=2&];{O@ 9mqyǡw eS|uR_wЛKQ lM@FT52iV dˆ)fyEEE>Lj8A7f ɡ# ʜC IDAT|7[K(Cxl +9T_c px&Ֆ)1VP[B]+}1u JqPDRҊ#:SjKMjqMh(@I\h[1|s/_žЙ /1+ غf_7ݹ@܉wejeIWM~zDem?Brt:x4йWs}٭]O(X);G nT6!EQ\w?2E)[?9t]QRHfz3HcћWx ~y/B}}v 7ON(I-0jH) Ak iZ]hn+#7K:lhOGG_3V4s7jsYyIJ)zQ8p($<ۜ{&߱6ae&w,vmd%9Z^r—L"ȇW2B\(k_~Ťጦ!֋LJP>0?E[O AmȺ,KTYYͨ T#Cfۗ'P$ A9bcq6an&H^Z"esK p?$nāH c4-)jMP5WH(%,6]6S( Kã_T? p"^-F_WruH'@9s,(qiɰ8 sf!-ι;Hq+|Q h΂(oo/ȋ ~׸sA!y}?s,rh,mzD $lup\4+iJNJ>*33OpujNmmGoeu 3Kt:=ny9spבwB)"c}pY 3s 1MiۀB#uu}b>775Z~#hdJV'VN W)';TNe?n]%,!#IfR8t*8Ng 'e/PKGxz0d8oӍ}jcwE"S=sH~+5B Ȼ`dXbA8ow !IѶO(Mn8,͌K V5DlZ׆>~?WO?=NvN/Tc" 0A3~Z[M~-:7HLyx5#/ 89nu#Y&*¾H>ޱ>:_mcP@Փ N !>{!nuu4REAB>X<?J>{s?G#;yAța񟥷ph^uY2 HGC81u RkS!awOy8v/qK~۰x,9|w{? Q;IXzF9)m퓔]ib2<,q=*8Ћ QloCe,`ZK W{ u9k/Ws52WCG>':@P:E侃K/<>K!ox!i'5D!8^K\G~s3ڹڂ9\"^0p K*J0}5g~Vv.ٍLw>[ }|Pz-~>xJpX |bWkހk4tD q`k4R3?Q˽{IcTR]S&y,hJqC;[97BFy K@$1AP4d sܻ 5:;=:<%uf]p)ry:ց^ +y1ütn:V[DYR>PM5"L|Ѡ G{h㨧++撈0Q{ 0 cc#Ee#2R-gSՔ jw}rϏ꧟=~=񟽕;?pJ'Msn &lXb.a/XgC8MNQt6xi}mk[%ѱ>unqHxI ו\;K/! xsq4ۺ\8t!ǀE`9nT7se֐ V#U.U՟? 3+;y?ɛ!yqB0;;G?7g LIB]lEڨ8DO))J GWfKJ;X]1X=sYzTٝx&pw|dSya~龛yfy$s# UwGBsԨ|Et#*olkbeۧ%W9lL7 , Q;f%b;JM@5QZRko+%LҒ[Dřv\dy ZqG|jGtޤ:lepEX52VMԅ"4;tISMU4)Wԍ'hl}guxڜ/]ZL^4URfЧrUd̴"lFsYZ*us5}]J>g!|I8:p uW|^\ =!p7ۥ">{l^#*GHG:'CVO$b$!e}yO)&;:ny;ѽ DIn]iw8k )uRj_KI՘FSpR>v{. ,qYE+} ]E}+G[:"+pQ_m_?8mɬl#E2BKI(gйHgD_ބ4qJ/W&?`>k%%jL3WYuSiMܞ}RITe2hFة涛88#geVS5:ҢB++-m'}D AWxi+ 3J I]XmaV V+\9%^ 2-`0SAES&F{Yz8O|y'3p-_A#@)X h^f *8^K\(qQ>?"i'֛s ;/zAKŌBsH_+|B\nJ WsIrY\Nj@HT{  VNMngy>,NFMo~ olg*Vӟg8AUqm(ϧJ-9<7B]^+ +=)҂81rE*!~h֯ԗ&%Z{͊|Z߉FSpi!Lj ,3Lt^:X'`A)ʼn}o}Ӝx|!w~џ{`6vMׂSx21Z>BLXI g4h@fxOw%ڽVRmRx,Xgc,9;wl `"HSKBE@J$ mYVRbPQmYXRJU*.W9ED) @@&ygtx}&t,ZrAj6A=xo݋ C_|B_Dk<'÷>&~6Ejm,872M& 'a"qPj c-q/!y}+gku}I$n^TvQtfڈvߋ[*﹩ 8beEn@łN?f~}!? ɲ7Yh5߱6I7k[A=N*N )iM2\2F 3^fp 3||׽$/ x ec,|BS?EU.?:wYWAqnk(7s bqfEs.7:uEJyfe-'B:X_ӸZ6W_b*rg p_gW=sc]ĝEy>~3růQ]؎B8a=L&)m0 #}9j/aRH^71|DǗ/Wi9'Kg1YZP%#f){(x hxQnJ7yDfuo]Qt:qc_3BB. B!h0^ `u3IuMXlyc:»x[CZK6y,^{|4'v,ܸl5)lFQbRT;/9R. JkTm|l|wɠ`g3zv9Q7$J|r>k/3+yK,TqR՗ @݆爻-#Ґ=A5sKӡw#nP0;((`嗶)Qka~|$YFR@? ^{ u "/dMd g(x _y6g)1h$a%Q Ua $>4WrnJSd;C<":ċc*S6 53Z]q//6X_}YbSK_f}dUtc8dp{pGhG~EsLFl wX3H1NxZk .ܾbZf9#k?zh }SD0^Ķs$M9 9ZH &jqWa+,l!ԣՔK==Ρ +}|IYaIjVw-yRn%SB>)quYd/Km'd%|߾ z_J=}]~pQg5-?b"& 4^iwZOH?F巼~/AD{v{"M:33:c02A{c&8nq$J c(%z;)H,_̬oCްy!nemuuEUJL ˊ;O?n^>S5QŤ(إ_>{VlF5|ymnwGA'-c%~/ޱB@/Ä́iD]y  ;V2{LZ3k;lH)?hNh/I">J 4#RQu2RHAI0'ѸвSsCu>(bDΫ ԅ&:,\37첶MPHx񳛼?|ʵmKozQ@h;4qy#ڐ=IUǗݿM}+ď-4u}^gNǚ&U{hXl: D7 wZ^w$(#B soNp)8 ݕ3iym?,.ߖ )%qMݢ37A, 0Hɍ!])SVB"%^zŅ `NH:EO|d?k zRsϙy3g)DvYpakȅ$AOmo.IYd4`|7.]QҙI7[%gY.~ :=ڋm.Z]oAX xZ&k[~lsK3|4NwuYD{.=DlV)-]ߧXXkdܥ' b'*1xC:j#Q\8\mT5~!QQiG! Z9wD%4AʧU IDAT6Cy73\A?D@)P;,\1#|-VI?+TE I_eι[s5;?=¥|=8\;}G n0"^ 6qy HH! _g!Ջ2aAYf zHs8:ԀS}Ko{ { luNbהCEu>'|tBx5fG7J&Wy^[X/:iKZiN6o|Cr&6$ #\m):u{;<D"j6RqשEf meG􄣲]ւ/%J]m,E%=Fΐ(tUŲ}_ PPז"ݐUd]yV`DSe~p&I13J&gE>m<-xvIO )9tH_pp%&OR2rI_D^!x>N'Cs@0"_a7D%hj]q>77'3g,܉kyo;y: vua##2rXV 6_; ux鄨Edc%^vº\Wge}wcf-*ZMC>)ȭG*gk[Flט75A+MZ6 zE.CޮQb9L7}e/xKIǧ2c:+BX"g7%9 dJ BkΤdq!2H%| Q@{B\30U vR C"VHA(`!nDcZ&mdx@Yf/RLKMV`p)x|ÇpFY/Txn2Wko, [Z|qp߽Ř{Wh=L8I2@ T'\ROf0OH>'8 ĵ< 0 *!QAk,'OooRW%m 2TxW*#<I"Z)zsE"T*ʩ.-S g[l[`3GƎbSI.q bs0a"} IgJsC $N|v@; C1kU3ѭc3$ dž5D󮱩\ђHa6W֍5]F96 Mhkj3( G8ܿ? _g)hDyU1u,u]C;XT"#ِmo>_&*gJZ>CS)4]nօ!ۛG+nZk`U08?ifIW蚡s i@¸5nn|3:ӛ_\ǯfCw-y)on*R)uSmPxu Iڳ]L NQϞ}XE\N"O"'MvZE !]k0$Lpbˊ:n\v_'#l]"L դۛo{Rc73 ZAhx9 izmvF/"E E _5\؅пc/  0Ĭt]0 gS>'k_ED"aQyv<ˊᾝa1T麦v鷚bq_^e7`KF$Coyva{YDA` qD*Ya*ZQ qՎi҂4đOW ÐJר#*h1hʲq R[ IEf4V|׬m+ H))KOsѧ .q2ܒ̕^%+c r5qѥ%n5$R=2K}+޷JƛMqAka&5җ`-ֶιC?sr:ZEщU_BPmk*SJk5k4FtU$mV / ͰuRao- uas,iwX!*r0:ֵpQ:ҥf1ss8P6<:cƓ1;" 7Q .mƌq!(BU!8)w9gQa|ʟ^xdA|2y{@r _d+f n)ɇ0d$hHYݔ8!(H)Ns ȁc !۹\ B¤!a2K"Ë[~-Ľ|vjQ cZgkG}1PAtW6LktvyyM,BV6[ܗ EkkV\)o2h~ۙo'9qP!k;Ɋ{fﺬ*,ܧUDWpf?a)G_e{m~>v짞M-hۚx}xfI}HlΜbXZ c8(()AZ\\1I SmfjKXB_5Vu( TiN>:B"&qMA(mk(Ҋv`'P]>7hrL)[!qL\@`yO. 1J5Ğ&h < -gL0,y@fMd'hY|p+):li+jxq8u?q9Qp'M?: !̓ |#e͛MDyA5_U q{l]KIעҙ8$~[ed *cJ(t\r=Be(|W~ecT ,f Z\b|oȌ6 ɏ?Tڰ8}p/:87]Wj-0t7aָۮLƜɟ`St{0/h!Tb?Ke؝c;2z :miڑ[)Ch%qU _J8@xX|%|VhͮN(⮏U3Hb-֌F96EtyE]K4&wz`I9izT52Edqf{7<8qkt6z4!$a_Gs㮶GCē\-kQvĉ ;q-j49 !FNۜ&Q̉=woOh9a$ cB(By7Γ9r?K+ƿQG #rmw\< j؏L#-kG1;<ύӿ_57$'IZPp9UD LP~q_%.'gsɖ +!: B*]AxyJhW9Ai-y(6lѤ$3+1fx3!$j<ȡm|z b PP sYd;l.gwO E @u|ǐ找ElTW =(Ȟ@:B#߅ +f_{bxUN>0`7*r Ɯc:'wZ%3xxs!% 찵zm'y;;;{礔"nw}+29:cd5bHnjL:`\ԽC3 _IlS%%B ux@$cv(<l?I+K䅜Rto:pKh4B^9/ٻ8((f l_ 4'IX1&<ڳxaDG8YηeY)X>rD|+]$񓛯5lPe5 5FyM{ae}8m;j{m"~4|Yn-x %#Z^00So,!Aљ s(C(3)9U][oZ`s=ZkQ*p"`dQjvs_"u(i IčtlKrc#bfdGK|i &UU3NnUH U;'}uLHcfZX;P@aT5eA7+)TjaB۫)_f# i dV;145c8@kG5*pc錣xq pu}]g؞ ? )v%+.џ~ĭ&HqT=Z 8] '$wZ%<.!ăιt?N8X_Cy c,Up>Gav~fMmtz F^X]\gnb{kuEygƽcZ M*B TMC8,͏8o4z_}_=^\2J :*VtWZEAg\1oz/;3?C{w on̽Xv;$ BQ -H|?B٩ pm(! #47(بhC{*4. 'ҭEE]wR%>klF@]NUSV5E#<@8H22,b6"WHk{9EESSMDz@o! "l>m# Y7w)vQOɞ {v;xE'f#qE :9)O>*zsn)GPa Q u d ;q-r%9>"sn~a{!Z$ͺ[#<`H;u6xB{![/qև?R++yY)3 Q:mk[tRt~KLL }$'> sU3wBA3I#[II z솘s"k)]= WDB s^TPؒY2yP B%ɍ!T(7ՁT00*m5M 8%ʂsF0 2s𤸬5/y>P[Z^?lL׎M3鏢i'v`n"[h%ٳOo׳K.' R",`ĝփ^ [Ya[aǖM8 G78~A|Ao!?ι_9~CHt}6G&q`u xۮ9h9p7TIpmMQmcy7鷘mlj&:r_?"+UfM=>>F_Ç֒1J;К([^ȩ xO^Ly}*e5o4ih !pHl~b򜴨Y8зR"ӌz8Г BE-Lh%yMUr_+VQ\S*ڒyn\6dLN* oeVޡHHAyB3{;^EUZz䉧f_0Д=xLB5J%TorO@]Gn)[ ʗ.mD gIX"z v7R.͓t/_z;pI>&8A$}<7 ;q-r0yM^G sg. ^+=D7osj<$3-ޚ<Q:B 'P\?ΐEjH)X0QK\;ϿRĽ_%v̯/: IDAT^|iy$HC8x?&.a\[^`5|wJᯜF-Qsui6TMH5G~y Weϩ$Tٛ'yz!tEiaxg՚B_ܔ';KZ;"J_,& ;=]s 8gbFƟ|E^ynPw~c>&QIXgE)a80<'ng0a:bv1ꖴ3߼|]=]'I1ZBg.p=)غJUG> sN\#9  x Ctm^ ڸiMg~L069GsJSRgC;7s-!Aʹ<(s uScZc[JGV<* WqacˏYGU>KIn:X V 3j_?~q2)bcI;/'W_;Ǟ18<%"m14鏭^7|4QCN䴯 ( dh/ uv{K v@7 7R.!`+@zTnnsgzk>Aӝ%Ko79ʧ66m\]NR_#K?(aKܢkx<4U8R"X?|/铏l_ty38:x/=YxX#/`PpċjЅFcRme' Ko{f'Cd,Cj%6iwڇfЭ? Υ Y'4ٰϜ/.s}={Z@h(hЯxjZ' *&,:Dϝc[nſK-YxW${8QЗx)#rp=-ܯVgpa!7Й[ 0QG&Ur0Wi`Js5q[F*I2E0ꕂpÛ: !xKGIs#d8{~|}ό}yu=a0o6:TsԥfRَc:}Oi2[)H۪Gn xpALeρ 'Z'y AԦv9֑eiT\8Իa;C9 =,'q Ip1oڍ8( J8s&D֔L>{\cy9[ !𲇫vg7v KK<%P!r9MpΡ'Ȩ: HڎCI49xvCRgs.PDZƿq٘.7%?{7Ν;5}>~4ث!\G:EmpbB(J&?? "$ {)d>B5&1,CkcP+!҈Cgb }lr8i -u]%ek8 Yj8le7; 6qֺ zu8ORp6 mn~<7?{CM ~m/[đ馟g^p6˃5VvTp ]oP!|GaklipW[(|I0}<{7 {q W&k^&=\DZ\BB1(mog*['AHnjCcS剠6C_>-%Ѕ #R3!?5/6XM3NWoCO3|aq8wn%`jCLE? ZcM!8_"F"d~љ?D ^L1#j,=Ų6L:O(@df-麡$sj>cWSւQYktY'ZCQW3 '֤D!:B%9 -gǾp.Q !ȝ=^mpXdcuiHzo 4X3Ρ/( X!Iگ8я>)jmV1ʈAAWȌ|B~H c?3xˏ<{{6kkO5BٲB P;jIj\l.E~ 1#,\

9O/ٺufum7q h%1] j dJJ`z'3 nDdݦؘOC<|r3 ְH3y9yHi^4G@%W P:+{T`%TVthS*3 S7BL!Ts—;یIl|^s䳇8Qqy_sҫ=\iP81*l#e@19Md>uvZӌ[p|鱧Ÿͯo=*o1\poN o[7$`zuDC8Ÿ^EڀǸ\xJ3 oQr#д4 n[[75]S)ʛ]OXW!\G"k%.F8 f\Sg%thuYM5( lEŤf/,H!*h٘B cK#nw4 v),|Ϝ*m͆%}kHs4 TRJogi&?CNˢ"Isث >ͯ=/ݺer[9nFI} AGA2/_| *Q&%>:Ijǚt''Im ܏Gnܜ@:A r/!^;15IS>.htum`D-% /֠ilK&lcYRL4hK(mÍO_ ۬ L=oWByqYG iu9śza7ۺ3Шіn125_wCW>ϝ&*'\ &&n[ϰj$3s }Fk5.i”{/J\%rgh=~GٽH>O>\cy9B<9Ώ8g $hTzPbmS$YNqj8DSs `/%yԧ|?էn (>F*,6fk=%jK]jIN/  λvg#N_j*`8ف;0GG{3}{' V3 #jh|=te@*B[9j]tL~\ܲ=QF׆BI.h'y9q; N#='e">PQI"hjZcCPAGUjKS[Fɨx,9C>)(H|` L%!7!o: &3R':j 6kRm "r>:AQ59 NgL<,<:Ò(ƖzV4 d5T]ޡ6h٫(6jKQ?QA>-@rm{$ݫk8c`Kk !8;ܫ/Pi g('…#k#IQQsR6Tڐ5}4Y#a>Zc?)>ϕv@$-Mm5{V`1^ݰKYӄ5TcejeyEz J)./on;T1mvx: dS5J%у)UNRN4d?OBI4lGXVs# 1.~Pڒ}qs(%E M}f?| ;wԣ k OI#`~F<5ոƖBI 5D͐`r )&cոlMj#d!K^|Iȿ&KN[8֤4J2O'{$ݫk8c` [߅pl"Q)Ǝ^ G!qмy]%._ |3̉MkNP3Jo? >ck!gɄ1_ꌤtv>~9:8`D1cn0,/~K42֓OATC\4' UL>/^w~p?"(gѭ.?}g/Z3i zIR G`Qhp ^(7g-i&[: _2gd:4G{O kl Jf%?D?f`W[\eeirySI+E+KN9րB1'K f 4KLV#Z3U3*cݰ@i0Sո"b{u||r }]vƑg9L7]u8 ŐR8@}H:pY&V0vCzd1?xO:VIO~c'$4\:$(G?>_76<~2\ڐv^akǺ]ԖhsxQ65P+ĩ 'nRT#[1 (),O`Yj&kzAlAb5;Ck5Թ_HqxR4Qcd4J͔4C i$(B` Hc$QNr uGٵH>O>\cIIڽx5Y(*8'7L)ݛDXxyXĜXy Hgt㽜?$ /z/)(0k#VYf۹_7~ڳ-$BzUL)TJ8?>qG`7iD &82K-  뵐a'*tGP,P/(v OBZ=1P(ǐ:|}m:mEsזOQwpƸ4ӿ 'ˣCFu޵vEevEvUKЎl=OehmS$|YD㩕|FzhA}fQQ3:pΡɁWɇq,oB[1BMqneJPdc\5k#EtTZYXq^z}/X0`>/,koo7ӯ{&"he`r59$cVQ,?u1U{^7Wz.sxZ.B؊:"U>do@<& Bꨇv!i{ j"Zw!k1kB&@m2zޣ%"TG{xJ'n?lj< Szi;Bvz97 otsY7K 2j*=ByF!)l`il"/:pCz@Dg"8cym`H`pL|-6XZㅜ\ngҿ<.˭뉖rWbzˋM |7ιN}¥΂s}%h^~W[/TZ9Q++dQ߶D.#tuP+(CXv>A!Vkx81C~~AL<O✣jͲ6pYJk4k*ʯ{x|9訔t\Di݄"l#dO٧>v9rVr7DTL-*Y\$)7e(frdqI!N_@Iҙqbm3 0d O>Hl[` sO"-HcHf/^c_T 00A\W“ g,RTBL0j4QH>Wɇq,/u{hg|7m.%Ù)?ιB %8sv9w i/9'uqH#UO5c9txdStCTe[ 6. &χ͋:wV*h(#f{@OSKy7 yueXОx`&|%8hR8:;9(~ 鍊%yTCAmqIH@QfeD6,0d6bD-Л|#Udi,~M̖,deQMЎɨddɘC;/PO;pk5wux 1&~9tbLqlZЮԉ8"q$[oE:#%$q1񶤙8 5z9ܢ Ǝ&j&Qk(!#($:5EGٽH>O>\cyo޽mv;ij^h! ?y| x8~Eʹ̇sۥ^Q!;mTwxW]OOA(]tg)K88"6j&>]SC /VgcN_Ex R. !Oh&*eEqyKrw 4i'] RrP7^d9RwʋMA:RTem-Fv|T[EY',k!=g%^5Fca:p,=zyAc _RֆGYSAO.Xn\3N[vm:'IzDȻfg#;vJZkrMVV=~fY6?xۿ usAMsbB”?;߹Yd4WhΡ1-ZWKpW4b0rYɇq,4$ܺsw?O>\cyєA!__qν rp o>v:WWp}XAˀw >rFvV SQ/ ZQgpD +++ YKeGu3Ǐ*l@KU|oZ-A'[sF#8k1ixy肟xq3ޥZѠ1ؠ1" |^5qe2Y S ts^a*dcد4>9=ecR; ĎU8F{ !L"GR.qRol?Icy-G.#!Ve4y˛7o[UUy̮&ʲqNsUr&I:NUvmW⚼mEo3?8zZx邐gU]b;Nӳ !6oLVXTo%^Cm4>TJeW>5fw$!7,ǓaoW?61#K_% X5#Jg%wLWݬw{]c:FU SZi ygŬ:G3hVܶ0n9މv1pgp儨RPE>Rh7cu7zxاgɨQ@vL5iE8Q Es8Ts e޳ʩEz#s^2m>=F+b&#k}|jkM&tZ1经ZIܖt#$N *#Ie;iQk@-&=}0EkKBz?۷\#SO7Nrv(UYؤ #θ7ocs(}cuُ+Fnsi ?ph_.]qyގky =Y]kbEѦ𛀻e{/20Wg 0uob2z,ȠuDC.11bB$3&'܅<7=cxPP=VF_|l>] yViO< Wo! UF< 0?'!/ ;`ΙtD[i m2¿Fdq_~?{ofYVִ3ĉ1ǚBUQlVZpbK۶b;< }۷/W|@@%(6PUUEMY18Ӟ׺'dFfYO>b|[~sm:?~cYkassk'" !BZSy1'߶Lgi p {j39c0[{pe0ش[`KoU IDAT3-D`5I~`ZEN#_/Q*'21^H%}Ξ99GWc`@:;|o^A/–v>2DO|f(i0e YRG{C3tK9JK[esVBh>w379EQ7$%rzȐNcz-ܦhC{Cga7T9~%`HW >ɘy-,ZjQ9߸<S_N pJ`V:{$-q"3> n#5=-`0?,,yYb"CkvrD Rg'6;G믟e ET%AGEOec*ж|nMkRjX-YV}Q2}&Z"Km˹kk[Vɳi++"٠".UBB6IsN+TKEUrK vJB/z-)ף([֘tJB? hiU@'LF5 JX鈙:j>oE l ߏQ!@-NrQ~?Gm?|oy+_Vt)JEn AԤ], qB!<}e"oZ$g5ߨūS 2+WO~7o}3LuOr[xg!N(zZ",8.W_R9<x3DŽokZYD` pCXC $#!gUIvH!p#r.C C`كx)!/,Y3~cTp*3[|nKaGǎJcBCcK- XtV&}CcAsƐOjhOvUVWxZJ$D SP @䰷76wssc. c:c91tGOzd5p ZʜroӶlJ-k+бη͊Xˋ=׹: ι?(<sc])*q [ZuzM[ 2MnuYFRbaj*,;,]R, X{"_TU9 [IVxmo+ _@K;흼W`Ҭ`@,dY+hsk Z:8y/ك_k2@aPGƹtaX GK]9@ >?6d8DXFEp*?}^SZLKK&?@<1֑d$ء]rK16G5;HWS۠xD4F0ChNTXU9G$WQKNjjC=2)p tSP h'ǜ{ J= f|a jznK_+^P#Υ(IV "?F׹Q;Ǒ^y05Sw^;?NofkGȾViHZkՆ3j_5#_׍| HK5~M9>P khF)Yg+ֹJ|8ȭ9W# e;kt< Qg9b-voTU8:B+,6)EAc`YԐuxJ AT e$N^$.g%|Kv䓦$[1mD3lP׶-ٖhc@w.ՔmJ z.h@A b[' O4쓐OQ4}7.0ޗk׎r,ls"$  1se!c>&Z=<#Z)"%DdENe:ؔ I! yZ o%s'UV 1I{'♯< _ϓґp=oqQt૮E&2H3|LZ x MRRBAi)$pXbCrMׇ&~ @9J*4M\Wc< /aC @ <Oʖ,C].gsi|v1N| U=~+bKP6^0VYmD1OS =?`V("<{f"dQ RYR:4qﳿ< `f&zLh{DHp,ouXiOc7=!LN u?H#dx yu77gA1f@AkAyiiD'| p*Suq6 nz_YePX^:E{x˞t/ XeRqdUf%͠A^aJ$i')ze6wQC}2@54e;Ǧ|LOԣ@oC))qut=CYk%|vI>p3BlWrsnJ\,A( T֫luL{nbu|G <}a9D, x')]}XWk;{k_‡0gʡPMs7񮗼 @ ,#>EL3Q-X^5B0!|Oo.b.'q1Bn/5`0HAރP89DZ|d+>L=JsI nQHs #<*2"ϩU ,$h-BP QL"qؑ)cςK^Ik7 1$A\(AA$r4aA= hx3 d:k~HGȚB6i|$]\I>C.vyӋO+g"sW KaFmK +,) $T If}h{~KG)7\$>^*^x/ZRI;a459֣lWF@32AH-*ؑTC9Pd3tTS({eUr2ZK&lb|Dg42Ј3uuU.\9LpցQuT9m*b5%Bx\#-v|sE &;A5fyd4:+l$+X<9>C6G-X(&o|7'#*|/~=m(y 8P8_^qjC+wgJ;_pt2sYA?Wd&jiXF_SAĚ>, 3xM)ϐ5Z{Bf*A͗ԣ}Yrwӿ/A%w)eRQyH3~ᒜTK"N0р:1 #VNG@THKpM'h'I =AJS&NO%fpUdxe.J*%j%NA,9u vI>$]ϥ׶K;E+i[$]η|vqFl[rn6`st`fwI&YXfDntmӾOw,'#O?.YʴpXk~rzU_o>EO3eewQ{!'foy( Y "OC)%D BPӒnA-C2fcQfEUL*iR {^DI[aKkqfYL-Gg๳uİ A0CZݧ>d&m;r.尃В桕$~VU @;9F몃{3&#3{wHQWLC"wB t)HkL+D |qvI>[]..$]\"05Kfee -ߣGdK;t) tzhYZKOq0vû>qXt^xW?*j? o_5{2~e[3|F['~7H{QJOjg:8⧬TOlԛFJ4ʪJMM PȬ"0HS3ܒf$uGknѭ QY=T1e+P*䐔#B_欣WJX}8L%5dJKDQ1ˡDQ ey@]7.DŰpB%1#L;I3/]`䳋 q-w R5Z'"C^&8P~'ځNMM X'ytw}>1f?'ϻhҒR}],~/?gPW9q7|x&N#Jxnmۿ!]<2hc[N`U VG+<@QnD]%w}_ƧdPLIJ'ѩ+lqSۥyhЙi(NZBL#쮭iW:mɳ/ФYNobkGĖ%) נt" aC . !&"iYM@?&\MgID`_uqh4.xB;Nn;.3J/t.)񸖻a;XPI/w8T0lM!J':OD4ɣ>q?S!_9][6^z3/<ĿyΕãM^n|޸g0:;2ͷ\Vt0=c^ؐp=so;?8Np<@h O7U%3d尜pa=l"2HY9mjFьƣoᅲG6fFiL't5D(Pc&|lQG A]{㜣VmۻXKiӎ̶ |k}_Jةe_)y$,rEc8A#o /r:18ٜ.9K{5%4|~WӬib9=C|&e,й<"(+3Rs?3h^5;ԛD{?-Ҝv?~ ( ,9qkǽ@IFm3HdE4%X>op O$|l@9܋335=8cMEAƪ14rhXcmuE^/H|̇sXiIm)$WH%x5Od%2{L_"^Yȃ%,W%5 =¾:Ӫ"O (XЏ.[DD"ΗQ{1SφEeRg;PZ{4Mj["_V9j;m9y1 0e_{rE~cXZ iJ]Զ0,[^@e,}jb:⇞u9 ~?7K6=1˿`5eHII bտzѣD219Ҙf!8<=xBcL@[:ݔgd;H1JyHb,=<0/ȳJyn@<pä~gnܱ,YW*O1;j ;..5:shΰ7\n"©U"'y_A5V$F.=S,r(k'Yyz媋|Kp΍~hl|-,c( IDATιg.ۓgӶ"L/ILtc Cֹ.6YiZO"S*ɗk9n Okyճmȕ?ĭY=vkgP:ŀr1x/ !`[0ssN#R&Y) Dt:zqz uӠ2btJ?|xR"^-k֟[[ԒCGѨS-eRㄙ :\឴ΡBdUagB(4enGi y>:ZO2dŔL5CR3 &"D`PsuYH*+#B S_!?~793X*>n6ε@x^r|k>4V3go'N㬣DRL7A (Ķ$-Xk I'ө*ꬽ{r|gO%kk2 :b{%ņpd ґs`y%òk;pgYR]BLgSxd-,I*ͩiy O lhp݌H@A ãxxF!]`5j{ӰOy~ŕ`D9B`=95%Bx\]2B^ZBbQ# DEZǟ~_=tusLx:+^WsYg/4n\~=<;G̞sHya19PD!1RTQ! 3&) 8@/9Ij'Wʚ8M<ǘy9Ҭ,,zVd!Q ,'WPZW9`ȭOUӑX%@Ɋ#&2cU֢@d#@h ,(ATT)k hM!244Y* TD*<裐Pi#K] %lm:?~޿x\]2B嬬,s$2d&Xc̕S=k:‡ ڔ-xva\2?3kD9yY ~=e~evz^ś:r'z=<G8@ԧ7TI|A%-H;eV"$ )|(jXba"<ٓ\KD4(GM#("i2ԓ:a*4flؐ"S3 S2PZlfkԒ[WIiIꭀ1!?|m%&i4}D鐾԰#<H'܂cU ଫ Bj2 5 <F߿֪4ӎ̶ |k}_Jx<它E"ƕxuj E^*,VۋK ~O>0AsVnPܟq`K;˭_?יuOz5o{Ȋ2q#\V(b/{zQ JkఃUq,MlQ,JINY9>`=޷HZZTOuԿ}?*:aJH|dHn9217~d!L9"V鑸D%ĝ: eL$"׀tWAtrwVL-,n({еx@ʱzkf'Ft\ZFTLvq1VcoswK ;2E(vBut|VR`@7 ( Zl^;َL予O|&5,p\xz1Gw{zr4kZ7T ~珙\X?|n%R!Y[$$2# S !$#:ޅdʗ\nUi09ow6WGNNa"tG,] Xz Y9Jp@ D͈/c5ܭ,ƒpt>)5i&UlUD5hEQTΥa(+6AYi4[ncؐ)*(@*NY$3U}X41qF!4px>KRPhY}1ICXW3aPɜۧA--BI|_6^z~m$vLQ-2EIlι1/Ծ,ݖs9GQA+StmcOMۮLeRÈZr \@,q9YI^O~}dh/a_zSb*jjL;|8!rnN[̟>=迍{`B0Q(8S;\_?=}qRiWIA] sL3ȝÖ[BVTu^MWfNORXJ$Ջk>N/2k!9nG(A)#Lm$" uf my>'tQ:g<T @F%VZ!P|m$sطSH.|o%֜U%C;l+бηX]]PXC<&')P{1΄Oݻȝ<~$"_^=hKAS$ W{It3]~_W6óys?K/SWY&kZa Џԙ놗2ZL ѳ!z6̆ȩK9[sKjԠجDtvT$z+`^rrq (ߠJn\Y@(GZ)Ggm;9VM|=oA#Q-?w%SӒa p^3$ ;5jWObf֟1 Pf%%j|^ܓwI>[]..ǵu0/#yI jBK"+K>ˉ$*O j/]|GmZ ^k%Oo:Mz,D6(D\) =Qq(Ex/>~ާG6ʕ!Cny G{+VDZF4%OrT9X;X~ỗ8%]ZTjgsdyѕ lSCi Xb-jP|H[ (NM2T AWE%NNFԽ)J8=jHhci qΞwDh`i4 0L͆ U0hiSAohQG{5֒t5]3jQ #)208ޗ#6^Tbݽsw#\5 E6PG?^`_Y Yw+W#s\*.Wɀ޿Wr#F8)QRc) jvYc.23RHyNQ$dѵ'E6YGatĶbc"qEF<_UuDN)2.GslSwQ*V} I=(Z!n:`ޯz8Fb\]bpl/ P%Fy7.((.xRJc4"4 m6_Tضӎ̶ |k}_Jx<它yYG9ǖR$ϱڀGj}?nh_s|=t6]$~%+ mk)z GILzÚkcy};Qkg/y)u >kȉ Nqjdr|5\]~1W QyhTq Һ+ef696eґ&H*9 Y;en) 0t9k#kX1 bS99=B=VF6RILȞUPxAyPA8[Ma5FDBQa$AQPQP3 㼏. ||vq!x<它y`!)DYǑe{nyr??5>pQ#Ϲ}΢PiDX- <0M -^}]rLK>UVG9~o9y~raRW^ZK פa&&<9*5}NI&##m/+ z[U5OU5eITTÜ\E<`( _U@KLhN*(8rG`nJFk`n.кselw1m-Y!$S=v{[vڟ;FqektL^yTQnjisyG5I[^ZGK1~Fpp>9;5`S MgS$qNKIC9( A N_6wp--6x^> rSlI* 54k|$U E%B?m${"5n(k09iڅv ιK䳝v\g_X\]{RN%ZQA%G>y ,3z3$Evv/#u_z^wVBk¬EQ.mWNO]6]s[baBkyw?Ȏc*᾽cz,Ճ߇l;ys:csK0nf!)!Sp ñY% t u\flT Hlq?|5-\ %E7`j֣!}X\WMsytZ$FOhɒ m7kpY uJl$csmH]3 f@fs=io 4Z?63凜Z_s,vZhօڲ++u0-#Q E`?i 9,99ȵBIJ>d ̛ObXyCVo;L~ڜ×tiY#A|'= B6olsS*AI9<{8ˮ|ǚҙCҁHP@ATT~=D|"OdPQ#A@L@B<=VwU霳~soUWUW=~>O>g:]^kAp>Zxw<'xKRAbA,l3 "!CgijBc"!>335*ܯӛa8xqLX sBWqG0wZ~i@`ƣJhhooECU?|<ʲ~Ɗ8h}ȲQ)@%aRE80Dt!s)6l TqY#>o~%)oY|6-G*Z] ^^n yq{[fg_Y"ܙxRj 3ڷ?LcKrCwa$gaR k8O ah.=O QiT`K1It#|M(}ILa5-G"aq8JJh`Ae_9yO?]v.w?GuJ8Y _u\e!V|+i4gq|Ooz啜{o߳%,$~@kI_rrlQҙ!|;>t2 dGPAK@Lf}pR znݥ.پШ1N꯸*RZiJmu[-e)^8 ̒%<6ׂ T97c{+x,u>~%L%!\q=^ =sǝ}ѳG`:)rz̞פfx(8H<+tzI#5w-B% ]Tq!#"U5d*>gNp˃Kq +PpiTxkŗt \<7<4OQSoi|k2qԥ%qvG>\2K(_\ģT̉?u>A񏷗80{~ z{bv8R9F1}*]ƞ_mZ9`|aG]YsJP5P0s%)/1劻7?q?&]8QwQVC4As IDAT8r\Y}OtZ1s W}׹4vE.Y*SUttb^0LBDI.Kb.ڍiw{Y%sP_hE.|zsy#ZHXoQl\^S*)n/!cDVOit;]!:-y[o4RvDHuK**rXHKY$f`nNui#^dnH%qUέv}( G<򵛸)2/y6-;]M9x&TWg,~=ĝʤcdƤ;L^(B0DuE' tЁ_;aݡRq|ghiDQ4>J8$ y줺wơMq[m8%"tl)AD^<-߸]4NUK;3UdYEfiv}+_g=JY6گj&5"K9d(YȒ0TJ+i3& "p6`dH T7펃w/>'32 ^;s:i2pkG> |y\zYX]ţ ;CwI?4>Q-YqG=nh;W|US4xGҫ ,zY& {4g#*wʔ8A3 ST^JzNXfʮ(a[cϬHmk7ZNb;ti" DWEP :~wT ]ߑ,uo>#M÷)v~Ͼgċ-ܓ8`|aG]Y=StwI6q$nfps#γD/j/r+Np3wR ]җH<~|K·!׭12!noR 馴].5I phB0K؀fʩV3UvLNThjJS`8GuKL>EeHG]YG*[!D >{ %'?8ǁK='tzIG_pcW\ǿ ~ۭKקB.}Y'op,ں2E.䳘)!U\d^/^gי F!3oy@{)vLIHB&=ms~(.ɧqԥ%ADH ^7& }"p@t2OAϬϱF'|>μz~]5;M¯u$3&4u h";)Lm/eץ9904$jm8T=i~cs'ջs43rNO,xN _^x//qWǙLV|ԐMΦ>++]ZI6яW ".A}#̀iUz|:~}}9} m~)_lS\[6qԥ%@UIqG:JT{O`}s%:p|B3%r>O}?=oɏ,Gןrŋaߕ'0W@]HYN9K Lozy9 X8qEHs7=[(PmΞ@eFmOtgm#Dt{]! Lۜ_>ʮKs)s1auifIH5 qɃw-9ܴOx,|!ߵx1Ps|S`S{k\s9=%JWNI'`Pwff]$B}I#VɍCG0$\Ѕ8EplM!ˢdz];s)-G8  "8AR%<6Њ^(.8"_mQv]O11 K30Kv qކ}6C3KwqΕz '\W\O5c%f^`F!g9_Ӧ8m7G>eii$_G($8K;q ydms~(.ɧqԥ#Ψw-8]墅s/=_8-4Z%4=E|37sK=/=9}|@YB(Ǩp-wyU҂.w'nP.Ƥq^cq! wوh/uq\g8oyHק ef߹21gVöeH.]?307x-:$ J%I±n6y*K\ki8.fiٌ}=lXIۀTyw;LthwnC0۠' >D@줄} tDׁȡmyI x,f}:a#=}]:vvDQT{T+Kv˲wv8C&KRn녾oӜI}3NUKSأ}ˣg$IwgN29[ېI} fض6[TNY-+eeY3q|Nbty7sW\7ݾ`(_ U%mKRڋw eXHw-w\s9ɕB% VO'?$I܊O2TTn+&UhN ڝ.gNTPe Toض6[axʮ"1gf1 ۡQefItdq%h~Z-s?C+Zr9pK&F"BH])$WT3(t !~MTG^!%|c8ʮ˝bOqm8R>Qf`VѠF*ںԀ}fȷ3[rR<D2S~ڸt!$8A(vyCsa GuS,Oqm8R>QL#'%<#h'ew Rɤ$wqޥ]ϬА4\KD1`Q MpD!T"a!]gH-jk7Zjmdʮ"aJ9Fl1aui3% MR=v'8ȡ" ʹI M͝c>nm6>HꞀ9]0E]wYr^Мj9n2#0.mL&p˺G/P"Bzv\; K21ڋMgY^JBiNa1ml/al[XXT?ɔ]Eðr8b 8f0K#8 ZdӠF=,::~w7}*G)<*;hC}mQv]O18b 8  kCL{4I hML%hxyZh$̜3Ecw6ϒ~~E_Yۜo CuSɧl)K["/ !]%I-Lg4|`3N'&3.{@s b4'bqqԥ% MS..rtoı'dKG(r hzLjLbI:Iu9#1.6Uo7oeץ9#0., =uH8yf ݔ^oĹEB5"N7E&r&DC3OkVF7j7ʷҜ|cQ8CsrF|&Gc, iTqirX<#²,2QD^^J\BTGc-{{-%B7C:8I9z㸡|(.ɧl1auifIHUV8dsCp53t>*vLqoc˰ EuiN>`1 K30KBz^TGC)̓HqS@x>_dotc[zY+a7ʷҜ|cQf`08} 841*D@1įx[DV=o󋩷Sݍeץ9#0.ɧ$HH$LTTRhx 3 bP.q0pq^Qqi9z㸡|(.w9ז#cui3TD>Q9wYv" =p\$a.6[f\ ]7J-a>9z㸡|(.ɧl1auif/4X2~zƄ8Jq֨[3`7ʷҜ|cQ10% y̋Ȋ$"r("m[D~^ ǣ0*2QZLMB:GSxSBkb4'bqqe`^ ܰ"rOd!"?\$gTc(Pq^f\N(G;0wjȲ,G|'q _ۜ_Ln(.ɧl1auYLׯqo)QU}pJo/"l2 ~Xw(9צ,:@ZCJJĈ/AS%mH $[3i7ʷr|Oqm8R>Q10UJE$^@=o:vWo.?o|8o+"rda3gN?94'gϙyi`kh("l7ʷҜ|cQeZ"?>pn$XU?sU{In;P,^/]mHIz-Hu\3al]EeƑbIl.E9pa's*?-+?WPOk -/|_^9 ATI5a9t 0 C>_8ld`濳ʕU?Bݕm-?O& KUROnA?5Sd.򞋔ض6[#Fǧ"˭=6ז#bt}(z<O.;?FV՛sfoNzw8r~w6So6j4N>^ D2P~I~mEz`Hض6[>vʻS,6)E@Ueٹ~LULD.ngjҎ/9`SG8LÞY1c\uYLI ge?ʋH6V49~i˜FBJ=cq.ˇ=b0=X43".W9"|dKoR?  0 0aaF9(aaQ4 0 0 L0 0 P,"2#"<." "r]m"WțDd^DNl-"??XCDL\GmBL8xr1Þ5nHUDPD}HD޺;^3ʮq3/M9dy֟>Y_>FJ?m=m,eRNH$ٻt0@R@$~>G6f>^DRM;5 {fRԸWwe{xp\|PQn=}J^ |Ogv6{vRYW?N!pG^vv˿S>@eM;s1Þ٪zzwe?:,d=긢(;?J׏ وB?Pên\7yF,^iPEUvUǁ rq1Þ 4n|G~<;]38f^D^RD$ %/mgL}i|PU?2e_Ųhyj̰g9֣7lf(,!s~mfkYv'EUC1`*? ɏ[,Khyj̰g9֣7lf(m,Z߷}⌜_~8/G:YvXrNN,W.w3mt;cFhf Q'UŪ E@ 9gE z>GTd +]iM(\v@D.tR$?eac̰g9֣7mΐcFhfQՏB! (v `X Uv b,}Pt:5.p˲s)aa KJfJUu23ֺHU,kOU+3 X ["7 x.-n xjbao%[f_"ܟfs׬o`_*"EyXD$"~~ly"~92MC"D"r/2sV5?!"<}:g9," "rVDe}s{'E"w"r "c"rL.ˍ_GODޗ[|9 ,uN\O_D^'"wH'"b14  [D'a `~Y+OUGW3fao~8L-_/8oofp>'"/Z鼽_׺Yy3El \F\%c|/e!+#5Loo޾JiyQpٶWo 8j>Kf,fkP5+&?ws4L~C@3? @;?em1/W}Y^.+y ӗ~x__0hz/}/(Gf+5k6lW ==  >euOf|?&3W>a yn^vpYhcq aEPQ$[Ч/SտRվc[ GU/z@US~իUU}_~/\d|d3߶B?gU9MfU@?w$3^#"O_QkdoPտa~dz2TJ-ZU@ٯ// >T2~QU_ݪa L0Ϗo~\D.FU/9%[z9}bv&\=/jTC6} ޽J_˹P=z'2߳6 ADdVat?8Xz6j uVzYekgFAX"0@TuAD~<Zǹu;" :>yٵ"س¹Tuu.ɏjwknjie ȊN{ɶIĽwCXUo~1w3Sal30 (w9||== g5])Vp I#_g)aTϒw-QDnF?;֌S^;*k|~tȾpڲk~OB;b2CU?/!D 4^ c00QVy>>%ʖy1?1r[~tǻ\˲Bf\@D.=Ja|qjAN2'Pȍ?a+y0 k7 c㘁iHȽIMU.B~| "Ȃ_7bWEdDYFTu?YX&lD[Eu ;1E}ޛ7z-7EH}䗀[D/~&?Uk)4 c3լE62<^y̙7 [Ȳü,ˮ#y/Y_]elC꟒$sIeiLJgF67-"YЗnl8d|xBDn&{~L[a L0FF|}mydvi\UoaQz\ ɼ??X"Kͮ^]o|'4"{?|F c,W3 0 0BL0 0 P4 0 0 L0 0 P4 0 0 L0 0 P4 0 0 L0 0 P4 0 0 L0 0 P4 0 0 L0 0 P4 0 0 L0 0 P4 0 0 0$Jt\IENDB`opt_einsum-3.4.0/docs/img/path_found_flops.png000066400000000000000000006345051467526163400214770ustar00rootroot00000000000000PNG  IHDRPQsBIT|d pHYsaa?i8tEXtSoftwarematplotlib version3.1.1, http://matplotlib.org/f IDATxy%YU]qɩ橫z@FIP*DFx/pZ*S( ^TA/"S ݶP]]5WVUySzDr8y2j?D8;bcoޢ `0 Zo `0 WF `0`0 b`0 j0 `+F `0`0 b`0 j0 `+F `0`0 b`0 8mήC^v}l17~K^)e%[>S Wco~ۻה n,S Ɣ)Ո)QMj^j 5^ύ `0%#"DDEzb"߱޶,3kG9K3\S ~k`0 k\/"*"76"f`0 kdaa<爈[ =e*`X2v6y|WD" Et'CDΊH]D,"7ن ".""RHP*" b["YD%" 3"{[E"Rc"ņi=)"[.u"r$k"r?r)zUQTWՏr63AMyTDݘ#" Cy<EoYϊ5XJ"pVD-("#" Ԃ̈HC|ꯉizD0~]/{JWO |~A=D@:p7L{UYc7nrXi9(z{<ߕx/YP|8?!"o[[Twb}@ާ'{`{=tUOD~o_U/{c/*qO _ްe-x)SK(S~{Ɍ [{WZ)2z8 ~Y=ƷԻA;ggKLs/NǁݪzRD> )UH` /T[5X #Z)/>ߡ "/>wn[p+t;U>|b}AoV-!|!O0HonY6QU?,"_|?g"2 ^5"]U,wx lxT}߹{)SLϕX<ޮ4fTGEy7=PD~_XI<,%o//SV V/8 A kW"0ޣDd?'~gW'.rZUkAF俉"uu iޤqOBa7+k""ҳJbogA%.R )_QWu9O7~_DbyKI-Lk&"OO@U= o귖h0$T~+^fn!NȗG _>{ }E䰈| `^ݥwp!`ESx)]ǿo=:߸s^; ~}}KsU)y|ZDv(^at}O) 5mE "0 .#;\op1-~ҝўbႨ )P xwt1&nE^ as{4` x{#"i`Y+BU58Uv⏊JϹ2~| ED.G\\-e f~٫/C?8ozLU'📿K@qi^ڍ,z{ل5f $>w5WdaI! =e B #Z5x~U^c7.p`ʁט2e^Uq=w,_<5ziξ ZO0P`0 C1 `0 }P`0 C_1`0 W5 `03 ~3sϛR8xrpæ,So2e`0^L90S ÆLôzC 5^OCzC`0l`0 W5"2("Y9|+͊|4Vw-KAD zbxl򼞈ȮZ\o[ W&FEV`*ቈHND4"`0459"b Z?|D^o6z6K'D{D"R9[ٿH[DnϊHUDD="  bTDv/܍;!"e9)""ES=5`W6s|LDڷk$D$,"ooh:;'^to UMD""?e\u"r$k"R?PU]U}~h/ta,üMD%"s7.(k?/"ZPOܾ(|HDfE$"">""ro[DҋҨ'"׊WD."E"94Dd|DoA}" M7Dm"2]p]=E,%E/]v|}ۂ߾5b&wfFzp|c=88w?e%/a;^$"PARO`,H4@Ya:eLxn뀿@8ȷT[}p ku8|`O{V>|xE`LwQΗ,HS𻮿Uy+|=7 H%"U~4_7 _'~-`~DYڏ_'=>p ~}x05_ ~\DO 3y2Ҽ"H#/3"GU4VBF^k"|.)&X=/+"ߋ_AID~SU?ؿL/1,_UDdA^o _NU7/7+t;U>AŋNO^Ap'Ut ezςaDd_hFU@DEN/Vգ/.~|+L]<]UbjKv-٪~`pq|9ܮ#cp' T" ~]U_D" B7x?{:U?:#T7x~>އ߰>0pG O_.MиC|U Ku3 ~8~ |`xF'YvG[] ~= ]| 2UuT.yUU`;!"~K1GEg{] JȠNԞ%pEE|EU5:Bh~6K <{YpO_^'"hb ^n'gì}YMKּ3ti˅V}cy~%.O8 `hMLʼnDd'1~I\&+D_ EQo\/v.HEvɳWذ+!=]\VЭ&-r^ʖʼnTu\w),fյKLӽVS D l$j_wò1p!^Dm^b *"9A~OzHDM*cw=I<Kg<^CWd%.~~v.|c?.^ Q't]o,eK_yF.)@Y~`;(k;|O/\ ]'ؚyL׵ڥ5~2Y"~7SE E8W _q`qamX곻TlpaE>_%"%߯z=U`;(>?K/5|޼wLUZ^߸EaIj?_1KD@ Ei'")"߅n074-" {O܍?蠺(]7 +e%y]n7XW >MP.޸s.Di'"^< eR0~^a2wqD{ˁw~l-" tgo\c]U;u SR}_P2x<>{E"r?nHÏq c +P d<jt<]UZ@J#+TO?U=ޯyb]lǟ*pO ^NSڎ+࿴&U%Fe^EU㋄#?s.&{ܾ";Ѓ< `R=sznğH| ]4Z΍eG{EUSgYCo.3{KoÏ~3!4'ò'NgXW6 %x TV6+fL90S6x=~XiTuJH_iX j0 `+f`0 j0 `+F `0`0 b`0 j0 `+F `0`0 b`0  D?iS1`0 a<^< <xc0 W6";E$޶ ax5U_ O`k06GWx3EODzsM"r4D"r]U(J7 `tTD?. }~b5_/p|,? DϊH2AL`0  6`[!"'Eݪ["r']vө"N}? AU"" ă?)CEdx1ph,w f%C|AUٶhA/^UϋKR{ۻmo 0p{-[4P4Ď;fpXzY:Ly O6oع}?}d;.'GçLA•cE,Fa n\8£jXXw nNӨ GN?DV\W,f 9m9(L<Bڵ0TNQ5^;"Ŏ#Hz[Rs8=]@¶ϧΖ^ a bq.SSUU+>%{[q 1M29yC')7L0ĩC}ø埫 'X ZH8D;^έI~bu"qhO2;0aI[#8A-ؔøVDOc7rxQ9x n?ZxРOET"^>]fVvu6߂'",ӌR+/(ڲ\"XW 'fO&3%k_n0NxZ o:-)6b& K;}I=1ߦq,rH\,cI~c?ũ FΝ{8gؚd_v՚U'pXhju05[e:KH&&"[htu&O=e~MR]/E6h6l_Ww۶w]4mQajv {rMGiMt:5±-Y"'E ?0?? ~i(SA࿊Hn[U]Jm&QDSw/#rM8JWҼo'"w=K`t./bJӿ.č8n075iSvAK&vq-heQ:{YPػ3C'SF8#[p]oݣ "(t mf[˃ 2}|8E:Ԡn –mu槣̷fxH*JLzK\c^5qA;B.7ꄇ%atG2$Z41X}RQ "Ko$Qb~Uǰs.V!uAK&YZhm!tD~8_7|tJxf  A AU=|]Dy|{U4uQD# "3/f)QlK4^=Bku}%/-@pvLlw'&O"(ꅉǣ"d[(D~4 ~{c˭6R%%O]GS ,"1`Gk1&vԨ7`(3@x=f9}PeTa֮Yg`xϟ$a`'K(aYu׾ͤ\m% e5aC 4^5N=iJ>LBDiZX-8t)7:k*@À49MANIE{2ǧSH^>|$!7 [.z(-flgU]DDZZ7UN H???;v_Z-z8w٢2PB B}<L5%È m\oiT:NT(ㆈ'ZUK8WX=a)dVI.Y-m!6WG%NݥJ7]N$B<&!3Eysz=*5{ JI9iC:,&O,;5D<gd$E"Zv#)vH%`QI1]OC3cO| 15YeK ۇsDaȚ.11^C3M: pmk׏\6|{B%$M޲h*#Ǎh7[fN˲HzF` PaS7w^=m}>$Vj'2IRьhuJdK۶Gs=:m9Nsh(J8^ qLOPskTfXQBk쉝4xd˞6 7[bfya]!FC[|tT9=r)ث .;$ňF 0DǶlvY0 Kex1Hmm:0Sjm *VBg+%c+-kRx<7lM-wc0R+TDۚ#]]cƳxV M.{fbsq kB{ܔm(gPO4Gm;M6Q M\eIq[JʊU;=cLf0S OjF6TO3wnΜ4笌4r7IX3luCP,!G]NjZT~TI6sq18gpHhժ[kx?_wT\;"*s癙XZ\b f XQ3a:wD+O.z:SG9߲C $R=\,^BR&Ui n'bmPńVJUG!b:Ar]:O:X|O=*Z*KRKF4DzFwtncqKJk|"E2`R,ku J6љ:";zb5@VcLLMbc,#V(vw:j6fO-Uڝ:N$TiS$s,N1Ch/ܦŮNS)Qzt]!v VEsEVHMb(F4^X j 1Fa>(N9A]aNISbȹ4dHk'^g1~#tUCBf8K:XqA瀵pMؒͬ(;3Sbr:N:}{wga"r؞rHZurd Q Q-zė tY:m"HBCMzDjB"!p`DjI _cl7a] N 17v5C.`4&ʀNQٳN-\K.y@j92ՠ<9F2cc{woJNP(B6ZژW7IgR9DiK̜nsTzRQo`g$ ̔ZEbّUO~6BVa0Y;K$FEb7ZFm$hlp}kWR\0[nТA&>lGW,j,"RfrMi7Huf9w_(WUuϡqzC9}@*Pkvؙ|oqMefT:T8K-&; ߗYnt*5HH:M{3U&*4m>N/5`8#ۄ)(KTfi5[Wzbc̏]* Ie<{ZEB83xnH"B|Na;6ۨcL+әh u!k[fz&бp4ҿxAleINaF 9y~HCLOqd`ڣtvbd5xV\,׳T&qr^#<1˾PBr]t"Ds0bqmfW?߲-"13CG8:ĵ),av$Jw`h]zb! g: 5;5C&gۮ=zz 6z=Yhқ(7m[2Cv?:T$h[= qbձ:-8r #@ B#?JxL|\pʙv%t=1Q"[t4xbÎ ISD8XD2NtĆ,RÒ6hжumED8K2q!Xb"yD>wc,I{pͦ8\Os0F`8+SUz%jgpkdBr[hPzNUw\Q;\ȣ s`<$3tJ{NZu?aRHDF‐TO8$v Oe"H_92E+Ua74t07Ye~ثV:ӨGر+K]Yư*,7\h]d'ިZʍHex$Jq]1fϞa\t8!hQS$F]7:N)4 ǰw(5+vG8}aNtJD!,gz-܎Kkr֡C+k.\\oˎz";J}Sz#[_jƲ-Tz;Ӱ:U hK,v|$E>y&y,gJ'?D4# (ze6}IS")BCCk*BECz\,HYh ?> R<< lҞU;)`BHE \TbE$"r6'_tt\fΝb1Bn"gw q{ƁV3g91wIfy£W-Kk2g`Ŗ($G4;]HLmqĜ>=;iJM^&1:gͲ.x\5U{L֓t,wx(z݉$] E{wD'F %FxJ/}ξ^cY6D3[>~9&^Ye!5Dd(ɹ K ,N^+P:zIL|_jT8yx!aBl}bxX}}F8_ 4\!NPMV0s!;E8IE*MfBX]CO Ur~ X'u8|VEHِM2l022Dv(Ndp[-±O<ߕp=S=ξlM6 ٙ*S*dZ#6hoM<0=*XbC.EDFIxU m@qi)8ScIjI%MX{+,i6\fUU7;$)kLE-7}&Njd+̪rkXv|y8XxheMt2@X"EBض,` oZl$QE,IFpg0U'7X[ 273{Qoݻp /p"®G!";O271K'iHg(tо4,eQB<ھpzmJPU2Q:ųl%Bjgtu;uix[^/ Dhϟer~Fᨍ z=#vm tt;(M5"]etjf\Ҫوc[v$bDlX"F(һ.F<Yev՞f2"#rya>,B$a:_VZ tsΌA,åajʩG%mA)&e'aЙ&} :&3c'8Qf}[oߍulܹĵeDbqj*.2΢)4C%?ŖN8^x{_ıWn[ McX z]8]/rHqzx/9 xϘcn39]eZh|UHs* Xh#J'jlLeq(P! .K4ZP*MQ(`74. Ŷ1utPB.#}B!]PƐ$'5&f˪g/5x־Rѕ[AK<ۡjR5r@˶3{(>:nӨ \ 5ǹ4ƏӴ# a(˫44,"c[MҊ!6cqf7}4OH4laifvkڑ 8+̸#C!Xfm鑑gy>g%dpo͑7p ԈEƻ @ZBl!ױs\DO(,+P<62~|:xOP9|e8;N*VW,]I'dֱCMc(>{}l|Nq8D'(uM{e$gh=ԡk85v.<-y1+6cݷ[HsɂFtsk etšg ǟq>ST6=Fz=,p=&r#@o@ N~'tn;,2Xx,0)ڛҊ'~ 9$XNsDJUrxXUB;1I&EJC!](3*ٯpyG8|0x3℻6IQ6r]BdOG,dC*>Tf4zIJX{K*`{HySZP{ g?Q6^ږټJjx-c͏c-g eRg*MYDf+DZkf' ^awl7bS`_1SAX$9:xO_^CVi\]+zRu~@9e"pCEU mhap62X/,l!IQ{Fo);"S}Æyaȭ>Nhr~ʻCmZ%sԀ]$}QB`}v*>[ߢ_"%ZkSx j;;l5:. QZSg5} IDAT4<:$CE.=ƫǜ>B8&hb$^&^K1GO(#”tMBc}S+|ۤ:DcR#jXgumiA܋ÔW <<[xp1_taj(Z ͭ~* ,moup#@oU))E{J1,y䜃!ڄ-7EBr{Ƨ<kI^Bf,oFsVZwJ(?.$ 7 .R".*]q&S@-j؈L\i&k̲9s,٤pqt+#@v:,Dy\*u[ms!-Eɋ'#> 4Ε߿,JG/8*jҴ}O7|,s ۰ 7#zhi4z=@Em5F VA y?"ë\OU8:{s<%ѓw1q}Jax>-ťU1L?ypj3 jUDch`)J?h!@vC "13<_kϭ6G<EZ(#,â1ȧ|:#q\bWWn£sg4rӢ澆P!oJ.ݾO!/%c3~׺ZzO8 <<<ŏgxXk-EJ1E*7 WnH7V gg 'g 3V5z!{o Y%hIpj۴&~2~"9عc4uO>`I፬-UgOgmlN5XkOR ψYQ ںԗ ZktY`ei՚$d\ze;1 !p6AO.z6Bpy7߇)$;H:}Sobwf$,*vE Ia'RHT4M2\ -TX3d4 oZ}~ԟ=ͷ2 [--iAoj`_b>:;Ӓ\ ZC#lQ /b4Jli]č)$zYXM惌LpΛY!&ոBz&f ʟLKbt'<rdW6#ڵ6 6oBǫR"̝:miJO1>f:]pz0`<8T?òV !. Nhߠֹ2 ]!_yY_o#t{9 ʦ#e}7;ASkH3y6}R`jv禋+8Izv/3/BKv֝bl=@켖R 5* r3MCX~6EcN;t,oNtDh2|!R&צh@k,=f{t#@oGUώ1뺻 i kI\ӧ!Xjgݘ-tA1mRHnnb[9dfQ%cMTMHјקԕ,/Ҋ8A1KXٚeY N{اr۽v+]1L elQ/u_R ;=zzO 5F·jK .T(ھylfIgF`]IJ1%<<:91DQa{kwBH2Ids.|9Kxc= ߫uaM!+&&=1ԚȀVoHS=d2[!ܢ۵˗3{hqgcdZԛm,mTUV~#~-5r#@o|6ptȽdkWs`&no%2 C|OLJE8/67 Ҥ Wصõ7\UiАџc||N2qZjN1fR~wԧ^W1ʊ MJ%dYq3NƸyʳs<74͎&BW>5ΚN%Vb^V ۺZeـ7qs)x!Fb/wiX) 2a1B+ⅅi+ | J֐ 7ϑi)/p sC vmׯ !60[ PJ,^ "RMMĊD lAV9pj.҉aa2/kg;~&.AOed~aC.?!EPfEm(덂zi){6%v{u_kEkMS=_2وhv@ˏwHϟ_ja4I#b1?;"+< L ( 0|y5 bU*!FKɧ/> 0H1n76OK(X|[zgf`%Y&@z!B"N b|e7QTWo.w-KFj]Q&4+|) ?\w锪PE 曵W_z×HC"yDBx>[=~t.o AqB`ňpɌ$Ή"sQ%=R/<=~L~6"ӷ%ak]BD M霞MTwW26caRVf 6"I 婥PQL ϓs +ķ4 aQiu-{b&M bLr$R(0DD`[1-1D$Rsk|_H'mNc(aǰot*ͺr/S쏟98Mۂل`=PէlP)v2gNze…8?͑٪q0)L66K+Mʒ*ϩ07n (p'_뢕F v-~XOp\^msɪ)C-(/y9pZL$S8kی9>iZ`Cc5Վ$s7PfqcUS X~$N9H_`]6uEַa;6iFl"0Ƶ<X a>s_ ^Nq. ^?} ]zY xE]+`V9n996ϓ]i}㮾 6,R䍀af1FJ~9ߴ-Kh63eہOov}5פ{ NgsJayRR &DaC{־7 Hp#@o J)R! <+1-^R9:;e)Ntnɭ𿱽* HN,!ڰII[o@CsW(QP~vk.qnL?wsA٤SZaC8bf 3{>`rs5fYa5\ [{ݟ@xo*L R:7j 9ҭ5u%Ӓ糈%A94t^9]TE&,SD)F~鶱]ף&JH Ԋ/Jd@tzX`ZJS/3 D^qTHJD#w_}~> /y˻}%36 Sz [E-(KEv2X̨jM4tX7B|k^rN[ufsYOesM`w^5\nxF9r3泠*E4N)K-LEWK=Fp1'Ι^+U7L_0Kj@rұ#Φk.)fpkccX"_.ѪZ%/ 1=;%9NU/"'D]fe蔲<-YDc*H3NCN'yZ^ Fb8)5q6'W|[`s}!hHW~ )/f:K:Ygs(aQo{kH[ݐ -<=1[kXYPL&L. cYEOFL?{ǵ[%G@Ą;5UddOZ#'׸eAw`4g];z77ER3OOyMRD-@B=QӔ7s I1}pLMȭ4$KGdϘN!=zW6sȤO͘bI3 IB<#Uδ8Fg1i,!:VsMT͡T?Ʃ !{WoBZ`L)=١rz4wz;=t]_),ƝN f =;8Έp#|ǿTDZZy4Ŕ9r$0-fn_AYNd.i!g),T YyDznv Zͨ0!l'/hz=6LνuZfYOx~DNߧnY`_]B<,Ӓj:(|VEVi]R)w3#U9 Ƿ.BT')&gTVZ ( NY 贋Va}~ c<7_&.J[]BgR}b0<8si/וM+MUHP>_5Fy4sݷc{o)BrgALശq6+]5J+iv I iHdSrϿ`63ȶxrsgg,ϑ-fGG/(zE41Z8;ci$&j:SVG&(BZZ(:g"wtוor8>Bȳ-*u!M7Q5IWJ+83yDSog)EY^iLQ ")QPԺZey𫒭/PVu|$"E/~v:3$ƕ%aX3&S&a뭥4yOn @<}0:L$}SNS&~&^Ϙ׍4$v4j.lȋ־ۥ Zka4'h{d"7Wk .MkK;8᜸ֵ*֨?@̋ueDKNgqS3%6K @*0]h{Xa46}e/ٌـM#YS$9Iy"םkahʣ2<\U`~jQ,91r"pM۔:!.+ᛆCoڛݺFc p˒$:\JIN4Q~ gwt?e.byL>O)e kD51j2A ,9#OmLw5*ůo??p4Yy Zv7 B/xݗZ%T&R/^58͟ IDAT<~BiӍ3nH;h]sm2oia-2DSCrcH8tcQb>J)!Jlm$%єpȟ-xϸ4zw)A4WOxU,BbӋ:_w#} +AiR Upqh6[¶IZ0)LRt/w p.ې$l93rݦO#Xi+U6$k|\տhu/10woa f,MAh̾vs E(9"ٯ|}z׽ AkaSoѰuQ,xp3~wim$ ɜI3'HC\s )m0/_[sq=%^ҚɳZ%vlIjl5o,aҊs-5j({ ~ckTdQt \F>aͻ0޻CRJ03Qw~VZ%J&s(dqb#LۤӶ>3>1wocAY%55KV*7x /Di,p01{xqiհ5 !77g%Y`{5'dk LTVz/6qMA ,{;~_v~ ;yB Qr΋~=lk:h%Νsv$/W!)>d^9 ҊR]_R ǖhA,AJ!ٮuH:x{UfI.e h5]lC^~-,ʜd6'o+vRYCH,#I,YD9;a#敮4v pB:4h[2E^*BQG3>m\|Bm`HkXJ!%V GU+<棠٢sz×h?>zNƛ.#,C:MӰhw;4-R|'\ZAE 8YC1lpClQZq24Vh7|Ҋ '!R5] pGk,3O8}<= Fw{~~Ɠ, ɨ`~xLmgk5@Y?{h`6Jc-RX^=J$jHTijϲxH ;l~wC"_?ecm^$On]I+&^ݯ8<|zͿҏ֚#9*E:h /1aaTTIb ObLY yˈ4X;UA`i;t=bPmx8Vn8 FT5[#! dr#@o.6)$?eݢ~s'*U1x '?LCd~_OG%iI}sV'[} leBH`(Izͣ^uu.PT! FYmHU3A&4QIKrsV̳9J* EI7nBRDb YZ Zc*Yp=)*΅Ш$B}G;Ź$JʽlAçuB1Z_Nfi'9#f@ y?=h_m5b>b_'7|D"Z ")mv\Fn  l!41WE.9p~Сq4w77{yɓA0ȅ`Q>#=U[V"JJcHÏtDoki25j o6għsƓ/߯[2Avb{"N;8KqewapF ǰYXʬD*Μ-%hg6I>WEZP-{0WxI"|t-K2B³ aZxAö zIͳkv`!KCxPUh^P |R_7Ϳ"BRURwܛ:ZY.[>9 0-ʯcEI>`c{xE$$6LSsZZH#_/fl~eӚd3px1fm%LPӫ]lLNOR1߼Ï"b+ y%[ dSi:$J]LӸqs:='W!aFȴ%4%6Xʜ^"`x^eyS{_M[+8//.ZcRc˝Fh0p%Am>?[ z Ύ>]jFh,ۼ78/OوI%(vwߧ_]5 _H4UFBZ Ɯ `6ǰLr:ӭWoEPzNMy6ir:%^Oi(0OPTchS Q_[z(`NLd(dj`08LAxiT;YZw4=>Y>6OKoPWAæ -w*+ḟC>n!naOJ?ョ`ڢݠD!UE2/Pqo`s͐nk.W  ~" Kk*e\,B&]6;WoJUBl2_*NSZ} ~*'!/j֖=Zc%ȣiV*@kIݤqw(`YEm'GEf<i}2Bz!w)/{]G/7Jiasw IyT.jIpp@UVUb1{n:M\II&EQAYtL'Zڀe0` dؐDaӔh&)(Yi\nӹr{횝tխԻ.n:{O|A15ѢrCsd^D7tmn:u%% ۝Q.sQ>%CaSQ2BJ$-_|2&A#G=uj3_(L=aqsIq0 dF*c.+T- > [fZviGat yxߍ-r' c,nҔ$Cf)]ŒE})`6̈Jj?&Q($6ߡj kLJyw]zGĪNmpMHKgodqBHU| }jBK>;`ծ2mTn( 2Ҡ!(mP]Bb1`~o`-"ɵpW>]rךUzDbZ7пTJl6*wQL˨.=lp{t6#b:L(T_TTe(w, sR40c-q++3~d4SH~|CDek{㜢~<Bʜ, xTr\85E}0L&'A撠a8`eX.$GH1!!5E}%V 3> 4 j *7b=3^:i*K P#&S5A9cBrTJ{w;k/S{x+ uR(f%لebǷ1E{ mcMq -wXܢ,]d>ghBC$+p N%{zRJ ֪K\lPR4Ai:둧)lKM-igqkJftsuU4MGJj?bA$Bi@0 #AaZ:͵",4FǗsW "ߣU VTl} u.NՕ+\[cyeӐg9o=}lUj.Z~չ(̷g)ToL5vItɰǽ/*wL$K?t:Wϥb\.}wQpI \-,ASY?x 7r)fk$ziQ]szS額sv3@alJLJ-Pܕɜ.>UC̒WVMl{T=AwP'8κ qb'"R9_#Tܕ%*iņw7B:a 5^iOgdE&?rA>s$`:eSk֨lRnKV0>ک8.C 研·-n-Xa源=ӞE H:8HP53aY;דi4h Fg:·/ge%ޗ  0Uu^\nѸSY&St6`xl Mg Ih\vf$z'hj:XXT*fFD =uG8d>Vg[qN! Ut ק.4*~X& g]D#rZ'3օ\yqڕ%o1~VDNv Ba4`j(LIyY^~aN8*@+(/dd}GYd3NfuNϻpeL=d +㔩H(:%]J+/ ,GG<7@QJ"sV8ޗ?h4vfl /3K^y5nQcFʋh2YRز+bƛL>  '}@fZ[&Q6B|}?} u@0P%)j&nIl,Zf h-ˠcQI37T (A)E: K$CxU9Fm(C3RS#$( hq ߛ@䧒"咽{ۤOiEoZ*!,ɨ8w3<81Qup5QӐ:W'sme2 !(7`6V.I3IRu3h:\97o|Wo "shL3 [F]װ %4!24]P|6GjBR_e=AaƒZ]bS IDATVF5J)p)Pc؋)֗8{Wþ_AVNxIɿN( GPzUhl#6ŢGnTJ)>뤞OC%84׾# Ob8$ uJ)]tMg Ѷ TiӹujO s90+q'dҍ1O]=.!Ysru*9z؞T3MDRػ3ԇ&K&|#SX3%Ctâr< L&![zbyqRJ7bM Y Y^! tFÈSƳ=1-NT|ts9!YmYTqC*<wxa8$Y^ڡLeiBse<~ĉPfKW^D$}F.aPuSg P!3 3ob6Lr{ys!=E-]ɴyהS5@]Bea$*JځTq:b"LGQbP]_ 0(u ޠQQW8)hXTǝX"NJO^KǮE/Hg!2čL<=tBTs0BFn+flGhFj z;oaڍ5l+FVJ ȽMIBڴ Y2:g G)1S͡Ћ%KG"B:~i Wg `W)`Yi𠻇;ܣ!0ayӽ1+E^xWmYT ՘hQf%4]Ch=0d(^i" 3<@uzĚ1ӦTsXB1 &)K6o咏nm2ŵc>_D;~?Bd ъe K,~tq=x`:Ή$/[>׀~~G|M7~E)wSnx.4ôub߽ h),cJzgx &ҫ\շp[4uų>)J)4CaLݐj]E I!Ш8u:/|B4~3t4C%ݘ@CO&nid7vIe0b:vNQ7<p;yϰnʍb^]$I2j8J3*h]-SMቢ%GHrÿv4\ Mru.i C"P!7[7/ ZC‡ BJfhV`[Ӈ<|nx8/cO !o?|W/@|O*0BugR1Y MJ!lUgfYt^2f$BKgv=)zCliPwㄉ*."ayUdL*ߟGdiCpߦg~g,^4c8sa뫸J߃g:}Bhzt^}waqBo=>oaydaAp} bi̳$# -y~X 89u" GXW>uFްu&:$ۚ룾H]4\ZBJKVa_h:c.`Q:Ye,>:#g"Z" +&_ˀޓeyO !~B)k.ibe&Ҫ A5~!&c>/ f}eM BI B0O< {ȃTDE''Pt=>D.VA(,21&ml&)4(/I#lVY?67l31|4L/YXK)HNN>KvmkF\n` t9-V j$4+: 1rv#2%(~sdiJ,G)~#Rh)J783ٌZvb"M>z_hbaZ|tG^iRRq-:WJ̀_~Q2_wO iɋsS/bd:3\JEXzf[ry ߥwq*i$EC^> J8Md5 e8zxID"fLyvn7'B`ɣwc(BLItLdSSRcA_\nunXzLZN'Z5,^i:m#zcQk(!:ǖϒD2D"WVk\8a7qYnөfxR&݀`7~fBM2tfQw=8Po9㈢sW ub VcaGG,Z C.BgG_RrN(LxM`oߧtƹ/#Ш{ujI#|ܣv}fX?~̧d|K=6WV0 mnrq{Dm?n \mVX)5.,4}ht0e L:~uVcgʠBuCȅ" ߧ5- ~3ʅ"7^}^@SkkN뫀8`#wo[xy _O.gIޔԬ j/̦ŵ ,{LàV(t֘eơdav0A]_[A#\!LJ6, )E,"vgᴂ\IPX[d"'6;^U(:0Ek uk27KoA\_[fY s&Qv&c~ק10sok3ŪXhDC?8Ku**m+YNv' dq߿GG,:5 (og-LO~btzxF{\u.Fo!s c E+aV.zZQZBɜ|o O]d^l L3bQ@CD'{߫\H%aV)6!WWE_V)c t0Acy;uFE 3[yYٸN!_< U0>qAhrI +B었M˘615hR"A0 Wm{hn -z#&Ex<|`Y&Zi*Xeg.79cF1}k*M *Mר7\4Gܼ0m :eS[{?wx_ySG.{ )RJU{?1BMⷅ') !W,> ! ` R'O :i1xt.!e RDm`XkAbX0HCiOV_\:FǨ4X[z{1CWre|ߦ^,*ιIݝ/o1}{hs֛x:A~mvqՄFխR^ʕ|0X6*v^a4jB#ZPZ`?RJp0'f],>YDH%;|VхD'b+-~k7:$BC*AtvGE6^}~u)ҟZ:N\[Z!I" %{ #RBT؞Q^|tĩ=J~i! agPo4'IbL:g1cǎ!WeS{RĽ]` J\F*=j8害RX! "FlL`\¥ҭbb5DҪ,ͩ:QJ&j$C4 8skVe{v^ K񃯑Ϊ"j-6G4J0"X#A$ t(I"3ؕ0 "DHɳ4(smzsv-xm%A=G⌃ᘃQ4fQų44&ak.F =$#fn]@_/>zyl3كRwRR_d }12L8FR`C)WR?<Ŀ ,X~|}o~gO)7!~R @H)IӔ$I.ki?/ɛﱷMf~Zfh\+M:Y](Ra֫Q0*R)TnqNcw9|-LF8YJIR'!C8:Z ӂu+7X1L#?qGA`)ZSX?q q?0E iPZ$mb󶖋1̈RIkizJEdFD'R̯+GU|&$1t A8`Ml[Tal?2Ą\{Sx2BblMP%r)!"#{b*|S08"syG)o}1)c" uvro08蓄7n0pG^꫟8\l{˙KH>hؓ~Q!=R*BԙwV1{BI !^e}7R_:_y *7?g?dBO+i_/k`0 VkTe?.ۜ5Pb[nλB×a~} a;0Smk@Vb:x~Ͳ,'ɦ{Dӌ7\AӴse[iHVQjz)u9󹘦6p6*ZqnX䙬Y,9K+lEیJ.)_ժQj8 CzXGMp1/Sk+k\S<"aG88c\Rc)dk:$ E0~\ǥ"*  }W)z<{eY[.%*;!>z QOa:q?(2NsxET4=J]| A h8h~o(>r=Ds1!FB-]6Bgy=_czX){BW+~?U𾿅'aB<zzEy%Qmafz2Fd ?CTq`n; (RpKWTL%iM4!(y&al8N~jBpTj,6-av*5DCTN`XX(fF}ZqZ^wRIt,@M3!N~*8D< D\c.8s̍ }r=R}!ğenD;{)හTJ!1湢B(~?3-2/8:r?:hEU?m$rl9Y< ̅/3CrDV)oRkJ2L1=\/"+7Xm<Mh}JwZSpJtts$^12~]+?6"]pk+j^dJ,=$8[Y&(nID80Ɖs ]SGC6FWdހkZX_G!)DNhT^j;0mHUF:WW,0 @י%q51A rS;ygɹi=tC?BQp|iR/ZtW+hC,}yq~y[N!C१La)~!3'/ /Ѳ CѦJܿ#L;aXf:`?}.KÄ(PśKu>7h.0q7`p@UD!zPlM! _.07Tn$3wAJtq%{`MUl[ɏ IDATX#Zq7}.a5˸Mキ2v>z? so+ 3?~R }IKJ'?Y֟XOI)3BeM}y,2LLܡ :~R\_$&=!)=$m\Z?(G/l̸eS+- K`.21F0 t$spӿ7I2Qv bJGYJC̞7)g&V*0r8>`{H~65, ((s0ޡuiICB^V!bw BFdH4mfΔC5 jFQ8v"( bk$>ôgw[˨*gT?ss,}(\g}km2!R.4vL)=f-&Wj0='O$r jOMw.kճJyI?<,&gޛ[d~=ǿR*{b]o17p d)O{QY1ǰ Mh_þ[$m8)ОILm|p $s[El` ݣ0P8~ƼWyL0 =tJt+xt0Rq*g&ɤ: _%+hEId$g ]+;aH7g1Wr Gȕ ]vu 8IG)R3qJvN]4-O0 O.nKԛ[n~ Xh[xuA+c}+HDD0 /Lp:._E*oݦjD\Y'IrIѷNwv![3 OciBGYCu1䀱2qŒ,?9E:s&PibqDls=å4LjM"n0Z7O%U٬P>f#&vU$)TAFFcV6 (E>#uOvC#trfnY<`6j^λi2P>7L,2{\ܲUla\MR~O~gW?)P* D\$ʈ V \\2XlMdJjɳ`80>+S_A5D)SXsNM(4 xu.m ^0H H'C| N| إ˝ad2}|G!!JIV x<6BqX+1p͢_mπ#ϐ2CV4 M!j-;ԯlP33eO)ӥfP]&m-s&H,Qo}xG WixŬ4L{o1YXeh5)VJ'sJ%1!(PSb*{Xey>9ݜ*w/<ΐ"%!L(Ȧa@%4l,YddRdAӢAS `Sb~+ߜN>{z53|nUWL@v>Թ'n'<, 0h fMC]: kDfBN󔝽jcAހaRw-3[)1J|}=w)47ѩ,W3(cn7uʅFET yBZ(u q tC'Tɳ&>:8)G}W7}^P& YeYHqkVphN3ΩURnYbh7JWɓ.aQz,upg81 p"iPj4peֵ+LR!t*K2yvH?=`/͇D>1;ئVNAXtOuPgTGc`R}&4<|Ϫs~9Kb!#mG4(y/U6R>xG{tQiS{Jd?JԬ~*F2F.7]|&@?!Isydg)3cӬQZDh/䏉⋏8Νwh?;s:<6R[ٿ[1uXZ ^D4!p- R_`A Yg*Q" lUN,$QO:K>qzR\W5z7ٚc1uu-ZMàߙbXMei hz@2ާl64WLt>qH҈j/GWU[6KA%GR($%SjDZ89G קz'SV|*%vΊTsSz=^zUn|fӔܩQ5]$ι?(%D_j2ɤsr3dIBe"#O + o}⋏x'Rm[~ϼBSh8dm*%@řկ]t4]ízԛ-0*Iq >'mRrA:pM{Ba'QKi ӜQH-fɳ("hqVsey}>wjKđE, 8@gDZLԤ=6Ld{I&-*Ps(9/Tx}4S}J}x`)n.5/Ėy 7(J++4SSXBkD)hsg^&* C)b W-ny$,RjqV:nT9?)ޟRq&oa]~T?T(,.QfQev: ,IH9`8.dD }=3O`!p?OWq0L OJSV8' R  b8(gVjs,P)mSc6G&41#çep:bѫˁ(&B9l z<, ]|Ip _eୂhչT<Ydt&9~1G ҅x!#o\JbU/9nPmy:PJ4YX^y%Ja..<̇b=QJ1a|ퟢp%xMh؆MQDԧ1XɔD9(a_"q|S|0wQ7pvܮSU$_O!7+(:;#?#e6_G[]fUAM]]ee&ęUW(/OlD tLq8w0 &躍:bQh6cm>s>A xqaL_)EVW/qwFצe0 ,Nc6UK4Qo12aiDH<647D5lWv{YI3:b%!u[k>0:3pW*r)򂽗{8.U4"=տT𲐄 57ϲ6c*!_~M2ϋT InI7c, (!(f3LIIh =*B4zbk󀁚ۿKa/H !z6˕&ar,f24lRJ=~?XEdckQA}+0bvY* UɌ8;]rd5Iw>&TQr7p5ȱx+*Rb՚4Lk7^u:nuV'քzbqcRM|E'=RLw6 o6dNg#"a0H)nusx[["}0C7, t?+H~5*?I8hnU^ ezNI,Ksc5d01Sqg1[\hz xGG4B)CBnfRjx"MPzh3[_RgOˍ*:ɕ+ܽwY2d9U,l}H%958ќ%r!8}7ؿh*ְ$O,Lrɘ\eر`.`׌΀< e0" v=5kM$ک7K<Č =nO5e9/o+!f6Gi0ܸW_^2fΘQ0 ,dw<#'ZJ`ykLf 67 82E3X6tAPUFFDϡ3;fb(6(rflWf:{ɀRKoQJz؃.~Cj- Džs￐0)MSiH`=k/M,2p|^Bi1Sy!v:*햄R޲͚Rj4{ d#fpDIe`frE=" ˄~4j G}N{0 )L۴ϵ{YZb>M*gg(ht Q9rݳ R7+CtiT:u)WmqmkXNx ]GB3h̛.4u|}^4~j:E`\W8ѪLal(ecT|VXIBCYaMw8f&TKP5Mń&gek' @>pz;K(4Ssdk[,X4Y8Bk4'ZI#bG.[Y}y %tXOFd ~Wx { |9z6 [BJE|pT6M{p]*y(qGy~!&S#5]M\G.rQ ıdTK[6KRSs N~8-ۢ4N`03bl|;p_eҵ3{9+ 4台j|Fف<"SsY[}~RAq-"?2U/9W[Wny=1㕵 Go^Zf] **X*/{2P.kpDR}8$2e5 E ָ? ƻ\m.kPc<dY)L讠YR/cyM~wPFV@@4GG, !43&K9_;D"c>tLpm8 ߿̕+W8Ι}Z&SƒF`OqY)i"Ū]Լn]faH2Z;bWWNFֲ>żKOT1BY=Α: r%l@yt`o,+ JN)0iJ' ! Ve:A{zFuJ)лYZX\7Xjl}|3Roy[kd6FK^!14̚,<*GM(;{l^FR9 qW]/9ӿK)-RB 8 }^04ᚂN,qa.?f맅Br[\ʤզ|k m$Hgwa\iw^uZ |aSu4M{St>k6~̽Pm#dh^>iw|Ɉ %Z;g#Ӡf x8&=u]0M ]0>sMRhK's82UMקjX%u Z0 Ŕ^:ɌԹb5Y=u  IDAT RJIj*ZfcQIiOm6|5|Xm{~}o_I(f&1l]\/İ \$ c?4t*sl_ܟ:9c> W?<#w| 3@)EC{E,5Zϓp>LÖיw9K*|ej }!E^PH,~"MILywH$NDHq}5]c\īɿ`ω)'MNЩ,d%u TKMM^(ZǼ+W&uVeYE!"1,#!3)URHy2w ]Y_nKBiɳncPc_H)؃ϣ2m}v>F}|#cV `:O0ٝ3؁+@o5)3;wHMf浶(RQxleOOEϐkȈcJ1=&$Hmvݲ;}ƽ N^["CEKrC;ݗh|sSljPTN3XCL5:̞[+&oY8' jtMg3F=#7RBK?l  \z ɄB2I9*[O7TģO'1?{t-&6.rhLnDsq^C7NXp(`2vC K`z/A#MSHQx6#/{GG, AB.!~2?׋S !T.cKH* ]xWyRp(b2ą Vi»F R)غ𷨔!!ħ/w'E\k7 џ6a7 r( Ɍ֥X<>#賢(2F^?'L3lyAm(z+]Z"gd`{DasoҮ&o~zg>yXtUnQ}k\gW:3 3Q\"s6S[gyex( <û;)Icb_'uMCt(JwREOP+&ڌۯ~}'*`ī}% 5dT '1%7w3=dol_%Nդ]νr\HQQ))%%3H`nµǸ(V/͌^0^~_)8Oy<~ax'Gbnʆd=3m\N".-Ɓ/F9M|MTv#s0\Q85]"ZLBy@Hp%{x,rdnDiHқUQi@$sv.ۯs O}s X~+BؖsfV[(kXX_aiݣit5[" NhuR[gͳ1hVJ]y>^(*ce"WLsvLztYR0ˠX]0&rT\:$!BL5CP oqj?R~_Oyɲ n3yhv؋|mW׎o?r(|K(D6*~r3f#=쀕E #bts5b;`4ۣTO]~v#ZZg\tN"9yfpRϩuw{1n2m_=j;sSf2O!_+W. M1Sxc:IAH7woH[V:&7[ / !*s ^SJi), -*x"e}Mw> -BJ2Qd*mc^~VJwh[.i:ޙO ZnoqQ)EK@&)&yKSwM\M_2G/S$M2Ԛcޡ%Wyk` chr8^+-/ہ ofJrI [=|1L?=fn` c(gI ^|zZ7uGs-7h2GNNYA?uMJ$#)2doLxe XsUGDN'#O؃G$CJZ@WDsNcM3lmOɖpMǓ?2LAp{۫TJnk7ۯw?c+HwvC/g`F8&]&5 u~3Q Nje^p2Ħ V0nuB]`^u[;8S!w|$lլR]z{ziyTByjMvlL=dhtZW41z1r~<3ٻMQF tZ,gë>V;_X>Bv@YqKX{JetNsUn]rmc.'?_>W}͵:'{X gQn( !{c靉q(2PS%d.W(ޠv!>%CO/6xg{]Օg9v*;ޣ7݂):p|vi1ԣpdB_KdZ /.Mfj{f?G[h'xN&f-HCJ-j5hވf%k60'RO8d^\W4d"8wbq.֛)̣;Vyk>VL ihO\ŵBfmBSkPYfF hεG3>?fRo^\a/$fst񈹄&1KdA4Coz >TsǸԬ6/NVjcyȸgkAӡQ)RɅo$EA{=k@Ϟ[&R{jB# DfFяIQy Ve0x8L>[>RSӨYF qtAK8 j#pn5MzsCz{=ڸ# [iՉ 5޾q-)ߍ;_fk0;ݗxKtaǖ^5䩌Sr fӂك;tS{]=EeS_Yx:jIo ]3i-YnJD,$nMs1Gz\֏ %#]MhˏWxj4$F>sNo @qƏsR?Ml^Fչi^& 0Kcg!>tȄ8$خV}ϺbѫGBz@K?srFB2&y2э/4hBVF+(+&d>~HV۔Ќ5E$JL#"DYS5TQzFMRU*V;}qHޥ!{1GJg䣐xL_GQc?,_)[_m<7i){t>:'_H,:e{BEB|o 𞵢O9?KzSaeEZ&.ZЦjWX^J/%u߆:\\FsGx4e'yo/">Qvl#4\ J2 {у?`O&Yx&㚺IШQnUT &ay+:,hc ͎9g,qv31 AA=CƳ\&tdKY2 [yV Qib.1Oy39.6/V^֍"!uYV-]wӿsCo]l' IQfE BE~nCs&CdB&sa9W?Y_cmol~"U"N,UJBo0|? 홾G),2SΎ#_\B>-]1~ZSz—@t~ABP4\K^.̕Uʶ@tj Jub+eNΡT{dzpN^L(*`xKU*|wwB bQ8+( \>@\!mӳ}2 -17OEL%V;TKexQN1qIK6qAY81O3xy|WaNVJ`{De9nЄHtK\[D.ϚiFfF2[2p7n9jKŲmxcSr *>u߾ hxd{~V&hKS?'/Kt;_w[eޛKw-Oy֮MZXbmlcf&{f"=ی6`1X$ ,#!RwWwWuw{s_N?nUZuoޥz"*ެs̳Wx(0!z).B'{')v?8ZR"{JǶq}o_r^餇xh d< 66;H J(ґ15 #Y YȊ^ڨ[Flzן,i [7oř˜~ OAG#u2 p<i2DE46-%n:gmy[bo2 x W󋫘:J@0WL/jȶ'R#ј(:t%[s١䗱hLwcp ZEQIULPUu0E u{Qߨ`]Z=Fɤ3"{/3)?K ~Oizxϴ@gB0BU5Te_4$ǁ@b~QC͝$Y1VBTf"'=i7^`GbmOHP1 KTuFc`(p$N8XGHٙZNSV 1(%&'r3\^:uq3A T.{{ jX.rګ(G8@PeAgUzFPgƝ9u_. ,5`AoV u9A[*UHFTgM4hCjoB ┭n+/2x:L!Lq4kG ۭ %Ub6fgg%L,=S!nስ71!3 l mPq }:F60**d6xe/k<m >k/R^^hW%MGA姢avnYxĉ3 Sv^|Q6"7Rx Hi[;{/6q0sW|~z|:%{bUͦpBM=/޾C-pO^QS1 SAaD;rApL2fNcvhƂ f$UZ8k6Tp-H@VY} *՚&"jεN}k,tV3p&:Lq f|@IZoQÄ,JbZpߍz52O|`LrJIb]h~WC1W47cY4&!ZQyy6#r]34g7_ׯ O >w]:zPغM^­TT8 !ޖGFҨU ėH4SC4RE4*^Rҳ=|ƹP|]?i94`fAdcfzS׭ }'-cDͷu10ϣi+!ط(-2$hdX$ $[ MXQnD^FuǹoyZo^4oͿCQBb"fNk@2sQ NN$HOr.0!QOk |\rh@雾w}U$r;NWQ$dW_O<2yPUxRH)]7n]cNj;6jG1ξnP4ViRjjS|ꨕ>BKc>SV\XtQO`a)$FfT ,>}E PpTqmvS0 ,۞~#RgF:-Sa˝ t3 AVuXEjųa?+nvZxI.HnS\"Sa 3f@ZEQ1,q 6'֨\XyjUME̖'|]Fl5s-g+|鷁$QD< r[;MT|Xnx~7@ڡM5I!Ul$f{KKq:fDxD&t SUP[N 48җNi8E$Iy\J hP*{,/X|]kNyHI7&.a8豁g[`y`sbHh$i*ŅgK>J`tSwU)%b!dB-%:Գ%I21S% ɪ%6qK%N1T\SCM$(aǴ*%|A0"b܂Z*k%zY 3KKfN4w`QAP(=*K( h>8+ 43\ c/q/=_}Hʑt$WMZcz"J1N'erO^vBdT !lbڧLL Ͷq E{XS<ω4$gPYbnYd*g._cSw;)UAڨb1J<^b: Pԩߘe'Imaeug˽nml2dØ kL!bxa!3™xtò1HvwQ%2dQĠ3XuO!:(F(f=&rvs8!,n kǴۂr fr .HSVb nj_fp.q0Ɥo\dvy++ax:gf˄nDfiщϷ=sƚXu4)uRrPtN TѨcUfWTlu 't6kM4y[XC:lN,MH#>isX!R~}H |2>1({k 0XyhR6Θ80Y:s03W 2(σzAR-տC'Rc\togIPuWQJ)ϝȱwm]>":Q $N8Omw0MV{KނcN$$ L/i5f@,yM4mqc1s׫3I%!%/)Y*/>Wl:wlhCv`q0#U7 &UF[*0)M1yĐIh;_tH%` $bVh,(`!Xo rO"ϐ 0;|Y;?I}ɥVA73?V$#Gg䁜N+=BI)w>B|k~91:k-[{ i*,VNzX'8Jb0!aC,9[WuIPH)ɝY ֈ r#HvuR#^Ac?چOE$IJxDjBP7)l_A9'[* u!Eٟ 8~[KnVe~PONh_ 2L>4{Lc> =XfN _c,%H<%3HzC<RJ[ktFHqb(BO_fװl,E[ ^̙IN>S=v-GdxQ\9'Z*d,/OࣈnL1]1_cK"<^]e5jSyFBSѤDq=q৅פW=!)Qt jL$_>O5u., YllR趋x/2?n҇*P\Aɵuj`EKeK/lj4cL zeE8Wb֑"@X˨0y۶_LƸ {z B㟿^#ᘲ樸5JI$s;tshݠ :}QMȘ~2<ѢZ{l^ޤxd8BQ49+5^Ft )Z,QR:lFy@,.)  oy>K9r&hI<;{$I֐nW|q,` cJ4 "'bvgeI}ɥ{]À ,w~je #NNhdnqLݼ|H)-< Tӥu) i;llG C;_<# Cr!,uZ U.] ~;ePkW. E4 58ø v4_;5g?A%YK<߀kS?Kc2yOrc@vޟrhpsE/O ȠU8[=[=P0 PLjFoQ**7,Uf-ΤmV.a:HɍsEr J(^&bZK9G1qݓ "{=s3y3%zRr)|F 85Ov sf5u*D#g=xc/d~ cyoX Ha3R|)lh$ 7R}$!KR>岒cP?r!S.!9qle䏸~6/av"v{ӹ6tUX{ !5æ):,8rM-ɬ_x7$hX3DdMGqyJ6M^%'sq| ?Dž&5-lQ.9MZWv1Lv=~o/IdƜb{ݝn,|SOv%6Ps(3,ᧀ_-Iw B&1)UCD3MʾO+ey{HUT)Y٦ס9 .o~ejRŝcpIZbń={g\(2 uN`L,ŌiLiK>#!; WWL2B5aHq*wCccKJE˪dk*E4}1拓!E>=&iJi|*j끤g88Qo"7'KGo}o=2MBE~n{H !o/R>m@io9Rwf 8̸!zA)$7^JIF ]cpMLzM/눗 F8U'Q/%Jք<0QU (8{-FE;{dّMrXݰLtLbJ ZSX"Fs}+_:R,TEQ'fvdQ相;l"z1]APfY\#ݤěf~pHD IDATifdY~ơrb{O*@.v8a"T-KRmpꇹtI?p`@r~y.9B dNHdϪE|?gܞyQc,Šl#|pyUv!_zΗ'4,, ґCRau ɫQDQ(UMھ${|g {>we9ք,UR(Ss; HGJ9<>ⓑRBќ.-Ŧ. u6hN0wq>.cB*NP)'M?ڹ 9{=6n̄zq B1[/=f:|Dt Stm 愋 H*1"ը̕<0 Mv rTh\:njSs˰2ٞdCj 'Sy(1CzP+֘ЋhLJx#-]ah9q"iUJrй3$ꘗwvz]&nHCJBބ~QqrΫ6zogB#Oz 4BK}C&X\}p@3M2&kyRCkᎏ "Ѭbգ8[EUOG8 7p1bFQE=:0L鵛G'۽CKJ&z(^;ITb~J*':L?j'C &r(FgQgn4Mrv,dTy+Mi9RqSW6X-wla4 u#Gfe ]aYL ;7?Fm,U FW=$4_~lvmS Ufg AI4d"rAzu{a`=B-pYvc*n|dAXwO g;QҐ]uD(fB|6TMEm hIji(*Oy;nם*ؾNk;J8]ct:jj#aS(98(dN cOPȺXLƌ _daDS\eH4 9I*ߩy,%h5Q|^hᘇg<a8DYDaL}Dʁ:͖[(DqH %YwrO U=Ow< E Ae QT`ΰL+..Y}OkkbsIwڭuQpXh̡PW65u,[TV35@3FzBiLi@2Q/^pio|x`F|n!tP>AjZ\D{ovZg}[Xz⩩HGcu:B{B<@J.sy2 1:')B}-Co*"qWxӀA&X"@6V[s,Jg!]װO,Rwc>0/cU`;A;a\8f矎ܩ`$mŐdD# =2`]|U|X4K ?"TJ7TM*ݘn/e1lȒUY|WSb+e'H{QBĹ`t[xۯPq9qShq+Wn:Zx9F2sgs'ܹK>Q|VTpw]/M!P/NM!ԗ`%[NTɮ: a}Kf%)KL^wK#9Иqn6*5fE*Qҧc{OCn_V Muh. ʒCOE n (d0 22ւ 7w:X~gDhn$g>`F1It&N|?Q)?wCW6; T]VU 2Cģ8=,k?C\ _chIeơ, ַ\;H~<=a!.<>G Y!3AɲDj(8f(YQQ)88}C<Trs-,{HOÆ/PN3枨b:(FjPqM&t¨@h 8W&)%MqĠ$Z<<7JU|%>E!phw2,"e 8sM;e~ v)Z zP'QHF\%%8`,G(w/ދ{DN4I$9W]3Q+S==k~~:On>$y)B=Ւ,͈`4$& V>F(ǟ |䥏VйszmHux\3ƽ݈k3pBTLA8d7 |D9l~}GNckaliBי+Ÿ98HEL&#z;kl6+5fɒ!%΂nPP-fNe T1."c'7 P4@4 V?VЏc=nM: .vtQQά(xO4DfTF/NG505 9-Ei|^퍇M xyG.?9N\[  VY^-wܽ&)DawKdĠfwϾOy9CÄ(~%Mڷst$A+2^g/kkϒcZEyx~!@`w+ !7-k!7F$GL{A4@"!;n:xݲV0#̥:UM%JCMb'>aO8jIm}bs &gTM\A̠-櫑W; Oة,Sdz,+Me*nlREX,8PX͒qeQQsı jGVoQ/Xq8{n>)iڤ.}pew}WNIdDyeDsci&B4|-i0 J1gN,>s?CypVj<ޯ`yX@uXeҔL2ϰQs!eAKY,wnzzQ^+x1ህ#KO=P[YOX1ӲV={'DLUf( -%;XSG4DIir'A6/N|6V9 p7iqJO3FsDܥ\oP~?=Z#S /JO*Fu*#d}E"} tRˆ;tCE,_a{AFiA_ɬ8EƊ~{Ad35@e!#c0 LvNdT0j)eNrB48el|NFc9.M]l͋ȢOT;\/i!P8b}" 0-ûξz,$nhh.㢏3,VEYbVc"rI#Tu>ۿIpqw 诳)%2+v)_:S{BEԏ(φiqyh@>8|D4MUmw\z3zZSS8WR;TZON߱)wOW~a/v{I'?<,?4G^>OdNJ)wvؽݣf=r9{^A'HLheg8u/xZp?"1˔E+µ3z1mxD$'F,ѐэF] 8r@6S CT$(dFDF &~>w77Xi~~B7$IApAOm*h'p㤑IU,W0We) I}Yv;; o1u)5yj`_IA[ϓ~ho/*ͭm"Q9& "X!s`ՂCCvU}Z,Gw&HO B%Slb0M7p!W,.}LaZY,z7q*%~3mIq/T°,4ۧHϒw+轲_*!KALs>ftB|--@(^)/f1Cf=φ01iFxiMM&<}s,i g.gWOҲLK^پ嗛|S_p:g~gqꊵFf?UK q³O~i3?>o! )t\*aڱ;R 8SVן6M ^6!n*>>͘=<Rź3Az+4ʭ?'zkM,% l4YxK[>"L`GA~F>/rsuF#pS,YUSc |EjBjDx,ju+h컙ijܠ ;Vgfl eV ".Sa1Ch!N7&L#FpXML<[SDd9X>sTsn#2'L3p~fk?[]oBW#pM&Yհz@ rjr>W˭{A?3ż+?BJGbD?:_|3H Ip  o x]#gR[B6rtfâNi|-Ibþ3K qEeg"FBNxfkK<& ) /9p|t':wp-h'S,0RFQ2pJka<dL6^"5+T9oxad]ah!Qc) {VVj1{O88%r^"g㵑EK$ e Niv]aCo (0 vismmQ2 &p+d$pb|ypO[yhAS*l@k-U܄͢84v3=M_Fx|ra0 9x:~Buسmx,ѳg)!/# h"sN0L2IBo>ޭkGABli\ -#!ldAdA9M˘r@?2 43wd<,2Xa >~M*zߧO¢yms/Ws4I<> Cr~(/(41m- 7H{S@ʲO;SIꉏfzLSxBF).UDudö1AKtdx&{wnx&}CYi>o&4j^PͶR#t;Mhtۡw/[`JFEo6)F%qT+{ᾒ{ypt )lwﰺpp<59,$a?CD75aZ.`GecOMXhָZs _7CYo{:>w 28[ M*}Үd<.7N|Ǡ^/ YPR#5>mKw~v^a̭Nd^u)" 2vonoTk,>y- fo@]opخ7!'@ez t* CVPyAeSm7r17;yÔ:ҩ yA;{mR< I6!t&T/pU`BK\G ~p9y&``@ڿc\="geBtϏ{/!ϭq۸d]&3$FU_h;^:. c HׁDv & ';>̎>s-׾.s4d+bvUA"֜3vx/ӟ;+೟oq/ vs37nmub`&RL}}fYxg/_&-nQVqg>iB-4ݼFO*>rrAO5EQ!% DQ8bEFceLR]**5wSyQ{!Py>ƒcH#k!mʥY>~Mp\~#-h>HcKWi+Sd8dq2"%w7hr5V&nҔ4 %SKK&a@bPYr9W SU JbI*&"09d!q}럺IǭGGRˏЩTqfcS!<*TR[}wh=P&:k Cqe}хHsJ2L˹fT;)&/yM %kgX0LP,< %w*6q&x"0L| *WM6lTP\T[a_nv7ow 8<ػkxU -S(Z[Տ!ä K+vmU]Okl#Rozk~2P IKU҂pD"dB5[? KE$kҤ0vK 59d!,;첔go!YJ_B7rjuo(}=cEK4.u[3.YZ?sC24~>5?_ öip"6RH͡}c\qYHۣ92$#.e*16#.=+hBDIT$I1e7öq=<$QiKt;TJ|.U`a|212B>qHg{aZnB)JgaBr{C&Mx{aN_4KVF)Yș3-|LpM [ID\Hѐe:tlH4>1v_bIs1Eڧ0tzR =a#R3֧6H4bE6l;%Μi,<՝-nlv)z}̼H ՏnU;&TG Z{s/^gw0i:j^3{j<,ܮqaKV13r a L3`?#S7!&ke,+vHxg܉0q1O I1m'w)~gT<7rbק}*@)uꌐs[&?V)%ĨI%69J:}4xBH& 7Bc[(U.0Q.k=SWW%,QA{.X^ i=꺎Sv3 Ôd]y6̚(2*4#D@Cd &4 iU,-cȤR Z{du"m!3tI[ciBxAp.QB)Yuk<}Vw4?_)%mZfB^ \G[kHXAtv11c㛳G ߺ w E|B&7~&W{"y(RFA6R]0H>& K_*>69=Lh [v}}c лU{1Ħ4X^:GiiZ3  OC<)d PMhiΪ2Лg<_X)J&N IU)IʙQ}%Kn⠗3NvGd8FKqD. i < ɚSb`421}Zx,[wXwj!tq~!y0nF;ĸ F#Q_7~S i Lu0$_q/skFV-^SKY)Ux7[! dƪdT\r+ ɰy&~r1 Sn&!0Q| 8/7?!DCZ^0IDp|@7 YH<' C 79 Hӌ7]}k/mRdũ4> ˢunr˧Ts*HlOusKKKRq@.#̂Mr&8pa5ZtEhLNg60;Odd{DͩC6&T@թ&=z冋t4 rɣTҸHR&)Wr \L)-5(xMh/8د?N=[Ihn˛okPyXU/Z;41yVܽթq0h d.,Snx@ExEP uPsM9i,-1}Kn{M=Ӈ YHaJ5dXzJ}3syP{=ڃ7b.\R+4 8|}w;7 Dr YNceMX raȴJ(a*nޚ}#`R6C\ͺJ@~9W>O/</KhCӇ_w\ Fflf0H v]Xz~ǸY>\jBGciSqf 5SE&$MWxwN3](zS!|ǀ}!s xuvl^Q`AO!`Ae+w**kGzԗ/gT ^\G4YЧ7|; +BL!A$A^Ldt(ZĩG? ~_0`Lj"&vOH#A[ ^BJ SsеETjOi~~Vu D`EicFLQ&N&HaN?A5dĮ)]G(t(? T߰!oLI4? K$f] ɋ,vBc9ᤙF) !>&pxȉpʢ^jh&{S{islooe ir3ܢנi5j<YcYHWN5\ɝ0&J쎁^򨖧u;Ep47D4"N(b:-͡ѦaC[dns[3OPJw\'6a6riX%K!q1NlnV&d } (X,w4:#\m'FShRl5&{Lq&[J[Uu/zN\$Zu7 cZ˟_ug]O]oMJ4]蓯dGd47>!Fk/`H="G)9k|{9~d!O`k\CnJ˘F8{8 (vV֪UDgadi(ɐ/4OTa6@C&촷B9Us." ;^W A=E !EH 6@{`߅LS/|k?~uVCP,jLI$36Kht90  `̊Phu 2\|ݧdzT`cuV*L1a/^wJT(F%*TKCVT+,>dőߴ*u&s)*ZJG ~ |^M G ;[1f/+ Ô@D9Qn?>iU/NxWnnee+_#G%dA}Qjd/ E5 U6}ĴB?͡~￀kz:I)^i'(G=]!<&IAYk3,'1q5M4joLr 4k)ϱãQ7;* +X*%BCc@twٸeҢƹWaXKkg2Tq>%a4lah~c sFƧkEGp܆P.vI_L$!QB1u&I|$QK]_%Ï?ұ5DZ)'1C;kGh3~7oyrj"))i%)*L1T\'InsT;cr9XƢ0+WQfؖThAhbӟK|| s8ۡjVI479IqpOS\Qg4Y||wnuq;E O/cV!j ;A{r@Z{`azТOXKP>"Ř/Y3_IT*MdBUbZuN.MXG̏;wO[7a!id1R2$eB=obZ!4o쓥-tfs`;B{'wn=K>ϻ딞||C ׿ IDAT0ι{jg!~*IzBR)35&lҳ],97L`a(ܺh q̈́@>qzk2tnw:Fq8ݼ>"]2vxMwXa8s(4sm'?_ǩ@9g'eDU\ }sgo"? baJucc=nۿ'XKN/c Dk)&ʑ=Bn 87k1!!W [u+oj̇a8g&>a2@cyWkoU"@C&AvZIg$l<6Ϲs(_V*]8eF=a٧آ|NRhk.ܣbrݧݛ0 *s2~ɇEIKt=4mvרPd,%&Su*N9"AraNsz*7*<'9t`$H:R<R.1]FPl:O~9ܔbxg`Bԋ0q'gIhȴ a P! BɻB.mJi{Jҍ #nĤXVkzz YHB;mߢ#'58 }*(WZÈbR!NYC$Mװ kI7q.׫u.GO>zJY!Y<'( j*)dC`x7A4]T)*_XƝl;J:ZxR2zŵ8۬!xOeq4I\оMu a1AM Ld!lDYH/&5}\pZM,_aҎ(| %Bƃ?J4זyS~p\e<5j;HE-puIcOHJI"^\c}AUwT wp6["9&'.Nt fQ$# i]?r(4o6<|'G bT4͘=hMx^gpXkTWOc4Ddԍv; Y( M9}R^m1m.rY7 7sK$6{QER(yl]c#T8eV6H\Md>i`COf b)Hz`V߰ jKg R`Ȑ:_cj@Q>ѳWid!A9OQu?R64KK6uvRIzq=. #5W FaxeA RTZgj~_q3|54]^k緩wc%\Cq}͗dѬ\b}{шYp|f2GСU';QhiAVH,AI{M..x./amzL~U)}B5޻)|/>B .@!) M:1bZV7rɾ0NdPxi0$6mn{?{oeI~w~~/orzo-$,$f|c306`ǀ3f6>FIH{WuUefe̷/G揗jz|/+syEƽ/7{ע`) I@DNޤ>i3e0ScwM]hHj(ˑ9Y2{\2ַwwv)sX(MmP& Hױsh۔c*ń=F,T)-nP2f^SXN<|$Ap4Db\ݤ5m yM^Q$ƘsSYg~YjB]#O(DQk DdI `Ÿmq G @ o{@JB|}^@O,TU%4P ~X@UrYt 2QU\ִ $穝 0=]ť,s8i#yPJkC/%KZXDJ[V e@n]5m"L8ϰwF)Au CZO^yn^̓=`,O͖u*=_#e-\ЊRRLVOÕuVbuKRys)R|IGeR?=cn iߋ"'gU~=bܠ#hCֹ(?ǀe&*U]xL"R:qPSWUA'+p&47!WL,0 EՑjB4F5*S)#- Fn$EM?8jzxJJJ+I)B;huRJk޸^Y)6I%!rC(;a-/qr}GQtbְ ''CxXTr\S  SGLIP|rU_ |F>mE0\hh]n UDvrZɨpP (K4 GGI]™3gf&ί&˽Kt2V5 PMFoCu7.sPb̏+<O<7.s/! qkz:$[$9r\qv:ġX[K< ϣPj=ΧStςov;sTraH#7i$Q0;NyUW^SbG,F^ _ D&3 :>zz H*(PErh$Ws]-pGۭJuE 蚁[61͓/1F8+.5EEQ_Tilu 2(bT4<{bwcz\ btMd:sRP|Au1L,}zjm83xWH7!T B5!Nюp0.UjKCMmj_O̧k(a:[Y7uNd2z,"RO~%`G)^/dlu㌕0|z 1fV&|%wH+c0G+u>!@ܻ6LJ0ƻv=W'sS4Jw0$w{lo\婵Mt:6P0 `QRd//)! F*ie[NJhhxVtp.rƒx Q۰)JVHl"23;^OB`BCHlZe23 9 |E(1ll`{N]X4 W(⣿~su4g&$(LMnol%Ko y(P4z8)F'o~CqU)eƗBKG:f\bNKsDYL'spcpBTRȗAJ(臄ek'aN78 ΄?xFi*;"fr%rO?I>\Ǥ֏ŧ@t"Y{vlnH0q 4j-챥$\eޘ݁NǪ%L 2‰}bDlk¡o1KEk kĚ%i/@{;I֣-Rg>7V<RZƹc;u"%>Eef鎋1sBTa΢#T8nm{u.등[G~r꾩J= E 3 ɪ#i0rd4Dz ;wӿnਝ>!A{B\9`~DJ#:fE MVEq'*FAHÑCB(dgyҌlF-eo rr(^HƳXdF1c XNc^E?Cq[!#+`+4/3_*᧗ɐA6`q g׮o`KNʛcoXsqNY(ɩ6ՕUjpIT/z݇/)%F9xo$m-O:UBi-[_~O^K->z!>(2FdQp, bMA8^BLjC~DV   n[/ˁ~LƄ7|ٻ)O,K:⑧WRî.s# %aH%Ej Z=ƣXwIsfG1"xIuC~BJ'G:f EU\tUSOc5E;D8өr,IR/W]ʮ}h$&nYDBA\y'd=oUXn 3#~I24]*x=G[.WG7_OW~;x vå ~wBDyikr2ɴs{E ]_Gf PT+Bz &{JEx ?o})%>+uo_xfZDC:2NSo~)DUQea(GT8iT&4 ! mԞ뀷O_-hdm:=} ʌVvw ]95E5Wn[ ,^a\J3kh0r/iJB֣.8%<;BkUJOdF[tZxAT~u8."yRI_YŘ6r.?l"9*Uv0PWݱLgܢ<}tG UI"qTDxMP:1VRH4F!ە"ylxew*l\ oBJ !> Bͱٟ$+Ө'0v+ 6\dMQpq#;%t5A#b;CK @,e'MD{"fhRt RBp8-Ӣn[YZ0g'Ɍj5cŎqzI93%t(tb z,딙B֨ ,K꣪&ne ґŎWq;-zl^V>hϲhjΔy9~<3)IPF4@ƈaf*YJsP1 %wx+"K3RǨ="#A/sy '=ƹ q}JPRuD(t5ƫU)\i1أfhXPS^3RLSo~_u!DŽ?(xH񪧟bE B h?qT!~B) !~O1z_ !B|B|J!>)[:[ru )%WOĿE6OS(~tf>Bbzވvaޛ(w]gv|DOTN)B(xo~9 !c"gL JLo lHπ~WJy_4?:^EQ7>9q56pD-!1!/ؗڻFdj#Q'_^3O[ 'o(}"qf8쒵7ڧye{MS',}4Ge}+A9\:xQqM=už !AX|Y1Nލ۬mLٳԊ ob$ݣE05ʎAY^ 5S y,6H? 0%JyRj}p]0ڟ!Swmޖ9[p@0MJbZ5׷BznԔr~en:ƭP*mk 'IJy _e}_LWOR !.H)B;z:BwR;g^BRw1.) !ցI'_B8&}Gʓ2loqFV?}l4.j ~pZc\gO-SjoK-Тm|;[ڤϮ돳S{F)LJz IDAT~LXC6LPII'qm#]]pJ CS0k 41qJAM(qw)]I H}mvAIf$FxOZg@&Iʠ=&NG=rǩqL?~n+QlJjmXIn7[}~ۺ[3  0< G춆oeRhtj 4RW)gv<`#IΜ>Tݶ*6NB(?qBN0 wII^9c{|>e95җ| FIT%EщՖiH6jVhUmW3wq:q(8!  #Cċ@ri(IUQVUKi\,AQ3 6B]}/uuѥ,dyvj" gF$w昚GS4jg*=7gjNP<2x7FQu2jUBR7Q%t dT[6̐"ER(B`ꡎA~ieQ6h%B%OP8K8(Ԍ5L? A !s~ԲFRh5tk5vaD# {H! aơ.ӴSN&!~苿f Q)`bggA(7RR ;(V&BNB `dǸ ] ObEHMagbz]躆Z$W$q$_>8x~ٷa:D/1ܠlKT5kM)pXOҁ?=DE- :c poz'iѼ婇7j ΋ܽtk1?EIK,;oJ6H$$ }@` ؎IusJ 4 q)lOոv2B+!eG\%o'K3B_?h<<;U*o~q>7R}?Bongd/Z&b0vF =\H|2ntMQyZWU ӨQ~"/%2W5FvMӘum2_#4Jݏѳ8waCQjLG*~8OhՉBjVxJ9ot7e67i=\_kV_GKTRnA$ bU7[HSy;T?=`Mjz!_="1NáBT-ăfظEj4'>umP!DI UL~Oл?/s!?FJ|L0)@zBZ]6/$V2+B_KB61۲_0H3vHc0W[uO^QhsuED+ yN!Qi4|KQ!iJ2"v x&T.B:B'xqXM0r@da Bj>hh 2h4a PrMXK@ {W/QhnhvUG 5i/xp_}a"w M)e R_j[,qt'i"֌orJ?[dv<hǗaxF UfQ]MVv吥5:#01#YWԾn[MP.Gx͈;5dF?c##41݇P8YJK'},_n٤s=RJxkQkHnr_dWW>As0z 5~cW7˻HU5 cяg?1D߸!R%I&_$ֱBܹ.Ǟeɤ,gȹ;AEjהƌ{:j@&$g߾TЄ$SSaJbhPq|Nq[h!=G1}o-HK@CDdG7`Z7]ۘ~v01t,`S;6`*4h 0GMnNJ7[ڡn}CBɢ?`ԹГ;|3 t?o4(ޢJ6#)fl0;|FfǪl*7`o'It*]^3tƺ!U;k»r>w4,im)v1eGU4Hmo6.,͡?nuy.|A A.bF2ha A;Lp9VRq[ {f 0 ?Пeo1̧ܯܭ(ť[.PelՔZ" x~qq+h~v nũ8FCJe0F"Wj)s,,YhEwY-+ɯ,? y+풨)#԰w/|>T**女h ht&%,32m3<~,l>C$N"Gח\#-(`K5xJ$Nx1} VXB Mdj )%t:q@ mVʳL ~æEJG;s/G. 2Q0 peV/@`ZyF$ܯ `o`j#LO&NB2L>4UƷBwX1npdzG"/яihQyhǏLftDPㄔU:0x:(a|Ңljb9` $w 8%N:< EeŜ]YiY EHٖV*y(F7p*gn;MSzF'2EWF~tޫ e xSb ᐜy8څ%"4MV*qZߴwqT]2jw7_ Pa{$J\_#o>K n+B_~JJ_@.rT nw(MaN_'>E]kep>&VXeq.0_'^qf! 'fEUcDgQk,J"oidsKlttEmaً8;@،6Zܡ[gon@KSXSV Cp1*Z „iiG)f25l2mC4&QGBA÷_ ]?-0cyKO-b0?~v}}ϯ?c>{SW ɲ14VK̻+T<9>̓裄)BLʥ"1M !*4Ȓgs" i6SIq$9lW'%~;ᅘ5*р+ZWƣB QHtʸ`9!Zq6ŅG @wf">I.PƤoB|͋^Ɂ"أwa{dPndiư)Lj`g&YXoY<1Y0OɄs+(]YQ`)TZR@&qLuB-?KCê螪5' aӧPVgd%)x^ &2noPBLH&--w\HqHꥻPu@_Phh,.29lVN2_p2vWwk |V[!ǟp~(Mz[5bd^ ,kHS@}wq\6EëCK)S$+6PQ[CGr]μk4|yq@3Žq@ NJc "Bܭ c|1K)/^Af"/hu^]4=YR$I]ݡ;pteFiCm[(nBYk5ƤTO` Y6 Y|!Z>\qՅ{9;w׼uUA]R~C^q*PB*)e"Ql(O)pwx$rjx;qdgN;X!"-a$Mݠk9CR67{>y횇t sy RJ~by_4l(*PȗU1=H?TdfaGF 4<++I&eJGp IH!iX@ so񝉍.N7`nU}K36<&E*dKyW2_0K)'!Y 4q_|KRa2v}Gll=^`U /T( ɮYWH4O޺=O`M,, i:$ q1n,;yc`̥t,/<}ԃȒ$$%l(%Q=(H&CFd; ~z>Vy/9$ 7`a{LsQ:Ol|7=;B?GiK GӐ m 46IC&~\ϞLC[HYCLV#v^t"0'x]'7;lv=vzwTiJdr*b.d~xxWId'#[hHI$Ff,#{i?vF4[MђR춈a 삎n%p <#|őg?3HȲ$  fqQ^%?.hB~N1`dѓ>LV#Bop݅m?'ߟ}T_BrA4E ؄x-/Ak]&b8]9Y;EUvāj5.mE* %wL %B2VM|?A`>(#wI˳㟦X/US8EA dݲ (8¼ 4 2b\e:׼PUEOL ]LЇ B!嫶P#{SFv8UkiOFzB9/A"G(a'}~xNQL>U1QǬ#1@9a;CfoQKD81b6Ґ^Ȱ !df Jf3.Lb2ǰrѩpf $R6!I>vɛ5;5 Q*Fg2L*J͢pqIH8#9|Yd渑cRc`m|{_֠hi:f2AIɛꦆ\bcgS XF\ɥ5Ztu9;)^RGDZԧT/Ӕm>;ՂݲQˑi&`W+|*ZUo+O]}W\b(M#7*,EiҀ8 m'Gd8jo~VB \)ㆨfA9ӾRE|¾KP2P5Fv{OaPfΤޛG[u}s<ŋ)3"rTADPEqh˪ʲ) QneZll[!"c7;OqeD&2d92Zos9%] .0Rr7Xpͪ9d KW&& 6=c?NLXyHER}ѯQ0H iK2)eQ,~x+UҬ$IyX%8w6A^^u$ C4 ϑjq@UQe0W!gt3cGXt=_~J2Tc$C,jPoo-%xd_q|(I5RwӲɡA[?XN1̐5Bg˯cV 5Mb;EZ ;b6mc^N W)3l~* ,1-wuzu׉4( )Xc:8aD_)Zp6LxyR;g܎WW9ogBW^ʹ%~O(!E //p2 ?3tĔTZc6'71V)5 \Clu3ᗙԔR#bY>a&˝wޤA0. IDATdԄ-`=wӿR0ՋVkLt <8 FgN7S>~/ x5(n\(_#Wf}0RLQRLP33L!jiBhLb*%V V)Gϝb) /OPr,ʭ s}bwX^:Av7s/o |8B]/sD*AX}I 0?h^87 B`x+騾"SYҢi4gLl-ѕMW'WV-[N%R' ƃj- 6~?9W"O}CGoo('ctYP2سU2y=B( d9"KrqZٱZ[C~fk=7ԎiF7Fk$5._&:T3cGКOykvOa7yVqW4%!tr☬~[)#wlU ^3sB S%1U6&^`A>s]öF#ԐQ#J2[/)SIkŌ| zmRYt ς 30M;663_(H!GcTlR1s~iQʓ-:# ]GRp,Ԡ(M?RI<pS5Z=Guݴrs6 JS)bLسt.McªH?# |I@ ΔHGgC~3(%]C澅[90moJʔ8QqB@k2@K:w;;)ev3$&6.rrTa*^6&Qb=ZdB4,MQ3˸o7J\jY"4cJ]Cx6>|Rx+^׿a9O^5S|‰``#]_ױ&4vC-A&)TJAя}6zM2m:HQČu̾e1`5?$m4r=B7Y2Y93Q$yZ99+_P;W  FCSJ~aW(O%k#$;l*+N02װ57y (g_pdfɻf5L V/"{ HhaIKaȚXdλ7,_7~Cd5jeʩEMR Da*{:I:MY/MH[B2KXäH]! -z4NZǑصo~GIe|JUO~rb[T0 qMa?`ЊuaڦB` !(0^9C?3Z_ |}y+vעfWV=\k[߸1u>P /5::}U}9Se7;IƎ8!nF')%~ k2 ;x5T7t2I45sG fzJ*'SEMg WشT2e}>!Khj M/I&H%pnxG i r@-W|V<`e#Wu3-19q3=u ﹞ꦆOC#Dĵ*p􂇮vJ%YoXF\Z^!RIR%ILB`*hU{8"5b✃7?-m {³6B@we kNA۠?,P.=s jx.!8&j0"F"n.RJ8wkJ_^B&/[KowֹZ~B{?BS/f!$N"0]#ӰƯ ېR^0;c& 7P%3= L'1WqJxng\zB&S'mt9>WVfoǧ^S?ۯ{\u +635 9`l1M]C. (N2Q1v||$)nDsqL6(=Lv c`hp I3{/@@cLس2 d*1i*Ecq+ԏ=zvCd  !'fF_ XP>q/vfDB;P JQ=QTqcis/H~c? Ӕ v{l$s!s/B  {WªTMR`0|˱"d~^2ʻca |U 4BX1)н]/74iǛ. -E> 쐸PM(rhS*/J)v c10`tqLij5M#m,?tc~+^^'t.i˿Bl01? N)g-6͋֘LzسD[r2Jj/R~qGRn<}Em/ tfv~NL*֯#s,a[j]Z4FɺG6\Шx|a(%T*n !6IV!Gd2F>/Wjd}1%E4V^aH&aq(!畩dmie#4rid6w!0 'Hch~. dэt!3*a*Sf O%5ѷ_*YS<4 %$u.BP '̖˝+\82hkxAV;xaY[y,G=y^q}GNmiBc*W&㞡Yl(KkCfKޖ8&S̷ky&+' ޾Z`( 1L%}yGfOgK^?c/x05Mr@aZ`hf>LF4>4, [CZlN'rT*P@v5RR J^N{N5{Ƽ#.-ez8MiJllG5,W]"*m2UuA,c y4chcV*to8fghUB?`pf|7`;R&b&չ:ሖ42 ^aT>l{;l6  4ZedY~++D˪7N*5!?q4vDDڏkSdQh1;k/,138^ЙL Fqt=)aj z*36 !` [KQľE(.!R8=QdS78BӸ}_]^y"fXHFqz OG VFs,3d*XM0ֶMXY9хKLbyhmv/Rj$/ۏnu,C{T0ɨywy9٭b9B 2"puZA-'92w(Wp'2͵Z理 /x@e"Qy`[H1㍇T>.]a6uṁh Gv[FdunHW j_,/rdw8kLMՉ'ԳQ5\*`CQs_ 4/6F\|25Pzla$besMh"EM4O:Bc˥L |HŒ]!xV)ElN{VβQi[O-?vmM71xj Rv!ڏDdC$l#BH)A7ZiFMD#X I;D>BI`dIϐ9t֠Mƫ1M$J)FQBA*2q Hھx16ИWQ12H--u9txFYJ[m$4nV?Wl拚o~ӛ)N9>R.5}Zc}v5QAD@sPΘ:"" {W'TFKH\z+?[=/$@;&ծC zfZEVS 111^I]#o,sXK*70%#->oϤBZd *"1N0M)cJL5r~q~lDݱ]g'$bb #1)_= 3(;&&4fR:fl]y7`:rE:P߃BY`!l*}M=Ykn$a)$X֍g^tB \@*!Laڙ$o1W%1̢3QXiLgQ͉ EQk=%2BW'M1!V.cfo׾/R+zF2yӒ_wr?6M3|qz7أ1ȐaZSNz19gkN*6"iE4 |jǿ^GKD5#Q>*F7ݑr$&?f.,_桅 8ù9ť$1|BZd܃N) L$::aV,v d*Iӈш@]sFf2L/ۥ.S"2Vm̡[Ǿ&Pq2fc!0mۿ+=] G瞠нI.ne֨NW#zF7LB1}~f_(ԉ.e%t1Y07/QXOΓC mJG?ưmj2,=2ʸ|Bn1+7X uxZ.3o_?"N4wL9+p( h2P-L8 a$[@5糏7i5EjfTl; CCȔF&#)u4ޮ:|%‹Y|ӏsq5+MJb&i)=|!~c#byf2bKƉ"FQ„ț&k^a'$ $qb=^ kۍfdq/B)+63Gϵxv}oaqIgAbrܞ/%RI D:%izÕ+("Kdqyp7HFZVHQ T>[=L41l{ODJ)Tw &%uC )ShN#ǾxaZ"o ?NxtCb aVc|Ab#ZA:TY@4bx4qsv#g<`vr3'GT255AT\ȕ%~~SdZV^w]9r|7$tɣkO1BU.P4$BJsAiwQd BV%c&!{23-kP;TX$I*ռCƵvqJid .a97Л<ǐI6z Vҩ;3.VF$\"C],s1Z^oWWYZAz]әpmuim#)l; E5 >9:lRd”u31E Mݛ:Yi,`Z,Ζyڋ܋B!Ҕ8R+1fa?g>L _F-^+JWXnsf1>;iJ6 IDATT q8KPDf6V?\ TP,J, [ XIԤdlA<toB񙧴n=w U _ptWdmB8%b\":E#@]A84a3xJ Jmff6$Ŋ"D.7UŝJ^rݳut_Jߍa6ƠC$-l@`$|prO3 Su^$f:s FF/_[O= <(Mi4]l7p~qJOu,7K"ƫN +HpGYe$ AFߜS%HM*FLi׽TY҈J֦(8^f׊(`yL?0/O r(hi(qn)Krw|/"yT"o ,C)gBJ LS# ǤI814Z:jeq'|;@n4z c$t\Ž;e+{i'_[rj\ Mh{x8b1ySU SߒD;|!f$+&+[br!b5>y'PgR4|̮Yaw _?uw3[r1 c>{ȇ3_Gsh~Ƨpx7򓿁뜜maJ~է8ZHMW~Jx9AD2BXieF*aN/ օgywS^8; VdaEzm[[F#`7ȁt6jT*Y_~? OU_Oȋ^=TR1}[OsATK-}OsVd2FQ7=t1AIq߉: g?Nk+C XAfc}{I)*^'6)x ̛ n wXyL&pmoOod(aף0"%L(gyI6xҕtb2;1OlqyB׫t!D7zC GCa(ÙIi/=̧/>+F~~;ĝQKW#)ur/+M2סZty}ȿwhk!qGeyW|7*MR6>,>p5ESg'ɖ"&4*:]sM3Vm'h+Rrf[ .C3Dq.~QjsSU@237iwWIң;M#~<6Sr)ozo$Ic. K!˹#)G @X"[+1<{tG//m`IR`ea#$QDGwGBIܑO'*E{` +=A)%?\Ǽ SIk; ^,D8r0Gx^DV3%<ޥL(Ӽr+4O7Uin(']өf+dfL:[59F1:I9tWLj1A5h =%Lk|t6C"`\,bSL͠R`öH%Y4h-6Ɉ zMsРamx+pEpn&13];8E})xc7ydb%WOskϽב([c Im嶷zu$IOasd݃ @xY+4!3_$N1RY`949k/*$Ԛ4 @oHBvϹz(utgO#zȖuT ζJ [#K$FֲH=M>_1[#6.oyU>u*e DΔ~Vj¾9eUy1PЬ"faj6Fv{1m&l`:g|Ж>EPzP/:e7` D (2U ;5 ~峬{ Oqm۴:TRbwY/}3B:qsb9+gxpL跣$AZp T3Fe/-M++<<_g.?p/ d9ؼ(H]B`kIxi&%}FbV1RZ{*q,ZF(@Ku5pꖅtLA7 ;=sRPJ%w=ܡE<į$~+/z+T'ox!K|;GI9^\5vYp-Ҙ͐" 6s<h!$ F!v{{_1~3dUtؖ,O{|+o!8n[Mv$Kbm'Q0x?Inנ,S+ 2!neE YzK0s+ڣk 8Y{(݀uFi. Z&s,kPpT-4&vCFDb@wPơ:ur׭010LŪ^!J"hwW0 I)0)>7z;s ^d}XCxG}\ڐ/e>3Q?l=d޿FI 1gl{_ bi*fǸ*)w=YA)Av/.BɻNRϘ[ì/Ddiy˿ _U_˶c6i{HzbGoNt;$\qx'( VFvrb1b(4 Cc(QD*ӛ[w*O!aǁcpAndt }8F!5. K[ĺ!gX~ +px\҇4FP@<)\i#8p*Bи 6Iƒ8UdOZafOaJglPq¦+ Bt'$)!_ $w >oA=[OP}%Be`W=_sj Hd@ [ ! ,@ām6 ./>y'+hj-f"9gkQyۧϾc~5&GY~;L#HO|gq|wó2OlHk8{'RfO$ݠK?^O?]j֮]{oZH:f^Fqأw1ZWWX,_yWn9])ru`ivƉ? W<L)E01 pDdɎBKt@-µo8Q$[Z KZo^×5ׯ1[;B _Cv>0[{FtY.9s]|!j`GH26:;2k[#4lb8qE[%̚53moh1D],C0\,nw-5\\%O%Fm>Lэܶ6)Rn8R+SȤ^z h楎}KLuBMna7iϜi;O2NQS Zn㪈HFyg:c{a2"a.Wѕ>,U& *$XvPRF-_t pNEīe7R߄k HLFV$+!0;:鈟6#6q,r"@'d(o%\^93\׌c? R(!E0ӤKbqUh4@XD4HL~ˆJ D6Z[w㭺"/qEӗ.(5_-lHPT *qT" T)Ld7Mg;\uNg'&]1pK1Wa&ZʈdX,NMЗ>vw`i꺉 ܡo$. Lunv:#qjF޾^ҽ}RX#/y~*gcӟhku3oX[>)zWkLcnQjNa2 )jMY05bU LL,ι{hK4!6E-Tyz9פ#KE1u$J`V, &F! ,YlTv)&gc[ԽD8}%q$?1(I dVEɈB ]OH@U)zFMKEtt.3y@S}GJ ğF)09 A74>^fnn[ m/U)Pa3)ԓ NLd0{{tw])D)`8 )Ձ58\7F5I9krLe@fkbYrr|KtL[Sn4"c~H:Iz$+L&q4 хyvO>F(kg;, C=sSh躉.?wh&fnxQ7udA.~3*x=[|]E=N=GtmURĺ;HNvbz5" 9tN42F0<Ψ>elS4]#P)"ъWU!RK,g@/ͪO2I:H"3Ziz\s w47rBO#~U+f_jK#N7-.+sgbBHf3QLQ OC$1eP 1ڿ, w=bv4=.&>|CqS@-29P쬞 ( mO` 4,Z:2#~c[WXc\$D! ,]tTc?c3~xCRNJ72M)io"Yl3FyMlW()RK}.'X>-.?aS ]O}zi.nHw*R opP 2]+L}I~yJv cxB:ѿ(\ܓ$v[9zZ8=]Ĝ$&Q`%\+'hR-Y)u?{a'}BM)Γq%!TCl4uL%^zԒwTU b $PJxu4::tJC/O8SRu`$5 -j:TkզGIFF;T$5=F=+ᬜwQ1a%}y!ZݛϗN`y,b#BiBvvvQ)F#l$]~.б-7oADYLE_w~}x3FJ&U6:qvDTۢ42浤~+ ptƩ5?YcC)0^򞙦r$?ȟ 9/VcDhXuyc5gsZ7*ekĜ0x1 3Ќ"fSīyd<1LbamX;<E@˿̪U/:@v<)0={(g nQX=u!^Tn[?Y#Wz> AQ!gQfj^U!~*O46H}dJDwN=jTLޒ: :☆QtPF4*% 7"4Rv6V.p"4N8oC+RI:c)Lcob' 4S $k{ݚy`5d$)Li( 0**U&FPq%@B H2peb8JTf,x뒓GbK1dY2n;XRW!'g]Y}t៯\1S!ԢVn@,cκPR(}%#j` `9NO C4RQ;Τ#vgRIYŨx5$&uK`t*T|ß$McnIf \q =_)n5klc&c-=;!iܻCM2G(,F*kO]t,XRSgehV=,j+TJOmM,!8U 6F&˨1مR$P+$QHiP"C ^Hк 8GD): !.z_8I2 ,C0|gS]R En7{4OT ^H# R#cCB`q1NZOYd@lgP-@k%}TtXƤsAT@(ҹ):0܎_O*{g|5An~{<ESF/Zb3B۟*?9ɖxg /|Y ptP/Ry 18ՊF@"-KųvLRqRHDc|eܺ֙\.I<dn~C<3S6@?y>\f䏾Mo;c%{n'0pY`^Og0 d>-+Px!1m8ҌĊ%ʼ@15j1t]zsLmkq6p.v*0tuE8-j|z ;!VߢjA)R #a)bF8땴'F+%Gj,{rpȨDc?>ЅF&FJEՋY)a6f^'v޳|'GCb9+dEqyTJ7zd_JhQCʍM(jFhʄŊ"r# I9h~ ǿ1)/Do'ϗ/2x=g(7_¦ͻXFna"nYC)EynJ):6qC2Vd^RZP‰ەĬ@{եT▯~o[6>zGˣ[CRD4,ɢRNБHUNFzH"%Iפ/%wE0 B.ͺ݄g)SiPN4$z!SIOPrH$r8.r)G'6S5*I,ȡRA&7lwxh#TW$jKSuB::;Q<|r=@ LJ0VnMVMťI,AG[nicts-!Mj‘*+;J3B1c=s3CǴgzz5J!iư9b QPmADH`t";ralCU!$H&p F,ZKGL'FqlF-F%ES;hK׉yfa#Ll{C4jCoәnU=q4ѕSS{&jL nbh.bHVcܣBݶm`nٳqӝW0H)\Oywџ1`jp Gp.b?e0jkY K6}PM/Yut%n֑^o p] $럇?}i 1'5*Huk/|/>p1ͥ!A"j˓>Y7@%CG ӰAo>ȶJ/a&l+w#[w!Q 6}cil\11^kpIM'|5\]xa/sٶi=MB`0ڱĬiL vrK/0kdH{xwļT}?!ijj=o$їG3Ob$u5u'Ԛ<ZOusg|V!u%7Y=e+yOfgu\sf?fPRg f{\58gGljWsVi­ooBi8M+1w&oAFJV$6X{_a}Ώbl׳6ot]?%_y  sdn$5tPö{EI !4NKgIQej2;l@Z={W{~Dcg:f̘ma{ӡn ?5 5I\tT! ,>6,@R4c.,ؚ#T{|4AJt횳|q)#BN}| 51F0db4* A/3n:2W [[4 Wl`q,71j!XDS ^SJ=XydЈ1x"PԄXT}(ȟZ@nj)u:]$:]%Dd!L#lܻ^{e|P#C&gmYR5A`jD 3[i aFԠ6>ϼX2YT(תy.Pװ.9|ba(wD0ぶ6iҿj!WK9SR>a@8>AT  '(NLM㏍BHkw07Ӆe]vWO\hD -цV@u"ERy:ˢ6]j,\lTJQG(uot9t9gO&<*LrwQq+3ܑ"nIXsVr}6cBn)Gհᷩ?4On;W̿+s^]2?EPv; we,$vܯj{m[8$bt)u,E[hղLS1B_I Ǎ|ɹ]q &:fD<^mj6Tٷ!JFɟB+⅘ Eܫ35Tfa\$)a}/6Fiͷ_C<$ɕl]M۹7rYKxC| o9K*Yރ>Q?#>R .XEyNgέٻή=ȵڣk3u0O#XUۏL)G_XB"@zFl^oWi8L>D#4M70,gN@x Xc=A"mht~cS+zHxA h3%M 09:X<#oB0Ha)N XlnqhΒ,Y 0M8q|xH.YXmn S' LD"RUJAZ:>۴N(g=a IDATfZK!vMW+9AHFטo qNƕlqpV~ֲB{N=N,yA9f>ve,h]l/[7J#j̴'&1B8X&ՠJ9(ʣTD/QKp $\j%+r+Go@۽x WN#֊h?y׿fr˓Hr=\p ?cFgrЇAKRJř4OB00#^HXA "svb2*flrR!T)E0:JgK3Q6j ow9,L HjC{.4YDi 2T*IHg/C7^]VO=yfIˏ$BGi 2_ B-ٽI:"}0sݐ<;j!pzp+L3+Ьe2O1зH9xPR}o /GN#t_!ԴgMXY9}s43e8c^u)<=~qްSZԶ?oI3\Z+p5~7|3PiK5{HrHi,Џ|*A_TL[9(7@w?ڽ%7sfjzR=-=Ge #UB_POKlKA)]И(2 1Y"YЖh GY²̧I_x٧pS)C)::f"00l[QxXN#IkuE12NXsNiq7ns0YBM܈HsaC)B!04qJ2hа)}h;ۏ1e/ZGUjYFBW)XJ3π =iq#'ܽ`RIAod<Ãlۼpf $MӏZ u h6DCo;}mXZ/a#`Jpv1eo朋e愈Z)@euX7x36؍lwVu!+{ҬI^֡7pg9˵,Tom/F;̤Þvr3mk%8bx %7 5y-rzsjE p?M-qc8@;w^' C 0 nvnǿw! L^'Gl/S~c?)t1Eߗ괙qWhJz_a 6JP|~HͲ '®KvUMr%]_Tmt!¢(6f t ͰO,D 4Ԟ؇ɷgXp^$+^j),!&jݛ!ٖ'anGG5Ԣ$c9USJWҤ_|yB[R!qfWytM 4+$xBFr:^ db$#pQ\QxnNc+8XqҮYeTJ1P`Z cZuxv`xo笎W`jsB,Ѡ4=k5$ۆ SB-_O}@3;W?J>xd=۾uAghB=>\f 5W t0~ a88?+ #tu05lPq`/QBc zD$z$gqWC?Fsb#;q׾2tOu43BZ]4CmNmbL<Fb&z%ŜAJ*&&=FL 솅RMcU + "{w z44P#ւqŠ. 2xԫ"@dr.4Ύ fC ~LD7rQJ96tt,o| ;!8IF{g;^B2ВmU h?KJ)vx-Fֱvx-#(pfǙ\7D!5Y#4Y?6uQ rdR zw&̟©itiSJqº/<uנRhKJut Q RX'1]l3P!TBfx(!M ]?AcJ^N؉%L4D!Lq-3ktVJ¢|p\ -ShDžYR-2dU/a.b w^x})/^3 DB)u10a*.1ҷ. RJ ͠ۏn:.(|~-a#6S/ˌg۾ݛۨYAb1o_H|htssfJg,M-eE hEENH?EyeD1<|c7Kw.ͻRdB|Ԥ^j=b26H4r|aػqthܱ>q'H!maU*4rGsf:~I:`\8Gs6o]=Kb( fbyyD~Q޺#{ \n\ge8; [Nٮ=_{{Ξ1s&8scT`u\lW>s\5@: y{)\%CU>O Q)/. R 97_H!RQVm)E"Tx2rE\LsƬp+ps= |+W+s4"~F?ˢ<0Z!vDni@ B]Ba}i4U%"%"oy饽ڎI 9I*>"|ne$g5>|>D?B~qZo{!]"Z\ƵW-g ¹J6ma<1¹a OJü#Fb%a:[#}hx3xl;zEE>v~w1= Z ) pꠧ B7w|{wߋ#OW7+?ˌ،m(%2,ea 5YG6`%Qn8G:Jmh&A:C)&xN_k~HjQe}6sng slw|!'G0TmbnvLH.S`k%#[>?g@'bI( Bn0MsfmiB5 CimFXysbnlWSZՒ]ûs+[漏ɻ͘ Ź̴A(cWA:ktuԊ*?/ڬ#.??^tyb!S,TL/昑>A|ŢELuucgohEQU7DjِI\C/U,:PN/?[hO )%%FBW7zBqX}ed(W 4 ͝ @Q΢dMD1YaV !a+ps9 $ZTJD1HY%) WAbc.B,?SL!ׁϿW%\<(B!HP2/@Rf6uFW8p:͡Νg:%BJZ^ o7~oߣ46Θ] ^_ͬZy%G^ `>A v)%Q)tqEhXs )B!ADnLC 7'(oS\|r'៳n:T#~|gwznw;]~ޟDb*BtCJoB Ş=|a6pgҧآ6~i|z۟8fƾ!RETz nmL&pAI[gdx\Uo`f F0 0B/$#^8&RU ]ww3(?[7!; ɶvVt=3.$@VoDZ֩rDoS[B jjl<ͻG#D˼S܊* \xu=T,\MP5b׎|EC~ZjP[-X ,MzRjO!8]r5DØv*/m,};O_->֧c - YĂi5z; rCe?–drsdi` 3<ԇ;!!FJDz&%8{TBuQ|>MBP` oS EQ"a~ + h-0~ȣϭ`WȥI'K)}B\  IRJ#?pՆhM-DBB;3-ɶ-F0%Sv){}>N}^O^Ol-\lK-tdj* |A1JU1keFS/d\3HE t3Vծ|B/cY2<#f*h~_[>v ƕy."Քxi"I wm6m6>\|ߗtF~H0Bů# R3PpqԸs͏ތkYfdp\@EQM]"wuc9n&3fzk+k}c\bme SJȑZ'4_mmmmD6rfym+Q0 e{wlՉ~lO}<wxSPw(A, ,U{J–~_pن?uC,H'rAҞA>c?/DP- AIDo}dDyD؇iusG,)xit%KD*QJ$RұZDy?vR$mN5o5QY,2tt"|9eJUAd"k&@ Ի ~a Ά %8!ŏ)PS3uDPQ p!T, l/Hr^le3y L!upS +I)!HCJQƬ:m,5U.jTC5޴sB ޔߥpx~D礜^f6ēHH^>Z+%o:`kt{I<3!-Uϫ7d|tE9rR@ÄM?3%!?aԄ[5!!{[HㄣR&SuX(;22gCD8 ;9`dRȌ` ƨ_N$c_dWv!goOc//uY 0-PNӿ{ ^{#p=' jOJwPVV,ϊsl[{O?ر:رa-Ȳ+XQ_%sk澦3M۷Sڴ͏'Ӻh.'_=WwM`4,N- /+>̓䁽ZF73wm~ͻaˎSSViXx%+f.eqú=g=lv|6shXqu mF=BΙ+֐RfEkWaᑓGhHyøç^5(ڵD6ĉ.ThMZ=14e5Ȁ!VB7sN}/܊XDүG7>/ߣϽCH뢱~Ֆ4 ( ,DУ>srxj6NX%l-t_ IDATgh= `%zsD!pԨj l2yjDGv*\d M#9\R^Rv0F Lba{AB@;<%LD_":k)oNHPe۽v M" _ _di %9^uGI;&Tآ, pDIms=ϱo+{iSX0w@gq~k9{}爓 gq&/!*I>e2qyJA78?@-OTSܷQez?ru>vV7T19ya ݗ',D$UϞ w8?0zO)7ιFV.bO!J"Nkyȋm gN-Fs}ӸQBYӸ8##ޟBZG&|y/{"?KZgcԅ1G(Q',c|n:pu%T`<6QykaM9~ %ޣG(vzH0h+lz5x`8VW \jLHY)4mS܅ht.G):!Bs$" <dž)DV?+JĶJ!cjL_4h4P*ƑR3 | V1O.% SIu+I+j p=B{*ORa xvlH1*lkł'=rVS.)#-5}9B_z.#r:/0n~wsߞxXDl<,VnfZFj izyI^0_:eb_W{/a;M:[/gǁ9+hR\zGvOs,8nPz}=zٽPxR c 1o?}[6hXP"V B>+oMeZ沧v.4A*~wTBHn+]/֊gsż%ܴj+{߭T ?wH#>GKp;8 7,A:@=B1(zbyc Db53&VApmDHJ0T(1r@2`h]j$wXZ7`>~¯};Ag v7}i eNf+g9Ф3Bp5hm%[ҩV8Сx15Y=HQϠ0O>Oyvt{?nwXUu&s}H`ݞu>"/"RO!]~ __i&P8ZYJyr#=[@3Fx#;=D5hd~Ï uם,M6qivO+TV.̢͆6}I))< e*n~??CJp1x4zhc~+ !ט2B̚ ;(8D)2}.jB˥YM{lGp1Ҷx &y‰f.[+i]'qm$x6$pϙ+bŻo=hTL*ɁT m&%e'qI>ᕢ~2l`k&-.p 6AT:<" 7FU8P2Fc2zQKª2Vlf7 9zuԲ4Z:z>o# #n8) p̿0hH)sSyK$T_4EdfˠG7\xC;/fg?B<3|Ly6ƒÂ%f-ӂJ}G݅k`ArVsu,N->C2r(EG+зcٖiRcsr7mi3^) RJb@?rCd9|N4+ cч◴,XuJ+d _]BgHǣQҖ-lAon&VQXz8e PcE)̽)nxw;]/M/ppVh@|W}:`8/ToIOl|qBD]m|zj}{?eBZ-uȖ*,!#{ikYZ?):qpFmD/= ^zh˖2v7wl3$(TT[UNOz%i cGw S͞  RÈcPH_st{j ʖhH7]S5܈pW%|L5Uk!lB4!3hJ &'NNj,esG) L$&gIP!WR9hl/BohwRO}F}*`ww3/1#v-|Ck?¡GyM`q̝μghNށe˨_TIǶٻ{4wp?R'U*b@_iÑi\6ACӭp4̞K%-ZB㜹ڙ/M$(1;38jb;tw&Z!1Xɏ qhfmDzbqpFnL! ,RTɧ4f| XꜣPXF'E_秒+"ۊR4sEʊ=5^sį.0Obh*iab # hE:HER~jl@Ŝp'%C6=KsE Ms2iDH;K&RJʹ,C$7*P𤎂aaE:vlm$Uy4ϧ'S\}sA~H6N+V}WT " v Ȁ.z4 ,o~ $L_} 7 @zUe۫ !%"\ 5WUpfYc H8\ǡIS̤8J=qygu:Һx -b&2<ڲ|cbOMFpN Rg4!RS˒Ȓ߈mٹ[7qh&J={Xc+f֬nI5)* "HE)5|/?'D65_SP Jw8 ==DYJެ^8OEJ\ I0tay6AY1G/@%T)R@x2#6(e "ގy ]4]BcߚOw7!|^rRv !nD@_GGFQT&f/>PC&g[ c߯iqOM00g>[N۵>Y߳=#{xhhsEÊ)WFӴix>Gs1Gmƣ9 g` ? 58@LDlP5hhhmhXp2JwbOE:V:` %G;>Χ ?}.MhO}aiV۠>7>5wA7gVS󨩙Ax<@oƦh/x)%'`_>QbB$? j>rLO=|%jhiIt,eL`v/jH)ˣd,1 br!Yc OWcK|:NH~MJZU[F*f yρٻ9=ua!4k)Zy7%+e͇q&{PkJ阊"̉_C\H +֒"_p*T$EETP4qRUO BqE\)”:WC0ڤcc`BRq*.#ݙ+Y Rx~s)eq!!d0PB<U'cla4JXm3(y:㔇6;J(~%h\I5  РQ.` I&"+rl)t 䳈lj*"Q*P11 :圃n Rbݍ%1g*&T &O (y<%ԫS*tǓhz=Ʃ5yUHɁgGḴg΢n~Gy R}Z ][F]g<IKSKթM94͛[)qFH lHq8^&`UIqY[G`46.<u!p=MP @x}wMCٷc˞:ƺ0$q&7Hdf7EtZj0yFw [`T8 "t*}}|[}(tOv,Fj | 18|^F۱4vԛ;j=Rԡݔ OE äj:xPGy], 1EFB9 bpMs_@yԓ, B60!ϚEK2f"QʨZZ![ /"<Ѫ!QOL,O}RRؔ\ %EU,0p ݐ;PU!C)P-n¡\:.#@&0yX%xﱶwR: >~."tL2fuT$>J m?塗e8R[+=fWɞGnkXݴMYմZ0 r/<HI~(f{3aSx2^-xzJ2@46%Id~7~ӯkhy\zui 3mbhdF#0yjԪX o<픒Y!^4II=Jj$?QXx4RlIg`Ɂm IDATÑ鐿)CߩB+UhEUY?c6ʫXDc\W BDѐx,#k,=Z8x?6wC#]?J 63׽킉CP*X&*ǬUO*8L#x%( *4MgwRTmAӌxB_܌J"&u8P1gmh=0 @X)!$[2زlmTj%ȌY*W*]9y23"#Ȉ}-\W( ֪tU:*͓'h?J{vnE6 1rfely@:Lg, 9c ر:°l&ށ쑔nԙ $BMe9f Gh M(^*eӾ[ؼV&ތɮQ.Usc<;Ub 9{錥YBsЩ&1dV\vr"R)MYvDRST*28X#?B'X]UT[ɌD ؔJ%wbpeVJ Wˑte4C}yX"P)%¥eH!KK7,_Ҫvq%tX0ӌd]AW;K B.p8._Fʦ0  Q"[nmĚ=)'|8+AR.x5T 0 tcE|ПyQ/:7zb.uC"Ax5L\c1۶Gn~Lv^bV[⶚)B:%;2F~#Y,)]}VCf*K ^ NMůgz =FtPD%LDaN!q  ZIfwFA1N;l[VTWJfNa&YW#"(bR%tjN#qQ#я␱4LnF͜jҨZBc\ZrEzMg >MQJRfc.~Hvdދ粴Ԡ3VM`'ȪHI0_b ]'1qf뎳Sn_)S&ncJ kc &7A7>އ.l.BTdѩtv cjhIpP9GZE3LR5N^ XOJ1~^nףX(BAJ)]765v`I1-|tw?7Nعc$;^Pý?%?JtϒnJz7nL%s!L:Z7I:ND]UUר >Z]=맔({ڜY .F"I 5PD"2r+!]9|byJ׮ :uٓs{:j-$L)V.|MOӝOHH5}ƅ>\M|J]ǺA]e}7f^G:k=sӌqfGxӃ?6` rOxcįQԾ{ne..|{g;]VѼ,`=,/z`sa1Z:vRwI;Ep诼i |c|}wbް&}H9# {Ӌ ge6/H(BP ul/#I:'ZL(ck?$N舭L-Ҙ IGJD"W}\5XG!;> *Hy+25n PT4pRAճW_US)c"fZ7L!܆ւR.-Wk¬O6 jzanDJE4@YJ19ɨmSN_;Q8iO-SkG++ҢT_v =XKՇTo2!6VImƽop& $R뻤}̚ҚG9yoyǺ ]Wv##R:Ľ:')X9^qy:m "~XSLQ6,Z1Ab,rLbqo"uT[C15*1>6Ե~q/0CnV0*q##5()54N$F둨!Bw})5wB1[j`cR)]Wkr3߉sS4|ݯ1~yeM? 1[П1չQ,;w33|;[CҰ\D2S$dCd%ҩ4ʙi瞣3x8uZYy;ļadž[ϖ;]?"~?|N{?h~}c׊/+Ϝ7ssS}ڷ?Cڼ(EU0LSϑJ(INdѡuMI4 2ĤY:^H6S+iC"R!6[ !RLDU ;\'q Aq%. Ǟa[>Gw,wel_k #`ʱO}G EIa[aTAQlP } B|, mdԝw#-W5޶N!OvI-%u[QBTKO#R&ocK _-V`'1ȡ8&ކҫCv܄L._EK4&^&(um_ˋ>̳OMe)}[ғUUg.-ĤpRJ> '}_ a96i߾rH'2aSeJvK]cSdFWT%IbΖlSQQ%Q$ju< 7 *@( 6 ~8DB{ ^b/  Vt<9*!Ls ]Mf;ǮyMd v𦮇[[ao~פod,)ґOBʓ k8b0wB P \[wg7@QME 6RDM@3)WD hNNN!ïTHw-H)Ij5 KhA".n⭨dDiH|a\}{s.ϼRYY&QY"ߧߩo-ҏ5ŽøeHiz+*HuH Rfuv봚>[7P$ ̝hГDZQ Yjt}V9 Y!Pe@!7T42iUt>nb:mԱ+~k !B;r%޸hSs;tR14h~Ș㐻6Ʊ.z}}>l"o)n}#XBs.q*xS6t {⦅z 5?klR%}yᕋo***d+B@o"@Gmc34-'VF8Տ]UB.tmDV(QK$}+ź[%(gVBiܩ!rR8?(裣0j-c଱ĨTbL9Z ]A[2-2j+ʤ ÈLpBee* ;,6(|]]@Qy"dY܎GʔЄ!H)%e74IDW3#k[]܎Gq XH~'tenp C 5)H B7RXq^l_J)XKgcB5Z*#^{^2%ĵ3rS1*B*K/mI|ϲ/+NO__]}G'{; c~vd :O.X]ù?Z鍚36^EECQta`t^=k(tvVG)L5C6e3-w%Hč5[%'(lh h'DV&g tqD@)s)^L,A)œ(Ni݈2فO&1 ܰ{M v;I/"pɥ ;"5I5BT#z˩',Ϛ3R̔:q ̈D&W1)$߫KZVV*1 jUQ3 ٮHK\PvkN:^Lʲ&$M2yTsm %J"qhI( L#o XBo5׬i>Ͼn>#':PBcSNi y̵U0ُqS"9GObu**#wnOZX^~n "Gұh6VWuMH#DaD&X|3LQ{~rC tѕb|&*xǯ^6q% R ޏQ܈DN-U.]@K2j*Uʎa<#}"# T8K>YAպtgӌ%hʆF@+;(KֳjirC[9V!5_$pt& #8ճ ! Ej/H!HrI\Z!vD6D+gl > #R:O/"*c4e}m!"`BX(ZN{(% 7RR=@Kq`k} 7,Bs4gh]ڋ'Ƿ6ߜ?ɇ>M g& ox`R 7,P/p o{g[#uʉ$z %D*s7<K7t }uYG|~6dl^L]LH%"%x䠇 ǰ4 J~H)Iu(@= _z[4ߣֱqCkL)6QѴWTS [M\D[TfqB5=IߝchY"4E]+x !P+eb+ԗ05oA$ł :.'nY N)Փk6,(fF.jlmԧ7ۘ*L5= ^tUǦW1xWULuffgPd@iN($ j2Q!1ݦGaZ/VdIyɔߏ0~E)e_q ضn^ՀnN-el!:'7?":G<;'f%N}_$*0%y-t{{識i [Z?tN:FHw? A1aĸyp_+/ p[|5}V,1>\g0wk~aW]ZgX*wЌՕwu SQi}2>$3we0[USO{cbb@b7Lhif%T ,0Dq6s"5! h%cD)vy)%zvHQj.F[*{eiYRQT>͝O IDAT؞FKBi*dSUIchCp A V)!2١2F:O_*W!HEդ iW[iM* Dҕ&yB 5c"{-4BG0-4k ":=B+MxK-}yݯ>\"]`̶*p#ctHo1{\}׻PGO{y|#t)R wcrCxWFA< -HY2y> k(跿o_BRz1m|-Q4ANJRhMTPTP&;*1?%yI/_:]$\YjMRݵ& aئNZ'c6kREF jzCY{Ub'hE]1MQdD&WY6Ѣ&J$]P*=WA`+Y)3 <'DqJDzL̩͜ { fj䮒QU8)#ciNqb ܹ6QR;(5 !0F+N):M@K^RX A"X(2DWSzX?nEJՀ+AŴI -kZ1 n+$',/Ϲh7I R9σwt~\?[;YJ<_'VIR1Lm]pKgK)„!)|?{׬YlPђ]o~benXf4>'geNSx^vTI!R|FYbxD($9&kB6Js>e"-{g3"'CKbD W2C슮')%2lP'~="A1|&25cRMzDɊ489.0/qij]XCX*" {J!) yic( gl4tVD6{=1vAseG&qBuCuypLj=W+zBI)ǀWGW>NJy!6DƦ^ǪGze~O[sns#-vM}x疷Ñr|0[Oa*M}vo={@Jzx{쒲I0 w,^I@C"IHC8ٳ[Dm;hr1@7~x2 v b^gTM[_PhQ¸%fH2;FԆC|H;LC2UW't"?HQbbZy"X U !L3Yb"rf*caz2^bR.Vq䫃D TAGb$y]qtdiBeGnv<)R}N:n4T!EY1LsIrp6Oc:ҏcڋGgXJ!!ėX5G)e6%Ȫ{z u}y0|5%=?i]@M.|sln4;x٤ŋTs92y޿|S{c/A^]D˒!Bow*Dz@ӊbQxUnۑF)%WT=\#_! ^,fc✵wԘ!mLжl .]i% =V`Y@KGs Y]bmr1SczKy\*x&1ACV\1q,YJA5%PÎ 7Ib*nbJ7$ (#R)S3i44ԘE(oCEϭE#>4UźVXE%[v(I79^,AQ6Xz^| r+63utCO9GeM sHĵ*%uG >%@iTVXYR~ `5m]փcy Cc״On<'[G5߭Xg`?Hʓs;}q Eh~⓴~~/l;Ip*d"Y0u: Ȥ7ʷBr>71C,W|Φȑ'H|&']LB$~C !K6zGP{d2{K :7ma=c#ggvn ҌQӔL6J_}8IuncUGOm„fP[}@Fl5W"EAY2Bt#Woz*N)cJ *C(42i9l1Lk grtq[ͤ+#h}~NϜ2 -L|r.#BD"e%/0AJ^ҷAJ!TOϐ9ڵ'DH-.a1Jl{zu, FBT.$'ž76|%L\ĻoWUs[|b+;Wl#X:yl=Oe6E};xt{>w%x0}ƙu_'.31j g(IG4mGGl.zjDvf;^]Nu嬬F -2P P4dp#.'Q V?1w}6nsxCMIBB] ShaX)DJ8!F" BHHr)!q P~wdN)uIR"gNz5(`JeU!Srl9G @C(p5q7w-oTT:O|O@6) iKɾҲIvY9sqYLRUd"{,_"㐠%Q4ܾEbHe ܯ qeG#_Bq˴44I)fbxHi}?{3 Z<ٓmPum9~6o\$%q./5X.o(ʺri8K@F6!5YJ%tꄖIJ As78J+0zBZ.@Y/mG$A 2 faN (\}5 B8@B 4[ R@~` OA{J739Bt]"ŴwɚB(#R|')s_-9p'Fm~к: 8@%G% /}tg0L|?_-l}6zw ݯ~|O\Z6i˖|}[_# bf7>XgPBﲿڔaӞޖ`fO2r9_ponM{ox}~ѝG h "A`ʷ wH_iu\AQdmӥYb)3D??956y'X:`d~y6)r3imqѧAJ"',s*uli`(H>YeŔIzjF !mQLYhSqbn -nCd,7\ۛ$t'A5:Ra&*<El&VS;ґSl+NIvϧ鹄§CefD0{$60|t"p]od]p^BZ@*栧K,2O%XNM%\ܔCQ#T&hCZpp)I8e`WBOK)]^^džC/1u Pc2;`_p"ϋ3/>~w8/Zi .J4r &vsQ&}d|kϞ+pH)i.Y9g7K-G=E&He_gL1\u:#2qƵ^KhI&H%}ӳmDe3ݱlQ}|ݡ&82 #\Nkf;" |a?wDdPCu^M߿*dB} UQhkRJqe4Z1TJ_~a޽ -2?{yw~o~ɳ; RL"EI KvD]>>+ttfr$r(ݝL[D%ZT $wXl<Թx ,  &t?t/dO}vzWFQW:CtYÈ0S4G,؃tya퍱QH\R Tu- $ I#>9 KBrF)s !1}taHDkI\m 3F;Quw3[fcEl@ؘՓSgh. W,hd]l,$X1v/3I0r5D 5qu|5Gw]jlU !"? o#^dryӠ~3%} MS1$/22:We>?N.5^`R(\GxG>r~˟[&i~G6)R/v&֭'SJ=Pe wܐ4Q%O8-d~L-l;7Fh:I=_~ds*p#|{ݕf(BE(zi"'Qj:t4-d(1Êw-rn96[D>$x"Sk{=vtdBg佛ߞY9f呵m[Y&RB$#Jxv mrk4mP{*Aj*v)Q'kQe iF-(cy`֞6@2Hl±ĆC8M*R@t- 57-MȢi^ƁUzF|c;^="THa"4EBG""sao&yw "}%}?C z,N| FI6|K$%,k~H|žVqLe[J)MƀBxb2C~̟]_Oe4+SN?J9/tM/[egg2f?U|5syez>Dij&h9$X@OPRW׸~tG[5Q+N.Br@\3N9܌5zDFP@x=; /_0= ;m ,4020a C+s@N6ܕRRq8Uc_oxi7s͌I u/t$ ~723:} / W70&=Nomc^lR[[$i`Dj=P:ەngz=1!+k*?0([UTJئ"%BH`|3tM7uv=b|0/S^#nja|`tgx8Rs_Z<<9,/y;{aue\ {{~qJ㯟G'h%4}Tn+ C $\9 uC+Ս@ (p)( S3hw.-\Y!P%8zkiLu9z[s6I% wF$Ӥ{p_Kd "ce.Rd-BרV.I [t"o4剉* ֚1K! Z!Ԏ|@ 57i1q vns49NC'l];:FwN_4McO_Уsj3J-X"9IUF'MF\Y[U*o\,Za CKFm=MJ1 }*S9{Y:ϧX)},{k[A5J!"zF%3:>łw`B4R/70'h(d톙9B]shE~ q!۔(~uu62=PN233oCDm?֑#m>}ֶIiv&[V9ڡZ%tcxJ){mzÌb{^A9gyaioSى䭻k Gy :nĉ3v,reia P0hGsgc?tĶ x%2IT:vl[[3-&trxpijԹڼ) sw֤H:!C,][e-fYF&2t%S>˲›g$ImOעu550FJ9Ĝ7Cխnia"ft ))vk cZdNو|bR)PjxaDضI4)Lc߀AȡbCr&JiⶣJ)Mu6T0]ʳ6#w+y5x9o{.C)T,N\.sO_;A?\@v~׻umyIJ)桕ڣ-=WZϕ6'QiJ$ ,YQ"ħ9@DeS3l/'ycw_dWBJ7Wigc9N`.Ox|}|,ǿ <8taaj>zB QZ=Rho͐~;l {?E ƨag 45jJ@0ùGolC9vKsR g˥5T G)qfjjyg[m,צl#7 f{oWu{RfAO6!! )p/h:6h^Af^;=9L>^!mvF/O?EC~x§?/0W+V2j>?#[ԾQ&6O23pB Y wPO~!.u/viY[__|%&61]06!#c #;1Y&#o ^4~W3 P+J ,X4R;gP_ܱ%+ٓ\"HRFf۱L㔍k]AJBS*%?yLj:coB55e-" |tVS)kBvC6Q2! >|wX+$:Wϑ6Zq˒ɹ BhDklt:. ~7bcy }MVwo E:+xA;$jBq C[D/LT ;ھ>>F|yLWhW`d mjK6t'UJ}݅Ṿ_3ޓ@q] 'mR4W7ڥ.2sWn4>SeS?*OiY|(@q>T렗-47\謵zaDܪSwp(,6qjh'2|Z|w.Xv%fkH7 `2Nzd4|ET,0 {wۈ 0ɣץtzg^}_Nm&?9j frB@ӴXO54B SpnBG:0 -$蝐"T ]: ?6l@q{7[Af;@CtV9OݱLSGXl,1wrrk HИƘKl.>,X,49<|O,n$Ju^/"$0 5t٠E*@m?ezdq!@/ r*w,5!(VL&L.hO7s]Ejh+ut?(GKhp] _\dX%i>G6gG'#.}{' Q12# eWb"INLota,YUBաP)Trncg |H!u([|#A7fi4Vo(}IŒ+]֯<8挢]]R!f-]2ye" a`:*e 1ActC n$C Z&4tMnK)oiJ<¸ =Оs慘#?P|"򳸅e2fC -rq/Dd]B#I{;ES+b!. ?e'3^AQWm ;PԳ ?'kHXjBQs=^cTyf1Lɡ1(#aIghk$hYg9ɸ!zMd5wt[fYJO|\:-f#18BakoĞChNr<GDYvYsC%oV*nP}tM[pRXQM$.a obS?ꃒ^=<2}\o<5B>׸5ҨWlLBDeH9U y{[csyV.^!n_l,O)Ccی?}/Q3|Y"?=l)  @d*CȌ~5aBDFd1:}"2a;"t!nA]C -? \H8ucE+[ ^d\QM 厠16[hsً )aN涟)Kّ2B́?0(Vot{#N}+_[e|Fr ScL &zxe6<~!A/oۄYHo8W$G'PHC$1*U4X7x~F`v,ᒓEb1ok<_2/:؄T!>_}# Efk˱o>Iӥ=mD>^zՅ˄DSe^^g7]efNڵ^ףj&Ե#?ɸW<`rԱ"SJJ[V|FiU14MBSDtDCڽ~F4׻V|<`,$l.ҊZ vۈ(#fwHh99bޥ2Z"MhB̔8Qa70f4ik.RJR?h$8;o+"t.Zr=d ; |GPqs`|QwU`( z (p?S!>Z۝ec7dЎ_y 8N58|_FQS ̆#@y*FBBrse"%5ñ}?㇦]fǚs =4FV(OS7֤k9?LZ/y /ǰ<3T|J%F]BXZppB\D̋mN wJ)uk>.\K$+Gz֫uԱS%&?\xSO_?NY(HV$ExiOpqLwUA 2N}H|qxGѩDT7}KH=&ណ.Nyҙ#6~{ J'{3(-z7h/k 09QAF*w+hB՘;MФ}uH Υ,lQ)ޱlyZ. s}`QSAHqɥons&/1uD@kbVmLK L)mG;q-Q&"NOdBߢd)LF3Vx}cP1Cq>G?DW3$!HRHCc`",ts%e17i/jJNa nE2;3Nvf;"wsίE2M0A0ƫLe?#O|RQJ}U]ǀwY=Й2xW?ME])H :d0_#a'|vk]2ӚIb\ @ʌO\-꬝xuLYeV:"L -ZI}ӋW:FLcOoF&c`Sf[WPJB݇PXN 'ɄƑ%L"A u./G,],(^/) !2.#"(105$E掾mY縛!׮\qi0`QRz S/7/6]& |,1H{Ue qu^\裆 aXCNV$ }]F}e$<$FDbϸ8YDL$ H' C%NJd$;&ڀUVxy飔\w}s=Ǭ_q]n,o꼗J_t҄Gi¥"Hd5 Ul6;H >%_( NA#h@B?-gO2iB''$"%JŜ"2IMZ:&|(" Hfy'Ѱ":m3ob4,os_='{lFcڿ4_4%~sW Z0 St7Z\H)+u [Dʌ4pLkW1Kqzd8  z(}xö1-YL;cgpLa)n=Iq`u>vYN91cK|4KH]dOICA/fC: HDrJ%1d2u"9ĠO"\nw0/<qag`k)Unӟ=69Q+]yeb$ݸ[tCx#<'__,,U,UDo|In}ö Ai̥4QIM IDATpQ9F*F HbM1- W8[ipGEEpķBQBuԆOqr "IaJ5M'W4"G.(Z!'#D$|Mc9"jAyrfL>MI?h˙@ 7~ʼn}Mqehi1J TJ$_2j$/o>(zk[=g~C*I 6}@8C$B{N18SbnRՈԢp"@ȍX5C 쀾鳧s8o&4*"գbWI m#J!Bє,Ce:$FyݥdHz(1%CGwG(W8% Gȩ$aW nt6dh_kE,v2E6W֦7Q9\lxHJo"Eaaw&Bh2)ìnG),(L0yC qh*1G4;T'UĴ1EijX`<1IYH"IBAdB )GFnbW& MݒNAUuKbI)o B -{(P 1tSkQBoy8{vNL]5RI"*MdL>ska{&D{Og"1lh6aK+$bT̀Hv̀,}8BQ׭CXsG(-ԜW;r7])NA;KJ)fpF<`PNSB(D&>RL&" e&&+V?uF:;?o$K3&Adj95Md2B ۮ)x.S|EJ2<3C#gH]ߞC@^A֛؁>V2D# |l}GԂnI*B|Yළ~RꆁȈ1:fRVFU ?7ǿXցS/20Sz޾YYB{2͐^TvyƂ"h2`(#H2Rf4t[ohфF*5ST!#tA;{ |uRo_BL ߀'wuR$N&*ВhBCjyGv?ɸ#;KH:n"yy濭\&W=U{J*ΦO}ˋ-ZnP 4Il4jep۞A`z݁T$kQP2 Ē ]$})ʰOSۑ V1l3q71dY攘AMש#XY%xa"_5\[hFlS\3#}6@`c96]IJFöqr%4?!1c.L]VL[ί*~N?5G%h>T+Y)oveS]&>katFGY@G?9dJAX4mڃ>i' ,; &ʰm((I6Ssapxa&`J$l<^Ćnfݦdf&Ğ~l,Rě e#E3 8sw~ cE\-a&N\K\ &.g޹^6sA#"c`T&q\-Gk!VM gD)pNTF'RdditWm+V1S~9|X? Z/~o`SJ%]+(8I\{=}y _ bLa4ġ[ J ; !琹' &5[\uC(F#Aak7 S 2| f4;<~"% (G$QD$D5=rnl U[E5 U+ =R>M10Dw,K WAar-D#覶蜋U N^MS|Ga@)23BI` }`E)ڝ%c.<_tCP2==VA swEnrȃt x$fF ,"N~A!5# \BaFr.G OqKă!LB=>=z^7w tQF7[YGg۽}c8'' +8tu>.LK4.p)!&q'CDZQ 3J zu[;QI:Y&o1j _qWx])Jz̀ O]'FLgj|]4yJI,E Fa#>,bxmIdNf+1`$wK }VZ> H*,3?aR8g}3("  æL3Q2)|v `d96IHLc&WwyWBJ sJ)^'>(Ι5SaJsu(cGN21?KnL[T{Cą,9"JZm$uZ34\CS9~oz7 x}D˕'Q"VxK\YZ ccGI  LS hJ)!!K2Z]5K%NQhBD !$As3= fI@g170u C[4+Qȑ;j#{_WޛXvw~s~}kիf%JG^Lg2^8 $L`{ &gƚdDqe[-HJ\lKu9HjcK]{Phv7s{skz78u@=%3׹?xÆI*c>S|_gdO. _~Nznhc0;`` Ľ|#}*O㟚cGXtè1Sݘ.¤%q|ɨ1JI^6G$>q ,c9po?ow*߾$u_Pm,b*Td'BMl(m/չs w~f=0$&|ƅb߾NʍO^Q1qPIVҚiQkENj7|*|"Co#7yWZw=Wœ;d4;wv;wlE(,AkA,&M2Hd1Q!8PG}RZ8^`'*$uKmzwbLj4 'yB! O++  (eȮ33~;}z*!Kb (EОaa=r1Gn@DT(>;gpSE寻!;%gC#9 ~@șAvl'ΰ0JW?'s[$í.n~ϙVdXPfjj2n҉zazA^}#WB)kc\h\AZnf}9}聹 d nڰ_q"b] 0Ռ> #2ѧ߻ {r/uFD&spN!#4kGv=) $pd;y?|X@2e3GїOG%8($B<)V$іFsnS4'p}H UQ1]:#&1d4f4&Ofu,ۢ~a<@AwD$A{?/$ h@:cʵcLcІ۠MШר4:oڊx4wtnn`66}Jw8J_ 5&aas`OO0J!Gc*V_ )Z.q¸Ѩ4wz4"I yyY,.XX;@֧h\a35j*XDwn5SmDSH-VR~dg *C~V~ɽ6r po7k{7 %㯵&{%/\cP\ec}Jj»a@4Qg/G1Zɓ0ŽB[E}pEHЊPhXhM$u '5 [407P6F|@0!ԙ{ǩL6kh+1 CEA(PJʳ/0X@VkXmZƲ( ]K`!0x:+C-3@YO>JJ3ؚN;K2ɟ ʧi Կ@S-"VN\!ElطuZSɀZᙳu~矠PW?1)*L^1$l0_ss~_Y!UlrA0MX 1Ph%l%.rԻxi7 &@:Dzxb@جQo# չ&U춻xF'87o5}fd|1`D.-.ov?DZ"ea(S hacARU8ŇGhUgmy;KY"mj| ea o ,rlk1Sq͘. ,4qZSҔZeIPD%jș<%IYahwvDI*{Kx6sћ?OoEa'J\t|a̸A1wZr_UÏ놊piZ$oVD%#Ux逹n ^ g׈uI2 Su2}m!*deKvmbeTG(%2LImg>@k7_bk41(b&a\&F# %* *UAoz:A26qI yIb<.tր>(<+ɿulOU\qk},vm;񽘠.pi9+-I}grsu420Dx4ϷyDk7'1 8:;T+:WᙄB6)3.͉:M !v1lup 'gjDշMxcjQ '6L&I292J s>5L.pcSx1|yNLjoDAMH( f  ߹kU*ZIyTVdN֐'$e*6WƤEmB(;p-_;FuiI#UGZDم t=DloU"dF[f^7ؚI B[;ָO/ n\;!)#lkgcaN1fyu3=Em2YF݌|R2䃐,Zu7`/k˘&&G!xBz_A={c@) df;0)[Z2\G[1aw+G7_E;Eɍ[[l O 4zF׀'4;7 qD+ͨsј!<|s1 Bm(m4%O(7iL?@PYJVv>cl^?"$ddT$tW`UJiQ 6mcU&Ϝ>6Dx'Y Czf_ GO?~ᇘ -w"_x_LQ~W^#?3FR*yxs _Ҋ`@ ױ)f0̏LWW!@2(5dZinB:@* ]HcDQ%{w൚XvjV4)@!1h<8B'ĭ<7ZwVi8]pesVZcy*7\5Ҍ' t=,!}6_"=jC i"}%-0@+=Nq]IIY6kN̫V&]Deҏ:-rj)y1@u\*H:EWbZ),2#68?[Uig*F1QJܸKhk1i7gjVxFf$#r,IjevP-'ؐml;HiOgs&vm?(mP7 4C7*u{PwfLdimz>>WPۉBmFl]\`rA#.z ]sJ⑚u!Ҍna |@OxQlYJqp,MкrW/9p_xT8vli3W geԧq6aPStq9'OѬWߒfhz$et3~R*r.#1mx*i ǶMVm#6E;]`ҚBqi)Jv}[!6#\ZGu衞7 T*5DJa?x1 zx=8a ^Gl]NS9e:s?BVSH!72zYZ-;Le&>0s|iID0EtHn'cZS60-Ҋ-:K ^@c#}* I:.Wf(F}Qsk8mLԫ +\kPn6?4S^\lmن T`o cRFE #|[cbqw7s,iI-T}@QJ0zH9 Pe%*FI:l6I2R6xk1h5w7 mT[_z+eL6Ј!>7BJײ0e p}; a吗>NДfb}G1/UIN524ϢG#Vx(/o\67P:F@s3WNzh'F,mU zC]uGԿ\vu^~ vC`cG!7Z,Q֔E\Qn.6AePDmtg$Rbņ_3fΝaNY3Hzt5 CAS69@)TʪE d&sާ}11^`Yv#ce"U{ ˥uwͫ%$:v'\:Ǹ3줌:)nNJYEk orGoGHdZK/\< TJhzVdCӵxGcti~6׿3L @TCN-KVf-A[ p`d$cI1,(NʼnG~O!NbY_6+_\`ڇ;Zi~qވ8٦"b"U=G80yD>xUKB$}EIz BXn8v*R;|UhF2ݬWdQ;^]=w#FcVX&Ff["6fTǪWW>~wߐB,=[X<A=c94WY}˷~=Z3Fă PK98-S̜m-ah[oBw_@c>#$tm< V{՛/>bH?F}NŹw0mPo!-I{*{42x%Ƚ+քq\zDL lz%Ugti;tTE1#3F=0ܲ/-(Jب2hsl4X%tAiBPiجZ17P=2| x%uWҶjS&aKZL_|'r + t?.<ƍPb3 KX%b'DJBh WzGKYWZ8UW 5Zō.gaξ}cp9UQR , i%n{>|;/ty\56n y% k(Q 3Go9_k?@C,c縺ʰ NS B e^6[x߅OVjC$w=Q;7G<9EY*D0eHIS$\^S=h0\A#fZXGh [Uc죺81V*^SWhR%77""57@ f|}Gwԯ_5;+c>K;e.'.^`!KGAm{O)p8~dsUL\z뛬u w^~;7xLv؏L>*[s\:;ukUQĝ2,sh~1[[PiX FŌlF֩P(Ū)P"H E0x鳈>qccW>0B[MjRaa0O7CInAI Ā아h'ƝuB`O#bkL)5RD4a\5eL+Mgxm^ , (NOc{JF-$D"c4"%[Ì(i" cٸZ}Cx\R$F#&4`syw,Om6o~t8Ic M5~Zi%>onkZO)x.yGUX"פAI"5_Cs*ғL-<ݵ1e~{|]떼$et UJ C ޲7cFJ9A6h#9ޭT.۫/wvLK]oCw^zt.3y@Y7,iѨzDmֶ!!n ]stI 9|ܑA:ڬ%8#Ңjºlգny`Dʲ ix9pB)6;15 d9ߦb`m3'jrտ\e1}Q3Ɛuh=ANL+ [W3 ϩw~p/p=dפnBV9C7H]loʲ2t:ݠS;;w]©YdH0 I =tw9,%ZmYhc}\+lIY0U#e2E`v< nQ[3 !K%1 Y6˛H=LKqv'A.rYAyU]Chm tXĬPkZ0I菋{:VL|~>|"?Oi0--tHtv(,+_v<|O\~M2c9^<&O oEy=Jphܹ}:k$Qò]ELq# 85&e)pS1hutEY^]\g4H.N0 nSyUXD!0.JF[+i~TX\GU)\o™Esw& 6y*{h3F#xoYciIg406N^WJ3Xqir|8YFUnt!I~$O׷I((@bO#kVi>?ndWrv}T'n` (1z@k3>?'n:~%59 Jx%A$џRㅿX7S6_%ĵ'PpqޮI }h;YZ[7:,MaD]kUh}EĪ4w,FMZv/h}rknj^,jK Gev![cSWzn_w^I/{:y6c*LW|rߺ*w[~Wd"f}]")͆A8!|C?y%%7(˜,- )у-6^vqqN'[w}= ֶɶo7ەеiG.jeU:+L̝{ /wv'PV7" Akw^Ͱ3U<:6ڐɐ ue@iRR~^2L.SU*mehSlF%TjY%!&"ͰQ_1qv *>X(pA6e H=i 1E[P()rTRi)Td2lQ,!`R@bQ-f-Q 0( 5+F襊a?6+IG|>~ s޴e^YOINHQុ0im'ϲ~-w|<̹u +UA0*9 F27\9~瞠9.2 ٿz:Mt֧,ʢ$BpL$4@`[[*yP;J!5nɰ\G2;+*>p?ՐL,&)\cZ^ 5^^loy.>1icC542,c!Bncz,2 fjKĭ-E/ my $畭U&%1(M`ԺXEWϡ陛7yBR`aν=GJؓ5|=duǨtfa,FTWα٣' YЧff(Mɍݗ)ƨ3 ]:CB6vrb :)h>ds|q#8^"[<“&s~`Tzvɱ5jq-VڝC%.4/nKK0ʔ[|J@y#lW+F4i2ؚYK$5lhbXi1y58f&k-f50)H-h/g濾7UwvmN ?43ߣW[LaPaB\#(($j+gK_7~ e3ϭ{l7$ҍac [8pI+sysOHʛ0r)G 7con܁9%5JvTE (bdz>#s.k=n?Koy Bm4xT&YqABj$ɑg矦Ԗo x>ck4ϝ'vZZ:yٜS:yc$"3!iM#wSHvwcD!b-̳<ȯ]Ϟa|l'Xbz͇&}P` /Xk4!s0b* -p|5n]IߟuF*6eôpk9 pլ?7d2\>޼'5RIjkgYi!B9=jףZ`s67nN1yb.Y2.Re@!"w!`jQ[W>P*+=2")%[.]JKEg!S aTge,/?}jTF(IA | ad(\ tIi'* &:1Ǫ();^&GaP@@JQwV|?3fnu_{X Y AHF?U_ů+|+Gg:0Z31v1L0hL9읙[O;; Oٹkons}DYq ";"\@VUZt()o}M^fEkC,qE>~8ܳ_`-imm[-y/RL\F.SJi<}dl)m̀5sBgd(-XF\a\ JW-B>voۇW*@"w3^|_xw8jk-OGzǠ<#봉!6fHI 4 D꠵!!p:yƄ7!=, *$"Zp]PKiciN0 /X+N<[`ΘŦBK!?w>W~ x~&G_1xT(tFl5 $|Y_Q7׹zj/c>>cX]ZL A ~\ed@ߋ8|^૿" q7կo7Y1RVe~jiAtw28ŏ 3 FɄ7Ơ\J*\zV*]7Y t3QY^Rr  6ZYrǘ+,bG <0ɹs,ކ %t11n2yRXVG ǤEzBAHmca_0]"7:t3MA:(Lj*2pe%I/wNǐMp|^]g[\Q=@ $(HW!@^y2<4NpGuXLQeLj.e^JRkBfp5L]_돳x2F[6.i/:ѭd" phbB0!1DqW(#=ßKxц:n-  Y <"I%=]c Bj !⻯5ƔƔ~YYV!OӃ#Oy0"jBoCϴwahä <[FP }m5%%$c:NG3C2snō2S,*d4fyO(!JfOFD)%Ѯ !ҕ̀pC ʀQAC/}-)%`.vMJV?[7%Ü0_o?0O}~ h#q_6G ".4 8!7 >gkl$+(gA+(2!1Ny޶`w7zf hFʝd$eBRP4w76qC-U,㠤TR?__,JQz=`VP]^)}8K5Kge6.0_y#0֖q"| <٪U_nz=z?̳?0H= Be[z1M]mb&! (eN g6g|w=֥wk {&M; [kYiDgNtnJu2;JЏ8-t}|ÎcxUB6'RktS3GM6z5[@J뀇g'7Y4]^ppYpqzh \ fJKf:û"&ғ7~!)4)f;^8ӂ,ȰMP@Yf/eS;brJ#8乢s9w!@5Ƙ0E &gG@5YȐ8@Rk{ށ0 (1ڳ;ZtYPzsp7& w|kw }Bpeo 4k'$aU0֙}HGsu l3L}}6V&ꩲUDSQE~aɏ7*x^#D8 4j 8c=Rmn>gcTۨqWDQ;^KIs [Y;}k-.i<cRrr\l[&۵W--3eR5o)Fqqj4*gH! )bM3E,{C~-6߾x-tsOv$,^hk{koyI'pa(U/Ux?:c,Fp4^զX#KdNp[TרwBPmT[yW;OKwnNOK# dӻ wă(xw,\Ic1;mL:YEob!|nޗO2 2 {]]盧*zU!I ${ۤK4Fȹc~/v{n_ŦKp}dEm~X4u5iDD%8+]˙[֏NC^fp9[yIzeǡ _RX4[<0+/1PzD*+w 4 |\&u\KۄC"Jq/}rϹ5k3X&lSZ_ g_b'%/-`D,??Q㹿wY'?_ǔxmm ~oW3Õ@!}hbd,L'e s?py8,_l@zޭ 0?ƒlMf#l[GZ^U[D<@`ksV+fJ`8anT_!sc oSn$=ePؒ (=0݃ %stEnq\Z E7.!! mлF$+C1~git&Egb<|E9:~ucV* A{/|ʣD{Fb-XJ;ey戳1SSH@+Ni͞(RZZ.]{x{yFσ]uLvTݏɔx2f#Te6 qDo4 1Ie7Y^xyBLHd&FҥyMc6x3;= Gd{,/K$i!7b*JNvثVisZtD:-&#Fg\oۦнޟoS*Bj\(ltƘKv{! yleIR)yP|o K9{-QdqBW*Ld{S@]GVZmQ#aLKL)=1̱e=(\t!,j@"ﭳ7as`r?Y6Loo.՛ z i70|y!i"a+oVYfОbJgtvLfc_$$ٔRx3K p|;KKq!N<S,C2 u98t:uK S0{̬8SOw 3ݛ22S߯"=@)-X"qH41 !j'[<xt!BK6nUH{=2].9֭1{Cg$g:.x4NICXS4ACAs0ˀz`"Lb0:āBuBHqi%jGx%:0 $e;(IXwgV]BRR 7`#<evT%ٙpMS zAbQ ˄ s"֙y:SB f51hI-j D3)I#݄ a7H!]٣tzh9> H[B9[5gy]Uck- KXnl5H6$)7Ha5ّdpr%(DV5 ;6h HJ8'IJt@L)$5J= 8Xc3`#ܡk0G@U fZ(2"'x5V*'@y@*ީK6J ;vDOvhº{' :I " [Cz %St(3w0ziiHCN #iWƕ8и0O>0 RI-Jgׯ)xƣәң!uL ?r3cc@V5ZKLwѽyH!1ZlM&2@P Φ$zĐ){ UG61VJH Buh/G#8_`-2gSŐ`ɄD !l%ߏe)L4 r4i/ \ְ;7,ijJTf<޸N䡞Q)$1B 5BzP9RJ2PCUUPxyF"s-D$C`HhO7*zM%%>h/SՆdZLG]`% }jK{m0߁-0\e3 e* ~ 0)aJt&O8=Ql׿ɛo!o_~};* ͊휥%/YxdV9)F=pm *o~:=+./__gKNM'33ꓤY CPFȂwe|ɓ;@Xǀ1HaĤ>~zlQb!cGxG-mmB2_C 5)Y]:*[-r"g..eC^Wc թ%#W.&wT 6gA;@@,4<|AEACnos2蜼LHpYƱ?{]qL~6 \JJl\\MV+UE9\ãܑW|s͠yb2){'F?ŕYEb@JIWͱ]G$?}INl#.Yoodȥ3? l P7_t62@IFV"-8s$i;Vk i$h) V8G~oG*`", NȮaK6{bd%sr ![ڙF.1u4֠HL8ܹq,Ed GdR;hMK!S\pkLwlXfN]`;^j*/~G~G _>÷qo;٥dDO^?XOuR˿3J`'wtgsy7Lu6_ˬpTa<ʷwg DFħ3|ǺM>ƿ[/>}a.Z3|K%/Ku &..fxLܥ{ZŗBO^櫿".Z-='"H\۟77lz_+_w>N2{tx:%}P K~.RGݦ`Da`lHovSS+yc(F* 3OsJ]{&N~H *2'-"t3)BN;:- vhVH!`EHm^fcpZKd[7ARW0~H~x4AUe)%MVE=Z-jXl"xXB<$ݝP9`do`F0!^振ܢ<\*%9g*G@=8>*>2k-zgHku9mi.<ߧtlr}+i>tJEС{qSMf$%z3] Nd`s5ͭI)YeN/B !^BL(8t)cBֻ=#MFmUw. [C"J41)R3%3h~G% p?q̚GڭGydaf$_Ǎ{h2&% SF^T̶G30>ϙ`xsx ̺`rt&pMB}L # WB;-43@Hͽ->Mx[q4;xؒ}ɧ; |D*,ОR'#AdeMIf!C q~mZt|A=U`g@aFxϲґ4-C ( 5\GkцQϒN&*p+m#(GrA=BT5%9࿹:5 )=$3/,s^1 [](#ICS|ꥅKd8jP8BxsddNOfs@@^$YHlzNF.K{,<|Mq&vo -B Y%a62O9ѱo !0+7!˙KM.c 4 n\uS>b8 Qpdm74;~wukm{8&qHJMV$؈"$# @Xr d  gA$pdm,(rfs8U]}sN>UÞe[ݼ?f>9r#BN1ުBBytpv2<% )ed|~Nޛ$,]0m0{#ȏ4g@olsk~,g_dUhL̘q=)vm3=h@yI2cgl~HOxk!QP՝g%vF|7W?o?N=˿%~W6l;/$㌝Ku^p3I`} noucc;/0%$uoHn$$k-I~Du`2$|cI%/ߤ{/nSI#\bJe_Swf'DWnþHKSO?*[ /7>GClAG*>Mkh4(|. P F)&B-tn迶QsLƽXmZk%!$CF_ߤ{{T/%ȍ]`$⫌GI0ڐf)A)q I2,\O2Aq`{Cqf./ք7>*ѥF=36,w^q0}=6fa'=?aR@]>a4 ݫ]D `6C#q&ôXy6~atGџbɬE ?C]a98EZskXWcOuV94Xc`bs `%rϡpuBb5w;<yӜ!kvW??Kw~wxױÜ >Pi#WQ20ٽW݆{<, y>}> .hoU(wMR}vdF"3m%ӿyfh=9@Y,!t#pՃ_G;p׼H5s.#}s(wP w9Ooo7bc@w$ug1H}twB.>nL٬YA< "cg:;/|?{@?|w|_'_.A]ϠG:&O{X K-}A:Jq%;"Lw!J"ggMsll !"P%'>xޓD[h 빹{kSxK߽⢼ua#vͅ }uvߕe=SJ=V֟ >/u%GycVyT2|6 '"MNu_zeѪLzdScjB&/čLcS3(bʬG‡X6#^|#?Zo&|SOO= [}k-?*nm IDAT\wDVG CY_kf\f\-q|%|LZ,1k͵LzO'x[|3/rk,33>^M_F!O|* ^gecх M]֦zlsw.AE\/gZTA(;j퐭oϿƄSu~ON<.*|2,ՔYQ.>Iq|cO\Y2|7 Lr'J +.'e4 uu:iI)?>w>moLdk O3$ˑދr3R(s?yoo2YP}_ƽp;߆r~2eɌgꬮpGO ,iN$%zmwݸHʮG%8QP+ = ǥ2u7&ARbQ TD U_*VRVXXG(1TRc9rD)*".4 #і֐D`K@J*;sb4)8%VkmQޫ _S|Gg,y5s,]HwY^]6݈ji"$pp4yl#4A1Lt$a#UI,%>ftrC4buq?HaLc iK[pQңԬRTQ(q>怵6(B ?_(K\)-5/40r nK.mp5}RLյq ,R)BJ=30'd()

VO8'Z3r!D&qP.;nvo`Y `)lq}ڂ zcوfLsh],SeBձZ!նlQ¿"| N(grw#USGe.*\n,6hm ld=w|u͗6B租6#H>Hxe^B'H<?Оh!c%#XMT < 66bny@!PnϮXkwv2C!PjMդ,S] gr]Rͧ~O\ϧҠV oy˷Ls;0DS10qa>o|M;HqzߗZ|apa2/%%P5,/+.w*ե$= JIJ?r=WT+.նj\*I8_d(AgqL̾Y0!ć^x>ϻ;e/|uZߋZμO灭>-ha^9DJ)V#I50FX՟{\mEdLN*J00֐e9y/,~=q fl}y\b Yv\~S=ֆX&=I BQr?z{'sntN:ɰ$SNm}Cq5/ K.NmtK!5ttk~h{gCŭ;񩛫H3Q--7x°;ߍIcKŔj~70cCJrj4-{!Ync93b ?;Ϩ# X^кTyq Ę3Ҥ$SY+OQ_Rx>9k肻PpZ^ϰw5O<qBZ21FNzEJn_yrq9]7mä$#n "agE9q25*jJI)Q^&w|"8p0費`Lh"Q%,9>QT {)1'z B/gq#I%27k*҉g だ? T ,! s>{{NXR]fyc,~rnLyzVB]kcR]_msMgw[},J0rN}B1~?ܨ}ɍg]pY-@ !IRGF6֮\ծwɈ[B[~` U}[JM$ mkRjLP.!BZzAM>QJK_VDU/tvX,P-]mq– W)ZH,5'^XZ@)Dd,/WH A8CtU1> *GπkAw{I5:3$xGQ )C p#IdNI6$di@ &"*^0R:7$;:)PR!ѽ6Ƴba.=XkIc :HlVBteO_>][)էoha2WuVR_=RJ` | m)TEӏ,(K%i6,)I#3X" !Qcv!ǛkS`ZdCIM0I׮e9 ߶yw .:uK>*So0t$5v;J MD7zxa`9YTTF Fhݜr7 7⹊zy* aN$&%S(G4,yߤ " ZK#Y4OgJj(Or>מD\9ь6 : LD4ՌfOEMk v$i$\]]G(LrK.Sj3QB./Ѻ>;\Oȍ(]ய$3z.2YJ7!Ha9یdP/bf zxB%]&RL%n`ӹ5Ru} @J YB擧s}SJbI=pA)@Cn,`Rx3fx! }g, wHB:廯$!"p#b԰Z_MLwܥgn8Ka !^HܜiE x5F%jD1jG8L=VоTFMk²GLF&ו,?Ah:Yo3J]/1tcy߉eSC~k1I T1'wz0s^q(vcX+$t 99 WxU)5g8bx}ḻz:p.K.`C/r,M2]p$!jM$C7fBu.?XKw@7aT=`q9e1<ăǙOAk-ܐ:J9T^sTk.0c|{xat} Et VOS{B뾺Ij ]k*rT&Yf>.+ML04KwbR+jrqXdX,mSIY6a%v$a7 TJg Ǖ!Un'$F'P*>zB:Q#'bENU`j};H\cTj0':%t3&(gHcLcI.IHCZZ}r?>Ͽ;>9]z A\Pb,H E)m>5&R]|^#S%sН>a)[$DtK}q )'*@HdI2 6-]HOk VOԻS mSuK.70d{0 :4&4X!枈B@(zʾ%9%tEQ şyba.YpˈҤ84uf'/~6X ]:okL Y_Z=wƖI"Wx@,Fbΐj7 Lk gTlHR9w=V:*2x%$C[;QK,-WW/GS+*@9{0@Q]c G^tN@^%,"#肻X$!X K5D',F{}reCv],qC6oj}>< A:}2BsD ǓDt[Zu묭g$ a i;GRnTL$סr͜[8aĸO! r=u TZt<:qbyRH*N-NɄ㭵&ČQ~JddDm Q]].tog%?tC&CgcD2)5|,gS~m 5&`_ \-NpQVRюЙ*ҝ, wUhq (O:ħXC? )xx Uy;8#HSƣ!^$ ~X3@)+%A9}sjeȥED9~!XTO EXGQIO` T~I!i Vu-_Utݐf-^T['ZX`vApRu]a~QHX) lTO|1o~c,$㌢|:[]ŠF)I-q%9%=(xg͂HB*x[tG.RG*1Ee:+˫qLjYs;~ D90X\Z{=]̘Я"Y?~I=3*'8eԴky`DAT5\'@Kn3?WSba.vREe3B*IUb]/qPwijH{ kkktp-vHoµW3Ri>yzիՙXC?3{TDc-JfKjjQ~ꗰ40'D -q ylCXN`FԔd/Oy)i r!ϮRI6hӬ$ד(W168aOBglaT[!HERϛNx@gYj; R =o<>oScv6&wIDATk ?0֠9w>n7VJq?8lkq?'%ƃ.枱o%wƄuUJkyI c,6zJT*F[e8gH׸41﮶ä1*tt 0N# sd}srS11cƃ.bmŌƉ"Bķۘ0x }x`aO1b+)QE2Q,OOzhͨaTu)7Gʝ, w8l1O#M<ی(yg/2mHBȩqhlY\Rbv7X# jLxIRNӜ, Bd}FEV<[Tո+~?bv%T6AR27 fe[I78@@Ҫz':'F[ V(W 7~29 Y+j'qqDA?H!M\sQo hc(7L3gzKc9gJry΅UX^ ?9/, wHB*0ڐkCXFq".wZ* Y;{] [mPex،.omuXjאgX*VTɲQ'C:j<ׅX&&fk_DS[kZ`;kAvȽ.תN^G?}ۈJDa)dR>Y\uQyI'vPeɫR*#gnZkɷwnކnH;c P*9TAti!=>nؿ9HӊsX]`hm<.h+ t],RM< J !qNާ6y _Vx\OnQ)%Da%6{؞d 񲈵 -+$Iq\1GS2Gll@E i# aμaeyKRO'UlnDz_Uɍ(:hz2!' !J=@wjD% D_}{)a"u<>%xZŵ׹)r4Yl@|wT"EP p䙖`= l ^z%=כoqg?⍱$}Ql.|;xZ1m JwaH:~9|[%A[lY~C9g7iAJfNw?(O@x))11Ni_TPd-m-p2!9i7 Ǡ{X&ADtF 7~s$C $x1]2c,qWsq[uEXQSN5I?'h~)&=76}ָx5ʓ%9#-oGxT G !&P3\0Kmt&?ާ{wsRAm T[xq"7@^ELﲓsZ)`%LФLrXe-ڕPMt7vr@BhV 9l;{i*Uڡ˛N| УT`[;3ϾR*C:(Y^UYEX 1>M3;H`$%V7wM1U7.Qk$z~yRLygb / "hxۛc;qy\ˣ6yk?cF3>ւ'a,Ykgq 9h3Y9!Dl}q8o|λ? ߙ B%X=a['Y{wmEuq(T !1$F1DDѮVJ|chHeEVd$Kc*tiVT)XC V  _8s\>f }fٳc0>=JRѥu O"0 I''77o$L^i-KŦuEV`bI3Ynj BMN"KY^OxO!mGV)>*oN~EQV_B>^3uR'_H?|S,~.)[n4G `B2xp?k)}BU]]HDlɏ4Ƒ_(䯖t p#ӁOν~>Բuc`~G?Kgʿ`ONn*wRI{/}󣪉 |#y%#OIJz="*ZW6ϖ$U'Iws'/{FyUI#bNo^o*EĶ "FąsB~T2?kT]/!u8b!߇nI<6\>Jj1 |͏/3&'""Gѯ;++һ.]LIH}EΖz^?~ys0$Z%ibnx]VfdRD̎/mS,=D^H&6?XHj:Z'i?Sh"WD,IG3DUN_ɏ둼QZ?R/H(ZO'Tv> iDX<ҿCHxݚٮfi%.eW:P33ۥDVH5!iǙf#x33Iooe>D 4{D۽Pv/@̬R-Xi=*"rǓ^+`M^_FQA E0Q0Ij%p!p`o8? xx8 OI 3  `Xև48)m%o#>徜BX!RJu tp'p+`Q IH׷s\!}H]ƓI,:`8[X`3w3D/^4e ; ee6UY'od[UJӷ(]^#M;4'O-sjNVx|9`h/ s'':v  nj{&B@|1}!{58\B?@I>+stN[RJxj[@ͬ # dTpNgDQ4=">OscqvD<]Ky7N. wfDWgޤ# (M!k"kGmù\{# uY{95*iIiMB]V >kpȧ9=Ч4/p{D /'Q5{vMV;_or.ψV"RݳI]K:Ycfb[-VwR^&w:"yyuxOlUj{a`h "4HH"mm̺fV t<#ޕT_,f?|4.eOfOҠaTDL>M>rMd85V4:Ib^ZLTL8yUkћjsVH|}Lґiv0CIl6ysre}dfhfYK3IoҠ⼞$i0IOhr ›mg@XCvjOcI%iۭPx45o~S҉s 8l#4TR FkJ~-WRI7 .7:RM?FA_O ^VHz4愼T=B`L$MDxT~*#=KH"hJ7&`Oz IˀQ o<2Rl-P^+igIsiE xAC.'mkfZ&ON߰]HTRKkDQD,fsi\舸\8"^?>Iw;jC#bSgT,".&Mt7U M4 8!"^nc[Z_"uvDDnU"*kKg~A8T{[X=.z:3333J*************7FtIENDB`opt_einsum-3.4.0/docs/img/path_found_flops_random.png000066400000000000000000023644101467526163400230340ustar00rootroot00000000000000PNG  IHDR괚sBIT|d pHYs.#.#x?v9tEXtSoftwarematplotlib version 3.0.2, http://matplotlib.org/8; IDATxy\UBBA$BT QD7uQg3wG]QQGWDPewH’qMJwUwUWu<=uoS{9D$I$I$IAzI$I$I$IR1,I$I$I$Ij` Y$I$I$I@$I$I$I$dI$I$I$IRɒ$I$I$I%I$I$I$I $K$I$I$IH$I$I$I$50,I$I$I$Ij` Y$I$I$I@$I$I$I$dI$I$I$IRɒ$I$I$I%I$I$I$I $K$I$I$IH$I$I$I$50,I$I$I$Ij` Y$I$I$I@$I$I$I$dI$I$I$IRɒ$I$I$I%I$I$I$I $K$I$I$IH$I$I$I$50,I$I$I$Ij` Y$I$I$I@$I$I$I$dI$I$I$IRɒ$I$I$I%I$I$I$I $K$I$I$IH$I$I$I$50,I$I$I$Ij` Y$I$I$I@$I$I$I$dI$I$I$IRɒ$I$I$I%I$I$I$I $K$I$I$IH$I$I$I$5HgןxS9wuHtRUK\$M K\q8//;e.!Ij/eW._:$I(g$K$I$I$IH$I$I$I$50,I$I$I$Ij` Y$I$I$I 2m$>?gHgp;^ETt ~]ʈAIo^g.o|*":ʹn]ǪkW03ڧlK?y_:*"nK?}@DN꼧nYs)#A޷G2k48#Y$IF4DHٙoAdܔ_\[y7vm}3;@ uE7e扙jP837dC?W1ꉈm@Xoirf.̧ﯼ4xȟnT$MUt/ܫ>4OkOSq {F $K$I\Bf~i2f+GFĎmYn \ <<31^gle'~<,3B_Rl1apRez%JjY:F $K$)%MXlAy!ijT$ME/ؒ.Cױ|0wkVR<8ն>@Ҕgf4kt|Ƭ;lVHSdI ij*ŗ?l> ISN-#9ĥ]F<&3n+ei=Za I]2}n;3V*O*sHj^7@$NDܟrӱ3e$JhK2. ʨ5d-#eۀpuFQ;0kFXOُr6߅@yL f4)[lC[:)Ѷ*`Х:()S=sj *3Fχ v w wfv\W+޹ UW0x4b`7Md_dSD xGf~zx6{: heeck;si>7k}x7`= 8R(8Ĩa<93n$5X l^[<~mciLD\=.o7m33&y*pF]ы3Su ؿrh;Y}n}i[93ED^ #Vv?>7^mԒE[XWu@ɰׅgl2si\ O^?x+C<Ԯ+if9BX[[S4#mJVv7"oM%Mj`ˆf;=Ma)@$`ן3طo{݆.w3R aT{SOa5𻭽IDY;#7 (ʈ84ìkW3 8xJD|f]'bAY5]|C* A$O1(ާ,]0%,]0,]Rfz:C>ۚUёuW}[;a""N yh,Ϊv튈/3hp4ptDxQf^Ͷ’3Ls3LSyyj3׎b*tNZ %[N@{ZVߏd;юa+8#*<xjD ',}O>`'mmy}D̖@ӀZc0Y7!ɒ4}I3\F#"r8mx9a4a>#yp^D<)3Wr@D<RkvdQD<`CDxw`}C砷Ew2sBof-5o*ok%Is@JD^FI9ze랔Rf2õj؛Cԕ]| 2ufl2ts֎]<> s%Gh`s~OSnWS?~]oNk<<#J)⎣gP7 (CiImqϷI;x9['ߍ3/<Ӱm>ӟZy5훹:FSi "_ |-epAo$bhy#sjv?{Q_Ŵn34[JQ3؉@KԂxC3I, N솇1t6Z'YkRԻ VZP¿c&pepM'Ї( ڙggj}FޝC)YKw-NKR_mN1ΉcG g$th 2,IRooV +>Hms3m{_QִPE9Wh "AY_+Mx.% }[]s&"gxgy&|/"x[o]o5R 꿯K^ՠwDC)geeJ`dЩH@ *4 >"N.dK`ಈxYf{+eX0e_l&Yˇ#rL}%k(i?| 3ojOOF(zokwDÁ+ş^*( <)%."f 'b)}H3Oˇ2ch(U1Q^5?HsM~ }E],ৗv]o76i$5n>`]%=8dY1Wg193/]bc)hoZ:Z @}FDweK0_2?*AἎ-Pf d(;f ^} ٜ<<4xu}@?mDbJJfA aYR1?Rn+ 8;".P22 X "[躺vq5Fid3,IR{re;tPf^GI=hh[l' z 7ӷ^f_WHfuKI=h#̼澓ύkGđ Q|1%1 [[l1Fwj+F Ji. Gt8%#5uQ{^Z~VyQf+8i  WkG:(ɼO^Esp % ʗ@Rtvo3>BYJwDf.E=fz@$Imv;k)Vef77V?9zN~njG]ǍS` M[yFr.yyh-%mLvyw1+{tjpdD< H}s#"+刘NI_?q -dCo:}d_a|#.#idGNYٚYt7oQH$RޡcؚRF|b2z6k1ݨvJxu]|RᎩݬ>RNKR'RnFy/Y4-Jmd\};F#"Y ׭oWmOhw-% WWF#":܆Z){CfVC%"w#@.o>݁qnRQU]Y]jRvAǀm?9"v@As\Zzg*stߊ'RxTfT8xw4ރ=%"\42̀ؑ$%@OV=׏Yfn(KI f |?t챘 fDfe}z"beQv 8("׉Pq8_QRN82;,"vcKpu="CY+ޑ2o yksτzS}@D{Uwp:pzD<W8a^,gefum_F@$w}^?ty̤y_ؒgzFX8"R<#:wl7;FuVڶu-lR6n7ԙ[f{O +<=9g#/]5,m+t}."g6IuAˁE)Wᔴ ]nS)"ɰdo"H+4f؅c32:kaYvʲIn^r!eNY6?dQ{0}-e9OFj_?h9}8jB 5sDR>ONa| 3Rߛ ވ8gpb'}C_|RfS}@m@jZ6O׎9S 򇘢oLm-IR?W_UTDLX?:!Niv2uԤ.տ5llZʪmإ6ISٻ_Wmmg̼2 S]D6sŔ5̼2#ee瀛"xM2WFq&$"f_ *̼z;Enqpv?_Ct:e&tEfH-tx_"B$>l FoNiif^D?Ya#mdI\f~h]QP}="D@D'"#O7/+/U=YIr6p{8~131)kb $3ʱYe\DD7Ԛj3*.dSFJJPmS3ݔwgR֩g@Vv[KJ\MyTbnrj۟dN\YM;4<ɒ$M 4))OhxVf?v1Ɵf#Au؁z"3֤fF+3?ɮ'V'gZk1MWFͯj"(Z'3ge-3d~7WvEYsZ%Xfr]]Qݻ(K)O|))"DɨT?jnXf>3wz"3Wf2LwVv[|:"I$M^n랣B4%joy*Iİ [In!9k#wѸfd75"6s04Mx83Nn2غ_GI%3 ^6GEL-%h\OC3u޴uyMm>xYϦē.l'"f*@zW'f&XEs̷f͏u IDAT'`oJ0z?GJt:{5%Is5o uXOM$UФV3iX>@wT'Lfje^El"b1a학zoMI}@_Pf(ֳ&.~aӧoi%Ic 7>s- |,"Ԃ_DYGˈm^W-8N}\f" MјZhue{x{nom724;y-w8 >8ifh?L>~4)Q= D&q/x;uac)@$Imfe1'-iQ- '+Ňﰟ»zv,vbhR4"ZZ+9"86S4<2>nZk{۞-7V;~+^|c-k*ۏ`bZ>"%4ܪn8 ۩WRgD-?ح]o@F8!`^gMy7R^e }c[9(" \ ,Ewd- h/1tIFD"OPFN~?ӘXu7ҡCICez*.' wlDEIxrie{|nUe\;׾YGVֲ@| RDk ~8J4>}pyD8R8rTq~f~kD9o[y=VE>ఈmJ^EijsDgP:N@ٽD"b޼Vl{Mf^>J2&=EFhޘj>M8y)I궟<5"SnCI5tpe}{V2sUDئQR( ,<8`8<3>L]xm$`yD[{*1(AcْtIDwf^7G{)h/?_ճH4R]Бq{틙:Im;83hw܈2R@9@g04v}gX)P-Mʹa|mWWQ;ߟNYʹqI4kKڬ࠺"uD>H9zڿ7]#0;26)gv \ߤd*3mZI&,P^o_yzঈx o}?Ƭ1[̬1)}%">B.^E9>kfVJ#%RfUmk}24w e۬1'Eķ<| ʿ9ZVڲ'eyk7FIÈx-WseqQ,>&uwV=D2:)ߦKAyry8oߧd7$M%IK)oS|mD,?uyeqzuzʣW[ $QD<2;n,>zffzVDѧFOdz6/m6|2HYaS1JZJo|(kg9ptdOjf^Tw[D|__Gϫ`z\2SJf_Eļ썗R<,(}ueL$)3E3Pmݝ2`a}QWւ@ue)נKs(3S)?5+)|my>w{徣~F@ ]G11=[m:}@f[x#֑ 3.\h 0$I}6ShS\l5$.3/(C2Z Ѣ04xHSiՂoKaD|`f03.;նÀ붶ɼnc2s%-?2" 'dke7-껙M^!3)kϽ֎䍔SZKWK z%mٔYKf<*3?w&3,+s[?n. (+ye)7P}6ݍ2|V߃Ƽ~G9Wh2*37dRf/d濹 vd潙 ߏS R,ewsMh‰>^&I}^ΐw.겈؆rZ/j3;n%~tNNkID Pn2CY_r&ڃN52rwZ]ku "3oP=)A](\\T;ƥu̼[u.;t>2Rνk(Y%~71noP$3;&"QC(6Q2<"3;9@L'QRN|Ofݑc_J?2xJ%g.r^^v2}("SG>r- %TZDlOVS>/2s`{mNYg{ʹ:\QAx^- HF<{J{)}TCW.иoK()no,QoZFdI>gSA ~.)y %Y䝙ocoz%"^Fi8W^G]b YdI $KS[Kԧ"!l "h9o?ڶo}FOZ!I$I$i1,IR:}oNeƦ{iBdz%9]{I$I$IdIעޣ}x8p@Ѿz+"f23=$I$I&HIlןxS9wuLIqƺf6h DOfnsC5"#7I 2hZ:$iRXr撥yy)˖vIRx),r.!IRG9#Y~qX+Gļx %%vu6+ "V^gD8 $I$INH2q1к⃀ #R_)֏ koot꘏G#?;0 Ms-I$I$Icb YLB`J!vl^D4. /ǯI$I$IS[K2J{c|sD8"bwJ'#3k$I$I"2m$I-#PRVo? \|8#3wy갈p(%}_fzd2!K\2|{+zY3fn^q@{j߹ezX$I$IŻo/rT K͙=fm`ݦ=|WNs񚍷,{]903WJ&%g.A2ءp'p;p7%mNYvOQ~9#Y$I$IҸZ~JjnW.7$MDKWmbwl4skgܛ雷_vm7ŭfʹA$3D[D $K֬Y3̠kϟWی&(vtMCڵ뮻]:_?X֬Y3{ nYx>5ܞnw% 0&(vaځmu-ya3_[﹑\^QҘl}kV_w嚍kVW H4Y \^}pEڢFی&(vk$u}sݺ nl?]sTǿћ0IOG>10@̚@`Y/h~i"`3bͽߑ;atڕL[$Wrp]/쵳nl}ޱxjN[|M@Vʶ6cw8&J.I߹d9is?en)㣷`Og`ΟwL?*~h~i jgݼy^?7½nsf%Ef%I$IkkkHքSniiXz̙7̜>9oq+߹j{ &K}m:?֋J%I$I$2cGdP+~6go/o2~a;r= ՂΒ>djkIš5kfSցt=;D|ΛniHvuמKRG5ܾu+X6o|6~=׬YsT'D|}Υ6=>bڂ=7\w~{]r7_~+o8}ǟW?޵Xɒԇ $K,.>GmQ#mpMk;]:ǿs+oZfMկWmRh=я1@̛S;GMU;d.gm}OA.W~kXaś*{Jnw ŵ{ &K}rz3llT/Ƴ67vwök_:}S5V'H4Y VVf'w0?Di_%s;W':m<1îec6@qwxu+7tg.S;GMM;d%4[/>7kݴ~ڪu097mYk6͜ vݰa6.nU%dfsl0c6HSN-.I$I4ޖa]ZY$Pmg޽q3{V&ۊmr!qH@ Z-J Zh)'m rMO r!ᒄW*Nd[f1x-;m}?ϣGW3+o}=ulBE%eEp|צ3GyG2E"w%hOpaLT7=Y~TAhc j!1 %$ U\I "2,"C70 `)UVDNMJ4Mf`0V+czC.3+ U=UU^xYv?RhohZu|X IDATvd6e\&_l*ɩ]}xaKd#h:--֫TDhlC+Ѓ8,T1* D]˖{R:v?jN"uNȺxlV|XMdRWlُ7b:<%r MWWwL!u_oNKET2ʕڦ#ؔ1sTdmd"r xlV}>%UsZ5UsGcL"rh~y?FCGv?T<'''oy5AW`DdSr[&iX3IlkBJY D&K'"""""""Z" sd"g(J7yLE{,*kg@[@0o7(.i,&8|Yj#JDDDDDDDDD;)ډ~CDyW@@-QE"v 3Eihsƪ8}}qFDi<0`Zyc:vo՜x\P깈rCȺxlVgf5׺&.mևN?voVe]bQ]&=%⑾&H_.)P7rmuE{{g愔6MNDDDDDDU6פ 0iowo{4SZ,`Hs; "H8WnN`I|Xwxsu"Rphk"rM|0灙7 />c:vo՜x\P깈rCW*55zkw^QUp釦ys0U=ƗHH`Pu$˥fd L,.9vydK~+FӑZemQZԥ|4D.YT.~D7ZE3ckxuU=~+:<{|}SRLDNl*eج}`K~j."^R^w7kwkY# R06 5|*̻4/i7$$~d~8̻U1zrydK~K,m=w= 5|©ag("{Fχ߫,^gzdB29Ed <6>t~}ߪ9*9OǧfA<*yJk|r0Б-f\9#b,N6A0 )6@.-3-Ɂg2]'zZ9}Mź×.a? ĊFV%@Xmt""""""H_@!`ޝyWSƣTrD/R]L¼ !!!US͟#GBٌW9NdO stw P?'x?m"u\Ȫ*<>sX~TAhQ9*J)}: +I6T$@N TM|$tL?8 erserwjg"Sk&"G4sy`0[t~}ߪ9*9J7jK< G7Px@/n.Md[~ 83yfښ<<.F ]x n uJO@x鹌L`ޙiw&;<%UsqO>tr?ph>. ΀'-,pkc! @rCUBY=gVi\DT9ΩxY E{H_#=''=2#?s4`iwydK~uU|rWt~}ߪ9*9U#Yho4ut*yrHh*R>bPE;g̩t}Y+<>Krz"[qt% x1H"6'@Xmt"""""""8P>u~6 te% S ;)V;E;E[uP? !9;-~ /^V1%UsZ5UsGc2Ij'Zc! @rCUBY=gVi\DT9U]0kE 4Q^JWd]oipm.4rk]ϟIzrydK~F v;;z,3O~' Y_aa 7! Y D ,5ج}`K~j."^ A4XL^Xʴsvl$Umȩ+Ղ~51c.-3MG" B_+oEȿne"Xwrc ~$<;cNdr&!v j3Bn-- ;h]H>c8䜋D6W@[z~F`΃jbaaWVbdR%""""""u-}w"2JˮH<2?eJhkyq< n9: t7:Ed8mMDi<0 ȱc:vo՜x\P깈r+}/¼yEYuxlV@Rǁ1mw@aϛ&k g;v7nQ->;dvBQL֊|i=BT%竝d"r.e=U) f؇][5UsQT:F ̻懍,#0䛷 YI=8^+dPT$2 _^5 ~}j9spu]7z,M3uik1mD^d"r xlV}>%UsZ5UNUho4y_/f| cԇ\}; ul)Gv?TrL?SONi>ogHfR+j Rjg p6Y:9_/YLQ3Dd \^l- 4j§rY@dysT=<#bj8{"u?/Ym@Wx 6ȶԖ}5ae1Hz?Տj<(R&`@EEܑHm/vJ[PDh.}ω&JU h_ I4Tr.0i䨩Do'KX/+"@x lj;`YDvޑLTVDh9̼`0V:f؇][5g<?#W(z.">|gn^cǞ[}Cv۵4^ =CLgpN?vo7|獮KsmuÛ+ɹ;ǡ]<(d,Q@s/|Qh?Y>Kd?CDNl*eج}`K~j."^bz--E^~!UQH_1Yn WiGpGwG1tnmy?~ĩݽYH#][&綄(m/}n #NLݬE{,.Xw|^ªX / @+0," D ,5ج}`K~j."^bAC_TGMS?:{tp`1xWfB=.^éF]9<%erFRNLOO(LDkrRE4Q2@d_ YW"RN+1uR jRuqhk*DDDDDDd-:҈͏vf ʏZxlD`_rXwX[oQ h A> ?4AdTۛ)BD'&Zkh ^Qe47:Vn&/ ;Lj#JDDDDDDDD6$<w u\&S#y5QehzgxJmywEd"{9PFֶ 1ro*?QOdanXTV޹%O8T缞b9/^ %D`3o0 fNY=gV *Ǫ?d}S2?&)J]m7u;Zw6?|FxLv Ϋmxx?nLd o"#]["A4N6Gt#&D H#k[\::?{7vۧ䦓 u 6r:;zҗyE6+y~#; D]˖{R:v?jN"uN+i]#H y祯Z;S_y&|.^xs^܋4߽0LH_$ހvydK~+lS¨v֎oW]s wpV|X̑F0OU5w&@w3@}'|zn08J N(ux@"~2<"RaΏ`OfwSZ bv *ĸO|9Ss5|V?RDDDDDDDD@L}Ca./׮OM+QOdKၘh@%_dʊĩQV@Ryg2gK] MUR&"2Q5܊ŋȣf ͿYњi5hj 3ژ3S9r,"H&} 4Mf`0V+czC.3+ U=UU&Jwuy =oov!uT%Wfn{?f.q9gx qG#][.g5l_9T><{GHL>b]ݾ7<2+Gݻ-ݹcO˝:6ߞ}!;j#ΑL5=(|Jq-8T,t:c:vo՜VEDV =o,v恲kѧ*A IDAT~>Rd4ʴ@n׮7ާ7|cc8s['gi~i$@!Oq#٦XHx낶Fd <6>t~}ߪ9*9Z&IgMD 4߮L,sJ^P>7④#_roj%^P,uydK~L8.݉\iF*~G⫝n[B =11>-ɹ9sg撓J|=- A6@Xnh""""""H_$+7Rdsl֚ll2c7 &"M+->(BTsW, Ė]0uNNіG9hcRjkO}*,"#dN9"t&Ewh(*-X k%EdSPg ٗ[v?jx<~FP(T\DT9V}!:֋nlKy1풩 B_npqyMyMi/`0fgV鋸/V zk;'SdaLJDJfyЉU;%@U>\+\|4^_d:kd4pX 'ٖXH&GB@oi~  @rCUBY=gVi\DT9iJwjVDKZ/0;[$2 3II _@L0_49?ol؇N?voŜ=wߙr=9qqy\DTYkur>) oxM妐'El&6\jdr,!D *-%5pp2Yv?jN"uN-}wTDmGg_LlYe(#~iE?ܝ:6f:<%rƺ?-=dο=ksF+Fd|"Ss%DT!p=O.aկbC|Sg1$J"(d8= )W49Ѫ!"0y0?8 '!< oRYj;(͏(G~=QĺYm@Wx 6)Ms`N028v]ՏWJ[q@ lAaIFJB UgiqGVh`)-aӋ3|#<ޢDdg/v>nʺ74o 5p駽LT!VZª@*- )վ85Aq?8p*KX]ABQJ9:N}PdO`3o0 fNY=gV *Ǫ?d]h:7{oưaOi<,ʔPCou'O> m#][&za(JC[kN+E7$BڑxM?G}Ώoh|b7pJ4NCi@S@ ~C 5 d `7qlO,$ .p-+!,"bN WSz)l;K)d3]˖{R:v?jN"uN˶\|7|?s #5 ၘ$~A'X#Z[n\z>_ ۆRCH_d# g[vcn/}'tc4}g;sźAp1f^ro @ώۮi(PC?9 slw6k !9Z!J)/s9_>؃!ǩaJGCd <6>t~}ߪ9*9H\۸ydMƗ{ϥVpa.zsOޥxets*4 ?~}쒿9#}wsKsT UNzFj'U|z+Ӳ7w0 XqEI&sGg(g0Wy#kz|IU"@U$sR{qqN)e,`5%|'! Q.KR޷`wfir6Y:zEФFS.5Tl¥r  tW2E"usA6UQqhʣၘ^ŸDKX@>^ hũjw#ZHY|UN?FlEdRh0;a4{Dd19Hj)X ch'yW%ݬLT KXJsEbu R r^6š78)1PBc:W}!D;4R&uDU~W1)BB@iCZo@`3o0 fNY=gV *Ǫ?d/ya. x<-vydK~K,R1qM߾μ.u(>ۆOSEG$p_.aկbkaŭw㺃9#:>+4r kc!,'[/J)_B|{?\o>O !>YO,Ȳ.X&kY=gVi\DT9ΩxYͿ\t{{rz&Ne'q kyUrZ&(SuߔJ} ߹gYVLlϙBePj"}L*yuR85kxH3 5x-©~7ZHBJY dQgںOJenc@sYӇ_Z=?,kz\J7,ֵl҉CiߝI\!.n4iEO)J]0fz]B ]ǏElgoXxРSs! M⩴OLfJs+9X~;i!"2<,\GJ)'fg/a}tEx/idww)U[ܘJxNQ{j J=Jgip<ȶ懳T9. NɶH_$kh>ŋqKo"}:@*-UQ#2!WQG"}u{a!RYږ;}0>2 | SK٘NRXf(M|0灙7 Cج}`K~g BUEDc76i:?aO<,qi6S3꩝k R0 |ɟ)qMU6ʝKN?vo9VonW(=vkd`7D%zkx Fi[iVi[SA"twvrIsH ^B29)21|(+$t/[pJYt<6>t~}ߪ9*9|r]וW,|.#5br@l۳IRhrど'nֆ1q9<%rF{H_d ../u$ ~٭$w)qjU"Zb_?䃖FiY Ҵueݯ冀c'Y4`^ua!RǂG[uB6ƅ W^yP/{$ͺ\`FM.kJR>m\NzB"١MU&R!T**|un~maʒ6ϓlVm|soIlֆoegr3{m 00@:OX,%>l)/6=|oI27LܸƚΚKoٱ`Nc;~y| *,էVk[P+pi|,Y6i-,X^X^"%""""""rҴq.sʕ #U sqyY4se9 :>R ]G'::jy uTkY(>i|iK4h7FD =d.v/ڲE{nT@a RLQKϺg!Bx4MWwڑ.MsZ6뷓a-sW<,D*x$p+/wsN9ත~\^@eQiۢtAY22LKx _]gW۾\|腼QP=5+}?nZa:J?+ vNw1Oz]bj$זS꛺' ɜ7h2QES}ֵ{k#M?Ź_lN^w67%wmÓs>շVQhdZKbJ߭5I)H)EJsY},d~?Pv`|xƩ:,mnzZ)z9f|o黥mlc'f6z~po=[7ʎ+R\ɼۺ~ˮekM~#>4`P7aO2/x;_-#-o8 ף?-s+tx݈mSqO ?Zw^}5'~1I)廗xoY/W PYӟK)?X6)ey@Ӵ6>mePج}`K~g*͓LDaH_$~7ohex/_/h.MWg2[uӖц wm<|lW|hy׃#][.zu<㵛6̹ܡ=}g`1S6o*XwfѱyUZ(g\ԕ+3mJAQg\[zo/oU9pbm.2$~)VL/eMOJ)/YAi\A)-w;Vb'""""""br p';P~.qwKPSiԧ<ɧ#ű[y]bp:(xFnLZ]J{wM IUK G{U Idg|t&ͬUH_@o%g7t:m^! `ܦN;ksIHlX~ġi--| p; oz!""""""R-`@5rΤxlɩ?"j'm>&cؑw@C'"BMT`Kuq" 2jJ9ĺ[|p ~z-%9fFB*Uϴ[S+'%瑧s- ъM,XnYMEKM|85? AXYv?jx<~FP(T\DT9V}!F vk6"x/O/nniοnn5r5K]pyj0I\y#Ppa<RιasydK~\0F@l|\5d٩gs?W/2J_-AB/T{+C.p-jgBS^mN\?nmdZK ~)ef|Ud"_PxlV}>%UsZ5UsGc.P-BTܕkMpMm}׶Lk?|lyr)#KwOWpVrW?ضhe]zi?P !MVg]ևWk6e| \gJ02 6ϓlvs[cYOlz>}S֞rQ׺wReFMӪ|}s?νxwᡚ]Hν?GЁ:17:g'F Smbp}s_=6iھ(>{n޿3<z72`CϾ+nX}m9ֆ٪mW_}u$.mMkJJ$N# >W [J9QlEn!ă_Z^oo.-Oal|ͥ<> C8afܒzmlc'f6=d̿-%jvu͹0xڛ_*3'֎}[+hWu\QDujskݟr[EMͳ;x$'59>|KM r_̨j o~oy[FZmh -_o]'|={ox?Znm5 Sx1=F~_ZOG>-UHe\z!Ļ: gَmj?{G}ދ33{hwuYi% ۻ0؄`& )4 iM!isڤCBȥi6qpF--=rᜐK!ae|/fs; dClI;ߙ}ޯ_>Yyf̈=Pz=(ǰ=01(>sWz!(I>32,;+^^[zgu4%X jWP,fmf%ssV Pķx`S9QUEwWsB'o BQt9nn+%!ުZ,v5k98&:T;J.M|ZT9kmݘZzJV iN8"f\xgWpQM>K ]) w;)}> |{%|q\>844Իo߾Ӏ7h4gVyt6jv P>#ԺQS{J>Ì2Ιs&Ue$IU{<G5QI]3!DQtvj<^3OKGsG/W5eE!OhkUl'^{M7e>k\3saL/|yS7rN#;'T)-}y29ZX64۩iʤ2IT./ZH>Mlks\} Ft#SG$s,M"p.5̶+rW^`a2& &n4MK990Mꉾh۬=0%?9rB!sBVb bӿgϋˠ4/}*g6s6#`) f3 -GG'̾}ќ^woCKfi?O9Pp ^25GlE%2y,=>NvQ ix8gXDpL{vPP3\y4W3Ct L3M"}?2%?k9c1):66䤜5_Z)*W\)r+/! vP1߀,$6+FG=굪C)wtj ̑xZ8Jt%cdBY ]x:e!gmrCgd5!d8'{`W׮Knx#N ";v8cL:+7ٿAT*vutCpCfߏ~FTHkޝ/鹲DIDY'S?b!}EִL$oZ,tYk,v-c?ūkgϋu;..tHE8]x¶#?ڇ#^EɄ0bhhOD~X}jjKr UEC@p?4j/,3HMŭ 41 Lfiܯ( ըf${U[aUWf^7]R>k'eUΖ2ҕt'a NgqLdhK`KnӁX9lɔZoVvG6-sY%1hhgOd'+ jT[Zvv6ȹkb<׽_\d}^{v+jwt[o ª静Pvo{4#5q]]nxxOA-zz(Xf}^fg~޿{P)Kt 38g6CNP(tO(bTc{YF?{{{=dZ}L8e)AjW~ȃ=nG,Cb5CNgqL]ے.Mn^V+<~bś?OR#Qjz _h•XB0YLde\x]Uym=WC?yrݺ>qC Oz2v\dB^?kA!B!xbñb2,PkWKǤ8,+i7 liapXz#\&yj6h9. ޤ[P+J.綵HV:ltT ]E~5JZKH- u[68Z!C5KEjbi*hNwN G15[R=@ 5(Yl@>F?e3gM,ǡZ& x[x :Twa:tuZZ!.ZW8 X=ݏ.w$dݮXFp4 D#q-vhI)5hgV,$ӥv1ޱ4M;!MkCCC;  ~l^\1Cv jVZ { +'kTUݯkx<,jTTcfC.6ۼ^AV\W ޶j>O<~Gڥ阪rw\{"WPKxIѧfzK蝊ߖ_z,jM\; Q!̿zne)8qW }~gws"iG^J~y>!M;yhyփڞ={?iɷq M$7H3d?tѶY9{`3J~Vs&7'b~.6&:Xֺ v她.NO66 u̾}pD 3]ܻv E{O[,v=EPdĬb"XysxV@U;yƠr +nY99|Z>?ƆcL+X?dBtځB!B!#Qu"N*CP{S?c#=nSm\y]pK~bP;v9N=CĬH'cE_n@D[l"z_U hr^(VCh|/#^J!B!Bij<6&U*{,M"bh'Kt O;ҺT/D]:%d- DdY-*jWȁi>چY>@BCbeLۀ,z k mrCgL$o tEY=~.6~IL? gBɪ9dU `M(Y?þp=cy]1? ,̫YVMl8&EG~G֭[z7IB<{_+Nr6(H&E<&lmrCgd5!d8'#vѶ9LVDIOTlr*Errk>GF_?g&g} oGڭ?2n..Wo[@r]5޷Eŕγbñbt$ :5qV[yV1o4M;!MB!B!4R}@?jƽfPPlf.Iq/_,kKNheE4RUjU)^qgyR,jLl8fKp +X'iMDG.oQ[wٸbhG& WnlfA{X?jOB!B!BQ9J\`Ere~撽 !+@kʵhruT8ECQJ\,˙&Y|KO"k>׀,k˘ g"dUQ @ېքSEс}`{/[4mF_?g5g"xCP({.BaC#vѶY H d~r&/fߏ~FBĒڽam@k V.VSy+SVۥi$1x8be,ϑ+kg -|t}]UEI|<  h|M$Bb) 9mF_?g5'!9Y ͅ(m嬔abGr'V.y=$6~d3J~rQHA)((:ևmr?ojWn.VKjrNƆci``e>߀,kia׮-*E <~a Lņc%sdBY${c6+G=4~FjNVsBVsh?bm p9Ld)93YU*Le- Ȁ#Qsab)_q_S[gŖ9%KaR Jn8Q$˃(WYkWT켚).}diF<3,}9EDZSёh]>pQW.Nm̓/X4> 5 IDAT+h'q'J. `I0bzPB!B!BHS{rj#D>x3p] 㐯AKx-)OIdb*pd=,c/d`ơEjujġͯBuls\rք0bhhhE1-SmYz-lE8C `;IU}ʜ|FuZ|:e3L&ӫ(vI&5Mx<,jTTcfC@qיj_ݫ2 Xmqg9Lbkֶ_])/ow50sf<;pA{y獛Z-/N\x鍊EQ BYըN>]~Q,d~wSJL_."(JULE^έB XZkCCCnHtF2!k9ۻp0 `jˮ][: `?̵<6Y7"^(j=e)aFL㸻l6ۣDZ?Qj?NR_6kq>xԵzYeo}?ӿgϳy kf01(㜙>snmc.l?ۺ[;~$ìjTZ?OM` -weݺY|Hۂo{b$5{t8d{W;?x-ܹ.փ9sE3 Y{qMV%$[м1s~ 38g_Y!8IgCFYp85?(ҷeINm> F>i3uiȶEޮ ߆r9op{~c5P츻 NNW2cwt" >G@;404L; Ŭj|SKy{@{_z@EݣsF?e3g t:Y!8IgCzgEQ܋9Z*c8wWb1 \ac9s}~}ioW4=f4B^s<1ٿ>r&YWŁ+8[*NwW¼TW`kꝗii:u8P}N_jTըF5QjTըF5QjTVZ;Vzke@x|TJkw^!xVDd!j~0'ᇏ>ʩ ݒ| gu XjA+l]O77;Qj{߿'i.WsdBtf@`(:p^;}ѶY9{`3J~Vs&7 B"V?Xh?bmF_?g1g<U}yWCL$|K,&m@D],U˂m dU+(>viXݶ₰6D& j7_ AѶY9{`3J~Vszh@h۬=0%?s9#cq%H xuQY\x8e,?L6l/I)wX\݁-[5nw^}v._Htm+WϹ*ɅdBY${c6+G=4~FjNVsBVsh?bmF_?g5'YZbll'V.T _ɋyP-KżX^qz%+C&D]B!B!D/3*tKB!FG^b?ſҀH S:Ifki6peNج IFK[/kG?B!B!B#sBa=Xz4o}#ժ[Mx.'UM Ǎ_RʨM"$qѥ ! ,zeѶY9{`3J~Vs&7 B"V?Xh?bm  :+WܡL}}i5#Q򳚓~!fG">E?:O#?͖풕M8`y]x4kN+f2$rQd%h"bF=NYh۬=0%?9YEY=4j]m.$2l lt]u8h#ggGF_?g5kdٗ~DE\\? ,+l@_ڏb´3m]w'-^W?_LhɞM& !fp9 h۬=0%?9YEY=4j]mSr}3rZuJz)R?:Rfߏ~Fj${s9kv>v,=ZP-}s?u$w8BG<p2\d,u׿x svWG[ռ;TiwBk7K'B!BiLxQ{{?,Oq@*6I&BLon(7@)A0;XG PNRIKVU-o$ǘ6Y 2d} lհ6C !B!B!M%AM;]J6t[BL`$rRSKkR\x77yMHȲ}KO"kl@O gP$zJs\|RS6Orv礭PghքSEсV{޲^yh۬=0%?9rB!sBVb,yE-Srp5ܨZMg-6fߏ~FbZ}7䨤bL%E)(7FG4;,cёXյΣp" jԔAjszr$v]?{{JduD2!,.z AѶY9{`3J~Vszh@hۜpLD3׽%[,8a ?rZ\p \v57E?;k}?2%?s9z]{ڮ|8 1wM<9y[U?vgPZM$WK,SpGWl8Vp-r_m  ꠉdBY${c6+G=4~FjNVsBVsh?bmG?^uMAU"WFwW~` *zm GF_?g&g<tvP/ߔ 3|EOWy.eOG>E22?yXp߃Ji:V؜m6R_Py/tzY=NiwBk7K'B!BiPJ)ZI^4k7տޏI2GzE,1(>\.A`THԚ*~WVe2r-k MY[Y}w?~O[Wo3O3?E;~Mûv=ɢKc2\3sяaF,u1Gg>ww7,33OM1jT{Z<| K{ u /_qXc:7y4[ܑ'^}s-\˯limuJf#Ι+Lp!@(9K {ރ q kq9^Ì2Ι3qp:rr$OvESqGS2,;+^^[zguĴl%kUZ)Yx~dw]{|5sa38gϑ`&JSSkїd.d]"`2\d,r*UMGSc3/wB$N?mߨw\tF2!k$jX\ԿB!BYÙ~*UwљNt$j-:D@-yZ!+S`4,LB LH^el(v@DțRR)-82SY!kq&[D)S*{2Ռ]nhizg pO. ۷45 Z; Vyq5sv0nT_sz@0s&dzE.IҤiUQjT3qjg~U.︼ogp^j$77\ [EсmxD>jё[6>dyGmsusI.h̕ڜmR;9̟ ߽nۍ}7^5пh3D"837O(efٓ/LI w/2?Q-cjkRdK%!27헿=x ɹh/Sl8&EG,jgwB3sʂMq[=RHԿ=c7;}ёw= 2/'ftYn N^Z9_@m>DYXzG5kQ*K*Ym[+]! V>3?LXD !B!63DM{f&1 ֮(4MLY,'U/6v@I[ԟzZt8RJ8MƻT,[NX̒!!k,t8ĢwE_m@$&-zj @:> A5k@jW3#^J!B!Bި›EވΞD6$%:eCM5-^lU-(AȄ+v7o_q 9'mL۽Xzy_7 yG'Ԯ&PO9zjLtikB)0Mꉾh۬=0%?9rB!sBV®p7[[={6Eqs@EڏAcؽ‡+U, hvZ9% BY&;}a'~O*WJ7[<='K,@?:Eyžx8'#cZa]j c+ՠ3(K\EΟqqjIyiEɄ06uBFf娇(Yj.BqN9=n űG1~ʆϩAWm϶X:ېϏt zm GF_?g"g~Ԯ* }KW4ϟJ'h;UFm2YN2(2]ZE+W~X-T1=qiU, ]h"bI.=1amF_?g5'!9 d }K`Ahy}[w@xw wgfg]M6dg׿ZXsRnxjRVrW8XdMUTJd0pd7=Xsq ] UTl6EMnJnkhizg vtB!B!FD=Z]ǯ(*< qM;5+p26r?tvnـf?Y_>d"!:#}C_eٺ.7^| 6#Q36+~Y?[l\uU+qVy dMRHKU<2vd,[)>(nĝQ Nsr?9}X?B!B!`agx5 IDAT%PP(<,9f܊JgK4LqM`9e7kU]+]iH)g.֤Jztn ix82erM"$2X()Դ>|)>#f9ߢ6BMѥ ! ,ztoжY9{`3J~Vs&7 B"?Tb1I ˆPs w\}QL1n$_EFخlR/t[l6W#;}(Y9٬28eiooh·X]s]OI=2e%9d1œ\z EN:sSTsgT[nMԄɅdBY ]x:e!gmrCgd5!d01yёh&6H*Wث_ch}6Yi+ sކ^o7F'=41(+JPp.ߺV>+-2y6 `9y3J3Gve,#cq"6 [yq>%ݻ@I ȿKZyޗIEɄHDŽ mVzh}՜"92t$ Lf_<<ʻnz_@/?{W/z&MVtFFEPjqN]N˩Gx^ʹtϏIԎQR]=(Yi}:mZJ,?f唃wq^ySG94L<|m> 5cDW o*w(g>S%.ʜ/URa>)S^ 8M@HafB!:s#3d@Px@c-؏-%\.I{mCb$ё@ joD9UY*=t̗x^0^rX^Ϭ# jeǴIUTyM6HTrH#Ñe,zed,c4uOQ㈺MQ44֒'S¿Jgw/kG?B!B!kϵPLvraN"@]+ 6t-_’3ebnW>,닗#i/|& jl=D z" G,l>Lo~L!U͓RLyf)$ܼVڷe&+G&CCC (A>3zT[V4jVyq5svQ{J>#ԺQS{J>Ì2Ιs&Ue$IU{<G5Q̀o^;zY BPБT%[o]DQeWT{Zou*>~Z5 YL*ٺK8^ɥ#ta!s3DQt 8Lcv:7 7tiUo;ة6ݦ޽IE&27fZ3t,~-m]·>T+yZ/9>Xǽ1([oZ6k_hyG5׬𧥱0ޚ'Q,df#Q˖K[fzgM[]vg\p>3%OﺞܹKgXZkCCCtF2!k9ۻp0 `jˮ][: `?̵Pȋ|F7ZOYG=cQ9}8.(qjT@]]oᦛ7M${n"ϭu]xb}amYv^@?}筑?K6*YdA^[,ަݸ c=ͷw/oGnzέվ{X˼5К38gϕ=wu`C{dսx3x7Āw |?jT;27` +|7~,df~2o^O`V:l;?޶q/~ۯè Do d6L휹"Ʉ~޸&k+ wzΒb?-܌Ì2Ι3qWGp'eU>뱤JBEeqX8`,S6ʶåj>7fB뵫ZOUg%C׬(eq/)TD)5H50=Xrm`;j#5Jw:#s]INjD\&?<<eݛb[c8$$b[RT[J ۖ)%š,ZRPH &l8َHFftg{y3,.}g_I{=3y+zw g-Ϟ-Z;ԗ czzҵ#.[HNW $H$cR ʹh-8 ih r,V%K@YNEs.զ^PUu/lR lp*q^X}0s[3c, ~G9nK~Mb88n!K#zj LF!ʚaMl!0*p8ʇ'r>ɧw$%cmż9#\ /<}P9CϰXuYgsdXbm?xRmyX,gv$X#~ܽ{w#<2 X??QQQQQ9Cwn( w 5<0;tuZkz.9[= sŷzް A;dWn֣e?\r։m';<]9H6;)}ήwvolO f=^_ii xGF…RΞ[ꍚʞڨVY q׆/~p``v N[;~l֎'w+Гm8Ͳay}!&&G2>|ٍp-;Cfٳ'o߾!snlTH&/UHOng'0>t8}߮9rZ|zQy_d2iiJIGGǟ LNQ1Ҵ cbk|G+GEdkk+*Sxrvzo ~'~MμoVM.rysJ~d5CC(.T6*'bB XBWQz/<2 _] QyfǞ*I (}(LTH&=&@fN?kN",y7SL1թ^8|jyUy> `9z-_9pi9;BY<:v_V/x:Mln|z+w:n?Noלn /V"]yDS9孧yMΓ '=GXLxTn~ouښ mjB!BUDEdBe>[2èktY/ƉyAH8Eo:J9l7:qDwLc \c9 j8RI`zձ_t8@`BB!B!*E WNPb<, u\G , ^+BNSdOY`;6JRoq,n  [,nS}]0Lű:P(oc0M&>T Uytl}sJ~L&/jy.BO>ϡrcs*S\œ)#-yojY {Wnv̩)f_ /aLS{SV#|nk?qp?*Cȗa\&a@3)&q*$Bܢ ,BFfN?kN",d9yd_tlO4@O]OnQuуԳV\en?No56l mUP˳ӷ JC&/V!T> }^m`p`o.%xD/rG%ML8@P!n>t8}߮9횋|h@}ѱ9?^S\Kǃ %6+,4+~9}69+Eo?w=Q.GBێSLC;V#+ǭҧ'#{R9ɪcJ&l<  @|i2Kq9:!kK'B!BYM5lɳ%! !enMXW ((p#-x `9Yؗ ֟P؎y-Zo[$12 p30?В0D٭~$XC !B!B!kW W&O3Jh:YmJ0*!y+#  8v$nmEl)*"/YukyJ%}Ҁ! 0_EQ*";MmMqUU}0ׁ3,v͙L&_\c,t%1rk]Sm3)˞f' m)k)6)},λb~9}F9kf$๬-̣-C#Bf@ MkM lsV!UǸpmE԰ѐ*>2tqzzԓn~ w;*$Bܢ 9{( 9>t8}߮9횋|h@}ѱ94ʆ;z>[Jz Y)Y0*}JW3Yg!+dB\IS0 M9MgMK;f?ZĦtfT> bVxoB_$Տ+~(!B!BYy7ә"Gc(ILLbH&u0Xcb띞 }Iʔ3txo$rIt$_XĦwPyeTʽ @@0.O,$Y" %n:0Up`Ur>t8}߮9rZ|Cr% coZ. ϊO}]lfɳG4TcFM.<Lf4"'4A'xU#S1ҧko~=l٢nl>D}?.Y@w?q|"Y~pדO䴜gr)e0gT6)fLq.<pȢ,ltl}sJ~k.BqN,p!:rϻG>:of쭡b1~fmAXj"9qEdӅ|aO;飙OV*+%ܻN#S*guۮ_qI,G=vqkkV"莅q/TD^y?-ض׀$M?70S2Ms,TH&Ł:6KG}>p9%]s5!d8'K?1|YH0uhy&Y=4Aetcm^Tq'gy_d0 bVw GN?Mι>5T.|#,KaO>*Sr> sWUȲ)}Jk|rdx~<2fM:`^ܤ)y7.V45!B!BeUO6^79`/tE2q9[oQDgw@溊*j)E'BOSdձ\5wLrzݱ6`_cėV!ҚU0E z,gp8xo<ߐخ~$XC !B!Bˋ'XEWoy0/eTD&Q9L0`^Ӆ] q"o^B/prpϼ9WESauQW,"x`~Gp+Z{gq%ښ `S5 V!gбY:C)3L(Wkk!Ǯ?1l֥j->2 #'w'zvTD{m0| )[%2xQ(41%n/"A`> ,(h&gB2!-!ѱY:C)Ӯ!ˇ99odFU sk*"[ҙ}h`Zʶ{Ǐ˲M1b#S"g7^Vh 7eumoD|GY{&zNqlO*dY欃lڎEAA/ᑇq4?: sZ )"anDdB[Lmcbtl}sJ~k.BqN[e9w̖薳#xɪ1tK@::UִU{k GN?Mxo<)P'LF uB%3ͧ8])JY;ZoXĦ7JY*Fa;HӅ٧&'1l9; @tE@8Vg dͱbB!BgΕUtq5m oN0LOcs{Ǫ3oDwLp6I?g"YJ6PSo>s6!k#Д֋c]L!B!b3̵J*&+?!av=?h-psSƹ-1۽!)ϓrZNߐ:tG. /=Ȫ-Ji4[*Edʙʹԯ{ A\3X NIV,t7 rt;j~֘nڌ5cȰq %c>M:֟HґHO[PK F| uTLKzhnTބM& Ʉ0ќKpGqp8TU  [z8> y{-b7ӟÜ2mό,~!9y@@ hjY_kT)&'fvo|Ve$g 㪪>J)[Q>%wmFqoGmgW5BQO.^+7ƹ}8+D7O?/>)~'7fky[jds f%cilb;y-Dq ՉCߚ?57:N$~`qL,-Z#١ 9Fg¹{Gyd~~j6j6j6j6j6j6jHH痞Yk$دTRѐ2SO?B}g; Ү]/㷾d6jŷyBSE&ܼp12g"Ꚃu]N<00ߩ/^iNAmֵ݆vij0/zYpOZ[_lk/8Ed8t ޙ'm{I۷ogk[2 Ka LEfN?kd2\",>{Sh塴vgÞژ5:lQh^PsN(EãY-0`2Yvt8}߮9횋|hs>0ڞ {6yC>W݄#1~~|.`׽񛳥YpQԋ7?7\QO) hGN?U{¡07*[XCjٶk,Wl4eX "~#F󏃵 %m1|/K#?J~/g+_qעB2!-&61:6KG}>p9%]s5!d8'RL.nv'<'XrA!%gNe~%iEcYn)m2?/1<79df cdT˼ش53,$IU;"6}+̡)Zј gdT2?N8~,-ٚB)I,Zښ mjB!B!olX-ۢ3xt2 }#+Ӕ8ҧ4J]Q(N 4c=Y5;\[p^O !B!BqDwL!aG0I ̫ EEdBGPsG'#62._B_!_Y`}wzL^MOESe @:Z(xbRy۔.E ߤ$dmAW , OdX].v,e~̹Kބ奪:0Up`Ur>t8}߮9rZ|C#cs~sSi(TMKgCo4qhga7λ~9}N97%ܕ]֨r 1;*frޞ|D?AdR,M 'V! 9[4a@@ָќQ$ TkP`l˝q(4?8 Ɍ k\Wm28M618q΍zBpp,BFfN?kN",d9yd_tlQvUo7" "}і<"~%M|n-pysJ~De45 4*7 剓 %Eӷ5,ػMOX8l5og C2k yӇ 2dɇOgIPZP[9xxi./lϑ\^i؝92lBMmcbtl}sJ~k.BqNGE\]BsH8{,"6JLM3Ms #1^ÊfJ~9}9>ED!PdMAȗs`${\*s†'N5O.dJl&೫>%szGC-J%ĉ`!5r(x\a2gXҧ8_a] RmbŸ }߳ |s>|?v[,B!B!dUix%`ȳMϯ39ȧ>~u~gQVO_֕D{΋e Q7â|*1PGڦ1h ΄4ֶDw169֟UD^ҧD5].m-pV;&LzH@7J9Q(ď7y3L{e ;G"1&x?pIy&/U}bq m ye97?&Z}O>~_s^3~૜}/B!B!5cR)yARBke)Ѿ׽B)2 uȯL0$H|%fRa2ִOc"I_]({9O[2o@q*rV&3|%.:tc'  :46dƘ@srr[, ? 9 朏.1sMm]| fcO4!2UU}0l@8.XAfN?kd2\",>g{M'o7ܭGcM7}cŅB3#%3&{AԵT1 ǂŢz}0sN#l~9}&90>Nd0.hqkȩTA5}a},*2i}DqJs_uw 8ۃa_cih>7$82q ɕ+_j{('997 .jjE~X)(߻Y !_yEY,vi\C,. YV{O{TSR4hOF%i"VoM2)e< 8lap*>%ξ~9}90#dMbF)S!'gN+I#'P+WM_˔> UBCt-^%Cl9Eo>2u=L_5Gdi!1^9K]}\mK1{<9s퓌&{:dĝ݌'&61:6KG}>p9%]s5!d8'a"]Ln\Z9mRunJ9}}Y+.j>]̡PpCyd$SSTdZݱaO+,G}>uJJR29`6YX:!B!{S7 @zޠ#WY?_TmEDs@Tf6V5pE2!)eޱq CU47blt&̦5lmJtW_oZH- 4)QY^oew4cuV'[HXp<:Q9'N("<9:R o\a~ 0̒B!BqJm~@v 穤,kH<2&c&19EA*",#/4VYh;,Qoz0SyM  5#b#J"?F~ M$%{1+qpaGyiz[9O1؆ >yis-7!1v+]q:v:`S5 V!gбY:C)3L(Wkk!Ǯ?Qjy_ڮp rJ0ח@;YE4o·" (e|%>k됙T!hyy2=,"OYzu4Rlسʖ+ȕsq[k,K_jqI+#[ۿsu& <[+E GN?K -)e{=35VsV P1y# lUB iq,Bdm{ctԇS5]sBs$x?>* rN k$֠1xgtbx!HQWY69/k v}!΢/g?txQjz4]7S2Y[Z_sݺzky-/=0kjTGN?SΖi^:75mheC28`<M%|{%P@Gd-'z+]ѣVgv Տ+~ `d77㌱10Ɯ~5!B!Bְ[o"rIb"kCgm2BLYDnf!YPIZ3/gF/׌2G!`K |O TDv,Iơ4Ly0ƵOuPnLea䁀asKzY5ra'qYTU\j CΠctԇS5g2|QVsB]3(}J,"JIm|@L♁O_=Y4+hO , K>mhuDnPÜ:)y7_vяpWI9孍vwL@UO l-e%<^ISij56/M B ҧ K`Q] #a#['Yaz|l=KΟ[ Us`>I}1v`Yp=YQNoלvEY>4yQ@~7v+WGn}#NvFcUW{;Ýmz.fhJA<50*_)mSS"hWRCGeg6?N?\3>W;DBO\8d{w|Dvt]{"$y>z.~GBrS g.*w͌~|bESBV=&@fN?kN",|y+ҳSϖ"]ߨәhph ")Qyrm IDAT=ʊy/~5#S"geƁuO|bKY O<Af)-X,O`ƪdU|dV! YfɃ;{rtɇ h8Ϟ°:Y:0vxJ;0wr/`MȲbB!Brf5dTz"N)Q޵m5#4A O~o qJ@=0:4=Rbh0C|tƹ$c-Gb/B$nƖЦRI4ĺ$D򌅣1y^OߣυG?t9qΟ| > ̂1{/k*3{ÌcK|-!B!BȪS9c"rā^lԴ3f[ƌgC|K8üie`0_`^O \$Ԯ05'X|V! YfJ"o*)Q L,H̫I!oJÛJ%ƶ9}jpΟ,[ca^n68SprGؽ 'sSUsp8\*9QNoלdEZ[[-EY>v}!>j5ٰ#%䯹佧hxoMY)3% 'Wpm- cf3Ee ̢CN]y9XQNoלvEY>4ɒ{%y "b/no_}'eYзl^(\A 3?}xH p9%]s5!d8'K)wv3w]uW bg35u\4]rt)\/r hȂO뜜JxMRXrysJ~sf0U(Dhyj94$xFˡ%i<.莽X.s3&LJCu3eM |ى R9bw|G@U&3 QQQQQQJkcdc]w s}NΫj[G ,v/FD͑wɭ;LmFm~z}뷇 ˸N)Wj*{r,D!̄OLví[J=d`{#vj;K.-xgR'lv~ml>^W5R$9"; G7^[:^ikQ֙ZϤ*{@ `PUWON=}!;)LO`~HҮk̓H>Mpfk९R g9W#'7Z#yEfҝAxFr60s1v然`~؉(=9e۲!]_v?j6js$٨힓 @Ͷm^x}OMT]1&0{dyU3!mO|Z{~Q>zXzs8E?y 3cw;?#[;bP",;:ӮٱamӵG޼%^9h%'o)W*Ej2S}t=9UC2b&{4vxEAKn64]|fIGh]Îmv[# ɋxw嶥r yls$$dy%cDZMsKC)} @\8z΍nD2 s>ޥd'>E3KtǾ, `s?]HdTV=aC;yffSa˗|:'!@+$M /(ǫ CBM RΖV B!iNNq|ɖVv5=g1Jv,ْv_4yffG<ϣ@8*0&C dܚ0OR}V?ب]063>{ן~qT8ֵgЇO3Ɯ8< !B!BV("GT4ߚ>UTD&LT,....Bub^En ,0檀IWawuK2V$!GA, *JLq8 Aj#y ?>72p0}oBV\nmy29kdYB!!جgV͙NOez.B&Gx^8îp:^'J|-mGnh{4~~}*9{Yۡf.ݡ T#BV\AS*s=t+ ;'YUY+Ms7)jQܙnɷ$% JnPgOc}sY 7.zMQ: vo՜VEY=_5C%W_9U텩a|^qD>"Oߌrc+-ڜHL`)uf&ʡSf2#][%g ִR)ӏ畒[$ESJY7G8Zi>HrJ ?/c{r:J*= L8}f;fPkm{o.Yd R{svCR^3#f !B!ε,A/Pe-:f~mM_T(20KQTp{081%t,!w<ϷG2!H ]RuS\svkk*i#th{13}ϥL=yHt?qOxEq6+w]~}4h4f`F1g1A*z!Z̭܏<8緞n8X87!c8lB!B!d՜ b|}b1FQ8c,{4MU09&!2!rmFdש~'!RgcǰKŌ[K0rQ:<♥~T,e]*";[skѴfMZ.|O樈lo.6>ߎW;轏o圗g3:?~\k%N ˲"UCPѬ̵-(ٟ'Ox»/w_(%osb~neRt/?C^}[;Ct\@, 嗞37gsgiF_/l}Q7?yJrͿwȬldeRx/c/Rّ3U7=mKs_F| H^4vD86 ߏ[>Íg˙OU|N x9,ڞ<(?fv6"к:YH2(=)x&vJX.g<ʰ*f-@pZ9[m;x1`>FX8 InVB!L'#9ZgxE QhZry &ڳn (('6HdԎ@ͫA@3IR<z|]А8@b ~Z[dG=b`&|>Lk"$a>Mz,="PIMrQOG]Eop-bluA}9ջl>2SB!Bq4H1^LvS\) =#kϸ3%AP0߳׍h|WJ5ݳ. Lm @ AɊ9bhk,6轏OS8ɲ AdYB`(*̣crԆo][5g:>!WWW!c~B@/TTDl)xщ$hrә}ۉ> Jֳrvol\0yo}!@NrydK~+L $nkٱ%sEt@7"s l"ۖGラZ!0[h9#k*spPnh\6$Ll)Ū[u911bFBS|tlVm`K~j.B1:7VK4}$@"M΋YP W ⛃=T/QƇN>ϝ~}R9d7nl]kڏץ~/(mb`|pky`~=Wu_qD__Y' s*IoK\6Q9Tm.V.oôO9ENsƧLǪC{{0Gv?ZN<̶Ua Wّ\·59vT,'^U6>:(9JU|t:;=t8l4ET#6Ca8{o< 9_< e1:\)y<>6Y:!B!kOV)"299$ !(p.*jHq#;y'gBflW^w t}[1^b՟SC$bo`;*Ɗ.Wxfg Pl?IC/j#"^ `+v*"|s*"B!B!֢"@5AEdbGyU_k|έi (oP*`O{轑[2 \v|F6aYc9]V,]DV|YlgY\/*|Rc.#'sy@؈݇n.ՄU#˲<0UCP'Cf v?jt:}B.sBVU-*"}-V_ky is?#ZAf[+{#ۼl' *nЄ#][5Mgo)9\e.t`L%,O*y~=>ڿj) hS-clWʶXtCt9~ C#6eB2 !5zy`IYBtlVm`K~j.B뜜c(Bw^Kn>"1-} g tbIFӪK*‹6s%ƓG:}Qϯt|gYa:bmӥiώOGڠyS-N &W3=񪭭{wJM0FR~f%Q09 ɄRc XQ: vo՜VEY=t1JB0IϥSz?Md%16s3ӒtX~je7~؝U\N?voHeSٰ" IDAT;V*ZE)\s ~fYX XラC, t+3c¡rv.\ TD7Fz ?MN!B!:mK?bAP0nzpJbj=6+@Y֠@XzA˯CΎr~fXK޳ji⃩:D"a\=8Ʒ(s-TR6Lx:ٟ55X~$QB!B!rrƇei9b{(KCP-"w9Tp#ĦHCy. +rt?T,'ܰ$a8؅N씆 U׻LKHV&8,^T BEytlVm`K~L'2=!dXX[?O $}|oo}z7Ӧ$ϡk|eڦY!o?y4IB=Stka}ߪ9<)p0;Edֺ>kH{G!*uƘ@\z.nFdBSBå^جgVi\C99#7iŝrGVB 芎k_%Vh5]m?:Ed#][*U7=m]pI]'3>mCEdJx2V>>jj2 }t捯 ^1Bؿ|c)~8 ɌAHpجgVi\C99cF1=+tWjƷ<πQx8Q9tr| <^?FgəH%&Xw}YR8p2V8dHL|E.l/'~.BPng_G dnF; 㜛a43%看f!` !B!B̐j S6B͘-W,j3r=|yL֓ů%V΋C$ba?[T"SV0זulmߓ3;X~$, !B!B!T,.bn+*5ubqAyx͊- y^=Pj`G,$ύP9MϩLj9LKQD 9ət&8,^T BEytlVm`K~L'2=!dX GEfg5Tm6v+uBlcSmEWʘ DU3%SÒ1{hy[0_U\EdO1Ʈ |~Vs{#˲<0UCPѬ]6dB2cގMsZlsf] A̷]OxZllԼפ,d!:6+Gm6%UsZ5!duNVGET{IBysWF&.z-m%xf8+ w~Z;<%erdyM}\Ve~3 CZR8p ʩmk؈:%_@K6i2{xupaNdB2 @/ ?W fɵ6!&ܸ5:6+Gm6%UsZ5!duNVGET E BIRp|t꧜I Ly7j{pb Qjn~}29DG c-џռsܤ=IέOl]|0ŗ^4)*(6=L|.;_s&/KrYVu_fc}ȿ✿8 :wrί\mgdB!B!R@;iazi6ٟi@" }J hy @a*FRI=O` uDlUΙ0% G:~ρ~@`?I%/j#Ng0\=匱X=O!B!B] ^J Lw n"rzn "SzX5EMN4gYtY>:+!~_ m#gXP+q ƹ[T9E,G-yhKO:nW޽hUncBAe/y`BYy<:6+Gm6%UsruuuzC#csfS'CNp9J] L` jĆ.3ٟ$hv7ccpcGc[0<5:EaOw~T![I*i~->ڿy?WD :< /w B@ vEWi Snj z0̖\HކU{I]VB^جgVi\cu"KG؜aԆ _y#𻃸k~r'3Fh[Gv?Z ;T<1yGWķw~얨Tн:2ιM*A^ as(\ur[UMEY+c+N@yqs!$:n4}BBX 7mtlVm`K~j.B1:_4 Lg}[^ɹH@Χ[ \Ň9M*oeyZI赸vk)M2O-g*jE1) Lj0}k};cԫs8cW4P}boV,B!\b2!#O޻M0-CVpEAyFQ geW̳>ۚ}׬(ư;.ʥbljv.6 `{|0E+,wEbPZlì8c";҆{3~``FWz?ٰ4Q8!B!Xa^ !uz0+0#^p`{/S*BMJ_E)T?\Z5T,'L3B/g{4@kx &[M6cF|3MJ*"ۓ>`Γ|5idY=&Ԑe }PhV2Q: vo՜t\]]]"9k!_ЋPz#tl m]b(Ƽ~ɧE6ILP98S|jpAUtydK~+L $lɷ\8?{YFT}.侨hH&Y,!. [uBl(ٟ'-BsU:_z+HHeB ůbsTm3PK9^{j^kR6t~}ߪ9z̺Ϋ$B{(E4 z܅ QPrLF==lx Ehp=0u>X0@8<%rVj{E|C7Gfjִ)Qh|`^cXR_ƪSt<2eA]/ nx=/^@>2`󽘉 ٹkXL0;sgVcM o҄pجgVi\cu^ŧ@A,c~t.:6)ٟ$w}MJTqo"y [?*-CSL $ ҋ.oQAU*g  ^.xԤ[]k/,0]Qr '#µtmsm 7tI{MUMEdrJ$sUk_uKE;9^ׯ*ͩX|yyhk@{'EH19c%a `7l|f%!9Y灩: f!جgV͙NOez.B1ǘ \Κ6ǽsg/Lj׸MwhZ=`I;*^fe?ܝ~}ߊ9oZ8r__8\L[LH?C[I;t!տGp `|YCTd44;(m4m8S]iU[ggfВu!s>{?oa~:?a=9[gmp n`E,{RX8Oy&e! ѱY9jC緁.Ӫ!(&WbJ4Ot(##],u~ې p36O(N9?6{He],~AZY?,˲Bv/CULX)M54?@,e| \lgUUVo?ZFh'Ɋ,M6ʲlzвkiMQ58WՙHLMgrn-y3\e3U?+n.B8U;g{c5"5\f:\;St:O;|+)\ Kn)zG|чot:h?'.q^Z(3-ɲ=M-=Ek8ʂD?\73#Wme2ae]a#yw) "/+8| w7 jq,,J/."W}s) `[߿廡?=K˖, vBo|jcc4n|vXv?o76R>jzunvvW|wwuuj2ZF˜>I,'r2y_-|7[%_/39_Vge/x^AK[sgA/g_p}hR˜~lt[CM޶nǮFy(W}|N]7x?`*k̴>ˊJ)h| clgSB+ M ӇHi3!ӲMi,[T+2{$\a];po8_j11GȩlCB!B!X$H<+h oI !tb8 S"srEŷ:aG+F |ɟ%+q3iM5JCd,?-T h=EM 1sZ䊌CGsCU|:7qQ|s~Jsp}\T(6!!uT5,AYݿOav-Μs1rܛN`04;!uH~ʟ0$io>I,NZnS#7<,d,^m+ O߹mEGV9'k+K6E{SK^a:V;@G O|ҹ.#|qoYj=g~wSC$ /$ "jY*X"J67Gn-QTvW?Y19>9Ms=[xz&/>9߻1.zct5M:wZ(_#/JU}J>;,{1).0m|fܒ<11qik\A+-ek_$-Û[y|b*}Ytٱߝ^zy-[ Ķ6yv?B^27YbW<>Oخ&^u˔U2ӽ⌗67s˴Da~b-{~ շq_ 4\ݹ)`9bTچ/Kдq {ㇷ^شui%7yOm(泮mM;vt>BEӌ_=1cu^$}fM$9UկǰP;|&pd!1{?y^tmy9dFuB2L|#pM5Q: vo՜t\<Ʉ8^b 5^JGL|gbX\mbk_s8 IDAT< W-_|K7{RfsMZd8 i'N.31oTZ`Sx;^Ҥp?p|{vgeāJezq|0Z!ΓHAپhۺMDb6)7rGsG0zKZх*p1@z|h9 xqixjF@!BH-*"ȘQdB!';">nGu 67L BYVaVT߻,/b EQ?8Y`L%1Цs͚VZWgEq|cRԐy&}K`MuD*17ɼǴND/gE Ýx6A;mV5D!dr`j0F@!BH=-zZD-&뤡׊ }]1vGă.iς2{FNpqFYM}r8 8Q+@U|g&1#ޫ,R 4^* L 2Hh,ٹ$,`g|0u]us_܃6nam +v)3(ȧjm\g!6'˲@o͢ crԆo][5g:>!WWWYc㫄Ed?}?jz{D67vMǣwDwAe5~:\nCKhڰQhb+~u.A Y8p2N?vofN( u%rF#YO7QaUqnC̋-P?9UNnZƪ_"2Y 7}G-ȲnƦѪ}6sw}`ma Ʉu&e! ѱY9jC緁.ӪYK%ʢ쎮srZD#zPTJ^:33R BK&W|QR+x>79wKxEr)qydK~3s>, '=|lLEl|;M|8}{該!1WŇt- SuBhlE{veYH Tr`*EGb 1G= ɄpجgVi\dHdʪ(ld:,ۢ"r'ޘjj&ş|sW@ν&S5~&vgͻ#&vM~oϩeARwFN/#]򛙳ArEKꦒZz<<(BqR(N0͇NgF+4K_ƪz+ O ~xw-IF=ʍ؝ݽҨdm4ɄjcB!b?\LshT3`="ys|1>͞ ڙÒ߫JAE1/b 5I{<㸶R{$QD+jVL(0&8J3ſ௖Xm`O򝢐\j#B!B!FQ c"2!ÂEj狭]I $w-k%ԴJ*jV:Eͺ9!Q`y|Ft4Qp"Icp{$ʠI1-cՏSrfhk۠-Ԅ'4SB,{Su0 CѱY9jC緁.3N\K?O $*?8,9U%UC4]%aGw7]㧯kEQHw9Y1خU\ԣZa4YY( q;<%r@kO2oU"p 3(P ?/^|n} |z1T:d!8c Ɍ1??p%/#gTHfsL~zy`IYBtlVm`K~j.B(;\s,>G2jݵ϶7Z}vؼ]㧡|qaX]odg"BuLN[Q?sydK~K4ɳ<^7UB@ `v[ CiMfFp߃k"_ uX)Bր ɌnCQ[N{h%}>z?OYun\X6t~}ߪ9z:'VӓZLnYłRPBPqGt13s_&c(\\(lBɤܹ}? 5!I쥅bQLvydK~+,p"t\´/Fdi3^ƪwSwuPŻktԗ% c8ǦJoo߳41OjYx|d8|H W?[=Ф!YmtB!B!R vb[D@8nQ)Z2vvU0ΘԤ3a s-^5숹{@Y.zo@T3g>E)IL bk`8]SuDq}7C/&{7dYhN's&FՏ36cc̠AV;鏝nʚ !B!B b3!vTW>5]db L^|NʌneZy=.I0fjrB*Aj ^vQ#2rRz|d M?}TOՠqN#p $fc uSgϻ\m;G8g; !+$˲<0UCPѬq'fL GCE۳yt2%Ŗܖf88;*sʨ$ErC[kZ;<%r&@TԠM#sG=6w, y% `|YH1C )1YCY8Ъr@/$0t۔ >8q41L69lO7>|&*zy`IYBtlVm`K~j.B뜬Hb ~/{TM(pEb 0 sm t0<fym >OeRO8~ deQ,~}29)*;#;\/"MH$88L*o^Yラk4d2H)HCͪ KТoe3!M $*=ٺc8y/%5alx'c죜sG?IMqkb tlVm`K~j.B뜜n 6E=>昧KYmqGʇgO&MGi;ʋ9/&Ƃ"frٙc횚e%$SAm~}9"r'3{=?DI/ljΌ\S|$CbrA0ۢDk AlKBy|!:s"0看GW;s~it֯>AwmLP(T4+Gf v?jt:}B.sBVG*[Ν ,Cs3v-޳@ۖ' cՒ1Uư@1̔]hcDkr@r&s*:<%9x}uoL`X }jHezC|0EmJ"75 % >.UcЋ4ٹ|yW{#9k'oN&},Df v?jN"eddete鞁m݈-7 JNl]OO н|ySaO75#u7_U! ;~͢qTtydK~sz(Uڒ v|  `tٯx JF϶Rޝqև<3{KӲ,ٱ8' ! mi4_!&\-ݖrH@ IH*NlKd밎y~neKY}߯^>;}]w)C(zUGjAd;H$\HxeZ7yn_10pd,a[B,C<ŃFK{|464>{t'M}fCFsn!PR~ZU[*=6qx; vl 4s&<=8z㬌1B)K'd a0UxF+n䦨=nKꅋ OmeTo4햎ȖPuS8M 8>߯Fl>w[/vG^WwMUy myjAڪMd+$)$ךI'LOr"Փ<pmsk`Q3 !V0pd,a[B'>6ZZ*4rūZhdr ϱ%{blbGb}$ioMί;qDkcQe#Wm#c"ݪ+ ')۾ \m !B!b(_l/?L\lIq('_aa[рV@LlT߄Ch_hKa-n:iw~0pnsT33(Kb͋(I" EmGYIdo]edƢPscC2RZUyTJxFjlST*™@4*1CIx~^߭qWWWWBo uw_%S¾p79C'f9~N]fNEatJ 6`z?^?801٠6UnmhkBB rаh48=l|Y|q blr$#"4,Dֺ$NDnWĕR/+ݎbY[< f ^?8by.Mvj ;GjxboH뗡xfh*<+ $,B!:jV. iN2\Ky^  s@m/(N5:LnRӺX#a )ϧ EfT 4f?ը%_Ug4 UwPQӌ_(u쵖/?KYV>ukn[\KQJ LB?R8k].wo^*!#Jp恩8FG̐}|҆^WwkU+g71{?[H'rm*H7۷g@HdwN"omzE= os['gr;˝.ڷK9c۱Il_fHh. \Js+`L4myM  w Bä/(J a77M}dop%)܍,ƴ IDAT kW2 ;hn!a"f}|҆^WwknKr;ϳ,XqkՇ(N"} un||.e-?3=#Wt\s7| \C9+nEw7;Qbo>Mk\JY pm&;PPPG^WYs>BbCkev%&d)*`^/ʚF3-kޱ%-\L!VF]$yJwܑsƕeM]Y^=o$2 :p7'mXmy%~ָ+gu"7 M3D1LfqfɈ Oil̨ b-[zVDOtO=8QUn]^tw,?{' m~TPqhkh@8:=< ~um7^ޣ8z-j*Tg)/Х1@`:l. C]7f1R~z#@e !Sxſt{MgPP &ZΗ/wmJˀO./:SRxˋPwn,]!Bs@ɊL▿5;D<טaꮘ:<U60,=ZݧܳrTT;r {R#t8 ]#8:arUA|s>O=x06L_;AC7lS~c/z'{bqr6֗5I3'Vʼ!r7iB9,sQ6oֿ\Z=g< XDB!Bs(f&!-?g7*KO1GߺȌEU@p׊+'8c8I" OJdO;?+dˁ|x;1/~m]BګjM'ﳍ?۠v>I>g2߶@{Y8"Bf%JfC?mCsI7u3|:x *;&1ZW/J!JHR!y`*Dl3d,aiquuu<.!ʹ~Mv_)f|G6/e*=@g2C8S0io+5y\BSs71{?[;IF#8R;L.How=q{MMpG| ~p uɶlPE| ;vW<>`R8zL& V<='B]v4oH ȉ}(0ޒɞX#Ed/j#Ĺ8Ѧ6*,ŞYkX HBԋ{kMIx~^߭q5.!ʙu?y>+|$+8EKyorSdӏ,!_H>/C>˗.sadv4now=L~ޗ8zL&VhIF6=-Wl܎§ 9w =xqZq˿nd{й@IkKf- p"? xU JuHVJqiŹ+:Y؄6 :p7'mXmy%~ָ+ &LN13v*ydMٴc3s>6uC O8p{J{tqPd¾p1d C8Xd/qy%~WYI&Gz<3'"w84=jY/Y/7u$X_rdbe?Wֵa(.< |Zkꢶ6YB!U凕S8ZC:DV;hI&]q!Mn*7s[ȨFWrܨĹ3I4)ޫ ^!B!X%dxaEUznHr9!<)ћ&ȁ&0P޶%[*0VOTWXD_GI͋(vI" 7$2_FFGuR;8ʢzIIدނ3DIjbR<0ѨoOڰJnspp𴸺jbܞq{t{ϦȦBGH -df8kI"Ӭy77t͖ʓ>pipn^Υn07b(m{t L Y/O~y~^߭q[EM&%AO>+S!z9>n_XX+n= _aLQQ&S@V <& MlIO (ZCH;n8N2z?^?8hIשcWC_MhH ۼ.dO>w?XxX +n]|gډs{PZK\PJ݈s'|=|Oww5 %M3"mK؆a"45TǑgy)j_xmܩsSJf2uyGOx"ĢXq|x"_ryoVܒt<̳dTsf'5 ,*]O${pDɾY>io+5N%8w8E uͦk.Gٲm?N٬o"@KງFnFp,_ P̄T׻nmԵk_7:71yw=:3`qMG^Ww[vTJ=qU==#;Y8WۙaLpzs Zdٯ,qI'Ɯ}F$=Jkp)RJ}x-3skZzZksۿjjGOn,]!BFbq"2̵™786pvtzyyߔc]cve6wᘡRCI[gm{߿jyK' }M/5IYqπO-OߏuǥnSw-0:3aܖ?r"Hsg&=ֺ})B!cN$!"@nF||o 0Ӄi71Z 3,MdsZ6j:{_(x0e3-= X$DYqF 6k7u%叼<p%հBTIR!y`*Dl3d,aiquuu<.!H&ҷ'n7Gll*t;ZS+%zi+nnm^Zc]-8r~` owXhtH @2dޏ#+%Ϊ$hk wBt7)_a0u i+nꩇb'xN"E $ߩMY,_M}yz'&3mH&{b "UGYq TX;y9gZ~lg<˄kcucoOڰJnӭq !VbuX%ؒ_㫑u\9Ǘ.s8o8;̾S~\ECkHzt\k+E+n Syqy%Y}Hd76M {/pii;?_¹_!qYD7ޜwT +nubByyySJ̑|zߙ_5˝#/e}ZKYX6ƽB!Bwc"_ 0S@/Yx85̏oI0H&jNVjKEL(՞WD'N|Mu9г@ѯ/Z8#+n5?.u,ɳ-8_833{ܪ+km!B!BԹ9IM@#3΅+nQ/źшs=urLʿ30U^z, QrŒqTiNF#@IPV(4m&y_okgdŭ ,>Doϰ`G~91i(lMkĭ/¹!lRn&/'I$W{>𯫽av)Nbjo[1T*™@4*1CIx~^߭qWWWWBwlj7^rѶ|)O&$ u>k94$8=ꋀib[%]l(L+ `H~y~^q&z}3pO(HG)oS5Gt7]#I:[\aɞXÊ?W;!Ċ[S%LM*ίL+ҌscQ^N$ߕ!oPJZXmnɹvg#Q,b67'mXmy%~ָ+Gsq.ⶋ{y]d^s݅ar/R Eވ-PXK7`?zRG.ޏ#+WM.B!}̑ SeNN$Ǧr- ƀ8pK&&Z!Ĺ▿X|B&sCϴ6.90+=qR *N q[C~:6Q !B!gWNfp\H3Iq sSD3Δy$ZV+nw-NnQiֺUq)9Nk8 8wh*=g${bZDѷKYԊ3Lb@ ؊" Q%M1.|pn#xFk}P)upX IDATvz$߯zZɪ2~8si8wͼ5X{kMIx~^߭q5.!ʑ\,G>\~?qJ}s~kr9@Wr/Q9|P}Of_{eŽ\Zz?^?8]ʸw`ta=6ٰSFJL* y1ɔ]Kֺ|L) %H" y,AIx~^߭q5.!ʑ\,G`z 7ⴟ o].'jBssU( NhTI(NOޏ#+&ΫSEѢ ?H$asL+XT.) /wCktdO>ߎ%1Wy;E//H&~9~}~O{!#h1mPQqÊ[Dobk#jIi=_~{CP箫RUyU/?[꿏OZ:טE(~S(^6YB!Bz/j2 0lqhl_ÇG} KOEV܊t hBNlLBwɞ t#<@[&aY9yz 8Kj${b/@1$֗tcuQǬɗ=i/yU7O]MӸg@octPw '3 +tvms ~u'QݗMdZp_h=Ck=\sr̗$yjSzrwWK=1!B!Bf'&:JbTGqjlnR8 0 loXN6 !>oߐe_"*'/'=' L/HY5+nX|$RyZg%Mް)) -v*'@ -\C[WZTJgNQ8߆3lrqbJ) \si ؏sCWiWV}XkZ5JB8#TFZ#fȾY>io+5y\BOj 䩇7OG7N ph&5aKNsSrs+PG,}#Tq-VܢoJnܻx'hitSfDl8<44mS=uy:47kx"_)粭Kɑf՘7U`C)MTb4MѧFpr>2ˆGU"BkJh?oQJ}x+B)R+nQS;}Urǟ;ȾY>io+5N%X9r8 tb7n|շ;^G^4Σ?R~^ԖKTrs+v7t~ƖgKtF:𝯽{ z=$8zMW]teŻh?M3( xgdOx"~$֗<1ہ?_d^M =FzxnQhKTdy k]uHZޤxA)8C,F g\8J)u9Z}q`uqz, xR9Zeݱ 7aμ\zk y,AIx~^߭q5.!ʑ\%6O?zŹPFn0|vOK0{'<5ds|隀`;lņFԡt|NϾ+nB͢^]~y~^Uq>݆oiPwtrpSZgR3  zkg2|h b1VzE xi7qN]ezb[6Lh߱vF7hF%4J|N&Fe;޹gR&p)؆3JN qVGk]w9R%|pppƵ֯8m4¹ $cy@l=m~hPW3Ûj1L&KB!BR{͟C[+v򩝅OJ2Yxڀ+/nUG:v۠hQ\̝\& ]V浡4J hTya]8hT8P܊N.X+nE4P!PY?ȗʹ>N"[X[W_eqID]IPh+|I"ׇuHgdIrrsxZROI2_[-JYaƻ_~2'\ J@4]Ź}|҆^WwkU+ǭ?iОqjt榍\8mF2Ѿ#?1?|m&;P8;9Ǘ,О3FS1<0ڔ)[)Rw{+N>TB8xX?^?8Zpn)D}ngS$=a,8y`¸'?1s; x"9֗\0dŭl&g'z+ 9m҆?}QÿޞX[HkQ8gVZkVJH0&%l7X~ẟ3_vgg+o Wx`bɾY>io+5N%X9r%\Wn䊫/zg"MԱQy%땜Kk)lZ|w_ `oCw}ԡC8=ڀDOAWǑgn庶%~1~K8 s;SQr8B`ŭN;8/~7JK|r%e`Z*]Ie U]fgrU_ġU8_Tgj]*2Sm6#Pi|0Jg~y~^-qV.FKttxM23TlI:O dozG<7zŠ[QER8;}A1`Ч(0s|r+n#\{ڛkJn+>-5 .͓Hk_uEi@)u!ȜZ߹YonˋnZg9\]5YB!Bw)H(?Ѱmd S1U~n C oipx4tmڧMFG*2̍]]B!BRIYi 1 UI亞3Vԭ? BR+b4xqMfRW}NS%zw6/~TExD4mRi_rr2ʍnf$rx"9+n)s,>UM" }#qg6X.Պ[ՎE<m tͳlnQÓ<_c<*3bTp SH* Sq fk!f ^?8Oq !V[%zi+nn]zږ}foy-Wr=s|i[b)SEP nV0cm6qظ /̟8zLPs>'7y=%d)tP`ѣ*{)0t&tm&I&gr'.W9! "~ x*Rp& SQ3r؉sS$dV5&⼜H.γljeRs߳-G)ejx޲7\Ԟ66z[tk\B#8gd_5@% jp94Qi-8vE*y ݜ-hGu)]/Iz?^?8KYnqjlޡ5D6C%x lD~Yq[Y+ {C< 36 40Y(-Ra$qcH> Y֎n3w-qsˇpm>./u&~b߇pa9;ȾY>io+5N%XeA w%XDo"}ϑ{|)|!9DLf}+Mߜ2hpX]Gz?^?8Mɑ [xTaa,?'&5D.(:ފdOE}o/yj"~7[Ő*N&ܙW*ZaZ3c9 T7!=H-.>JOqH@5 (qq+V-iCK%iZ)>cuVˋޮ~RZM.B!X9V܊-UݒNp˜BZ)On}Y" p߅>JILg[Rŝ:BŦΗ̆#G@;osMB6' zb}I s.~!5{iۑ/\9sGgO -Gܖ?rޛqS%%۲-/펳98qV,-~0nNp0CGB@3,!1!cqŶVkm[չTnVZu>O:USk{{H@E}t), N\0[8[ <&<&mu:m;_ˬj1Key#7򎌑4)MiJSҔ4)Mn򧻞9ҩw/}w֝[ݫVQHKTTtCp[8jSډñw|ϯy)Mi~~k#[45:w '"늆+ YiJSgU v%TEoհs1SUzWCF=gK޹SΎ<+8v> hȃUp|zu@ko'!eFtPbH@u{!pP !wBtb3WNG<~&Y^ӄHd]$Y'-p.`"g -֑S+a8-\ϙuݖ?)MiSk?޵vӳgUƫ>Zzy05xm^W6^y5g?{eÕM@EZD)hb =5g=s~읣XB"7l~dy E'tO507zߕ׬VruˍKK&6nz^lsz&ԐMɪ?uhPu`k]s sOPt }H7K j]xL)s^]oDe3/+F2w|ZRLP{Ս_-i>6l hncZG)fyg2<()SI=@jqb>P%VUUM|IŁ]g:A1[" woVZ~[T*u-p+X,?bleuj%s5繅9s<`0% Z4My;]z_>%_'|^'wt1~z৏>u詛COw΍XWJC{Sѽ=j3><|, _9 p vC,62=+ jhG|;VM*)Bc<1NSGJ/2ޞeۘSIbN$r@P~GQf:,:ſU}vww+ ܗB>`@H\3jMŚH$x p'<#y _xUՋxp"34D@X.Ck]T֍]uη}P`KyB&qd"gJV -*w9HF'ڡ3sSrǼyB=Aq E0 "? |A4qn9#$@B!|7U.$ !ҟd83t3Wd׊c:0iɝO0W lϚ^Q /cQf:,:ſU}Z՗B8r)tbz(VGa)$ZkzeG@W_yc]<~ÿjP`ԽdrY~?W2 /G_JT4k- grGv>Lh-Yj /^܈Gs'9ԏ4n+HèjyjkgG\Q,I=R4Jt*(OCIpվ=6'sW'i.lr*s@훙gViU_ Injk*֤(y>YD<4~}la@j1C}=kL t@&i mՄ͗8*T%~#]<qd1ry D"kg鮤&7Z'fйR>OQ"^-DKpP%@J3 m@1Cl=Fȳ\o27i{fard2Bz^JiVya BP( baU_6V3zw;ؚBqJdZ*?ru!J˒@uJc(碲n[z$+EC=/+ $f9RVR:#^r˓KΝbBxhim:E?yX@Cgaf՝^p[2+I-_'V66xRʄGBaptтnG? YFNEGqrޚDkD;r `Q( BP(K- ԋ{9~ୠxxy+Pvjb.z!2WԼ }H7$ LF4CzI9ХKEҭ9vzޝ怿e r?-1tG\'ģ+/:H 5~}">=o $8+%eޔKOiRsiTgGhiܒGѿl(x#~9tTm?έ$" Š+qn BJ((@la)!Y&Xؘi ۦ?/2Ծ9}voUVP(fu+fuYo w%@[X:~G5J}F:q`fb?}voʈԮoA_YM݊3F\TH+6>҇|AT=QrhiW(Q, Bc*7뉸#Z:%>wwn@R@ɸ&(3 T8u YJY rl0j(6ȿ%_bδ}3sT}ߪ>KPJ8Kz'si.KmG~^ ͫNXtb$yrW .m lq ]{#[n=sHI) ҈IU9R?r_j>!d݂Bۅ[mY䝘u֬4)MiJSҔ4)MiJ[ZGKC&]5y4 jk}cg׭(`W=k%w/.[Dp7}8YҔihOO?҇˪,9D eKW,[p ƀ*Kiuޒolٰ3{g><?8UH7̵-( D~OriB{>y -yGyDΔgh9c [qPUBI)$|X;r2BX#Ⱥߵu%siD" d0疬g)SA"h]ZZZh[ bvuRaM%-uTV2k7=d؞lK$r٢9Y88CsP/ pq;ݢlC}gj%"{]HBW7s=*ȁҁRB \;}DZĩ1W ӟܤsIGKk.ΣxN ͵_q3ytKKs3fD- iHYقg;fuL?ӅF1ׁݯav9-YRJT*eS(] aj- X*NrɢE]j$L(}x up[8Y立T8J1%%Rd miѦUD1Hpo:;煬g,1sG{ְ(oZ/R1@x:8+U:boR_rb?Ea7Pw=Op)oPd𺍈_UHM ;4jR19jKeMxۥ$:xc[Iǘ˙} wA<'(GS?~o! Y[~HUA[\?Ga!5.%y```uH{$[4u?>t/+ՕZӻ*>xecl5KiV[S x^Zz/?y@ gVv\W2l]|Ɇ+SjOyi|fնc5K+@o:~|^td2b49pz+.[u K=7D2ҷplٿs^s]{2nl}fI)p ge8OSף=qИ&(5 Rbཌྷ3/_|?`g5 xv9)Sc\n NJS5f5& $S BP( BXC~"K81-`&@9_|YE&ݦڇ [jU{r.h0pXߣa slSOEB1C5hhJ$+t}.'&HJ!>8d|eku>1E}@KkgǜV7̤Uy.ϭ!*{&w8m=5??ur!| MB%B ! ! !bBB_B,+7 |l!,P( BP( 'U :*]) 7%c>JR^q`ÅWQD;1&]p%&.J1Wj.> }HX\] v+qdߨ\k;шC+18{ "+fJ=& rAdP " ʁÞ8.bi9G8ZqB| [*`SBoH)GۣUR~W x00)圷FS؟H$iPofo][gwwq`}) ן s8ފP{CZvv|ZgpPV'Bs{KjWm /po/@[9n'ף̗n#mh=wN1 |Zrx3(Rv{J.J}g"^~0 P{ x hʣn έ98:h@\&wGYwGR5v$g [qpވdt''B뤔dLz&^!D%p>s1r$P(ri[m(ű}3sT}ߪ>KP=ӽȵ@ =] ^XLZJXH8kUШT^ogNS= IȍCXZ[zYe10(:|S>^ b?}vop\ݽ<[T-F029oΑA. HGKeUyc!]wL=~ lsO?CKsJt$ q$Tżg~sji;%,5ќ X|-dW !.RvΥ?#~Zhbδ}3sT}ߪ>KPy'6Tz=o'/uAK0DjO j\tF=HdPJ[xԽ<2#,éW_y9]ghg M|Ӥ؏#o][{˟y{^)vA`jOl|8nj,̝,Ҫ_ɣO[;;u+|4Y>943c]q)ICJR!NV m xg! HR[!#rV`7QJ9E1vvu+W,@[-l]N  Wb37ԳkX-~TԭB!O! BBׄO!,d/nb -N BP( B9'Bv q?f9fz4QXelU#$Ջ8Ⱥ@ è)u>DuQΑ-񄯰 ũZDP{/fHCT&9ھty3lt/Q[* ПGmD RH4@7[DmO>!D=p/Іȿ1DK!g?U]^~Ϥ>72e? x@J)_PD"v؉+ofo][gwwq`})YbKC?cir{2k;z^cg@y3r NC:ZZ2ڙkYўz}W;xE(>cXJ IRse'"C1ʫ ]5C=@gK(gV6U 8ƯN^i\:҄ȡHl/s{L|72Ɓ/ P{}y#p]3mVn r9fU?6bB#q8E(@C@%o&a!ħ[]Xׅ9az)Yn+Bopl{^Bq<8ofo][էU})aQr{R͗=2R$$R]畎1ӽ>;G?@Zf?|ej3_Xu/q̆,@X^rN$eU%T9;H7(f8ſ%|f+O_}]8<_ɟ<;s! E<~gׯXC7{w‘94xp9:f#J 7q&HGSvO`2MۄWJ)w湮9ː/sGW,]  l_ 8CJJU(|1gZa Ծ9}voUVP(f^mH'= >X@\ (Nb0{߸0Sf^zJIE"^ª{40{}R}*6r#w׊XQǑݷ.3lr{:>^͛<4^*ӟ ސq瀲)_+P{41{Nap[2Nca ;KGHi4! c9QDA`r(f/;ߜb!ku* P( BP(۾Xl@T_Jew\7(}o{ 3՜ U9B1C@T6[Q&<=\cIU&X4a\&f(fhi] t0uGvv<8V, Bo1S. _[WCVCU*`9 XR.iu* - KbN3Vc@q&8tcP9)w|F7汮I4(!7?ZM $/`.LK="H֑qL4)MiJSҔ4O my?X4%1VWV}o}snh.|5ݣ7_9@$?#OiJSZjnܶ#|nO85u˗U׸g޽ˢco3.V\qi'?ݟx YiJSZ~ڶU௖=T$;I **Ryk$ZZ3JO;]^ D"]t{wՖ/|/3iSP{!ХOY?wѹwm^VَSmh=-ͷ4;cQ_L ! D * Q*j};V.‘[䰚_-%| IDAT؊q-@rt)Rus`ߙp*,`)!;ӏ"G𫃿%/gpM"b&KxUx][е@|/.30;gӟ$##]FىZoh>m|w:5#"Nkק,Wv㳹nEq#Cgw903 OnN"0tQe4PlTk?c{'0SY;^e J-K0Se_J)nB%sfR^:] 1`^x{ >Ҕ4)MiJSҔB!-ͷ4//[^ȮG{ Dniŷly}s6Fr$Ջ5ch˚`o-ͷT߶65nҔy^}ie"=D]z(P51MD1pgo۟>p:MhxO-v̆vޏӁ[ovkOְg= }׈i80^URg۫+O;|{UWLԮڑ[9Nys Vm)fm >)eg# mx]Jy)W؊BP( BP(P{T'@*p-uenFؙF~FmᱹP(qᛀPMK6vub) FtfGclk9Ba- u@;)VR8\))W5&c6O:EcLקX8CɳoXIȲF5BT:WȞNg>[`j#;' }@2ݩZ/͔IK))D"^HKEaQf:,:ſU}vww+ ܗ^tӠC?QYm߿chG<`ʤNØ ,bv}L) 8]h$\ZЁޞǜK傹6qd1`«*J+֧ O$yU0FJ(K9f2K!uDVLP{j[y \WA4ٿ/nQ>ҘtIHR^ G'M98ĥѥ`-,qũa@r$3\9ӵ3\TDrU Y8uY5A1;}3sT}ߪ>Ka/LwąD4XrsY3 #ͧ[w>Vn 'oѾ *Xʁɰy5^u.jL8 _^\zgj4777)V`GGv>p[8jŁʊUm+&c09Qj%f|K~?|yP,0B1>MEpU-<0 Oƌg].Wϝ"p 2]/$]b6$S9lI.3p 79^BQ_̙VXofo][էU})l@'rnWL w}X/$ܻ߸߿ؑIg ^[1kR{N_Xu/%4"Iz Fb`_jgNqdLQ8t8~;OxW/q qCTCSiҺLEm}PLJ=xQ<\n SS"C`{AiK_'S)lUmqxA/]C)Ѓ@5~l5Bp EbЉ/vOQl/ٱ`+NP{ƱiOD'֕5<t޾]H34ju_/{7ZSj?P@0ٜ9e3$eݓh\ߒiu") BP( bNX_)l+U>3*ҺBaz^`W7}O.S*E.HVq P)*:ZZ7my "+!*쉜Om GDEA!YLQiHT8sj@(G 3gw ')Dx*ZrG9BHD{b873Gaׁݷ.곻8_` adk+z6-ڴf(>TRŝ;vTCFEӢt[WZ%ҥj{WF0-8ſ|(RNRW axt;h\"5 3Khi==8Y.~p ۠X`;8;Y?lA:%}- vM "v$9w&5B/K)]\@tfYyYVdϞ>4՞N9-B؞5x@^ǢQuXu`/ HJtyvjזP{H8mZs~}3q%%qJJze-M7}Wr2 $SǑݷ.-3=z3B%|w?G23[g++swkg=Tsm͡%[ rq`@'BMRʼ{ !c3=N29x5uk tLs~Bq~9 kQuXu`/Xh/FAۛ*9Zf/!՛x^K453^K`I˩@rPWjVuX6K<2O4(͂PǑݷ.stO }p'0&t`1_nqOhiu`FvvlF( _"4wϡ[\R(&B<\/A7H)c#0obR>2<>̠<߄$DJ_ao6XBP( B(^ueK;)5|# t"*lM=kӓ~f+d[ꑬ tܰW6)5rdr1B1Xξ ]x3܋<%S:ZZۀNzXy P{Ny:VcnsQKs]願[H\Lz^1 VM{{YgHyc.x@q›=Jq96YxX%!D kEK֛ L%佬 BP( B8%B!W ],[Epyj̞ɮ,BQ@/҇+#RX *}1"N̆* +=NO'XҁW D‰kk x=trСa.4 3Vǿ[UY1ЍYu=*| 7\I8w84&Ȱ7B؞`hbsJV4ீ?BLqiTݚ"!ʥOYl-&凜=|BE$baw ʏ(jU_v>|R(G?-;kv72]ETw^ýQݢH`VV-ʣ^*u5՗{ =/SY,U1L-K{1NeR}%^\íگI|졸`(gVnVĂiCNK=_^`r GH,gpa܉u!:yNۘ=RID^Ixw5P0.㚠V7اbvu 9͟+8>}Hr "ۀ6L2_voEq+R8IݓoBf`{z4£QuXu`/B1{<]z/@ʁ;'^ti%@ P=+,HGKC8OKƫ_TSzMP.}wƺ^~N"uV/;=t? ÿLCO q)gVX<^]ٰ;zͣM#jH921hZk*w曠(VBOIS0\n wͭ+{D+=N adj3} YJ9&STWoOs|PzcRG?Rч2,'srMë ܴ"H8XGZ *mJmb KH$ⵐa^|JVg ?Hd:X0s[nu~]׭^JSlv755\ЉUJ=.g|uXD ^WJ;^|q6j|jDz8ܽ1khX2";Z8wQjmVێ_0?iAiFdaLNw>?K<n.k>{׽dsagS.e Yjm"12;=IFd2DXTrp``|ptN'I C9)Gɻo8؂Hiy5:[_C\hKsS}Тv?36qhT" &ƋK Nڅ^8uVH@J 䗆  8GJSJ?d)++KY`q=fm=%𿤔)Ev!į?kkk[5y'ff孕-@` f󷐵[bmhmS+Suav9-YnVwgii`0hSҔf+sYYU`Ӛ.r>~ЁՋN*_±[Yu7<3qڴhӚ|TSVێq}VgEUꥋ/me&57y_[cOu|ͽû\6]{ݒ%Ͻ҆SY 5'oH)ɶ+,2࢜y4P( BP(/P7"3d_<=^(KʼnpEФp*FJH 0|F&>?P|tƹh*js[s3wKV-10gpH!e|Q*t,>rjN^x2=֪B"WyiԀ:!Rd+SʓtK(qÑq'e)2jU뮛 Q =^?c|χOuS˖pOH#& Df, .Wa$I;V̄!c߀Sc=Kd0>)x8X $0V=Oq(NNZ;߀?*l>ͅ &6t0SB(C^DvЋ;O~ ynzR:$nݥP(f]'N/͗o\uvWťp[8uUXMCT-04NZXTNawUD}hdWLC ٞpppLۘbXIm_8UCR*I1ŸE]gmTH3:BӀ6մ p8Ą>AȽljǟxwq_sf׌V˒VKO,$@ )@ӊ.6дNGiK.R$g'c[v'%yFŲH,9Úy3gf>s_bnj]{+I^QJNImdJgҺ_r͖/u.J$&4S&wO1`0bL)VJ4Nޗ:PNk)gaoRJ(wT| (􁼆ye?we?'K8!Mڤï"hږUZy72¾J[We/ŧ5O;*9Ӫl(¯_VH2Grum Xl[k5ȎUlk/;3vpK{nYRCYHYxNoWmZ;shWi{"抈x3Xo8Ub16jgBZc9%_:wDfiD?QmbWʿ|yNjxQ6k3\E`>[)CDk[)2Q{Er<._!ɐNC@甦W%I~x}߭9^깄'[_GlNlnZy7-_;ɰ. \s4ƅWϜOq^zg!Kqn˙Id̆S.S}u>@*-8oS^붽] a{gޓ\x3X0pe'= &ciPW.*?FC>3[b,)7PFT<7'}X}J~tk.!#);NGJNS`8qf,{ Hh;N9/J9~ݧnƩ|4[py۷Ml Zg}1+ѓ=ja086a "BAX-BV$[,Aٓ>>y%[s5\ T>u{uG@q d?NDъ[@#.M=L|%7F&~jq;'WW?3Eoﵾy}ߕ9 .mZ%>eڅ/3]ˁfp׷u=iYqkh%}s6Yq+B8") h*ZTȵ|^ֺXp6YB!BweO ~nxP!B!B13"T.7Vs*EQƒmlטbF5(aD/fWl>..P9> ^j'c%Gש3Uqfxmz~wRD̋ȟ"+Brn&! ]B Cx m- t:DyIcXZy̞a+ݚU:::KqGxChָi] ֎Ga ZQg'ѓ|;m#M xn蹌Q ;NOLP5vJ~7 `cC)!mFG]Xdŭc?j K/Ċ[ 4Û|K bX[(e 3 lf!OFFa){;%d!DM^,h̞a+ݚӭ'b6/EgtJ5w|w(P&k!,/Ygy> vQ;ɧ #vBWW79jaNoG^_?wS Ս={ٛn;YM1T-vub2gg+ѓg=PX Jr&GRD͓ P+/ܰW%d!DHsY<7'}X}J~tk.!#<@ SK 792Wr׼@YVώm_=4kq_h+Ȏ\?nʙc'{TO=~;gP {Mg#O]l%V0y?\IHAsiwrˆMsl\\p̆BQcYƧ5KvZ=0H1ٻ !&KB!B̝ЎA _1*sL.|fS."g*VSny}cX8ܠciCҒV /{\o#h^ `8 *M6R#@'?KX߽wל`ŭ 9ѓTϊ[?MmHfe=?:<ФmV'cW8K|*Տf !B!T@me!Nh)%EdyZU`N hpbe2J5 s)W3U~ d ~W\P)"Gfp&Ed`ŭ 2AJ)"4FɌRf(>Ȧ"9C1f Ƥ ܲPZQt<0vb\#乙=W5g__߫ruttT=b*EuM낗/3 n{goy-EheteS|ԋOgwIq V$uS&M <'#_ \Š[Zաַ#W1g'嗷'7gSH^r X:]sbZ^#L'EnS-(!$Z7PXRN⌡PheR8Df§>i:TC #d!DM^,h̞a+ݚӭ0Y킵g-:pYq1)LَB5v֕+Lf{>,G';-g\;=/yO;3 Q ֿ|yŒ+Vכud9:u"\) ;0YYq`pu'm%Ō%zE+nLsI"\V,Mi'84{1R x(k.Np7'NӋ)ʯmڶ1*hN![mF(O)GښV@.'}_~~ڶ;lv{II ےdǺuc;Fvpn82n?]Ͼ<еvt%5ܺ }mR=i]W0w3((S{Vq\/I7d^mIC|̰{go/ =Xnh/Scg]>cd@ G>6~~v\YvjLF |ehq10Fv7i^7qΟ[$]_tzB['ß 8.|j8K#dh?b pmRןglϳím7nLmݺ9cJ)2 =)m3nbcf`| Jym+Go3>uS>y ~~ׅ;::&m6ö:3Nٴc->-y[>ǿOmZCugܒY׶*6|Ų+qşǿ7sW]uUw_}Δ\ g#)=ƫn<}隳~?۝躏^ziz:Z+Oӟ<ږ\zp4l׷녑gb_i\ 6Gc@WZi~y;|3p7}n[Zi+GWVv G)rd}}a]yW.7q[ێU,;xKC!B!GLY\O]NWi`P)(:E?d3Kb*SSC]T4շj 8it7ue*!?ߘ.7S?h l0om۞n5|c…eo|,qŏ\wuq.X B3| (2Mц@C! U7R@zW1=Ǵ?JM T=&5t`wxd߳T}0gO)EPFK1 >GwSA+lNo9}њ5s9Qk3q2[Ka V/`hWp ׌8WUt:đtzpb]Gkfy}{V'H#Ƌ%,_dsjjy=lx3ss-uF'hP4] -w|9;//|Ro.]݀V>gLç|6ˣ7uZc:R>çU̒ڛϡRO(hV33j+6nܸ<ߣm)]z5p-K(4i幄ܒ mLÍIkWsWs2qhԍ'm&mv.2t]]w p~ܵkW;y͊[-7iyVuHa#1 G}Q7d^hmնqĆX,-սD// vwe˾-5ޗ}m][7!y=]?yh?wU?/?+~smÄZ9pŲkuY?K<]veW?F2Gh֣۾ysCzGj~YhlW ?le17dJۦMR[nkT T.N_k?[HBk A-0ؑjDs3{҇^_?wkξW̓,V܊\ym禕>88l^7T?^Y߹~cksuu/C@enmmVg}USt*|NK{˧.r ɵy}m9+ǰzC}L2qlxCMss ӽy*\Ȋ[ xK'q2bXq+ N;2 Rl:lw]N$qV?r!y?099|`XkbfB B!;/Q@>ѓylq|IW,Φ<p0 Q /6XjIDH/3jY':R5[L64&X(wS6'<7wcŭKQYl:{ =$VVݜZ2u,)Ȓ)رOޟΜG⼧B!B!@KD| rA9ؕ6_Mx`9y(JcqdsBDk%?0FL|!igYr՚ R ]j> wHy%zE+ne)`:496vy ?4/ǁcdCbJ!sJ+s fk~^֜}}}Q\Bǭ?*_ҍZjb-/G;FvO&&C׹+1Gd?~]% @1j𷵬]ii_hm. Sn>Psַ#W)goWmZZB zmus~ldٻ\3S}sRV[,ޕIpPЊCr݆~'fvu/wqf)KRj-ˑ3峔jX06YB!bnYq+4Ni8nhP(C'17޼>s^_>u3TƒI#lS{o}iX1;#$3kL{fx͉ĭ/&h*up 3sG}9sgm#z2hwwR. OnN"!B!Վ)"O XibF̆hSZ770)dRD^̩NyY)ʢSQ5n^(8AW0;ǟ 뭸vn!'̼o.8mai,ڄmz&X9߳qUĬyyhk?.Z)(Z?VdByNCL2iw,U+8Bٓ>>y%[s*WGGGs !N+nE5ktʦH~;\LFb:V܊|xu7/ǃcd#?Ue;Zq$Q=[YqR7 -C1_1ǟ  ԙ>͇rC;:` 5;boG^_?JN! ._ H./;"B)ǣ/GdVt!Yk=P.&+ީ~6dtfk~^֜n%sNٴֳ)Rfg br1ѓ∘o^^o^ߕ-eW<޻5QvTmr,?]B;_>|0ppM]$r0ow(8M>j};y% 96T+5}tuOrDbVn>I08֪?Ңk[(`eF mt=T͌bv<]HZ?zʿL@ U)I_ed!$p1;s3{҇^_?wkNB^`T˓Hc@(1gU A /GתÚûӾ]ߜlKQ#y޷#q9?YX,ֺ*q_@bq(m`::_,LqxiX-7g_%#p+n] |u?\%5ngMK @;`1,Z*Ρ\L^Αa5,IW1GqdB!BR,Bx<)Md|H`Tso^c*)NrF2v$l\ok u4f-]C~_ j0Br /۷rg6D?vQ`\_a>$`ŭs(O]0~DOb\fϊ[nI5ѡB&T)9F%WR`{gw&H~R)e|#3)o!B!ޒI5Jp;YqtyJEdXefNiJzfZ ؜fgv$l Iah`/3)S@lBxW8ݭF>~##k<+nu?ffE4[RDv)|"*\;16 [@sҨjV1{.$+*O{d1Yg<Ǒ,Dy`&bjGs3{҇^_?wkξWz.!ɑIdn{)-e}??#;`>1M~85gvyB2ͭ*),{2BxW'm *eGfk~^֜n%8In:%RbK/|َc38z' Mk?lnV;X~|67߂¡gA yUK.,SݥjGgy}9WJ{q m_&(?\"5Ȋ[Qg"wNlŇ=a$1;yTTVe5 2!;Dz(Zy TմbV^HFc Bn=pynfOn\B'nL)[״y>.X:3(( $_޺rWOT%Ydci$˩J( eG݅zd䀿a׶BSTFbj!Pۑ+ۿ<Iw[i92G~nӉjp oDOa$1KSy$w\x")AmھeQKa(nEȱ&){"Rg+@kj҅B!]k3Rt;@84Û𧉞>bs}OQd Emm4X~V?YU !B!Tfr 1]D/v\)OL:`#EIp)Bv Y 8%Fɧ*82buO]+-O(Aȵ6f^Dpf'/g EqJQJJC[og$ !,N8zݱX,zˋ#I~x}߭9^깄'^=9S6VJ! j4  S_:P*bNNpy}9?xz[ rP5or,ǯdŭ |z?~']"1ޝsq a`U 3gC! X^<]HZ_Z BM^,h̞a+ݚӭ'+cRDQ qW,_ 㘆/53A&W㞳9ea cu1>\H<>/pRd|g/j};y% p p οa_&v|EuXq뷁 = y/AnZ},3fdAfPRʿ1Y~w}r,I.$ QK6ntz19^ՠM6Z:9N\oQ9`I7H[3Y|z>Xaxg?we?mmMڤ^'}d6_9p{=J^ݖIGh~͏Dq/#OEwbȎy.ږYx#nڶVCF򞢿ɐ:_Խ3i= ±bڼ+|pa?Ks;Ԫ߷}|tM!m3k ??= gNe2؜2`¹rtz[2mƍ[2GRꁩ\OO)S.@׃6X,9m&(}| Jym+Go3>uS>y ~~ׅ;::&mV#g>uΧڧাhtp+ۗg?|!w\zqſYhrVk2/>=m@kw>Ծ5Gގ; +^^um%X1mL<:m_L| G@W|uzHrܶg.Rh& EJ) `4 G5Hfkݐ mԊN B̽SjB!B̯S"1[q_,›Bm~gmy;#L%W;|?vTX_S5XCKQ^;$}4MBw'z;> RHds#5’a`0Cksr3dzI?@_%C[ 1G'[2T1yL&a^]ZkRB;V;$JR] [nYmtMՎ%<&WGhx`87lȮ]scV;ނNCyoљNuWISSؘ7@XB{ܻ2GrMR[Cm!mwK>7Yqm]W|$MZo[ۙ!p8TK.U `p>Ѷ g:Ͻ]4/rs"]Ί K^_fyYؒ:.Si=7?/:ŋNk8_ݶv|mOrɎ_FMK\vŲ+S,F5S@2xͪ󙳷ő}uǖeNY -=RI?p`){.2ϊ[p'gDOsỊ;+EiOk"@ꋲ`,Ks[H BT^B!'dr1*d+wK1Y+nEҺUTTDOb 7xml\`Ql}|BL+OCۀ Ŭ1Aan5zrvu/`C_m׬vTKtl3fr#r1`Ŋ[q?\W X#sLhF;F)VRJW:8;<-8!)7۫EMٓ>>y%[s5b=FƫW],2>p(J,B81}7]|2|M2#*cqRL^W:.|R(R/ߝ\h.0|Ok)PȲw-8H$?FC>.컣!>_wM唇dT98 5?d :d=ǣjZā7M6ML8R* (~8θB+ ze̞a+ݚӭ4Y(>=nr5ӥt/ӗ(caJ k駇?؁SOu/Wc H$2V x 4Έ=kbz"Q iZߎ~^?9{sg]X` O}|!Y)}Cmasch0[qˑY[gwS~:Iıs9f"mkMQ)P ʟsYRZƐJ\6g8[+yjDrm !B!92d'"i$ Fzd=_jWI=~zU;'9[HU(ut1xz%ۥ$ vux4\o^k,Wg̛FpVwh@^2>`/͊[gpi'ĜUU9#ۡCfՀvXd;,8H!qq[Ș~SJ}@#EdNy |\8!B!bDOb~i0XjjYoqR-ǺՕQKhŢ/Ğh=#"ս/}r~ݼlzZ&bvXh ,S|ƢbUS>t6¥lafEdFȵ%44hhT sy~hkoHq)(<< QBllj<>ox r")t:YcXZy̞a+ݚU:::KqУ}t]ޑؽ{ݻcda@ζ3_9xv+ E-` #K]9D=4ԵKmZāHϾT=lN8j};y%\0゚)Nc(-*h_)C#1wx=V K65PUV܊?&IlH%*FH(gR *0峔|>O8+/"K{桿@ GJ)$ QM)7۫EMٓ>>y%[s5bA /vN`ƵlȎ+IYMK/޲9>ЎnQ旬*9 &жh},P*•o~P oÿ~ !@@1ַ#WUοNr7tI("23nd4Jh۔cɜbYq \8Û|:ѓ%nQXhJ68FZq/MӅd_,"OVާ>8RjrJsRlSsBi%[,Aٓ>>y%[s5ʯ\{|!5{HYR3b-;.\>?]DhŭlSU!Q)"<=,^;bԷO|tK_^>\ 8Tַ#W]?{g+ &L،`I#w`gAEP0n#Ft~)8E3G CPG-') Rp%Z4w8r6Z|BJ/zw<#&M.B!"2Ybŭ(Pޒp^e$)OU= Zה"*9\5Pm_^^_cd{.+f/&]g$ :] %iM];{+g)R~O>dT0SCi>Ф@Ms?"0 <Acbŭ&k= y^ {a:!KIq[Ȩƃ$dʯ+4O_FB!Bc?P ^_zSylG,1 >SȻ>/b |ӽ? E%n4﯋,"{L_DTA ,"{04;7tH\0c!'\Ê[̋ȏ+E䅥R\U,"WJ<[=yFO֏peB#N(3iw,˽bs3{҇^_?wkξWz. Kb' V[_w$z-i;g8yO|QW5X!Өo`Puh_ 9g&]j-RCΘQ'3goWw33X S.GP2Okv1WĩSlzq*䗁rs +n7 ;ѓa$RDƊ[a ~ysdtBٯ_SO!z<>h)7P^T<7'}X}J~tk. GKuu1@LEd?[+kubyO07}c7WaKRLVJ&uډ]?D:Mg] Ù>kIoG^_??9?Ǒak_62RN.E+ Ě%R贺ռ\H^M;o_ky||!ђ=܊7̞a+ݚӭ72-e[\̊"v^[x@f T%s,C}|&6l67 mKRm;4 d Ʋ9faj};y%I},OQ#=zu&HC )RPѢS|u)>' *IQ.H*i \D7$zJJi*@)5AzֺouI3wRzPZ~҅B!w1EJIv d_>.y&Ed ű@F)Oyyhqᘶ_̇^o[qt:<̤3s{7m'd8fa }0030oX 3IX2 I ,,BMvw{{KҮ%ewU>ѕ[J{Nϗb 63ư~!dԜ5DU|F^3˟ `}5E.6GMıt i!̡11z߬:ͪy39Gb~q3uEmt<>_ DYfe[_핅O\RcbR<-K:/# Ho{^}c/;U4n` LGVUTw`d8 ^'L;sk_xֲ># ;!x;RbbbAA1e"(+p!,_ш#k$ t%ҍx*!@jN6+gʆZw1r ˉ|oȲCѮb}Pe[GB%>txƏbl^e]=8v52   (0e"#םwMQnDa}V9qcy|% Ң`["YLTАH0qƄ CO;hd`D<7әb^MX:`Qz@?h "[ 7L(L%$eǑM}Ca@BX{v pEE3²91bj&p=c3d'GyA(:0v|i/lCfVXVoVjmm.(3_L>YiPb+wgt_wmxoiF*bs3iJ;gBϱve헻':y_+^c'{@c&$${:ice9pFD]cXRK UX[jjߏ??n)YpsrH`Isԭ 4c?y: A)5w!5cw{ÓeEX &2)bpr\&!Xy^L`&14cYGFw> Ӣ =0R̡11z߬:ͪ I&WκLVvVfy<*8?D.@f Yw9YpJ"C奓Z's~0QG&.]z;~ ^ch՞#*OIgw=]I:E-N]MRKZ.ud,6l:9]U!FWG \ Wa1 .{B$FU۵8fA1,d.ؿHq10) X_~9 st? /.ʀ(M0ҽ5HicB:EQ$雷1{aLQIEbuS7չ(gH]t跆Svf]|űg}fj|˘2u`1m٥11v c>pr)f'DUcǎnY0fvQ|azds|m4b2}V=[cLͤƀaV9M9VQf?QlVc+jV?]ەvm5_f.]p\rӋ{.lo`4/\rŊ3[V7;_Ğs oZ=w(qnVvJaXſ+o: %sML-YW_ [/l FsAk%γLKd::)8Wy\ul01w?`!>m_2[?(Vuu4E.xu-_pv}a;8r`tZ]vZFfcGyEF2<F)`&|mc>a}1v?c~ @X.wbw%G=ί  0+jVFCtp:lnPX}e=璤G_#yD4#46PrJalڅCZ$\+ oDr"l,tq$5'1KD'4cp_u՗msȷH"ٞtpy\/@isj0pkO8gl>:ztg:~[NUdtp\;':ڃI` ~)O'+vRaTΝg'F"&.*e .p/), kKfTbPȯJ!MƏ3;0j8 bHDlP?sNӂ1`8v/ܰa9-sxhH{ϱ`V*YY!/Ëad0>:Y878^~xrn5QbyrMm}Oybo_O[ݸvwQM"&'_xZ3ho1ŘS|-fgwΡ?s|O^]O"j J&G?h&{=a_\EEW{ԏYYtc q>8Oí#˧y&`l;߾N:7fr?Wi=7v.ojő;<:e_s&SKƆ;oݍ_n)2U?(fXd۶3o%-xt߿w,[vmgݏ#i✏T\1qkP<@0Y˜suF"ydTDP O- 뛪WCT63ư~6n L{ÔT.o.e}a(ɉ-b`a0 *T~dYE):;%ww2SMW|q[kgMi)oRfEɟpO͟pc7LQ2rH׫Z x(T^(V0/_`po fHXk|T;[0s0V:缴bqv"   e@ S+ZntsĜd;0&Gaɴ KP|>it.i瘧``\6D 遅lWЄ 8}mp5x|zQLzPoWrH0 afD]~ po8QFIDr_Ju%luƞ,~F.HɎ#:p'8NaaD@'d"AAA+`17I1p%ܜ`;:ala6/ۄM#0tuѕ&9r|RԐv搴iq_/S9Q|ӛY,d]sy96mi<qcPULEU.Ubm֒L2Fj͹VqM:[Ջ wűMp0Dq tfBEPp3Dem3sh  ?7ctV\A+kW6\1&־2`$F(jpo8)d0n0nRI '~ngsUlr56}cQ{~Snڞ& MsJg: # q='mڜMIݙC)Ҩ/վYV2wDG~\dE8t)T*%: Bnwt0-l'L䐼#(pU7 NËphvnk5{l| ]]ty`V$9$7ApS7zyUU\R$H;u:Ce _|zؘ@XJqX:AAAOfjci +p )1'`>PL{eْCFCۗY^rH8Td^YSE!\R&$c"L/w}̹hg-T[ f@wp90,('>!rHIڕ.8ޒb̭L.. 0H&=po2J" rH׫Zx}۽*cqŁ[,0ߧ#ZLAAAe !9 ceNa 1l2Z!tY u_֠FgrH ޗ `cZ9>9l)c[u!m7Wt((>Dv^$gD(ދG-i_&d&g# ǭzA2Wl1&r@8o>':UkCF:ɧE~C(D ,]r[~jJ`@Ƿ{~9?Ti=ATEQ$gK=1wж94?VUU1Z[[+ Y#wv….Okiq01X+{FR#"FJBh9f!}N}YBb /jD3>/I% d&-v [ϸ9[ʲ'Ǭf}L뾹}k0u]%L-#rƭ>/=2)T~dYE:dz'/'ѵ`;(l~.&=v$sݗVMfߒ!đSF ķ|7ʧd f"m/^p:nAǷ屴 `3|1~9W*+ `s[*863ư~4. fHa% \q q`_G_4Z-#4epK*ϮֽL65_E-{s##HIƣ7R8<#kF4kwUyq[NoZln]_|SV!䲜'MDGVU֩+ x:=^{ '同|Lv ]߾ܶI- ]!dߺ>QL| %_ SSbs52)CERΧUFǷű\@^0V*sAT 0.怶̡11z߬:ͪ P0`Ėg|+eݛ[_:#e2lAM.$s"'D-l5x22ɱQcimom`u2+ }AFZ}hiQߐ[j{a>pl|K@QzGVU9Ͻ6]co~]Ek3Ӗb G5{ܻw8t]W9&l3YG,poxr5T+rH0/|{- y`pKtֺ:l |I ƹu'0t_v^*&O8RA K'  b(6`<FkC7 ޝPzp>b IDAT,Rx=Uos<^;crqy}JG9$k^wz.cʯy9B7 +Ql$o`6`\Zf2A s#?2j.K&.hK$AIH߬gځs" ie!JhEpyuݾ0=8ex6z?y L}A0X |k#   NB,i) dpggtCkHgvB:ғsOyt=nw2k"NQ3C5h?X16XS?տ%l iaIVl"]AІK"0Υa&!9g ('M8*^4 u TYD'[i1W$u|`L!NSf"p5\,KóDHf8Do*/_`8GAXEQ$u` |'63ư~r jʵ.Γ-qs-(ț-Qdg,@kϋ7>//TX$ak 3TvB}+ZJY#q5X8f.9t~EQ$e_m߾'8e &^tgټvP'eOR1ԧܞ Ls  TB(½UEktvv g@&NՍwMȧAijci+[FA=TH q$mfagfiV]1'e"WC5mag֟z]u?:D NyU_oNn{ÓrH2&9lIN2әXWN=H&96zξ 5÷l.{*,0S 8Я8tE& }Wඹ cEc0V`[4}?z,?coS| M2J]w4͓sJ67wsM&lp@M9;l*ce! Jhpm7l:M5Kɜ 60p # pbS9_6?aʿӎObzN63ư~4.(+E)]0k [LίHhߗ9gR}cLȿ6'7Lýq9$FzI Mڌz.Nb~cbAA1W!7`Z*# Qy|!Ԏ.~L =V20}CFBjX+~\Rhl4cWFHZd+Aۑ IZY E|̑oT w8!+/[a9$O}ЩgX'ZU[`#|r[UO廛j0Lw{/$8pcj'R[ ι9s0f_ `(D>-EMcl1ؒ9AAADR~ Scer! HHZ0 +*ҷpox޼$hU)gwz*exGtX5^G㋳+HWaIzCCC@&2ALKwPpo Mwrj m7[sP ͕cz̛㒊C1 N# s5QF&=d"sh~䃨,z:8O2 iop+WOy9%_b ~q˩ SCQ F;}>ߴ|CfVXVoVjmm.(ǩ\#-oƪI7^9`_傖 WM4R/ҧ2}kȘ1%l/snOC̵`uWVKn GR#T*VW fư--g~E-#v;9rHt#}<8П*>-uyFZmueXTl'y "ɪq |ia u)R f1 juvBUpUƘUna* ͊R;'<qι.b`s[*863ư~4.Uj"F=d>i&`I0y;/lgn.хW;"}uF~ " MCd&5v n _u?p#XGJU݄]~5gOJrUl]Sh`K<9_jߏ?.>M5GnϰY!9K:oB #|a; urHOI WW S2*ښ^?tD<;( 3ob89+ƘF[\ ShV߂lpMg˭ 2 #{@sж94?VUUYulSHld¤\pRP䔃};fxF͠Q{vNfȯм$nq:uMqyFWW ]~j$Rht#5p"cLkjJ˜k}?zL;|ӗˈdMe7E~=RBS؟\uZ_Qݦ驜M&C{|# r8*na*7_: ]kYKc8uV,   M~ErcSf2`4=j-A2`l$1)~i2j^vI)Ap¨=#WW1CSXօlh C:g.Kq$h&ig%4TpSt#t9NN6!5^NذͶ9'/;L].˫ NNarڎ[l"1$Ld9p9k.Q` s5   <$a 0XMA/0VیVoL.mE1}͓1Qp.9w0Uf2@faA[`"pO4Rά* U78M+2&6ZT+acPW4CB!9$J3G\E&2aVn<y0pcc+za _L(^M>ꗛ63ư~L7쒻R.j_qCrnվY\ cӵ^s/́$L6pvxENW]8! $4W!F:k0j"R^Uq؜:YZw 0&d$crLH.̢aF|9m3sh  ?7N"7s0Vd9P<]1?ADɲ0m#̓`5 +xk⭇Suܹ7Ta+L}F6 kGb?fSҹ/zf)6|ϫ}?zL?&l%snܨ27ݔ1aA2Ih'sd5=Fy. Aa`dcK+J|_{ÿ-$8=D?#1*[u0#3q41`-Sw$V,   _qTrHv"!1 7o &r5$}f! c 8 '+" N~hc^ Ia/Rqt>Lq<\n=G#F+X]O95͕!uY{{ZgC 0½.$8=D9`3ivx[%b6褳:X/c1_bHc],.@.~AAAqUx/[t0.Jg`W6NbLԡ^ yd";UZz2d 7oɛ4U *,}^1pL_-YΉ0@˜ AHd=E WHgŐC2o(DJ1M\4*E "Y֌)op+g^Oxb&(َv|tSж94?VUU1Z[[+ asx%z?mCgƇ`D\9$kkn抻ob,#DlF#0ٙjٴÌiMY1LLI;zW3겹` |죿?8{I9$8Ε7iU7顧_ Z[C.  S:`”yrI61.4Eut~fq捑Hq+aJ7K~rC'A(/0mfagfiV]À{l<1qK_g=}i` :5rHͲV0 ]JY-j7 Uxj|pid@,3 ]~j r-}p,d\8m jߏ޿:;mCA`껽b '}GX2ė(v NuRvnW|ۇC5+ d;$g6={F&#ED)ƠrZhްQ(͈yNL=xO9:يAA1\۶]> `gv, >@'ýl}~~Erc-2Uݦ#H =FiE9nQ *r0e0`d6(7lwRէPN{*, *Nw\BkO[O\a~~ʉZU`.M ׺.ćِCy]BCWA>rHhw?bA ߵA^ Uk-UUƘ1v+ckH0~p1? #ޞ 5p?E&2AAAQ*FU6RCi< H0 7OguUN.ܰ_]ʔ׻XեLynJDD6/#dG&t=#Ú '*CT7;Zj;Ƙd.]oCr}D%.QSw:5,d̍eY\`IN9PAR'U5rH^(Dp5ȄPC7Ld@~sv/XAy Ɍ1 {wp^*jv 0RW/fex3J.6l84X=)VRp)o"}9X57>+r2?fGc@0h4PӴs~yNk(vqp3ڊ3bzr os쭉" .ξ0¶Hp7,?FWyx߇2V;q R˵ 5;(9?ճRN xZ3ho1EQ$q=ԟBc{^_9mDzlbGCd=I ̠1\Snҿ*uw;'' ks_ cĖ?l}TuE)gUK,;^~pwq~G;S˚b(v޷]{Y%K\~;6FSh.롮Sx-FW&9o5޷_iakYyMu0*1\Sn*u+D`qC}g'ls!*,XٶC{> .M9pnR\oQ d~PbNj-Y7/w/悭6Oq `phk.8#%eVU[̐_0Oe1H]c2i#0n\%K_ s3Q1z//?= J <V?Y8783ƒf? N9~p`d2;{d,=d"\6Y\9$Cg 4]c0VCա!9B.yI.M}9Ԁ~3iQY 8}W,c2 #%88i5'>ђss \F^S551Ѧ,Fmj*3ʿ8|aוgg<2qdf3:ץJrYqX~jZ˟GFˬ,y^n]18m! PyfBUN%K&V7 b s]AqY+ IDATs/|@Q09@|-(JX[_a-0gX\.Ǐ ӄs1v+{?9E'^}?~]*ypkd"RvΓ$RjV܎0Oʩꠣ&cޡ?򅡍c;u18D0L6u$5"9E'$Ta 7(3L>o’LM,Rc^q]lsQ }ӣZBֈN%Y !]_rM=,B#\RqlmŨ=q-IffrcF-/ۄj(C2߾v%2"1v'8$dIhoJ*NFJk|k*-8 ,]#1&r!0OΕ68T#b(F1Qb19$o麥{q϶lt_|V7]UK["}Y߶RKً{6v?rG [lqIK_ܘ8ƽgbճsr疉̄@bz !7C?(Fݷtly$0AW zN _d"_}W.[~Pb ֫ ot)mwA3|C AsV-& cR> `ƛ6z+L{`I~k~O.kA1Mz?'a">]~pι0ɨPE‘BfVXVoVjmm. f9${W֮lxa#l8d7vè n2όa%41ϹM3෵HgE[bsbxRKFخ@'Ęl!)4!@ڼ tNqF޽0u .uGV\68oc@%ǹp׫*^vn_`[[S]MۆE5!Wb?xw7%A 9$k^w&q{ʩsdæs;4|xA kSlQ`08~+C8}?8CfVXVoVfEY۹ゖ RHݏLF7?{wUz{WZGے=ecx#lc !!CxByr%!_Bp 3=bLlb^l3fH?i%Y#uU9GG߽U]]%]@:nL^0뵊s޵h+;[3ڜ/x?WAs~E dXI<+,_PQDr /j 5]z$ʊrWftH9x3o=+K'޻0\QvLXfx,|AX,F겒;$;2}coxۓuP^#IdDG?cn 09 rX \;NJ~"n)7N-gO'J3Z2 d=`_ |QS0T_JAU9٭&*sXXrZ>uzqR~@!B 3]M/]]o2/8*uLKQΛufwG:p\.=`ZҺqH-"cԉ\T)2\{f`^"yG8_޶mRW2iU6@v0FFڌc9$^D=,KK,V;4t&нXq31*JY ם`B'Әfȴe05.q ;7|`. cbXue͞6͹ڶK涂ݚ+P"UR"1|@m7Y^9,Idt?m\*=ZcM 5؂>BNxTlll*1OI~A߯q<-%8w? qo mvztȹʅ GZ xQw8lN#۷C͌\aヲKVT,=SS+TĻ@\As Fm\~ܕ6̫hSrN캛1<'Ok]Q􆁿\ƢG?xֺS}=`2tk]h\L ^/쥸S}6*!Ge  o \ E1o4 b!9W .I$ !n`߂{ޝȶY=io/(5N%8w~zw:xџ:za|Jy$K:u};"xz^8_{w4 {_h<5'+PM4Y.RU#V(N.'yt+y[S ՗kR;RTi./XNR OhmbdB!Beq*uϖ͵Ҟ:gI Xo6O|䝇qN6eu.Zڢ;wo~+[.PE=?Nfclӛ}x^~k?K'r5oT_*kc@cuJs:gyhO>k3c7H >FSMDILk_Y\%ԣk>ԟ9X8 ۷6M+"xICR/L:n.:o@Jׁ"g[W_ 9B!B<Idc!"g&<-'j_>Zv?y'ZD3s㍮WT# ç'©Ge-,IXtzx|63GbBqWE"*Id K'$g5lRKU~UyoβY)-;WuB\:Su1_x<6'mXm%~922򴸺j3U'grw ؂# ;hsǖׄڝl0퐱ks\1ZOYud'R_Zˁ D-x_Xęd۬aA_Ar$r$j/y3{#*e  ;{n{UkG2U,&z!k#HeƵђ_R&nz7Ѕzߏ^sZXGsm\97}  ?vv%/xߔ* x{OǺ=`[?/XSg/u$oUbqxb%Z</ElIJ8-X? mz҆A_Pk~KRu'#qV5?;VvZodؘ3^y3Ⱦ+Δ|B!.e9-֩rF͏ Wrmc.Gn hkȍ>֐t{o9ޓ}? zV`OKe,ޡJ_/@,4r5ߝ"LS\7=[ zOsب Swk8*Fi^ʧR غQk}zߙ;#Zbmt!Bp#@z)n` 6C詜aTОNx^@bfwwȜ ݅=Xgء河湹Nfr0Zsy8#=҉L6=&D= ?zXpQ`f|w]x~>>@ܣu3&hP4K2-#}'e.~󩾔| 2q;6pԣSTo괁<~X鹠z1sa^䏯U@kjѿv(Z !B!B=`*gXTK=`'7]rQƁ]7;O5Mu|)X"R}Ҵe}%𓨦4mYCu0unKc|-0{IznN"zГz,iR"1c4Y榇bщinb~FoE6D%I"r6S.55XZG m}Y2^klZT~#:_H:Su1_x<6'mXm%~922򴸺jʝ Og'G9g$|?=b\#Y[\hӔ=]5W\fç˓I}Gsidc}l 9kǯ>7=c_jl^($Q4nU(˜Mni'eUN8uo5byɯ_~O90aƷ+siw6 %~$=2x (} \|?pk/}X5PB ˜a\YpGH# r"E F{uqW.(]Μkn!3 [x/I=6'mXm%~׸O-J"9ܙdI"G͎??Dqf,L&7ntQf^sE{^{&t:y[0W-ZS0Q870,_T_dn,)ޔMfM]SPxsSGAsWĖX4whpPּoIgJDb|2g;,q֛AN><LWce)P(l?yX(R.gN/gz#G~=iAumh{ :1. 5wd:;f'fSz2f'nxM|b),^Zs{ T+R}kW)liu0h*;DݺSZ&PJ ՇxmZu`ڂwQZ7Emt!B9:*Ij2`\]M3׺UʌkTz MPsf `KЄ" %KU{2xr ᒾDkwwSɽ{ƽP4˨֒sro~45OrYM@.\6Td+ijlQ4TVىp[2–s9F!\Dsz*w,cpc/uF%D'bm-p^kBJ-KLkKѠ IDATFZ9取3T_:lZ]KB!B\,qq*JcMMy0' #*I1bHJ!,,Y@L\r ߫e׭Gux״9֌oqMPѲŠ:zc 8b$2-|0dYsS,%Lwkqsa&|xF؉G|%5Dbqm.C-A ]9߁ mcGrUXag)˯Ӻ(<0U6'mXm%~922򴸺j3=x,{ID¡',Ӹ?;~64$e6Lf|ǶHWɹC]9C֡aT疔k~uވ 7yU2JMi8V%oubYP3sb([i=6[xޡsa;w.|0 E\wIˌ\]Jdc ;ľ\Iךso8ӵ<K_OV8$r)kSO5ttulJ*]WIep,6?9*=+ȉqHa9KBط^`bgmz҆A_ ύ_jqc'@sPUΑŁ=`OKoSXliOXfM'zsVfu/lpb}o2ǾrדѹGnŊ)s]׎|q].',pLoqH=Fگ}? z`O5K~D7V<|2V*>41M]<g%F0K(п}ަ'.*BܨxE"y=`7,)K}j-b"@ޓ{u{C/b*HT(6drw r")`s :e :[t mz҆Apoq66哑_} H Ŷj9=כI&º Ӯ^>bժT'"E>t*7u7NN'c9q7VjS_o^>%+k_wvviGޝRdiK6sXb)W9Y?2;A>}? zV;4xۡ6?П&; 064foL\=oʎ^P,LӼ2o{( 9,x2x"DUȖjV[ζP=K67'>~sLi^ʇRO$+SksJ("`ӂukZ\~,]!gzUl[S֢za4R7{NMxymgYdp6՗ʬglb*7tmтn(kTGpѓ1G笖f.ˀ (|o:xv_)Kg-]ŸiqDl>}qzd\n|A0<7>pMРQ#biXe gv4X-ʉg c:uABXeṫ=`&e.M#"q xR[o޴m˧{-dbȿ:,n!BLgڵx>Q\\K93L}=AZZX:o$2PiqG:ΡW)%/qڷ9WK/R98sWrFnd:X$Y~vI" qV/e$tM+"C[kTJUz[)M}k^9sHmZZu !NxTlll*1OI~~Юbڮ|u7@Ke?xԁ:22y ̙\KZ'e9~|Nƹ 93I`iMK+t훓\ @xЦp^Tmfn`~=o?OR\ESwmH"xC4X*ϝdL^Q뷜{zz)|\Wvq{zGڣNW.d-А&Z6%/Nߌ'֟T;TSDr_iPMj]koreJ/%Z\Y_u !Vl7o"$f ^?_bWo7SgCe 6=O&Ӭ^uRs|5vE`]۟d?Un 8*ZW~4Wц#_;"_akN>Wr_,U.B%c6vo%H85Az~=k=!௖:'sٙ|ĭvϻmF→9A?59_K/MٺS})1K xCYJL L'-I1KJ[;*s"]ŽO!\XlՓ66z S#s#w$EՊ_O<97x?q0\M"ju|V)3H4vH2ٿ*Xnd=*3 6Oda\>$kM>W&w~6tFyvrLv9'' cx6^>TQT\ޡvn8mhQ34Z̨uz"H-DHvc6|\yW]9{ގ7o2D~j-b"{:X+yZ EҔsRZ/ΉR3?uBտO}+Z)ĻEpUTCl0~,]!Wg#l rqRԱE|OdzԅM3׺RW }x6n e(pbc͡r{*]  ሡ/)3'e |]pK/sןH.).j{u1^? ZnuǕRRJݩI)uRS)QJYJv˔RSJ}8gN"VB!TIMWf $,Т}]i>40 0mqӌ~{[> 6ፒt 3͛ҘSYN@1 iFO Nh碣hM3$?c$rxFH"tH[1eZkXcM2-Sak0B?t(i{_eyId_$ 'M yPb2Uoc!b}G2R* |; g&W<|xֺ(t:7L|d۬aA;~QE7i@oKo !Α_WWWTIF g~ДtX4iT_*^qg(#nƻk:Ni,7N:GjxP{t/jMٌ7;v])+g4C nϲzߏ^gx n!Q7d z ]JD.qSMtem*f[iܹZ=`=|S} x6sW1@ȢIƆǏMX検.GA#uQ)u +y xn$ط^`bgmz҆AO55 a,QIorq?`-̘fG(=6DUn &[:c^vGwǁÕeJ}\.Մ|?GE +#=[{^zǟ4A s9xc\G~OhK1s=SH gK2;:;bG4?6oaQ[m&\_O^|عܧhp=TJӚ0њ'T0 `D2:;}zsxZ&?Ɓ;= f ^@q2;EycNkLNJ= 4M#SM&WҋW"xlZNs47|lGV:ds9o:9 @Gd[;,_!{M55G}Gb|OJMXnF{75zߏ^A`2kCW\ΔCrzwMPJΩa/s/H?dBM_ȸ,e\Sܓh~l_Vץ5Eh2i$Xu1bJytyhq%L˧ZwU oC!B!AK ..= ^RJx@a Cǧdrg ߋ:'tQr;fi`dS{I$ ;j;4v!/=ETGѢS+,å/p`G aux\eonY9OF:Om%O+(~--?QelynϳJѰT"hdcP=gQ5KW`39o'Id!B!+Idz&kBbi/Y%Id\\K%)^y qD.%G*!ʅ- {/3gNMuA5Ei~'U-$f1 `Oko$4𞵏ȷBZ cd\ELA1}^˭=`e.>,?Bm0 '-/-*6eUk֜Yywj#sWfhZRBvxw>^>ujMBZ:Su1_x<6'mXm%~922򴸺jIQ_U}l>~pdܢ:kG`/FȾUIxfC*t(J^(0Cp/Y1ϯ>Uxl]Twbm=.ZZs'BDRGƚil߯}? z[_^ek/\9<S.5. EbL+6eU wkW}n.exE/5\%D]O^38UNg\Nl*/.(IW3c( Inz N$Wi;#J)l";sxwBn`߂{5EII~A߯q5.S(Hɷvw^YBGo-3,]L@U/g==k6_󦼓'B{=û17lڐ^<.@SKzox91C-14''g2ՄwεR~9Ӕ_ ߵ jΕsv`S#|y?+!Ffۉ('+>{um噤WR+?>F->G;e T[I{ie kR6^QuY^6D"y!M }# mz҆A_Pk~K=`KS5*}؁ΖCqeH^z.謪X3 m'k0ў-Xvty"\͝f+6),_T_dxIޔroKE3jEKOħL޳:P}? zƁ;'33- wh]C;GfhluGs\ R&»$7芎q{t,cpk/ʪ"DO6n[3"3 {7 #4th4e KTo&KyyU!zdB!"x%- d 17u]J"yd!/VUd2Ǹk3y!]i\åSi_ {n.Zs{\wiMjOJO ĺ2dou<~e1-x@[NQr?;|ba!՗B:ԟ"1\e l}_O%hMZZ>7J>|O]Vm]!B!i{+>Mwp|``ÚDX<B̏TAJBtF6]s .%qbEfL$'3zmGwR*杣:lh2JS]#:*j7kb72= |p;ZE^!4. !9DmI" ?yCVDngR4r%((QZ5o}O 66BNxTlll*1OI~A߯q<-%{0,] Gܼ8O? q=ˋ>:|8 Ź0N\4]FUر)srfJa @346w$͝uh3:=F;EC3pSxGAD~[ 2ޡ٥[>i= yBYq#\FQsn^8;Թ=`+o/3R{5"Go)6g~rSxy!4aG(Ehv]n*23XOSQ$,Ȩ Q,LmVOڰ J~ӯq Zi1d  :t:߷pwc#%pdC}o&L6cX^yiL-u?,5d֖|P)lֶmvE&CR[{RiLxG`O6ZN/osa7i%^zs#bDHͤq4^.;wC?j!DOv?g~Ug斱0֜WЈ cU,_7ի%RZZ֔RMZݝ&D\XlՓ66z_k\¿iP}}s婾Ta>\dNm$_5<=?=:T0ǧE'zI (VY\EnϚŹG1#ferRZS~Dw Y{Gl9@)sF-L❷Nx>빫=`epT_]rI!QEx7l]O?ʍ#3тpI"M.>Ft(7%)a#D(><^Smt!B,g#l=L7EwĿ[o_N%\h2RV?;hZϷ-9Sy?\q.Aw \S;L̴C#YxB.R{Ƣ RZmd/M@ 12)2)2)2)2)=xۃU@monL?xۃt:O1KYR}#i( IDAT.8-Ӈ~Ŭ⓲e/eS?*;gb[r&TLDO_rˣ^=1K-cly?\Szspc9Mi˹8[~9]2ܭ!e_V|BGOV({#[{{/ڑ :0Dķsr\0qW ;_\>Lg d8.R&ekY·N:0P#NGk_wx%wm㟜8_hMQPR. >ˮ%qMB7{o>UJR}cZKJ˔R 2D/ E)ޤK۹g[ʖ]֛N/N㽧-\땲+(Rv}Wz)6{XPs_ׁ}bƑGFF~R泲JOvoߴ0y|Rvd-;9~ˡC} ~ne-;ֹ l%edz;@,}kvJu_|I7Ǯ-7˶qY嘮[XyVm՛K.=lY2*=煗oym-v65w E__rqߧ#FyyʂrN@}gOlz!f|Εo Pn7yo_zIwpq/{oΦVz0z}^Kӫ˷IYPsgIΗ }WsYooKC7iGkq]iwK;ԛࡵnz*[+uO$r ~RϔR sBy^0p;`:lh'E?W2: w/G||n4A qvZeT_*-m!՛a)]LwL~+Q}cW#Hr2:y{gzC[kś'5'VKƁwPJ= |'O _>ŕ okQ,$ϵ)?Px\Mc#6{XPs_R*[>._boi 71UB7cCH {bcH)˜5xLM?|y.>ᴴ# p|_p7q/sVqQ+1|aJQer:;/fEfǕ3(!fSuk)(ԫt=~5Β̴!y;WO+cќ{,j/@elfKYr\5OH|*ƻx).ԃts[!|?i/,g*mS|53IWƅ?lpQ.a%®fB e7ޱՈRZ륗Z+Rxp@oiO[KPJ] TY²{&KqR&eR&eR&eR&eR&eRx7u[cq׆65w쾣U;^~YQ6S*^hܶ9in?<{8](gRXǦ $՗*R&eg+WwdG|vf67U+FP/L2CĎf=8{0 >xۃqCl{~xbk'9/1 3;w,}tuud{M_^?S ǯ-g\6 jF ?Wʤlb_Iwx+)o _عoZq$_I,pݭMm~j?tM3Eoֺ&74 }`/ϞPz /L,+lWp:|Zh̓wD25|#B!B[;*@y6K36^>:`j*j15ЪuFR}R^ef8zw!Iy#g}SU:[js{cnBI~ 8fI ̑, Yo$b48瞾:K(ѴntTR߯WUV=%TzwW?.P~)HзƬJiW,+"RE&dgLs E` w^Wӿ'9|ǖ/%b7ZRHf^X\ T~n: ūq{QKk!_:ri#Kfd>hkjz\B90C Gauv߼9;3uϹLqpĈXCbwNep! @bnf\=BxX7W?cxM. u)vZiJ e}e#돞* NM*,{ݏھ?b$c %cp]>U"=ý \g '>q>S=[zyԟD- ^/J~cyI!Un1o*AF) 2`gŝhr~+-*'O($~`riepI=n嫞QJʹS}UBwOTǵ/>>%\5G>l}*{5N%؀r׿^=ϸc݁~d#ա vOȴh/-Yf#bXd{i;C>ǽaQ!+mr.O;!duP}eE8>2t!7}򉣸]M~y~ƇGy"ox܀gssGߍ#\XYZhk/K:WcFPR %9lpB4B"-K\~$R7;ܰΒ2L v*7T>z}SS*ׁ+v㞼>$/IzN*k$.w/Ǵ+uOyf;VM o8هZ}Z%~ոW`|xw};10U8Gv,SHL aW3luzi$fZVr4Iu<-ffϥN|i03"p Az7Sq&4q1,U.+y^ mpDG޾ Sp&3?!< /.;`@,gs\Jwd앲[3ywn0^u> B]'[׹L"U ONLN7\P LXgg|,mkDz(yh3ĵ|?>mkc !B!6G5\>OtGfc1QC KJ"[Cj74qc~`8L3aud5di@'~}9*l~KS^XZWkV&Z_ýVyYms/f`:{$,B!b#uRn|wU9{A7Pw6"!K@l3s>-G-[-[}N^3D^Wy[ʄ7|6ˀc823բm) "EV@l?#w1뗁Olq8-泇{~ ;z!XX9a[gR5}G?ϟԙD^,Id-$bD7$[D^ YU (uu8dwt \]yQOmSJ8ppcazz"V8~xnnBl#t:[D4ݪa;:Hl}W㜜|\\CCCMKyV>i|;*Q$rw9 ef`_a{$S#K9d<4۞ ë*öv>C!KYQ\,Ұ2ǑǷπ_?{M9>O}lѠ[&}V,9|슖$bQ[_H"5A]BJ&>E QA)E@|,-%ɵ܂_w1 +#@U~w7pȩ2İ- pfm6NaV߾V߫qz5.!/ƇGvV~+E^/L?d-WD^Xܖaҫk'>:|ͳ7~rȹ|SEr{#Q_>w})|ޛ8 ⓲؛|wͿ<exr?o&9^b%bu.;I>||4YR&aáCk|!InNFiQ-H~"Zk8[BYUm6NaV߾V߫qz5.!LW>y}jjX-HT/ظsD.W[B5Cӥ+/u20tq.H% 먉Ƒs:%GX`Kor:sˠfФ +/pVXp:HR9wKz),b2VE=;RAmƇG~:VTtGr4u<u.jcfud2`s~%:!e!dь !B!ɓ+VVK2&#V?hUJ$;vͱ7嚞 I(Wp+KPs;Jܡk)m &"rlM5><2B}I$b$bYN"WaeS>9 (֚2%*YnBbB%NqTFf#.8هZ}Z%~999bϻȉ>3b,Qm 3.93pָIdpD.kj,/؟3P̝Ξr𪢹2ee+_mp_x3UsthsWw'R{ΝVlcݏ#/m'[2S8#ר;p_tLM\=ha^hDc}:* 9T-1uN"hZ1!›R˃$bYYl.I$ !Ah=DIl}Wj\BM|ޝGǎVJ+/GkfDnr4vLea Ew wFukB{8hNYK?O921^~Xktf:VpIoIYDL%A^G"-Nd)>_vgri 5@ :UĽ,5]AN{,كf-$bcմi}շUj^KA:_9B ~ h|9oKHd9V^a 3+S8Wb(BZs;Z:Cё͒Y(Tw}$5r._]?qc3sgQ\qEð|Ǒ'o|x@~iO_/YSR,k!U2?Mz" :x='d=Cfg  ֔o =ǵ1Qo|xVfclvB >zX.9|`C1=]SjnI\t :q2JQVfYhͷ`O9DJn]HBњ#uUDIl}Wj\qJ|,.C6O7܃;tU_eXbK^|xAC]XM'hZIvЏ/M ¾Oy~/]}桩;aMWpb|`6x`ӯyo˔ÙԷ?89>vlv[ݏfo[F&Ɨ.f_// WM~ic.c+ֹ瀟!{Q>s5\naDvvwQ)|tNqQH|ya<kvH"Y.f;VM o8هZ}Z%~ոDXD튏őRSqOx.?Xd_/sߟ~X#dr2$hJɣ9rKegK|֛L٣:cN?!|)]*O~G;f'X\S1a(zfb~5mƇGvc֯Jx!^Zţdz cOsk;?$r$LBqci/h|@Td-6{_X'&n* IDATv Bl;^+.B!ZejFqդRlX< Hm< ukV#Rۊ] n)- LFJ52ZH" j:c_xcOktZy:\PI&%Q双fT!B!l}*{5N%z+pU/J[o(3O|zM@'}>Vu Q3u01&n*uR@33?G wkunr._0AS9 \ONq߫:CqԌ{;p:21VUڧqVz+0x+Y֔=7cK_DU^.X t kS zsɹ|LMmd.I؆с\Y ϰ~5tƇG~Y?121:kih񱸉[+X|wkchraSb%b %!oKjw3T*`*Ra) 94myQZB.KB!2>9/R*5+դc|X<6ۈ(OOU74$~p337Z`dqr'} /Z )}k6@OޯlNvVbc9`I˺?kLc|xD_^Ƭi`xdbG՞co|h2b}OsTjkON3odw4p9k#+B!B~/{pkG2I"7E.`m-b=ƭU5:&t#һKP@`٨ Cg)@S vܿӦCg%љ LC/%QQOvDrϱId!''xq;$-U;NEMg١)u|lӸIR-1!D[HA:0U'ZmDHl}W㜜|\\CCCMKx~)7qNYIJhS` 4žWtb2oB<%.NnNf߿1CsFj򄣗˽ NJ<^e5%f&(ha_Z̜k'zl]k^L~5jƇG1>3>7yD':ױT9OmMP͓Mfc9 p49Lrw)$,h5G>l}*{5N%鲉ʊ%.U,&H&Knj[D_?qO|  yijwx nTe:LEoMنv WV bvpv˿wxk|GK밪D:v^ƒSR&x_~ofb2Xh_qԨ{/0<xĸ|Z} ;lۛ@u{ 1g,̊Ek1?RT&Mq&1;*G;8yuz}|Vi-3> n iXֹ??O"%9.EN),%c|ѼV,]!BU,.Q$w{{ê6 V~WlH;U6{5_*GpLP^7>r:Quwʋ.nޱ|v&IM[5ۡvߟ-U*||PlH#~i"UI}Sטu_K|,n&_Zn?0he5?.UYRe·=w*jT1R^O{ױT$R"z @ZA09?g׮,=u?2R!B!W%|2i\sV/Y*Fl$ruTJy&3߾x_T4a)Fr,9?ul9c2^c?ԁ[g>t=Q5Jc2*PCiF$~!I+'ԓDwl{{Kl#;:Сh'䔲ȭh( dtEf}I$R?m$`q>EBNu`ND/Gfd>hkjz\*C(pwUUu9>wm歃^XXt;}#/>w_v4{K}]Y=`Cᄍ;V.Q ;}Tg#|eq3Ëksd'@]*޳cfl0}\jh+o|xd'nm| +YGVz3PTdfgYh+(f`rHqiYz-JĂ_uK DipXV>mJw];WӁ9 Lgi L}-擶8هZ}Z%~ոD H&K#0E鑉qI*5Azͳ_?Ľ3Ujm*W㚏 g'2~Qsr<{Dxr._wUݧR>rʉL(wugcg1Z9^2\/@qۓ)421~=[}6=Xϟgg-kC~.t,8b)?ӏѥHwp8vD͗> ܼ%? :Tqa0(pIR9V-e=[T&R>Umx9q>i'67B!&X5-Afd>hkWBl̏~p΃wVxp"k[oib6<."5[FB:wWV9߹kz)lsrMys:9.5[}ƣz+q.BD[*\vT2]0鰲i8ڒy:f㑉\m8cøIz~!up/O f)m'{ʜ]JӾ"sۖGOȍmc~IGݣG{ֶ5LR* /T[k < !BU#I*=+a.)U#xN+5j%IPnA``Ǹ)SUv2fy_"y˜ G7/|.! ќc3bTr49؅$phYL֘OԈŻq꽺$G5#|xTpb((1R.)G/c[)Bhkjz\uTz_DIm-\}m+bwY!+ܩϝ~xF's+Ikjkl=`F1S ;gϟoG-HVJY/p^'Rv1J_Z.\5G>l}*{5NP5=8 2,^{V%T߸3؄ssMQ^kڳ8b9΁ݥ.wnNɷ'}-K|iȹ|zS:wVNG8xuz"A+-Ν2){ݏM۾|1k+YeJlFo~y+9'x_PB=os7ςeI"N4G"#\)[%M$RwoMPr3hrevM*> >|vZ> 1R?y8~~ .9j?*hܬB\Yܻj7Hl}Wj\ g|,.uBnUq&r>8u=Q[Rzxc]^k-X[*dq2ӑй./BQ+],,?]]{ᆱwj!+C*gKg̠rv\)OkіmE n~ih3 #uVφ⌏7r=>|f0e#@jssN޷t~޿2./(U0xk\Azȏm~PL y$0?Q/a*_kJQF'3\L"7hqitD&Zk=/ˬ"P*c )*GNiK@i[:.b3 ݩ KdMpš,|*eIIx7k'5I"/>>G}Iǀ׬DxMCB/GhI"E}+mkHĞ|%K/D_7>|T2(C@Co!T)$ZvhkuحM>Rk}~ZO)/pժuRۀ?W&NqTFf#.8هZ}Z%~999VHZ= 05 \<-Z\L YV8{97iȱ.lnC9윩B>oѝ& 9e8*sH[6W?cxT-Y(JՅit݅A9w~mN|Ǜt#q7>GCzTP9ۡB)^Nh@)I4M)X_>ZnI\mbdbԫu2A*cٳsp-ek8fLk-Գ/լTufWQњ#CME\Jfd>hkWjk,&w Yd)>_MU/Vk$dE1?usҘc]^k-rݶd)菆v'C!o(MWid>Y.mx\nd;^>P,;gY>b$10"CLh*胏ɻn?VXBGھ_=,uGViu+ீhz1ra5w~].xHWQtV,"7C͖uwoZ@"5AG_^C0ȢP`mMJ)6ʉ筚V@mUZI rUbB5w mqJ^ӫqm'brXh2dr5AkeJ3E{Ņc]Ϝ|9HǺZ{vp۝W9?|ȶώ,˜w2[*E|i0rH[6v=_ۗR_kT?vh0Rt5em|q9F.8\|921fy+*8 /u>&G_7wf޲~,K;˓Gr.hSrf@n" 䑛fIs?~DJ_CM`: )" ŦPZ 9`:3Z4`ݯWzyXB!D3\nkgG o'Zͪ`|9? 0k%Èt9NP̼e:l.u۝WG-O|;ϧs΀id{Ca"^ʮ)x* jvt]b?|N ֮ F&[w> uݴ_J&ڷx;{?GuE{"TcfJda+u,gښK|N?v''ӳ_=2]v Œfڊ?Zk(/qՈk|M IDAT?[yIiXB!XLfy$%Z\帝z1]ӝ7 )r9˶Of27 [}kuuW᳇Kp4(LP ;z1uƧui|/^V[eu #d^ЩuL#WJJ+{~6 SN"_$r}c8ԗD*֑D]I0jE+Gp%YبD${7 I"?"IuU9Nt43tiR3d@=AZ)M>ya_*W$j5tLՉh4oV<"i}շUjkhhq5ʪါÇIbKEPBh")G;92Y)_Hb4 =g}3>k_;:} ]Nu|qQtƧ) x7 g  ʎSe-\6\0o/ŔgpN)}=:fG~]xcxƷViz⌏"u<1uL+V]]g@SojSlRT5,#jIz-?,fקeǿTʫ7`.l/Y YZ2.(ԅZw !Ah&".%mqJ^ӫq5L%U½TLF~y]|g-<)NJ_=Xm`QT^k0[9rےR|,>/rgGOqЅi{gSmsy _zV.緕 t3Ow Dm~8ceXv?ֽ}#u<)=WY}Z}4X<3Z^M.3=̾p}ϸͷB1w27?9J-SYDlH"TSu,oDJF2XS{.PVPR*b@_YКs4dOW|Ӓi?u?{9 \R7Hl}Wj\ uIN!ڌ1wlމ>s_*0M"UnTz@QXXXmd|dz Ҏ  I悴_ɹKuO(tYYCev'[ʧ,|1N/}+JvѕloW1F&Ʒ}U ㌏g<6hzӁ>tT&SL gOߓ̴+s9GED瀿­[9 $RoKbc^7TNdFip4A?<.7;>ukl\VZ=;Pg~ڼV,]!B1L@ͣdx鯗* -Ʃ,2 IW>~IU&((|N tg4堾d:]E qvwϕ$򕋏C$~mSY:cYXχ5QM:C[ xߪ8z#\.i[J:ց:F͊G\$mqJ^srrqq 5=.!Ħ;嬿 ?dN@#2ILpk&!=;ܜ^0rg`.;}/WΫcfǹy3%GUgs{ytgzRHw޹D+gqɥvݏunk}db! ViO?sXO77F=fg 32cW|;RGAf芏 ({qoK_$tV~8R7g9V3>R `o|beZJsqx(h嫦˸o`B8;Q&".%mqJ^ӫq !6**M?vK^hy¹%.s /9<4>ror$2HkD>wu:4rKhM pxcGgrɹ|1 d;o90ap(9m?(.6KGumH'pkI9եU8?{b'0SѤOZ}1yL99O!decygo.؆oQ~ #7i$Rߒe`'Y`?Abh`08ablr4kNbZ6\ॸIdpʕV'g;VWf;VM o8هZ}Z%~ո ~33/JlLn{foH\r4Yz{,˺1!:9VBErK;*Ìw}*YUv)Z}p[tBP( B13Y:d4Efvݶfn & }r9g1(xk8&"̘y[ŮKyUkE@B~WQC {ד,iZ8Qש`_~W߶ 3f [모^^߽B9oh%][CRm{-MħMB4rN: \hEQ}'OY@?]BAV[|#~OSs#6h!!̬ٛU!DMx !6dDV( BP( ,f̚c׵!Ø׵d;VGei͹C;BzG6Uu0ߴhg5"ǤXҴ^G3]1ٲ+A4ilmoiM zGYK Lg_W墳DxR Eld!) lLZrej D#~L$p-?*vTrÉ2h=M-kQ>wbiH)Goc)=)T%Ѐ9uV(u$Nq̲/GquljoF߿FVDIz{{KP,uLwVh~a:=ΌdonLS㜀f  Ŷ3VGJ.*6TKpf˚r<)\8 f棙&r2*,yq31cfk'v 7vTKd;x4*r$dL*m%Ulo=Lmt: Vʿ_@qW[lo@h4 &Y%q&M3РhPɇҋR4pЁRЖt- J9{Q7! x;'f xﰁ?RQ E 윳U'-Qf6l6hknV] bqn Ʈd7~v۶/t7>cBcx&3ȹ-ºѲw, h¿{ErÙU }l(m~pLMW `u4~_Y=o4B=W~Gqf:ޏr{pLq7[ziU#|M>*'}cVEbfl[3Hc:"ITO\N4%,s8-ׅMZ bnD^hh#Yсs LYO+IBiRʆ> np,Ն߭:ݪKP,ʌ[C!13(dG*xZ>3#f/N+|[mVs K-oˌ2$\'kh͔2?t[ޒ dJÀόAuꎺW쒦mXl禧&Jq8&Q?4(OSV1s@|VRU= )>i׾ЀGpl)ɲgU` R8}fs]TD#n8[-eீM:;1,M#-l ΀Nx3s\o<{n !l88ѕ󖗊ZlWJ)%ަŸ-YBP( B f J 55̘Z#}F-ia4ᛲ66ʐ# d-hЊ!pB|=^c꥜.F /mU ֍걘X9Ur0*WEՏ O3[pfl_PEQ@PmU=qwdd<νl?UtJ4"wG8_DIV•p,qONәt[yoϋqB`qK13\3߬^GP( BP(MJ| 0[C4+:˖v}:v.+ f@[EZ]*{l;̉hemC53˞s˶s˶M# t`8q|OޔBJfT/z\voaǖc뙻e(ttZ ⵿ϾC;BuU)}>UT=|r3fjP\[sd~kِ!2%CqBYD#Aca&D^vNzVS^BEZH9!Hk8pLdPzC ᔟjF򩖗n_ N8agң8:6GaA_wD"$]uץP({_u=<=_\^`xxI,GkC"l8?_ p^q^Оe2lTJ:0dvÇ2RS)C֕Í?#+insǧ'K\%~a%̸o~t lbw 5ˏWVYk)fJT 1_x%55Wv`4@+Whd _3槁%Tfyb@LY3jۤ4N–I [Jh#y.ʘU(V.[swEq2,Ն߭:ݪKP,[wf-y~E.ߡ`KIGʢ%$/bۓ;c8/,Pɭ= tfe3>ڊ6zi呉G/@R;^zdh5#lmݺO >_^VfG'_k_x?4ÚW3fUVp| Ze633toy r]@z;O) b̔0Djo%vmD)Nǜg6NX %h%y9 R4(`$zֱBh ƀ-+܁:6GaA_wNR(KGhҺm[Ş$DtIQJ钦%9HpxЀn[u|B"'S#SϏx7;3=u/_}2 zYIb.;>5`@T+xHM+7 N# ªunj_'0clu\t5& E~*r.KJQlM&#@/NΠbF4, hrik*jJ| 5c&0m󘠴49j#lIBְTH)+/-YBP( BhN̘:˖vq>Y_ahIp1,0ׯfzq^: ֖ :FX. %x8g[xIyΌ_v1:\=JR R21ฺ>5}n s4"ft. @|Yƒ13Gm-6xF$h) š$p|'M(ɉF:pydk M&^LmG;ypB }&]Ry:5de* BP( Bqj̘.pwYŢ+kl^u2iEРژ9z]p( ($2bk[BQ-䮂3wNkqV%t]eR\Z_BQJJyxՁeҺR48 m$+O"x5pЎ"e?py)屺 T,9tڏf}p8_/=cxT645~L$O[w] bWk]M 'qBɓ@،ie&G6 [ð51,O:,khRyf a\8-Zq^+[1L| ȎFKefǓ^l]BoΏOm&x8+`j~4k?Uh5-nj:MO@]oN&;i Cʂ.<jRA[qdjV?Ӈz(RP5mL}Zwf#t6M[n >5.HV4BgV ?,{qfc&)`v.l{!h8x$`d u/_ }6U- e}mˎ͗Q :;}*M>tI>v_o4mޚfG[ƪ_Zq8j*~ZwU=B¶ mu;KK!Qk9bCÚhċYjI0cflB$ H,N$\^ i`h*onDߞ~}-߅9)e59Yg q޲cxT645~t.Bt<Kf̜VՁU~_5ieGXnbʓٖαic:$*$h}QjF奈x,ʆE!O;]2L!hںqIL`Ռ&Ț9e;MIC1c[wWS^]uGڠ0 -})lݙB|'-Cis{eɅy3DM͓|꬀6d4eZ IDAT@"6(BJyZ E x-.e3sb5)`2Z],]P( BP4/flD8Zpf%SK*,/9k^}X4"])o] Z%S4 ؎ m#mti+xAF{kZkBXW4eC`ܫ[h0gp۴2hJ;Uh+5ѤXr̘s;ixml~n噙0ѤUo͍#UΈk"H)Gq&˪RP( BP(@<,f*& )*/fM t""3L[Ϻq Ǻĸ$T9ECaL^X-Mmcn$!e'evB۳Be2ݜh W=j,0cV࿨D-zA;˖l+ufFF:-V)hD9 3Q&rIQд؍9M#/3`RV&rcB[+)f)OS/+,J -FEH~N̲UQmm(ݪ3HPK#0>0cf D\fY-97uzZz'KL:#)L:g 7O*1sE0:WE(nӅ>]LNc=6Rﴭ֭'~o* d?4h/Sc#iݴ%Nϖխ.|5@`mԻK-)ʭZ1R:d[AK6D͠R446H',kρM/(Eр @FФ26? s(#YTH)@ڨQ,3[swEq2,Ն߭:ݪKP,6H͢یX u/? ?T /p٪:Y"?]p}6jo,1eֺg7e?UTx,e?>f4}UTy7pI?1NZDڎ{W3NQz3@+Nx(D#}8GPU`εg=i@R׈X6e ]'i9 d\Ûe$+ +}%pЂ#yHJ)?GzοUX` q޲cxT645~t.Bt<'09ȳx|?Ody_0HZEM˭th |G8yH=ϧ'7U}-$u[d'V!L)e3 ld/LF%yu*QT$ MZM`SpA mIAB"mN"*@#kBl^蕢 !ڀoTpBNWJ!XW[Y~d BP( bg"q^99_&מi?VhPp1sI$#/nhOr: ;.r9HRPԒ}~Ŷ{-rk_ӛ~.h]KmBP( B8%.Md*U-=aF^\}vwnbQ1!Q֕Hd¡Z8d2}&65? E2[?i$J'u](W㼀‰dh7PEXNCaLrN4;,,|JR)ӖJ(G`D#,D,e"7>sv'q`"lYڒvgK $88ᭃOEiB[qTf _<x9pn Oa0N<.nB\#a:<8F,?X6'Nq̲//LvřQmm(ݪ3Hf|!{OKQ0vg.=el.HPۥ<:sXf3'>,j>C4]QTpm1xΑ8KjHF2fFhH#Y8g/O; xr=OtN,E?6T[)寗`9gyΌzE ,evpzj0Tn6hknV] bx_W;92]Ȯ3=DyD#x ^K4yWMt)396i᩸Lڃ2 Iɳmvtj܆sm QJY[(|gs.L,BjݳSU4c`,YH~d4y(`$[nOܧnyL5745~t.Bt{Sc:Q Xآ}%>cK C_L{!prOvȕ1E S0uSVX֧jhɨ pvSi?&?].5=UfKɑ%VA='=Zۭ=k ]:?Z!<nb&wX,0tRFЙㄶnؐ z !f$K) 9:6KLJ3[W):#L>:[8'<rnK*ߓRLܖ,]%f vȟ6o"v1XP( B☛gxFge}rrdZ2}R̘iO˞kSAY^Jf1 bx7-Ag1CV"`cXA`$7}]E 3%UTqLV0cfذu-u6rK8KX$IgLE}Z}S֭8&P.pM4 Sh:A(jww ճqK13RRS}pB^/ !DNHt&rE~Zq|&:&83َB3f7Onx ΔW)o:,_zkT( B(ӕ%5+/n?_~8D֕ne"@ ( @ljEȊF#?<>yQ8?Sr*?ڞkudg Dn UE՘2OTg"M iOhZBXv\ nS4,rW!7WoSx9&ߩLÛn4h؀%e: 8g$z9\ɉgq 185 a0KF~;xNB\ |(?R_6&Nq̲/矪1Y:3k}}E;J& w}f,O߭:ēt]BX:S W1 hNβ6 fGAjZ B[VY oپexw?V0@\n}p5ш\V*m,L6F Ln^"o%5{FG}EN~d4-N:>f=_>t\ԏ xѫ?[n~O(XECXCR!'>jۈF40e*GkKJtӶЖbќ4$)]EI@$7n$x*F!<)efy+fE)By۫HB8gd?,i+9;]uҢp]twn~u]y"c|J,^]龉$tm(ݪӭ yi͞ɐ2}ן+Kf̜֕gs.KEDI>"0L亣 gmMnyN|'+={^+xvf[NW=i wxnjߡw.ͣ+Q5 =.hW} _ Y_̞~X lsHpf"Oix7αa[Hu!A)gg$'{*"RFr9d~l™ͺKqe%yμ;l$_QB8sR}`|pk(4gcEط3VI#%طZPՠwA_wN)pV5P絞X~z,o@M)YܗYE23<:=l}F5?+JxRN32bZ}v[n{`FdwHP.f\?42Hr5fg?T$gCU13؞<`wwkغM5[dH."yj@44&!Yc z ۧtqM0ldwۀi(X| mQ5a32\-6%PS-g~}?'OB'L=K`"++@<;a蓷Bc5azJKkJ7LdBX3g#$Ue_\U>~S#!4s^]CݿA+E<a& #7=0flǂZ𧁐|mzKU<5}Wpz3D3f KTg"[kDKGV[ueaQ$ef U)A4%, f"?\LR|E.?iYi?m #m4I.GV4 zR!~U/ Wun)B͟ ΈSBD;Rt xr|߫h 鴟î zQWkݳ{Yc{ڿЁqe"W߭:ēt]W-g"q\,΋$Aьi{N˻Y t]^ZSx>eZ ZpCxLs­'7NZk[{zj{X~37.7V3fЈh|t9e߿,kU}g| ? xQPjUltϪMe=vx{)F8!'3U&Y||k~h2C4i\#XFeάqc*iV1:e$/)!ĻJwxRW+Y=oLrڌpj!89/MWK)VbнU\~OM${E*{`04A۶)Jd2wEJ.+J<+|][[(m.4s~ df7k2,{prP*H$&ݢOJgjviTюD"1}nog88fqe-;6\bcX_sEDžo?v!3fKnЬTR 둏|e`u}!˭oojHPr𽇿yNsBn+Uv`?' c޼8Q&≰{>( ^=4R^նRJ*`ݐǻUxiP`};S޸EmL<{(9fLcznhokm{/R6oE}཯\0>jog*~ݗoZ C2Eۺ.>W&czY޿&>l%n*+~ኗ{U!SvSS[H}?TYd{Wϟvy$HNZ 6rkU=;V+1s\O_v'汽C-1) F>3nDeӎW30^*gN]-Og)VQ!g_B|)> 6 =o|7b{[UYueB!X,Y*ns\V(r)47vneR6˲@ kݤo9ʚ 6{9Fcn҇_WtYe?u\}[./^⍳\Y%)W:SN&nMM}y]n-b/;^ϕ_L,[Zoy+ReNٹmre.{]XvmSgyƞ5SO t~b9Cc XwEK3;y=!qz0s̡J]#^v΋Wk[?w~,eY{/|0cf>;l幜Li#3GˮKdFN_gH>DRJw^^oǫ6 p8oi3 ~i䑍M~?o:Ԍ3S]*3M>=)ꜪLP( B*9Xz72kp `[d[ZjU("w;점0b60imH==JnCE14K/@۞^ (=- usj@ˍ3mֱ XyO>$I'QF#RDNpFL+)Wp"f̘~0Si?<N_LGQСS^\ĶeWƲuC6@wf4o%[$Xjt~!7>ɗLk'k$M%$'%CΒU7;[_ e$9NQStk~ا.RʨR,s r>W7?}2s4NN|+MVri7{]nӬTb-϶mG/=ۼ:BkEO)8tln*;#>1-/CDxyWJ.\'O|3Evj ޽ܦ3i^h^etw1k23fz{ۯi~""d |{S2xto=?9KeLMt캍L>gjWqއ Rԧow<;ֲl]7bP:3g6VA_Ww G'd}@ۿ>S9957{Yw^/pՓ拯B3\̽ef R4t >>%~my@4|)yE\QN#!DCK/JlT" 7 4iM Pb,eh#Æ瑂FqWn7nT3Tۗ][>lWnp,Ն߭:ݪfY3fpf>ihf̘鉞8 Kȳnmh$="fٙv~:C\obㅤ-dԐYS. +3{"(Tf|=\LFv&4l)rnEi4k3cfIUG};5+~NÂ1z7u)L hB1py.>OS3504z<ai~r+yFp!hkh2MJH2HI޲ ڄG,%ωgEf$!B)|óYQRn;e@S4 n-mDBP( ['`V4_EjW֝s_Xjޖn#!=0.7LɼP+Q3\Ĝ)KRy2hK?_Jf&WBQ?N?j5M3BtBdu (x<{qfWǁI4L#EUT]@gl#FVIIQ "v1w(jqr$9o8Ep?T3!D'ȧڮBP( 1N+ ECb`{ZvNGҳ!Pߪv9ۺq>c mlpf"+ٕpzE~䌮u[j9nگ:hte4\pxB lY-^iP [{F׏ㄶLf2ՇNo"gkR x}FERϕ``BI7DkVZBlԺuϑIZe 3ǀM~BȊj= ,%Aۦ 'e*lY>Dn\Th3@ ZN e98#CcF4n}p3iT{ka_6Wrn<1ICܩMwwN_[˧7_5Tr!pRd`xy| Z:h/e;!ƼzKG^ V= 0rv9Nu8q׫"gJ4> FQ4#? bha)-z1qQFB9a""]ye[qUm+R4+Qmm(ݪӭy&ri 2y3fN732CΞsW>pǏwG#Gjv\jZ!it hIn޿jxZfԀpQ*k~<lNYnjޤGqeFZC>v]nN(bef(Rs8/^_hR3aߔb&w6$r7>WWe$!jx!,rY~C9e& 3/OJ?gpe;Pf6l6hknV]\Ӎ&2sΚɥ~b ysʅM I'i De{嵝c&+wㄏfεflV0P_!ir4?VtJz\kgYΝFfE3}{\_ =̍&)-38{[iɖ8mL6x1$$A›kdAlB7 d 'dCH  c[2F$>f?z cIX333Q?~9=$_2zO,GuqI~$7͂p `gP73}R,L<_m$io2{SS&lO)$pa}C?ty8 +Ѝ3 =G$8;lҲ ُfVF94CIJB7g?ouiZnF9)ǗDB)NY#`0 Q8֔I8zyܭ`W,53l{3JH<}f߷ɉuPn*㫓p!Ȍh{8!4!>FYq KHU_B̈0:SQurDKdy4G^{GOaz#2|z?3L{_̣:alK #aSOL!'&ƑjB}`e,]*fg35̘̈KMI}> 3"'J͙d]^”kBnݕe;PRwn9^B9R ν W<4 6OIjbu\I&@S& +wF |5X}p }Q+Yv^6nP$FяkJ2CPdY:N#_^dΠPCP:xh kS&ښMp3(uz6Ըk64RIއz>T=_X,;Тj;12"^]qN9U?ڻgrY-+Ky[IlK%pLV>~@'oIzNW!P$PqfxH `:]aÆ;`J}Gr!FΒݕW@)}o|tB"_J\V!B@_x9gmL6c.;^2~YyLvhK*ɛJ|hbt+8穑cyڰsg|&|l6b˛󮿸Ƿni>镸f5_W^9.N麊ju/hZ/mt4ޢh!d~UH4_rͦMX @Ҳ:Qt>U%-, .]k/|G=֍ q8^l"}vlc곉l\v'6|S}W:;= uHo$KUmW}EWf[J4*MgZZ g\Z[YsgAM*ɛ pOz啿אJ~zP[;kzvxVcztޏ+Bs U߹\;kAyy巿]e_l4z미邿fwr$zEOcvFPríku-ʑޘteˏ4B H4^pûߕg>$b+*:#9<5(|Rh)U wńSJvs> ` ~h>q/8R<<7{>qhx3|ȘpS"RyPmqǞ0d>Bo_^ VMn8#{˼˒suݘ\+gq!s#!pl4ϟuyQP&ΔV\=$=0Piɂzo_|`yDpn:@bTa9ɧҥ9(!,&R*C;Yͨl%8ΖTU[('-rAY !6XaNEjbm^ O'iLx9i빻VWBqti'Mg{6KyLwz-OVNsG/37&9[v~{!XPX2}~)q"<&[2ޕfkA^G1CgC8 @Q#rGBId{zq`r I{罟RR[.W~L SJr R:5r)pzG3s JY3r@.82s@Վpf\G˵8Z#ކ9Ϩ-gBH l6/$$"r`V55sr 3 tx9sHfQ@ @]Y-'ÆjRH*I $9I>ZlMi<=?c}aP*UqL[, ofU}>ũi3 +,Zں)ffX\.׈$IO cHv\#EVɰ;d,%A%HbbS+6ނP_0U9p8*L'-#lJ!Ow$/<`VRʒRS35 _ ]Nvdrlk4P ~قjo--;QN.Jo?B _@z\#@w~ٔ#VRJDגR ก |~>! |_5LdLdSPC-91ylω<'qx>x/ ܷR92`l[6BJp/~P`:[Sj{#.X]ڷ3#Amkn3_G!}[۶s], ^n17"]+xjSu^\MxtQ9bdL6{lTNШ=i5^m䰆b㔧CZSU(>MEjf#G9ʺ_y:󻌠s!e7=qӍ'v93_:BӫnX~]DB`tvC4?o d⣿p4$tP@jV|#qOt6,3}0Y6w=?=do$A5AqeSû5/gٖ-[;vPJ⭤ ɌS'wvվ_% Q議]yPW*UU___t E&>RuЎ]N!D;X12:-1 :y 3twY7%ПE$E9 L  IDAT˙Ví[bUdfVK1 i_kżݶJs$L/WmQQ&'${a>ҳEq3IlkG* NӪ6NtO:폗(F(G^^,l~w*HdzG f tcQyYYx Ζ~?4Ojc^]fyp%E/#g@8kA߬ qnj1\[3JJ !2Iה7ڠ`wtaOxu]:}}WޟlLJz fH~+|FӨzl|-wD3"՘1pd])Bx뢁puPVUjzxٓ_ýB4ň]]"X7E KY05w|ΥGpb_ߋ&s&'Id\3 |ϊLOMsT4úЃNLV(Gҏ.|`3u غ|\ll_Һ- ~-زB_8n >ty~klx dL? #2q9vMCp? `7JfHfJ齄 }O% nh0 ) c0ʁr(r@(ꖣl&+~Q4^"׸(@Ō1YnN1'c` A7hf'r n/g1XOWH ŇqJ&̻lj(V#2rd 7iZMUk{눭)H7r+ I[U5 `]r7.16f]4Sj㵚:b/hqF<ڮ&96N] ` }1 y߭5./PW󀾨ZeB̽(p=P#Hl3 r\:Mo4U-~3l7JJ`p sUJ.6g [im\nY#fgšT{/z/}u^V,x9n ~0n;˕T=&0/|5Cƒ ;VyTfqy9Uts[xػ|dۤWyQюb?\C;jgM7]U:S֨55Aw(B.uqXgq+h^tb0fAnXd"*@)Ap;Rphg1KBQq h tVnEkHfe~6VmY)ĀX ,QzNuvYӐ4$M ^D֑WRf2 }'1SĀ讌)ĄjTR IB4tiwøy cOD ag;ժt3L ]@zJ P`?G A'+In/]afc1 :XMd^Ը*«/˥HAF˲9fqV I~b0N~jY/O.qpi*L|ƪ~jtᲬyhH&\k J)]]l%ˆ ʑ$=&Vfۮ\.I#o2K$IFѯDdgCNn$i@]6PauH %nذq"vn4γtҩgAjC4_9ﶶmuG-dohor={R쫫W/XZzȣ +ȅM/-.ml֝.+b@okֶнW~5t8zX <9E$t{/'1 ﰔp}ϥ.Cpd^vzzf$ !I8xTnJv}i^ڥ$]Rmذ!cGnӵVfK{ [ \Gy"Suvv~ f,s#yzHg{3@>ӯdzIʒJf{zԻtڳ.ǼI%yQt~RoJ2-{v;x7zloh dvcnxӪUmK©𧌦s,$oTuK ;%͗\w~{QtWuunt3kb@$ZWx/4h-I=sT(yd'hέ=6wۗF<;_-ڰ㆟o\~meZO>lz,Ν2Ѿ`߹` @]O60Y)yľe%k]|އ~Yl +Ȼ"c/h4T}-~i k[#e3޿Fg 䇗~}/'f44 fDґ8j+^-kU^e$:>(;1;;#v2u7>NVeyK˖nq<3(xb_4Υ"b+*:Eۑ`#Zl, $u幑eq\@"S_Wu)(q%.sgLM:qWUOS۰RgBH l6Q4tl7ٳm@|$1bu8cmbBI\FɄ4-ՠ(pbxv٪\Q◴=p:PX2DҘOY`\.״?9$I,F=㕁EMlYU %>9lY9jVrH=.k*5M 9`"H&bbhlw;"`M2D vnYdJg~iә/e=9Ƶb@l7sm*UMh˚ =f@:YF$F/po^WZKcH/mHNB\ӓJ +zn|BͪeRt:%/M/D2{oEEG?8ֶCK?U۪A6jIU.YHiu\UF[y15sH ڹuH1dZ_-s\]5|_B~BG?ݻt̃ [mSlj}P4EwaY+:[T}ڝ2RGɽܿ #@YavAS ܧnO1=lzy_Ckw~CHqk_ zow O7Ӷ{<5Iː&Ϭ=3n}ȿw,#:^G43o_ \=n`2&޻ûe IX*q[۶K[.5/.m.۲eKxǎ}8J(@ FS]d~[O)}K[DȐ"6$I+ʸalNz$.I7$o~7=J}r?RߨzEU z$%Ѧ\g!>EUJ|DhÕ#ڄ]-7B$CQ`ĀhI.QRQk"-֞qP"S!娻x 97g\y֝}0'(P̽cs毩ѝ07J~wyj y<>]؜`1 ,{pqLlzUM Kd( ُwp*H3i~r:/8fLRz^`sF1a س9uXVzGJMF#֡pF^.JKEiTid+RiSs5Lx6nBʞ`3E‘1"Wձqn{+^u'~ϪJU'lZ-<1&xw3P NB(4&D5= B>{UՕC*xɖFJuTy~xY: Dŀ8V*XÒ=ShNnAI]#1UIH24͖Lq`b|az#2|3|33"g3Č0J>gc#BJGcCCr^LOJ|78|&(> { 𙌒%PI`^^-ظ)ڎ乂*Yt/k)9N%89`=幺c~`% QJd|ZJF12\o@ Y%cHıAY/j c)FL**]O O$XkG !C{S V7V5*/ڴr5&y3)d1 :1Ed' *E`(t,#H"t`g5im&lƝ=8lw`1 d5Ā:M,&@iZ RMk/}3hbH+ `wK#2PJ ! `Az6%tPJ@`0t'Anֈl>3N@1\ n^ؾReḦ\\bv;e*t4 .=i5a]S+HcL|4BIPDM*׃T` 8n<iWN& 0a8ϤnɶfSث()x ID]"VbBjn Mܚá^ IDAT;1dFwN3+ܲ##ɑD öuM}}!LW (9crO]W(8衢x( H$k|TA_%JI !+)PJ_(6J0,9@пG'-kRxaF“h.z$W[^d|B9H #ӆ`gPDF> }wPR7"HA>̼u*&BRJ<,U-5M 1 QF#}+Xo2mUfbS_)M:ū'Of g=s)g*Ů'b@9l}'[b4=' 6TX)C CϕbN@gX93 }2Aw]mOq 85-bv?0>%mHʰ4!y3`J68)mvw]$]ÞͩT7FիV9V+ ryDxw|Fy h9akRj:ѧJ&G?J"RAZg vb@`ƱE TdY뫽U\qTj0ki3,9URcGݪ곚egVd)縤 0b@>rT> g̍(wW:B_78)cmqUVɇlVRj}ZU4g }GzlpfD60?J<44o){b7Fc/9.0VW*Xjre"G4Gx~z{U.O.Go>.1 ?nUW;oR ƒ٩1|H ~Vc6 8}&F_|)k,o؊p0/z1E 0 xBvzR¬QdbBiiy tAos ɟW=rҞB\Q-X:`0 |!אcW@`r+pLP+~1WebA /:n`4-,7Cbq6ۡq;4`g 58b@%i7iu'Iw1BUx[w,1B-@=n,lx! =+XeCwbAtߞo}`g s1 *DUOlT+g޳ }.\:3p-W(b@tB{kT];1IB`Jq{mzM#:Fv'T?|ٕ>`0 %jUlЍ 2V1ETFLW:7bVbyi i}m!v7;f&ȄWP<0. fB*58i2x{2bV0H!<H3{xvg?at2[ z8  y9F$%EZM?qBx , 6ߟA^^1 ^wyniOmA'}uUkax%NEΈL|Q{ ][+U ^Qh k* DH1Q,Y x]'m( F$Yǁr҇q lN~Q|^E׫ɸQqz3nŲF:.,w8^1 źpz| '*(G@3Q7Āx0/sEƕzv!8mV;̷>3LlB<)#>0ݘ\2x{|jM.{W׵!Y<O sc> A7"[L U<99Sc:9W؋VK/ݮGn,o/X4ttqX3qC;YRѳ_=tV&J+> 7Sjlzdc<:\#Q(>N "k%әJ:| ɕ'IdY^`O_`wta{6σRRߨzU&3-Vt\[##Ȥ+Z2H0'p,*'[ D19.0uu묗\6>l9r 2A`p$n1.8.h^ٺʍ?ZvQ݅}G= \aYCoFiLʪkP$V_tjwGL|`?r_3HPz"zngqΠ2MR)"Xv[Wqɉ O~7=oƥ.z̗‡^)8d@_1".)^\`_){c!tY twD.Ndf0aSƀ=SaA_oT=4Px2*Mڡޛe@P5"MĥppRSF*IЍɲMC!P䵉~ \ _^ 9e״fEq BTqXcD,>rF]> 2$,"LDȁоnժIzq!Qw'3E٩6'|L8˂'J=/b@4y+tu#4!q%l'^mNJmzuyY<]aRg0ܐEJۛM4@U 1 &1t!N]Bq軂?L)@?38^)?1Zt`0 Fi"D'tC`E擻#9 }7`g0ZD=s'4.?D[D z L\a Ked$ՙ L[O˂e7 Τi&EY*M@ 'M 1 |%:b'<2 myce0N@vFQζOiFa(Ԕ"{+bd_+F tW)OwO1"p `gpG~dxIT8GZ@JqAO9iACG<C[ϔ4ta qнMf6,D=i4|z}Bb خ~T;X$_P=eƆ .B$z|4 11111 dmm^7IM& ns\{C{E%έ;zmB\YDPPJKA,Z[vX:\W 㷭Q$yVnႻ_{|F?Wm\tA$ImknkLz#-RW{&?oRҾ1AxsMٵ76|/v۹M;LܺN;]XI6+޸_<V31Ld{䞥V DA+5v&HT'-4۝fWe۹=Cg,%c݇d?bwNJZ$Ys>d}?y&xֹLeʕ f}丝&*wDk0U6=޸$I-E[M)7uFP讬_0P3M3QVWUX*^{FxȄf2A^YҾzuHb$ݠl{3lÆ ;Ή++9gco&,?7|.е%!:B.v5㙴1ٌe~IVHo>n.<#+E9eY[.r΃RoJ2)ؕN/\188hc2ʂA޿eW]i]o\~ϯ^ru-Ş+Ο^!/[VE a'ڳ_zWWTpCwM n(T_XWn-I]guk֎e/]o,i;suGڊKt-9ܛ> eSæխ{|[Mk|4U(֞k {}SOU.|EkE߼{/w | ,^3FbۯllUmǩ6y[iӭKsM&M,~Ge|s"]1#\$7t_(LdŒ}niA&dօ[_>UNMңɪi4Djj떖-iMM]t[Q)p @YC)UuaB?8:1V<2Q,EJ}OѴ(.ކJ=7d>SJ}(bc#'$|_ @?B°KFrW ŀit6ƬR@@̙emqGUNX=g(μ>fzF%C08@%$,Y6dM66 KvI%ȒLcX2Ɩe˺Fnj?z ,{TGiJOUwMwׯ;-}, +GB<F֩D @8Ez4 ł1t[BY 8-u.?k^ ]iNkV˞K3H9*&^M;?oVrHH]8A9"gw_ڦWz2+GOǰE"trD>'uwx8s8@UG5_ uWLG.;<~z+pX7Ԏ+̽'+daIN@W]W1*o&(|nXh5d9pFY:bYH~愃,nJO:BZ|'E[1j#Q&`Mi&|`⽕(N^ Va̟bTZe[ !0N)@xɪǰ0 _5SA}\mS VyW}qE@--E^v6Y)yn\0:T&FկfS?u|v~"Kn@ \ev{J9̰2P{@:Ŵ\xazBd!\1J)e+s2[;wzge2VXҕ=oC'w_kX.o n}Vo nьlOY,k>=5t%Wneۆw|{"3Дq덷^4TԾ\Qr٢JV"CJPPŘO5zVhԗ/L'zјtt 7|m{ze k㪷>0Q 62VVnٷ~{g~Vw~c3:#Q` j6{7j3Rl֎j }sޞ`bӞy 2`Z5U.i͡u{YYH:Q%N̐fJs9#C;w]"4_we\3' =:/[Y+r7tni<ô0up0Ccv)0 ɨ`0 Gd7eiU ;Rk/C<3 @0V i|HQaʩBnKp%yNr2/;VѠ36@3s w8!\GuGP 4 q2mdxG-g0*MmxtP 9G1*)8Utv.$,/hMF:HzB'WD>F6 QbP}tT,6B2PJ&p R8n'`70M0`ZhpF᧳db5Jʴ`I}%xJ0Nr7C7]x%~SoEA9"+Z«WD"R[Ư\bu睹NOax뿾J.#j)ץR8uV?<7J98 SDV`F*z0Q"&׭ѲKo989^|H:;62v$pg6^|W<|懏n DD.PuuL痹ǮޞEm1Xq"G|}:Ǚ]y5Ym/9pSu#UOӸ]UB'Iw8 -O8@w87"صh05FƸDU34(h]C+U6 l/$ p8bo,82IJPJszf3E$#0ցVKuuwR%aW a.M S,!Oa u ͓ԳycǺ)ώ>[k IDATxל'qQAP!N;_?@Ly]"ͼ[=}WxpP""TGycEVx([I$lYTշ)l '۪E1mnHüw(`Q,g= IS\?@/P-BJpi& +ղjtvm2["(OD&"/@,l8M;Ly},"‰E8icjFH.B)!a_.AhEswUHV5im :l~b UjV4"J1CRnɵ^b]6=@f|1g2uE܎[02N2\Scqn;+B8 /a~QIފ`.NK3QAp;Itpj+b#5jNHJ Bn!7jt(L(. cVl5`f>>{bvG3쪯w?Z,xM;iMa ST4%doMr&PE/S(.='9ѪiZif_;Q0ښ64]xb&]lL1`R"huOWT/ pdAY/n Uc3wl6j9GqMB~sK=+:!A@XÅU_0̱3(~' |v TI]mi_..胳/=L?-i\|bH,d|evG+1kqn;p \3-noQu|N,*Ш5$1fPBrJi%|.@i{`ݔR61_a عY8k>oI;77۲ZVp .-$U&mcNØhWozYGZt=_{0{}ɷ%SuEq !yU<84קȄL  NRTq2eRJ$58Щ("*Ս^ol\rD3z}(Ir\B xcDH{&zEbbQu,a!b3Er+91 <=RZPlRWWԍW+[zK: V ໋lbqZD e kXe#`<0Cr `T:|[y~! q>F&&B|R Pf_sCcZZ0Q& )~> !WLgg8"e q7kH`{.82:{6>z$᭹ pɶ k]Snp⊋EF<efsg]xb0Ehwy%[˜Y0%X2M )m֍G}I`b2ʔ8ewQ穷%p!>'5pYX=ӤHT;:U&Tή( z{&- rD wĹMȑȜ:Gr8ppcnB8񫅛`0 (x Op-ֳ]=|Vӏ`T}؝93Da0 F#GdwPӛvfQM) ||nɊٓHWssr#鄑 IM@QP98Z%0iI#rvʨ KQ dn&lB`ݛ5qP A)xTSßx~f = #4m"`EB!?4;@'@nQ7p6gyc5C[3ڧ"nw=y]9$I f"|>_TagjЫjii]K Q%#2 D9">riץRDdy30:'brm^ \Wঁ%8*G8M_Œ pz]#HCqá $‰PL`a8rDV9]za5 ߉BMZIΣFC~L$r2tOs󻬦v Co[Dtl[ 3N \Wi.vD!õj0qtCaA4dOgoY g=p.xaϖ[T%[ .[Nڵ$2)LΫO\S_KBD[F!&K,Fj֚ʟf{Dϣ%e 0RU Hs$%"@u!qtb\I9P<,{<1_i%YF38VnoU;jWřy?teP#@- 0'8\fqUkk7qQ<ԠMb ԝO 7'h0P3"Hœx.F+gwPv ٴ;N2ys;gAV]yl׸AUs8W8J8@21 @XgK$Iw8@| f8k~ m]^qg$G#fXXd X-ƽ#lahNE`0 Fy&pVd@E$3}~@ju Aȃ=ɿҹ@-& x怬d8s O`>tv'wQMg L8rDk/ѯUi`z${:?'ilp$-rjx!-˫B^wx0aΝd <&2V1qC'hr4;^/t<Կr*62VX+ceY/'Gd 7tC'v4u yC v۞m.ܤl^HYOg_4rO71S [Pp 벻ns?4펪V+Vf}ϵ g7wx~o J>XXYWI۾`Aje[)OQ+ Y*~?zu:lzʊ!Ю^s{n<; u|\ W\Zmzy} j|Os?_h^beeg7֝-2 hsp}ںgʋ.)\+M;_w*0񾜖Uڱ clqEeR3Bg|CְM]ye> nP۸Q)o6t+_ $1VhG> `>6f1p-؎*N܋B?U,r"%%PR|L &hf1HAC8iƷu~zxӟm,k?׽7YCDd9cň7>\Y;n{j0(0%LM@Ys͍7{Zêe3SsɄV@70y KNͼ{B.0|f3k\Rm#jhw4306S +V^c39|\MdE_~o!6%^5+K-*>aqn~Bi%/8jZ|so0OJ CWymEWNOZPVÞ8M@Llj֭8gp~;YrZ==>C}A:O_0`"xm\qzE/jZ'!.: .I+.j@Ѳ>)\F qF9[aqd'D@LH:2>79y {z~H!Nhw4L&fP/ԹoҎ_i?TܪUtO =tʋע9k.>vUwq6HNz&Ցàp8.|Vx:(޻ǿ>qx[w}wy}UQ $+Ό!N{vx)TݸSDd\:âԔLw`>x^%% Mm"A)ퟧ J\g@i9dL<& s%Aڶ1NP|@Ø?O5 "0$sK3!$Sm+3kݕ_[ՔcbHMNy?R\XgWrZL*ᩡZ j2~Q-'DP[91fĚ?lU>0@1pm.HDKpa"19#"baTKp3+xy& T oT:}W9 xu^2ڱcяt+]z)։yY>'ioLG &҂;;g۲v`mI!q0({( J'1P:+~%O2C ڝ@s lF VA ܅iBsUCsۡa ?wʵw`ZaPrB הQ?{^F35%K߹s|~ ~;=p=5~wce2VVv}p7tZ^# 㻯q|y͑#9tdꈭs$?o5?ۜra@~ڿgBg:8}CC9#p+ߘ;,G?)r) 7yss{jxzرRU6 uބ}XI5Poѕ_f^~fel1ˊߓy~^RhxˆU5xVI4Wlvw^ PnYbti7GS d?oOU慔N67oXn9 '}V6{5'Tʫo8*DBѤ'm|puK_KAe\-'PoIFؑ}s\ pG}MBw4 C?}үe]}Չ]v4QJB2!bZ>ʌ9 8=!y1M`\[G)=~:m`,?fQ/`0R 9S|>W3|q (xV|=][7?C0TO/UZ^$7݅B$4 0O&T%besP#.Djk!_8>&]sw2;w P4,Y5u去8/g@ h<Hc@w[vOg׍~ZFտF4rD)'oV"GFa>wO<(pP ( /r=٤_G!}ģ1rDv c\SL^;=d D)C Eb-Vӏj!\S.nx/QRzr7,9t`0N2prb+yՅVshhUvTͮЪQ; (Gd2Nhw4#GdjBD.Pny\&KFWmQU=7*q.CGa@4 E币epil-$<Br10")/Bu.J`I g|fXvn.[N*!IL{Ƃ)*p{֢rG) )A󑩾TC|+aOJ{D1c 8BգT%maOS9܆=O@onj'r'ӔO *ڽڄ.is3 (3N.p$ahy(h&^X `5 l.z{vWڞ ;:O[Z5U*mXe[<: s<<Xǝy7ND*a4g:g\ #B1 @BJRO}2ms$BB0Wږ* F 3}GJgj1 `0JVZnjkyH36FNaPJs!]O18_PrD3gX.NvG+8=>K3UTU9(|9'Vz 䤃b-8h= Gi;DUԨ LSqAܟ1Qj.WrOgiQu @gWom;Q=hwV1*ΩqN#wN(8%Fype"S { i qI+N+UFXc5hזZȥd|d,eۗ `0 F(xp!x+-"4 ˀ"rqp@;i%Qc=OaEZĩm\CupIkkQ|)BQ!0=1ٺ|}7f} @$ࣿ)B|tBج:s= 8 TcC\ȃ?(4O:/% 9WqUyB|r>2 ӫ6y?6 :l_kSfNn]_Q8  'KvdsÀ!h7Ed06shKK.zRTJ.z%[c3$I f"|>_TK;7 agjЫjii]<0b8JȥBrʉݶ׀:Ά&$:%\Ҟ Fx%ipq8P9 fXpB6/fCjl7V^kiJQǑ(Fq4kz&>cX^#wr+EeeZ +#Nup<|5|BOg&r刜%=]ZF'='eu?Z.u]y,,j t=wI֤ G !:nޙ(K'*’`,zi8T@6 vE0cV,$oKx\ d:+KUq2,ևvo]췪V(&`%Mf#=/&,-L ¿y׀b:@ dY޵ٌ|'qs3Ъim48[eEӑu:6ojU<O*Hp:VLV,{/"oos:Aw8;B5; Ï城ʐn) ץRO\S0) 0G z{왛2~,jKR\gn;5]&! 9fK9`0NpBuplG-bg!y5LORz= F\Xa عY8k>oU;jsE* Edh%s|RE7b`Ѫ0 _Щe&@9Ud3ޱsDQ?1nr!Gdwb \k6d*C9hBK|t"pp ¼W؞ή\FotXQ, 9"?aFrZ 2ΫmgFXYyپUR.>^p=‰Co`0 Ԟ !9LH.nb`:$5+/!~L@R:V Ւ3 `T9"{a[LAq&0ĩhw4j&z Ggr)x7`ZHv7br+bv-љ 圴>DpfMi״^ol\G$+`sF ykBE @KgSm ~APzxoQښaiJJs9TAh=dT)4UǍ }j$J{ߐ^U$ R9ۓU<h.8?Um_꽰O|wkC~<7'lڄXÉr1f`5hy-s*F,e b0 `0E/: pXJ[mw'I3{) g/+sai9nG@1$vr@6yU"D%Xg f,]TǡҜS ނð&A.ZaKELߡ!npq|_g"28a.jY i4JډtI^ԡHf|>EdEd Q< &"wdž|}>"24(w3`0C[-Xpt]\U9 F$I J"|>_Z0af>>{bUz]---Uk)vGU9"a % E(Y™0Ϸ9Q(-j~*P3>ƻFC x ,ȕlS, C_N$"wXڂ]+)!)7`8bMpL:`vU1,JfDP9˒ :AIN'9Uĵ6Son&Dήu>;W=v LZtLeT5=XY]y Z:<r7/;ď˟T2`&vhywxn)6G38J>o`   @r\!%Ή:g{C68%1_a عY8k>oU;jג1CL^l't'dmMے#{}ͥ9z{*rff8R1yP@U}C \MPxSn0=83UEvG՛8u^&O #S8 9"VDra:Dwun{SkszZV6W%VXb7lxz_)WMOYa\>iJIo?w:*q XW翶7xb.)}927 J)qnco.w?Ւ3 `XxȤ\ɱ/6(~fEɀwp5\U)m-\O{pĽr8ɀR>Ǯ}k!Gd/̉x ztc7VH0B< 6 =`ٚ*l!эQWX/htڢs谠ZUO_mbɰmcq,G<> -(@7pe9~ۓZJO83,Ds?xzyHt=y+^WS(% lRH<O1̠!B_ݔlZEdMEV<y?w2/~"K{=y8(& Sa>4 F P H)jX4l+$SJ5B|[.D!onM ϔtb0#LJ09rX:عY8k>oU;^eWKKKY ]qbkF gn 0[pV^=GEG4n8g}:7mK6o1 9d@'.j~g sSVes456~lU1,a@ /kW2+6_e =]g؜y>OO&-[\G@B9G[7wmzתd2i8_2;;M]>&Ac0әdB(d AN|\UxVH.M$PQ}+!樂.8$!D]+).{ta0 f"[T%['a}X}`~iUja9ErDa̫D:sp:TbwՆK/O<\mPr83򃷯I r77sO+pOow),li17H _c绲!N<;:u}8Re;^^of]0Z/o>r~{}3S4= |gtvq 9%v'lvpsʨ}mkg˷ov畷3IzqyJ)laI5٘J %Kg0 X{M'FH( c2Zݐi ^Iq5y#T gikw7*^Cr\v:RN*lſ ~>a,]0ճ]vB}C%4C9(~o8v/T' Ƣ=ǎOv:5Y`6=ZधpX [E <h\braS`,ulRY+a7e=SJ;]588fppЬgieݶz_ނ{;_ _d{YeE3Cb$%-'q-ræǓ͍l0퀫~7/?7ȴ,Vzg)[t\~uQAtem9+[6"y;[o\foJyoľ5*nx+6 y;}]SB\7eի ©+.Mn^FUTFpWkU; ˏ} cۦl-wl\ӹaKІy~k7ßpi-ٸ,np۶vz *7ޢl}\鸱 '] /|>ikj{{MK>f;q2:rt紞?~?x37"g̎ԭV\E n]"׬Me+Hry&c2&cY{}׶mMNU7k:궦mwEg+&يJbH4`;!`4VTq ʅs̘̈!.)K/2 OG8%Ӣ,:3*)R @UUןIϨ0BD9dEs[tg$ATXBgFV 3!?rO#@U4&DabڟQ3$HAsP W"k<4SX^jg%S}Y%)hWJ;0sNF͠'0c &ףvk҃zޞs|] m IDAT-ǽ<ؓC|Z%L ?ktS:u̍\Tp^]k-I]ÜƩDǁlyC.Ng2~j$'0 TQ~黧+WU+[cꔚ¿I#i ?QpBtV禞u؟#mED'鮭_TB "ǁY=+,a8z:3EwWH(r$QEc\,G) !pQA<N,* ?ͅ%ON6-*({_ f7赏*`4ǘ=fJjϰT),MFp UP(Op='SI%)[pY`> 9-G'Ϸ:͐kN qHY,H #=מmu5O%Q?Ƙ/Fa_SǬmT5q5⇟Te5v8u\,yTSSC)`|}'Uƥn7rӕ.9']$2ZUϻY-j6Ά[?˾7++Y>?zIΪs1]('#]7![S` l:ń@ tC`q ;4ygP 8( j:$j>F8O!]pYx'\lh;2c.*Y-[|~1B闛8-ۃ˼˂GG$111T<\#49m4^c&5|oFFf87Tlh\\k{a}ys{]J#OvC~8CUiE'R#jĩQ_97DD=D`y&59a|y#۵:Y&3a uL׎64_},TscHe{2|/g WK`d_va:z_ >3M}-v펃;)9"Qnwgw7y壉1,G2YE7)|_vx3rŰ u:r<~plJh $)s]S= (}۰nCbulO7/|*pN%?x:3ʾUG2<퐤%vP:ӝF#Җ7G#C+k|T_'بW9np|px(2m0o#~bP #d ,z0.˯jf%nN)`TÂ0s\ݥeq63 k)ȼ+5GC=;_O}HoX9~芥Sj5DN0 j&"]~ @~]ϦaߎZ9gُ]h멠M$uA` \ eY©Oa,,JGep[Ӷ@<>s `{ׁ*UUSSSrI}Bݡy7;J;4?nXjh0 (x= 8ՈvƢy;cb| .5>sN ptQ,>%"/H9<?H2Mt:l$.[[0ڽ#78gD@6N~#i5-D2F2# 0e-h"56;qv!p#)񜔓zT=퐤US@"H 2g e;MOh4 P8%)pD$fe Ƣe= [<}PLyW־XY4^s8#`DuWLC~ezHC 0|28΄8~Z9e<3翟: ܓ60B$G2c(6"O Ez= oq5,|.uĊ Zv~2#1`O9ˤϑKdsg'P?rNQ;b0L?;=|gaD$3o!$)zO[9^ QØ$/%K/?S&=@iҝ1/PR_ wT+ƷT|'pz+`xN}JގBݡK Wg%?*]~i>ltd j%# %@{zKi'yXp13_,<" bNxB(Fr n c,jC2!6 4E)y]0KQLf1YvG+ R]ٳTwAQ^쾚`d=08x|ZzbklͪYs&GpրICVPwul0b}q0>9fsxU5Cpg8]j} ='ѳK 0TΑolĦe:H˜0Mϩݤ9asUNYHs׵H)QsW>6[B/*c'todKE?92XX2}Rl`4k LHRT:ⱁo,G=J|ۡx{o>M9(Z> fEz=|,~+جVo;7f2+S:G q:#َ7ڞwF`0'9ѯ$+r94Thg['~RRUs3ci{-ˋx^J x<#JT^eG|ĪX%ܾ288b'O _ MZ_/VV߬zԘRb1yL0MNbE*Ifv80+3BP!j}̋'~ѽV -꺽FQ<'Whͮ|ճw3+fo7[?d<I5D,ρtDpmTvw"qGXt"xWr}f6*jN)ܺRPx]{Cݡ, WjBJX=w9 qᏞoǰB>:!5''`0 $]1 8)ܼ?F`@E m*~v)?|0# a!FQ9dGrH@j*« :ܨ? uX $١빋:wa*\FyuEGH\H(x@ h WbSگqSɐY4GE 8^ c@u> a* #V 7˥x~ #xS餍oh=m6,s?,`x uhA$Պ1gt|w1fnDlȧ?Q(I`1 "xvcL$mc0OQnV8N?, ȩ7Tð#1I3i?;\Yt*ێ(!,K08xXٳw`K-55-XTGcT5fspp-zԔ\&Z-%p::!trLP^lSuTX"ѫ W"n"u:yW) `|fkjl$GLSAFd[~,- ʂկOfԌrD P^A7bƬc 36Iq8<&տR.Hq4DNgAO3 ;ïA~XEb=<(83DWg38È<#OPuPRFX%Q HBb5 G : 'mNJ,ڑYdBހP"pg8u\.yWUec5W߳pHs`7'$vj7m6Ҡ( 4S~wvd]=1Ihwhk.JQͳfE՚+SJ:Qqhsj"RFu0!Cݡ$ ΒgϤ,2{9]_}MNz&L 3(;hgÂPwaχ;Ï~XECϬ w;:k;~: eYrc# #]GhG"Rx# 381A @WSu$ @(?Ly/N2 .oѸ(E#E(7 ƙ9ǬK߮tTf|v Lg6cv,:lp47pb2"ֿV߬zUyЇm/{z/IRyk.'d шF4ķ#ޞFB\v] |fCy}bG׿#>Ңt0+Si\q۲ K¥0Ջs݃X׬b0J~Q'C\7k;(iy$ Itgs@ PSF/xR!(q|Rz&XzB*`*+RjA)4-ДMD3`,X>wե/*pƖX=zCoIVMt f˅y&j7nWp睇9l u #D <\s~ /CTgls:r!ّ͒6nS`ȏy*8ޑL\#%CAnPr0;`FhV!Ut% q@F$x(87 A/7 P`8L w(bƐ<0C2a2B!7 Od웃Ï(Tx)pc]JfǭG\):N5"_tPJʈ|PJpd~`0f@0 PE~`,"a%NX0`0f>ܟ1&%㽨PL_]>wUPՔZ)BH Txn_ɦ$ a^PwH ȴ'~ 85c<`;&s3Ahq:^D IDATRJ.Ant^% ,4(Ą;q+kmQGD$մJ F[vݍE"?Y" p0"t ?#|쌌 c)S<*T t>MJ8-e !6ǩFd #7Ք<_>S=<XROҶzZTUWgI CclbȲ,SɔJ+pׁ*UUSSSr惩J*NS />YC7ԋTtL?nl/KUZgrݖ>.5l_ҼMR*=bT19|U2yP.xP0"P* ^a@?}8{^מRPSqOAG"#iP`Lȓ ">fcwwe馴D#CYQm/%~q̯NuU9P~;JۦanoɝC6;J w50Ө9+S`,V*8u0g qS =ں^05$xbC.W `D?0$s`G~ysޑT^(8N f<]B] Lқ!SK^V??oV=ͪ|> -%,Xu)dè8NK5x[C^ޛ! 5zY 0N,G3\ö i,m>Dt~ГNGa擾!ru<)]k4'吼z^^q0/3&i-M1. e7}"2z@l/Ը3^I&JG@PD2c[XR_~tRYO-gu>v5`?rWx}\R|fEYj^Q;D/Πpgx.۱s|fW{{j~b0|t VB <nXJ8{lH7cҿ,O&V.бNaKYyݍ?v.%'ڣ3|KQ68D|o')uN^V??oV=ͪ|>;'s%/a4y<(4NRS46QE]ޘ@#TKL UeU0e-o:{萜 jƕ3L1Ox]fW"]6OtTPn9W `]1#p?]G16TǞK|ZZU)5:DR0rRπM-$K/ ^t٥dH9.Qyu$~L&m}Jenupݎ>gXcs||'ӿgn^G\X5Wu3*i{ō UP_GT&Eodc3azB!STH Hpt 't<$]JϘtR& M0 C)?zY'él~41[t+2i J0:L0;j%i& c0EdNO0N3Ho'T>0q/0x3lu_ˬ]\0-aӐ(4 T~txU_ _l l!*m10O+r{e*'jc^,gϥ|&L g&P3@sċWTx]P5pp1?7`S1, i"$&T1q#R判pp ȱ G9n.xik Ϡ{{o}ΔPw]0"s3(|<RW.^\؂0ڟҨ(26hDrEQUajBݡ*WрA^~[ :u脠FUqgMU SSSُf2x0+qjXkxq?k`,iD~S>SȀ1\X9ldL1Is ԇ`9KiD~z̈́J&8iD6 PwH|]{Z=GTEoj=Bm;-g1:%akLC^1ju"1#Bl i.mڕ/S73L;Ǘ)*ghܩS dN$JSPAU'6q)ٮ"x2#2tAiWD M#>Q7x7fPE3rl)Pcfp3".ravF.[H#rIJsJf+4ǹSpHmU%Б`̜882Tٰ_בSJKU#!3"[+M!lO dh$M=V ˧ztW%$59Mjȩ <%b왿eu Y&V*eB/Y(rTizoX0ӳLUj\Qr]X;Pw@; ")jCGpRF_C!'3&[+X )d<>xN' mDyust]m Mװb}7$ hhR*{X ujjqhHTr|xgKO6oL1:`lY6q~hRU ft84]1-s]/G~\fs ckR}F$6pKu=yOex\jSUrW*[D"Xr;Yw?Z%&& M5)JKrїrV^Y':CHn c@-X}3fPޞsڎB!;_Q;;Ñ3= }Rz|Sci ۾WRǓҕZÚ-_6Kc_Hldc,5a9 O%7 Mi ˂%s 0V6$'V .б Fΰ"l쾑9=w&k;pDnb%&K({&m/5{X,?<:ܳ;6F' kR#Yɂ&xaɦ~7ZaV#rG :Ǎl MD`â<;jFq=X<<mNH%tŽ=1 EKޯkTh{uqUQ@>dy\N }_+zo8O\|O_u_jafaC(89UC=gKYNhD5 F ~04v7ϠyߙoX>)]O.~A9Aͽ㳿]xwf>(&F_٩@鉉,&b^RQ.Ng2`FdR<-ǵH #S)"ʆ<ԕaɵEo.б-[#r%5'0/^}s{5ek'F;)3Te y|]V^}/ї.OVYKIe_+ɲd:8{YWL{5.V= bZ柉Q$ҺK&E){}M[;?ibot/L<ܲ,/3Χ2F ue:,rno^[~ECW׭)Fsm>tk]U=1[A&\^+ʉW"i79r+˸p%iqX3K-u_^˶&mҨ2DVAG6דWC͠Ry<Yo] *Ժ ~]J2:W3QI .eY`v@d#مҏ++t`ƻQwڽ'fr=DW_s%.Ȼ7}?߬;5c *"/r~GU(p׭}]軷㼌ɘl~d?sv @ڍb-}˼˂^:!4yQe˖SO=`圾oL!{B 8Ո /.ւr !?\h0E0dp5oyB,O[Vr[?+?X/3qiݥMg&c2&cۼ6Z뚯۱bC'ԹTu4:/Y~0i-[mM8[rf# wkQZuJu;oZy΍4p ] )fLemMnY_.\Q㦌zv<7iǺ 7w\j9W.Օ<'7*k_y+-qlne?##[Ko'$Y,Gn}]EWxy-}Xا0h1XHv6IʊߠY1K;"lvc44U8˱">=Ujί ;7åSo,lqXnsa/<3G5%oډ܅>a\%]:P,s̍8H6/c0z; 5f2# lhde,aOb'[7_%Vo#ҿq''D0c\0NOwdLR&gGq~ɴ(- ;>0m(azq¿*Y |gC`Z<-M*PT)@駟:;@$-H?I%)I8hNt .PBBa2*":'֕κu#r˱|o#=j]S`v8dzb4YX5.)iv5$͞|)1}X(UQbew)Tw@!Ӱ s`JI ktS:ȕdsʾ>ihn/Nz^/a"~]DŊkWsޟM=mafFeyU81xf;W8ۡ1V<+-}N"!ᮟn?O~a~%Eo[UԣcZdEsCG"ӛI*IQ CuB`0CbcP:j!'\_~c}udR9Jc#> ƒR`Xe˖'|(} ~B!qR̦0&g*WE?Vg/0禩y?#Flnѝ?#G9W[n=gu`-ȔRr<]Їs˦_nTlojޘV ew erŠ}PL^oC;=2$ eGH*L?Pz'NZ*oQ{|ϬG6ndYk_L◯Hpzy{8^SdY-pB'!  q $(ڴB_(Z(p@)!PB \ "ږKlZ53֊mliwF<=ٙ|39^]R/ h?Jh{oJ)lݧs[ _'U| ]?;j|V"ԓR^t qp88yaa;Jݙ^i>=z)b Hi"miD*!P8Mg]v}ѣ8vy B8ye5`*$B _xqjd`zy] ˩d4E`G*檒{d@ ؊uia @i O@pVD"^0:~Y8pL29`dl0mȂ nvXsȜ98of<X<;L)[PY9J;-8+넎8S~Χ^t ҍW X*H1@X7d`.'IrJx66XI[Ÿv}UxOWҖ[5xul0s Do0#\A-އhWΨG ۘZJmZ2<ށMs!'g|(edkgS.im"SH>9-UK:0|܏` oB֞9!}ĩEd௄,ԏS KE fCDd"2Q"Cʔ]7)MΠymG9!RU< :&*_fiZF;!Ѳ. ZPt5%;:BD> .gHH/I\&I@IpPQ(4\h4Gn+$k%YP$8-ZVnog5 &Dd!"[h KD"r-V`f%GgrO?H Y c$WWxVop!Z~*ovTۏpο<"t:.]\V IDATZg>RDKAcd2.*{DD<~+ށWj MLL\ Bo-e'%Fcnǝّ))PP+2ue CD0Ji!7onZ`sh~5g_셱ݶ.W lcXw޻ٻC7$ΘRfm2fT|8^R2 +b55’Qd(Zx^I,рF -nB40vfKsd({Ty_Juw o>fM9@ 9$\e ̋kA:pWOVmG9Yk5Q!c^Dx|eǕsH.jCGl ՟v>oU;bJ VEbZKL6Eʦq֣qM1H9MdBͅHz$1vw{#{T9 PdQ*xSk (w+CBҊkd[_%T<%@iq)_JI9{c1qX.WAT*kF^ZUS=ߛ&#EG52\0' BO֞BB.gy+| j9;ܬ^ @܎V@ 4`+kE'z?CJSLnw`NMto'dlGb,"un Ca,\nnY 89륄,z%85Uϵ c"&z*+S IgSP_t+Pz,6~ltPݣ[R  @r@8! /e2{W|f. rl11԰{ؑ5J4г ཈,&Z>u2ֱmu՗5:;*3L ຽFH{(O9ZV8RE4U'X#ڈ90\YpjјB1?w0K7v Y ?b^>0gF@ `ƶh3©H0V'U\VhNUMKs 96|""rzmն;S(s0V+ ])LqxRzn 7rۋ>Oj98|1x-CPlKµTz#S|]*!`E жJ(P[L{,&"SD27 bD8&"lR> (m.]R '?%AqU\ShHxZ4#K)⒄r'%XUz!{! /a4 w*B c_sGP@db|d(@S&Lc5Eqo՟v>oU;'&&^fWWWW:UlSSqCX C rMpWMPB)(c2̯BX펝;x{Rn٭[׶.cYOƸ (3ϖp9$ ҩT?^٘ =l VmcXĥ2 EIzt}:C2h6z<  |k6ۖ%EjHj9FЦ/Ϫs> /!:;to_+@Lm= 0Orad ygjUZ*i0c&a\üǩvkoyb:e'(v>ٹ筛z[2;;w^: ܮc* 8כ+?r]M3R "t3z4L~AGj؎GDaD]8U4Iܸi6 `z4'9/O\X~N/Qd(vUo}26Y|vNhjm6DS?]1@} #R,ߦשjȞ.Ӓ{EI]*1cL^ ؀jyDcPd5Ƚ_sYBryF B$\Fcq1<9@p^`*x[[43s+x!qo?~}vߪvZծU"y1Y[eM!` Peٓ)DSz G" ~O%[ Wۗ,'?ŀ3ЈS]}ϺZP ɶz֖rb(L9H0\\{OٖD9B$&|y `6`A6ψ|0ʪJ3J=9=9@"Ik8x9+Q32QN!-Əw["-Gȕ.&X ?'gg4o޹s  *k*RyRx\J= E-ҢiB+؁J""ORI9BRi 2+p.\FjYi9>+vV E0\@ZNKƊtl0ff>pq=0\aUe8f@z;oؖiܦ \i(-qc.5ȡwXl(ep"l >x["C>Oha\-+p9 `xn G= `NɄvᜓ5qq@ykb ӪMfғꘇs-.I{?G#"HOuO$,õ1xuo1wkbv@` @ lN`^@V%;u`̭:^K Ed3{x ,5¦s0Gaiw3.IIJ;?ve3m¼2~KPb1uQ>{ӌ7#3NT8HMdv<@?:jmNY`u`;2h5LI6Yd* BHd|(0d2.+{DDaH ϲ3+u7S)cͭ6-y"r30>Zd(2akTbtr !߶ # s߬dN[_1梃xcnU4Ds*j$L(H w.I64r8JZ"'ʣI|έ{Sî|\u,,GON=9-scc+d9cdIG;`K89ϱXZ*oHSwJ|N(dGX,$\ޱIU0 Tc9 ŸM~D!Y ؎+:ٹ!(jEd6gKF]-y_ԊӉCCG"OYЅU٪v՝:^6;a)&#C`^L.@ co<2cMs t]JeNcŗ 0|m Hjv%5M)ד`,lGj(BU e?d*uz `7ifRIAxFڥbuLr^9$(N1]pM;:Bʔpy]x={o8Ng( E"9V#._ ͡sOk׆kCq@f~cgsIM .:}}ÍN*G7xocOUˇݟn_8+b|gM-G JK_f :nvSu9˹-c-t^5[ag`hu S6]7$Xz`q,lc$^HPּupIwiDGl ՟yvMӚ^&#Y[&VTX^+FTdu: d[apa-OkK:(8/pB]%"7V&0$sX3b/L$vO5yo,mo=!{zIs܏ւ!U&>P9:(E9@p:X{c8#T r38.%㝐}@ E#%R32zt恴^9)~-G]0<}Ï΁=M'~>}kZ6,n4/j'Y.DS>gN2xDp KY_r{"AIu8F)Ύ*1.p5i1_ jpRZt;aT1`  D~  sd{`i,YǷBaJ8CMc:JV_ ! ]j"!Xy9ܤ,(=`Ɗ Oo"k~t$q8 Swq>رpFƗa)֢p'lc㱚X5'&&Nc~n].I ^:aFØ7cy'9ϵ;RKPgyS&dfN@pqXD'N84O75Spcozȉ J-P&=M@ۻmLhW3( ]T |XB1qMV m\ tm$+z,gR \]?ٱV$Uxo U6Bu]vsL?wo?2ag[ |]9rGYeqcJ۵\99+Syf9`|^ 05g/^:ٛ3c{r'ضQ1B NW :!"!VLnwRB KGV@tX[s?><<;FX gcŽvD<{.izb 9۸x'c|>aWQ/qv=5)DSr/WYɩH(˜ Uߝ.Ƈ=mv}ԭl@)508/=btMBRb^ .Py~XrV'2cQ*[4yg|P/8!9ʍoGrԁfWk݋ʃo S:BzXQ)IsP,¸O+ Hs:6G@N!]CDZ\hp$G}U|k{^ *24\St.!Nv^2+/7n SI;M 'q?w#Z too꽴uJ/~Dϼ4/ }o]#Dx ;]R19UɫU%$Bd(1Tq- Hձw?? sCż6xn\M<(&4R0ӰJHGl ՟h2Il mWR#YN1j>|4]N+R5M`ލsX~@~q\D:pB6ʑe^/nfۚ+{8z9IwhJG40xXG^ulH~ɟI9:)SX&bc|*{-*DWUBT!&ST'begPp"e>{t=|!NcnW߳.gYK4:ѩzƩ%Y*Tr)NF F,񼟟Xai*"2u/%_;Լ8ЦRimK ><bx߰>UW׸bVԚ ucܩV>CVzb2I c$3ޟ%9Ũ>>whؒ? EL9)O9J 2!$_%θ IDAT !M8Y@>ieb0f}s.*6Ya`v$2œzW.a !x a^HY M}q匲F~5 xpgŖ9L=O ]s.ǂƉ:>'canu(T-^ ~tXv:̫N*t'íȀ @F>(0uN$Jeu2/@p>c>} HD)r@#FZkkBeeWKN '%\9q:Sq 9rz*T)㓏g -'ɸpr̠C>({՟vL&z' qy2?dF#ˉ@V׭y^'OekUV6TDW' `unL\e[v]d(圂e0v:\FSz4p?Ѿ__D.60JsXS+xrmJ)fMj1O͡~ɉ6=v%.gξ=91;:Osccư*D itA˹ek2}g*`l :X"C0b2>cu-i$9@V v!zv: IQe")Em)`@X"؊}<±18ɗE=gP =x:e,&mY0DO㖽qWs~o, D>#є{7wS{z"D=}*.MMsO.C)gPDsy_Tǎ(mc]5! tB#q_ۦ3`Ed81߾ ;ng+gPiM(˶kQ2 7L EBc,r1)6jM{>'рݼ Yu&f[ cnn^6Wn8,q0hjl@`J.R 1Zkͅd`^.W>4oq?Bp#p+ծ+/5s@pvT*d)9sy5/46 >`[4D<~KjH/]RSGͯH^9- NLKj걪vQӖ*7nVYa w`>"&G"JeSkGcDuzn%od"lLp^Vbc|DrI85ևfm 0;LeX~*TP6wy"C_ L Òm SD`l'eG^vV]oۍ$-k8 fmk= `Wl0V븦s tx%K8gnC4ը=VW<=Y:2M2/s\ll˃ s⣓1M7G)XeU;!# !8#*"rE$qy!$ ܀W&W?X-Xj+o@ Ӭ/屒."fnV~. tˆ7 ޗ*1S.&G"^d-fyS0|:6[^9:v=ͫL5qVԽgE({|+jSz /a.>D+m~>x:Zzm~RcS[Dܡ#- {(% Yo"rVx9 ɜ{qTG: 0VanXԇl ngP"?aw ؃+kD[/%5h螫mf%Ƽ^ghvp>3#I3PAFL6*Ύ>ϷO [ta#ڈ.d/xs>955[s #6Sc]1O*bREdh\qc*EdGq s[^Y "K0V$1p3=>nKaykd̉rvfHH3.88c)x)uf|#~{2^D˰P~_GKC'rLs|Mօ9LB;VmcXrjRd/gJd*0DS@xj8}}?ZXk|}[- +lR]s R "U;VJ(Mo~E;)>w[W:Rˊ ey|z<u@`?֋?B*G~Nn_x1nG4uVX&cw?sjv՟dT/P-aRK7rs.WlGn(:fIpYHq9orQټ.M үFɍ}oD";]}]Dܛ#_-ߟ?jGh;*v"VU݊\F\=W F 5Qr ^q(-PPʒK%%9.I._d(r`5p$}dvgͿyFPbz5t-+|a@ sop+E6#0DiM=E :ͼ0OΎ(3o)j\H EU".':2Vt%VQ/JHfnG65~ρVt@Xh$W} xF 3w>|ɇUJY9۵ 'Tl:;,NUc\i*5uA/ ^"?&K:Sr* Vqx`UaN s/|4 'DGZ5(7`Y  Fq|-: l89\ Ղ +,XdAy@ $s0;mf7犛qfcYEd(djS鈢 eBa<\}s]Ù*_.k`Ou)[ЩJh/:I+ SFaL4M?/cof}S2qyikI:d-z^ )S)PS"fH\$:+l1>8 N : 3WyNо)pyx߰~Nd(cְ{Z%8h ;^p30 c"rl&d.d3v8qqntֈ,U < ۋ'2*(C#^"ߨGS(hmiu<@ XD.uPD E`8۸:`zFa.+0M* !iUz{8t=M@XED& ,OI:Rٰuk' q7;q_L_ZK3*:LXi@Trhnc؜4T^({g4&<]}B"|kC՟v>+_N.mt Zݭ<8L5zz۫_:bL͖颻`n`a Hga4 7:F>\S0N;s*:.М0~Z_1e*GӣV fn'0a>~6`k)"{-qYȲHx9oʌO94#d+@T,2mgU8:粓bʷQod^`L:@rP7Ԋ\);kpUJӘ¦͸>ٵgaE"zyJ̋2*[99[p*uXB#wbls_ M±c {w\ȍŒm!2P*w myBrӒJ/lbVvq@JԽȎC ӆ.e_;tLJ^ Evw{\]D7@S?}a&YX&^|3п%svOkl"@`mN5{Yؒ s,(ًuf]}&}0fsGc\gJjBYi_(9> F"=ZN[}M:tah3=;ՙ:D޲Dnb v+O۫thESΐG[FbO$Jx+g/{#Cr!VsZg` ΙV:iр4m8zcW͆&LJ8~uMj˕;ß L]ٴ^EplJ{n?aqg d2lS/c%tNO@Z c՟sKs&i#G?t'sgR:(N>ƉeД)#"Mۧ:ߥmC?ʿd\*p8&s"O?2].Ӯԣ> `S߸`u/ & \W>EiE73nr*x*Oiw_Ν?[\-o=:=o'NlG>s_ wX̾o|b偿r;3r-b_ oMw=u׽w=u׽^ٛѾ]va~f[`u{Kg+=Pշ뷛Ϙ-/%_ ' VԊo'4%b۪.9ZZ~w=y"CO뺯{p{^}Znut]s-^ iTw~Q: 5[7z6-9Vy)i\w^{Y%+Z.|]9_JGʷ7+]8r(AGO/n[C[0\wJ78/|ծ47{/xͻv= ӳsK Oڹ@Eɯ x;_J?߼x'Xx2n0[2$jO3>9̷d:;۱w~ڢp_ybsetЮu_=oc?O| ?{$s䃿wxۋO_黪VdYM\iEifk]ho=DSe2}g|t!r4Y/uT;rp,Of7mb#i"M--- ?mh2펛7v_ScN)({89wj}}Fu,iFVٖ-^1lcCH-7$pyons I Ɛ8\ IDATtHXc ExmY]hޫs8ݚV{鱺zGէ:Ugyȅ t  >7|mZQñc,ݢ`޿"^sU5|BNiG s.UW#NpI./K(كRd.e6>*vOIxtS_gΪ8)7nэ3)~; S4, RpT|/RQ.p-@JKW=[ |B8<Q [39>hWǝ"e|`cr@<bMAg0 R!g(g -1|ݗ7Lݙ<]Mbi9PR:xK<wlu*wvCM;!/ PR%yHHZx2 N9*Wphq' o3tO=Gw3|;)/H3tOG Y!(ݟ|dvrɲNzJia|PWK<C}?X?˚Y`KDBٿyl|{iȹh :53N $A`h4 :;SQ&dJ1).gZ5t ۾):ab# p N|R c/xߞF,&! YHnx Ze|5\u*<]Fwÿ_{ܱwAiDwmoccjTbX.K"5QvnKQGѡhݩ@׼K;>' R_ckֆO_!:hES-UH07RX-oszTZDM⹵aJbC1@P35a:7D!6&!M<V9Z9#%Y(2_X8xЯy`ԶPG{$5awѝtdJ u=^aGV誙wA#i]@Bi/ e,8,5]mgղ uY<)5bߧԇR_rٶ9yd̂V0dve9imtQO#NxNcx`mUK/I%ߘN~wݿSאǮez_h낓͞sKnuhuv {."1>u&&pBqehA]DoP ALAE\]DSX"m`xB(K(}668 `Rq'XO)Vi.!˷]{k|11˱;MFϴܸu23ƢC{ɷ-{.;.r YfmS";jg_cj nэ={~?g/^7EVۮC,p-9 wWom׀P+aGG.1(zK6x7<)dxe 7n9"ƶnl4=;C]xnb+ot]Jm##ħsӳwv^\hY[{.G~Ӛ7Rwϴ mkpk@hh*o/ܶusfR<=Ս\yYIMeܾkckqߟLLőЭr){vMW_|~m/wvn?맭/?|z9v{-ĚX`*Ym '^{q 7r#S['B@p d3G?~6y^e046*$C_|=;?5٩gz׏o*,76=r}}SOe&$9  %۶n67{cw}V:n۵kW⩧:餔l-$!tQ>Jp <(b,&$/;D| @Ύ;6LG#?E붰sv"Ϭ,! =:ϻjGQ9f}5_#mjzdxzZ]g ةD;׽57`CtN>͇F:R纲],XmG}`^S`i F< O `mzc^EtO왣 !nU1׭@Fƕ=Fԉ n{tVM`"ϷZYdzD?vh4=Mdɔy3R|Nփ=>4uc[u)to|jg|sg#إ/dJ褐a8 N>5^auf<  ^u|LgMRS8 %UP}h/, aRE;B8aT~acE;t[ dW1FEJw?s((c}V' 's7Dw NIm9[i^HBj$&R:cZv, 'k},NbiIHlfX}D4X}u9 塌X&R#lj;D`}"EIඪF. g,lp mEE/տzgs0 ght*eJ@~@ ^!՟wfs@3<=3[)@BiH`W 5oVVQΊ–9MQȹtdfnFTK{VbdPe@Wp4c>18뎁YoQ"`av6~ P磯7U _Qyl9B6d뙥RYI)"v:,hy<O5^YA0@DVvuN۵Jآx[ 1;R[I&vDcD^`\JӱpεQqKrE˃ KQoM "Λ)N _i]"H"s!2~'hBD6}tNm$آk5d-$%7+ѡhEGig\r8@kSp7FZ;ǒSyJCEM. K 9-Sr_@&ߞtWLkXZDNXӷ^(:y"r  ?^YpQ<7fsԀ@'B8 h;ԍiIRlvUhgY8 y}zs{k-?i"ևR:Ky?] BHeaX/qS9BH5u /u*Etw:zM(y#/əFR :sfCQM(NwqQEm152MS>}>ɥ<'& h@b L%ݔD(@sV+H)d"][hpC(oݭbQx#?#7T >tڠD7X5UpKt(8[fGu?pPZƯ܂pWKgeZ&Z@!d*iwM%Swl/xñyz4L96$M`.cmZH&|aTxK=>VCbS579eP6voSPe?|{0DIlJD탡%Tk 46'gnx{F5|w?ܫOy6=(luK`jI?eXEgg΁[6xd\//_xo3԰g1o0^,2\3oU+ 赠x>`xlÂ9mP̫,mYEKPoཛ&L\s/Uu\Ȱ0 Xԟ擶k9䑓5 (;ROۺ^^ {UNOxU8$JD}l Y'&tCo#C@cd^;w{?B+K(#:=ZEfG;p n]Ư ı*XN''<oyv~x&7 )7 =y'42*K#dӑ Ob1ébZM3 (_h_l-$8Nv+9woʄҵڷUs8+"έi}cPz`@܊\Ln ]˝N5 j`+8UfW|<=/I-M](`!a\~+sg]w}`CtGG-|4T U/GӣĽ/_{-QV ~*~,j.F ]3z גP4D#`gQ KuK.:*d9Ε:RzdKJ $꺐n])E`23G!0 sTT=#Ki2q9]L'D@zlyB*y0H =aJӂxnGK##{[`¶S8x%CF{,ѡUmzT BW#x ',]$4A0鸜yx0ef0Ҝ(҂Jℶ7j,P4)ѡl+Rjn=N?@)%9MՒۉsGcIPBX7dXH|2eX$'Eٵz+(PM-$/pd1ϭ=ιH/xˋ,Xl8#~&:_s=&U"JLL.7-pݏRjnhzaX.ym(ٞEӋ퇳=stS$dD+w醬 ^J*qt d9:~#O\H&~2#۬~ǍܢO &B4'RN P"{|~zAذ_}NX*RK3D.։ٷF6jx$JyBTidUMEñ,@<#)A@#kyXM?Gr%+WypӼ&|``MIi,cCZ hYBaA~a!eSzS?y9+͖I)M`R/lzaoia]â"r_4~:XS\u{s+X!&`XX?_|o^+TNb-&HJ4c h1(<K4M:5#i:t!I Aju߫]7?+^+`+@(f ڶ* ƌp 0c iB*2AF`C>FpƂnJ!4B S ."7 $2t5ñ>>p .Z d䱜kńNw.vB7U"T .qܴl!N-tw]}U_5hWTQWTjXBیnhsK O3W_OO%_bmXĥvH[TD>e?K= lрQhaC!/&t*v!.am.5i: PMpߞ/_rF?"HS"iR$pPD8c=.$GmYYp*mJn'IB𳱟}< ɓ:*=Ʊ}Ǧ\mA}}1\[!w]qYX{,L6ɩ# ]s/BMDE9;`o^k-oK_wmuUW=~ `_zSK9c%"[Vٖ |MKAMלPM opW@DQ|`ަX^Jfޙ7U31, Fi!b1ug' fzP:A_>ߖ,/K?')QRA0E'ju TLX΂y$Z͢A@ )ؽ;_8Fq5nruP?aǪ' EDqzLDQ3D73NNҦ!!%f;('`bI?؀=%`oAJX:,˛TU? 'WRb5{q8R$y% 7 ."75OM氐誔`Ru ,ETصkB4U#s@e$rRV z*@ IDAT@ D]$n]$nJX A$:":]6BS\DnVQL3R^7` |%GQ+{I!'ؽ&%A xHk(wQy."׉pX8k0Dg],TE /Ss 0'TA#}`S`sQ.":1I*[p8b'SKR.c4^.25æ5 ]㕽Msӥ5 LjdYc65~ypZν6 'klwG#BR´1M'~ɽM:®  /#{w^ l# -넇>) `_t(r,OiSw;*|}jp.%`Ȼ(pmt(zڴ ϖy#E]lOk .gpNcJ }>7 >O؏pPuLpUa@JNÞ.,Pq}3b5h1AG."WOe~rr`"qpO)_= UVfE;϶aO6! g6b&Zn|{٢lk  Bb˕vҨ0Lߚ1a%7\Kbk2a-[nt"M@4M '.ik$eTaf& DžjO +u6 Dd"r- 嚜:rK:3ۧi]wSW JO=ҜQU 1IFeim$ 4@Ȕ6^B j¨L8 a? 85HR.<0%~OD6{cr:e *xz<[o<cӹXglUtš~911:zzzn Qp r `{NXfKakz %$*͇Ҥһ>u;15danM1sRE0qPB5 n%38tX#rSHC$$tJ93ɬLZd hЩD+UVE(//;H(-U>'p]Q>Ult(Y/l k_d͌< v?30>wk`=Ww.̄Fdg:5r%Aaq~ml\'FtNYQI)V𾩍i !"-JkSy`op$|RZϼgy[y;d t;/wO v_u?TCKt~xX]f~~vߪvZծSp#P`z-wMy1O~A5<0(("E0"9"rVAmHiDIHR+7_}_ {{^BLD.IZÄi!Q@&Dsd:?l(%vs:M3Db mN{z Ԅ@S'Swfrfw:`)P}\yVm[Fxf}O9 ]lo>9 x>+:Te|=@ף/Q~D-]T" 3-vz7<uǟ'ދb.Xw1$Y$}[& i"#d*x4 ! %ʿBr5*J\>!x/Mjñ;1wW|X~oΑVGw"`g^va\izdVӪvŅ3^@lyΓJ6-ғ\LNa!R At(xuHAf$XT.0:iLO$ ڡdjiCqĩPս.Ij"Hd"0lɛz-xTXάr !4HTl̴&5 1 5Ic`tVu[|MxHS|ŏu(P/|(:fG?pR3ZGé<5#$7KIm47K"_[Z pk @2Mh,udžJY!o ' `{(/c\_TE!rx(VKpGǜX4K~Xb=jFQrȯsp%tyOt ]X84GD&*E\,Y TcΞ9 dzNejptaJH ]oה`@ l fMkmϛsnJ5Ge' G֬R(Vi:t}Kp[R>9 PtVvp %P94à!ҠHɀ*ZaՄ(N[p*,oI?[%<,2F;Z,\tgB8("_l R+-*vV9\,$ L@>U̕X֓w1R$,u  i7Y'Z4 nS2!<֦nהs-^A[ D:'bA, W\@۳2.ڴ$:LskcNBO9͙ac,/],Ta.$` rdN5OF-^?*E䘟;GXIPr?3n"r ˉ\r>=< 8 Y.Y*XO_c X()b0Ʀcք/)JiUM!ϲ}+<YB)a>é!TŶNf'nO8Fali#,l (AZnM] q`! Dì7htXwt۷{`훜]{N3I4!ݟoU;'&&^gWOOOZ *jF)@P5y."p齱'-&av>%ܒ=$wGy HnB şV +.4ۦ{]th0':iJM#5x]ː &\$CiY[S(˄佔&:1Mt,,2_-)3,O}u@7@FxL*9ڜT 5Y=6cSJ]SUηY1[Qey7x+)RjVE9 }ѡ+5:izJ\P7{O -3nE8llYw^r gd+s8y],  Dlp8fsw %DGiqE`k!̓DI~ReCI .>?\M Ci?éluK`8~{>oZl %qXt\uGZуgw27h`@>"#2 /zto\cԜ̫{FOv BLz9VӪvՕ|-`i &TB#@۾uHM A 5 ."(/b_($g 1lAl%Bxp( S =YB@VÐx3@ !(#Y&+L`^?:)CqCHQsJRnyWѡhR(/A~w܎w;(8ql_wONR#r5ͷͩUٖWv1KVس ;`aQM{)Ue?E:cVIS#a*z㹿:p3‰u2k94΢VictMҋ;7OrzP/UG'?<8=p86M)$ÀFdJ!7 NͰLB>疱`p>ݷTxB<&, { !4p8QixSp=FIR^d:^H&| b+s.MLc MZў+~uŏWv kK"\0ąd2'sF(n\.kQ wX:[ <^ۖ}Ե3xL[NH!]9B6@ $p+9V#oG:_M]]kb({7\r>2 Ai:dG ڱ<X$s.  z< ◛M$}D`i|ϵD}3 Dͷ`w 1ضZ0pr9gG(>#.gn6J[ .]$nC `NlN#~cGSb@#oX~d[dWW|5C|ύ@)}0q75`z8 P$"<4CRX&F[M."׀pj?k۫) sɒ+RznT8р P”tM`}q=ؘ!H %Lt8x}X-[ ,/r5LH.e;Bbv;ۮ꾪cӹiR)G b}{d$:3 `,S8NwdR) R:|J`t~Mﺼcmv+7t %h|:˄Ҷ.NY}o-ggY4/9A>3ւgr]MX"JɧBLK$H /i{U<9y yQs`ްAK̓v v pp, LQt:  ;gLSWM8/o#)9 2v` JawI0ᾔW!ޛ'4tk@JT%RS)Am)$;N}oh#Slx -ѡ{4]= ߰b)LC8O3ch;f]d!ӛ΢qGg4-YO9S." m8E\?\w?)UK;PԇRRߵ~WꞫOE9C7ݷ8^Ugmۮd䑃|5MK`I^o}HtܫQQd[M/l{ߖkH@ݭ{K5C]v5Ȗ7]췚]n{zڶ<ͻ?ڲ11;쯶ol٣$&Wu8;tspóãKc*B`"2M7Xsb> 1e:aߕLgwmp^ad( c,91&TmMaV26}Vg%a4yw囡=m& iW("@ IDAT[miz3'\O?6?uk78gj}2<0x?jD\_EqoE{,Y2~'Q5.v/0wh yoR\w$ 6ퟎ|s /؞r9G ۃZΩ !0OJʘg}'//ÌV&.'L 9G'#SZdBMcL:\jJKh%{s.xmDq;@,NiB6ɓ?Lh|&֗M8a'ė@:wq?1<1wW|vjvNf68r%"{`A<.Z\& s/s({32M,J` Xeڹ4&m0p _p_˵r 5?_894 5N|1 9>^:xj%XdyyXC I'ܺ ry%Q$D t<=)j jH0hFQ ,PBQ8( YƯ&ċ1fXr19&IU2D{ 9ojBM7f%Q%?OG (Ry &PZBhQfqz~m8~l|>tJiZ8%K;Ű`E<+ xP iU6(NvM.릁]XO,IoNSQ o ӯJyb[^>8VCo=M)Os*+I0Ԗ}#_h[ ׌IR(u㤋Gs=9:;WGj}`cصƂ*oO-ʑ/yX{|S96O4mD q#`^rNO{VEs$+&`al|GCQ{NZp{nZƯ^p3 I)oM/̕"i|Jb3-pV%JDx*!$^^jz{..LF3ð~dK"q,A+p N)Yl\^ i$E ]_vF*~NM ^ZuxΫ9MJ1|;L x U<\KQ)M,اȶLHR;.&E/` vZ $"2|m7fLNm.lpZ"dX?X[ܦO9b=5kNyL U6IQTϛZ{N/{gYjW%'lO;v`*IP_[.B M4rndm˗lKΕ{gx~&_@ M0 F,Dhp\bIumJEo8BشA?\ܽO=Oe׮8 ) ~s|?M˝`Pţr| mB uBfD_սYH~~NiB /kqP;G-/?7\?<7\ f"RفM$F#Dn" ^XZGF; 66ۧlfS7}ܹͣhy5sNv-.:,m>K|r}mWacFaܘqQ/l`'"V~B'n~)֗ BVPj0M-:ZMƞk3dI}?BPcj.}M11LzO"3Qmv"ݶSڣE5Kbu ءjpW;K)_md)N H.0<@bc,K)/֩\8cU7dBHLrGc?\R8-Y[) 6X[%̓`Cj29Y~fL`@b& n@jan^'to8x!7{ZTC;|?R46RM1pH~Y@/x>mO5\e':tY&j$ZLST,JO_Y"1r;4! %zS}RWj ̳B~ǜyʔxg1KQjUXU+d D JCŊ$p"&ٶ&&2c'IE }G@>*R t cc-q~Dkq16[XbS&!? ||0-KK C/q?(|K9paR.%U90p^52:x>ߧ8hQ-P V!p}y}$Z#i\N\dIψ΃bZy9澃CB/%%{E+xurlZeD6anKg̕FduA~%}5`!}yAm^ozkN0o#')R DV v  ^!2T/"_^枢Qh/XAKƼL QIs+o:7n*!"'!D|iP!"@3fü4Q`,yj]6к\jm4ͮ#!<>X2(_,_ϖP 0L 0~NsbbEvܮHi` @7x8:,؊8{lT'r'q9Ohp}A9 iK{u[6Rno#c&zѻ>E -{H7Ox9`"Zxۗ/\](\fz.O3 I̶AlCΒb2f 1Gr pjc nn;4_BQEu:la Ov5qٷ+~{lZTQ,Dz)X<ǷP|R+>{0p_K;GTl4w3@%`KiMR!7/GERn?F@2hQ,?9nYY'/#7Hc!CX ȕd/ED. |j%G ,X`}ۚA7uw<8`a֢KP8U=ڴm[.{W}ԇ"+y[x6z fa?3 D"79LO!K/6`V˗ޱդW_Vɋ$rdx랴={H"H~r}jSZurAπӜ^G6\'κ,"7╟mbrk\NMϺ( >G(WllUcc?;7FXj -NK8 !-KGނdy”sϯ:b-<+@pGf(M1F(`_+@03F%u@ wm 81%BH7^Bu;cBn^س^K2\ ,ZT*^}WrS]TF2#:&pȢS M&g~ˆMO/ /3/fZm9dh[H4AsѲ){M͟HVn+dzȸS"~ pN~8NڵZ)烵=4 , b! ۋ([JTxT~5;+x}g{ *$ӓSCw@xSD c1Cj}#ݒ-J,h|?(f|c$$'Inf&SCI2cպm)'e*K]>.6V<\MSI(!K럠B3sPAa}>力,Xj^4r.>?皵Ùh t'U˗)3ϯzb-,0W-Emxaɀ M5lC<ى@ X !@,@a /W0t.m] !||`l'EL-CKs!*g{~F .Y͔Z:lW^fg-R؊ѢZ<סw<7:j_?o6騾xPjFlFf5tq_2hQ{M0̔&,P(J@g1ޣy/C<e"䞷y) yZz6 V)"ku^g'T2U[ᶽVem s4xhܛfk`:@ؒ F@aLV̦L-lQO|:X?k,5e +"e3AH !'%iM3%p'}* ;4˗Z/n]SqŒWPk0KfHE0C'$kQVa K#8=^د8HAgX}cYWlӔ6!2#N4jG@H5v_KiAWW\SUL4mKKg]e"Dd6TxK7u܀e,;/} S.}å YТhZ ҳ^ 9Z#,W]5!5A KOD/aG>I _O򘵓0bD%=J@L"_D+[.;Qh}/`ouk]d":T=QLdX\ v΀Ob(MZTTibrݚv4>KjH>zs~[wFвh.MVԑVnNSHmNBa%XŪ.br|ҪRV\ cl!YQd@P;tXݮ]ݭ.i$?ǎ$pI@i]k__OÅ9(k@ іolisSȄ!;$+3XzZgi<ɺpKM_,a3|7 :Yr9<xKݰl n>8; +o5(pCJp .&7\D^oa9,?D\LƖ;:7$/l5}o@dktleAPlbz^&jc5IqEAD* CMIt3 =kPvEf+Ѕx5VPbվ{Q 0P-/9W 7_Lbɍ 0(s6l*CPv4Kja y. ;739R}@ڰےi(0+n0ୱkmG&P-a܆d5>qNSA L9AX i<?@6ɱ>RZW'iQGܐ/"I.0&RV%Kw3Anp/"xka4zuPhQ@ QqU7h۸϶#2zw:P{b#M IEޑ2 M]\ t5bgxW8R_j~ ̂߃X,s;g u\}T?=j(Mk*'B44%O9xt_E5'7@ ӌ7vnm/>0F1cad~ɋ:s"ΥR^EDZ]~Miz"P򔦟 y&3_(xp/$f \F(KcZ6(-ˋԈ ..6!'TH&}X:\6JvESGj R$/7QD+vW߰V|==M{m4;,›20vLd0Hv#sANEj#XȚ XN{ZBW#"x]"2>filIj|0Y9Аeͅ}ՉE!D%0ܳx)"xg##+gτ,ՑXNd{U\ JG2%<(~!xH4a Z X,G>hnYY"{tA@5gڇ&p&NR5fuϺ=c1e:?M'ҳl\(qQ-t P0,m}7&]\o3}͑t:s`sdugkBOOPOwxQ;. g_Cʗ)uXu_>ZngСE5G{Pq[?{bum}zXx-1` Ee3} d=5(<5Yoqf*wأK Ԥ ۺ 6b /K=$;cܛf|3ѡJjI}Cd{3'1q;"K)IFȶK? I:6p/} ΍m-Ԁ3&x_t:s'Y)}i;Hxɽ|'bߥ\vLD."kdl5O8>ǗM&_.0&aoI6@N|]e^)]3 Sk9<{(9xM5?[yw}om!۶O_ pTtٽ];___l$yrM5 Hq|ǿ3nZ4l -1.fՔ;z]_GɌx"y*o}Ơ9@"zoT?f8\Vo'6tlצ =ݞ}vI=JY ?~ϼ#5M+N {2r{{cOU>}:k2r9;};Pd&t}>spib԰K,No[fk0<-퓈ע ԫz_cGG;؎mH4>:]bESP+׾Ӄu7}8oyw'\MQ\xMWȊ`6Ñ~Q&Dʔ$y?'I|pM io}&oHȯ}Z󦀓Ie{I>Cx!"@Z!?X^wwN{DYe3?镼h:dߥ\vT_YdmJޯ_M wxϺ=k0{Q6@=ma`|d_U9Qa{SxZfggA/d ۾HU~?$IrldՔκn֝P ?~k筿yk.r7mw>C 3Q/K(S-;JoX7_~oz9oBږk9rg`׺^f6ʁ]gNˬ{Yx~ mOTO8 UǬ?{24ݶwv4IR^1-G;I0vqwu{>[{Eb`:Dj:u޺{G۶ӹsKN<{[76zm˵>}8KIe[k`ךv_GL_P˖<0sSdDomm_wRD0U̿|-ٻs[iɌco6ui(el fa&ⅸ7Cb[x3]V#j~_t:K>tMZ2}*WJ>19VRO*i#\@fL#6)ԫP _aj>ѭ&3Ϲ&o'DO=InV􃠙Zf^knz;~ӹ>w\=̄kF~ئX@,дF*H)JJ`b>QH}>(T1'hKs|bZ$II7z&7 EY2wݼu^v͆P1 {ZwsZ 3s*+&cFXhT'TIjo;m@*xm5YVG̪i$\pS9dY`ug7^ƌ"/i漦&%А13ޔBz`.z*#+SS{=!E-OeN3Fb+MTc)go(؆]N~ne%@׼S>7aSvc yr\2ɏ8<}F MDv" N'@H "|33 ᡞ.X2"G@PD);T 2dߥ\ `;QgCd:)JuDgs;jM|E#aw}hCV웟,ka"@ [ɲ>/sOHλ_.ojn o;8vcYvxp\)|GON>wRVʑqUUk'&V1 5=\>~Diƾ%~;8gYau>eMVd 3mX!g)u6?V:?|ǔ$ 6o]:raܮ]H|'Z4OOh-ٺ=lΆ暔bcf 3bLmT5"R#{>wCE *!d?wh0u @+:_%i/3Vk A?ܨzٴXGnsJ֜ƽo{Iuze+ק ~`m ;mM-E+YԆL13<8P27vwGRL*˞}s> E (6Dߕokeύ#\eNˑ,dIHF t:<@RAmu{G?r(~|CVlxQ;Vz]:>.Kp $Z w%pEѼMj z~E|*04Dl{h}+T? ejjpK9.5u(a}x&gpG fz $gjU=Bf2ɒ4>Мp$] .-)]){yCB%sSg2:ً'SOócTmTqC_L ux@GwhpKEtĝ cYv4,%W6p[w ;n/)zL=$Aae cl[;LHCS#wq\,p\8W\ayĬu*kiOfOڿ`uBSVeIE Ob#8.+$Z֢KS oWwb`Үht3dEK"ȃGXBD#Gs{<*mǚpĐ(b `揤YUɈk[H@hv2y[:ގDAU *Vwh9H!cz [ W(ࡶ{a۝uZ %lΗ,R;*d/[|r*>`hl;Ӵd2 YpY|W#Z @ 5bjяF45,vdlݸWjʤ@1)H@it}#")54Yp,ĤMi~Lϐm.NSLBcbR"< | \Dr:x(:;6Ey*_&@i>lȩ:ROY(Kh֖НϖqoFҶ# Չ5b w,MDpH{)ZMĂ  #6V \ ̵Z ^-Dl*k[3bDhk@*H^=E j6_n??؟N]O=;|ċ꯽qܘE-v9itU2)YR<,. o\ JB[Ң@ ~m-JCeJ]?c%yĥ9_u0dȄI6txMz4EV[圡?<=u5E&%NlFj|5@ςk ؠE& 4ڨ"`Np/ww-Xn*r;4+i`eiGܺ: $ǖt%E~٩-KmJɍkm[̪zN9ۃb]ϸⶉ0‘ d%-f",V =W,opF^6_n??T;j׊E5?ZE:zG S#l5'| ܸ,)" 9X -9%Ty AU,x`LJO|=u]*":ԫ& 6Euͺm_`@f?x\ H.HZMhW?ZN̪X(y?Dc\|Bv ziѫqEɏ7 6mֱwv] c^hpx\cBNTiQ-uSlLbWx`. ^kK8O9_\qn)v19h*PxX:!&&Rs9e%c5+F<!hlcY+0}:LZTsDgB@ X-Y0 4gLUIsѲ`i:\usNөvSh\Rdf y0飊K)cY$"a-uW$7ࡔji<ĵ `Όl>oG(Srl砽(dCGUZ|#0 @բ%y &lcDsc׀seCp^cßk9n)vJA]\a~?M  =~Q9HxX@Q $4SCR|&i {v)1VkK%K_-,tAN {)E7 TŶC}b|LUuJC9(@@/ \:,X\JLY( VOen6)&A,OsZ'mJ/y js˗yW0( X ZJ?q?PnyIkVoNɛ YϪtxrIIʀRt &ŵ,foDZ|z);48RhQm 3*7pkg ϕ^- HaEz=^kaC&!,c[gr42/g@$*:5>'5YXYZ9#Z rs/f$`ТE@vIqr\lvީ0A^ IDAT^}}:ƸD^Ri[=Tvv@Z>fPM,K,fߓJ?3ڌ` i>M(`؄^3YjK$𶳼!޾j5"rVXD^T+"3O:,f C"roc !" VR"L!%%iBhѶz@̓MS 88<k?l D=Փ"@ XhQͿ9[z3g?I9!/YA}ZTZ-kg's?޷bOɚ۵Rc'v1." ՙצh!EZSc\(KM pܵB)ʗ5 Udn0RۦoHیb @f&hZ?:]f̖lPCۯŪaMi{v u&eM`6i c;!-@ǩ}>V }W,z=;ϵ.PMo(SZWX, (OH>tF^NO-;r,DڿdƤ/iC5UXx*e{u mnT1C6aL_~sXbCq\_h{T&wh+eծp?a ~˼07%imW׎B*K @w8>Y"n vX3=]7t f"|O^d2SPCN⡭$ 16r k<_T}Q1H͌gC}rIe&̎%ryUxTԎ8;- F<'?=SOC_Ah`G5d6%2VXE)ksN*[Z=Yh8Ö |S,k #JQ:q;m[de`,; D2dD$9@`c;܆?W{BViGF6>R, ,\|W JE]~~KBl@=e4KߔuiQmz?ݎB ~%Ia 9uA]8NO[쯹N'`۠vbHVl;dP:iUө},B2)*Aa .*'yCs9!d clfLBv$+VYA|1IpidnFjX>/`{|p:U]\T~2x`ҹw{݅upI}{1ѢZ gXe\Jclٮ >d#rl9YS(PTPˤAQ jġ.2\PɑX1}(Xg--.vBmec$,$ L4cCaNxW٭&َ0=բ3 U11sLÞ9\ :aW I'ҖBZ,Jԑ&Ќl\(8Xl{m `o|տ բ~g%]  6 򛖰=ފ+߫wRv}ej)oIJGU0W >rꑅʌ{Ű0!& ʚ%z<U ^( 1eV Lܤ*K<*57!f@Gm;=*C'㐃rm. o([PZZ v|!Q(Ca!zR@ڧYqg@ר"PrdSّ^Ж^Qfۊdci"@Pb)Rbm(Rk352ܐ A9{4x@|+WumRN.f#v)l^r v-3sr=* D\*/~;dgEA)qInr<)$D;9qvEکk 'sL|||.3wn3|C _,[b1wXS3R򦮛v^~a%[f^K޹坛VC_4yrv4<6Bns;jWxx/wOa*~M߲O'8p`t-r;~Λ;S-t5 oݝE*g)CgjiZ:s;ki- 44Wnw*`@Wݠ9=|)x[3olA\QC v! 1nwfTNfS%I;m1%Odcm3-jf;Nntq :wlź>/KXLneyCnp]R,a6wr!RY)YKYa@+C<mFآ_E<}+h(fc?\oˤY_s; D"1nh&H|r CnVOy}||. d YY>9 dm?Or9!:t]br}_br5jڴB0n3j6DA@ Ur/οhD aX<1&^Cfr+3`,Ctwg6m.Н>2 gdnpLLŅ"%]T_@S>\;k) `M%P T\1-Pgugri%?=B jժRH D4 juڪ{ZZk,him43iv BH wd}vPKg8&MlKɟ;lo?6 %1D6x۝9[",wS6d3ZZboƢ& 1U>a-fUiq>!ZZk`YS!&itdRVQ)&7RR53Jim+ϊ ʁ FG0j yF1֪}bWJGR}V^.K vhi#}7=ϾR BFʼɼs>L  (9<֎TT2Ґzs %(xcϥށjuy*uIۖMPNX9px-=Ǻ"߿B~g(> Ɯ?E [e]Ƹ+4J;Ckۯm+mTejm. 9SnEm)|M>0 Ġ;੻:<WO8IQs}-UdZ,N%Dʔ7Z,{o{1֔f} Bp2ski-!9RQʪǰKhݐΎd!"BHBL.C9B mP<*{оc, =ʮK2U[ڬg[j{^;lÒw nQJA%M[lLTԷlԄbr̎ l,s 4ډ2i gplhDĘ*wPpRS7ÄQPϣЏt/ ey{X,VmyR࿭p늖(/+݇0犅=,v"4.% 2wu^G{5ʿf^n_+7}\֪ԋf+v|Ϣ6(٬Y\Y,W&Dc]qNs1(}y!Nup!< jcw9/Bk;dU&ubomxW@UR?8U!=p=#7mﶇTIߧZR_kj`я=ߢu:1< Vp]iiMe\n)\.8+x=Qb9!ƞ ze8H*ݧJ! g o|OC Y̪3ޯmb @VjCq[ς0fD!&˶ ({mL VAFmg/砄\v\`IPs~t!8;4us_Yjf6E"D2`d LMFEZܙyzjBf|bzg7lGq4XJ0/NB8.H^kZZ B/ )s;Ưǯ=V`^w#aJ5Z!D=]g>R*cs?s/nl 'OcmlT!# @(o'.̐fi[xd.OIP+&72%"ķjWHrvMMČs|pHvb'? zdG6@LjZ"Gr{y8r "?gJpOBLR O fʴ]2Ks2GgK! |pRo{[ 9#0c`iʼnQɖ%\*6 h^)iMY@j?p] -ccﺈ>|ީ#MXqmSL[7”&OvʼP}pX6c(7 4{Yzdi eVG˓-P"rEPZoH4>>> uCG(!/ zk9ݟ}DՋ JtIe[c2E"#DYN H17BL)52|68톇e0 fҵǸkxcizd*+TF q̴cnaJTz~T < guJu|"*x6(۪ "*,,$,CSf3ٵJ\lʓ5~Da9} \ sqj,\*D' Q6%,yx:zbDۂ sGW 3p @AtPu "+"bD>Q%Ic 8u;S\r8XP8ֈȋ^1,EQqU9W^*o{BD8Z"cS5B3l@ ,a)q BvYKC6β>øܓJٳ|”,OYpZ &) {bo{7%"d{s*z4T\ͫ UlAȱkMj%{ЮD6@湹%o(KR$h\1<x+hXlxo\%@ ȹ0RJ ss<3ȧ!%+n2pq""O3reSs3IF% T)l[!&3L ^4z;^.x9$U8wn)_Rq<&N Y9eScF@Q8,B2 a,&UQEiMPwWV><| +؜Oi<RpWf0s.S-48@P@5(-D)/S,DE/}.D "4m~oPiSE5{YC- ry.ZR(!,r`E" ĄZhix$tcss93i߮P>>>ul7l|0lO<910٭ʪ2[o齽 @,CŪYxHkqwgD+~w&w?ޏx ^lrx懜޷,P\_w<ש^&&gox߃ e/|ɵ :ݽ:=T6]~/bo>wU׷_&3 $U{ x8/x$; 0 !f! NDq="EZ},$IGb4~ZOfNxa#snoGq{ >|MٰWZuWSOc2oS !;}[\GG8rD1kL~)\- m۩o w]h[;2:l9A6!vE; cmZ:47iM4_pȌ{PVf6۱(lni+@9h[0Vd,S13*`V(3F+ !`rKG cF`rZ.>>>KőoV슢,;&ӧ,;?R*#A)h~ ZhiM{Kz_P2gO}'@26mYj<-cA_=U<59uT i4s,5UlfYw6ČSs-/e%o9#wg^{̔x臇4g@ JA5(ZOdB>!DЊu'ALm-BLdmx^WBxx'$cw4. %="&"DVwm7x%A=bIL&' 'PjWy#_xѼ+83LRoetI6ikQZO'6*Emf/>ixLZ)ώ1HĐ btFe8UKkW Wgڪ5cVgS#]ϓkim M]53yz(ۍ.'YjIIoLRЭSB!Ph3I>>W<"3z D,r/F"CrqUιu_wpvXk2mN@4km9~w d͌֒B4: ݁2ćʆ5r$B4(Dc)7pxe~}׳rpH%c!F=k~#CX 2Qoe3M]XVȵ,|>>Z_GK9 JBη:b2Uk'<\s 0g.Pϱ}|Vus$|VGaɻj :bо$9o_["Rkƭn=`AYs_R;hKVSM~q,5zQ_DpǽnbV\mABx֊ȳhs͝bK)vlT"7zBMd[1Q R< Rn]JH/;*!bR`GTﶬ̑ ۶  1)97[D<1{7̒X XtڔbE6+W*5 \7c"Z6# 6!z|Hmh_#c<>cx u`e" "SD \D> T2Er(Rt8B &%ϰ7yE %>ቼR0/"4+H4 oRZ A˜k2c,|||j "%Pȑt6yW(m076r}u.or_. cYeS}R`b#}1@7rZuLoL<"G"" \yl+YIg;KKk9_Tכ[Wm[w]{}?{_sZ۹ w,5e;72D[ {P%5Q"{_soӔ >> &3)O9P,f63>(k 1xU⪁m~ۧ$*[yR2 ~~.xy-@UibQAKoKOb%{r/ު'NV?`0%tM,{qT(n7 { f=-D?t:i^s+VKeY5(s< :z{|vλkarWf(m(h.6^U+_dPBܳ]8U&_{XU_rVyZ/p>~d^r_Zz?~Et^|!Bǧ1ö1+I uy~&Oct%!G^l]"kZ/dG/³od,UdH|||~jvP!I޿i>c#zMVA㩅3X]9 K/ x^>'8ϥ̘L8Y{—L8?|~$/DC3ʸ`"j¿ ICiR>ӤůlRrY3<|zB*A.(/(&+/*/Ax!AFXVvmֺqۓsߦ1ȱ&Ѐ a(GEdCtMK*z]X|:u^C68"qH6}n߻K %xqO%ȅIt[P.K]ɞP_x}p*p4VdL+Pq h%K;oS4/^gȏRDd7ʔAI8 kX/Mmʼnȟp/"7M )r٠4"qnp@!jcC#火W;T( !R@L>77 m9/B Z/p?JB{k;/gg8s{ |\H~NH B"˱X,V=>Cf0SG-$Ď\~6|` CAӠP\ַۂ-u\77,ynq<Zv7uݴsA_SOTf& {fÚ~)Rj6ƣWc=GBLIrɒI,`<^s9_ϲqgqB/슕MTs߂l,6I !H6M~x{q=Dz9&bձvl! u[M%"AA -=7{~_V,{n1Bb}&AA©"dY)mZ: k($N=>U^%ӭxдK o4G=ިGcx >\!:-]2m "J(maBdsŊjC @x[=װ4u%.1w۪ٯYI)GmQSڔ9}H>el(8_?||WDulUBV"PTw=c(e]ij<#$;5`IvEB@eǪyg_ !! t=sI_5ŧXŬʖ~Ͷm{W(HDΝG߲5؊Ppe*kwՏP+{طJ"Pl:Yo۬|kVZ>֊x-0oɇ@|@LQw}D$eBZ=H2cmCʸSߚh*=ХX\4.FeDBi o"ƽz}D29 &]Х99Sn[ErOTr IDATmԶ%°$]EyQB[LU:#GvQP'Lˢ N0Rk/sN9ŧlydH߭prjdغ5!HT4_ f nHJb-Ѯց7|X/ &1m^@: (+Cd[45^-[7[@2Jl,E ijN$>2Hj&ƚow)!s~ٹ D> \l[,[qyNf-TsP\>lTD<w P+&?29>_,[ڳw6lmRx< H%=o84esuHIּfFyW) ;퓧T:wZE$f>87Q2%6=_X ƵbrC;hgF$%E|Q6oJ952lHLy]Ucu*os̪U 3H DT u|kU޾y;[ 3ZB{.o̔I@x)gxO9p}!_7d [(%M-3W%RW&:|jd#9"~+3lcBz~qLn#-$ 1[H]^މSԗI__;uh)padc(- C6iT jqꈪԅ< ">>>+Af4:si*uA P0 Ewޜ "ˣ3- rWݦV.턐~/A;!s>V,Ǜ @ڷq䘮 t~ae k-"/?GMS͇۾@.%& r(!ھL]ݲq,ФbZԪXg{pX0(#|x#- ށ`^iքၔSygWaϴ%JB0 I )Cu-E!g4`%%Y[, qXQ2&126֎qK&S^LZ[o{u2B Qt2vYGE-X,o/ϫHCxo_ nN ji,DĽim Po9@`YCx`i eߴD(1?||Cwl1LB8@T US6r$94Qzq-;b]2vEJ!UTƠxۥ|c*&Pq\Y58:_HgjWO="A ծv2hi-46|^;/p~'t;˺dD9Z ")0$Kb`cZlpD 6JA{gسp$ C ikvRrf^ue+ oeyӫ}+ۦx=bb# ag(1Y38,By fVMLRlWHyb8~ ĤfƥF M!*SR G.ĐUJ bu" YeNJx Qb"0N BjMdD2x"ߴqne1#ԡݶϯ^K8D^M@*[XlN" ˸82߯ ADmm˖DlS@.XoPD>W L3'U˼3ɞy>'[y!^OS|sIUOG6e@ i)#=fQج@v:ŒHQB!99&׀m («WxFt ZZS!RuVf0= foҮ>Kym4qC,m48keOZRGZ%;<:A _qԗK__%;{ЮLH+mi^l2X^r[nQKkV3||t4EsJ EaBVЛcr ,TY<)$ !z_p^. ٴoWT~#D=ǹ8<>>>E?D>=Q |֘Έy1V[.J.nSׁff3vF>ny|\g}y>h%ˋl8!iHBBPJZVm{[-NPZ&l!@ YH$ǒ-Ke33g?HVX˚s9lP1ZQQ)s^FWJtt)Y::[]GvX."[ٮ/Qe좴:W,Q^yU y jSxxW͞I:*ĩJtdr?ef6;<޷od+d-I"A,EFVw߳-Ie@xcc m4m*e%;d`vɆ$Ij3;.?1ĺsE~1,ߕ͙ͶݰHid'Ll0toi2&$ AӴS[N},w K򙑒U̹ӣI/CF3rJ;vcz)#iQΫªBC}nZ \t^Ze}y~-oq8'VbdmDǟI7fe;Ɯv2)a0nR8>߮(5=5z>2ճ9w6RRz*7XhB!"qB..Ml V0~/yExܝ3y{sj].؆7T! ~V7;&gTO8֊l˄2@xZT|_@Td%.@xdJ?]jkcAp#j@;"Y,Mdc>%g׶RY'N9M bzA$(Z _Ewa}zߎ5[g+qUa+ bb;EiE@Cqr6DjQ^KUR^w[2؆+ ^rM΀`vƽGl==}ercwxQ%X7oȲ^bmw#hvsɴ믷>QU%4#Ӓأ4kQjpf=YNA@%|ɃqyЇUNgֳrИv񴳯du9bȾ6!%'ZPJ7X Owp;QoO,bxk𐱞cjQ-r;co縗Bjү'S}٢zSR )Qx  EL·E/z 6?JzI[ݿCkث=L?9rq};O,o]PH;$aC"3j/zf0X0A !wwY,ʍH^jra3c7ccc_,|<;RZ]\\\.̊ZzD+^,eǨW5@y4 .g"?o)n("Q HBSEU|*a(EDa0$|8n_0-9Hȣ{%,_'yZl vIilgvuF+R@ vN,ou)da1:5@am@2bL5Gei~˹"ru(* DVPHD]"^1؝yBݦ x%ߝW C}<ՉC޹"r;b"r[7[D E_ef((R@ d.L !ZDY?.W2+F2uMY;K"'Ylť^Ꮄ`H Erи?,鐮\tjZ1UB8*7elVSa4jϕ̊Cc@ 괙-D0OO' v |RcdrmM$*Ə8;;{yK,(T]JEUPx2eJ.Р4|7-RH4%R%;gZûtǔOX6))+%`)PـOQu@ a`ipt$?6 |l! 4 q‹lf)"" |PV- xK1uu^j2IpwU GOsЬAArD1,:6 ':6Ex}:/[ | ka0}rYsPW/v*J`8tMoӴB<2ǎ&hn K;7$4 "WS}t۶`tx;{=*ggϾ:4v_H޷|? ,~+ɣ"W2>f̶2lH,B}a/,^QŴ{FG~NUG- i`mxrv p;_GC¨$vDߨ1,b#%Su4E 4bç﷋GX1cXXP>_]4) 0o_戮. Tmly?6^_;~'[Wrb8F &E0&. 4Cv5W 8 $jaldpgyO9~8UaXAppѹP_CW=:-Wdmرw 6Le>kNes.:o ,čR)a0^S5wc0zS_.~~Zhg ̡aaf :zA'_x9͇3Dť(fRW4JÒi`ȍHS\!e]C Mcٱ MEp)oZfx9?=WSfZ:<ЬEm[,V^[:9_iԁCg 9H&-Y;cf3JP7<_L""׃E !5 T>>9Z Vf'e*5aWF64nTQUuLEFR2"%R“m FSE,I[ >ƞ:@U~ߚp3,$RbiaFhЊ*ܣAjT%8&=HjaSm,fdgf dfhIP)g3kYsEQt#]gQHbIBaϋ"(5ǜ;^V ΅_p*x_к"vG4ǹ)6;㮑9SEB2p~ ח5)є$8 &V'WR~ԗK_8K!1lNȄe}IQ'KJ!%f&'MռwqbY|1*A usإrqqPjXFEf;u`) ̓W"6Qܩ%^c'.,s V/"[>"˫ *4 &K )1*2~4gq..W&skڶ>u.pS[l٬ ^h غJ.<-qE:ru`<5BⅩ܄5r]-IsΩܔ/^&'DeuI&ɹ*rU8UJ,ǒOO\L7,b13 eY?6F y$гhNV v%lnW/ Q`ۓ!b NI3.DPb8O<slS׉휀 Li\h;r=:7#6_w\ S'EAȌj7мC"G 3sSi `p {eG7)ݮQW/v>zܞS96Ӎ2];wH( L=h4/ŜYE*dmR ědAu%UyC'j"˫qT/qhUS';I!ԢRckWX.WKny.gX #6q (h':wdQO8tqX&&8+pEm@ Ʉ/6g$c,q/qqqَ|jk*~hdWRJ}aܠ֢jĠ] NͧÏ9^HL1[JKv"9N)*F|qoBOT%j+G]a޷D{N My;r*b컳;pF{zzq&:cUl]]^Rv8bXP`MAv$1 *OX|,-mfR y%)1n<}rԃ(eOy=Kn=틬ݘ#!⼕8}Bs@*3'*7o>4|~qZ3wHDOr 8+ l&AiDj*J.+([MVd20UJ}DUصMˡ/1*pGPrEGtw]}|33FF:9l.i#ɘϬ BQo\^/ӗsz?ziUT0'^YYNa6rQ( yoɘ bhΆn;zq +g$- GBț|[pi/KYcngu)jXfRk7(XJA\1VJtT1a!tca[V7vQY/R>ֿZiP}."oߠָ}3b$)5-odlZ2@{ȃ<^n!qyU @\<9Oʙ9HȢۇ=9v5D"2dm^<ЛK^gfO- *갥ǔ'ղ1KE9XȺ,58Ust* w#""e0E X-GL J~UhIhRJ3Yk\hQ~8Gd(6#aX!1'. <w)r^?<Oj5U?Մ"zv;zUw ߏbh0 R`0}¿˕By+FC0cw¹!#S/T" LJ&@ <|l VkIK3#_L-o6z,V BH'![^w (",7wg.x$jӰ] C}O']Sa0):Y%mmҺBٰ= .,qPs"vwzrD{ᖖBF F5roQI\."([}my7 j`,ҢE5۱|~a;Rwh;Ա_Yb{K"rpR:<&3~&PVkU 9zlۡLFZ!+@dYXO%lS\"3 g,b2 Q{AN:x* (`:C!@*. k藺l*C}/cu" k{jHD{"ܩ/߫d+ g0t-g6>w"(t,M;d4d"J8c{g\sq^,ȯKSө !@ hU^ !eƷťx W`W_l4[F@k^ʁʑ#cbx[ A= =Wp$gA2-ݱ/jE0ضdYɻu2uR=?L&)^Df*x- 5=Z(v(P"@"^YKޖ硉0Pv$PM&"XfS=?yQZ333Hf?LC^-IX]EQF%\V .Ҳ"qXrTצ]Wƫe?@QY'mSSN7ipSom t,s*/:ļ)㫞|q~\# wc{!8&5 <6!hָ(N;U]^~=t4A*Q` ymrP!ռ' D>Xm#CߺciQCGb(XwP4AxN{ n-J?z/o&t5ZP;%u 'h3G!p) .˱LG(ٙ "UeY!rGd ʕϖN|gVE5'đ6o@tzUn P}7-7"e12qlqnpӺ`Ȫ#퍴?p-1e#VS*Q<RcOp5?z^`h ғw?esٶxfK&+x{{\?`L}(= Ԇ74;zm{~v >Q_bʵG2#nlেå+?iU+ֹ- ,/߯+ղ:+D3rnˢ@-1N.a[C6顾OB[[" @ wlr;obT׮9 zǷ;˱ @xv(]P/ZV=Ugg4"c]>u& Si_ )>3Vِ99fm &..Wsxm1y5>sjRH&xk$/H^.Y{ !/3i3BoeAfR Sܝ}wVy.d,{+X)^{zM qvcEc<8m۱Iɦj%]O1V| D*Bhl ]׏M=O-ۤ+>ҽ9e ~c@Whw89Jk ߿onLg Ǣ3vQ:.اުxE5ۻn-Y)ke壋G+ƓV庪P6!{0z[JXPy x z"MRϮXe1y2TApA\?iFy6]1RMט.[l$U7+μy O%dgؤ>\*47.ҖiӐTl&IMfzLUn 63o_@wF0q-#9L( xx Fo!C}WW[׌D_5IXc"2a,Nѕ,%OێM5! ,<[[ Qk5qb0^Y,{J; k rmdRŅaPʆiaͶHr11j0 z9 X'BO +y4_b&geb #$ ^OcBj~E@OJJ(b_|-vCh.*,<^-69Nd'/7k=\۩UTP r*_Ǭ{?b @M Z9lzX{DXḬ5QEE9 AVQ(ooU_w럄?<%)x;=8G$Ln+`? ֯Asi/2"R;Qޣ #,"r+BGS[̰YhQʱ y(YMO iن1Ǐo_h:O^/鮂}Y- 6#:33]!c :>)^˂ח)"*0M&NL`sXZq  j?rZT<5@/zBjv_wGR qܩ( `VDv|E2)gS",#l:$ج\sc{0(&"?&WDvqY70 ePl,P8xɳ(\\\V`Hxܣ<*!`K;K)Y!7QS ܓ"WcΌK;^~2[wz<q"vʇ4-MVUb1O|m.oŬUz4,%gT5v]-yE m&B%GV|2{JTVJb4/#~Krw+?s06?l4 z5ڹVF0f6{hgE&s6SO&tTYQPpp|LvS/LR֙F } l8E:M/Mi?渼6ZTBU8TjdDJ69ZHU.y f,O2ڒ[P_73@\($ZT xOr b_뱶@\ H'>;E%}QX*ѰZyo]CLWf*xTvZSo~~ige"`t$%0 CdD KN9H]\("eZ"80.&?'K-E]ْg.O- ? 9X2tYs]\\yFZn۾DA*vwOt:o>ݜ/>8XJhK ?y5v`xSM=o|fA9y[yi?ZV/3ov(pJnr_׍|(뚯뻱*'}M7IgeJagm7+yq4~?ɠJϊ5pcsm4N# yТZA7T xJl#ut~&:VS};!HY܈ ԞJm ,%Hl#3{]Q~Oʶ;$"JS婹r6O ﻑt{ 鑊D C MuFfZqn8v-b5GNl +i䨚ض>'~QeT3gd"71d-ە~\pܷMw 8ZTkmׯrwbX뱪EVK3#]mn  ]6OzY0.6]z .F[ d{׵2(UogyW;6zsXoBrc|pť |9z EtWPeY{LkuY5%$B:n+Z1~cB~=eQpdeˌecؿABrQiՂo|޽|)%3)]sU-q'F~5 #B_,"cx*u*.d5NUyz?$Voz) 3M1=, g]ee+brH˚@@ QGUjwys;>-=j+:7/$ xfճ$ IDAT|UΊSFυL8&1xOġlSבxЭEKrMh\]pR,I",Xng@OA%INldso>-u}PdfYUQS)pêMӿ{3|suZ$>8j@!  HcńB=M&*%a)]y,)'/)񣺥Jc*Sdm).P_?OnY.?<Gjm n[ ywbk>V5);M(q,M.>K2F,+ 3f 4~Ox9f0`&JVNK QH`55]} bmy;wq/Z$I!BB^( Oxz8XTԗd\a]z-.W ɷ0ƞ\ `uO\Z+^hQ-nW#?൨j* JBj\][^T<|92㱘ٗǕI[sCLy\~_Wǐil|搿sni]PIj$90A;F`Nz1 j15Yz8KB_MG=_;U}tVFYvvH-1 a' F@lS\o{¬YYDjZТZkeA?# $;Lb"5dYclB!fP D1ϫy#'hQ%'܈qy`N8mm[`/6C}wWZEn𺾫Mɜ@hQQ5Ξ9FE0DdI RA8㳒A8Co5o9p*7s]kJ$=8 nsKksO6*"8x{"#ٮԚ~Tk.zD2_lXu^*R66+FX2]۹l!ZT z^HBV2US0]$ Gh`,(&v=N9z,;UDd\\? -I'HCl(B1")6 ]@wjqԁs*,X@ d"/kf]Zܿ*)E\0~^ۢrAe1WiGo t_mɢo+-IZTo1VY&"~dbTҒ p92Ƒ5``ӌu1#Θ`ՋnuEdM oˎ.8 x&:\ =5u^Jc +R EJ=^Ԛ~\z1O rByzť:,&hUiU[md"G*bkP" N!Ա(&-Qllaž6qAjxWzQKl8kܻ+x ah"S5QK\'gejWtLQ)63yJQXbPfOfV*ic;vc;Wh8ƌٱX֎[}G|O\'>p=7G't?vz7 4_d`4Q~hJdޔ3%2_I KG">*'܈7D6l6.[`KkqE] 2qGyڻ<]A&*zu"tqrL۷;M3 @'J&W*dMو\FMH=Acx}SY<tvi9K /Ü>7nt?R2AjRIJ_W,6RT%)u*Bܬl@o,9Fj,/NGq8cd *qql52 UI.gy [5'prh.J2 x}Z+ʛ3 E g\!L9U |\pODŽgvK&F04S3M1eʟ OMG].xX DK*񥢑Qll♝tlX>KCu$R^f>ZM*c ;Hg2f s+*p<3|H!9dgPC2g:&Miu,;-PZ!&ݴ&V00:5B9ul# t>fG-<ǭ-El5EPC`; UAi\h)<ռr]l%ed)Ic)JdB0E戄:^uXEt'EII)mǦm}u\?C};4_\Nj? aj8@lz$!!g 0X%X(ZɅRI%ـmS"r*ۃ~г~1E5ZW<|2Ԝ />bfsgT eFzfa _=/ʩ p&cX1ș3,P R\k'Q#6"C[VBH<XJmۀ X Xzۥ6!P7x?_7@1*5 @KW};#Jt_' Rl'&l{5z'CwA| wx\y9m{C/VIh5JEFrtXvd*q78M|cDZǺMb9n)EŶ,Z"@$lSgg!J\vm)`WkzVsic=M5Mb@AH(-s83eeIM)o4+ &F ʜNӄ )ԑU !,ѻ|^_+SlALɧu65@VbPj@LdlSжo+& pRc1a0y8)@o־.;Ը+ƹ$u7VY{ӵ Ⲓn(~/oHBpXW q*d:-5iٹiQu^|dxR tBiwDb5.2ZZd2({=\:*uK!q8w/\ NORH8eI'̬ 1^36NkARb\c-E>WrȕaD+S+}UΗz2"Z?GeW\]- G[SJ.(kJέlQ[pz9eqD89<5O -%ςzf~[Wԫqy_gu_oY<p:f¼j%] ]M7F,Gf iN25:gY9k"Z}6J)'N1&%Ȕ]a`~XvWf@ɶ}ԉ%Ymz&ˢE.q^HvkC bA{R%I3YԸF1D"LѬK&j fE`M]Qձvoxڞ[46ZVǀ$vFC{ I8/1_HF[ I9}uSopžɞ)֬L4pdҎl$I ~?ѼmlpX6AK%E15ٱUI g!&B;ۘrk7WrMPJ1 `(g@i,S i۶ gNO'2wFº78Brj\*wk0rޅW[J5AՋ5!޴቞*=#4vwƣw5t(闃/tϘYYu~ˌ2'10)ljlq2A[jF gpkBaHv=s68eIjcd#ǓOPnhN=w3l)׃_kֵ}U"(ع߿xee ߳=-`R[?矻\%6y4y:NӕZ%G?m}DD*H-p.67a흷cHH]ňAi DT$<$جA'R3m4kcq|(GWp  f4NsB$b31M6lKa81 º.e ҜB|*FxE3ӏBglh(&kuz;߯uԸz_Hx_?ͅ1؛>XmAHݮ *^ 9;;Gx}Ѡ(+oW∞&צHfEpSQ+չo]\9v8 R nh]O-)]\ BU$DpBX7ghH}/~ѯ> g9 7uU()͗}a;[<(-[-sO=21@Z( 1`|w/R`L^Ҹxd!7$5b5zu =)?ZM$(mz;lѿ{[>ER pfYm s֘o)2ͦ9hP"s 9/m&H4Υ(TC2~MnpRA.Ni36@4l˲%Vs|j\ %i.)AcMM)("a-"X+kxYkFxqLbmaN_f@ycs95\HDbEEY^D>SmA^u&zzfkgqی#vh͝99#)"YR^p4v`\G%iz|t\\\Ni=s[tz6J8TW.C8!?FUEwmJ?-94,Qj pBJpQ"OYd CY* ;׍+4ضba"_%>RnZ{w]]шRa1c~R}9* \If9g6%&9!E} 'b4aKXR)j\^(svgR{  @A 9%8s,hoj\m-o>e{gĐ(´nr?>yUFj\XhhJ!ؘ9Tl6V[VZꅁ޾3W 7 TWԸJ?^H_ĊՆmnմkokc#(!h,l6c*e7c..UF!n_iҾI 5/aA# ȹX2J+L@NoZ,ƷόLs\ںZUZUe!/B'!&!d3BȟBT[FڦRxؘߟ?8Yv9߯m"p8fh{op9R(qx5AK ^ 8%!!KHQ(^R;*}_#Gs42n4JqY:U 8ϰ'p dRØ豌UCG#3 "dփQ$@l @1mߠ{S8볔yM)TE&c qP-3p?CHˠIjsEry4T S1Tky8Ag@jPJ%B(ճjSiQ`1 > opz.4Wכ= ~K'j#|2g.`j ` &hA'{uVҚBՋ5"Cvg2<#ҬG̲B2Ѩ1JeNȄ3|'$I^kZ-k3?=_J3Ff#G)s&qq. o5N^"'z+.k!wr]e\پ鶎۾13GG}Ox@Vu800;pGу1Ԕ](m mnj}~|N{'-թn8ێJlRdy̛d ͶknqU{.-J:2ۿ#X֐ƕ7,$FSCD 5vw . jaa8N' ϟ~>Sbl/|~U^{_ŬGL\Xskm8{qE ,%EPa8^}2QMÜf(X+rbQkwQLVFk]5G eܒՔ:s@by]#Go!_!40 Hiz2xj8y]71Zh`rJ(Wo!ɋ̡Ys6 g([/duI*)ؐ g$,5rL(GhnkޱS`&NO849 N /@o[TPxo/_c>{PQlH5,ܨ h{dR./+bՋ `Qð=j-xrGFc])40qn4H...5<'rz>)96w\gK\WଗnVW,wT"3F7ŭKӢJ'r|KW !]9kt.D @i13E }_U3߿Bi c1ιK&qBtRj L2p+S:ӯq.'pjSX{.y$ґ36,[ Ȑ?BQS)I)۳_Iq5gǓlG7rueN{K$"N77jG5B}0c#L[s÷]%K}0gK0{:®#©5Qz$9%R\3N GVuSR;[>9r_ 9O'RR?lx^Yce \SS"Qm*yyi8^8mX9OQ|^na538R`BBAh@1'Z =zό&%oP{hiZw3eBMYgd:PK"5;qrM 8'}b G=\Oa ^iX^[xֆ(@;9394 GkGwZ ʛRlm%DB AQ+5ypyjbs;zXFuv3|f̈^޺&U3_< tD7pnxC|h=a^QS"erV2GKz gn\+vK'+o⽘O*O\J.co:TUl6끓߶`0UKŦ^9KQQz8AppF Qz8y416ÀHrri8svЉj s0pYH^L텔ƋqVv/)Sx{ })'33E:A2W)ι;踜%џC-Pi <89Ar0sJK*2glJVϰXP VS-j߀}ٗGuJhXQVrմ8/o@A8"4}rHoNydFB8xN'nxjT5%>7VPd8tp2& yԸo_oݻioL SdD[!چvM[?9VǞWoəWEy猃1Icd!Xd,h.ʶaGd)mR*Q.2Ylw U(ucp6clTWۃsQ8#uc'ELcdRfv@`sxr"LEi 5!џ(鋛i?B6K ,S8AD^o}o_AZ6HI$i|Lbʏb3)@ BP͕6yaIzvʌy8^K&<ft iH@k3 n SFLJ t-97(rgl): U>VPξzqu3GaU7%_Y w;*=Ɣ |JꚕkADՓL݄mb(gh@i$y:@P㪯^~..!evf(P ̿jC/^e`o8?M[IIAk)G9t'էgot8gD.o W>e\JRqj߯$ $k?n)`? {|/gw!$iQ/L#eτDH d_l32}=vM[_ D8- EB|!Ajl ٔ9-LiZUijx3'>3̙dRDv'A6$ɍqj6yAg?圚B:nnyn`<suOI޳2?gYl*6YqzMO5feNeAyXaPpr^y!|Zo̤vgJ)?܄2x36P\"cRo$cYq.wUj3z\:':y7e&C@tFR#MEz9}RИXM4NN`Tb)-Z(2J<1%AQTHzԂ1 g,{%+쑣O #,ԨR[`S6@(AwesoD#Hilaڦ"FHd%0;d4WC%#Ns*p^Wo&;x%=џbo# 'uDE,Y9QSu^$٬N~2WҺ^%9i56JJnj[DBMi(=kˡ3}r0cG>L - JmVhX.G(]V, P =X\2ѲcRn0am,7v6_vp$u䊘{Z>޾=}F9uͭyC~^~b崡MަM&XBb:qGу@i^BEYqnZ zC[W!Q<?;"-POl{S4кfPG(9%QҡG IDATJ(m)Evr1'sme N4E(E(ϡ8/+t^ G< 'WEbE#J8ϑ8ϲ8͋3$|p-+[PGi s JL#i8Brt(<6"ccp %8E [ɣ `(h$#ФY-9"caˆf+Tm$QZ+D"I]&na|(/$Ѳ:ݶJf?!IAi@W0w7Z8JD< ~ `w?1Uaް |t! ~VS148(tG.ksEì~"ȩyvUiܰ93asfofJuj\=}uzÉ ZXepga]ָd{ޱ9X5/P"fsϑgP5UZlV\%2di6ka%l~ >o\qwڻto и{.X=h|9o%x!B+G 8?dq3?4qQ 7YrVV9>VV騮yǦOǢga9dL2+>['vM[ʲ'z*4[}֦8̲͢?9Qfb0hO)ɞQIU,./9U+o)TNc5+A ^WZYOwey^Nr;bpb8gR/}aܯƬp G~bp>44m8 `T݈)P78'[0zhcp1z̓LsꊬIʹFhQZ3:5XlzvxOopV%57Qg3ޜO+rn+=sQËgmM8gv9$7~HVK%^ 9KsN2aL sYb~m<&>ť/h3)EfecU"Թ,.ל'\BN|eps'>;hs>_|kp dN8kCoR)QO-V=g`ll|mmm[ʲ]vBw}nLʚ< @jHRONݷk_2_ex;m{~< xSMU|i+;ZZkL=]{vu[cژ̞=Ra(?t~vd^̲]vQ=]{$"u?2H.ef-;wd^m4LR:eWlNNɚFA߿z=55̑Wv|чLY9PDu} f?kziKkZ 64E{oo]^6==͞O=hu6`C9+7 -6ol1h/ |i=]{‹5֩qUӵYino'ӛu $wHt  :v?0{``0=8Oj]\k"1- "챡0-|]vnnЙtyxԫy&&Cy;ƸqeOy3OowǩL>wɇև䰘%]Unm̞M??\tixwFOEwSC' ͺB$Մ@e򂗧|/^{6j??ޘM :y$-3?|vaeg bHҐuF_;>}pIP ?g߮}Zy.U~y_:"~%[akD3Yk떹en =]{ֆp'!m m `fNR>ǚ/>R #۵Op2<`Pnᇑ13&_B~Uƹ\3ڹ\/w{{_Yb-JswC_BY?xk뭏yg93޺ꭻ>CyK-87xrc׷]p޿bWݺ-=p<=WF\>x2 ƶ7u[mɱJW_x.rYPwsuuٳ?kgsOЩ+ߠޮhhܵkWםձ+ 8}x`dmu{R 7BнD% [7g2 ٫V]k}WTe(h7#93T5[[]Zqfu;dZ@o_u*R"+J17 / | A1&żz( >=[y?R}ٔ@JEh>;nrͷ94j~2-{eܽ;tUUޤ( UU5{I" tcpc[7sߕ+W>2-xٍ-77hSx*vR yJ@ݱ~ѿhkˡlS Y0nhk?xBRrp(vݹ\,Ά\<C.!gOL"Fz |HyXGTM,n!mQ"4dQ=o|6&Դu Д_^9T ɡ|%kkV LPrFNi&,(Xy9VG"77/.“OF]-Rao$JD(FD?d*pBjg <}U9o V%5!7W*íW~ JOY86m!/9$͡ q@8!n͂3Vrq@lWWgνu/f=&y>Ag.?U~ AiDCIѠr+x$|f3ӈ:a9 YZ7,@0ys @)D+ R ۥ.?Bލɯ:.+8{ZX 3=w exrιބ#t>k4bs;eԹY)"Ero:x vAHlkM W}[uT9튣b1 XbKÖSJ! 2R >qq\NޱN$"UBJ%,K qI\vz Evl";nqXp$Pͪ%Ѣ EQԒIcev}]I .3gܹs=SuHd̾FWo"R,C5Y59Ɵ## U֮ 7 GxMTEYp -+~3S6-لϬ &Zo?pLC qMk4HP NNg% C`m{_r! (8Ѭ% S YF>-r: 9s9g@`GW6Ӡg]ޔJQe=[Q I}R%Jy`x]?>CO =u /[ؑ6?؋z73"voܶ偾Qu($vD;Sr!9k{= HyfJrm XSV'r?&E8:dߣ'sɟɯzOﳩϴ}nT˻=D8j<|0ȁ w[S#klKn+[G&>'\~/{qsf!l_lw<]p2>|AxbOTxz|@uȓ 7hG #/ B7](3<9[|7 Ő';&{Ū['|?LR؁-7> i;;xwʲ_ vc :Dչa@&afw'3*a7sZ7oonڥ)$9FʉIe"xykfBW|_zz LO7{{l_ 呭omvo`˧z {i<^nZ?xi%~Ym_Y{,&OP㳾b9^/~@Tq-=k,%d hGUTj ly|05xrƺ*q?F1W^ FS,qʵq~3yg=*<h +h?r'vbgP戕Ja<-vsT{3Ah?e䎉yqԂ?J$ᙡg:W_E6]OT´]@t.4[Q g13kH*Bz,"jѕ "N)$05QJ3 /ib4xKd EwM.zQ蓏Q w:59vyXGӽ&{Ă)YVgd8UCL0{,ʲr>Mpxat~բ.iύ'rٜzC_^[`/5$ƭjڱ^^A$j%Rv׼_CgSu/Sef>Ae#z_SiU!@z&a,DeYHOyk#[.L)`4FA|uv*jeB,et6 @k`ksR@܅h[(QNgS3g)Yw qyP% I (CD=2`W1my+00kFPX5 JюfOُJ%퓍h=%NrT%gD6BҋjNP&Esձ]8Æ\ˇ~T+oזOOsF2TUb#w]!c ȹA)u$61X+ %[)0biK/u99n~-c> .X Ʃ4 KL5H̡~@k@y9/s@_@a\:QGGkչ SA1̮2D$&l~9:|B\Ӊ%DBhKVPuinSaF¨ZڬjȪ EUUO(=Jrji0kT$h LIfu"[Q6z@pg7'/A CQb @1Q|R/Z#bKvNe]\;J{A7Kin4w65_{Z<È,fgDb5#AaK(QQqu? i,A[zX%J(`5yT* < j(209!@ jxMЍK*F 襔ys<ߕIS 35agm9x0zp?/Bؖ^X L5eUUX\y$LhGJhրZQ7sFcuU$ D ۼIJNُw.ʲ d? NJ&pa{{'™(P<7ni{~cgD}ܵsL,m&qS鮰/8l8phx,(?!$|/Xɫ@<l~;e"to5.Z)c$<1J1Aw~/ Lнg^ j5N)=ZyVrΙ2q0BTAUs@4E+`DKV}Vr=v?ryfX$7ilMQ)Q6eC(/#eL\fB,k?1ɨy[U퓥UfPDg5@a`,Q6e!|!i+U5RTtfJ?+T#fI 2F"yoo:xG.V={ܼ}l? OO|*%4N>}^Nbdףbbѿl"1Vf(s/rḨQ %J-ٱiRNU;dpiLhȋ7$Bxث?:vx 3Ҏ4fbvl@q8 fX@0@W IDAT;׾}8xlUxgK߮CC7Tl210 n}nk$3vk)srşFΈ#h{I&kط>۳(};{OXix=USY\F{#|O.XyֈssZR~2r/d=b&WNBrZ`0rF@= :2J1*Z"kg16YbĠߧEbG~}ŢlשljJS;AǬk]TCF屗?vm"Β#HEԹyRdBzЍI:B`=AapP8]VRS)TATByEK 8Y\5ՠK)X=V^(K[Dd|2WpũvA $:.qԽFƽ9!q }n$+@7tĠ/<-F& k Gk4v $E&Ėdy`<]mQE/^12lܖ3$4D4kCfȟSe%8fge +2BwAC5 BH.Q VePt2s"Rmy9/f@kiC})ۋ6G玞M(GɈ<w=*+ Iϱךx/_yӡNt{Yª TVȋr|ȔVMO)-wOAh \.ȉrt'I!X:EN)c_W){qq46JiOBK^KO M[ 줥7iaO\ޛ `M /Y*A˗iKSgH"ʵ+\S=!"w39,1KlUoL2uJ0Y0Ԯi$P(cf2i͐7VWvfBS8Q*X&/tZ?"\;7Tw2ehT A7:2zi]x=U.VEte7O&b nE!I0d%0S;Y΅:>OD nw#ԯ=wސڑ!5v|aS]<4dY:Q0' 3ħ0Gaxs!M2ZXHQ+4 :su?SE-[%J5KS*;U-qs Xe`˖ьJh(°b1Gd^žM_gKA8fi Ƥ= r}TaG,<&MSڨظ h !F%" @nycX85wF7u[E:AX Xe#vJM,C2b" %߷,{?nc}o7؂# vob˽'mu6C_6S>웁}JhBT%;Mü4EB3'YbYb6WI1F57;nD%J:oH&| j\q7=]v2L=NXӏ vB?¹N7Hc՘VB9/̑^%s˾(0,`0&8ӥᎅ PQ}.`xq/By^!lapNZl1?0? U rpXM4Au 74pũl ?eߙ=:I(AtՑ* TIaCZN| ~8_ÿXa=[%Ul%H(DJjQkeIVbZ4u3Č{^K _Jk f7o1a6O\=t9'-V&MHqfuDX i ;(#ǔ#MWc J۲iq) 67%$ $||pWxLpy5y/w\r f^'*QcjU\HD`p%`XLHFmpYu,ztlEBh^|orI%{7T0nEHD%6$B8X^@7&/}ûAϗ*p\.Zӏ?u3}vQO^NYO)}mGVS 7n6*W[H7LmJ cWXf_b}z3sY<|s[V_V['&B &ٳrپsw5rÅ޳Wozv`lQom,6qLC21!Lŧm0;^&x+{ g&f[6VDd$5( ax[Vq<9e*KLuWƒo@f>tq0n ##F656A߿ʵB+#Lv;y+N^VT}JZ59 %!$xuk*UU]Zb裸oiЮTey-]m\sMS<?x݋ I3oڞOs=BQ~3}F2P{m:થW> xdž}^ᛯjuu-NE]\}%k>W>X[ƫ]Fcu>xo}C?.¹s˞,w?#wژ" YlҸk]z߬?ۋ ;ϸM%\V,GƤJLWԾk^yՊ\yK6|J螰7vam۴MgESxbZmC?t֟kL,$9]pֻ7v>*ee/g+ݴt_Ԧ\ivc_rZuf_smDjMm_Yݓ{&s]]v˓knU{ЈQCeg]r?6ZmuBGF?oZ/{Wkt V5VDiЅ556{B+j yeg;Z51xO>34" `C5=m68>ܧ1=͗;3o+JleǢ+ 4[Q)HC2!"MS6`5rJRJCz^J^J].i@nL#!d4ῧm_E ~ENpb>Sbk*mpgП85nBr iR4>m0AoȪ̰)dThj4n ESc>BbQKBJUy",ep%V wDHg$S0Ę'lx?Z)qM)M/ml2iR%AfjtbTMԳnޕEqyh ȨeY)2HtԘ$(xY8hN)Csk-*ccfY"R15gQ?-b!֋bКbYJ)EMU/)4Ùe)9/$M!åB&2|iC4UK:'%$*Xzƒ(QDPp#pw\D)R:+"8,ιӍ6턐S|Ўqrݱv&?n^/MlϧB #gT|f̜9hktpXY`t#WOe\NIAjTCb}*oJ% iRn@˨^dxM^oҪKBP&`: ր.3a2i$ *+-ZJJRܮE3+'8E!#ِcgnVRhFH0kg+wW0U&) +oQՆr=S)2™rLgjDŽ8Ӥ-j -Yp,"ƌA9>/vۢR}AEuPj"i5SFbs2fqa܉*TUˆpR(0&c'TcP'08dk;,ܘFaBW2P=˪ YUM`bЧ0,dNpqλ=© IDAT3&Fn᚛'*^ e `3d;lIcSubFhly -b'$`Y7l}_7xB͕l "<}Gx?^ճA_\$QBeQhc8U$pu$ , ,Q-lE59kl̎ ͒)㞢EL9AP-K5ob (3Uz]UUq3gTlU}:g%J8>ZJ 8lj}RJ~uZ =cE|Ri |@{r% !5컇R|BȹsXOP!K-k< Ji{Z4BƧ6nXK/ _z[߱y)rFJIy/N`o|cȶGSA/HoMCOg+ y]PyWc>}4ޒz_v[Bml0U^ZtQE_p8vw}etz%ߞ̷s-_?۾ڶS_۵u]Q$ cr(ڰ3$U};7sEG2G_lw=ڵt/dʕyVoh`pp$1>vLa]h k==Dy=ø ,r T޻VmO2?4K8Wi*9TXb|>m@5 Ϸ~v?wV{ {;I5^Z}iY>yEwMͬZj6 >MR[aXLMS[>8>H&Pw_R^ɺL(rRqj ]^353}g{`!#πYywx*t^~yd23h0԰gF\уB$t&~z{|_I)Õ{69i9pg$k[+\jN|J1' K[ddM̈́Ϳm|ss[oۿ;x?v9)%+f–;ϾW/2[㺱fϔclRGɾW#C_ l>Isܶe4%L%;oT\޾6c;gMp$&G^u]'2Ŗ3xl9Z-NUnBby _y\&kURx֡޽JnyYQٿ)Jb966EIWDM6E_~i飔* ɄnPIaBS.‘ R1 |^^r}<ZJ'Xq,C2v>uQEXu^3 Yd;qʖ^TyFJ),%ѿnO } S7p~ wqM8bo1\T\o ]0+]jjt5KP0i%}=44*4V7ޘرb-lGSD?ιUP+N˯کycfb Y^v6/oܸQ jc-Co1:-zTɅ*[=/L:{]b;LROQ%~gWRɠ=ѝH0m$~3'#Qыlߧ<۝M,#h&OiwM4%x62%I5YW35Fy4vċOrhh e3(XXSU;5VE-;Ms,Ozcq9f2}q+jAZ q_TyMGzAUdGu=lMΆH@#Yi\I@5ȃWRj ܟsu@5 eQ nM#Ta9c/F:ykx6^_ ?,U՗t nVK kR]C0[xu?U:3::]o pdq Nj^rhsl6;O}`as0kRaن \zUMcx0$&b&{܉F@bτG'A___hzv65+Z.X2k(;վ~% IShB ! 3"<R$\ +}]ࣘRKB }@70a/&#r9!7hnPVɇ{~zz~Y%CB B7'2c{7?Ȇ<p2Z1th85,yo/^Znv?`0H43N()e_p QLIXƣұ*]o SyM_"pڢ>GU9ޗJs{!`X VI.0,W1ʠv(3hIRW,V><ĢEQJrT2"(QDSh9GzQ|sPJnѝV QqB)}~dD.1_U!ONjY9ݐ)b2 콉@/`3 }U($bb?d'ݝ(DbPX#8Ex4.& TBQai,R6[A9iD&l#C14DL|_B;PḙYuby_:/=E5 d%6$UD4ͪ3<,Ei^ʩ_7t\ymv;o3:VfsƔS&Ao[ OT#*&6E@!* ާt?+8@aaNhN  ܙQ L4Qz0d44nMMTK ܓ;Rgi8bJBC?Jf7g7-#}1^w`XRF8!;)E=wIG a+bBI T~ aQ>ar|')Լ}3Uw4D*+X\Ƥ$x&*)rڬÄy0q890%?Jpno& s9o]eqOvջG^ޣB\99{yg_]ʸfE_\I䲞DZn桭jnMfЍɹ@hsKX2x` e"6RCC|ynQzVB70${]弰%6ROܰƒ.0S薣͑_(tC" ˚҄15 ?`%7)}^)0j EU&HO,@`x30 !.{E*h;W@N/t:9O|?@k 1}17< 6ECsST˽+[5-;МIЄgARƢjh_Ph(+ QψBw6][Ʀ9jΠlhsҸD%JI\v YZpho+r)^(a蹈J 0}2InRQ~Ye_teh͏<22/d U,BTy sS1 ;fQO,v]ZEykjν6zMG#3!0Nְe^7=z(2|}%7QRc?{o_U{̓FBJk` |pk1-/d"ω"WPak|9&+k,.>6T)_+|pӝL-}ٖB Ge{ `;ݧ8t~UΩ\uͺLBƂMV>p% ~F5@zV$Bu@IS!ڥR/"#pN ½86e,S>IP"rm_E~6|nA'R?^cvf?E4߃>oH?N̋r,(c=7_:W[*j"">8&*$gݞ>zC"56@9 g,Ok tM9ha=st};{ oUwa_jDD^L[W! }Uz GJs]#[wQ]@n#=& &/gAE )ޖSJuU})@ a8Ql7KE{"DQ7o~Ts_E}N]Dv9/" R %Dy9D ;g_5qGNR"C( L(<2pƈ{|1h:uV ߞN{@jfxmoP.kl@<η}LIςME9m׶~ټh9쵕ql͛6.U7 ]m2/+_}x)oxWOӡ&r;!piẺ);?%*Tl$K 2HsE'D`DtJRYC},KX5l>+j-!+V5ddJDD ZvΘ0c:fь .N:'2-P7w) jBH&(8}!*s,cM{-ԩs0ֽ]S|P^;gE& IDAT ۮᄇʇ9w?2,\ORV)½ z'}߹Bd=mk&nJ} 9A0Q;BCmzFD$<<J2 m;n?v/ *6#Fvk6>ꯊD[;7@S/1UVm0z%0c@j%,MhMkx5'ЁUj LP iS^__݁+z1Q(3S,7tl,gJ9  E➕@LFD-C})h21]":vw{0s_ [[@3\. ^ynT _/ Ňni oVrVr4?- *:wڶ~ v0!0w -y kHg57-Cߗ{[IDZհY{*g r襁է`O[|7z9$ ~ Sܿ?;mCOv{C^{{vf4FH_ku%j{cWKcz6QRdE?φNp[)׊ܱ@lRɍT4wd!э HoKT`vDj qHSFj| =pldq҆+6N(ͭ3 '|)NX.]@/SyNȨR/1V볰Ozc|ǯGYZpYrbOv5!K8h}Ƥ-bŊ %?dK\/'4 9N۔(0NF8,[$1$1d>Dzd 8|6Oi[-/Pih+bF)ԗh6GqBƋTD_3ܟ]m+n{p@U$78+ysG?Myg`b.5w1S r1_xQ*apHM fs1_猠9A?\"q>Mi(`<(ds"ri9 ICQX2dwܰ˧25ޡA}6?sGgbiR;N8 ؙyiiT"mqnXC9va~uEg&gWV,y=tgKͿ%+VUs;`2Č/+x_fvC%ĸ$wid}שs.;+YB9\G>W5!$Ý ZH#jWHn>IYn٭spUWı Lȶ{{wW+<|I״^rZP -t{h@d|=+e4=qAm gY)ZorhP[\yJYCfZQm]n_y1gu\hSp{?ȢrfENN/ւgYsaY.֒}(o鼥Qꧦ)(Ej~bױy3)$-?mȃ~GOKx&|ۻw9DJ%ۻQ9L,,#Cɗ^ˎV: ˸m#wRԕ_>tLif@q{ǞׇY"k{~ֶCyUiffY !TQk5:2Sũ%VRhۻ]uw%ʟq۞{6z 3LG&KcsDt,ocFwo9|+>m=xbP!<j,MgY[24M"ͶKX `/` y4w:/I}}Ă%TsfwovQue|yQdEҁ=Cfa\Kۘ33k4c?ӭ\λX0BKז[(=H(ʛA d>*[သrL=l4T} m{N<( llD1쨝x$4ia `x^{!T#{zA`ӂ2G~?%H%VSBeu('֟g~L.LgNN*pB'݁* c{hW+34˛.ۤi`,}nqﹲaW腢67[fMpMEDmJޗkUoﬖgZ&ohc77m1 'J*r;.ޯoF9Mõ-~`Qm_w\ycRoد6! gS`k톋O[*Ԯ:=*?mwjkk[$A.Jǚ}U "N1/6nYsӻW]ybyl A0Z?rl䩊Ț.z,f0y )" ~ؙy*i:hn D:6 T1DA`w7n|]n5ez٫+.$$Ƕtro,aŵ7dMW9΅ -~2 F͝[^V/{uY[[c"!0@RLt^F ZQթ%6<7RpnE*WWۈslfEkq>3]>Ѩ\gDY9 cBe5&":4M˾.XBlv޼e*d&z>=/z^#zji!ؒYݿ?cY@HRVc\X293R`.Ϭ؛f6gcq5n]Xs,H+UPVʦ}Ț515+UdA*U &[JR,pdPq2jhyBFq_L*b^Gؿ_=S)13&i 7T[ՋrL8bOR"Tp8GbL؎DȂIk:X4'ԐI(RWaRU"(zK'ĺ,{lRE1a)T|jL$~[yQuxDOUL~vYr,2Rp#Hdɢ UTpbAg˜w7Q9,|aH_bH5MI} m&7fQ)+<LfGI~ ӵ_:gxQ6~m;.mW6(^ɋp)RkF L ##rfnu[ waMҿؠ6Sc:\V#JDx"x{uwqKE5'iKWz [.~_EV_srЈRbn~VOڠtYw[ jJϟlvyB@A)Û_pc-)-e<17jld&|t'\&# 8T.Y; [ ѼEL/͔f<`877***%cgOW0' BmK7 !Z\dr؛޻36k~WU)9%#`-Kg8fJk0Ms/-b^eJlF[ȵ5h1zU3m%7"((z2d%#ZeAYФKk[۟:.D%f:& qm"y@ܡn('A0jn|8> '{w."pSg`ҍccxϒEC~ooq\a^uϮL|Qr"J j@A54;/T|DkUjg4Q[EvU!^tP98v+e 6gY 0VtDŽ.e/OHq驧cuY!T+3AAP8: p&uV@y3pL _fI 1ƫm﫚auV 8\/\uU?8P+;s=ȵ-׾9i$Ɏ<+>52=wmޟZKI ❑pEcY D`rm§N>`d{v-moQ8*U }xrhifOu#Ͼ,L4l^2g>Я#8~sy~l~dGO?|Z;TV΁芎J[; Z# ȁxlMmۗ690/UMZӇ9tL({ֽ-E^3yVd3/M7o3Zѧɶ>wkZ-WM[7 M]/|k=}8[KYWe61޽=xs͋#yfvGu$'kZwp񬕖&}xQyR<m".ʎw_Y+{nbR%ƶ =iZTQˎdUFClO^L[QOLy枙u>suIOHji+D)ƳM}_+uF8?k Ȇ]s)uxC.盷lf& vH-.F|yկ scP[D G_C 뗽V)jA/ՑI 98ڑa_Ejo[r$O߷(~ޡA~߱?9z*]38O|S]c gO.pBY·\zy'~?nB[xf9te4&}>W.%S}/)m?!W˗V;۲n*|jW{׷r_J, m(pK@!1lw&J5XzY7=3Mo8xǠ0L 43 E2Sdyjy.+ l{#\-%}i̬HbWx ݃$^uNQBs!&S2gP%JOWS)VEP3m)(W~X'y!їh9G' 2I~hYCo?״YQϥ>o @E&KqٽZ7E$P9%|(GIp07@vbG4Ss}z$Ļ81I"it2Ŭ9òߠt btq1;~ "HA%CXaףB~jm%EYF3$D 2nE,I6Kg}pE>6_hcio9= ra.T]S8(yv/[ۨsX{e_`e[-N,"yJb94O"0 P3=op?N-ޏwhN%W8|G5<>_ؙD_BN㍅B[&%KA6aœ98&gg?8bu꼑47&([cRh%BKs$$AABᦾ թH%\dBðɊ|L#9-UM[j!"{N8-[T$K NjZ7de@=42KH%nL2!'֞EeldA/_\F &}"EY,;#-𒢬/ЈA6/ "B\,pB`;4!{ڔ"rn?*P];}?Ü_3/  ĿL Vb]XyT7B~p(>A&($r.~s2jr&#N01 S"#ŴY↾6E5GxD9/x:T  WDfp }e[b P8 !@pC1ӭdzbAyXӴ QfWs>sqIo;U,gDQWe) lj2#`>{X_ |Ms4 BL! L`(A :?W'Q1oL?gS!U (Rʋsa%pjD1b^[$aL=3&; e=SsXD^W(? IDAT>~ewM曻6d320[;m!w{didDNLQN;,? k_}txYD_By)WtE/Q>D_8dѲ;dH91F 8J<&NOl/{̧ { ;p+DFVQzq3JdDq4a,S[;.*ڨ(Em D8KEC u}^mxO."~mDӫ\ ^F"(\7KXuMNhE .ARȑ0EdaFrE3EYp+w7M/xݲ''!+LJԫGb@ISNp-Mwh0K.W;޿w.|GC1; ^nsguǛ{d~yI VI͑9L9)& )E.J%p.7.I;!Vk̆ P*ӾJ2JDuOA}2,b:u,~!:ru9s9 !8&"W~ !D !~ 8^D7zN7״\ŴLeY5}ፂI)Ks$[οDE ύfKܭo}=says!7m F/df)Y/xOڑȧԋ`CBu[cs Mݩ#]_K^!^cicdc;WUAELAkR34x7Y=wW)R2/]_V;P|C#~ڦ ##/:O !O^tح[@w~_kC%l{ma(.#d D2bgIC@4w aR]`(&mIb<^1Dp5O.pEE ##{H}L;ۀs0,ɻ 5Q&+V5cgҍܛqLI2} UL`rWfI6v9B2^;᷼§֩Sg1PbE$`o$jJH.n%pqB9?BZk-XnrRNc=-PfKsB!"y}ބ;WK%kY(Ȁ#,:$'r:9=H$'y0^8OYҵŒ>/ѵI*v0)^Čb.x˴Ky?a,'盝ΑID_B *x2A[N%%G/CJDV$ 9J}EBrxSX!Sˀ@=;̎{-zrE䅚M̿nIU?9,, NVKL 8_;@ψLf;icP2Q`].1}ŲrSK$37,-*\$\Ɔl#` Rj$ym:m|錏?A 42UpB O-#ڴ<19@W͢V-Jlj ;hi \IcWr p-WL{GCPP8 -z.l= b21A*=҈1FFC0`g鹽mQdgbԌGlӒiwىơ9lP*68P7+)lOЗ 3qoP.X;Y=3on?=O`gf%V!sǜ=2e`a$lr^'Y/'S)?YQdqQo_3v&ڇc򼐛b 7E3f!^ca˱i'RtN[QN@Z^_:KL ɜ9B|m !|rΗ$!$`'<4[ཛྷsuYvʓcS|#2(A+Ԝ+kd@e ŔB缆I ,J4rf|TWKHXԼ5 C|>_y\_,Ra@#XGީyQ8<.#X?[ @r 0I‘(Xz+Wl L'n} 5@j uS`Ϥ3_;kbyB+Ģ)gcC2&[Х\jAF9n+EDoTpxE$&%![D 3+9qBAE5Y$qwql'徎=y);?%'NP;kjvC:svS{ؙ:vuQ٥|]OZkJeLLd: ?LE":mVĘLXvTì[)׊p)mܣ 2YGF}^N:+ 9={Br !tBHۄ_xDdcBB[>9l[N‚;_7 &>wXı|uuŜF&~6I8%T|d88I(Mds<ʼ(Uy)@aP%hH1:oX} )j;[ S8g>0_9Nǘ#8I6bcE:u%v5瑼O-\L&T('<7>!p>\curcnթSgqPdb@o67g##6\h_F"z6_k lJé7(; V. { ˽I# 1KbpސWmiHW8=h`MܟGӥ}ުӧNU}$:/dbLH3yt,jnO>y$y` a!Σ`2gf g&ˮӍ>CDn\T3RP=6thtMxaAbRy$d$"z"P*UQġT& ):|5ǶqZl'Zp7\IgjƉ XE}IQ]YU4攲"lAw-cȸF<~?xYOOqMTx.2 _vOC OC װ8{6vۏ$^Ɋ@ZGqp\J0$CUso?20O:>5X=wNX[/׉rED3WdٍI'$o֍eOUrp8=yp Ί̭նg V9r/ńwgN"o_= =s)N<ۗ=ߟG4hrīڮj9s;N> cdnmO`V3x$̹O[ nxwTj-]2!p N}'8ZE؎ ҃v;:nv\)'f?P0ޢgzcoxT ņvu| \CF]dc_e]~# `Elп£)ql׼dS}s ϝ,` KT76_Sl@LL=pa##~iaKAQu{r>;qf0[3n)s醁JWEĵU‹z$4D߄m#INMm:9ͦ$.̎RyV.%YxuJkg..`P"8ûrcr11=.]Q^f٠/scK:,{|ڶr2xh߻hN `I Ƽ "EѢl"0(OpL.:4=:kO팁V,a7(]vCؘ*zB(9N?1:8t5o=,@(x''ƛ jVք:soРi뜺OL[5< XRv&a,?Mؙu`} ='} 4X}$X0 _=Z: i5x~ M%"IhOƾPŁ 'k_NM(cxUժy^&98he`(lj; uWp̚Zy,gl1kt̿2I_|jM\^ v]?&b2{tu1$[֌1m]%,"rLdl3Fa519>Ι)Uvh.1,\LF5RLs1aҕ+qx,y8Ⱥ9[;gpڑ|.k G| ?MǶ=v.9fK@nPrq8jN)'&S#)}BT@|]Ȑ9x7@Xo]>vWeQqܶ'qW6J.%eoTBt?8y@9f6U.Ԙ&\cHa:!d:cg̐!j@ Z}Uu ljg6{7/.>W/ v_ΞHSgq0`նwb̩9a.iV@"tpvzzL/Ug9U:ǰ -znk 0v6h`u؄@|i4gCL^O![|u[g>Seg|s7fg'9:KjL͵}&h C⇷Oϩ oT#In1m Bm#3^5@>X]6յII]",D$Qv0IQf8%2VV(xvtBgo7㮐-!tEx@,6fqm *@ِO~)Bz8]^%[Tǭ@6v̂Knn[I_="'hExB x"h|!5jpζz9xB8,Tl*?R$ǎKuݷք䶒}]!$*,ĠpE2Ɵ= T;L C&- p'Ëk.WXo &\r'#2$$ TbF]Xslt#s˟[ ;R#vvّW'8$GxEҠmHx ϲ0 EMZ26 %xwx8*7C x7-.~Ͻ_zܓN۹X쉼WSRY].,_qYpn^`;}EP¹(DOug[w04XHnZ:,I}v:M*(U;9NHLlBNJLo`'K /PHp<,Kfc@Gt-Nz.prop gc9옥 W\9_CDnРX|煯‹fR *hmѺx]Dx Ex"r"^FRa-%[mBAln|`uKoњ`vr3qQn M-'NYRkmP[2P($fRƳmS^t z/I q]GWp괈rG:kjAxiSQp)p0 8Лu=#Na"j4Ii.iz" s&N战XqRe-vO\5^v0( <%UW@ĥrITo#jxE p3<ϣ "4BjKk*zÝȱv27لx+ ry! XϹHJe t3Jq:xYp.QZ; IDATT,渎$:D p,LNE45p냥P%?} )e%`-A $T4in^;ј?6hPkEJ)@|n"9kzIz xFBL\"> 揯;ZN BX/k "%H vC@kؠA 5J̈~EJ@AyVU"i/uG9B|nzWϋl[SX Ͼ`qWJcnH i߇.ɿ|/EK"0̖~@"#{{:ۏ aU-W D|~|ũK^r T*xWlniJCC_*fKӱ@sdx>f9Ͽ74 .tFo27Ԕ' c:1I٦M+'yS#)]w{wrVnyQEEoXp%(\$7Wr&~;lШ1:84'nxiK;Ɵ֫^ؿGxD%Դ{4ayK"(~$[ҳjq>5LtOټ֫&0v0PpAs-k}.nP:[l&`2/[( '1PS46:+wK_y{zˮc--."L8:?8_k}As9Un VB}G oX Ne/_v֍oH+oj{-xxow4׃ͯ?0Q Ƌ_̏XX[߱i#JdȗDž.3R--y՟ 5mTr/kYUEv/㶞 =]8߲[{  njtS GMfG^yefw[=[&cm>]N<{HJj˲[UƩ܋Up<~%}{ oꁗxw(raO;KvV6؛?zEo{6PFx);.U}~h͢1/)won~flI@{L^T"Ed)K=pHiِSH9p(Z|BKkCԡ\ ;Dznk[|"T~`mE>THm6oRca$T}?AFQ=gQ'B}[ll=Tڿ紑3η%uZ}ɾsȾŲ5műwzA0pԙ @ֳcLg00}֨eFy9yiCx.c 'R(uEM2yzC`z(;C+ZsmD/s^ ܰF\)U{t_il ɡJ?HsITl̾PL_qTe*%/FR{h:gNU Bs(F9w伏"XlzU) Aje!ҋ.SfE<5#EIVs3̋݉f 6Ӟ#}\kρYګ<8rDxOl5q7G3MkF@X)ʱ9hrYt }! /5mp 4Z@1. $N|t{zv9_k (:S -E)DVŐJ)D*.64|]8R/ZVr1[f*CPP9}6\H;lM͍"C+}YR́"($98G"s$/1YZ.PFtQ@@I9 E";4-j E΂~pgܵ8&%ry2ya Ms% OjmwJdH0:- S0`YAjQ(S!)9x\^Q;1*JwA?S2lFRWЭFj5%='&U%Om rBaS;_h2o!RWl\fRV̮?c w WnuY*~F:v' kgB3wug?M8Me]S).D7hjq :w#AUb Y1\X"]79Z\L(:+\mrV} ͯI/Zɖk@)g31҉[7 <"sa69t@SͦJ0[h6uʺHn`pWC1[R#)mDo✓[)T-=ήJR#NWNh##0j\tyhCs 9T pW3/JAA% [Y:qO d"JTDLP-$]˩M8gEEon?}6aly BHv"n V\peWhsKTsVe?X`f5\ ".HE^u 5C0@d\K]FĈaS(a1d̖2PRLq;l9b;>FpiFUB8lI*$ZU*clzn4YECRzöMTyq"9MPVbME'Zf,(h5Jrs;Xwi9s D`K6`6 'b%DF*ϱՠEt h>,A@a ;fC.ǏCOaO6"iZk:~]й K'?8z֭= Ax@W qf8S(1BRHxѥABcA`Z/V*#&S,J躛7h42љwڎg qoVw]ץ?.k^=#4h2B_裏>|Tv7vl޹1$ڞ<#61 HnXx`wUWS GKGw)gQtbNef{ۻozROXÅ]E vauE٦;^dbBlP*&ɯ_;!T~N[_?ܩg-ShRwЧ7pnrdp,[{~'ܿνz˕/oۯ$}Dzݦ@`Ѐ#C#1TVyuw򹉾#kmeWjwKc>|9(YEKR4O$' ?*p?Ʀ؅ۇ󓹟:p'r8w8oŻva)H^x|H l޹Imjyrɒn~jܨ+XU_,NMnPM7}?cI.@[_=eVU$&+}nfRu'WL?>U:{۳f'g&lu.OM37KH/-L^so$`UXpK줲g4Ğ[˕/?zKU[`~ßlbUό+mm*hj3Uuwh=r˞=l>pSWN!$J'l4dNtndm~S\}}=O=|Mv#;i$t *AS c"*A_XNpu}M_e鉧6ӡ-OojW"Dt;f/>vW]ʭ=ʛ-[/a8N^G?~qcku{ϥL4ⱇ7y]][?RͽAnU֋7* E0b΁s" N&}r>RK猲.;`#ηljjuծh.쫧vN;wjRZ~VjX&20}>cڱ)/_VQ(e_{[~o|xT) ~=/znc=v ?Ks&Y Brk/z$5 h}m-kfQu؟@.<$qtu-m~I @;0m] ʼnpSJZ^P,J Z^FR>;\Y>r_rH'Z15{I1H8n?Ћty^iF}IA%Қx9xԏt VsS4aSdz8[kφ؝ eC󊞍|VAf ?f:zsUOgͿH5Wm/}܉1Y:Pz^"ٵkt^Ѵ󖛚v\@?zf\)Iz"c+W;s@Ha̿Ѳ$΍֡b7}" 0\ 'Edh>D̊G O_xƿЗUh ⯈h'˄QPae pz+[p^gV3+4dX2QHyC-x^J.[eCʹ8|~v{Tp[Lspґ;?a.0$F jS^KS#)).0q ۔#Dc=Ok5̬!~қ@E?d]@*F)R/NsOtpDV9HJlsm_R䴿cWa"PSu3}84݃n, zjZbms~\%I?Sl(1fӊM@PLԳvtpGvұ H'?pz24M*L%ϪJžcdZ]Ru-'\U۶ D Ixwp8Yi[핸ȶP-=zz쬭%E}4_1 }}.70v O>~狾R}!EJ YEIC+zި7h7jРAsĄ]I##ar̨'^R#u-'L)3BA[!QHl_ʚ_?8喛 +iveb`bܙ =pw:4=~'Y$t) Ke&$(FRzxĈԞrU%͓N(ͦ@9ψbSz$/5Jhϸu-7aåmznL/]oY>JuPTuM޶ [hZpod݋tuRlF2dU ƘRh+`s'/[S]?זCdXTq!)R+ IDATzuX1u m~GtBYϞ +ZŭZ*`B6`ő&{All8s%09  3|7X龦9/LȢ2cF)f\q1NlDž-A7\7:8Dg~E>f*$~GޜN_@vRg3Ğ&Z8 pJEK`yq:7DjfKv2 xc,.yd/&{֋` o7scڱ1Ƹ_ۓI&.YxsE9} Y;Pt2@MU8'tJR#)=F_`Ў*HKED%"N3JUvl0֑֣C#[%Ӆ.*Ik6kiҞ#0Ϋ mr):$[Csʈ"p(576FR (Q R`&Ms C$[ o<¦48G>.!Ԗ"rSp84q%RÄJL2 o`c 9o!\?ܕN+he7#~{G;=>!8 T7\G ӧlTg f]:-PhcX[/׃g8Қe];ye$Ab֯(prfׅr ~ }kj \xLxBo_PN֔-/3d294ss_BJSKPh+&Kp* h׫!ig0e M^Ui$B H$( BN* 1OH(FkXM" cL@ 8@91Lm[I¨ `LQ(w]x xa= .X&ܢ DM,P{fV7T% P`긅u YI-贮@_Ŕ9m*Mo) ˶|:aEW 18h;VڵעB"r'(FUNaU*8RIK:).%>Kx"!Ƹ|P5o;S06dGR=2 4l#aZط㤙p0K&ѹ @bI."`=ȫXD& m9B:rn o4 ]5$5&ME5Japn;=$xPUxc7C9|J(y]p6" }ȵߧ|â.)x%*SvӠJm7^%'ŀޠ`Q/ BL'c)<vz8Њ'r?YKrGپ!6f\RdNxDl1Ui%_j$L!+i*Dz"CoV 982ÁJQ%pzG|1ZSA^L(J /:S=!w[$4;ܚb+a&Ü2:OR#) <"KVem bqeq@}0u uSyHZOd9`_u[4M: ^uFQpvQi82qŅpھJ eRW.Q* OryJiIHL I:uF˒b kdpobN6}ZQz8^zgOx7٭=)N]ű (2f$G((>ܸdLukQZ75ҒX#[V^bYwhš+Di ]90xobamPL6\TŮ|G5ȏD{FRl<%5oW>\ PB+TnYYce#z %Dp熪Ppgl>^:tR;]-*4=1><t.SŒDJ4"0EB|a'B56VF,`&>9B8[s&X}=kh*,G2oLLd4^"DcBxoգo$rnIp:Lj!Y"gKc;E/:Œ!_е3EGrsW:cq S}VCYnq!D!g Ja6ܚUd|cAU8^ y}W~EV3 Ӳ. ,٥w$ *ܠ+sWڴymn cr˿6mCr6m6"+7>o\h, l,FLfUXa,͛ߜf^T4YJV\4.{p0t+1LPUT|5Y$bc)/䟩>a' %p>\-z\JYQY ]2- j# C!%Ɋ:$,1(F;g'Q| %戒*@}غM#cyn"E[8,&<&= *%\^/x@```#8oLu"ky`|<ટzQyzeGʔryemo5x?tu+s2)WbT7VrcR$AL pM;=0hxHBmV#ӵS8pаssrA4ubϹ??vW9ͻd|6XB2W,ER,:BɕIqL*0*Mk\ w]^MԦ3T2}HG#!d۴5Q{9:qzU%' 7BLj",GXrf|x$ z.t%rR۟2/S> UښTZ!U @BQQ78f"nUF[boBr::|ϘJGT6k6mڬ2/ -yfXkr>|۴ih*El'Bz;fMvm*۬!/MtR*0Z`[iL7qw5,dAW)0I2PP AM=Salq#)/fN "A׉G~8!Cnش( x&l"!I'}98#uøy\#7?2iu-R|Fb.)¹^'X* %h.ds*p($e @a:A`<";tq@}x4NY~xOuj} g,h铰x09/c`~mLWj)/)\G5 ӖƦ;X6{,EI 瘀H4Oְ ],i*'M*јd/uҙjf#oyȝ T5U/<$VWEYZS8!#/’2>hg Q5|Lćk+$oHQ.EIZZ +e;`t0Le^)6#c$]y}/HX?/bUt-\H%+lJy)T u *> .”U.󾿘ψ6./b(v{ssX9Z xhc<1V_368wAhHI@ReUuM_t9^гVj5 #h4J)n^~EV9>U$$fyGdKqϱ R~m\IgهF+!M6; g f})25w *~h [AhF_lu o& !8Q5vyyhOB-xkocLO6Ma/#s;Sl}|Y1pٍB){#v O{kb2_3|(:Es~X~ W `MZu?oRVlQ" < ? tT -oIlI/ ȫ&N)JnqvҬ?}KMt /\XOd|᾵^kUXVG<ܗbDJ $-Z"ՙnbfy#HؔaKpOwN =0mZE@d6N;=tOTk8zEmZ"!?P.jwh;'K~f$2zj(>qRqz%R:kf5hQN;M]DT*#6"`Ų;>8d0Vĥ C /_[ ҥ|t.E/|ktmI Q$:GI- h.,:4O'K۰F~|$ZQo 9sg'E JRJ|k700J>S4hueE:жifmh]as8@WmCr6m6 MeʲYo+NX҄5przܕ xY)!0"KWTn# 6u)(<#QC,prK_!'sdFcU6I &I\#7ZfOwD$y{>V{g(!9D_DBPl&Tf)%x!FeWA@="uxG#@f>LbR~iɛ:@ɭ)^*j9|ziM-TqEgɼnf+Evs8M|K%[+;={Jqu(4;%d!&^QTe!;Slq% 30EH4T``,Jﹼɭ3Tw^1sr^}>x\Kt[4LE a8$z\8Zi+_"F^#ܦ\*M '|{96HIQ>XC IDAT%R hOQBE7@)YNz."+D* NGU&]* "L ,08;,  LZ’6\ (򷊜]?[7eNJR̓c!=fi*Bq!fM+h8T8if}2JmHnӦF"4x"3AH5P#P0ʕP^a,+<!;eFݫ]z<e`QqOͥ_n;s|aҗ WiG޶wfz˻4ڈ\qJQ,]}"D<:KTXW/x=?ӞWS&uU u"*BA'{DT`<[wuP=B>АOj. .rv T(=@=0*C2&ԉm6.$D-07/pD`-t/#xܚ'%N X[e ?W' ْ,8%A=&9ڵ=-AO=1<[*P* xDDGAR=HriEq> J?@ݓ]E!DxH}%.Ԫ7ι<-Litm7m֑1<9S¢DVPxK|6S/5{e1} F"7\!F_0.͈p=*]LlC)3jPPe;++IC83vϱ5:i֑mڴyN PJ J&IlB&uXUmRyif"cX(QE`k!M62 !ȋ*Q},CV/(6fV6i4v,H*Qyޥ&夞)^7 /s ?Cn5Y}`t{&3%%h s.^( 'eEh&)*y, YaXl4$KęP&g7RM3bTXKR~Z픸p+`eLVM㊦K1A}]9 `@DBGs[fw,p Ծ7\yJ P fa'9*gve;y򺂷z>ǔ^AK%Y;wpy|osErqQLB,R)V". eL*![\*!&|FNA![>{=aG=aU,)uf)2P1N Tga0xl cgj~)-f'88TNvBxYmQnG6d4x]NdSQ'BGzP׊X%Ǎ^SMT( T!"rCVH}_4H::9dL>uQzKl>FW<MO4T1T"/kD^p{nSK2W04R&Uj5VZsACkcvPrȺCȌq" >IEIp{^JoG~EVstptST[b`3ߑ3?(y%cZ8ifhiOA6 I)$IYB1؎@XmL޸C[i"vm/,jZ'h4jˢ:cp Kb!.S9GS71]~`|jIy_rGb )[nWL>9^>Ƀ,-юM{3{}A~8ՙNO&Un+գUMofy?AŸqI(j%JKV%[A*{OɈ7[.;pz [FZx걲,2Ol78-F$GzȨbɭ9".*ÿUg{jur~sBFӤ#{M3@ 9 ijFŭ@{Oj&ȱq MfiNܹiǑv S1IiW}U}k%Qc_8d}RRutן1HDF;j۷#_X|c-|'v|=K-xJOr)8 SQW ;[?}?sg6?^3쉪;U5żF;^<}f-ά3{_:p)*hVyf1#j33 ?*k$ⲗdba1^;H|depmS*RfW{\t:Yۼy4uFV ҳPYd ?sYTY :ycF0ggTOj[4 oVv$v JdYNq}C)=y'>GQ|¨ﻎ Y&T =I<&5 JZ}M#Y[-l71yhD/l{fgA_a\v/t楍z=?}VxVL~~~Ӆ 8GWLA#+ Vo}亏&o薢F-]uFՄ!!=QPݫ[Wھge<ݿV[EU(+w[V+|*(%3Sտ'uz6:{h~WlDpK؞=k3.|t`3mewzgِ|dB @1XM )wN]-T,*>:6 6m62B^+/n+ P,(Ϲ~;nЛ6) **u5.撹t+Tޛ{{W+$r>xĎ׻OM5nعp 3SSnݺsW|זGٷn%nz,҃G_;}@}=ComCo[d^23EcG2cMψyPށkQcؕj_ӿPg޲ Hu7\{dt8fs5f F4= Dlz,ݸ[uΓ0vh ə,)ޟ7tlF-2/~]ܽOa`cKgsO t}; ll5O{ﹱƇ\ȷomIʤ@#]=Vt^wf}CyiY֦w޴ܺMnxݛ~ϛ{V#ɑ޼:Q qox$&T} -_x?/\=^;;so-jd7ߝӟ^=.cj=ӛxb;;ك=dnVsEHDqm>J\CT:nc7VӿoڛZB*tĶH\R/sSӆg]G2{h ~ޱZk}skgb+ҕܹWTVOly;>/<9kLٹsvBڷ-mr ɦp4P-ݪd3#/}VoqOQxiuQ\/,nw2?pS_y}3PK*6pϋUN2)UʼV\b 1ɴħ!{V ] C ;0/U;&U1 sV1DqhJ|[7=YINԹ!ͥsH_Y$D䈁!Vׅ4SOu|Sש_2էZF6X тY0A-LPK: `Ʋy4梶Q+^S4ǿgKO/<'N>S&% 8/.7yQ eܧn?fCKNk1%ۿZ)V0$0VyFWO5nhƣrZr0MPxpYQϯd3|n: 9/\OEѱ+-m !`|ݟ3%";rԶ< N%X!^qǬ[f$Ld-Ȼ~w|]? 2T$?/(ni}1V9⽦$ tّB@Ii@N,5:DM0 Vzyumڴs[֙pHwLdHhifWnZK#.C) ۷=e B BHkBq{FY%!?xm?#e7f]] SNNq9 WRX<7U:3?{gVǕZs_ij9&Ǯ]0T;Ű.gJ?Vv+6+lQ[{C28qmoyFozYV"LѐI͈rBSG#Y;s 7=!uOhz<3L_?ssur<5G `Uw:O߱'f^||n~eu.#p| ."ڵw ]Z|4>l;^>Ƀ,\‘/ު4)Bg'Omcw:??9rl|Mr$XXyU~V>c/}ꗣ]'w':%Dru7]BJ{cۣ[xpL,]sw>u.Okڌ=u#KY3lUO '%Voz<׉r<9+lkZK1[q)',g,s=g>6o'6ԻT5Ez4] *4)kuj r,ZfزFD-'fܹN"ץ&G:\R|&*IL9|lNַㅵ=ijT\)C 4\W=OjMۭ;$7t_ǻz%Y?ofiu7WIa%H!cƫlx',_/kT e9;\?סrss~.L:a;1"-z+<Ư<`KޣVi&Lo3h?ӳVclSg; hzY9ck b?mpA VՖ"`Kڬ_es3:ۘ3;/{\%=IdoT-$ݹ뢛ssɂ7 IDAT?rGJ-ev%?[8^'eJI>&Gz憒;疞էss -s}ݕG}t ?N"umH~ m^-!8lT'k߾9GH Sg@a:?~P;T*|PJni#'47?0rl|MO7f`9mr=0)Ȭ 62%$l Ӊhl^DzcqvZz%3;TU&q*^*t}|jn~ooWjv"l04 Q*J,g]ȖYBy?3V(2dGosI Zdh ʹWi6 ${y!!8j!7Ǟ>Lum7 ?Uo4߳o!$a"+y.A)TI8{lq/2m^fx.ɛM{K.c>!W~1 J"*~۟+2/2B/[ޖ۟3Wj| ,C;1Vօ.j[fw4}҄|1z`4vSպhd_1* t,VƿZkh@ᄪ<۟[T-•ގ6z6"gs77n&WgvB@J0={ A7<㾱M6'Y@2ߑ0ey֣$g~Z~$M۴if5F V~L) @AKI=0*'Ʋ}|)0=@U-[kT});L![q*0' ڼ{.4yqm”g*24QnO<wܢ ϗh]7Bk 1fKT eap6;ODyZa\We̮+8of*y.9d̃ؤ E727vtU Zq+e.atj? >ҹ/ZKKa#U8ɕ3Βa "x_@0F$Fb- IM@8Z^6 . MlqbUɖBHdZwdlqW7~'G FZ2GE3'LH 3! "ߝݶ;qku#?-}>!%1q2w V!׎ ~{z|)4s'&|u8I\?Mk=LD)T(z&2~Ւ' f) eEGKBA $@ Q!W"0SD)?BumڼϹG}J 琅0`HlT}}6$ifTօEH3LD%``kOR5h36w 8Mk#Px5Mք"]PiFp6WgXj8hQ#ǫ/y{N;,-ѤIza\$T jrm'HNoIAl+Т{. ;ż+1?/kכf.TIm`,&=A9KϨ VA37:bS6Ô~̡?,FB.h93M&XL4*\c*kzr6 I7%,93pz4ʅ` :[C5EF|E˞u*nU¹=г 2=KD5U@!7<1>*wLNK4({NB!kiߛѪD"tIbVtN=0B?'7)N}& @bINAU`5׳Nţ!}~1.ɬb@ W8wuu]aa$2:XBREU !*DIMF$_sWX=k $_q c!܌YB$:Ar\"7,.>6K? 9.hi2 Cc~ .f=0*'k"y7HkxǧEt*`PAr֛+mm[IN݁-p&UL> N@iN|){+RѦkYhpA!Fr寷d3Qo0ZƐLٴ2\M6X'0@PDpETڣq'Ѓ`sKfy|+*׋DA"HPDD3*gg`O{M%x,==2!Gn1%ILlg'ბrn #QjV) pNP8ςjPBHm͈5 -Ls#c_.ezIbNrscҥ|)8tsSW%!9 $.Jube`,Q謆P:GMй Y^veB]` #'$|ϮK{&U=]-*s*lOjs.F TDH+QR?\"뫚D5`\-$ce-vU%5I ;/:۾5}dz8A+KO~S{Yu:U3r;(dr=em̝@yybabT6(!5AU`îPI9f]-j)~'4O0p M:K))1+6E-o褚|pgn[UxM ]I quMFܫ-I/JBHu q>W^׃^=sF|0 *lEPZ@*\ܑi30CB05tHC4ecδL1}d:|d*nθ4QQxdiD/$`a~ZU }QUs1mk{, ~-"n5 POqKrAPZG,Jtsm>#rFz.)uF3ji!D Sj3L~cxwLٷ *v{0|1t@8;F#Ixn2{l#U jcWjM[5 "MݏvG#>oy;rOoOmG}uĎn 5v{ݾ8t%5$5JV-[(rܱ#λMs%.'N7h=oCzin t$-&hzmvdUa4wv{d~{~xl,J!kH@lbCӉY>Ν&Nbo]_k$7.,~&X`@k zgJ@II("0)H;e">*ێmd0c$a!B!֠+§ =|[q_ "YI)D &ⱐ7S|OuCKF % I0U¶AI{;:T!6T}Td?:>lnߕۯiVX!p".=,Q@,f f*(8kg+"plgK#ӡ*r:^^smM[{ra  5 tYplϯ[;}j $5OTv[C'vw\Mф=][ )$8Us so餈d{{brG[`J vxjPڌF/#!ZwUdKۈN ` p17'PG #dzRg Fب¿)P}Y NvtV|0Rᙋ+OJ1eZryY\w*yl?k%xtq斉Vm&۝@)\*{Wr,"CZ CeX{ԬaG2ytRx+U5Dt?(HyT3-ŧl1AS911qFDþhLs ~ǁvz͘ɄEI B|*fI3?ĥ!rfK:ɵEBJg9Q,_pT!g".ql띞'"RTsDHN@I q ,qAyf9 !cQ4&c6c;F2PJ ) * ;yt)mpqG'g%^JUȐBiՍЇk%Kbr F>+„vMt@V8_Vc|\f+ # &I%՛/H/ ^v1}d膜F3e[=zCNR+qL"٬cTF+ E*夜d~h<&|,#^f?G~~b'y͘B|2p]Y#!:(J6|:ϮGfYJ8*Y2JזN)*GG Nm nӼ֧if"5΁T?dȠ2)%3T6T$f9MI0>sP?"H @yb gu>2|plJj!:YQLܴ f F#$T8=*|E:# U*#`g "# DO2ʋIQvdRҾX4>kg OTRipH"L&8EM giI*_)5Aԝ>2a6} 22]"= b mɮ 2QM`)PHqrx3 D[LL7xx+z|;$TH/Hj ."PUin , /0s\G˛DlB> 4))V)[ ~|v=zt/G*iE/@iBr/GCۉZBD j4 .P]h,/ v׍G`X\7I` FtBva&;Vɴ"WZ F7D$b҆/}?ʒf)'^eѻeoQ*O[*@YshwHEA$m$AX*0L#"Ij*vQRMu"YJ*i2P)BՂ&s6fٛsW[Ty6kh H|!_̨*#nUlW$LHrH" ^ ծ!qtr|#EpAIFjw۩USS- .P4Gd O-*쪢R.(*,ELSy(U-1*h$`U6~s<=" IDAT8I}S9#nG`A3.^Fc=ޟ=x afe0DHxK;Eg-G rHRH  glRդ}B\hXj@وmS^[JN\x*{1\<o>2M0꙲)Tz8oCz6Jmp~cmTq TN^8祑"WxAO0JzR3.Euubgkв$%aͼ܄)_ѭD-*OQ~O5RnIGI|1]lȎ | 1,.t$A\IR>{$m0jф=0ҷd؄'9t_w3*[F܆yY+ʭ f42 w%l X}Xz‡7S_tU'(BibL2ޗ"חE6jQ)$D Eu,2 `jjې-P$ȏuQT"'(n}nVVj(y4#͚>DTUiobd@QiwBݮw}D[7!v Eɹ4a.Q5QO!I q7|<:&%R skg9D2HBW6ml  Y%FĂ7}bF|>ե,%Ո*w3LEZMY>}J%?ǣ%sT6`: `q(bA9ZD$b> `u@87uGV]%SIđ7 olqv8&j\eQ>k~ `.GˏQ#K`.՟n?nllUt&nRSTQl;e= ,ѣkiɤ(P&%x E/Sh1Br;U=zc@WJBPKmjGR(oTv_B )C,!I@BI1pZKݓK[<_K6HJF֌.ӧS}o*ǔ=| 4JUrLw&d@??LCCg|,m0Xygi֧.g#i UF$:l#EkkyzTQ.$*_IKk%K@<:YشH*ilYMɈD +ҩ e- n+v uYQq-47+Õr3B,&N:uEtl;)nU8J)pKwĂba>('@L(5¶U; SUumE\ y d_SU!Ej#6hFv\I}ojBgsnq FP5DsyM2Y -H F$w}#\] IˁҎd|qD+W5GusFIQVR&U.[oŹuD\ܮD|mw nؓG'k_2N&tuL}WoZz߂U{vp]Js_2` }8'ͥGr`FX +G~a%u`?G~~bڹ& ݚˑÿϹ569jehR?]Y(8ސD$I s-G i+LFL8-im4NdD\䘔#>c܊DãDOŸQ2J#S 4S;J RSi>QǶЌ\^gtNAAJy408#`X_Sj}V׏}OlZ;Ʃ/RXĥl6K)ջ5!nG?rɳQk*< ,4,' kd5,/^zծޮQ.IT&(GGۈC:{\S@D^M0꘲o@\yU6LUaCljJVLm1ˬa`!-œ_1";NJ x۴՟n?nlg`,qcQވBk'HIY]&7>l._u1(J8"eo˖{)Uzy0M$vM T\zz R4/'UH2AAԄbR@'L WjJj:(gPSz !\)5(°hcHѺIR()`ؐ6qR+"~=5ytRd9ܬaDP(" TlpXHi 8Կ^Z47xX RQPIhj#Pedis\ #uk5IjrJٔDA+_v ںT=#Eti$D*!@ y4b0}î[?7YX3ׇ^/$F@\#YTT!B@MF}]cQHDTבThBRBDRH%zS%}忼ykJ'Η|ċKPRu}P蚭B*pB)Q3aHNZaEGumg|@J*}-(i0_(/E+뺕<9EfCj"΁T#EqΊD7`%jF40hiYkm^NФgLYa5Kcae#[6B3'v ~`B(Vgx)\*.Ww7݁ӚV)d12TQtSOGR@LWF;k;5NumiZ~}nUA!&KKڌR,xnu"#kEtN1{W\gLiHRc.I K"lW*13"}`ɆʾL!ѢdLB ⭾mZ'@fզJ +:v |?oedï0ϩV:biju]"TF\r1O(&Nz?L?,*J{yt,W YL#7J!ߧŴ2sEUШW!sRoD.! cDG Y0ފm]c8'F!8.gZ_@T·|8vSj_G8]Hkr G275}1Snr}mPIw]^ oTcԷeo=9Bm_: nX' TK$RIG0`/BQ_)v6lUU2X/hS\2R 6MGPIώ0HR!uJ 'S; =zVtNu]^'AGI"N)"K27  _mK _! RAG1$}"!Y)֎/HMNzF ohkZoy 3paUfMعv("d!y_tOTa>[I3k-W?596/ gRBu뚾?Dz'ħxҊwrj/-v;)liM 48!VN o@٥cs3#_+*+%nbаܐDW$PU9Sdr9ب D CH[&2cTTÈ6hXU˭(te je)3W+&+:7 j!+RbI f>a 4B鹗!5_?Rz `S߮!ARFRl~M*Sq$9ERXAXp߉Z\N4_7t;!ib \y/2$)hn=_OY0B>HcD0ӗa2RRqU$WLyrXW]?ȜÙ^.Sc/7T*`j3E-P' 4Fro i@R('=A-v?G~~b4p]Zj^DtCYP `ފ~=4N[ )$5:1 !lM=zh8ڊw;G\Զ$Sy@IəGvZ MO0 99ĂDA/}1}d0V;g y1?G͉HYpX~|N|'87J !v@%q@s)*/hnji.*њsVϟ;7zq8k%t O'SvJkO~NdxM wGѮ#h8*d@0DQ CƄ,OvQG&cе$+Q4LB' 2&p2 )L j:ֿ "!1 _eJujuWLN!v&̀Rđ{[ǜhܮJi+!K 4 "\4\18?;jT!y8T"^H|F2!JJ+Q&kPw,a8b)9HQ3. Eؿ-z͹蚔 N+d*ġHH*$] _߭u =P+? {\>] ri TE?M6XP%Yj_]!F8Ot{LEoLf@V`4KSmNU?$$<ԣGoUp5RDSûNe\p~!=z(hc2aLؙܹ@D, B1C'yJYTT"uJTEa}ճ  c=,v訯kuz֑&":ȔYe1thߡ _ΪJ'JTkʅA}UѓTtKSpMZ0ziSU1jbd2ܞ YXijf$3d\]LyT٨nI.~%AK.=&oɛa?SpGpU Kʘ6Hv#A ^a&f(JḮ=Θ^[}Ŝ54 I"7XӣENdۡ0@,}iVZbn,sa=#E=-Ɋ%c\nCO[#Y|LS5 㴗\|ܥìQ߸L 0cb̸L c1Pֵ& k$A` F2)S ,PE㦪uͯXRAZ̻PF: TaxLaB熉da$}|D IDATm*D4 F5.XI .asQq7vp$w_ 7qp5c3TZYE*D"6(&jL4YEm0*c-bkq?G~~b)\JtMjvhۅ5Q h 9=* V=z2 ""E$tk'r Tbe[NKmr0{s:3`T*p;?l"{~]e*`=Nw~?&e fA귬!CrTxYp{V<Xq9vu>U$al?PPh'3.M?91<6o6ĢRrx1d  .ê_JĿȕu#5qͶJ}'߾-7W\s0]/|9Guh!G9 6eq?L,\QϲR͇!IaͥM뼪Qx xH+~HVݷ^CY8NZwrrҳg#Z2~Sjא;cO~73hr<-+ ؠv7>6?Sv:`&/\Pޞܞ:_izw?w?p f;@W^Mf~^wS?8F'EfLkƒv/}~8fч|sl>2|߫di.Y]^ЭB0B _\ňңkj5 ly#|~s8jط5w8os?]/\4[-jvB->G\zvۏ'j'v{cg?wU +$lH~h⡾ھ̾Z6Nv=T?CͥӖ֧G-!턐ϭxwȑk~iăӉ޶[+׽Gȟ0ԉʉ9]9)7r{GlTt_*۸?s`lDOXi81l&o:Auൃ}o֟|`i:&g걃/p z)ݯ8|SO>WNakFEiɷkv뵭-~ ̻33zuw?kLo('1XldI_|Ͷ;3 hF@]{7߉V_Ms;_͛(f&2F__6=tR% (57x1t0zkkAyכrEr*s2z^|nR38#]{nnW{N8\~f41x?m oJ Tf;OPMj C>fww_SV[6T0<O )$ynM_~>~g:9~oJ%WYmvÄ8!d#2!l=4M3L:@==L?!nx2 4,x NĎTU*~g?*K1&*սyzT֢U|S]&rd3zȊsހ';I%KG'b'V+ؕrISk$wݥU]#N[F7U:7}HQ'Zz;Iwu~> 7wHY*LG~zk:mؔQI%nN^b+v:͐B,BW^햫}Sz R3b7vxK_f?JP9K E5^O1:HF֮R$E) lU~uQJ`vgמFZ6RmK''g>wkOM2) Yz41&g/̶WDw 5*q3Ͷ+|žRn(>s3_|eⲗERKno"k"4,B*ٵs} rA 4֘vFhW g z]b47g~,gjM7o GV%hK'b"a:WZ[S5 Z>O?Мwiԥ٭K$5T,1U )E.T 쾠ۨ-}GZR  "d&X  5}UQqLD%Y3gP2JϹaH*ChAq~8Xތ>n&t\J̉HAlmM5Gմ*pcu!&TvԤ SzM0bUDPJF@4B Kg?yhFMCA!a*&(pbhQ %*T΁Thsˈ`2Ec B }5tٵv3g2iJ}s!RSP(Np@U*a]~>POgξYQJ1b|Ҷb"ǶB Up%nXUA lOTlEqggM`"|6ս\">=K# R` JzէcN<@(8do5L.9]DClJ?7Y:݄ :BjFp|DTd )S7&ԱxRz \m2LYC",; f` v7iM),BF4@b IE_Qƣ]XtfumŚOtMWi_sHjpVuf5L7Mj0Ot4ujoOAĈg9U4]a>O?"zh=l JI⛤tiΙkԳ$hx3_:8cjwU\HDy"VmhwV~G7zsc mgfi1V)uXwE^JSP*&s%=6pUt|O?@W]7>GQtM`aAD: T`RBA~-џm\d;'C--=jsPp-`kw-]ҍ7_ͅO^ o-=8z`A-[ٗ *zeIxP~RewwYXJ؊qtKn2"(s7/jտ=ܹ°vϜoo Oٻk7KE4r{kЙ}UE|,ou~e;xF?x1X"53Lmve$O/@ ?1kj[;{vW/L,{|HRKX>.Ms}-x޷=8~r;9#$5! )b5R3/?;u`v3?̇ ߼id (!2>U<!b;˿ܯgୃo5ڕf.W20| ԉI9OАʠ6eR3'ui|Oi?GG6dʇUE)+ZdAx'j(*z=3$c'ne롡z7@A~'jm[M17l:^MsP WJ}~Zbb8$r^uz].&M=o)\BE_0ds؜:6'é-2v 7z4ɀGˆg fSHՕnr?nߎ08/nn[d40p3÷= NIr$cqXaG~ .=G;ß5u'W#3g?}iY>g'iX8vȨsFN)ių~Q 8Bn/norvjanRLa^,Y5&EN69篼k>eGUĩ1O 4cJMTclz7~vzxHHGf%6 FC|mv5SǦM'gtuj>!,06pu!' L>=,?_X8]2'%γbW*PI/L^u,u\׼ʓeE;Riw5l7}`i=n%yaGekU$ G̬;fԸ[!C:WiB) 64Vk{ 譟qxAyk'Fd&8y}3rq3}&r👔x\L46VuI f2%Of<\3/0@-˜0Vۋ`]3ILw8u$熎~zW鮿nm`NW/MSǦ!c=6Đ t=f?zѣG2ul+O`UO qA5n({Je=gYJ*3ZjИd[x"#IAD:ukHFw)(<P%.cB )Z\WaJlϥp  }k^ZMTS꺔\z6C]:f[㕿i͕ QU33X~ϻ>X EhK/UkQPp"E์L`L6D`c.Rsi0fmϮi,[,-~gHi*FTJzH(ʆ 9e}W*`l&2B,Ļ*0**+K$#oouiIm*U;d*^X+Qwڲ-Fd?=-;Y^y@5MK m_:h. Srkg shQVh"%4"'N΃Z@mo]eQ'QcSk#2>d] "* 5_̓b,l^:6=;%49RS'-NU(((-N)R[hDBH7ҶnJKVji[(BUL$1R F3T ] HCɻ)_,ǯg`zlz $z #Us?*~L( #G0X|6 _~Z7jOSA*ZhhՊkT5Czn_IrnW\>C $ثPBiL%0D* 1 8CD&MU;t㜠j3bLRAg/H}̱Xn=VKP4ZSse |E,B^Bx…ͫÊZDiI eSH-A%#҂J]-/Wֲp+DӦƔn!|ݘ=>_Fd9ϧOdņcSqy\gi%3B]󔊅_&%uHtDE_3/Vt0j؂b,tYC$&@A9ښ@M>ɲ^#?sZq_&"L*k\glVtp2aq ݤ 9Hۑ5ʓe=9|?TT2$bTW7}y첡[wUs}u2 T ʋrb ^m~p3FF`93Pi/>Ni4Bs 7x~+wY@@VDZ@!9&BsTL~m/=:juD!:5&]a@d2+&[N皵Z(h$\]%(%GZA#mQ[09_ܿ<_}~z[sʁR*HA_(?@O%k=zt9<~M" IDAT$wJ=zt&)rH]dE6$uh{=nͤOӭ*cP*PiJ*5)TRE:Y@Q y.rRj;ʀBclzl|d<;I.T;2Hz*fnܯN4ߢ_fK8[ThpSE6qrk}ͱHۦf?=-~j~d0P]RWY'% FZT}_HW1_~80:ȳ}/OE#r2"xgDh|{\\ 5"#nttK*vaJ) $^=z2מ!}дTךg \{='˺|nG{f^^='s1GfИ&lfϯ>6oHZܔC;1<%~G( E3a@q8`ȞۅUX_KX" tJ.Bi(S#d@n@ya5ca,=IfbMc\Sh[D”ۄj{z[!R%ޟٟҾ2*` "y>^^'0O;.(@)@'.JhH9xc˓eRy\6nZhWQQˇLzyMc[~ףB}&]$W VWl_z,:]3 T5XءgfbHa`C'D3tiK-IrԸ!P-dxr ~Aa* 0Q‰D)d҈*c !|۽TB@bґ/ @[+龜P<], BHXQRR*h C#\>v%Y e.h%hZjMoTٔnT}J%Bɲ"DF(\n:DQ(Bi}%>9;`?9 Hr%~Ag>'Dm 5+ecuZ- k.d2~*,7۪OP[YM(CeԡsbTJlq;IupJkihB,Qoe m*"ձzަRX.G3$ѣHھ쾛o@JK޿xn9@],;ֳlSoMFh_N[b6LWy,T'J|SD ~OAϭHӰGg{#4M,kk@dAJ_jEj"0Ajf2Ni$!L(h{Sf@Kڰ9FW]H7>7|V1לC,sq$N u 0;&,f[O#18p6oyAa)|U1cWuF1heqܨ8UgH<ط!.c@J,BkUJg9K` X @j5I B3{HId0$26NKI ޚ60!!`BGNo O!|{}WcދF 8qHJxyr$Õlʘr#1"0օi("\,,V;}u{Es}=DoGka 8p!}^# rC=z\tƑ]Jo7&Stzl@9iD{ѕHy\%̶g5$$eXo!z:6U}r"m54 `uˤzC,~aR\ԮA?BD9A%j9ŌL >\󮭻2ӜͶfaZ}\wCɰqY'+E&tM貸hP"-O=nDrkC+4qnIZodŠH ^AQ8*0[juCD }2YazzzX%l]DwURL"R`ļeVYF1pu?bz̜Qd%8iԢRMF nŋ#$5@bh{Uu[7 :9KLNG޿n\ߋ!1"e~q RI&\H´ e5^zG7r&_w+uwgz=ztפ (š+;{ETH"H n k _DFl"d I0D]5Xs}d햹ch}{>j,(>MAr˓N1&\.Ay,RqIjIj7z5h1Àgʡ\, k˙8j56ko9R}4o '-ؔ'%$Z{9wb鳒"Cc/#AÈ(ۈ1f av=*kxl"b "pILQ ]7d(S1fF^"LYk t ^G/NSç,%% ߸4 x@5vj0jAoæTFL8uKUxAdN5\LuO+,p@/:U@)w)Hț>'NȬRA4 1'Pj\Q-2}0=65w~w2eFSǦAIRO8zP#!)IZPdy 0; /p}6Oa'[#ԍ#ɬn9 .̌ J0%Q}JI:I$v8u"4CbLWŠҗ @Hpuh4}JHmcyi,POh':8?N#G,"ɎԣG`"Q& Q$<}T:7\/%SX@A! ]JCΐtu899v-6_[fY RH CB-AJ߰R􇟒]\2c*bm$dMcO- qr_SH}װo_'<+XP uh7 HX\ 1:ۣZ ^'cPĜc-RSfHU.Z [P,gt,cxFZ#kAB!cS@u+Bdre]U׹v(Dkòan<Y֑8Juj:R^]e<8dLn(vB$W3י 4^+Had}@4KObU>x ܋:QеhݤUBp@tHfZ~!݀t1h_H B (U l7RsE*ӪC2}DŘ|4(R"k] H֯fe9M}%t>Bq- A6hÆRhК${*5^ZWx?/:_~E#rLcSdY4V RN&V;4"d̔2 e ;uDAo ψ<`DP:L~洈馔Z-s (r M*%TglR=z^ D ${uHrJ\,qQycm岮\[ߺxzN%֍fэ =z$A Xn0휖FIw@y95KR[Do圂d5ݴ"M 3NˮM` >kD7Ԣڹ̝2Muc &3fB blKcȬǠZH0hhR+/;$E$. m6j}cӷ-*TJ#j2ټ %+H5l"`+Gd4O3zNf$7)eʴWʴXʎ]QGNiwJKoYvHyWmOȬ\4w! 7)}P5j Ifʳ|dqMav B4_Vբ!a- 2"wB9%KĚ--cT-ߓ mW_DӥCq/gɕeT@FPĶl aI6֒3ul|xZAihPٚ *դH 7DC +IwcͭjVu䚟1{0$$˔i%մr-4ZhdaZѹ^NG޿n\_"U1>{́lXJ))waSp㻲WH/ˆB#V3zںGF=X@3ro}7>H$Ԉ]džsMcN[޽njv!Z)p{H`'NoÐp'4u)BCg(p}o!᪡n1lnj_O%܊N mXWtFPڇ$2v}=@H㫵i>阯cS)!X =TTj (Q TeF12KCP u d́C!oSdeI؂?~zZ`lrW#w(KSrD&و$3ȝ`sd;&ަ]*^PrנP76]\7ul*70_l&t!*hmwFlIM",qѼ# ܰѴ$B[e(*AMh VK)ԩlSǦ7V bTDQ(qPI"@oU>R{ƿ?KLǬU$hyMzMˤoBע{S-˔\DD `@T_Zo~Nfzl>Wj&Ie}a^WԱ)<9[1<|JGFQAZ`c4ZQw:e1w^瑿 综qk>prddBxδ. xK6%"Q=kVG2$',3鎏-wSǦdܜ77a3_K\E8ңGrYy^FH L)$5Jjt.j5s#${t =Cr=BCR;T/x ǥD':b/9^KW]Q4DҚY#%A2*G&5` iLC P)a8 "elאDH|7 u;j|G(/Ri$HkH9/)5qp^ɲ@3@[΢?SIB)SɔS6?WZ{8Bi)ag/= ZA,op}s4v:':BNxb}ZPa}u݋)\C$隆rRrZmi-~~]x JƆn&qQ*Tj R8sv >Ov:;}u{ENd_SޕV{f_쟵b^q)5.=K=^#oJ vM ʌ~U{shZürnڕcS]3$ѣ; Ъ1Pwyl0}$Fd|F&ˊb|C"㸭QMgHe# Jñ"j_ 㧧Ey\W[L0Tdv%+VAm:B%f<%TorǍYA!Jrk(قi.#j}?)䟱h J}$@l+\FΘ\q.-2J5rqA 1Tm_A:\lEOeҼ QYjK؜6ܧU#%Ś[, TʁX9:<=Գ>@8 ؇t~_yȷ-XFÁ3:G WlC\uʪo<뵢fA8Hi=1|K8:T=" IDAT/ޟA?,"49DyF5/kUNHRhwf0=n@C1gRCVJX?Qb;ߵ&d#-w:b% R5}QJՃwՈ}%Xz*0&E:M$ƱDpMݪy\֨G;[H6{x<$HeC(Jw!cOP8!0*HH[/bW#NR? T`L4EX,H3&U: h RL]琌Po9RwA] X!&VZ1@ 5H^n+'_Уgt<k˒* hj(nS 7l?{oeU~p;׽FUJCky"lc ۀiCD! yIJ y+Cu:F/͋W: 00URwΰ)ɂ`ɪRݒgZU>>o4B<[Z%+xiYqhJ冄H7jݲ{uuNt)MD cϨ>+y1G0؋i= մ*$$@k'"_`R1Ӵ) bc ՘5W[E= Ph1*^ "M,-ghXi<3o K5Z{>t+"k'J2:o4F?krOI|(.1Aڥ f M$#w8cfVm)aO!]J4oʛGUZZ-CF3V1T.Y0(ѼGiAaeԑ#3݅ɩCb3&?AQwDdSDO ӂZP@7" ´e^;AՉ_pۍ,"wj,޾Ä/r+8T.,S&Xf7ZKŲgxDN\ER{^ܥ˦fztbFJB\12?'8 *_݌t#t)?]+,!Z0tH`6`Kjj]7A MQM$&LhFK(6@IyJm7bcuہ9D٦DOHZbl# Q8XZjv8z'k@Qph!D5-sk\]RՔziGLq˱tJ[WiiWn&qna]'J"ZȤx;B-"M;on4q::|cSK\ٰWP=zW_XXwJn@U\1 ঢJIs$r-,upuNmXTiYH 6 B]d@ P @d mG隣_"!ʣZ̋Aynj]y1:D91 :KLOœz*fqv@`diƀtU`lN,"ٍzVFJ"Nby|`iK6qmQE-JE3_+RI2@ RS GP :vM/뿛NFХKhw8&1a0__f*3R蔻2j)h 6cܰ !Q [F,ZQzfw-252H4$3 nQZa8/,Ұ-mN;^1Com'H/Z{aEyᛟ.d`yztqmB.կDtWf>L2z@88LuTUv^IJ,6K{ȌL=\f  TɄݺ4n#n;? ~%+/GW؀U*O9qkۢ= kh=^ˢRU;jIŴRٚN _iOS8Xn"G!grólDҖI,;&h&0к)b8r5WdYfRpE5- i݅JT<mW EQ"LP8fsΟ/139 Q=+R~/M )wOnp~$]MWڇ׶Q(T/,@C,_`Yubw+$TRT䪕d IYioho v^|rPmV Ι_r '7ךZK8eD(:}K.?H_{[)J]o:]\:~o.] 9Do,K IJ.ߨ.\}'faߖ6YxNP(Ϧc'd^#˾ҕZ۴/̓P_qИ;mO0-L`! ` $k#!GJ9PD$ (nsőeYHP1"K# \=jY$& oqB _8+,l'}VXXHu  ,P IE<V8X0:t\ Bl4UDhNDm(RD)Rx)w# \ @K=_NA&H6WhH+۔Zt~, `GSD#K:N˴\bjJE `zY! qpUn-@LhՄơc3S?O({Ѵ?xm OMBBRZT3edSC3CZ Sɦ  5__DWW?q_ D"F۱sV{ i@E[Hpd 0N r$ [r4VYZ̍~mm;w͕B.l/1~!(xFut84J\ @(R!#%9̮e.ռlz ~{_n]tY_btBD\4NnHOOљ~#yz YoDg V'V rZ^Nv2h=اqz?KB^(5ۆ!@ :K6-FW8|U2[d>"+sb^b Okjhs 6a i,f ӤTʠQ 1J Rq_LcLu[$u\!B!Ik>Ekg:]`%T-~t1C2 iCP]Jc9[IsyVVXS*2gGu"Q'[`QJ),8k{fD j88jnq 9Rgl1Z,_t0PnIBXP䒓);u\Ɏ"b* PќGJiZ*#%UѼhќi#J=B&4jz\R .hken{*1$2T3rB*1Tع e5;ѯTW7":7khiN#xNeXq4Al- O:O:ز3S^w5"e8c' ?țnDtXlCg%TUb[6ڸW9~Hi|s%mI/J9/^TSjkv+\9NSJ #)Jc' uUSaHqj f%%3$Do޷>#[>E>BPaiJ;BZ=A}&fnSVDfLʆT-bRYF3-Hc:kll20356-` M`'GECSZG:Ng ̅%B)\( @TCKMD{1"Q 6YJD'@{`(B/ ZS $DKX) mr&)k2B$6VǰO2x&>*$- 5" ڬ6_~3SiY8Q $}z7єw&(mZRJf09@/ښh5mZȘ}McO!rRB??yEA69H$?xh$fEIjhyL'g=VnI)ffCR{|xRā|TL9.hD활_ۈU]tv2) ("3 ӛKtZG O.]6&==Aw(RǹՈ8Ҿ}Gvd^s97oetn:$k]wsS?nۚq!d=mq=;_ O۫S{G-nZ=7 @) lّC{G#IR'P_V˭s4隰z\]0VbǖwԾw~-O,%{L3 ,)KA ?n$n~˭w~&A'6EtRBҜ͏m2cIgK&^Bυ3X|{ӷO%DsͶ1 VhQ͘TvTDK e. z XV!)5&ѩD[O<"t-ET#Pjo1Ki;$KoRl)U\ښQN"8NuHMosC!mHiKjk].Iӑ*Qmo%î=TSkS0udFRoSp&zMQK1 ) )-(e"z Þt%Tbgh2hq )5P"qaS;כɩn# (~MI> 5/}=grT?5CyohHBܛ|o_Xy oDDQȯjy .iW$wM'?0p^c`dWcQibig #\Z4nho v[<\Y25S澻y7 5kvep1B1#_A@Ep(E` n"tr8ROJ~?R>dVZ 4S#k\ױಈR$riY]KT*-68 ֯$s*H\g(Lgͭ@u(+d$ T  gn>I*UKH9rZ{梷8&J+) -v,:^3uMV[3KKտlf! 3k6Zs.{L77StHq/H ]WhVM:yXu}߯6Z%k]e),))A>DB1,5`-0rD4( ^&X1r^Z8\IЦ 8b#K:pP˒z/Z#ӤVi+`pHF;]VB/"GBX9xGIum&Tm[jo,PSD˜VjdxM`lعcЊU`ԒRdDHHFi d IDATH`2 +1 ɔ!9M8 &3}u)tV|N8fBTwl7`P,huvPihJnҋk\7 N2s&,L;)uL;r%E +Z%9i695139DWD[fFH{OD|X*1v>!`SRhS+P-QxزC,suceT|W Do82]~0@@F >_>sRZh$tǗՁCֈ:,w[5wGۻA)e5[+_U&4z|'~d0άnsCfFd 0`H9,CPhT)l),PG.W@' ɯht9~Da7Dc -zوD1DA`]1q. sL:G_tnNK )xͤ=>eK%lB0x޲omUxUMUaDx[%[VZCJ~Wӟ-Z!r-J~r?\.BYOQ&0o>Fl!gY,,DbGPM^,%+W6:}m7;$(~~_:YcICABhLk1Jٵyt] hM jbj5!H zCr CFVy\` H}%+; sxW-@$B \gpJZHs8 0REn@ W::`e-c,4N)+@WMbҩSЭ 4-j6]"* ܁~tI MO )Qu[3А[-jV]4 ":wq|͙>fqloa(%ɳ1Zڵz, r1_lCB`ZKIY-&dsV?'fM=jM&@NrޗzL29@F (Gc T`|3 2^VZh=IB5iGE  ܘ 9d&6&lyިP(ZpT>Rt%(!l K,Em"Z 61 !ƅ9E"aowlGo.^l&ˍM*d~L6*46&g{y[+7$4Wֶ԰(`84*+8OL5~]!\FIVf[.HhMf5Z Gehed` yMgq͖̮$kQqC^%o([꒯%@h#USA'82pR/b\$F ),&DC:%(5=  3U8X5@5EU =E4O\L}˿?#*מ؀&ěpL.DH++!Oogڒ IjZ JyH 8h RMZȨhĚ\sR @8Y:]J`u ut2e~%UXifzsj:,oR&]tDQƯia5$x)+S8X0I]ڹ.ղ뽈>L$^-j{s;>{g3,i$[$ 4`tGju=}?QFFj{gwϟz`Ԗ1s-'z@-97Ds.D~vznuJ?6f*ه>p|* =JM+(5{PCs'>T: =-K}ŎUu]짭h4(g6cR,)M&3]%}r{pA=:?<\>g>{܋mIabazOZ~rzM+\Nآg~ݑ-;ZRIw2ݤ [`(m'һS[=,_8^zzγy(3RTRXh@%rUt mszˣ?[ẓdVB% V "!LHtўQ) >'z}t- ??q:3PB !MśiMW-۞4s#b-ã/|g{ v<_w4M' ujћ)5c=A{3װ_Dzcɱ_xl ﵘc*FmjTe2S/UQ8Xg˵{m偉DddOD# 5FUONeSM<%ǶGmS'ܛ3~&z{Y- we|%N ϝnpGzGS=wwzwSh,sa:EJm$FmQ^qRjѕ&o;;_&[Nm#+ 0 jP(Qr3󹚨\1{J 2coxfc%n۟zwrtx .. qiJf4HekI2Om]ZyRKٗǁk5'+V~^^s mzD̬w}?|nO_r^*Aн> Ӳݛ;!UՕӭN: #r8y$"NZۆqڿNF;8M<K[_QRkĀF lɦ_klH~c/_m¶~VyBj48ޞ=Kk׫>SKE.f!"|}|/C&m/ɇ<4(*ٽ[OlHMܴ%w7nuӇ ҽ=Onu_KMnt?nRm@{\eDN+ӽYaxtdl=:CsMorhƲ;SuF [[['{]7?.X׻_Oe~vwo|6|geo=ݳ#g}y:5SgLNG` |\I1J;wC@o{Οv^ty'_Wz>౞ѭvw0BI,jCWj)ݾķ8[^o';;|盒f߽ؖλCY+[  ƐwenR)`o.޻u0 "ԏz][v{p-˾};l`oou4=S#\IPAޡ}?ܲˮIp}?<~{'MP\r S%[Fo%::f,ޘ΃[@,RsS8&Q}lolGMo D>7}˗kary&/Z`÷m7̠-tqw,eS㘮e[Hܝ}w\&H'dOBCI+ږھ7097$}]=VϷ;іSav[߲>2S\S0´`44'P4ěS8VN:kVxjD$${̏~&pn}kgz-D.wΛ~l2ўv?˱ᩑ.&&܇ &p ~x5" ~u={Mx |Nvw瞾{%>ہ@թTdzl%8OGn}_}`Grx)+Kc>I]k۷/ۡv}7}чoڔН:_Пے^uۺmݶkHN|Mo̹Z!/%2JAFB;zk׳ ܥmč]Qp#yVr @P/{S 8)h)3*@MT k!4B\P[(r=Ԟ⩰eF[ǻV_sdltERq|D+(qVZE.lFQ*ЄM%ZHB )˥)DJ4{lp0/SO?ΞTfh k}ufZX(*Oz|ǹ;\6v1D~]+-B);c:RJZ`4)cS*`6\W*z~ݙ]eWTE_- D@؋I"Յ![m%`0mEVEMR =TwZ$KT_QQ#2hky&٘g5,O}-XHTvک,Eʭrt(o܅.PIŌҎBJ J:R+(L,סRKPR/Pix ݈Gl# yl|ÏsJ2>Y2}~R{-# mYw?ĭ.]lV[Jp$AHIu0g3uAWHzpDr w]S676e=S3V%i@ڦXHee>8k2^i;}`#%d %jl.Z &JYZ ’tBpSPp!ceֳܦ06btC 11wƷ%˜Q pƵ宐Z/1\ E<ӷ+D~ I. r')+)vwz|&Sy^X6NGJYɽ}rb8gP=j"X\k.fsm*A&n8 (p/м-,Nmb@(V7Hb1 x=m h@0.[, 9x6tƲR;3]򖋦T'm6|dy%GؾUj\ q!Y6h%n|8S?܎d@@9Q*J+h5#J؈?䕬W$$H"R85AVI 4]@jW*E[AĴ^OxSXOxt[A+lM6WT+%"V)"b,O @%Tfj6SRpJimDxE6`1g5Л=i<}MA9V X9v5j7r㈇1f )J&355q~gN-_X>e/eTԀn90,! !yuԟxnov_ħkS ?z~`L5d^ȌuƠLZb)X >˅~ hX0K,\>f/hkjDd [M]p$ze LDbiMhZ@塪]3SF [ug1RIMR5y\ljDE׉v`m*6}#uVHE?e8-g?~uC@&iEnl@p>3er.]U LġY}rsʕ+l.]7s#H/plxʗ}޲](%{'P_kyxf!/-.NR9w-Ӊle~K/[)+﷍wJ?~Pk~(n ܽNȕ Oz;kNOi~Gڔ{gF|%S/^L~JN ]'PS_ m;{'kׅTRʶ@iN$38/ڡVx,!z\oYWJߑO=.T, /r61Vl5E-&džOΰ@U-Rlحsfrk'F6DId}o}}>lRNtqgV_-ϝnp'?|qn6ԞT7 1^iO3M?{omuw~{3yyPUIu5ؖml˖1v` Y Nҝ4!ݦYC4&ȶeْT%zL{_q޳ U ުNϞշO wuIGί<]j{DžopξDP"\/ F7UcϽuy|7yB>vGw&<RMt+କq];^Z'4%>×;msƮ~{?j,FK$=[ 00dJqޘ-rҞL+?lO\v}_{'k5},|D 5X.$ ʎdF=k$ا~{_XxRGa(1`kUXGu]Jࡗ{ ,8N{c{3OL6M^I???ɫ[>'rcCer})^ B,-u͋_j]h}ݟSnϧóKZH ~'z=}jS;~ۿۛ=d%F_HgۄdlcG_ IDATMr# =FN 2X4"/golٯ*kX/ڷ$Җ)}1BAƷQԘ/J9k<3ӽ{'QUp8ZrJ,[i=ۛeup^Z  k$'z$}R{doL'O9}/ {=)[!ܸs"~1>m.Yĕ\"냏 ;V-)ZA\36 {kWi^..G|WBȚ"ݩw>5>dWIr_&!nH' '-OSpxn1wBA -'csT ia\u'RLwn紵Z@ /IiẝG[*K˕/OEOM~eg+|Dh0uz^DJj"gvLê4aE$ҷ ;&WpbiBTRQ^R絤Oиc8}4 UX҉\į &k%)Vfr:Np?ظnHo-뷭:H)x+ZU@Ts#XL.R!:Ȳ,lM՜wuߨ}Uڅ<1ҎƂFhKf! g-\)mv8>nٺ>Bn;k}Nec%çF@S#M22m#s9@Wi=z}ltOx76O2vWַ`_axiiwYZ CPU 9*ZK/sjli{^蛾{-(;9N!qRNjVl2vњO>/R=҅^f& ~N@ndG}5l\U `t8>WU0O>s\@/^L^M?veȉxh|b;?[jI}6pV[\tPjڻג5xu{ @@wN8% @sB,I; O%ad!]R;0 CHS9P Ow dxxNQHv{3}fU]p PT;)6:7dimni{T57uopc2(Mق8)fqvޥTIqtKl.=s4g{.\iviNgߵf'APCWc|b"6o Ϊ!jo8>kSH:\p-VDCxyoPðo\rܦBWd+VPt}vE+"2[;KNӽ:2@mێhW1a''jo.^@ͥC6҈$۔(Eӵڞ,Ȅj-ҹllb%P2`6Uk,xbJR+F6BS{QCsGD~=f_[unQk"RqDQ}CC6&֝E(@m=Gh(JET\LjS^͇j3_j52W #a_^orjSV/fY# ₒp'ntfK2&H}kSV?@{ݽ7مR"Gc=4%ȅ!9|-[*ʅ 4n<ȂDZDS!"laWA'&$ Fjl9,uA6v5ǻK@/;oK%3}f[iYX7U|g_EV}%gێͺ GS_ͧӧOdrNF@& #\dϥZ|y^b_"?E.q_DDbK+Ş>16,:IyayDXaG}d>s7T-7M;=sjLlAG3=ʚCalL\v}z1YYBB ['YQ k[a $Yc92Fe,$YS1Do:oMG{z轗{{~‚U!dŘ#{NLkD^\Rd̀b҈oMI>]2䍒ю\vf,jlú jxmZYD8*'eR>L_y-5BR8B2s..` j3vhxSV [om ĐFr 1Y[F&mw,&"v0j 1K0]VYF6u_69'B}_S~ʞ!HedibI2IZAw3m>3x)rv`ghyv$v;);Ji ټyccgWSO}|u=\mPjr*,V=j JË{}nѧϫ7ᡖp\<3,IGt9z\E>}*֣6,k((Ȃ D@1h Kw /oLi [xnN{d]YBʐ|(h\  ۴I DXmO7euOJ̇ >5j6]^w[#Ecr6= Slky4ZoV n'vnd}הRHgT~Z^@ێ|^qz%c!uF%UL"dc  W]vGOuwu5ϰM\|%[^BeJbdimh8@jq,IVb-K5DKLpJm[JV5+Hܕk WE}$%r{R"x@ -`!E0Ԣ9 GNIHqO_KȌ ġU%l#{5wsWmC7>>s̿^WۦL׷ȼ 8ۼ݆nnv 7hyn56_5*ABmZF+a-+VPxh_ny rW  fRMwx䆜B\9:gsH? Z #a$JB"X]v6=L۳sy>}^ݬ*[{o9Q>P)"Km $T倓5%pT`V&AXrY4چ#.w\IãͺwueX;MBOrIiN?'HΑuq\7_\=8&bDYYRZ,KKw~Lvb#?iCpˢ< L zOr`־gLP4m7xtfOUˉ*[)PAg,EzckI_RcR},#A*=Tp8q!9tEPH ir/?yJ/94Z-މ&NP[F"s$؊47u{?ر*Yp we1,oVhl#!ZOP"TA|J/əH22Wr>baJA#2v]]G3Rbz;xz)u D>zKG -`z% 4{½ןPԒ=ssqʣ# pu9 6" 2Q $cȹ:*__A #E2] /W*_,/<75D^!HZFS$0lM6v~S} [}=WS]` 8e3G[}:@~ "$J-4 Hbx/햵F/$gW2}f:M@W.w.?,0㣟}NwL-w92jՆ`V&`$9 KJdWDn%ZšQQ%DJ i0Tbm]RFS#y4܊;vdVx)X)b`7hipy$bd7)Vljy͑8.v;e&aSym7LoS+Z>PTOrծ.FBԉ=4E"M.؁AO_^J9lIE;ɂlE诖]Q)Ec!n ˎn󱔋ڕgV4B(77HK@M܈.+N 9^S)QjD"0v9M Y0 a_Kr83QMdFF\sn7qИJY\ʷQ 4"1!DytyElsE#p'/rv`C-ǢY`J/] X%%̮? NX/\ECP \6NCZ6O i`P8XI$s+`SP˖MllIx:K{ƿ\^J*+D v9"jBdbj ǡ߷GʶWYgo>?s7B0% ?R#^={:ONm^,HX\Ka٦ϔ#;pf=A$ZY,sIfCI̡mh^oGv;Sϝ7Ο<51\!7?4(xZn^@(0C[F q^³gwvO_\ӧnfed}g *Al %1"hHN%<+[.!\kkEŊĈ.2؍B?Qw<2'.0AZ ߃/,l(>;$&BТTIDex]p҃JqEM6VP9c >I#>X@Pe%̰*AF]K ͽCutN:RDAO|2_Pwl޹~b8f%%>Z>9EB0 p# IDAT kgU/ heu?w Ӈp䢐J/])!Z.^)4,ٸ`aW=:~Jb!RH EpC):R$;6mXUW&4 ,H <ܔ71ݦB^˩/ @ͮ kec%* Ǎ؁7"be!L,--BaEuve]@ɶ \ nZAvV~MtO+-"ol:6S HU! ܎6UoWO­ȟ=I7~'"j6-,z"c{{"xS_DSO\*^*F2J HR#H+lϓ ;0Gӧs)Vyr&v68|֖<_OƸ2Ÿb ւ6>ssx]J?"O>+*.wA*7^ W (7"vWY(9 h@CHV J)blrQ;u[j6Pdm-)Iz9a H0R+WJ̡#gzio";M1ؓ:Tq- R(&Hlbߠ'DVCIΟ<%w^yDNGqb*(ALm.FD5}G#D7b~E)!J󲝏2rd|:_,1X?ގ<ݺYĂQA][c{m@>)א/(x-UBOy ,aFW}R#7oo(pg͕r|hҲ(%LM׬# KTAr3G֏.Q-ٳeBFWbClg)á\%c'Ċ aoz7k7 <o׊0$'lJ˚rp/,:vσbWUhy<4pR+9S4[I |O  "v@mUͼv4^ + 'qbٲ+&koN(R \ Md} Yp6U{v8/Lm6|%?o%~Lۭps91%oc¹&b櫩n:-u˦6Us ^/T37ZR.)Ɏ C%V /#ҳUvۯoؿ|bL/vkъ4//ˏFO٘s>}:06۝$pl_ #kYHeKZC8#?6/#PFxDE604҂7S ⵧG_ɇT؈%d."K}iX%WNN{u scR"# {gBbm[FzjRP%t匁!#45N rG.y98*r#s!yA$I-guqa᛻=0h~^V w#Ǿ#y}nx}zQ m86ю+ք48Q.GL0- 60$fك0![, c`;8%њ)S~igeCWs\'hRjRM4kd%Ѱu~d .x%֜Zy 8~eWqfl :U׊s! b?Ҁ[vpɱys$n^$@RhT #r呶RG4=:m\7?shbmK\DvFΛ'U6 @DW0ດq)D೵F7hG @̨c}v%cDBw-wRopt<(Y:{AkAcs< vHK_϶UĎk^^R"l"CeqPI̬%_!VdF.dR `u/{2`mY6m@X"HCh[B `iF`]!I0BD3>g$+Edp%Ci[#svLS/K,_,H?!Rz>2=;F܎e3z`%u^nAdHCămkW+FY^{ !/aBybNO$byJՊ4tE۱H|~ *u%bg$莯@$PrY1 g TiDAFuY9}ZY e ymDjH$S!Dxxi*Ip _KTNɳDlWIT'T$ܾ{*{"tH?ZVeV_8>l3q[X!'J$PEJlIK`nH9L̼M~'XokzГ+К-H( ^hSK:qDbqׯȗ 723RFùDP Wf TkSS9A?OߚzuWG~w튺/6Us;tůO.m^ ,g/W'.oE&خ^Hʮ\o 93dknh_nY9 *jt^z kVt]Hs섹G>}n=Ɏ7 =@_HӧϮ%"@],uU٢sc"gX4-nkh EhWu&EݿUȓצj"c}X!̚ lp3uSCr=JyZ!({ҵr6)춳," #muHCp$]2h-+u$3o@kzk5k儘VF0.vU9p)г wE3[sUdKȜyzojG @$1R.JG:L@CZ lm;6*YbaȵaF0BH.0qrgkyHtF` ̥YGʎASpÝ*{s(Bg1WSa?R*u~uۻ^.ᱨ88se$Ksk"r`/:'"-8[~?ߪGD}vM{!d Ȣ% FsI x5uc55d^{{y`bMѦ($p!":BR#/%s;<{'<q q`=b1–R/H01ȉi(e:]RNa{Q39@WRX{ڶs>xWNrOc# 5ЀW!%TBz@KO5e\{JE(lK')(D**i!N([aD`YBv$P Hy{č*& l}`y_aЂɻ+JUK!@{yo0<8JF9ĕy-€F )=ac kZWզj%أ_bҖ < [96̫eL`#dF"o `>uЕ1Hfgl>@u$7591оu}7$q5줂l A0Ǵ] L6=`!-HldBB0$3r!(lgCRˉCNf_4LC-)ELkRe Q0Іk9'e(? f6aluwO/9;<TF/QAsH0Ǧ Y"mbRצjEbfk ]8YE-w7-~=ig̓,s/Mώ!0<.@rP]qT%L(XJ,5,bUWYKXҶ-(K0Z#R&0ֻs~vs`Ty{s9-?WǓ#6S#W!}ZJLKBV",V((cnYr(ŦXyya?bSgݠ;iG 9L7e% ߦjʔ)i|$ TH~hf$O20,]ͨzk|{ovBqY,')q`KR^ڌWX.Ι#cfD7ǎykTm-(+1?'QVӳsq|mL+<֌I/pQ Wְpiw >`,ԓ1QOf]ͼV?fwķf%/7d//^x쬼˶DO)g1z+;~NkMCkTkZ9۾̹<=6Z jN [nVֈ:$Pw-jwpL!hM+]À'pٟMmU+$R4sn^Q5V :* H"oʮr %:VE9<=3qrVn7؆*pr +ǂ>&i7Qu\:YiND,5tT\Ta\6 Y x~ջ6z}DZOA&X5QAĀPsp\Gƌ=uEo ?mD 7}P=$VzL~9>BNC:?f$YXgq.|]OxoxǑor*ˠ5R@A)J=<a iP+;}w|{点Yz*L2_)"ץ®ʏ ӌ)S&23`_\%+,,@S(1~eaow & 嵉 Nta؛Hbp?|u}]-YOe\ 5Q 2-5W#'wdL}}1g:cY3 L`.vdI&쁉.lWW$5OPP@d ^&ņ?W`(]=NqܓY>7Dt`2[ BBjsumv IKp ꐪLPf5d&^ȬhݿaDuvLBhmcǂA 5c05 ( ܛޠy)R֎OmPÍp G J_=BHrw#ylpn^ZO$֙ 0( ge(1@&@y5HGDm-15 f"v@ !4Jg^7 {_'YFf)+X aЅ:B'/a? A=g7 L!W4@ ajV1:yc>=w? kfHf`dй&D"A:cJ2׎lW"2"lEnSڲ/on``[I'EbS^9k`;y349Mv[ ?:?3m`Mkx~/$[>p{)OM3 (| ]ξ2Gwb|XFM($\AGmc:}4^} @ԴfKBRĕ##:kR|ŮNnIVlrM٥.%l6+(Rr߰LW۰~v1. Xs ƱMV 0k 3[v-Cځ@ObTkL:!QM@GY0#hEsޑ$ wӖEo~a 5/DLk{¡|w "~C8ZX.< rsbg4_1ea^HvI!o1ƚimk\l@SL,?\xAB*7,PNm+8(XHaہnW&In6b e5ǣ)>4NގX ]̟=l|8 !D3Ax8ə#,ci2hrY-UEpk&|ۍbV2  kw>*EԬtOf2H0{sYr?Poɜ拢(#LzQJ85oWʵԥޠm4>:u]2t!@?B>K@T !3oŤXwˎ ; P5 EuM޾+O_\]ݩzK!BdQ5LH0eʢp- ϰpMAD/8%s .Wڝ٥hn1141%Fj*s}A4&rjyUG=hb25P 2r5춆9<ykgPrs?"]\vi"/^^ByEOIx洦j·!"k\>K5;0Aʹ7x{UWP 33}kcj1"  9!jP*HNR-~6J|Ont%O-g/^tLCoxNpThBZa4[^뗽L*V U"/S~ǻ4Q:^b>.I樢tJzLT]8œ bni=o-.ә#@QMZm;Ǟ~2m}b:fr"$:/FO{H9[)QKVlpM/y| II4ȩ4(T 3k{pC.ǖhb筰0cATR[PBL^zuX =szK>}|g.}"- g/^8c|=O{'FL+cyi Y+bDǡuwF!mM;x5?Mobs{& [785haDQ aaGr0/jy}ő֛go:h@84ASL}qhB@`7kC̴G)S}UeIdzɥaE3zHy)sgE|e36$g/^佰sNΘgyʫiڷKccC1DxU 1S?>oɚ#O?ϭI!$07Sܨ[1akq-҇|_~|bon\Da[ZfɵT|$JO:)S|m]zWd3cPؑUKZI|(4+ SL9T,?\zk(#CBb羀I=A|0tq'rgJcp|m8\OjWt!'7z,BP:_i/4k=0Ѯ؆ Pm0 a HpLqo G) < Oi%X.A1Qn<Ќ}GU9Ƒ6 ݡm f%AjMaՂ8PcJ(DŽٕ)lT DIG<*Ґu(k.3v[d}Lš"vtdeN,'+ N]=^g/^0ggfVRp)`[w,5UWxl8U-?7 ڴm| TDK&2Q ,\ΜO"rs"ۅJ/=#Zp_0,fC#IXH͎6rٕVfnѬSObΚ)M5Ll?LP {n4b1Y; &P YNRE \E9|]v{RP[IΆ2Vhm `Hb! JNjsBkDU5j/6PVG&f1&Ս6rR _H߷?R d|ًu9_#kV;nnv,N;o_>Ѧ)_j㰰r]xh=c*ʎ$K@`It3!j챈C޿#qt؏PPrc;ҧ? t$3/;u⅃9eʔۣx-i-CAHZY|η`??`0-m=eʔH}ҝt͢t(3ý 7#.Uρ,E|?gk1Vnsh+j(ʠ'bb @ F@㻀_Ga~ϧCQ} K:܉B'دT \i ;4˄֮+/W^z앦0a7L(hx$ ؇C:I#E) A]HTMYa8&4G~'r$DI+i2 a˞B3 Ůx>=Rw|y[UzYBЮ4JCqW4'E"V{|P0@șƄ@Fn;`어_~q_'Ks2}~^\E\ 4 `6+ 1_rˎ|{zS \#8,I9#;hWO~An ** 4bj/3+w~"l-AF0`1gV.$3 j3^Qj{wY[<kah4!SPMXmc[wzO|}/| |x]D2GK1Jp׳I@)@drK S.jE \#>BuוnP5\%|Ҿ"N>hLrf]*I.aR $ ha(t1|hf$O20 &({T D6sSN(dqIӔo#]09AM T*Cּ!njQ? t`m#J--d %|-2>TqHPf0[Jj#j&D`f1VcIϟ ܡ,lɑƁK:H+lrc/zΤjw5FG1w> `X8<+!]d/krwnDb0Dt5s1fd bF׆(Yﵭ IhPEI@ȢhP?WmhR.@;D躹$as ;'uz+Q+[y4+FgֲPYk+0-Gc]T~N HDܮјD6-!1_5bn4f% C9Ԡ0nloα>?]"Z 쓦ZɄ7DFo]}@Å-8aϐkvÂm2 ׳b+Є?9K"ieCSuCvטg$dډdϔ 6Prumc7G N}^ʕl*pm}!9.^' $Y bI5RO|u?MH ;g/^XS I;ʽ˔Ch4}H_VW&gUcpxQ(RbI2e\qaGlB2O&dqRX+bFv">ft6_ōif)Riܹ<E_I8`\qBQ&{ݵv]S/ӌ)SF9J1y*ֹo?];SS EXG鬞Gٜrh uD5 ǒZiz$NaMƐÔ ~hz'R[jkȵQ7e{3sUv% amRqߣ ;^bYE*f# ©`"ɜ>olQVg16H<+J+FV5]ATㅮ:ŃϺ܂JH< ! yP+PV5T9{(B5hxJ Y:zun\ #b3|5ƾl)wfJ똤UN-W\(Wt/+fP""]d]ɡY-]-;C+ӲVښ#[X5 ql d^:if^vzǍa˚(%[a8@nF0&W7aXgͭ$"z·;KJxѠ`a!}ckʐ"(8{UX6;kؾֺJ!,;@08v| Ӝ\8DU7~ZquyLpnjhskUד™!m I7q_qKhPBn=Lj1Yi2 =J?R8?O|r"}HD@yܙ{ߟr9^o~d7jlѪX=vOv@[F y6ya?bsbJ;{?׬՟|o{wr.;:j_8ISL9@xj=g=[ҧaGg'lٗ:xYnul}JRis  "%^)S"Wh[ ̰ ,C-$_IS.)S{BRD^kkkM @Z>C<tzї8B*0 >ALJ"Ӳ|bSڗʽvwfk6B@ifn:V-){OnBQ& i6^^@QHb L`bMD;7jջC^{Zp,XC9%(4wQ7Y?מ }o_0$'c'R30ug×P;g8Lmmn e%'@׆̥%fBEV :ڿNג-1e*7"!Ɠ*oFjuྟc/?|Wm e17odZJdvfέ5ħ߭5]{KIZ)(3## UI̦勮>d(_ |B-7yFl+M+,`H-q!~Y*^r@=xsaWC# ܥuX~aF8VP]u[z G?fpjmG>|Y~ y'|y~Oz޲!eGc+ 4݊&M }uzWzVVNm I7E6ɱqRlwP)v,:#U/TP򰏣~|eZKj]ᄌB1VQD"}e*1f Wi2egG,Q- FXdB2e"rq[M˙f$O20rkF4,ҙ!JQh>,=73 k]7Є%1 hT0X80retq!T !@edXaYH;5o,C`boPs %Nc/ ,Y0i*a2H\ʷv<3() x̣81 >V@ø@+mnl~zsq5Ę0Q~-cÀ1ĂЯB3gGʄKQA)ܗkf>YѨ$ÀK doNj՘{:Wv*$*(dRAd)YK |ikʥy{aY ?"+@-j,:J< R4~y͛PE\0iDZ2xZ~4/XΟ{??{ \eIU\\dr&Vu`+e fAAVFMkA 8-$VvQPB+ZljͲ7~\u69R΢C׈aa?BxH %f9h]9sGc8qvf'Z Y@Ubh)܎(5zdƾvk,$ '屇YlZH m)zK73jӿp"^_X|p7\aܙ xW ?~kncgpt;hyhЗؔȔpqs2 3/xl4X0Sv꺑z LisLQ31~E)SRf/9 1D&"T_kBJ\4egQH91`X.Y78b5P&z Qf&'o{Y`N:cememk~ѸM ת $PV vvh ?~N?'g|3Į2t9.@+K;$ n6F,SE>cwec9l B& ڳFULj ;5Az[0O)E/xً>vv8_?/? 7`i{'W j8PɔBtL"%Kh |F#4=qN3_|:o83N8T"sUIW)߈aeD(JUH<,{>cAbNAS_rJG nth ieP06eʔh OmK t-0 3CnV'O[lqf8dكI ݄shWJKcaEֲM2lv=GEQ,( dƺ[d0JH) XC+br& ,oKTZ{}`DY4LU$K9= Sj@JFr,a.:[JbICR3@mͺ }k+%k3]Rғ͂Dylxd጗A{t:z+c,-:WvEFP#kx鮣\*4xvztOw~ߏ}-~KHǏD6^pzxMgy{Ŭ4Ev`1I,JrBy-PbB@K(p#1 ~&VuL]v+uԶe)#S_(Ll)KuвSTS1pnF951}Tjm?gs ͙k_~y)7 #-%S.]/4ȭ #ZlPfxƉ_]~85t鲡8m;BgC4p<4-|&թl閛:i,t')n<=H,b*uٮ9CS|U! 쭞9u4'ۺ"A XZk9pEOo N.y] LM{emqL ! +"d6Q޷6mܩ}S%Fo.\u4xKal?kT@+љ{w]N?hPid1BJ|-xϬE+h]4.]l4NzrЉV/Ƌ>s3-t6RtLn$uuPY(viQ4nUM|jA >p2 lw!&8V+% Maő8fRʟy軥Jૺ1*66I\C'GǴ `oQÉUȣ֎|]rT!Rl!y.e8oVyztkjIL2PnnB$^&l4[ [L[*&$J0d&-@–LjmGiGYF 7hfmfb!΢ zuN3=Z fDҦ6dІl .łҜs `EhY2'B4f `4C)չH yJkسt떰ƁGI)k7 ұdʷ!3c2(,CsqNՋD5zRu*&8 ! A:)ם37;ZZmOJ),@ e;F)oBt0o[=a>mY^%Ϟ]gy{[V}SNA߆Hm-!Ki0̛GzP5<E&ػzlV*.*~loj|fhOkO b N 0K˞3uRTX@ޏ6}Eu y(7aI*4i#f :tbݽ.]9ˆM &O=X ~M5p_TJpY̶gZU}OoezR ~}=l|߇ky>5YVu5V1w: 2CccGol?qdٱV︻Co#AJ(T˱e&6;µ,%=A}z>8W7o_$ 8YI xd R) i< J&˓x9R^Y/v|?هn#q]9V2B…dcKgVǖщ\;L>ΥO=G|WF$5I$ dc/PBf*wqw^_pW#=>2J  ?%C{jQFJH6 (w^5/~~p8uO==zm0o*|٦p ǿPKA;&Z‹H҆ L8&v7}r{=%=#>? B-xzSC\:pZpe BPa/ | ~;3?K;;1퐇:t}%\^V%+[>R)Ls̴Ҥg?lo =~q&u TD9Rq?\4f_0{]u[Yy='&Qß/-8/SȏSrX]%k2^;>ÃJMw^_~߱0 ?~fF= _oS{}ȑ~R;^?~ іK  !ġ5s~ֻ7h=]ُ]o_eոz{BOgOmK򛜾ʉrdʺ>9򥩧gQN$#liExjT,_ۖf֓]YW֕}lwNN'q/h$2Y.x'c=nꗿe6V.]6 D"?>oϞ=O:&]}AC]=+;yՍ7d%Ws~ӕ+DG#k׍L B;8p6M^_Y.o;CCѨ_xFo/WY*tرVHGoʻ b m)@f㎠r;n 3][Ovkl.;;oNnXveG^* $[ڴ=1ͽj˫^^dJq7}..̍W=8Ɛ&2BadrpTp _|eo]k;^{n-dj=iP $YDp~NkK%4|jDP._L /O/{ֵld}:yjs@ey%$!}~y6سkXp ;o⻮~Wi'V~RnTB ʣR(_vj#o5|o;z蛿_Mf[wY8??}*ٴ酒S^k˓r IDATttN/?m/k?Ckzy-÷7R`Szd£MNvW1 y!=j,Iw'2Wte?^~}Evu:yKG^'WTSL'@~)yVG|ZA6\?ޑF߻N:j׉Jv<Ӈvڶ4{ד~s<m~?L]՟l{g6^yU_M&-[yB7>xoDY[kV]YW֕lzt;S._/ 9HڂX!Zr&ݗ?3w֜#K f7kFgGqGNJƲaC0|ȭ[CVziC%u9;8=cJ:oI2ñ?\mp2sB7p=[C۳kz[J@jS3#T JIO)?\S}}Q8hf >@|-١)ljbA n|y? , !!դ3(wi]]L8T(? [d`3+y/-_$԰Fu%P|o )k(}P?^wk~П|%H.x39zT7Tuz+ Ruq̕ a,Pld\ptrFLwnvy ֶ3$ԑ-m&_OQp2 Nc$NҀ Li'˗ =g(l|۹[sCD͖.4~UWloQԗߞNs&weS '=Xf4P'aYJrZ\k.]2]gYsrGgT(R8\; C@d>T'3f\Guݹݖ:\JȒ@ݖ. 9o Zdžuz|hCZ5'Tn 8Iɨl{aP(PMmĦXj3mQ7UlBzZtv!T;p I¶=+Zb6,gL123[jZ2d}#sJ!a)T(mBh|EGg3UϩjStE<.7 Cc%{cQwr*et^|cWiWg_7`U83#W!٬!"Y v8phr^ʜbiL-P^!k1"Ș5b#Iu[gM}ΫU' <ΩmdRN"j2WH=Glc+|3Y/,= ?3:J59I܂.d)d҆0x"ߊ}S;_5o' \\u?/4𯳷pu0sz??#M~Лo:"1Ђ+ya3n1ض棙>)%%<:.J]ŸW< =Ki[GͲ!X!Y/J,LMHsǝLl˘{VwWХ؏N>2kY5oյfbQAdm鋅|Imk n 'K.%2O[! C -\>,F])ݛ٥E̝.馛_ϲcR3.|p{*I%fF=^OSYtWTy`ǥ,+_6aܠMV76ِt8RNu/S:ON5nZMV"КIX#$lώ{LO$r?ۋKŎs7{.n>d_޻<_3bmXX9Rɉ7\y#onxh=dӋV=5e| ;/ťDe"kq|).+]vdGqGP__+;M9zUG m˥TV=n)W9u5Hijsn\+wqwb<ߞz]{l1zQNj/ Iabm 0j{jnڞCovO8u{|R;¤[gyG^6pJ tșj`*n{/M]Tşl\6XT?$ZRWY[+"EZ+5I}xn\Нw,z>".m:/%5qb1Kd\ smK[_XP?z|<`E8מHB%fÉx}GGm>r.^H~ɯ=M*޳{bjI ^*ʨUp/fxƮ=׾K_:?p{{ _ ;1=(-a4J)ΊBO7LC+WTw}FbN{/\]5lM-ƀB*O=o"58ywS|7}^:9cM }RE&*mG=#[`odi,F/}  '| ,:#kL*Vhs7}ޚ:<$\hPݗh/GY.[{?{R^4ݧMLf[vӮ^ĻF0i(>W t1`6g_hE[=yt Ku'z =Sy|1ZF2-s]Ჶ2wH-Y'ܿi~sgYyJZm^z\%ZSvO fJ4bL= )i"B iц,It2,\n]ϭ^ƭA_X`4hٳktġD;n{89EW&i.r^  $کG]_6Z(=`;~;w=}ԕ[pI@,4wV/&ʸ5'<<>gnq{K8of-ZH5OpX<14_/;u8#utMyS- 1 4v*ys<=Ip[Xwr.]e~C۳w<>t Zimѩ~uwg͙=5G.]./~}w^),}A-:4p9C{[kFbt鲑X-P߿)iX\ϴLgȕfESDˣYÓ2,zѢsk#o [/'% GR,sj7$۝İBX`!(! e"Too4<ʟ/7P\Q JzOdf*tꮅDjP@@smYIWrxu&2r@DZ!ljƪes( Ye%r Bb@#D AJ1(Q*6\[9:hmNDD6 ^A; TnKÞWPp#@=ӭWd.$\!*\[:-6rv[j$!jV`eZlmMR-Ae[±|4Hbi(jKy9>^OtVHc51&;^rX@ s )Y(h}S/~('=_5>cawN䔍Q+KI!`y<.u"wA78_ lKhh3P`0z@sbA6\UR1i3i+uL.Bg3[cQZRi1F!#D?[ o4'ȊT*"xZ{ Ջ1zF..V(H#0`wF|x.&{?bu caJU"cDY^"!BMO>/ܕԞ/Ԯٔ@6F) c"J%jGqoR:Wk#8ԑlei>۰}a-B @x6b`,ǹU' Wzb.XCir硡 aA԰bzSM)$IfOXֈY\~ls%xa%{`F&Yh`:@;! r*c:e >-A76U8& yEHBSQX&g.-NvM!|o2|BYE.{ ~*z(u$nEr5&Y㖆'Qdxq$S-tsr2 >_[k˺ee(|Q*>VGKF3MdDX cHfFAR=oΏgCl+)=XHRL5d`p3uB";&Sҳi~ĴqsOlEl0R|RlxL} Z|#2B ?IzoRNr^[cУ-e%1"fX.i:28!gjsU<15 aX+a bY9yc=pWSkL~Fy M!@X\ ^8-G=yqm_#ێ{W}i[d*e킚ˆNZoe=}Y X>⨙-ަCd`1RI}ӛ͏St~sFe6P.[ IDAT'tPuB6_[ ? 0|WnꙝǾ<''uLoLqJ)|ZbxxQOq:f(Щ`e]?קOrΘ֢UJa :A3 =fxEF׸FoNkh#pD?Z*ܥK3c|cWiPEK@dh\ƞϳﭱ] tҥY`ѩ:/l23+sS2&%@l%X.g`$ݯuHְk^D<>[[;Ps2fbη@lA:arb y`J1r#͐v9K TU:5Wֵ9d]?ag1SbEt[.0)4S%aN=Եzo~Gl6(BZmR&D,D24]|a]Ew5o*/ue-bX/ZlF09ӃVZ"/8hsB>&)z=D9SBTb iJ ܨեٗ5Mm \r\)R !KYl 9`ɠfưAJc,)X-8 x U$LԾz(Bζp o*%i2rgы 賱b#(A YB Nd@3 EXLM²bKWZ*1ly ӊ#?  c% Ը°>1(wY-PrFeVUU䃞3ç? ؖ@q} ^;o]PB|(c9bӝf'.W٩8UÓ <9^eگs֡~_^۴i.6݊1soMR'&Vs%-m)TJRDjVj4Cab߷ 4򗃓^'9fX/_wںTߪ5f̘Kw~•#- 3~yMG6R~' 'k WkH5/Wؼ<ʌ?:6qqf:ruGp+JS\*L\C(@0͜gF1߳s?;%?a01::ՑV]9&ȟ@T>Ɯ?0~;gޚyu"1m%U YGN{/dL }?x~ל7_9]ǃ05-waapKLiӭ??K.׶1zv+Ɠ-hhپ@ӭi فU0((cPlޚs|ZS҆d6g##е*-Y'<=Xfiy+N-ꕮ "0 2:T"wɵ u;7M An4v)>{PzuꑜWX]m+f˞뎑cmQlaX D2 ݒKj9@ջRkc=#Ñ  CI]@WZW\w?by9bRA sX }*#lvK`K{*23O]e b-%P^nPpO(k؃y~=(8b}B1La[i^7i:0~lI ?!_78zw!XO_^(_799Bw?D;LPqNۧD+T6bXϪ7Όx7x: 9RݾN>Ccƌ}E%-rhX Vaj|B1c2u@N\^^(((k$e}ݓ}7F]J4]ƧNR|4Aq?H~ie-_&#".IV24Xg'7EE}ZUjB '󌹃"IdXz󞩉ğQIEOFCD"bz!yVQsS0غ.%:+z>ՙ ќO(e4~ww݋u@z r" V XЬ@D(H-9vqNLwSLvQ@k@ aL((4xsyGۛ&9\Eu jX?7B P0o10} 3R)kPdp&!\0Gl pmH] 0knޯ-5}lL Tm݀X @>PJ>;{lˆ/omq•yH9Abn&('zH#z dJΘs1I~scWE CV`h{4i02& .6\(% 3Lc2TGQUfn:z/oI tT,KƱFOnI"vT"½w/*2vzs?7>k?a~^c}P{8ʿXv*eb~$ /T)\Z g%Ak\Vά<ƌ9XXZa@tgi5f3fAfW >"`s|(ʱfK'! gQ.0mޞ0/C'`38?L<um#(9Vܡ[5֫U%blVp((PSQבܲᙎmYɓR=&~÷`е?uR-\z:q^Q@]Z8Gl"Q!e֗ra>'}46t n@ @UaB "p!@P2XxbOja`>Dx ^n5n92ho -s34gj=RFG: & }ZLP5(iE=^<*tC2Q%Bjf+C BJgD0Ͱ뀑 Nѕ.~:+z `LyDfdT ?w]:_ d猠VRPI}QSW!eTrl `U+\z5m"xb+Yx5VlpΕb3l.6򕿋k7Ə]ȟ=j,~z^Ev,t=("z.|KxJꝹ 398J0D> lȑ{GИ1f\W?E7fHOSgn=DAp#gKYP7 ^Q@3x8f#r^\!ˮəG(ci̘^yeW w " 0}}(^^ό1cXp'O\paɧ6N^|u٥=5uKK 'wKR^-) : &Ji?-/@Uϻ(8@4l)5cNJ(O [7ˢjZnjZ_-v*W\Α+T9!prGMG7C3MuQtս6 -kyCZRʺ Q ʡTxGQ}a[ګHN0u"^M!`;N~})#gBWcy^:X>Ь- DQF0@ n+Jb پڬXPN@J @ qc|/_@;_@*`Q* [QFDss Q>[k!/!=NTY(p@)[V"c^+ls^ψ_pvwA*xf'~?o}8rCe_}kweX}/nY ?Iv~V4:Z iDRJbg,`ɭH9Voz=~`mڏܹN2zA40[15r{er-y8nNZx[H>{~4=M~7N=HaG(CI!>3f4Qm 3_dNF8 uB Pg\z̘1k{÷_Itno^Ϳpy,".﫼rt^{ ߴB1h]]v92 wϑ;[J%' HC5?Wu5{6\r/zébqGexJJ#lL`JwPk} o8ȫ\lVŠ8c9XO6/:CQe:Ž둜[2ft jCY;(˄VdiMw%Xq?؍2moˮ'WXufnI,ufDy?e=/N1F;*H'6IL3 xƦ̏x<+rJ( +2%HLpF#=D}?|?ҫDN=GF~^@3!=K%*e'Dhb@Z(JKh^!o+58g |uQOa٥;nɓig퐸*] wra%b(ҍ1 P'[_}<+!DD~`<btjd@)sȟ46Z-_7J\5o)ř ${g"cF#\lBFAk2(TJ2#5'e]Gq8zªRJ@ZDo kYd)(}X5~Z'x<9T"$l0蒑Μ53WE% |+mR6cH\ :.~E*~8kjz~s'z~RhpB2ZVfHjK):eχa\lF0\l ϵϼ`yupoW2}.=3j ^ kZW~EcFL#3{݆/RceE}7gT*kڎVDgRom=yX*"lzh, tzF#WaHMױ)~x=0utwPovK4䥫/Mϙڅ}hz/]h5f  cU2H@"!y6={$39"OB|07{*Cۦkk`p3BYsM>4巵8)6M(kl<7"p{`Q:A ekc_[6 h`ib 06aGڒ;ZK :PDAʉ8URFLh#k5Σyv,/=.>~V}gO\|Sl遣4O!0y.ϵb]U0sL3 K\'ICе<Dx;`? )5bJ7ȬW~"AuD8> ko ?jl6R3>JLZn\v ӪU]reA)_v,t-#2R r-ERIoiR`{SՖ]w@zBA$ ̋ǀ `ylD ܜ"u>?$b<>ںp!h2NP8ۓWg} PM_W0Ώ휈O_)t_,Ծ &"('\m 89F 0!iPvh?[;^2f̗ҳKmlzTAm?ێQYظvjHA~]ysNc|}Y{t-t*ˠQ,;}k,:ٺG; _cjb Ƞ M1c()bֿuұұr zt_{Qs83yWS"%k4@5WM5IIR1 W'`\ J + u&:ސO4 +?g-=@@qd{8IsCsUHNeY]0%Ãv(%}N q٤:K0|0" 0D@d CŽ?[z#433iDT/v-u>}럗 ?=sǹY`I >sfn7d~崎Jpֵ <#&^Wf|jJ՛=o|ˌ۰[b W+V !Vqi աx ٝ? /@Śiߵs} =G ,x੫{I蓻cP{8/X| dٓJMX'ȑv(~u`8D0LdSSOmv0\lrۼRTgzma>eN>w"Cj_!H_9zWt8eutwP/vnFdSY^O*MRԽz`Lq1cK.E˹F.[ico^c!y̘1 Zs;*Q>zOؼ2^>p> @hTLaAHe˴f&"[kA .֮P]Q9sC8UIy]+iMFL5 4Q @\l>篹t:q:Tl5ÖR>!a~L2*IES%!o.6x.X{odAȣh~#%䁂xPY)J:%JߔRA @ԀJ4,S @ E1ʇr[纨u@i{O)E</НkIvuԆu8H*`a2_#&,ֲHY=Q˼@\ii]TFU˱ dXfoI1ʮu5PHmis5׵~n_JU@)'H.G$°HW{3].}O]Ts>WU@S9hBXDbWZl|gtq7z|IΟaUPB-;T BΟ{;?mKj48*!ZUd,(dd2< '|z'YF.oF2vf#`XbV1nMi3QB ؉[pqm@109'$ M=}nS/tE $ZҸsmKcuFRY$Q*nl"4 ]3 q4[eabS@6\T߃ze6Թ3Pdw=x˱o͹6sN xh Kd `},oto>v;ocܘN;. 6f3 }ɇ 2^?` 5 E4k4pĩ۲bOZ"2M2g鉎r ^x|?nWo?7S/iڟ ڳ 7RSr`Xd,Ҿ[0::;(艹[5P<i*/ɰuo;(Fsa({rcP]}gnrxrýjN3njs46P_s{?1>D9-hXb,&?pH56vE2R0v؍ Hh $Uk u"a8)z 6hN ^> ˂Rn(7(J0sR){zb3`@kPA" `lLw,zp%Q 3@؝$&햽Ŧ>n92)45$LD` KrYOvA>w/c+uy+zϟv^ }eL4,,Di؉nR/Cjؙk!r4:xQ\I(D ; z՞ {#ٝ'Weؼ =OH @W&":=Gyk!LoDhOո$@©KYLgR{{Js6@/pu]"X3!xl(F "p֍y*0r@Y fPxe7cgcYhXM%,YoLC0W_Wc6pƐjջ֨`(w`}9Q?fp>fCsqO+,`oL"O\"x S E1mͽ+E9XTT r al,ڏޔ0F1g>}SYn@eL:x~R`d@6cD 4=UGhU3]zSZ#a&RP%9Nrb]GnzH_H͕[4n jBi*U0 2&~hU~;>jNXnL.0z#n`]} "?I7 (go800❫P;"?ý9,t,=ԛmͯ>oS,jҍ>uG7@zX{Lo(=c+ @2cN ô%Qr*; 2#mBMicvqF1c$[q m#D*V@@n<p [%uRxL蕘hYU0 boy+};BU Lt)'r*9(+lerԌqoޛY9o=ꮮzFjI4@`vCh10bKcl;0C,4 !$ЂpgwWuWWמ{z7juVVefDzY{ϹoI A˶ kO Cn5CN>KlXp}?B۩;x2Z&GR)c.aLr _q{ah&7 H>iEm%-^vkȼ< !tg[Zpa f m$&<(J*vj1_<-r˜X+| J.Fn9$35y~'vo|/_3ql5Ifd9D (bLWgPd5?6G@ `I &u%6S)5v(SK'i4< 嵌/lώ//;ھx:Lȥf,x)9l1)ThX;n C[KҒ7,sKMG EVrcL Sȸs4sr |眜%ƻeg{_zclwK pg|䙋_s (;yw?¿5[~PL)vm ƈT|k l`D qX#.!>2 |}IosV%{e>' 7I9!H0_5"0,%?01v~)8:wPvP&iPNPjg|#i7V1{=2xRt:.})X X̳n%wI\RRr i/(2 @0~~=kǿXط28`lUA5{PJK/S]t7GD[:ي^MzڱSS_9NjQ&Dhx'̑c=Do0^͜CcCu)dlLV@ $dʊT*wdtSq˻Z}pX S! ;|٬@ԅMr3F$+act:u0%^H urO VhIl' ]GԾl d @Y"QG!(>X&(9uBv}mongn7J <A˩ _I~KD Cqϧ`û*ᛳ74cX8V rK-iA1wl/Í:N|2бfrC 4[e/?M_9w>bN.jY7#7A6_X+9Lǖx阹~]n(u)Mx#8lIB1 Z(/8ܣyc(k_֬gCJćϮ>'o_Gw]D5n5hG IDATu'7o }?MoT~ۄnY`j0 I|"Uml$]iXފRt*S>_N_Șe93}Mcf߹t|W2#Ԫon8:wPS;׬+(4e sc_s;N|ǿ~￝1}?+)) mg  v(@\q*>eFrIIɁcb8S p5^V&& " _:^?̰~^֖/ +2h: OQd:(UJ{|yX>`c{`7xH 'eb/3סV[hb8%Sqj{6&F$"2Zfc a>aK-4SWXkJv@qqD!Gbx Į ÔD?0%|_D"c'JbU٢r݃󋻚|[D~z(sko)w#/5`x!%Y[giEݰd_96nt%f~^nE:D#1XA! 8u\X%F)V+Jd}0T3 6*>(kr;ʰ]HYKsirPX24sVCyKnu")<|tLrצ$ `q97_ZbYPZZ_jTεsZeY<8W!|/;ۇ7~ǭn  _7A߼-0_kOw栄,gF"da9 0/z&v}W:|/4|0GD/#|g džK}=gå6>񠏣~|=s{ͺȲ0]Snsh.T\sKJJ^?^Fvk?M)[#LEQ'r]V8BrIIɁb=D l⾦Q8\"V},_=B۲&l)i.]Q#+ˌf *K:B@jڈ1f h AN3}OHy{=fMҺ '66Bsćצx^=YP`=9P0F묲Yˠ Mcv O/BzطE6pr9" jhgfENsHj$TFHdC-7F+7wӈ;z\#$D^c`L0),@X.vgI=0\9VF bT8بAKF*-s"|qd_<57D~ ~"6 ᬒ8Nxi'd0o6-"Kbdah" 'k˹5tVw{~{}pkχ[C2iHC̀e:Eri]0"! ؋R]\ FqƉ,IN,M>u FEz *im?uP?wmחE!g.^XF?wsg]>kvp^YZk_$Vtͦc=d7#D"lz]|Ej5*$E1-5 C4|2o2 UyB -3ug \@;qtЏؿ_{Ęf|Y4@X6w0,䒒m_CXR!c!cp2ϳMK ⁼Y hBbVd D借_te6}5i$=֢%X0+UxdXɁlf{]e;ng*scg7N_3M 90 lZC24wi4hNנ! `zKb[583ǝ(VC b`>(%ngƤbH%SIZP*%nF}V FL+Ơ 1`H Q\!^)5|߳d3R?@YJR XiAddPa*5&}k/Z`k+2g.^x~a_ xDe gӵnrb2 Q6 ]Cv=pWRf#ghՠhb\@іRMBІoYC嗾M0%%B&xo;M3H,+jx,{[Rrc> 'Sȴ74"O~}+oCrVRRrиH$ (+V豶`lPT#DΠ*MaF6#Ό8R$ŎJ>L ׬heffQч6q@cwȜ 3œ8^hq>z*Ie I0L cL;& Ҳ Ca4 WҷwGt9 ,UYqK{tvƙ,{AP9rI$aIx9C!+b(ջ_m]b$]2G]\]2`';'zJ=b-^n-`+EFe*J!a6+#2M]($>Y >?揚Qz3i մ9b&$}wbG")brX* Kb&"vZ1wg.^0_h/%voN[}aV+1&#ɂ&&ZZof kaO2vkAf@?[acP @!(̏뜎ň0RH$5ÌD>`%0TED2@}'[(9ً,ꯄB-w'-jk+`"g.^xMU #h;b3) 2!X;AT)JIx.l)E#nUOe~?|omXŷ\&AC SBK1 |>k]#<(4 'ђ?e US.X} "(<8AGG,$꨺$70xܰ:Z8yߟxS%ʲ%%p<YC"t¬XvԹfnCϗH.))9Pl;m+0=:󦳭瞘x≆jQ\CQXr>>νuգG?CvLyY>ai͵ iZE |?dH6<^nx~1_uWҠ# SÜ(HF qB3(ĭ}`Zo\ ˄ӧrLK{@OPF61k'|eےJųZ/;,ĐH;Ͼ}RH.))9pl;3mHl_]Bwy;"G̃m@ Uddp*f(o2Vbak-H\vԡXHe 3:u[iJGUShrWJBUCC; ͞"t5/4!DPNDFF˓ ٷLJ8jFdaXy& #7SA! g~ы/jmN#t|BDZzPq3/xYj/?tLפ>Y:V@6=,&&2M=& x7;[5n5DmjvsG\7-a @D᠘\365d?3,380^,{[ۛscOJ*"fs?뱊>ҵH\gO01VW`] 0  hC\5r^ m;N2v~1[l}+?x~qnt1r.^}x2/CE r:yi-&D mXjmsGoC s}V%_jƸG|rS)l,\.%a{@lZcJ5Wl/x~A?b>sjeG Ƈ}hX7ǬM'yTK_PI`hFklWnjA@;K(*,퉕%wŃq.))yp;jm /py]A& mjx%xf_F|HQqamiaB1cPF Apoش,e UNO]4$($R%sIUc8ko}}O>S;摭*y9U8Y$Sϩhy 6d8R:+C/eMZ9 KF6flR ~ Ϊl/ _|o?3yM%~m*+NcRD~F'J`Y  m1ll5ySX<\>Y@mZ*7Ju$iɲSu@IIW{í\?uSD$R%%v,Ɍ1S\cƠE'4AYyRf$Ȣ8 ;[Cn~z7w|}t,cmkR>9=؎9]PR*&,gS y\PvjϰKQs@=nϼ[R,u2|,b,k/59dG&: ˆj W-dA&FB{OBXqМ\k. ,PzOl*@Iw+!e Pu z>ɾ/2*q{`j IO$X)%` $`4 s UI?E~`7WsDHU!WY4 *J@:mLpRx01L,!s/2wlgHأ)J6 fZ B [FBx~q=86}V1A(Dq,$hm>/}ۗ' ֭mz4 2U•ĔYc/D: jaRkuصzRP A,5Nr^VT3 s~*}m7~]o'(Xa 9lkױ3k-y !r!QA cBiHI Y1 |>k`#Ɋ湘P1tZeDShH{wŃ>=* ~f2C'o~."rIU~9$Ajy\J! q{Rx\5D{0E ^) YqoIq2˛]lוS'zG"4Z<PGFYew>SZj9X gKҨ[u~b!bBl!/gͼ9K83>9TuPD$|Jb6\PT[@YB@^ IDATlt4*Pp(Rz $4*+Go{W}4kk{mx{7֎K@:p{FUfk .Mǹ~2G+u򠏣~|cbp.h2zwafZ$ETamP\RRrQQ/#=C['Hֿ`Pt/٤ rc8UZٵ)8Sʿkob£gZw\X EVA#%0n2+D⺔+^~x3O^~Bp5,0@FؗNnҴ&dߴ)Xr"M$2'a82Ҹ\K-YY^kgU!f~(}-&5) ژ8 P\ WS07"Hx`?4Ǝ]!9^۹u'_J3Ko}'Ġ_XW&c2מ<'2ă_AGBrl 2˵< S(;d޺>%lqz(J^K$gpmB6H Sv I}1U R!4p.XՀ'aG.l\! |S9s>q-|)Ɔgix]Z&sɿ5{hV tn]kXszXuV`„piŰ JcNmw5&~?k+ոCU2X/XF,vC56ӜZnPAgWC!Xx,HvȏB$Kae I1[X_x ~o٘Vҍ>=SK%WjL /͊CKB^zQknܲLc8 <+Q )*Õ|l(D4z'3rb=CD}*5 8 SRXy14A<ڹ)+ą`7W6;`Rz[mom-աe}Olkb 52]Gs7-(̕.7Ppj5q 6^ 8?X4FV4TBApZ"&ѕXu=AG}iWII^h 8!p ts(צ.WRRRr?o;t##-8 `C Qq@IA"THrPŀrb}vBw(p,Zޚh& x4B2:gk :xDKiу,q5i){_8*>7ѥ[M:uiyH.@Wݕxq5]\> Ffݐ+MJȇ` B5 {H _F`p!,Au݀L ,!b@]Nxvx/[ܪW)ު5߀fYWJ8B1K^DØ%@/F>LgQe"=?g5_M*#:u`;U2KEdFp$]L,'r,z( m-Yk5T؅<S@Lp'Sөj{ŽTGёQG8H, AaHSi@؏Ɛ;Ia-;ow."O,zB F PޫQ#[w#"?aRDUl 7箛W!l E;j9&yO7_2$Iɗ;mi2˱!ld5axl'6x\i7F! knq ZKHU%%soйɽ(䒒B`QC&o>z%w(zJv}~vHaɿk+UZAJ%%yJj$`2" v;f$U(iTb*KWѲ7֌kX )%BH#O9 cAhQA3W4 ,`ad~΁!W=zsv6cw1S<p :lF3=d&J,6a'd$کɊ㍄73r"$39alk2V( K{xHLPA Ylp"AՁzĖ% s`pj(# PdSe`oJm\{}/O||fMؚέ D·T";S~}lW.^ʇC @`$UĐϤbHg-_K 0M|7Y7˧WC)Yj*T(#C7CGrwPOyA?b~syy_^^>{k_URRrw H 5YɱF/å_`S.))944ƣg[g/)<7W7ҍ E?])ZWx~^h_Pc!6CvTbst=xҤ`O ǹX=p4\` }Ftk׈+# r$ȥPJdfb5Bo>Oo.@4lhGSsNkJx[( ~Kwdutn]$*P!DӴ"=GdwlfOQ{gޛGIv\ߍVYuwu@ nh.(.5GBGej#ShDKC{,ڒ#h`HS$tcU][Vǫ&@&FuwV!ndƋ/'r}e5 F{RsorN93 G+ 3NRVHB<-6PLtjޓ3kG*2^ 0A(E4h0XҢ&vos)H@6ڐA!3l 5 <8MjV<^G&.a,nIد*vzvj5bĈg@ țDJb&@EC}ȑ{C`>{Hְf]J`$Z< $נpN 27c{6L(ꦝZ2~?!\ )]Er1{b#iyjoXJD.[c-is E!NpqĩI'˵%6=$ "'-n_Pb\q6w=28w`-pP*enkG ˳F>~hO4*m>Z%`y  sgL'W\K;ѣ'Ol< )7+/ll+<g'x+dE LܪG pYXUG~ wnc=Xkp߇-T?9'L:pz TNvJr0c})Ǝ?|P3-vݜ1LLQ EVHVAѮ-Pׄ#Y.^9X଻UN-Ad AzLIbY[>[') ͳCr}ڟڲ4!cfY@-%q` "nkC&"A)OqP,M6t3ޕ"#πגQHg\h;Vy?9|͂nף'O2h2u0  p1FǑcIaŽ}L޿U#? oDFގz?ñ0*xfrca/Ⱥa]%:! AU-_pv=rymR8D c5;@yR]]q:Ilә+ Z53 E'NqSV;gffV;q7 uA*{w`#F\"[%CL+X3x։9w$#G#v")p ע,I%d➵b 4moxsi`1ueQT6v .ʚRL\SgKfL2%Rd+Jȸļd tݘ})EJ9 +u T:Ne(Tv䝆`fYC#S@;L'ٞ<և9s *``BU^Bԕ{?n5VP9ÁaVQ]٪ƈzhqYXU"&'a3Lpb@bQ&n ~\h W u(''4#u&`l@ \?|{\lAT1OZd(g0Z 0ڃ%DZ|M/'s.sfGI lsMlrrX2O˽Oe(FT.D ]ĬO*kB_bb3px-)۵8҂@  |R.[VZua}:kkZ˞avzpJ̶Ye ģ ҅:=+vVj1JN@e qvH$ִ^a&!<ͅS^WcsR < \ q,”ę*%K Efe/\h&F c |(z>*%V$l͐c8GÎU`ñoMc؍@=p&)hu+Y>`zUN-UuIO0 ֙$SٙY.An=E"){ׇIRs5Qes\ߊPQ9X&: pT{э B?D|}:5Z,&f#0La4P>e^P{l~J9@ *e#Hr}bFky4n}\h h-]ZS1{Ҏ /D8~g; IDAT/iD)~kV26` JLL`&a>P} X2}MQcr 0 `uM=\X6]̽A8e&Klh\Ms wi޿byӟO\ͥZSilmč}W}1bHq b-P<9(UApa(6EF1XCX{uͯxK^^sjr/nnIG0g*x pO^gWr9~4[R8z}FxzL":K]%}lc&ASpkq(Nm !(bArh$"-1FnPjU'ǭYw"pYNfBa%RmITخx0#h,a>HC^;ófZ3;0'аi2W{F߬+@1.=Bf5r*] ^@{)mx%]!I|"姾@̰`oЅ̡3op@!{ۗBy;2B+| ?zJNvŃֶ̓SuaaTI+N\d y 2*O*+zGʟK;*9GڪbsEn*'s44ljL9?L CcOϭk0pu@hfl#[cY0qeGV1V˾Vdq.S뱜8J2s'z3ˮ=y:Y;p,뜄a21h` D`%qm[gcAtn:~\h֚ prrK2t'2Op~Uȅ/.y4'{1r"_],&{(aA0ۄ?9_euUP4g=8oQXzeymLmA{73UF Jah(ȼ`gP\ho?vr_z>5wݭ^Zg+5Ԛ 6bĈֵ[Щj 9J^[BW )8aױ7idXJܸ'314ּ7N+#oWXYD `-r'c>Ư CirO'qz6%$eXAfA)A#WjvY$Id,kI#ZQgi\>pVr PH[϶l$Fm#=o.4{#jR\2cQ2 G*-Lu!RR }WU}OXXuRB3BӉJMe\`-rb &a3IeyMIM@d8!r3(W2u6j yqyHr^w6)-[O< ְ.dc} -69 Qr."g[j$oyxhmڼ$nJp"-jܐd.ŶԺ>ȃ3 >K@%, -b~V}).fQ:/n*('+ Q{>h7ֽHb 0 cU qF]R(HX}]"@. 2 `Z()5P8{K:[Y/Аk5MF6cAHVr$}A}& |>S7"[|e0ܬ>%%k9({R㉒ c{h*7pzNV+avCM3HՔld IcQ\.8vzs=ɉ͵OO[9hRp2)£i6?tp9ho?vzwuObM6|=i)pFxP=XdĈ݆{W?‹<a @p{Uf_+oT#yg2r$1b\hVxGipHPH6Pl ci7+'l0W&9XdBt$X"5Αц" >,I<rl /j$% )9$1܁ H&%5P1R7dJHw_}2`3î@Nc]$B nQ'-q3zYǍot"3@%&u8T)qIP\B3BΫ a6+]ߜ$e=`r0!_ }]LZSc3#c=x0R +u XKSwGS/B&nh `B`0*@7$SiqRtv:uE,8Zi"Y9:#^C1=cu_S -}Zgi_>%#ɚnvuMPu=gHj3N@׈ٍu+ hGE0 7BIW9K}Uyk|bQՍIKG +d[e;>8 +>nCI2cGQ\h wj~18Wvk,`XY>^^sRy>fe[f~j٬uTA$84p2=z5?جFEԞꃞ;5ܹH;d~a!%IVSNX"_Qls.CM1/>tx(3ks/4^ ^ Es>xĈJ*h?^ V>I\1b|H!g†( +vz_jUN'RĸZ#.#yĈ; ($\1O2XVem0A])ec7'5,b- G# Hq!I~mxmqm0@)lG$*9.UeBT%^& :Wie=+30}s6$Bb#)EؒO0/LUϗ`-RpI0VIXt}`b岡D T\dHoe%H*f_Q%2eu`#׍J,D)Ǹ"+i;)c~P ,׌i5%%[ɠmМpq^u;"X8^`8u S05pަPhmm V8nk +UVI\ꜳ/>:) SS=0, Um" qZ r @cI۟ZGAd,a_ BP+ ` 7X!9ї25[q"T9ɳt2wRN+0FhQ pqQ fR6bVgz,^ ~6;pϮ??L[j7BmBhJdB !/K$qfW>$A=]v b!#y$p(鮺 sE~R7݃}d=ˁ <BYn6l^t]^r|5k5[RbH(3pemӵ}UR%Dρ>vzvhSg헦/?ve{n7>SӜlxM~`=c勁#Fn7/tI`\,ƌ\RL}Bjup1bĈS/d(+J/~_4m궟{ys\Fw,~po>фdHouz e8hpdW!RpYŚH rQ(JUrB*7w{v` {"exa cH * $Ufl΢'&=AwS~1t+zF_e%% Ł5b6p0u<_1},DlUDd$zrWrOt$AtA1UX;`n~/~㼢#u#Z^i8ET%U}λ%:st̖ǓӶ\h(IiHOPdDthl+htJ޺:ۉ ̅m})\#D™_NG(}'<:Jb@ uV0@bmKa]/I}Wߣ4D)c:q SB(jT=Ke[P$,\YR2\lPvKX#TR:EUcjm!xJz~+20s!xSHˆR"{>6LLxl|2ֿ'=akK6 n$OFB^H1$E}؞`hSp:`{3v9T:@˜$gتi69OEїR9SL,W#(2Tfţ([dCo9Ӵ*fZNJ‰@BX>֧PFT$oMʧ%ky3`P@yPd˛CsiiY\峓+:Gpc?(1[g ~ B*1Z~^wwD7=fw[i]9}<ߧc"$3pO'pwnyesOj}_1p-Vp>}ݒqQ;]vzvf=eKNY]O7NWrPB,{տ1\h:c5VW6LBZ"@K ${^[Z ǪbH1bHۿv(6k%?3j{_g~ MQ7^sw d & ϰI_ŷ}qU?vc}O7룟j5}LHۛZLXg.sǭ8@3ǥ|? mәR31N^2in~\j[vO^ouecSc` S@DIG324^9sv[a}O7>ُŰ{5VCP7v.Tp 7>smoN4%k|Uq*o9x˫D άU`BέzMAہ uKO]Sa۽rͭWnB8BRٹ~UIĚDRTg=׼<{|Wo;C!φOkNo, " V+'Ŵ9,k1ngiKz{&}z\`^ $8QJl[]RT g|U{>Xe%!KQ1E*Od%9vvkKso3V+X!ZY(@7RDseAl kvϏq5\k+7G_ٴ,f!&c | @H _|ݢY[B!}͟KS2Mp% %G1bB;/k! [y;Kq2-mfo;87&Up$_V龺k޳t8USX;a,[kGrPo!Ikkw^s-n+Wϥrvplֶ-PWj/ |alj> M"c7i*}F}z=6Ykͅfŷ}ql]m[`elͧu̾rWoO;Da9sg{Fdr/^m/~ ?nu?Qۨmm+njiY[ck1`JGه_7‰3_\9q0vc(n?y #i#.3DD٧O]wu)/)?3jj{7 GяLe2u^oc_É|`&isJ213[j e65{Kl:F(ymPjq~se_~=P ؕ=_^!B(z`ϋ/aǥ;7^GޚUD%LP ,!$ZTvuٷx˻; nm^:һ_K4'9'vu* DLHr:RXK&_;g W[dkK/}ˇxIѱJ.V^TBK(,1!~ߑѯ\nϏ&ji=vHYr2rKn9•yq 3^W#mVfةz^{{S0:0~Zh6G IDAT(ޘT( 箼uƾ _0y{k%)B}`p~JDPϥ)[5T>ُgD36ǛSL:gε9_D{.RMSs=?~5N_{ ۛI-Epre@#7MY u>X98ˡڡ]kGlUl|bG0"eAV o+i`nK$ƙ"3YH H+P$.2n3^|~/>z{ko{O^_jm>pc~dL=6^`o'Oo?n>ah׼?y'U&m*9"tzM܇vy8Ah(K0 `׾}燡Q6m*nzָhK/^?(+! FXpQ|]j^{Cԏl{3H1s+7щqk@Hmꡐrz|_]k*ԩI+?BPu zn`9^!!13@Q37͠stQ9?-sLc0(W CV+I%,_ lvU[H,J d@H-1V&ķЂܴdg;{UD/G+^o,MNQJ BX PJ8DDۑD^$A^ʚߛ)Xɻ^HtJ*rSQZ99@V1͖V@dk6TN5kWlqdE5a m c G*b@Xa*#?7ti^w_/oZnN߅^hEb 1kQDzӮw˼ lV) H4LrƅMcCZX[`:18A Q9zp'xl'orӍ2|7o[P wr] S@Jr(q`C-G;1zt]EF vO2}N zE>%cUōe20` J`bPv+,]N\..4vyhb߀/îh-@,(PpCd1|4qMmM7c-q¡,O5bĈ.?[,s`r+#=Pb Aʩo.Xیgv;=b4=+o`5^U(#^szȉk>Fk-PsYB=|kN\'3\N'uͰ_J6hFeemG J׺E{t.IC xJd6Bp0(ԳUZ+* >4«|z@ׇ[SO-%T;W^MVXܛW KQM *PX@b^)ddHF+]zˏ9jFu]u9׀\Qv\aﻷޱ4@ ABk!Kd[=qrpeds ;Qm$3qƉ38N(mFI p-Q:D t7~y U߭Uonڑ(c]6岍};jۢL@55Ͽ&O_ӷ`2Gm\B/A pqdj~hp;.Vi눦R"E`ȳ0 ѦTk0]z5X ׏80lؘiEʣbd;FjR_o|oN$٨rWJZJ&=ؘ @Ј7/Dw5}YldmWNCևAb (T醒6(1j -cD10඗䥑ȇ~!t㚭R>=9]#=5/J<(N\W~wsN^هLz=3_ 'Su|=yO>o/nNc y}ȵG=K+4KFNPD|8<{-^0zqZlʼ:?7XW+UѰ4 G&Yc?z>ي牭n}-An!|bפxy|O\%T}OkPX8qx:57u=^NijLF=`Dy`̘1\ L惔 kZPwhj:޷ώk#CDuGcƌy }x;|c _K0;Nd73\;nRң#7zxShNx9ё8Ym߸>+iqU<?:^iwiw9w/~ZQs^=&M #YBj(O}ߧ^hxk|JW:QhWTGER uFKqIm[gG蓿_X+m}͹_|$|OupSĦ\WJ \<^k׽ Z73f;_Wo]Y+' ;=䡖當 *&_ïe>_y_g2Oͧty*!eD% (; H:\׌}[4>3(/o}7Ͼxq{_;K& xȸxpw02^vE'z{WO>xjB0.=skɛJ]zr(P0(Yw尬|?yWWF'''^u•/}M~7kkfVyN:ԘeBZpqތ'>ѝ/kgo׼f`/œǯ-uD#!aj+366sI`>#~xo,}ʕm-;r_WvJ7|ovN ᝆ)꣎o]51sO~ˬ|p;(q|:CZ_x+nLy[j?'b`N>7w' yfyx=^X|IsoҽS,=3o^k^ _ˬ c!]|7-)rB_Fnxʔ{Zf+9~A6f<_ ->, uW#%|]L=C{3-ơg}G҆>t BB։ȲjO^Oǁ|q܂?}F(UDc]!YXf]oD G#ζ_~KlKxU߼1F_rf:!>Ct <~k;ه-xS0xy}p^}VʣA3 yS8|晧}4,R囕oK{=N[ZD;Vj<e s-^湫dok;]RL1qnLFFG%t}tYx^gyC䫮cj k y\~Hv5٫lgƹw%E]Y)T}dXaG[gHkɧ>?Ώ#ƌ'?=1G'V(P&"s$PW%6X[|hqb3E5_mn}YvgZ\N&¤:O}{e`?ߜf?3f̾bK\bAo< Xؠ]*PZ8*}1TMQD=E43DN4*;:%zemN_8KWg5{0SRv0^QKeXQL'x.]sl `ɒ߷Q'_ja.W%I,(iwZ'-`c_iv8UttG#<t"10QIw/[`Jo.!7&PJ(ni TnV6MiuBoUʟmtuzqL2᛬moPڨB)EԢW!))0bL~LV* N\oتͫdJxq`n$UUcU|~-ϓiV9qs#U@?*r(jDj^]t,O:(Yۘ 8'E:a@yz0#%,K3:.E0х0+jSG),MĈf7\'u 1߀s p/pgnL '_ʻ9^7v+mX( ȯe _D|jbn53:H¹*VR|f;p`k%ЫFkIk6XzG\0MF@_Nu$臌&{D %8,9}UT1cbizkf)wQեYRu4sGDBYӝr930c'6,Sb^4Pĩ:#^ù'`BWڻ*1c^4_gDrw]ᑪy2bRmk0&7-blH3f~c`\eAze|DT3f79y@adF1 <qں/L:ޗcHEHWՕs+էv'n qkyWek:Ҥ'.y#ϵ sֶoY|h1]8In`tM"JŸbYB/]7",NMu]ֶv0-6V,::A "} ;BX4nG&ݷհpn\C'12R_Hjf0AszMVtAr)5: R9tRn_NfNmYy|nL yܙMo* A8/ B6'DjX}S-[|p;z +uFبq ʤ,q1u!,5IeKTC8%+CXID˔Vx) xM%ݳmLj1(D|Wd:04*"ׯOu[{[UYH=N)#p\w;K %J}N)%} 6Oop~Ǣx9(W(2XZ?Fc}iåiǸ}աޱ%w^Õ`'+[Zd\33Wj0.TcNnV{qFhWe%n׾3pL YSyȨ\oW╧)<uG˥+3y~yrÚX̽SLiߞ$K܄oS9}suWRw#CuQ_+F'D0'RK , J¹}=`=1q̷jֈmRW,~kʶIfPB}`L_8PNydžYP7#$OEskq0@Dnh %QlLH~v7pnaxBauˡMJ5t 0S,^>EqG.o 6Jʋ+%k>4s0|BS@nRuҹ|>fl[_9J\[s" *5^dp&9 :&3F;%LLYJ!9C)%C-(/˒BMUI<L{|(yv,I**Q/ q ^ ƪu@VϝD`_Χ3=dt^I$vPJU.#"rz+K'NSDrC#L9)Pr"L'*wgO "oUōl)nACaIF UZwQOܼb%}WwIH+&4@3k67~p_8Xl5aA(e_A(sUȐ~;ҁ?n R=gwI=|gAQ-78 #3]=c&HoI=ոm[{YhTNs8cFLՁiIf]Ñ'͎>KHc)ٷ!|Yv Q*dS32 WA2O<%I^&%Xnİ&:;\H2蔠?xW8͋6p %oӕ36UHFHs= \hq3`}"ߪoR$,.5mL"<3{?]oU JP栈\k1~7 #aٽؓ 2Mŋ_W ׇэ Q{)*h]_n[o%g /*;\ oN_83 _lcpָzҧ|_h=WL3ĞHi(6)0?0Lfmm,jMjJ,Q˕Dܘ鶸fcESV-~}~3sRiexȆ -Ov4F❮x~o~<|1B3KP;|5e}q1c g1dQ1 =_ On6o̘1cv5f}I1 P\N}BsY g֬ D ~AE0U=u%lTQ(gEC6@(Lj#hA9Frg8749y&*5YDL[ 3#""ƞz`}`mӑBAsDZ7򋚴@Ug1"31HvD[7K xI![%QPVC)S71T07{Ň]k d f  ҏlm#V[eUGM^TMe M;\3neykkòUje0^Ԋ*h*#[Ӽ4/3PK|Q&CizjtkU|5RrjNQ(n{JNWwQ@ v&wpm~݆/0~` s-}Q+@~'~vy+_/W-f}_TS)j Ԥ6kysy߮Mw&ڜ_W7zRZvFLO{#&bZ~=5ѕq4v#<[F%'}z.}}/m6$`:U!LsFڸޒl1{;_9 $*MGӧK\hq5-.EZk3f/ R]=z}%9QQ(pet%cƌ$@k:?3}_;~īb+)ȓ&8pn¾B(M{*j _!Njְ͞5G"ڏb́˯ 1V{qI[c[UzD"zvhyƲ`ةk'3ZΊFfa$w*˧H-^lT\ Z"Q~٨z2T'}iөٚ8?{ *QN@[锕~<< *D`qE`H̵ʥ5v)CuCZm+jr!pYFF r!TLŹk+ZmE5syzت\.F9\ɋx $ Y:WF2"|oo8zh4iZ%/)^1EWD R=4LzB;kns ėsR\%ǂ/DSw(Jܷ\ND*NDR#(eܦR e/7/:[rӵ q*v M &A'X3f#D-P8Oϟ:[oUydDp ,_:qճ;?qmrk]_ߨvh y 5ѥRk z獍{uzp~UEo~Fc ʓ}yH%uK5Ss.[x%gMN_~v@~*\J؉lv(03Gm='͆dp޾"^s۩3Õy_y{zp?Oߝ'B@5"nj٣l9ylY.'Dg[jcMkHDthSR'wW178"y̘1x7&fYYWO%ΌR(W("5u ̘[})]44区9crکd\O, G15ա+ #<r*,VshVJO_ʀtbIε \%?tu߻|>n|u?(V|B5W~ %C1Hнrn ?(6ؘuM:4#QG'TVUs2Pzb|k1gRM=DCG36au8}tU?X:+o}: q}Fj4ҭxe8(!3 TrOU@Ɓ|f\Wf/u<(ocWAmxƑf"u;/M^-Ak{SLv}FjO: 5I[5hiC^P.J:)ݩu7wpV"b5l~%qsBN[N2|o7+78ۘ,~^7Eζ_{Y?us3.|-vZVLy VnL gaǎǺe;*s33NetcR scY$(LwBNSGޏkr qW#Q?Ȅ0jl`Q.0H,ڼO?Z..[J*s_}ױ^}%gSizQ)^ 7Ѥ輽~gW@;Ne }\޽x&}Rʚh|(Jz~Z]i<~Y|hqpnah(`s:ա\@K ֮s 3?nj_V7XyBa`(R>W40w\֢L:+TɊdWhZ#HIJ嫞7ŶuOjmĉM<aakkyL $R)qeK<9w_%SUc,FA` B]&kݛ_b8Jܤ7?^e`6)Ү7nxJIa8Ο:= 落k #z7+&((p[;J•Pi/?AQfyr|zb4?􂒧 K}z )aca꬧}1L8eA-ˏ35{M* !Zdj)=z,2yiYe5TFz_+S_JOD*ˠX-q~SVr* #-[&:yfnrӍJ]f%pa;ޏ{{AR:! js+ɨZBIU:T4?ԾgJa[nIͨƊsT!UցgQ-cC1c+1Et E5U_}]OS'rb=F/ǎؑh`ب;eb¶xע,T'fXԴ(ryH ^j]Igc _ٚbJWY~C+im2@?6Э!Νm9:;=zK9^-gj3~$t˒5nEkcLw{mqm6{2qt.MCA2t7Ę> uK WK=Z9bs_e'4pM Gu_<ս~( |ZtHTGPAsPHJ#):Da/^ߘz}x%R -eSx CxfLثPxne7ε}S9|n],(jDnL I a Z'w3ꔴsh@mȉ/K0V45W1BQg>yET`+U+{F*H/s}kULfY0wC1cƼdzUKs[Ԋ.z9F8 i̘1s %RP汻G ZH 2L9%6<^r-Q!cC1c%[mpd0-G\fB !R^Q6++&زˏ Yy}m<8yB?TUeƬP(<"`i'([ك}K+*DWQSe+* Bn!ƹ)N6/׫u|j?bK` Q /XI| y(=_5_!̶hR*Ɓ n /mk@9JU\ub| bV,t0euS7rS%O.Na<. G[Ixpe0 _m="/M8O:sG~۷_Cr@f$w„~=0g\y.9f̘M}보1k08<-TtUG~I-uK%{T3.`1S (E RBT0BE E50q(B2Tmlhf[3ִԯyǹH}|N~cwJ_ѹ#Ƣ7y q ![6ł&9^薱=+{yLt@9 ~s(kGI$1ŷQKY;+L4ma?}Zos~?bs'df^+5w?9"0y{wׂ8\7+qbѧ,99UZs% ZB̪~]犞Oţ+**3 Jgɨ;>,lqMkEȊ)4Z`/K?&S9dA%%\ESgMNmG0;,[ ΕOOV IDATyAE&c<DGw,pR(y>I|OvퟮGsnRv*!"NdYR- bN jT8ő5'y$6 9J4Bp>[S˫7%\lFdM(xIIQ|A1N$x6M^E$/uZ™" FZIa74A^ǚei(ha(0ޫM 4'08Ro­,fRAh:EvVK1L [F&=YB}NM$ȤqmZ!43)ەHDDVŸ2=zb˵\le^XxBnTq[9^ytnw: gُja-BW<< Gו#pd]9ހFw{8? F3szHqpQCom }|zfVƖN ąĐIw$-/7Ԙ@cO]Q#MjZq Phf/4kMb>&ergծM (C}!p|VfĺsaWj \0묬aYHĘ:$N$e23g%'Wx&6f[vtwn ^y}!(# x0%`M'V?\8},wEgx!f6Kl~̝/ҙާcR?=VXka* Fpj'̚˔q(/LLphĩ `M5Ƕ$x{`(x@eͧ+mBhzRE7"A ʴz.m)5Q:ed# D)6k^mS@))2۹B|ߍ맄WN^ݑ%ʧ.knL>5bAC+ MA0懮` cQl0: AVwfaXK[: cic3Wt9?rbYe'fθQ=&M" y<o` B+3BzGYgLh(F{q ti+ݶcg{Hw>,.( ԷԚ_ѱ-tda7ߡkU=EB; 1Baleъ}F%$WTT;W2mSuQ+܀/i.>cOsϛCkd2/s{ Of*RB.[y&`>4kčBL uZStDUky1 E1fM]M:\me%x`I(6e*:@ɭ'V&CƗ)jAl c u^xA%K'L1>7A E@ڔ_)f=_ayb3̏%'5`9APj0b qhoL" P\Q^s>ؾLnVNl<Ѡ3'-{ P4A |w+!e_o}ᡉȓD'_x̤9O=0 .c 4:KPw<=d~r_~%%Բ^|8 1 (NҙUz}g}-/-Q1LLJT@3Qڑ;΅/RS+v\I'u70zzS*DŸբה|r@訢S!Q [֦L:c ^ԂYS8T ɬEwtn1DMboVm ήKt* T9!9ÐruQvs@+u׺ޏ_ߚ3>䊊}+3J, S𘔴 mQ`? l{KGk4 8(@B7RHbU ʲ8N?9ɏHϸ^z[XB ۯ[uQ5⴦aM>a(ug^$j`ߍUO% ՟HKI1PoPQlܫДrOcq r5 j(y}xS_]>}IksL]*0#J!54w.eتhb5Q㬰Qfܜ%Yc~B)|TywGWT}LJ!7("%7kJq+wFx~ aQ˨P}tNy:%vQF3oo~}>ÛF=~K?}5CQԀN Yae\N`36-k6S Sn?r{3Wf锠va!*&Ȉ\!2xu/y>sV< ޘp '9F2 Cm7r]1b6=3 bʺ;\j(?}8ya0^4t qW4X}k"oL^|~?b^sg<_gnNX?25tmzU):mW/?+W7I./D~Ȍ2UM;G fcQ@Vku=sK :\QQ߈x^Z@o'ˎ_P:'7-#DQ k ƵuXսNQhRxr7>r0V^GD&44k3EMkx0f6~^:۽fMK֕5 \8F7%dׂuz BT+s''6 jm0;$t zӢwojWaatbycJ w%0ʴIGqJjPa*:jGg}ig/>jq -ƬE?~JqgМ͉-q)6rv.{lwg޽ۏ_R _l6@n;K bꧯ Stk I 43)SdCYv SvY3^YH;uӈ jI ښ QLhf3a*k3Ru+(aLC>= lXAl7hh}ʾb(.&w?G٧+5PՐVD4N!$neVvI9ff _z;_+vG租~kachkvoOק+**)7vv26B]=b ht cx%*vJHorζa1lޘܸU]%sوr @jU|0'!Oj4ʍSTdO6rF_oqxqAc"Ƙ1 'QŚt&FEJ?|Fћ_>`"Px,Z̋q:5^MO4Kb߀N|`Ttc9D^B`\Su. x*B[J;Q% [;ѣغ=ErXv=y~a_?Yǯ&])U׏k?>o`8sȹ6v{N|$́Olg+3'NS D /?J*"5Ɣ,Ҩ$$:94k:#)nxD,lwE?~ 8քՕ/xQA3 LP7`ԮwKC`RqG{ک1$Y@Z#֥> 5pg]wpsKPhn"`8K9AP TuSރ2n堷~~bgJh(0sC^eB|?{]>c !R04'YK%$WTT+Qv׳un߈Z9R>g.^pgJszI=7m1lVӹL,)sS^=-Ձ#lטhwnkkuP ŏZZmKYOk1ڎGExDL7UޙpױA9(ߗ-T6 a F2 s V"2^Hjnm#;s?i2Vgp-"`\ 05.ˋIk ⱪ9ɤ I=k 1p±)LŞ#q^#*g{Vu(S[WGL^{m1y#t~DV̊U)֩ ZuH|f(fb ?Tqm,/!;>9>.ze;k`kX[]~s)g^ Reb ޘS۔Ef%*\QQؙ|SLkn?Du)4^^:t7vOe,>ޫ |⽡VrQN.LFHu?*PݱDNm4'H#M$8+~VίoGᎈy v0 F\Y_ezKZVƼN90ݫDkzZQA 8EP!fӼ3܉-Rjͻyl d}|?3;)rql֙3BYRar4ws~5-6"_jמxc9Яݙ7Rl %p`THòy!4DÿN7Kq(s} sK,S@ku=kM"5wM|EEa{ю2Ы0##[K /XϨ  e0#H莳LSҹA5|,[j4A; Ƙ c$rNhrP9\ "-7}50 Ѻ=MZl}vor~kޮk}w|O]umaԶME57ڰ؃*/WČc!`FcE~6D)>2h%bp-fx-<5Mp&$0RHF&AcEg@fpv7Wol?z*[?Zcv䇫#>_˕M8ـ<7٧UoNq7Yh4\i=LYZF2qx3L-&XUEq4GjCi1 c׳dm1s$g&]_ 2\g*><^[yQ(>Utj6(Q D5^5ʍiS* R4RNv˞=ٮa0+g~UScMԈ`Èۂ(7n95;زU/ﶝK!IFi¦èFVV6.7fSݍ}Ϩ/F[`0L06z)$;JQl宅䊊JJl{,J}ZP$vT2ۃ9h*ɉ%T j$( rw@0堢F*Ua:uݡh8kPRHOUSg_lJ G9VJbTIzf a $#n!; V]rc>ߓ媄2GySfܖ/ i?dj -.>w3/ܷ(QpL@YGig |~/RxuSI& ?40}{( %۫/o>۵/ⱕpTi-͜BaJAЧnθo5E CSTk׃G;cZ:C=nM(85.9v2˶.k]#8ɑ5=Q"jL"ooluuދyr19I~7vɖɼ(/M7akZ1`&0V]kFfbA9h~ MQtzXdj艴->{Q!55xݟ/= ***KP}M=ҥ`D!d@0\?mO%$WTTK^O;=UN3A9*AO6"өNCbo7$k1ެ^DD5z[˽99I:EBjaKУ'ajC~,'_p'_x_xXo9c M^D0+(r`׵LyR_8}fI? ԒG|H9'c3q?_p̋ӔJq|C׀o|AoGbv68s5ߚ4 7m8vmYϯL^] XQQLeYmgdJU[Ӆ' `ZS2I9XJHط|*:ܷ6 \TJeȤI=,̲$!s.E 5d{#΀1CQ$NMbMA !DYDuM #q F [fKhQȘ+֮ng3|evه\+3?pCtn^Oլe@ *lr0m/j&# B(ąg0#>R IDATyd\^^9et"mɄM>70mnhcVKopbF$6YoAߞnO_"kx~wGS]Ӎv;t˻iG e2fˣz)ePW6ZVhm(f7_yg\V7Nt>+i^c>Cש BaЀ" B4yc״?gomgu>XhױdzӍwZ(sKaQ^GI0"0 H$Oq$LqC;8?&(qfGtH@c> $n3 MPق0AaTVЯkYAt{=%‰Jw,yk9!PoTT']oz]9z|2boNeٔwf vonF|gg!p}md~(ˍS"HǞTBuQJHؗa(|Gc?RAl=gz![gG"E+5>@{9A"H䩥sKNҹƏ^ӫoa7xgwaz/uQ ww|q}g/D$}"n8ŦaHe YLLyN?B)!E7h1lDŽo>&{?$4ɄGu׀OQ^~?͑ۧY^%ξ}8vku'4_ goスV%^b@?1Fۼ3؊mB|~84%AC[PO@!sPPvЖMf?$SQs, .p]vB#+ABZC!Sn4oFwRc̃M*>FMYICl6 afOx34[+! ,åv={=_MYpա#o 4\CR7.J,Ԅan6[?ǹ⠷~~ݲs40vgln"X?^6$82Ré$ZNλDØ9}`Lػܙ4Xlvg̙dfSAi ʅ"'JHwqӪ-$ȑ~gxmխ|+L?*R!qd0^ ?n>bs}Zfs}îw%'f>q?(-;~Wn Ƿ?^ϟ_[fܒP6e?{;ru8u]yҚ%W:%va+w ߻@ ق ʸ& qȀI3H#~Xمg:Sǿ%A:\\jpysWڄ1b4VpBcvgưՄk{wuv#JiW9+ 힥>g{;oyxRݵ-}=0@ TGB°+ĩdc|;rmtOr ,\8FcnK Eu :KE:@-N\ҋwcw/\pLu;ey>;k}񰬚0C-sET2*ܘVh,Yw-MPOHCݜnIse*h[M )H/A ȖVEjnpx(S9V܃߷:5;lq\$Vs8ڴ&ί3Ojz񠷣~~]K疂9 I f-8Z<#qyH .Й)=bkn2C a)h-5ˊ[[P(Oz\Y5!NoEe6 m({l#G#rt'L:~h:12=;0a c34' ߊv/syj0hNhoWMkPs`MiNT~ǽon3Q?ݧ31=Դ&O$70aeJ2i7?r5E(= V H`> ki97zٳ[y(IͿkD?zG$iX fW[œ>O گgO;t3=5a.EaH #WWӋގwN8\3 ug6snkD$GHՍ$<._.s_TQ{[Y)_f ~bpr!̕3ܜ'tnfzR VBf96_5 @2Zv N6t14ٚbsi4l W]lTicԶ`uɛ? WԨܞ~Kh>o3i!Ki,wTw9x0gβulopoֱx? pWP ?Z'}bOsgsq|ej ؚC.`X{zua) e%ZJbnj+[-ߺ3 *}8X._V% asZMy򎇎#jbLs 9aVE4PM=*6>"OE}+{&no%~|!!j3~q"vҐ8N(S-<8RoiѦ;-rcD$3fFxnq!D,6c6DT^ 3_6EU摳Sw.>1bTthqMgjۢ /uV W,(WUvm;i/Kˎ{ގBm9̌4R-lmmmC)68ҝǓ\od7[Z:4:}bsgVACnI. =iDϧg//o$KnT}|R))՘I8(*8UTC 뇳|AQ_zВ(hnӚsA0`߯,Nޡl;{{&%(+⧮gTљ̐t@y?zM$+o_ҙݳJ}.}tBhz֭5l:ְn-Ʋi 5U"[w>1D=_w{9>J_pf_&6g}[^U- )CEXzWxۇ*oS)3[8Er"V72.|7RXF-N L-[؃,\ZhCD"Gx(SI&*p%ӣav]Q m?t;a 8v 3D[U߇TBrEEžd5`sТenP < eeruzܫ/@f-W1?xϽsK e{n}? {*╣[O$LӣwʋgafRzn~hN6n]g'_71'7NնevٰӷR?jwkwûjEX-xu[4ް/)$<oƊWo).3jo3ZGLGCQ~Th.n.[ Ν\?6uWW63Tx8\ rS}.MZ]-{\>,ˇmw_􏭷i-l RdBkP(Z-Y[wh:ہ\X>7`ff"aj! ihl\{-brdmQAmJHMFU0T=Bc!2lRfBZ:W0 bʺ;\jnٳYFͤÖNkF816 M,&{0ȃ䠷~~`nZtxOzwhu*\=y]v Վۂ`w **:wɋ,&M䖕!xMcSљiSxȨ+**%K:yᩇ? $}n'{Apsn _zͿ7j)2Y-?W+E[3Moޅ p1;|Qvd=b}]m|a9ÙMDfen ( tЋ(ިt~Z]J<}^_׏LO00JZ dRAm}IOK$>qF`ß;)/뷿k2E>ٮe6l`n@B #lKbfLO\aDy;?FRy}9AA_Ĺ|a]^z]BYtcnOMH?ͲA}r>S6v7bsīGP@Z}=7fPB)S;}){fPWG_QM^ګPt;O@u LwWVK: o5~F9ќ`5/eO‚e_7W?-8;ͣ8 j9aܛ =ϬBkX\Vţ~h̏|gcB_$ݴB׷-c~.uka!q6F-!D^))3Qq-2TwsnzhDx DW(hT2!c:a^.~}#w˲u|" d#)װYU}Sk)Eu)Jʃ3.̰ :1p%&}gk}^f1ݘ SL9P Ll:NiEL5^|JA{4*0=!=x wCT9cQ}CyrzuWwK ۱X+G.#fsR7v6UO&Ȇu.uD7$T)ȢӨ氯G}|%}gIv&A[t+yHpayoLE)S;n;+[s v|C& h;a$TH2eA#w(*)EeR^P.3Cdw;N|pvz rHhJcxGݞVNm.'$$YP Ow/6C­4tdz|Ȁ[V+IxbecFӉDp+2LBa/eDaqιml:<T"I&RhPM:l%"F'bp|%wJ !U 40;.W!FEdfSj\oodߤF؜utW7'hfBPB  .TWFLdXș( @*PN%C\G&ΞDbH3 /#'݀aURheOGֶWS)1@vZhVz?*:UWov@(=ؔ)S9ҰEƅE6<*@ svS viSڌM(G+( W3&nT9[;CBaATi{O{b-\1JOM~l0z_S3pfzf)BTH (pm/NU81VWk5)eq MP PW-}WlS&ݼwO$CY.QJ6S3JrxԋPwP.슮mX;8wi&j 5HO }Y ҡbU_3C{R+ IDATek: V#,o0 *Ȉp0GAvn}pRwZwF>sx$BDE0qEUGe_+{=BViKfseR//F}ہ֨jA0@{LSoob[C[hx(-YA}-oK[kMr)熫:u* :cH@pkPz#r׆kTH2eʁbo*ҲH#h,~|? qֳl;ޠVS7.uۼH{GMTӲn%۽U ٝ+vD77"WE=ybz,bL)W2s9a!Ȓll`nD G,XVŌo -I$bSl@hgZaqNHx|nP s7w$M8~}3aZ7SA; tJq\ Dq,Was&0YDnFU(>A%!}Ыb<=MiGkmVs֫*” -E|k=at2wO l+q& TFC/$0dC}+ KbZ|_9O)ŲoY~bT\Y![c6¨ `Zu| GþSUndP'|ortnʔS8Hg{PrZ٘/W~#ӄTH2eʁcrԽJ96^]~/VM54 -R̮R r^]xS޽af׆m7n*ZRͭH\YZ>qXcE1VqȌoĽ{&jTfjJ'G,dCK}Fl익nugH{۞3\nVqZy{"p+ DlM"&?2DC/ l4ᩇO N{|Věb`|k;f;w7'0FX`4p]JD؏nXȶ1維[kְZˆ*8|v<C>3IC!dZ]t&'N]zO5aV:pkVW"oVS?H^ ×?SE]ʐղtR$F~)t5~j~vfk ]Tz!Ip(jY FQ0Fl>R97}YOZ9jS9Q#҈$,J!90&L8暤U!UEDPQ*ylv ,jkh13~έG16_S0I)puA}6̀Nw;_x)ZG6:r0Gw.A]YT2[ #@'I蠏ĿoÉ05_{~+OpfODfǫ)S; `jOlЙ驝b*+`V TX$τ)wTݥnDi1}w*^ܫ)cBy;ZMu׏?|#߰g>ptЃ >ߑ&yg#I uՂI D$U6>ydޑkz*uEAwWTjӎ"Ak}qh6Ž s,z(O\:[EMfЈ jx$z^$ |ף>b4By=h̏GjH> %!:kQxZ<LakʑMY_'RԂrmn 2 FjױsS~y0rp SL9 L(35{v.un=}.-=|0/,/}]MHVe|̚8)Ew޽oߨ4e ExR4~* ./K~["Şo~mE`21=M @͗y`Z[iNofY0ۇx$<ᩇ۳k*vԽ[{@|ays?XH>$5{ϙts&/w+aW+6acryx|/ݻQLq`%($jV p}3dǽMWNg~ʉuJ G)]8֛X>.`f;b;r7s>Ѱsf[ E"d.$FaXS>DIͧj݈Ƽ ~e&|擯g`@E) \٫9;."vJ_nb=`Gdlٵ'^ J=viO.5CT8kn:cʇb>ֱTΛhT&>{u@jm`%t'u;9:4z>ƗROrHp@p*ȌBxP2Y8ۍֆŇ{'y?}k~'yj8SN+Ox_u\u! {o֋72*3ya,RŻ3\m\yJϵC qySGs`2eRWÀXKw-vh =eo.&|CBvѮ3c~uÚSy;88|P(/t T:>O}=+_Τ̜Tq,<ܜd*?w><|ays/c![˜w4ˊ^(+LG;(<ȑ+Q<]N6Mt4pPs}gjgX! aD ŕBI`cEt/@F5EkH9y.p%- ַ=,ĜFWZjJovLy_dzb)NYB^vab0T(rlc)s?bc=oq.$WUBsۭ"D [?˜&erR@,q*ztwPGqGl?ՅVKl>^s1gGyH $}VmQL2eb)\gQ` `.>k~/2s1T!}GDۻչ|!? <#~)wֿ}?񩣛jc \OP1A@3k'tcV7ϿwT#HJ(anfZ~oi,ncGLNMY}5bĤγT*DBsdR B(մݮ`Ƭf 2SVi]7ۜFxz)*kL?1F,a{01c[P9EP42aūilMJC)5 oy<]8q$2cG76m[.Պ~^5>5&LL<þMl߹Zl"WlFÚS!yʔ)ڟ3 mS_xjRN)oƇpygr. >fٸV~V|̥,bgPt;FP+i\ǕiS)޽ӸߡbSN0>sA-UDcn.rmN9;ۡ''_՚w}|^|U:=Q jr ~vvLx 1'Ply&_zT>υ62AmM *DIA[kE4eG>.uCbI/juG0 Ԕ%X!usXl ${@ce_;^dyAJVړ 9I(DU/j&ES[s-~&,/O4&qsBnN,laUYy!6CkMbKrNܚT_OJ_)f ⤬L"@'&̸M3d̝ U EYKDže0Jhe:`ujU^_fsͱ3$j Н}2:nQR6j+RRmM1\Sz.|k8n;k6joE_>y-!SRXҘUO?j?卹'O|y. #Uqc?yI9a͆źIYr/fsNyw3#J&<$!pkA$ xI̲SU*/V鰯G}|%}gWLfV'[g8b5Zm Ei`}ʔ}?h7YHf|xdnj'J!y,4l9rp'^^CB)SRvxqcL(+`NUKO޷/rTvkB5#}͟ukw[:[M(+* oT8xk:λA|`v' WdnuVJ4& <ƱiJ\e*FݥUى3'e"Bs\n֠WC,2䝲ΦLh<Tk_?m~척 rj憰рZZ]=#:1v+QK|s/)SS^x10~;G[5G5l8c˧lSW.-pƓoGQZs"Te*I8δ]"B̫^Ŷ*S|ʔ)Sfg9}II$P<ŏ\ sy1GPXefd P2`> L8ςqIPqTJ~.gT(EQ4~@Yό1ᥖlB[1ɨdѱm^6Gyj={w] ;֙b (VǶRC5Gd1a!Tk,1ݥn>A#ς@:wsN*032LOT<_x\W9nhLA\g 0azO2dGR<}P1*;쥻Kp~N.[,\-Jb} MhzlC;sJ3Q ֗S#!nT5.3fJv7(Q DRXo2`n[upqDF(.u/,ouM'bõ٠oR$LZVZ'xCԅӷ4T\Uأ?QSs~cdapt10,nCV ankz#Vn|w{kmN`eT#gD2BT"yI'zݑI4mfq.cbdÊr۹x ^"j̈ұf}f' `qvO?q ҚOx̨"W *yd.1"^䨹!ee֔yJLJ]{г;7V B<ҺI #/[@M8AAysWg"-#-{c EUqƋjJP_&S|Y͟|.Jǵ =vH snp3yqc SLr0Ż[O_ۋ?t?} #P//co{e7Nʕ߭^]| |!ry#d=oB7h(+qGk7t?cC{G^zu 2$VZ@|1S;{K\utnrW<8%1;)+ }dHAXCϫt0&[ )ֿW[ʠn#<W{3Wy#, J+IqUQơ vv0%{3+H>Zd46MJT/tᶀԻc_2I~G 5~~a胼P֡ZAQZ}@EuH:9LʂT|ay]:N[dUɛ|@to@*Hjyw___[[,vIˈ5I`8rBJ}@m=g3q'$_|\6JL8g V_ >Q&ª'(hgܫq|[eyz`GA&̍4 fכo?J:pv_ߺjQDAk㰬\<'z7Dޘu*Y`:s;+ɳcvB=1O%$` 0n#k'̶2s)5 oyn7dOx6S::Y&hW)Sp#96񛡑d[ĦEB l}sF`2)}c*$O2e_֪Wx#SQyw~>hcqhbsy#.[#j-GQ7|/wj}h_ŘORt PT#2>*&¸n˜˼wl= [ښ_LτQ3RЯ_RP(*Y| l k 6]{**mkƩ EkZ a)VjZG|k4֣Jamm-_XfY~oD1JQPQNl Q Ltvh1Xր@եV7LT ബVDee(@Z}9[4V&|߯j.|Fq|JEЉQ*jQD%zV%/k7Vz%ވWDBreѝzuV[ _7x=Y7>pUMŕ;;g JX _1j1 j"0GI gSlkլv/Lk @Մ 4.2+m_|?N1N>+x$ ՂA,oLDPWp3.THDȬmם7H̰1L"|i=ק>cHp8sMP Ih*B-BnU u&wug*x[94Ur:q||׺=lݮ7nXQ)6iRSF Rk26zaMP^+Ģa_J%/H>w9]̼f^h3"i>nzc{)S5•k 1IPI!,EǣgƁ8`ޣ^:d^xq쳾koc_M^cK]?OqcQZ[E[%a)y%xXD5&>X[|ߞ^ھiK(F%ni*C%K|3R E[s>NDZbe;l>;Vᄚw,Yr8k+oFBI*=Ʉ21DFϢm|EY$K!yɒ%g=_#tSɗ~t!wu,ĞՀGǿXth1Jm;(nBme|k&y~XC~_m.$ߧV?[+<("kt>IFˤKAD0w5Ƌ:.7NUbcֵY|CՋvM6a)~i2)6kdNx {%!nP#rqOs\cw2+7rao\&)BRQ%I֏`m4ӰRrC{}l n(i}IGoJJS 9 aG fsSroٺ | -ڻ|F3땴F u еA {@4DAXQ4EZA!tXIYwkͱiI~0xaE{݇qhJ==vZIĩ:e1XY RE^,l 4HsfxqeȕKwvIEs3LWO:(~K_gnzw{s;Dőֶ#<.iR_i=ut֏q޵iD;7I:5ޚp?t,z4/_ǧ)/Ţq)0-Yr)+ML0Ϡ q!b=heL"ck,YrVI}˜?wb X`2Yv,c*Tk7'082C}ʗA}o:H4jQ濔gZ/'`|l$6Omi6;"b18w=M޴@VauW4d'xFfu59t auW,9XmunI}#+OG-1b|mH ߌ!`✈e9%`S(sn(Wk]+ȟ[?6M;ձFĪjU(,ccJYۤMih"+tm_gЮntPP%PEBDŝ;Rnm9 sIt sEs+Dps8lUr4''Wu/tj0°33(bw :0jS{Kt+C)L5_wFQKӕWJ vL悊"b9a5غUc<6ʾUn)PUL4A_!㾶4$sF]3(|wJEE5U*y"DP,xcL8N`5Z)Gv`e Y\(`{MQDaIvb*:,'ֵO+i&|Kl QQA=l4&443/nwwLY͹娥+L?JfX5JR7t|+]b4I_DڻþOAw-6L"^}?V?I#!Vޚ3s Ƀ٣.Y?j-q[lUGR%`f}N%u%:Q?WY{-٬^/Ùx_dk[w~Ϳ?LH?x?zm_ *4wG#6nE{!jk/x~x<2FTmmh}u;NB{XauL|3·=.ءpezjStԃ,v,40S᪖J0v|rf =ӹE:H ˗6&SZfolHs}gׇěCL3 :N0snɻٺ?ڣsi<>J%tCNTQ\2 D5"%x%P1g,V NK_Rd.`Rv}Ukv:J/DF}j}+3Uc5* Er9>b&|LsumGf8T#^8*GYX,R8;r1:ttĖeLlduf.TIn,t_~1[}x~/-AO9 v!d2Oš{m*&xO_&1 aw;yt:GW a|z^Py7hcu]{ؕbG Q|pk."î$A 4[׶^^&r, &}xW9&N%;(P# ^ب\]0]wN`>7-nȆ—\UJ7#Y/Yr)TbǸHP]1qd`GF)g9vͯՑi|_d;XLs/m7"X(Fi` aDzO}wZݲp䌰,Ydɱ?*A|W|uԑty̽ofWϷmMsވZž"P(#`9PalaiP(5<Ӭ00K-.BD)S_ONtsEk4q╼ ^Wݡf㋝($|Ziti-FI}q`# IDAT&)lus-#{ϣ3DiP[RYP Zb)rUVoC52LGBn҄.2l&5 &iw^{S2ϛG.k.I0Nnƹo&QF][;kw1f kAsg/=sX<c[ YDD%t`Ę`R=M/:ͱ[׶>;|E9P". OPx1NR({pv^ogsYc*`P$tV؝$V: JVAE罀Wt6o7"qO%_Koc(Hƻpw !VgUC &ɕ26#JIQJ 23ҾQL^jʉ| .7>RiKZVJHbWE.bsojg}\zY?IyjHUO3ﳩ0oek r2P^ş9K,y'I:oƱZ"D(+t#fZE{OxojX B%K,y_Gr}{5N:o=I)ێ2Rڽ\|'3姟VOM壇nyVZf76{_sܺh^[G 0T- W\v d3Ȝ{]ᓽM >Գh`$V *΂-+t Nh+-W?2^޺utb_zsX٣,i 2'i4)s0#"rGk[wE'WG՚lYRlj+|DqKٜIۊnm4Քnch#Q[O.Z_F4PC%S 6E!II tv3ן> ؁*li#d(qaHU?2yj^fBoL2]t$bL\Jg^ۿz)cJM耊<춡gEۢf !sg_{$IKX./>xMH. XZQzSϰkKFT|f, fn#wy%ӹՕUaPZB\$~Az4V}Վ1&A˚8Bt_j"׍ Hm+1hw6!\kK_z#I׋&m"7Q-UژX/˄܃ Y'˩fVLz;D t\: `ڂ2X;&mL''''}a_GgJ!%>sQw_s3XY~ƾla̜ 9C%K>ho_i+/9^Eu>cO 8f-Evy`K!yɒ%Kkv>yMaT=?T/仳މDʸvܽeƝW:S[ _v3.GX;X1V4z:Sp3nI1t7rn}N]]ŞD6r{j[eI ݼEH0Nةd"Y Aί>}(W5 2j(l>y-y#;͏U2xx0FZ ;X2ͣ٢w:a{bVܿ8(.櫜O$I %ajXp8  j ]^k/\bѴ$p@%J2'vW.y \vӒںݮ^UdC{(vL˖$'٧~)3hFA\zո]J{FY7FgALH^Of- f{ؿBh6DSӿS*LETɷc<^ދ[7?&'^J,mpl,Xy F^7qGk=_K4iVhnf:V0baD8h+^[KA$aլRweٯ}קBWn[U?J$t-(H C#6oӯ?ka_GgJ!ukQWM%PMi:/33WD5qFھACDӒ%K.r ;jb_q> ]^W/x=eGw*b.rR0 H#1ȴ=ѹCy*l;)bb!)ʄyxDU Y&)7t5؛9cg\8D+%Q:aؒȃuc9NHߔ"{QLI ;xwPcV4}8\J`mK *S@HCG748:٣|m2.;[_ū\<VfBVХʆP_8Q}@晹e4 W!'n8qۿcجu6Vf0͔j EačjEyijoqGKsGiIȇ[x# 5o$Fs>+Zg֘:Rn)P2n}7`Gv $#%]m]>,EUozPkxRAЙk\f#:"gbTe^NqDMQxv5F z:i.esD%K jܚ3kwCd! D;QD  y9!gw*d,Yٺ_ToTwcm4afjsЭG_қ,sgdɒ3"ђ&кf [[6~{귳W\iD=?U{w\vQoĉM?K?;>൭~rJNv VfP$ e1jɝ$qD<"ן^xvy&"L;ǐES(AT//S5:'ǻz/V׀:V9? ]i ڣ.zs'~瓢V{ĸ"F!ٞC #(ozu W qtѢkPTT5Ȩv?oFq>f0o}_=qŶH\qGw=" ݉P.>|Kc޷p\>13ٺ1ËU,fΚt^Fjw}5-P#gm?֟B=>~[ښu7׶& HQQ^uf5W>&W?+Y*z+!mBV OQ΍g~n&^>r>CXY7am2r.|qoQƝ>h/dݓFs"B2W"- f]Ļq +N"dJS'4.t% G`2q.x%$Q/բ͟_~H1.V/jiDP2 ŸdƉz¥xH(| *F[iZ_ۊjS?O"LeЩhUBo41Dgqsvxs)m8ic̅7D0S>l|}|]-Y:)Eq 18y 4V!1Gdcvxh<$ojJ.xQQ_n=?r0\#C4%As(Ľ66tV_45+t`+[׶^yb}{#.}6M/F^]e 18O!q>sI7`l`l]z,X.*>yWT(ƃ8S=+WlMYB=OmdJgo#PT+i| &4y_Wո"Oĥn']$nd#6kpoZ[Lr4E[9+}`xrQT*p<|? |b9t0׏zZaK^ZfYmin9J(h{h>~5.?O SþO4Ώ>q6s1qiMG=~7ANZ@6l 8Y:1Boä|n\۱z3>D#?E7ۢY;euD1iqwUX~Բ}V_sk {ؕSQL_avD ڨfFT"*(Jo"k$>|u Y#^E3Ka$qM3mc(L3 na`jo sÎ7ԋyo\;ފ+jk8_nViEdu=ㅕ ɬ&L9<M38wU! 4 # 7G0l{6S}ssOC4[00MUBozv䮔%Bo҇|N4/?6*)J2¦54.Q%$[aځdRlpn} 1D`ڄI)3~7N+u$[|{s%㸵1YRXCyA\K›/W8 }olJ̬bP"'ׯ4g=i^I)39jޕ;6 ( ~Re!fdX[/8wК7zeuBqiduz#ŭk[~~k~_5, %r&3mdB>W\-9 34Q ;w%_Q}a_GgJ'`B:4D$#Հ/]pŴnHMhXn>x,Y{kiV+-/OpE ^+?yY|#aS?V):PױQZ=ɣW+R'%6 }y{Fpԏbm 4WzJA,* ފi~8_}*?>`ؑΰ\ܕqD5ds"-\}1 7sGt+U}dկvDYHդ54Mù! ~W@ݨ9z?[׶Z+9sGLv;:,P ~&iՙѽDw޶i!V'B` "Оm6lnݱ"y#]k#kQW{nZ/ 8t tʐX<[؞ۺi';U8*RS sݩƓFmNm@f&3B ;63e!"Ʒzs[/ݖyl. CBKY0v'18`OɒG{߻XUbE/|+ (siMdrHrO(q@vwO:;F#`<>T$VT$&:% q%WFzs0hSu<Y|ꖖyI)?iɍW{JAAR'qT96*!'dɒ''3>fHmHOZ^΋1_+,Wg~뒇1"EMȫ"wD{O:%;^B[1 7!T0拟)!6<W/h/v~qF}VӴ/_fo| xN IDATw/}\TFyHBA%{iN? . +%Q&:? (HeOэ ~|":=gk5 ބ|)qq#t M]z t?}ox:}eH췰64V M,rB^G|;RBl, w^ʘīlC!LUCoӻvqsez {W7C4qBT1G(J:=~+ϟ;ЈӤvƆ2l4 _;pB>z5?8),otrƸ:ɃX%c1gw(ڊq c=}[׶Z/>"fW/vi1E:ܽBiPWn;}zC 5iSBxVG) seQ[suvž"~ҰjҭLaqXcĉ^$\lI!5UTkT`%Ğ_qc̓mo=ͯ'ݺl$Ff"ctS 6E␈RQN eH*\.ĒmY~Z{psϸ~cԖV瞻9k/i-`b~8}mskwV @VuJ+Aph9Hf !I$F'$\AS2Wjk_1IE@m6N&O^da*a5NP*~:G5H -y5u90ۋ."J+7JB%詶یL[sYs11e챿sڵHL^mZ(emT3jV 0 8 1,^ywuZ=X߆]h ۭԞkMI'sE$DdQ[_gÎo)! pbXGkW_S7yՔmFRn}|W=o,z8c1JTVq5ՓO|{s\P?xs?ė9?~ʷ܇C8v8 x딥!-j4Nh\ZiBbמSqg.W6\WbMQ%,9ݳ ,f H|A\&-~臎a& qt*_6v05>U-!R leXf&4"ʨ!Ḓܚ#XrYc][¾3{PHiM @4JUJ7ƍ-Qo54+aeJ;@bķff":o\l\ڨ{Ӊ`j43iԙ܂[Pc.yWodzlF|ݮwd.Ѡ AInĝZE_o4~S!-(q^@{8P) ވ1P|h^~wayǮ?ntsp)7#ͳ)!I ӄEQva;=v\s\m|[w9neL^~b5/NRIā&q{BJPFZ2,ݮͶl7??xgw}EIE( <(ImHm6FYaSflV.[﬏yJ${5g㩑AJ%3u&+cyg3e^KRv99sAyPw gYnlЄi æEMPG(rXߧ8"錃oqbXYqn`Д[,>0|L]Kc=77 {nVq6jN/$XwrfRF8vqtϲBw',jmMa /=39V򈻻 nef䌔*Қ(K#hVak6wq!Ao[7ݗ\c{msXjI,*4Au]ޑZkuv`0S#rn$y$$TgOEiH@NB$ ?AŌ\CJ+Yzu[qe,DPD!'P?puW {ono1&fE(j|fLL!CB∊rm]Qɲxd^|S{tKF9Gu< .(#ϫ9bVҝ1[ƥ87ӏդY<?hAYřKlԚB cfڄY k{c=+cHAćo|E?O=9P t'9ټ7N-q`>硍K7Nbž?YM*o."mzVv?e~'׿CkA F޻ػk2򩅭ehL((х-yB]΄r{3eTq \*h8[B]W1~Ί[[ Ecϧ /đY-k~o07`q)DC{&Y Fz3*ٞ~Uec*[j xi.ʛUP٩T1^ᇑl:jؼe P[&Pw( =3vYܧЂS1=pqVJip 3r'q:qA%k@:]:lY/JQXpF{pkQyy]pV>]w~W{ԊNRuq`;/4+|cmSoM]`'_T_mxӠF6|2#P#ۘ ,4_'$(X}9 5cI gEs om@ R&g.Wwج̶X l*LL&to4zQr"͟=~t)f :}0 j=+hdzhvaKa4!֚ӳK),}-LLS+(&F3u{eOqgDŕleeVSrgI7%uPP4`*"{Vs8dt:M٣`ۥ8Q{4 5cV!t{-+~#73H[;)8*fM0J<օ<4V=`H#c96SY;M˧+ATFao&~[MnQs?Yo鼜+rOޓ{JoY=%Sk8 EyCɂ؟g.W=|e4,*SPSLSbhϩ,nEQ1+h~wE)tvŋ6IvlΈњFC^Sp;PDr8+ʙT͙HPE5*BiT}sj,FU$WoMl@H00KYTlaXVJCBT9$&)ٍ?E u[#m zr- 5Z:c3|ضb;PfdWΕΒW"R [Skkޚ-rG7]Nhb3Э-!ڭ,ՆJi&)@\/Ϝ[: Ф „$Q:StG)Ǡo)wnq]֧k1Uچg^{{ bUHQfc{HkdS2KT(mH8۬`ܜH6 e:Avq%?ҐHfOcA!,UuiN,j|${?{oh!M\P/CIVXasys8_j8e51M‚{LǍ< ^}(/bs\}saƗ!}Gq9bQ,BfJF9,25%vt֌7 ԘIp{+xI?1z6qAnzTJFA,`' *7ƴ"k~Oqiڃz1x#[X*\^_ unA\kШ5Z/c,a~"ܦx sEG+","}DdWD?"[v}+5DZl@93ys?7=ӏ/ʘ3Q!ͧ&8w,ksULWnv)+=9{abz@0a"xVu?%7?5rwKr-<W=S)Lb"u`*'ձf Gqj[=wYls3ýo#yQSĬdI f[dOZ)q mO^g{wf>k [9;)Y?1tePE$QoI ͪS mU32F #wc9*#X/"6Ǿmls{p-$3$S+ԘE?]bN$e!"_G}S|i;e"YDxכxU}Ex}M|&x]flua#E փ%S5Bj N>iǩюW_$( MZw?PO6f{mYN0\fE]aeLoo];≏76.mjSkH{FTLS~8 V7EDhFvߍK$잨Q%*;QS&A ) k+=3:% (zT۠^*: =(EpI6g۹5 hV5+X^7,UmF/?ٻ!Hҟn6WVP5/Yި WTz3"]9HJ8Z\)`.#=mc]Bon蕥x _q=SFEH>i^6(/yJgd'y#KzV'"~ڭI(߆NUfڔ^r;RR;eԉr~3f,g6$Xm0[޸q$87߽ٛPOI[**u >&\]XS__Fxt6g:s̠_8šbz]**%M;Z]yr𠷣~|'%tWZ֢@XYq~Rs܋xH+- S16g?׃i;W(^{EE d ~ҩSbb?~gdeJ wnK/ :Ŋ1ΘAi3VZMkNqqickq1',n_k 2vw#V.ీ/r!4jeϻ;Q+O] \*Aok5l& //$FnR3:wkR<}|X4D%AQ,BL!+7.m ,tMw{Z`ڞ@A݂J`4T8+V\Q&v0;ûub@:j30әvuF5(B QmHUbZYq`u˅M`Qe呏gm*7dI)ei_Y.Ly E"n{N^]wn[{P{$tBJuTFj%g$ō2Xa]_ohޯ=W7.m]#7TUdR-k0|?ZxmrZ=RdFO Dr>%-}o37~K~ c2̶"%-νn,@J1P3tve{Π !$e 7{a߄A3i|i2_cc~u'~ őFB9FB ;"Z=̟]sq챲5 n1*8daKPDo%ay|z0<"r!<~xRU߭WU_yϿכ͜s2?-ԂGGx۶/g6LM|[n~7 |vr;;}'sw?^X8?rǎD>Xlh\Un}Ọ;VѝZ@sc), \83Ov}nvğ DtvfZ9lwATĄsIVݡj4fO0RTQ8"2 •e'|99gۀvj1Л$(VkUoԞ3#ʟKc"k htr%_ 9]ɷG;ȃ>)TbUSU f+lk`\0I`A%R"?=9*U@4  !Xa8AS.:s)wб(ǔV$'gT4V\H\\Eri4V۹q %%l嬠JkHEƉ.܎kU>ũRលZ -C#Ex`{ ` ڌ"D44D Ԗ ?g;̢"TNŔZ޸_rbzݩuu#@LUUpj77N\#\~r4I)nd BrD`ݝh5/g{jF\B r҄Y  .z(N2rCjVyƛPBRA)!"qעU!jG0OݱeG1EuJ?DڳUiP}w0HCu~҃ގN2g/[naB; "8Bc M"c -:HDó;BbxV]sZ1M(S9%Ol lYe׽cT;TO k"r|͝Mv~@J ,=p@"7hi?x?]Rf) q 02Fa "Ee$x\{)>LEm q4##?lo{D#a]śj}).?sy:W;лU5ejNChG =5ܓez5#Q q8 YoJ23J\LxIY7H7 # RoF>ڇD;t!vȤl;3dV#;+;AT ,݈>^1SQ#%F6f ^L]8Y(.6s1VjOd-U}Hc @א:(a}REj-s c98u FT\QS(Rg荔1uI#ƣW0<'?hq$+C8$p lwZYCo*7D/)9ς{ގN43Ldlo3& ڀ2ɼ%rU)X$]s;sqo+VW},i$TE_,H %dmwĮa~-bnm=a|@Tr;DDK2T8o+|ǝ7;p# FOsײ(Ghtkzk`wW/r{hظYWB~"JЦ`1n4 yxDž1^cg;qO5YtcboQ1:@.hg&O? )uНvʴr󩢐ˍƅK\>Ag#S{S5$,r%E 2.VU\0{MLeYLcXB(;pgax1> ?G/? 幕ZYWH͹mX:"͊a8Q$Vok्}n5{ CI; r~E$65{VHY^;m)\m 7'Y5L Qּv]?9h|^Ή;hVBRY8AST+Q4[[ <'dEF{]l4znxޯ\zcFfg.Wo&͂Ik՝H(3;F$w`kvЀD$ 'Y;M\vTf*>Н)8:ԡډB1\L Q8Dr[BBCfo<<[U /ǝ,~1Utw*KEjێm:pSwm #Δ&8Զʇ5FM/Uܙ˜} -^iTɴo2'j5*πQu*wE}&R%х񠷣~|'%#ԮNd4.Np6UHؗO(8"Lc98w⦎#b]W=TJ-eU500=eث]3>AsW d\u;^8"aUr׍7ޝqclP{W46ѭ&<>s笯忨b}cublJ:Gm~x'|ۈ;-k?WשYfiMw f1h8v:oN2%Xab`Agt0.'31U0=O^LѺT0bǙ OpV1oXy"3P;"8 _\פX7v #//(QVZ I`8v]+~KE}b71&>YUVo-Ɋǔ  FMX(_@XSo{};7LJΓ$X8F>rSy'QY#M>+道BE{"Ԭ53mOD cpNeꚐsnwF7n5ۑs;E$8^XQVpq.d/3{m!aB;zwo7^oy=ߙ(gwC 7;a<୽19D<Y>XZZU`EBˌD|U`H3hi>\Ԫ6ZD.)RIjԞ߆* {KPqh&TVL(㾠8F` sH g:pq:L0c8UQA0~ԱqX ͱ1*.li(_^eMf7q! xdoœ^1t*Wә}qO's>ȗ'?D _;^x.DU1o}kޏg|~H[UTuUT4VzqϢmSlI)ٞl-RE_Z3N[mcLNtK;yMf];LM8'ɫׯnSgǒK&'{'MmHɴ3dXSRjn󔔘H$:l9MxR[OJ-5ۦ[*H؏+x ~WwУL3 Zom&\cmSyEwrMII *duՒDbjRO}B Co/OfнyLKS)KL&shg{zD{BR&|ȝ DFRBZ_ڶ0HgQpyNJzTxIgoG:3֗Iۼ}:֔2sg,LO$ )Ǵg4퉁tft^:dG=T)IhTm,ɔk,!mͤ—)2Ak䶩`dBScfcSĖ8$3{}GG:=̀Rut:Z]X}IERq9Me<,CL[*mxj2ivhУGƒx&S?cXZC= ^z2I3.#m>|$.WG&a$^@$iѾ% K2Ltrj2ޕH%ܛ:&RVBhPfNOhQ}@}m<:Gսz;G:jsW-xaZvF$swﳎ+hw@D]W_})N;oT#dF _Oe{{ҩ= +JHEHF#\3Cw?w~m*|{L gRhySJvdOhb_Jw6fh%Ke9r'TWKlR3O?mW:{\?2ZPxg?]ZDG}IDǐ,ݝYL{{Aig=̑2RAK3֯cL9ը%Pqw^U85ou$!0ՖN<1t4(!---&`R=#1c#cY*Õ,bg,hxPJ559#x"w:GmrLMzM=C ]t}B7JdLr? ڝL̞hzs;ljNSz_dA-}nIJ&*-#;?j;?ٹ#y@IH=wdL+>p=IHSfq%RMC'i, 61՝t0< i?p?n$m@k*l7#M-zǕj,M=L|)IJ$&E{)Z$g6N!M;+xYdJ8皶);jgg4I:&V]Ama-k\֣HnNts__XWuiqLdSIuLk44^9O)cJe3ӣwIۤT0Iߨ'NGS]8)5ڝI+9&)|3M% I,P*9"#w)|/O2)iaVћegO/6j-R$}6_RjL2 Zd[Q_i~v[_QɎ.MkSfaCor귩/bUΛYK뼍1%K3c_8KcTT5*q2|~722rYEjVe ̕YKo D{ @KErhzMD=lɒ*CHz=g7PL"r.\vm_fMޱ֮]H]fMޮ׮]@0[fHz$~;8*Ǐm5}D'+w4֑ޥ%Oԗ_:u{(Ě5k+\aH$ގș.7.]?^^,dFR\fDu0?3TvQe˖It,$-*NIJ&q*WҵCCCksВ'''ԣ*cl<6WzaR.9J]rTe&jyRttt|ohhy>{?iO P-FF0[n6zԛ-bfACVIzrֲtrl絪9cϓt+;3Si===wz߲Q|vѢE im贶G=3:Ec&Rrij1rZگ/9I_Ztr|v}m'%=OHZl]4444kbKZ^s$o`k% V\ɨ `f&s}grIt.&Wa񅽚?־W+#}=$x~^a7 ,q$cD2Ic:VD9ӛ}4L#$ŶG&1"KK7gE%Xrx2Y"X*I.?vj3?&p~#_~qB⼏~_DM5ӣ;굩{HJsyKыsp8{ݽ65v$5Pc~ylYJr;k[#ٕf!G ]q+&_GFFN9Yr߆eQgKYߖn1=,.y$ <44GeUz;_ro=uyk[,VePl¿}8L|1)ߓ9zu<44ԙdH=DQFe%%-zM׹s}p Lq)5-(*?mf/wYMNSOܬt~fȘ|V5+>mZ \<>455rH*!zQV{(V*O >Uj^8'i.8tG8zm{{sOX['.Pہ{槥=m]C '5D"^Ab䬲lݿTr71z"閜6IOo|(-m/(ZI;oIRO3iV>q:q6ߨ?}kgq 8]Q<;-zs6C]';R|,mtL=sfǀ&2Kʚ~H(0Ofvj .髒c$Le9to)kl,;[n*5~(2(2(2(2(2(ec{v~3 +5 #s .%ޔpH$qxjs_0JҿYJ|d5FTI-kp8p@ ><<8l D-Dh(w&%}RRg VJ">FFF:5s`AsTc aq-[q/GgS;oN<3'dݫ/mjP Q/.G5Ny68`f!sufvwK3YIkFƇZ)ic*Iw5)gS=a_\jQ @p8Ϧ3>cj3o.JmuLn(gTP A2QNH$quE]#r3/I#i%7#6Iks |61%ոNSM'̞>Ms)1J}]|6 Lg-;ʼn]쒴TsV?q?qF5.,#hqum:'޽^D`ٗ@ ldD-DdZPyi咶2@lWT|4 d-addSx+65+gS=a_\jCCCŵlٲvzApEM18U;]ܶHn̓s[?q?qE"@X)ic*Iw5)gS=a_\jQ @p8ϦEOGϙ$rϣ_\jQ 0 ZIks |61%ո'ޕ+uJ"l9g'b֭~}Tj\Y_ s*Z1sݛiԶ' ^GH# tUěXSC;L#b826#ipԄwXQyʚ<" 4ǂ%3 $ofmU-P'dJIWw5>KK{LCn M$[!fH"?[!NH$E-9e]h|(%1 ̝Z,)ݒ sKM f⳩ǰA/.G1'J5k\IhR,'QtTc '<O1@͎՘dIw`0M8 q?qْ=Q @D<.>q [}xGDD d $3H̐jvPC$mQ u⳩:q ש:{)S<z։NGQN|6Z':1Xx:#uGZ:qi9͎dIV]͊jg/@"0d $3H̐jvCڜih<@L7;@е5`H$f D2`H$f D2`TXfvW(xbf%JI/tF$'{>4-@)sf,!L_\Rg8k_٤*fvK:b%1Q@kE2lK%-hv,P+f*I֡\nIMґΑt/7#V#HZ" ]AyJ;%t%tSjff,-IY(H.@\,nIGKzߜ?jf/t); I42P+@sdO٠H$0I|"ˍ`+ID2D2w4T¢?D10f/f+3kff~ff15;FTyFQ@KE2P"3{%%âߺ U9 cB̞/iUfvX5|ZȬ҂ 4I zT1#%@ %,wN7J 33 -D2#|c IJLuFt*I$=,hI'?[җu\Z\z16I/*Zu\A"bfGKz@wVk*&IȊ4IT۴gIz9F-f>coA0'$1I )˲P$wnnYlYТ3!iMVњBG"hkHzO[G%])i4G T!*I)p/(\y1JzN8SVRe$z䦍J\^3@E j@H$ԀQ+X;U2IzOntGfZs͎@H$;3@f]mtgY9풺 IE>I$=^$ W*ׯ5kvG"@]ef[T"l!~ lnwlP)HlݒnvPgJ׽tZҕ9IdfvV ^wHFH$Q3c\Mqtj jD28]+T`a?4bnHHUQ/@"@3 Q6P|Q@ H%$c2u(ohPC$4C>Mfv\*Н3C"@ H'I9`d'I3fva@D2fZ =3K68$ffffh~}Ds"$}a0ILI&iUJ|T.IwIϻekΑbIgIZ!_^IJ[ҷ$hwbfO|IgK:Q &i%N%}6(IϓtsXI&% KO~$>ވrb#XI.>U5 );g#$}HKg$wTi<zIǔIJfNHAk* %ȽY*T 7JzJ1) we%Rs=%YC?HJ ?Yvs2$}@Sf?EIopm23$}Py%9>8X*x T$i[80;L %݇$s-R$!JsT-4/+H6DH5L(?%}W%%[һ$m0y%S3;nR${nfVКJD*Iwٟ2.IK'fO"oo`%QK $H.0$w+5`f/t{~IdIjSЪf&l!^+QnVœRZTn3$ÄF_-vD fXm}QT^Y >Jdfיjb@ixL_\yy=Aǒa;%ºN 3 ?_(Ozifo[VhI?4(enQKC- =83g+{I R2/HRCI=la& _N/ɵKx(H -tg13 \M(H3 v.—(H&o$}[R1?\KäWuxwۛ%Y9@Akͳ%S uafIcKoW ">SA$}Vs,vH:CD*Zש=5sEz>^a\ \Wf*̻O$=U=hI(~O:_ffO2>:gu^snw5ab83*ZIϖ\}g>XPs/ v|sYv7,I_ɳݒNqJA4-~A)udյE[וSW =[ʨg+JXt^̎S(47$# v[(:wv=YJG{XA^0vNI(Pbʌ , Ioq|/Rdstr?tKiܮa*OԺkޯ|2 z,xS{$Q_c1nQ{ą:ȽY*Tߡ­[7J;w,u%s해ݷϠK^l)KN C,rO],niCIOa$&\  {WBϺz޷E3KYjq˾|HLUOl }TfI ȒKX[]II:?Q( bWFI'%%ݧ P5fVnS$KGwlI0I:WA7Ӕv9N$nIpiR,IVcR,,I>oQp^jqfVm׿(=I |Uҙ%%)LPA\*|#;wJe'5Sw(hHE.$*Dݩ׆B$LiʟDْa<~>%W zG@HLNxk–R(zI{.~DE%@zϬXIWe; ZTtI. |(H ]˗-&$]װΒk)I/rSg|q~ C>cGҋ@{Fy+VwT {KYݧ{[NwԠޣTg\(w:cq(8> ʐHL|{I5KN .ز2[Ngz ?^+hmf/?%k&-1u 3;:t@XXIz)0)vQ'fsm畴|yuYTQ]( +~g58@ʌ1qHLyɡ'O5RF}M q*ܵ,U,et!?rWSAxPAE!%Ts)7ReRеn)-M*^SvQ$UZNmyf=:5_+he_=u_? [ײRՅzE1@ HLxInMQI976.m.z.,aIS~]wMyfb߿oƘVՅ#?Z`ͬn{Q3;N3O 6q}Z\ukPO1S7(wסR[ QA,h0iH?_b_hft?5yu^Eց-r(__YDZ*: OILQBר|3{|uNKQ{o WA<h "+ӷPbfVCHsQU-?+N۫ʟdf,%<6k.sif]UU[+(kw&iCZ͢z*P^RAs%zϗ#3+4 d1ϬT|,B- QF'':봽jꆻWұE;UR/]TQg"L?xs?/P~FPxx u\wU0x^e:"mf+gf 3;P_<7)^4?YqI$F-Tlݝ7+:@愈%p5F IOQ^IGx[sݑr-)5TW$}씤Jn0Y[1NH$VCxM,ͳ8_5-2?)yn}NlHd(D2x|cNS{Sź-ZT@ʐjⶫȼbIJj=[(IBů;IZ,鍒n5WT9;*D"@,>Io3$}4OyƋsȼ [ۮVwyN$X(- z/as$]ef@H'%y2d<@muZyW]OX|gR[\$vw"V[`(fvQ=!< wHzC6gZ%u_}ȼB-VR3QUxǺ_d^+'(p*IgIN>Vu$ċTyf$9ebmE)P~\TDrŁq= wZ2ItGM5f `# ^hA3kϚxVPy(\[̫uұX}x[s]au64DwwAeWHHXihV9F BC!4H?mHR(Xe#dXB+_Z#B4TW<)>g|>3;g}g}ޝ$9<U3hh$A2tIY)f2m7=Ҿۜs{HE<i#= ]Yջ7?$ݖ WCx,}e{YI]AbzuNA!ݼf$/~$0ppHl[}$GhDXwߟk|z7tB׎u}I>=k9֏~/#/9~t-+$Rwߛa=!)5##폚S}vRUu`gt_رǯd\+Gڏ^zl-U#/*+<ܼ@H [$,uZU=&Wt{FW_d]x"}ZF=8s82c~INXˁtw'Hr,A2ޝa;G\aݷxVQU=.{n?uݽe eޓu_Ԫs%'ǿvJ곰d~CU$[G=J] tfXtpUt:-I5pve߱}GtZU92_Rm箰6$k0ROikN؁ CgT3#ߛ3WOz$}H$,'H;m{WՋg):9nՓᡑxwύ^auMVv.|>k2?f w'y*,kkOfϤ飯f>6x 3wgΩﯪ|(Ch3OW%)VIDAT9n2kdr]_Y=&;g'y DZB}sU$c+ؖU` ,m l4~+uR}INM߹z<&축ڒe{K`꡾a6_0so\$GOƺI~1yPIeYe$K9~ ɫ9`d`C}J?a=3ؒg'\N<ߞ!~.Hyu$?!y|5ɛCRw=3,Kw%9_ZUwݧfXzBܟIݧwj=XL~n>+ö_C[3}j0FtfWpw_ K'/ג5*gO>4K>a5N&A~I,ז 3Mʬ~_%qOO< K{lЭ%wXӽ$?W|r_I$O{%sۺ {bFf(s[}qx,=u~"1fIa%tK\|;:4ɱIj<:[3W'y@^*Iy@'&+ÃHrG]ݟZ1&_dSz3zoJ6'DkY2,g~H'yRݒ|3õ|3s}GU~}MI*C_uIIrmwo `&H`"H` )d"H` )d"H` )d"H` )d"H` )d"H` )d"H` )d"H` )d"H` )d"H` )d"H`vgSIENDB`opt_einsum-3.4.0/docs/index.md000066400000000000000000000121741467526163400163040ustar00rootroot00000000000000# Overview Optimized einsum can significantly reduce the overall execution time of einsum-like expressions by optimizing the expression's contraction order and dispatching many operations to canonical BLAS, cuBLAS, or other specialized routines. Optimized einsum is agnostic to the backend and can handle NumPy, Dask, PyTorch, Tensorflow, CuPy, Sparse, Theano, JAX, and Autograd arrays as well as potentially any library which conforms to a standard API. ## Features The algorithms found in this repository often power the `einsum` optimizations in many of the above projects. For example, the optimization of `np.einsum` has been passed upstream and most of the same features that can be found in this repository can be enabled with `numpy.einsum(..., optimize=True)`. However, this repository often has more up to date algorithms for complex contractions. Several advanced features are as follows: * Inspect [detailed information](paths/introduction.md) about the path chosen. * Perform contractions with [numerous backends](getting_started/backends.md), including on the GPU and with libraries such as [TensorFlow](https://www.tensorflow.org) and [PyTorch](https://pytorch.org). * Generate [reusable expressions](getting_started/reusing_paths.md), potentially with constant tensors, that can be compiled for greater performance. * Use an arbitrary number of indices to find contractions for [hundreds or even thousands of tensors](examples/large_expr_with_greedy.md). * Share [intermediate computations](getting_started/sharing_intermediates.md) among multiple contractions. * Compute gradients of tensor contractions using [Autograd](https://github.com/HIPS/autograd) or [JAX](https://github.com/google/jax). ## Example Take the following einsum-like expression: $$ M_{pqrs} = C_{pi} C_{qj} I_{ijkl} C_{rk} C_{sl} $$ and consider two different algorithms: ```python import numpy as np dim = 10 I = np.random.rand(dim, dim, dim, dim) C = np.random.rand(dim, dim) def naive(I, C): # N^8 scaling return np.einsum('pi,qj,ijkl,rk,sl->pqrs', C, C, I, C, C) def optimized(I, C): # N^5 scaling K = np.einsum('pi,ijkl->pjkl', C, I) K = np.einsum('qj,pjkl->pqkl', C, K) K = np.einsum('rk,pqkl->pqrl', C, K) K = np.einsum('sl,pqrl->pqrs', C, K) return K ``` ```python >>> np.allclose(naive(I, C), optimized(I, C)) True ``` Most einsum functions do not consider building intermediate arrays; therefore, helping einsum functions by creating these intermediate arrays can result in considerable cost savings even for small N (N=10): ```python %timeit naive(I, C) 1 loops, best of 3: 829 ms per loop %timeit optimized(I, C) 1000 loops, best of 3: 445 µs per loop ``` The index transformation is a well-known contraction that leads to straightforward intermediates. This contraction can be further complicated by considering that the shape of the C matrices need not be the same, in this case, the ordering in which the indices are transformed matters significantly. Logic can be built that optimizes the order; however, this is a lot of time and effort for a single expression. The `opt_einsum` package is a typically a drop-in replacement for `einsum` functions and can handle this logic and path finding for you: ```python from opt_einsum import contract dim = 30 I = np.random.rand(dim, dim, dim, dim) C = np.random.rand(dim, dim) %timeit optimized(I, C) 10 loops, best of 3: 65.8 ms per loop %timeit contract('pi,qj,ijkl,rk,sl->pqrs', C, C, I, C, C) 100 loops, best of 3: 16.2 ms per loop ``` The above will automatically find the optimal contraction order, in this case, identical to that of the optimized function above, and compute the products for you. Additionally, `contract` can use vendor BLAS with the `numpy.dot` function under the hood to exploit additional parallelism and performance. Details about the optimized contraction order can be explored: ```python >>> import opt_einsum as oe >>> path_info = oe.contract_path('pi,qj,ijkl,rk,sl->pqrs', C, C, I, C, C) >>> print(path_info[0]) [(0, 2), (0, 3), (0, 2), (0, 1)] >>> print(path_info[1]) Complete contraction: pi,qj,ijkl,rk,sl->pqrs Naive scaling: 8 Optimized scaling: 5 Naive FLOP count: 8.000e+08 Optimized FLOP count: 8.000e+05 Theoretical speedup: 1000.000 Largest intermediate: 1.000e+04 elements -------------------------------------------------------------------------------- scaling BLAS current remaining -------------------------------------------------------------------------------- 5 GEMM ijkl,pi->jklp qj,rk,sl,jklp->pqrs 5 GEMM jklp,qj->klpq rk,sl,klpq->pqrs 5 GEMM klpq,rk->lpqr sl,lpqr->pqrs 5 GEMM lpqr,sl->pqrs pqrs->pqrs ``` ## Citation If this code has benefited your research, please support us by citing: Daniel G. A. Smith and Johnnie Gray, opt_einsum - A Python package for optimizing contraction order for einsum-like expressions. **Journal of Open Source Software**, *2018*, 3(26), 753 DOI: https://doi.org/10.21105/joss.00753 opt_einsum-3.4.0/docs/javascript/000077500000000000000000000000001467526163400170145ustar00rootroot00000000000000opt_einsum-3.4.0/docs/javascript/config.js000066400000000000000000000004541467526163400206220ustar00rootroot00000000000000window.MathJax = { tex: { inlineMath: [["\\(", "\\)"]], displayMath: [["\\[", "\\]"]], processEscapes: true, processEnvironments: true }, options: { ignoreHtmlClass: ".*|", processHtmlClass: "arithmatex" } }; document$.subscribe(() => { MathJax.typesetPromise() }) opt_einsum-3.4.0/docs/paths/000077500000000000000000000000001467526163400157655ustar00rootroot00000000000000opt_einsum-3.4.0/docs/paths/branching_path.md000066400000000000000000000054611467526163400212640ustar00rootroot00000000000000# The Branching Path While the `optimal` path is guaranteed to find the smallest estimate FLOP cost, it spends a lot of time exploring paths which are not likely to result in an optimal path. For instance, outer products are usually not advantageous unless absolutely necessary. Additionally, by trying a 'good' path first, it should be possible to quickly establish a threshold FLOP cost which can then be used to prune many bad paths. The **branching** strategy (provided by [`opt_einsum.paths.branch`](../api_reference.md#opt_einsumpathsbranch)) does this by taking the recursive, depth-first approach of [`opt_einsum.paths.optimal`](../api_reference.md#opt_einsumpathsoptimal), whilst also sorting potential contractions based on a heuristic cost, as in [`opt_einsum.paths.greedy`](../api_reference.md#opt_einsumpathsgreedy). There are two main flavours: - `optimize='branch-all'`: explore **all** inner products, starting with those that look best according to the cost heuristic. - `optimize='branch-2'`: similar, but at each step only explore the estimated best **two** possible contractions, leading to a maximum of 2^N paths assessed. In both cases, [`opt_einsum.paths.branch`](../api_reference.md#opt_einsumpathsbranch) takes an active approach to pruning paths well before they hit the best *total* FLOP count, by comparing them to the FLOP count (times some factor) achieved by the best path at the same point in the contraction. There is also `'branch-1'`, which, since it only explores a single path at each step does not really 'branch' - this is essentially the approach of `'greedy'`. In comparison, `'branch-1'` will be slower for large expressions, but for small to medium expressions it might find slightly higher quality contractions due to considering individual flop costs at each step. The default `optimize='auto'` mode of `opt_einsum` will use `'branch-all'` for 5 or 6 tensors, though it should be able to handle 12-13 tensors in a matter or seconds. Likewise, `'branch-2'` will be used for 7 or 8 tensors, though it should be able to handle 20-22 tensors in a matter of seconds. Finally, `'branch-1'` will be used by `'auto'` for expressions of up to 14 tensors. Customizing the Branching Path ------------------------------ The 'branch and bound' path can be customized by creating a custom [`opt_einsum.paths.BranchBound`](../api_reference.md#opt_einsumpathsbranchbound) instance. For example: ```python optimizer = oe.BranchBound(nbranch=3, minimize='size', cutoff_flops_factor=None) path, path_info = oe.contract_path(eq, *arrays, optimize=optimizer) ``` You could then tweak the settings (e.g. `optimizer.nbranch = 4`) and the best bound found so far will persist and be used to prune paths on the next call: ```python optimizer.nbranch = 4 path, path_info = oe.contract_path(eq, *arrays, optimize=optimizer) ``` opt_einsum-3.4.0/docs/paths/custom_paths.md000066400000000000000000000076761467526163400210400ustar00rootroot00000000000000# Custom Path Optimizers If you want to implement or just experiment with custom contaction paths then you can easily by subclassing the [`opt_einsum.paths.PathOptimizer`](../api_reference.md#opt_einsum.paths.PathOptimizer) object. For example, imagine we want to test the path that just blindly contracts the first pair of tensors again and again. We would implement this as: ```python import opt_einsum as oe class MyOptimizer(oe.paths.PathOptimizer): def __call__(self, inputs, output, size_dict, memory_limit=None): return [(0, 1)] * (len(inputs) - 1) ``` Once defined we can use this as: ```python import numpy as np # set-up a random contraction eq, shapes = oe.helpers.rand_equation(10, 3, seed=42) arrays = list(map(np.ones, shapes)) # set-up our optimizer and use it optimizer = MyOptimizer() path, path_info = oe.contract_path(eq, *arrays, optimize=optimizer) print(path) #> [(0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1)] print(path_info.speedup) #> 133.21363671496357 ``` Note that though we still get a considerable speedup over `einsum` this is of course not a good strategy to take in general. ## Custom Random Optimizers If your custom path optimizer is inherently random, then you can reuse all the machinery of the random-greedy approach. Namely: - A **max-repeats** or **max-time** approach - Minimization with respect to total flops or largest intermediate size - Parallelization using a pool-executor This is done by subclassing the [`opt_einsum.paths.RandomOptimizer`](../api_reference.md#opt_einsum.path_random.RandomOptimizer) object and implementing a `setup` method. Here's an example where we just randomly select any path (again, although we get a considerable speedup over `einsum` this is not a good strategy to take in general): ```python from opt_einsum.path_random import ssa_path_compute_cost class MyRandomOptimizer(oe.path_random.RandomOptimizer): @staticmethod def random_path(r, n, inputs, output, size_dict): """Picks a completely random contraction order. """ np.random.seed(r) ssa_path = [] remaining = set(range(n)) while len(remaining) > 1: i, j = np.random.choice(list(remaining), size=2, replace=False) remaining.add(n + len(ssa_path)) remaining.remove(i) remaining.remove(j) ssa_path.append((i, j)) cost, size = ssa_path_compute_cost(ssa_path, inputs, output, size_dict) return ssa_path, cost, size def setup(self, inputs, output, size_dict): """Prepares the function and arguments to repeatedly call. """ n = len(inputs) trial_fn = self.random_path trial_args = (n, inputs, output, size_dict) return trial_fn, trial_args ``` Which we can now instantiate using various other options: ```python optimizer = MyRandomOptimizer(max_repeats=1000, max_time=10, parallel=True, minimize='size') path, path_info = oe.contract_path(eq, *arrays, optimize=optimizer) print(path) #> [(3, 4), (1, 3), (0, 3), (3, 5), (3, 4), (3, 4), (1, 0), (0, 1), (0, 1)] print(path_info.speedup) #> 712829.9451056132 ``` There are a few things to note here: 1. The core function (`MyRandomOptimizer.random_path` here), should take a trial number `r` as it first argument 2. It should return a *ssa_path* (see `opt_einsum.paths.ssa_to_linear` and `opt_einsum.paths.linear_to_ssa`) as well as a flops-cost and max-size. 3. The `setup` method prepares this function, as well as any input to it, so that the trials will look roughly like `[trial_fn(r, *trial_args) for r in range(max_repeats)]`. If you need to parse the standard arguments (into a network for example), it thus only needs to be done once per optimization More details about [`opt_einsum.paths.RandomOptimizer`](../api_reference.md#opt_einsumpath_randomrandomoptimizer) options can be found in [`RandomGreedyPathPage`](./random_greedy_path.md) section. opt_einsum-3.4.0/docs/paths/dp_path.md000066400000000000000000000105501467526163400177270ustar00rootroot00000000000000# The Dynamic Programming Path The dynamic programming (DP) approach described in reference [1] provides an efficient way to find an asymptotically optimal contraction path by running the following steps: 1. Compute all traces, i.e. summations over indices occurring exactly in one input. 2. Decompose the contraction graph of inputs into disconnected subgraphs. Two inputs are connected if they share at least one summation index. 3. Find the contraction path for each of the disconnected subgraphs using a DP approach: The optimal contraction path for all sets of `n` (ranging from 1 to the number of inputs) connected tensors is found by combining sets of `m` and `n-m` tensors. Note that computing all the traces in the very beginning can never lead to a non-optimal contraction path. Contractions of disconnected subgraphs can be optimized independently, which still results in an optimal contraction path. However, the computational complexity of finding the contraction path is drastically reduced: If the subgraphs consist of `n1`, `n2`, ... inputs, the computational complexity is reduced from `O(exp(n1 + n2 + ...))` to `O(exp(n1) + exp(n2) + ...)`. The DP approach will only perform pair contractions and by default will never compute intermediate outer products as in reference [1] it is shown that this always results in an asymptotically optimal contraction path. A major optimization for DP is the cost capping strategy: The DP optimization only memorizes contractions for a subset of inputs, if the total cost for this contraction is smaller than the cost cap. The cost cap is initialized with the minimal possible cost, i.e. the product of all output dimensions, and is iteratively increased by multiplying it with the smallest dimension until a contraction path including all inputs is found. Note that the worst case scaling of DP is exponential in the number of inputs. Nevertheless, if the contraction graph is not completely random, but exhibits a certain kind of structure, it can be used for large contraction graphs and is guaranteed to find an asymptotically optimal contraction path. For this reason it is the most frequently used contraction path optimizer in the field of tensor network states. More specifically, the search is performed over connected subgraphs, which, for example, planar and tree-like graphs have far fewer of. As a rough guide, if the graph is planar, expressions with many tens of tensors are tractable, whereas if the graph is tree-like, expressions with many hundreds of tensors are tractable. [1] Robert N. C. Pfeifer, Jutho Haegeman, and Frank Verstraete Phys. Rev. E 90, 033315 (2014). https://arxiv.org/abs/1304.6112 Customizing the Dynamic Programming Path ---------------------------------------- The default `optimize='dp'` approach has sensible defaults but can be customized with the [`opt_einsum.paths.DynamicProgramming`](../api_reference.md#opt_einsumpathsdynamicprogramming) object. ```python import opt_einsum as oe optimizer = oe.DynamicProgramming( minimize='size', # optimize for largest intermediate tensor size search_outer=True, # search through outer products as well cost_cap=False, # don't use cost-capping strategy ) oe.contract(eq, *arrays, optimize=optimizer) ``` !!! warning Note that searching outer products will most likely drastically slow down the optimizer on all but the smallest examples. The values that `minimize` can take are: - `'flops'`: minimize the total number of scalar operations. - `'size'`: minimize the size of the largest intermediate. - `'write'`: minimize the combined size of all intermediate tensors - approximately speaking the amount of memory that will be written. This is relevant if you were to automatically differentiate through the contraction, which naively would require storing all intermediates. - `'combo'` - minimize `flops + alpha * write` summed over intermediates, a default ratio of `alpha=64` is used, or it can be customized with `f'combo-{alpha}'`. - `'limit'` - minimize `max(flops, alpha * write)` summed over intermediates, a default ratio of `alpha=64` is used, or it can be customized with `f'limit-{alpha}'`. The last two take into account the fact that real contraction performance can be bound by memory speed, and so favor paths with higher arithmetic intensity. The default value of `alpha=64` is reasonable for both typical CPUs and GPUs. opt_einsum-3.4.0/docs/paths/greedy_path.md000066400000000000000000000112531467526163400206040ustar00rootroot00000000000000# The Greedy Path The `'greedy'` approach provides a very efficient strategy for finding contraction paths for expressions with large numbers of tensors. It does this by eagerly choosing contractions in three stages: 1. Eagerly compute any **Hadamard** products (in arbitrary order -- this is commutative). 2. Greedily contract pairs of remaining tensors, at each step choosing the pair that maximizes `reduced_size` -- these are generally **inner** products. 3. Greedily compute any pairwise **outer** products, at each step choosing the pair that minimizes `sum(input_sizes)`. The cost heuristic `reduced_size` is simply the size of the pair of potential tensors to be contracted, minus the size of the resulting tensor. The `greedy` algorithm has space and time complexity `O(n * k)` where `n` is the number of input tensors and `k` is the maximum number of tensors that share any dimension (excluding dimensions that occur in the output or in every tensor). As such, the algorithm scales well to very large sparse contractions of low-rank tensors, and indeed, often finds the optimal, or close to optimal path in such cases. The `greedy` functionality is provided by [`opt_einsum.paths.greedy`](../api_reference.md#opt_einsumpathsgreedy), and is selected by the default `optimize='auto'` mode of `opt_einsum` for expressions with many inputs. Expressions of up to a thousand tensors should still take well less than a second to find paths for. Optimal Scaling Misses ---------------------- The greedy algorithm, while inexpensive, can occasionally miss optimal scaling in some circumstances as seen below. The `greedy` algorithm prioritizes expressions which remove the largest indices first, in this particular case this is the incorrect choice and it is difficult for any heuristic algorithm to "see ahead" as would be needed here. It should be stressed these cases are quite rare and by default `contract` uses the `optimal` path for four and fewer inputs as the cost of evaluating the `optimal` path is similar to that of the `greedy` path. Similarly, for 5-8 inputs, `contract` uses one of the branching strategies which can find higher quality paths. ```python M = np.random.rand(35, 37, 59) A = np.random.rand(35, 51, 59) B = np.random.rand(37, 51, 51, 59) C = np.random.rand(59, 27) path, desc = oe.contract_path('xyf,xtf,ytpf,fr->tpr', M, A, B, C, optimize="greedy") print(desc) #> Complete contraction: xyf,xtf,ytpf,fr->tpr #> Naive scaling: 6 #> Optimized scaling: 5 #> Naive FLOP count: 2.146e+10 #> Optimized FLOP count: 4.165e+08 #> Theoretical speedup: 51.533 #> Largest intermediate: 5.371e+06 elements #> -------------------------------------------------------------------------------- #> scaling BLAS current remaining #> -------------------------------------------------------------------------------- #> 5 False ytpf,xyf->tpfx xtf,fr,tpfx->tpr #> 4 False tpfx,xtf->tpf fr,tpf->tpr #> 4 GEMM tpf,fr->tpr tpr->tpr path, desc = oe.contract_path('xyf,xtf,ytpf,fr->tpr', M, A, B, C, optimize="optimal") print(desc) #> Complete contraction: xyf,xtf,ytpf,fr->tpr #> Naive scaling: 6 #> Optimized scaling: 4 #> Naive FLOP count: 2.146e+10 #> Optimized FLOP count: 2.744e+07 #> Theoretical speedup: 782.283 #> Largest intermediate: 1.535e+05 elements #> -------------------------------------------------------------------------------- #> scaling BLAS current remaining #> -------------------------------------------------------------------------------- #> 4 False xtf,xyf->tfy ytpf,fr,tfy->tpr #> 4 False tfy,ytpf->tfp fr,tfp->tpr #> 4 TDOT tfp,fr->tpr tpr->tpr ``` So we can see that the `greedy` algorithm finds a path which is about 16 times slower than the `optimal` one. In such cases, it might be worth using one of the more exhaustive optimization strategies: `'optimal'`, `'branch-all'` or `branch-2` (all of which will find the optimal path in this example). Customizing the Greedy Path --------------------------- The greedy path is a local optimizer in that it only ever assesses pairs of tensors to contract, assigning each a heuristic 'cost' and then choosing the 'best' of these. Custom greedy approaches can be implemented by supplying callables to the `cost_fn` and `choose_fn` arguments of [`opt_einsum.paths.greedy`](../api_reference.md#opt_einsumpathsgreedy). opt_einsum-3.4.0/docs/paths/introduction.md000066400000000000000000000210401467526163400210250ustar00rootroot00000000000000# Introduction Performing an optimized tensor contraction to speed up `einsum` involves two key stages: 1. Finding a pairwise contraction order, or **'path'**. 2. Performing the sequence of contractions given this path. The better the quality of path found in the first step, the quicker the actual contraction in the second step can be -- often dramatically. However, finding the *optimal* path is an NP-hard problem that can quickly become intractable, meaning that a balance must be struck between the time spent finding a path, and its quality. `opt_einsum` handles this by using several path finding algorithms, which can be manually specified using the `optimize` keyword. These are: - The `'optimal'` strategy - an exhaustive search of all possible paths - The `'dynamic-programming'` strategy - a near-optimal search based off dynamic-programming - The `'branch'` strategy - a more restricted search of many likely paths - The `'greedy'` strategy - finds a path one step at a time using a cost heuristic By default (`optimize='auto'`), [`opt_einsum.contract`](../api_reference.md#opt_einsumcontract) will select the best of these it can while aiming to keep path finding times below around 1ms. An analysis of each of these approaches' performance can be found at the bottom of this page. For large and complex contractions, there is the `'random-greedy'` approach, which samples many (by default 32) greedy paths and can be customized to explicitly spend a maximum amount of time searching. Another preset, `'random-greedy-128'`, uses 128 paths for a more exhaustive search. See [`RandomGreedyPath`](./random_greedy_path.md) page for more details on configuring these. Finally, there is the `'auto-hq'` preset which targets a much larger search time (~1sec) in return for finding very high quality paths, dispatching to the `'optimal'`, `'dynamic-programming'` and then `'random-greedy-128'` paths depending on contraction size. If you want to find the path separately to performing the contraction, or just inspect information about the path found, you can use the function [`opt_einsum.contract_path`](../api_reference.md#opt_einsumcontract_path). ## Examining the Path As an example, consider the following expression found in a perturbation theory (one of ~5,000 such expressions): ```python 'bdik,acaj,ikab,ajac,ikbd' ``` At first, it would appear that this scales like N^7 as there are 7 unique indices; however, we can define a intermediate to reduce this scaling. ```python # (N^5 scaling) a = 'bdik,ikab,ikbd' # (N^4 scaling) result = 'acaj,ajac,a' ``` This is a single possible path to the final answer (and notably, not the most optimal) out of many possible paths. Now, let opt_einsum compute the optimal path: ```python import opt_einsum as oe # Take a complex string einsum_string = 'bdik,acaj,ikab,ajac,ikbd->' # Build random views to represent this contraction unique_inds = set(einsum_string) - {',', '-', '>'} index_size = [10, 17, 9, 10, 13, 16, 15, 14, 12] sizes_dict = dict(zip(unique_inds, index_size)) views = oe.helpers.build_views(einsum_string, sizes_dict) path, path_info = oe.contract_path(einsum_string, *views) print(path) #> [(0, 4), (1, 3), (0, 1), (0, 1)] print(path_info) #> Complete contraction: bdik,acaj,ikab,ajac,ikbd-> #> Naive scaling: 7 #> Optimized scaling: 4 #> Naive FLOP count: 2.387e+8 #> Optimized FLOP count: 8.068e+4 #> Theoretical speedup: 2958.354 #> Largest intermediate: 1.530e+3 elements #> -------------------------------------------------------------------------------- #> scaling BLAS current remaining #> -------------------------------------------------------------------------------- #> 4 0 ikbd,bdik->ikb acaj,ikab,ajac,ikb-> #> 4 GEMV/EINSUM ikb,ikab->a acaj,ajac,a-> #> 3 0 ajac,acaj->a a,a-> #> 1 DOT a,a-> -> ``` We can then check that actually performing the contraction produces the expected result: ```python import numpy as np einsum_result = np.einsum("bdik,acaj,ikab,ajac,ikbd->", *views) contract_result = oe.contract("bdik,acaj,ikab,ajac,ikbd->", *views) np.allclose(einsum_result, contract_result) #> True ``` By contracting terms in the correct order we can see that this expression can be computed with N^4 scaling. Even with the overhead of finding the best order or 'path' and small dimensions, `opt_einsum` is roughly 3000 times faster than pure einsum for this expression. ## Format of the Path Let us look at the structure of a canonical `einsum` path found in NumPy and its optimized variant: ```python einsum_path = [(0, 1, 2, 3, 4)] opt_path = [(1, 3), (0, 2), (0, 2), (0, 1)] ``` In opt_einsum each element of the list represents a single contraction. In the above example the einsum_path would effectively compute the result as a single contraction identical to that of `einsum`, while the opt_path would perform four contractions in order to reduce the overall scaling. The first tuple in the opt_path, `(1,3)`, pops the second and fourth terms, then contracts them together to produce a new term which is then appended to the list of terms, this is continued until all terms are contracted. An example should illuminate this: ```console --------------------------------------------------------------------------------- scaling GEMM current remaining --------------------------------------------------------------------------------- terms = ['bdik', 'acaj', 'ikab', 'ajac', 'ikbd'] contraction = (1, 3) 3 False ajac,acaj->a bdik,ikab,ikbd,a-> terms = ['bdik', 'ikab', 'ikbd', 'a'] contraction = (0, 2) 4 False ikbd,bdik->bik ikab,a,bik-> terms = ['ikab', 'a', 'bik'] contraction = (0, 2) 4 False bik,ikab->a a,a-> terms = ['a', 'a'] contraction = (0, 1) 1 DOT a,a-> -> ``` A path specified in this format can explicitly be supplied directly to [`opt_einsum.contract`](../api_reference.md#opt_einsumcontract) using the `optimize` keyword: ```python contract_result = oe.contract("bdik,acaj,ikab,ajac,ikbd->", *views, optimize=opt_path) np.allclose(einsum_result, contract_result) #> True ``` ## Performance Comparison The following graphs should give some indication of the tradeoffs between path finding time and path quality. They are generated by finding paths with each possible algorithm for many randomly generated networks of `n` tensors with varying connectivity. First we have the time to find each path as a function of the number of terms in the expression: ![Path Finding](../img/path_finding_time.png) Clearly the exhaustive (`'optimal'`, `'branch-all'`) and exponential (`'branch-2'`) searches eventually scale badly, but for modest amounts of terms they incur only a small overhead. The `'random-greedy'` approach is not shown here as it is simply `max_repeats` times slower than the `'greedy'` approach - at least if not parallelized. Next we can look at the average FLOP speedup (as compared to the easiest path to find, `'greedy'`): ![Path Finding](../img/path_found_flops.png) One can see that the hierarchy of path qualities is: 1. `'optimal'` (used by auto for `n <= 4`) 2. `'branch-all'` (used by auto for `n <= 6`) 3. `'branch-2'` (used by auto for `n <= 8`) 4. `'branch-1'` (used by auto for `n <= 14`) 5. `'greedy'` (used by auto for anything larger) !!! note The performance of the `'random=greedy'` approach (which is never used automatically) can be found separately in [`RandomGreedyPath`](./random_greedy_path.md) section. There are a few important caveats to note with this graph. Firstly, the benefits of more advanced path finding are very dependent on the complexity of the expression. For 'simple' contractions, all the different approaches will *mostly* find the same path (as here). However, for 'tricky' contractions, there will be certain cases where the more advanced algorithms will find much better paths. As such, while this graph gives a good idea of the *relative* performance of each algorithm, the 'average speedup' is not a perfect indicator since worst-case performance might be more critical. Note that the speedups for any of the methods as compared to a standard `einsum` or a naively chosen path (such as `path=[(0, 1), (0, 1), ...]`) are all exponentially large and not shown. opt_einsum-3.4.0/docs/paths/optimal_path.md000066400000000000000000000042511467526163400207720ustar00rootroot00000000000000# The Optimal Path The most optimal path can be found by searching through every possible way to contract the tensors together, this includes all combinations with the new intermediate tensors as well. While this algorithm scales like N!, and can often become more costly to compute than the unoptimized contraction itself, it provides an excellent benchmark. The function that computes this path in opt_einsum is called [`opt_einsum.paths.optimal`](../api_reference.md#opt_einsumpathsoptimal) and works by performing a recursive, depth-first search. By keeping track of the best path found so far, in terms of total estimated FLOP count, the search can then quickly prune many paths as soon as as they exceed this best. This optimal strategy is used by default with the `optimize='auto'` mode of `opt_einsum` for 4 tensors or less, though it can handle expressions of up to 9-10 tensors in a matter of seconds. Let us look at an example: ```python Contraction: abc,dc,ac->bd ``` Build a list with tuples that have the following form: ```python #> iteration 0: #> "(cost, path, list of input sets remaining)" #> [ (0, [], [set(['a', 'c', 'b']), set(['d', 'c']), set(['a', 'c'])] ] ``` Since this is iteration zero, we have the initial list of input sets. We can consider three possible combinations where we contract list positions (0, 1), (0, 2), or (1, 2) together: ```python #> iteration 1: #> [ (9504, [(0, 1)], [set(['a', 'c']), set(['a', 'c', 'b', 'd']) ]), #> (1584, [(0, 2)], [set(['c', 'd']), set(['c', 'b']) ]), #> (864, [(1, 2)], [set(['a', 'c', 'b']), set(['a', 'c', 'd']) ])] ``` We have now run through the three possible combinations, computed the cost of the contraction up to this point, and appended the resulting indices from the contraction to the list. As all contractions only have two remaining input sets the only possible contraction is (0, 1): ```python #> iteration 2: #> [ (28512, [(0, 1), (0, 1)], [set(['b', 'd']) ]), #> (3168, [(0, 2), (0, 1)], [set(['b', 'd']) ]), #> (19872, [(1, 2), (0, 1)], [set(['b', 'd']) ])] ``` The final contraction cost is computed, and we choose the second path from the list as the overall cost is the lowest. opt_einsum-3.4.0/docs/paths/random_greedy_path.md000066400000000000000000000114411467526163400221430ustar00rootroot00000000000000# The Random-Greedy Path For large *and* complex contractions the exhaustive approaches will be too slow while the greedy path might be very far from optimal. In this case you might want to consider the `'random-greedy'` path optimizer. This samples many greedy paths and selects the best one found, which can often be exponentially better than the average. ```python import opt_einsum as oe import numpy as np import math eq, shapes = oe.helpers.rand_equation(40, 5, seed=1, d_max=2) arrays = list(map(np.ones, shapes)) path_greedy = oe.contract_path(eq, *arrays, optimize='greedy')[1] print(math.log2(path_greedy.opt_cost)) #> 36.04683022558587 path_rand_greedy = oe.contract_path(eq, *arrays, optimize='random-greedy')[1] print(math.log2(path_rand_greedy.opt_cost)) #> 32.203616699170865 ``` So here the random-greedy approach has found a path about 16 times quicker (`= 2^(36 - 32)`). This approach works by randomly choosing from the best `n` contractions at each step, weighted by a [Boltzmann factor](https://en.wikipedia.org/wiki/Boltzmann_distribution) with respect to the contraction with the 'best' cost. As such, contractions with very similar costs will be explored with equal probability, whereas those with higher costs will be less likely, but still possible. In this way, the optimizer can randomly explore the huge space of possible paths, but in a guided manner. The following graph roughly demonstrates the potential benefits of the `'random-greedy'` algorithm, here for large randomly generated contractions, with either 8, 32 (the default), or 128 repeats: ![Path Finding](../img/path_found_flops_random.png) !!! note Bear in mind that such speed-ups are not guaranteed - it very much depends on how structured or complex your contractions are. ## Customizing the Random-Greedy Path The random-greedy optimizer can be customized by instantiating your own [`opt_einsum.paths.RandomGreedy`](../api_reference.md#opt_einsumpath_randomrandomgreedy) object. Here you can control: - `temperature` - how far to stray from the locally 'best' contractions - `rel_temperature` - whether to normalize the temperature - `nbranch` - how many contractions (branches) to consider at each step - `cost_fn` - how to cost potential contractions There are also the main [`opt_einsum.paths.RandomOptimizer`](../api_reference.md#opt_einsumpath_randomrandomoptimizer) options: - `max_repeats` - the maximum number of repeats - `max_time` - the maximum amount of time to run for (in seconds) - `minimize` - whether to minimize for total `'flops'` or `'size'` of the largest intermediate For example, here we'll create an optimizer, then change its temperature whilst reusing it. We'll also set a high `max_repeats` and instead use a maximum time to terminate the search: ```python optimizer = oe.RandomGreedy(max_time=2, max_repeats=1_000_000) for T in [1000, 100, 10, 1, 0.1]: optimizer.temperature = T path_rand_greedy = oe.contract_path(eq, *arrays, optimize=optimizer)[1] print(math.log2(optimizer.best['flops'])) #> 32.81709395639357 #> 32.67625007170783 #> 31.719756871539033 #> 31.62043317835677 #> 31.253305891247 # the total number of trials so far print(len(optimizer.costs)) #> 2555 ``` So we have improved a bit on the standard `'random-greedy'` (which performs 32 repeats by default). The `optimizer` object now stores both the best path found so far - `optimizer.path` - as well as the list of flop-costs and maximum sizes found for each trial - `optimizer.costs` and `optimizer.sizes` respectively. ## Parallelizing the Random-Greedy Search Since each greedy attempt is independent, the random-greedy approach is naturally suited to parallelization. This can be automatically handled by specifying the `parallel` keyword like so: ```python # use same number of processes as cores optimizer = oe.RandomGreedy(parallel=True) # or use specific number of processes optimizer = oe.RandomGreedy(parallel=4) ``` !!! warning The pool-executor used to perform this parallelization is the `ProcessPoolExecutor` from the [`concurrent.futures` ](https://docs.python.org/3/library/concurrent.futures.html) module. For full control over the parallelization you can supply any pool-executor like object, which should have an API matching the Python 3 [concurrent.futures](https://docs.python.org/3/library/concurrent.futures.html>) module: ```python from concurrent.futures import ProcessPoolExecutor pool = ProcessPoolExecutor() optimizer = oe.RandomGreedy(parallel=pool, max_repeats=128) path_rand_greedy = oe.contract_path(eq, *arrays, optimize=optimizer)[1] print(math.log2(optimizer.best['flops'])) #> 31.64992600300931 ``` Other examples of such pools include: - [loky](https://loky.readthedocs.io/en/latest/) - [dask.distributed](http://distributed.dask.org/en/latest/) - [mpi4py](https://mpi4py.readthedocs.io/en/latest/) opt_einsum-3.4.0/docs/requirements.yml000066400000000000000000000003031467526163400201100ustar00rootroot00000000000000ansi2html==1.* black devtools markdown==3.* markdown-include==0.* mkdocstrings[python]==0.25.* mkdocs==1.* mkdocs-awesome-pages-plugin==2.* mkdocs-exclude==1.* mkdocs-material==9.* pygments==2.* opt_einsum-3.4.0/mkdocs.yml000066400000000000000000000056771467526163400157400ustar00rootroot00000000000000site_name: Optimized Einsum repo_url: https://github.com/dgasmith/opt_einsum repo_name: dgasmith/opt_einsum theme: name: material features: - navigation.instant palette: # Palette toggle for automatic mode - media: "(prefers-color-scheme)" toggle: icon: material/brightness-auto name: Switch to light mode # Palette toggle for light mode - media: "(prefers-color-scheme: light)" scheme: default toggle: icon: material/brightness-7 name: Switch to dark mode # Palette toggle for dark mode - media: "(prefers-color-scheme: dark)" scheme: slate toggle: icon: material/brightness-4 name: Switch to system preference plugins: - search - awesome-pages - mkdocstrings: default_handler: python handlers: python: # paths: [opt_einsum] options: docstring_style: google docstring_options: ignore_init_summary: true docstring_section_style: list filters: ["!^_"] heading_level: 1 inherited_members: true merge_init_into_class: true parameter_headings: true preload_modules: [mkdocstrings] separate_signature: true show_root_heading: true show_root_full_path: false show_signature_annotations: true show_source: false show_symbol_type_heading: true show_symbol_type_toc: true signature_crossrefs: true summary: true unwrap_annotated: true extra_javascript: - javascript/config.js - https://polyfill.io/v3/polyfill.min.js?features=es6 - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js extra_css: - css/custom.css markdown_extensions: - markdown.extensions.codehilite: guess_lang: false - markdown_include.include: base_path: docs - pymdownx.arithmatex: generic: true - admonition - codehilite - extra - pymdownx.extra - pymdownx.arithmatex: generic: true - toc: toc_depth: 2 nav: - Overview: index.md - Getting Started: - Installing: getting_started/install.md - Input Format: getting_started/input_format.md - "Backends & GPU Support": getting_started/backends.md - Reusing Paths: getting_started/reusing_paths.md - Sharing Intermediates: getting_started/sharing_intermediates.md - Path Information: - Introduction: paths/introduction.md - Optimal Path: paths/optimal_path.md - Branching Path: paths/branching_path.md - Greedy Path: paths/greedy_path.md - Random-Greedy Path: paths/random_greedy_path.md - Dynamic Programming Path: paths/dp_path.md - Custom Path Optimizers: paths/custom_paths.md - Examples: - Reusing Intermediaries with Dask: examples/dask_reusing_intermediaries.md - Large Expressions with Greedy: examples/large_expr_with_greedy.md - API Reference: api_reference.md - Changelog: changelog.md opt_einsum-3.4.0/opt_einsum/000077500000000000000000000000001467526163400161005ustar00rootroot00000000000000opt_einsum-3.4.0/opt_einsum/__init__.py000066400000000000000000000015021467526163400202070ustar00rootroot00000000000000"""Main init function for opt_einsum.""" from opt_einsum import blas, helpers, path_random, paths from opt_einsum._version import __version__ from opt_einsum.contract import contract, contract_expression, contract_path from opt_einsum.parser import get_symbol from opt_einsum.path_random import RandomGreedy from opt_einsum.paths import BranchBound, DynamicProgramming from opt_einsum.sharing import shared_intermediates __all__ = [ "__version__", "blas", "helpers", "path_random", "paths", "contract", "contract_expression", "contract_path", "get_symbol", "RandomGreedy", "BranchBound", "DynamicProgramming", "shared_intermediates", ] paths.register_path_fn("random-greedy", path_random.random_greedy) paths.register_path_fn("random-greedy-128", path_random.random_greedy_128) opt_einsum-3.4.0/opt_einsum/_version.py000066400000000000000000000006521467526163400203010ustar00rootroot00000000000000# file generated by setuptools_scm # don't change, don't track in version control TYPE_CHECKING = False if TYPE_CHECKING: from typing import Tuple, Union VERSION_TUPLE = Tuple[Union[int, str], ...] else: VERSION_TUPLE = object version: str __version__: str __version_tuple__: VERSION_TUPLE version_tuple: VERSION_TUPLE __version__ = version = '0.0.0.dev' __version_tuple__ = version_tuple = (0, 0, 0, 'dev', '') opt_einsum-3.4.0/opt_einsum/backends/000077500000000000000000000000001467526163400176525ustar00rootroot00000000000000opt_einsum-3.4.0/opt_einsum/backends/__init__.py000066400000000000000000000011461467526163400217650ustar00rootroot00000000000000"""Compute backends for opt_einsum.""" # Backends from opt_einsum.backends.cupy import to_cupy from opt_einsum.backends.dispatch import ( build_expression, evaluate_constants, get_func, has_backend, has_einsum, has_tensordot, ) from opt_einsum.backends.tensorflow import to_tensorflow from opt_einsum.backends.theano import to_theano from opt_einsum.backends.torch import to_torch __all__ = [ "get_func", "has_einsum", "has_tensordot", "build_expression", "evaluate_constants", "has_backend", "to_tensorflow", "to_theano", "to_cupy", "to_torch", ] opt_einsum-3.4.0/opt_einsum/backends/cupy.py000066400000000000000000000016661467526163400212150ustar00rootroot00000000000000"""Required functions for optimized contractions of numpy arrays using cupy.""" from opt_einsum.helpers import has_array_interface from opt_einsum.sharing import to_backend_cache_wrap __all__ = ["to_cupy", "build_expression", "evaluate_constants"] @to_backend_cache_wrap def to_cupy(array): # pragma: no cover import cupy if has_array_interface(array): return cupy.asarray(array) return array def build_expression(_, expr): # pragma: no cover """Build a cupy function based on ``arrays`` and ``expr``.""" def cupy_contract(*arrays): return expr._contract([to_cupy(x) for x in arrays], backend="cupy").get() return cupy_contract def evaluate_constants(const_arrays, expr): # pragma: no cover """Convert constant arguments to cupy arrays, and perform any possible constant contractions. """ return expr(*[to_cupy(x) for x in const_arrays], backend="cupy", evaluate_constants=True) opt_einsum-3.4.0/opt_einsum/backends/dispatch.py000066400000000000000000000114271467526163400220300ustar00rootroot00000000000000"""Handles dispatching array operations to the correct backend library, as well as converting arrays to backend formats and then potentially storing them as constants. """ import importlib from typing import Any, Dict, Tuple from opt_einsum.backends import cupy as _cupy from opt_einsum.backends import jax as _jax from opt_einsum.backends import object_arrays from opt_einsum.backends import tensorflow as _tensorflow from opt_einsum.backends import theano as _theano from opt_einsum.backends import torch as _torch __all__ = [ "get_func", "has_einsum", "has_tensordot", "build_expression", "evaluate_constants", "has_backend", ] # known non top-level imports _aliases = { "dask": "dask.array", "theano": "theano.tensor", "torch": "opt_einsum.backends.torch", "jax": "jax.numpy", "jaxlib": "jax.numpy", "autograd": "autograd.numpy", "mars": "mars.tensor", } def _import_func(func: str, backend: str, default: Any = None) -> Any: """Try and import ``{backend}.{func}``. If library is installed and func is found, return the func; otherwise if default is provided, return default; otherwise raise an error. """ try: lib = importlib.import_module(_aliases.get(backend, backend)) return getattr(lib, func) if default is None else getattr(lib, func, default) except AttributeError: error_msg = ( "{} doesn't seem to provide the function {} - see " "https://optimized-einsum.readthedocs.io/en/latest/backends.html " "for details on which functions are required for which contractions." ) raise AttributeError(error_msg.format(backend, func)) # manually cache functions as python2 doesn't support functools.lru_cache # other libs will be added to this if needed, but pre-populate with numpy _cached_funcs: Dict[Tuple[str, str], Any] = { ("einsum", "object"): object_arrays.object_einsum, } try: import numpy as np # type: ignore _cached_funcs[("tensordot", "numpy")] = np.tensordot _cached_funcs[("transpose", "numpy")] = np.transpose _cached_funcs[("einsum", "numpy")] = np.einsum # also pre-populate with the arbitrary object backend _cached_funcs[("tensordot", "object")] = np.tensordot _cached_funcs[("transpose", "object")] = np.transpose except ModuleNotFoundError: pass def get_func(func: str, backend: str = "numpy", default: Any = None) -> Any: """Return ``{backend}.{func}``, e.g. ``numpy.einsum``, or a default func if provided. Cache result. """ try: return _cached_funcs[func, backend] except KeyError: fn = _import_func(func, backend, default) _cached_funcs[func, backend] = fn return fn # mark libs with einsum, else try to use tensordot/transpose as much as possible _has_einsum: Dict[str, bool] = {} def has_einsum(backend: str) -> bool: """Check if ``{backend}.einsum`` exists, cache result for performance.""" try: return _has_einsum[backend] except KeyError: try: get_func("einsum", backend) _has_einsum[backend] = True except AttributeError: _has_einsum[backend] = False return _has_einsum[backend] _has_tensordot: Dict[str, bool] = {} def has_tensordot(backend: str) -> bool: """Check if ``{backend}.tensordot`` exists, cache result for performance.""" try: return _has_tensordot[backend] except KeyError: try: get_func("tensordot", backend) _has_tensordot[backend] = True except AttributeError: _has_tensordot[backend] = False return _has_tensordot[backend] # Dispatch to correct expression backend # these are the backends which support explicit to-and-from numpy conversion CONVERT_BACKENDS = { "tensorflow": _tensorflow.build_expression, "theano": _theano.build_expression, "cupy": _cupy.build_expression, "torch": _torch.build_expression, "jax": _jax.build_expression, } EVAL_CONSTS_BACKENDS = { "tensorflow": _tensorflow.evaluate_constants, "theano": _theano.evaluate_constants, "cupy": _cupy.evaluate_constants, "torch": _torch.evaluate_constants, "jax": _jax.evaluate_constants, } def build_expression(backend, arrays, expr): """Build an expression, based on ``expr`` and initial arrays ``arrays``, that evaluates using backend ``backend``. """ return CONVERT_BACKENDS[backend](arrays, expr) def evaluate_constants(backend, arrays, expr): """Convert constant arrays to the correct backend, and perform as much of the contraction of ``expr`` with these as possible. """ return EVAL_CONSTS_BACKENDS[backend](arrays, expr) def has_backend(backend: str) -> bool: """Checks if the backend is known.""" return backend.lower() in CONVERT_BACKENDS opt_einsum-3.4.0/opt_einsum/backends/jax.py000066400000000000000000000020751467526163400210120ustar00rootroot00000000000000"""Required functions for optimized contractions of numpy arrays using jax.""" from opt_einsum.sharing import to_backend_cache_wrap __all__ = ["build_expression", "evaluate_constants"] _JAX = None def _get_jax_and_to_jax(): global _JAX if _JAX is None: import jax # type: ignore @to_backend_cache_wrap @jax.jit def to_jax(x): return x _JAX = jax, to_jax return _JAX def build_expression(_, expr): # pragma: no cover """Build a jax function based on ``arrays`` and ``expr``.""" jax, _ = _get_jax_and_to_jax() jax_expr = jax.jit(expr._contract) def jax_contract(*arrays): import numpy as np # type: ignore return np.asarray(jax_expr(arrays)) return jax_contract def evaluate_constants(const_arrays, expr): # pragma: no cover """Convert constant arguments to jax arrays, and perform any possible constant contractions. """ jax, to_jax = _get_jax_and_to_jax() return expr(*[to_jax(x) for x in const_arrays], backend="jax", evaluate_constants=True) opt_einsum-3.4.0/opt_einsum/backends/object_arrays.py000066400000000000000000000037401467526163400230570ustar00rootroot00000000000000"""Functions for performing contractions with array elements which are objects.""" import functools import operator from opt_einsum.typing import ArrayType def object_einsum(eq: str, *arrays: ArrayType) -> ArrayType: """A ``einsum`` implementation for ``numpy`` arrays with object dtype. The loop is performed in python, meaning the objects themselves need only to implement ``__mul__`` and ``__add__`` for the contraction to be computed. This may be useful when, for example, computing expressions of tensors with symbolic elements, but note it will be very slow when compared to ``numpy.einsum`` and numeric data types! Parameters ---------- eq : str The contraction string, should specify output. arrays : sequence of arrays These can be any indexable arrays as long as addition and multiplication is defined on the elements. Returns: ------- out : numpy.ndarray The output tensor, with ``dtype=object``. """ import numpy as np # type: ignore # when called by ``opt_einsum`` we will always be given a full eq lhs, output = eq.split("->") inputs = lhs.split(",") sizes = {} for term, array in zip(inputs, arrays): for k, d in zip(term, array.shape): sizes[k] = d out_size = tuple(sizes[k] for k in output) out = np.empty(out_size, dtype=object) inner = tuple(k for k in sizes if k not in output) inner_size = tuple(sizes[k] for k in inner) for coo_o in np.ndindex(*out_size): coord = dict(zip(output, coo_o)) def gen_inner_sum(): for coo_i in np.ndindex(*inner_size): coord.update(dict(zip(inner, coo_i))) locs = (tuple(coord[k] for k in term) for term in inputs) elements = (array[loc] for array, loc in zip(arrays, locs)) yield functools.reduce(operator.mul, elements) out[coo_o] = functools.reduce(operator.add, gen_inner_sum()) return out opt_einsum-3.4.0/opt_einsum/backends/tensorflow.py000066400000000000000000000074631467526163400224400ustar00rootroot00000000000000"""Required functions for optimized contractions of numpy arrays using tensorflow.""" from opt_einsum.helpers import has_array_interface from opt_einsum.sharing import to_backend_cache_wrap __all__ = ["to_tensorflow", "build_expression", "evaluate_constants"] _CACHED_TF_DEVICE = None def _get_tensorflow_and_device(): global _CACHED_TF_DEVICE if _CACHED_TF_DEVICE is None: import tensorflow as tf # type: ignore try: eager = tf.executing_eagerly() except AttributeError: try: eager = tf.contrib.eager.in_eager_mode() except AttributeError: eager = False device = tf.test.gpu_device_name() if not device: device = "cpu" _CACHED_TF_DEVICE = tf, device, eager return _CACHED_TF_DEVICE @to_backend_cache_wrap(constants=True) def to_tensorflow(array, constant=False): """Convert a numpy array to a ``tensorflow.placeholder`` instance.""" tf, device, eager = _get_tensorflow_and_device() if eager: if has_array_interface(array): with tf.device(device): return tf.convert_to_tensor(array) return array if has_array_interface(array): if constant: return tf.convert_to_tensor(array) return tf.placeholder(array.dtype, array.shape) return array # Standard graph mode def build_expression_graph(arrays, expr): """Build a tensorflow function based on ``arrays`` and ``expr``.""" tf, _, _ = _get_tensorflow_and_device() placeholders = [to_tensorflow(array) for array in arrays] graph = expr._contract(placeholders, backend="tensorflow") def tensorflow_contract(*arrays): session = tf.get_default_session() # only want to feed placeholders - constant tensors already have values feed_dict = {p: a for p, a in zip(placeholders, arrays) if p.op.type == "Placeholder"} return session.run(graph, feed_dict=feed_dict) return tensorflow_contract def evaluate_constants_graph(const_arrays, expr): """Convert constant arguments to tensorflow constants, and perform any possible constant contractions. Requires evaluating a tensorflow graph. """ tf, _, _ = _get_tensorflow_and_device() # compute the partial graph of new inputs const_arrays = [to_tensorflow(x, constant=True) for x in const_arrays] new_ops, new_contraction_list = expr(*const_arrays, backend="tensorflow", evaluate_constants=True) # evaluate the new inputs and convert back to tensorflow, maintaining None as non-consts session = tf.get_default_session() new_consts = iter(session.run([x for x in new_ops if x is not None])) new_ops = [None if x is None else to_tensorflow(next(new_consts), constant=True) for x in new_ops] return new_ops, new_contraction_list # Eager execution mode def build_expression_eager(_, expr): """Build a eager tensorflow function based on ``arrays`` and ``expr``.""" def tensorflow_eager_contract(*arrays): return expr._contract([to_tensorflow(x) for x in arrays], backend="tensorflow").numpy() return tensorflow_eager_contract def evaluate_constants_eager(const_arrays, expr): """Convert constant arguments to tensorflow_eager arrays, and perform any possible constant contractions. """ return expr(*[to_tensorflow(x) for x in const_arrays], backend="tensorflow", evaluate_constants=True) # Dispatch to eager or graph mode def build_expression(arrays, expr): _, _, eager = _get_tensorflow_and_device() fn = build_expression_eager if eager else build_expression_graph return fn(arrays, expr) def evaluate_constants(const_arrays, expr): _, _, eager = _get_tensorflow_and_device() fn = evaluate_constants_eager if eager else evaluate_constants_graph return fn(const_arrays, expr) opt_einsum-3.4.0/opt_einsum/backends/theano.py000066400000000000000000000032421467526163400215030ustar00rootroot00000000000000"""Required functions for optimized contractions of numpy arrays using theano.""" from opt_einsum.helpers import has_array_interface from opt_einsum.sharing import to_backend_cache_wrap __all__ = ["to_theano", "build_expression", "evaluate_constants"] @to_backend_cache_wrap(constants=True) def to_theano(array, constant=False): """Convert a numpy array to ``theano.tensor.TensorType`` instance.""" import theano # type: ignore if has_array_interface(array): if constant: return theano.tensor.constant(array) return theano.tensor.TensorType(dtype=array.dtype, broadcastable=[False] * len(array.shape))() return array def build_expression(arrays, expr): """Build a theano function based on ``arrays`` and ``expr``.""" import theano in_vars = [to_theano(array) for array in arrays] out_var = expr._contract(in_vars, backend="theano") # don't supply constants to graph graph_ins = [x for x in in_vars if not isinstance(x, theano.tensor.TensorConstant)] graph = theano.function(graph_ins, out_var) def theano_contract(*arrays): return graph(*[x for x in arrays if not isinstance(x, theano.tensor.TensorConstant)]) return theano_contract def evaluate_constants(const_arrays, expr): # compute the partial graph of new inputs const_arrays = [to_theano(x, constant=True) for x in const_arrays] new_ops, new_contraction_list = expr(*const_arrays, backend="theano", evaluate_constants=True) # evaluate the new inputs and convert to theano shared tensors new_ops = [None if x is None else to_theano(x.eval(), constant=True) for x in new_ops] return new_ops, new_contraction_list opt_einsum-3.4.0/opt_einsum/backends/torch.py000066400000000000000000000067771467526163400213640ustar00rootroot00000000000000"""Required functions for optimized contractions of numpy arrays using pytorch.""" from opt_einsum.helpers import has_array_interface from opt_einsum.parser import convert_to_valid_einsum_chars from opt_einsum.sharing import to_backend_cache_wrap __all__ = [ "transpose", "einsum", "tensordot", "to_torch", "build_expression", "evaluate_constants", ] _TORCH_DEVICE = None _TORCH_HAS_TENSORDOT = None _torch_symbols_base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" def _get_torch_and_device(): global _TORCH_DEVICE global _TORCH_HAS_TENSORDOT if _TORCH_DEVICE is None: import torch # type: ignore device = "cuda" if torch.cuda.is_available() else "cpu" _TORCH_DEVICE = torch, device _TORCH_HAS_TENSORDOT = hasattr(torch, "tensordot") return _TORCH_DEVICE def transpose(a, axes): """Normal torch transpose is only valid for 2D matrices.""" return a.permute(*axes) def einsum(equation, *operands, **kwargs): """Variadic version of torch.einsum to match numpy api.""" # rename symbols to support PyTorch 0.4.1 and earlier, # which allow only symbols a-z. equation = convert_to_valid_einsum_chars(equation) torch, _ = _get_torch_and_device() return torch.einsum(equation, operands) def tensordot(x, y, axes=2): """Simple translation of tensordot syntax to einsum.""" torch, _ = _get_torch_and_device() if _TORCH_HAS_TENSORDOT: return torch.tensordot(x, y, dims=axes) xnd = x.ndimension() ynd = y.ndimension() # convert int argument to (list[int], list[int]) if isinstance(axes, int): axes = range(xnd - axes, xnd), range(axes) # convert (int, int) to (list[int], list[int]) if isinstance(axes[0], int): axes = (axes[0],), axes[1] if isinstance(axes[1], int): axes = axes[0], (axes[1],) # initialize empty indices x_ix = [None] * xnd y_ix = [None] * ynd out_ix = [] # fill in repeated indices available_ix = iter(_torch_symbols_base) for ax1, ax2 in zip(*axes): repeat = next(available_ix) x_ix[ax1] = repeat y_ix[ax2] = repeat # fill in the rest, and maintain output order for i in range(xnd): if x_ix[i] is None: leave = next(available_ix) x_ix[i] = leave out_ix.append(leave) for i in range(ynd): if y_ix[i] is None: leave = next(available_ix) y_ix[i] = leave out_ix.append(leave) # form full string and contract! einsum_str = "{},{}->{}".format(*map("".join, (x_ix, y_ix, out_ix))) return einsum(einsum_str, x, y) @to_backend_cache_wrap def to_torch(array): torch, device = _get_torch_and_device() if has_array_interface(array): return torch.from_numpy(array).to(device) return array def build_expression(_, expr): # pragma: no cover """Build a torch function based on ``arrays`` and ``expr``.""" def torch_contract(*arrays): torch_arrays = [to_torch(x) for x in arrays] torch_out = expr._contract(torch_arrays, backend="torch") if torch_out.device.type == "cpu": return torch_out.numpy() return torch_out.cpu().numpy() return torch_contract def evaluate_constants(const_arrays, expr): """Convert constant arguments to torch, and perform any possible constant contractions. """ const_arrays = [to_torch(x) for x in const_arrays] return expr(*const_arrays, backend="torch", evaluate_constants=True) opt_einsum-3.4.0/opt_einsum/blas.py000066400000000000000000000066541467526163400174060ustar00rootroot00000000000000"""Determines if a contraction can use BLAS or not.""" from typing import List, Sequence, Tuple, Union from opt_einsum.typing import ArrayIndexType __all__ = ["can_blas"] def can_blas( inputs: List[str], result: str, idx_removed: ArrayIndexType, shapes: Union[Sequence[Tuple[int]], None] = None, ) -> Union[str, bool]: """Checks if we can use a BLAS call. Parameters ---------- inputs : list of str Specifies the subscripts for summation. result : str Resulting summation. idx_removed : set Indices that are removed in the summation shapes : sequence of tuple[int], optional If given, check also that none of the indices are broadcast dimensions. Returns: ------- type : str or bool The type of BLAS call to be used or False if none. Notes: ----- We assume several operations are not efficient such as a transposed DDOT, therefore 'ijk,jki->' should prefer einsum. These return the blas type appended with "/EINSUM" to differentiate when they can still be done with tensordot if required, e.g. when a backend has no einsum. Examples: -------- >>> can_blas(['ij', 'jk'], 'ik', set('j')) 'GEMM' >>> can_blas(['ijj', 'jk'], 'ik', set('j')) False >>> can_blas(['ab', 'cd'], 'abcd', set()) 'OUTER/EINSUM' >>> # looks like GEMM but actually 'j' is broadcast: >>> can_blas(['ij', 'jk'], 'ik', set('j'), shapes=[(4, 1), (5, 6)]) False """ # Can only do two if len(inputs) != 2: return False input_left, input_right = inputs for c in set(input_left + input_right): # can't deal with repeated indices on same input or more than 2 total nl, nr = input_left.count(c), input_right.count(c) if (nl > 1) or (nr > 1) or (nl + nr > 2): return False # can't do implicit summation or dimension collapse e.g. # "ab,bc->c" (implicitly sum over 'a') # "ab,ca->ca" (take diagonal of 'a') if nl + nr - 1 == int(c in result): return False # check for broadcast indices e.g: # "ij,jk->ik" (but one of the 'j' dimensions is broadcast up) if shapes is not None: for c in idx_removed: if shapes[0][input_left.find(c)] != shapes[1][input_right.find(c)]: return False # Prefer einsum if not removing indices # (N.B. tensordot outer faster for large arrays?) if len(idx_removed) == 0: return "OUTER/EINSUM" # Build a few temporaries sets = [set(x) for x in inputs] keep_left = sets[0] - idx_removed keep_right = sets[1] - idx_removed rs = len(idx_removed) # DDOT if inputs[0] == inputs[1]: return "DOT" # DDOT does not make sense if you have to transpose - prefer einsum elif sets[0] == sets[1]: return "DOT/EINSUM" # GEMM no transpose if input_left[-rs:] == input_right[:rs]: return "GEMM" # GEMM transpose both elif input_left[:rs] == input_right[-rs:]: return "GEMM" # GEMM transpose right elif input_left[-rs:] == input_right[-rs:]: return "GEMM" # GEMM transpose left elif input_left[:rs] == input_right[:rs]: return "GEMM" # Einsum is faster than vectordot if we have to copy elif (len(keep_left) == 0) or (len(keep_right) == 0): return "GEMV/EINSUM" # Conventional tensordot else: return "TDOT" opt_einsum-3.4.0/opt_einsum/contract.py000066400000000000000000001166251467526163400203020ustar00rootroot00000000000000"""Contains the primary optimization and contraction routines.""" from decimal import Decimal from functools import lru_cache from typing import Any, Collection, Dict, Iterable, List, Literal, Optional, Sequence, Tuple, Union, overload from opt_einsum import backends, blas, helpers, parser, paths, sharing from opt_einsum.typing import ( ArrayIndexType, ArrayShaped, ArrayType, BackendType, ContractionListType, OptimizeKind, PathType, TensorShapeType, ) __all__ = [ "contract_path", "contract", "format_const_einsum_str", "ContractExpression", "shape_only", ] ## Common types _MemoryLimit = Union[None, int, Decimal, Literal["max_input"]] class PathInfo: """A printable object to contain information about a contraction path.""" def __init__( self, contraction_list: ContractionListType, input_subscripts: str, output_subscript: str, indices: ArrayIndexType, path: PathType, scale_list: Sequence[int], naive_cost: int, opt_cost: int, size_list: Sequence[int], size_dict: Dict[str, int], ): self.contraction_list = contraction_list self.input_subscripts = input_subscripts self.output_subscript = output_subscript self.path = path self.indices = indices self.scale_list = scale_list self.naive_cost = Decimal(naive_cost) self.opt_cost = Decimal(opt_cost) self.speedup = self.naive_cost / max(self.opt_cost, Decimal(1)) self.size_list = size_list self.size_dict = size_dict self.shapes = [tuple(size_dict[k] for k in ks) for ks in input_subscripts.split(",")] self.eq = f"{input_subscripts}->{output_subscript}" self.largest_intermediate = Decimal(max(size_list, default=1)) def __repr__(self) -> str: # Return the path along with a nice string representation header = ("scaling", "BLAS", "current", "remaining") path_print = [ f" Complete contraction: {self.eq}\n", f" Naive scaling: {len(self.indices)}\n", f" Optimized scaling: {max(self.scale_list, default=0)}\n", f" Naive FLOP count: {self.naive_cost:.3e}\n", f" Optimized FLOP count: {self.opt_cost:.3e}\n", f" Theoretical speedup: {self.speedup:.3e}\n", f" Largest intermediate: {self.largest_intermediate:.3e} elements\n", "-" * 80 + "\n", "{:>6} {:>11} {:>22} {:>37}\n".format(*header), "-" * 80, ] for n, contraction in enumerate(self.contraction_list): _, _, einsum_str, remaining, do_blas = contraction if remaining is not None: remaining_str = ",".join(remaining) + "->" + self.output_subscript else: remaining_str = "..." size_remaining = max(0, 56 - max(22, len(einsum_str))) path_run = ( self.scale_list[n], do_blas, einsum_str, remaining_str, size_remaining, ) path_print.append("\n{:>4} {:>14} {:>22} {:>{}}".format(*path_run)) return "".join(path_print) def _choose_memory_arg(memory_limit: _MemoryLimit, size_list: List[int]) -> Optional[int]: if memory_limit == "max_input": return max(size_list) if isinstance(memory_limit, str): raise ValueError("memory_limit must be None, int, or the string Literal['max_input'].") if memory_limit is None: return None if memory_limit < 1: if memory_limit == -1: return None else: raise ValueError("Memory limit must be larger than 0, or -1") return int(memory_limit) _EinsumDefaultKeys = Literal["order", "casting", "dtype", "out"] def _filter_einsum_defaults(kwargs: Dict[_EinsumDefaultKeys, Any]) -> Dict[_EinsumDefaultKeys, Any]: """Filters out default contract kwargs to pass to various backends.""" kwargs = kwargs.copy() ret: Dict[_EinsumDefaultKeys, Any] = {} if (order := kwargs.pop("order", "K")) != "K": ret["order"] = order if (casting := kwargs.pop("casting", "safe")) != "safe": ret["casting"] = casting if (dtype := kwargs.pop("dtype", None)) is not None: ret["dtype"] = dtype if (out := kwargs.pop("out", None)) is not None: ret["out"] = out ret.update(kwargs) return ret # Overlaod for contract(einsum_string, *operands) @overload def contract_path( subscripts: str, *operands: ArrayType, use_blas: bool = True, optimize: OptimizeKind = True, memory_limit: _MemoryLimit = None, shapes: bool = False, **kwargs: Any, ) -> Tuple[PathType, PathInfo]: ... # Overlaod for contract(operand, indices, operand, indices, ....) @overload def contract_path( subscripts: ArrayType, *operands: Union[ArrayType, Collection[int]], use_blas: bool = True, optimize: OptimizeKind = True, memory_limit: _MemoryLimit = None, shapes: bool = False, **kwargs: Any, ) -> Tuple[PathType, PathInfo]: ... def contract_path( subscripts: Any, *operands: Any, use_blas: bool = True, optimize: OptimizeKind = True, memory_limit: _MemoryLimit = None, shapes: bool = False, **kwargs: Any, ) -> Tuple[PathType, PathInfo]: """Find a contraction order `path`, without performing the contraction. Parameters: subscripts: Specifies the subscripts for summation. *operands: These are the arrays for the operation. use_blas: Do you use BLAS for valid operations, may use extra memory for more intermediates. optimize: Choose the type of path the contraction will be optimized with. - if a list is given uses this as the path. - `'optimal'` An algorithm that explores all possible ways of contracting the listed tensors. Scales factorially with the number of terms in the contraction. - `'dp'` A faster (but essentially optimal) algorithm that uses dynamic programming to exhaustively search all contraction paths without outer-products. - `'greedy'` An cheap algorithm that heuristically chooses the best pairwise contraction at each step. Scales linearly in the number of terms in the contraction. - `'random-greedy'` Run a randomized version of the greedy algorithm 32 times and pick the best path. - `'random-greedy-128'` Run a randomized version of the greedy algorithm 128 times and pick the best path. - `'branch-all'` An algorithm like optimal but that restricts itself to searching 'likely' paths. Still scales factorially. - `'branch-2'` An even more restricted version of 'branch-all' that only searches the best two options at each step. Scales exponentially with the number of terms in the contraction. - `'auto'` Choose the best of the above algorithms whilst aiming to keep the path finding time below 1ms. - `'auto-hq'` Aim for a high quality contraction, choosing the best of the above algorithms whilst aiming to keep the path finding time below 1sec. memory_limit: Give the upper bound of the largest intermediate tensor contract will build. - None or -1 means there is no limit - `max_input` means the limit is set as largest input tensor - a positive integer is taken as an explicit limit on the number of elements The default is None. Note that imposing a limit can make contractions exponentially slower to perform. shapes: Whether ``contract_path`` should assume arrays (the default) or array shapes have been supplied. Returns: path: The optimized einsum contraciton path PathInfo: A printable object containing various information about the path found. Notes: The resulting path indicates which terms of the input contraction should be contracted first, the result of this contraction is then appended to the end of the contraction list. Examples: We can begin with a chain dot example. In this case, it is optimal to contract the b and c tensors represented by the first element of the path (1, 2). The resulting tensor is added to the end of the contraction and the remaining contraction, `(0, 1)`, is then executed. ```python a = np.random.rand(2, 2) b = np.random.rand(2, 5) c = np.random.rand(5, 2) path_info = opt_einsum.contract_path('ij,jk,kl->il', a, b, c) print(path_info[0]) #> [(1, 2), (0, 1)] print(path_info[1]) #> Complete contraction: ij,jk,kl->il #> Naive scaling: 4 #> Optimized scaling: 3 #> Naive FLOP count: 1.600e+02 #> Optimized FLOP count: 5.600e+01 #> Theoretical speedup: 2.857 #> Largest intermediate: 4.000e+00 elements #> ------------------------------------------------------------------------- #> scaling current remaining #> ------------------------------------------------------------------------- #> 3 kl,jk->jl ij,jl->il #> 3 jl,ij->il il->il ``` A more complex index transformation example. ```python I = np.random.rand(10, 10, 10, 10) C = np.random.rand(10, 10) path_info = oe.contract_path('ea,fb,abcd,gc,hd->efgh', C, C, I, C, C) print(path_info[0]) #> [(0, 2), (0, 3), (0, 2), (0, 1)] print(path_info[1]) #> Complete contraction: ea,fb,abcd,gc,hd->efgh #> Naive scaling: 8 #> Optimized scaling: 5 #> Naive FLOP count: 8.000e+08 #> Optimized FLOP count: 8.000e+05 #> Theoretical speedup: 1000.000 #> Largest intermediate: 1.000e+04 elements #> -------------------------------------------------------------------------- #> scaling current remaining #> -------------------------------------------------------------------------- #> 5 abcd,ea->bcde fb,gc,hd,bcde->efgh #> 5 bcde,fb->cdef gc,hd,cdef->efgh #> 5 cdef,gc->defg hd,defg->efgh #> 5 defg,hd->efgh efgh->efgh ``` """ if (optimize is True) or (optimize is None): optimize = "auto" # Hidden option, only einsum should call this einsum_call_arg = kwargs.pop("einsum_call", False) if len(kwargs): raise TypeError(f"Did not understand the following kwargs: {kwargs.keys()}") # Python side parsing operands_ = [subscripts] + list(operands) input_subscripts, output_subscript, operands_prepped = parser.parse_einsum_input(operands_, shapes=shapes) # Build a few useful list and sets input_list = input_subscripts.split(",") input_sets = [frozenset(x) for x in input_list] if shapes: input_shapes = operands_prepped else: input_shapes = [parser.get_shape(x) for x in operands_prepped] output_set = frozenset(output_subscript) indices = frozenset(input_subscripts.replace(",", "")) # Get length of each unique dimension and ensure all dimensions are correct size_dict: Dict[str, int] = {} for tnum, term in enumerate(input_list): sh = input_shapes[tnum] if len(sh) != len(term): raise ValueError( f"Einstein sum subscript '{input_list[tnum]}' does not contain the " f"correct number of indices for operand {tnum}." ) for cnum, char in enumerate(term): dim = int(sh[cnum]) if char in size_dict: # For broadcasting cases we always want the largest dim size if size_dict[char] == 1: size_dict[char] = dim elif dim not in (1, size_dict[char]): raise ValueError( f"Size of label '{char}' for operand {tnum} ({size_dict[char]}) does not match previous " f"terms ({dim})." ) else: size_dict[char] = dim # Compute size of each input array plus the output array size_list = [helpers.compute_size_by_dict(term, size_dict) for term in input_list + [output_subscript]] memory_arg = _choose_memory_arg(memory_limit, size_list) num_ops = len(input_list) # Compute naive cost # This is not quite right, need to look into exactly how einsum does this # indices_in_input = input_subscripts.replace(',', '') inner_product = (sum(len(x) for x in input_sets) - len(indices)) > 0 naive_cost = helpers.flop_count(indices, inner_product, num_ops, size_dict) # Compute the path if optimize is False: path_tuple: PathType = [tuple(range(num_ops))] elif not isinstance(optimize, (str, paths.PathOptimizer)): # Custom path supplied path_tuple = optimize # type: ignore elif num_ops <= 2: # Nothing to be optimized path_tuple = [tuple(range(num_ops))] elif isinstance(optimize, paths.PathOptimizer): # Custom path optimizer supplied path_tuple = optimize(input_sets, output_set, size_dict, memory_arg) else: path_optimizer = paths.get_path_fn(optimize) path_tuple = path_optimizer(input_sets, output_set, size_dict, memory_arg) cost_list = [] scale_list = [] size_list = [] contraction_list = [] # Build contraction tuple (positions, gemm, einsum_str, remaining) for cnum, contract_inds in enumerate(path_tuple): # Make sure we remove inds from right to left contract_inds = tuple(sorted(contract_inds, reverse=True)) contract_tuple = helpers.find_contraction(contract_inds, input_sets, output_set) out_inds, input_sets, idx_removed, idx_contract = contract_tuple # Compute cost, scale, and size cost = helpers.flop_count(idx_contract, bool(idx_removed), len(contract_inds), size_dict) cost_list.append(cost) scale_list.append(len(idx_contract)) size_list.append(helpers.compute_size_by_dict(out_inds, size_dict)) tmp_inputs = [input_list.pop(x) for x in contract_inds] tmp_shapes = [input_shapes.pop(x) for x in contract_inds] if use_blas: do_blas = blas.can_blas(tmp_inputs, "".join(out_inds), idx_removed, tmp_shapes) else: do_blas = False # Last contraction if (cnum - len(path_tuple)) == -1: idx_result = output_subscript else: # use tensordot order to minimize transpositions all_input_inds = "".join(tmp_inputs) idx_result = "".join(sorted(out_inds, key=all_input_inds.find)) shp_result = parser.find_output_shape(tmp_inputs, tmp_shapes, idx_result) input_list.append(idx_result) input_shapes.append(shp_result) einsum_str = ",".join(tmp_inputs) + "->" + idx_result # for large expressions saving the remaining terms at each step can # incur a large memory footprint - and also be messy to print if len(input_list) <= 20: remaining: Optional[Tuple[str, ...]] = tuple(input_list) else: remaining = None contraction = (contract_inds, idx_removed, einsum_str, remaining, do_blas) contraction_list.append(contraction) opt_cost = sum(cost_list) if einsum_call_arg: return operands_prepped, contraction_list # type: ignore path_print = PathInfo( contraction_list, input_subscripts, output_subscript, indices, path_tuple, scale_list, naive_cost, opt_cost, size_list, size_dict, ) return path_tuple, path_print @sharing.einsum_cache_wrap def _einsum(*operands: Any, **kwargs: Any) -> ArrayType: """Base einsum, but with pre-parse for valid characters if a string is given.""" fn = backends.get_func("einsum", kwargs.pop("backend", "numpy")) if not isinstance(operands[0], str): return fn(*operands, **kwargs) einsum_str, operands = operands[0], operands[1:] # Do we need to temporarily map indices into [a-z,A-Z] range? if not parser.has_valid_einsum_chars_only(einsum_str): # Explicitly find output str first so as to maintain order if "->" not in einsum_str: einsum_str += "->" + parser.find_output_str(einsum_str) einsum_str = parser.convert_to_valid_einsum_chars(einsum_str) kwargs = _filter_einsum_defaults(kwargs) # type: ignore return fn(einsum_str, *operands, **kwargs) def _default_transpose(x: ArrayType, axes: Tuple[int, ...]) -> ArrayType: # most libraries implement a method version return x.transpose(axes) @sharing.transpose_cache_wrap def _transpose(x: ArrayType, axes: Tuple[int, ...], backend: str = "numpy") -> ArrayType: """Base transpose.""" fn = backends.get_func("transpose", backend, _default_transpose) return fn(x, axes) @sharing.tensordot_cache_wrap def _tensordot(x: ArrayType, y: ArrayType, axes: Tuple[int, ...], backend: str = "numpy") -> ArrayType: """Base tensordot.""" fn = backends.get_func("tensordot", backend) return fn(x, y, axes=axes) # Rewrite einsum to handle different cases @overload def contract( subscripts: str, *operands: ArrayType, out: ArrayType = ..., use_blas: bool = ..., optimize: OptimizeKind = ..., memory_limit: _MemoryLimit = ..., backend: BackendType = ..., **kwargs: Any, ) -> ArrayType: ... @overload def contract( subscripts: ArrayType, *operands: Union[ArrayType, Collection[int]], out: ArrayType = ..., use_blas: bool = ..., optimize: OptimizeKind = ..., memory_limit: _MemoryLimit = ..., backend: BackendType = ..., **kwargs: Any, ) -> ArrayType: ... def contract( subscripts: Union[str, ArrayType], *operands: Union[ArrayType, Collection[int]], out: Optional[ArrayType] = None, use_blas: bool = True, optimize: OptimizeKind = True, memory_limit: _MemoryLimit = None, backend: BackendType = "auto", **kwargs: Any, ) -> ArrayType: """Evaluates the Einstein summation convention on the operands. A drop in replacement for NumPy's einsum function that optimizes the order of contraction to reduce overall scaling at the cost of several intermediate arrays. Parameters: subscripts: Specifies the subscripts for summation. *operands: These are the arrays for the operation. out: A output array in which set the resulting output. use_blas: Do you use BLAS for valid operations, may use extra memory for more intermediates. optimize:- Choose the type of path the contraction will be optimized with - if a list is given uses this as the path. - `'optimal'` An algorithm that explores all possible ways of contracting the listed tensors. Scales factorially with the number of terms in the contraction. - `'dp'` A faster (but essentially optimal) algorithm that uses dynamic programming to exhaustively search all contraction paths without outer-products. - `'greedy'` An cheap algorithm that heuristically chooses the best pairwise contraction at each step. Scales linearly in the number of terms in the contraction. - `'random-greedy'` Run a randomized version of the greedy algorithm 32 times and pick the best path. - `'random-greedy-128'` Run a randomized version of the greedy algorithm 128 times and pick the best path. - `'branch-all'` An algorithm like optimal but that restricts itself to searching 'likely' paths. Still scales factorially. - `'branch-2'` An even more restricted version of 'branch-all' that only searches the best two options at each step. Scales exponentially with the number of terms in the contraction. - `'auto', None, True` Choose the best of the above algorithms whilst aiming to keep the path finding time below 1ms. - `'auto-hq'` Aim for a high quality contraction, choosing the best of the above algorithms whilst aiming to keep the path finding time below 1sec. - `False` will not optimize the contraction. memory_limit:- Give the upper bound of the largest intermediate tensor contract will build. - None or -1 means there is no limit. - `max_input` means the limit is set as largest input tensor. - A positive integer is taken as an explicit limit on the number of elements. The default is None. Note that imposing a limit can make contractions exponentially slower to perform. backend: Which library to use to perform the required ``tensordot``, ``transpose`` and ``einsum`` calls. Should match the types of arrays supplied, See `contract_expression` for generating expressions which convert numpy arrays to and from the backend library automatically. Returns: The result of the einsum expression. Notes: This function should produce a result identical to that of NumPy's einsum function. The primary difference is ``contract`` will attempt to form intermediates which reduce the overall scaling of the given einsum contraction. By default the worst intermediate formed will be equal to that of the largest input array. For large einsum expressions with many input arrays this can provide arbitrarily large (1000 fold+) speed improvements. For contractions with just two tensors this function will attempt to use NumPy's built-in BLAS functionality to ensure that the given operation is performed optimally. When NumPy is linked to a threaded BLAS, potential speedups are on the order of 20-100 for a six core machine. """ if (optimize is True) or (optimize is None): optimize = "auto" operands_list = [subscripts] + list(operands) # If no optimization, run pure einsum if optimize is False: return _einsum(*operands_list, out=out, **kwargs) # Grab non-einsum kwargs gen_expression = kwargs.pop("_gen_expression", False) constants_dict = kwargs.pop("_constants_dict", {}) if gen_expression: full_str = operands_list[0] # Build the contraction list and operand contraction_list: ContractionListType operands, contraction_list = contract_path( # type: ignore *operands_list, optimize=optimize, memory_limit=memory_limit, einsum_call=True, use_blas=use_blas ) # check if performing contraction or just building expression if gen_expression: return ContractExpression(full_str, contraction_list, constants_dict, **kwargs) return _core_contract(operands, contraction_list, backend=backend, out=out, **kwargs) @lru_cache(None) def _infer_backend_class_cached(cls: type) -> str: return cls.__module__.split(".")[0] def infer_backend(x: Any) -> str: return _infer_backend_class_cached(x.__class__) def parse_backend(arrays: Sequence[ArrayType], backend: Optional[str]) -> str: """Find out what backend we should use, dipatching based on the first array if ``backend='auto'`` is specified. """ if (backend != "auto") and (backend is not None): return backend backend = infer_backend(arrays[0]) # some arrays will be defined in modules that don't implement tensordot # etc. so instead default to numpy if not backends.has_tensordot(backend): return "numpy" return backend def _core_contract( operands_: Sequence[ArrayType], contraction_list: ContractionListType, backend: Optional[str] = "auto", evaluate_constants: bool = False, out: Optional[ArrayType] = None, **kwargs: Any, ) -> ArrayType: """Inner loop used to perform an actual contraction given the output from a ``contract_path(..., einsum_call=True)`` call. """ # Special handling if out is specified specified_out = out is not None operands = list(operands_) backend = parse_backend(operands, backend) # try and do as much as possible without einsum if not available no_einsum = not backends.has_einsum(backend) # Start contraction loop for num, contraction in enumerate(contraction_list): inds, idx_rm, einsum_str, _, blas_flag = contraction # check if we are performing the pre-pass of an expression with constants, # if so, break out upon finding first non-constant (None) operand if evaluate_constants and any(operands[x] is None for x in inds): return operands, contraction_list[num:] tmp_operands = [operands.pop(x) for x in inds] # Do we need to deal with the output? handle_out = specified_out and ((num + 1) == len(contraction_list)) # Call tensordot (check if should prefer einsum, but only if available) if blas_flag and ("EINSUM" not in blas_flag or no_einsum): # type: ignore # Checks have already been handled input_str, results_index = einsum_str.split("->") input_left, input_right = input_str.split(",") tensor_result = "".join(s for s in input_left + input_right if s not in idx_rm) if idx_rm: # Find indices to contract over left_pos, right_pos = [], [] for s in idx_rm: left_pos.append(input_left.find(s)) right_pos.append(input_right.find(s)) # Construct the axes tuples in a canonical order axes = tuple(zip(*sorted(zip(left_pos, right_pos)))) else: # Ensure axes is always pair of tuples axes = ((), ()) # Contract! new_view = _tensordot(*tmp_operands, axes=axes, backend=backend, **kwargs) # Build a new view if needed if (tensor_result != results_index) or handle_out: transpose = tuple(map(tensor_result.index, results_index)) new_view = _transpose(new_view, axes=transpose, backend=backend) if handle_out: out[:] = new_view # type: ignore else: # Call einsum out_kwarg: Union[None, ArrayType] = None if handle_out: out_kwarg = out new_view = _einsum(einsum_str, *tmp_operands, backend=backend, out=out_kwarg, **kwargs) # Append new items and dereference what we can operands.append(new_view) del tmp_operands, new_view if specified_out: return out else: return operands[0] def format_const_einsum_str(einsum_str: str, constants: Iterable[int]) -> str: """Add brackets to the constant terms in ``einsum_str``. For example: >>> format_const_einsum_str('ab,bc,cd->ad', [0, 2]) 'bc,[ab,cd]->ad' No-op if there are no constants. """ if not constants: return einsum_str if "->" in einsum_str: lhs, rhs = einsum_str.split("->") arrow = "->" else: lhs, rhs, arrow = einsum_str, "", "" wrapped_terms = [f"[{t}]" if i in constants else t for i, t in enumerate(lhs.split(","))] formatted_einsum_str = "{}{}{}".format(",".join(wrapped_terms), arrow, rhs) # merge adjacent constants formatted_einsum_str = formatted_einsum_str.replace("],[", ",") return formatted_einsum_str class ContractExpression: """Helper class for storing an explicit ``contraction_list`` which can then be repeatedly called solely with the array arguments. """ def __init__( self, contraction: str, contraction_list: ContractionListType, constants_dict: Dict[int, ArrayType], **kwargs: Any, ): self.contraction = format_const_einsum_str(contraction, constants_dict.keys()) self.contraction_list = contraction_list self.kwargs = kwargs # need to know _full_num_args to parse constants with, and num_args to call with self._full_num_args = contraction.count(",") + 1 self.num_args = self._full_num_args - len(constants_dict) # likewise need to know full contraction list self._full_contraction_list = contraction_list self._constants_dict = constants_dict self._evaluated_constants: Dict[str, Any] = {} self._backend_expressions: Dict[str, Any] = {} def evaluate_constants(self, backend: Optional[str] = "auto") -> None: """Convert any constant operands to the correct backend form, and perform as many contractions as possible to create a new list of operands, stored in ``self._evaluated_constants[backend]``. This also makes sure ``self.contraction_list`` only contains the remaining, non-const operations. """ # prepare a list of operands, with `None` for non-consts tmp_const_ops = [self._constants_dict.get(i, None) for i in range(self._full_num_args)] backend = parse_backend(tmp_const_ops, backend) # get the new list of operands with constant operations performed, and remaining contractions try: new_ops, new_contraction_list = backends.evaluate_constants(backend, tmp_const_ops, self) except KeyError: new_ops, new_contraction_list = self(*tmp_const_ops, backend=backend, evaluate_constants=True) self._evaluated_constants[backend] = new_ops self.contraction_list = new_contraction_list def _get_evaluated_constants(self, backend: str) -> List[Optional[ArrayType]]: """Retrieve or generate the cached list of constant operators (mixed in with None representing non-consts) and the remaining contraction list. """ try: return self._evaluated_constants[backend] except KeyError: self.evaluate_constants(backend) return self._evaluated_constants[backend] def _get_backend_expression(self, arrays: Sequence[ArrayType], backend: str) -> Any: try: return self._backend_expressions[backend] except KeyError: fn = backends.build_expression(backend, arrays, self) self._backend_expressions[backend] = fn return fn def _contract( self, arrays: Sequence[ArrayType], out: Optional[ArrayType] = None, backend: Optional[str] = "auto", evaluate_constants: bool = False, ) -> ArrayType: """The normal, core contraction.""" contraction_list = self._full_contraction_list if evaluate_constants else self.contraction_list return _core_contract( list(arrays), contraction_list, out=out, backend=backend, evaluate_constants=evaluate_constants, **self.kwargs, ) def _contract_with_conversion( self, arrays: Sequence[ArrayType], out: Optional[ArrayType], backend: str, evaluate_constants: bool = False, ) -> ArrayType: """Special contraction, i.e., contraction with a different backend but converting to and from that backend. Retrieves or generates a cached expression using ``arrays`` as templates, then calls it with ``arrays``. If ``evaluate_constants=True``, perform a partial contraction that prepares the constant tensors and operations with the right backend. """ # convert consts to correct type & find reduced contraction list if evaluate_constants: return backends.evaluate_constants(backend, arrays, self) result = self._get_backend_expression(arrays, backend)(*arrays) if out is not None: out[()] = result return out return result def __call__( self, *arrays: ArrayType, out: Union[None, ArrayType] = None, backend: str = "auto", evaluate_constants: bool = False, ) -> ArrayType: """Evaluate this expression with a set of arrays. Parameters: arrays: The arrays to supply as input to the expression. out: If specified, output the result into this array. backend: Perform the contraction with this backend library. If numpy arrays are supplied then try to convert them to and from the correct backend array type. evaluate_constants: Pre-evaluates constants with the appropriate backend. Returns: The contracted result. """ backend = parse_backend(arrays, backend) correct_num_args = self._full_num_args if evaluate_constants else self.num_args if len(arrays) != correct_num_args: raise ValueError( f"This `ContractExpression` takes exactly {self.num_args} array arguments " f"but received {len(arrays)}." ) if self._constants_dict and not evaluate_constants: # fill in the missing non-constant terms with newly supplied arrays ops_var, ops_const = iter(arrays), self._get_evaluated_constants(backend) ops: Sequence[ArrayType] = [next(ops_var) if op is None else op for op in ops_const] else: ops = arrays try: # Check if the backend requires special preparation / calling # but also ignore non-numpy arrays -> assume user wants same type back if backends.has_backend(backend) and all(infer_backend(x) == "numpy" for x in arrays): return self._contract_with_conversion(ops, out, backend, evaluate_constants=evaluate_constants) return self._contract(ops, out=out, backend=backend, evaluate_constants=evaluate_constants) except ValueError as err: original_msg = str(err.args) if err.args else "" msg = ( "Internal error while evaluating `ContractExpression`. Note that few checks are performed" " - the number and rank of the array arguments must match the original expression. " f"The internal error was: '{original_msg}'", ) err.args = msg raise def __repr__(self) -> str: if self._constants_dict: constants_repr = f", constants={sorted(self._constants_dict)}" else: constants_repr = "" return f"" def __str__(self) -> str: s = [self.__repr__()] for i, c in enumerate(self.contraction_list): s.append(f"\n {i + 1}. ") s.append(f"'{c[2]}'" + (f" [{c[-1]}]" if c[-1] else "")) s.append(f"\neinsum_kwargs={self.kwargs}") return "".join(s) def shape_only(shape: TensorShapeType) -> ArrayShaped: """Dummy ``numpy.ndarray`` which has a shape only - for generating contract expressions. """ return ArrayShaped(shape) # Overlaod for contract(einsum_string, *operands) @overload def contract_expression( subscripts: str, *operands: Union[ArrayType, TensorShapeType], constants: Union[Collection[int], None] = ..., use_blas: bool = ..., optimize: OptimizeKind = ..., memory_limit: _MemoryLimit = ..., **kwargs: Any, ) -> ContractExpression: ... # Overlaod for contract(operand, indices, operand, indices, ....) @overload def contract_expression( subscripts: Union[ArrayType, TensorShapeType], *operands: Union[ArrayType, TensorShapeType, Collection[int]], constants: Union[Collection[int], None] = ..., use_blas: bool = ..., optimize: OptimizeKind = ..., memory_limit: _MemoryLimit = ..., **kwargs: Any, ) -> ContractExpression: ... def contract_expression( subscripts: Union[str, ArrayType, TensorShapeType], *shapes: Union[ArrayType, TensorShapeType, Collection[int]], constants: Union[Collection[int], None] = None, use_blas: bool = True, optimize: OptimizeKind = True, memory_limit: _MemoryLimit = None, **kwargs: Any, ) -> ContractExpression: """Generate a reusable expression for a given contraction with specific shapes, which can, for example, be cached. Parameters: subscripts: Specifies the subscripts for summation. shapes: Shapes of the arrays to optimize the contraction for. constants: The indices of any constant arguments in `shapes`, in which case the actual array should be supplied at that position rather than just a shape. If these are specified, then constant parts of the contraction between calls will be reused. Additionally, if a GPU-enabled backend is used for example, then the constant tensors will be kept on the GPU, minimizing transfers. kwargs: Passed on to `contract_path` or `einsum`. See `contract`. Returns: Callable with signature `expr(*arrays, out=None, backend='numpy')` where the array's shapes should match `shapes`. Notes: The `out` keyword argument should be supplied to the generated expression rather than this function. The `backend` keyword argument should also be supplied to the generated expression. If numpy arrays are supplied, if possible they will be converted to and back from the correct backend array type. The generated expression will work with any arrays which have the same rank (number of dimensions) as the original shapes, however, if the actual sizes are different, the expression may no longer be optimal. Constant operations will be computed upon the first call with a particular backend, then subsequently reused. Examples: Basic usage: ```python expr = contract_expression("ab,bc->ac", (3, 4), (4, 5)) a, b = np.random.rand(3, 4), np.random.rand(4, 5) c = expr(a, b) np.allclose(c, a @ b) #> True ``` Supply `a` as a constant: ```python expr = contract_expression("ab,bc->ac", a, (4, 5), constants=[0]) expr #> ac', constants=[0])> c = expr(b) np.allclose(c, a @ b) #> True ``` """ if not optimize: raise ValueError("Can only generate expressions for optimized contractions.") for arg in ("out", "backend"): if kwargs.get(arg, None) is not None: raise ValueError( f"'{arg}' should only be specified when calling a " "`ContractExpression`, not when building it." ) if not isinstance(subscripts, str): subscripts, shapes = parser.convert_interleaved_input((subscripts,) + shapes) kwargs["_gen_expression"] = True # build dict of constant indices mapped to arrays constants = constants or () constants_dict = {i: shapes[i] for i in constants} kwargs["_constants_dict"] = constants_dict # apart from constant arguments, make dummy arrays dummy_arrays = [s if i in constants else shape_only(s) for i, s in enumerate(shapes)] # type: ignore return contract( subscripts, *dummy_arrays, use_blas=use_blas, optimize=optimize, memory_limit=memory_limit, **kwargs ) opt_einsum-3.4.0/opt_einsum/helpers.py000066400000000000000000000102561467526163400201200ustar00rootroot00000000000000"""Contains helper functions for opt_einsum testing scripts.""" from typing import Any, Collection, Dict, FrozenSet, Iterable, List, Tuple, overload from opt_einsum.typing import ArrayIndexType, ArrayType __all__ = ["compute_size_by_dict", "find_contraction", "flop_count"] _valid_chars = "abcdefghijklmopqABC" _sizes = [2, 3, 4, 5, 4, 3, 2, 6, 5, 4, 3, 2, 5, 7, 4, 3, 2, 3, 4] _default_dim_dict = dict(zip(_valid_chars, _sizes)) @overload def compute_size_by_dict(indices: Iterable[int], idx_dict: List[int]) -> int: ... @overload def compute_size_by_dict(indices: Collection[str], idx_dict: Dict[str, int]) -> int: ... def compute_size_by_dict(indices: Any, idx_dict: Any) -> int: """Computes the product of the elements in indices based on the dictionary idx_dict. Parameters ---------- indices : iterable Indices to base the product on. idx_dict : dictionary Dictionary of index _sizes Returns: ------- ret : int The resulting product. Examples: -------- >>> compute_size_by_dict('abbc', {'a': 2, 'b':3, 'c':5}) 90 """ ret = 1 for i in indices: # lgtm [py/iteration-string-and-sequence] ret *= idx_dict[i] return ret def find_contraction( positions: Collection[int], input_sets: List[ArrayIndexType], output_set: ArrayIndexType, ) -> Tuple[FrozenSet[str], List[ArrayIndexType], ArrayIndexType, ArrayIndexType]: """Finds the contraction for a given set of input and output sets. Parameters ---------- positions : iterable Integer positions of terms used in the contraction. input_sets : list List of sets that represent the lhs side of the einsum subscript output_set : set Set that represents the rhs side of the overall einsum subscript Returns: ------- new_result : set The indices of the resulting contraction remaining : list List of sets that have not been contracted, the new set is appended to the end of this list idx_removed : set Indices removed from the entire contraction idx_contraction : set The indices used in the current contraction Examples: -------- # A simple dot product test case >>> pos = (0, 1) >>> isets = [set('ab'), set('bc')] >>> oset = set('ac') >>> find_contraction(pos, isets, oset) ({'a', 'c'}, [{'a', 'c'}], {'b'}, {'a', 'b', 'c'}) # A more complex case with additional terms in the contraction >>> pos = (0, 2) >>> isets = [set('abd'), set('ac'), set('bdc')] >>> oset = set('ac') >>> find_contraction(pos, isets, oset) ({'a', 'c'}, [{'a', 'c'}, {'a', 'c'}], {'b', 'd'}, {'a', 'b', 'c', 'd'}) """ remaining = list(input_sets) inputs = (remaining.pop(i) for i in sorted(positions, reverse=True)) idx_contract = frozenset.union(*inputs) idx_remain = output_set.union(*remaining) new_result = idx_remain & idx_contract idx_removed = idx_contract - new_result remaining.append(new_result) return new_result, remaining, idx_removed, idx_contract def flop_count( idx_contraction: Collection[str], inner: bool, num_terms: int, size_dictionary: Dict[str, int], ) -> int: """Computes the number of FLOPS in the contraction. Parameters ---------- idx_contraction : iterable The indices involved in the contraction inner : bool Does this contraction require an inner product? num_terms : int The number of terms in a contraction size_dictionary : dict The size of each of the indices in idx_contraction Returns: ------- flop_count : int The total number of FLOPS required for the contraction. Examples: -------- >>> flop_count('abc', False, 1, {'a': 2, 'b':3, 'c':5}) 30 >>> flop_count('abc', True, 2, {'a': 2, 'b':3, 'c':5}) 60 """ overall_size = compute_size_by_dict(idx_contraction, size_dictionary) op_factor = max(1, num_terms - 1) if inner: op_factor += 1 return overall_size * op_factor def has_array_interface(array: ArrayType) -> ArrayType: if hasattr(array, "__array_interface__"): return True else: return False opt_einsum-3.4.0/opt_einsum/parser.py000066400000000000000000000317251467526163400177560ustar00rootroot00000000000000"""A functionally equivalent parser of the numpy.einsum input parser.""" import itertools from typing import Any, Dict, Iterator, List, Sequence, Tuple from opt_einsum.typing import ArrayType, TensorShapeType __all__ = [ "is_valid_einsum_char", "has_valid_einsum_chars_only", "get_symbol", "get_shape", "gen_unused_symbols", "convert_to_valid_einsum_chars", "alpha_canonicalize", "find_output_str", "find_output_shape", "possibly_convert_to_numpy", "parse_einsum_input", ] _einsum_symbols_base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" def is_valid_einsum_char(x: str) -> bool: """Check if the character ``x`` is valid for numpy einsum. **Examples:** ```python is_valid_einsum_char("a") #> True is_valid_einsum_char("Ǵ") #> False ``` """ return (x in _einsum_symbols_base) or (x in ",->.") def has_valid_einsum_chars_only(einsum_str: str) -> bool: """Check if ``einsum_str`` contains only valid characters for numpy einsum. **Examples:** ```python has_valid_einsum_chars_only("abAZ") #> True has_valid_einsum_chars_only("Över") #> False ``` """ return all(map(is_valid_einsum_char, einsum_str)) def get_symbol(i: int) -> str: """Get the symbol corresponding to int ``i`` - runs through the usual 52 letters before resorting to unicode characters, starting at ``chr(192)`` and skipping surrogates. **Examples:** ```python get_symbol(2) #> 'c' get_symbol(200) #> 'Ŕ' get_symbol(20000) #> '京' ``` """ if i < 52: return _einsum_symbols_base[i] elif i >= 55296: # Skip chr(57343) - chr(55296) as surrogates return chr(i + 2048) else: return chr(i + 140) def gen_unused_symbols(used: str, n: int) -> Iterator[str]: """Generate ``n`` symbols that are not already in ``used``. **Examples:** ```python list(oe.parser.gen_unused_symbols("abd", 2)) #> ['c', 'e'] ``` """ i = cnt = 0 while cnt < n: s = get_symbol(i) i += 1 if s in used: continue yield s cnt += 1 def convert_to_valid_einsum_chars(einsum_str: str) -> str: """Convert the str ``einsum_str`` to contain only the alphabetic characters valid for numpy einsum. If there are too many symbols, let the backend throw an error. Examples: -------- >>> oe.parser.convert_to_valid_einsum_chars("Ĥěļļö") 'cbdda' """ symbols = sorted(set(einsum_str) - set(",->")) replacer = {x: get_symbol(i) for i, x in enumerate(symbols)} return "".join(replacer.get(x, x) for x in einsum_str) def alpha_canonicalize(equation: str) -> str: """Alpha convert an equation in an order-independent canonical way. Examples: -------- >>> oe.parser.alpha_canonicalize("dcba") 'abcd' >>> oe.parser.alpha_canonicalize("Ĥěļļö") 'abccd' """ rename: Dict[str, str] = {} for name in equation: if name in ".,->": continue if name not in rename: rename[name] = get_symbol(len(rename)) return "".join(rename.get(x, x) for x in equation) def find_output_str(subscripts: str) -> str: """Find the output string for the inputs ``subscripts`` under canonical einstein summation rules. That is, repeated indices are summed over by default. Examples: -------- >>> oe.parser.find_output_str("ab,bc") 'ac' >>> oe.parser.find_output_str("a,b") 'ab' >>> oe.parser.find_output_str("a,a,b,b") '' """ tmp_subscripts = subscripts.replace(",", "") return "".join(s for s in sorted(set(tmp_subscripts)) if tmp_subscripts.count(s) == 1) def find_output_shape(inputs: List[str], shapes: List[TensorShapeType], output: str) -> TensorShapeType: """Find the output shape for given inputs, shapes and output string, taking into account broadcasting. Examples: -------- >>> oe.parser.find_output_shape(["ab", "bc"], [(2, 3), (3, 4)], "ac") (2, 4) # Broadcasting is accounted for >>> oe.parser.find_output_shape(["a", "a"], [(4, ), (1, )], "a") (4,) """ return tuple(max(shape[loc] for shape, loc in zip(shapes, [x.find(c) for x in inputs]) if loc >= 0) for c in output) _BaseTypes = (bool, int, float, complex, str, bytes) def get_shape(x: Any) -> TensorShapeType: """Get the shape of the array-like object `x`. If `x` is not array-like, raise an error. Array-like objects are those that have a `shape` attribute, are sequences of BaseTypes, or are BaseTypes. BaseTypes are defined as `bool`, `int`, `float`, `complex`, `str`, and `bytes`. """ if hasattr(x, "shape"): return x.shape elif isinstance(x, _BaseTypes): return () elif isinstance(x, Sequence): shape = [] while isinstance(x, Sequence) and not isinstance(x, _BaseTypes): shape.append(len(x)) x = x[0] return tuple(shape) else: raise ValueError(f"Cannot determine the shape of {x}, can only determine the shape of array-like objects.") def possibly_convert_to_numpy(x: Any) -> Any: """Convert things without a 'shape' to ndarrays, but leave everything else. Examples: -------- >>> oe.parser.possibly_convert_to_numpy(5) array(5) >>> oe.parser.possibly_convert_to_numpy([5, 3]) array([5, 3]) >>> oe.parser.possibly_convert_to_numpy(np.array([5, 3])) array([5, 3]) # Any class with a shape is passed through >>> class Shape: ... def __init__(self, shape): ... self.shape = shape ... >>> myshape = Shape((5, 5)) >>> oe.parser.possibly_convert_to_numpy(myshape) <__main__.Shape object at 0x10f850710> """ if not hasattr(x, "shape"): try: import numpy as np # type: ignore except ModuleNotFoundError: raise ModuleNotFoundError( "numpy is required to convert non-array objects to arrays. This function will be deprecated in the future." ) return np.asanyarray(x) else: return x def convert_subscripts(old_sub: List[Any], symbol_map: Dict[Any, Any]) -> str: """Convert user custom subscripts list to subscript string according to `symbol_map`. Examples: -------- >>> oe.parser.convert_subscripts(['abc', 'def'], {'abc':'a', 'def':'b'}) 'ab' >>> oe.parser.convert_subscripts([Ellipsis, object], {object:'a'}) '...a' """ new_sub = "" for s in old_sub: if s is Ellipsis: new_sub += "..." else: # no need to try/except here because symbol_map has already been checked new_sub += symbol_map[s] return new_sub def convert_interleaved_input(operands: Sequence[Any]) -> Tuple[str, Tuple[Any, ...]]: """Convert 'interleaved' input to standard einsum input.""" tmp_operands = list(operands) operand_list = [] subscript_list = [] for _ in range(len(operands) // 2): operand_list.append(tmp_operands.pop(0)) subscript_list.append(tmp_operands.pop(0)) output_list = tmp_operands[-1] if len(tmp_operands) else None # build a map from user symbols to single-character symbols based on `get_symbol` # The map retains the intrinsic order of user symbols try: # collect all user symbols symbol_set = set(itertools.chain.from_iterable(subscript_list)) # remove Ellipsis because it can not be compared with other objects symbol_set.discard(Ellipsis) # build the map based on sorted user symbols, retaining the order we lost in the `set` symbol_map = {symbol: get_symbol(idx) for idx, symbol in enumerate(sorted(symbol_set))} except TypeError: # unhashable or uncomparable object raise TypeError( "For this input type lists must contain either Ellipsis " "or hashable and comparable object (e.g. int, str)." ) subscripts = ",".join(convert_subscripts(sub, symbol_map) for sub in subscript_list) if output_list is not None: subscripts += "->" subscripts += convert_subscripts(output_list, symbol_map) return subscripts, tuple(operand_list) def parse_einsum_input(operands: Any, shapes: bool = False) -> Tuple[str, str, List[ArrayType]]: """A reproduction of einsum c side einsum parsing in python. Parameters: operands: Intakes the same inputs as `contract_path`, but NOT the keyword args. The only supported keyword argument is: shapes: Whether ``parse_einsum_input`` should assume arrays (the default) or array shapes have been supplied. Returns: input_strings: Parsed input strings output_string: Parsed output string operands: The operands to use in the numpy contraction Examples: The operand list is simplified to reduce printing: ```python >>> a = np.random.rand(4, 4) >>> b = np.random.rand(4, 4, 4) >>> parse_einsum_input(('...a,...a->...', a, b)) ('za,xza', 'xz', [a, b]) >>> parse_einsum_input((a, [Ellipsis, 0], b, [Ellipsis, 0])) ('za,xza', 'xz', [a, b]) ``` """ if len(operands) == 0: raise ValueError("No input operands") if isinstance(operands[0], str): subscripts = operands[0].replace(" ", "") if shapes: if any(hasattr(o, "shape") for o in operands[1:]): raise ValueError( "shapes is set to True but given at least one operand looks like an array" " (at least one operand has a shape attribute). " ) operands = operands[1:] else: subscripts, operands = convert_interleaved_input(operands) if shapes: operand_shapes = operands else: operand_shapes = [get_shape(o) for o in operands] # Check for proper "->" if ("-" in subscripts) or (">" in subscripts): invalid = (subscripts.count("-") > 1) or (subscripts.count(">") > 1) if invalid or (subscripts.count("->") != 1): raise ValueError("Subscripts can only contain one '->'.") # Parse ellipses if "." in subscripts: used = subscripts.replace(".", "").replace(",", "").replace("->", "") ellipse_inds = "".join(gen_unused_symbols(used, max(len(x) for x in operand_shapes))) longest = 0 # Do we have an output to account for? if "->" in subscripts: input_tmp, output_sub = subscripts.split("->") split_subscripts = input_tmp.split(",") out_sub = True else: split_subscripts = subscripts.split(",") out_sub = False for num, sub in enumerate(split_subscripts): if "." in sub: if (sub.count(".") != 3) or (sub.count("...") != 1): raise ValueError("Invalid Ellipses.") # Take into account numerical values if operand_shapes[num] == (): ellipse_count = 0 else: ellipse_count = max(len(operand_shapes[num]), 1) - (len(sub) - 3) if ellipse_count > longest: longest = ellipse_count if ellipse_count < 0: raise ValueError("Ellipses lengths do not match.") elif ellipse_count == 0: split_subscripts[num] = sub.replace("...", "") else: split_subscripts[num] = sub.replace("...", ellipse_inds[-ellipse_count:]) subscripts = ",".join(split_subscripts) # Figure out output ellipses if longest == 0: out_ellipse = "" else: out_ellipse = ellipse_inds[-longest:] if out_sub: subscripts += "->" + output_sub.replace("...", out_ellipse) else: # Special care for outputless ellipses output_subscript = find_output_str(subscripts) normal_inds = "".join(sorted(set(output_subscript) - set(out_ellipse))) subscripts += "->" + out_ellipse + normal_inds # Build output string if does not exist if "->" in subscripts: input_subscripts, output_subscript = subscripts.split("->") else: input_subscripts, output_subscript = subscripts, find_output_str(subscripts) # Make sure output subscripts are unique and in the input for char in output_subscript: if output_subscript.count(char) != 1: raise ValueError(f"Output character '{char}' appeared more than once in the output.") if char not in input_subscripts: raise ValueError(f"Output character '{char}' did not appear in the input") # Make sure number operands is equivalent to the number of terms if len(input_subscripts.split(",")) != len(operands): raise ValueError( f"Number of einsum subscripts, {len(input_subscripts.split(','))}, must be equal to the " f"number of operands, {len(operands)}." ) return input_subscripts, output_subscript, operands opt_einsum-3.4.0/opt_einsum/path_random.py000066400000000000000000000340241467526163400207510ustar00rootroot00000000000000"""Support for random optimizers, including the random-greedy path.""" import functools import heapq import math import time from collections import deque from decimal import Decimal from random import choices as random_choices from random import seed as random_seed from typing import Any, Dict, Generator, Iterable, List, Optional, Tuple, Union from opt_einsum import helpers, paths from opt_einsum.typing import ArrayIndexType, ArrayType, PathType __all__ = ["RandomGreedy", "random_greedy", "random_greedy_128"] class RandomOptimizer(paths.PathOptimizer): """Base class for running any random path finder that benefits from repeated calling, possibly in a parallel fashion. Custom random optimizers should subclass this, and the `setup` method should be implemented with the following signature: ```python def setup(self, inputs, output, size_dict): # custom preparation here ... return trial_fn, trial_args ``` Where `trial_fn` itself should have the signature:: ```python def trial_fn(r, *trial_args): # custom computation of path here return ssa_path, cost, size ``` Where `r` is the run number and could for example be used to seed a random number generator. See `RandomGreedy` for an example. Parameters: max_repeats: The maximum number of repeat trials to have. max_time: The maximum amount of time to run the algorithm for. minimize: Whether to favour paths that minimize the total estimated flop-count or the size of the largest intermediate created. parallel: Whether to parallelize the random trials, by default `False`. If `True`, use a `concurrent.futures.ProcessPoolExecutor` with the same number of processes as cores. If an integer is specified, use that many processes instead. Finally, you can supply a custom executor-pool which should have an API matching that of the python 3 standard library module `concurrent.futures`. Namely, a `submit` method that returns `Future` objects, themselves with `result` and `cancel` methods. pre_dispatch: If running in parallel, how many jobs to pre-dispatch so as to avoid submitting all jobs at once. Should also be more than twice the number of workers to avoid under-subscription. Default: 128. Attributes: path: The best path found so far. costs: The list of each trial's costs found so far. sizes: The list of each trial's largest intermediate size so far. """ def __init__( self, max_repeats: int = 32, max_time: Optional[float] = None, minimize: str = "flops", parallel: Union[bool, Decimal, int] = False, pre_dispatch: int = 128, ): if minimize not in ("flops", "size"): raise ValueError("`minimize` should be one of {'flops', 'size'}.") self.max_repeats = max_repeats self.max_time = max_time self.minimize = minimize self.better = paths.get_better_fn(minimize) self._parallel: Union[bool, Decimal, int] = False self.parallel = parallel self.pre_dispatch = pre_dispatch self.costs: List[int] = [] self.sizes: List[int] = [] self.best: Dict[str, Any] = {"flops": float("inf"), "size": float("inf")} self._repeats_start = 0 self._executor: Any self._futures: Any @property def path(self) -> PathType: """The best path found so far.""" return paths.ssa_to_linear(self.best["ssa_path"]) @property def parallel(self) -> Union[bool, Decimal, int]: return self._parallel @parallel.setter def parallel(self, parallel: Union[bool, Decimal, int]) -> None: # shutdown any previous executor if we are managing it if getattr(self, "_managing_executor", False): self._executor.shutdown() self._parallel = parallel self._managing_executor = False if parallel is False: self._executor = None return if parallel is True: from concurrent.futures import ProcessPoolExecutor self._executor = ProcessPoolExecutor() self._managing_executor = True return if isinstance(parallel, (int, Decimal)): from concurrent.futures import ProcessPoolExecutor self._executor = ProcessPoolExecutor(int(parallel)) self._managing_executor = True return # assume a pool-executor has been supplied self._executor = parallel def _gen_results_parallel(self, repeats: Iterable[int], trial_fn: Any, args: Any) -> Generator[Any, None, None]: """Lazily generate results from an executor without submitting all jobs at once.""" self._futures = deque() # the idea here is to submit at least ``pre_dispatch`` jobs *before* we # yield any results, then do both in tandem, before draining the queue for r in repeats: if len(self._futures) < self.pre_dispatch: self._futures.append(self._executor.submit(trial_fn, r, *args)) continue yield self._futures.popleft().result() while self._futures: yield self._futures.popleft().result() def _cancel_futures(self) -> None: if self._executor is not None: for f in self._futures: f.cancel() def setup( self, inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], ) -> Tuple[Any, Any]: raise NotImplementedError def __call__( self, inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], memory_limit: Optional[int] = None, ) -> PathType: self._check_args_against_first_call(inputs, output, size_dict) # start a timer? if self.max_time is not None: t0 = time.time() trial_fn, trial_args = self.setup(inputs, output, size_dict) r_start = self._repeats_start + len(self.costs) r_stop = r_start + self.max_repeats repeats = range(r_start, r_stop) # create the trials lazily if self._executor is not None: trials = self._gen_results_parallel(repeats, trial_fn, trial_args) else: trials = (trial_fn(r, *trial_args) for r in repeats) # assess the trials for ssa_path, cost, size in trials: # keep track of all costs and sizes self.costs.append(cost) self.sizes.append(size) # check if we have found a new best found_new_best = self.better(cost, size, self.best["flops"], self.best["size"]) if found_new_best: self.best["flops"] = cost self.best["size"] = size self.best["ssa_path"] = ssa_path # check if we have run out of time if (self.max_time is not None) and (time.time() > t0 + self.max_time): break self._cancel_futures() return self.path def __del__(self): # if we created the parallel pool-executor, shut it down if getattr(self, "_managing_executor", False): self._executor.shutdown() def thermal_chooser(queue, remaining, nbranch=8, temperature=1, rel_temperature=True): """A contraction 'chooser' that weights possible contractions using a Boltzmann distribution. Explicitly, given costs `c_i` (with `c_0` the smallest), the relative weights, `w_i`, are computed as: $$w_i = exp( -(c_i - c_0) / temperature)$$ Additionally, if `rel_temperature` is set, scale `temperature` by `abs(c_0)` to account for likely fluctuating cost magnitudes during the course of a contraction. Parameters: queue: The heapified list of candidate contractions. remaining: Mapping of remaining inputs' indices to the ssa id. temperature: When choosing a possible contraction, its relative probability will be proportional to `exp(-cost / temperature)`. Thus the larger `temperature` is, the further random paths will stray from the normal 'greedy' path. Conversely, if set to zero, only paths with exactly the same cost as the best at each step will be explored. rel_temperature: Whether to normalize the `temperature` at each step to the scale of the best cost. This is generally beneficial as the magnitude of costs can vary significantly throughout a contraction. nbranch: How many potential paths to calculate probability for and choose from at each step. Returns: cost k1 k2 k3 """ n = 0 choices = [] while queue and n < nbranch: cost, k1, k2, k12 = heapq.heappop(queue) if k1 not in remaining or k2 not in remaining: continue # candidate is obsolete choices.append((cost, k1, k2, k12)) n += 1 if n == 0: return None if n == 1: return choices[0] costs = [choice[0][0] for choice in choices] cmin = costs[0] # adjust by the overall scale to account for fluctuating absolute costs if rel_temperature: temperature *= max(1, abs(cmin)) # compute relative probability for each potential contraction if temperature == 0.0: energies = [1 if c == cmin else 0 for c in costs] else: # shift by cmin for numerical reasons energies = [math.exp(-(c - cmin) / temperature) for c in costs] # randomly choose a contraction based on energies (chosen,) = random_choices(range(n), weights=energies) cost, k1, k2, k12 = choices.pop(chosen) # put the other choice back in the heap for other in choices: heapq.heappush(queue, other) return cost, k1, k2, k12 def ssa_path_compute_cost( ssa_path: PathType, inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], ) -> Tuple[int, int]: """Compute the flops and max size of an ssa path.""" inputs = list(map(frozenset, inputs)) output = frozenset(output) remaining = set(range(len(inputs))) total_cost = 0 max_size = 0 for i, j in ssa_path: k12, flops12 = paths.calc_k12_flops(inputs, output, remaining, i, j, size_dict) # type: ignore remaining.discard(i) remaining.discard(j) remaining.add(len(inputs)) inputs.append(k12) total_cost += flops12 max_size = max(max_size, helpers.compute_size_by_dict(k12, size_dict)) return total_cost, max_size def _trial_greedy_ssa_path_and_cost( r: int, inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], choose_fn: Any, cost_fn: Any, ) -> Tuple[PathType, int, int]: """A single, repeatable, greedy trial run. **Returns:** ``ssa_path`` and cost.""" if r == 0: # always start with the standard greedy approach choose_fn = None random_seed(r) ssa_path = paths.ssa_greedy_optimize(inputs, output, size_dict, choose_fn, cost_fn) cost, size = ssa_path_compute_cost(ssa_path, inputs, output, size_dict) return ssa_path, cost, size class RandomGreedy(RandomOptimizer): def __init__( self, cost_fn: str = "memory-removed-jitter", temperature: float = 1.0, rel_temperature: bool = True, nbranch: int = 8, **kwargs: Any, ): """Parameters: cost_fn: A function that returns a heuristic 'cost' of a potential contraction with which to sort candidates. Should have signature `cost_fn(size12, size1, size2, k12, k1, k2)`. temperature: When choosing a possible contraction, its relative probability will be proportional to `exp(-cost / temperature)`. Thus the larger `temperature` is, the further random paths will stray from the normal 'greedy' path. Conversely, if set to zero, only paths with exactly the same cost as the best at each step will be explored. rel_temperature: Whether to normalize the ``temperature`` at each step to the scale of the best cost. This is generally beneficial as the magnitude of costs can vary significantly throughout a contraction. If False, the algorithm will end up branching when the absolute cost is low, but stick to the 'greedy' path when the cost is high - this can also be beneficial. nbranch: How many potential paths to calculate probability for and choose from at each step. kwargs: Supplied to RandomOptimizer. """ self.cost_fn = cost_fn self.temperature = temperature self.rel_temperature = rel_temperature self.nbranch = nbranch super().__init__(**kwargs) @property def choose_fn(self) -> Any: """The function that chooses which contraction to take - make this a property so that ``temperature`` and ``nbranch`` etc. can be updated between runs. """ if self.nbranch == 1: return None return functools.partial( thermal_chooser, temperature=self.temperature, nbranch=self.nbranch, rel_temperature=self.rel_temperature, ) def setup( self, inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], ) -> Tuple[Any, Any]: fn = _trial_greedy_ssa_path_and_cost args = (inputs, output, size_dict, self.choose_fn, self.cost_fn) return fn, args def random_greedy( inputs: List[ArrayIndexType], output: ArrayIndexType, idx_dict: Dict[str, int], memory_limit: Optional[int] = None, **optimizer_kwargs: Any, ) -> ArrayType: """A simple wrapper around the `RandomGreedy` optimizer.""" optimizer = RandomGreedy(**optimizer_kwargs) return optimizer(inputs, output, idx_dict, memory_limit) random_greedy_128 = functools.partial(random_greedy, max_repeats=128) opt_einsum-3.4.0/opt_einsum/paths.py000066400000000000000000001447771467526163400176150ustar00rootroot00000000000000"""Contains the path technology behind opt_einsum in addition to several path helpers.""" import bisect import functools import heapq import itertools import operator import random import re from collections import Counter, defaultdict from typing import Any, Callable, Dict, FrozenSet, Generator, List, Optional, Sequence, Set, Tuple, Union from typing import Counter as CounterType from opt_einsum.helpers import compute_size_by_dict, flop_count from opt_einsum.typing import ArrayIndexType, PathSearchFunctionType, PathType, TensorShapeType __all__ = [ "optimal", "BranchBound", "branch", "greedy", "auto", "auto_hq", "get_path_fn", "DynamicProgramming", "dynamic_programming", ] _UNLIMITED_MEM = {-1, None, float("inf")} class PathOptimizer: r"""Base class for different path optimizers to inherit from. Subclassed optimizers should define a call method with signature: ```python def __call__(self, inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: dict[str, int], memory_limit: int | None = None) -> list[tuple[int, ...]]: \"\"\" Parameters: inputs: The indices of each input array. outputs: The output indices size_dict: The size of each index memory_limit: If given, the maximum allowed memory. \"\"\" # ... compute path here ... return path ``` where `path` is a list of int-tuples specifying a contraction order. """ def _check_args_against_first_call( self, inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], ) -> None: """Utility that stateful optimizers can use to ensure they are not called with different contractions across separate runs. """ args = (inputs, output, size_dict) if not hasattr(self, "_first_call_args"): # simply set the attribute as currently there is no global PathOptimizer init self._first_call_args = args elif args != self._first_call_args: raise ValueError( "The arguments specifying the contraction that this path optimizer " "instance was called with have changed - try creating a new instance." ) def __call__( self, inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], memory_limit: Optional[int] = None, ) -> PathType: raise NotImplementedError def ssa_to_linear(ssa_path: PathType) -> PathType: """Convert a path with static single assignment ids to a path with recycled linear ids. Example: ```python ssa_to_linear([(0, 3), (2, 4), (1, 5)]) #> [(0, 3), (1, 2), (0, 1)] ``` """ # ids = np.arange(1 + max(map(max, ssa_path)), dtype=np.int32) # type: ignore # path = [] # for ssa_ids in ssa_path: # path.append(tuple(int(ids[ssa_id]) for ssa_id in ssa_ids)) # for ssa_id in ssa_ids: # ids[ssa_id:] -= 1 # return path n = sum(map(len, ssa_path)) - len(ssa_path) + 1 ids = list(range(n)) path = [] ssa = n for scon in ssa_path: con = sorted([bisect.bisect_left(ids, s) for s in scon]) for j in reversed(con): ids.pop(j) ids.append(ssa) path.append(con) ssa += 1 return [tuple(x) for x in path] # N = sum(map(len, ssa_path)) - len(ssa_path) + 1 # ids = list(range(N)) # ids = np.arange(1 + max(map(max, ssa_path)), dtype=np.int32) # path = [] # ssa = N # for scon in ssa_path: # con = sorted(map(ids.index, scon)) # for j in reversed(con): # ids.pop(j) # ids.append(ssa) # path.append(con) # ssa += 1 # return path def linear_to_ssa(path: PathType) -> PathType: """Convert a path with recycled linear ids to a path with static single assignment ids. Exmaple: ```python linear_to_ssa([(0, 3), (1, 2), (0, 1)]) #> [(0, 3), (2, 4), (1, 5)] ``` """ num_inputs = sum(map(len, path)) - len(path) + 1 linear_to_ssa = list(range(num_inputs)) new_ids = itertools.count(num_inputs) ssa_path = [] for ids in path: ssa_path.append(tuple(linear_to_ssa[id_] for id_ in ids)) for id_ in sorted(ids, reverse=True): del linear_to_ssa[id_] linear_to_ssa.append(next(new_ids)) return ssa_path def calc_k12_flops( inputs: Tuple[FrozenSet[str]], output: FrozenSet[str], remaining: FrozenSet[int], i: int, j: int, size_dict: Dict[str, int], ) -> Tuple[FrozenSet[str], int]: """Calculate the resulting indices and flops for a potential pairwise contraction - used in the recursive (optimal/branch) algorithms. Parameters: inputs: The indices of each tensor in this contraction, note this includes tensors unavailable to contract as static single assignment is used:> contracted tensors are not removed from the list. output: The set of output indices for the whole contraction. remaining: *The set of indices (corresponding to ``inputs``) of tensors still available to contract. i: Index of potential tensor to contract. j: Index of potential tensor to contract. size_dict: Size mapping of all the indices. Returns: k12: The resulting indices of the potential tensor. cost: Estimated flop count of operation. """ k1, k2 = inputs[i], inputs[j] either = k1 | k2 shared = k1 & k2 keep = frozenset.union(output, *map(inputs.__getitem__, remaining - {i, j})) k12 = either & keep cost = flop_count(either, bool(shared - keep), 2, size_dict) return k12, cost def _compute_oversize_flops( inputs: Tuple[FrozenSet[str]], remaining: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], ) -> int: """Compute the flop count for a contraction of all remaining arguments. This is used when a memory limit means that no pairwise contractions can be made. """ idx_contraction = frozenset.union(*map(inputs.__getitem__, remaining)) # type: ignore inner = idx_contraction - output num_terms = len(remaining) return flop_count(idx_contraction, bool(inner), num_terms, size_dict) def optimal( inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], memory_limit: Optional[int] = None, ) -> PathType: """Computes all possible pair contractions in a depth-first recursive manner, sieving results based on `memory_limit` and the best path found so far. Parameters: inputs: List of sets that represent the lhs side of the einsum subscript. output: Set that represents the rhs side of the overall einsum subscript. size_dict: Dictionary of index sizes. memory_limit: The maximum number of elements in a temporary array. Returns: path: The optimal contraction order within the memory limit constraint. Examples: ```python isets = [set('abd'), set('ac'), set('bdc')] oset = set('') idx_sizes = {'a': 1, 'b':2, 'c':3, 'd':4} optimal(isets, oset, idx_sizes, 5000) #> [(0, 2), (0, 1)] ``` """ inputs_set = tuple(map(frozenset, inputs)) output_set = frozenset(output) best_flops = {"flops": float("inf")} best_ssa_path = {"ssa_path": (tuple(range(len(inputs))),)} size_cache: Dict[FrozenSet[str], int] = {} result_cache: Dict[Tuple[ArrayIndexType, ArrayIndexType], Tuple[FrozenSet[str], int]] = {} def _optimal_iterate(path, remaining, inputs, flops): # reached end of path (only ever get here if flops is best found so far) if len(remaining) == 1: best_flops["flops"] = flops best_ssa_path["ssa_path"] = path return # check all possible remaining paths for i, j in itertools.combinations(remaining, 2): if i > j: i, j = j, i key = (inputs[i], inputs[j]) try: k12, flops12 = result_cache[key] except KeyError: k12, flops12 = result_cache[key] = calc_k12_flops(inputs, output_set, remaining, i, j, size_dict) # sieve based on current best flops new_flops = flops + flops12 if new_flops >= best_flops["flops"]: continue # sieve based on memory limit if memory_limit not in _UNLIMITED_MEM: try: size12 = size_cache[k12] except KeyError: size12 = size_cache[k12] = compute_size_by_dict(k12, size_dict) # possibly terminate this path with an all-terms einsum if size12 > memory_limit: new_flops = flops + _compute_oversize_flops(inputs, remaining, output_set, size_dict) if new_flops < best_flops["flops"]: best_flops["flops"] = new_flops best_ssa_path["ssa_path"] = path + (tuple(remaining),) continue # add contraction and recurse into all remaining _optimal_iterate( path=path + ((i, j),), inputs=inputs + (k12,), remaining=remaining - {i, j} | {len(inputs)}, flops=new_flops, ) _optimal_iterate(path=(), inputs=inputs_set, remaining=set(range(len(inputs))), flops=0) return ssa_to_linear(best_ssa_path["ssa_path"]) # functions for comparing which of two paths is 'better' def better_flops_first(flops: int, size: int, best_flops: int, best_size: int) -> bool: return (flops, size) < (best_flops, best_size) def better_size_first(flops: int, size: int, best_flops: int, best_size: int) -> bool: return (size, flops) < (best_size, best_flops) _BETTER_FNS = { "flops": better_flops_first, "size": better_size_first, } def get_better_fn(key: str) -> Callable[[int, int, int, int], bool]: return _BETTER_FNS[key] # functions for assigning a heuristic 'cost' to a potential contraction def cost_memory_removed(size12: int, size1: int, size2: int, k12: int, k1: int, k2: int) -> float: """The default heuristic cost, corresponding to the total reduction in memory of performing a contraction. """ return size12 - size1 - size2 def cost_memory_removed_jitter(size12: int, size1: int, size2: int, k12: int, k1: int, k2: int) -> float: """Like memory-removed, but with a slight amount of noise that breaks ties and thus jumbles the contractions a bit. """ return random.gauss(1.0, 0.01) * (size12 - size1 - size2) _COST_FNS = { "memory-removed": cost_memory_removed, "memory-removed-jitter": cost_memory_removed_jitter, } class BranchBound(PathOptimizer): def __init__( self, nbranch: Optional[int] = None, cutoff_flops_factor: int = 4, minimize: str = "flops", cost_fn: str = "memory-removed", ): """Explores possible pair contractions in a depth-first recursive manner like the `optimal` approach, but with extra heuristic early pruning of branches as well sieving by `memory_limit` and the best path found so far. Parameters: nbranch: How many branches to explore at each contraction step. If None, explore all possible branches. If an integer, branch into this many paths at each step. Defaults to None. cutoff_flops_factor: If at any point, a path is doing this much worse than the best path found so far was, terminate it. The larger this is made, the more paths will be fully explored and the slower the algorithm. Defaults to 4. minimize: Whether to optimize the path with regard primarily to the total estimated flop-count, or the size of the largest intermediate. The option not chosen will still be used as a secondary criterion. cost_fn: A function that returns a heuristic 'cost' of a potential contraction with which to sort candidates. Should have signature `cost_fn(size12, size1, size2, k12, k1, k2)`. """ if (nbranch is not None) and nbranch < 1: raise ValueError(f"The number of branches must be at least one, `nbranch={nbranch}`.") self.nbranch = nbranch self.cutoff_flops_factor = cutoff_flops_factor self.minimize = minimize self.cost_fn: Any = _COST_FNS.get(cost_fn, cost_fn) self.better = get_better_fn(minimize) self.best: Dict[str, Any] = {"flops": float("inf"), "size": float("inf")} self.best_progress: Dict[int, float] = defaultdict(lambda: float("inf")) @property def path(self) -> PathType: return ssa_to_linear(self.best["ssa_path"]) def __call__( self, inputs_: List[ArrayIndexType], output_: ArrayIndexType, size_dict: Dict[str, int], memory_limit: Optional[int] = None, ) -> PathType: """Parameters: inputs_: List of sets that represent the lhs side of the einsum subscript output_: Set that represents the rhs side of the overall einsum subscript size_dict: Dictionary of index sizes memory_limit: The maximum number of elements in a temporary array. Returns: path: The contraction order within the memory limit constraint. Examples: ```python isets = [set('abd'), set('ac'), set('bdc')] oset = set('') idx_sizes = {'a': 1, 'b':2, 'c':3, 'd':4} optimal(isets, oset, idx_sizes, 5000) #> [(0, 2), (0, 1)] """ self._check_args_against_first_call(inputs_, output_, size_dict) inputs: Tuple[FrozenSet[str]] = tuple(map(frozenset, inputs_)) # type: ignore output: FrozenSet[str] = frozenset(output_) size_cache = {k: compute_size_by_dict(k, size_dict) for k in inputs} result_cache: Dict[Tuple[FrozenSet[str], FrozenSet[str]], Tuple[FrozenSet[str], int]] = {} def _branch_iterate(path, inputs, remaining, flops, size): # reached end of path (only ever get here if flops is best found so far) if len(remaining) == 1: self.best["size"] = size self.best["flops"] = flops self.best["ssa_path"] = path return def _assess_candidate(k1: FrozenSet[str], k2: FrozenSet[str], i: int, j: int) -> Any: # find resulting indices and flops try: k12, flops12 = result_cache[k1, k2] except KeyError: k12, flops12 = result_cache[k1, k2] = calc_k12_flops(inputs, output, remaining, i, j, size_dict) try: size12 = size_cache[k12] except KeyError: size12 = size_cache[k12] = compute_size_by_dict(k12, size_dict) new_flops = flops + flops12 new_size = max(size, size12) # sieve based on current best i.e. check flops and size still better if not self.better(new_flops, new_size, self.best["flops"], self.best["size"]): return None # compare to how the best method was doing as this point if new_flops < self.best_progress[len(inputs)]: self.best_progress[len(inputs)] = new_flops # sieve based on current progress relative to best elif new_flops > self.cutoff_flops_factor * self.best_progress[len(inputs)]: return None # sieve based on memory limit if (memory_limit not in _UNLIMITED_MEM) and (size12 > memory_limit): # type: ignore # terminate path here, but check all-terms contract first new_flops = flops + _compute_oversize_flops(inputs, remaining, output_, size_dict) if new_flops < self.best["flops"]: self.best["flops"] = new_flops self.best["ssa_path"] = path + (tuple(remaining),) return None # set cost heuristic in order to locally sort possible contractions size1, size2 = size_cache[inputs[i]], size_cache[inputs[j]] cost = self.cost_fn(size12, size1, size2, k12, k1, k2) return cost, flops12, new_flops, new_size, (i, j), k12 # check all possible remaining paths candidates = [] for i, j in itertools.combinations(remaining, 2): if i > j: i, j = j, i k1, k2 = inputs[i], inputs[j] # initially ignore outer products if k1.isdisjoint(k2): continue candidate = _assess_candidate(k1, k2, i, j) if candidate: heapq.heappush(candidates, candidate) # assess outer products if nothing left if not candidates: for i, j in itertools.combinations(remaining, 2): if i > j: i, j = j, i k1, k2 = inputs[i], inputs[j] candidate = _assess_candidate(k1, k2, i, j) if candidate: heapq.heappush(candidates, candidate) # recurse into all or some of the best candidate contractions bi = 0 while (self.nbranch is None or bi < self.nbranch) and candidates: _, _, new_flops, new_size, (i, j), k12 = heapq.heappop(candidates) _branch_iterate( path=path + ((i, j),), inputs=inputs + (k12,), remaining=(remaining - {i, j}) | {len(inputs)}, flops=new_flops, size=new_size, ) bi += 1 _branch_iterate(path=(), inputs=inputs, remaining=set(range(len(inputs))), flops=0, size=0) return self.path def branch( inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], memory_limit: Optional[int] = None, nbranch: Optional[int] = None, cutoff_flops_factor: int = 4, minimize: str = "flops", cost_fn: str = "memory-removed", ) -> PathType: optimizer = BranchBound( nbranch=nbranch, cutoff_flops_factor=cutoff_flops_factor, minimize=minimize, cost_fn=cost_fn ) return optimizer(inputs, output, size_dict, memory_limit) branch_all = functools.partial(branch, nbranch=None) branch_2 = functools.partial(branch, nbranch=2) branch_1 = functools.partial(branch, nbranch=1) GreedyCostType = Tuple[int, int, int] GreedyContractionType = Tuple[GreedyCostType, ArrayIndexType, ArrayIndexType, ArrayIndexType] # Cost, t1,t2->t3 def _get_candidate( output: ArrayIndexType, sizes: Dict[str, int], remaining: Dict[ArrayIndexType, int], footprints: Dict[ArrayIndexType, int], dim_ref_counts: Dict[int, Set[str]], k1: ArrayIndexType, k2: ArrayIndexType, cost_fn: Any, ) -> GreedyContractionType: either = k1 | k2 two = k1 & k2 one = either - two k12 = (either & output) | (two & dim_ref_counts[3]) | (one & dim_ref_counts[2]) cost = cost_fn( compute_size_by_dict(k12, sizes), footprints[k1], footprints[k2], k12, k1, k2, ) id1 = remaining[k1] id2 = remaining[k2] if id1 > id2: k1, id1, k2, id2 = k2, id2, k1, id1 cost = cost, id2, id1 # break ties to ensure determinism return cost, k1, k2, k12 def _push_candidate( output: ArrayIndexType, sizes: Dict[str, Any], remaining: Dict[ArrayIndexType, int], footprints: Dict[ArrayIndexType, int], dim_ref_counts: Dict[int, Set[str]], k1: ArrayIndexType, k2s: List[ArrayIndexType], queue: List[GreedyContractionType], push_all: bool, cost_fn: Any, ) -> None: candidates = (_get_candidate(output, sizes, remaining, footprints, dim_ref_counts, k1, k2, cost_fn) for k2 in k2s) if push_all: # want to do this if we e.g. are using a custom 'choose_fn' for candidate in candidates: heapq.heappush(queue, candidate) else: heapq.heappush(queue, min(candidates)) def _update_ref_counts( dim_to_keys: Dict[str, Set[ArrayIndexType]], dim_ref_counts: Dict[int, Set[str]], dims: ArrayIndexType, ) -> None: for dim in dims: count = len(dim_to_keys[dim]) if count <= 1: dim_ref_counts[2].discard(dim) dim_ref_counts[3].discard(dim) elif count == 2: dim_ref_counts[2].add(dim) dim_ref_counts[3].discard(dim) else: dim_ref_counts[2].add(dim) dim_ref_counts[3].add(dim) def _simple_chooser(queue, remaining): """Default contraction chooser that simply takes the minimum cost option.""" cost, k1, k2, k12 = heapq.heappop(queue) if k1 not in remaining or k2 not in remaining: return None # candidate is obsolete return cost, k1, k2, k12 def ssa_greedy_optimize( inputs: List[ArrayIndexType], output: ArrayIndexType, sizes: Dict[str, int], choose_fn: Any = None, cost_fn: Any = "memory-removed", ) -> PathType: """This is the core function for :func:`greedy` but produces a path with static single assignment ids rather than recycled linear ids. SSA ids are cheaper to work with and easier to reason about. """ if len(inputs) == 1: # Perform a single contraction to match output shape. return [(0,)] # set the function that assigns a heuristic cost to a possible contraction cost_fn = _COST_FNS.get(cost_fn, cost_fn) # set the function that chooses which contraction to take if choose_fn is None: choose_fn = _simple_chooser push_all = False else: # assume chooser wants access to all possible contractions push_all = True # A dim that is common to all tensors might as well be an output dim, since it # cannot be contracted until the final step. This avoids an expensive all-pairs # comparison to search for possible contractions at each step, leading to speedup # in many practical problems where all tensors share a common batch dimension. fs_inputs = [frozenset(x) for x in inputs] output = frozenset(output) | frozenset.intersection(*fs_inputs) # Deduplicate shapes by eagerly computing Hadamard products. remaining: Dict[ArrayIndexType, int] = {} # key -> ssa_id ssa_ids = itertools.count(len(fs_inputs)) ssa_path: List[TensorShapeType] = [] for ssa_id, key in enumerate(fs_inputs): if key in remaining: ssa_path.append((remaining[key], ssa_id)) remaining[key] = next(ssa_ids) else: remaining[key] = ssa_id # Keep track of possible contraction dims. dim_to_keys = defaultdict(set) for key in remaining: for dim in key - output: dim_to_keys[dim].add(key) # Keep track of the number of tensors using each dim; when the dim is no longer # used it can be contracted. Since we specialize to binary ops, we only care about # ref counts of >=2 or >=3. dim_ref_counts = { count: {dim for dim, keys in dim_to_keys.items() if len(keys) >= count} - output for count in [2, 3] } # Compute separable part of the objective function for contractions. footprints = {key: compute_size_by_dict(key, sizes) for key in remaining} # Find initial candidate contractions. queue: List[GreedyContractionType] = [] for dim, dim_keys in dim_to_keys.items(): dim_keys_list = sorted(dim_keys, key=remaining.__getitem__) for i, k1 in enumerate(dim_keys_list[:-1]): k2s_guess = dim_keys_list[1 + i :] _push_candidate( output, sizes, remaining, footprints, dim_ref_counts, k1, k2s_guess, queue, push_all, cost_fn, ) # Greedily contract pairs of tensors. while queue: con = choose_fn(queue, remaining) if con is None: continue # allow choose_fn to flag all candidates obsolete cost, k1, k2, k12 = con ssa_id1 = remaining.pop(k1) ssa_id2 = remaining.pop(k2) for dim in k1 - output: dim_to_keys[dim].remove(k1) for dim in k2 - output: dim_to_keys[dim].remove(k2) ssa_path.append((ssa_id1, ssa_id2)) if k12 in remaining: ssa_path.append((remaining[k12], next(ssa_ids))) else: for dim in k12 - output: dim_to_keys[dim].add(k12) remaining[k12] = next(ssa_ids) _update_ref_counts(dim_to_keys, dim_ref_counts, k1 | k2 - output) footprints[k12] = compute_size_by_dict(k12, sizes) # Find new candidate contractions. k1 = k12 k2s = {k2 for dim in k1 for k2 in dim_to_keys[dim]} k2s.discard(k1) if k2s: _push_candidate( output, sizes, remaining, footprints, dim_ref_counts, k1, list(k2s), queue, push_all, cost_fn, ) # Greedily compute pairwise outer products. final_queue = [(compute_size_by_dict(key & output, sizes), ssa_id, key) for key, ssa_id in remaining.items()] heapq.heapify(final_queue) _, ssa_id1, k1 = heapq.heappop(final_queue) while final_queue: _, ssa_id2, k2 = heapq.heappop(final_queue) ssa_path.append((min(ssa_id1, ssa_id2), max(ssa_id1, ssa_id2))) k12 = (k1 | k2) & output cost = compute_size_by_dict(k12, sizes) ssa_id12 = next(ssa_ids) _, ssa_id1, k1 = heapq.heappushpop(final_queue, (cost, ssa_id12, k12)) return ssa_path def greedy( inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], memory_limit: Optional[int] = None, choose_fn: Any = None, cost_fn: str = "memory-removed", ) -> PathType: """Finds the path by a three stage algorithm: 1. Eagerly compute Hadamard products. 2. Greedily compute contractions to maximize `removed_size` 3. Greedily compute outer products. This algorithm scales quadratically with respect to the maximum number of elements sharing a common dim. Parameters: inputs: List of sets that represent the lhs side of the einsum subscript output: Set that represents the rhs side of the overall einsum subscript size_dict: Dictionary of index sizes memory_limit: The maximum number of elements in a temporary array choose_fn: A function that chooses which contraction to perform from the queue cost_fn: A function that assigns a potential contraction a cost. Returns: path: The contraction order (a list of tuples of ints). Examples: ```python isets = [set('abd'), set('ac'), set('bdc')] oset = set('') idx_sizes = {'a': 1, 'b':2, 'c':3, 'd':4} greedy(isets, oset, idx_sizes) #> [(0, 2), (0, 1)] ``` """ if memory_limit not in _UNLIMITED_MEM: return branch(inputs, output, size_dict, memory_limit, nbranch=1, cost_fn=cost_fn) # type: ignore ssa_path = ssa_greedy_optimize(inputs, output, size_dict, cost_fn=cost_fn, choose_fn=choose_fn) return ssa_to_linear(ssa_path) def _tree_to_sequence(tree: Tuple[Any, ...]) -> PathType: """Converts a contraction tree to a contraction path as it has to be returned by path optimizers. A contraction tree can either be an int (=no contraction) or a tuple containing the terms to be contracted. An arbitrary number (>= 1) of terms can be contracted at once. Note that contractions are commutative, e.g. (j, k, l) = (k, l, j). Note that in general, solutions are not unique. Parameters: c: Contraction tree Returns: path: Contraction path Examples: ```python _tree_to_sequence(((1,2),(0,(4,5,3)))) #> [(1, 2), (1, 2, 3), (0, 2), (0, 1)] ``` """ # ((1,2),(0,(4,5,3))) --> [(1, 2), (1, 2, 3), (0, 2), (0, 1)] # # 0 0 0 (1,2) --> ((1,2),(0,(3,4,5))) # 1 3 (1,2) --> (0,(3,4,5)) # 2 --> 4 --> (3,4,5) # 3 5 # 4 (1,2) # 5 # # this function iterates through the table shown above from right to left; if type(tree) == int: # noqa: E721 return [] c: List[Tuple[Any, ...]] = [tree] # list of remaining contractions (lower part of columns shown above) t: List[int] = [] # list of elementary tensors (upper part of columns) s: List[Tuple[int, ...]] = [] # resulting contraction sequence while len(c) > 0: j = c.pop(-1) s.insert(0, ()) for i in sorted([i for i in j if type(i) == int]): # noqa: E721 s[0] += (sum(1 for q in t if q < i),) t.insert(s[0][-1], i) for i_tup in [i_tup for i_tup in j if type(i_tup) != int]: # noqa: E721 s[0] += (len(t) + len(c),) c.append(i_tup) return s def _find_disconnected_subgraphs(inputs: List[FrozenSet[int]], output: FrozenSet[int]) -> List[FrozenSet[int]]: """Finds disconnected subgraphs in the given list of inputs. Inputs are connected if they share summation indices. Note: Disconnected subgraphs can be contracted independently before forming outer products. Parameters: inputs: List of sets that represent the lhs side of the einsum subscript output: Set that represents the rhs side of the overall einsum subscript Returns: subgraphs: List containing sets of indices for each subgraph Examples: ```python _find_disconnected_subgraphs([set("ab"), set("c"), set("ad")], set("bd")) #> [{0, 2}, {1}] _find_disconnected_subgraphs([set("ab"), set("c"), set("ad")], set("abd")) #> [{0}, {1}, {2}] ``` """ subgraphs = [] unused_inputs = set(range(len(inputs))) i_sum = frozenset.union(*inputs) - output # all summation indices while len(unused_inputs) > 0: g = set() q = [unused_inputs.pop()] while len(q) > 0: j = q.pop() g.add(j) i_tmp = i_sum & inputs[j] n = {k for k in unused_inputs if len(i_tmp & inputs[k]) > 0} q.extend(n) unused_inputs.difference_update(n) subgraphs.append(g) return [frozenset(x) for x in subgraphs] def _bitmap_select(s: int, seq: List[FrozenSet[int]]) -> Generator[FrozenSet[int], None, None]: """Select elements of ``seq`` which are marked by the bitmap set ``s``. E.g.: >>> list(_bitmap_select(0b11010, ['A', 'B', 'C', 'D', 'E'])) ['B', 'D', 'E'] """ return (x for x, b in zip(seq, bin(s)[:1:-1]) if b == "1") def _dp_calc_legs(g, all_tensors, s, inputs, i1_cut_i2_wo_output, i1_union_i2): """Calculates the effective outer indices of the intermediate tensor corresponding to the subgraph ``s``. """ # set of remaining tensors (=g-s) r = g & (all_tensors ^ s) # indices of remaining indices: if r: i_r = frozenset.union(*_bitmap_select(r, inputs)) else: i_r = frozenset() # contraction indices: i_contract = i1_cut_i2_wo_output - i_r return i1_union_i2 - i_contract def _dp_compare_flops( cost1: int, cost2: int, i1_union_i2: Set[int], size_dict: List[int], cost_cap: int, s1: int, s2: int, xn: Dict[int, Any], g: int, all_tensors: int, inputs: List[FrozenSet[int]], i1_cut_i2_wo_output: Set[int], memory_limit: Optional[int], contract1: Union[int, Tuple[int]], contract2: Union[int, Tuple[int]], ) -> None: """Performs the inner comparison of whether the two subgraphs (the bitmaps `s1` and `s2`) should be merged and added to the dynamic programming search. Will skip for a number of reasons: 1. If the number of operations to form `s = s1 | s2` including previous contractions is above the cost-cap. 2. If we've already found a better way of making `s`. 3. If the intermediate tensor corresponding to `s` is going to break the memory limit. """ # TODO: Odd usage with an Iterable[int] to map a dict of type List[int] cost = cost1 + cost2 + compute_size_by_dict(i1_union_i2, size_dict) if cost <= cost_cap: s = s1 | s2 if s not in xn or cost < xn[s][1]: i = _dp_calc_legs(g, all_tensors, s, inputs, i1_cut_i2_wo_output, i1_union_i2) mem = compute_size_by_dict(i, size_dict) if memory_limit is None or mem <= memory_limit: xn[s] = (i, cost, (contract1, contract2)) def _dp_compare_size( cost1: int, cost2: int, i1_union_i2: Set[int], size_dict: List[int], cost_cap: int, s1: int, s2: int, xn: Dict[int, Any], g: int, all_tensors: int, inputs: List[FrozenSet[int]], i1_cut_i2_wo_output: Set[int], memory_limit: Optional[int], contract1: Union[int, Tuple[int]], contract2: Union[int, Tuple[int]], ) -> None: """Like `_dp_compare_flops` but sieves the potential contraction based on the size of the intermediate tensor created, rather than the number of operations, and so calculates that first. """ s = s1 | s2 i = _dp_calc_legs(g, all_tensors, s, inputs, i1_cut_i2_wo_output, i1_union_i2) mem = compute_size_by_dict(i, size_dict) cost = max(cost1, cost2, mem) if cost <= cost_cap: if s not in xn or cost < xn[s][1]: if memory_limit is None or mem <= memory_limit: xn[s] = (i, cost, (contract1, contract2)) def _dp_compare_write( cost1: int, cost2: int, i1_union_i2: Set[int], size_dict: List[int], cost_cap: int, s1: int, s2: int, xn: Dict[int, Any], g: int, all_tensors: int, inputs: List[FrozenSet[int]], i1_cut_i2_wo_output: Set[int], memory_limit: Optional[int], contract1: Union[int, Tuple[int]], contract2: Union[int, Tuple[int]], ) -> None: """Like ``_dp_compare_flops`` but sieves the potential contraction based on the total size of memory created, rather than the number of operations, and so calculates that first. """ s = s1 | s2 i = _dp_calc_legs(g, all_tensors, s, inputs, i1_cut_i2_wo_output, i1_union_i2) mem = compute_size_by_dict(i, size_dict) cost = cost1 + cost2 + mem if cost <= cost_cap: if s not in xn or cost < xn[s][1]: if memory_limit is None or mem <= memory_limit: xn[s] = (i, cost, (contract1, contract2)) DEFAULT_COMBO_FACTOR = 64 def _dp_compare_combo( cost1: int, cost2: int, i1_union_i2: Set[int], size_dict: List[int], cost_cap: int, s1: int, s2: int, xn: Dict[int, Any], g: int, all_tensors: int, inputs: List[FrozenSet[int]], i1_cut_i2_wo_output: Set[int], memory_limit: Optional[int], contract1: Union[int, Tuple[int]], contract2: Union[int, Tuple[int]], factor: Union[int, float] = DEFAULT_COMBO_FACTOR, combine: Callable = sum, ) -> None: """Like ``_dp_compare_flops`` but sieves the potential contraction based on some combination of both the flops and size,. """ s = s1 | s2 i = _dp_calc_legs(g, all_tensors, s, inputs, i1_cut_i2_wo_output, i1_union_i2) mem = compute_size_by_dict(i, size_dict) f = compute_size_by_dict(i1_union_i2, size_dict) cost = cost1 + cost2 + combine((f, factor * mem)) if cost <= cost_cap: if s not in xn or cost < xn[s][1]: if memory_limit is None or mem <= memory_limit: xn[s] = (i, cost, (contract1, contract2)) minimize_finder = re.compile(r"(flops|size|write|combo|limit)-*(\d*)") @functools.lru_cache(128) def _parse_minimize(minimize: Union[str, Callable]) -> Tuple[Callable, Union[int, float]]: """This works out what local scoring function to use for the dp algorithm as well as a `naive_scale` to account for the memory_limit checks. """ if minimize == "flops": return _dp_compare_flops, 1 elif minimize == "size": return _dp_compare_size, 1 elif minimize == "write": return _dp_compare_write, 1 elif callable(minimize): # default to naive_scale=inf for this and remaining options # as otherwise memory_limit check can cause problems return minimize, float("inf") # parse out a customized value for the combination factor match = minimize_finder.fullmatch(minimize) if match is None: raise ValueError(f"Couldn't parse `minimize` value: {minimize}.") minimize, custom_factor = match.groups() factor = float(custom_factor) if custom_factor else DEFAULT_COMBO_FACTOR if minimize == "combo": return functools.partial(_dp_compare_combo, factor=factor, combine=sum), float("inf") elif minimize == "limit": return functools.partial(_dp_compare_combo, factor=factor, combine=max), float("inf") else: raise ValueError(f"Couldn't parse `minimize` value: {minimize}.") def simple_tree_tuple(seq: Sequence[Tuple[int, ...]]) -> Tuple[Any, ...]: """Make a simple left to right binary tree out of iterable `seq`. ```python tuple_nest([1, 2, 3, 4]) #> (((1, 2), 3), 4) ``` """ return functools.reduce(lambda x, y: (x, y), seq) def _dp_parse_out_single_term_ops( inputs: List[FrozenSet[int]], all_inds: Tuple[str, ...], ind_counts: CounterType[str] ) -> Tuple[List[FrozenSet[int]], List[Tuple[int]], List[Union[int, Tuple[int]]]]: """Take `inputs` and parse for single term index operations, i.e. where an index appears on one tensor and nowhere else. If a term is completely reduced to a scalar in this way it can be removed to `inputs_done`. If only some indices can be summed then add a 'single term contraction' that will perform this summation. """ i_single = frozenset(i for i, c in enumerate(all_inds) if ind_counts[c] == 1) inputs_parsed: List[FrozenSet[int]] = [] inputs_done: List[Tuple[int]] = [] inputs_contractions: List[Union[int, Tuple[int]]] = [] for j, i in enumerate(inputs): i_reduced = i - i_single if (not i_reduced) and (len(i) > 0): # input reduced to scalar already - remove inputs_done.append((j,)) else: # if the input has any index reductions, add single contraction inputs_parsed.append(i_reduced) inputs_contractions.append((j,) if i_reduced != i else j) return inputs_parsed, inputs_done, inputs_contractions class DynamicProgramming(PathOptimizer): """Finds the optimal path of pairwise contractions without intermediate outer products based a dynamic programming approach presented in Phys. Rev. E 90, 033315 (2014) (the corresponding preprint is publicly available at https://arxiv.org/abs/1304.6112). This method is especially well-suited in the area of tensor network states, where it usually outperforms all the other optimization strategies. This algorithm shows exponential scaling with the number of inputs in the worst case scenario (see example below). If the graph to be contracted consists of disconnected subgraphs, the algorithm scales linearly in the number of disconnected subgraphs and only exponentially with the number of inputs per subgraph. Parameters: minimize: What to minimize: - 'flops' - minimize the number of flops - 'size' - minimize the size of the largest intermediate - 'write' - minimize the size of all intermediate tensors - 'combo' - minimize `flops + alpha * write` summed over intermediates, a default ratio of alpha=64 is used, or it can be customized with `f'combo-{alpha}'` - 'limit' - minimize `max(flops, alpha * write)` summed over intermediates, a default ratio of alpha=64 is used, or it can be customized with `f'limit-{alpha}'` - callable - a custom local cost function cost_cap: How to implement cost-capping: - True - iteratively increase the cost-cap - False - implement no cost-cap at all - int - use explicit cost cap search_outer: In rare circumstances the optimal contraction may involve an outer product, this option allows searching such contractions but may well slow down the path finding considerably on all but very small graphs. """ def __init__(self, minimize: str = "flops", cost_cap: Union[bool, int] = True, search_outer: bool = False) -> None: self.minimize = minimize self.search_outer = search_outer self.cost_cap = cost_cap def __call__( self, inputs_: List[ArrayIndexType], output_: ArrayIndexType, size_dict_: Dict[str, int], memory_limit_: Optional[int] = None, ) -> PathType: """Parameters: inputs_: List of sets that represent the lhs side of the einsum subscript output_: Set that represents the rhs side of the overall einsum subscript size_dict_: Dictionary of index sizes memory_limit_: The maximum number of elements in a temporary array. Returns: path: The contraction order (a list of tuples of ints). Examples: ```python n_in = 3 # exponential scaling n_out = 2 # linear scaling s = dict() i_all = [] for _ in range(n_out): i = [set() for _ in range(n_in)] for j in range(n_in): for k in range(j+1, n_in): c = oe.get_symbol(len(s)) i[j].add(c) i[k].add(c) s[c] = 2 i_all.extend(i) o = DynamicProgramming() o(i_all, set(), s) #> [(1, 2), (0, 4), (1, 2), (0, 2), (0, 1)] ``` """ _check_contraction, naive_scale = _parse_minimize(self.minimize) _check_outer = (lambda x: True) if self.search_outer else (lambda x: x) ind_counts = Counter(itertools.chain(*inputs_, output_)) all_inds = tuple(ind_counts) # convert all indices to integers (makes set operations ~10 % faster) symbol2int = {c: j for j, c in enumerate(all_inds)} inputs = [frozenset(symbol2int[c] for c in i) for i in inputs_] output = frozenset(symbol2int[c] for c in output_) size_dict_canonical = {symbol2int[c]: v for c, v in size_dict_.items() if c in symbol2int} size_dict = [size_dict_canonical[j] for j in range(len(size_dict_canonical))] naive_cost = naive_scale * len(inputs) * functools.reduce(operator.mul, size_dict, 1) inputs, inputs_done, inputs_contractions = _dp_parse_out_single_term_ops(inputs, all_inds, ind_counts) if not inputs: # nothing left to do after single axis reductions! return _tree_to_sequence(simple_tree_tuple(inputs_done)) # a list of all necessary contraction expressions for each of the # disconnected subgraphs and their size subgraph_contractions = inputs_done subgraph_contractions_size = [1] * len(inputs_done) if self.search_outer: # optimize everything together if we are considering outer products subgraphs = [frozenset(range(len(inputs)))] else: subgraphs = _find_disconnected_subgraphs(inputs, output) # the bitmap set of all tensors is computed as it is needed to # compute set differences: s1 - s2 transforms into # s1 & (all_tensors ^ s2) all_tensors = (1 << len(inputs)) - 1 for g in subgraphs: # dynamic programming approach to compute x[n] for subgraph g; # x[n][set of n tensors] = (indices, cost, contraction) # the set of n tensors is represented by a bitmap: if bit j is 1, # tensor j is in the set, e.g. 0b100101 = {0,2,5}; set unions # (intersections) can then be computed by bitwise or (and); x: List[Any] = [None] * 2 + [{} for j in range(len(g) - 1)] x[1] = {1 << j: (inputs[j], 0, inputs_contractions[j]) for j in g} # convert set of tensors g to a bitmap set: bitmap_g = functools.reduce(lambda x, y: x | y, (1 << j for j in g)) # try to find contraction with cost <= cost_cap and increase # cost_cap successively if no such contraction is found; # this is a major performance improvement; start with product of # output index dimensions as initial cost_cap subgraph_inds = frozenset.union(*_bitmap_select(bitmap_g, inputs)) if self.cost_cap is True: cost_cap = compute_size_by_dict(subgraph_inds & output, size_dict) elif self.cost_cap is False: cost_cap = float("inf") # type: ignore else: cost_cap = self.cost_cap # set the factor to increase the cost by each iteration (ensure > 1) if len(subgraph_inds) == 0: cost_increment = 2 else: cost_increment = max(min(map(size_dict.__getitem__, subgraph_inds)), 2) while len(x[-1]) == 0: for n in range(2, len(x[1]) + 1): xn = x[n] # try to combine solutions from x[m] and x[n-m] for m in range(1, n // 2 + 1): for s1, (i1, cost1, contract1) in x[m].items(): for s2, (i2, cost2, contract2) in x[n - m].items(): # can only merge if s1 and s2 are disjoint # and avoid e.g. s1={0}, s2={1} and s1={1}, s2={0} if (not s1 & s2) and (m != n - m or s1 < s2): i1_cut_i2_wo_output = (i1 & i2) - output # maybe ignore outer products: if _check_outer(i1_cut_i2_wo_output): i1_union_i2 = i1 | i2 _check_contraction( cost1, cost2, i1_union_i2, size_dict, cost_cap, s1, s2, xn, bitmap_g, all_tensors, inputs, i1_cut_i2_wo_output, memory_limit_, contract1, contract2, ) if (cost_cap > naive_cost) and (len(x[-1]) == 0): raise RuntimeError("No contraction found for given `memory_limit`.") # increase cost cap for next iteration: cost_cap = cost_increment * cost_cap i, cost, contraction = list(x[-1].values())[0] subgraph_contractions.append(contraction) subgraph_contractions_size.append(compute_size_by_dict(i, size_dict)) # sort the subgraph contractions by the size of the subgraphs in # ascending order (will give the cheapest contractions); note that # outer products should be performed pairwise (to use BLAS functions) subgraph_contractions = [ subgraph_contractions[j] for j in sorted( range(len(subgraph_contractions_size)), key=subgraph_contractions_size.__getitem__, ) ] # build the final contraction tree tree = simple_tree_tuple(subgraph_contractions) return _tree_to_sequence(tree) def dynamic_programming( inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], memory_limit: Optional[int] = None, **kwargs: Any, ) -> PathType: optimizer = DynamicProgramming(**kwargs) return optimizer(inputs, output, size_dict, memory_limit) _AUTO_CHOICES = {} for i in range(1, 5): _AUTO_CHOICES[i] = optimal for i in range(5, 7): _AUTO_CHOICES[i] = branch_all for i in range(7, 9): _AUTO_CHOICES[i] = branch_2 for i in range(9, 15): _AUTO_CHOICES[i] = branch_1 def auto( inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], memory_limit: Optional[int] = None, ) -> PathType: """Finds the contraction path by automatically choosing the method based on how many input arguments there are. """ return _AUTO_CHOICES.get(len(inputs), greedy)(inputs, output, size_dict, memory_limit) _AUTO_HQ_CHOICES = {} for i in range(1, 6): _AUTO_HQ_CHOICES[i] = optimal for i in range(6, 17): _AUTO_HQ_CHOICES[i] = dynamic_programming def auto_hq( inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], memory_limit: Optional[int] = None, ) -> PathType: """Finds the contraction path by automatically choosing the method based on how many input arguments there are, but targeting a more generous amount of search time than ``'auto'``. """ from opt_einsum.path_random import random_greedy_128 return _AUTO_HQ_CHOICES.get(len(inputs), random_greedy_128)(inputs, output, size_dict, memory_limit) _PATH_OPTIONS: Dict[str, PathSearchFunctionType] = { "auto": auto, "auto-hq": auto_hq, "optimal": optimal, "branch-all": branch_all, "branch-2": branch_2, "branch-1": branch_1, "greedy": greedy, "eager": greedy, "opportunistic": greedy, "dp": dynamic_programming, "dynamic-programming": dynamic_programming, } def register_path_fn(name: str, fn: PathSearchFunctionType) -> None: """Add path finding function ``fn`` as an option with ``name``.""" if name in _PATH_OPTIONS: raise KeyError(f"Path optimizer '{name}' already exists.") _PATH_OPTIONS[name.lower()] = fn def get_path_fn(path_type: str) -> PathSearchFunctionType: """Get the correct path finding function from str ``path_type``.""" path_type = path_type.lower() if path_type not in _PATH_OPTIONS: raise KeyError(f"Path optimizer '{path_type}' not found, valid options are {set(_PATH_OPTIONS.keys())}.") return _PATH_OPTIONS[path_type] opt_einsum-3.4.0/opt_einsum/sharing.py000066400000000000000000000154021467526163400201070ustar00rootroot00000000000000"""A module for sharing intermediates between contractions. Copyright (c) 2018 Uber Technologies """ import contextlib import functools import numbers import threading from collections import Counter, defaultdict from typing import Any, Dict, Generator, List, Optional, Tuple, Union from typing import Counter as CounterType from opt_einsum.parser import alpha_canonicalize, parse_einsum_input from opt_einsum.typing import ArrayType CacheKeyType = Union[Tuple[str, str, int, Tuple[int, ...]], Tuple[str, int]] CacheType = Dict[CacheKeyType, ArrayType] __all__ = [ "currently_sharing", "get_sharing_cache", "shared_intermediates", "count_cached_ops", "transpose_cache_wrap", "einsum_cache_wrap", "to_backend_cache_wrap", ] _SHARING_STACK: Dict[int, List[CacheType]] = defaultdict(list) def currently_sharing() -> bool: """Check if we are currently sharing a cache -- thread specific.""" return threading.get_ident() in _SHARING_STACK def get_sharing_cache() -> CacheType: """Return the most recent sharing cache -- thread specific.""" return _SHARING_STACK[threading.get_ident()][-1] def _add_sharing_cache(cache: CacheType) -> Any: _SHARING_STACK[threading.get_ident()].append(cache) def _remove_sharing_cache() -> None: tid = threading.get_ident() _SHARING_STACK[tid].pop() if not _SHARING_STACK[tid]: del _SHARING_STACK[tid] @contextlib.contextmanager def shared_intermediates( cache: Optional[CacheType] = None, ) -> Generator[CacheType, None, None]: """Context in which contract intermediate results are shared. Note that intermediate computations will not be garbage collected until 1. this context exits, and 2. the yielded cache is garbage collected (if it was captured). **Parameters:** - **cache** - *(dict)* If specified, a user-stored dict in which intermediate results will be stored. This can be used to interleave sharing contexts. **Returns:** - **cache** - *(dict)* A dictionary in which sharing results are stored. If ignored, sharing results will be garbage collected when this context is exited. This dict can be passed to another context to resume sharing. """ if cache is None: cache = {} _add_sharing_cache(cache) try: yield cache finally: _remove_sharing_cache() def count_cached_ops(cache: CacheType) -> CounterType[str]: """Returns a counter of the types of each op in the cache. This is useful for profiling to increase sharing. """ return Counter(key[0] for key in cache.keys()) def _save_tensors(*tensors: ArrayType) -> None: """Save tensors in the cache to prevent their ids from being recycled. This is needed to prevent false cache lookups. """ cache = get_sharing_cache() for tensor in tensors: cache["tensor", id(tensor)] = tensor def _memoize(key: CacheKeyType, fn: Any, *args: Any, **kwargs: Any) -> ArrayType: """Memoize ``fn(*args, **kwargs)`` using the given ``key``. Results will be stored in the innermost ``cache`` yielded by :func:`shared_intermediates`. """ cache = get_sharing_cache() if key in cache: return cache[key] result = fn(*args, **kwargs) cache[key] = result return result def transpose_cache_wrap(transpose: Any) -> Any: """Decorates a ``transpose()`` implementation to be memoized inside a :func:`shared_intermediates` context. """ @functools.wraps(transpose) def cached_transpose(a, axes, backend="numpy"): if not currently_sharing(): return transpose(a, axes, backend=backend) # hash by axes _save_tensors(a) axes = tuple(axes) key = "transpose", backend, id(a), axes return _memoize(key, transpose, a, axes, backend=backend) return cached_transpose def tensordot_cache_wrap(tensordot: Any) -> Any: """Decorates a ``tensordot()`` implementation to be memoized inside a :func:`shared_intermediates` context. """ @functools.wraps(tensordot) def cached_tensordot(x, y, axes=2, backend="numpy"): if not currently_sharing(): return tensordot(x, y, axes, backend=backend) # hash based on the (axes_x,axes_y) form of axes _save_tensors(x, y) if isinstance(axes, numbers.Number): axes = ( list(range(len(x.shape)))[len(x.shape) - axes :], list(range(len(y.shape)))[:axes], ) axes = tuple(axes[0]), tuple(axes[1]) key = "tensordot", backend, id(x), id(y), axes return _memoize(key, tensordot, x, y, axes, backend=backend) return cached_tensordot def einsum_cache_wrap(einsum: Any) -> Any: """Decorates an ``einsum()`` implementation to be memoized inside a :func:`shared_intermediates` context. """ @functools.wraps(einsum) def cached_einsum(*args, **kwargs): if not currently_sharing(): return einsum(*args, **kwargs) # hash modulo commutativity by computing a canonical ordering and names backend = kwargs.pop("backend", "numpy") equation = args[0] inputs, output, operands = parse_einsum_input(args) inputs = inputs.split(",") _save_tensors(*operands) # Build canonical key canonical = sorted(zip(inputs, map(id, operands)), key=lambda x: x[1]) canonical_ids = tuple(id_ for _, id_ in canonical) canonical_inputs = ",".join(input_ for input_, _ in canonical) canonical_equation = alpha_canonicalize(canonical_inputs + "->" + output) key = "einsum", backend, canonical_equation, canonical_ids return _memoize(key, einsum, equation, *operands, backend=backend) return cached_einsum def to_backend_cache_wrap(to_backend: Any = None, constants: Any = False) -> Any: """Decorates an ``to_backend()`` implementation to be memoized inside a :func:`shared_intermediates` context (e.g. ``to_cupy``, ``to_torch``). """ # manage the case that decorator is called with args if to_backend is None: return functools.partial(to_backend_cache_wrap, constants=constants) if constants: @functools.wraps(to_backend) def cached_to_backend(array, constant=False): if not currently_sharing(): return to_backend(array, constant=constant) # hash by id key = to_backend.__name__, id(array), constant return _memoize(key, to_backend, array, constant=constant) else: @functools.wraps(to_backend) def cached_to_backend(array): if not currently_sharing(): return to_backend(array) # hash by id key = to_backend.__name__, id(array) return _memoize(key, to_backend, array) return cached_to_backend opt_einsum-3.4.0/opt_einsum/testing.py000066400000000000000000000143201467526163400201270ustar00rootroot00000000000000"""Testing routines for opt_einsum.""" import random from typing import Any, Dict, List, Literal, Optional, Tuple, Union, overload import pytest from opt_einsum.parser import get_symbol from opt_einsum.typing import ArrayType, PathType, TensorShapeType _valid_chars = "abcdefghijklmopqABC" _sizes = [2, 3, 4, 5, 4, 3, 2, 6, 5, 4, 3, 2, 5, 7, 4, 3, 2, 3, 4] _default_dim_dict = dict(zip(_valid_chars, _sizes)) def build_shapes(string: str, dimension_dict: Optional[Dict[str, int]] = None) -> Tuple[TensorShapeType, ...]: """Builds random tensor shapes for testing. Parameters: string: List of tensor strings to build dimension_dict: Dictionary of index sizes, defaults to indices size of 2-7 Returns: The resulting shapes. Examples: ```python >>> shapes = build_shapes('abbc', {'a': 2, 'b':3, 'c':5}) >>> shapes [(2, 3), (3, 3, 5), (5,)] ``` """ if dimension_dict is None: dimension_dict = _default_dim_dict shapes = [] terms = string.split("->")[0].split(",") for term in terms: dims = [dimension_dict[x] for x in term] shapes.append(tuple(dims)) return tuple(shapes) def build_views( string: str, dimension_dict: Optional[Dict[str, int]] = None, array_function: Optional[Any] = None ) -> Tuple[ArrayType]: """Builds random numpy arrays for testing. Parameters: string: List of tensor strings to build dimension_dict: Dictionary of index _sizes array_function: Function to build the arrays, defaults to np.random.rand Returns: The resulting views. Examples: ```python >>> view = build_views('abbc', {'a': 2, 'b':3, 'c':5}) >>> view[0].shape (2, 3, 3, 5) ``` """ if array_function is None: np = pytest.importorskip("numpy") array_function = np.random.rand views = [] for shape in build_shapes(string, dimension_dict=dimension_dict): if shape: views.append(array_function(*shape)) else: views.append(random.random()) return tuple(views) @overload def rand_equation( n: int, regularity: int, n_out: int = ..., d_min: int = ..., d_max: int = ..., seed: Optional[int] = ..., global_dim: bool = ..., *, return_size_dict: Literal[True], ) -> Tuple[str, PathType, Dict[str, int]]: ... @overload def rand_equation( n: int, regularity: int, n_out: int = ..., d_min: int = ..., d_max: int = ..., seed: Optional[int] = ..., global_dim: bool = ..., return_size_dict: Literal[False] = ..., ) -> Tuple[str, PathType]: ... def rand_equation( n: int, regularity: int, n_out: int = 0, d_min: int = 2, d_max: int = 9, seed: Optional[int] = None, global_dim: bool = False, return_size_dict: bool = False, ) -> Union[Tuple[str, PathType, Dict[str, int]], Tuple[str, PathType]]: """Generate a random contraction and shapes. Parameters: n: Number of array arguments. regularity: 'Regularity' of the contraction graph. This essentially determines how many indices each tensor shares with others on average. n_out: Number of output indices (i.e. the number of non-contracted indices). Defaults to 0, i.e., a contraction resulting in a scalar. d_min: Minimum dimension size. d_max: Maximum dimension size. seed: If not None, seed numpy's random generator with this. global_dim: Add a global, 'broadcast', dimension to every operand. return_size_dict: Return the mapping of indices to sizes. Returns: eq: The equation string. shapes: The array shapes. size_dict: The dict of index sizes, only returned if ``return_size_dict=True``. Examples: ```python >>> eq, shapes = rand_equation(n=10, regularity=4, n_out=5, seed=42) >>> eq 'oyeqn,tmaq,skpo,vg,hxui,n,fwxmr,hitplcj,kudlgfv,rywjsb->cebda' >>> shapes [(9, 5, 4, 5, 4), (4, 4, 8, 5), (9, 4, 6, 9), (6, 6), (6, 9, 7, 8), (4,), (9, 3, 9, 4, 9), (6, 8, 4, 6, 8, 6, 3), (4, 7, 8, 8, 6, 9, 6), (9, 5, 3, 3, 9, 5)] ``` """ np = pytest.importorskip("numpy") if seed is not None: np.random.seed(seed) # total number of indices num_inds = n * regularity // 2 + n_out inputs = ["" for _ in range(n)] output = [] size_dict = {get_symbol(i): np.random.randint(d_min, d_max + 1) for i in range(num_inds)} # generate a list of indices to place either once or twice def gen(): for i, ix in enumerate(size_dict): # generate an outer index if i < n_out: output.append(ix) yield ix # generate a bond else: yield ix yield ix # add the indices randomly to the inputs for i, ix in enumerate(np.random.permutation(list(gen()))): # make sure all inputs have at least one index if i < n: inputs[i] += ix else: # don't add any traces on same op where = np.random.randint(0, n) while ix in inputs[where]: where = np.random.randint(0, n) inputs[where] += ix # possibly add the same global dim to every arg if global_dim: gdim = get_symbol(num_inds) size_dict[gdim] = np.random.randint(d_min, d_max + 1) for i in range(n): inputs[i] += gdim output += gdim # randomly transpose the output indices and form equation output = "".join(np.random.permutation(output)) # type: ignore eq = "{}->{}".format(",".join(inputs), output) # make the shapes shapes = [tuple(size_dict[ix] for ix in op) for op in inputs] ret = (eq, shapes) if return_size_dict: return ret + (size_dict,) else: return ret def build_arrays_from_tuples(path: PathType) -> List[Any]: """Build random numpy arrays from a path. Parameters: path: The path to build arrays from. Returns: The resulting arrays. """ np = pytest.importorskip("numpy") return [np.random.rand(*x) for x in path] opt_einsum-3.4.0/opt_einsum/tests/000077500000000000000000000000001467526163400172425ustar00rootroot00000000000000opt_einsum-3.4.0/opt_einsum/tests/__init__.py000066400000000000000000000000001467526163400213410ustar00rootroot00000000000000opt_einsum-3.4.0/opt_einsum/tests/test_backends.py000066400000000000000000000363121467526163400224320ustar00rootroot00000000000000from typing import Set import pytest from opt_einsum import backends, contract, contract_expression, sharing from opt_einsum.contract import ArrayShaped, infer_backend, parse_backend from opt_einsum.testing import build_views try: # needed so tensorflow doesn't allocate all gpu mem try: from tensorflow import ConfigProto # type: ignore from tensorflow import Session as TFSession except ImportError: from tensorflow.compat.v1 import ConfigProto # type: ignore from tensorflow.compat.v1 import Session as TFSession _TF_CONFIG = ConfigProto() _TF_CONFIG.gpu_options.allow_growth = True except ImportError: pass tests = [ "ab,bc->ca", "abc,bcd,dea", "abc,def->fedcba", "abc,bcd,df->fa", # test 'prefer einsum' ops "ijk,ikj", "i,j->ij", "ijk,k->ij", "AB,BC->CA", ] @pytest.mark.parametrize("string", tests) def test_tensorflow(string: str) -> None: np = pytest.importorskip("numpy") pytest.importorskip("tensorflow") views = build_views(string) ein = contract(string, *views, optimize=False, use_blas=False) opt = np.empty_like(ein) shps = [v.shape for v in views] expr = contract_expression(string, *shps, optimize=True) sess = TFSession(config=_TF_CONFIG) with sess.as_default(): expr(*views, backend="tensorflow", out=opt) sess.close() assert np.allclose(ein, opt) # test non-conversion mode tensorflow_views = [backends.to_tensorflow(view) for view in views] expr(*tensorflow_views) @pytest.mark.parametrize("constants", [{0, 1}, {0, 2}, {1, 2}]) def test_tensorflow_with_constants(constants: Set[int]) -> None: np = pytest.importorskip("numpy") tf = pytest.importorskip("tensorflow") eq = "ij,jk,kl->li" shapes = (2, 3), (3, 4), (4, 5) (non_const,) = {0, 1, 2} - constants ops = [np.random.rand(*shp) if i in constants else shp for i, shp in enumerate(shapes)] var = np.random.rand(*shapes[non_const]) res_exp = contract(eq, *(ops[i] if i in constants else var for i in range(3))) expr = contract_expression(eq, *ops, constants=constants) # check tensorflow with TFSession(config=_TF_CONFIG).as_default(): res_got = expr(var, backend="tensorflow") assert all( array is None or infer_backend(array) == "tensorflow" for array in expr._evaluated_constants["tensorflow"] ) assert np.allclose(res_exp, res_got) # check can call with numpy still res_got2 = expr(var, backend="numpy") assert np.allclose(res_exp, res_got2) # check tensorflow call returns tensorflow still res_got3 = expr(backends.to_tensorflow(var)) assert isinstance(res_got3, tf.Tensor) @pytest.mark.parametrize("string", tests) def test_tensorflow_with_sharing(string: str) -> None: np = pytest.importorskip("numpy") tf = pytest.importorskip("tensorflow") views = build_views(string) ein = contract(string, *views, optimize=False, use_blas=False) shps = [v.shape for v in views] expr = contract_expression(string, *shps, optimize=True) sess = TFSession(config=_TF_CONFIG) with sess.as_default(), sharing.shared_intermediates() as cache: tfl1 = expr(*views, backend="tensorflow") assert sharing.get_sharing_cache() is cache cache_sz = len(cache) assert cache_sz > 0 tfl2 = expr(*views, backend="tensorflow") assert len(cache) == cache_sz assert all(isinstance(t, tf.Tensor) for t in cache.values()) assert np.allclose(ein, tfl1) assert np.allclose(ein, tfl2) @pytest.mark.parametrize("string", tests) def test_theano(string: str) -> None: np = pytest.importorskip("numpy") theano = pytest.importorskip("theano") views = build_views(string) ein = contract(string, *views, optimize=False, use_blas=False) shps = [v.shape for v in views] expr = contract_expression(string, *shps, optimize=True) opt = expr(*views, backend="theano") assert np.allclose(ein, opt) # test non-conversion mode theano_views = [backends.to_theano(view) for view in views] theano_opt = expr(*theano_views) assert isinstance(theano_opt, theano.tensor.TensorVariable) @pytest.mark.parametrize("constants", [{0, 1}, {0, 2}, {1, 2}]) def test_theano_with_constants(constants: Set[int]) -> None: np = pytest.importorskip("numpy") theano = pytest.importorskip("theano") eq = "ij,jk,kl->li" shapes = (2, 3), (3, 4), (4, 5) (non_const,) = {0, 1, 2} - constants ops = [np.random.rand(*shp) if i in constants else shp for i, shp in enumerate(shapes)] var = np.random.rand(*shapes[non_const]) res_exp = contract(eq, *(ops[i] if i in constants else var for i in range(3))) expr = contract_expression(eq, *ops, constants=constants) # check theano res_got = expr(var, backend="theano") assert all(array is None or infer_backend(array) == "theano" for array in expr._evaluated_constants["theano"]) assert np.allclose(res_exp, res_got) # check can call with numpy still res_got2 = expr(var, backend="numpy") assert np.allclose(res_exp, res_got2) # check theano call returns theano still res_got3 = expr(backends.to_theano(var)) assert isinstance(res_got3, theano.tensor.TensorVariable) @pytest.mark.parametrize("string", tests) def test_theano_with_sharing(string: str) -> None: np = pytest.importorskip("numpy") theano = pytest.importorskip("theano") views = build_views(string) ein = contract(string, *views, optimize=False, use_blas=False) shps = [v.shape for v in views] expr = contract_expression(string, *shps, optimize=True) with sharing.shared_intermediates() as cache: thn1 = expr(*views, backend="theano") assert sharing.get_sharing_cache() is cache cache_sz = len(cache) assert cache_sz > 0 thn2 = expr(*views, backend="theano") assert len(cache) == cache_sz assert all(isinstance(t, theano.tensor.TensorVariable) for t in cache.values()) assert np.allclose(ein, thn1) assert np.allclose(ein, thn2) @pytest.mark.parametrize("string", tests) def test_cupy(string: str) -> None: np = pytest.importorskip("numpy") # pragma: no cover cupy = pytest.importorskip("cupy") views = build_views(string) ein = contract(string, *views, optimize=False, use_blas=False) shps = [v.shape for v in views] expr = contract_expression(string, *shps, optimize=True) opt = expr(*views, backend="cupy") assert np.allclose(ein, opt) # test non-conversion mode cupy_views = [backends.to_cupy(view) for view in views] cupy_opt = expr(*cupy_views) assert isinstance(cupy_opt, cupy.ndarray) assert np.allclose(ein, cupy.asnumpy(cupy_opt)) @pytest.mark.parametrize("constants", [{0, 1}, {0, 2}, {1, 2}]) def test_cupy_with_constants(constants: Set[int]) -> None: np = pytest.importorskip("numpy") # pragma: no cover cupy = pytest.importorskip("cupy") eq = "ij,jk,kl->li" shapes = (2, 3), (3, 4), (4, 5) (non_const,) = {0, 1, 2} - constants ops = [np.random.rand(*shp) if i in constants else shp for i, shp in enumerate(shapes)] var = np.random.rand(*shapes[non_const]) res_exp = contract(eq, *(ops[i] if i in constants else var for i in range(3))) expr = contract_expression(eq, *ops, constants=constants) # check cupy res_got = expr(var, backend="cupy") # check cupy versions of constants exist assert all(array is None or infer_backend(array) == "cupy" for array in expr._evaluated_constants["cupy"]) assert np.allclose(res_exp, res_got) # check can call with numpy still res_got2 = expr(var, backend="numpy") assert np.allclose(res_exp, res_got2) # check cupy call returns cupy still res_got3 = expr(cupy.asarray(var)) assert isinstance(res_got3, cupy.ndarray) assert np.allclose(res_exp, res_got3.get()) @pytest.mark.parametrize("string", tests) def test_jax(string: str) -> None: np = pytest.importorskip("numpy") # pragma: no cover pytest.importorskip("jax") views = build_views(string) ein = contract(string, *views, optimize=False, use_blas=False) shps = [v.shape for v in views] expr = contract_expression(string, *shps, optimize=True) opt = expr(*views, backend="jax") assert np.allclose(ein, opt) assert isinstance(opt, np.ndarray) @pytest.mark.parametrize("constants", [{0, 1}, {0, 2}, {1, 2}]) def test_jax_with_constants(constants: Set[int]) -> None: jax = pytest.importorskip("jax") key = jax.random.PRNGKey(42) eq = "ij,jk,kl->li" shapes = (2, 3), (3, 4), (4, 5) (non_const,) = {0, 1, 2} - constants ops = [jax.random.uniform(key, shp) if i in constants else shp for i, shp in enumerate(shapes)] var = jax.random.uniform(key, shapes[non_const]) res_exp = contract(eq, *(ops[i] if i in constants else var for i in range(3))) expr = contract_expression(eq, *ops, constants=constants) # check jax res_got = expr(var, backend="jax") # check jax versions of constants exist assert all(array is None or infer_backend(array).startswith("jax") for array in expr._evaluated_constants["jax"]) assert jax.numpy.sum(jax.numpy.abs(res_exp - res_got)) < 1e-8 def test_jax_jit_gradient() -> None: jax = pytest.importorskip("jax") key = jax.random.PRNGKey(42) eq = "ij,jk,kl->" shapes = (2, 3), (3, 4), (4, 2) views = [jax.random.uniform(key, s) for s in shapes] expr = contract_expression(eq, *shapes) x0 = expr(*views) jit_expr = jax.jit(expr) x1 = jit_expr(*views).item() assert x1 == pytest.approx(x0, rel=1e-5) # jax only takes gradient w.r.t first argument grad_expr = jax.jit(jax.grad(lambda views: expr(*views))) view_grads = grad_expr(views) assert all(v1.shape == v2.shape for v1, v2 in zip(views, view_grads)) # taking a step along the gradient should reduce our 'loss' new_views = [v - 0.001 * dv for v, dv in zip(views, view_grads)] x2 = jit_expr(*new_views).item() assert x2 < x1 def test_autograd_gradient() -> None: np = pytest.importorskip("numpy") autograd = pytest.importorskip("autograd") eq = "ij,jk,kl->" shapes = (2, 3), (3, 4), (4, 2) views = [np.random.randn(*s) for s in shapes] expr = contract_expression(eq, *shapes) x0 = expr(*views) # autograd only takes gradient w.r.t first argument grad_expr = autograd.grad(lambda views: expr(*views)) view_grads = grad_expr(views) assert all(v1.shape == v2.shape for v1, v2 in zip(views, view_grads)) # taking a step along the gradient should reduce our 'loss' new_views = [v - 0.001 * dv for v, dv in zip(views, view_grads)] x1 = expr(*new_views) assert x1 < x0 @pytest.mark.parametrize("string", tests) def test_dask(string: str) -> None: np = pytest.importorskip("numpy") da = pytest.importorskip("dask.array") views = build_views(string) ein = contract(string, *views, optimize=False, use_blas=False) shps = [v.shape for v in views] expr = contract_expression(string, *shps, optimize=True) # test non-conversion mode da_views = [da.from_array(x, chunks=(2)) for x in views] da_opt = expr(*da_views) # check type is maintained when not using numpy arrays assert isinstance(da_opt, da.Array) assert np.allclose(ein, np.array(da_opt)) # try raw contract da_opt = contract(string, *da_views) assert isinstance(da_opt, da.Array) assert np.allclose(ein, np.array(da_opt)) @pytest.mark.parametrize("string", tests) def test_sparse(string: str) -> None: np = pytest.importorskip("numpy") sparse = pytest.importorskip("sparse") views = build_views(string) # sparsify views so they don't become dense during contraction for view in views: np.random.seed(42) mask = np.random.choice([False, True], view.shape, True, [0.05, 0.95]) view[mask] = 0 ein = contract(string, *views, optimize=False, use_blas=False) shps = [v.shape for v in views] expr = contract_expression(string, *shps, optimize=True) # test non-conversion mode sparse_views = [sparse.COO.from_numpy(x) for x in views] sparse_opt = expr(*sparse_views) # If the expression returns a float, stop here if not ein.shape: assert pytest.approx(ein) == 0.0 return # check type is maintained when not using numpy arrays assert isinstance(sparse_opt, sparse.COO) assert np.allclose(ein, sparse_opt.todense()) # try raw contract sparse_opt = contract(string, *sparse_views) assert isinstance(sparse_opt, sparse.COO) assert np.allclose(ein, sparse_opt.todense()) @pytest.mark.parametrize("string", tests) def test_torch(string: str) -> None: torch = pytest.importorskip("torch") views = build_views(string, array_function=torch.rand) ein = torch.einsum(string, *views) shps = [v.shape for v in views] expr = contract_expression(string, *shps, optimize=True) opt = expr(*views, backend="torch") torch.testing.assert_close(ein, opt) # test non-conversion mode torch_views = [backends.to_torch(view) for view in views] torch_opt = expr(*torch_views) assert isinstance(torch_opt, torch.Tensor) torch.testing.assert_close(ein, torch_opt) @pytest.mark.parametrize("constants", [{0, 1}, {0, 2}, {1, 2}]) def test_torch_with_constants(constants: Set[int]) -> None: torch = pytest.importorskip("torch") eq = "ij,jk,kl->li" shapes = (2, 3), (3, 4), (4, 5) (non_const,) = {0, 1, 2} - constants ops = [torch.rand(*shp) if i in constants else shp for i, shp in enumerate(shapes)] var = torch.rand(*shapes[non_const]) res_exp = contract(eq, *(ops[i] if i in constants else var for i in range(3)), backend="torch") expr = contract_expression(eq, *ops, constants=constants) # check torch res_got = expr(var, backend="torch") assert all(array is None or infer_backend(array) == "torch" for array in expr._evaluated_constants["torch"]) torch.testing.assert_close(res_exp, res_got) # check can call with numpy still res_got2 = expr(var, backend="torch") torch.testing.assert_close(res_exp, res_got2) # check torch call returns torch still res_got3 = expr(backends.to_torch(var)) assert isinstance(res_got3, torch.Tensor) torch.testing.assert_close(res_exp, res_got3) def test_auto_backend_custom_array_no_tensordot() -> None: x = ArrayShaped((1, 2, 3)) # Shaped is an array-like object defined by opt_einsum - which has no TDOT assert infer_backend(x) == "opt_einsum" assert parse_backend([x], "auto") == "numpy" assert parse_backend([x], None) == "numpy" @pytest.mark.parametrize("string", tests) def test_object_arrays_backend(string: str) -> None: np = pytest.importorskip("numpy") views = build_views(string) ein = contract(string, *views, optimize=False, use_blas=False) assert ein.dtype != object shps = [v.shape for v in views] expr = contract_expression(string, *shps, optimize=True) obj_views = [view.astype(object) for view in views] # try raw contract obj_opt = contract(string, *obj_views, backend="object") assert obj_opt.dtype == object assert np.allclose(ein, obj_opt.astype(float)) # test expression obj_opt = expr(*obj_views, backend="object") assert obj_opt.dtype == object assert np.allclose(ein, obj_opt.astype(float)) opt_einsum-3.4.0/opt_einsum/tests/test_blas.py000066400000000000000000000070061467526163400215770ustar00rootroot00000000000000""" Tests the BLAS capability for the opt_einsum module. """ from typing import Any import pytest from opt_einsum import blas, contract blas_tests = [ # DOT ((["k", "k"], "", set("k")), "DOT"), # DDOT ((["ijk", "ijk"], "", set("ijk")), "DOT"), # DDOT # GEMV? # GEMM ((["ij", "jk"], "ik", set("j")), "GEMM"), # GEMM N N ((["ijl", "jlk"], "ik", set("jl")), "GEMM"), # GEMM N N Tensor ((["ij", "kj"], "ik", set("j")), "GEMM"), # GEMM N T ((["ijl", "kjl"], "ik", set("jl")), "GEMM"), # GEMM N T Tensor ((["ji", "jk"], "ik", set("j")), "GEMM"), # GEMM T N ((["jli", "jlk"], "ik", set("jl")), "GEMM"), # GEMM T N Tensor ((["ji", "kj"], "ik", set("j")), "GEMM"), # GEMM T T ((["jli", "kjl"], "ik", set("jl")), "GEMM"), # GEMM T T Tensor # GEMM with final transpose ((["ij", "jk"], "ki", set("j")), "GEMM"), # GEMM N N ((["ijl", "jlk"], "ki", set("jl")), "GEMM"), # GEMM N N Tensor ((["ij", "kj"], "ki", set("j")), "GEMM"), # GEMM N T ((["ijl", "kjl"], "ki", set("jl")), "GEMM"), # GEMM N T Tensor ((["ji", "jk"], "ki", set("j")), "GEMM"), # GEMM T N ((["jli", "jlk"], "ki", set("jl")), "GEMM"), # GEMM T N Tensor ((["ji", "kj"], "ki", set("j")), "GEMM"), # GEMM T T ((["jli", "kjl"], "ki", set("jl")), "GEMM"), # GEMM T T Tensor # Tensor Dot (requires copy), lets not deal with this for now ((["ilj", "jlk"], "ik", set("jl")), "TDOT"), # FT GEMM N N Tensor ((["ijl", "ljk"], "ik", set("jl")), "TDOT"), # ST GEMM N N Tensor ((["ilj", "kjl"], "ik", set("jl")), "TDOT"), # FT GEMM N T Tensor ((["ijl", "klj"], "ik", set("jl")), "TDOT"), # ST GEMM N T Tensor ((["lji", "jlk"], "ik", set("jl")), "TDOT"), # FT GEMM T N Tensor ((["jli", "ljk"], "ik", set("jl")), "TDOT"), # ST GEMM T N Tensor ((["lji", "jlk"], "ik", set("jl")), "TDOT"), # FT GEMM T N Tensor ((["jli", "ljk"], "ik", set("jl")), "TDOT"), # ST GEMM T N Tensor # Tensor Dot (requires copy), lets not deal with this for now with transpose ((["ilj", "jlk"], "ik", set("lj")), "TDOT"), # FT GEMM N N Tensor ((["ijl", "ljk"], "ik", set("lj")), "TDOT"), # ST GEMM N N Tensor ((["ilj", "kjl"], "ik", set("lj")), "TDOT"), # FT GEMM N T Tensor ((["ijl", "klj"], "ik", set("lj")), "TDOT"), # ST GEMM N T Tensor ((["lji", "jlk"], "ik", set("lj")), "TDOT"), # FT GEMM T N Tensor ((["jli", "ljk"], "ik", set("lj")), "TDOT"), # ST GEMM T N Tensor ((["lji", "jlk"], "ik", set("lj")), "TDOT"), # FT GEMM T N Tensor ((["jli", "ljk"], "ik", set("lj")), "TDOT"), # ST GEMM T N Tensor # Other ((["ijk", "ikj"], "", set("ijk")), "DOT/EINSUM"), # Transpose DOT ((["i", "j"], "ij", set()), "OUTER/EINSUM"), # Outer ((["ijk", "ik"], "j", set("ik")), "GEMV/EINSUM"), # Matrix-vector ((["ijj", "jk"], "ik", set("j")), False), # Double index ((["ijk", "j"], "ij", set()), False), # Index sum 1 ((["ij", "ij"], "ij", set()), False), # Index sum 2 ] @pytest.mark.parametrize("inp,benchmark", blas_tests) def test_can_blas(inp: Any, benchmark: bool) -> None: result = blas.can_blas(*inp) assert result == benchmark def test_blas_out() -> None: np = pytest.importorskip("numpy") a = np.random.rand(4, 4) b = np.random.rand(4, 4) c = np.random.rand(4, 4) d = np.empty((4, 4)) contract("ij,jk->ik", a, b, out=d) np.testing.assert_allclose(d, np.dot(a, b)) assert np.allclose(d, np.dot(a, b)) contract("ij,jk,kl->il", a, b, c, out=d) np.testing.assert_allclose(d, np.dot(a, b).dot(c)) opt_einsum-3.4.0/opt_einsum/tests/test_contract.py000066400000000000000000000206151467526163400224740ustar00rootroot00000000000000""" Tets a series of opt_einsum contraction paths to ensure the results are the same for different paths """ from typing import Any, List import pytest from opt_einsum import contract, contract_expression, contract_path from opt_einsum.paths import _PATH_OPTIONS, linear_to_ssa, ssa_to_linear from opt_einsum.testing import build_views, rand_equation from opt_einsum.typing import OptimizeKind # NumPy is required for the majority of this file np = pytest.importorskip("numpy") tests = [ # Test scalar-like operations "a,->a", "ab,->ab", ",ab,->ab", ",,->", # Test hadamard-like products "a,ab,abc->abc", "a,b,ab->ab", # Test index-transformations "ea,fb,gc,hd,abcd->efgh", "ea,fb,abcd,gc,hd->efgh", "abcd,ea,fb,gc,hd->efgh", # Test complex contractions "acdf,jbje,gihb,hfac,gfac,gifabc,hfac", "acdf,jbje,gihb,hfac,gfac,gifabc,hfac", "cd,bdhe,aidb,hgca,gc,hgibcd,hgac", "abhe,hidj,jgba,hiab,gab", "bde,cdh,agdb,hica,ibd,hgicd,hiac", "chd,bde,agbc,hiad,hgc,hgi,hiad", "chd,bde,agbc,hiad,bdi,cgh,agdb", "bdhe,acad,hiab,agac,hibd", # Test collapse "ab,ab,c->", "ab,ab,c->c", "ab,ab,cd,cd->", "ab,ab,cd,cd->ac", "ab,ab,cd,cd->cd", "ab,ab,cd,cd,ef,ef->", # Test outer prodcuts "ab,cd,ef->abcdef", "ab,cd,ef->acdf", "ab,cd,de->abcde", "ab,cd,de->be", "ab,bcd,cd->abcd", "ab,bcd,cd->abd", # Random test cases that have previously failed "eb,cb,fb->cef", "dd,fb,be,cdb->cef", "bca,cdb,dbf,afc->", "dcc,fce,ea,dbf->ab", "fdf,cdd,ccd,afe->ae", "abcd,ad", "ed,fcd,ff,bcf->be", "baa,dcf,af,cde->be", "bd,db,eac->ace", "fff,fae,bef,def->abd", "efc,dbc,acf,fd->abe", # Inner products "ab,ab", "ab,ba", "abc,abc", "abc,bac", "abc,cba", # GEMM test cases "ab,bc", "ab,cb", "ba,bc", "ba,cb", "abcd,cd", "abcd,ab", "abcd,cdef", "abcd,cdef->feba", "abcd,efdc", # Inner than dot "aab,bc->ac", "ab,bcc->ac", "aab,bcc->ac", "baa,bcc->ac", "aab,ccb->ac", # Randomly build test caes "aab,fa,df,ecc->bde", "ecb,fef,bad,ed->ac", "bcf,bbb,fbf,fc->", "bb,ff,be->e", "bcb,bb,fc,fff->", "fbb,dfd,fc,fc->", "afd,ba,cc,dc->bf", "adb,bc,fa,cfc->d", "bbd,bda,fc,db->acf", "dba,ead,cad->bce", "aef,fbc,dca->bde", ] @pytest.mark.parametrize("optimize", (True, False, None)) def test_contract_plain_types(optimize: OptimizeKind) -> None: expr = "ij,jk,kl->il" ops = [np.random.rand(2, 2), np.random.rand(2, 2), np.random.rand(2, 2)] path = contract_path(expr, *ops, optimize=optimize) assert len(path) == 2 result = contract(expr, *ops, optimize=optimize) assert result.shape == (2, 2) @pytest.mark.parametrize("string", tests) @pytest.mark.parametrize("optimize", _PATH_OPTIONS) def test_compare(optimize: OptimizeKind, string: str) -> None: views = build_views(string) ein = contract(string, *views, optimize=False, use_blas=False) opt = contract(string, *views, optimize=optimize, use_blas=False) assert np.allclose(ein, opt) @pytest.mark.parametrize("string", tests) def test_drop_in_replacement(string: str) -> None: views = build_views(string) opt = contract(string, *views) assert np.allclose(opt, np.einsum(string, *views)) @pytest.mark.parametrize("string", tests) @pytest.mark.parametrize("optimize", _PATH_OPTIONS) def test_compare_greek(optimize: OptimizeKind, string: str) -> None: views = build_views(string) ein = contract(string, *views, optimize=False, use_blas=False) # convert to greek string = "".join(chr(ord(c) + 848) if c not in ",->." else c for c in string) opt = contract(string, *views, optimize=optimize, use_blas=False) assert np.allclose(ein, opt) @pytest.mark.parametrize("string", tests) @pytest.mark.parametrize("optimize", _PATH_OPTIONS) def test_compare_blas(optimize: OptimizeKind, string: str) -> None: views = build_views(string) ein = contract(string, *views, optimize=False) opt = contract(string, *views, optimize=optimize) assert np.allclose(ein, opt) @pytest.mark.parametrize("string", tests) @pytest.mark.parametrize("optimize", _PATH_OPTIONS) def test_compare_blas_greek(optimize: OptimizeKind, string: str) -> None: views = build_views(string) ein = contract(string, *views, optimize=False) # convert to greek string = "".join(chr(ord(c) + 848) if c not in ",->." else c for c in string) opt = contract(string, *views, optimize=optimize) assert np.allclose(ein, opt) def test_some_non_alphabet_maintains_order() -> None: # 'c beta a' should automatically go to -> 'a c beta' string = "c" + chr(ord("b") + 848) + "a" # but beta will be temporarily replaced with 'b' for which 'cba->abc' # so check manual output kicks in: x = np.random.rand(2, 3, 4) assert np.allclose(contract(string, x), contract("cxa", x)) def test_printing(): string = "bbd,bda,fc,db->acf" views = build_views(string) ein = contract_path(string, *views) assert len(str(ein[1])) == 728 @pytest.mark.parametrize("string", tests) @pytest.mark.parametrize("optimize", _PATH_OPTIONS) @pytest.mark.parametrize("use_blas", [False, True]) @pytest.mark.parametrize("out_spec", [False, True]) def test_contract_expressions(string: str, optimize: OptimizeKind, use_blas: bool, out_spec: bool) -> None: views = build_views(string) shapes = [view.shape if hasattr(view, "shape") else () for view in views] expected = contract(string, *views, optimize=False, use_blas=False) expr = contract_expression(string, *shapes, optimize=optimize, use_blas=use_blas) if out_spec and ("->" in string) and (string[-2:] != "->"): (out,) = build_views(string.split("->")[1]) expr(*views, out=out) else: out = expr(*views) assert np.allclose(out, expected) # check representations assert string in expr.__repr__() assert string in expr.__str__() def test_contract_expression_interleaved_input() -> None: x, y, z = (np.random.randn(2, 2) for _ in "xyz") expected = np.einsum(x, [0, 1], y, [1, 2], z, [2, 3], [3, 0]) xshp, yshp, zshp = ((2, 2) for _ in "xyz") expr = contract_expression(xshp, [0, 1], yshp, [1, 2], zshp, [2, 3], [3, 0]) out = expr(x, y, z) assert np.allclose(out, expected) @pytest.mark.parametrize( "string,constants", [ ("hbc,bdef,cdkj,ji,ikeh,lfo", [1, 2, 3, 4]), ("bdef,cdkj,ji,ikeh,hbc,lfo", [0, 1, 2, 3]), ("hbc,bdef,cdkj,ji,ikeh,lfo", [1, 2, 3, 4]), ("hbc,bdef,cdkj,ji,ikeh,lfo", [1, 2, 3, 4]), ("ijab,acd,bce,df,ef->ji", [1, 2, 3, 4]), ("ab,cd,ad,cb", [1, 3]), ("ab,bc,cd", [0, 1]), ], ) def test_contract_expression_with_constants(string: str, constants: List[int]) -> None: views = build_views(string) expected = contract(string, *views, optimize=False, use_blas=False) shapes = [view.shape if hasattr(view, "shape") else () for view in views] expr_args: List[Any] = [] ctrc_args = [] for i, (shape, view) in enumerate(zip(shapes, views)): if i in constants: expr_args.append(view) else: expr_args.append(shape) ctrc_args.append(view) expr = contract_expression(string, *expr_args, constants=constants) out = expr(*ctrc_args) assert np.allclose(expected, out) @pytest.mark.parametrize("optimize", ["greedy", "optimal"]) @pytest.mark.parametrize("n", [4, 5]) @pytest.mark.parametrize("reg", [2, 3]) @pytest.mark.parametrize("n_out", [0, 2, 4]) @pytest.mark.parametrize("global_dim", [False, True]) def test_rand_equation(optimize: OptimizeKind, n: int, reg: int, n_out: int, global_dim: bool) -> None: eq, _, size_dict = rand_equation(n, reg, n_out, d_min=2, d_max=5, seed=42, return_size_dict=True) views = build_views(eq, size_dict) expected = contract(eq, *views, optimize=False) actual = contract(eq, *views, optimize=optimize) assert np.allclose(expected, actual) @pytest.mark.parametrize("equation", tests) def test_linear_vs_ssa(equation: str) -> None: views = build_views(equation) linear_path, _ = contract_path(equation, *views) ssa_path = linear_to_ssa(linear_path) linear_path2 = ssa_to_linear(ssa_path) assert linear_path2 == linear_path def test_contract_path_supply_shapes() -> None: eq = "ab,bc,cd" shps = [(2, 3), (3, 4), (4, 5)] contract_path(eq, *shps, shapes=True) opt_einsum-3.4.0/opt_einsum/tests/test_edge_cases.py000066400000000000000000000122431467526163400227370ustar00rootroot00000000000000""" Tets a series of opt_einsum contraction paths to ensure the results are the same for different paths """ from typing import Any, Tuple import pytest from opt_einsum import contract, contract_expression, contract_path from opt_einsum.typing import PathType # NumPy is required for the majority of this file np = pytest.importorskip("numpy") def test_contract_expression_checks() -> None: # check optimize needed with pytest.raises(ValueError): contract_expression("ab,bc->ac", (2, 3), (3, 4), optimize=False) # check sizes are still checked with pytest.raises(ValueError): contract_expression("ab,bc->ac", (2, 3), (3, 4), (42, 42)) # check if out given out = np.empty((2, 4)) with pytest.raises(ValueError): contract_expression("ab,bc->ac", (2, 3), (3, 4), out=out) # check still get errors when wrong ranks supplied to expression expr = contract_expression("ab,bc->ac", (2, 3), (3, 4)) # too few arguments with pytest.raises(ValueError) as err: expr(np.random.rand(2, 3)) assert "`ContractExpression` takes exactly 2" in str(err.value) # too many arguments with pytest.raises(ValueError) as err: expr(np.random.rand(2, 3), np.random.rand(2, 3), np.random.rand(2, 3)) assert "`ContractExpression` takes exactly 2" in str(err.value) # wrong shapes with pytest.raises(ValueError) as err: expr(np.random.rand(2, 3, 4), np.random.rand(3, 4)) assert "Internal error while evaluating `ContractExpression`" in str(err.value) with pytest.raises(ValueError) as err: expr(np.random.rand(2, 4), np.random.rand(3, 4, 5)) assert "Internal error while evaluating `ContractExpression`" in str(err.value) with pytest.raises(ValueError) as err: expr(np.random.rand(2, 3), np.random.rand(3, 4), out=np.random.rand(2, 4, 6)) assert "Internal error while evaluating `ContractExpression`" in str(err.value) # should only be able to specify out with pytest.raises(TypeError) as err_type: expr(np.random.rand(2, 3), np.random.rand(3, 4), order="F") # type: ignore assert "got an unexpected keyword" in str(err_type.value) def test_broadcasting_contraction() -> None: a = np.random.rand(1, 5, 4) b = np.random.rand(4, 6) c = np.random.rand(5, 6) d = np.random.rand(10) ein_scalar = contract("ijk,kl,jl", a, b, c, optimize=False) opt_scalar = contract("ijk,kl,jl", a, b, c, optimize=True) assert np.allclose(ein_scalar, opt_scalar) result = ein_scalar * d ein = contract("ijk,kl,jl,i->i", a, b, c, d, optimize=False) opt = contract("ijk,kl,jl,i->i", a, b, c, d, optimize=True) assert np.allclose(ein, result) assert np.allclose(opt, result) def test_broadcasting_contraction2() -> None: a = np.random.rand(1, 1, 5, 4) b = np.random.rand(4, 6) c = np.random.rand(5, 6) d = np.random.rand(7, 7) ein_scalar = contract("abjk,kl,jl", a, b, c, optimize=False) opt_scalar = contract("abjk,kl,jl", a, b, c, optimize=True) assert np.allclose(ein_scalar, opt_scalar) result = ein_scalar * d ein = contract("abjk,kl,jl,ab->ab", a, b, c, d, optimize=False) opt = contract("abjk,kl,jl,ab->ab", a, b, c, d, optimize=True) assert np.allclose(ein, result) assert np.allclose(opt, result) def test_broadcasting_contraction3() -> None: a = np.random.rand(1, 5, 4) b = np.random.rand(4, 1, 6) c = np.random.rand(5, 6) d = np.random.rand(7, 7) ein = contract("ajk,kbl,jl,ab->ab", a, b, c, d, optimize=False) opt = contract("ajk,kbl,jl,ab->ab", a, b, c, d, optimize=True) assert np.allclose(ein, opt) def test_broadcasting_contraction4() -> None: a = np.arange(64).reshape(2, 4, 8) ein = contract("obk,ijk->ioj", a, a, optimize=False) opt = contract("obk,ijk->ioj", a, a, optimize=True) assert np.allclose(ein, opt) def test_can_blas_on_healed_broadcast_dimensions() -> None: expr = contract_expression("ab,bc,bd->acd", (5, 4), (1, 5), (4, 20)) # first contraction involves broadcasting assert expr.contraction_list[0][2] == "bc,ab->bca" assert expr.contraction_list[0][-1] is False # but then is healed GEMM is usable assert expr.contraction_list[1][2] == "bca,bd->acd" assert expr.contraction_list[1][-1] == "GEMM" def test_pathinfo_for_empty_contraction() -> None: eq = "->" arrays = (1.0,) path: PathType = [] _, info = contract_path(eq, *arrays, optimize=path) # some info is built lazily, so check repr assert repr(info) assert info.largest_intermediate == 1 @pytest.mark.parametrize( "expression, operands", [ [",,->", (5, 5.0, 2.0j)], ["ab,->", ([[5, 5], [2.0, 1]], 2.0j)], ["ab,bc->ac", ([[5, 5], [2.0, 1]], [[2.0, 1], [3.0, 4]])], ["ab,->", ([[5, 5], [2.0, 1]], True)], ], ) def test_contract_with_assumed_shapes(expression: str, operands: Tuple[Any]) -> None: """Test that we can contract with assumed shapes, and that the output is correct. This is required as we need to infer intermediate shape sizes.""" benchmark = np.einsum(expression, *operands) result = contract(expression, *operands, optimize=True) assert np.allclose(benchmark, result) opt_einsum-3.4.0/opt_einsum/tests/test_input.py000066400000000000000000000201231467526163400220100ustar00rootroot00000000000000""" Tests the input parsing for opt_einsum. Duplicates the np.einsum input tests. """ from typing import Any, List import pytest from opt_einsum import contract, contract_path from opt_einsum.typing import ArrayType np = pytest.importorskip("numpy") def build_views(string: str) -> List[ArrayType]: """Builds random numpy arrays for testing by using a fixed size dictionary and an input string.""" chars = "abcdefghij" sizes_array = np.array([2, 3, 4, 5, 4, 3, 2, 6, 5, 4]) sizes = dict(zip(chars, sizes_array)) views = [] string = string.replace("...", "ij") terms = string.split("->")[0].split(",") for term in terms: dims = [sizes[x] for x in term] views.append(np.random.rand(*dims)) return views def test_type_errors() -> None: # subscripts must be a string with pytest.raises(TypeError): contract(0, 0) # out parameter must be an array with pytest.raises(TypeError): contract("", 0, out="test") # order parameter must be a valid order # changed in Numpy 1.19, see https://github.com/numpy/numpy/commit/35b0a051c19265f5643f6011ee11e31d30c8bc4c with pytest.raises((TypeError, ValueError)): contract("", 0, order="W") # type: ignore # casting parameter must be a valid casting with pytest.raises(ValueError): contract("", 0, casting="blah") # type: ignore # dtype parameter must be a valid dtype with pytest.raises(TypeError): contract("", 0, dtype="bad_data_type") # other keyword arguments are rejected with pytest.raises(TypeError): contract("", 0, bad_arg=0) # issue 4528 revealed a segfault with this call with pytest.raises(TypeError): contract(*(None,) * 63) # Cannot have two -> with pytest.raises(ValueError): contract("->,->", 0, 5) # Undefined symbol lhs with pytest.raises(ValueError): contract("&,a->", 0, 5) # Undefined symbol rhs with pytest.raises(ValueError): contract("a,a->&", 0, 5) with pytest.raises(ValueError): contract("a,a->&", 0, 5) # Catch ellipsis errors string = "...a->...a" views = build_views(string) # Subscript list must contain Ellipsis or (hashable && comparable) object with pytest.raises(TypeError): contract(views[0], [Ellipsis, 0], [Ellipsis, ["a"]]) with pytest.raises(TypeError): contract(views[0], [Ellipsis, {}], [Ellipsis, "a"]) @pytest.mark.parametrize("contract_fn", [contract, contract_path]) def test_value_errors(contract_fn: Any) -> None: with pytest.raises(ValueError): contract_fn("") # subscripts must be a string with pytest.raises(TypeError): contract_fn(0, 0) # invalid subscript character with pytest.raises(ValueError): contract_fn("i%...", [0, 0]) with pytest.raises(ValueError): contract_fn("...j$", [0, 0]) with pytest.raises(ValueError): contract_fn("i->&", [0, 0]) with pytest.raises(ValueError): contract_fn("") # number of operands must match count in subscripts string with pytest.raises(ValueError): contract_fn("", 0, 0) with pytest.raises(ValueError): contract_fn(",", 0, [0], [0]) with pytest.raises(ValueError): contract_fn(",", [0]) # can't have more subscripts than dimensions in the operand with pytest.raises(ValueError): contract_fn("i", 0) with pytest.raises(ValueError): contract_fn("ij", [0, 0]) with pytest.raises(ValueError): contract_fn("...i", 0) with pytest.raises(ValueError): contract_fn("i...j", [0, 0]) with pytest.raises(ValueError): contract_fn("i...", 0) with pytest.raises(ValueError): contract_fn("ij...", [0, 0]) # invalid ellipsis with pytest.raises(ValueError): contract_fn("i..", [0, 0]) with pytest.raises(ValueError): contract_fn(".i...", [0, 0]) with pytest.raises(ValueError): contract_fn("j->..j", [0, 0]) with pytest.raises(ValueError): contract_fn("j->.j...", [0, 0]) # invalid subscript character with pytest.raises(ValueError): contract_fn("i%...", [0, 0]) with pytest.raises(ValueError): contract_fn("...j$", [0, 0]) with pytest.raises(ValueError): contract_fn("i->&", [0, 0]) # output subscripts must appear in input with pytest.raises(ValueError): contract_fn("i->ij", [0, 0]) # output subscripts may only be specified once with pytest.raises(ValueError): contract_fn("ij->jij", [[0, 0], [0, 0]]) # dimensions much match when being collapsed with pytest.raises(ValueError): contract_fn("ii", np.arange(6).reshape(2, 3)) with pytest.raises(ValueError): contract_fn("ii->i", np.arange(6).reshape(2, 3)) # broadcasting to new dimensions must be enabled explicitly with pytest.raises(ValueError): contract_fn("i", np.arange(6).reshape(2, 3)) with pytest.raises(TypeError): contract_fn("ij->ij", [[0, 1], [0, 1]], bad_kwarg=True) @pytest.mark.parametrize( "string", [ # Ellipse "...a->...", "a...->...", "a...a->...a", "...,...", "a,b", "...a,...b", ], ) def test_compare(string: str) -> None: views = build_views(string) ein = contract(string, *views, optimize=False) opt = contract(string, *views) assert np.allclose(ein, opt) opt = contract(string, *views, optimize="optimal") assert np.allclose(ein, opt) def test_ellipse_input1() -> None: string = "...a->..." views = build_views(string) ein = contract(string, *views, optimize=False) opt = contract(views[0], [Ellipsis, 0], [Ellipsis]) assert np.allclose(ein, opt) def test_ellipse_input2() -> None: string = "...a" views = build_views(string) ein = contract(string, *views, optimize=False) opt = contract(views[0], [Ellipsis, 0]) assert np.allclose(ein, opt) def test_ellipse_input3() -> None: string = "...a->...a" views = build_views(string) ein = contract(string, *views, optimize=False) opt = contract(views[0], [Ellipsis, 0], [Ellipsis, 0]) assert np.allclose(ein, opt) def test_ellipse_input4() -> None: string = "...b,...a->..." views = build_views(string) ein = contract(string, *views, optimize=False) opt = contract(views[0], [Ellipsis, 1], views[1], [Ellipsis, 0], [Ellipsis]) assert np.allclose(ein, opt) def test_singleton_dimension_broadcast() -> None: # singleton dimensions broadcast (gh-10343) p = np.ones((10, 2)) q = np.ones((1, 2)) ein = contract("ij,ij->j", p, q, optimize=False) opt = contract("ij,ij->j", p, q, optimize=True) assert np.allclose(ein, opt) assert np.allclose(opt, [10.0, 10.0]) p = np.ones((1, 5)) q = np.ones((5, 5)) for optimize in (True, False): res1 = (contract("...ij,...jk->...ik", p, p, optimize=optimize),) res2 = contract("...ij,...jk->...ik", p, q, optimize=optimize) assert np.allclose(res1, res2) assert np.allclose(res2, np.full((1, 5), 5)) def test_large_int_input_format() -> None: string = "ab,bc,cd" x, y, z = build_views(string) string_output = contract(string, x, y, z) int_output = contract(x, (1000, 1001), y, (1001, 1002), z, (1002, 1003)) assert np.allclose(string_output, int_output) for i in range(10): transpose_output = contract(x, (i + 1, i)) assert np.allclose(transpose_output, x.T) def test_hashable_object_input_format() -> None: string = "ab,bc,cd" x, y, z = build_views(string) string_output = contract(string, x, y, z) hash_output1 = contract(x, ("left", "bond1"), y, ("bond1", "bond2"), z, ("bond2", "right")) hash_output2 = contract( x, ("left", "bond1"), y, ("bond1", "bond2"), z, ("bond2", "right"), ("left", "right"), ) assert np.allclose(string_output, hash_output1) assert np.allclose(hash_output1, hash_output2) for i in range(1, 10): transpose_output = contract(x, ("b" * i, "a" * i)) assert np.allclose(transpose_output, x.T) opt_einsum-3.4.0/opt_einsum/tests/test_parser.py000066400000000000000000000040451467526163400221520ustar00rootroot00000000000000""" Directly tests various parser utility functions. """ from typing import Any, Tuple import pytest from opt_einsum.parser import get_shape, get_symbol, parse_einsum_input from opt_einsum.testing import build_arrays_from_tuples def test_get_symbol() -> None: assert get_symbol(2) == "c" assert get_symbol(200000) == "\U00031540" # Ensure we skip surrogates '[\uD800-\uDFFF]' assert get_symbol(55295) == "\ud88b" assert get_symbol(55296) == "\ue000" assert get_symbol(57343) == "\ue7ff" def test_parse_einsum_input() -> None: eq = "ab,bc,cd" ops = build_arrays_from_tuples([(2, 3), (3, 4), (4, 5)]) input_subscripts, output_subscript, operands = parse_einsum_input([eq, *ops]) assert input_subscripts == eq assert output_subscript == "ad" assert operands == ops def test_parse_einsum_input_shapes_error() -> None: eq = "ab,bc,cd" ops = build_arrays_from_tuples([(2, 3), (3, 4), (4, 5)]) with pytest.raises(ValueError): _ = parse_einsum_input([eq, *ops], shapes=True) def test_parse_einsum_input_shapes() -> None: eq = "ab,bc,cd" shapes = [(2, 3), (3, 4), (4, 5)] input_subscripts, output_subscript, operands = parse_einsum_input([eq, *shapes], shapes=True) assert input_subscripts == eq assert output_subscript == "ad" assert shapes == operands def test_parse_with_ellisis() -> None: eq = "...a,ab" shapes = [(2, 3), (3, 4)] input_subscripts, output_subscript, operands = parse_einsum_input([eq, *shapes], shapes=True) assert input_subscripts == "da,ab" assert output_subscript == "db" assert shapes == operands @pytest.mark.parametrize( "array, shape", [ [[5], (1,)], [[5, 5], (2,)], [(5, 5), (2,)], [[[[[[5, 2]]]]], (1, 1, 1, 1, 2)], [[[[[["abcdef", "b"]]]]], (1, 1, 1, 1, 2)], ["A", ()], [b"A", ()], [True, ()], [5, ()], [5.0, ()], [5.0 + 0j, ()], ], ) def test_get_shapes(array: Any, shape: Tuple[int]) -> None: assert get_shape(array) == shape opt_einsum-3.4.0/opt_einsum/tests/test_paths.py000066400000000000000000000460051467526163400217770ustar00rootroot00000000000000""" Tests the accuracy of the opt_einsum paths in addition to unit tests for the various path helper functions. """ import itertools from concurrent.futures import ProcessPoolExecutor from typing import Any, Dict, List, Optional import pytest import opt_einsum as oe from opt_einsum.testing import build_shapes, rand_equation from opt_einsum.typing import ArrayIndexType, OptimizeKind, PathType, TensorShapeType explicit_path_tests = { "GEMM1": ( [set("abd"), set("ac"), set("bdc")], set(""), {"a": 1, "b": 2, "c": 3, "d": 4}, ), "Inner1": ( [set("abcd"), set("abc"), set("bc")], set(""), {"a": 5, "b": 2, "c": 3, "d": 4}, ), } # note that these tests have no unique solution due to the chosen dimensions path_edge_tests = [ ["greedy", "eb,cb,fb->cef", ((0, 2), (0, 1))], ["branch-all", "eb,cb,fb->cef", ((0, 2), (0, 1))], ["branch-2", "eb,cb,fb->cef", ((0, 2), (0, 1))], ["optimal", "eb,cb,fb->cef", ((0, 2), (0, 1))], ["dp", "eb,cb,fb->cef", ((1, 2), (0, 1))], ["greedy", "dd,fb,be,cdb->cef", ((0, 3), (0, 1), (0, 1))], ["branch-all", "dd,fb,be,cdb->cef", ((0, 3), (0, 1), (0, 1))], ["branch-2", "dd,fb,be,cdb->cef", ((0, 3), (0, 1), (0, 1))], ["optimal", "dd,fb,be,cdb->cef", ((0, 3), (0, 1), (0, 1))], ["optimal", "dd,fb,be,cdb->cef", ((0, 3), (0, 1), (0, 1))], ["dp", "dd,fb,be,cdb->cef", ((0, 3), (0, 2), (0, 1))], ["greedy", "bca,cdb,dbf,afc->", ((1, 2), (0, 2), (0, 1))], ["branch-all", "bca,cdb,dbf,afc->", ((1, 2), (0, 2), (0, 1))], ["branch-2", "bca,cdb,dbf,afc->", ((1, 2), (0, 2), (0, 1))], ["optimal", "bca,cdb,dbf,afc->", ((1, 2), (0, 2), (0, 1))], ["dp", "bca,cdb,dbf,afc->", ((1, 2), (1, 2), (0, 1))], ["greedy", "dcc,fce,ea,dbf->ab", ((1, 2), (0, 1), (0, 1))], ["branch-all", "dcc,fce,ea,dbf->ab", ((1, 2), (0, 2), (0, 1))], ["branch-2", "dcc,fce,ea,dbf->ab", ((1, 2), (0, 2), (0, 1))], ["optimal", "dcc,fce,ea,dbf->ab", ((1, 2), (0, 2), (0, 1))], ["dp", "dcc,fce,ea,dbf->ab", ((1, 2), (0, 2), (0, 1))], ] # note that these tests have no unique solution due to the chosen dimensions path_scalar_tests = [ [ "a,->a", 1, ], ["ab,->ab", 1], [",a,->a", 2], [",,a,->a", 3], [",,->", 2], ] def check_path(test_output: PathType, benchmark: PathType, bypass: bool = False) -> bool: if not isinstance(test_output, list): return False if len(test_output) != len(benchmark): return False ret = True for pos in range(len(test_output)): ret &= isinstance(test_output[pos], tuple) ret &= test_output[pos] == list(benchmark)[pos] return ret def assert_contract_order(func: Any, test_data: Any, max_size: int, benchmark: PathType) -> None: test_output = func(test_data[0], test_data[1], test_data[2], max_size) assert check_path(test_output, benchmark) def test_size_by_dict() -> None: sizes_dict = {} for ind, val in zip("abcdez", [2, 5, 9, 11, 13, 0]): sizes_dict[ind] = val path_func = oe.helpers.compute_size_by_dict assert 1 == path_func("", sizes_dict) assert 2 == path_func("a", sizes_dict) assert 5 == path_func("b", sizes_dict) assert 0 == path_func("z", sizes_dict) assert 0 == path_func("az", sizes_dict) assert 0 == path_func("zbc", sizes_dict) assert 104 == path_func("aaae", sizes_dict) assert 12870 == path_func("abcde", sizes_dict) def test_flop_cost() -> None: size_dict = {v: 10 for v in "abcdef"} # Loop over an array assert 10 == oe.helpers.flop_count("a", False, 1, size_dict) # Hadamard product (*) assert 10 == oe.helpers.flop_count("a", False, 2, size_dict) assert 100 == oe.helpers.flop_count("ab", False, 2, size_dict) # Inner product (+, *) assert 20 == oe.helpers.flop_count("a", True, 2, size_dict) assert 200 == oe.helpers.flop_count("ab", True, 2, size_dict) # Inner product x3 (+, *, *) assert 30 == oe.helpers.flop_count("a", True, 3, size_dict) # GEMM assert 2000 == oe.helpers.flop_count("abc", True, 2, size_dict) def test_bad_path_option() -> None: with pytest.raises(KeyError): oe.contract("a,b,c", [1], [2], [3], optimize="optimall", shapes=True) # type: ignore def test_explicit_path() -> None: pytest.importorskip("numpy") x = oe.contract("a,b,c", [1], [2], [3], optimize=[(1, 2), (0, 1)]) assert x.item() == 6 def test_path_optimal() -> None: test_func = oe.paths.optimal test_data = explicit_path_tests["GEMM1"] assert_contract_order(test_func, test_data, 5000, [(0, 2), (0, 1)]) assert_contract_order(test_func, test_data, 0, [(0, 1, 2)]) def test_path_greedy() -> None: test_func = oe.paths.greedy test_data = explicit_path_tests["GEMM1"] assert_contract_order(test_func, test_data, 5000, [(0, 2), (0, 1)]) assert_contract_order(test_func, test_data, 0, [(0, 1, 2)]) def test_memory_paths() -> None: expression = "abc,bdef,fghj,cem,mhk,ljk->adgl" views = build_shapes(expression) # Test tiny memory limit path_ret = oe.contract_path(expression, *views, optimize="optimal", memory_limit=5, shapes=True) assert check_path(path_ret[0], [(0, 1, 2, 3, 4, 5)]) path_ret = oe.contract_path(expression, *views, optimize="greedy", memory_limit=5, shapes=True) assert check_path(path_ret[0], [(0, 1, 2, 3, 4, 5)]) # Check the possibilities, greedy is capped path_ret = oe.contract_path(expression, *views, optimize="optimal", memory_limit=-1, shapes=True) assert check_path(path_ret[0], [(0, 3), (0, 4), (0, 2), (0, 2), (0, 1)]) path_ret = oe.contract_path(expression, *views, optimize="greedy", memory_limit=-1, shapes=True) assert check_path(path_ret[0], [(0, 3), (0, 4), (0, 2), (0, 2), (0, 1)]) @pytest.mark.parametrize("alg,expression,order", path_edge_tests) def test_path_edge_cases(alg: OptimizeKind, expression: str, order: PathType) -> None: views = build_shapes(expression) # Test tiny memory limit path_ret = oe.contract_path(expression, *views, optimize=alg, shapes=True) assert check_path(path_ret[0], order) @pytest.mark.parametrize("expression,order", path_scalar_tests) @pytest.mark.parametrize("alg", oe.paths._PATH_OPTIONS) def test_path_scalar_cases(alg: OptimizeKind, expression: str, order: PathType) -> None: views = build_shapes(expression) # Test tiny memory limit path_ret = oe.contract_path(expression, *views, optimize=alg, shapes=True) # print(path_ret[0]) assert len(path_ret[0]) == order def test_optimal_edge_cases() -> None: # Edge test5 expression = "a,ac,ab,ad,cd,bd,bc->" edge_test4 = build_shapes(expression, dimension_dict={"a": 20, "b": 20, "c": 20, "d": 20}) path, _ = oe.contract_path(expression, *edge_test4, optimize="greedy", memory_limit="max_input", shapes=True) assert check_path(path, [(0, 1), (0, 1, 2, 3, 4, 5)]) path, _ = oe.contract_path(expression, *edge_test4, optimize="optimal", memory_limit="max_input", shapes=True) assert check_path(path, [(0, 1), (0, 1, 2, 3, 4, 5)]) def test_greedy_edge_cases() -> None: expression = "abc,cfd,dbe,efa" dim_dict = {k: 20 for k in expression.replace(",", "")} tensors = build_shapes(expression, dimension_dict=dim_dict) path, _ = oe.contract_path(expression, *tensors, optimize="greedy", memory_limit="max_input", shapes=True) assert check_path(path, [(0, 1, 2, 3)]) path, _ = oe.contract_path(expression, *tensors, optimize="greedy", memory_limit=-1, shapes=True) assert check_path(path, [(0, 1), (0, 2), (0, 1)]) def test_dp_edge_cases_dimension_1() -> None: eq = "nlp,nlq,pl->n" shapes = [(1, 1, 1), (1, 1, 1), (1, 1)] info = oe.contract_path(eq, *shapes, shapes=True, optimize="dp")[1] assert max(info.scale_list) == 3 def test_dp_edge_cases_all_singlet_indices() -> None: eq = "a,bcd,efg->" shapes = [(2,), (2, 2, 2), (2, 2, 2)] info = oe.contract_path(eq, *shapes, shapes=True, optimize="dp")[1] assert max(info.scale_list) == 3 def test_custom_dp_can_optimize_for_outer_products() -> None: eq = "a,b,abc->c" da, db, dc = 2, 2, 3 shapes = [(da,), (db,), (da, db, dc)] opt1 = oe.DynamicProgramming(search_outer=False) opt2 = oe.DynamicProgramming(search_outer=True) info1 = oe.contract_path(eq, *shapes, shapes=True, optimize=opt1)[1] info2 = oe.contract_path(eq, *shapes, shapes=True, optimize=opt2)[1] assert info2.opt_cost < info1.opt_cost def test_custom_dp_can_optimize_for_size() -> None: eq, shapes = rand_equation(10, 4, seed=43) opt1 = oe.DynamicProgramming(minimize="flops") opt2 = oe.DynamicProgramming(minimize="size") info1 = oe.contract_path(eq, *shapes, shapes=True, optimize=opt1)[1] info2 = oe.contract_path(eq, *shapes, shapes=True, optimize=opt2)[1] assert info1.opt_cost < info2.opt_cost assert info1.largest_intermediate > info2.largest_intermediate def test_custom_dp_can_set_cost_cap() -> None: eq, shapes = rand_equation(5, 3, seed=42) opt1 = oe.DynamicProgramming(cost_cap=True) opt2 = oe.DynamicProgramming(cost_cap=False) opt3 = oe.DynamicProgramming(cost_cap=100) info1 = oe.contract_path(eq, *shapes, shapes=True, optimize=opt1)[1] info2 = oe.contract_path(eq, *shapes, shapes=True, optimize=opt2)[1] info3 = oe.contract_path(eq, *shapes, shapes=True, optimize=opt3)[1] assert info1.opt_cost == info2.opt_cost == info3.opt_cost @pytest.mark.parametrize( "minimize,cost,width,path", [ ("flops", 663054, 18900, [(4, 5), (2, 5), (2, 7), (5, 6), (1, 5), (1, 4), (0, 3), (0, 2), (0, 1)]), ("size", 1114440, 2016, [(2, 7), (3, 8), (3, 7), (2, 6), (1, 5), (1, 4), (1, 3), (1, 2), (0, 1)]), ("write", 983790, 2016, [(0, 8), (3, 4), (1, 4), (5, 6), (1, 5), (0, 4), (0, 3), (1, 2), (0, 1)]), ("combo", 973518, 2016, [(4, 5), (2, 5), (6, 7), (2, 6), (1, 5), (1, 4), (0, 3), (0, 2), (0, 1)]), ("limit", 983832, 2016, [(2, 7), (3, 4), (0, 4), (3, 6), (2, 5), (0, 4), (0, 3), (1, 2), (0, 1)]), ("combo-256", 983790, 2016, [(0, 8), (3, 4), (1, 4), (5, 6), (1, 5), (0, 4), (0, 3), (1, 2), (0, 1)]), ("limit-256", 983832, 2016, [(2, 7), (3, 4), (0, 4), (3, 6), (2, 5), (0, 4), (0, 3), (1, 2), (0, 1)]), ], ) def test_custom_dp_can_set_minimize(minimize: str, cost: int, width: int, path: PathType) -> None: eq, shapes = rand_equation(10, 4, seed=43) opt = oe.DynamicProgramming(minimize=minimize) info = oe.contract_path(eq, *shapes, shapes=True, optimize=opt)[1] assert info.path == path assert info.opt_cost == cost assert info.largest_intermediate == width def test_dp_errors_when_no_contractions_found() -> None: eq, shapes = rand_equation(10, 3, seed=42) # first get the actual minimum cost opt = oe.DynamicProgramming(minimize="size") _, info = oe.contract_path(eq, *shapes, shapes=True, optimize=opt) mincost = info.largest_intermediate # check we can still find it without minimizing size explicitly oe.contract_path(eq, *shapes, shapes=True, memory_limit=mincost, optimize="dp") # but check just below this threshold raises with pytest.raises(RuntimeError): oe.contract_path(eq, *shapes, shapes=True, memory_limit=mincost - 1, optimize="dp") @pytest.mark.parametrize("optimize", ["greedy", "branch-2", "branch-all", "optimal", "dp"]) def test_can_optimize_outer_products(optimize: OptimizeKind) -> None: a, b, c = ((10, 10) for _ in range(3)) d = (10, 2) assert oe.contract_path("ab,cd,ef,fg", a, b, c, d, optimize=optimize, shapes=True)[0] == [ (2, 3), (0, 2), (0, 1), ] @pytest.mark.parametrize("num_symbols", [2, 3, 26, 26 + 26, 256 - 140, 300]) def test_large_path(num_symbols: int) -> None: symbols = "".join(oe.get_symbol(i) for i in range(num_symbols)) dimension_dict = dict(zip(symbols, itertools.cycle([2, 3, 4]))) expression = ",".join(symbols[t : t + 2] for t in range(num_symbols - 1)) tensors = build_shapes(expression, dimension_dict=dimension_dict) # Check that path construction does not crash oe.contract_path(expression, *tensors, optimize="greedy", shapes=True) def test_custom_random_greedy() -> None: np = pytest.importorskip("numpy") eq, shapes = rand_equation(10, 4, seed=42) views = list(map(np.ones, shapes)) with pytest.raises(ValueError): oe.RandomGreedy(minimize="something") optimizer = oe.RandomGreedy(max_repeats=10, minimize="flops") path, path_info = oe.contract_path(eq, *views, optimize=optimizer) assert len(optimizer.costs) == 10 assert len(optimizer.sizes) == 10 assert path == optimizer.path assert optimizer.best["flops"] == min(optimizer.costs) assert path_info.largest_intermediate == optimizer.best["size"] assert path_info.opt_cost == optimizer.best["flops"] # check can change settings and run again optimizer.temperature = 0.0 optimizer.max_repeats = 6 path, path_info = oe.contract_path(eq, *views, optimize=optimizer) assert len(optimizer.costs) == 16 assert len(optimizer.sizes) == 16 assert path == optimizer.path assert optimizer.best["size"] == min(optimizer.sizes) assert path_info.largest_intermediate == optimizer.best["size"] assert path_info.opt_cost == optimizer.best["flops"] # check error if we try and reuse the optimizer on a different expression eq, shapes = rand_equation(10, 4, seed=41) views = list(map(np.ones, shapes)) with pytest.raises(ValueError): path, path_info = oe.contract_path(eq, *views, optimize=optimizer) def test_custom_branchbound() -> None: np = pytest.importorskip("numpy") eq, shapes = rand_equation(8, 4, seed=42) views = list(map(np.ones, shapes)) optimizer = oe.BranchBound(nbranch=2, cutoff_flops_factor=10, minimize="size") path, path_info = oe.contract_path(eq, *views, optimize=optimizer) assert path == optimizer.path assert path_info.largest_intermediate == optimizer.best["size"] assert path_info.opt_cost == optimizer.best["flops"] # tweak settings and run again optimizer.nbranch = 3 optimizer.cutoff_flops_factor = 4 path, path_info = oe.contract_path(eq, *views, optimize=optimizer) assert path == optimizer.path assert path_info.largest_intermediate == optimizer.best["size"] assert path_info.opt_cost == optimizer.best["flops"] # check error if we try and reuse the optimizer on a different expression eq, shapes = rand_equation(8, 4, seed=41) views = list(map(np.ones, shapes)) with pytest.raises(ValueError): path, path_info = oe.contract_path(eq, *views, optimize=optimizer) def test_branchbound_validation() -> None: with pytest.raises(ValueError): oe.BranchBound(nbranch=0) def test_parallel_random_greedy() -> None: np = pytest.importorskip("numpy") pool = ProcessPoolExecutor(2) eq, shapes = rand_equation(10, 4, seed=42) views = list(map(np.ones, shapes)) optimizer = oe.RandomGreedy(max_repeats=10, parallel=pool) path, path_info = oe.contract_path(eq, *views, optimize=optimizer) assert len(optimizer.costs) == 10 assert len(optimizer.sizes) == 10 assert path == optimizer.path assert optimizer.parallel is pool assert optimizer._executor is pool assert optimizer.best["flops"] == min(optimizer.costs) assert path_info.largest_intermediate == optimizer.best["size"] assert path_info.opt_cost == optimizer.best["flops"] # now switch to max time algorithm optimizer.max_repeats = int(1e6) optimizer.max_time = 0.2 optimizer.parallel = 2 path, path_info = oe.contract_path(eq, *views, optimize=optimizer) assert len(optimizer.costs) > 10 assert len(optimizer.sizes) > 10 assert path == optimizer.path assert optimizer.best["flops"] == min(optimizer.costs) assert path_info.largest_intermediate == optimizer.best["size"] assert path_info.opt_cost == optimizer.best["flops"] optimizer.parallel = True assert optimizer._executor is not None assert optimizer._executor is not pool are_done = [f.running() or f.done() for f in optimizer._futures] assert all(are_done) def test_custom_path_optimizer() -> None: np = pytest.importorskip("numpy") class NaiveOptimizer(oe.paths.PathOptimizer): def __call__( self, inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], memory_limit: Optional[int] = None, ) -> PathType: self.was_used = True return [(0, 1)] * (len(inputs) - 1) eq, shapes = rand_equation(5, 3, seed=42, d_max=3) views = list(map(np.ones, shapes)) exp = oe.contract(eq, *views, optimize=False) optimizer = NaiveOptimizer() out = oe.contract(eq, *views, optimize=optimizer) assert exp == out assert optimizer.was_used def test_custom_random_optimizer() -> None: np = pytest.importorskip("numpy") class NaiveRandomOptimizer(oe.path_random.RandomOptimizer): @staticmethod def random_path( r: int, n: int, inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int] ) -> Any: """Picks a completely random contraction order.""" np.random.seed(r) ssa_path: List[TensorShapeType] = [] remaining = set(range(n)) while len(remaining) > 1: i, j = np.random.choice(list(remaining), size=2, replace=False) remaining.add(n + len(ssa_path)) remaining.remove(i) remaining.remove(j) ssa_path.append((i, j)) cost, size = oe.path_random.ssa_path_compute_cost(ssa_path, inputs, output, size_dict) return ssa_path, cost, size def setup(self, inputs: Any, output: Any, size_dict: Any) -> Any: self.was_used = True n = len(inputs) trial_fn = self.random_path trial_args = (n, inputs, output, size_dict) return trial_fn, trial_args eq, shapes = rand_equation(5, 3, seed=42, d_max=3) views = list(map(np.ones, shapes)) exp = oe.contract(eq, *views, optimize=False) optimizer = NaiveRandomOptimizer(max_repeats=16) out = oe.contract(eq, *views, optimize=optimizer) assert exp == out assert optimizer.was_used assert len(optimizer.costs) == 16 def test_optimizer_registration() -> None: def custom_optimizer( inputs: List[ArrayIndexType], output: ArrayIndexType, size_dict: Dict[str, int], memory_limit: Optional[int] ) -> PathType: return [(0, 1)] * (len(inputs) - 1) with pytest.raises(KeyError): oe.paths.register_path_fn("optimal", custom_optimizer) oe.paths.register_path_fn("custom", custom_optimizer) assert "custom" in oe.paths._PATH_OPTIONS eq = "ab,bc,cd" shapes = [(2, 3), (3, 4), (4, 5)] path, _ = oe.contract_path(eq, *shapes, shapes=True, optimize="custom") # type: ignore assert path == [(0, 1), (0, 1)] del oe.paths._PATH_OPTIONS["custom"] def test_path_with_assumed_shapes() -> None: path, _ = oe.contract_path("ab,bc,cd", [[5, 3]], [[2], [4]], [[3, 2]]) assert path == [(0, 1), (0, 1)] opt_einsum-3.4.0/opt_einsum/tests/test_sharing.py000066400000000000000000000315051467526163400223120ustar00rootroot00000000000000import itertools import weakref from collections import Counter from typing import Any import pytest from opt_einsum import contract, contract_expression, contract_path, get_symbol, shared_intermediates from opt_einsum.backends import to_cupy, to_torch from opt_einsum.contract import _einsum from opt_einsum.parser import parse_einsum_input from opt_einsum.sharing import count_cached_ops, currently_sharing, get_sharing_cache from opt_einsum.testing import build_views from opt_einsum.typing import BackendType pytest.importorskip("numpy") try: import numpy as np # type: ignore numpy_if_found = "numpy" except ImportError: numpy_if_found = pytest.param("numpy", marks=[pytest.mark.skip(reason="NumPy not installed.")]) # type: ignore try: import cupy # noqa cupy_if_found = "cupy" except ImportError: cupy_if_found = pytest.param("cupy", marks=[pytest.mark.skip(reason="CuPy not installed.")]) # type: ignore try: import torch # type: ignore # noqa torch_if_found = "torch" except ImportError: torch_if_found = pytest.param("torch", marks=[pytest.mark.skip(reason="PyTorch not installed.")]) # type: ignore backends = [numpy_if_found, torch_if_found, cupy_if_found] equations = [ "ab,bc->ca", "abc,bcd,dea", "abc,def->fedcba", "abc,bcd,df->fa", # test 'prefer einsum' ops "ijk,ikj", "i,j->ij", "ijk,k->ij", "AB,BC->CA", ] to_backend = { "numpy": lambda x: x, "torch": to_torch, "cupy": to_cupy, } @pytest.mark.parametrize("eq", equations) @pytest.mark.parametrize("backend", backends) def test_sharing_value(eq: str, backend: BackendType) -> None: views = build_views(eq) shapes = [v.shape for v in views] expr = contract_expression(eq, *shapes) expected = expr(*views, backend=backend) with shared_intermediates(): actual = expr(*views, backend=backend) assert (actual == expected).all() @pytest.mark.parametrize("backend", backends) def test_complete_sharing(backend: BackendType) -> None: eq = "ab,bc,cd->" views = build_views(eq) expr = contract_expression(eq, *(v.shape for v in views)) print("-" * 40) print("Without sharing:") with shared_intermediates() as cache: expr(*views, backend=backend) expected = count_cached_ops(cache) print("-" * 40) print("With sharing:") with shared_intermediates() as cache: expr(*views, backend=backend) expr(*views, backend=backend) actual = count_cached_ops(cache) print("-" * 40) print(f"Without sharing: {expected} expressions") print(f"With sharing: {actual} expressions") assert actual == expected @pytest.mark.parametrize("backend", backends) def test_sharing_reused_cache(backend: BackendType) -> None: eq = "ab,bc,cd->" views = build_views(eq) expr = contract_expression(eq, *(v.shape for v in views)) print("-" * 40) print("Without sharing:") with shared_intermediates() as cache: expr(*views, backend=backend) expected = count_cached_ops(cache) print("-" * 40) print("With sharing:") with shared_intermediates() as cache: expr(*views, backend=backend) with shared_intermediates(cache): expr(*views, backend=backend) actual = count_cached_ops(cache) print("-" * 40) print(f"Without sharing: {expected} expressions") print(f"With sharing: {actual} expressions") assert actual == expected @pytest.mark.parametrize("backend", backends) def test_no_sharing_separate_cache(backend: BackendType) -> None: eq = "ab,bc,cd->" views = build_views(eq) expr = contract_expression(eq, *(v.shape for v in views)) print("-" * 40) print("Without sharing:") with shared_intermediates() as cache: expr(*views, backend=backend) expected = count_cached_ops(cache) expected.update(count_cached_ops(cache)) # we expect double print("-" * 40) print("With sharing:") with shared_intermediates() as cache1: expr(*views, backend=backend) actual = count_cached_ops(cache1) with shared_intermediates() as cache2: expr(*views, backend=backend) actual.update(count_cached_ops(cache2)) print("-" * 40) print(f"Without sharing: {expected} expressions") print(f"With sharing: {actual} expressions") assert actual == expected @pytest.mark.parametrize("backend", backends) def test_sharing_nesting(backend: BackendType) -> None: eqs = ["ab,bc,cd->a", "ab,bc,cd->b", "ab,bc,cd->c", "ab,bc,cd->c"] views = build_views(eqs[0]) shapes = [v.shape for v in views] refs: Any = weakref.WeakValueDictionary() def method1(views): with shared_intermediates(): w = contract_expression(eqs[0], *shapes)(*views, backend=backend) x = contract_expression(eqs[2], *shapes)(*views, backend=backend) result = contract_expression("a,b->", w.shape, x.shape)(w, x, backend=backend) refs["w"] = w refs["x"] = x del w, x assert "w" in refs assert "x" in refs assert "w" not in refs, "cache leakage" assert "x" not in refs, "cache leakage" return result def method2(views): with shared_intermediates(): y = contract_expression(eqs[2], *shapes)(*views, backend=backend) z = contract_expression(eqs[3], *shapes)(*views, backend=backend) refs["y"] = y refs["z"] = z result = contract_expression("c,d->", y.shape, z.shape)(y, z, backend=backend) result = result + method1(views) # nest method1 in method2 del y, z assert "y" in refs assert "z" in refs assert "y" not in refs assert "z" not in refs method1(views) method2(views) @pytest.mark.parametrize("eq", equations) @pytest.mark.parametrize("backend", backends) def test_sharing_modulo_commutativity(eq: str, backend: BackendType) -> None: ops = tuple(to_backend[backend](x) for x in build_views(eq)) inputs, output, _ = parse_einsum_input([eq] + list(ops)) inputs_list = inputs.split(",") print("-" * 40) print("Without sharing:") with shared_intermediates() as cache: _einsum(eq, *ops, backend=backend) expected = count_cached_ops(cache) print("-" * 40) print("With sharing:") with shared_intermediates() as cache: for permuted in itertools.permutations(zip(inputs_list, ops)): permuted_inputs = [p[0] for p in permuted] permuted_ops = [p[1] for p in permuted] permuted_eq = "{}->{}".format(",".join(permuted_inputs), output) _einsum(permuted_eq, *permuted_ops, backend=backend) actual = count_cached_ops(cache) print("-" * 40) print(f"Without sharing: {expected} expressions") print(f"With sharing: {actual} expressions") assert actual == expected @pytest.mark.parametrize("backend", backends) def test_partial_sharing(backend: BackendType) -> None: eq = "ab,bc,de->" x, y, z1 = build_views(eq) # type: ignore z2 = 2.0 * z1 - 1.0 expr = contract_expression(eq, x.shape, y.shape, z1.shape) print("-" * 40) print("Without sharing:") num_exprs_nosharing: Any = Counter() with shared_intermediates() as cache: expr(x, y, z1, backend=backend) num_exprs_nosharing.update(count_cached_ops(cache)) with shared_intermediates() as cache: expr(x, y, z2, backend=backend) num_exprs_nosharing.update(count_cached_ops(cache)) print("-" * 40) print("With sharing:") with shared_intermediates() as cache: expr(x, y, z1, backend=backend) expr(x, y, z2, backend=backend) num_exprs_sharing = count_cached_ops(cache) print("-" * 40) print(f"Without sharing: {num_exprs_nosharing} expressions") print(f"With sharing: {num_exprs_sharing} expressions") assert num_exprs_nosharing["einsum"] > num_exprs_sharing["einsum"] @pytest.mark.parametrize("backend", backends) def test_sharing_with_constants(backend: BackendType) -> None: inputs = "ij,jk,kl" outputs = "ijkl" equations = [f"{inputs}->{output}" for output in outputs] shapes = (2, 3), (3, 4), (4, 5) constants = {0, 2} ops = [np.random.rand(*shp) if i in constants else shp for i, shp in enumerate(shapes)] var = np.random.rand(*shapes[1]) expected = [contract_expression(eq, *shapes)(ops[0], var, ops[2]) for eq in equations] with shared_intermediates(): actual = [contract_expression(eq, *ops, constants=constants)(var) for eq in equations] for dim, expected_dim, actual_dim in zip(outputs, expected, actual): assert np.allclose(expected_dim, actual_dim), f"error at {dim}" @pytest.mark.parametrize("size", [3, 4, 5]) @pytest.mark.parametrize("backend", backends) def test_chain(size: int, backend: BackendType) -> None: xs = [np.random.rand(2, 2) for _ in range(size)] shapes = [x.shape for x in xs] alphabet = "".join(get_symbol(i) for i in range(size + 1)) names = [alphabet[i : i + 2] for i in range(size)] inputs = ",".join(names) with shared_intermediates(): print(inputs) for i in range(size + 1): target = alphabet[i] eq = f"{inputs}->{target}" path_info = contract_path(eq, *xs) print(path_info[1]) expr = contract_expression(eq, *shapes) expr(*xs, backend=backend) print("-" * 40) @pytest.mark.parametrize("size", [3, 4, 5, 10]) @pytest.mark.parametrize("backend", backends) def test_chain_2(size: int, backend: BackendType) -> None: xs = [np.random.rand(2, 2) for _ in range(size)] shapes = [x.shape for x in xs] alphabet = "".join(get_symbol(i) for i in range(size + 1)) names = [alphabet[i : i + 2] for i in range(size)] inputs = ",".join(names) with shared_intermediates(): print(inputs) for i in range(size): target = alphabet[i : i + 2] eq = f"{inputs}->{target}" path_info = contract_path(eq, *xs) print(path_info[1]) expr = contract_expression(eq, *shapes) expr(*xs, backend=backend) print("-" * 40) def _compute_cost(cache): counts = count_cached_ops(cache) return counts["einsum"] + counts["tensordot"] @pytest.mark.parametrize("backend", backends) def test_chain_2_growth(backend: BackendType) -> None: sizes = list(range(1, 21)) costs = [] for size in sizes: xs = [np.random.rand(2, 2) for _ in range(size)] alphabet = "".join(get_symbol(i) for i in range(size + 1)) names = [alphabet[i : i + 2] for i in range(size)] inputs = ",".join(names) with shared_intermediates() as cache: for i in range(size): target = alphabet[i : i + 2] eq = f"{inputs}->{target}" expr = contract_expression(eq, *(x.shape for x in xs)) expr(*xs, backend=backend) costs.append(_compute_cost(cache)) print(f"sizes = {repr(sizes)}") print(f"costs = {repr(costs)}") for size, cost in zip(sizes, costs): print(f"{size}\t{cost}") @pytest.mark.parametrize("size", [3, 4, 5]) @pytest.mark.parametrize("backend", backends) def test_chain_sharing(size: int, backend: BackendType) -> None: xs = [np.random.rand(2, 2) for _ in range(size)] alphabet = "".join(get_symbol(i) for i in range(size + 1)) names = [alphabet[i : i + 2] for i in range(size)] inputs = ",".join(names) num_exprs_nosharing = 0 for i in range(size + 1): with shared_intermediates() as cache: target = alphabet[i] eq = f"{inputs}->{target}" expr = contract_expression(eq, *tuple(x.shape for x in xs)) expr(*xs, backend=backend) num_exprs_nosharing += _compute_cost(cache) with shared_intermediates() as cache: print(inputs) for i in range(size + 1): target = alphabet[i] eq = f"{inputs}->{target}" path_info = contract_path(eq, *xs) print(path_info[1]) expr = contract_expression(eq, *[x.shape for x in xs]) expr(*xs, backend=backend) num_exprs_sharing = _compute_cost(cache) print("-" * 40) print(f"Without sharing: {num_exprs_nosharing} expressions") print(f"With sharing: {num_exprs_sharing} expressions") assert num_exprs_nosharing > num_exprs_sharing def test_multithreaded_sharing() -> None: from multiprocessing.pool import ThreadPool def fn(): x, y, z = build_views("ab,bc,cd") with shared_intermediates(): contract("ab,bc,cd->a", x, y, z) contract("ab,bc,cd->b", x, y, z) return len(get_sharing_cache()) expected = fn() pool = ThreadPool(8) fs = [pool.apply_async(fn) for _ in range(16)] assert not currently_sharing() assert [f.get() for f in fs] == [expected] * 16 pool.close() opt_einsum-3.4.0/opt_einsum/typing.py000066400000000000000000000016511467526163400177670ustar00rootroot00000000000000"""Types used in the opt_einsum package.""" from collections import namedtuple from typing import Any, Callable, Collection, Dict, FrozenSet, List, Literal, Optional, Tuple, Union TensorShapeType = Tuple[int, ...] PathType = Collection[TensorShapeType] ArrayType = Any ArrayIndexType = FrozenSet[str] ArrayShaped = namedtuple("ArrayShaped", ["shape"]) ContractionListType = List[Tuple[Any, ArrayIndexType, str, Optional[Tuple[str, ...]], Union[str, bool]]] PathSearchFunctionType = Callable[[List[ArrayIndexType], ArrayIndexType, Dict[str, int], Optional[int]], PathType] # Contract kwargs OptimizeKind = Union[ None, bool, Literal[ "optimal", "dp", "greedy", "random-greedy", "random-greedy-128", "branch-all", "branch-2", "auto", "auto-hq" ], PathType, PathSearchFunctionType, ] BackendType = Literal["auto", "object", "autograd", "cupy", "dask", "jax", "theano", "tensorflow", "torch", "libjax"] opt_einsum-3.4.0/paper/000077500000000000000000000000001467526163400150255ustar00rootroot00000000000000opt_einsum-3.4.0/paper/paper.bib000066400000000000000000000044721467526163400166210ustar00rootroot00000000000000@article{NumPy, author={S. van der Walt and S. C. Colbert and G. Varoquaux}, journal={Comput. Sci. Eng.}, title={The NumPy Array: A Structure for Efficient Numerical Computation}, year={2011}, volume={13}, number={2}, pages={22-30}, doi={10.1109/MCSE.2011.37}, ISSN={1521-9615}, month={March},} @Misc{Dask, title = {Dask: Library for dynamic task scheduling}, author = {{Dask Development Team}}, year = {2016}, url = {http://dask.pydata.org}, note = {(accessed date May 9th, 2018)} } @article{Tensorflow, author = {Mart{\'{\i}}n Abadi and Ashish Agarwal and Paul Barham and Eugene Brevdo and Zhifeng Chen and Craig Citro and Gregory S. Corrado and Andy Davis and Jeffrey Dean and Matthieu Devin and Sanjay Ghemawat and Ian J. Goodfellow and Andrew Harp and Geoffrey Irving and Michael Isard and Yangqing Jia and Rafal J{\'{o}}zefowicz and Lukasz Kaiser and Manjunath Kudlur and Josh Levenberg and Dan Man{\'{e}} and Rajat Monga and Sherry Moore and Derek Gordon Murray and Chris Olah and Mike Schuster and Jonathon Shlens and Benoit Steiner and Ilya Sutskever and Kunal Talwar and Paul A. Tucker and Vincent Vanhoucke and Vijay Vasudevan and Fernanda B. Vi{\'{e}}gas and Oriol Vinyals and Pete Warden and Martin Wattenberg and Martin Wicke and Yuan Yu and Xiaoqiang Zheng}, title = {TensorFlow: Large-Scale Machine Learning on Heterogeneous Distributed Systems}, journal = {CoRR}, volume = {abs/1603.04467}, year = {2016}, url = {http://arxiv.org/abs/1603.04467}, archivePrefix = {arXiv}, eprint = {1603.04467}, timestamp = {Wed, 07 Jun 2017 14:40:20 +0200}, biburl = {https://dblp.org/rec/bib/journals/corr/AbadiABBCCCDDDG16}, bibsource = {dblp computer science bibliography, https://dblp.org} } opt_einsum-3.4.0/paper/paper.md000066400000000000000000000102631467526163400164600ustar00rootroot00000000000000--- title: opt\_einsum - A Python package for optimizing contraction order for einsum-like expressions tags: - array - tensors - optimization - phylogenetics - natural selection - molecular evolution authors: - name: Daniel G. A. Smith orcid: 0000-0001-8626-0900 affiliation: "1" - name: Johnnie Gray orcid: 0000-0001-9461-3024 affiliation: "2" affiliations: - name: The Molecular Science Software Institute, Blacksburg, VA 24060 index: 1 - name: University College London, London, UK index: 2 date: 14 May 2018 bibliography: paper.bib --- # Summary ``einsum`` is a powerful Swiss army knife for arbitrary tensor contractions and general linear algebra found in the popular ``numpy`` [@NumPy] package. While these expressions can be used to form most mathematical operations found in NumPy, the optimization of these expressions becomes increasingly important as naive implementations increase the overall scaling of these expressions resulting in a dramatic increase in overall execution time. Expressions with many tensors are particularly prevalent in many-body theories such as quantum chemistry, particle physics, and nuclear physics in addition to other fields such as machine learning. At the extreme case, matrix product state theory can have thousands of tensors meaning that the computation cannot proceed in a naive fashion. The canonical NumPy ``einsum`` function considers expressions as a single unit and is not able to factor these expressions into multiple smaller pieces. For example, consider the following index transformation: ``M_{pqrs} = C_{pi} C_{qj} I_{ijkl} C_{rk} C_{sl}`` with two different algorithms: ```python import numpy as np dim = 10 I = np.random.rand(dim, dim, dim, dim) C = np.random.rand(dim, dim) def naive(I, C): # N^8 scaling return np.einsum('pi,qj,ijkl,rk,sl->pqrs', C, C, I, C, C) def optimized(I, C): # N^5 scaling K = np.einsum('pi,ijkl->pjkl', C, I) K = np.einsum('qj,pjkl->pqkl', C, K) K = np.einsum('rk,pqkl->pqrl', C, K) K = np.einsum('sl,pqrl->pqrs', C, K) return K ``` By building intermediate arrays the overall scaling of the contraction is reduced and considerable cost savings even for small ``N`` (``N=10``) can be seen: ```python >> np.allclose(naive(I, C), optimized(I, C)) True %timeit naive(I, C) 1 loops, best of 3: 829 ms per loop %timeit optimized(I, C) 1000 loops, best of 3: 445 µs per loop ``` This index transformation is a well known contraction that leads to straightforward intermediates. This contraction can be further complicated by considering that the shape of the C matrices need not be the same, in this case the ordering in which the indices are transformed matters greatly. The opt_einsum package handles this logic automatically and is a drop in replacement for the ``np.einsum`` function: ```python from opt_einsum import contract dim = 30 I = np.random.rand(dim, dim, dim, dim) C = np.random.rand(dim, dim) %timeit optimized(I, C) 10 loops, best of 3: 65.8 ms per loop %timeit contract('pi,qj,ijkl,rk,sl->pqrs', C, C, I, C, C) 100 loops, best of 3: 16.2 ms per loop ``` The above automatically will find the optimal contraction order, in this case identical to that of the optimized function above, and computes the products. In this case, it uses ``np.dot`` internally to exploit any vendor BLAS functionality that the NumPy build may have. In addition, backends other than NumPy can be used to either exploit GPU computation via Tensorflow [@Tensorflow] or distributed compute capabilities via Dask [@Dask]. The core components of ``opt_einsum`` have been contributed back to the ``numpy`` library and can be found in all ``numpy.einsum`` function calls in version 1.12 or later using the ``optimize`` keyword (https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.einsum.html). The software is on GitHub (https://github.com/dgasmith/opt_einsum/tree/v2.0.0) and can be downloaded via pip or conda-forge. Further discussion of features and uses can be found at the documentation (http://optimized-einsum.readthedocs.io/en/latest/). # Acknowledgements We acknowledge additional contributions from Fabian-Robert Stöter, Robert T. McGibbon, and Nils Werner to this project. # References opt_einsum-3.4.0/pyproject.toml000066400000000000000000000047251467526163400166420ustar00rootroot00000000000000[build-system] requires = ['hatchling', 'hatch-fancy-pypi-readme>=22.5.0', 'hatch-vcs'] build-backend = 'hatchling.build' [project] name = 'opt_einsum' description = 'Path optimization of einsum functions.' authors = [ {name = 'Daniel Smith', email = 'dgasmith@icloud.com'}, ] license = 'MIT' classifiers = [ 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', 'Intended Audience :: Developers', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: MIT License', 'Topic :: Software Development :: Libraries :: Python Modules', ] requires-python = '>=3.8' dependencies = [ ] dynamic = ['version', 'readme'] [tool.hatch.version] source = "vcs" path = 'opt_einsum/_version.py' [tool.hatch.metadata] allow-direct-references = true [tool.hatch.build.hooks.vcs] version-file = "opt_einsum/_version.py" [tool.hatch.metadata.hooks.fancy-pypi-readme] content-type = 'text/markdown' # construct the PyPI readme from README.md and HISTORY.md fragments = [ {path = "README.md"}, ] [tool.hatch.build.targets.sdist] exclude = [ "/.github", "/devtools", "/docs", "/paper", "/scripts" ] [tool.hatch.build.targets.wheel] packages = ["opt_einsum"] [tool.pytest.ini_options] filterwarnings = [ 'ignore::DeprecationWarning:tensorflow', 'ignore::DeprecationWarning:tensorboard', ] [tool.ruff] line-length = 120 target-version = 'py38' [tool.ruff.lint] extend-select = ['RUF100', 'UP', 'C', 'D', 'I', 'N', 'NPY', 'Q', 'T', 'W'] extend-ignore = ['C901', 'D101', 'D102', 'D103', 'D105', 'D107', 'D205', 'D415'] isort = { known-first-party = ['opt_einsum'] } mccabe = { max-complexity = 14 } pydocstyle = { convention = 'google' } [tool.ruff.lint.per-file-ignores] 'opt_einsum/tests/*' = ['D', 'T201', 'NPY002', 'ANN001', 'ANN202'] [tool.coverage.run] source = ['opt_einsum'] omit = ['*/tests/*', 'opt_einsum/_version.py'] branch = true relative_files = true [[tool.mypy.overrides]] module = "cupy.*, jax.*, numpy.*, theano.*, tensorflow.*, torch.*" ignore_missing_imports = trueopt_einsum-3.4.0/scripts/000077500000000000000000000000001467526163400154055ustar00rootroot00000000000000opt_einsum-3.4.0/scripts/README.md000066400000000000000000000001461467526163400166650ustar00rootroot00000000000000Compare ======= This is a scratch folder to compare large numbers of contractions in different ways. opt_einsum-3.4.0/scripts/compare_random_paths.py000066400000000000000000000070071467526163400221500ustar00rootroot00000000000000import resource import timeit from typing import Literal import numpy as np import pandas as pd import opt_einsum as oe rsrc = resource.RLIMIT_DATA limit = int(1e9) resource.setrlimit(rsrc, (limit, limit)) pd.set_option("display.width", 200) opt_path: Literal["optimal"] = "optimal" # Number of dimensions max_dims = 4 min_dims = 2 # Size of each dimension min_size = 10 max_size = 20 # Number of terms min_terms = 3 max_terms = 5 # Additional parameters max_indices = 6 max_doubles = 1e7 alpha = list("abcdefghijklmnopqrstuvwyxz") alpha_dict = {num: x for num, x in enumerate(alpha)} print("Maximum term size is %d" % (max_size**max_dims)) def make_term(): num_dims = np.random.randint(min_dims, max_dims + 1) term = np.random.randint(0, max_indices, num_dims) return term def get_string(term): return "".join([alpha_dict[x] for x in term]) def random_contraction(): # Compute number of terms num_terms = np.random.randint(min_terms, max_terms) # Compute size of each index index_size = np.random.randint(min_size, max_size, max_indices) # Build random terms and views int_terms = [make_term() for x in range(num_terms)] views = [np.random.rand(*index_size[s]) for s in int_terms] # Compute einsum string and return string sum_string = ",".join([get_string(s) for s in int_terms]) out_string = sum_string.replace(",", "") out_string = [x for x in alpha if out_string.count(x) == 1] # sum_string += '->' sum_string += "->" + "".join(out_string) return (sum_string, views, index_size) out = [] for x in range(200): sum_string, views, index_size = random_contraction() try: ein = np.einsum(sum_string, *views) except Exception: out.append(["Einsum failed", sum_string, index_size, 0, 0]) continue try: opt = oe.contract(sum_string, *views, path=opt_path) except Exception: out.append(["Opt_einsum failed", sum_string, index_size, 0, 0]) continue current_opt_path = oe.contract_path(sum_string, *views, optimize=opt_path)[0] if not np.allclose(ein, opt): out.append(["Comparison failed", sum_string, index_size, 0, 0]) continue setup = "import numpy as np; import opt_einsum as oe; \ from __main__ import sum_string, views, current_opt_path" einsum_string = "np.einsum(sum_string, *views)" contract_string = "oe.contract(sum_string, *views, path=current_opt_path)" e_n = 1 o_n = 1 einsum_time = timeit.timeit(einsum_string, setup=setup, number=e_n) / e_n contract_time = timeit.timeit(contract_string, setup=setup, number=o_n) / o_n out.append([True, sum_string, current_opt_path, einsum_time, contract_time]) df = pd.DataFrame(out) df.columns = ["Flag", "String", "Path", "Einsum time", "Opt_einsum time"] df["Ratio"] = df["Einsum time"] / df["Opt_einsum time"] diff_flags = df["Flag"] is not True print("\nNumber of contract different than einsum: %d." % np.sum(diff_flags)) if diff_flags > 0: print("Terms different than einsum") print(df[df["Flag"] is not True]) print("\nDescription of speedup in relative terms:") print(df["Ratio"].describe()) print("\nNumber of contract slower than einsum: %d." % np.sum(df["Ratio"] < 0.90)) tmp = df.loc[df["Ratio"] < 0.90].copy() tmp["Diff (us)"] = np.abs(tmp["Einsum time"] - tmp["Opt_einsum time"]) * 1e6 tmp = tmp.sort_values("Diff (us)", ascending=False) print(tmp) # diff_us = np.abs(tmp['Einsum time'] - tmp['Opt_einsum time'])*1e6 print("\nDescription of slowdown:") print(tmp.describe())