pax_global_header00006660000000000000000000000064141427026720014517gustar00rootroot0000000000000052 comment=6df2ff9bd1d21c74e688aff6f67a19fbbefdd53b traits-6.3.2/000077500000000000000000000000001414270267200130355ustar00rootroot00000000000000traits-6.3.2/.clang-format000066400000000000000000000006761414270267200154210ustar00rootroot00000000000000# A style for the clang-format tool that roughly matches Python's PEP 7. # Used with Clang 9.0 to update ctraits.c, via: # # $ clang-format --style=file -i traits/ctraits.c BasedOnStyle: Google AlignAfterOpenBracket: AlwaysBreak AlwaysBreakAfterReturnType: All AllowShortIfStatementsOnASingleLine: Never BreakBeforeBraces: Stroustrup ColumnLimit: 79 IndentWidth: 4 BreakBeforeBinaryOperators: NonAssignment StatementMacros: ['PyObject_HEAD'] traits-6.3.2/.coveragerc000066400000000000000000000007441414270267200151630ustar00rootroot00000000000000[run] branch = True source = traits omit = */tests/* [paths] source = ./traits */traits [report] # Regexes for lines to exclude from consideration exclude_lines = # Have to re-enable the standard pragma pragma: no cover # Don't complain about missing debug-only code: def __repr__ # Don't complain if tests don't hit defensive assertion code: raise AssertionError raise NotImplementedError if __name__ == .__main__.: ignore_errors = True traits-6.3.2/.gitattributes000066400000000000000000000003361414270267200157320ustar00rootroot00000000000000# For archives, substitute the commit hash in the setup.py file. /setup.py export-subst # Make sure that pickle files are treated as binary, else Git # may try to modify line-endings when cloning on Windows. *.pkl binary traits-6.3.2/.github/000077500000000000000000000000001414270267200143755ustar00rootroot00000000000000traits-6.3.2/.github/pull_request_template.md000066400000000000000000000003131414270267200213330ustar00rootroot00000000000000**Checklist** - [ ] Tests - [ ] Update API reference (`docs/source/traits_api_reference`) - [ ] Update User manual (`docs/source/traits_user_manual`) - [ ] Update type annotation hints in `traits-stubs` traits-6.3.2/.github/workflows/000077500000000000000000000000001414270267200164325ustar00rootroot00000000000000traits-6.3.2/.github/workflows/release-to-pypi.yml000066400000000000000000000036021414270267200221750ustar00rootroot00000000000000name: Release to PyPI on: workflow_dispatch: release: types: [published] jobs: build-wheels: strategy: matrix: os: [windows-latest, macos-latest, ubuntu-latest] runs-on: ${{ matrix.os }} steps: - name: Check out the release commit uses: actions/checkout@v2 - name: Set up QEMU uses: docker/setup-qemu-action@v1 with: platforms: arm64 if: runner.os == 'Linux' - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.8' - name: Install Python packages needed for wheel build and upload run: | python -m pip install --upgrade pip setuptools python -m pip install twine wheel - name: Build wheels uses: pypa/cibuildwheel@v2.1.2 env: CIBW_SKIP: 'pp*' CIBW_ARCHS_LINUX: "auto aarch64" CIBW_ARCHS_MACOS: "auto universal2" - name: Check and upload wheels env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | python -m twine check --strict wheelhouse/*.whl python -m twine upload wheelhouse/*.whl build-sdist: runs-on: ubuntu-latest steps: - name: Check out the release commit uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.8' - name: Install Python packages needed for sdist build and upload run: | python -m pip install --upgrade pip setuptools python -m pip install twine - name: Build sdist run: | python setup.py sdist - name: Publish sdist to PyPI env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | python -m twine check --strict dist/*.tar.gz python -m twine upload dist/*.tar.gz traits-6.3.2/.github/workflows/run-core-traits-tests.yml000066400000000000000000000015071414270267200233560ustar00rootroot00000000000000# Test run with no optional dependencies installed, to help # detect any accidental dependencies. name: Core tests on: pull_request jobs: core: strategy: matrix: os: [ubuntu-latest, windows-latest] python-version: ['3.6', '3.7', '3.8', '3.9', '3.10'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install local package run: | python -m pip install --upgrade pip setuptools wheel python -m pip install . python -m pip uninstall -y setuptools wheel - name: Test Traits package run: | mkdir testdir cd testdir python -m unittest discover -v traits traits-6.3.2/.github/workflows/run-style-checks.yml000066400000000000000000000011631414270267200223560ustar00rootroot00000000000000name: Style check on: pull_request jobs: style: strategy: matrix: os: [ubuntu-latest] python-version: ['3.8'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies and local packages run: | python -m pip install --upgrade pip python -m pip install flake8 python -m pip install flake8-ets - name: Run style checks run: | python -m flake8 traits-6.3.2/.github/workflows/run-traits-tests.yml000066400000000000000000000030241414270267200224240ustar00rootroot00000000000000name: Tests on: pull_request jobs: tests: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] python-version: ['3.6', '3.7', '3.8', '3.9', '3.10'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - name: Install Linux packages for Qt 5 support run: | sudo apt-get update sudo apt-get install qt5-default sudo apt-get install libxkbcommon-x11-0 sudo apt-get install libxcb-icccm4 sudo apt-get install libxcb-image0 sudo apt-get install libxcb-keysyms1 sudo apt-get install libxcb-randr0 sudo apt-get install libxcb-render-util0 sudo apt-get install libxcb-xinerama0 if: matrix.os == 'ubuntu-latest' - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies and local packages run: | python -m pip install --upgrade pip setuptools wheel python -m pip install .[test] python -m pip install traits-stubs/[test] - name: Create clean test directory run: | mkdir testdir - name: Test Traits package uses: GabrielBB/xvfb-action@v1 with: working-directory: testdir run: python -m unittest discover -v traits - name: Test Traits typing stubs uses: GabrielBB/xvfb-action@v1 with: working-directory: testdir run: python -m unittest discover -v traits_stubs_tests traits-6.3.2/.github/workflows/test-documentation-build.yml000066400000000000000000000012721414270267200241020ustar00rootroot00000000000000name: Doc build on: pull_request jobs: docs: strategy: matrix: os: [ubuntu-latest] python-version: ['3.8'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies and local packages run: | python -m pip install --upgrade pip python -m pip install Sphinx enthought_sphinx_theme python -m pip install . - name: Build HTML documentation with Sphinx run: | cd docs python -m sphinx -b html -W source build traits-6.3.2/.github/workflows/test-from-pypi.yml000066400000000000000000000102111414270267200220470ustar00rootroot00000000000000name: Test installation from PyPI on: workflow_dispatch: schedule: # Run at 03:27 UTC on the 8th and 22nd of every month - cron: '27 3 8,22 * *' jobs: test-pypi-sdist: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] python-version: ['3.6', '3.7', '3.8', '3.9'] python-architecture: [x86, x64] exclude: - os: macos-latest python-architecture: x86 - os: ubuntu-latest python-architecture: x86 runs-on: ${{ matrix.os }} steps: - name: Install Linux packages for Qt 5 support run: | sudo apt-get update sudo apt-get install qt5-default sudo apt-get install libxkbcommon-x11-0 sudo apt-get install libxcb-icccm4 sudo apt-get install libxcb-image0 sudo apt-get install libxcb-keysyms1 sudo apt-get install libxcb-randr0 sudo apt-get install libxcb-render-util0 sudo apt-get install libxcb-xinerama0 if: runner.os == 'Linux' - name: Set up Python ${{ matrix.python-version }} (${{ matrix.python-architecture }}) uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} architecture: ${{ matrix.python-architecture }} - name: Install prerequisites run: | python -m pip install --upgrade pip setuptools wheel - name: Install Traits and test dependencies from PyPI sdist run: | python -m pip install --no-binary traits traits[test] - name: Create clean test directory run: | mkdir testdir - name: Test Traits package uses: GabrielBB/xvfb-action@v1 with: working-directory: testdir run: python -m unittest discover -v traits test-pypi-wheel: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] python-version: ['3.6', '3.7', '3.8', '3.9'] python-architecture: [x86, x64] exclude: - os: macos-latest python-architecture: x86 - os: ubuntu-latest python-architecture: x86 runs-on: ${{ matrix.os }} steps: - name: Install Linux packages for Qt 5 support run: | sudo apt-get update sudo apt-get install qt5-default sudo apt-get install libxkbcommon-x11-0 sudo apt-get install libxcb-icccm4 sudo apt-get install libxcb-image0 sudo apt-get install libxcb-keysyms1 sudo apt-get install libxcb-randr0 sudo apt-get install libxcb-render-util0 sudo apt-get install libxcb-xinerama0 if: runner.os == 'Linux' - name: Set up Python ${{ matrix.python-version }} (${{ matrix.python-architecture }}) uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} architecture: ${{ matrix.python-architecture }} - name: Install prerequisites run: | python -m pip install --upgrade pip setuptools wheel - name: Install Traits and test dependencies from PyPI wheel run: | python -m pip install --only-binary traits traits[test] - name: Create clean test directory run: | mkdir testdir - name: Test Traits package uses: GabrielBB/xvfb-action@v1 with: working-directory: testdir run: python -m unittest discover -v traits notify-on-failure: needs: [test-pypi-sdist, test-pypi-wheel] if: failure() runs-on: ubuntu-latest steps: - name: Notify Slack channel on failure uses: voxmedia/github-action-slack-notify-build@v1 with: channel_id: ${{ secrets.ETS_BOTS_SLACK_CHANNEL_ID }} status: FAILED color: danger env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_ACTION_SECRET }} notify-on-success: needs: [test-pypi-sdist, test-pypi-wheel] if: success() runs-on: ubuntu-latest steps: - name: Notify Slack channel on success uses: voxmedia/github-action-slack-notify-build@v1 with: channel_id: ${{ secrets.ETS_BOTS_SLACK_CHANNEL_ID }} status: SUCCESS color: good env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_ACTION_SECRET }} traits-6.3.2/.gitignore000066400000000000000000000003411414270267200150230ustar00rootroot00000000000000.coverage.* # file types to ignore *.pyc *.pyd *.so *.enamlc *~ .DS_Store # ignore the build directories *.egg-info/ build/ dist/ docs/build/ # ignore mypy cache .mypy_cache/ # Auto-generated by setup.py traits/version.py traits-6.3.2/.readthedocs.yaml000066400000000000000000000003471414270267200162700ustar00rootroot00000000000000# Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details version: 2 python: version: 3.8 install: - method: pip path: . extra_requirements: - docs traits-6.3.2/CHANGES.rst000066400000000000000000002043471414270267200146510ustar00rootroot00000000000000Traits CHANGELOG ================ Release 6.3.2 ------------- Released: 2021-11-10 Traits 6.3.2 is a bugfix release, fixing an issue with duplicate notifications from ``Property`` traits using the ``observe`` framework. Fixes ~~~~~ * Fix that ``Property`` traits using ``observe`` metadata could be fired twice in subclasses. (#1587) Release 6.3.1 ------------- Released: 2021-10-12 Traits 6.3.1 is a bugfix release, fixing an incompatibility between Traits 6.3.0 and Mayavi <= 4.7.3. Fixes ~~~~~ * Make ``PrefixMap._map`` available again, for compatibility with Mayavi. (#1578) Release 6.3.0 ------------- Released: 2021-10-08 Traits 6.3 is the latest feature release in the Traits 6 series, with several improvements and fixes over Traits 6.2. Highlights of this release ~~~~~~~~~~~~~~~~~~~~~~~~~~ * There have been various minor performance improvements to the core ``on_trait_change`` and ``observe`` machinery. These may improve startup time for some Traits-using applications. * The ``observe`` mini-language now has in-language support for listening to all traits, using the ``*`` character. * Support for Python 3.10 has been added. Migration guide ~~~~~~~~~~~~~~~ Traits 6.3 is intended to be fully backwards compatible with Traits 6.2, and most projects should have no difficulties upgrading. However, you may see some new deprecation warnings for existing code, warning about behaviour that will be changed in Traits 7.0. There are two particular sets of changes to look out for: * Starting with Traits 7.0, the ``Any`` trait type will treat a default value of type ``list`` or ``dict`` differently. Currently, instances of ``list`` and ``dict`` are special-cased, and a per-instance copy of the default is provided to each ``HasTraits`` instance. In Traits 7.0, this special-casing will be removed, and the default value will be shared between all instances. For the 6.3 release of Traits, a deprecation warning is issued whenever a trait definition of the form ``Any([1, 2, 3])`` or ``Any({})`` is encountered. Users can retain the existing behaviour and suppress the warning by changing their code to use the new ``factory`` argument to the ``Any`` trait type, for example replacing a trait declaration ``foo = Any({})`` with ``foo = Any(factory=dict)``, and a trait declaration ``foo = Any([1, 2, 3])`` with ``foo = Any(factory=list, args=([1, 2, 3],))``. * Starting with Traits 7.0, the ``Date`` trait type will no longer accept ``datetime`` instances by default. Traits 6.3 will issue a deprecation warning whenever a ``datetime`` instance is assigned as a value for a ``Date`` trait. The existing behaviour can be preserved and the warning silenced by using ``Date(allow_datetime=True)``; alternatively, you can use ``Date(allow_datetime=False)`` to adopt the Traits 7.0 behaviour right now. Detailed PR-by-PR changes ~~~~~~~~~~~~~~~~~~~~~~~~~ Over 80 pull requests went into this release. The following people contributed to the release: * 0xflotus * Aaron Ayres * Kit Choi * Mark Dickinson * Chigozie Nri * Poruri Sai Rahul * Corran Webster * John Wiggins * Peter Zahemszky Thank you to all who contributed! Features ~~~~~~~~ * The ``observe`` mini-language now supports use of ``"*"`` for listening to all traits on a ``HasTraits`` object. Currently this support is limited to cases where the ``"*"`` appears in a terminal position. For example, ``observe("foo:*")`` is supported, but ``observe("*:foo")`` is not. (#1496, #1525) * The ``Any`` trait type now supports a ``factory`` argument (with accompanying ``args`` and ``kw`` arguments). This can be used to specify a per-instance default, for example with ``Any(factory=dict)``. (#1557, #1558) * The ``DefaultValue`` enumeration has a new member ``DefaultValue.disallow`` intended to be used for trait types that don't have a meaningful default. For traits using this default value type, an attempt to retrieve the corresponding default using ``default_value_for`` will raise ``ValueError``. (#1546) * When a method is decorated with an ``observe`` decorator, the method signature is now checked, and a warning issued if it doesn't match the expected signature. This should catch the common error of forgetting to provide the ``event`` parameter. (#1529) * In ``ETSToolkit``, the ``"qt"`` toolkit name is now supported as a synonym for ``"qt4"``. (#1436) * The ``Date``, ``Datetime`` and ``Time`` trait types have a new argument ``allow_none``. In the future, these trait types will not accept ``None`` unless ``allow_none=True`` is specified. (#1432) * The ``Date`` trait type has a new argument ``allow_datetime``. In the future, ``datetime`` instances will not be valid values for a ``Date`` trait unless ``allow_datetime=True`` is specified. (#1429) Performance ~~~~~~~~~~~ * The ``ObserverGraph`` instances that result from compiling ``ObserverExpression`` objects and observe mini-language strings are now cached. This should speed up creation and instantiation of ``HasTraits`` subclasses that involve listening for the same pattern in multiple places. (#1516, #1528) * The equality definition on ``ObserverExpression`` has been simplified. (#1517) * The ``ObserverExpression``, ``ObserverGraph`` and related classes now use ``__slots__`` to improve speed and memory use. (#1513, #1515) * The ``on_trait_change`` method has been sped up by almost a factor of two, by removing unnecessary internal usage of Traits in the parsing and listener functionality. (#1490, #1491, #1492, #1493) Changes ~~~~~~~ * An invalid static default value in a ``PrefixList`` or ``PrefixMap`` trait declaration now raises ``ValueError`` rather than ``TraitError``. (#1564) * ``PrefixList`` and ``PrefixMap`` no longer cache completions. (#1564) * A failure to parse an ``observe`` mini-language string now raises ``ValueError`` rather than ``LarkError``. (#1507) * The ``NotifierNotFound`` exception is now published in ``traits.observation.api``. (#1498) * An attempt to access a nonexistent "dunder" attribute (an attribute whose name starts and ends with "__") on a ``CTrait`` instance will now raise ``AttributeError``. Previously, it would return ``None``. (#1469, #1474, #1477) Deprecations ~~~~~~~~~~~~ * The ``Any`` trait type currently implicitly makes a per-``HasTraits``-instance copy of the default value if that value is an instance of either ``list`` or ``dict``. This behaviour is deprecated, and will be removed in Traits 7.0. For a per-instance default, use the new ``factory`` argument to ``Any`` instead. (#1548, #1532) * The ``Date``, ``Datetime`` and ``Time`` trait types will no longer accept ``None`` as a valid trait value in the future. To keep the existing behaviour, use the new ``allow_none`` keyword argument to these trait types. (#1444) * The ``Date`` trait type will no longer accept ``datetime`` instances by default in the future. To keep the existing behaviour, use the new ``allow_datetime`` keyword argument. (#1441) * The ``Symbol`` trait type is deprecated. For resolution of a string representing a package/module/object combination, use ``import_symbol`` instead. (#1542) * The ``MetaHasTraits.add_listener`` and ``MetaHasTraits.remove_listener`` methods are deprecated. (#1550) * The ``clean_filename`` and ``clean_timestamp`` utilities are deprecated. If you need these utilities in your own project, you're advised to copy the code directly into your project. (#1527) * The ``find_resource`` and ``store_resource`` functions are deprecated. New code should use ``importlib.resources`` or ``importlib_resources`` instead of either of these functions. (#1501) Fixes ~~~~~ * Invalid assignments to ``PrefixList`` and ``PrefixMap`` traits produced an unnecessarily nested exception. This has been fixed. (#1564) * An ``observe``-decorated listener method whose name has the special form ``"_traitname_changed"`` will no longer be triggered both as as result of the ``observe`` decorator *and* the special naming: it will only be triggered via the ``observe`` decorator. (#1560) * The ``delegate`` parameter was mistyped in the typing stubs for the ``Delegate`` trait type. This has been fixed. (#1556) * The ``Function`` and ``Method`` trait types will no longer fail when arguments are passed. Note that these trait types are already deprecated, and should not be used in new code. (#1543) * Inner traits of a ``Union`` trait are now validated properly. Previously, in trait declarations like ``foo = Union(List(Int), Str)``, the list entries would not be validated. (#1522, #1534) * Traits with a dynamic default that appear as inner traits of a ``Tuple`` trait are now validated properly. (#1521) * A potential race condition in ``ListenerHandler`` has been fixed. The race condition is hard to exercise and has not been witnessed in the wild. (#1495) * Use of ``add_class_trait`` to add a ``List`` trait was broken in the presence of subclasses. This has been fixed. (#1461) * A use of the (deprecated) ``distutils`` library has been replaced with ``sysconfig``. (#1452) * Dynamic default handing has been fixed in the ``_instance_handler_factory`` used by the TraitsUI ``TableEditor``. (#1446, #1450) * The trait descriptions (the "info" text) for the ``File`` and ``Directory`` traits have been fixed to avoid giving a misleading error message when ``exists=True``. (#1440) * Clones of ``BaseInstance`` traits didn't correctly respect the ``allow_none`` parameter. This is now fixed. (#1433) * An outdated reference to the "pyglet" Kiva backend has been removed. (#1431) Documentation ~~~~~~~~~~~~~ * Brief installation docs have been added. (#1559) * Occurrences of ``Any(some_list)`` in docs have been replaced. (#1547) * The documentation for ``sync_trait`` has been updated to note that it only synchronises items for ``List`` traits, not for ``Dict`` and ``Set`` traits. (#1519) * A configuration file for Read the Docs has been added. (#1478) * A ``DeprecationWarning`` arising from an unnecessary override of the ``add_content`` method in the ``TraitDocumenter`` has been fixed. (#1475) * The Sphinx version was temporarily pinned to avoid build failures arising from bugs in Sphinx 4.0.1. That pin has since been reverted. (#1471, #1462) * Various docstring fixes have been applied. (#1468, #1465) * Various typo fixes have been applied. (#1458, #1442) * References to ``HasTraits.set`` have been replaced with ``HasTraits.trait_set``. (#1451) * Some issues with the tutorial CSS used in the ETS demo application have been fixed; the colour scheme has been changed to Enthought colours. (#1421, #1419) Cleanup and refactoring ~~~~~~~~~~~~~~~~~~~~~~~ * All built-in TraitType subclasses now provide the default value type directly rather than inferring it. (#1555, #1536, #1531, #1539, #1532, #1540) * The ``trait_added`` and ``trait_modified`` traits on ``HasTraits`` now have proper trait type declarations. (#1552) * Redundant ``unittest.main blocks`` have been removed. (#1545) * Style fixes have been applied to ``trait_types.pyi``. (#1523) * ``ObserverExpression`` and other key observation classes now have more debug-friendly ``repr`` implementations. (#1514) * The ``observer`` parsing internals have been reworked to make ``ObserverGraph`` the key "compiled" object that the rest of Traits cares about, rather than ``ObserverExpression``. (#1512) * The grammar and parser for the observe mini-language have been simplified. (#1506) * Confusion between "any_trait" and "anytrait" in non-user-facing functions and classes has been cleaned up. (#1497) * Unnecessary ``noqa`` markers have been removed. (#1499) * A use of the ``property`` callable has been replaced with a ``property`` decorator. (#1470) * A bad observe-decorated listener signature in a test has been fixed. (#1530) Build and development workflow ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Python 3.10 is supported and tested, and wheels are built for Python 3.10. (#1425, #1567, #1569, #1571) * Wheels are now built for Linux/aarch64. (#1567) * Universal wheels are now built for macOS, to support Apple Silicon. (#1567) * Cron jobs now send failure/success Slack notifications to Enthought's internal channel. (#1481) * All cron jobs now include a ``workflow_dispatch`` trigger. (#1480) * The main development branch is now called "main" rather than "master". (#1467) * Automated tests have been added for PyPI wheels. (#1417) Release 6.2.0 ------------- Released: 2021-01-21 The Traits library is a foundational component of the Enthought Tool Suite. It provides observable, typed attributes for Python classes, making those classes suitable for event-driven dataflow programming and for immediate use as models for graphical user interfaces, like those provided by the TraitsUI library. Traits 6.2 is the latest feature release in the Traits 6 series, with several improvements and fixes over Traits 6.1. Highlights of this release ~~~~~~~~~~~~~~~~~~~~~~~~~~ * The Traits examples are now distributed as part of the Traits egg, and are contributed to the ``etsdemo`` application. (The latter can be installed from PyPI with ``pip install etsdemo``.) * Performance of the ``observe`` framework has been significantly improved. * It's no longer necessary to specify a trait comparison mode of ``ComparisonMode.identity`` when using ``observe`` to observe items in a ``List``, ``Dict`` or ``Set``. * Support for Python 3.5 has been dropped. * When importing from Traits, you should always import from one of the ``api`` modules (for example, ``traits.api``, ``traits.adaptation.api``, etc.) This recommendation has now been made explicit in the documentation. If you find something you need that's not available from one of the ``api`` modules, please let the Traits developers know. Detailed PR-by-PR changes ~~~~~~~~~~~~~~~~~~~~~~~~~ More than 60 PRs went into this release. The following people contributed to this release: * Aaron Ayres * Alexandre Chabot-Leclerc * Kit Choi * Mark Dickinson * Kevin Duff * Glen Granzow * Matt Hancock * Rahul Poruri * Eric Prestat * Kuya Takami * Hugo van Kemenade * Aditya Vats * Corran Webster Features ~~~~~~~~ * The ``Property`` trait type now supports the ``observe`` keyword. (#1175, #1400) * Add ``|=`` support to TraitDict for Python 3.9 and later. (#1306) * Add casting keyword to numeric array types. (#547) * The Traits examples are now part of the Traits package, and so are contributed to ``etsdemo``. (#1275) * The Traits examples package now includes a beginner's tutorial. (#1061) Performance ~~~~~~~~~~~ * Parsing of the ``observe`` string was previously a performance bottleneck. This has been fixed, by removing some redundant parsing calls and by caching parsing results. (#1343, #1344, #1345) Changes ~~~~~~~ * The ``NoDefaultSpecified`` constant (used as a default value for the ``TraitType`` ``default_value`` argument) is now public, made available from ``traits.api``. (#1384, #1380, #1378) * The deprecation of the ``TraitMap`` trait type has been reversed, because there are existing uses of ``TraitMap`` that are hard to replace. Nevertheless, it is still not recommended to use ``TraitMap`` in new code. Use ``Map`` instead. (#1365) * An attempt to use ``PrefixList`` with an empty list, or ``PrefixMap`` or ``Map`` with an empty dictionary, now raises ``ValueError``. As a result, the default default value (which used to be ``None``) is always valid. (#1351) * ``TraitListEvent`` arguments are now keyword only. (#1346) * It's no longer necessary to specify a trait comparison mode of ``ComparisonMode.identity`` when using ``observe`` to observe items in a ``List``, ``Dict`` or ``Set``. (#1165, #1328, #1240) Deprecations ~~~~~~~~~~~~ * The ``Function`` and ``Method`` trait types are deprecated. Use ``Callable`` or ``Instance`` instead. (#1399, #1397) * The ``edit`` parameter to ``configure_traits`` has been deprecated. (#1311) * The ``UnittestTools._catch_warnings`` function has been deprecated. (#1310) * The use of the ``CHECK_INTERFACES`` global variable for automated interface checking has been deprecated. (#1231) Fixes ~~~~~ * Non-``TraitError`` exceptions raised during ``Tuple`` validation are now propagated. Previously they were converted into ``TraitError``. (#1393) * Dynamic ``Range`` and ``Enum`` traits are now properly validated when inside a container (for example ``Tuple`` or ``List``). Previously no validation was performed. (#1388, #1392) * Remove the unused module-level constant ``traits.has_traits.EmptyList``. (#1366) * Don't hard-code class names in ``__repr__`` implementations of ``TraitListEvent``, ``TraitSetEvent`` and ``TraitDictEvent``. (#1335) * Don't notify on empty ``update``\ s of ``Dict`` traits. (#1308) * Fix exception raised when assigning a NumPy array to a ``List`` trait. (#1278) * Fix uses of deprecated ``logger.warn`` function. (#1283) * Fix a bad ``Instance`` trait declaration for a private trait in the ``_TraitChangeCollector`` class. (#1411) Documentation ~~~~~~~~~~~~~ * Add "Tutorial" section to the main documentation, based on the new ``traits.examples`` tutorial content. (#1374) * Clarify that only the ``api`` modules should be used for imports. (#1387) * Update copyright header end years. (#1376) * Update contents of ``image_LICENSE.txt``. (#1362) * Remove mentions of the removed functions ``adapts`` and ``implements`` from the examples and tutorial. (#1367) * Move Traits introduction description to ``index.rst``. (#1358) * Fix path to Enthought logo when building docset. (#1285) * Fix the ``trait_documenter`` extension to be less fragile. (#1247) * Add user manual documentation for the ``Instance`` trait type. (#1395) * Document that the ``List``, ``Dict`` and ``Set`` trait types copy on assignment. (#1402) * Various other minor improvements, typo fixes, and other documentation fixes. (#1396, #1383, #1381, #1384, #1292, #1355, #1350, #1319, #1292, #1401) Cleanup and other maintenance ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Remove dead code. (#1281) * Update ``super`` usage to the usual Python 3 argument-less pattern. (#1280) * Remove per-import ``# noqa`` comments in ``api`` modules in favour of per-file ignores in the ``flake8`` configuration. (#1269) * Remove out-of-date and non-functional coverage badge from README. (#1263) * Rename ``_i_observable`` module to ``i_observable``. (#1296) * Refactor and simplify method checks. (#1176) * Fix typo in optional_dependencies comment. (#1235) * Use ComparisonMode constants instead of magic numbers. (#1229) Test suite ~~~~~~~~~~ * Prevent test_enum failures if traitsui or GUI toolkit are not installed. (#1349) * Tests that require ``pkg_resources`` are skipped if ``setuptools`` is not installed. (#1301) * Fix an order-dependency bug in the ``test_subclasses_weakref`` regression test. (#1290) * Fix a typo in a test method name. (#1309) * Various additional or improved tests for existing code. (#1359, #1336, #1330, #1248, #1225, #1208, #1209) Build and development workflow changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Traits now uses GitHub Actions for continuous integration. The Travis CI and Appveyor configurations have been removed. (#1296, #1360) * CI runs are no longer based on EDM. (#878) * New CI run for the core test suite, without any optional dependencies. (#1314) * Test Python 3.9 in the continuous integration (and drop tests for Python 3.5 and older). (#1326, #1313, , #1303) * Make ``traits.examples`` into a package. (#1348) * Make examples directories ``flake8``-clean. (#1353) * Fix examples packaging nit. (#1363) * Support ``-h`` for getting help in ``etstool.py``. (#1347) * Add ``shell`` command to ``etstool.py``. (#1293) * Use the ``flake8_ets`` package in place of the local ``copyright_header`` package. The ``copyright_header`` package has been removed. (#1341) * Add script ``check_observe_timing.py`` to benchmark performance of ``observe`` to compare with ``on_trait_change``. (#1331) * Correct the minimum Sphinx version in README. (#1216, #1320) * Restrict Sphinx version to avoid buggy versions. (#1276) * Make ``mypy`` an optional dependency. (#1289) * Speed up CI builds for Travis and Appveyor by caching the ``pip`` directory (now redundant). (#1241) * Add automated wheel and sdist building for Traits releases. (#1404, #1291) * Add cron-job workflow to regularly test install of the latest releases from PyPI. (#1406) Release 6.1.1 ------------- Released: 2020-07-23 Traits 6.1.1 is a bugfix release fixing a handful of minor documentation and test-related issues with the Traits 6.1.0 release. There are no API-breaking changes in this release. It's recommended that all users of Traits 6.1.0 upgrade to Traits 6.1.1. Fixes ~~~~~ * Don't mutate global state at import time in a test module. (#1222) * Standardize and fix copyright years in source files. (#1227, #1198) * Fix trait-documenter extension tests for Sphinx 3.1. (#1206) * Fix trait-documenter extension to handle properties correctly. (#1246) Documentation fixes ~~~~~~~~~~~~~~~~~~~ * Expand user manual to mention dispatch. (#1195) * Fix some spelling and grammar errors in the user manual. (#1210) * Fix description in README to match the one in the setup script. (#1219) * Update PyPI links and capitalization in README.rst. (#1250) * Fix user manual mentioning a nonexisting feature in metadata filter. (#1207) * Fix typo in comment in optional_dependencies. (#1235) Release 6.1.0 ------------- Released: 2020-06-05 The Traits library is a foundational component of the Enthought Tool Suite. It provides observable, typed attributes for Python classes, making those classes suitable for event-driven dataflow programming and for immediate use as models for graphical user interfaces, like those provided by the TraitsUI library. Traits 6.1 is the latest feature release in the Traits 6 series, and contains several major improvements. Highlights of this release ~~~~~~~~~~~~~~~~~~~~~~~~~~ * A new :mod:`observation ` framework for observing traited attributes and other observable objects has been introduced. This is intended to provide a full replacement for the existing :func:`on_trait_change` mechanism, and aims to fix a number of fundamental flaws and limitations of that mechanism. See the :ref:`observe-notification` section of the user manual for an introduction to this framework. * New :class:`~traits.trait_list_object.TraitList`, :class:`~traits.trait_dict_object.TraitDict` and :class:`~traits.trait_set_object.TraitSet` classes have been added, subclassing Python's built-in :class:`python:list`, :class:`python:dict` and :class:`python:set` (respectively). Instances of these classes are observable objects in their own right, and it's possible to attach observers to them directly. These classes were primarily introduced to support the new observation framework, and are not expected to be used directly. The API for these objects and their notification system is provisional, and may change in a future Traits release. * A new :class:`.Union` trait type has been added. This is intended as a simpler replacement for the existing :class:`.Either` trait type, which will eventually be deprecated. * New :class:`.PrefixList`, :class:`.PrefixMap` and :class:`.Map` trait types have been added. These replace the existing :class:`.TraitPrefixList`, :class:`.TraitPrefixMap` and :class:`.TraitMap` subclasses of :class:`.TraitHandler`, which are deprecated. * Typing stubs for the Traits library have been added in a ``traits-stubs`` package, which will be released separately to PyPI. This should help support Traits-using projects that want to make use of type annotations and type checkers like `mypy `_. Notes on upgrading ~~~~~~~~~~~~~~~~~~ As far as possible, Traits 6.1 is backwards compatible with Traits 6.0. However, there are a few things to be aware of when upgrading. * Traits 6.1 is not compatible with TraitsUI versions older than TraitsUI 7.0. A combination of Traits 6.1 or later with TraitsUI 6.x or earlier will fail to properly recognise :class:`~traitsui.view.View` class variables as TraitsUI views, and an error will be raised if you attempt to create a TraitsUI view. * Traits now does no logging configuration at all, leaving all such configuration to the application. In more detail: trait notification handlers should not raise exceptions in normal use, so an exception is logged whenever a trait notification handler raises. This part of the behaviour has not changed. What *has* changed is the way that logged exception is handled under default exception handling. Previously, Traits added a :class:`~logging.StreamHandler` to the top-level ``"traits"`` logger, so that trait notification exceptions would always be visible. Traits also added a :class:`~logging.NullHandler` to that logger. Both of those handlers have now been removed. We now rely on Python's "handler of last resort", which will continue to make notification exceptions to the user visible in the absence of any application-level log configuration. * When listening for changes to the items of a :class:`.List` trait, an index or slice set operation no longer performs an equality check between the replaced elements and the replacement elements when deciding whether to issue a notification; instead, a notification is always issued if at least one element was replaced. For example, consider the following class:: class Selection(HasTraits): indices = List(Int) @on_trait_change("indices_items") def report_change(self, event): print("Indices changed: ", event) When replacing the `8` with the same integer, we get this behavior:: >>> selection = Selection(indices=[2, 5, 8]) >>> selection.indices[2] = 8 Indices changed: TraitListEvent(index=2, removed=[8], added=[8]) Previously, no notification would have been issued. * The :func:`.Color`, :func:`.RGBColor` and :func:`.Font` trait factories have moved to TraitsUI, and should be imported from there rather than from Traits. For backwards compatibility, the factories are still available in Traits, but they are deprecated and will eventually be removed. * As a reminder, the :data:`.Unicode` and :data:`.Long` trait types are deprecated since Traits 6.0. Please replace uses with :class:`.Str` and :class:`.Int` respectively. To avoid excessive noise in Traits-using projects, Traits does not yet issue deprecation warnings for existing uses of :data:`.Unicode` and :data:`.Long`. Those warnings will be introduced in a future Traits release, prior to the removal of these trait types. Pending deprecations ~~~~~~~~~~~~~~~~~~~~ In addition to the deprecations listed in the changelog below, some parts of the Traits library are not yet formally deprecated, but are likely to be deprecated before Traits 7.0. Users should be aware of the following possible future changes: * The :class:`.Either` trait type will eventually be deprecated. Where possible, use :class:`.Union` instead. When replacing uses of :class:`.Either` with :class:`.Union`, note that there are some significant API and behavioral differences between the two trait types, particularly with respect to handling of defaults. See :ref:`migration_either_to_union` for more details. * The ``trait_modified`` event trait that's present on all :class:`.HasTraits` subclasses will eventually be removed. Users should not rely on it being present in an object's ``class_traits`` dictionary. * Trait names starting with ``trait``, ``traits``, ``_trait`` or ``_traits`` may become reserved for use by ETS at some point in the future. Avoid using these names for your own traits. Detailed PR-by-PR changes ~~~~~~~~~~~~~~~~~~~~~~~~~ More than 160 PRs went into this release. The following people contributed code changes for this release: * Ieva Cernyte * Kit Yan Choi * Maxime Costalonga * Mark Dickinson * Matt Hancock * Midhun Madhusoodanan * Shoeb Mohammed * Franklin Ventura * Corran Webster Features ~~~~~~~~ * Add ``os.PathLike`` support for ``Directory`` traits. (#867) * Add ``Union`` trait type. (#779, #1103, #1107, #1116, #1115) * Add ``PrefixList`` trait type. (#871, #1142, #1144, #1147) * Add ``allow_none`` flag for ``Callable`` trait. (#885) * Add support for type annotation. (#904, #1064) * Allow mutable values in ``Constant`` trait. (#929) * Add ``Map`` and ``PrefixMap`` trait types. (#886, #953, #956, #970, #1139, #1189) * Add ``TraitList`` as the base list object that can perform validation and emit change notifications. (#912, #981, #984, #989, #999, #1003, #1011, #1026, #1009, #1040, #1172, #1173) * Add ``TraitDict`` as the base dict object that can perform validation and emit change notifications. (#913) * Add ``TraitSet`` as the base set object that can perform validation and emit change notifications. (#922, #1043) * Implement ``observe`` to supersede ``on_trait_change`` for observing trait changes. (#976, #1000, #1007, #1065, #1023, #1066, #1070, #1069, #1067, #1080, #1082, #1079, #1071, #1072, #1075, #1085, #1089, #1078, #1093, #1086, #1077, #1095, #1102, #1108, #1110, #1112, #1117, #1118, #1123, #1125, #1126, #1128, #1129, #1135, #1156) Changes ~~~~~~~ * GUI applications using Traits 6.1 will require TraitsUI >= 7.0. (#1134) * ``TraitSetEvent`` and ``TraitDictEvent`` initialization arguments are now keyword-only. (#1036) * ``TraitListObject`` will no longer skip notifications even if mutations result in content that compares equally to the old values. (#1026) * ``TraitListEvent.index`` reported by mutations to a list is now normalized. (#1009) * The default notification error handler for Traits no longer configures logging, and the top-level ``NullHandler`` log handler has been removed. (#1161) Fixes ~~~~~ * Allow assigning None to ``CTrait.post_setattr``. (#833) * Fix reference count error. (#907) * Improve ``HasTraits`` introspection with ``dir()``. (#927) * Fix the datetime-to-str converters used in ``DatetimeEditor``. (#937) * Raise ``TraitNotificationError`` on trailing comma in ``on_trait_change``. (#926) * Fix exception swallowing by Trait attribute access. (#959, #960) * Allow collections in valid values for ``Enum`` trait. (#889) * Fix ``TraitError`` when mutating a list/dict/set inside another container. (#1018) * Fix setting default values via dynamic default methods or overriding trait in subclasses for mapped traits, used by ``Map``, ``Expression``, ``PrefixMap``. (#1091, #1188) * Fix setting default values via dynamic default methods or overriding trait in subclasses for ``Expression`` and ``AdaptsTo``. (#1088, #1119, #1152) Deprecations ~~~~~~~~~~~~ * ``traits.testing.nose_tools`` is deprecated. (#880) * ``SingletonHasTraits``, ``SingletonHasStrictTraits`` and ``SingletonHasPrivateTraits`` are deprecated. (#887) * ``TraitMap`` is deprecated, use ``Map`` instead. (#974) * ``TraitPrefixMap`` is deprecated, use ``PrefixMap`` instead. (#974) * ``TraitPrefixList`` is deprecated, use ``PrefixList``. (#974) * ``Color``, ``RBGColor`` and ``Font`` are now deprecated. Use the ones from TraitsUI instead. (#1022) Removals ~~~~~~~~ * ``traits_super`` is removed. (#1015) Documentation ~~~~~~~~~~~~~ * Add details on creating custom trait properties. (#387) * Cross reference special handler signatures for listening to nested attributes in list and dict. (#894) * Replace 'Traits 5' with 'Traits 6' in the documentation. (#903) * Use major.minor version in documentation. (#1124) * Add initial documentation on Traits internals. (#958) * Fix example class ``OddInt``. (#973) * Add Dos and Donts for writing change handlers. (#1017) * Clarify when default initializer is called and when handlers are registered. (#1019) * Fix documentation rendering issues and front matter. (#1039, #1053) * Clarify when dynamic default values are considered to have existed. (#1068) * Expand user manual on container traits and objects. (#1058) * Add intersphinx support to configuration. (#1136) * Add user manual section on the new ``observe`` notification system. (#1060, #1140, #1143) * Add user manual section on the ``Union`` trait type and how to migrate from ``Either`` (#779, #1153, #1162) * Other minor cleanups and fixes. (#949, #1141, #1178) Test suite ~~~~~~~~~~ * Allow tests to be skipped if TraitsUI is not installed. (#1038) * Add ``extras_require`` entry for testing. (#879) * Add tests for parsing ``on_trait_change`` mini-language. (#921) * Fix a missing import to allow a test module to be run standalone. (#961) * Add a GUI test for ``Enum.create_editor``. (#988) * Fix some module-level ``DeprecationWarning`` messages. (#1157) Build and continuous integration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * CI no longer runs on Python 3.5 (#1044) * Add configobj dependency and remove remaining 3.5 references in ``etstool.py``. (#1051) * Codecov reports are no longer retrieved for pull requests. (#1109) * CI tests requiring a GUI are now run against PyQt5 rather than PyQt4. (#1127) * Add Slack notifications for CI. (#1074) * Fix and improve various ``setup.py`` package metadata fields. (#1185) Maintenance and code organization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Refactor CHasTraits ``traits_inited`` method. (#842) * Add support for prerelease section in version. (#864) * Rename comparison mode integer constants in ``ctraits.c``. (#862) * Follow best practices when opening files. (#872) * Initialize ``cTrait`` ``getattr``, ``setattr`` handlers in ``tp_new``. (#875) * Check ``trait_change_notify`` early in ``call_notifiers``. (#917) * Refactor ``ctraits.c`` for calling trait and object notifiers. (#918) * ``BaseEnum`` and ``Enum`` fixes and cleanup. (#968) * Split ``ctraits`` property api to ``_set_property`` and ``_get_property``. (#967) * Fix overcomplicated ``__deepcopy__`` implementation. (#992) * Add ``__repr__`` implementation for ``TraitListEvent``, ``TraitDictEvent`` and ``TraitSetEvent``. (#1006, #1148, #1149) * Remove caching of editor factories. (#1032) * Remove conditional traitsui imports. (#1033) * Remove code duplication in ``tutor.py``. (#1034) * Fix correctness in ``Enum`` default traitsui editor. (#1012) * Use ``NULL`` for zero-argument ``PyObject_CallMethod`` format. (#1100) * Miscellaneous other minor fixes, refactorings and cleanups. (#874, #882, #915, #920, #923, #924, #935, #939, #944, #950, #964) Release 6.0.0 ------------- Released: 2020-02-14 No changes since the 6.0.0rc0 release candidate. Release 6.0.0rc0 ---------------- Released: 2020-01-30 Release notes ~~~~~~~~~~~~~ Traits 6.0 is a major update to the Traits package, with a number of backward incompatible changes from its predecessor. Notable changes: * Python 2.7 is no longer supported; Traits 6.0 requires Python 3.5 or later. * Trait types related to Python 2 (for example ``Unicode`` and ``Long``) have been deprecated in favour of their Python 3 equivalents (for example ``Str`` and ``Int``). * Many little-used historical features of Traits have been deprecated, and are scheduled for removal in Traits 7.0. * Some historical features of Traits that had no evidence of external usage were removed in Traits 6.0. * Introspection of ``CTrait`` and ``HasTraits`` objects is greatly improved. All of the internal state that was previously hidden within the C extension is now accessible from Python. * The Traits codebase has undergone some significant reorganizations, reformattings and style cleanups to make it easier to work with, and to improve the separation between Traits and TraitsUI. * This release was focused mainly on cleanup and bugfixing. Nevertheless, it contains a sprinkling of new features. There's a new ``Datetime`` trait type. The ``Enum`` trait type now supports Python enumerations. The ``File`` trait type supports path-like objects. More than 150 PRs went into this release. The following people contributed code changes for this release: * Kit Yan Choi * Mark Dickinson * Kevin Duff * Robert Kern * Midhun Madhusoodanan * Shoeb Mohammed * Sai Rahul Poruri * Corran Webster * John Wiggins Porting guide ~~~~~~~~~~~~~ For the most part, existing code that works with Traits 5.2.0 should continue to work with Traits 6.0.0 without changes. However, there are some potentially breaking changes in Traits 6.0.0, and we recommend applying caution when upgrading. Here's a guide to dealing with some of the potentially breaking changes. * The ``Unicode`` and ``CUnicode`` trait types are now simply synonyms for ``Str`` and ``CStr``. ``Unicode`` and ``CUnicode`` are considered deprecated. For now, no deprecation warning is issued on use of these deprecated trait types, but in Traits 6.1.0 and later, warnings may be issued, and in Traits 7.0.0 these trait types may be removed. It's recommended that users update all uses of ``Unicode`` to ``Str`` and ``CUnicode`` to ``CStr`` to avoid warnings or errors in the future. * Similarly, ``Long`` and ``CLong`` are now synonyms for ``Int`` and ``CInt``. The same recommendations apply as for the ``Unicode`` / ``Str`` trait types. * Uses of ``NO_COMPARE``, ``OBJECT_IDENTITY_COMPARE`` and ``RICH_COMPARE`` should be replaced with the appropriate ``ComparisonMode`` enumeration members. * The validation for a ``Instance(ISomeInterface)`` trait type has changed, where ``ISomeInterface`` is a subclass of ``Interface``. Previously, an assignment to such a trait validated the type of the assigned value against the interface, method by method. Now an ``isinstance`` check is performed against the interface instead. Make sure that classes implementing a given interface have the appropriate ``provides`` decorator. One notable side-effect of the above change is that plain ``mock.Mock`` instances can no longer be assigned to ``Instance(ISomeInterface)`` traits. To get around this, use ``spec=ISomeInterface`` when creating your mock object. This change does not affect ``Instance`` traits for non-interface classes. * The format of ``TraitListEvents`` has changed: for list events generated from a slice set or slice delete operation where that slice had a step other than ``1``, the ``added`` and ``removed`` fields of the event had an extra level of list wrapping (for example, ``added`` might be ``[[1, 2, 3]]`` instead of ``[1, 2, 3]``). In Traits 6.0, this extra wrapping has been removed. There may be existing code that special-cased the extra wrapping. * Many classes and functions have moved around within the Traits codebase. If you have code that imports directly from Traits modules and subpackages instead of from ``traits.api`` or the other subpackage ``api`` modules, some of those imports may fail. To avoid potential for ``ImportError``s, you should import from ``traits.api`` whenever possible. If you find yourself needing some piece of Traits functionality that isn't exposed in ``traits.api``, and you think it should be, please open an issue on the Traits bug tracker. Features ~~~~~~~~ * Add new ``Datetime`` trait type. (#737, #814, #813, #815, #848) * Support Python Enums as value sets for the ``Enum`` trait. (#685, #828, #855) * Add ``Subclass`` alias for the ``Type`` trait type. (#739) * Add path-like support for the ``File`` trait. (#736) * Add new ``ComparisonMode`` enumeration type to replace the old ``NO_COMPARE``, ``OBJECT_IDENTITY_COMPARE`` and ``RICH_COMPARE`` constants. The old constants are deprecated. (#830, #719, #680) * Add fast validation for ``Callable`` trait type; introduce new ``BaseCallable`` trait type for subclassing purposes. (#798, #795, #767) * Add ``CTrait.comparison_mode`` property to allow inspection and modification of a trait's comparison mode. (#758, #735) * Add ``as_ctrait`` converter function to ``traits.api``. This function converts a trait-like object or type to a ``CTrait``, raising ``TypeError`` for objects that can't be interpreted as a ``CTrait``. It's intended for use by users who want to create their own parameterised trait types. The ``as_ctrait`` feature comes with, and relies upon, a new informal interface: objects that can be converted to something of type ``CTrait`` can provide an zero-argument ``as_ctrait`` method that returns a new ``CTrait``. Types can provide an ``instantiate_and_get_ctrait`` method, which when called with no arguments provides a new ``CTrait`` for that type. (#783, #794) * Add a new ``HasTraits._class_traits`` method for introspection of an object's class traits. This parallels the existing ``HasTraits._instance_traits`` method. This method is intended for use in debugging. It's not recommended for users to modify the returned dictionary. (#702) * Add ``CTrait.set_default_value`` method for setting information about the default of a ``CTrait``. This provides an alternative to the previous method of using ``CTrait.default_value``. The use of ``CTrait.default_value`` to set (rather than get) default information is deprecated. (#620) * Add new methods ``HasTraits._trait_notifications_enabled``, ``HasTraits._trait_notifications_vetoed`` to allow introspection of the notifications states set by the existing methods ``HasTraits._trait_change_notify`` and ``HasTraits._trait_veto_notify``. (#704) * Add ``TraitKind``, ``ValidateTrait`` and ``DefaultValue`` Python enumeration types to replace previous uses of magic integers within the Traits codebase. (#680, #857) * The various ``CTrait`` internal flags are now exposed to Python as properties: ``CTrait.is_property`` (read-only), ``CTrait.modify_delegate``, ``CTrait.setattr_original_value``, ``CTrait.post_setattr_original_value``, ``CTrait.is_mapped``, and ``CTrait.comparison_mode``. (#666, #693) Changes ~~~~~~~ * When pickling a ``CTrait``, the ``py_post_setattr`` and ``py_validate`` fields are pickled directly. Previously, callables for those fields were replaced with a ``-1`` sentinel on pickling. (#780) * A ``TraitListEvent`` is no longer emitted for a slice deletion which doesn't change the contents of the list. (For example, `del obj.mylist[2:]` on a list that only has 2 elements.) (#740) * The ``added`` and ``removed`` attributes on a ``TraitListEvent`` are now always lists containing the added or removed elements. Previously, those lists were nested inside another list in some cases. (#771) * Change ``Instance(ISomeInterface)`` to use an ``isinstance`` check on trait set instead of using the dynamic interface checker. (#630) * Create an new ``AbstractViewElement`` abstract base class, and register the TraitsUI ``ViewElement`` as implementing it. This paves the way for removal of Traits UI imports from Traits. (#617) * ``ViewElements`` are now computed lazily, instead of at ``HasTraits`` subclass creation time. This removes a ``traitsui`` import from the ``trait.has_traits`` module. (#614) * The ``traits.util.clean_filename`` utility now uses a different algorithm, and should do a better job with accented and Unicode text. (#589) * Floating-point and integer checks are now more consistent between classes. In particular, ``BaseInt`` validation now matches ``Int`` validation, and ``Range`` type checks now match those used in ``Int`` and ``Float``. (#588) * An exception other than ``TraitError`` raised during validation of a compound trait will now be propagated. Previously, that exception would be swallowed. (#581) * Traits no longer has a runtime dependency on the ``six`` package. (#638) * Use pickle protocol 3 instead of pickle protocol 1 when writing pickled object state to a file in ``configure_traits``. (#796) * In ``traits.testing.optional_dependencies``, make sure ``traitsui.api`` is available whenever ``traitsui`` is. (#616) * ``TraitInstance`` now inherits directly from ``TraitHandler`` instead of (the now removed) ``ThisClass``. (#761) Fixes ~~~~~ * Fix a use of the unsupported ``ValidateTrait.int_range``. (#805) * Remove unnecessary ``copy`` method override from ``TraitSetObject``. (#759) * Fix ``TraitListObject.clear`` to issue the appropriate items event. (#732) * Fix confusing error message when ``[None]`` passed into ``List(This(allow_none=False))``. (#734) * Fix name-mangling of double-underscore private methods in classes whose name begins with an underscore. (#724) * Fix ``bytes_editor`` and ``password_editor`` bugs, and add tests for all editor factories. (#660) * Fix coercion fast validation type to do an exact type check instead of an instance check. This ensures that instances of subclasses of the target type are properly converted to the target type. For example, if ``True`` is assigned to a trait of type ``CInt``, the resulting value is now ``1``. Previously, it was ``True``. (#647) * Fix ``BaseRange`` to accept the same values as ``Range``. (#583) * Fix integer ``Range`` to accept integer-like objects. (#582) * Fix floating-point ``Range`` to accept float-like values. (#579) * Fix a missing import in the adaptation benchmark script. (#575) * Fix issues with the ``filename`` argument to ``configure_traits``. (#572) * Fix a possible segfault from careless field re-assignments in ``ctraits.c``. (#844) Deprecations ~~~~~~~~~~~~ * The ``NO_COMPARE``, ``OBJECT_IDENTITY_COMPARE`` and ``RICH_COMPARE`` constants are deprecated. Use the corresponding members of the ``ComparisonMode`` enumeration instead. (#719) * The ``Unicode``, ``CUnicode``, ``BaseUnicode`` and ``BaseCUnicode`` trait types are deprecated. Use ``Str``, ``CStr``, ``BaseStr`` and ``BaseCStr`` instead. (#648) * The ``Long``, ``CLong``, ``BaseLong`` and ``BaseCLong`` trait types are deprecated. Use ``Int``, ``CInt``, ``BaseInt`` and ``BaseCInt`` instead. (#645, #573) * The ``AdaptedTo`` trait type is deprecated. Use ``Supports`` instead. (#760) * The following trait type aliases are deprecated. See the documentation for recommended replacments. ``false``, ``true``, ``undefined``, ``ListInt``, ``ListFloat``, ``ListStr``, ``ListUnicode``, ``ListComplex``, ``ListBool``, ``ListFunction``, ``ListMethod``, ``ListThis``, ``DictStrAny``, ``DictStrStr``, ``DictStrInt``, ``DictStrFloat``, ``DictStrBool``, ``DictStrList``. (#627) * Use of the ``filename`` argument to ``configure_traits`` (for storing state to or restoring state from pickle files) is deprecated. (#792) * The ``TraitTuple``, ``TraitList`` and ``TraitDict`` trait handlers are deprecated. Use the ``Tuple``, ``List`` and ``Dict`` trait types instead. (#770) * Use of ``CTrait.default_value`` for setting default value information is deprecated. Use ``CTrait.set_default_value`` instead. (#620) * Use of the ``rich_compare`` trait metadata is deprecated. Use the ``comparison_mode`` metadata instead. (#598) Removals ~~~~~~~~ * Python 2 compatibility support code has been removed. (#638, #644) * Traits categories have been removed. (#568) * The following trait handlers have been removed: ``ThisClass``, ``TraitClass``, ``TraitExpression``, ``TraitCallable``, ``TraitString``, ``TraitRange``, ``TraitWeakRef``. (#782, #711, #699, #698, #625, #593, #587, #640) * ``CTrait.rich_compare`` has been removed. (#598) * The ``cTrait.cast`` method has been removed. (#663) * The magical ``TraitValue`` and associated machinery have been removed. (#658) * The ``Generic`` trait type has been removed. (#657) * The ``UStr`` trait type and ``HasUniqueStrings`` class have been removed. (#654) * The ``str_find`` and ``str_rfind`` helper functions have been removed. (#633) * The global ``_trait_notification_handler`` has been removed. (#619) * ``BaseTraitHandler.repr`` has been removed. (#599) * ``HasTraits.trait_monitor`` was undocumented, untested, and broken, and has been removed. (#570) * The ``TraitInstance`` trait handler (not to be confused with the ``Instance`` trait type) no longer supports adaptation. (#641) * The ``DynamicView`` and ``HasDynamicViews`` classes have been removed from Traits and moved to TraitsUI instead. (#609) * ``DictStrLong`` has been removed. (#573) Test suite ~~~~~~~~~~ * Fix various tests to be repeatable. (#802, #729) * Fix deprecation warnings in the test suite output. (#820, #804, #716) * Add machinery for testing unpickling of historical pickles. (#787) * Remove print statements from test suite. (#752, #768) * Fix a test to clean up the threads it creates. (#731) * Add tests for extended trait change issues #537 and #538 (#543) * Other minor test fixes. (#700, #821) Documentation ~~~~~~~~~~~~~ * Improve documentation of trait container objects. (#810) * Improve documentation for the ``traits.ctraits`` module. (#826, #824, #659, #653, #829, #836) * Fix badly formatted ``TraitHandler`` documentation. (#817) * Fix and improve badly formatted trait types documentation. (#843) * Fix broken module links in section titles in API documentation. (#823) * Additional class docstring fixes. (#854) * Add changelog to built documentation, and absorb old changelog into the new one. (#800, #799) * Remove deprecated traits from the user manual. (#656) * Fix various Sphinx warnings (#717) * Use SVG badges in README (#567) Build and continuous integration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Enable C asserts in Travis CI runs. (#791) * Abort CI on compiler warnings in Travis CI runs. (#769) * Run a ``flake8`` check in both Travis CI and Appveyor runs. (#753, #762) * Checking copyright statements in Python files as part of CI runs. (#749) * Turn warnings into errors when building documentation in CI. (#744) * Add ``gnureadline`` as a development dependency on macOS and Linux. (#607) * Add an ``etstool.py`` option to run tests quietly. (#606) * Enable the coverage extension for the documentation build. (#807) * Remove mocking in documentation configuration, and fix a deprecated configuration option. (#696) Maintenance and code organization ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This release includes a lot of refactoring and many minor improvements that will primarily benefit those working with the Traits codebase. These changes should not affect user-visible functionality. Here's a summary of the more significant changes. * A major refactor has removed most of the circular dependencies between modules. (#730) * The codebase is now mostly ``flake8`` clean. (#786, #753, #747, #748, #746, #595) * Copyright headers have been made consistent for all Python files. (#754) * ``ctraits.c`` has been run through ``clang-tidy`` and ``clang-format`` in order to bring it closer to PEP 7 style. (#715) * Editor factories have been moved into a new ``traits.editor_factories`` module, to help compartmentalize code dependencies on TraitsUI. (#661) * Trait container object classes (``TraitDictObject``, ``TraitListObject``, ``TraitSetObject``) have each been moved into their own module, along with their associated event type. (#677) * Miscellaneous other minor fixes, refactorings and cleanups. (#785, #777, #750, #726, #714, #712, #708, #701, #682, #665, #651, #652, #639, #636, #634, #626, #632, #611, #613, #612, #605, #603, #600, #597, #586, #585, #584, #580, #577, #578, #564, #806) Release 5.2.0 ------------- Released: 2019-11-18 Enhancements * Support installation from source archives. (#528) Fixes * Ensure ``TraitListEvent.index`` is always an integer. (#548) * Update the deprecated ``collections.MutableMapping`` import. (#530) * Fix inadvertent modification of the ``Category`` base class. (#509) * Rework version handling in ``setup.py``. (#515) * Don't autogenerate documentation for ``ViewElement``. (#559) * Ensure that all tests are ``unittest`` compatible. (#551) Changes * Replace occurences of deprecated ``AdaptsTo`` with ``Supports``. (#532) * Remove ``Class`` trait. (#520) * Deprecate ``Category`` trait. (#510) * Fix typos in docstrings. (#502) * Use decorator form of ``classmethod``. (#500) * Remove redefinition of ``NullHandler``. (#518) * Add an import check helper. (#521) * Clean up Cython tests. (#555) * Clean up test output. (#553) Miscellaneous * Update EDM version on CI to version 2.0.0. (#560) * Don't finish fast on CI. (#556) * Use ``unittest`` to run tests in CI. (#552) * Low-level fixes and style cleanup in ``etstool.py``. (#550) * Add ``--editable`` option for ``install``, ``update`` CI commands. (#546) * Make git commit hash available to archives. (#526) * Fix use of non-edm envs as bootstrap envs on Windows. (#512) * Remove edm installed package before installing from source. (#516) * Add help text to click options. (#514) * Various cleanups, fixes and enhancements in ``etstool.py``. (#511) Release 5.1.2 ------------- Released: 2019-07-08 Fixes * Traits documenter no longer generates bad reST for traits whose definition spans multiple source lines. (#494) Release 5.1.1 ------------- Released: 2019-04-18 Fixes * Revert a change (#449) which accidentally broke external uses of ``_py2to3.str_find`` and ``_py2to3.str_rfind``. (#472) Release 5.1.0 ------------- Released: 2019-04-15 Enhancements * Make UUID trait initializable. (#459) * Change default ``FileEditor`` behavior for a ``File`` trait based on whether ``exists=True`` is specified for that trait. (#451, #467) Changes * The changes made in #373 to make dynamically-added traits pickleable have been reverted. (#462) * ``traits.api.python_version`` has been removed. Internals have been refactored to use ``six.PY2`` in preference to ``sys.version_info``. (#449) * Don't depend on the 3rd party ``mock`` library on Python 3; use ``unittest.mock`` instead. (#446) Fixes * Fix a fragile NumPy-related test that failed (``RuntimeError: empty_like method already has a docstring``) with the newest version of NumPy. (#443) Miscellaneous * ``traits._version.git_revision`` now gives the full commit hash (for local builds) instead of an abbreviated 7 hex-digit version. (#453) * Fix copyright years in documentation build. (#445) * Rename ``README.txt`` to ``README.rst``, so that GitHub renders it nicely. * Code cleanups: remove "EOF" markers from code. Remove ``__main__`` blocks for unit tests. Remove imports of ``unittest`` from ``unittest_tools``. (#448, #446) * Update Travis CI and Appveyor configurations to run tests against all PR branches, not just PRs against master. (#466) Release 5.0.0 ------------- Released : 30 January 2019 This major release accumulates more than an year's worth of improvements, changes and bug fixes to the code base. A few highlights of this release are : * Removal of 2to3 fixers and the use of six to provide Python 2/3 compatibility * Removal of deprecated ``traits.protocols`` submodule and related utils. * New ``HasRequiredTraits`` class * Better IPython tab completion for ``HasTraits`` subclasses Changes summary since 4.6.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Enhancements * CI for documentation (#431) * Remove 2to3 fixers (#430) * Enthought Sphinx Theme for docs (#427) * New ``HasRequiredTraits`` class (#419) * Free ``HasTraits`` subclasses from hashing/comparing by identity (#410) * Unify and fix default list editors (#396) * Add ``__dir__`` method to ``HasTraits`` for IPython tab completion (#382) * Python 3 compatibility fixes (#374) * New context manager for setting trait-change-event tracer (#365) * Default trait type constants (#354) Changes * Remove deprecated ``traits.protocols`` submodule and related utils (#435) * Fix invalid string escapes (#429) * Apply the "black" code reformatting utility on the Traits codebase (#432) * Update CI to use edm and etstool module (#420) * Clean up ``Float`` and ``BaseFloat`` validation (#393) * Merge master into Cython port (#370) * Docs and minor refactoring of ``MetaHasTraits`` class (#366) * Remove ridiculous premature optimization (#362) * Add support for PyInstaller app bundler (#361) * Add description and example for ``Either`` trait type (#360) * Drop support for Python 2.6 and Python < 3.4 (#345) * Add make target for docset to be used with Dash/Zeal (#180) Fixes * Fix odd error message and wrong exception type (#426) * Fix Color and RGBColor doc strings (#417) * Fix use of deprecared ``inspect.getargspec`` function (#408) * Fix extended names in ``on_trait_change`` lists (#404) * Support Unicode on trait documenter on Python 2.7 (#386) * Clear exception from Numpy properly (#377) * Fix pickling and deepcopying bug with dynamically added traits (#373) * Set ``auto_set/enter_set`` default once (#371) * Fix validation of ``This`` trait (#353) * Make ``cTrait.default_value_for`` raise a ``ValueError`` instead of seg faulting when asked for the default value of a trait that doesn't have one. (#350) * Fix misuse of ``unittest.expectedFailure`` decorator (#346) * Fix issue with overridden ``HasTraits.trait`` function (#343) Release 4.6.0 ------------- This is an incremental release over 4.5, accumulating over a year's worth of bugfixes and small improvements to the code. Highlights of this release include: * support for Python 3.4 and 3.5. * new Bytes and ValidatedTuple traits. * a new ArrayOrNone trait which correctly handles None comparisons with Numpy arrays. * clean-up of the ETSConfig code for TraitsUI toolkit selection. * better compatibility with NumPy scalar types. * many other bugfixes and improvements. Change summary since 4.5.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~ Enhancements * Added a ``Bytes`` Trait and related traits (#329) * Added support for finding resources from zipped Python source code (#316) * Added in-place set arithmetic operations for ``TraitSetObject``s and accept match behaviour of ``TraitSetObject`` with regular Python sets when performing operations with non-set types (eg. lists, dictionaries) (#289) * Added a context manager to allow provisional selection of a toolkit to ``ETSConfig`` (this generally improves reliability of toolkit selection for Pyface and TraitsUI). (#276) * Added Trait change recorder to aid in debugging event-driven code. (#139) * ``__iadd__`` and ``__imul__`` implemented on TraitListObjects. (#165) * Added new ``ArrayOrNone`` trait type to replace the ``Either(None, Array)`` idiom. The old idiom results in warnings on NumPy >= 1.9. (#219) * Added a new ``ValidatedTuple`` trait that supports custom validation. (#205) Changes * Removed redundant, internal ``ETSConfig`` from Traits codebase. (#327) * Better error reporting for failed attribute access. (#243) * Removed buggy ``-toolkit`` commandline option ``ETSConfig``. (#326) * Removed buggy ``*names`` positional arguments from ``on_trait_change`` decorator in improved argument passing (#207). * Allow ``Float`` and ``BaseFloat`` traits to accept Python longs. (#272) * Clean-up and fixes to example code. (#126) * Remove outdated ``ImportSpy`` and ``ImportManager`` utilities. (#188) * The ``deprecated`` decorator now issues a DeprecationWarning (using the Python ``warnings`` module) rather than logging a warning via the ``logging`` machinery. It no longer tries to remember when a warning has been previously issued. (#220) * Deprecated ``HasTraits.get()`` and ``HasTraits.set()`` (#190). * The default ``View`` shows all (non-event) traits whose ``visible`` property is not ``False``. Private traits are set ``visible=False`` by default. (#234) Fixes * Fix Bool traits so that value stored is always a Python ``bool`` (and in particular, not a NumPy ``np.bool_``). (#318) * Fix Bool traits so that regular validator accepts NumpPy's ``np.bool_`` boolean values (bringing it in agreement with the fast validator). (#302) * Fix use of ``next`` in ``TraitDocumenter`` for Python 3 compatibility. (#293) * Fix off-by-one error when ``TraitListObject`` is setting or deleting slices. (#283) * Fix reference cycles caused by ``sync_traits``. (#135) * Fix so that ``sys.exc_info()`` works as expected in exception handlers in Python 3 (#266) * Fix ``String`` trait to accept ``str`` subclasses (like ``numpy.str_``). (#267) * Fixed incorrect in list events for ``insert`` operations with an index outside the range [``-len(target_list)``, ``len(target_list)``]. (#165) * Fix incorrect behaviour of ``check_implements`` for overridden methods. (#192) * Fix error when trying to listen to traits using list bracket notation. (#195) * Fix reference leak in ``CHasTraits._notifiers``. (#248) * Fix reference leak from use of ``DelegatesTo``. (#260) * Instance traits weren't included in the result of ``traits()``. (#234) Release 4.5.0 ------------- Traits is now compatible with Python 3! The library now supports Python 3.2 and 3.3. The release also includes increased code coverage and automatic coverage report through coveralls.io. Change summary since 4.4.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~ Enhancements * Test files cleanups (#108, #111, #121) * Add automatic coverage reports (#110, #122) * Removed obsolete code (#109, #112, #113) * Increased test coverage (#114, #118) * Python 3 support (#115). Thanks Yves Delley. * Allow setting and resetting the global adaptation manager (#145) * Various documentation improvements (#132, #133, #148, #154). Changes * The Int trait type now accepts Python ints *and* Python longs, as well as instances of any Python type that implements the ``__index__`` method. Previously, long instances were not accepted. (#104, #123). Fixes * Fix crash when trying to validate a property that has been deleted. (#138) * Fix clearing exception when raising a TraitError (#119) * Fix automatic adaptation when assigning to List trait (#147) * Fix some ctraits refcounting and exception clearing bugs (#48). Thanks Yves Delley. Release 4.4.0 ------------- The major new feature in this release is a new adaptation mechanism in the ``traits.adaptation`` package. The new mechanism is intended to replace the older traits.protocols package. Code written against ``traits.protocols`` will continue to work, although the ``traits.protocols`` API has been deprecated, and a warning will be logged on first use of ``traits.protocols``. See the 'Advanced Topics' section of the user manual for more details. The release also includes improved support for using Cython with ``HasTraits`` classes, some new helper utilities for writing unit tests for Traits events, and a variety of bug fixes, stability enhancements, and internal code improvements. Change summary since 4.3.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~ New features * The adaptation mechanism in Traits, formerly based on the 'traits.protocols' package, has been replaced with the more robust 'traits.adaptation' package. (#51) * Added utility function for importing symbols (name, classes, functions) by name: 'traits.util.api.import_symbol'. (#51) * Users can set a global tracer, which receives all traits change events: ``traits.trait_notifiers.set_change_event_tracers``. (#79) Enhancements * Update benchmark script. (#54) * traits.util.deprecated: use module logger instead of root logger. (#59) * Provide an informative message in AdaptationError. (#62) * Allow HasTraits classes to be cythonized. (#73) * Improve tests for cythonization support. (#75) * Extending various trait testing helpers (#53) Refactoring * The Traits notification code has been reworked to remove code duplication, and test coverage of that code has been significantly improved. (#79) Fixes * Fix race condition when removing a traits listener. (#57) * Fix ugly interaction between DelegatesTo change handlers, dynamic change handlers and two levels of dynamic intialization. (#63) * Use a NullHandler for all 'traits' loggers. (#64) * Fix race condition in TraitChangeNotifyWrapper.listener_deleted (#66) * Fix leaking notifiers. (#68) * Fix failing special instance trait events. (#78) * Fix hiding KeyError exception inside trait default initialize method. (#81) * Fix Adapter object initialization. (#93) * Fix cyclic garbage arising from use of the WeakRef trait type. (#95) * ``TraitSetObject.copy`` now returns a plain rather than an uninitialized ``TraitSetObject`` instance. (#97) * Fix cyclic garbage arising from dynamic trait change handlers. (#101) Releases 4.3.0 - 3.6.0 ---------------------- Changelogs unavailable. Release 3.5.0 ------------- Released: 2010-10-15 Enhancements * adding support for drop-down menu in Button traits, but only for qt backend * adding 'show_notebook_menu' option to ListEditor so that the user can right-click and show or hide the context menu (Qt) * added selection range traits to make it possible for users to replace selected text Fixes * fixed null color editor to work with tuples * bug when opening a view with the ToolbarButton Release 3.4.0 ------------- Released: 2010-05-26 Enhancements * adding new example to make testing rgb color editor easier Fixes * fixed NumericColumn to not expect object to have model_selection attribute, and removed more dead theming code * fixed API bugs with the NumericColumn where its function signatures differed from its base class, but the calling code expected them to all be the same * fixed bug which was related to type name errors caused when running Sphinx * when using File(exists=True), be sure to validate the type of the value first before using os.path.isfile() Release 3.3.0 ------------- Released: 2010-02-24 Enhancements The major enhancement this release is that the entire Traits package has been changed to use relative imports so that it can be installed as a sub-package inside another larger library or package. This was not previously possible, since the various modules inside Traits would import each other directly through "traits.[module]". Many thanks to Darren Dale for the patch. Fixes There have been numerous minor bugfixes since the last release. The most notable ones are: * Many fixes involve making Traits UI more robust if wxPython is not installed on a system. In the past, we have been able to use Qt if it was also installed, but removing Wx would lead to a variety of little bugs in various places. We've squashed a number of these. We've also added better checks to make sure we're selecting the right toolkit at import and at runtime. * A nasty cyclic reference was discovered and eliminated in DelegatesTo traits. * The Undefined and Uninitialized Traits were made into true singletons. * Much of the inconsistent formatting across the entire Traits source has been eliminated and normalized (tabs/spaces, line endings). Release 3.2.0 ------------- Released: 2009-07-15 Enhancements * Implemented editable_labels attribute in the TabularEditor for enabling editing of the labels (i.e. the first column) * Saving/restoring window positions works with multiple displays of different sizes * New ProgressEditor * Changed default colors for TableEditor * Added support for HTMLEditor for QT backend using QtWebKit * Improved support for opening links in external browser from HTMLEditor * Added support for TabularEditor for QT backend * Added support for marking up the CodeEditor, including adding squiggles and dimming lines * Added SearchEditor * Improved unicode support * Changed behavior of RangeEditor text box to not auto-set * Added support in RangeEditor for specifying the method to evaluate new values. * Add DefaultOverride editor factory courtesy Stéfan van der Walt * Removed sys.exit() call from SaveHandler.exit() traits-6.3.2/LICENSE-CC-BY-3.0.txt000066400000000000000000000460131414270267200157550ustar00rootroot00000000000000Creative Commons Legal Code Attribution 3.0 Unported CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. License THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 1. Definitions a. "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. b. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. c. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. d. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. e. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. f. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. g. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. h. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. i. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; b. to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and, d. to Distribute and Publicly Perform Adaptations. e. For the avoidance of doubt: i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(b), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(b), as requested. b. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4 (b) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. c. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. 5. Representations, Warranties and Disclaimer UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. 8. Miscellaneous a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. Creative Commons Notice Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License. Creative Commons may be contacted at https://creativecommons.org/. traits-6.3.2/LICENSE.txt000066400000000000000000000031401414270267200146560ustar00rootroot00000000000000This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative. (C) Copyright 2005-2021 Enthought, Inc., Austin, TX All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Enthought, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. traits-6.3.2/MANIFEST.in000066400000000000000000000005241414270267200145740ustar00rootroot00000000000000include CHANGES.rst include LICENSE.txt include LICENSE-CC-BY-3.0.txt include MANIFEST.in include README.rst include image_LICENSE.txt graft docs prune docs/build recursive-exclude docs *.pyc graft examples recursive-exclude examples *.pyc include traits/ctraits.c recursive-include traits *.py include traits/observation/_dsl_grammar.lark traits-6.3.2/README.rst000066400000000000000000000047611414270267200145340ustar00rootroot00000000000000====================================================== Traits: observable typed attributes for Python classes ====================================================== http://docs.enthought.com/traits The Traits project is at the center of all Enthought Tool Suite development and has changed the mental model used at Enthought for programming in the already extremely efficient Python programming language. We encourage everyone to join us in enjoying the productivity gains from using such a powerful approach. The Traits project allows Python programmers to use a special kind of type definition called a *trait*, which gives object attributes some additional characteristics: - **Initialization**: A trait has a *default value*, which is automatically set as the initial value of an attribute before its first use in a program. - **Validation**: The type of a trait attribute is *explicitly declared*. The type is evident in the code, and only values that meet a programmer-specified set of criteria (i.e., the trait definition) can be assigned to that attribute. - **Delegation**: The value of a trait attribute can be contained either in the defining object or in another object *delegated* to by the trait. - **Notification**: Setting the value of a trait attribute can *notify* other parts of the program that the value has changed. - **Visualization**: User interfaces that allow a user to *interactively modify* the value of a trait attribute can be automatically constructed using the trait's definition. (This feature requires that a supported GUI toolkit be installed. If this feature is not used, the Traits project does not otherwise require GUI support.) A class can freely mix trait-based attributes with normal Python attributes, or can opt to allow the use of only a fixed or open set of trait attributes within the class. Trait attributes defined by a class are automatically inherited by any subclass derived from the class. Dependencies ------------ Traits requires Python >= 3.6. Traits has the following optional dependencies: * `NumPy `_ to support the trait types for arrays. * `TraitsUI `_ to support GUI Views. To build the full documentation one needs: * `Sphinx `_ version 2.1 or later. * The `Enthought Sphinx Theme `_. (A version of the documentation can be built without this, but some formatting may be incorrect.) traits-6.3.2/ci-src-requirements.txt000066400000000000000000000000001414270267200174650ustar00rootroot00000000000000traits-6.3.2/docs/000077500000000000000000000000001414270267200137655ustar00rootroot00000000000000traits-6.3.2/docs/Makefile000066400000000000000000000100651414270267200154270ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " changes to make an overview of all changed/added/deprecated items" @echo " docset to make a docset for use with the Dash/Zeal api browsers" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/traits.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/traits.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." docset: BUILD_DOCSET=1 $(SPHINXBUILD) -b html -c source/ $(ALLSPHINXOPTS) $(BUILDDIR)/docset_html @echo "Creating docset with doc2dash" doc2dash -f -d $(BUILDDIR) -i $(BUILDDIR)/docset_html/_static/img/e-logo.png -n Traits $(BUILDDIR)/docset_html @echo "Traits docset is available in $(BUILDDIR)/Traits.docset" traits-6.3.2/docs/make.bat000066400000000000000000000145101414270267200153730ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source set I18NSPHINXOPTS=%SPHINXOPTS% source if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\SimPhoNy.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\SimPhoNy.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end traits-6.3.2/docs/source/000077500000000000000000000000001414270267200152655ustar00rootroot00000000000000traits-6.3.2/docs/source/_static/000077500000000000000000000000001414270267200167135ustar00rootroot00000000000000traits-6.3.2/docs/source/_static/default.css000066400000000000000000000323121414270267200210520ustar00rootroot00000000000000/** * Sphinx Doc Design */ body { font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; font-size: 100%; background-color: #333333; color: #000; margin: 0; padding: 0; } /* :::: LAYOUT :::: */ div.document { background-color: #24326e; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 0 0 230px; } div.body { background-color: white; padding: 0 20px 30px 20px; } div.sphinxsidebarwrapper { padding: 10px 5px 0 10px; } div.sphinxsidebar { float: left; width: 230px; margin-left: -100%; font-size: 90%; } p.logo { text-align: center; } div.clearer { clear: both; } div.footer { color: #fff; width: 100%; padding: 9px 0 9px 0; text-align: center; font-size: 75%; } div.footer a { color: #fff; text-decoration: underline; } div.related { background-color: #24326e; color: #fff; width: 100%; height: 30px; line-height: 30px; font-size: 90%; } div.related h3 { display: none; } div.related ul { margin: 0; padding: 0 0 0 10px; list-style: none; } div.related li { display: inline; } div.related li.right { float: right; margin-right: 5px; } div.related a { color: white; } /* ::: TOC :::: */ div.sphinxsidebar h3 { font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; color: #acafb3; font-size: 1.4em; font-weight: normal; margin: 0; padding: 0; } div.sphinxsidebar h4 { font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; color: #acafb3; font-size: 1.3em; font-weight: normal; margin: 5px 0 0 0; padding: 0; } div.sphinxsidebar p { color: white; } div.sphinxsidebar p.topless { margin: 5px 10px 10px 10px; } div.sphinxsidebar ul { margin: 10px; padding: 0; list-style: none; color: white; } div.sphinxsidebar ul ul, div.sphinxsidebar ul.want-points { margin-left: 20px; list-style: square; } div.sphinxsidebar ul ul { margin-top: 0; margin-bottom: 0; } div.sphinxsidebar a { color: #fff; } div.sphinxsidebar form { margin-top: 10px; } div.sphinxsidebar input { border: 1px solid #9bbde2; font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; font-size: 1em; } /* :::: MODULE CLOUD :::: */ div.modulecloud { margin: -5px 10px 5px 10px; padding: 10px; line-height: 160%; border: 1px solid #666666; background-color: #dddddd; } div.modulecloud a { padding: 0 5px 0 5px; } /* :::: SEARCH :::: */ ul.search { margin: 10px 0 0 20px; padding: 0; } ul.search li { padding: 5px 0 5px 20px; background-image: url(file.png); background-repeat: no-repeat; background-position: 0 7px; } ul.search li a { font-weight: bold; } ul.search li div.context { color: #666; margin: 2px 0 0 30px; text-align: left; } ul.keywordmatches li.goodmatch a { font-weight: bold; } /* :::: COMMON FORM STYLES :::: */ div.actions { padding: 5px 10px 5px 10px; border-top: 1px solid #598ec0; border-bottom: 1px solid #598ec0; background-color: #9bbde2; } form dl { color: #333; } form dt { clear: both; float: left; min-width: 110px; margin-right: 10px; padding-top: 2px; } input#homepage { display: none; } div.error { margin: 5px 20px 0 0; padding: 5px; border: 1px solid #db7d46; font-weight: bold; } /* :::: INLINE COMMENTS :::: */ div.inlinecomments { position: absolute; right: 20px; } div.inlinecomments a.bubble { display: block; float: right; background-image: url(style/comment.png); background-repeat: no-repeat; width: 25px; height: 25px; text-align: center; padding-top: 3px; font-size: 0.9em; line-height: 14px; font-weight: bold; color: black; } div.inlinecomments a.bubble span { display: none; } div.inlinecomments a.emptybubble { background-image: url(style/nocomment.png); } div.inlinecomments a.bubble:hover { background-image: url(style/hovercomment.png); text-decoration: none; color: #598ec0; } div.inlinecomments div.comments { float: right; margin: 25px 5px 0 0; max-width: 50em; min-width: 30em; border: 1px solid #598ec0; background-color: #9bbde2; z-index: 150; } div#comments { border: 1px solid #598ec0; margin-top: 20px; } div#comments div.nocomments { padding: 10px; font-weight: bold; } div.inlinecomments div.comments h3, div#comments h3 { margin: 0; padding: 0; background-color: #598ec0; color: white; border: none; padding: 3px; } div.inlinecomments div.comments div.actions { padding: 4px; margin: 0; border-top: none; } div#comments div.comment { margin: 10px; border: 1px solid #598ec0; } div.inlinecomments div.comment h4, div.commentwindow div.comment h4, div#comments div.comment h4 { margin: 10px 0 0 0; background-color: #2eabb0; color: white; border: none; padding: 1px 4px 1px 4px; } div#comments div.comment h4 { margin: 0; } div#comments div.comment h4 a { color: #9bbde2; } div.inlinecomments div.comment div.text, div.commentwindow div.comment div.text, div#comments div.comment div.text { margin: -5px 0 -5px 0; padding: 0 10px 0 10px; } div.inlinecomments div.comment div.meta, div.commentwindow div.comment div.meta, div#comments div.comment div.meta { text-align: right; padding: 2px 10px 2px 0; font-size: 95%; color: #598ec0; border-top: 1px solid #598ec0; background-color: #9bbde2; } div.commentwindow { position: absolute; width: 500px; border: 1px solid #598ec0; background-color: #9bbde2; display: none; z-index: 130; } div.commentwindow h3 { margin: 0; background-color: #598ec0; color: white; border: none; padding: 5px; font-size: 1.5em; cursor: pointer; } div.commentwindow div.actions { margin: 10px -10px 0 -10px; padding: 4px 10px 4px 10px; color: #598ec0; } div.commentwindow div.actions input { border: 1px solid #598ec0; background-color: white; color: #073d61; cursor: pointer; } div.commentwindow div.form { padding: 0 10px 0 10px; } div.commentwindow div.form input, div.commentwindow div.form textarea { border: 1px solid #598ec0; background-color: white; color: black; } div.commentwindow div.error { margin: 10px 5px 10px 5px; background-color: #fff2b0; display: none; } div.commentwindow div.form textarea { width: 99%; } div.commentwindow div.preview { margin: 10px 0 10px 0; background-color: ##9bbde2; padding: 0 1px 1px 25px; } div.commentwindow div.preview h4 { margin: 0 0 -5px -20px; padding: 4px 0 0 4px; color: white; font-size: 1.3em; } div.commentwindow div.preview div.comment { background-color: #f2fbfd; } div.commentwindow div.preview div.comment h4 { margin: 10px 0 0 0!important; padding: 1px 4px 1px 4px!important; font-size: 1.2em; } /* :::: SUGGEST CHANGES :::: */ div#suggest-changes-box input, div#suggest-changes-box textarea { border: 1px solid #666; background-color: white; color: black; } div#suggest-changes-box textarea { width: 99%; height: 400px; } /* :::: PREVIEW :::: */ div.preview { background-image: url(style/preview.png); padding: 0 20px 20px 20px; margin-bottom: 30px; } /* :::: INDEX PAGE :::: */ table.contentstable { width: 90%; } table.contentstable p.biglink { line-height: 150%; } a.biglink { font-size: 1.3em; } span.linkdescr { font-style: italic; padding-top: 5px; font-size: 90%; } /* :::: INDEX STYLES :::: */ table.indextable td { text-align: left; vertical-align: top; } table.indextable dl, table.indextable dd { margin-top: 0; margin-bottom: 0; } table.indextable tr.pcap { height: 10px; } table.indextable tr.cap { margin-top: 10px; background-color: #dddddd; } img.toggler { margin-right: 3px; margin-top: 3px; cursor: pointer; } form.pfform { margin: 10px 0 20px 0; } /* :::: GLOBAL STYLES :::: */ .docwarning { background-color: #fff2b0; padding: 10px; margin: 0 -20px 0 -20px; border-bottom: 1px solid #db7d46; } p.subhead { font-weight: bold; margin-top: 20px; } a { color: #24326e; text-decoration: none; } a:hover { text-decoration: underline; } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; background-color: #dddddd; font-weight: normal; color: #073d61; border-bottom: 1px solid #666; margin: 20px -20px 10px -20px; padding: 3px 0 3px 10px; } div.body h1 { margin-top: 0; font-size: 200%; } div.body h2 { font-size: 160%; } div.body h3 { font-size: 140%; } div.body h4 { font-size: 120%; } div.body h5 { font-size: 110%; } div.body h6 { font-size: 100%; } a.headerlink { color: #edaa1e; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; visibility: hidden; } h1:hover > a.headerlink, h2:hover > a.headerlink, h3:hover > a.headerlink, h4:hover > a.headerlink, h5:hover > a.headerlink, h6:hover > a.headerlink, dt:hover > a.headerlink { visibility: visible; } a.headerlink:hover { background-color: #edaa1e; color: white; } div.body p, div.body dd, div.body li { text-align: left; line-height: 130%; } div.body p.caption { text-align: inherit; } div.body td { text-align: left; } ul.fakelist { list-style: none; margin: 10px 0 10px 20px; padding: 0; } .field-list ul { padding-left: 1em; } .first { margin-top: 0 !important; } /* "Footnotes" heading */ p.rubric { margin-top: 30px; font-weight: bold; } /* "Topics" */ div.topic { background-color: #ddd; border: 1px solid #666; padding: 0 7px 0 7px; margin: 10px 0 10px 0; } p.topic-title { font-size: 1.1em; font-weight: bold; margin-top: 10px; } /* Admonitions */ div.admonition { margin-top: 10px; margin-bottom: 10px; padding: 7px; } div.admonition dt { font-weight: bold; } div.admonition dl { margin-bottom: 0; } div.admonition p { display: inline; } div.seealso { background-color: #fff2b0; border: 1px solid #edaa1e; } div.warning { background-color: #fff2b0; border: 1px solid ##db7d46; } div.note { background-color: #eee; border: 1px solid #666; } p.admonition-title { margin: 0px 10px 5px 0px; font-weight: bold; display: inline; } p.admonition-title:after { content: ":"; } div.body p.centered { text-align: center; margin-top: 25px; } table.docutils { border: 0; } table.docutils td, table.docutils th { padding: 1px 8px 1px 0; border-top: 0; border-left: 0; border-right: 0; border-bottom: 1px solid #a9a6a2; } table.field-list td, table.field-list th { border: 0 !important; } table.footnote td, table.footnote th { border: 0 !important; } .field-list ul { margin: 0; padding-left: 1em; } .field-list p { margin: 0; } dl { margin-bottom: 15px; clear: both; } dd p { margin-top: 0px; } dd ul, dd table { margin-bottom: 10px; } dd { margin-top: 3px; margin-bottom: 10px; margin-left: 30px; } .refcount { color: #24326e; } dt:target, .highlight { background-color: #edaa1e1; } dl.glossary dt { font-weight: bold; font-size: 1.1em; } th { text-align: left; padding-right: 5px; } pre { padding: 5px; background-color: #e6f3ff; color: #333; border: 1px solid #24326e; border-left: none; border-right: none; overflow: auto; } td.linenos pre { padding: 5px 0px; border: 0; background-color: transparent; color: #aaa; } table.highlighttable { margin-left: 0.5em; } table.highlighttable td { padding: 0 0.5em 0 0.5em; } tt { background-color: #ddd; padding: 0 1px 0 1px; font-size: 1.2em; } tt.descname { background-color: transparent; font-weight: bold; font-size: 1.2em; } tt.descclassname { background-color: transparent; } tt.xref, a tt { background-color: transparent; font-weight: bold; } .footnote:target { background-color: #fff2b0 } h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { background-color: transparent; } .optional { font-size: 1.3em; } .versionmodified { font-style: italic; } form.comment { margin: 0; padding: 10px 30px 10px 30px; background-color: #ddd; } form.comment h3 { background-color: #598ec0; color: white; margin: -10px -30px 10px -30px; padding: 5px; font-size: 1.4em; } form.comment input, form.comment textarea { border: 1px solid #ddd; padding: 2px; font-family: 'Verdana', 'Helvetica', 'Arial', sans-serif; font-size: 100%; } form.comment input[type="text"] { width: 240px; } form.comment textarea { width: 100%; height: 200px; margin-bottom: 10px; } .system-message { background-color: #edaa1e; padding: 5px; border: 3px solid red; } /* :::: PRINT :::: */ @media print { div.document, div.documentwrapper, div.bodywrapper { margin: 0; width : 100%; } div.sphinxsidebar, div.related, div.footer, div#comments div.new-comment-box, #top-link { display: none; } } traits-6.3.2/docs/source/_static/e-logo-rev.png000066400000000000000000000075111414270267200214010ustar00rootroot00000000000000PNG  IHDRoi*sRGB pHYs  tIMELIDATx]ktT>z\$m ȥ!TD jV|_CWph PT\"B$$6aIf9qfB%= By}; vo`!4ChVv[12 !HGiyg):QVd8SmsQAj2~~AH3qU:?!4[a6SRu ǎ7H'1"_Qq!JbBwx$I-S^QO>AO~( HAPU)=Ojjm+ v$~ئ"33zviJn[*.\v(/E1U`Ycֿ&y3g>=x$;GS@]d1YÓo"۾X6n8o2 ,c_܊U?y" "cdL5HfFj~}Q]H錩/Oxcq'~lӕ_ ţeW\| &cLMhdȶ9-՗ $ Θڳ9i˗>xa6>#E _h2$}앿"a\l߰0/"ޑҦ.*:UQyٕ~`:oYfxu? b)<̜>җ'rYgԾ6ngeSMkm>uv" Snhj ̌ry_ݚLM01@$(]vƏ{_{#&>4l|c.8~rK05bjԈm;14*:Ο3yK|ީT\> 8nd٤B]j맻]8#&[5TEUlu#u\/kk^6t=Zo`Ӌ-,R'*EP1#EQ DfsnlOYYYҨ!${G2yZ~\pN|olӋnϯBu-\$5˘TYgNR^\8gF{@|4Ņ0ov2֊^:j)D"zM En1]WfN@wǛ뿨k B|c!>8T'JԉaZxubOW~;c%dLynظedNSt~WX\f-pO',9UI21`xĥd  ,{ER"Z G 4PLq@$#15! G}\.-2kEfV=G15Q&ph!9Ce Cvj(# 5#GX:InHJZmڞU__(h݆' H7cHκ})"Db-&`i\eU?*YJ05 D S[GabDěrqEʪ9կm"4LwtGTدr{OPۿhj?:}"i b:/7yA@eK#$t13mj51K &^w !%PSSSֆlr{s^#w4DmQI S#3a@57Q; S#:į v4yR+A&P0j/))-&Z4S.[Z2d^!j8J01-j(T!05Q)"jԌ+@vpd"'4LuyC͉cv,@A1i_qLq|s4bvGz!U !KIQD1E3[1vI $00h6FL̙dnu˞?SScw\LGaʃcf-N]y/4u: c c PM18_h>4~h޽f l%&N^>?2=iC)9v!˜j>hN'N~(aİ}Wx+' u0?1sL _/>_nH ! x9zq@bzlLؘO_6Ac6~t=F&מc2\汋rh3.婓Jx`x^_>_mqKkj+-++Y.zw3TU+qܹ~M\_:pBI" D5 JcTubd!P%+~fz*EP]6R2;/uz] g,'Nd=C^n188D,dZ}W/)~ǎ/z~*0P]g*ݐ[{s]b76 $?`[퍘JTDDKŽ t "((}qqwZΦO11fZ XSXk71E~;{GbN#"k" r@4˗mrN"srLڀ?Vh?݁nw'?0l۶`bF4]2UU ;llgL bkx'ۄ&%QU#c*B{awE|DǶBhZ-f/wIENDB`traits-6.3.2/docs/source/_static/et.ico000066400000000000000000000236261414270267200200300ustar00rootroot00000000000000(f 00hvh F00( r5(H73iKD]ZZzols$jV4{H5Fg@Hg @' 9c]sE{c@Ec{bFQEPkG\ 1}m( @_-!p3%7)&[B<]VU~okWU#XW$iU$zu5{j6Yv1GWw"X f$I qJ QJ[JډJc4jJ5{J 1FJ qGI Q#W6 Q$j#XA${#h1IQ$j1< s4{A a5S Q}A\1J7|xp``?`8(0`W,"4(%p3%v>1IGF~QFja_~wtdFwG܆ h즋" ij""!zi"""!g""""ۆ"""""F얋""""""Gzޥ""""""Hi """"" ih s"""""  c"""""! R""""!|2"""!|{2""!|2"1"!5 y@y`"!""" 2""""G s"""""H b"""" i R""""!yR""""!qh2""""0i2""""GR"!z"""""hr"""r"""" """""FB""""#93"""""GB"""""62"""""hp"""""%""""" ht"""""#|"""""!"""""k """""""""""Y s"""""""""8 b"""""""&R"""""%2"""#|2"#k"Y?????( f-t1!j/#i1$n3$j2&r4&s4&s5&u5&]0'`1'^2'u5'v5'v6'x6';+(X2(_2(r4(u6(w7(x7(z7(y8(z8({8(P0)s7)z8){8)|9):*c5,i9-A1.R4.E3/W7/u=1x?2A97>;:{F:F?>{I>mH?DBAMDB~ODJHHOMLhSOQPPPQQSRRUTTaW\YXx_[c[]]]^^^b_^___dddpghhhmhkjijjjrksmnnnrpopppsssuttwwwyyy~{}}}t@4LhO\b$8PraKx_ *?VNdcpI 0M}Wfm:1n{|wFvu2!5yziAUSyxj?]GRryxj>E-BYyzk7l`, %3Jg~Z+DaT)9hzC&6Ooe" [q. *>;'#QX( <H/s=^( @m,6#>%D&K'O(R)P) Y+ q0!2%"`."8'#g1#4($l2%p3%q3%q4%0'&a0&r4&t5&u5&v5&e2'p4't4't5'u5'u6'v6'w6'x6'/)(r6(v6(x7(Y3)z8)v8*l6+2--m:-v;-w>1543Q93v@3lA7vC8;:9wF:><;N?<VA=?>>@??zK@AAAoJAFFF~SHbNIKKKnQKLLLrTMONNPNNZPQQQSRRVVUdXVXWWaWaX[ZZwa\d_^e^i_```iabbbedceedhhhphqh}mipijjjlkkplrlwmoooqpopppxqwrsssyvuwwwyyy{{}}}~~~ŻjjybO =iٙWa"HuihZ!.SWZ% 9bݫXxaBmnczq2 !*NwܐVr-% 3]wt\#%XzF' Dz:  EIv- N}I`')uHYH޾Hn65S|HJ' 9dH<%"DpHs0!.SDe(! ;g9pQ("GuM8b> .Uo0@m~1% KL  *Nwג7%%?4%% 3XжP& +_l,$ =g^/#AT($ ! 1>  )[4 #Ck,1{R(%+_f|xp``?`8(0`<5"=$H&/"S)m-*" -# X+ s0!b."o1"+%#h0#+%$l2$u3$p3%q3%q4%r4%+&&8)&V.&g2&r4&t4&t5&u5&.('O/'t5'u5'v5'u6'v6'q6(v7(y7(o7)}9),+*V2*g4*x9*:.,x;,/..70.C2.z=/211u=1l=2z@3666X?9:::}E:><<PB>~I>AAALAlKCODEEERFIIIUIUJKKK`OKMMMZPRRR\TS^TUUU_WaWYYYs_Zt`[`^^__^g_a``bbaccceeeofhggiiillksknmmpppxptsruuuxvxxxyyy}{y}z{{{|}}}~}~¿ȏՎV)IzEl~zEzEtgzE{=?bzEM+$0LqzE9!$ 8YzE5$CdzEc/$0LtzEW$$ :ZzEG$!Ce|?>$$0Ovo*R}u7$:Zc5 ?ac&!CeD $*JmN$$0R\%$ 4Rxf,! .eF <]v=)6u7!$EeږM'#(Tc-#0Ot׽a+ !AQ$# 8Yvh=$$6jB$ 1!!%Ty7!!!"A`&$6jQ&"%T@$Ay7!$6j`&!%SQ'$A?????traits-6.3.2/docs/source/_templates/000077500000000000000000000000001414270267200174225ustar00rootroot00000000000000traits-6.3.2/docs/source/_templates/layout.html000066400000000000000000000003631414270267200216270ustar00rootroot00000000000000{# Filename: .templates/layout.html #} {% extends '!layout.html' %} {% block relbaritems %} {% if current_page_name != 'index' %}
  • {{ title }}
  • {% endif %} {% endblock %} traits-6.3.2/docs/source/_templates/search.html000066400000000000000000000017451414270267200215640ustar00rootroot00000000000000{% extends "!search.html" %} {% block body %}

    Search

    Enter your search words into the box below and click search. Note that the search function automatically searches for all of the words. Pages containing some but not all of them won't appear in the result list.

    {% if search_performed %}

    Search Results

    {% if not search_results %}

    Your search did not match any results.

    {% endif %} {% endif %}
    {% if search_results %}
      {% for href, caption, context in search_results %}
    • {{ caption }}
      {{ context|e }}
    • {% endfor %}
    {% endif %}
    {% endblock %} traits-6.3.2/docs/source/changelog.rst000066400000000000000000000000361414270267200177450ustar00rootroot00000000000000.. include:: ../../CHANGES.rsttraits-6.3.2/docs/source/conf.py000066400000000000000000000210621414270267200165650ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # Traits documentation build configuration file, created by # sphinx-quickstart on Tue Jul 22 10:52:03 2008. # # This file is execfile()d with the current directory set to its containing # dir. # # The contents of this file are pickled, so don't put values in the namespace # that aren't pickleable (module imports are okay, they're removed # automatically). # # All configuration values have a default value; values that are commented out # serve to show the default value. import os import sys # The docset build will use slightly different formatting rules BUILD_DOCSET = bool(os.environ.get("BUILD_DOCSET")) # If your extensions are in another directory, add it here. If the directory # is relative to the documentation root, use os.path.abspath to make it # absolute, like shown here. sys.path.append(os.path.abspath("../../")) # General configuration # --------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ "sphinx.ext.autosummary", "sphinx.ext.coverage", "sphinx.ext.githubpages", "sphinx.ext.intersphinx", "sphinx.ext.napoleon", "sphinx.ext.viewcode", "traits.util.trait_documenter", ] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] # The suffix of source filenames. source_suffix = ".rst" # The master toctree document. master_doc = "index" # General substitutions. project = "traits" copyright = """\ (C) Copyright 2005-2021 Enthought, Inc., Austin, TX All rights reserved. """ # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. version_info = {} traits_init_path = os.path.join("..", "..", "traits", "__init__.py") with open(traits_init_path, "r", encoding="utf-8") as version_module: version_code = compile(version_module.read(), "__init__.py", "exec") exec(version_code, version_info) # "release" is the full version string, including the bugfix portion and any # modifiers. "version" is of the form "6.2" and is what's used in titles. release = version_info["__version__"] version = ".".join(release.split(".")[:2]) # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. today_fmt = "%B %d, %Y" # List of documents that shouldn't be included in the build. # unused_docs = [] # List of directories, relative to source directories, that shouldn't be # searched for source files. # exclude_dirs = [] # The reST default role (used for this markup: `text`) to use for all # documents. # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = "sphinx" # Options for the autodoc extension. autodoc_default_options = { "members": None, } autodoc_member_order = "bysource" # Options for HTML output # ----------------------- # Use enthought-sphinx-theme if available try: import enthought_sphinx_theme html_theme_path = [enthought_sphinx_theme.theme_path] html_theme = "enthought" html_static_path = [] templates_path = [] except ImportError as exc: import warnings msg = """Can't find Enthought Sphinx Theme, using default. Exception was: {} Enthought Sphinx Theme can be installed from PyPI or EDM""" warnings.warn(RuntimeWarning(msg.format(exc))) # Use old defaults if enthought-sphinx-theme not available # The name of an image file (within the static path) to place at the top # of the sidebar. html_logo = os.path.join("_static", "e-logo-rev.png") # The name of an image file (within the static path) to use as favicon of # the docs. This file should be a Windows icon file (.ico) being 16x16 # or 32x32 pixels large. html_favicon = os.path.join("_static", "et.ico") # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. html_style = "default.css" # Add any paths that contain custom static files (such as style sheets) # here, relative to this directory. They are copied after the builtin # static files, so a file named "default.css" will overwrite the builtin # "default.css". html_static_path = ["_static"] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] # When using docset browsers like Dash and Zeal the side bar is redundant. if BUILD_DOCSET: html_theme_options = {"nosidebar": "true"} # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". html_title = "Traits {version} Documentation".format(version=version) # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = "%b %d, %Y" # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no index is generated. html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, the reST sources are included in the HTML build as _sources/. # html_copy_source = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = "Traitsdoc" # Options for LaTeX output # ------------------------ # The paper size ('letter' or 'a4'). # latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). # latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, # document class [howto/manual]). latex_documents = [ ( "index", "Traits.tex", "Traits {version} User Manual".format(version=version), "Enthought, Inc.", "manual", ) ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = "enthought_logo.jpg" latex_logo = "e-logo-rev.png" # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # Additional stuff for the LaTeX preamble. # latex_preamble = '' # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_use_modindex = True # Options for Texinfo output # -------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ( "index", "traits", "Traits {version} User Manual".format(version=version), "Enthought, Inc.", "Traits", "Explicitly typed attributes for Python.", "Python", ) ] # Options for intersphinx extension # --------------------------------- intersphinx_mapping = { "pyface": ("https://docs.enthought.com/pyface", None), "python": ("https://docs.python.org/3", None), "traitsui": ("https://docs.enthought.com/traitsui", None), } traits-6.3.2/docs/source/index.rst000066400000000000000000000006521414270267200171310ustar00rootroot00000000000000Traits |version| Documentation ============================== Tutorial -------- .. toctree:: :maxdepth: 3 traits_tutorial/index User Reference -------------- .. toctree:: :maxdepth: 3 traits_user_manual/index Developer Reference ------------------- .. toctree:: :maxdepth: 3 traits_api_reference/index Miscellaneous ------------- .. toctree:: :maxdepth: 2 changelog * :ref:`search` traits-6.3.2/docs/source/traits_api_reference/000077500000000000000000000000001414270267200214425ustar00rootroot00000000000000traits-6.3.2/docs/source/traits_api_reference/base_trait_handler.rst000066400000000000000000000002761414270267200260130ustar00rootroot00000000000000:mod:`traits.base_trait_handler` Module ======================================= .. automodule:: traits.base_trait_handler :no-members: Classes ------- .. autoclass:: BaseTraitHandler traits-6.3.2/docs/source/traits_api_reference/constants.rst000066400000000000000000000005171414270267200242130ustar00rootroot00000000000000:mod:`traits.constants` Module ============================== .. automodule:: traits.constants :no-members: Classes ------- .. autodata:: TraitKind .. autodata:: ValidateTrait .. autodata:: DefaultValue .. autodata:: ComparisonMode .. autodata:: NO_COMPARE .. autodata:: OBJECT_IDENTITY_COMPARE .. autodata:: RICH_COMPARE traits-6.3.2/docs/source/traits_api_reference/ctrait.rst000066400000000000000000000002621414270267200234620ustar00rootroot00000000000000:mod:`traits.ctrait` Module =========================== .. automodule:: traits.ctrait :no-members: .. currentmodule:: traits.ctrait Classes ------- .. autoclass:: CTrait traits-6.3.2/docs/source/traits_api_reference/ctraits.rst000066400000000000000000000003651414270267200236510ustar00rootroot00000000000000:mod:`traits.ctraits` Module ============================ .. automodule:: traits.ctraits :no-members: Classes ------- .. autoclass:: CHasTraits .. automethod:: _class_traits .. automethod:: _instance_traits .. autoclass:: cTrait traits-6.3.2/docs/source/traits_api_reference/editor_factories.rst000066400000000000000000000010221414270267200255140ustar00rootroot00000000000000:mod:`traits.editor_factories` Module ===================================== .. automodule:: traits.editor_factories :no-members: .. currentmodule:: traits.editor_factories Functions --------- .. autofunction:: bytes_editor .. autofunction:: code_editor .. autofunction:: date_editor .. autofunction:: datetime_editor .. autofunction:: html_editor .. autofunction:: list_editor .. autofunction:: multi_line_text_editor .. autofunction:: password_editor .. autofunction:: shell_editor .. autofunction:: time_editor traits-6.3.2/docs/source/traits_api_reference/has_traits.rst000066400000000000000000000031241414270267200243350ustar00rootroot00000000000000:mod:`traits.has_traits` Module =============================== .. automodule:: traits.has_traits :no-members: Classes ------- .. autoclass:: MetaHasTraits .. autoclass:: MetaInterface .. automethod:: __init__ .. automethod:: __call__ .. autoclass:: HasTraits :exclude-members: wrappers .. attribute:: wrappers :annotation: = | {'same': TraitChangeNotifyWrapper, | 'extended': ExtendedTraitChangeNotifyWrapper, | 'new': NewTraitChangeNotifyWrapper, | 'fast_ui': FastUITraitChangeNotifyWrapper, | 'ui': FastUITraitChangeNotifyWrapper} Mapping from dispatch type to notification wrapper class type .. autoclass:: HasStrictTraits .. autoclass:: HasRequiredTraits .. autoclass:: HasPrivateTraits .. autoclass:: Vetoable .. autoclass:: Interface .. autoclass:: ISerializable ABC classes ----------- .. note:: These classes are only available when the abc module is present. .. autoclass:: ABCMetaHasTraits .. autoclass:: ABCHasTraits .. autoclass:: ABCHasStrictTraits Functions --------- .. autofunction:: cached_property .. autofunction:: get_delegate_pattern .. autofunction:: observe .. autofunction:: on_trait_change .. autofunction:: property_depends_on .. autofunction:: provides .. autofunction:: weak_arg Deprecated Classes ------------------ The following :class:`~.HasTraits` subclasses are deprecated, and may be removed in a future version of Traits. .. autoclass:: SingletonHasTraits .. autoclass:: SingletonHasStrictTraits .. autoclass:: SingletonHasPrivateTraits traits-6.3.2/docs/source/traits_api_reference/index.rst000066400000000000000000000013211414270267200233000ustar00rootroot00000000000000API Reference ============= Traits core ----------- .. toctree:: :maxdepth: 1 traits has_traits base_trait_handler constants ctrait ctraits editor_factories interface_checker trait_base trait_converters trait_dict_object trait_errors trait_factory trait_handler trait_handlers trait_list_object trait_numeric trait_type trait_types trait_notifiers trait_set_object traits_listener version Subpackages ----------- .. toctree:: :maxdepth: 1 traits.adaptation traits.etsconfig traits.observation traits.testing traits.util Indices and tables ================== * :ref:`genindex` * :ref:`search` traits-6.3.2/docs/source/traits_api_reference/interface_checker.rst000066400000000000000000000004211414270267200256150ustar00rootroot00000000000000:mod:`traits.interface_checker` Module ====================================== .. automodule:: traits.interface_checker :no-members: Classes ------- .. autoclass:: InterfaceError .. autoclass:: InterfaceChecker Function -------- .. autofunction:: check_implements traits-6.3.2/docs/source/traits_api_reference/trait_base.rst000066400000000000000000000013261414270267200243130ustar00rootroot00000000000000:mod:`traits.trait_base` Module =============================== .. automodule:: traits.trait_base :no-members: Classes ------- .. autodata:: Uninitialized .. autodata:: Undefined .. autodata:: Missing .. autodata:: Self .. autoclass:: HandleWeakRef Functions --------- .. autofunction:: strx .. autofunction:: class_of .. autofunction:: add_article .. autofunction:: user_name_for .. autofunction:: traits_home .. autofunction:: verify_path .. autofunction:: get_module_name .. autofunction:: get_resource_path .. autofunction:: xgetattr .. autofunction:: xsetattr .. autofunction:: is_none .. autofunction:: not_none .. autofunction:: not_false .. autofunction:: not_event .. autofunction:: is_str traits-6.3.2/docs/source/traits_api_reference/trait_converters.rst000066400000000000000000000006011414270267200255660ustar00rootroot00000000000000:mod:`traits.trait_converters` Module ===================================== .. automodule:: traits.trait_converters :no-members: .. currentmodule:: traits.trait_converters Functions --------- .. autofunction:: as_ctrait .. autofunction:: check_trait .. autofunction:: trait_cast .. autofunction:: trait_from .. autofunction:: trait_for .. autofunction:: mapped_trait_for traits-6.3.2/docs/source/traits_api_reference/trait_dict_object.rst000066400000000000000000000003631414270267200256520ustar00rootroot00000000000000:mod:`traits.trait_dict_object` Module ====================================== .. automodule:: traits.trait_dict_object :no-members: Classes ------- .. autoclass:: TraitDictEvent .. autoclass:: TraitDict .. autoclass:: TraitDictObject traits-6.3.2/docs/source/traits_api_reference/trait_errors.rst000066400000000000000000000004371414270267200247170ustar00rootroot00000000000000:mod:`traits.trait_errors` Module ================================= .. automodule:: traits.trait_errors :no-members: Functions --------- .. autofunction:: repr_type Classes ------- .. autoclass:: TraitError .. autoclass:: TraitNotificationError .. autoclass:: DelegationError traits-6.3.2/docs/source/traits_api_reference/trait_factory.rst000066400000000000000000000004541414270267200250510ustar00rootroot00000000000000:mod:`traits.trait_factory` Module ================================== .. automodule:: traits.trait_factory :no-members: .. currentmodule:: traits.trait_factory Classes ------- .. autoclass:: TraitFactory .. autoclass:: TraitImportError Functions --------- .. autofunction:: trait_factory traits-6.3.2/docs/source/traits_api_reference/trait_handler.rst000066400000000000000000000002531414270267200250140ustar00rootroot00000000000000:mod:`traits.trait_handler` Module ================================== .. automodule:: traits.trait_handler :no-members: Classes ------- .. autoclass:: TraitHandler traits-6.3.2/docs/source/traits_api_reference/trait_handlers.rst000066400000000000000000000015261414270267200252030ustar00rootroot00000000000000:mod:`traits.trait_handlers` Module =================================== .. automodule:: traits.trait_handlers :no-members: Classes ------- .. autoclass:: TraitCoerceType .. autoclass:: TraitCastType .. autoclass:: TraitInstance .. autoclass:: TraitFunction .. autoclass:: TraitEnum .. autoclass:: TraitCompound .. autoclass:: TraitMap Private Functions ----------------- .. autofunction:: traits.trait_handlers._undefined_get .. autofunction:: traits.trait_handlers._undefined_set Deprecated Handlers ------------------- .. deprecated:: 6.0.0 The following :class:`~.TraitHandler` classes and instances are deprecated, and may be removed in a future version of Traits. .. autoclass:: TraitDict .. autoclass:: TraitList .. autoclass:: TraitTuple .. deprecated:: 6.1.0 .. autoclass:: TraitPrefixList .. autoclass:: TraitPrefixMap traits-6.3.2/docs/source/traits_api_reference/trait_list_object.rst000066400000000000000000000003631414270267200257020ustar00rootroot00000000000000:mod:`traits.trait_list_object` Module ====================================== .. automodule:: traits.trait_list_object :no-members: Classes ------- .. autoclass:: TraitListEvent .. autoclass:: TraitList .. autoclass:: TraitListObject traits-6.3.2/docs/source/traits_api_reference/trait_notifiers.rst000066400000000000000000000012611414270267200254010ustar00rootroot00000000000000:mod:`traits.trait_notifiers` Module ==================================== .. automodule:: traits.trait_notifiers :no-members: Classes ------- .. autoclass:: NotificationExceptionHandlerState .. autoclass:: NotificationExceptionHandler :members: _push_handler, _pop_handler, _handle_exception, _get_handlers, _check_lock, _log_exception .. autoclass:: StaticAnytraitChangeNotifyWrapper .. autoclass:: StaticTraitChangeNotifyWrapper .. autoclass:: TraitChangeNotifyWrapper .. autoclass:: ExtendedTraitChangeNotifyWrapper .. autoclass:: FastUITraitChangeNotifyWrapper .. autoclass:: NewTraitChangeNotifyWrapper Functions --------- .. autofunction:: set_ui_handler traits-6.3.2/docs/source/traits_api_reference/trait_numeric.rst000066400000000000000000000005771414270267200250520ustar00rootroot00000000000000:mod:`traits.trait_numeric` Module ================================== .. automodule:: traits.trait_numeric :no-members: Classes ------- .. autoclass:: AbstractArray :show-inheritance: .. autoclass:: Array :show-inheritance: .. autoclass:: ArrayOrNone :show-inheritance: .. autoclass:: CArray :show-inheritance: Function -------- .. autofunction:: dtype2trait traits-6.3.2/docs/source/traits_api_reference/trait_set_object.rst000066400000000000000000000003551414270267200255230ustar00rootroot00000000000000:mod:`traits.trait_set_object` Module ===================================== .. automodule:: traits.trait_set_object :no-members: Classes ------- .. autoclass:: TraitSetEvent .. autoclass:: TraitSet .. autoclass:: TraitSetObject traits-6.3.2/docs/source/traits_api_reference/trait_type.rst000066400000000000000000000006051414270267200243610ustar00rootroot00000000000000:mod:`traits.trait_type` Module =============================== .. automodule:: traits.trait_type :no-members: Classes ------- .. autodata:: NoDefaultSpecified .. autoclass:: TraitType Private Functions ----------------- .. autofunction:: traits.trait_type._infer_default_value_type .. autofunction:: traits.trait_type._write_only .. autofunction:: traits.trait_type._read_only traits-6.3.2/docs/source/traits_api_reference/trait_types.rst000066400000000000000000000116141414270267200245460ustar00rootroot00000000000000:mod:`traits.trait_types` Module ================================ .. automodule:: traits.trait_types :no-members: Traits ------ .. autoclass:: Any :show-inheritance: .. autoclass:: BaseInt :show-inheritance: .. autoclass:: Int :show-inheritance: .. autoclass:: BaseFloat :show-inheritance: .. autoclass:: Float :show-inheritance: .. autoclass:: BaseComplex :show-inheritance: .. autoclass:: Complex :show-inheritance: .. autoclass:: BaseStr :show-inheritance: .. autoclass:: Str :show-inheritance: .. autoclass:: Title :show-inheritance: .. autoclass:: BaseBytes :show-inheritance: .. autoclass:: Bytes :show-inheritance: .. autoclass:: BaseBool :show-inheritance: .. autoclass:: Bool :show-inheritance: .. autoclass:: BaseCInt :show-inheritance: .. autoclass:: CInt :show-inheritance: .. autoclass:: BaseCFloat :show-inheritance: .. autoclass:: CFloat :show-inheritance: .. autoclass:: BaseCComplex :show-inheritance: .. autoclass:: CComplex :show-inheritance: .. autoclass:: BaseCStr :show-inheritance: .. autoclass:: CStr :show-inheritance: .. autoclass:: BaseCBytes :show-inheritance: .. autoclass:: CBytes :show-inheritance: .. autoclass:: BaseCBool :show-inheritance: .. autoclass:: CBool :show-inheritance: .. autoclass:: String :show-inheritance: .. autoclass:: Regex :show-inheritance: .. autoclass:: Code :show-inheritance: .. autoclass:: HTML :show-inheritance: .. autoclass:: Password :show-inheritance: .. autoclass:: BaseCallable :show-inheritance: .. autoclass:: Callable :show-inheritance: .. autoclass:: BaseType :show-inheritance: .. autoclass:: This :show-inheritance: .. autoclass:: self :show-inheritance: .. autoclass:: Function :show-inheritance: .. autoclass:: Method :show-inheritance: .. autoclass:: Module :show-inheritance: .. autoclass:: Python :show-inheritance: .. autoclass:: ReadOnly :show-inheritance: .. autoclass:: Disallow :show-inheritance: .. autoclass:: Constant :show-inheritance: .. autoclass:: Delegate :show-inheritance: .. autoclass:: DelegatesTo :show-inheritance: .. autoclass:: PrototypedFrom :show-inheritance: .. autoclass:: Expression :show-inheritance: .. autoclass:: PythonValue :show-inheritance: .. autoclass:: BaseFile :show-inheritance: .. autoclass:: File :show-inheritance: .. autoclass:: BaseDirectory :show-inheritance: .. autoclass:: Directory :show-inheritance: .. autoclass:: BaseRange :show-inheritance: .. autoclass:: Range :show-inheritance: .. autoclass:: BaseEnum :show-inheritance: .. autoclass:: Enum :show-inheritance: .. autoclass:: BaseTuple :show-inheritance: .. autoclass:: Tuple :show-inheritance: .. autoclass:: ValidatedTuple :show-inheritance: .. autoclass:: List :show-inheritance: .. autoclass:: CList :show-inheritance: .. autoclass:: PrefixList :show-inheritance: .. autoclass:: Set :show-inheritance: .. autoclass:: CSet :show-inheritance: .. autoclass:: Dict :show-inheritance: .. autoclass:: Map :show-inheritance: .. autoclass:: PrefixMap :show-inheritance: .. autoclass:: BaseClass :show-inheritance: .. autoclass:: BaseInstance :show-inheritance: .. autoclass:: Instance :show-inheritance: .. autoclass:: Supports :show-inheritance: .. autoclass:: AdaptsTo :show-inheritance: .. autoclass:: Type :show-inheritance: .. autoclass:: Subclass :show-inheritance: .. autoclass:: Event :show-inheritance: .. autoclass:: Button :show-inheritance: .. autoclass:: ToolbarButton :show-inheritance: .. autoclass:: Either :show-inheritance: .. autoclass:: Union .. autoclass:: Symbol :show-inheritance: .. autoclass:: UUID :show-inheritance: .. autoclass:: WeakRef :show-inheritance: .. autoclass:: Date :show-inheritance: .. autoclass:: Datetime :show-inheritance: .. autoclass:: Time :show-inheritance: Deprecated Traits ----------------- The following :class:`~.TraitType` classes and instances are deprecated, and may be removed in a future version of Traits. .. deprecated:: 6.0.0 .. autodata:: AdaptedTo .. autodata:: BaseUnicode .. autodata:: Unicode .. autodata:: BaseCUnicode .. autodata:: CUnicode .. autodata:: BaseLong .. autodata:: Long .. autodata:: BaseCLong .. autodata:: CLong .. autodata:: false .. autodata:: true .. autodata:: undefined .. autodata:: ListInt .. autodata:: ListFloat .. autodata:: ListStr .. autodata:: ListUnicode .. autodata:: ListComplex .. autodata:: ListBool .. autodata:: ListFunction .. autodata:: ListMethod .. autodata:: ListThis .. autodata:: DictStrAny .. autodata:: DictStrStr .. autodata:: DictStrInt .. autodata:: DictStrFloat .. autodata:: DictStrBool .. autodata:: DictStrList Private Classes --------------- .. autoclass:: HandleWeakRef Functions --------- .. autofunction:: default_text_editor traits-6.3.2/docs/source/traits_api_reference/traits.adaptation.rst000066400000000000000000000017121414270267200256260ustar00rootroot00000000000000:mod:`traits.adaptation` Package ================================ .. automodule:: traits.adaptation :members: :undoc-members: :show-inheritance: :mod:`traits.adaptation.adaptation_error` Module ------------------------------------------------ .. automodule:: traits.adaptation.adaptation_error :members: :undoc-members: :show-inheritance: :mod:`traits.adaptation.adaptation_manager` Module -------------------------------------------------- .. automodule:: traits.adaptation.adaptation_manager :members: :undoc-members: :show-inheritance: :mod:`traits.adaptation.adaptation_offer` Module ------------------------------------------------ .. automodule:: traits.adaptation.adaptation_offer :members: :undoc-members: :show-inheritance: :mod:`traits.adaptation.adapter` Module --------------------------------------- .. automodule:: traits.adaptation.adapter :members: :undoc-members: :show-inheritance: traits-6.3.2/docs/source/traits_api_reference/traits.etsconfig.rst000066400000000000000000000004341414270267200254630ustar00rootroot00000000000000:mod:`traits.etsconfig` Package =============================== .. automodule:: traits.etsconfig :no-members: :mod:`traits.etsconfig.etsconfig` Module ---------------------------------------- .. automodule:: traits.etsconfig.etsconfig :no-members: .. autodata:: ETSConfig traits-6.3.2/docs/source/traits_api_reference/traits.observation.rst000066400000000000000000000031211414270267200260310ustar00rootroot00000000000000:mod:`traits.observation` Package ================================= .. automodule:: traits.observation :members: :undoc-members: :show-inheritance: :mod:`traits.observation.exception_handling` Module --------------------------------------------------- .. automodule:: traits.observation.exception_handling :members: :undoc-members: :show-inheritance: :mod:`traits.observation.exceptions` Module --------------------------------------------- .. automodule:: traits.observation.exceptions :members: :undoc-members: :show-inheritance: :mod:`traits.observation.api` Module ------------------------------------ .. automodule:: traits.observation.api :members: :undoc-members: :show-inheritance: :mod:`traits.observation.expression` Module ------------------------------------------- .. automodule:: traits.observation.expression :members: :undoc-members: :show-inheritance: :special-members: __eq__, __or__ :mod:`traits.observation.events` Module --------------------------------------- .. automodule:: traits.observation.events :members: :undoc-members: :show-inheritance: .. autoclass:: DictChangeEvent :members: :inherited-members: .. autoclass:: ListChangeEvent :members: :inherited-members: .. autoclass:: SetChangeEvent :members: :inherited-members: .. autoclass:: TraitChangeEvent :members: :inherited-members: :mod:`traits.observation.parsing` Module ---------------------------------------- .. automodule:: traits.observation.parsing :members: :undoc-members: :show-inheritance: traits-6.3.2/docs/source/traits_api_reference/traits.rst000066400000000000000000000007431414270267200235060ustar00rootroot00000000000000:mod:`traits.traits` Module =========================== .. automodule:: traits.traits :no-members: .. currentmodule:: traits.traits Classes ------- .. autoclass:: Default .. autoclass:: ForwardProperty Functions --------- .. autofunction:: Trait .. autofunction:: Property .. autofunction:: Color .. autofunction:: RGBColor .. autofunction:: Font Private Classes --------------- .. autoclass:: traits.traits._InstanceArgs .. autoclass:: traits.traits._TraitMaker traits-6.3.2/docs/source/traits_api_reference/traits.testing.rst000066400000000000000000000016371414270267200251650ustar00rootroot00000000000000:mod:`traits.testing` Package ============================= .. automodule:: traits.testing :members: :undoc-members: :show-inheritance: :mod:`traits.testing.doctest_tools` Module ------------------------------------------ .. automodule:: traits.testing.doctest_tools :members: :undoc-members: :show-inheritance: :mod:`traits.testing.nose_tools` Module --------------------------------------- .. automodule:: traits.testing.nose_tools :members: :undoc-members: :show-inheritance: :mod:`traits.testing.optional_dependencies` Module -------------------------------------------------- .. automodule:: traits.testing.optional_dependencies :members: :undoc-members: :show-inheritance: :mod:`traits.testing.unittest_tools` Module ------------------------------------------- .. automodule:: traits.testing.unittest_tools :members: :undoc-members: :show-inheritance: traits-6.3.2/docs/source/traits_api_reference/traits.util.rst000066400000000000000000000035511414270267200244620ustar00rootroot00000000000000:mod:`traits.util` Package ========================== .. automodule:: traits.util :members: :undoc-members: :show-inheritance: :mod:`traits.util.async_trait_wait` Module ------------------------------------------ .. automodule:: traits.util.async_trait_wait :members: :undoc-members: :show-inheritance: :mod:`traits.util.camel_case` Module ------------------------------------ .. automodule:: traits.util.camel_case :members: :undoc-members: :show-inheritance: :mod:`traits.util.clean_strings` Module --------------------------------------- .. automodule:: traits.util.clean_strings :members: :undoc-members: :show-inheritance: :mod:`traits.util.deprecated` Module ------------------------------------ .. automodule:: traits.util.deprecated :members: :undoc-members: :show-inheritance: :mod:`traits.util.home_directory` Module ---------------------------------------- .. automodule:: traits.util.home_directory :members: :undoc-members: :show-inheritance: :mod:`traits.util.resource` Module ---------------------------------- .. automodule:: traits.util.resource :members: :undoc-members: :show-inheritance: :mod:`traits.util.import_symbol` Module --------------------------------------- .. automodule:: traits.util.import_symbol :members: :undoc-members: :show-inheritance: :mod:`traits.util.toposort` Module ---------------------------------- .. automodule:: traits.util.toposort :members: :undoc-members: :show-inheritance: :mod:`traits.util.trait_documenter` Module ------------------------------------------ .. automodule:: traits.util.trait_documenter :members: :undoc-members: :show-inheritance: :mod:`traits.util.event_tracer` Module -------------------------------------- .. automodule:: traits.util.event_tracer :members: :undoc-members: traits-6.3.2/docs/source/traits_api_reference/traits_listener.rst000066400000000000000000000002531414270267200254070ustar00rootroot00000000000000:mod:`traits.traits_listener` Module ==================================== .. automodule:: traits.traits_listener :members: :undoc-members: :show-inheritance: traits-6.3.2/docs/source/traits_api_reference/version.rst000066400000000000000000000002651414270267200236640ustar00rootroot00000000000000:mod:`traits.version` Module ============================ .. automodule:: traits.version :no-members: Attributes ---------- .. autodata:: version .. autodata:: git_revision traits-6.3.2/docs/source/traits_tutorial/000077500000000000000000000000001414270267200205165ustar00rootroot00000000000000traits-6.3.2/docs/source/traits_tutorial/index.rst000066400000000000000000000001671414270267200223630ustar00rootroot00000000000000Traits |version| Tutorial ========================= Tutorial -------- .. toctree:: :maxdepth: 3 introduction traits-6.3.2/docs/source/traits_tutorial/introduction.rst000066400000000000000000000046251414270267200240000ustar00rootroot00000000000000============ Introduction ============ This tutorial is intended to introduce you to the basics of Traits and to give you an idea of what capabilities the Traits library provides. This tutorial assumes that you are comfortable with the Python programming language, object-oriented programming, and the core tools of the Python scientific ecosystem, such as NumPy. This tutorial is designed to introduce the basics of Traits, but also to explain *why* you might want to use Traits in your own code. An interactive version of this tutorial can be accessed using the `ETS Demo application `_. .. include:: ../../../traits/examples/introduction/0_introduction.py :start-after: """ :end-before: """ .. literalinclude:: ../../../traits/examples/introduction/0_introduction.py :start-at: import datetime Links ----- - :download:`Source code <../../../traits/examples/introduction/0_introduction.py>` .. include:: ../../../traits/examples/introduction/1_validation.py :start-after: """ :end-before: """ Links ----- - :ref:`defining-traits-initialization-and-validation` - :download:`Source code <../../../traits/examples/introduction/1_validation.py>` .. include:: ../../../traits/examples/introduction/2_initialization.py :start-after: """ :end-before: """ Links ----- - :ref:`defining-traits-initialization-and-validation` - :download:`Source code <../../../traits/examples/introduction/2_initialization.py>` .. include:: ../../../traits/examples/introduction/3_observation.py :start-after: """ :end-before: """ Links ----- - :ref:`observe-notification` - :download:`Source code <../../../traits/examples/introduction/3_observation.py>` .. include:: ../../../traits/examples/introduction/4_properties.py :start-after: """ :end-before: """ Links ----- - :ref:`property-traits` - :download:`Source code <../../../traits/examples/introduction/4_properties.py>` .. include:: ../../../traits/examples/introduction/5_documentation.py :start-after: """ :end-before: """ Links ----- - :ref:`hasstricttraits` - :download:`Source code <../../../traits/examples/introduction/5_documentation.py>` .. include:: ../../../traits/examples/introduction/6_visualization.py :start-after: """ :end-before: """ Links ----- - `TraitsUI Documentation `_ - :download:`Source code <../../../traits/examples/introduction/6_visualization.py>` traits-6.3.2/docs/source/traits_user_manual/000077500000000000000000000000001414270267200211665ustar00rootroot00000000000000traits-6.3.2/docs/source/traits_user_manual/advanced.rst000066400000000000000000001622021414270267200234700ustar00rootroot00000000000000.. _advanced-topics: =============== Advanced Topics =============== The preceding sections provide enough information for you to use traits for manifestly-typed attributes, with initialization and validation. This section describes the advanced features of the Traits package .. _initialization-and-validation-revisited: Initialization and Validation Revisited --------------------------------------- The following sections present advanced topics related to the initialization and validation features of the Traits package. * Dynamic initialization * Overriding default values * Reusing trait definitions * Trait attribute definition strategies .. index:: initialization; dynamic .. _dynamic-initialization: Dynamic Initialization `````````````````````` When you define trait attributes using predefined traits, the Trait() factory function or trait handlers, you typically specify their default values statically. You can also define a method that dynamically initializes a trait attribute. To do this, you define a method on the same class as the trait attribute, with a name based on the name of the trait attribute: .. index:: default value; method .. method:: _name_default() This method returns the default value for the *name* trait attribute and it overrides any default value specified in the trait definition. Similar to static default values, default values defined dynamically should be thought of as existing **prior to** setting object state during initialization. For performance purposes, a default initializer method is called when: 1. the attribute value is accessed the first time or 2. an instance is constructed with a specific value, if there is a change handler defined for the trait. This is needed so the default can be reported as the old value (see :ref:`static-notification`). While it is possible to use a default initializer method to lazily initialize attributes based on the object state post-instantiation, this relies on not having to observe for changes on the trait. This is often difficult in practice, since trait notifications can be set up by external objects, and are often needed for Property traits, delegation and GUI applications. These use cases may cause the default values to be computed eagerly prior to instantiation, instead of lazily after instantiation. .. index:: get_default_value() It is also possible to define a dynamic method for the default value in a trait type subclass (get_default_value()). However, using a _\ *name*\ _default() method avoids the overhead of subclassing a trait. .. index:: default value; overriding in a subclass .. index:: pair: examples; overriding default values .. _overriding-default-values-in-a-subclass: Overriding Default Values in a Subclass ``````````````````````````````````````` Often, a subclass must override a trait attribute in a parent class by providing a different default value. You can specify a new default value without completely re-specifying the trait definition for the attribute. For example:: # override_default.py -- Example of overriding a default value for # a trait attribute in a subclass from traits.api import HasTraits, Range, Str class Employee(HasTraits): name = Str salary_grade = Range(value=1, low=1, high=10) class Manager(Employee): salary_grade = 5 In this example, the **salary_grade** of the Employee class is a range from 1 to 10, with a default value of 1. In the Manager subclass, the default value of **salary_grade** is 5, but it is still a range as defined in the Employee class. .. index:: trait; definitions; reusing .. _reusing-trait-definitions: Reusing Trait Definitions ````````````````````````` As mentioned in :ref:`defining-traits-initialization-and-validation`, in most cases, traits are defined in-line in attribute definitions, but they can also be defined independently. A trait definition only describes the characteristics of a trait, and not the current value of a trait attribute, so it can be used in the definition of any number of attributes. For example:: # trait_reuse.py --- Example of reusing trait definitions from traits.api import HasTraits, Range coefficient = Range(-1.0, 1.0, 0.0)) class quadratic(HasTraits): c2 = coefficient c1 = coefficient c0 = coefficient x = Range(-100.0, 100.0, 0.0) In this example, a trait named **coefficient** is defined externally to the class **quadratic**, which references **coefficient** in the definitions of its trait attributes **c2**, **c1**, and **c0**. Each of these attributes has a unique value, but they all use the same trait definition to determine whether a value assigned to them is valid. .. index:: explicit trait attribute definition .. _trait-attribute-definition-strategies: Trait Attribute Definition Strategies ````````````````````````````````````` In the preceding examples in this guide, all trait attribute definitions have bound a single object attribute to a specified trait definition. This is known as "explicit" trait attribute definition. The Traits package supports other strategies for defining trait attributes. You can associate a category of attributes with a particular trait definition, using the trait attribute name wildcard. You can also dynamically create trait attributes that are specific to an instance, using the add_trait() method, rather than defined on a class. These strategies are described in the following sections. .. index:: wildcard; trait attribute names pair: wildcard; examples .. _trait-attribute-name-wildcard: Trait Attribute Name Wildcard ::::::::::::::::::::::::::::: The Traits package enables you to define a category of trait attributes associated with a particular trait definition, by including an underscore ('_') as a wildcard at the end of a trait attribute name. For example:: # temp_wildcard.py --- Example of using a wildcard with a Trait # attribute name from traits.api import Any, HasTraits class Person(HasTraits): temp_ = Any This example defines a class Person, with a category of attributes that have names beginning with ``temp``, and that are defined by the Any trait. Thus, any part of the program that uses a Person instance can reference attributes such as **tempCount**, **temp_name**, or **temp_whatever**, without having to explicitly declare these trait attributes. Each such attribute has None as the initial value and allows assignment of any value (because it is based on the Any trait). You can even give all object attributes a default trait definition, by specifying only the wildcard character for the attribute name:: # all_wildcard.py --- Example of trait attribute wildcard rules from traits.api import Any, HasTraits, Int, Str class Person ( HasTraits ): # Normal, explicitly defined trait: name = Str # By default, let all traits have any value: _ = Any # Except for this one, which must be an Int: age = Int """ >>> bill = Person() >>> # These assignments should all work: >>> bill.name = 'William' >>> bill.address = '121 Drury Lane' >>> bill.zip_code = 55212 >>> bill.age = 49 >>> # This should generate an error (must be an Int): >>> bill.age = 'middle age' Traceback (most recent call last): File "all_wildcard.py", line 33, in bill.age = 'middle age' File "c:\wrk\src\lib\enthought\traits\\trait_handlers.py", line 163, in error raise TraitError( object, name, self.info(), value ) TraitError: The 'age' trait of a Person instance must be an integer, but a value of 'middle age' was specified. """ In this case, all Person instance attributes can be created on the fly and are defined by the Any trait. .. index:: wildard; rules .. _wildcard-rules: Wildcard Rules '''''''''''''' When using wildcard characters in trait attribute names, the following rules are used to determine what trait definition governs an attribute: 1. If an attribute name exactly matches a name without a wildcard character, that definition applies. 2. Otherwise, if an attribute name matches one or more names with wildcard characters, the definition with the longest name applies. Note that all possible attribute names are covered by one of these two rules. The base HasTraits class implicitly contains the attribute definition ``_ = Python``. This rule guarantees that, by default, all attributes have standard Python language semantics. These rules are demonstrated by the following example:: # wildcard_rules.py -- Example of trait attribute wildcard rules from traits.api import Any, HasTraits, Int, Python class Person(HasTraits): temp_count = Int(-1) temp_ = Any _ = Python In this example, the Person class has a **temp_count** attribute, which must be an integer and which has an initial value of -1. Any other attribute with a name starting with ``temp`` has an initial value of None and allows any value to be assigned. All other object attributes behave like normal Python attributes (i.e., they allow any value to be assigned, but they must have a value assigned to them before their first reference). .. index:: Disallow; object, examples; Disallow object .. _disallow-object: Disallow Object ''''''''''''''' The singleton object Disallow can be used with wildcards to disallow all attributes that are not explicitly defined. For example:: # disallow.py --- Example of using Disallow with wildcards from traits.api import \ Disallow, Float, HasTraits, Int, Str class Person (HasTraits): name = Str age = Int weight = Float _ = Disallow In this example, a Person instance has three trait attributes: * **name**: Must be a string; its initial value is ''. * **age**: Must be an integer; its initial value is 0. * **weight**: Must be a float; its initial value is 0.0. All other object attributes are explicitly disallowed. That is, any attempt to read or set any object attribute other than **name**, **age**, or **weight** causes an exception. .. index:: HasTraits class; predefined subclasses .. _hastraits-subclasses: HasTraits Subclasses '''''''''''''''''''' Because the HasTraits class implicitly contains the attribute definition ``_ = Python``, subclasses of HasTraits by default have very standard Python attribute behavior for any attribute not explicitly defined as a trait attribute. However, the wildcard trait attribute definition rules make it easy to create subclasses of HasTraits with very non-standard attribute behavior. Two such subclasses are predefined in the Traits package: HasStrictTraits and HasPrivateTraits. .. index:: HasStrictTraits class .. _hasstricttraits: HasStrictTraits ''''''''''''''' This class guarantees that accessing any object attribute that does not have an explicit or wildcard trait definition results in an exception. This can be useful in cases where a more rigorous software engineering approach is employed than is typical for Python programs. It also helps prevent typos and spelling mistakes in attribute names from going unnoticed; a misspelled attribute name typically causes an exception. The definition of HasStrictTraits is the following:: class HasStrictTraits(HasTraits): _ = Disallow HasStrictTraits can be used to create type-checked data structures, as in the following example:: class TreeNode(HasStrictTraits): left = This right = This value = Str This example defines a TreeNode class that has three attributes: **left**, **right**, and **value**. The **left** and **right** attributes can only be references to other instances of TreeNode (or subclasses), while the **value** attribute must be a string. Attempting to set other types of values generates an exception, as does attempting to set an attribute that is not one of the three defined attributes. In essence, TreeNode behaves like a type-checked data structure. .. index:: HasRequiredTraits class .. _hasrequiredtraits: HasRequiredTraits ''''''''''''''''' This subclass of :ref:`hasstricttraits` ensures that any object attribute with ``required=True`` in its metadata must be passed as an argument on object initialization. An example of a class with required traits:: class RequiredTest(HasRequiredTraits): required_trait = Any(required=True) non_required_trait = Any() All required traits have to be provided as arguments on creating a new instance:: >>> new_instance = RequiredTest(required_trait=13.0) Non-required traits can also still be provided as usual:: >>> new_instance = RequiredTest(required_trait=13.0, non_required_trait=14.0) However, omitting a required trait will raise a TraitError:: >>> new_instance = RequiredTest(non_required_trait=14.0) traits.trait_errors.TraitError: The following required traits were not provided: required_trait. .. index:: HasPrivateTraits class .. _hasprivatetraits: HasPrivateTraits '''''''''''''''' This class is similar to HasStrictTraits, but allows attributes beginning with '_' to have an initial value of None, and to not be type-checked. This is useful in cases where a class needs private attributes, which are not part of the class's public API, to keep track of internal object state. Such attributes do not need to be type-checked because they are only manipulated by the (presumably correct) methods of the class itself. The definition of HasPrivateTraits is the following:: class HasPrivateTraits(HasTraits): __ = Any _ = Disallow These subclasses of HasTraits are provided as a convenience, and their use is completely optional. However, they do illustrate how easy it is to create subclasses with customized default attribute behavior if desired. .. index:: trait attributes; per-object .. _per-object-trait-attributes: Per-Object Trait Attributes ''''''''''''''''''''''''''' The Traits package allows you to define dynamic trait attributes that are object-, rather than class-, specific. This is accomplished using the add_trait() method of the HasTraits class: .. method:: add_trait(name, trait) .. index:: examples; per-object trait attributes For example:: # object_trait_attrs.py --- Example of per-object trait attributes from traits.api import HasTraits, Range class GUISlider (HasTraits): def __init__(self, eval=None, label='Value', trait=None, min=0.0, max=1.0, initial=None, **traits): HasTraits.__init__(self, **traits) if trait is None: if min > max: min, max = max, min if initial is None: initial = min elif not (min <= initial <= max): initial = [min, max][ abs(initial - min) > abs(initial - max)] trait = Range(min, max, value = initial) self.add_trait(label, trait) This example creates a GUISlider class, whose __init__() method can accept a string label and either a trait definition or minimum, maximum, and initial values. If no trait definition is specified, one is constructed based on the **max** and **min** values. A trait attribute whose name is the value of label is added to the object, using the trait definition (whether specified or constructed). Thus, the label trait attribute on the GUISlider object is determined by the calling code, and added in the __init__() method using add_trait(). You can require that add_trait() must be used in order to add attributes to a class, by deriving the class from HasStrictTraits (see :ref:`hasstricttraits`). When a class inherits from HasStrictTraits, the program cannot create a new attribute (either a trait attribute or a regular attribute) simply by assigning to it, as is normally the case in Python. In this case, add_trait() is the only way to create a new attribute for the class outside of the class definition. .. index:: interfaces .. _interfaces: Interfaces ---------- The Traits package supports declaring and implementing *interfaces*. An interface is an abstract data type that defines a set of attributes and methods that an object must have to work in a given situation. The interface says nothing about what the attributes or methods do, or how they do it; it just says that they have to be there. Interfaces in Traits are similar to those in Java. They can be used to declare a relationship among classes which have similar behavior but do not have an inheritance relationship. Like Traits in general, Traits interfaces don't make anything possible that is not already possible in Python, but they can make relationships more explicit and enforced. Python programmers routinely use implicit, informal interfaces (what's known as "duck typing"). Traits allows programmers to define explicit and formal interfaces, so that programmers reading the code can more easily understand what kinds of objects are actually *intended* to be used in a given situation. .. index:: interfaces; defining, examples; interface definition .. _defining-an-interface: Defining an Interface ````````````````````` To define an interface, create a subclass of Interface:: from traits.api import Interface class IName(Interface): def get_name(self): """ Returns a string which is the name of an object. """ Interface classes serve primarily as documentation of the methods and attributes that the interface defines. In this case, a class that implements the ``IName`` interface must have a method named ``get_name()``, which takes no arguments and returns a string. Do not include any implementation code in an interface declaration. However, the Traits package does not actually check to ensure that interfaces do not contain implementations. By convention, interface names have a capital 'I' at the beginning of the name. .. index:: interfaces; implementing .. _implementing-an-interface: Implementing an Interface ````````````````````````` A class declares that it implements one or more interfaces using the :func:`~traits.api.provides` class decorator, which has the signature: .. currentmodule:: traits.has_traits .. function:: provides(interface[, interface2 , ... , interfaceN]) :noindex: .. index:: examples; interface implementation, interfaces; implementation; example Interface names beyond the first one are optional. As for all class decorators, the call to provides must occur just before the class definition. For example:: from traits.api import HasTraits, Interface, provides, Str class IName(Interface): def get_name(self): """ Returns a string which is the name of an object. """ @provides(IName) class Person(HasTraits): first_name = Str( 'John' ) last_name = Str( 'Doe' ) # Implementation of the 'IName' interface: def get_name ( self ): ''' Returns the name of an object. ''' name = '{first} {last}' return name.format(name=self.first_name, last=self.last_name) You can specify whether the provides() decorator verifies that the class calling it actually implements the interface that it says it does. This is determined by the CHECK_INTERFACES variable, which can take one of three values: * 0 (default): Does not check whether classes implement their declared interfaces. * 1: Verifies that classes implement the interfaces they say they do, and logs a warning if they don't. * 2: Verifies that classes implement the interfaces they say they do, and raises an InterfaceError if they don't. The CHECK_INTERFACES variable must be imported directly from the traits.has_traits module:: import traits.has_traits traits.has_traits.CHECK_INTERFACES = 1 .. deprecated:: 6.2.0 Interface checking with the ``@provides`` decorator is deprecated. In the future, the ``@provides`` decorator will ignore the value of ``CHECK_INTERFACES`` and will not do any interface checking. .. index:: interfaces; using, examples; interface usage .. _using-interfaces: Using Interfaces ```````````````` You can use an interface at any place where you would normally use a class name. The most common way to use interfaces is with the :class:`~traits.trait_types.Instance` or :class:`~traits.trait_types.Supports` traits:: >>> from traits.api import HasTraits, Instance >>> class Apartment(HasTraits): ... renter = Instance(IName) >>> william = Person(first_name='William', last_name='Adams') >>> apt1 = Apartment( renter=william ) >>> print 'Renter is: ', apt1.renter.get_name() Renter is: William Adams Using an interface class with an ``Instance`` trait definition declares that the trait accepts only values that implement the specified interface. Using the ``Supports`` traits, if the assigned object does not implement the interface, the Traits package may automatically substitute an adapter object that implements the specified interface. See :ref:`adaptation` for more information. .. index:: adaptation .. _adaptation: Adaptation ---------- *The adaptation features of Traits have been rewritten in v. 4.4.0 . See the* :ref:`migration guide ` *below for details regarding changes in API.* Adaptation is the process of transforming an object that does not implement a specific interface needed by a client into an object that does. In the adapter pattern, an object is wrapped in a second object, the *adapter*, that implements the target interface. Adaptation enables a programming style in which each component or service in an application defines an interface through which it would like to receive information. Objects that need to communicate with the component declare an adapter for that interface, as illustrated in the figure below. .. image:: images/adaptation.png Adaptation allows decoupling the data model from the application components and services: introducing a new component in the application should not require modifying the data objects! Traits provides a package to make this pattern easy and automatic: In the :mod:`traits.adaptation` package, adapters from a protocol (type or interface) to another can be registered with a manager object. HasTraits classes can either explicitly request to adapt an object to a protocol, or they can define special traits that automatically invoke the adaptation manager whenever it is necessary. For example, if a :class:`~traits.trait_types.Supports` trait requires its values to implement interface ``IPrintable``, and an object is assigned to it which is of class ``Image``, which does not implement ``IPrintable``, then Traits looks for an adapter from ``Image`` to ``IPrintable``, and if one exists the adapter object is assigned to the trait. If necessary, a "chain" of adapter objects might be created, in order to perform the required adaptation. Main features ````````````` The main features of the :mod:`traits.adaptation` package are: * Support for Python classes, ABCs, and traits :class:`~.Interface` s Protocols can be specified using any of those. * Chaining of adapters Adapters can be chained, i.e., an object can be adapted to a target protocol as long as there is a sequence of adapters that can be used to transform it. * Conditional adaptation Adaptation of an object to a protocol can be conditional, i.e. it may succeed or fail depending on the state of the object. * Lazy loading The classes for the adapter, the origin, and the target protocols can be specified as strings, and are only loaded if they are required. Note on terminology ``````````````````` To avoid confusion, let's define two terms that we will use all the time: * We say that a class *provides* a protocol if it is a subclass of the protocol, or if it implements the protocol (if it is an interface) * We say that a class *supports* a protocol if it provides the protocol or an adapter object can be built that provides the protocol .. index:: adapters; defining .. _defining-adapters: Defining Adapters ````````````````` .. index:: Adapter class .. _subclassing-adapter: The :class:`Adapter` class :::::::::::::::::::::::::: The Traits package provides two classes for defining adapters, one for Traits adapters, :class:`~traits.adaptation.adapter.Adapter`, and one for for pure-Python adapters, :class:`~traits.adaptation.adapter.PurePythonAdapter`. These classes streamline the process of creating a new adapter class. They have a standard constructor that does not normally need to be overridden by subclasses. This constructor accepts one parameter, which is the object to be adapted, and assigns that object to an :attr:`adaptee` attribute (a trait in the case of :class:`~traits.adaptation.adapter.Adapter`). As an adapter writer, you need to take care of the following: * Declare which interfaces the adapter class implements on behalf of the object it is adapting. For example, if we are working with Traits :class:`~.Interface` s, the adapter would be decorated with the :func:`~traits.has_traits.provides` decorator. In the case of Python ABCs, the class would be a subclass of the abstract base class, or be `registered with it `_. * Implement the methods defined in the interfaces declared in the previous step. Usually, these methods are implemented using appropriate members on the adaptee object. .. index:: adaptee trait * For Traits adapters, define a trait attribute named **adaptee** that declares what type of object it is an adapter for. Usually, this is an :class:`~.Instance` trait. .. index:: pair: example; Adapter class The following code example shows a definition of a simple adapter class:: from traits.api import Adapter, Instance, provides # Declare what interfaces this adapter implements for its client @provides(IName) class PersonToIName(Adapter): # Declare the type of client it supports: adaptee = Instance(Person) # Implement the 'IName' interface on behalf of its client: def get_name ( self ): name = '{first} {last}'.format(first=self.adaptee.first_name, last=self.adaptee.last_name) return name .. index:: pair: registering; adapters .. _registering-adapters: Registering adapters :::::::::::::::::::: Once an adapter class has been defined, it has to be registered with the adaptation manager using the :func:`~traits.adaptation.api.register_factory` function. The signature of :func:`~traits.adaptation.api.register_factory` is: .. currentmodule:: traits.adaptation.api .. function:: register_factory(adapter_class, from_protocol, to_protocol) :noindex: The :func:`~traits.adaptation.adaptation_manager.register_factory` function takes as first argument the adapter class (or an :ref:`adapter factory `), followed by the protocol to be adapted (the one provided by the adaptee, :attr:`from_protocol`), and the protocol that it provides (:attr:`to_protocol`). .. index:: examples; registering adapters This is the example from the previous section, were the adapter is registered:: from traits.adaptation.api import Adapter, Instance, provides # Declare what interfaces this adapter implements for its client @provides(IName) class PersonToIName(Adapter): # Declare the type of client it supports: adaptee = Instance(Person) # Implement the 'IName' interface on behalf of its client: def get_name ( self ): name = '{first} {last}'.format(first=self.adaptee.first_name, last=self.adaptee.last_name) return name # ... somewhere else at application startup. register_factory(PersonToIName, Person, IName) .. index:: adapters; factory; factories; conditional adaptation .. _adapter-factories: Adapter factories, and conditional adaptation ````````````````````````````````````````````` The first argument to the :func:`~traits.adaptation.api.register_factory` function needs not be an adapter *class*, it can be, more generally, an adapter *factory*. An adapter factory can be any callable that accepts one positional argument, the adaptee object, and returns an adapter or None if the adaptation was not possible. Adapter factories allow flexibility in the adaptation process, as the result of adaptation may vary depending on the state of the adaptee object. .. _conditional-adaptation: Conditional adaptation :::::::::::::::::::::: A common use of adapter factories is to allow adaptation only if the state of the adaptee object allows it. The factory returns an adapter object if adaptation is possible, or None if it is not. In the following example, a ``numpy.ndarray`` object can be adapted to provide an ``IImage`` protocol only if the number of dimensions is 2. (For illustration, this example uses Python ABCs rather than Traits Interfaces.) :: import abc import numpy from traits.api import Array, HasTraits from traits.adaptation.api import adapt, Adapter, register_factory class ImageABC(object): __metaclass__ = abc.ABCMeta class NDArrayToImage(Adapter): adaptee = Array # Declare that NDArrayToImage implements ImageABC. ImageABC.register(NDArrayToImage) def ndarray_to_image_abc(adaptee): """ An adapter factory from numpy arrays to the ImageABC protocol.""" if adaptee.ndim == 2: return NDArrayToImage(adaptee=adaptee) return None # ... somewhere else at application startup register_factory(ndarray_to_image_abc, numpy.ndarray, ImageABC) # Try to adapt numpy arrays to images. The `adapt` function is # introduced later in the docs, but you can probably guess what it does ;-) # This adaptation fails, as the array is 1D image = adapt(numpy.ndarray([1,2,3]), ImageABC, default=None) assert image == None # This succeeds. image = adapt(numpy.array([[1,2],[3,4]]), ImageABC) assert isinstance(image, NDArrayToImage) .. index:: pair: adapters; requesting .. _using-adapters: Requesting an adapter ````````````````````` The ``adapt`` function :::::::::::::::::::::: Adapter classes are defined as described in the preceding sections, but you do not explicitly create instances of these classes. Instead, the function :func:`~traits.adaptation.adaptation_manager.adapt` is used, giving the object that needs to be adapted and the target protocol. For instance, in the example in the :ref:`conditional-adaptation` section, a 2D numpy array is adapted to an ImageABC protocol with :: image = adapt(numpy.array([[1,2],[3,4]]), ImageABC) In some cases, no single adapter class is registered that adapts the object to the required interface, but a series of adapter classes exist that, together, perform the required adaptation. In such cases, the necessary set of adapter objects are created, and the "last" link in the chain, the one that actually implements the required interface, is returned. When a situation like this arises, the adapted object assigned to the trait always contains the smallest set of adapter objects needed to adapt the original object. Also, more specific adapters are preferred over less specific ones. For example, let's suppose we have a class ``Document`` and a subclass ``HTMLDocument``. We register two adapters to an interface ``IPrintable``, ``DocumentToIPrintable`` and ``HTMLDocumentToIPrintable``. The call :: html_doc = HTMLDocument() printable = adapt(html_doc, IPrintable) will return an instance of the ``HTMLDocumentToIPrintable`` adapter, as it is more specific than ``DocumentToIPrintable``. If no single adapter and no adapter chain can be constructed for the requested adaptation, an :class:`~traits.adaptation.adaptation_error.AdaptationError` is raised. Alternatively, one can specify a default value to be returned in this case:: printable = adapt(unprintable_doc, IPrintable, default=EmptyPrintableDoc()) Using Traits interfaces ::::::::::::::::::::::: An alternative syntax to create adapters when using Traits Interfaces is to use the interface class as an adapter factory, for example :: printable = IPrintable(html_doc, None) is equivalent to :: printable = adapt(html_doc, IPrintable, default=None) (the default argument, None, is optional). Using the ``Supports`` and ``AdaptsTo`` traits :::::::::::::::::::::::::::::::::::::::::::::: Using the terminology introduced in this section, we can say that the :class:`~.Instance` trait accepts values that *provide* the specified protocol. Traits defines two additional traits that accept values that *support* a given protocol (they provide it or can be adapted to it) instead: * The :class:`~.Supports` trait accepts values that support the specified protocol. The value of the trait after assignment is the possibly adapted value (i.e., it is the original assigned value if that provides the protocol, or is an adapter otherwise). * The :class:`~.AdaptsTo` trait also accepts values that support the specified protocol. Unlike ``Supports``, ``AdaptsTo`` stores the original, unadapted value. If your application works with adaptation, it is natural to use the ``Supports`` trait in place of the ``Instance`` one in most cases. This will allow that application to be extended by adaptation in the future without changing the existing code, without having to invoke adaptation explicitly in your code. For example, a Traits object can be written against the ``IPrintable`` interface and be open to extensions by adaptation as follows: :: from traits.api import (Adapter, HasTraits, Interface, List, provides, register_factory, Str, Supports) class IPrintable(Interface): def get_formatted_text(self, n_cols): """ Return text formatted with the given number of columns. """ class PrintQueue(HasTraits): # This is the key part of the example: we declare a list of # items that provide or can be adapted to IPrintable queue = List(Supports(IPrintable)) def is_empty(self): return len(self.queue) == 0 def push(self, printable): self.queue.append(printable) def print_next(self): printable = self.queue.pop(0) # The elements from the list are guaranteed to provide # IPrintable, so we can call the interface without worrying # about adaptation. lines = printable.get_formatted_text(n_cols=20) print('-- Start document --') print('\n'.join(lines)) print('-- End of document -\n') class TextDocument(HasTraits): """ A text document. """ text = Str @provides(IPrintable) class TextDocumentToIPrintable(Adapter): """ Adapt TextDocument and provide IPrintable. """ def get_formatted_text(self, n_cols): import textwrap return textwrap.wrap(self.adaptee.text, n_cols) # ---- Application starts here. # Register the adapter. register_factory(TextDocumentToIPrintable, TextDocument, IPrintable) # Create two text documents. doc1 = TextDocument(text='very very long text the will bore you for sure') doc2 = TextDocument(text='once upon a time in a far away galaxy') # The text documents can be pushed on the print queue; in the process, # they are automatically adapted by Traits. print_queue = PrintQueue() print_queue.push(doc1) print_queue.push(doc2) while not print_queue.is_empty(): print_queue.print_next() This scripts produces this output: :: -- Start document -- very very long text the will bore you for sure -- End of document - -- Start document -- once upon a time in a far away galaxy -- End of document - Implementation details `````````````````````` The algorithm for finding a sequence of adapters adapting an object ``adaptee`` to a protocol ``to_protocol`` is based on a weighted graph. Nodes on the graphs are protocols (types or interfaces). Edges are adaptation offers that connect a ``offer.from_protocol`` to a ``offer.to_protocol``. Edges connect protocol ``A`` to protocol ``B`` and are weighted by two numbers in this priority: 1) a unit weight (1) representing the fact that we use 1 adaptation offer to go from ``A`` to ``B`` 2) the number of steps up the type hierarchy that we need to take to go from ``A`` to ``offer.from_protocol``, so that more specific adapters are always preferred The algorithm finds the shortest weighted path between ``adaptee`` and ``to_protocol``. Once a candidate path is found, it tries to create the chain of adapters using the factories in the adaptation offers that compose the path. If this fails because of conditional adaptation (i.e., an adapter factory returns None), the path is discarded and the algorithm looks for the next shortest path. Cycles in adaptation are avoided by only considering path were every adaptation offer is used at most once. .. _migration: Migration guide ``````````````` The implementation of the adaptation mechanism changed in Traits 4.4.0 from one based on PyProtocols to a new, smaller, and more robust implementation. Code written against ``traits.protocols`` will not work any longer as the ``traits.protocols`` API has been removed in Traits 5.0.0 . This is a list of replacements for the old API: * :class:`traits.protocols.api.AdaptationFailure` Use :class:`traits.api.AdaptationError` instead. * :func:`traits.api.adapts` Use the :func:`traits.api.register_factory` function. * :func:`implements` Use the :func:`traits.api.provides` decorator instead. * :func:`traits.protocols.api.declareAdapter` Use the function :func:`traits.api.register_factory`, or the function :func:`traits.adaptation.api.register_offer` instead. It is no longer necessary to distinguish between "types", "protocols", and "objects". * :func:`traits.protocols.api.declareImplementation` This function was used occasionally to declare that an arbitrary type (e.g., ``dict``) implements an interface. Users that use Python ABCs can use the ``register`` method for achieving the same result. Otherwise, use the function :func:`traits.adaptation.api.register_provides` that declares a "null" adapter to adapt the type to the interface. * Testing if a class is an Interface ``issubclass(klass, Interface)`` is not reliable, use :func:`traits.api.isinterface` instead Gotchas ``````` 1) The methods :func:`~traits.adaptation.adaptation_manager.register_factory`, :func:`~traits.adaptation.adaptation_manager.adapt`, etc. use a global adaptation manager, which is accessible through the function :func:`~traits.adaptation.adaptation_manager.get_global_adaptation_manager`. The traits automatic adaptation features also use the global manager. Having a global adaptation manager can get you into trouble, for the usual reasons related to having a global state. If you want to have more control over adaptation, we recommend creating a new :class:`~traits.adaptation.adaptation_manager.AdaptationManager` instance, use it directly in your application, and set it as the global manager using :func:`~traits.adaptation.adaptation_manager.set_global_adaptation_manager`. A common issue with the global manager arises in unittesting, where adapters registered in one test influence the outcome of other tests downstream. Tests relying on adaptation should make sure to reset the state of the global adapter using :func:`~traits.adaptation.adaptation_manager.reset_global_adaptation_manager`. Recommended readings about adaptation ````````````````````````````````````` This is a list of interesting readings about adaptation and the adapter pattern outside of Traits: * `PyProtocols `_, a precursor of ``traits.adaptation`` * `PEP 246 `_ on object adaptation * `Article about adapters in Eclipse plugins `_ .. index:: property traits .. _property-traits: Property Traits --------------- The predefined Property() trait factory function defines a Traits-based version of a Python property, with "getter" and "setter" methods. This type of trait provides a powerful technique for defining trait attributes whose values depend on the state of other object attributes. In particular, this can be very useful for creating synthetic trait attributes which are editable or displayable in a TraitUI view. .. _property-factory-function: Property Factory Function ````````````````````````` The Property() function has the following signature: .. currentmodule:: traits.traits .. function:: Property( [fget=None, fset=None, fvalidate=None, force=False, handler=None, trait=None, **metadata] ) :noindex: All parameters are optional, including the *fget* "getter", *fvalidate* "validator" and *fset* "setter" methods. If no parameters are specified, then the trait looks for and uses methods on the same class as the attribute that the trait is assigned to, with names of the form _get_\ *name*\ (), _validate_\ *name*\ () and _set_\ *name*\ (), where *name* is the name of the trait attribute. If you specify a trait as either the *fget* parameter or the *trait* parameter, that trait's handler supersedes the *handler* argument, if any. Because the *fget* parameter accepts either a method or a trait, you can define a Property trait by simply passing another trait. For example:: source = Property( Code ) This line defines a trait whose value is validated by the Code trait, and whose getter and setter methods are defined elsewhere on the same class. If a Property trait has only a getter function, it acts as read-only; if it has only a setter function, it acts as write-only. It can lack a function due to two situations: * A function with the appropriate name is not defined on the class. * The *force* option is True, (which requires the Property() factory function to ignore functions on the class) and one of the access functions was not specified in the arguments. You can use the **observe** metadata attribute to indicate that the property depends on the value of another trait. The value of **observe** follows the same signature as the **expression** parameter in |HasTraits.observe|, which is also described in the :ref:`expression section `. The property will fire a trait change notification if any of the traits specified by **observe** change. For example:: class Wheel(Part): axle = Instance(Axle) position = Property(observe='axle.chassis.position') .. index:: property traits; caching value .. _caching-a-property-value: Caching a Property Value ```````````````````````` In some cases, the cost of computing the value of a property trait attribute may be very high. In such cases, it is a good idea to cache the most recently computed value, and to return it as the property value without recomputing it. When a change occurs in one of the attributes on which the cached value depends, the cache should be cleared, and the property value should be recomputed the next time its value is requested. .. index:: cached_property decorator, depends_on metadata One strategy to accomplish caching would be to use a private attribute for the cached value, and notification observer methods on the attributes that are depended on. However, to simplify the situation, Property traits support a |@cached_property| decorator and **observe** metadata. Use |@cached_property| to indicate that a getter method's return value should be cached. Use **observe** to indicate the other attributes that the property depends on. .. index:: examples; cached property For example: .. literalinclude:: /../../examples/tutorials/doc_examples/examples/cached_prop.py :start-at: from traits.api The |@cached_property| decorator takes no arguments. Place it on the line preceding the property's getter method. As mentioned above, the **observe** metadata attribute accepts extended trait references. As a result, it can take values that specify attributes on referenced objects, multiple attributes, or attributes that are selected based on their metadata attributes. .. index:: persistence, __getstate__(), __setstate__() .. _persistence: Persistence ----------- In version 3.0, the Traits package provides __getstate__() and __setstate__() methods on HasTraits, to implement traits-aware policies for serialization and deserialization (i.e., pickling and unpickling). .. index:: HasTraits class; pickling, pickling HasTraits objects .. _pickling-hastraits-objects: Pickling HasTraits Objects `````````````````````````` Often, you may wish to control for a HasTraits subclass which parts of an instance's state are saved, and which are discarded. A typical approach is to define a __getstate__() method that copies the object's __dict__ attribute, and deletes those items that should not be saved. This approach works, but can have drawbacks, especially related to inheritance. .. index:: transient; metadata The HasTraits __getstate__() method uses a more generic approach, which developers can customize through the use of traits metadata attributes, often without needing to override or define a __getstate__() method in their application classes. In particular, the HasTraits __getstate__() method discards the values of all trait attributes that have the **transient** metadata attribute set to True, and saves all other trait attributes. So, to mark which trait values should not be saved, you set **transient** to True in the metadata for those trait attributes. The benefits of this approach are that you do not need to override __getstate__(), and that the metadata helps document the pickling behavior of the class. .. index:: examples; transient metadata For example:: # transient_metadata.py -- Example of using 'transient' metadata from traits.api import HasTraits, File, Any class DataBase ( HasTraits ): # The name of the data base file: file_name = File # The open file handle used to access the data base: file = Any( transient = True ) In this example, the DataBase class's file trait is marked as transient because it normally contains an open file handle used to access a data base. Since file handles typically cannot be pickled and restored, the file handle should not be saved as part of the object's persistent state. Normally, the file handle would be re-opened by application code after the object has been restored from its persisted state. .. index:: transient; predefined traits .. _predefined-transient-traits: Predefined Transient Traits ``````````````````````````` A number of the predefined traits in the Traits package are defined with **transient** set to True, so you do not need to explicitly mark them. The automatically transient traits are: * Constant * Event * Read-only and write-only Property traits (See :ref:`property-factory-function`) * Shadow attributes for mapped traits (See :ref:`mapped-traits`) * Private attributes of HasPrivateTraits subclasses (See :ref:`hasprivatetraits`) * Delegate traits that do not have a local value overriding the delegation. Delegate traits with a local value are non-transient, i.e., they are serialized. (See :ref:`delegatesto`) You can mark a Delegate trait as transient if you do not want its value to ever be serialized. .. index:: __getstate__(); overriding .. _overriding_getstate: Overriding __getstate__() ````````````````````````` In general, try to avoid overriding __getstate__() in subclasses of HasTraits. Instead, mark traits that should not be pickled with ``transient = True`` metadata. However, in cases where this strategy is insufficient, use the following pattern to override __getstate__() to remove items that should not be persisted:: def __getstate__ ( self ): state = super().__getstate__() for key in [ 'foo', 'bar' ]: if key in state: del state[ key ] return state .. index:: unpickling HasTraits objects, HasTraits class; unpickling .. _unpicking-hastraits-objects: Unpickling HasTraits Objects ```````````````````````````` The __setstate__() method of HasTraits differs from the default Python behavior in one important respect: it explicitly sets the value of each attribute using the values from the state dictionary, rather than simply storing or copying the entire state dictionary to its **__dict__** attribute. While slower, this strategy has the advantage of generating trait change notifications for each attribute. These notifications are important for classes that rely on them to ensure that their internal object state remains consistent and up to date. .. note:: If you're manually creating state dictionaries for consumption by __setstate__(), you should be aware of an additional implementation detail: when pickling, the HasTraits __getstate__() method returns a dictionary with an extra ``'__traits_version__'`` key giving the version of Traits used at pickling time. If this key is not present when unpickling, the HasTraits __setstate__() method falls back to a compatibility mode and may not restore the state correctly. For the same reason, if you're overriding __getstate__(), you should be careful to make the appropriate ``super().__getstate__()`` call. .. index:: __setstate__(); overriding .. _overriding-setstate: Overriding __setstate__() ````````````````````````` You may wish to override the HasTraits __setstate__() method, for example for classes that do not need to receive trait change notifications, and where the overhead of explicitly setting each attribute is undesirable. You can override __setstate__() to update the object's __dict__ directly. However, in such cases, it is important ensure that trait notifications are properly set up so that later change notifications are handled. You can do this in two ways: * Call the __setstate__() super method (for example, with an empty state dictionary). * Call the HasTraits class's private _init_trait_listeners() method; this method has no parameters and does not return a result. .. index:: HasTraits class; methods .. _useful-methods-on-hastraits: Useful Methods on HasTraits --------------------------- The HasTraits class defines a number of methods, which are available to any class derived from it, i.e., any class that uses trait attributes. This section provides examples of a sampling of these methods. Refer to the *Traits API Reference* for a complete list of HasTraits methods. .. index:: add_trait() .. _add-trait: add_trait() ``````````` This method adds a trait attribute to an object dynamically, after the object has been created. For more information, see :ref:`per-object-trait-attributes`. .. index:: clone_traits() .. _clone-traits: clone_traits() `````````````` This method copies trait attributes from one object to another. It can copy specified attributes, all explicitly defined trait attributes, or all explicitly and implicitly defined trait attributes on the source object. This method is useful if you want to allow a user to edit a clone of an object, so that changes are made permanent only when the user commits them. In such a case, you might clone an object and its trait attributes; allow the user to modify the clone; and then re-clone only the trait attributes back to the original object when the user commits changes. .. index:: trait_set() .. _trait_set: trait_set() ``````````` This method takes a list of keyword-value pairs, and sets the trait attribute corresponding to each keyword to the matching value. This shorthand is useful when a number of trait attributes need to be set on an object, or a trait attribute value needs to be set in a lambda function. For example:: person.trait_set(name='Bill', age=27) The statement above is equivalent to the following:: person.name = 'Bill' person.age = 27 .. index:: add_class_trait() .. _add-class-trait: add_class_trait() ````````````````` The add_class_trait() method is a class method, while the preceding HasTraits methods are instance methods. This method is very similar to the add_trait() instance method. The difference is that adding a trait attribute by using add_class_trait() is the same as having declared the trait as part of the class definition. That is, any trait attribute added using add_class_trait() is defined in every subsequently-created instance of the class, and in any subsequently-defined subclasses of the class. In contrast, the add_trait() method adds the specified trait attribute only to the object instance it is applied to. In addition, if the name of the trait attribute ends with a '_', then a new (or replacement) prefix rule is added to the class definition, just as if the prefix rule had been specified statically in the class definition. It is not possible to define new prefix rules using the add_trait() method. One of the main uses of the add_class_trait() method is to add trait attribute definitions that could not be defined statically as part of the body of the class definition. This occurs, for example, when two classes with trait attributes are being defined and each class has a trait attribute that should contain a reference to the other. For the class that occurs first in lexical order, it is not possible to define the trait attribute that references the other class, since the class it needs to refer to has not yet been defined. .. index:: pair: examples; add_class_trait() This is illustrated in the following example:: # circular_definition.py --- Non-working example of mutually- # referring classes from traits.api import HasTraits, Trait class Chicken(HasTraits): hatched_from = Trait(Egg) class Egg(HasTraits): created_by = Trait(Chicken) As it stands, this example will not run because the **hatched_from** attribute references the Egg class, which has not yet been defined. Reversing the definition order of the classes does not fix the problem, because then the **created_by** trait references the Chicken class, which has not yet been defined. The problem can be solved using the add_class_trait() method, as shown in the following code:: # add_class_trait.py --- Example of mutually-referring classes # using add_class_trait() from traits.api import HasTraits, Trait class Chicken(HasTraits): pass class Egg(HasTraits): created_by = Trait(Chicken) Chicken.add_class_trait('hatched_from', Egg) .. index:: performance of Traits .. _performance-considerations-of-traits: Performance Considerations of Traits ------------------------------------ Using traits can potentially impose a performance penalty on attribute access over and above that of normal Python attributes. For the most part, this penalty, if any, is small, because the core of the Traits package is written in C, just like the Python interpreter. In fact, for some common cases, subclasses of HasTraits can actually have the same or better performance than old or new style Python classes. However, there are a couple of performance-related factors to keep in mind when defining classes and attributes using traits: * Whether a trait attribute defers its value through delegation or prototyping * The complexity of a trait definition If a trait attribute does not defer its value, the performance penalty can be characterized as follows: * Getting a value: No penalty (i.e., standard Python attribute access speed or faster) * Setting a value: Depends upon the complexity of the validation tests performed by the trait definition. Many of the predefined trait handlers defined in the Traits package support fast C-level validation. For most of these, the cost of validation is usually negligible. For other trait handlers, with Python-level validation methods, the cost can be quite a bit higher. If a trait attribute does defer its value, the cases to be considered are: * Getting the default value: Cost of following the deferral chain. The chain is resolved at the C level, and is quite fast, but its cost is linear with the number of deferral links that must be followed to find the default value for the trait. * Getting an explicitly assigned value for a prototype: No penalty (i.e., standard Python attribute access speed or faster) * Getting an explicitly assigned value for a delegate: Cost of following the deferral chain. * Setting: Cost of following the deferral chain plus the cost of performing the validation of the new value. The preceding discussions about deferral chain following and fast versus slow validation apply here as well. In a typical application scenario, where attributes are read more often than they are written, and deferral is not used, the impact of using traits is often minimal, because the only cost occurs when attributes are assigned and validated. The worst case scenario occurs when deferral is used heavily, either for delegation, or for prototyping to provide attributes with default values that are seldom changed. In this case, the cost of frequently following deferral chains may impose a measurable performance detriment on the application. Of course, this is offset by the convenience and flexibility provided by the deferral model. As with any powerful tool, it is best to understand its strengths and weaknesses and apply that understanding in determining when use of the tool is justified and appropriate. .. # substitutions .. |HasTraits.observe| replace:: :func:`~traits.has_traits.HasTraits.observe` .. |@cached_property| replace:: :func:`~traits.has_traits.cached_property`traits-6.3.2/docs/source/traits_user_manual/appendix.rst000066400000000000000000000024661414270267200235400ustar00rootroot00000000000000 ======== Appendix ======== .. toctree:: :hidden: listening.rst Trait Notification with **on_trait_change** -------------------------------------------- See :ref:`on-trait-change-notification` for details on how to set up change notifications using an older API. Property **depends_on** ----------------------- The **depends_on** attribute on a **Property** trait allows change notifications to be fired for the property when one of its dependents has changed. This makes use of **on_trait_change** internally and therefore this is an older API. See :ref:`caching-a-property-value` for the current API. .. index:: depends_on metadata For example:: from traits.api import HasStrictTraits, List, Int, Property class TestScores(HasStrictTraits): scores = List(Int) average = Property(depends_on='scores') def _get_average(self): s = self.scores return (float(reduce(lambda n1, n2: n1 + n2, s, 0)) / len(s)) The **depends_on** metadata attribute accepts extended trait references, using the same syntax as the on_trait_change() method's name parameter, described in :ref:`the-name-parameter`. As a result, it can take values that specify attributes on referenced objects, multiple attributes, or attributes that are selected based on their metadata attributes. traits-6.3.2/docs/source/traits_user_manual/custom.rst000066400000000000000000000532051414270267200232370ustar00rootroot00000000000000.. index:: custom traits .. _custom-traits: ============= Custom Traits ============= The predefined traits such as those described in :ref:`predefined-traits` are handy shortcuts for commonly used types. However, the Traits package also provides facilities for defining complex or customized traits: * Subclassing of traits * The Trait() factory function * Predefined or custom trait handlers .. index:: subclassing traits, TraitType class .. _trait-subclassing: Trait Subclassing ----------------- Starting with Traits version 3.0, most predefined traits are defined as subclasses of traits.trait_handlers.TraitType. As a result, you can subclass one of these traits, or TraitType, to derive new traits. Refer to the *Traits API Reference* to see whether a particular predefined trait derives from TraitType. .. index:: pair: subclassing traits; examples Here's an example of subclassing a predefined trait class:: # trait_subclass.py -- Example of subclassing a trait class from traits.api import BaseInt class OddInt ( BaseInt ): # Define the default value default_value = 1 # Describe the trait type info_text = 'an odd integer' def validate ( self, object, name, value ): value = super().validate(object, name, value) if (value % 2) == 1: return value self.error( object, name, value ) The OddInt class defines a trait that must be an odd integer. It derives from BaseInt, rather than Int, as you might initially expect. BaseInt and Int are exactly the same, except that Int has a **fast_validate attribute**, which causes it to quickly check types at the C level, not go through the expense of executing the general validate() method. [6]_ As a subclass of BaseInt, OddInt can reuse and change any part of the BaseInt class behavior that it needs to. In this case, it reuses the BaseInt class's validate() method, via the call to super() in the OddInt validate() method. Further, OddInt is related to BaseInt, which can be useful as documentation, and in programming. You can use the subclassing strategy to define either a trait type or a trait property, depending on the specific methods and class constants that you define. A trait type uses a validate() method, while a trait property uses get() and set() methods. The :class:`~.TraitType` initializer provides an optional argument ``default_value`` to support easy setting of the default value of the trait type. The default value for that argument is :data:`~.NoDefaultSpecified`: we don't follow the common Python idiom of using ``None`` to represent no default here, since for many trait types ``None`` may be a valid default value. When subclassing :class:`~.TraitType` and overriding or extending its ``__init__`` method, it's recommended to re-use the singleton :data:`~.NoDefaultSpecified` if you need a way to indicate that no default value was specified. .. index: trait type; defining .. _defining-a-trait-type: Defining a Trait Type ````````````````````` The members that are specific to a trait type subclass are: .. index:: default_value attribute, get_default_value() * validate() method * post_setattr() method * **default_value** attribute or get_default_value() method Of these, only the validate() method must be overridden in trait type subclasses. A trait type uses a validate() method to determine the validity of values assigned to the trait. Optionally, it can define a post_setattr() method, which performs additional processing after a value has been validated and assigned. The signatures of these methods are: .. method:: validate( object, name, value ) .. method:: post_setattr( object, name, value ) The parameters of these methods are: .. index:: object parameter; validate(), name parameter; validate() .. index:: value parameter; validate() * *object*: The object whose trait attribute whose value is being assigned. * *name*: The name of the trait attribute whose value is being assigned. * *value*: The value being assigned. The validate() method returns either the original value or any suitably coerced or adapted value that is legal for the trait. If the value is not legal, and cannot be coerced or adapted to be legal, the method must either raise a TraitError, or calls the error() method to raise a TraitError on its behalf. The subclass can define a default value either as a constant or as a computed value. To use a constant, set the class-level **default_value attribute**. To compute the default value, override the TraitType class's get_default_value() method. .. index:: trait property; defining .. _defining-a-trait-property: Defining a Trait Property ````````````````````````` A trait property uses get() and set() methods to interact with the value of the trait. If a TraitType subclass contains a get() method or a set() method, any definition it might have for validate() is ignored. The signatures of these methods are: .. method:: get( object, name) .. method:: set( object, name, value) In these signatures, the parameters are: * *object*: The object that the property applies to. * *name*: The name of the trait property attribute on the object. * *value*: The value being assigned to the property. If only a get() method is defined, the property behaves as read-only. If only a set() method is defined, the property behaves as write-only. The get() method returns the value of the *name* property for the specified object. The set() method does not return a value, but will raise a TraitError if the specified *value* is not valid, and cannot be coerced or adapted to a valid value. In order for the property to trigger notifications you must call either: * object.trait_property_changed(name, old, value) to not cache the value. * self.set_value(object, name, value) to cache the value. Likewise if the property will not be read only the get method must use self.get_value(object, name) in order to behave correctly. The following example demonstrates the use of a property trait to set temperature:: class TempFloat(BaseFloat): default_value = 20.0 info_text = 'A calculated temperature float in Celsius' def set(self, obj, name, value): celsius = (value - 32) * (5/9) setattr(self, name, celsius) self.set_value(obj, name, celsius) def get(self, obj, name): val = self.get_value(obj, name) if val is None: val = self.default_value return val .. index:: TraitType class; members .. _other-traittype-members: Other TraitType Members ``````````````````````` The following members can be specified for either a trait type or a trait property: .. index:: info_text attribute, info(), init(), create_editor() * **info_text** attribute or info() method * init() method * create_editor() method A trait must have an information string that describes the values accepted by the trait type (for example 'an odd integer'). Similarly to the default value, the subclass's information string can be either a constant string or a computed string. To use a constant, set the class-level info_text attribute. To compute the info string, override the TraitType class's info() method, which takes no parameters. If there is type-specific initialization that must be performed when the trait type is created, you can override the init() method. This method is automatically called from the __init__() method of the TraitType class. If you want to specify a default TraitsUI editor for the new trait type, you can override the create_editor() method. This method has no parameters, and returns the default trait editor to use for any instances of the type. For complete details on the members that can be overridden, refer to the *Traits API Reference* sections on the TraitType and BaseTraitHandler classes. .. index:: Trait() .. _the-trait-factory-function: The Trait() Factory Function ---------------------------- The Trait() function is a generic factory for trait definitions. It has many forms, many of which are redundant with the predefined shortcut traits. For example, the simplest form Trait(default_value), is equivalent to the functions for simple types described in :ref:`predefined-traits-for-simple-types`. For the full variety of forms of the Trait() function, refer to the *Traits API Reference*. The most general form of the Trait() function is: .. currentmodule:: traits.traits .. function:: Trait(default_value, {type | constant_value | dictionary | class | function | trait_handler | trait }+ ) :noindex: .. index:: compound traits The notation ``{ | | }+`` means a list of one or more of any of the items listed between the braces. Thus, this form of the function consists of a default value, followed by one or more of several possible items. A trait defined with multiple items is called a compound trait. When more than one item is specified, a trait value is considered valid if it meets the criteria of at least one of the items in the list. .. index:: pair: Trait() function; examples The following is an example of a compound trait with multiple criteria:: # compound.py -- Example of multiple criteria in a trait definition from traits.api import HasTraits, Trait, Range class Die ( HasTraits ): # Define a compound trait definition: value = Trait( 1, Range( 1, 6 ), 'one', 'two', 'three', 'four', 'five', 'six' ) The Die class has a **value trait**, which has a default value of 1, and can have any of the following values: * An integer in the range of 1 to 6 * One of the following strings: 'one', 'two', 'three', 'four', 'five', 'six' .. index:: Trait(); parameters .. _trait-parameters: Trait () Parameters ``````````````````` The items listed as possible arguments to the Trait() function merit some further explanation. .. index:: type; parameter to Trait(), constant_value parameter to Trait() .. index:: dictionary parameter to Trait(), class parameter to Trait() .. index:: function parameter to Trait(), trait handler; parameter to Trait() .. index:: trait; parameter to Trait() * *type*: See :ref:`type`. * *constant_value*: See :ref:`constant-value`. * *dictionary*: See :ref:`mapped-traits`. * *class*: Specifies that the trait value must be an instance of the specified class or one of its subclasses. * *function*: A "validator" function that determines whether a value being assigned to the attribute is a legal value. Traits version 3.0 provides a more flexible approach, which is to subclass an existing trait (or TraitType) and override the validate() method. * *trait_handler*: See :ref:`trait-handlers`. * *trait*: Another trait object can be passed as a parameter; any value that is valid for the specified trait is also valid for the trait referencing it. .. index:: type; parameter to Trait() .. _type: Type :::: A *type* parameter to the Trait() function can be any of the following standard Python types: * str or StringType * int or IntType * float or FloatType * complex or ComplexType * bool or BooleanType * list or ListType * tuple or TupleType * dict or DictType * FunctionType * MethodType * type * NoneType Specifying one of these types means that the trait value must be of the corresponding Python type. .. index:: constant_value parameter to Trait() .. _constant-value: Constant Value :::::::::::::: A *constant_value* parameter to the Trait() function can be any constant belonging to one of the following standard Python types: * NoneType * int * float * complex * bool * str Specifying a constant means that the trait can have the constant as a valid value. Passing a list of constants to the Trait() function is equivalent to using the Enum predefined trait. .. index:: mapped traits .. _mapped-traits: Mapped Traits ````````````` If the Trait() function is called with parameters that include one or more dictionaries, then the resulting trait is called a "mapped" trait. In practice, this means that the resulting object actually contains two attributes: .. index:: shadow values * An attribute whose value is a key in the dictionary used to define the trait. * An attribute containing its corresponding value (i.e., the mapped or "shadow" value). The name of the shadow attribute is simply the base attribute name with an underscore appended. Mapped traits can be used to allow a variety of user-friendly input values to be mapped to a set of internal, program-friendly values. .. index:: mapped traits; examples The following examples illustrates mapped traits that map color names to tuples representing red, green, blue, and transparency values:: # mapped.py --- Example of a mapped trait from traits.api import HasTraits, Trait standard_color = Trait ('black', {'black': (0.0, 0.0, 0.0, 1.0), 'blue': (0.0, 0.0, 1.0, 1.0), 'cyan': (0.0, 1.0, 1.0, 1.0), 'green': (0.0, 1.0, 0.0, 1.0), 'magenta': (1.0, 0.0, 1.0, 1.0), 'orange': (0.8, 0.196, 0.196, 1.0), 'purple': (0.69, 0.0, 1.0, 1.0), 'red': (1.0, 0.0, 0.0, 1.0), 'violet': (0.31, 0.184, 0.31, 1.0), 'yellow': (1.0, 1.0, 0.0, 1.0), 'white': (1.0, 1.0, 1.0, 1.0), 'transparent': (1.0, 1.0, 1.0, 0.0) } ) red_color = Trait ('red', standard_color) class GraphicShape (HasTraits): line_color = standard_color fill_color = red_color The GraphicShape class has two attributes: **line_color** and **fill_color**. These attributes are defined in terms of the **standard_color** trait, which uses a dictionary. The **standard_color** trait is a mapped trait, which means that each GraphicShape instance has two shadow attributes: **line_color_** and **fill_color_**. Any time a new value is assigned to either **line_color** or **fill_color**, the corresponding shadow attribute is updated with the value in the dictionary corresponding to the value assigned. For example:: >>> import mapped >>> my_shape1 = mapped.GraphicShape() >>> print(my_shape1.line_color, my_shape1.fill_color) black red >>> print(my_shape1.line_color_, my_shape1.fill_color_) (0.0, 0.0, 0.0, 1.0) (1.0, 0.0, 0.0, 1.0) >>> my_shape2 = mapped.GraphicShape() >>> my_shape2.line_color = 'blue' >>> my_shape2.fill_color = 'green' >>> print(my_shape2.line_color, my_shape2.fill_color) blue green >>> print(my_shape2.line_color_, my_shape2.fill_color_) (0.0, 0.0, 1.0, 1.0) (0.0, 1.0, 0.0, 1.0) This example shows how a mapped trait can be used to create a user-friendly attribute (such as **line_color**) and a corresponding program-friendly shadow attribute (such as **line_color_**). The shadow attribute is program-friendly because it is usually in a form that can be directly used by program logic. There are a few other points to keep in mind when creating a mapped trait: * If not all values passed to the Trait() function are dictionaries, the non-dictionary values are copied directly to the shadow attribute (i.e., the mapping used is the identity mapping). * Assigning directly to a shadow attribute (the attribute with the trailing underscore in the name) is not allowed, and raises a TraitError. The concept of a mapped trait extends beyond traits defined via a dictionary. Any trait that has a shadow value is a mapped trait. For example, for the Expression trait, the assigned value must be a valid Python expression, and the shadow value is the compiled form of the expression. .. index:: trait handler; classes .. _trait-handlers: Trait Handlers -------------- In some cases, you may want to define a customized trait that is unrelated to any predefined trait behavior, or that is related to a predefined trait that happens to not be derived from TraitType. The option for such cases is to use a trait handler, either a predefined one or a custom one that you write. .. index:: TraitHandler class A trait handler is an instance of the traits.trait_handlers.TraitHandler class, or of a subclass, whose task is to verify the correctness of values assigned to object traits. When a value is assigned to an object trait that has a trait handler, the trait handler's validate() method checks the value, and assigns that value or a computed value, or raises a TraitError if the assigned value is not valid. Both TraitHandler and TraitType derive from BaseTraitHandler; TraitHandler has a more limited interface. The Traits package provides a number of predefined TraitHandler subclasses. A few of the predefined trait handler classes are described in the following sections. These sections also demonstrate how to define a trait using a trait handler and the Trait() factory function. For a complete list and descriptions of predefined TraitHandler subclasses, refer to the *Traits API Reference*, in the section on the traits.trait_handlers module. .. index:: TraitPrefixList class .. _traitprefixlist: TraitPrefixList ``````````````` The TraitPrefixList handler accepts not only a specified set of strings as values, but also any unique prefix substring of those values. The value assigned to the trait attribute is the full string that the substring matches. .. index:: pair: TraitPrefixList class; examples For example:: >>> from traits.api import HasTraits, Trait >>> from traits.api import TraitPrefixList >>> class Alien(HasTraits): ... heads = Trait('one', TraitPrefixList(['one','two','three'])) ... >>> alf = Alien() >>> alf.heads = 'o' >>> print(alf.heads) one >>> alf.heads = 'tw' >>> print(alf.heads) two >>> alf.heads = 't' # Error, not a unique prefix Traceback (most recent call last): File "", line 1, in File "c:\svn\ets3\traits_3.0.3\enthought\traits\trait_handlers.py", line 1802, in validate self.error( object, name, value ) File "c:\svn\ets3\traits_3.0.3\enthought\traits\trait_handlers.py", line 175, in error value ) traits.trait_errors.TraitError: The 'heads' trait of an Alien instance must be 'one' or 'two' or 'three' (or any unique prefix), but a value of 't' was specified. .. index:: TraitPrefixMap class .. _traitprefixmap: TraitPrefixMap `````````````` The TraitPrefixMap handler combines the TraitPrefixList with mapped traits. Its constructor takes a parameter that is a dictionary whose keys are strings. A string is a valid value if it is a unique prefix for a key in the dictionary. The value assigned is the dictionary value corresponding to the matched key. .. index:: pair: TraitPrefixMap class; examples The following example uses TraitPrefixMap to define a Boolean trait that accepts any prefix of 'true', 'yes', 'false', or 'no', and maps them to 1 or 0. :: # traitprefixmap.py --- Example of using the TraitPrefixMap handler from traits.api import Trait, TraitPrefixMap boolean_map = Trait('true', TraitPrefixMap( { 'true': 1, 'yes': 1, 'false': 0, 'no': 0 } ) ) .. index:: handler classes; custom .. _custom-trait-handlers: Custom Trait Handlers --------------------- If you need a trait that cannot be defined using a predefined trait handler class, you can create your own subclass of TraitHandler. The constructor (i.e., __init__() method) for your TraitHandler subclass can accept whatever additional information, if any, is needed to completely specify the trait. The constructor does not need to call the TraitHandler base class's constructor. The only method that a custom trait handler must implement is validate(). Refer to the *Traits API Reference* for details about this function. .. index:: pair: custom trait handler; examples .. _example-custom-trait-handler: Example Custom Trait Handler ```````````````````````````` The following example defines the OddInt trait (also implemented as a trait type in :ref:`defining-a-trait-type`) using a TraitHandler subclass. :: # custom_traithandler.py --- Example of a custom TraitHandler import types from traits.api import TraitHandler class TraitOddInteger(TraitHandler): def validate(self, object, name, value): if ((type(value) is types.IntType) and (value > 0) and ((value % 2) == 1)): return value self.error(object, name, value) def info(self): return '**a positive odd integer**' An application could use this new trait handler to define traits such as the following:: # use_custom_th.py --- Example of using a custom TraitHandler from traits.api import HasTraits, Range, Trait from custom_traithandler import TraitOddInteger class AnOddClass(HasTraits): oddball = Trait(1, TraitOddInteger()) very_odd = Trait(-1, TraitOddInteger(), Range(-10, -1)) The following example demonstrates why the info() method returns a phrase rather than a complete sentence:: >>> from use_custom_th import AnOddClass >>> odd_stuff = AnOddClass() >>> odd_stuff.very_odd = 0 Traceback (most recent call last): File "test.py", line 25, in ? odd_stuff.very_odd = 0 File "C:\wrk\src\lib\enthought\traits\traits.py", line 1119, in validate raise TraitError(excp) traits.traits.TraitError: The 'very_odd' trait of an AnOddClass instance must be **a positive odd integer** or -10 <= an integer <= -1, but a value of 0 was specified. Note the emphasized result returned by the info() method, which is embedded in the exception generated by the invalid assignment. .. rubric:: Footnotes .. [6] All of the basic predefined traits (such as Float and Str) have a BaseType version that does not have the **fast_validate** attribute. traits-6.3.2/docs/source/traits_user_manual/debugging.rst000066400000000000000000000132051414270267200236540ustar00rootroot00000000000000.. index:: debugging, exceptions, trace trait change events ========================= Tips for debugging Traits ========================= Re-raising exceptions in change handlers ======================================== Traits will typically log (instead of raise) exceptions when an exception is encountered in a trait-change handler. This behavior is often preferred in applications, since you usually want to avoid critical failures in applications. However, when debugging these errors, the ``logging.Logger.exception`` only displays the tip of the traceback. For example, the following code changes a ``constant``: .. code-block:: python from traits.api import HasTraits, Int class Curmudgeon(HasTraits): constant = Int(1) def _constant_changed(self): raise ValueError() c = Curmudgeon() c.constant = 42 The ``constant`` trait-change handler raises an exception that is caught and logged:: Exception occurred in traits notification handler. Please check the log file for details. Exception occurred in traits notification handler for object: <__main__.Curmudgeon object at 0x107603050>, trait: constant, old value: 0, new value: 42 ... File "curmudgeon.py", line 12, in _constant_changed raise ValueError() ValueError This logged exception, however, only contains the tip of the traceback. This makes debugging a bit difficult. You can force exceptions to be re-raised by adding a custom exception handler: .. code-block:: python from traits.api import push_exception_handler push_exception_handler(reraise_exceptions=True) (For example, you could add this to the top of the original code block.) Re-running the original code example with this custom handler will now raise the following traceback:: Traceback (most recent call last): File "curmudgeon.py", line 15, in c.constant = 42 ... File "curmudgeon.py", line 12, in _constant_changed raise ValueError() ValueError Notice that this traceback has information about *where* we changed ``constant``. Note: This is a toy example; use ``Constant`` from ``traits.api`` if you actually want a constant trait. Tracing Traits Change Events ============================ Occasionally it is necessary to find the chain of event dispatches in traits classes. To help with debugging, a |record_events| context manager is provided in mod:`traits.util.event_tracer`. Trait change events taking place inside the context block will be recorded in a change event container (see example below) and can be saved to files (a file for each thread) for further inspection. Example: .. code-block:: python from traits.api import * from traits.util.event_tracer import record_events class MyModel(HasTraits): number = Float(2.0) list_of_numbers = List(Float()) count = Int(0) @on_trait_change('number') def _add_number_to_list(self, value): self.list_of_numbers.append(value) @on_trait_change('list_of_numbers[]') def _count_items(self): self.count = len(self.list_on_numbers) def add_to_number(self, value): self.number += value my_model = MyModel() with record_events() as change_event_container: my_model.number = 4.7 my_model.number = 3 # save files locally change_event_container.save_to_directory('./') Running the above example will write a file named MAinThread.trace in the local folder. The file contents will be similar to the lines below:: 2014-03-21 14:11:20.779000 -> 'number' changed from 2.0 to 4.7 in 'MyModel' 2014-03-21 14:11:20.779000 CALLING: '_add_number_to_list' in example.py 2014-03-21 14:11:20.780000 ---> 'list_of_numbers_items' changed from to in 'MyModel' 2014-03-21 14:11:20.780000 CALLING: 'handle_list_items_special' in C:\Users\itziakos\Projects\traits\traits\traits_listener.py 2014-03-21 14:11:20.780000 -----> 'list_of_numbers_items' changed from [] to [4.7] in 'MyModel' 2014-03-21 14:11:20.780000 CALLING: '_count_items' in exampler.py 2014-03-21 14:11:20.780000 -------> 'trait_added' changed from to 'list_on_numbers' in 'MyModel' 2014-03-21 14:11:20.780000 CALLING: '_trait_added_changed' in C:\Users\itziakos\Projects\traits\traits\has_traits.py 2014-03-21 14:11:20.780000 <------- EXIT: '_trait_added_changed' 2014-03-21 14:11:20.780000 <----- EXIT: '_count_items' [EXCEPTION: 'MyModel' object has no attribute 'list_on_numbers'] 2014-03-21 14:11:20.780000 <--- EXIT: 'handle_list_items_special' 2014-03-21 14:11:20.781000 <- EXIT: '_add_number_to_list' 2014-03-21 14:11:20.781000 -> 'number' changed from 4.7 to 3.0 in 'MyModel' 2014-03-21 14:11:20.781000 CALLING: '_add_number_to_list' in example.py 2014-03-21 14:11:20.781000 ---> 'list_of_numbers_items' changed from to in 'MyModel' 2014-03-21 14:11:20.781000 CALLING: 'handle_list_items_special' in C:\Users\itziakos\Projects\traits\traits\traits_listener.py 2014-03-21 14:11:20.781000 -----> 'list_of_numbers_items' changed from [] to [3.0] in 'MyModel' 2014-03-21 14:11:20.781000 CALLING: '_count_items' in example.py 2014-03-21 14:11:20.781000 <----- EXIT: '_count_items' [EXCEPTION: 'MyModel' object has no attribute 'list_on_numbers'] 2014-03-21 14:11:20.782000 <--- EXIT: 'handle_list_items_special' 2014-03-21 14:11:20.782000 <- EXIT: '_add_number_to_list' .. |record_events| replace:: :func:`~traits.util.event_tracer.record_events` traits-6.3.2/docs/source/traits_user_manual/deferring.rst000066400000000000000000000255211414270267200236720ustar00rootroot00000000000000.. index:: deferral .. _deferring-traits: Deferring Trait Definitions =========================== One of the advanced capabilities of the Traits package is its support for trait attributes to defer their definition and value to another object than the one the attribute is defined on. This has many applications, especially in cases where objects are logically contained within other objects and may wish to inherit or derive some attributes from the object they are contained in or associated with. Deferring leverages the common "has-a" relationship between objects, rather than the "is-a" relationship that class inheritance provides. .. index:: delegation, prototyping There are two ways that a trait attribute can defer to another object's attribute: *delegation* and *prototyping*. In delegation, the deferring attribute is a complete reflection of the delegate attribute. Both the value and validation of the delegate attribute are used for the deferring attribute; changes to either one are reflected in both. In prototyping, the deferring attribute gets its value and validation from the prototype attribute, *until the deferring attribute is explicitly changed*. At that point, while the deferring attribute still uses the prototype's validation, the link between the values is broken, and the two attributes can change independently. This is essentially a "copy on write" scheme. The concepts of delegation and prototyping are implemented in the Traits package by two classes derived from TraitType: DelegatesTo and PrototypedFrom. [5]_ .. _delegatesto: DelegatesTo ----------- .. class:: DelegatesTo(delegate[, prefix='', listenable=True, **metadata]) .. index:: delegate parameter to DelegatesTo initializer The *delegate* parameter is a string that specifies the name of an attribute on the same object, which refers to the object whose attribute is deferred to; it is usually an Instance trait. The value of the delegating attribute changes whenever: * The value of the appropriate attribute on the delegate object changes. * The object referenced by the trait named in the *delegate* parameter changes. * The delegating attribute is explicitly changed. Changes to the delegating attribute are propagated to the delegate object's attribute. The *prefix* and *listenable* parameters to the initializer function specify additional information about how to do the delegation. .. index:: pair: delegation; examples If *prefix* is the empty string or omitted, the delegation is to an attribute of the delegate object with the same name as the trait defined by the DelegatesTo object. Consider the following example:: # delegate.py --- Example of trait delegation from traits.api \ import DelegatesTo, HasTraits, Instance, Str class Parent(HasTraits): first_name = Str last_name = Str class Child(HasTraits): first_name = Str last_name = DelegatesTo('father') father = Instance(Parent) mother = Instance(Parent) """ >>> tony = Parent(first_name='Anthony', last_name='Jones') >>> alice = Parent(first_name='Alice', last_name='Smith') >>> sally = Child( first_name='Sally', father=tony, mother=alice) >>> print(sally.last_name) Jones >>> sally.last_name = 'Cooper' # Updates delegatee >>> print(tony.last_name) Cooper >>> sally.last_name = sally.mother # ERR: string expected Traceback (most recent call last): File "", line 1, in ? File "c:\src\trunk\enthought\traits\trait_handlers.py", line 163, in error raise TraitError( object, name, self.info(), value ) traits.trait_errors.TraitError: The 'last_name' trait of a Parent instance must be a string, but a value of <__main__.Parent object at 0x014D6D80> was specified. """ A Child object delegates its **last_name** attribute value to its **father** object's **last_name** attribute. Because the *prefix* parameter was not specified in the DelegatesTo initializer, the attribute name on the delegatee is the same as the original attribute name. Thus, the **last_name** of a Child is the same as the **last_name** of its **father**. When either the **last_name** of the Child or the **last_name** of the father is changed, both attributes reflect the new value. .. _prototypedfrom: PrototypedFrom -------------- .. class:: PrototypedFrom(prototype[, prefix='', listenable=True, **metadata]) .. index:: prototype parameter to PrototypesFrom The *prototype* parameter is a string that specifies the name of an attribute on the same object, which refers to the object whose attribute is prototyped; it is usually an Instance trait. The prototyped attribute behaves similarly to a delegated attribute, until it is explicitly changed; from that point forward, the prototyped attribute changes independently from its prototype. The *prefix* and *listenable* parameters to the initializer function specify additional information about how to do the prototyping. .. _keyword-parameters: Keyword Parameters ------------------ The *prefix* and *listenable* parameters of the DelegatesTo and PrototypedFrom initializer functions behave similarly for both classes. .. index:: prefix parameter to initializer methods .. _prefix-keyword: Prefix Keyword `````````````` When the *prefix* parameter is a non-empty string, the rule for performing trait attribute look-up in the deferred-to object is modified, with the modification depending on the format of the prefix string: * If *prefix* is a valid Python attribute name, then the original attribute name is replaced by prefix when looking up the deferred-to attribute. * If *prefix* ends with an asterisk ('*'), and is longer than one character, then *prefix*, minus the trailing asterisk, is added to the front of the original attribute name when looking up the object attribute. * If *prefix* is equal to a single asterisk ('*'), the value of the object class's **__prefix__** attribute is added to the front of the original attribute name when looking up the object attribute. .. index:: single: examples; prototype prefix pair: examples; prototyping Each of these three possibilities is illustrated in the following example, using PrototypedFrom:: # prototype_prefix.py --- Examples of PrototypedFrom() # prefix parameter from traits.api import \ PrototypedFrom, Float, HasTraits, Instance, Str class Parent (HasTraits): first_name = Str family_name = '' favorite_first_name = Str child_allowance = Float(1.00) class Child (HasTraits): __prefix__ = 'child_' first_name = PrototypedFrom('mother', 'favorite_*') last_name = PrototypedFrom('father', 'family_name') allowance = PrototypedFrom('father', '*') father = Instance(Parent) mother = Instance(Parent) """ >>> fred = Parent( first_name = 'Fred', family_name = 'Lopez', \ ... favorite_first_name = 'Diego', child_allowance = 5.0 ) >>> maria = Parent(first_name = 'Maria', family_name = 'Gonzalez',\ ... favorite_first_name = 'Tomas', child_allowance = 10.0 ) >>> nino = Child( father=fred, mother=maria ) >>> print('%s %s gets $%.2f for allowance' % (nino.first_name, \ ... nino.last_name, nino.allowance)) Tomas Lopez gets $5.00 for allowance """ In this example, instances of the Child class have three prototyped trait attributes: * **first_name**, which prototypes from the **favorite_first_name** attribute of its **mother** object. * **last_name**, which prototyped from the **family_name attribute** of its **father** object. * **allowance**, which prototypes from the **child_allowance** attribute of its **father** object. .. index:: listenable parameter to initializer methods .. _listenable-keyword: Listenable Keyword `````````````````` By default, you can attach listeners to deferred trait attributes, just as you can attach listeners to most other trait attributes, as described in the following section. However, implementing the notifications correctly requires hooking up complicated listeners under the covers. Hooking up these listeners can be rather more expensive than hooking up other listeners. Since a common use case of deferring is to have a large number of deferred attributes for static object hierarchies, this feature can be turned off by setting ``listenable=False`` in order to speed up instantiation. .. index:: single: deferral; notification with pair: examples; deferral .. _notification-with-deferring: Notification with Deferring --------------------------- While two trait attributes are linked by a deferring relationship (either delegation, or prototyping before the link is broken), notifications for changes to those attributes are linked as well. When the value of a deferred-to attribute changes, notification is sent to any handlers on the deferring object, as well as on the deferred-to object. This behavior is new in Traits version 3.0. In previous versions, only handlers for the deferred-to object (the object directly changed) were notified. This behavior is shown in the following example:: # deferring_notification.py -- Example of notification with deferring from traits.api \ import HasTraits, Instance, PrototypedFrom, Str class Parent ( HasTraits ): first_name = Str last_name = Str def _last_name_changed(self, new): print("Parent's last name changed to %s." % new) class Child ( HasTraits ): father = Instance( Parent ) first_name = Str last_name = PrototypedFrom( 'father' ) def _last_name_changed(self, new): print("Child's last name changed to %s." % new) """ >>> dad = Parent( first_name='William', last_name='Chase' ) Parent's last name changed to Chase. >>> son = Child( first_name='John', father=dad ) Child's last name changed to Chase. >>> dad.last_name='Jones' Parent's last name changed to Jones. Child's last name changed to Jones. >>> son.last_name='Thomas' Child's last name changed to Thomas. >>> dad.last_name='Riley' Parent's last name changed to Riley. >>> del son.last_name Child's last name changed to Riley. >>> dad.last_name='Simmons' Parent's last name changed to Simmons. Child's last name changed to Simmons. """ Initially, changing the last name of the father triggers notification on both the father and the son. Explicitly setting the son's last name breaks the deferring link to the father; therefore changing the father's last name does not notify the son. When the son reverts to using the father's last name (by deleting the explicit value), changes to the father's last name again affect and notif .. rubric:: Footnotes .. [5] Both of these class es inherit from the Delegate class. Explicit use of Delegate is deprecated, as its name and default behavior (prototyping) are incongruous. traits-6.3.2/docs/source/traits_user_manual/defining.rst000066400000000000000000001314351414270267200235120ustar00rootroot00000000000000.. index:: validation, using traits .. _defining-traits-initialization-and-validation: ============================================== Defining Traits: Initialization and Validation ============================================== Using the Traits package in a Python program involves the following steps: .. index:: importing Traits names, traits.api; importing from 1. Import the names you need from the Traits package traits.api. 2. Define the traits you want to use. .. index:: HasTraits class 3. Define classes derived from HasTraits (or a subclass of HasTraits), with attributes that use the traits you have defined. In practice, steps 2 and 3 are often combined by defining traits in-line in an attribute definition. This strategy is used in many examples in this guide. However, you can also define traits independently, and reuse the trait definitions across multiple classes and attributes (see :ref:`reusing-trait-definitions`). In order to use trait attributes in a class, the class must inherit from the HasTraits class in the Traits package (or from a subclass of HasTraits). The following example defines a class called Person that has a single trait attribute **weight**, which is initialized to 150.0 and can only take floating point values. .. index:: single: examples; minimal :: # minimal.py --- Minimal example of using traits. from traits.api import HasTraits, Float class Person(HasTraits): weight = Float(150.0) .. index:: attribute definition In this example, the attribute named **weight** specifies that the class has a corresponding trait called **weight**. The value associated with the attribute **weight** (i.e., ``Float(150.0)``) specifies a predefined trait provided with the Traits package, which requires that values assigned be of the standard Python type **float**. The value 150.0 specifies the default value of the trait. The value associated with each class-level attribute determines the characteristics of the instance attribute identified by the attribute name. For example:: >>> from minimal import Person >>> # instantiate the class >>> joe = Person() >>> # Show the default value >>> joe.weight 150.0 >>> # Assign new values >>> joe.weight = 161.9 # OK to assign a float >>> joe.weight = 162 # OK to assign an int >>> joe.weight = 'average' # Error to assign a string Traceback (most recent call last): ... traits.trait_errors.TraitError: The 'weight' trait of a Person instance must be a float, but a value of 'average' was specified. In this example, **joe** is an instance of the Person class defined in the previous example. The **joe** object has an instance attribute **weight**, whose initial value is the default value of the Person.weight trait (150.0), and whose assignment is governed by the Person.weight trait's validation rules. Assigning an integer to **weight** is acceptable because there is no loss of precision (but assigning a float to an Int trait would cause an error). The Traits package allows creation of a wide variety of trait types, ranging from very simple to very sophisticated. The following section presents some of the simpler, more commonly used forms. .. warning:: Unless otherwise stated as safe to do so, avoid naming attributes with the prefix 'trait' or '_trait'. This avoids overshadowing existing methods on HasTraits. A note about the Traits package structure ----------------------------------------- We described above how trait type definitions and the :class:`~.HasTraits` class can be imported from the ``traits.api`` module. For example:: from traits.api import Float, HasTraits, Int In fact, the :class:`HasTraits` class and various trait type classes are defined in other modules nested inside the Traits package structure, but they're re-imported to ``traits.api`` for user convenience. In general, everything you need should be available in either ``traits.api`` or one of the other ``*.api`` modules inside the package structure (for example, ``traits.adaptation.api`` or ``traits.observation.api``). As a matter of best practices, you should import the things you need directly from one of these ``*.api`` modules. If you discover that there's something that you need that's not available from one of these modules, please discuss with the Traits development team (for example, by opening an issue on the `Traits bug tracker`_). .. index:: predefined traits .. _predefined-traits: Predefined Traits ----------------- The Traits package includes a large number of predefined traits for commonly used Python data types. In the simplest case, you can assign the trait name to an attribute of a class derived from HasTraits; any instances of the class will have that attribute initialized to the built-in default value for the trait. For example:: account_balance = Float This statement defines an attribute whose value must be a floating point number, and whose initial value is 0.0 (the built-in default value for Floats). If you want to use an initial value other than the built-in default, you can pass it as an argument to the trait:: account_balance = Float(10.0) Most predefined traits are callable, [2]_ and can accept a default value and possibly other arguments; all that are callable can also accept metadata as keyword arguments. (See :ref:`other-predefined-traits` for information on trait signatures, and see :ref:`trait-metadata` for information on metadata arguments.) .. index:: simple types .. _predefined-traits-for-simple-types: Predefined Traits for Simple Types `````````````````````````````````` There are two categories of predefined traits corresponding to Python simple types: those that coerce values, and those that cast values. These categories vary in the way that they handle assigned values that do not match the type explicitly defined for the trait. However, they are similar in terms of the Python types they correspond to, and their built-in default values, as listed in the following table. .. index:: pair: types; casting pair: types; coercing pair: type; string .. index:: Boolean type, Bool trait, CBool trait, Complex trait, CComplex trait .. index:: Float trait, CFloat trait, Int trait, CInt trait .. index:: integer type, floating point number type, complex number type .. index:: Str trait, CStr trait, Bytes trait, CBytes trait .. _predefined-defaults-for-simple-types-table: .. rubric:: Predefined defaults for simple types ============== ============= ====================== ====================== Coercing Trait Casting Trait Python Type Built-in Default Value ============== ============= ====================== ====================== Bool CBool Boolean False Complex CComplex Complex number 0+0j Float CFloat Floating point number 0.0 Int CInt Integer 0 Str CStr String '' Bytes CBytes Bytes b'' ============== ============= ====================== ====================== .. index:: pair: types; coercing .. _trait-type-coercion: Trait Type Coercion ::::::::::::::::::: For trait attributes defined using the predefined "coercing" traits, if a value is assigned to a trait attribute that is not of the type defined for the trait, but it can be coerced to the required type, then the coerced value is assigned to the attribute. If the value cannot be coerced to the required type, a TraitError exception is raised. Only widening coercions are allowed, to avoid any possible loss of precision. The following table lists traits that coerce values, and the types that each coerces. .. index:: pair: types; coercing .. _type-coercions-permitted-for-coercing-traits-table: .. rubric:: Type coercions permitted for coercing traits ============= =========================================== Trait Coercible Types ============= =========================================== Complex Floating point number, integer Float Integer ============= =========================================== .. index:: pair: types; casting .. _trait-type-casting: Trait Type Casting :::::::::::::::::: For trait attributes defined using the predefined "casting" traits, if a value is assigned to a trait attribute that is not of the type defined for the trait, but it can be cast to the required type, then the cast value is assigned to the attribute. If the value cannot be cast to the required type, a TraitError exception is raised. Internally, casting is done using the Python built-in functions for type conversion: * bool() * complex() * float() * int() * str() * bytes() .. index:: single: examples; coercing vs. casting The following example illustrates the difference between coercing traits and casting traits:: >>> from traits.api import HasTraits, Float, CFloat >>> class Person ( HasTraits ): ... weight = Float ... cweight = CFloat ... >>> bill = Person() >>> bill.weight = 180 # OK, coerced to 180.0 >>> bill.cweight = 180 # OK, cast to float(180) >>> bill.weight = '180' # Error, invalid coercion Traceback (most recent call last): ... traits.trait_errors.TraitError: The 'weight' trait of a Person instance must be a float, but a value of '180' was specified. >>> bill.cweight = '180' # OK, cast to float('180') >>> print(bill.cweight) 180.0 .. _other-predefined-traits: Other Predefined Traits ``````````````````````` The Traits package provides a number of other predefined traits besides those for simple types, corresponding to other commonly used data types; these predefined traits are listed in the following table. Refer to the *Traits API Reference*, in the section for the module traits.traits, for details. Most can be used either as simple names, which use their built-in default values, or as callables, which can take additional arguments. If the trait cannot be used as a simple name, it is omitted from the Name column of the table. .. index:: Any(), Array(), Button(), Callable(), CArray(), Code() .. index:: CSet(), Constant(), Dict() .. index:: Directory(), Disallow, Either(), Enum() .. index:: Event(), Expression(), false, File() .. index:: Instance(), List(), Method(), Module() .. index:: Password(), Property(), Python() .. index:: PythonValue(), Range(), ReadOnly(), Regex() .. index:: Set() String(), This, .. index:: ToolbarButton(), true, Tuple(), Type() .. index:: undefined, UUID(), ValidatedTuple(), WeakRef() .. _predefined-traits-beyond-simple-types-table: .. rubric:: Predefined traits beyond simple types +------------------+----------------------------------------------------------+ | Name | Callable Signature | +==================+==========================================================+ | Any | Any( [*default_value* = None, \*, | | | *factory* = None, *args* = (), *kw* = {}, | | | \*\*\ *metadata* ) | +------------------+----------------------------------------------------------+ | Array | Array( [*dtype* = None, *shape* = None, *value* = None, | | | *typecode* = None, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | ArrayOrNone | ArrayOrNone( [*dtype* = None, *shape* = None, | | | *value* = None, *typecode* = None, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Button | Button( [*label* = '', *image* = None, *style* = | | | 'button', *orientation* = 'vertical', *width_padding* = | | | 7, *height_padding* = 5, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Callable | Callable( [*value* = None, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | CArray | CArray( [*dtype* = None, *shape* = None, *value* = None, | | | *typecode* = None, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Code | Code( [*value* = '', *minlen* = 0, | | | *maxlen* = sys.maxsize, *regex* = '', | | | \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | CSet | CSet( [*trait* = None, *value* = None, *items* = True, | | | \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Constant | Constant( *value*\ [, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Dict | Dict( [*key_trait* = None, *value_trait* = None, | | | *value* = None, *items* = True, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Directory | Directory( [*value* = '', *auto_set* = False, *entries* =| | | 10, *exists* = False, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Disallow | n/a | +------------------+----------------------------------------------------------+ | Either | Either( *val1*\ [, *val2*, ..., *valN*, | | | \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Enum | Enum( *values*\ [, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Event | Event( [*trait* = None, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Expression | Expression( [*value* = '0', \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | File | File( [*value* = '', *filter* = None, *auto_set* = False,| | | *entries* = 10, *exists* = False, \*\*\ *metadata* ] ) | +------------------+----------------------------------------------------------+ | Function [3]_ | Function( [*value* = None, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | generic_trait | n/a | +------------------+----------------------------------------------------------+ | HTML | HTML( [*value* = '', *minlen* = 0, | | | *maxlen* = sys.maxsize, *regex* = '', | | | \*\*\ *metadata* ] ) | +------------------+----------------------------------------------------------+ | Instance | Instance( [*klass* = None, *factory* = None, *args* = | | | None, *kw* = None, *allow_none* = True, *adapt* = None, | | | *module* = None, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | List | List( [*trait* = None, *value* = None, *minlen* = 0, | | | *maxlen* = sys.maxsize, *items* = True, | | | \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Map | Map( *map*\ [, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Method [3]_ | Method ([\*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Module | Module ( [\*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Password | Password( [*value* = '', *minlen* = 0, *maxlen* = | | | sys.maxsize, *regex* = '', \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | PrefixList | PrefixList( *values*\ [, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | PrefixMap | PrefixMap( *map*\ [, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Property | Property( [*fget* = None, *fset* = None, *fvalidate* = | | | None, *force* = False, *handler* = None, *trait* = None, | | | \*\*\ *metadata*] ) | | | | | | See :ref:`property-traits`, for details. | +------------------+----------------------------------------------------------+ | Python | Python ( [*value* = None, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | PythonValue | PythonValue( [*value* = None, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Range | Range( [*low* = None, *high* = None, *value* = None, | | | *exclude_low* = False, *exclude_high* = False, | | | \*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | ReadOnly | ReadOnly( [*value* = Undefined, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Regex | Regex( [*value* = '', *regex* = '.\*', \*\*\ *metadata*])| +------------------+----------------------------------------------------------+ | self | n/a | +------------------+----------------------------------------------------------+ | Set | Set( [*trait* = None, *value* = None, *items* = True, | | | \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | String | String( [*value* = '', *minlen* = 0, *maxlen* = | | | sys.maxsize, *regex* = '', \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Subclass | Subclass( [*value* = None, *klass* = None, *allow_none* =| | | True, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | This | n/a | +------------------+----------------------------------------------------------+ | ToolbarButton | ToolbarButton( [*label* = '', *image* = None, *style* = | | | 'toolbar', *orientation* = 'vertical', *width_padding* = | | | 2, *height_padding* = 2, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Tuple | Tuple( [\*\ *traits*, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Type | Type( [*value* = None, *klass* = None, *allow_none* = | | | True, \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | Union | Union( *val1*\ [, *val2*, ..., *valN*, | | | \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | UUID [4]_ | UUID( [\*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | ValidatedTuple | ValidatedTuple( [\*\ *traits*, *fvalidate* = None, | | | *fvalidate_info* = '' , \*\*\ *metadata*] ) | +------------------+----------------------------------------------------------+ | WeakRef | WeakRef( [*klass* = 'traits.HasTraits', | | | *allow_none* = False, *adapt* = 'yes', \*\*\ *metadata*])| +------------------+----------------------------------------------------------+ .. index:: Instance trait .. _instance: Instance :::::::: One of the most fundamental and useful predefined trait types is :class:`~.Instance`. Instance trait values are an instance of a particular class or its subclasses, as specified by the **klass** argument. **klass** can be either an instance of a class or a class itself (note this applies to all python classes, not necessarily just :class:`~.HasTraits` subclasses). However, one should typically provide the type or interface they want an instance of, instead of providing an instance of a class. If **klass** is an instance or if it is a class and **args** and **kw** are not specified, the default value is ``None``. Otherwise, the default value is obtained by calling the callable **factory** argument (or **klass** if **factory** is None) with **args** and **kw**. Further, there is the **allow_none** argument which dictates whether the trait can take on a value of ``None``. However, this does not include the default value for the trait. For example:: # instance_trait_defaults.py --- Example of Instance trait default values from traits.api import HasTraits, Instance class Parent(HasTraits): pass class Child(HasTraits): # default value is None father = Instance(Parent) # default value is still None, but None can not be assigned grandfather = Instance(Parent, allow_none=False) # default value is Parent() mother = Instance(Parent, args=()) In the last case, the default ``Parent`` instance is not immediately created, but rather is lazily instantiated when the trait is first accessed. The default ``Parent`` will also be instantiated if the trait is assigned to and there is a change handler defined on the trait (to detect changes from the default value). For more details on change handlers and trait notification see :ref:`observe-notification`. Somewhat surprisingly, ``mother = Instance(Parent, ())`` will also yield a default value of ``Parent()``, even though in that case it is **factory** that is ``()`` not **args**. This is a result of implementation details, however the recommended way of writing this code is to explicitly pass **args** by keyword like so ``mother = Instance(Parent, args=())``. Another common mistake is passing in another trait type to Instance. For example, ``some_trait = Instance(Int)``. This will likely lead to unexpected behavior and potential errors. Instead simply do ``some_trait = Int()``. .. index:: This trait, self trait .. _this-and-self: This and self ::::::::::::: A couple of predefined traits that merit special explanation are This and **self**. They are intended for attributes whose values must be of the same class (or a subclass) as the enclosing class. The default value of This is None; the default value of **self** is the object containing the attribute. .. index:: pair: This trait; examples The following is an example of using This:: # this.py --- Example of This predefined trait from traits.api import HasTraits, This class Employee(HasTraits): manager = This This example defines an Employee class, which has a **manager** trait attribute, which accepts only other Employee instances as its value. It might be more intuitive to write the following:: # bad_self_ref.py --- Non-working example with self- referencing # class definition from traits.api import HasTraits, Instance class Employee(HasTraits): manager = Instance(Employee) However, the Employee class is not fully defined at the time that the **manager** attribute is defined. Handling this common design pattern is the main reason for providing the This trait. Note that if a trait attribute is defined using This on one class and is referenced on an instance of a subclass, the This trait verifies values based on the class on which it was defined. For example:: >>> from traits.api import HasTraits, This >>> class Employee(HasTraits): ... manager = This ... >>> class Executive(Employee): ... pass ... >>> fred = Employee() >>> mary = Executive() >>> # The following is OK, because fred's manager can be an >>> # instance of Employee or any subclass. >>> fred.manager = mary >>> # This is also OK, because mary's manager can be an Employee >>> mary.manager = fred .. index:: Map trait .. _map: Map ::: The map trait ensures that the value assigned to a trait attribute is a key of a specified dictionary, and also assigns the dictionary value corresponding to that key to a shadow attribute. .. index:: pair: Map trait; examples The following is an example of using Map:: # map.py --- Example of Map predefined trait from traits.api import HasTraits, Map class Person(HasTraits): married = Map({'yes': 1, 'no': 0 }, default_value="yes") This example defines a Person class which has a **married** trait attribute which accepts values "yes" and "no". The default value is set to "yes". The name of the shadow attribute is the name of the Map attribute followed by an underscore, i.e ``married_`` Instantiating the class produces the following:: >>> from traits.api import HasTraits, Map >>> bob = Person() >>> print(bob.married) yes >>> print(bob.married_) 1 .. index:: PrefixMap trait .. _prefixmap: PrefixMap ::::::::: Like Map, PrefixMap is created using a dictionary, but in this case, the keys of the dictionary must be strings. Like PrefixList, a string *v* is a valid value for the trait attribute if it is a prefix of one and only one key *k* in the dictionary. The actual values assigned to the trait attribute is *k*, and its corresponding mapped attribute is map[*k*]. .. index:: pair: PrefixMap trait; examples The following is an example of using PrefixMap:: # prefixmap.py --- Example of PrefixMap predefined trait from traits.api import HasTraits, PrefixMap class Person(HasTraits): married = PrefixMap({'yes': 1, 'no': 0 }, default_value="yes") This example defines a Person class which has a **married** trait attribute which accepts values "yes" and "no" or any unique prefix. The default value is set to "yes". The name of the shadow attribute is the name of the PrefixMap attribute followed by an underscore, i.e ``married_`` Instantiating the class produces the following:: >>> bob = Person() >>> print(bob.married) yes >>> print(bob.married_) 1 >>> bob.married = "n" # Setting a prefix >>> print(bob.married) no >>> print(bob.married_) 0 .. index:: PrefixList trait .. _prefixlist: PrefixList :::::::::: Ensures that a value assigned to the attribute is a member of a list of specified string values, or is a unique prefix of one of those values. The values that can be assigned to a trait attribute of type PrefixList is the set of all strings supplied to the PrefixList constructor, as well as any unique prefix of those strings. The actual value assigned to the trait is limited to the set of complete strings assigned to the PrefixList constructor. .. index:: pair: PrefixList trait; examples The following is an example of using PrefixList:: # prefixlist.py --- Example of PrefixList predefined trait from traits.api import HasTraits, PrefixList class Person(HasTraits): married = PrefixList(["yes", "no"]) This example defines a Person class which has a **married** trait attribute which accepts values "yes" and "no" or any unique prefix. Instantiating the class produces the following:: >>> bob = Person() >>> print(bob.married) yes >>> bob.married = "n" # Setting a prefix >>> print(bob.married) no .. index:: Either trait .. _either: Either :::::: Another predefined trait that merits special explanation is Either. The Either trait is intended for attributes that may take a value of more than a single trait type, including None. The default value of Either is None, even if None is not one of the types the user explicitly defines in the constructor, but a different default value can be provided using the ``default`` argument. .. index:: pair: Either trait; examples The following is an example of using Either:: # either.py --- Example of Either predefined trait from traits.api import HasTraits, Either, Str class Employee(HasTraits): manager_name = Either(Str, None) This example defines an Employee class, which has a **manager_name** trait attribute, which accepts either an Str instance or None as its value, and will raise a TraitError if a value of any other type is assigned. For example:: >>> from traits.api import HasTraits, Either, Str >>> class Employee(HasTraits): ... manager_name = Either(Str, None) ... >>> steven = Employee(manager_name="Jenni") >>> # Here steven's manager is named "Jenni" >>> steven.manager_name 'Jenni' >>> eric = Employee(manager_name=None) >>> # Eric is the boss, so he has no manager. >>> eric.manager_name is None True >>> # Assigning a value that is neither a string nor None will fail. >>> steven.manager_name = 5 traits.trait_errors.TraitError: The 'manager_name' trait of an Employee instance must be a string or None, but a value of 5 was specified. .. index:: Union trait .. _union: Union :::::: The Union trait accepts a value that is considered valid by at least one of the traits in its definition. It is a simpler and therefore less error-prone alternative to the `Either` trait, which allows more complex constructs and may sometimes exhibit mysterious validation behaviour. The Union trait however, validates the value assigned to it against each of the traits in its definition in the order they are defined. Union only accepts trait types or trait type instances or None in its definition. Prefer to use Union over `Either` to remain future proof. .. index:: pair: Union trait; examples The following is an example of using Union:: # union.py --- Example of Union predefined trait from traits.api import HasTraits, Union, Int, Float, Instance class Salary(HasTraits): basic = Float bonus = Float class Employee(HasTraits): manager_name = Union(Str, None) pay = Union(Instance(Salary), Float) This example defines an Employee class, which has a **manager_name** trait attribute, which accepts either an Str instance or None as its value, a **salary** trait that accepts an instance of Salary or Float and will raise a TraitError if a value of any other type is assigned. For example:: >>> from traits.api import HasTraits, Either, Str >>> class Employee(HasTraits): ... manager_name = Union(Str, None) ... >>> steven = Employee(manager_name="Jenni") >>> # Here steven's manager is named "Jenni" >>> # Assigning a value that is neither a string nor None will fail. >>> steven.manager_name = 5 traits.trait_errors.TraitError: The 'manager_name' trait of an Employee instance must be a string or a None type, but a value of 5 was specified. The following example illustrates the difference between `Either` and `Union`:: >>> from traits.api import HasTraits, Either, Union, Str >>> class IntegerClass(HasTraits): ... primes = Either([2], None, {'3':6}, 5, 7, 11) ... >>> i = IntegerClass(primes=2) # Acceptable value, no error >>> i = IntegerClass(primes=4) traits.trait_errors.TraitError: The 'primes' trait of an IntegerClass instance must be 2 or None or 5 or 7 or 11 or '3', but a value of 4 was specified. >>> >>> # But Union does not allow such declarations. >>> class IntegerClass(HasTraits): ... primes = Union([2], None, {'3':6}, 5, 7, 11) ValueError: Union trait declaration expects a trait type or an instance of trait type or None, but got [2] instead .. _migration_either_to_union: .. rubric:: Migration from Either to Union * Static default values are defined on Union via the **default_value** attribute, whereas Either uses the **default** attribute. The naming of **default_value** is consistent with other trait types. For example:: Either(None, Str(), default="unknown") would be changed to:: Union(None, Str(), default_value="unknown") * If a default value is not defined, Union uses the default value from the first trait in its definition, whereas Either uses None. For example:: Either(Int(), Float()) has a default value of None. However None is not one of the allowed values. If the trait is later set to None from a non-None value, a validation error will occur. If the trait definition is changed to:: Union(Int(), Float()) Then the default value will be 0, which is the default value of the first trait. To keep None as the default, use None as the first item:: Union(None, Int(), Float()) With this, None also becomes one of the allowed values. .. index:: multiple values, defining trait with .. _list-of-possibl-values: List of Possible Values ::::::::::::::::::::::: You can define a trait whose possible values include disparate types. To do this, use the predefined Enum trait, and pass it a list of all possible values. The values must all be of simple Python data types, such as strings, integers, and floats, but they do not have to be all of the same type. This list of values can be a typical parameter list, an explicit (bracketed) list, or a variable whose type is list. The first item in the list is used as the default value. .. index:: examples; list of values A trait defined in this fashion can accept only values that are contained in the list of permitted values. The default value is the first value specified; it is also a valid value for assignment. :: >>> from traits.api import Enum, HasTraits, Str >>> class InventoryItem(HasTraits): ... name = Str # String value, default is '' ... stock = Enum(None, 0, 1, 2, 3, 'many') ... # Enumerated list, default value is ... #'None' ... >>> hats = InventoryItem() >>> hats.name = 'Stetson' >>> print('%s: %s' % (hats.name, hats.stock)) Stetson: None >>> hats.stock = 2 # OK >>> hats.stock = 'many' # OK >>> hats.stock = 4 # Error, value is not in \ >>> # permitted list Traceback (most recent call last): ... traits.trait_errors.TraitError: The 'stock' trait of an InventoryItem instance must be None or 0 or 1 or 2 or 3 or 'many', but a value of 4 was specified. This defines an :py:class:`InventoryItem` class, with two trait attributes, **name**, and **stock**. The name attribute is simply a string. The **stock** attribute has an initial value of None, and can be assigned the values None, 0, 1, 2, 3, and 'many'. The example then creates an instance of the InventoryItem class named **hats**, and assigns values to its attributes. When the list of possible values can change during the lifetime of the object, one can specify **another trait** that holds the list of possible values:: >>> from traits.api import Enum, HasTraits, List >>> class InventoryItem(HasTraits): ... possible_stock_states = List([None, 0, 1, 2, 3, 'many']) ... stock = Enum(0, values="possible_stock_states") ... # Enumerated list, default value is 0. The list of ... # allowed values is whatever possible_stock_states holds ... >>> hats = InventoryItem() >>> hats.stock 0 >>> hats.stock = 2 # OK >>> hats.stock = 4 # TraitError like above Traceback (most recent call last): ... traits.trait_errors.TraitError: The 'stock' trait of an InventoryItem instance must be None or 0 or 1 or 2 or 3 or 'many', but a value of 4 was specified. >>> hats.possible_stock_states.append(4) # Add 4 to list of allowed values >>> hats.stock = 4 # OK .. index:: metadata attributes; on traits .. _trait-metadata: Trait Metadata -------------- Trait objects can contain metadata attributes, which fall into three categories: * Internal attributes, which you can query but not set. * Recognized attributes, which you can set to determine the behavior of the trait. * Arbitrary attributes, which you can use for your own purposes. You can specify values for recognized or arbitrary metadata attributes by passing them as keyword arguments to callable traits. The value of each keyword argument becomes bound to the resulting trait object as the value of an attribute having the same name as the keyword. .. index:: metadata attributes; internal .. _internal-metadata-attributes: Internal Metadata Attributes ```````````````````````````` The following metadata attributes are used internally by the Traits package, and can be queried: .. index:: array metadata attribute, default metadata attribute .. index:: default_kind metadata attribute, delegate; metadata attribute .. index:: inner_traits metadata attribute, parent metadata attribute .. index:: prefix metadata attribute, trait_type metadata attribute .. index:: type metadata attribute * **array**: Indicates whether the trait is an array. * **default**: Returns the default value for the trait, if known; otherwise it returns Undefined. * **default_kind**: Returns a string describing the type of value returned by the default attribute for the trait. The possible values are: * ``value``: The default attribute returns the actual default value. * ``list``: A copy of the list default value. * ``dict``: A copy of the dictionary default value. * ``self``: The default value is the object the trait is bound to; the **default** attribute returns Undefined. * ``factory``: The default value is created by calling a factory; the **default** attribute returns Undefined. * ``method``: The default value is created by calling a method on the object the trait is bound to; the **default** attribute returns Undefined. * **delegate**: The name of the attribute on this object that references the object that this object delegates to. * **inner_traits**: Returns a tuple containing the "inner" traits for the trait. For most traits, this is empty, but for List and Dict traits, it contains the traits that define the items in the list or the keys and values in the dictionary. * **parent**: The trait from which this one is derived. * **prefix**: A prefix or substitution applied to the delegate attribute. See :ref:`deferring-traits` for details. * **trait_type**: Returns the type of the trait, which is typically a handler derived from TraitType. * **type**: One of the following, depending on the nature of the trait: * ``constant`` * ``delegate`` * ``event`` * ``property`` * ``trait`` .. index:: recognized metadata attributes, metadata attributes; recognized .. _recognized-metadata-attributes: Recognized Metadata Attributes `````````````````````````````` The following metadata attributes are not predefined, but are recognized by HasTraits objects: .. index:: desc metadata attribute, editor metadata attribute .. index:: label; metadata attribute, comparison_mode metadata attribute .. index:: transient metadata attribute * **desc**: A string describing the intended meaning of the trait. It is used in exception messages and fly-over help in user interface trait editors. * **editor**: Specifies an instance of a subclass of TraitEditor to use when creating a user interface editor for the trait. Refer to the `TraitsUI User Manual `_ for more information on trait editors. * **label**: A string providing a human-readable name for the trait. It is used to label trait attribute values in user interface trait editors. * **comparison_mode**: Indicates when trait change notifications should be generated based upon the result of comparing the old and new values of a trait assignment. This should be a member of the :class:`~traits.constants.ComparisonMode` enumeration class. * **transient**: A Boolean indicating that the trait value is not persisted when the object containing it is persisted. The default value for most predefined traits is False (the value will be persisted if its container is). You can set it to True for traits whose values you know you do not want to persist. Do not set it to True on traits where it is set internally to False, as doing so is likely to create unintended consequences. See :ref:`persistence` for more information. Other metadata attributes may be recognized by specific predefined traits. .. index:: metadata attributes; accessing .. _accessing-metadata-attributes: Accessing Metadata Attributes ````````````````````````````` .. index:: pair: examples; metadata attributes Here is an example of setting trait metadata using keyword arguments:: # keywords.py --- Example of trait keywords from traits.api import HasTraits, Str class Person(HasTraits): first_name = Str('', desc='first or personal name', label='First Name') last_name = Str('', desc='last or family name', label='Last Name') In this example, in a user interface editor for a Person object, the labels "First Name" and "Last Name" would be used for entry fields corresponding to the **first_name** and **last_name** trait attributes. If the user interface editor supports rollover tips, then the **first_name** field would display "first or personal name" when the user moves the mouse over it; the last_name field would display "last or family name" when moused over. To get the value of a trait metadata attribute, you can use the trait() method on a HasTraits object to get a reference to a specific trait, and then access the metadata attribute:: # metadata.py --- Example of accessing trait metadata attributes from traits.api import HasTraits, Int, List, Float, Str, \ Instance, Any, TraitType class Foo( HasTraits ): pass class Test( HasTraits ): i = Int(99) lf = List(Float) foo = Instance( Foo, () ) any = Any( "123" ) t = Test() print(t.trait( 'i' ).default) # 99 print(t.trait( 'i' ).default_kind) # value print(t.trait( 'i' ).inner_traits) # () print(t.trait( 'i' ).is_trait_type( Int )) # True print(t.trait( 'i' ).is_trait_type( Float )) # False print(t.trait( 'lf' ).default) # [] print(t.trait( 'lf' ).default_kind) # list print(t.trait( 'lf' ).inner_traits) # (,) print(t.trait( 'lf' ).is_trait_type( List )) # True print(t.trait( 'lf' ).is_trait_type( TraitType )) # True print(t.trait( 'lf' ).is_trait_type( Float )) # False print(t.trait( 'lf' ).inner_traits[0].is_trait_type( Float )) # True print(t.trait( 'foo' ).default) # print(t.trait( 'foo' ).default_kind) # factory print(t.trait( 'foo' ).inner_traits) # () print(t.trait( 'foo' ).is_trait_type( Instance )) # True print(t.trait( 'foo' ).is_trait_type( List )) # False print(t.trait( 'any' ).default) # 123 print(t.trait( 'any' ).default_kind) # value print(t.trait( 'any' ).inner_traits) # () print(t.trait( 'any' ).is_trait_type( Any )) # True print(t.trait( 'any' ).is_trait_type( Str )) # False .. rubric:: Footnotes .. [2] Most callable predefined traits are classes, but a few are functions. The distinction does not make a difference unless you are trying to extend an existing predefined trait. See the *Traits API Reference* for details on particular traits, and see Chapter 5 for details on extending existing traits. .. [3] The Function and Method trait types are now deprecated. See |Function|, |Method| .. [4] Available in Python 2.5. .. external urls .. _Traits bug tracker: https://github.com/enthought/traits/issues .. # substitutions .. |Function| replace:: :class:`~traits.trait_types.Function` .. |Method| replace:: :class:`~traits.trait_types.Method` traits-6.3.2/docs/source/traits_user_manual/images/000077500000000000000000000000001414270267200224335ustar00rootroot00000000000000traits-6.3.2/docs/source/traits_user_manual/images/adaptation.png000066400000000000000000001012541414270267200252700ustar00rootroot00000000000000PNG  IHDR<~ CiCCPICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs  tIME*4:L IDATxy|Օܪwٲc`=’$ d~ !{ M$L2Yf !yM =llco]jGu$/`chcT]]un}{9BJ)Q( B񮠩.P( B BP(J BP(!V( B BP( % BP(!V( BXP( % BP(+ BXP( bBP(+ BPBP( bBP(J BPB<Hlio[P(c@6 }tuILEHr:{KyCURb&M}!uU( !r έ́tB֧ ];P3Nq1DP([;=ϳ 5zݸ=.viR,)%ec6i˚d3tL:eva7VԖsYQ( ⮾1$9+SP^>7/υ "\&G*!ːgF-Xi ЄsS( m¦Fq[ % #I2!I]U^RYKd1t B15x_zWt@4+VpwliL18P˯e 4e!+ b q4?Ŷ}AK41L$菓Ih7T7W]Q B2X1W1_)jNa.S:t&~}^gUNEO(._>E]} c[9m[ܽ]/{dq5.]u4 4!l[ i٘$kuMI IyJ|O,~8нŌ5>!q7\M*P(N C7ӿ > &\}n|nDžЎ랝3m9T$5'$3Qms^Jv.7{KIctES󱫿PݢP(+?}>7eAe1>mK" dXr2 Q><ϺYK՗4BG?5frGI}_/dqB11:^\OK& ˼Tp":RJb$XX^6P}g+!u[Z4ͬ$PS#=X_3_:EP0xnlMCe^hZH89Sy!/4͋l󄣝TT+S-H$R?&t>zTB8!އ n,衾2HwblR;+ k:neɬ5^1fB~Ɔ0cv5*40|7;h*_P 1c.fՔMiAiCPmax44u+.ifLo/?B0kN-n5/|l w7ٌ3?ƙKRuB8fwʮ}\rCi P[9( sV3/O'\HJG)UA%58.6hb@uB8+b~{>G.9Hyų*']:sʙTq*!~;6n};p *Cj'>2?9+cKuBxKr[<!4KP˘%WKn5W F{[x>%Gw%dxj=6MY'Bum)m߳tRP(Hz7~^2X8ڊeho*fǾG'jW|DzC U:`z{U(H獟 pAS+xp; A6 mJ V޸5JN4McoǫtUP(nc˝S0CצŹ̛Q 6?¶{l3`ˮ爧z] X(-w7=:DPmc=_ĩ.3l/X0a0yv&&c*+!غYA! 4'_݆Q2.Y|n31t?Oo!COx/4cftJB>ټ! 4&毾H6GYi'μrtMh{W4r}:/J7m\uB1]6;h/S<r8b[l#e~uU1å3=HO~! 4{}3Bs?PZgZtB*5`v!<ۥ1F%U;:D'hpcTJߵڿ'h42Rե^l뿁m&w>(kx :NVu~z.\Ȃ Ng><ӣ0_2^WX<<ꪫp/344?1^nmtM~֭[ƍOKFٵv$TV[\SJHee%k׮糟-Z38-?۶m\}Փj{d4LYc.` M~;&gf㲈S8=hB+x!n4;t);旿%eee|ӟ{aΝx,X^nϒ%K1 L&smFEE@dYNoΪUk1c3fvSUUg]<. ˊ3gg}6fbܹ;6l HOxb㴶rwzj~_[RM6p #@:?!vf~a馛(-mv?1VEH1hs/ΞҏJvr\Gٳϣ"NU ޽]ubLX~=_Wꪫظq#gqPիWs֭[Yj_җxgyя~D2[og޼yz-Ͻ=Ek,c͚5\|{Ok.VXQ<믿˗pBnʆ /|/袋hjj+V.2.RcyOg>JJJG?:.ߍmZ[[y>(ՇHto6/ 8B0ƩwO?&N?.t~G$< יOӊ1|֜go]t:כ˲x{^ۙ;w. .䳟,vXիWH$k4axks7r嗳h"l??WYY~~rr޶ݱXGۇbHTϑ7'B%H+J|nJ|nb!=O͒ #^ǂie̓odi_ckxnۏF S) 6bZ{J8l?efjJ[4݃[mjJ -Ŷ>O9eElibhfV@+=4T,"g929+M[̪ds _'Bb !_= ݃[F.u@{hXBW@lgyh: '-fkGr 熑JR|&Lǩ:p*doNEPUK|RYz^{hj q6~'c2aNs#]9o&c(сU²WOvθ3It#,y /ﺇ}/3܆W:#H{*XzAo KqJlx[?@"=@WoR3}Oqd^مX{ynۏ9ny ?fV,j-mxݥ,hZexYдxK!.$zRjd)u~Yӑ-O:Rc*^ڴ(Ѷ d"xJk[X'X$D4JDS,i 6o^7_ of `3 fd.9]Ϭ^cM,s8}hNB\oY==NM%W.}Y)\ |-VwMvu>S[ )%g.d{{k˾L$K;Zș8B82[B s&(IҿyW]5,%t,kCw RQ?m4V.b)Bh^l?Kodq+u_`'?$ɟ`F2TsVV*Kf!FXOHok[AIQ;Άӓ|;455M9}G}A$%ϞBvV;WU+.mN~dQYz {{+ A~ h )m2kMcAlĉT̄OxRJ\ >vVɆ X~=L+;p5}466J޲}2d466rJW_}~P(D[[_XIwŋۿ[ZZZ&lI"v _ݧǓC$%־ujXuB\W)!ୠ*t(z9Itp0峯!}MrشwHiZҹ[<@l/jW2iU:ǢJgxv_GJ,ުb@ױ Qj*Ԋ6璶MG57||#%\͛Bp%p]wDWOӣr|SK_7|3v.EQ[[_8՞/_-׿ulg_[榞$zcR<. ]UOt7&qZo6uֽ^x3m̆yqݴ2햶Є΢KY:Jlۦ?wNf¼z-k@8ήjh%,y)}={E<X6r;ykCh`+8fO~7KoK23C~~4M+6bbr 7EOO3f̠sspmؑWUU1sLp-p5HSS .,V{z?Sm}svwǩRMH\{Ҷtqq%k+==hK~ `Kv|e>wG孶ŋ;~{5|n-y,3Br ;أ>6݇[(9K 7́|=2Co7#ĥ%UjD)&$'x<,YhhtT-]׋+Fg d2m=Igɞܪxi ͒W8}?YHI2=R٣ie0|h4vth<#}1E2{KjD)&hӃiEsKK ml6s=GKKQݻݻwO?Ͳeˊ=44QI 8I|IdMΩ!5G6QAeZ"Wi# q饗reQRRB0đXKzjimm-~>R~s#:{/y{Kyo~sjOG4Ivqوy{0S2z&1W6ȤMJ6+5\W٢:C1a뮻bQU~L&b0Ծ xb v(Zsa՞I#١@q=5mQ*B\_uZIfh)q} M!JYGk_HՑ4YDer)4c+_0DvlBT2S"nCXL&1xyș?L _$;p\v-mX>1o͘V xEl7jfD%u bˁ /Ck{_ WzS09z_͘ZuB,r./; HC iSS>F! 8ݘC$ىճ LY a#@0;7B\1[r?[{xdhKGF̥іmŇ@Zm!;^tR]1­%5ta!XRG&6z~^Qb[6Vnl1Y{Lb-HG_]鸨V@p-ۑ#ԉ^=O N1ĂKayd܅53dg,Kr}1e1$s.?(RJ!;;8HO'FB#FCb yV~ ]fnŞx̄!3Iδqgv-[: B^)n!_;|ѩ2׷ 1D09΍ %t2{^!5o5l{̚y!VL=!^ز?\M4G"$ `6A-}TP&RiEGG72wXx55 B."%ѱ8%Q-a:R0MsӞF2CdY~Qxe HGe>w` d}eN|bkby%Nc,vR]1_ >@sKJq vE,pC8.+B0 Rޙ0s`/6.#GPh'˙[݊UՄu-XK)0vdfل0 $IdzU"bW<-bcvtװU5Dm} eM2k.{xo`A0'N&RCCr^ f ͙[6g=qՄ%눅@YDVyqSa3fo' dFDh,{0P]z:pG!Z:#I9ovsX{1= ٵ:">cA4X e5GN\%}q95iK$H%Ԕso3N<Ǥr 6T:VLY[U!Ayb!H }e>Ga8?F ƋEkq]m~a)!/4}Q%cM,#37Q8 1D,f njSjmH q_e6)%\'t)ul[qV/˭X1e1 `{B8N_wz>.yb #‰`ަɯ)a,%uމ juM 6@߯Ies*hk rמ69 )g%[6};\4ͮFIIOG\V2cv.)s>z.d)%e¶;lEJ [W )5*pyJSol僤6z{zygE-,:65&l<"Kd0х!r%nyɋZ9z#aO _#LJ`~(ڠjlNop&~4ܸ 1@2@ESs1Iw{x,MQ7 beG)oq\! m/cбFQfR(Wb~7l. ac`̢yv煷j:6`R!{qG0f en^o r ǐVų4މg0AK{E\ pufUrM.[J:R2Bca{tۮO< زQu>Zm)yز5$zQF^KuY RL;ҩ\[1eqְhEA܆3^%Vˀ! R:\.wQl}>_gۍ0 4MCu>=z^SU|"LM{O`] $ͣ@ Caf>{jeG"J[/[Ɗޅl6{^ƶ]ض@-aAF m Mv{iX1ػ};#FAdхU\Z.ZdIt7@x<[|G >% =k RZ,= n}S1|\5 7/A`;ѡ&=SbH&Ҵ 1 yқIdɣ⎧x` ^wbl6xeH)ma-aulc˖CSBUJӊRn݂mhH"yՄD0M+l^hSʛWRQQAEEeee Ea.q5R _l"Fs+ٜ2U_; $sp'OR"/^в i tI"! zSb}z:jJ-M+ypit-TS;z Μ@˸2ʂ '"9w˶R4,XÎE[g[]@j4V+1VL4]TtVa#B M8e# >taaC^A6lZ@eeeQx ~c\ߣ>$4Σ絇H&}nj!5]qu]2 qATf5.f{_#LJ=;t?5<0@t(@paݹexy$ Y {b.m RS6XJI4LJ)9.i(ѕH[s mA\:{%̪i:@1b240@o/NXA Z [k= 0{$mo./O-Ux΁kry[O(/cќG8M," 'zc[D$3) Vs_gќsQ@8I*ep iڸ\:ƻ2mqmIe .9Y|o;M]0(E&+ ZvK[͎bH.B^\9b;G{x~ؒah$\YI_O)ݝ|sK1M5]9f-c!SB8eOЌ:vo#5*ʻN*c3D2}Hi=x9ؽ6=ۼ>R?%!I+"aKD$E4" UKdAwӶm,"N 3`H(ѭJ,W ii #IVrq>+̨/qd6[ YԟNYI}>R uql\Eċ?QDNH$clQ|5X` ' PHQd Hm! 9|oa]Lء+[莖 ",K,(fe!ક9cncŤGJϼޝ{S[2gXx4gDsPktbgOg oͻ>mQ]Belk$j^&>WLh!~5m&M˥q{\utc=!iKEjf-rE6cNfr Mn\–̝u:>OpoRJrDh4J?MyײiBj ym;*R.X qaZk{ؒ>cVWZݥ Ŝ#]aȢa g;^dǽ_AJR*CiPd\0eR.]xmy@P_5 ٰY q|'L$Jѻ%ٴ;"[VA`v;[H};,y74awm~޷rx<e+&Սڲ,$/7vt,]b%G"]S$"/:.2 5qy_B)Җb([~wIŔ8IW}A4T71i3 H'C>">tNn``eJk.AUy~W0 ,KZ愁`FKX]#DwD;gْkIRpG۶F왪JbZ7lS_BK|mb SjhPXǍG `I CXX6!Ε<@:>S7nTbmO]MImZ}ZA,. [SF'&bBʲI%xqHQw8Qp$t!a,#E>(KXФwuk.,TWni'hn2ՋDbJ!z>2Z1"/6BXy!  zaנDڴ:4+mQLۦrzpLHfrxgC_EԺfհ}E8֟EQEȼN[1"BzXs2ևoܗ#.qތj*~X)FlVaz D~ ) Y$8S@ )#!XAo+e1޳| gM3菳;m)]&2&[ gɍߛr"xeYH/3GejK=ÃF,lRcuS 5 ys*r?&NЦeሱ jVwgtGl1<0+6a&'#ܦXWp$y@T֜c`ma29Ь,ȿDORi߃t nUx]rm9n7^?6jKotr>$lGCE IU=5iM:i~Zf^ɶx*pwxc,[F'ݰG'TlZj{Dʼ57לյo}g۳`0Hyy9>Og))144ğ_A<8,< . a9i. ٴ4 i}za·[GSUͱ ^$HJ)ib1v9sUÉ;Wv%>gP-mjkVnŞ ޱS_̏6,T֢k Fԩ.Nê0=Dwݵ$>Ǔ<$s#FEHQˎ F'-=^ IDAT,KS7L|XAz -;8)k}aߗqfFVYT6 7$^cb/1"ɽnyI$DQ#zA $( 63=3TGwݳ(p|9y44M~31MJ?KlFVT7n:,*TRFM%{d^v*sIu]SN(Gh4Xn &*Ն`S ;cڬ)3EUA[%&r6)N3⍉oߌ7Qf9V㴓$=ɍqn W:HEMa=biv7Ϡӈ˵*y2`kњTU?:8>B0"Uh`ajvu.8B>_Q0 ˺Ƅ8&V!Am!%W[;l);In^ʼn:u t SwY^$BB *:ā:bǥu{\`f-GY wĚYk|lAh۫:k}qs-|0 C;(|={7R_q"niWqm5{L4 PȠ>>F}z:^0(w3|>(++cr2h v#1qYbB5u0#-caBpZ_nn{*ʎ+EuNjPw|/i gNrHv;1 #7zZq kRol8NM)'2b'2dC2ЂoaAn>3;L+-8UńjЃ hvT́IAs<*}&E""tZ" C8\2hD|QDtt LjJDBai 4=ͱR5ΨB(.H;9PD=W? w$zMbӀiْ@,'ntՙ\+؊VR[qlBu)_}pXYfvn7>Oi"nb( nۚCVUfgGA|a=!i%1rY:fgp8ԕ({ڗ՟6jI}!nNH_ZRHy0VTKtMS;PPPCvIIJ1"‚ Opg8bG5T*Fn F.!hb*.233bpwzՄJ%L&*Cy! eR >fq\c뺸"n1XkRi8g6:YԆ2 ENLj%lm/B,iŸKZ8ʶ q8r!n(E) uqιscJqq1?O$r%UYfB,eQmP5: (i aF"01=ܢ^Ep}1yd{Ǹq 37n'Nȑ#L4ÇG!K{:u*[owm3|ݻk" q*ƯS%Q}َjTEDf-XatTMG‘0OLL|-]-#}ꫯfǎݻ#G Xb_طozz/A'pwnYA{9o뤦3x`k>K,a۶m͛9tW楗^SNk׎˗/R__O(K/k׮lٲLBVVn:z)֯_O.]̴}ҥɦMꪫXlCYYуe˖~;6mDAA@_lذJzA0䩧^ȑ# 4UUygᣏ>nn݊gԨQA~iy|>2-m 41z>8!/^'x-Z] bbtP UDQLՌXZE3A1P40(Io6klذロ"ϟo77 7x#]ta޽l߾-[XYd ~ϟ~i(**bɒ%Y?Ou]$'']v1{lڷoϸqk0 K/t&MĠA=5kְxb̙e]Ƅ (+k<sND<f"99]vyf{wk2q<ǏK.L>vڱk.F}ǺuXjדO> 7܀f;lt,?l̟?_^zIZ4+ ᵏ^u;?~{_EA1ma"֭E\jO3⫣8v6E30=^XΚ &2u`-Imm-@+VP^^f{!55Zq]w1tP MgYp!'NdΜ9 >p8ҥKx饗9r$O>G?"^;6mZ%iTUUѻwo^/$##پy~g[3fp-PXXH^3gC=d[C~_ѯ_?v;-B4rssIKKʫ9t}?0#77ʕ+B˖-ȑ#ffϞ-w2Ahe `U`ۍy|;(15Mi2U@1Wa%V5Pbm3ĚIdcOi˘ڼ׏jӱ"lHKK# RRRBnS٧,ÑXp@yy9>"KzϨdaYYT׏< YHԭp8My7Xt)ӦM&4?vݺu/ 7TY8)FR4Ƚ++bmDE$4&-9-T#l n>+:i!/|MkuϞ=sNڷoOZZ '222πHÇϨ222,0S>9N|>I-₂֮] x;v<+%Rʕ+Yp!FKxHٸq#yyy|g?GFΝ1b={BV ¦IxoQK>TM{Z1 ՌH[AVQFF7jkG.E?b.eL `XʪYQSЪۜ'%%1bTUcǎ \tEX뮻^zQZZʲe?>]wo&>e˖1ay*zɠA 9sf;v'hr3g2ydϟo͵6\`nf}]˹[MLxc߽{wB_~9O<g?! @4hmcƍygl2fΜE]Dee%~;ӧO; p!Bz,fD Y1EU^M8 4,O&舷xuoDٓi'\[Π?0eLy֣&99>ǃa[z][[ Ixlj_555VZxKp7Mj+)G Rmx ׼ -0wx+_ 86#j)J-6<궎2J4 Lyb4N4׿jXLAI4Mfww&5Y9 7"l6cjuK+8wsLx-K[Yݑu1(o!AZO_-ѹ\%dSk#!%ꖵjZ.Xh8n)${;(`D&հئ>BǴ8"Ă BBlURJŬF8'c)VP''E5"P佘jIg5plVUnJ!B,HOOhnD*hb%fCv"e 獸k׺ciD=+C<QZ6[n`QX a3?%(tvm,B-c-Zk&F1 m+E PD2vtMa\vto$,h!v:TsqkMl h w]r΃W?:x.:ȏ&JMvB<̠XK+h+:@l7gQ+7vtA+0n@яT x‘hPP뙃8 8V\ `&^{-O>)ۿ?g֬Y8&#_L~~|1Au]gOKcl=R~rJ"-*lԪ#kzp$(KF8ką EymIHPNIwb(ہBqEzlb쁨ZJNZc;zpX V_Jee%6ŋ7>C=D~s5tjO͓Qdњ3>-f\l<.'NZ[>Ink)k5{:>GR5ޑ}8z@Y<C*MD@ia0Ѡ-5/t=UU[oH,soYX~=AmmmBMw AՍbW{*))IT:O܈p8f󾲯}0~\b-NczǀXtk~727Q^mx4_AZ02/G7ujbMU+JIIt_һwo6lp16l@^^[l5u= /g"E_FUp8|O b Ekh˖NTURC+vi5}=;z`f *?n:v ֲ& L+GR鿘>dyZ߃9jEK,aҤI1tP+Ծ?x5t՞3@HzfFR3]UŎ&jԡ[LZ?ߏV19~8:tcpb Jtpzވ+j(n Q7učxǞ3 \``(*Uc(BeMjzpD *@>SV1 M:u*=]vMnWGSW{N0Wh7&׎fktywذawG}h",YgŊ$J:JCK4jXF3 6M#>!8O ^EMyP*j^v;vӉrrp8VR,sLp?Y6~ScSRRR(Eid}8X_>rB&o:o999 6e˖vZ?4Gjj*7p)*((>,p(v:Љdj *z4WtlSTnp :>jNLprp8):iCikpVXAjj ķd{|ppD }eԨQу?4ZW>i$>Sƌ͛ Bر{2g9x ?0cǎꫯ_fƍdff2o<:u@}}=K,p w 7ᯋ󑑑~%\OSv͟gݺu뮻x;#[Ul읩_˹0w)*| vR"U(u17φ !6j4[ˆ}fΜɓ?>ӦM׿5dddzYYY\veAfΜINN~[.!l\.k'\yD3{$9eEv# -ፏd 4Al2XU"qLO׏mT5~}zj\u4MkY555Z.kB!t]v7#FB!S]]MYYr؟fKXVPt " \qsMÛ`L ~PײjY ׼78D[rHOOXcKҲ"bAi^7a~T B, !i""Ă ·!"gI$yɺڂ B,p;w.{쑁bANݻke "sĂFW_sάZaÆq7( ˖-cX[n}0w\t]=[nTWIDATeѢE̙3=z[or馛۷/cέJ>}8z(_(+++`ʔ)XĂpa;ظq#W^W_`֬Y$''swSTT~x<ƏO.]>}:ڵc͚5,^9spe1a(//ꫯfС\{l޼j&Laø~k&_ E,ݺuc…̟?UVqC1tP+V=Cjj*@\((('??|Oκu4QF1c oW^ɕW^ ~3}YquP~_H'xQ̜n&ۛɛoɚ5kHMMn{^7t:ٳ'Ǐ} ۿ;|V>tA8gzդ[Ul6iii*'jNMM жvԖBcŜƍcĉ9r'&lW_}Ŷmۘ3g.SZddd0vX|>FbӦM ?Xsٷo}aڵeOL,CNN;w}QRRBiiնk2x` .7x#,[ i#//?v>ƌ#_J ^z={j*&LСCOrr2 ,P\\̊+8x dܹl6>O?'%%#F0qD>̲e˨g 4Ⱥy˨Qh*sΖG,\@ 鴬1c0frss;زe ۶mo߾\wu̟?͛70`ݻwOx=c ^~e6nHff&#=='xEQbʕ>""--{dza-o xŊ\wu̘1,[ ݻ ٺu+ ,waҤI\zzr%PPP3f ֭cС\y\r%L<۷3o޼F - Y~=7x#v?6mEEE,Y]v1rH>֭[ǪUH3f|gy/jf̘iӘ1c_=CslݺѣG["ܐcDzsN*++xW9s&ӧOgڵٳgsu{w^zիٺu+q?~\,bAU| _!;v,۶md}M_z5~۝UU/K~pB5 -ݻ[ĉ3gÇ'tR VСCӇ`hadggzjz,͛73y&o.!PSS~3|fAQRRRa^|E><۷3`͛^̚5өS'v}^}U xyE\*kV!34M!&JM£hꙧ TFǔƋp"mxnxC'6ܐxa۱տ2-x?7`ҥL6BrrrPUA1ev;?QUG n7s`sr]w1bĈfqq٬]BK\:+b q>uQQgfԩ8NMƐ!C;9x  !(v&3G(b~Z&uSꙻhUUvP!YYY{E 焕+WpBFc=ixgIIIsQ]]_oվ>"wѣ曛ݾ{wŋ( //Ì=_<?K.޽?ϖiܸq}֔ e4 Izz:. 4(0 Pn?#XUUv;⣖TU캉cՖ_̞= 0M8pe.]z6mbYUUٽ{7s!))3Ϝ5sk( |֭#  Yf @$fq|ٳg3k,ڷoI,bAXFh4Wh޼y̘1tܙC(I+θq }0sL&O;j^F(՗\iѷRZgg۳#CrM m*xo+(..殻0 \.WB555x<kMUyjXĂ BE'kp8#)))QؚREX,bM$ Zz6sus:d5#QWWag,XB0 ?@[3wwv gWE=d@S,!Pp"B,#TdUW RAbAA!AAXADAA!AbAADAAXAbAA!AAXADAA!AbAADAAXAbAA!AAXADAA!AbAA@-&G+_R{Zێ&c_}bbAV}%5~C{=ˋa>2gsA! wNK(lRrhx6wI;dlBl>Pi-l MU\RXiט6 ϯ=%|| B,\ (|/{sU}'7@UμqST^  t<7./^yo,+Gv~f B,\|qG˦2*'{%sOG+딌ۡ`X Cz)ŗl?5w:^d]зak_aL7#Sl>PAU]%85A Ӥ.Jڧ91 /p,kr#nʪl=\ed$9p94>_܎I|!s26Me*ֱ֞ B,\uº@f{YG1a@{SȌО$ M4##+L,qg/lgimwqTzQ(_zzeyXx}?g"sIW(f~E_e ;Яk*oou_3GvnS?/l6k,nGw?_1dNۋ#nT&ǧWIC:Gy^\v팎E3C/ -.̹; /gC mVm:bt yܢZV?ayn_ӡc{qa _ZKYui.4U!cxe~W5z[{Xl*ߛf]3T`H .6P~:z K ao&P#W%2P_Y9g b m]%cWo*J FBӌdEԭ>A=8:N[z #b{r8RZp&QUxd'9*ӆwa'5Ppԓ\;^;{g$Ag٩N*A?;c "BV[j ۏsUAxnһkv86)cNq)|wdޕyia d€¼#XA!Z& ?7b6vgm6|]|oZ]Sr;yWgV]릹~uӴT7LAj:Titpo{5  yo1; . >Ql*\?;7 @m ?+:lW1:n_tJj,}g/?ϼi _4MSA8[u?]t=% Sdrj*Z (bh'^UV 5*a¤1+w=%=S/Kرk*5NvI Lpl GUh4͍ D/Ie3:;CTЭޯňilN H_l{4E7lv*ఫ G_F2rr-ָ==ΧlnLO!2O,"ĂТYu|o7 M6†2@  ¹$}mvL}ӲA!,Q9Z!klAhIq) "Ă  B,     B, "Ă     "Ă  B,     B, "Ă   B&C LLz!  BQbJlRrx p>Tcr}DC8m=r.L4MSAA$XKADAAXAbAA!AAXADAA!A >+g([IENDB`traits-6.3.2/docs/source/traits_user_manual/index.rst000066400000000000000000000041641414270267200230340ustar00rootroot00000000000000============================ Traits |version| User Manual ============================ :Authors: David C. Morrill, Janet M. Swisher, and Enthought developers :Copyright: | (C) Copyright 2005-2021 Enthought, Inc., Austin, TX | All rights reserved. Contents ======== .. toctree:: :maxdepth: 3 intro.rst installation.rst defining.rst notification.rst deferring.rst custom.rst advanced.rst testing.rst debugging.rst internals.rst appendix.rst Indices and tables ================== * :ref:`genindex` * :ref:`search` License ======= Redistribution and use of this document in source and derived forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source or derived format (for example, Portable Document Format or Hypertext Markup Language) must retain the above copyright notice, this list of conditions and the following disclaimer. * Neither the name of Enthought, Inc., nor the names of contributors may be used to endorse or promote products derived from this document without specific prior written permission. THIS DOCUMENT IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENT, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. All trademarks and registered trademarks are the property of their respective owners. | Enthought, Inc. | 200 W Cesar Chavez | Suite 202 | Austin, TX 78701 | United States | 1.512.536.1057 (voice) | http://www.enthought.com | info@enthought.com traits-6.3.2/docs/source/traits_user_manual/installation.rst000066400000000000000000000016431414270267200244250ustar00rootroot00000000000000.. index:: installation .. _installation: ============ Installation ============ The latest release of Traits is available from the Python Package Index (PyPI), and the normal way to install Traits into your Python environment is using pip:: python -m pip install traits Traits includes a C extension module. Binary wheels are provided on PyPI for common platforms, but some platforms may need to compile Traits from source. On those platforms, a suitable C compiler will be needed. Installation from source on macOS --------------------------------- The system Python 3.8 on macOS Catalina has trouble installing Traits from source, due to an apparent mismatch in architecture settings. This issue can be worked around by specifying the "ARCHFLAGS" environment variable for the install:: ARCHFLAGS="-arch x86_64" python -m pip install traits See https://github.com/enthought/traits/issues/1337 for more details. traits-6.3.2/docs/source/traits_user_manual/internals.rst000066400000000000000000000326461414270267200237320ustar00rootroot00000000000000.. index:: internals Traits internals ================ This section of the documentation is intended both for those developing Traits itself, and for those using Traits who would like a better understanding of the Traits internals. Fundamentals ------------ The runtime behavior of Traits is governed by two key classes: |CTrait| and |HasTraits|. Each of these classes inherits from a superclass implemented in the |ctraits| C extension module: |CTrait| inherits from |cTrait|, while |HasTraits| inherits from |CHasTraits|. The |CHasTraits| and |cTrait| base classes are not intended for direct use and do not provide a complete, coherent API: that API is provided by their respective subclasses |HasTraits| and |CTrait|. The existence and precise semantics of the base classes should be regarded as implementation details. In what follows, we'll frequently refer to behavior of |HasTraits| and |CTrait| even when the behavior we're referring to is actually implemented by |CHasTraits| or |cTrait|. We'll examine both of these classes, along with some of their hidden state, in more detail below. Key class: |HasTraits| ~~~~~~~~~~~~~~~~~~~~~~ The primary purpose of the |HasTraits| class is to override Python's normal rules for attribute access. It does this by overriding the ``__getattribute__``, ``__setattr__`` and ``__delattr__`` special methods. At C level, this is done through providing ``tp_getattro`` and ``tp_setattro`` "slots" to the |CHasTraits| ``PyTypeObject``: ``tp_getattro`` controls attribute retrieval operations, while ``tp_setattro`` is called for both attribute set and attribute deletion operations. To support trait get and set operations, a |HasTraits| object (that is, in normal use, an instance of a user-defined subclass of |HasTraits|) has two key pieces of state: a dictionary of **class traits**, and a second dictionary of **instance traits**. Each dictionary is a mapping from trait attribute names to |CTrait| objects. A |CTrait| object encapsulates the rules for getting and setting the corresponding attribute, as well as providing an attachment point for trait notifications. In addition to these two dictionaries, a |HasTraits| object has a ``__dict__`` that stores attribute values for that object in the normal way. Analogously to class variables and instance variables in a normal Python class, the class traits dictionary for a given |HasTraits| subclass is shared between instances of that class, while the instance traits dictionary is specific to a particular |HasTraits| instance. (As an internal optimization, the instance traits dictionary is created on demand when first needed, while the class traits dictionary is always present for each instance.) For introspection and debugging purposes, both of these dictionaries can be retrieved directly, using the |_instance_traits| and |_class_traits| methods. However, it's not recommended to use either of these methods in production code, and you should be especially careful when modifying either of these dictionaries. For example, consider the following |HasTraits| subclass:: from traits.api import Float, HasTraits, Str class Ingredient(HasTraits): """ An ingredient in a recipe listing. """ #: The name of the ingredient. name = Str() #: Ingredient quantity. quantity = Float() Here's what happens when we create an instance of this ingredient and inspect the instance and class trait dictionaries:: >>> eggs = Ingredient(name="eggs", quantity=12) >>> eggs._instance_traits() {} >>> eggs._class_traits() { 'name': , 'quantity': , 'trait_added': , 'trait_modified': , } >>> eggs.__dict__ {'name': 'eggs', 'quantity': 12.0} Note that the actual values for the ingredient are stored in the ``__dict__`` as usual, not in the ``CTrait`` objects. If we create a second ingredient, it shares class traits (but not instance traits) with the first one:: >>> flour = Ingredient(name="flour", quantity=3.5) >>> flour._class_traits() is eggs._class_traits() True >>> flour._instance_traits() is eggs._instance_traits() False Key class: |CTrait| ~~~~~~~~~~~~~~~~~~~ A |CTrait| object has two main purposes: - It encapsulates the rules for getting and setting a traited attribute on a |HasTraits| object. - It provides an attachment point for trait notifiers. The hidden state for a |CTrait| instance is encapsulated in the ``trait_object`` C ``struct`` in the |ctraits| source. There are several interesting fields, not all of which are exposed at Python level. Of particular interest are the ``getattr`` and ``setattr`` fields, which hold pointers to C functions that act as the entry points for attribute access via the given trait. See below for a fuller description of attribute access mechanics. Attribute retrieval ~~~~~~~~~~~~~~~~~~~ When evaluating ``obj.name`` for a ``HasTraits`` object ``obj``, the following sequence of steps occurs (see ``has_traits_getattro`` in the C source): - The ``name`` is looked up in ``obj.__dict__``. If found, the corresponding value is returned immediately. - If ``name`` is not found in ``obj.__dict__``, we look first for an instance trait named ``name``, and then for a class trait named ``name``. Thus an instance trait with a given name will shadow a class trait with the same name. - If a matching trait is found, its ``getattr`` field is invoked to retrieve the trait's value for the given object. - If no matching trait is found, we try to access the attribute value using Python's usual attribute rules (via the ``PyObject_GenericGetAttr`` C-API call). - Finally, if the ``PyObject_GenericGetAttr`` call fails, we invoke the **prefix trait** machinery to get a new ``CTrait`` object, and use that new trait to get a value. Note that the above sequence of steps applies to method access as well as attribute access. Note also that there's no mechanism to automatically search for ``CTrait`` objects in superclasses of the immediate ``HasTraits`` subclass. Attribute set operations ~~~~~~~~~~~~~~~~~~~~~~~~ The rules for setting an attribute (evaluating ``obj.name = value`` for a ``HasTraits`` object ``obj``) are analogous to those for attribute retrieval. The starting point is ``has_traits_setattro`` in the source. - First we look for the name ``name`` in ``obj._instance_traits()``, and retrieve the corresponding ``CTrait`` instance if present. - If no matching entry is found, we then look up ``name`` in ``obj._class_traits()``, and again retrieve the corresponding ``CTrait``. - If still not found, we invoke the **prefix trait** machinery to get a new ``CTrait`` object. By default, this goes through the ``HasTraits.__prefix_trait__`` method (which is implemented in Python), and this may still fail with an exception. - If one of the above steps succeeded, we now have a ``CTrait`` object, and its ``setattr`` function is invoked (passing along the trait object, ``obj``, ``name`` and ``value``) to perform the actual attribute set operation. Attribute deletion ~~~~~~~~~~~~~~~~~~ Attribute deletion (``del obj.name``) goes through the same code path as attribute set operations. Most ``CTrait`` types do not permit deletion. Traits Containers ----------------- Traits has the ability to watch for changes in standard Python containers: lists, dictionaries and sets. To achieve this Traits provides special subclasses of the standard Python classes that can validate elements and can fire trait notifications when the contents change. These classes are, respectively, |TraitList|, |TraitDict| and |TraitSet| (not to be confused with the deprecated Trait Handlers of the same names). In addition to being able to take an appropriate value to initialize the container (such as a sequence or mapping), these container subclasses also take keyword-only arguments for validators (either a single item validator for |TraitList| and |TraitSet|, or key and value validators for |TraitDict|) and notifiers. These classes were introduced in Traits 6.1 and the implementation details described here are provisional and may change. Backwards Compatibility ~~~~~~~~~~~~~~~~~~~~~~~ In practice, most traits containers are instances of |TraitListObject|, |TraitDictObject| and |TraitSetObject| which are subclasses that are created by the validators of |List|, |Dict| and |Set| traits respectively and supplied with appropriate element validators that wrap the standard trait validators so that constructs like ``List(Str)`` can work. These objects are designed to be API compatible with the classes of the same name from Traits 6.0 and before, and so have different constructors and may behave slightly differently from the base classes in some cases. In particular |TraitListObject| classes can have restrictions on their length, which is not part of the base |TraitList| API. All of these backward compatibility classes are strongly tied to a particular object and trait, and are not designed to operate as stand-alone entities. These relationships are required to support the `object.*_items`-style event traits, but complicate the implementation, for example by having to use weak references to the object, and having to take this additional structure into account when serializing and deserializing. It is a long-term goal to phase out the use of these backwards compatibility classes. Container Validators ~~~~~~~~~~~~~~~~~~~~ Container validators are callables that are expected to take a single value and either return a validated value or raise a TraitError. The default validators simply pass the input value directly through, but validators can potentially do much more. Validators are expected to be idempotent: ``validate(validate(x)) == validate(x)`` should hold as long as ``validate(x)`` does not raise an error. For example, the following validator casts the list items to integers, raising a TraitError if that fails:: def int_validator(value): try: return int(value) except ValueError: raise TraitError( "List items must be castable to an int, but a value %r was specified." % value ) So if we were to use this as the validator for a |TraitList| we would get the following behaviour:: >>> int_list = TraitList(item_validator=int_validator) >>> int_list.append("5") >>> int_list [5] >>> int_list.extend([3, 5, "aaaarrrghh"]) TraitError: List items must be castable to an int, but a value 'aaaarrrghh' was specified. In Traits 6.1 validation is not done uniformly before performing operations to keep behaviour the same as Traits 6.0 and earlier, so results of operations can sometimes be surprising:: >>> int_list.append("6") >>> int_list.remove("6") ValueError: list.remove(x): x not in list This is expected to be resolved in a future traits version by providing clear guidance to users about when validation is performed, and possibly changing the behaviour. Container Notifiers ~~~~~~~~~~~~~~~~~~~ Container objects also have a list of notifiers that fire when the contents of the container change. Like trait notifiers, container notifiers are low-level callbacks that are used by the higher-level, more user-friendly observer and listener systems. They have a fixed signature, which is slightly different for lists, dicts and sets, but in all cases starts with the container object itself. Notifiers are called in the order that they appear in the notifiers list and should not mutate the parameters that they have been passed. List notifiers must take 4 arguments: the **trait_list** object, the **index** value or slice that identifies where the change occurred, a list of **removed** elements, and a list of **added** elements. The |TraitList| methods make an attempt to normalize indices and slices to make things easier for notification writers. Dict notifiers expect 4 arguments: the **trait_dict** object, a dictionary of **removed** items, a dictionary of **added** elements, and a dictionary of **changed** items, where the values are the old values held in the keys. Set notifiers expect 3 arguments: the **trait_set** object, the set of **removed** elements, and the set of **added** elements. Users should not usually need to interact with the container notifiers directly, just as they do not usually need to interact with trait notifiers. .. # substitutions .. |_class_traits| replace:: :meth:`~traits.ctraits.CHasTraits._class_traits` .. |_instance_traits| replace:: :meth:`~traits.ctraits.CHasTraits._instance_traits` .. |cTrait| replace:: :class:`~traits.ctraits.cTrait` .. |CTrait| replace:: :class:`~traits.ctrait.CTrait` .. |ctraits| replace:: :mod:`~traits.ctraits` .. |CHasTraits| replace:: :class:`~traits.ctraits.CHasTraits` .. |HasTraits| replace:: :class:`~traits.has_traits.HasTraits` .. |TraitList| replace:: :class:`~traits.trait_list_object.TraitList` .. |TraitDict| replace:: :class:`~traits.trait_dict_object.TraitDict` .. |TraitSet| replace:: :class:`~traits.trait_dict_object.TraitSet` .. |TraitListObject| replace:: :class:`~traits.trait_list_object.TraitListObject` .. |TraitDictObject| replace:: :class:`~traits.trait_dict_object.TraitDictObject` .. |TraitSetObject| replace:: :class:`~traits.trait_dict_object.TraitSetObject` .. |List| replace:: :class:`~traits.trait_types.List` .. |Dict| replace:: :class:`~traits.trait_types.Dict` .. |Set| replace:: :class:`~traits.trait_types.Set` traits-6.3.2/docs/source/traits_user_manual/intro.rst000066400000000000000000000161411414270267200230560ustar00rootroot00000000000000============ Introduction ============ The Traits package for the Python language allows Python programmers to use a special kind of type definition called a trait. This document introduces the concepts behind, and usage of, the Traits package. For more information on the Traits package, refer to the `Traits GitHub repository `_. For additional documentation on the Traits package, refer to the `Traits API Reference `_ What Are Traits? ---------------- A trait is a type definition that can be used for normal Python object attributes, giving the attributes some additional characteristics: .. index:: initialization * **Initialization**: A trait has a *default value*, which is automatically set as the initial value of an attribute, before its first use in a program. .. index:: validation * **Validation**: A trait attribute is *explicitly typed*. The type of a trait-based attribute is evident in the code, and only values that meet a programmer-specified set of criteria (i.e., the trait definition) can be assigned to that attribute. Note that the default value need not meet the criteria defined for assignment of values. Traits 4.0 also supports defining and using abstract interfaces, as well as adapters between interfaces. .. index:: deferral * **Deferral**: The value of a trait attribute can be contained either in the defining object or in another object that is *deferred to* by the trait. .. index:: notification * **Notification**: Setting the value of a trait attribute can *notify* other parts of the program that the value has changed. .. index:: visualization * **Visualization**: User interfaces that allow a user to *interactively modify* the values of trait attributes can be automatically constructed using the traits' definitions. This feature requires that a supported GUI toolkit be installed. However, if this feature is not used, the Traits package does not otherwise require GUI support. For details on the visualization features of Traits, see the `TraitsUI User Manual `_. A class can freely mix trait-based attributes with normal Python attributes, or can opt to allow the use of only a fixed or open set of trait attributes within the class. Trait attributes defined by a class are automatically inherited by any subclass derived from the class. The following example [1]_ illustrates each of the features of the Traits package. These features are elaborated in the rest of this guide. .. index:: examples; Traits features :: # all_traits_features.py --- Shows primary features of the Traits # package from traits.api import Delegate, HasTraits, Instance,\ Int, Str class Parent ( HasTraits ): # INITIALIZATION: last_name' is initialized to '': last_name = Str( '' ) class Child ( HasTraits ): age = Int # VALIDATION: 'father' must be a Parent instance: father = Instance( Parent ) # DELEGATION: 'last_name' is delegated to father's 'last_name': last_name = Delegate( 'father' ) # NOTIFICATION: This method is called when 'age' changes: def _age_changed ( self, old, new ): print('Age changed from %s to %s ' % ( old, new )) # Set up the example: joe = Parent() joe.last_name = 'Johnson' moe = Child() moe.father = joe # DELEGATION in action: print("Moe's last name is %s " % moe.last_name) # Result: # Moe's last name is Johnson # NOTIFICATION in action moe.age = 10 # Result: # Age changed from 0 to 10 # VISUALIZATION: Displays a UI for editing moe's attributes # (if a supported GUI toolkit is installed) moe.configure_traits() Background ---------- Python does not require the data type of variables to be declared. As any experienced Python programmer knows, this flexibility has both good and bad points. The Traits package was developed to address some of the problems caused by not having declared variable types, in those cases where problems might arise. In particular, the motivation for Traits came as a direct result of work done on Chaco, an open source scientific plotting package. .. index:: Chaco Chaco provides a set of high-level plotting objects, each of which has a number of user-settable attributes, such as line color, text font, relative location, and so on. To make the objects easy for scientists and engineers to use, the attributes attempt to accept a wide variety and style of values. For example, a color-related attribute of a Chaco object might accept any of the following as legal values for the color red: * 'red' * 0xFF0000 * ( 1.0, 0.0, 0.0, 1.0 ) Thus, the user might write:: plotitem.color = 'red' In a predecessor to Chaco, providing such flexibility came at a cost: * When the value of an attribute was used by an object internally (for example, setting the correct pen color when drawing a plot line), the object would often have to map the user-supplied value to a suitable internal representation, a potentially expensive operation in some cases. * If the user supplied a value outside the realm accepted by the object internally, it often caused disastrous or mysterious program behavior. This behavior was often difficult to track down because the cause and effect were usually widely separated in terms of the logic flow of the program. So, one of the main goals of the Traits package is to provide a form of type checking that: * Allows for flexibility in the set of values an attribute can have, such as allowing 'red', 0xFF0000 and ( 1.0, 0.0, 0.0, 1.0 ) as equivalent ways of expressing the color red. * Catches illegal value assignments at the point of error, and provides a meaningful and useful explanation of the error and the set of allowable values. * Eliminates the need for an object's implementation to map user-supplied attribute values into a separate internal representation. In the process of meeting these design goals, the Traits package evolved into a useful component in its own right, satisfying all of the above requirements and introducing several additional, powerful features of its own. In projects where the Traits package has been used, it has proven valuable for enhancing programmers' ability to understand code, during both concurrent development and maintenance. The Traits |version| package works with versions 3.5 and later of Python. It is similar in some ways to the Python property language feature. Standard Python properties provide the similar capabilities to the Traits package, but with more work on the part of the programmer. .. rubric:: Footnotes .. [1] All code examples in this guide that include a file name are also available as examples in the tutorials/doc_examples/examples subdirectory of the Traits examples directory. You can run them individually, or view them in a tutorial program by running: python /examples/tutorials/tutor.py /examples/tutorials/doc_examples traits-6.3.2/docs/source/traits_user_manual/listening.rst000066400000000000000000001010671414270267200237210ustar00rootroot00000000000000.. _on-trait-change-notification: =========================================== Trait Notification with **on_trait_change** =========================================== **on_trait_change** is an older method for setting up change notifications. It has several design flaws and limitations. A newer mechanism **observe** is introduced for overcoming them. See :ref:`observe-notification` for details and for how to migrate. Change notifications can be set up with **on_trait_change** in several ways: .. index:: notification; strategies * Dynamically, by calling on_trait_change() or on_trait_event() to establish (or remove) change notification handlers. * Statically, by decorating methods on the class with the @on_trait_change decorator to indicate that they handle notification for specified attributes. * Statically, by using a special naming convention for methods on the class to indicate that they handle notifications for specific trait attributes. .. index:: notification; dynamic .. _dynamic-notification: Dynamic Notification -------------------- Dynamic notification is useful in cases where a notification handler cannot be defined on the class (or a subclass) whose trait attribute changes are to be monitored, or if you want to monitor changes on certain instances of a class, but not all of them. To use dynamic notification, you define a handler method or function, and then invoke the on_trait_change() or on_trait_event() method to register that handler with the object being monitored. Multiple handlers can be defined for the same object, or even for the same trait attribute on the same object. The handler registration methods have the following signatures: .. index:: on_trait_change; method .. method:: on_trait_change(handler[, name=None, remove=False, dispatch='same']) .. index:: on_trait_event(); method .. method:: on_trait_event(handler[, name=None, remove=False, dispatch='same']) In these signatures: * *handler*: Specifies the function or bound method to be called whenever the trait attributes specified by the *name* parameter are modified. * *name*: Specifies trait attributes whose changes trigger the handler being called. If this parameter is omitted or is None, the handler is called whenever *any* trait attribute of the object is modified. The syntax supported by this parameter is discussed in :ref:`the-name-parameter`. * *remove*: If True (or non-zero), then handler will no longer be called when the specified trait attributes are modified. In other words, it causes the handler to be "unhooked". * *dispatch*: String indicating the thread on which notifications must be run. In most cases, it can be omitted. See the *Traits API Reference* for details on non-default values. .. index:: examples; dynamic notification .. _example-of-a-dynamic-notification-handler: Example of a Dynamic Notification Handler ````````````````````````````````````````` Setting up a dynamic trait attribute change notification handler is illustrated in the following example:: # dynamic_notification.py --- Example of dynamic notification from traits.api import Float, HasTraits, Instance class Part (HasTraits): cost = Float(0.0) class Widget (HasTraits): part1 = Instance(Part) part2 = Instance(Part) cost = Float(0.0) def __init__(self): self.part1 = Part() self.part2 = Part() self.part1.on_trait_change(self.update_cost, 'cost') self.part2.on_trait_change(self.update_cost, 'cost') def update_cost(self): self.cost = self.part1.cost + self.part2.cost # Example: w = Widget() w.part1.cost = 2.25 w.part2.cost = 5.31 print w.cost # Result: 7.56 In this example, the Widget constructor sets up a dynamic trait attribute change notification so that its update_cost() method is called whenever the **cost** attribute of either its **part1** or **part2** attribute is modified. This method then updates the cost attribute of the widget object. .. index:: name parameter; on_trait_change() .. _the-name-parameter: The *name* Parameter ```````````````````` The *name* parameter of on_trait_change() and on_trait_event() provides significant flexibility in specifying the name or names of one or more trait attributes that the handler applies to. It supports syntax for specifying names of trait attributes not just directly on the current object, but also on sub-objects referenced by the current object. The *name* parameter can take any of the following values: * Omitted, None, or 'anytrait': The handler applies to any trait attribute on the object. * A name or list of names: The handler applies to each trait attribute on the object with the specified names. * An "extended" name or list of extended names: The handler applies to each trait attribute that matches the specified extended names. .. index:: pair: extended trait names; syntax .. _syntax: Syntax :::::: Extended names use the following syntax: .. productionList:: xname: xname2['.'xname2]* xname2: ( xname3 | '['xname3[','xname3]*']' ) ['*'] xname3: xname | ['+'|'-'][name] | name['?' | ('+'|'-')[name]] A *name* is any valid Python attribute name. .. index:: pair: extended trait names; semantics .. _semantics: Semantics ::::::::: .. _semantics-of-extended-name-notation-table: .. rubric:: Semantics of extended name notation +------------------------------+----------------------------------------------+ | Pattern | Meaning | +==============================+==============================================+ |*item1*\ .\ *item2* |A trait named item1 contains an object (or | | |objects, if *item1* is a list or dictionary), | | |with a trait named *item2*. Changes to either | | |*item1* or *item2* trigger a notification. | +------------------------------+----------------------------------------------+ |*item1*\ :*item2* |A trait named **item1** contains an object (or| | |objects, if *item1* is a list or dictionary), | | |with a trait named *item2*. Changes to *item2*| | |trigger a notification, while changes to | | |*item1* do not (i.e., the ':' indicates that | | |changes to the link object are not reported. | +------------------------------+----------------------------------------------+ |[*item1*, *item2*, ..., |A list that matches any of the specified | |*itemN*] |items. Note that at the topmost level, the | | |surrounding square brackets are optional. | +------------------------------+----------------------------------------------+ |*item*\ [] |A trait named *item* is a list. Changes to | | |*item* or to its members triggers a | | |notification. | +------------------------------+----------------------------------------------+ |*name*? |If the current object does not have an | | |attribute called *name*, the reference can be | | |ignored. If the '?' character is omitted, the | | |current object must have a trait called | | |*name*; otherwise, an exception is raised. | +------------------------------+----------------------------------------------+ |*prefix*\ + |Matches any trait attribute on the object | | |whose name begins with *prefix*. | +------------------------------+----------------------------------------------+ |+\ *metadata_name* |Matches any trait on the object that has a | | |metadata attribute called *metadata_name*. | +------------------------------+----------------------------------------------+ |-*metadata_name* |Matches any trait on the current object that | | |does *not* have a metadata attribute called | | |*metadata_name*. | +------------------------------+----------------------------------------------+ |*prefix*\ +\ *metadata_name* |Matches any trait on the object whose name | | |begins with *prefix* and that has a metadata | | |attribute called *metadata_name*. | +------------------------------+----------------------------------------------+ |*prefix*\ -*metadata_name* |Matches any trait on the object whose name | | |begins with *prefix* and that does *not* have | | |a metadata attribute called *metadata_name*. | +------------------------------+----------------------------------------------+ |``+`` |Matches all traits on the object. | +------------------------------+----------------------------------------------+ |*pattern*\ * |Matches object graphs where *pattern* occurs | | |one or more times. This option is useful for | | |setting up listeners on recursive data | | |structures like trees or linked lists. | +------------------------------+----------------------------------------------+ .. index:: extended trait names; examples .. _examples-of-extended-name-notation-table: .. rubric:: Examples of extended name notation +--------------------------+--------------------------------------------------+ |Example | Meaning | +==========================+==================================================+ |``'foo, bar, baz'`` |Matches *object*.\ **foo**, *object*.\ **bar**, | | |and *object*.\ **baz**. | +--------------------------+--------------------------------------------------+ |``['foo', 'bar', 'baz']`` |Equivalent to ``'foo, bar, baz'``, but may be | | |useful in cases where the individual items are | | |computed. | +--------------------------+--------------------------------------------------+ |``'foo.bar.baz'`` |Matches *object*.\ **foo.bar.baz** | +--------------------------+--------------------------------------------------+ |``'foo.[bar,baz]'`` |Matches *object*.\ **foo.bar** and | | |*object*.\ **foo.baz** | +--------------------------+--------------------------------------------------+ |``'foo[]'`` |Matches a list trait on *object* named **foo**. | +--------------------------+--------------------------------------------------+ |``'([left,right]).name*'``|Matches the **name** trait of each tree node | | |object that is linked from the **left** or | | |**right** traits of a parent node, starting with | | |the current object as the root node. This pattern | | |also matches the **name** trait of the current | | |object, as the **left** and **right** modifiers | | |are optional. | +--------------------------+--------------------------------------------------+ |``'+dirty'`` |Matches any trait on the current object that has a| | |metadata attribute named **dirty** set. | +--------------------------+--------------------------------------------------+ |``'foo.+dirty'`` |Matches any trait on *object*.\ **foo** that has a| | |metadata attribute named **dirty** set. | +--------------------------+--------------------------------------------------+ |``'foo.[bar,-dirty]'`` |Matches *object*.\ **foo.bar** or any trait on | | |*object*.\ **foo** that does not have a metadata | | |attribute named **dirty** set. | +--------------------------+--------------------------------------------------+ For a pattern that references multiple objects, any of the intermediate (non-final) links can be traits of type Instance, List, or Dict. In the case of List or Dict traits, the subsequent portion of the pattern is applied to each item in the list or value in the dictionary. For example, if **self.children** is a list, a handler set for ``'children.name'`` listens for changes to the **name** trait for each item in the **self.children** list. .. note:: In the case of Dict, List, and Set with nested patterns (e.g., ``'children.name'``), not all handler signatures (see :ref:`notification-handler-signatures`) are supported; see section :ref:`dynamic-handler-special-cases` for more details. The handler routine is also invoked when items are added or removed from a list or dictionary, because this is treated as an implied change to the item's trait being monitored. .. index:: notification; dynamic .. _notification-handler-signatures: Notification Handler Signatures ``````````````````````````````` The handler passed to on_trait_change() or on_trait_event() can have any one of the following signatures: .. index:: handler; signatures, trait change handler; signatures - handler() - handler(*new*) - handler(*name*, *new*) - handler(*object*, *name*, *new*) - handler(*object*, *name*, *old*, *new*) These signatures use the following parameters: .. index:: object parameter; notification handlers * *object*: The object whose trait attribute changed. .. index:: name parameter; notification handlers * *name*: The attribute that changed. If one of the objects in a sequence is a List or Dict, and its membership changes, then this is the name of the trait that references it, with '_items appended. For example, if the handler is monitoring ``'foo.bar.baz'``, where **bar** is a List, and an item is added to **bar**, then the value of the *name* parameter is 'bar_items'. .. index:: new parameter to the notification handlers * *new*: The new value of the trait attribute that changed. For changes to List and Dict objects, this is a list of items that were added. .. index:: old parameter to the notification handlers * *old*: The old value of the trait attribute that changed. For changes to List and Dict object, this is a list of items that were deleted. For event traits, this is Undefined. If the handler is a bound method, it also implicitly has *self* as a first argument. .. index:: notification; special cases .. _dynamic-handler-special-cases: Dynamic Handler Special Cases ````````````````````````````` In the one- and two-parameter signatures, the handler does not receive enough information to distinguish between a change to the final trait attribute being monitored, and a change to an intermediate object. In this case, the notification dispatcher attempts to map a change to an intermediate object to its effective change on the final trait attribute. This mapping is only possible if all the intermediate objects are single values (such as Instance or Any traits), and not List or Dict traits. If the change involves a List or Dict, then the notification dispatcher raises a TraitError when attempting to call a one- or two-parameter handler function, because it cannot unambiguously resolve the effective value for the final trait attribute. Zero-parameter signature handlers receive special treatment if the final trait attribute is a List or Dict, and if the string used for the *name* parameter is not just a simple trait name. In this case, the handler is automatically called when the membership of a final List or Dict trait is changed. This behavior can be useful in cases where the handler needs to know only that some aspect of the final trait has changed. For all other signatures, the handler function must be explicitly set for the *name*\ _items trait in order to called when the membership of the name trait changes. (Note that the *prefix*\ + and *item*\ [] syntaxes are both ways to specify both a trait name and its '_items' variant.) This behavior for zero-parameter handlers is not triggered for simple trait names, to preserve compatibility with code written for versions of Traits prior to 3.0. Earlier versions of Traits required handlers to be separately set for a trait and its items, which would result in redundant notifications under the Traits 3.0 behavior. Earlier versions also did not support the extended trait name syntax, accepting only simple trait names. Therefore, to use the "new style" behavior of zero-parameter handlers, be sure to include some aspect of the extended trait name syntax in the name specifier. .. index:: examples; handlers :: # list_notifier.py -- Example of zero-parameter handlers for an object # containing a list from traits.api import HasTraits, List class Employee: pass class Department( HasTraits ): employees = List(Employee) def a_handler(): print("A handler") def b_handler(): print("B handler") def c_handler(): print("C handler") fred = Employee() mary = Employee() donna = Employee() dept = Department(employees=[fred, mary]) # "Old style" name syntax # a_handler is called only if the list is replaced: dept.on_trait_change( a_handler, 'employees' ) # b_handler is called if the membership of the list changes: dept.on_trait_change( b_handler, 'employees_items') # "New style" name syntax # c_handler is called if 'employees' or its membership change: dept.on_trait_change( c_handler, 'employees[]' ) print("Changing list items") dept.employees[1] = donna # Calls B and C print("Replacing list") dept.employees = [donna] # Calls A and C .. index:: notification; static .. _static-notification: Static Notification ------------------- The static approach is the most convenient option, but it is not always possible. Writing a static change notification handler requires that, for a class whose trait attribute changes you are interested in, you write a method on that class (or a subclass). Therefore, you must know in advance what classes and attributes you want notification for, and you must be the author of those classes. Static notification also entails that every instance of the class has the same notification handlers. To indicate that a particular method is a static notification handler for a particular trait, you have two options: .. index:: pair: decorator; on_trait_change * Apply the @on_trait_change decorator to the method. * Give the method a special name based on the name of the trait attribute it "listens" to. .. _handler-decorator: Handler Decorator ````````````````` The most flexible method of statically specifying that a method is a notification handler for a trait is to use the @on_trait_change() decorator. The @on_trait_change() decorator is more flexible than specially-named method handlers, because it supports the very powerful extended trait name syntax (see :ref:`the-name-parameter`). You can use the decorator to set handlers on multiple attributes at once, on trait attributes of linked objects, and on attributes that are selected based on trait metadata. .. index:: pair: on_trait_change; syntax .. _decorator-syntax: Decorator Syntax :::::::::::::::: The syntax for the decorator is:: @on_trait_change( 'extended_trait_name' ) def any_method_name( self, ...): ... In this case, *extended_trait_name* is a specifier for one or more trait attributes, using the syntax described in :ref:`the-name-parameter`. The signatures that are recognized for "decorated" handlers are the same as those for dynamic notification handlers, as described in :ref:`notification-handler-signatures`. That is, they can have an *object* parameter, because they can handle notifications for trait attributes that do not belong to the same object. .. index:: pair: on_trait_change; semantics .. _decorator-semantics: Decorator Semantics ::::::::::::::::::: The functionality provided by the @on_trait_change() decorator is identical to that of specially-named handlers, in that both result in a call to on_trait_change() to register the method as a notification handler. However, the two approaches differ in when the call is made. Specially-named handlers are registered at class construction time; decorated handlers are registered at instance creation time. By default, decorated handlers are registered prior to setting the object state. When an instance is constructed with a trait value that is different from the default, that is considered a change and will fire the associated change handlers. The ``post_init`` argument in @on_trait_change can be used to delay registering the handler to after the state is set. .. literalinclude:: /../../examples/tutorials/doc_examples/examples/post_init_notification.py :start-after: post_init_notification .. index:: notification; specially-named handlers .. _specially-named-notification-handlers: Specially-named Notification Handlers ````````````````````````````````````` There are two kinds of special method names that can be used for static trait attribute change notifications. One is attribute-specific, and the other applies to all trait attributes on a class. .. index:: _name_changed(), _name_fired() To notify about changes to a single trait attribute named name, define a method named _\ *name*\ _changed() or _\ *name*\ _fired(). The leading underscore indicates that attribute-specific notification handlers are normally part of a class's private API. Methods named _\ *name*\ _fired() are normally used with traits that are events, described in :ref:`trait-events`. To notify about changes to any trait attribute on a class, define a method named _anytrait_changed(). .. index:: pair: examples; _anytrait_changed() pair: static notification; examples Both of these types of static trait attribute notification methods are illustrated in the following example:: # static_notification.py --- Example of static attribute # notification from traits.api import HasTraits, Float class Person(HasTraits): weight_kg = Float(0.0) height_m = Float(1.0) bmi = Float(0.0) def _weight_kg_changed(self, old, new): print('weight_kg changed from %s to %s ' % (old, new)) if self.height_m != 0.0: self.bmi = self.weight_kg / (self.height_m**2) def _anytrait_changed(self, name, old, new): print('The %s trait changed from %s to %s ' \ % (name, old, new)) """ >>> bob = Person() >>> bob.height_m = 1.75 The height_m trait changed from 1.0 to 1.75 >>> bob.weight_kg = 100.0 The weight_kg trait changed from 0.0 to 100.0 weight_kg changed from 0.0 to 100.0 The bmi trait changed from 0.0 to 32.6530612245 """ In this example, the attribute-specific notification function is _weight_kg_changed(), which is called only when the **weight_kg** attribute changes. The class-specific notification handler is _anytrait_changed(), and is called when **weight_kg**, **height_m**, or **bmi** changes. Thus, both handlers are called when the **weight_kg** attribute changes. Also, the _weight_kg_changed() function modifies the **bmi** attribute, which causes _anytrait_changed() to be called for that attribute. The arguments that are passed to the trait attribute change notification method depend on the method signature and on which type of static notification handler it is. .. note:: The :func:`~.on_trait_change` and :func:`~.observe` decorators nullify the effect of special naming. A method that looks like:: @observe("foo") def _foo_changed(self, event): do_something_with(event) will only be called once when ``foo`` changes, as a result of the ``observe`` decorator. .. _attribute-specific-handler-signatures: Attribute-specific Handler Signatures ````````````````````````````````````` For an attribute specific notification handler, the method signatures supported are: .. method:: _name_changed() .. method:: _name_changed(new) :noindex: .. method:: _name_changed(old, new) :noindex: .. method:: _name_changed(name, old, new) :noindex: The method name can also be _\ *name*\ _fired(), with the same set of signatures. In these signatures: * *new* is the new value assigned to the trait attribute. * *old* is the old value assigned to the trait attribute. * *name* is the name of the trait attribute. The extended trait name syntax is not supported. Note that these signatures follow a different pattern for argument interpretation from dynamic handlers and decorated static handlers. Both of the following methods define a handler for an object's **name** trait:: def _name_changed( self, arg1, arg2, arg3): pass @on_trait_change('name') def some_method( self, arg1, arg2, arg3): pass However, the interpretation of arguments to these methods differs, as shown in the following table. .. _handler-argument-interpretation-table: .. rubric:: Handler argument interpretation ======== =================== ================ Argument _\ *name*\ _changed @on_trait_change ======== =================== ================ *arg1* *name* *object* *arg2* *old* *name* *arg3* *new* *new* ======== =================== ================ .. _general-static-handler-signatures: General Static Handler Signatures ````````````````````````````````` In the case of a non-attribute specific handler, the method signatures supported are: .. method:: _anytrait_changed() .. method:: _anytrait_changed(name) :noindex: .. method:: _anytrait_changed(name, new) :noindex: .. method:: _anytrait_changed(name, old, new) :noindex: The meanings for *name*, *new*, and *old* are the same as for attribute-specific notification functions. .. _trait-events: Trait Events ------------ .. index:: events The Traits package defines a special type of trait called an event. Events are instances of (subclasses of) the Event class. There are two major differences between a normal trait and an event: * All notification handlers associated with an event are called whenever any value is assigned to the event. A normal trait attribute only calls its associated notification handlers when the previous value of the attribute is different from the new value being assigned to it. * An event does not use any storage, and in fact does not store the values assigned to it. Any value assigned to an event is reported as the new value to all associated notification handlers, and then immediately discarded. Because events do not retain a value, the *old* argument to a notification handler associated with an event is always the special Undefined object (see :ref:`undefined-object`). Similarly, attempting to read the value of an event results in a TraitError exception, because an event has no value. .. index:: pair: events; examples As an example of an event, consider:: # event.py --- Example of trait event from traits.api import Event, HasTraits, List, Tuple point_2d = Tuple(0, 0) class Line2D(HasTraits): points = List(point_2d) line_color = RGBAColor('black') updated = Event def redraw(self): pass # Not implemented for this example def _points_changed(self): self.updated = True def _updated_fired(self): self.redraw() In support of the use of events, the Traits package understands attribute-specific notification handlers with names of the form _\ *name*\ _fired(), with signatures identical to the _\ *name*\ _changed() functions. In fact, the Traits package does not check whether the trait attributes that _\ *name*\ _fired() handlers are applied to are actually events. The function names are simply synonyms for programmer convenience. Similarly, a function named on_trait_event() can be used as a synonym for on_trait_change() for dynamic notification. .. index:: Undefined object .. _undefined-object: Undefined Object ```````````````` Python defines a special, singleton object called None. The Traits package introduces an additional special, singleton object called Undefined. The Undefined object is used to indicate that a trait attribute has not yet had a value set (i.e., its value is undefined). Undefined is used instead of None, because None is often used for other meanings, such as that the value is not used. In particular, when a trait attribute is first assigned a value and its associated trait notification handlers are called, Undefined is passed as the value of the old parameter to each handler, to indicate that the attribute previously had no value. Similarly, the value of a trait event is always Undefined. .. _trait-items-handlers: Container Items Events `````````````````````` .. index:: pair: container items; event single: _name_items_changed() For the container traits (List, Dict and Set) both static and dynamic handlers for the trait are only called when the entire value of the trait is replaced with another value; they do not get fired when the item itself is mutated in-place. To listen to internal changes, you need to either use a dynamic handler with the ``[]`` suffix as noted in the Table :ref:`semantics-of-extended-name-notation-table`, or you can define an *name*\ _items event handler. For these trait types, an auxiliary *name*\ _items Event trait is defined which you can listen to either with a static handler _\ *name*\ _items_changed() or a dynamic handler which matches *name*\ _items, and these handlers will be called with notifications of changes to the contents of the list, set or dictionary. .. index:: TraitListEvent, TraitSetEvent, TraitDictEvent For these handlers the *new* parameter is a :index:`TraitListEvent`, :index:`TraitSetEvent` or :index:`TraitDictEvent` object whose attributes indicate the nature of the change and, because they are Event handlers, the *old* parameter is Undefined. All of these event objects have **added** and **removed** attributes that hold a list, set or dictionary of the items that were added and removed, respectively. The TraitListEvent has an additional **index** attribute that holds either the index of the first item changed, or for changes involving slices with steps other than 1, **index** holds the _slice_ that was changed. For slice values you can always recover the actual values which were changed or removed via ``range(index.start, index.stop, index.end)``. The TraitDictEvent has an additional **changed** attribute which holds the keys that were modified and the _old_ values that those keys held. The new values can be queried from directly from the trait value, if needed. Handlers for these events should not mutate the attributes of the event objects, including avoiding in-place changes to **added**, **removed**, etc. .. _on-trait-change-dos-n-donts: Dos and Don’ts -------------- Don't assume handlers are called in a specific order ```````````````````````````````````````````````````` Don't do this:: @on_trait_change("name") def update_number(self): self.number += 1 @on_trait_change("name") def update_orders(self): if self.number > 5: self.orders.clear() Do this instead:: @on_trait_change("name") def update(self): number = self.number + 1 self.number = number if number > 5: self.orders.clear() The first example is problematic because when ``name`` changes, calling ``update_orders`` after ``update_number`` produces a result that is different from calling ``update_number`` after ``update_orders``. Even if the change handlers appear to be called in a deterministic order, this would be due to implementation details that may not hold true across releases and platforms. Don't raise exception from a change handler ``````````````````````````````````````````` Don't do this:: name = String() @on_trait_change("name") def update_name(self, new): if len(new) == 0: raise ValueError("Name cannot be empty.") What to do instead depends on the use case. For the above use case, ``String`` supports length checking:: name = String(minlen=1) Traits consider handlers for the same change event to be independent of each other. Therefore, any uncaught exception from one change handler will be captured and logged, so not to prevent other handlers to be called. traits-6.3.2/docs/source/traits_user_manual/notification.rst000066400000000000000000000536671414270267200244270ustar00rootroot00000000000000.. _observe-notification: Trait Notification ================== When the value of an attribute changes, other parts of the program might need to be notified that the change has occurred. The Traits package makes this possible for trait attributes. This functionality lets you write programs using the same, powerful event-driven model that is used in writing user interfaces and for other problem domains. Traits 6.1 introduces a new API for configuring traits notifications: **observe**, which is intended to fully replace an older API (**on_trait_change**) in order to overcome some of its limitations and flaws. While **on_trait_change** is still supported, it may be removed in the future. See :ref:`on-trait-change-notification` for details on this older API. Requesting trait attribute change notifications can be done in these ways: * Via class definition: By decorating methods on the class with the |@observe| decorator to indicate that they handle notification for specified attributes. * Via instance method: By calling |HasTraits.observe| instance method to establish (or remove) change notification handlers. Via class definition -------------------- Observers can be defined for every instance of a |HasTraits| subclass by applying the |@observe| decorator on an instance method. For example, to observe changes to a specific trait on an object: .. literalinclude:: /../../examples/tutorials/doc_examples/examples/observe_decorator.py :start-at: from traits.api The decorated function *notify_age_change* is called a **change handler**. Section :ref:`observe-handler` explains the signature and behaviour expected for these functions. The value *"age"* is called an **expression**. Section :ref:`observe-expression` explains how to write an expression for observing traits and containers following different patterns. Notice that a change event is emitted at instance construction time because the initial value is different from the default value. The *post_init* argument can be used to delay adding the change handler until after the object state is set. .. literalinclude:: /../../examples/tutorials/doc_examples/examples/observe_post_init.py :start-at: @observe :lines: 1-3 Via instance method ------------------- The |HasTraits.observe| method on |HasTraits| is useful for adding or removing change handlers on a per instance basis. The example above can be rewritten like this: .. literalinclude:: /../../examples/tutorials/doc_examples/examples/observe_method.py :start-at: from traits.api The behaviors of the |@observe| decorator and the |HasTraits.observe| instance are very similar. The only differences are: * |@observe| decorator does not support removing change handlers. * |@observe| decorator supports setting up change handlers prior to setting object state at instantiation. * |@observe| decorator sets up change handlers for all instances of a class and those change handlers can be inherited by subclasses. Unless otherwise stated, the following sections apply to both methods for setting up change notifications. .. _observe-expression: The *expression* Parameter -------------------------- The *expression* parameter in |@observe| provides significant flexibility in specifying not just attributes directly on the current object, but also attributes on nested objects and containers. There are two approaches for creating an expression: * :ref:`observe-mini-language` * :ref:`observe-expression-object` .. _observe-mini-language: Traits Mini Language ```````````````````` Traits Mini Language is a domain specific language which provides a convenient and concise way to specify observation rules via a single text. It supports most of the use cases commonly encountered by users. .. rubric:: Semantics of Traits DSL .. list-table:: :widths: 15 25 :header-rows: 1 * - Pattern - Meaning * - *attr1\.attr2* - Matches a trait named *attr2* on an object referenced by a trait named *attr1* on the current object. Changes to *attr1* or *attr2* will trigger notifications. * - *attr1\:attr2* - Matches a trait named *attr2* on an object referenced by a trait named *attr1* on the current object. Changes to *attr2* will trigger notifications. Changes to *attr1* will not. * - *attr1\, attr2* - Matches trait named *attr1* or trait named *attr2*. * - *items* - Matching items in a list or dict or set, or a trait named "items". * - [*item1*, *item2*, ..., *itemN*] - Matches any of the specified expressions. * - *\** - Matches any trait. The ``"*"`` may only appear as a "terminal" item in an expression - one that's not followed directly or indirectly by a ``"."`` or ``":"`` connector. For example, ``"*"``, ``"name.*"`` and ``"[a.*, b.c]"`` are all permitted, but ``"*.name"`` and ``[a, *].name`` are not. * - *+metadata_name* - Matches any trait on the object that has metadata *metadata_name* .. rubric:: Examples of Traits DSL .. list-table:: :widths: 15 25 :header-rows: 1 * - Example - Meaning * - ``"*"`` - Matches all traits on the current object. A change to any trait will trigger notifications. * - ``"foo.+updated"`` - Matches any trait on the *foo* that has a metadata attribute named *updated*. Changes on those traits and changes on *foo* will trigger notifications. * - ``"foo,bar"`` - Matches traits named *foo* or *bar* on the current object. Changes on *foo* or *bar* will trigger notifications. * - ``"foo:[bar,baz]"`` - Matches *foo.bar* or *foo.baz* on the current object. Changes on *foo.bar* or *foo.baz* will trigger notifications, but changes on *foo* will not trigger notifications. * - ``"container.items.value"`` - If *container* is a list or dict or set, matches the *value* trait on an object that is an item of the container. If *container* is an instance of *HasTraits*, matches attribute *container.items.value* on the current object. Changes to any of these will trigger notifications. * - ``"container:items:value"`` - If *container* is a list or dict or set, matches the *value* trait on an object that is an item of the container. If *container* is an instance of *HasTraits*, matches attribute *container.items.value* on the current object. Only changes to *value* will trigger notifications, assignments or mutations on *container* will not trigger notifications. * - ``"container:items:*"`` - If *container* is a list or dict or set, matches all traits on an object that is an item of the container. .. _observe-expression-object: Expressions as objects `````````````````````` |ObserverExpression| supports all the use cases supported by the Traits Mini Language and beyond. Users can compose these objects programmatically and supply them to |@observe|. These objects are typically constructed using the following functions from the |observation.api| module. .. list-table:: :widths: 15 25 :header-rows: 1 * - Function - Purpose * - |trait| - For observing a specific named trait. * - |metadata| - For observing multiple traits with specific metadata. * - |dict_items| - For observing items in a dict. * - |list_items| - For observing items in a list. * - |set_items| - For observing items in a set. * - |match| - For observing traits satisfying a user-defined filter. * - |anytrait| - For observing all traits on an object. * - |parse| - For parsing a string written in Traits domain specific language into an expression object. Users can combine complex expressions using |ObserverExpression.then| or Python's bitwise-or (`|`) operation. Most of these functions will have a **notify** argument for setting whether notifications should be fired for changes. .. rubric:: Example expressions * ``trait("attr1")`` Matches a trait named *attr1* on an object and notifies for changes. * ``trait("attr1", optional=True)`` Matches a trait named *attr1* if it is defined. Ignore if it is not defined. * ``trait("attr1", notify=False).trait("attr2")`` Matches a trait named *attr2* on an object referenced by a trait named *attr1* on the current object. Changes to *attr2* will trigger notifications, while changes to *attr1* do not. * ``trait("foo").list_items().list_items().trait("value")`` Matches the *value* trait on an item of a nested list in another list *foo*. Assignment changes to *foo*, mutations to the lists or changes to *value* will trigger notifications. * ``metadata("updated")`` Matches any trait on the current that has a metadata attribute named *updated*. Changes on those traits will trigger notifications. * ``trait("foo") | trait("bar")`` Matches traits named *foo* or *bar* on the current object. Changes on *foo* or *bar* will trigger notifications. * ``trait("foo").then(trait("bar") | trait("baz"))`` Matches *foo.bar* or *foo.baz* on the current object. Changes on *foo*, *foo.bar* or *foo.baz* will trigger notifications. * ``anytrait()`` Matches all traits on the current object. * ``trait("foo").anytrait()`` Matches all traits on *foo* on the current object. Changes on *foo* or the nested attributes will trigger notifications. * ``trait("foo", notify=False).anytrait()`` Matches all traits on *foo* on the current object. Changes on the nested attributes will trigger notifications. Changes on *foo* will not trigger notifications. .. rubric:: Extend an expression in text Using the |parse| function, one can extend an expression in text with additional features supported by |ObserverExpression|. For example:: parse("foo.bar").match(lambda name, trait: name.startswith("my_")) will observe traits with a prefix "my\_" on *foo.bar* on the current object. .. _observe-handler: Notification Handler -------------------- By default, the **handler** is invoked immediately after the change has occurred. The **dispatch** parameter in |@observe| can be set such that the handler is dispatched elsewhere to be invoked later (e.g. on a GUI event loop). The following expectations apply to any change handler: * It must accept one argument: the **event** parameter (see below) * It is called **after** a change has occurred * No assumptions should be made about the order of which handlers are called for a given change event. A change event can have many change handlers. * No exceptions should be raised from a change handler. Any unexpected exceptions will be captured and logged. When the handler is invoked, it is given an **event** object which provides information about the change observed. The type and signature of *event* depend on the context of the change. However they all include a parameter *object* referring to the object being modified: .. rubric:: Change event types .. list-table:: :widths: 15 25 :header-rows: 1 * - Change - Event Object Type * - Attribute value - |TraitChangeEvent| * - Dict membership - |DictChangeEvent| * - List membership - |ListChangeEvent| * - Set membership - |SetChangeEvent| This means if the handler needs to act on the specific details of the change event, |@observe| should be configured to only notify for that specific type of changes, or the handler will need to check the type of the event parameter when it is invoked. The following example shows the first option: .. literalinclude:: /../../examples/tutorials/doc_examples/examples/observe_different_events.py :start-at: from traits.api Features and fixes provided by |@observe| ----------------------------------------- In addition to the new flexibility provided by the |ObserverExpression| object, |@observe| aims at overcoming a number of design flaws and limitations in the older API. The following sections highlight the differences and new features supported by |@observe|. Existence of observed items is checked by default ````````````````````````````````````````````````` The existence of a trait is checked when the handler is being added to the instance:: class Foo(HasTraits): name = Str() @observe("nam") # typo, or an omission in renaming def _name_updated(self, event): print("name changed") foo = Foo() # Error here: Trait named 'nam' not found There are situations where it is desirable to add the change handler before a trait is defined. In that case, the *optional* argument on |trait| can be used: .. literalinclude:: /../../examples/tutorials/doc_examples/examples/observe_optional.py :start-at: class Arbitrarily nested containers are supported ``````````````````````````````````````````` It is now possible to notify for changes on an object in a very nested container. Suppose we have these classes:: class Bar(HasTraits): value = Int() class Foo(HasTraits): bars = Dict(Str(), List(Instance(Bar))) To observe *Bar.value*, one can do:: foo = Foo() foo.observe(handler, "bars.items.items.value") Or:: foo.observe(handler, trait("bars").dict_items().list_items().trait("value") |@observe| decorator can be stacked ``````````````````````````````````` The same handler can be used against different changes and with different parameters. With |@observe|, one can stack the decorator on the same method:: @observe("attr1", post_init=True) @observe("attr2", post_init=False) def _update_plots(self, event): ... Duplicated objects are now monitored ```````````````````````````````````` Consider this example:: class Apple(HasTraits): count = Int(0) class Bowl(HasTraits): apples = List(Instance(Apple)) @observe('apples:items:count') def print_status(self, event): print("Count changed to {event.new}".format(event)) granny_smith = Apple() bowl = Bowl(apples=[granny_smith, granny_smith]) granny_smith.count += 1 # print: 'Count changed to 1' The **granny_smith** object is repeated in the **apples** list. When one of the items is removed from the list, the **granny_smith** object is still there and we expect a change notification:: bowl.apples.pop() # granny_smith is still in the list. granny_smith.count += 1 # print: 'Count changed to 2' In the older API, this situation was not accounted for. With |@observe|, this situation is handled by keeping a reference count on the observed objects. This means |HasTraits.observe| cannot be idempotent. |HasTraits.observe| is not idempotent ````````````````````````````````````` For most use cases, change handlers can be put up in a fire-and-forget fashion and they are never removed. However for some use cases, it is important to remove change handlers when they are no longer needed. Calling |HasTraits.observe| to add an existing change handler will increment an internal reference count. The change handler can only be completely removed by calling |HasTraits.observe| the same number of times with *remove* set to True. In other words:: foo.observe(handler, "number") foo.observe(handler, "number") foo.observe(handler, "number") foo.number += 1 # handler is called once foo.observe(handler, "number", remove=True) foo.observe(handler, "number", remove=True) foo.number += 1 # handler is still called once foo.observe(handler, "number", remove=True) foo.number += 1 # handler is not called. Attempts to remove change handlers that do not exist will lead to a |NotifierNotFound| exception. Migration from |@on_trait_change| --------------------------------- |@observe| can be used alongside |@on_trait_change|. Therefore it is possible for projects to add new code using |@observe| while slowly migrating existing code from |@on_trait_change| to |@observe|. The following sections provide some guide to help migrations. Observe extended trait names ```````````````````````````` The expression syntax has not changed for extended trait names excluding containers. For example, given these classes:: class Bar(HasTraits): value = Int() class Foo(HasTraits): bar = Instance(Bar) To observe *bar.value* on an instance of *Foo*, this:: @on_trait_change("bar.value") will be changed to this:: @observe("bar.value") Observe nested attributes in a container ```````````````````````````````````````` Suppose we have these classes:: class Bar(HasTraits): value = Int() class Foo(HasTraits): container = List(Instance(Bar)) To notify for changes on *Bar.value* for an item in *Foo.container*, with |@on_trait_change|, one may do:: @on_trait_change("container.value") Where the container nature is deduced at runtime (see :ref:`trait-items-handlers`). With |@observe|, one will explicitly specify when items of a container are being observed, like this:: @observe("container.items.value") or:: @observe(trait("container").list_items().trait("value")) Similarly, this:: @on_trait_change("container_items.value") will be changed to this:: @observe("container:items.value") or this:: @observe(trait("container", notify=False).list_items().trait("value")) The specially named *name*\_items for listening to container changes is still defined for supporting |@on_trait_change|. Monitoring this *name*\_items trait with |@observe| is discouraged as this special trait may be removed when |@on_trait_change| is removed. Change handler signature is different ````````````````````````````````````` |@on_trait_change| supports a range of call :ref:`signatures ` for the change handler. |@observe| supports only one. The single argument contains different content based on the type of changes being handled (see :ref:`observe-handler`). For example, for this handler:: name = Str() @on_trait_change("name") def name_updated(self, object, name, old, new): print(object, name, old, new) It will have to be changed to:: @observe("name") def name_updated(self, event): print(event.object, event.name, event.old, event.new) For mutations to container, e.g.:: container = List() @on_trait_change("container_items") def name_updated(self, object, name, old, new): print("Index: {new.index}") print("Added: {new.added}") print("Removed: {new.removed}") It will have to be changed to:: container = List(comparison_mode=ComparisonMode.identity) @observe("container:items") def name_updated(self, event): print("Index: {event.index}") print("Added: {event.added}") print("Removed: {event.removed}") Syntax "[]" is not supported ```````````````````````````` Suppose we have this class:: class Foo(HasTraits): container = List(Instance(Bar)) To notify for both reassignment of *Foo.container* and mutation on the list, one may do:: @on_trait_change("container[]") or:: @on_trait_change(["container", "container_items"]) With |@observe|, the syntax will be changed to:: @observe("container.items") or:: @observe(trait("container").list_items()) Note that assignment changes to *container* and mutations to the container will emit different event types for the change handler. See :ref:`observe-handler` for details. Syntax "-" is not supported ``````````````````````````` With |@on_trait_change|, the syntax *"-metadata_name"* is used to notify for changes on traits that do NOT have a metadata attribute with the given name. This usage can be replaced by |match|:: match(lambda name, trait: trait.metadata_name is None) Dispatch parameter differentiates observers ``````````````````````````````````````````` In the following example with |@on_trait_change|, the second call is an no-op because a handler for *"name"* has already been added:: instance.on_trait_change(handler, "name", dispatch="same") instance.on_trait_change(handler, "name", dispatch="ui") # does nothing With |@observe|, the **dispatch** parameter is taken into account for distinguishing observers. The following example will result in the change handler being called twice, via different dispatching routes:: instance.observe(handler, "name", dispatch="same") instance.observe(handler, "name", dispatch="ui") Likewise, when removing change handlers, **dispatch** must match the value used for putting up the observer:: instance.observe(handler, "name", dispatch="ui") instance.observe(handler, "name", dispatch="ui", remove=True) .. # substitutions .. |ObserverExpression| replace:: :class:`~traits.observation.expression.ObserverExpression` .. |observation.api| replace:: :mod:`~traits.observation.api` .. |trait| replace:: :func:`~traits.observation.expression.trait` .. |metadata| replace:: :func:`~traits.observation.expression.metadata` .. |dict_items| replace:: :func:`~traits.observation.expression.dict_items` .. |list_items| replace:: :func:`~traits.observation.expression.list_items` .. |set_items| replace:: :func:`~traits.observation.expression.set_items` .. |match| replace:: :func:`~traits.observation.expression.match` .. |anytrait| replace:: :func:`~traits.observation.expression.anytrait` .. |parse| replace:: :func:`~traits.observation.parsing.parse` .. |print| replace:: :func:`~traits.observation.expression.print` .. |ObserverExpression.then| replace:: :func:`~traits.observation.expression.ObserverExpression.then` .. |NotifierNotFound| replace:: :exc:`~traits.observation.exceptions.NotifierNotFound` .. |TraitChangeEvent| replace:: :class:`~traits.observation.events.TraitChangeEvent` .. |ListChangeEvent| replace:: :class:`~traits.observation.events.ListChangeEvent` .. |DictChangeEvent| replace:: :class:`~traits.observation.events.DictChangeEvent` .. |SetChangeEvent| replace:: :class:`~traits.observation.events.SetChangeEvent` .. |HasTraits| replace:: :class:`~traits.has_traits.HasTraits` .. |@observe| replace:: :func:`~traits.has_traits.observe` .. |HasTraits.observe| replace:: :func:`~traits.has_traits.HasTraits.observe` .. |@on_trait_change| replace:: :func:`~traits.has_traits.on_trait_change` .. |HasTraits.on_trait_change| replace:: :func:`~traits.has_traits.HasTraits.on_trait_change` traits-6.3.2/docs/source/traits_user_manual/testing.rst000066400000000000000000000117311414270267200234000ustar00rootroot00000000000000.. index:: testing, test trait classes Testing ======= .. _testing_trait_classes: Testing Traits Classes ---------------------- A mixin class is provided to facilitate writing tests for HasTraits classes. The following methods are available when |UnittestTools| is added as a mixin class in the developer's test cases. .. autosummary:: :nosignatures: ~traits.testing.unittest_tools.UnittestTools.assertTraitChanges ~traits.testing.unittest_tools.UnittestTools.assertTraitDoesNotChange ~traits.testing.unittest_tools.UnittestTools.assertMultiTraitChanges ~traits.testing.unittest_tools.UnittestTools.assertTraitChangesAsync ~traits.testing.unittest_tools.UnittestTools.assertEventuallyTrue The above assert methods, except |assertEventuallyTrue|, can be used as context managers, which at entry, hook a trait listeners on the class for the desired events and record the arguments passed to the change handler at every fired event. This way the developer can easily assert that specific events have been fired. Further analysis and checking can be performed by inspecting the list of recorded events. Both normal and extended trait names are supported. However, no check is performed regarding the validity of the trait name, thus care is required to safeguard against spelling mistakes in the names of the traits that we need to assert the behaviour. The following example demonstrates the basic usage of the mixin class in a TestCase:: import unittest from traits.api import HasTraits, Float, List, Bool, on_trait_change from traits.testing.api import UnittestTools class MyClass(HasTraits): number = Float(2.0) list_of_numbers = List(Float) flag = Bool @on_trait_change('number') def _add_number_to_list(self, value): """ Append the value to the list of numbers. """ self.list_of_numbers.append(value) def add_to_number(self, value): """ Add the value to `number`. """ self.number += value class MyTestCase(unittest.TestCase, UnittestTools): def setUp(self): self.my_class = MyClass() def test_when_using_with(self): """ Check normal use cases as a context manager. """ my_class = self.my_class # Checking for change events with self.assertTraitChanges(my_class, 'number') as result: my_class.number = 5.0 # Inspecting the last recorded event expected = (my_class, 'number', 2.0, 5.0) self.assertSequenceEqual(result.events, [expected]) # Checking for specific number of events with self.assertTraitChanges(my_class, 'number', count=3) as result: my_class.flag = True my_class.add_to_number(10.0) my_class.add_to_number(10.0) my_class.add_to_number(10.0) expected = [(my_class, 'number', 5.0, 15.0), (my_class, 'number', 15.0, 25.0), (my_class, 'number', 25.0, 35.0)] self.assertSequenceEqual(result.events, expected) # Check using extended names with self.assertTraitChanges(my_class, 'list_of_numbers[]'): my_class.number = -3.0 # Check that event is not fired my_class.number = 2.0 with self.assertTraitDoesNotChange(my_class, 'number') as result: my_class.flag = True my_class.number = 2.0 # The value is the same as the original Using Mocks ----------- Trying to mock a method in a |HasStrictTraits| instance will raise an error because the |HasStrictTraits| machinery does not allow any modification of the methods and attributes of a |HasStrictTraits| instance. To circumvent the |HasStrictTraits| machinery, and mock methods using ``unittest.mock`` or `the mock library`_, please follow the logic in the example below:: from traits.api import HasStrictTraits, Float from unittest.mock import Mock class MyClass(HasStrictTraits): number = Float(2.0) def add_to_number(self, value): """ Add the value to `number`. """ self.number += value my_class = MyClass() # Using my_class.add_to_number = Mock() will fail. # But setting the mock on the instance `__dict__` works. my_class.__dict__['add_to_number'] = Mock() # We can now use the mock in our tests. my_class.add_to_number(42) print(my_class.add_to_number.call_args_list) .. note:: The above method will not work for mocking |Property| setters, getters and validators. .. _the mock library: https://pypi.python.org/pypi/mock .. |HasStrictTraits| replace:: :class:`~traits.has_traits.HasStrictTraits` .. |UnittestTools| replace:: :class:`~traits.testing.unittest_tools.UnittestTools` .. |Property| replace:: :func:`~traits.traits.Property` .. |assertEventuallyTrue| replace:: :func:`~traits.testing.unittest_tools.UnittestTools.assertEventuallyTrue` traits-6.3.2/edm.yaml000066400000000000000000000002431414270267200144650ustar00rootroot00000000000000# Change this if you are using on-premise brood store_url: "https://packages.enthought.com" repositories: - enthought/free - enthought/lgpl - enthought/gpl traits-6.3.2/etstool.py000066400000000000000000000421301414270267200151000ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tasks for Test Runs =================== This file is intended to be used in a Python environment equipped with the click library, to automate the process of setting up test environments and running the tests within them. This improves repeatability and reliability of tests be removing many of the variables around the developer's particular Python environment. Test environment setup and package management is performed using `EDM http://docs.enthought.com/edm/`_ To use this to run your tests, you will need to install EDM and click into your working environment. You will also need to have git installed to access required source code from github repositories. You can then do:: python etstool.py install --runtime=... to create a test environment from the current codebase and:: python etstool.py test --runtime=... to run tests in that environment. You can remove the environment with:: python etstool.py clean --runtime=... If you make changes you will either need to remove and re-install the environment or manually update the environment using ``edm``, as the install performs a ``pip install .`` rather than a ``pip install -e .``, so changes in your code will not be automatically mirrored in the test environment. You can update with:: python etstool.py update --runtime=... You can run install, test and clean all at once with:: python etstool.py test-clean --runtime=... which will create, install, run tests, and then clean up the environment. And you can run tests in all supported runtimes:: python etstool.py test-all Currently supported runtime values are ``3.6``. Not all combinations of runtimes will work, but the tasks will fail with a clear error if that is the case. Tests can still be run via the usual means in other environments if that suits a developer's purpose. Changing This File ------------------ To change the packages installed during a test run, change the dependencies variable below. To install a package from github, or one which is not yet available via EDM, add it to the `ci-src-requirements.txt` file (these will be installed by `pip`). Other changes to commands should be a straightforward change to the listed commands for each task. See the EDM documentation for more information about how to run commands within an EDM environment. """ import glob import os import subprocess import sys from shutil import rmtree, copy as copyfile from tempfile import mkdtemp from contextlib import contextmanager import click # Ensure that "-h" is supported for getting help. CONTEXT_SETTINGS = dict( help_option_names=["-h", "--help"], ) # Dependencies common to all configurations. common_dependencies = { "configobj", "coverage", "cython", "enthought_sphinx_theme", "flake8", "flake8_ets", "lark_parser", "mypy", "numpy", "pyqt5", "Sphinx", "traitsui", } # Dependencies we install from source for testing source_dependencies = {"traitsui"} # Unix-specific dependencies. unix_dependencies = { "gnureadline", } supported_runtimes = ["3.6"] default_runtime = "3.6" github_url_fmt = "git+http://github.com/enthought/{0}.git#egg={0}" # Click options shared by multiple commands. edm_option = click.option( "--edm", help=( "Path to the EDM executable to use. The default is to use the first " "EDM found in the path. The EDM executable can also be specified " "by setting the ETSTOOL_EDM environment variable." ), envvar="ETSTOOL_EDM", ) runtime_option = click.option( "--runtime", default=default_runtime, type=click.Choice(supported_runtimes), show_default=True, help="Python runtime version for the development environment", ) editable_option = click.option( "--editable/--not-editable", default=False, help="Install main package in 'editable' mode? [default: --not-editable]", ) verbose_option = click.option( "--verbose/--quiet", default=True, help="Run tests in verbose mode? [default: --verbose]", ) @click.group(context_settings=CONTEXT_SETTINGS) def cli(): """ Developer and CI support commands for Traits. """ pass @cli.command() @edm_option @runtime_option @click.option( "--environment", default=None, help="Name of the EDM environment to install", ) @editable_option @click.option("--source/--no-source", default=False) def install(edm, runtime, environment, editable, source): """ Install project and dependencies into a clean EDM environment and optionally install further dependencies required for building documentation and mini-language parser. """ parameters = get_parameters(edm, runtime, environment) dependencies = common_dependencies.copy() if sys.platform != "win32": dependencies.update(unix_dependencies) packages = " ".join(dependencies) # EDM commands to set up the development environment. The installation # of TraitsUI from EDM installs Traits as a dependency, so we need # to explicitly uninstall it before re-installing from source. install_traits = _get_install_command_string(".", editable=editable) install_stubs = _get_install_command_string( "./traits-stubs/", editable=editable ) commands = [ "{edm} environments create {environment} --force --version={runtime}", "{edm} --config edm.yaml install -y -e {environment} " + packages, "{edm} plumbing remove-package -e {environment} traits", install_traits, install_stubs, ] click.echo("Creating environment '{environment}'".format(**parameters)) execute(commands, parameters) if source: commands = [ "{edm} plumbing remove-package " "--environment {environment} --force " + " ".join(source_dependencies) ] execute(commands, parameters) source_pkgs = [ github_url_fmt.format(pkg) for pkg in source_dependencies ] commands = [ "python -m pip install {pkg} --no-deps".format(pkg=pkg) for pkg in source_pkgs ] commands = [ "{edm} run -e {environment} -- " + command for command in commands ] execute(commands, parameters) click.echo("Done install") @cli.command() @edm_option @runtime_option @click.option( "--environment", default=None, help="Name of the EDM environment to install", ) def shell(edm, runtime, environment): """ Create a shell into the EDM development environment (aka 'activate' it). """ parameters = get_parameters(edm, runtime, environment) commands = [ "{edm} shell -e {environment}", ] execute(commands, parameters) @cli.command() @edm_option @runtime_option @click.option( "--environment", default=None, help="Name of EDM environment to check." ) def flake8(edm, runtime, environment): """ Run a flake8 check in a given environment. """ parameters = get_parameters(edm, runtime, environment) commands = ["{edm} run -e {environment} -- python -m flake8"] execute(commands, parameters) @cli.command() @edm_option @runtime_option @verbose_option @click.option( "--environment", default=None, help="Name of EDM environment to test." ) def test(edm, runtime, verbose, environment): """ Run the test suite in a given environment. """ parameters = get_parameters(edm, runtime, environment) environ = {} environ["PYTHONUNBUFFERED"] = "1" options = "--verbose " if verbose else "" commands = [ "{edm} run -e {environment} -- coverage run -p -m " "unittest discover " + options + "traits", ] commands += [ "{edm} run -e {environment} -- coverage run -p -m " "unittest discover " + options + "traits_stubs_tests", ] # We run in a tempdir to avoid accidentally picking up wrong traits # code from a local dir. We need to ensure a good .coveragerc is in # that directory, plus coverage has a bug that means a non-local coverage # file doesn't get populated correctly. click.echo("Running tests in '{environment}'".format(**parameters)) with do_in_tempdir( files=[".coveragerc"], capture_files=[os.path.join(".", ".coverage*")], ): os.environ.update(environ) execute(commands, parameters) click.echo("Done test") @cli.command() @edm_option @runtime_option @click.option( "--environment", default=None, help="Name of EDM environment to build docs for.", ) @click.option( "--error-on-warn/--no-error-on-warn", default=True, help="Turn warnings into errors? [default: --error-on-warn] ", ) def docs(edm, runtime, environment, error_on_warn): """ Build the html documentation. """ parameters = get_parameters(edm, runtime, environment) build_docs = ( "{edm} run -e {environment} -- sphinx-build -b html " + ("-W " if error_on_warn else "") + "-d build/doctrees source build/html" ) commands = [build_docs] with do_in_existingdir(os.path.join(os.getcwd(), "docs")): execute(commands, parameters) @cli.command() @edm_option @runtime_option @click.option( "--environment", default=None, help="Name of EDM environment to remove." ) def clean(edm, runtime, environment): """ Remove a development environment. """ parameters = get_parameters(edm, runtime, environment) commands = [ "{edm} environments remove {environment} --purge -y", ] click.echo("Removing environment '{environment}'".format(**parameters)) execute(commands, parameters) click.echo("Environment removed.") @cli.command(name="test-clean") @edm_option @runtime_option def test_clean(edm, runtime): """ Run tests and build documentation in a clean environment. A clean EDM environment is created for the test run, and removed again afterwards. """ args = ["--runtime={}".format(runtime)] if edm is not None: args.append("--edm={}".format(edm)) try: install(args=args, standalone_mode=False) test(args=args, standalone_mode=False) docs(args=args, standalone_mode=False) finally: clean(args=args, standalone_mode=False) @cli.command() @edm_option @runtime_option @click.option( "--environment", default=None, help="Name of EDM environment to update." ) @editable_option def update(edm, runtime, environment, editable): """ Update/Reinstall package into environment. """ parameters = get_parameters(edm, runtime, environment) if editable: install_cmd = ( "{edm} run -e {environment} -- " "python -m pip install --editable . --no-dependencies" ) else: install_cmd = ( "{edm} run -e {environment} -- " "python -m pip install . --no-dependencies" ) commands = [install_cmd] click.echo("Re-installing in '{environment}'".format(**parameters)) execute(commands, parameters) click.echo("Done update") @cli.command(name="test-all") @edm_option def test_all(edm): """ Run test-clean across all supported environment combinations. """ error = False for runtime in supported_runtimes: args = ["--runtime={}".format(runtime)] if edm is not None: args.append("--edm={}".format(edm)) try: test_clean(args, standalone_mode=True) except SystemExit as exc: if exc.code not in (None, 0): error = True click.echo(str(exc)) if error: sys.exit(1) @cli.command(name="generate-parser") @edm_option @runtime_option @click.option( "--environment", default=None, help="Name of EDM environment to use." ) def generate_parser(edm, runtime, environment): """ Regenerate the mini-language parser for the observe framework. """ parameters = get_parameters(edm, runtime, environment) root_dir = os.path.dirname(__file__) observers_dir = os.path.join(root_dir, "traits", "observation") # parser file to be generated. out_path = os.path.join(observers_dir, "_generated_parser.py") # grammar file. parameters["grammar_path"] = os.path.join( observers_dir, "_dsl_grammar.lark") command = ( "{edm} run -e {environment} -- " "python -m lark.tools.standalone " "{grammar_path}" ) with open(out_path, "w", encoding="utf-8") as out_file: execute([command], parameters, stdout=out_file) click.echo("Written to {out_path!r}".format(out_path=out_path)) # Utility routines def get_parameters(edm, runtime, environment): """ Set up parameters dictionary for format() substitution. """ if edm is None: edm = locate_edm() if environment is None: environment = "traits-test-{runtime}".format(runtime=runtime) return { "edm": edm, "runtime": runtime, "environment": environment, } @contextmanager def do_in_tempdir(files=(), capture_files=()): """ Create a temporary directory, cleaning up after done. Creates the temporary directory, and changes into it. On exit returns to original directory and removes temporary dir. Parameters ---------- files : sequence of filenames Files to be copied across to temporary directory. capture_files : sequence of filenames Files to be copied back from temporary directory. """ path = mkdtemp() old_path = os.getcwd() # send across any files we need for filepath in files: click.echo("copying file to tempdir: {}".format(filepath)) copyfile(filepath, path) os.chdir(path) try: yield path # retrieve any result files we want for pattern in capture_files: for filepath in glob.iglob(pattern): click.echo("copying file back: {}".format(filepath)) copyfile(filepath, old_path) finally: os.chdir(old_path) rmtree(path) @contextmanager def do_in_existingdir(path): """ Changes into an existing directory given by path. On exit, changes back to the original directory. Parameters ---------- path : str Path of the directory to be changed into. """ old_path = os.getcwd() os.chdir(path) try: yield path finally: os.chdir(old_path) def execute(commands, parameters, stdout=None): for command in commands: click.echo("[EXECUTING] {}".format(command.format(**parameters))) try: subprocess.check_call( [arg.format(**parameters) for arg in command.split()], stdout=stdout, ) except subprocess.CalledProcessError as exc: print(exc) sys.exit(1) def locate_edm(): """ Locate an EDM executable if it exists, else raise an exception. Returns the first EDM executable found on the path. On Windows, if that executable turns out to be the "edm.bat" batch file, replaces it with the executable that it wraps: the batch file adds another level of command-line mangling that interferes with things like specifying version restrictions. Returns ------- edm : str Path to the EDM executable to use. Raises ------ click.ClickException If no EDM executable is found in the path. """ # Once Python 2 no longer needs to be supported, we should use # shutil.which instead. which_cmd = "where" if sys.platform == "win32" else "which" try: cmd_output = subprocess.check_output([which_cmd, "edm"]) except subprocess.CalledProcessError: raise click.ClickException( "This script requires EDM, but no EDM executable was found." ) # Don't try to be clever; just use the first candidate. edm_candidates = cmd_output.decode("utf-8").splitlines() edm = edm_candidates[0] # Resolve edm.bat on Windows. if sys.platform == "win32" and os.path.basename(edm) == "edm.bat": edm = os.path.join(os.path.dirname(edm), "embedded", "edm.exe") return edm def _get_install_command_string(pkg_or_location, editable, no_deps=True): """ Create and return a command string configured by the provided parameters. Parameters ---------- pkg_or_location : str Either a location in the filesystem containing setup.py or the name of a package. editable : bool Whether to add --editable flag no_deps : bool Whether to add --no-dependencies flag Returns ------- cmd : str A command string, which if executed will install the package or run the setup script at the provided location. """ cmd = "{edm} run -e {environment} -- python -m pip install" if editable: cmd += " --editable" cmd += " {}".format(pkg_or_location) if no_deps: cmd += " --no-dependencies" return cmd if __name__ == "__main__": cli(prog_name="python etstool.py") traits-6.3.2/examples/000077500000000000000000000000001414270267200146535ustar00rootroot00000000000000traits-6.3.2/examples/README.rst000066400000000000000000000003031414270267200163360ustar00rootroot00000000000000This folder contains examples for demonstration and documentation purposes. To aid discovery, symbolic links are created for files hosted in the package in order to be included as package data. traits-6.3.2/examples/tutorials/000077500000000000000000000000001414270267200167015ustar00rootroot00000000000000traits-6.3.2/examples/tutorials/default.css000066400000000000000000000001111414270267200210300ustar00rootroot00000000000000pre { border: 1px solid black; background-color: #E8E8E8; padding: 4px } traits-6.3.2/examples/tutorials/doc_examples/000077500000000000000000000000001414270267200213445ustar00rootroot00000000000000traits-6.3.2/examples/tutorials/doc_examples/__init__.py000066400000000000000000000007431414270267200234610ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Traits examples Please see doc_examples.rst for more information. """ traits-6.3.2/examples/tutorials/doc_examples/default.css000066400000000000000000000015001414270267200234760ustar00rootroot00000000000000body { background-color: #FFFFFF; } h1 { font-family: Arial; font-size: 14pt; color: #303030; background-color: #FCD062; padding-top: 3px; padding-left:8px; padding-bottom: 3px; padding-right: 8px; } h2 { font-family: Arial; font-size: 12pt; color: #303030; background-color: #FCD062; padding-top: 3px; padding-left:8px; padding-bottom: 3px; padding-right: 8px; } pre { border: 1px solid #A0A0A0; background-color: #FDF7E7; padding: 4px; } dl { border: 1px solid #A0A0A0; background-color: #FDF7E7; padding-top: 4px; padding-bottom: 6px; padding-left: 8px; padding-right: 8px; } dl dl { border: 0px solid #A0A0A0; } dt { font-family: Arial; font-weight: bold; dd { padding-bottom: 10px; } traits-6.3.2/examples/tutorials/doc_examples/doc_examples.rst000066400000000000000000000041561414270267200245470ustar00rootroot00000000000000Documentation Examples ====================== This tutorial is simply a collection of the various examples taken from the Traits documentation. They are presented as a tutorial so that interested users can see the results of actually executing the example code, as well as to promote further study and exploration of various Traits topics in an interactive environment that allows easy modification and testing of changes to the code. So please feel free to explore the examples as your time, fancy and interest dictate. Have fun! A brief description of each of the examples presented in this tutorial follows: Add Class Traits Defining mutually-referring classes using the *add_class_trait* method. All Traits Features Shows the five primary features of the Traits package. Bad Self Ref Shows the incorrect way of defining a self-referencing class. Cast Simple Shows use of some of the simple casting types. Circular Definition Shows the incorrect way of defining mutually-referring classes. Compound Shows the definition of a compound trait. Custom TraitHandler Example of a custom TraitHandler Use Custom TraitHandler Example of using a custom TraitHandler Delegate Example of trait delegation. Delegate Prefix Examples of the Delegate() 'prefix' parameter. Delegation Notification Example of notification with delegation. Event Shows the definition of a trait event List Notifiers Example of zero-parameter handlers for an object containing a list Metadata Example of accessing trait metadata attributes Minimal Minimal example of using Traits. Override Default Example of overriding a default value for a trait attribute in a subclass Static Notification Example of static attribute notification This Example of This predefined trait Trait Reuse Example of reusing trait definitions Temp Wildcard Example of using a wildcard with a trait attribute name. All Wildcard Shows the trait attribute wildcard rules. Wildcard rules Example of trait attribute wildcard rules traits-6.3.2/examples/tutorials/doc_examples/examples/000077500000000000000000000000001414270267200231625ustar00rootroot00000000000000traits-6.3.2/examples/tutorials/doc_examples/examples/__init__.py000066400000000000000000000010021414270267200252640ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ This directory contains a collection of the various examples taken from the Traits documentation. """ traits-6.3.2/examples/tutorials/doc_examples/examples/adapt_metadata.py000066400000000000000000000014121414270267200264630ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # adapt_metadata.py - Example of using 'adapt' metadata # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Instance from interface_definition import IName # --[Code]--------------------------------------------------------------------- class Apartment(HasTraits): renter = Instance(IName, adapt="no") traits-6.3.2/examples/tutorials/doc_examples/examples/add_class_trait.py000066400000000000000000000020311414270267200266500ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # add_class_trait.py --- Example of mutually-referring classes # using add_class_trait() # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Instance # --[Code]--------------------------------------------------------------------- # Defining mutually-referring classes using add_class_trait() class Chicken(HasTraits): pass class Egg(HasTraits): created_by = Instance(Chicken) # Now that 'Egg' is defined, we can add the 'hatched_from' trait to # solve the mutual-reference problem... Chicken.add_class_trait("hatched_from", Instance(Egg)) traits-6.3.2/examples/tutorials/doc_examples/examples/all_traits_features.py000066400000000000000000000033641414270267200275760ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # all_traits_features.py --- Shows primary features of the Traits # package # --[Imports]------------------------------------------------------------------ from traits.api import Delegate, HasTraits, Instance, Int, Str # --[Code]--------------------------------------------------------------------- # Shows the five primary features of the Traits package. class Parent(HasTraits): # INITIALIZATION: last_name' is initialized to '': last_name = Str("") class Child(HasTraits): age = Int # VALIDATION: 'father' must be a Parent instance: father = Instance(Parent) # DELEGATION: 'last_name' is delegated to father's 'last_name': last_name = Delegate("father") # NOTIFICATION: This method is called when 'age' changes: def _age_changed(self, old, new): print("Age changed from %s to %s " % (old, new)) # --[Example*]----------------------------------------------------------------- # Set up the example: joe = Parent() joe.last_name = "Johnson" moe = Child() moe.father = joe # DELEGATION in action: print("Moe's last name is %s " % moe.last_name) # Result: # Moe's last name is Johnson # NOTIFICATION in action moe.age = 10 # Result: # Age changed from 0 to 10 # VISUALIZATION: Displays a UI for editing moe's # attributes (if a supported GUI toolkit is installed) moe.configure_traits() traits-6.3.2/examples/tutorials/doc_examples/examples/all_wildcard.py000066400000000000000000000026061414270267200261610ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # all_wildcard.py --- Example of trait attribute wildcard rules # --[Imports]------------------------------------------------------------------ from traits.api import Any, Str, Int, HasTraits, TraitError # --[Code]--------------------------------------------------------------------- class Person(HasTraits): # Normal, explicitly defined trait: name = Str # By default, let all traits have any value: _ = Any # Except for this one, which must be an Int: age = Int # --[Example*]----------------------------------------------------------------- # Create a sample Person: bill = Person() # These assignments should all work: bill.name = "William" bill.address = "121 Drury Lane" bill.zip_code = 55212 bill.age = 49 # This should generate an error (must be an Int): print("Attempting to assign a string to an Int trait object...\n") try: bill.age = "middle age" except TraitError as c: print("TraitError: ", c, "\n") # Display the final results: bill.print_traits() traits-6.3.2/examples/tutorials/doc_examples/examples/bad_self_ref.py000066400000000000000000000017231414270267200261320ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # bad_self_ref.py -- Non-working example with self-referencing class definition # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Instance # --[Code]--------------------------------------------------------------------- # Shows the incorrect way of defining a self-referencing class. try: class Employee(HasTraits): # This won't work. # 'Employee' is not defined until the class definition is complete: manager = Instance(Employee) except NameError as excp: print(excp) traits-6.3.2/examples/tutorials/doc_examples/examples/cached_prop.py000066400000000000000000000017201414270267200260030ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ This example demonstrates the use of Property, with caching and notification support. """ from traits.api import ( cached_property, HasStrictTraits, Str, observe, Property, ) class Person(HasStrictTraits): full_name = Str() last_name = Property(observe="full_name") @cached_property def _get_last_name(self): return self.full_name.split(" ")[-1] @observe("last_name") def _last_name_updated(self, event): print("last_name is changed.") obj = Person() obj.full_name = "John Doe" # print: last_name is changed. traits-6.3.2/examples/tutorials/doc_examples/examples/circular_definition.py000066400000000000000000000020061414270267200275460ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Instance # --[Code]--------------------------------------------------------------------- # Shows the incorrect way of defining mutually-referring classes. try: class Chicken(HasTraits): # Won't work: 'Egg' not defined yet: hatched_from = Instance(Egg) class Egg(HasTraits): # If we move this class to the top, then this line won't work, because # 'Chicken' won't be defined yet: created_by = Instance(Chicken) except NameError as excp: print(excp) traits-6.3.2/examples/tutorials/doc_examples/examples/compound.py000066400000000000000000000024051414270267200253610ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # compound.py -- Example of multiple criteria in a trait definition # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Range, Trait, TraitError # --[Code]--------------------------------------------------------------------- # Shows the definition of a compound trait. class Die(HasTraits): # Define a compound trait definition: value = Trait(1, Range(1, 6), "one", "two", "three", "four", "five", "six") # --[Example*]----------------------------------------------------------------- # Create a sample Die: die = Die() # Try out some sample valid values: die.value = 3 die.value = "three" die.value = 5 die.value = "five" # Now try out some invalid values: try: die.value = 0 except TraitError as excp: print(excp) try: die.value = "zero" except TraitError as excp: print(excp) traits-6.3.2/examples/tutorials/doc_examples/examples/configure_traits.py000066400000000000000000000015501414270267200271040ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # configure_traits.py -- Sample code to demonstrate configure_traits() # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Str, Int # --[Code]--------------------------------------------------------------------- class SimpleEmployee(HasTraits): first_name = Str last_name = Str department = Str employee_number = Str salary = Int sam = SimpleEmployee() sam.configure_traits() traits-6.3.2/examples/tutorials/doc_examples/examples/custom_traithandler.py000066400000000000000000000016671414270267200276210ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # custom_traithandler.py --- Example of a custom TraitHandler # --[Imports]------------------------------------------------------------------ from traits.api import TraitHandler # --[Code]--------------------------------------------------------------------- class TraitOddInteger(TraitHandler): def validate(self, object, name, value): if isinstance(value, int) and (value > 0) and ((value % 2) == 1): return value self.error(object, name, value) def info(self): return "a positive odd integer" traits-6.3.2/examples/tutorials/doc_examples/examples/deferring_notification.py000066400000000000000000000036771414270267200302640ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # deferring_notification.py -- Example of notification with deferring # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Instance, PrototypedFrom, Str # --[Code]--------------------------------------------------------------------- class Parent(HasTraits): first_name = Str last_name = Str def _last_name_changed(self, new): print("Parent's last name changed to %s." % new) class Child(HasTraits): father = Instance(Parent) first_name = Str last_name = PrototypedFrom("father") def _last_name_changed(self, new): print("Child's last name changed to %s." % new) # --[Example*]----------------------------------------------------------------- dad = Parent(first_name="William", last_name="Chase") # Output: Parent's last name changed to Chase. son = Child(first_name="John", father=dad) # Output: Child's last name changed to Chase. # Change Parent's last_name dad.last_name = "Jones" # Output: Parent's last name changed to Jones. # Child's last name changed to Jones. # Override Child's last_name son.last_name = "Thomas" # Output Child's last name changed to Thomas. # Change Parent's last_name; Child's is not affected. dad.last_name = "Riley" # Output: Parent's last name changed to Riley. # Reset Child's last_name del son.last_name # Output: Child's last name changed to Riley. # Change to Parent now affects Child. dad.last_name = "Simmons" # Output: Parent's last name changed to Simmons. # Child's last name changed to Simmons. traits-6.3.2/examples/tutorials/doc_examples/examples/delegate.py000066400000000000000000000040371414270267200253120ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # delegate.py --- Example of trait delegation # --[Imports]------------------------------------------------------------------ from traits.api import DelegatesTo, HasTraits, Instance, Str, TraitError # --[Code]--------------------------------------------------------------------- class Parent(HasTraits): first_name = Str last_name = Str class Child(HasTraits): first_name = Str last_name = DelegatesTo("father") father = Instance(Parent) mother = Instance(Parent) # --[Example*]----------------------------------------------------------------- tony = Parent(first_name="Anthony", last_name="Jones") alice = Parent(first_name="Alice", last_name="Smith") sally = Child(first_name="Sally", father=tony, mother=alice) # Child delegates its 'last_name' to its 'father' object's 'last_name' print(sally.last_name) # Output: Jones # Assign an explicit value to the child's 'last_name' sally.last_name = "Cooper" print(tony.last_name) # Output: Cooper # Validation is still controlled by the father's 'last_name' trait print("Attempting to assign a Parent object to a Str trait...\n") try: sally.last_name = sally.mother # ERR: string expected except TraitError as c: print("TraitError: ", c) r""" The exception printed will look similar to the following: Traceback (most recent call last): File "", line 1, in ? File "c:\src\trunk\enthought\traits\trait_handlers.py", line 163, in error raise TraitError( object, name, self.info(), value ) traits.trait_errors.TraitError: The 'last_name' trait of a Child instance must be a value of type 'str', but a value of <__main__.Parent object at 0x009DD6F0> was specified. """ traits-6.3.2/examples/tutorials/doc_examples/examples/disallow.py000066400000000000000000000014141414270267200253520ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # disallow.py --- Example of using Disallow with wildcards # --[Imports]------------------------------------------------------------------ from traits.api import Disallow, Float, HasTraits, Int, Str # --[Code]--------------------------------------------------------------------- class Person(HasTraits): name = Str age = Int weight = Float _ = Disallow traits-6.3.2/examples/tutorials/doc_examples/examples/dynamic_notification.py000066400000000000000000000024001414270267200277220ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # dynamic_notification.py --- Example of dynamic notification # --[Imports]------------------------------------------------------------------ from traits.api import Float, HasTraits, Instance # --[Code]--------------------------------------------------------------------- class Part(HasTraits): cost = Float(0.0) class Widget(HasTraits): part1 = Instance(Part) part2 = Instance(Part) cost = Float(0.0) def __init__(self): self.part1 = Part() self.part2 = Part() self.part1.on_trait_change(self.update_cost, "cost") self.part2.on_trait_change(self.update_cost, "cost") def update_cost(self): self.cost = self.part1.cost + self.part2.cost # --[Example*]----------------------------------------------------------------- w = Widget() w.part1.cost = 2.25 w.part2.cost = 5.31 print(w.cost) # Result: 7.56 traits-6.3.2/examples/tutorials/doc_examples/examples/event.py000066400000000000000000000017701414270267200246620ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # event.py --- Example of a trait event # -------------------------------------------------------------------- from traits.api import Event, HasTraits, List, Tuple from traitsui.api import RGBColor # --[Code]--------------------------------------------------------------------- point_2d = Tuple(0, 0) class Line2D(HasTraits): points = List(point_2d) line_color = RGBColor("black") updated = Event def redraw(self): pass # Not implemented for this example def _points_changed(self): self.updated = True def _updated_fired(self): self.redraw() traits-6.3.2/examples/tutorials/doc_examples/examples/instance_trait_defaults.py000066400000000000000000000017421414270267200304360ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # instance_trait_defaults.py --- Example of Instance trait default values # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Instance # --[Code]--------------------------------------------------------------------- class Parent(HasTraits): pass class Child(HasTraits): # default value is None father = Instance(Parent) # default value is still None, but None can not be assigned grandfather = Instance(Parent, allow_none=False) # default value is Parent() mother = Instance(Parent, args=()) traits-6.3.2/examples/tutorials/doc_examples/examples/interface_definition.py000066400000000000000000000014121414270267200277020ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # interface_definition.py - Example of defining an interface # --[Imports]------------------------------------------------------------------ from traits.api import Interface # --[Code]--------------------------------------------------------------------- class IName(Interface): def get_name(self): """ Returns a string which is the name of an object. """ traits-6.3.2/examples/tutorials/doc_examples/examples/interface_implementation.py000066400000000000000000000024551414270267200306070ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # interface_implementation.py - Example of implementing an interface # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Instance, provides, Str from interface_definition import IName # --[Code]--------------------------------------------------------------------- @provides(IName) class Person(HasTraits): first_name = Str("John") last_name = Str("Doe") # Implementation of the 'IName' interface: def get_name(self): """ Returns the name of an object. """ return "%s %s" % (self.first_name, self.last_name) # --[Example*]----------------------------------------------------------------- class Apartment(HasTraits): renter = Instance(IName) william = Person(first_name="William", last_name="Adams") apt1 = Apartment(renter=william) print("Renter is: ", apt1.renter.get_name()) # Result: Renter is: William Adams traits-6.3.2/examples/tutorials/doc_examples/examples/keywords.py000066400000000000000000000016221414270267200254040ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # keywords.py --- Example of trait keywords # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Str # --[Code]--------------------------------------------------------------------- class Person(HasTraits): # 'label' is used for Traits UI field labels; # 'desc' can be used for tooltips. first_name = Str("", desc="first or personal name", label="First Name") last_name = Str("", desc="last or family name", label="Last Name") traits-6.3.2/examples/tutorials/doc_examples/examples/lesson.desc000066400000000000000000000015051414270267200253260ustar00rootroot00000000000000Examples from the Traits User Guide all_traits_features all_wildcard bad_self_ref circular_definition add_class_trait cast_simple compound custom_traithandler default_trait_ui delegate delegate_prefix disallow dynamic_notification enum_simple event explicit false graphic_example imageenumeditor include_extra instanceeditor instance_example keywords mapped map_simple minimal multiple_criteria object_trait_attrs override_default override_editor person_bmi range reuse_editor static_notification temp_wildcard this traitcasttype traitdict traitenum traitinstance traitlist traitmap traitprefixlist traitprefixmap traitrange traitstring traittuple traitype trait_reuse type_simple user_custom_th use_custom_th validator view_attributes view_multi_object view_standalone widget wildcard wildcard_all wildcard_name wildcard_rules wizard traits-6.3.2/examples/tutorials/doc_examples/examples/list_notifier.py000066400000000000000000000031321414270267200264050ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # list_notifier.py -- Example of zero-parameter handlers for an object # containing a list # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, List # --[Code]--------------------------------------------------------------------- class Employee: pass class Department(HasTraits): employees = List(Employee) # --[Example*]----------------------------------------------------------------- def a_handler(): print("A handler") def b_handler(): print("B handler") def c_handler(): print("C handler") fred = Employee() mary = Employee() donna = Employee() dept = Department(employees=[fred, mary]) # "Old style" name syntax # a_handler is called only if the list is replaced: dept.on_trait_change(a_handler, "employees") # b_handler is called if the membership of the list changes: dept.on_trait_change(b_handler, "employees_items") # "New style" name syntax # c_handler is called if 'employees' or its membership change: dept.on_trait_change(c_handler, "[employees]") print("Changing list items") dept.employees[1] = donna # Calls B and C print("Replacing list") dept.employees = [donna] # Calls A and C traits-6.3.2/examples/tutorials/doc_examples/examples/mapped.py000066400000000000000000000037021414270267200250040ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # mapped.py --- Example of a mapped trait # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Trait # --[Code]--------------------------------------------------------------------- standard_color = Trait( "black", { "black": (0.0, 0.0, 0.0, 1.0), "blue": (0.0, 0.0, 1.0, 1.0), "cyan": (0.0, 1.0, 1.0, 1.0), "green": (0.0, 1.0, 0.0, 1.0), "magenta": (1.0, 0.0, 1.0, 1.0), "orange": (0.8, 0.196, 0.196, 1.0), "purple": (0.69, 0.0, 1.0, 1.0), "red": (1.0, 0.0, 0.0, 1.0), "violet": (0.31, 0.184, 0.31, 1.0), "yellow": (1.0, 1.0, 0.0, 1.0), "white": (1.0, 1.0, 1.0, 1.0), "transparent": (1.0, 1.0, 1.0, 0.0), }, ) red_color = Trait("red", standard_color) class GraphicShape(HasTraits): line_color = standard_color fill_color = red_color # --[Example*]----------------------------------------------------------------- my_shape1 = GraphicShape() # Default values for normal trait attributes print(my_shape1.line_color, my_shape1.fill_color) # Output: black red # Default values for shadow trait attributes print(my_shape1.line_color_, my_shape1.fill_color_) # Output: (0.0, 0.0, 0.0, 1.0) (1.0, 0.0, 0.0, 1.0) # Non-default values my_shape2 = GraphicShape() my_shape2.line_color = "blue" my_shape2.fill_color = "green" print(my_shape2.line_color, my_shape2.fill_color) # Output: blue green print(my_shape2.line_color_, my_shape2.fill_color_) # Output: (0.0, 0.0, 1.0, 1.0) (0.0, 1.0, 0.0, 1.0) traits-6.3.2/examples/tutorials/doc_examples/examples/metadata.py000066400000000000000000000040511414270267200253140ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # metadata.py --- Example of accessing trait metadata attributes # --[Imports]------------------------------------------------------------------ from traits.api import ( HasTraits, Int, List, Float, Instance, Any, Str, TraitType) # --[Code]--------------------------------------------------------------------- class Foo(HasTraits): pass class Test(HasTraits): i = Int(99) lf = List(Float) foo = Instance(Foo, ()) any = Any("123") # --[Example*]----------------------------------------------------------------- t = Test() # Prints values of various metadata attributes for each of the traits. print(t.trait("i").default) # 99 print(t.trait("i").default_kind) # value print(t.trait("i").inner_traits) # () print(t.trait("i").is_trait_type(Int)) # True print(t.trait("i").is_trait_type(Float)) # False print(t.trait("lf").default) # [] print(t.trait("lf").default_kind) # list print(t.trait("lf").inner_traits) # (,) print(t.trait("lf").is_trait_type(List)) # True print(t.trait("lf").is_trait_type(TraitType)) # True print(t.trait("lf").is_trait_type(Float)) # False print(t.trait("lf").inner_traits[0].is_trait_type(Float)) # True print(t.trait("foo").default) # print(t.trait("foo").default_kind) # factory print(t.trait("foo").inner_traits) # () print(t.trait("foo").is_trait_type(Instance)) # True print(t.trait("foo").is_trait_type(List)) # False print(t.trait("any").default) # 123 print(t.trait("any").default_kind) # value print(t.trait("any").inner_traits) # () print(t.trait("any").is_trait_type(Any)) # True print(t.trait("any").is_trait_type(Str)) # False traits-6.3.2/examples/tutorials/doc_examples/examples/minimal.py000066400000000000000000000023531414270267200251650ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # minimal.py --- Minimal example of using traits. # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Float, TraitError # --[Code]--------------------------------------------------------------------- class Person(HasTraits): weight = Float(150.0) # --[Example*]----------------------------------------------------------------- # instantiate the class joe = Person() # Show the default value print(joe.weight) # Assign new values joe.weight = 161.9 # OK to assign a float print(joe.weight) joe.weight = 162 # OK to assign an int print(joe.weight) # The following line causes a traceback: try: joe.weight = "average" # Error to assign a string print("You should not see this message.") except TraitError: print("You can't assign a string to the 'weight' trait.") traits-6.3.2/examples/tutorials/doc_examples/examples/object_trait_attrs.py000066400000000000000000000024051414270267200274230ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # object_trait_attrs.py --- Example of per-object trait attributes # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Range # --[Code]--------------------------------------------------------------------- class GUISlider(HasTraits): def __init__( self, eval=None, label="Value", trait=None, min=0.0, max=1.0, initial=None, **traits ): HasTraits.__init__(self, **traits) if trait is None: if min > max: min, max = max, min if initial is None: initial = min elif not (min <= initial <= max): initial = [min, max][abs(initial - min) > abs(initial - max)] trait = Range(min, max, value=initial) self.add_trait(label, trait) traits-6.3.2/examples/tutorials/doc_examples/examples/observe_decorator.py000066400000000000000000000020211414270267200272360ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ This example shows how to set up notifications for changes on a single trait, for all instances of this class. Note that a change notification is also fired when the instance is created. This is because the value provided in the instance constructor is different from the default value. """ from traits.api import HasTraits, Int, observe class Person(HasTraits): age = Int(0) @observe("age") def notify_age_change(self, event): print("age changed from {} to {}".format(event.old, event.new)) person = Person(age=1) # print 'age changed from 0 to 1' person.age = 2 # print 'age changed from 1 to 2' traits-6.3.2/examples/tutorials/doc_examples/examples/observe_different_events.py000066400000000000000000000027421414270267200306200ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ This example shows how to set up notifications for changes on an object that is an item in a list. Note that when a new list is assigned, the change event is of a different type compared to when a list is mutated. """ from traits.api import HasTraits, Int, List, observe from traits.observation.api import trait class Person(HasTraits): scores = List(Int) @observe("scores") def notify_scores_change(self, event): print( "{event.name} changed from {event.old} to {event.new}. " "(Event type: {event.__class__.__name__})".format(event=event) ) @observe(trait("scores", notify=False).list_items()) def notify_scores_content_change(self, event): print( "scores added: {event.added}. scores removed: {event.removed} " "(Event type: {event.__class__.__name__})".format(event=event) ) person = Person(scores=[1, 2]) # print: scores changed from [] to [1, 2]. (Event type: TraitChangeEvent) person.scores.append(3) # print: scores added: [3]. scores removed: [] (Event type: ListChangeEvent) traits-6.3.2/examples/tutorials/doc_examples/examples/observe_method.py000066400000000000000000000017431414270267200265460ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ This example shows how to set up notifications for changes on a single trait, for a specific instance of HasTraits. The change handler can be removed using the 'remove' argument on ``observe``. """ from traits.api import HasTraits, Int class Person(HasTraits): age = Int(0) def print_change(event): print("{} changed: {} -> {}".format(event.name, event.old, event.new)) person = Person(age=1) person.observe(print_change, "age") person.age = 2 # print 'age changed: 1 -> 2' person.observe(print_change, "age", remove=True) person.age = 3 # nothing is printed. traits-6.3.2/examples/tutorials/doc_examples/examples/observe_optional.py000066400000000000000000000020441414270267200271060ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ This example shows how to set up notifications for a trait that is defined after the instance is created. The optional flag suppresses the error that would otherwise occur because the trait is not found at the time ``observe`` is called. When the observed trait is defined, the change handler will be aded to the new trait. """ from traits.api import HasTraits, Int, observe from traits.observation.api import trait class Person(HasTraits): @observe(trait("age", optional=True)) def notify_age_change(self, event): print("age changed") person = Person() person.add_trait("age", Int()) person.age = 2 # print 'age changed' traits-6.3.2/examples/tutorials/doc_examples/examples/observe_post_init.py000066400000000000000000000020371414270267200272730ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ This example shows how to set up notifications for changes on a single trait, for all instances of this class, but only after the object state is set during instantiation. The 'post_init' argument suppresses change notifications during instantiation, but allows subsequent changes to trigger notifications. """ from traits.api import HasTraits, Int, observe class Person(HasTraits): age = Int(0) @observe("age", post_init=True) def notify_age_change(self, event): print("age changed from {} to {}".format(event.old, event.new)) person = Person(age=1) # no output person.age = 2 # print 'age changed from 1 to 2' traits-6.3.2/examples/tutorials/doc_examples/examples/override_default.py000066400000000000000000000023641414270267200270640ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # override_default.py -- Example of overriding a default value for # a trait attribute in a subclass from traits.api import HasTraits, Range, Str # --[Code]--------------------------------------------------------------------- # Example of overriding a default value for a trait in a subclass: # Define the base class: class Employee(HasTraits): name = Str salary_grade = Range(value=1, low=1, high=10) # Define a subclass: class Manager(Employee): # Override the default value for the inherited 'salary_grade' trait: salary_grade = 5 # --[Example*]----------------------------------------------------------------- # Create an employee and display its initial contents: joe = Employee(name="Joe") joe.print_traits() # Now do the same thing for a manager object: mike = Manager(name="Mike") mike.print_traits() traits-6.3.2/examples/tutorials/doc_examples/examples/post_init_notification.py000066400000000000000000000017471414270267200303230ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # post_init_notification.py --- Example of static notification from traits.api import Float, HasTraits, on_trait_change, Str class Part(HasTraits): cost = Float(0.0) name = Str("Part") @on_trait_change("cost") def cost_updated(self, object, name, old, new): print("{} is changed from {} to {}".format(name, old, new)) @on_trait_change("name", post_init=True) def name_updated(self, object, name, old, new): print("{} is changed from {} to {}".format(name, old, new)) part = Part(cost=2.0, name="Nail") # Result: cost is changed from 0.0 to 2.0 traits-6.3.2/examples/tutorials/doc_examples/examples/prototype_prefix.py000066400000000000000000000030721414270267200271600ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # prototype_prefix.py --- Examples of PrototypedFrom() prefix parameter # --[Imports]------------------------------------------------------------------ from traits.api import PrototypedFrom, Float, HasTraits, Instance, Str # --[Code]--------------------------------------------------------------------- class Parent(HasTraits): first_name = Str family_name = "" favorite_first_name = Str child_allowance = Float(1.00) class Child(HasTraits): __prefix__ = "child_" first_name = PrototypedFrom("mother", "favorite_*") last_name = PrototypedFrom("father", "family_name") allowance = PrototypedFrom("father", "*") father = Instance(Parent) mother = Instance(Parent) # --[Example*]----------------------------------------------------------------- fred = Parent( first_name="Fred", family_name="Lopez", favorite_first_name="Diego", child_allowance=5.0, ) maria = Parent( first_name="Maria", family_name="Gonzalez", favorite_first_name="Tomas", child_allowance=10.0, ) nino = Child(father=fred, mother=maria) print( "%s %s gets $%.2f for allowance" % (nino.first_name, nino.last_name, nino.allowance) ) traits-6.3.2/examples/tutorials/doc_examples/examples/simple_adapter.py000066400000000000000000000020411414270267200265220ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # simple_adapter.py - Example of adaptation using Adapter # --[Imports]------------------------------------------------------------------ from traits.api import Adapter, Instance, provides from interface_definition import IName from interface_implementation import Person # --[Code]--------------------------------------------------------------------- @provides(IName) class PersonINameAdapter(Adapter): # Declare the type of client it supports: adaptee = Instance(Person) # Implement the 'IName' interface on behalf of its client: def get_name(self): return "%s %s" % (self.adaptee.first_name, self.adaptee.last_name) traits-6.3.2/examples/tutorials/doc_examples/examples/static_notification.py000066400000000000000000000026431414270267200275760ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # static_notification.py --- Example of static attribute notification # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Float # --[Code]--------------------------------------------------------------------- class Person(HasTraits): weight_kg = Float(0.0) height_m = Float(1.0) bmi = Float(0.0) def _weight_kg_changed(self, old, new): print("weight_kg changed from %s to %s " % (old, new)) if self.height_m != 0.0: self.bmi = self.weight_kg / (self.height_m ** 2) def _anytrait_changed(self, name, old, new): print("The %s trait changed from %s to %s " % (name, old, new)) # --[Example*]----------------------------------------------------------------- bob = Person() bob.height_m = 1.75 # Output: The height_m trait changed from 1.0 to 1.75 bob.weight_kg = 100.0 # Output: # The weight_kg trait changed from 0.0 to 100.0 # weight_kg changed from 0.0 to 100.0 # The bmi trait changed from 0.0 to 32.6530612245 traits-6.3.2/examples/tutorials/doc_examples/examples/temp_wildcard.py000066400000000000000000000013531414270267200263540ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # temp_wildcard.py --- Example of using a wildcard with a trait # attribute name # --[Imports]------------------------------------------------------------------ from traits.api import Any, HasTraits # --[Code]--------------------------------------------------------------------- class Person(HasTraits): temp_ = Any traits-6.3.2/examples/tutorials/doc_examples/examples/this.py000066400000000000000000000012771414270267200245120ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # this.py --- Example of This predefined trait # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, This # --[Code]--------------------------------------------------------------------- class Employee(HasTraits): manager = This traits-6.3.2/examples/tutorials/doc_examples/examples/trait_reuse.py000066400000000000000000000013571414270267200260700ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # trait_reuse.py --- Example of reusing trait definitions from traits.api import HasTraits, Range # --[Code]--------------------------------------------------------------------- coefficient = Range(-1.0, 1.0, 0.0) class quadratic(HasTraits): c2 = coefficient c1 = coefficient c0 = coefficient x = Range(-100.0, 100.0, 0.0) traits-6.3.2/examples/tutorials/doc_examples/examples/trait_subclass.py000066400000000000000000000016261414270267200265630ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # trait_subclass.py -- Example of subclassing a trait class from traits.api import BaseInt # --[Code]--------------------------------------------------------------------- class OddInt(BaseInt): # Define the default value default_value = 1 # Describe the trait type info_text = "an odd integer" def validate(self, object, name, value): value = super().validate(object, name, value) if (value % 2) == 1: return value self.error(object, name, value) traits-6.3.2/examples/tutorials/doc_examples/examples/traitprefixmap.py000066400000000000000000000014111414270267200265700ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # traitprefixmap.py --- Example of using the TraitPrefixMap handler # --[Imports]------------------------------------------------------------------ from traits.api import Trait, TraitPrefixMap # --[Code]--------------------------------------------------------------------- boolean_map = Trait( "true", TraitPrefixMap({"true": 1, "yes": 1, "false": 0, "no": 0}) ) traits-6.3.2/examples/tutorials/doc_examples/examples/transient_metadata.py000066400000000000000000000015271414270267200274100ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # transient_metadata.py - Example of using 'transient' metadata # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, File, Any # --[Code]--------------------------------------------------------------------- class DataBase(HasTraits): # The name of the data base file: file_name = File # The open file handle used to access the data base: file = Any(transient=True) traits-6.3.2/examples/tutorials/doc_examples/examples/use_custom_th.py000066400000000000000000000015331414270267200264170ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # use_custom_th.py --- Example of using a custom TraitHandler # --[Imports]------------------------------------------------------------------ from traits.api import HasTraits, Range, Trait from custom_traithandler import TraitOddInteger # --[Code]--------------------------------------------------------------------- class AnOddClass(HasTraits): oddball = Trait(1, TraitOddInteger()) very_odd = Trait(-1, TraitOddInteger(), Range(-10, -1)) traits-6.3.2/examples/tutorials/doc_examples/examples/widget.py000066400000000000000000000015641414270267200250250ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import Float, HasTraits, Trait class Part(HasTraits): cost = Trait(0.0) class Widget(HasTraits): part1 = Trait(Part) part2 = Trait(Part) cost = Float(0.0) def __init__(self): self.part1 = Part() self.part2 = Part() self.part1.on_trait_change(self.update_cost, "cost") self.part2.on_trait_change(self.update_cost, "cost") def update_cost(self): self.cost = self.part1.cost + self.part2.cost traits-6.3.2/examples/tutorials/doc_examples/examples/wildcard.py000066400000000000000000000011051414270267200253220ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # wildcard.py --- Example of using a wildcard with a trait # attribute name from traits.api import Any, HasTraits class Person(HasTraits): temp_ = Any traits-6.3.2/examples/tutorials/doc_examples/examples/wildcard_all.py000066400000000000000000000011141414270267200261520ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # wildcard_all.py --- Example of using a wildcard with all trait # attribute names from traits.api import HasTraits, Any class Person(HasTraits): _ = Any traits-6.3.2/examples/tutorials/doc_examples/examples/wildcard_name.py000066400000000000000000000011171414270267200263250ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # temp_wildcard.py --- Example of using a wildcard # with a trait attribute name from traits.api import Any, HasTraits class Person(HasTraits): temp_ = Any traits-6.3.2/examples/tutorials/doc_examples/examples/wildcard_rules.py000066400000000000000000000014011414270267200265330ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # wildcard_rules.py --- Example of trait attribute wildcard rules # --[Imports]------------------------------------------------------------------ from traits.api import Any, HasTraits, Int, Python # --[Code]--------------------------------------------------------------------- class Person(HasTraits): temp_count = Int(-1) temp_ = Any _ = Python traits-6.3.2/examples/tutorials/doc_examples/examples/wizard.py000066400000000000000000000012441414270267200250350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # wizard.py ---Example of a traits-based wizard UI from traits.api import HasTraits, Int, Str class Person(HasTraits): name = Str age = Int street = Str city = Str state = Str pcode = Str bill = Person() bill.configure_traits(kind="modal") traits-6.3.2/examples/tutorials/doc_examples/lesson.desc000066400000000000000000000000651414270267200235100ustar00rootroot00000000000000The Traits Documentation Examples Tutorial examples traits-6.3.2/examples/tutorials/introduction000077700000000000000000000000001414270267200275562../../traits/examples/introductionustar00rootroot00000000000000traits-6.3.2/examples/tutorials/traits_4.0/000077500000000000000000000000001414270267200205705ustar00rootroot00000000000000traits-6.3.2/examples/tutorials/traits_4.0/decorators/000077500000000000000000000000001414270267200227355ustar00rootroot00000000000000traits-6.3.2/examples/tutorials/traits_4.0/decorators/cached_property.py000066400000000000000000000075171414270267200264740ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # --(cached_property Decorator)------------------------------------------------ """ cached_property Decorator ========================= New in Traits 3.0 is the *cached_property* method decorator which helps streamline the process of writing properties which cache their current value. Defining properties is a very powerful technique for exposing as traits items whose value depends upon the current state of other object traits. In particular, this can be very useful for creating synthetic traits which are editable or displayable in a traits-based user interface. In some cases however, the cost of computing the current value of a property may be fairly expensive, so it is often a good idea to *cache* the most recently computed value of the property, and return it as the value of the property until one of the traits the property depends upon changes value, at which point the cache should be cleared and the property value recomputed the next time its value is requested. Combined with the **Property** *depends_on* metadata, the *cached_property* decorator greatly simplifies the process of writing a cached property. Take a look at the following code for example:: class TestScores(HasPrivateTraits): scores = List(Int) average = Property(depends_on='scores') @cached_property def _get_average(self): s = self.scores return (float(reduce(lambda n1, n2: n1 + n2, s, 0)) / len(s)) Presumably this is much easier to write and understand that the following equivalent code written without using *depends_on* and *cached_property*:: class TestScores(HasPrivateTraits): scores = List(Int) average = Property def _get_average(self): if self._average is None: s = self.scores self._average = (float(reduce(lambda n1, n2: n1 + n2, s, 0)) / len(s)) return self._average def _scores_changed(self): old, self._average = self._average, None self.trait_property_changed('average', old, self._average) def _scores_items_changed(self): self._scores_changed() The *cached_property* decorator takes no arguments, and should simply be written on the line preceding the property's *getter* method, as shown in the previous example. Use of the *cached_property* decorator also eliminates the need to add *cached = True* metadata to the property declaration, as was previously required when using *depends_on* metadata with a cached property definition. """ from traits.api import cached_property, HasPrivateTraits, Int, List, Property # --[TestScores Class]--------------------------------------------------------- class TestScores(HasPrivateTraits): scores = List(Int) average = Property(depends_on="scores") @cached_property def _get_average(self): print("...computing average:", end=" ") s = self.scores return sum(s) / len(s) # --[Example*]----------------------------------------------------------------- # Create a sample TestScores object with some sample scores: test_scores = TestScores(scores=[89, 93, 76, 84, 62, 96, 75, 81, 69, 90]) # Display the average: print("First average:", test_scores.average) print("Check that again:", test_scores.average) # Now add a few more late scores into the mix: test_scores.scores.extend([85, 61, 70]) # And display the new average: print("Second average:", test_scores.average) traits-6.3.2/examples/tutorials/traits_4.0/decorators/on_trait_change.py000066400000000000000000000141151414270267200264350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # --(on_trait_change Decorator)------------------------------------------------ """ on_trait_change Decorator ========================= Until Traits 3.0, the only way to define a static trait notification handler as part of a class definition was to define the method following a certain naming convention:: def _name_changed(self, ...): ... or def _name_fired(self, ...): ... where *name* is the name of the trait to which the notification handler method applies. Starting with Traits 3.0, there is now an alternate method for declaring notification handlers using the **on_trait_change** decorator. The syntax for the decorator is:: @on_trait_change('extended_trait_name') def any_method_name(self, ...): ... where *extended_trait_name* is the name of the trait for which the following method is the notification handler, and *any_method_name* is an arbitrary method name, which does not need to follow any particular naming convention. Although the new syntax is more verbose than the original syntax, it has several advantages: - It does not require using special method names. - It allows using the extended trait naming support added to the **on_trait_change** method in Traits 3.0. The last item is especially important since it allows you to statically declare notification handlers for many more cases than were previously possible. For example:: @on_trait_change('foo,bar,baz') def _update(self): ...perform update logic... defines an *_update* method that is called whenever the class's *foo*, *bar* or *baz* traits change. Previously, this would have required writing three separate notification handlers (one each for the *foo*, *bar* and *baz* traits), or adding *event* metadata to each of the trait declarations for *foo*, *bar* and *baz*. Similarly, the previous technique of writing methods such as:: def _bar_changed_for_foo(self, ...): ... which statically defines a notification handler for changes to the *bar* trait of the object's *foo* trait can now be written as:: @on_trait_change('foo.bar') def any_method_name(self, ...): ... Perhaps even more importantly, this technique can be applied in even more complex situations, such as:: @on_trait_change('foo.bar.baz') def any_method_name(self, ...): ... or @on_trait_change('foo.+dirty,foo2.[bar,baz,foogle]') def any_method_name(self, ...): ... The first case is a simple extension of the previous example, while the second is a somewhat far-fetched example which can be interpreted as defining a method that handles: - Changes to any trait on the object's *foo* trait which has *dirty* metadata defined, or - Changes to the *bar*, *baz* or *foogle* trait of the object's *foo2* trait. Note that there is one important semantic difference between writing:: def _name_changed(self, ...): ... and:: @on_trait_change('name') def any_method_name(self, ...): ... While both are recognized as being notification handlers for the object's *name* trait, the interpretation of the argument signature for the first case follows the static trait change handler pattern, while the second case follows the dynamic **on_trait_change** method pattern. While this might seem obvious, given the fact that the decorator is called *on_trait_change*, it is an important enough difference to note explicitly. A Complete Example ------------------ Refer to the code tabs of this lesson for a complete example using the *on_trait_change* decorator. In particular, look at the definition of the *sick_again* method in the **Corporation Class** tab. """ # -------------------------------------------------------------------- from traits.api import HasTraits, Int, List, on_trait_change, Str # --[Employee Class]----------------------------------------------------------- class Employee(HasTraits): # The name of the employee: name = Str # The number of sick days they have taken this year: sick_days = Int # --[Department Class]--------------------------------------------------------- class Department(HasTraits): # The name of the department: name = Str # The employees in the department: employees = List(Employee) # --[Corporation Class]-------------------------------------------------------- class Corporation(HasTraits): # The name of the corporation: name = Str # The departments within the corporation: departments = List(Department) # Define a corporate 'whistle blower' method: @on_trait_change("departments:employees.sick_days") def sick_again(self, object, name, old, new): print( "%s just took sick day number %d for this year!" % (object.name, new) ) # --[Example*]----------------------------------------------------------------- # Create some sample employees: millie = Employee(name="Millie", sick_days=2) ralph = Employee(name="Ralph", sick_days=3) tom = Employee(name="Tom", sick_days=1) slick = Employee(name="Slick", sick_days=16) marcelle = Employee(name="Marcelle", sick_days=7) reggie = Employee(name="Reggie", sick_days=11) dave = Employee(name="Dave", sick_days=0) bob = Employee(name="Bob", sick_days=1) alphonse = Employee(name="Alphonse", sick_days=5) # Create some sample departments: accounting = Department(name="accounting", employees=[millie, ralph, tom]) sales = Department(name="Sales", employees=[slick, marcelle, reggie]) development = Department(name="Development", employees=[dave, bob, alphonse]) # Create a sample corporation: acme = Corporation( name="Acme, Inc.", departments=[accounting, sales, development] ) # Now let's try out our 'reporting' system: slick.sick_days += 1 reggie.sick_days += 1 traits-6.3.2/examples/tutorials/traits_4.0/decorators/tutorial.desc000066400000000000000000000001551414270267200254410ustar00rootroot00000000000000New Method Decorators on_trait_change: on_trait_change Decorator cached_property: cached_property Decorator traits-6.3.2/examples/tutorials/traits_4.0/default.css000066400000000000000000000015001414270267200227220ustar00rootroot00000000000000body { background-color: #FFFFFF; } h1 { font-family: Arial; font-size: 14pt; color: #303030; background-color: #FCD062; padding-top: 3px; padding-left:8px; padding-bottom: 3px; padding-right: 8px; } h2 { font-family: Arial; font-size: 12pt; color: #303030; background-color: #FCD062; padding-top: 3px; padding-left:8px; padding-bottom: 3px; padding-right: 8px; } pre { border: 1px solid #A0A0A0; background-color: #FDF7E7; padding: 4px; } dl { border: 1px solid #A0A0A0; background-color: #FDF7E7; padding-top: 4px; padding-bottom: 6px; padding-left: 8px; padding-right: 8px; } dl dl { border: 0px solid #A0A0A0; } dt { font-family: Arial; font-weight: bold; dd { padding-bottom: 10px; } traits-6.3.2/examples/tutorials/traits_4.0/delegation/000077500000000000000000000000001414270267200227035ustar00rootroot00000000000000traits-6.3.2/examples/tutorials/traits_4.0/delegation/delegation.py000066400000000000000000000121761414270267200253770ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # --(Delegation Fixes and Improvements)---------------------------------------- """ Delegation Fixes and Improvements ================================= In previous versions of Traits there were a number of problems (i.e. bugs) in the delegation support that made delegation virtually unusable in some situations. As a result, one of the primary goals of Traits 3.0 was to fix all known problems with delegation, thus allowing it to reclaim its role as one of the five keys pillars of the Traits package (those pillars being *initialization*, *validation*, *notification*, *delegation* and *visualization*). We are happy to report that not only have all known bugs been fixed, but a previously unsupported, though often requested, feature has been added as well. Delegation Event Notification ----------------------------- Previously, many Traits users implicitly assumed that changes made to a *delegatee* trait would generate a change notification on any *delegater* trait (no matter how many such traits there might be). Unfortunately, this was not the case. However, starting with Traits 3.0, this feature has now been implemented. An example of what this means is shown below:: class Parent(HasTraits): first_name = Str last_name = Str class Child(HasTraits): mother = Instance(Parent) father = Instance(Parent) first_name = Str last_name = Delegate('father') In this example, we've created two classes, **Parent** and **Child**, and the value of the **Child** class's *last_name* trait delegates its value to its *father* object's *last_name* trait. Next, we'll set up a simple set of test objects:: mom = Parent(first_name='Julia', last_name='Wilson') dad = Parent(first_name='William', last_name='Chase') son = Child(mother=mom, father=dad, first_name='John') Finally, we'll set up a notification handler on the *son* object's *last_name* trait and then try out various combinations of setting both the *father* and *son* object's *last_name* trait to see in which cases the notification handler is called:: def name_changed(name): print('Your last name has been changed to %s.' % name) # Set up a change notification handler on the son's last name: son.on_trait_change(name_changed, 'last_name') # This should cause the son's last name to change as well: print("Changing dad's last name to Jones.") dad.last_name = 'Jones' # This change overrides the father's last name for the son: print("Changing son's last name to Thomas.") son.last_name = 'Thomas' # This should no longer have any effect on the son's last name: print("Changing dad's last name to Riley.") dad.last_name = 'Riley' # Son decides to revert his name back to his father's name: print("Reverting son's last name.") del son.last_name # Now changing the father's name should affect the son again: print("Changing dad's last name to Simmons.") dad.last_name = 'Simmons' For the actual results of running this code, refer to the **Output** tab. Note that for each case in which an explicit or implicit change is made to the *son* object's *last_name* trait, a corresponding call is made to the change notification handler. """ # FIXME - this need to be redone without traitsui from traits.api import Delegate, HasTraits, Instance, Str # --[Parent Class]------------------------------------------------------------- class Parent(HasTraits): first_name = Str last_name = Str # --[Child Class]-------------------------------------------------------------- class Child(HasTraits): mother = Instance(Parent) father = Instance(Parent) first_name = Str last_name = Delegate("father") # --[Example*]----------------------------------------------------------------- mom = Parent(first_name="Julia", last_name="Wilson") dad = Parent(first_name="William", last_name="Chase") son = Child(mother=mom, father=dad, first_name="John") def name_changed(name): print("Your last name has been changed to %s." % name) # Set up a change notification handler on the son's last name: son.on_trait_change(name_changed, "last_name") # This should cause the son's last name to change as well: print("Changing dad's last name to Jones.") dad.last_name = "Jones" # This change overrides the father's last name for the son: print("Changing son's last name to Thomas.") son.last_name = "Thomas" # This should no longer have any effect on the son's last name: print("Changing dad's last name to Riley.") dad.last_name = "Riley" # Son decides to revert his name back to his father's name: print("Reverting son's last name.") del son.last_name # Now changing the father's name should affect the son again: print("Changing dad's last name to Simmons.") dad.last_name = "Simmons" traits-6.3.2/examples/tutorials/traits_4.0/delegation/tutorial.desc000066400000000000000000000000421414270267200254020ustar00rootroot00000000000000Delegation Fixes and Improvements traits-6.3.2/examples/tutorials/traits_4.0/extended_trait_change/000077500000000000000000000000001414270267200251005ustar00rootroot00000000000000traits-6.3.2/examples/tutorials/traits_4.0/extended_trait_change/extended_trait_change.py000066400000000000000000000270201414270267200317630ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # --(on_trait_change Method Enhancements)-------------------------------------- r""" on_trait_change Method Enhancements =================================== In Traits 3.0, the capabilities of the **HasTraits** class's *on_trait_change* method has been greatly enhanced with the addition of a new *extended* trait name syntax for specifying the name of the trait the notification handler applies to. Previously, the trait name argument to the *on_trait_change* method could only be one of the following: Omitted, None, or 'anytrait' The notification handler applies to any trait on the object. name The notification handler applies to the trait on the object called *name*. [name1, ..., namen] The notification handler applies to each of the traits on the object with the specified names. In Traits 3.0, all of these forms are still supported, but now the syntax for specifying *name* has been expanded to allow a much broader set of traits that are *reachable* from the object the *on_trait_change* method is applied to. New *name* Parameter Syntax --------------------------- In Traits 3.0, the *name* parameter, in addition to being omitted, None or *anytrait*, can now be a single *xname* or a list of *xname* names, where an *xname* is an extended name of the form:: xname2['.'xname2]* An *xname2* is of the form:: (xname3 | '['xname3[','xname3]*']) ['*'] An *xname3* is of the form:: xname | ['+'|'-'][name] | name['?' | ('+'|'-')[name]] A *name* is any valid Python attribute name. The semantic meaning of this notation is as follows: [item, item, ..., item] A list which matches any of the specified items. Note that at the topmost level, the surrounding square brackets are optional. name? If the current object does not have an attribute called *name*, the reference can be ignored. If the '?' character is omitted, the current object must have a trait called *name*, otherwise an exception will be raised. prefix+ Matches any trait on the current object whose name begins with *prefix*. \+metadata_name Matches any trait on the current object having *metadata_name* metadata. \-metadata_name Matches any trait on the current object which does not have *metadata_name* metadata. prefix+metadata_name Matches any trait on the current object whose name begins with *prefix* and which has *metadata_name* metadata. prefix-metadata_name Matches any trait on the current object whose name begins with *prefix* and which does not have *metadata_name* metadata. \+ Matches all traits on the current object. pattern* Matches object graphs where *pattern* occurs one or more times (useful for setting up listeners on recursive data structures like trees or linked lists). Name Syntax Examples -------------------- Some examples of valid names and their meaning are as follows: 'foo,bar,baz' Listen for trait changes to *object.foo*, *object.bar*, and *object.baz*. ['foo','bar','baz'] Equivalent to 'foo,bar,baz', but may be more useful in cases where the individual items are computed. 'foo.bar.baz' Listen for trait changes to *object.foo.bar.baz*. 'foo.[bar,baz]' Listen for trait changes to *object.foo.bar* and *object.foo.baz*. '([left,right]).name' Listen for trait changes to the *name* trait of each node of a tree having *left* and *right* links to other tree nodes, and where *object* is the root node of the tree. '+dirty' Listen for trait changes on any trait in the *object* which has the 'dirty' metadata set. 'foo.+dirty' Listen for trait changes on any trait in *object.foo* which has the 'dirty' metadata set. 'foo.[bar,-dirty]' Listen for trait changes on *object.foo.bar* or any trait on *object.foo* which does not have 'dirty' metadata set. Additional Semantic Rules ------------------------- Note that any of the intermediate (i.e., non-final) links in a pattern can be traits of type **Instance**, **List** or **Dict**. In the case of **List** and **Dict** traits, the subsequent portion of the pattern is applied to each item in the list, or value in the dictionary. For example, if *self.children* is a list, 'children.name' listens for trait changes to the *name* trait for each item in the *self.children* list. Also note that items added to or removed from a list or dictionary in the pattern will cause the *handler* routine to be invoked as well, since this is treated as an *implied* change to the item's trait being monitored. Notification Handler Signatures ------------------------------- The signature of the *handler* supplied also has an effect on how changes to intermediate traits are processed. The five valid handler signatures are: 1. handler() 2. handler(new) 3. handler(name,new) 4. handler(object,name,new) 5. handler(object,name,old,new) For signatures 1, 4 and 5, any change to any element of a path being listened to invokes the handler with information about the particular element that was modified (e.g., if the item being monitored is 'foo.bar.baz', a change to 'bar' will call *handler* with the following information: object object.foo name bar old old value for object.foo.bar new new value for object.foo.bar If one of the intermediate links is a **List** or **Dict**, the call to *handler* may report an *_items* changed event. If in the previous example, *bar* is a **List**, and a new item is added to *bar*, then the information passed to *handler* would be: object object.foo name bar_items old **Undefined** new **TraitListEvent** whose *added* trait contains the new item added to *bar*. For signatures 2 and 3, the *handler* does not receive enough information to discern between a change to the final trait being listened to and a change to an intermediate link. In this case, the event dispatcher will attempt to map a change to an intermediate link to its effective change on the final trait. This only works if all of the intermediate links are single values (such as an **Instance** or **Any** trait) and not **Lists** or **Dicts**. If the modified intermediate trait or any subsequent intermediate trait preceding the final trait is a **List** or **Dict**, then a **TraitError** is raised, since the effective value for the final trait cannot in general be resolved unambiguously. Handler signature 1 also has the special characteristic that if a final trait is a **List** or **Dict**, it will automatically handle *_items* changed events for the final trait as well. This can be useful in cases where the *handler* only needs to know that some aspect of the final trait has been changed. For all other *handler* signatures, you must explicitly specify the *xxx_items* trait if you want to be notified of changes to any of the items of the *xxx* trait. Backward Compatibility ---------------------- The new extended trait name support in Traits 3.0 has one slight semantic difference with the pre-Traits 3.0 *on_trait_change* method. Prior to Traits 3.0, it was necessary to make two separate calls to *on_trait_change* in order to set up listeners on a **List** or **Dict** trait's value and the contents of its value, as shown in the following example:: class Department(HasTraits): employees = List(Employee) ... a_department.on_trait_change(some_listener, 'employees') a_department.on_trait_change(some_listener_items, 'employees_items') In Traits 3.0, this is still the case if the *some_listener* function has one or more arguments. However, if it has no arguments, the *on_trait_change* method will automatically call the function either when the trait's value or its value's contents change. So in Traits 3.0 it is only necessary to write:: a_department.on_trait_change(some_listener, 'employees') if the *some_listener* (and *some_listener_items*) function has no arguments. The net effect of this difference is that code written prior to Traits 3.0 could set up two listeners (e.g. *some_listener* and *some_listener_items*, as in the example), and then have *both* methods called when the contents of the trait are modified if the *some_listener* method takes no arguments. Since no data is passed to the *some_listener* function, there is probably no harm in doing this, but it does create unnecessary notification handler calls. As a result, to avoid creating this unwanted overhead in existing code, the *on_trait_change* method applies pre-Traits 3.0 semantics to all simple names passed to it (e.g. 'employees'). If you are writing new code and want to take advantage of the new Traits 3.0 *on_trait_change* semantics for a simple trait name, you will need to modify the name to use some recognizable aspect of the new extended trait name syntax. For example, either of the following lines would cause *new style* semantics to be applied to the *employees* trait:: a_department.on_trait_change(some_listener, ' employees') a_department.on_trait_change(some_listener, '[employees]') A Complete Example ------------------ Refer to the code tabs of this lesson for a complete example using *on_trait_change* with an extended trait name. In particular, check near the bottom of the **Example** tab for the code that sets up an extended trait change notification handler using *on_trait_change*. """ from traits.api import HasTraits, Int, List, Str # --[Employee Class]----------------------------------------------------------- class Employee(HasTraits): # The name of the employee: name = Str # The number of sick days they have taken this year: sick_days = Int # --[Department Class]--------------------------------------------------------- class Department(HasTraits): # The name of the department: name = Str # The employees in the department: employees = List(Employee) # --[Corporation Class]-------------------------------------------------------- class Corporation(HasTraits): # The name of the corporation: name = Str # The departments within the corporation: departments = List(Department) # --[Example*]----------------------------------------------------------------- # Create some sample employees: millie = Employee(name="Millie", sick_days=2) ralph = Employee(name="Ralph", sick_days=3) tom = Employee(name="Tom", sick_days=1) slick = Employee(name="Slick", sick_days=16) marcelle = Employee(name="Marcelle", sick_days=7) reggie = Employee(name="Reggie", sick_days=11) dave = Employee(name="Dave", sick_days=0) bob = Employee(name="Bob", sick_days=1) alphonse = Employee(name="Alphonse", sick_days=5) # Create some sample departments: accounting = Department(name="accounting", employees=[millie, ralph, tom]) sales = Department(name="Sales", employees=[slick, marcelle, reggie]) development = Department(name="Development", employees=[dave, bob, alphonse]) # Create a sample corporation: acme = Corporation( name="Acme, Inc.", departments=[accounting, sales, development] ) # Define a corporate 'whistle blower' function: def sick_again(object, name, old, new): print( "%s just took sick day number %d for this year!" % (object.name, new) ) # Set up the function as a listener: acme.on_trait_change(sick_again, "departments.employees.sick_days") # Now let's try it out: slick.sick_days += 1 reggie.sick_days += 1 traits-6.3.2/examples/tutorials/traits_4.0/extended_trait_change/properties.py000066400000000000000000000175671414270267200276660ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # --(Extended Property depends_on References)---------------------------------- """ Extended Property *depends_on* References ========================================= In Traits 3.0, the **Property** *depends_on* metadata has been extended to take advantage of the new extended trait name support offered by the *on_trait_change* method. Previously, the *depends_on* metadata for a *Property* was restricted to referencing traits defined either on the same object as the **Property**, or on an object immediately reachable from the object. For example:: class Wheel(Part): axel = Instance(Axel) position = Property(depends_on = 'axel.position') ... Starting with Traits 3.0, the *depends_on* metadata may now include any extended trait reference that is allowed by the enhanced *on_trait_change* method. So, for example it is now legal to write things like:: class Wheel(Part): axel = Instance(Axel) position = Property(depends_on = 'axel.chassis.position') or:: class Child(Person): mother = Instance(Person) father = Instance(Person) mood = Property(depends_on = ['mother.+mood_affecting', 'father.+mood_affecting']) In particular, in the last example we are declaring that the **Child** class's *mood* property depends upon the values of any of either its mother or father object's traits that have *mood_affecting* metadata defined. Thus, a **Child** object's *mood* property will fire a trait change notification whenever any of the its mother's or father's mood affecting traits change. Refer also to the code tabs for this lesson for a complete example using a **Property** definition using *depends_on* metadata containing an extended trait reference. In particular, take a look at the **LeagueModelView Class** tab's *total_hits* trait definition. """ # FIXME redo example without traitsui from traits.api import ( Button, cached_property, HasTraits, Instance, Int, List, Property, Str) from traitsui.api import ( HGroup, Item, ModelView, ObjectColumn, TableEditor, VGroup, View) # --[Player Class]------------------------------------------------------------- # Define a baseball player: class Player(HasTraits): # The name of the player: name = Str("") # The number of hits the player made this season: hits = Int # --[Team Class]--------------------------------------------------------------- # Define a baseball team: class Team(HasTraits): # The name of the team: name = Str("") # The players on the team: players = List(Player) # The number of players on the team: num_players = Property(depends_on="players") def _get_num_players(self): """ Implementation of the 'num_players' property. """ return len(self.players) # --[League Class]------------------------------------------------------------- # Define a baseball league model: class League(HasTraits): # The name of the league: name = Str("") # The teams in the league: teams = List(Team) # --[LeagueModelView Class]---------------------------------------------------- # Define a ModelView for a League model: class LeagueModelView(ModelView): # The currently selected team: team = Instance(Team) # The currently selected player: player = Instance(Player) # Button to add a hit to the current player: got_hit = Button("Got a Hit") # The total number of hits (note the 'depends_on' extended trait # reference): total_hits = Property(depends_on="model.teams.players.hits") @cached_property def _get_total_hits(self): """ Returns the total number of hits across all teams and players. """ return sum( sum(p.hits for p in t.players) for t in self.model.teams ) view = View( VGroup( HGroup( Item("total_hits", style="readonly"), label="League Statistics", show_border=True, ), VGroup( Item( "model.teams", show_label=False, editor=TableEditor( columns=[ ObjectColumn(name="name", width=0.70), ObjectColumn( name="num_players", label="# Players", editable=False, width=0.29, ), ], selected="object.team", auto_add=True, row_factory=Team, configurable=False, sortable=False, ), ), label="League Teams", show_border=True, ), VGroup( Item( "object.team.players", show_label=False, editor=TableEditor( columns=[ ObjectColumn(name="name", width=0.70), ObjectColumn( name="hits", editable=False, width=0.29 ), ], selected="object.player", auto_add=True, row_factory=Player, configurable=False, sortable=False, ), ), "_", HGroup( Item( "got_hit", show_label=False, enabled_when="player is not None", ) ), label="Team Players", show_labels=False, show_border=True, ), ), resizable=True, ) def _model_changed(self, model): """ Handles the 'league' model being initialized. """ if len(model.teams) > 0: self.team = model.teams[0] def _got_hit_changed(self): """ Handles the currently selected player making a hit. """ self.player.hits += 1 def _team_changed(self, team): """ Handles a new team being selected. """ if len(team.players) > 0: self.player = team.players[0] else: self.player = None # Function to add two numbers (used with 'reduce'): add = lambda a, b: a + b # --[Example*]----------------------------------------------------------------- # Define some sample teams and players: blue_birds = Team( name="Blue Birds", players=[ Player(name="Mike Scott", hits=25), Player(name="Willy Shofield", hits=37), Player(name="Tony Barucci", hits=19), ], ) chicken_hawks = Team( name="Chicken Hawks", players=[ Player(name="Jimmy Domore", hits=34), Player(name="Bill Janks", hits=16), Player(name="Tim Saunders", hits=27), ], ) eagles = Team( name="Eagles", players=[ Player(name="Joe Peppers", hits=33), Player(name="Sam Alone", hits=12), Player(name="Roger Clemson", hits=23), ], ) # Create a league and its corresponding model view: demo = LeagueModelView( League( name="National Baseball Conference", teams=[blue_birds, chicken_hawks, eagles], ) ) traits-6.3.2/examples/tutorials/traits_4.0/extended_trait_change/tutorial.desc000066400000000000000000000002451414270267200276040ustar00rootroot00000000000000Extended Trait Change Notification Syntax extended_trait_change: on_trait_change Method Enhancements properties: Extended Property depends_on References traits-6.3.2/examples/tutorials/traits_4.0/getstate_setstate/000077500000000000000000000000001414270267200243245ustar00rootroot00000000000000traits-6.3.2/examples/tutorials/traits_4.0/getstate_setstate/getstate.py000066400000000000000000000161471414270267200265270ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # --(__getstate__/__setstate__ Changes and Improvements)----------------------- """ __getstate__/__setstate__ Changes and Improvements ================================================== Originally, the **HasTraits** class did not define specific *__getstate__* or *__setstate__* methods for dealing with *pickling* and *unpickling* of traits-based objects. However, in the course of developing a number of fairly large-scale applications using Traits, experience has shown that some traits specific support in this area would be of benefit to most application developers. Accordingly, Traits 3.0 introduces *__getstate__* and *__setstate__* methods that implement several traits aware serialization and deserialization policies. The *__getstate__* Method ------------------------- One of the most frequently occurring requirements for serializing an object is the ability to control which parts of the object's state are saved, and which parts are discarded. One typical approach is to define a *__getstate__* method which makes a copy of the object's *__dict__* attribute and deletes those items which should not be saved. While this approach works, there are some drawbacks, especially in cases where heavy use of subclassing is used. The **HasTraits** *__getstate__* method uses a somewhat different approach by providing a generic implementation which implements *policies* that developers can customize through the use of traits *metadata*, in many cases completely eliminating the need to override or define a *__getstate__* method in their application classes. In particular, the **HasTraits** *__getstate__* method saves the value of all traits which do not have *transient = True* metadata defined. This policy allows developers to easily mark which trait values should not be saved simply by adding *transient = True* metadata to them. Besides avoiding having to write a *__getstate__* method for their class, this approach also provides good documentation about the *pickling* behavior of the class. For example:: class DataBase(HasTraits): # The name of the data base file: file_name = File # The open file handle used to access the data base: file = Any(transient = True) In this example, the **DataBase** class's *file* trait has been mark as *transient* because it normally contains an open file handle used to access a data base. Since file handles typically cannot be pickled and restored, the file handle should not be saved as part of the object's persistent state. Normally, the file handle would be re-opened by application code after the object has been restored from its persisted state. Predefined *transient* Traits ----------------------------- The Traits package automatically assigns *transient = True* metadata to a number of predefined traits, thus avoiding the need to explicitly mark them as transient yourself. The predefined traits marked as *transient* are: - **Constant**. - **Event**. - *read-only* or *write-only* **Property** traits. - The *xxx_* trait for *mapped* traits. - All *_xxx* traits for classes that subclass **HasPrivateTraits**. Also, by default, delegated traits are only saved if they have a local value which overrides the value defined by its delegate. You can set *transient = True* on the delegate trait if you do not want its value to ever be saved. Overriding *__getstate__* ------------------------- In general, you should avoid overriding *__getstate__* in subclasses of **HasTraits**. Instead, mark traits that should not be pickled with *transient = True* metadata. However, in cases where this strategy is insufficient, we recommend overriding *__getstate__* using the follow pattern to remove items that should not be persisted:: def __getstate__(self): state = super().__getstate__() for key in [ 'foo', 'bar' ]: if key in state: del state[ key ] return state The *__setstate__* Method ------------------------- The main difference between the default Python *__setstate__*-like behavior and the new **HasTraits** class *__setstate__* method is that the **HasTraits** *__setstate__* method actually *sets* the value of each trait using the values passed to it via its state dictionary argument instead of simply storing or copying the state dictionary to its *__dict__* attribute. While slower, this has the advantage of causing trait change notifications to be generated, which can be very useful for classes which rely of receiving notifications in order to ensure that their internal object state remains consistent and up to date. Overriding *__setstate__* ------------------------- For classes which do not want to receive change notifications during *__setstate__*, it is possible to override *__setstate__* and update the object's *__dict__* attribute directly. However, in such cases it is important to either call the *__setstate__* super method (with an empty state dictionary, for example), or to call the **HasTraits** class's private *_init_trait_listeners* method directly. This method has no arguments and does not return a result, but it must be called during *__setstate__* in order to ensure that all dynamic trait change notifications managed by traits are correctly initialized for the object. Failure to call this method may result in lost change notifications. """ from time import time from traits.api import Any, HasTraits, Str # --[Session Class]------------------------------------------------------------ class Session(HasTraits): # The name of the session: name = Str # The time the session was created: created = Any(transient=True) def _name_changed(self): self.created = time() # --[Example*]----------------------------------------------------------------- # The following shows an example of pickling and unpickling a Session object. # Unfortunately, it is not possible to successfully pickle objects created as # part of a tutorial, because of problems with pickling objects derived from # classes dynamically defined using 'exec'. So just use your imagination on # this one... # Create a new session: session = Session(name="session_1") # Display its contents: print("Session name:", session.name) print("Session created:", session.created) # # Simulate saving the session to a file/database: # # from pickle import dumps, loads # from time import sleep # # saved_session = dumps(session) # # # Simulate the passage of time (zzzzZZZZ...): # sleep(1) # # # Simulate restoring the session from a file/database: # restored_session = loads(saved_session) # # # Display the restored sessions contents (note that the 'created' # # time should be different from the original session): # print 'Restored session name:', restored_session.name # print 'Restored session created:', restored_session.created traits-6.3.2/examples/tutorials/traits_4.0/getstate_setstate/tutorial.desc000066400000000000000000000000421414270267200270230ustar00rootroot00000000000000__getstate__/__setstate__ Changes traits-6.3.2/examples/tutorials/traits_4.0/interfaces/000077500000000000000000000000001414270267200227135ustar00rootroot00000000000000traits-6.3.2/examples/tutorials/traits_4.0/interfaces/interfaces.py000066400000000000000000000077331414270267200254220ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # --(Interfaces)--------------------------------------------------------------- """ Interfaces ========== In Traits 3.0, the ability to define, implement and use *interfaces* has been added to the package. Defining Interfaces ------------------- Interfaces are defined by subclassing from the **Interface** class, as shown in the example below:: from traits.api import Interface class IName(Interface): def get_name(self): " Returns the name of an object. " This same code is shown in the **IName Interface** tab of the code. Interface classes are intended mainly as documentation of the methods and traits that the interface defines, and should not contain any actual implementation code, although no check is performed to enforce this currently. Implementing Interfaces ----------------------- A class declares that it implements one or more interfaces using the **provides** decorator, which has the form:: @provides(interface [, interface2, ..., interfacen]) The decorator declares that the decorated class implements each of the *interfaces* specified as an argument to **provides**. For example:: from traits.api import HasTraits, provides @provides(IName) class Person(HasTraits): def get_name(self): ... Note that in the current version, traits does not check to ensure that the class decorated with **provides** actually implements the interfaces it says it does. Using Interfaces ---------------- Being able to define and implement interfaces would be of little use without the ability to *use* interfaces in your code. In traits, using an interface is accomplished using the **Instance** trait, as shown in the following example:: from traits.api import HasTraits, Instance class Apartment(HasTraits): renter = Instance(IName) Using an interface class in an **Instance** trait definition declares that the trait only accepts values which implement the specified interface. As before, the **Instance** trait can also be used with classes that are not interfaces, such as:: from traits.api import HasTraits, Instance class Apartment(HasTraits): renter = Instance(Person) In this case, the value of the trait must be an object which is an instance of the specified class or one of its subclasses. """ # -------------------------------------------------------------------- from traits.api import HasTraits, Instance, Interface, provides, Str # --[IName Interface]---------------------------------------------------------- # Define the 'IName' interface: class IName(Interface): def get_name(self): """ Returns the name of an object. """ # --[Person Class]------------------------------------------------------------- @provides(IName) class Person(HasTraits): first_name = Str("John") last_name = Str("Doe") # Implementation of the 'IName' interface: def get_name(self): """ Returns the name of an object. """ return "%s %s" % (self.first_name, self.last_name) # --[Apartment Class]---------------------------------------------------------- # Define a class using an object that implements the 'IName' interface: class Apartment(HasTraits): renter = Instance(IName) # --[Example*]----------------------------------------------------------------- # Create an object implementing the 'IName' interface: william = Person(first_name="William", last_name="Adams") # Create an apartment, and assign 'renter' an object implementing 'IName': apt = Apartment(renter=william) # Verify that the object works correctly: print("Renter is:", apt.renter.get_name()) traits-6.3.2/examples/tutorials/traits_4.0/interfaces/tutorial.desc000066400000000000000000000001111414270267200254070ustar00rootroot00000000000000Interfaces and Adaptation interfaces: Interfaces adaptation: Adaptation traits-6.3.2/examples/tutorials/traits_4.0/trait_types/000077500000000000000000000000001414270267200231375ustar00rootroot00000000000000traits-6.3.2/examples/tutorials/traits_4.0/trait_types/core_traits.py000066400000000000000000000023061414270267200260300ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # --(Rewritten Core Traits)---------------------------------------------------- """ Rewritten Core Traits ===================== For several reasons, including the ability to subclass types, many of the previous core Traits package types have been entirely rewritten as subclasses of **TraitType**, the new base class for subclassable trait types. The core trait types which have been rewritten as subclasses of **TraitType** are: - Any - Bool - CBool - CComplex - CInt - CFloat - Code - Complex - CStr - Dict - Directory - Enum - Expression - File - Float - HTML - Instance - Int - List - Password - PythonValue - Range - Regex - Str - String - Tuple - WeakRef This may be useful information if you find yourself in need of creating a new trait type with behavior similar to any of these core trait types. """ traits-6.3.2/examples/tutorials/traits_4.0/trait_types/new_types.py000066400000000000000000000206541414270267200255350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # --(Creating New Trait Types)------------------------------------------------- """ Creating New Trait Types ======================== You create a *new style* trait type by subclassing the **TraitType** class or one of its subclasses, such as **Float** or **Str**. **TraitType** provides the infrastructure for creating a trait type and allows subclasses to define specific methods and class constants used to create either a new trait *type* or *property*. In the next section, we'll cover the methods and class constants used to define a new trait *type*, and in the section following that we'll show how to define a new trait *property*. Defining a New Trait Type ------------------------- The thing that distinguishes a trait *type* from a *property* is the existence of a *validate* method in the subclass. The *validate* method should have the following signature: validate(self, object, name, value) This method validates, coerces, or adapts the specified *value* as the value of the *name* trait of the *object* object. This method is called when a value is assigned to an object trait that is based on this subclass of *TraitType* and the class does not contain a definition for either the *get()* or *set()* methods. The method must return the original *value* or any suitably coerced or adapted value that is a legal value for the trait. If *value* is not a legal value for the trait, and cannot be coerced or adapted to a legal value, the method should either raise a **TraitError** or call the *error()* method to raise a **TraitError** on its behalf. In addition to *validate*, the subclass can also define the *post_setattr* method, which should have the following signature: post_setattr(self, object, name, value) This method allows the trait to do additional processing after *value* has been successfully assigned to the *name* trait of the *object* object. For most traits there is no additional processing that needs to be done, and this method need not be defined. It is normally used for creating *shadow* (i.e., *mapped* traits), but other uses may arise as well. This method does not need to return a value, and should normally not raise any exceptions. The subclass can also define a constant default value by setting the class- level *default_value* attribute to the desired constant value. For example:: class OddInt(BaseInt): default_value = 1 ... If a non-constant default value is desired, you should override the **TraitType** class's *get_default_value* method. Refer to the documentation for the **TraitType** class for more information on what this method does. If you have a constant string that can be used as the type's *info* value, you can provide it by simple setting the string as the value of the class-level *info_text* attribute:: class OddInt(BaseInt): info_text = 'an odd integer' ... If you have a type info string which depends upon the internal state of the trait, then you should override the **TraitType's** *info* method. This method has no arguments, and should return a string describing the values accepted by the trait type (e.g. 'an integer in the range from 1 to 5'). If you also have some type specific initialization that needs to be performed when the trait type is created, you can also override the **TraitType** class's *init* method. This method has no arguments and is automatically called from the **TraitType** class constructor. If you would like to specify a default Traits UI editor for your new trait type, you can also override the **TraitType** class's *create_editor* method, which has no arguments and should return the default **TraitEditor** for any instances of the type to use. This provides a basic overview of the basic methods and class constants needed to define a new trait type. Refer to the complete documentation for the **TraitType** and **BaseTraitHandler** classes for more information on other methods that can be overridden if necessary. Defining a New Trait Property ----------------------------- You can also define new trait *properties* by subclassing from **TraitType** or one of its subclasses. A *property* is distinguished from a *type* by the existence of a *get* and/or *set* method in the **TraitType** subclass. The signature for these two methods is as follows: get(self, object, name) This is the *getter* method of a trait that behaves like a property. It has the following arguments: object The object that the property applies to. name The name of the *object* property. If this method is not defined, but the *set* method is defined, the trait behaves like a *write-only* property. This method should return the value of the *name* property for the *object* object. set(self, object, name, value) This is the *setter* method of a trait that behaves like a property. It has the following arguments: object The object the property applies to. name The name of the property on *object*. value The value being assigned as the value of the property. If this method is not defined, but the *get* method is defined, the trait behaves like a *read-only* property. This method does not need to return a value, but it should raise a **TraitError** exception if the specified *value* is not valid and cannot be coerced or adapted to a valid value. Because the value of a *property* is determined by the *get* method, the *default_value* class constant and *get_default_value* method are not used. However, all other values and methods, such as the *info_text* class attribute and *info* method apply to a *property* as well as a normal type. Please refer to the preceding section on defining a trait type for additional information that applies to properties as well. """ # -------------------------------------------------------------------- from random import randint from traits.api import HasTraits, List, TraitError, TraitType # --[DiceRoll Type]------------------------------------------------------------ # Define a type whose value represents the roll of a pair of dice: class DiceRoll(TraitType): # Set default value to 'snake-eyes': default_value = (1, 1) # Describe the type: info_text = ( "a tuple of the form (n,m), where both n and m are integers " "in the range from 1 to 6 representing a roll of a pair of " "dice" ) # Validate any value assigned to the trait to make sure it is a valid # dice roll: def validate(self, object, name, value): if ( isinstance(value, tuple) and (len(value) == 2) and (1 <= value[0] <= 6) and (1 <= value[1] <= 6) ): return value self.error(object, name, value) # --[RandInt Property]--------------------------------------------------------- # Define a read-only property whose value is a random integer in a specified # range: class RandInt(TraitType): # Define the type's constructor: def __init__(self, low=1, high=10, **metadata): super().__init__(**metadata) self.low = int(low) self.high = int(high) # Define the property's getter: def get(self): return randint(self.low, self.high) # Define the type's type information: def info(self): return "a random integer in the range from %d to %d" % ( self.low, self.high, ) # --[Craps Class]-------------------------------------------------------------- # Define a test class containing both new trait types/properties: class Craps(HasTraits): rolls = List(DiceRoll) die = RandInt(1, 6) # --[Example*]----------------------------------------------------------------- # Create a test object: craps = Craps() # Add a number of test dice rolls: for i in range(10): craps.rolls.append((craps.die, craps.die)) # Display the results: print(craps.rolls) # Try to assign an invalid dice roll: try: craps.rolls.append((0, 0)) except TraitError: print("Assigning an invalid dice roll failed.") traits-6.3.2/examples/tutorials/traits_4.0/trait_types/trait_types.py000066400000000000000000000116201414270267200260600ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # --(New Trait Definition Style)----------------------------------------------- """ New Trait Definition Style ========================== The Traits package comes with a number of predefined traits, such as **Str**, **Int**, **Float**, **Range** and so on. While these core traits suffice for most common programming situations, quite often the need arises to create a new *custom* trait. Traits has always supported creating new traits, but in the past this has typically involved creating a new **TraitHandler** subclass and invoking the **Trait** function to define a new trait based on that subclass, as shown in the following example:: class OddIntHandler(TraitHandler): def validate(self, object, name, value): if isinstance(value, int) and ((value % 2) == 1): return value self.error(object, name, value) def info(self): return 'an odd integer' OddInt = Trait(1, OddIntHandler) OddInt = TraitFactory(OddInt) While not overly complex, nevertheless several developers have complained that that: - The process of creating a new trait is not overly intuitive. - The resulting trait cannot be subclassed to derive a new trait with slightly different behavior. As a result, in Traits 3.0 a new method of defining traits has been added that hopefully addresses both of these issues. Note that this new style of creating traits does not replace the old style of creating traits, but is simply a new technique that can be used instead of the original method. Both old and new style traits can be defined, used and interoperate in the same program without any adverse side effects. OddInt Redux ------------ Using the new style of defining traits, we can rewrite our previous **OddInt** example as follows:: class OddInt(BaseInt): # Define the default value: default_value = 1 # Describe the trait type: info_text = 'an odd integer' def validate(self, object, name, value): value = super().validate(object, name, value) if (value % 2) == 1: return value self.error(object, name, value) This provides the exact same functionality as the previous definition of **OddInt**. There are several points to make about the new definition however: - The **OddInt** class derives from **BaseInt** (not **TraitHandler**). This has several important side effects: * **OddInt** can re-use and change any part of the **BaseInt** class behavior that it needs to. Note in this case the re-use of the **BaseInt** class's *validate* method via the *super* call in **OddInt's** *validate* method. * As a subclass of **BaseInt**, it is related to **BaseInt**, which can be important both from a documentation and programming point of view. The original definition of **OddInt** was related to **BaseInt** only in that their names were similar. - The default value and trait description information are declared as class constants. Although there are more dynamic techniques that allow computing these values (which will be described in another tutorials), this provides a very simple means of defining these values. - No use of **TraitHandler**, **Trait** or **TraitFactory** is required, just good old OO programming techniques. Hopefully this will make the process of creating a new trait type a little more understandable to a wider group of developers. """ # -------------------------------------------------------------------- from traits.api import BaseInt, HasTraits # --[OddInt Definition]-------------------------------------------------------- class OddInt(BaseInt): # Define the default value: default_value = 1 # Describe the trait type: info_text = "an odd integer" def validate(self, object, name, value): value = super().validate(object, name, value) if (value % 2) == 1: return value self.error(object, name, value) # --[Test Class]--------------------------------------------------------------- class Test(HasTraits): any_int = BaseInt odd_int = OddInt # --[Example*]----------------------------------------------------------------- # Create a test object: t = Test() # Set both traits to an odd integer value: t.any_int = 1 print("t.any_int:", t.any_int) t.odd_int = 1 print("t.odd_int:", t.odd_int) # Now set them both to an even value (and see what happens): t.any_int = 2 print("t.any_int:", t.any_int) t.odd_int = 2 print("t.odd_int:", t.odd_int) # Should never get here! traits-6.3.2/examples/tutorials/traits_4.0/trait_types/tutorial.desc000066400000000000000000000001761414270267200256460ustar00rootroot00000000000000Trait Types trait_types: New Trait Definition Style core_traits: Rewritten Core Traits new_types: Creating New Trait Types traits-6.3.2/examples/tutorials/traits_4.0/tutorial.desc000066400000000000000000000001671414270267200232770ustar00rootroot00000000000000Changes starting with Traits 3.0 interfaces trait_types extended_trait_change decorators delegation getstate_setstate traits-6.3.2/examples/tutorials/tutor.py000066400000000000000000000024471414270267200204370ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # fixme: # - Get custom tree view images. # - Write a program to create a directory structure from a lesson plan file. """ Script to run the tutorial. """ import os import sys from traitsui.extras.demo import demo # Correct program usage information: usage = """ Correct usage is: tutor.py [root_dir] where: root_dir = Path to root of the tutorial tree If omitted, 'root_dir' defaults to the current directory.""" def main(root_dir): # Create a tutor and display the tutorial: path, name = os.path.splitext(root_dir) demo(dir_name=root_dir, title='Traits Demos') if __name__ == "__main__": # Validate the command line arguments: if len(sys.argv) > 2: print(usage) sys.exit(1) # Determine the root path to use for the tutorial files: if len(sys.argv) == 2: root_dir = sys.argv[1] else: root_dir = os.getcwd() main(root_dir) traits-6.3.2/image_LICENSE.txt000066400000000000000000000017011414270267200160210ustar00rootroot00000000000000The icons are mostly derived work from other icons. As such they are licensed accordingly to the original license: Project License File, URL --------------------------------------------------------------------- Enthought BSD 3-Clause LICENSE.txt http://www.enthought.com/licenses/BSD.txt Hannes Grobe/AWI CC BY 3.0 LICENSE-CC-BY-3.0.txt https://creativecommons.org/licenses/by/3.0 Unless stated in this file, icons and images are the work of Enthought, and are released under a 3 clause BSD license. Files and original authors: ---------------------------------------------------------------------------- docs/source/_static: e-logo-rev.png | Enthought docs/source/traits_user_manual/images: adaptation.png | Enthought traits/examples/introduction/images sample_0001.png | Hannes Grobe/AWI sample_0002.png | Hannes Grobe/AWI traits-6.3.2/setup.cfg000066400000000000000000000001761414270267200146620ustar00rootroot00000000000000[flake8] exclude = traits/observation/_generated_parser.py ignore = E266,W503,E722,E731,E741 per-file-ignores = */api.py:F401 traits-6.3.2/setup.py000066400000000000000000000244131414270267200145530ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import os import runpy import subprocess import setuptools # Version information; update this by hand when making a new bugfix or feature # release. The actual package version is autogenerated from this information # together with information from the version control system, and then injected # into the package source. MAJOR = 6 MINOR = 3 MICRO = 2 PRERELEASE = "" IS_RELEASED = True # If this file is part of a Git export (for example created with "git archive", # or downloaded from GitHub), ARCHIVE_COMMIT_HASH gives the full hash of the # commit that was exported. ARCHIVE_COMMIT_HASH = "6df2ff9bd1d21c74e688aff6f67a19fbbefdd53b" # Templates for version strings. RELEASED_VERSION = "{major}.{minor}.{micro}{prerelease}" UNRELEASED_VERSION = "{major}.{minor}.{micro}{prerelease}.dev{dev}" # Paths to the autogenerated version file and the Git directory. HERE = os.path.abspath(os.path.dirname(__file__)) VERSION_FILE = os.path.join(HERE, "traits", "version.py") GIT_DIRECTORY = os.path.join(HERE, ".git") # Template for the autogenerated version file. VERSION_FILE_TEMPLATE = '''\ # (C) Copyright 2005-2021 {company}, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Version information for this Traits distribution. This file is autogenerated by the Traits setup.py script. """ #: The full version of the package, including a development suffix #: for unreleased versions of the package. version = "{version}" #: The Git revision from which this release was made. git_revision = "{git_revision}" ''' # Git executable to use to get revision information. GIT = "git" def _git_output(args): """ Call Git with the given arguments and return the output as text. """ return subprocess.check_output([GIT] + args).decode("utf-8") def _git_info(commit="HEAD"): """ Get information about the given commit from Git. Parameters ---------- commit : str, optional Commit to provide information for. Defaults to "HEAD". Returns ------- git_count : int Number of revisions from this commit to the initial commit. git_revision : str Commit hash for HEAD. Raises ------ EnvironmentError If Git is not available. subprocess.CalledProcessError If Git is available, but the version command fails (most likely because there's no Git repository here). """ count_args = ["rev-list", "--count", "--first-parent", commit] git_count = int(_git_output(count_args)) revision_args = ["rev-list", "--max-count", "1", commit] git_revision = _git_output(revision_args).rstrip() return git_count, git_revision def write_version_file(version, git_revision): """ Write version information to the version file. Overwrites any existing version file. Parameters ---------- version : str Package version. git_revision : str The full commit hash for the current Git revision. """ with open(VERSION_FILE, "w", encoding="utf-8") as version_file: version_file.write( VERSION_FILE_TEMPLATE.format( version=version, git_revision=git_revision, company="Enthought" ) ) def read_version_file(): """ Read version information from the version file, if it exists. Returns ------- version : str The full version, including any development suffix. git_revision : str The full commit hash for the current Git revision. Raises ------ EnvironmentError If the version file does not exist. """ version_info = runpy.run_path(VERSION_FILE) return (version_info["version"], version_info["git_revision"]) def git_version(): """ Construct version information from local variables and Git. Returns ------- version : str Package version. git_revision : str The full commit hash for the current Git revision. Raises ------ EnvironmentError If Git is not available. subprocess.CalledProcessError If Git is available, but the version command fails (most likely because there's no Git repository here). """ git_count, git_revision = _git_info() version_template = RELEASED_VERSION if IS_RELEASED else UNRELEASED_VERSION version = version_template.format( major=MAJOR, minor=MINOR, micro=MICRO, prerelease=PRERELEASE, dev=git_count, ) return version, git_revision def archive_version(): """ Construct version information for an archive. Returns ------- version : str Package version. git_revision : str The full commit hash for the current Git revision. Raises ------ ValueError If this does not appear to be an archive. """ if "$" in ARCHIVE_COMMIT_HASH: raise ValueError("This does not appear to be an archive.") version_template = RELEASED_VERSION if IS_RELEASED else UNRELEASED_VERSION version = version_template.format( major=MAJOR, minor=MINOR, micro=MICRO, prerelease=PRERELEASE, dev="-unknown", ) return version, ARCHIVE_COMMIT_HASH def resolve_version(): """ Process version information and write a version file if necessary. Returns the current version information. Returns ------- version : str Package version. git_revision : str The full commit hash for the current Git revision. """ if os.path.isdir(GIT_DIRECTORY): # This is a local clone; compute version information and write # it to the version file, overwriting any existing information. version = git_version() print("Computed package version: {}".format(version)) print("Writing version to version file {}.".format(VERSION_FILE)) write_version_file(*version) elif "$" not in ARCHIVE_COMMIT_HASH: # This is a source archive. version = archive_version() print("Archive package version: {}".format(version)) print("Writing version to version file {}.".format(VERSION_FILE)) write_version_file(*version) elif os.path.isfile(VERSION_FILE): # This is a source distribution. Read the version information. print("Reading version file {}".format(VERSION_FILE)) version = read_version_file() print("Package version from version file: {}".format(version)) else: raise RuntimeError( "Unable to determine package version. No local Git clone " "detected, and no version file found at {}.".format(VERSION_FILE) ) return version def get_long_description(): """ Read long description from README.txt. """ with open("README.rst", "r", encoding="utf-8") as readme: return readme.read() version, git_revision = resolve_version() setuptools.setup( name="traits", version=version, url="http://docs.enthought.com/traits", author="Enthought", author_email="info@enthought.com", classifiers=[ c.strip() for c in """ Development Status :: 5 - Production/Stable Intended Audience :: Developers Intended Audience :: Science/Research License :: OSI Approved :: BSD License Operating System :: MacOS :: MacOS X Operating System :: Microsoft :: Windows Operating System :: POSIX :: Linux Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering Topic :: Software Development Topic :: Software Development :: Libraries Topic :: Software Development :: User Interfaces """.splitlines() if len(c.strip()) > 0 ], description="Observable typed attributes for Python classes", long_description=get_long_description(), long_description_content_type="text/x-rst", download_url="https://pypi.python.org/pypi/traits", project_urls={ "Issue Tracker": "https://github.com/enthought/traits/issues", "Documentation": "https://docs.enthought.com/traits", "Source Code": "https://github.com/enthought/traits", }, install_requires=[], extras_require={ "docs": [ "enthought-sphinx-theme", "Sphinx>=2.1.0,!=3.2.0", ], "test": [ "Cython", "flake8", "flake8-ets", "mypy", "numpy; python_version<'3.10'", "pyface", "PySide2; python_version<'3.10'", "setuptools", "Sphinx>=2.1.0,!=3.2.0", "traitsui", ], "examples": [ # dependencies for examples "numpy", "pillow", ] }, ext_modules=[setuptools.Extension("traits.ctraits", ["traits/ctraits.c"])], package_data={ "traits.examples": [ "introduction/*", "introduction/*/*", ], "traits.tests": [ "test-data/historical-pickles/README", "test-data/historical-pickles/*.pkl", "test-data/historical-pickles/*.py", ], }, entry_points={ "etsdemo_data": [ "introduction = traits.examples._etsdemo_info:introduction", ], }, license="BSD", packages=setuptools.find_packages(include=["traits", "traits.*"]), python_requires=">=3.6", zip_safe=False, ) traits-6.3.2/traits-stubs/000077500000000000000000000000001414270267200155015ustar00rootroot00000000000000traits-6.3.2/traits-stubs/LICENSE.txt000066400000000000000000000031401414270267200173220ustar00rootroot00000000000000This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative. (C) Copyright 2020-2021 Enthought, Inc., Austin, TX All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Enthought, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. traits-6.3.2/traits-stubs/MANIFEST.in000066400000000000000000000001401414270267200172320ustar00rootroot00000000000000include LICENSE.txt include MANIFEST.in include README.rst recursive-include traits-stubs *.pyi traits-6.3.2/traits-stubs/README.rst000066400000000000000000000017471414270267200172010ustar00rootroot00000000000000========================================= traits-stubs: Type annotations for Traits ========================================= The *traits-stubs* package contains external type annotations for the Traits_ package. These annotations can be used with static type checkers like mypy_ to type-check your Traits-using Python code. Installation ------------ - To install from PyPI, simply use ``pip install traits-stubs``. - To install from source, run ``pip install .`` from this directory. Usage ----- You'll usually want to install mypy_ (or another type checker) into your Python environment alongside these stubs. You can then use mypy_ from the command line to check a file or directory, for example with:: mypy Alternatively, some IDEs (including VS Code and PyCharm) can be configured to perform type checking as you edit. Dependencies ------------ This package depends on Traits_. .. _Traits: https://pypi.org/project/traits/ .. _mypy: https://pypi.org/project/mypy/ traits-6.3.2/traits-stubs/setup.py000066400000000000000000000045651414270267200172250ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import setuptools def get_long_description(): """ Read long description from README.rst. """ with open("README.rst", "r", encoding="utf-8") as readme: return readme.read() if __name__ == "__main__": setuptools.setup( name="traits-stubs", version="6.1.0", url="https://github.com/enthought/traits", author="Enthought", author_email="info@enthought.com", classifiers=[ c.strip() for c in """ Development Status :: 4 - Beta Intended Audience :: Developers Intended Audience :: Science/Research License :: OSI Approved :: BSD License Operating System :: MacOS :: MacOS X Operating System :: Microsoft :: Windows Operating System :: POSIX :: Linux Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering Topic :: Software Development Topic :: Software Development :: Libraries Topic :: Software Development :: User Interfaces Typing :: Typed """.splitlines() if len(c.strip()) > 0 ], description="Type annotations for the Traits package", long_description=get_long_description(), long_description_content_type="text/x-rst", download_url="https://pypi.python.org/pypi/traits-stubs", install_requires=["traits"], extras_require={"test": ["mypy"]}, packages=[ "traits-stubs", "traits_stubs_tests", "traits_stubs_tests.examples", ], package_data={"traits-stubs": ["./*.pyi", "./**/*.pyi"]}, license="BSD", python_requires=">=3.6", ) traits-6.3.2/traits-stubs/traits-stubs/000077500000000000000000000000001414270267200201455ustar00rootroot00000000000000traits-6.3.2/traits-stubs/traits-stubs/__init__.pyi000066400000000000000000000000001414270267200224150ustar00rootroot00000000000000traits-6.3.2/traits-stubs/traits-stubs/api.pyi000066400000000000000000000121501414270267200214400ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from .constants import ( ComparisonMode as ComparisonMode, DefaultValue as DefaultValue, TraitKind as TraitKind, ValidateTrait as ValidateTrait, NO_COMPARE as NO_COMPARE, OBJECT_IDENTITY_COMPARE as OBJECT_IDENTITY_COMPARE, RICH_COMPARE as RICH_COMPARE, ) from .traits import ( Color as Color, Default as Default, Font as Font, Property as Property, RGBColor as RGBColor, Trait as Trait ) from .ctrait import CTrait as CTrait from .has_traits import ( ABCHasStrictTraits as ABCHasStrictTraits, ABCHasTraits as ABCHasTraits, ABCMetaHasTraits as ABCMetaHasTraits, AbstractViewElement as AbstractViewElement, HasTraits as HasTraits, HasStrictTraits as HasStrictTraits, HasPrivateTraits as HasPrivateTraits, HasRequiredTraits as HasRequiredTraits, Interface as Interface, SingletonHasTraits as SingletonHasTraits, SingletonHasStrictTraits as SingletonHasStrictTraits, SingletonHasPrivateTraits as SingletonHasPrivateTraits, MetaHasTraits as MetaHasTraits, Vetoable as Vetoable, VetoableEvent as VetoableEvent, observe as observe, on_trait_change as on_trait_change, cached_property as cached_property, property_depends_on as property_depends_on, provides as provides, isinterface as isinterface, ) from .trait_types import ( Any as Any, Int as Int, Float as Float, Complex as Complex, Str as Str, Title as Title, Bytes as Bytes, Bool as Bool, CInt as CInt, CFloat as CFloat, CComplex as CComplex, CStr as CStr, CBytes as CBytes, CBool as CBool, String as String, Regex as Regex, Code as Code, HTML as HTML, Password as Password, Callable as Callable, This as This, self as self, Function as Function, Method as Method, Module as Module, Python as Python, ReadOnly as ReadOnly, Disallow as Disallow, Constant as Constant, Delegate as Delegate, DelegatesTo as DelegatesTo, PrototypedFrom as PrototypedFrom, Expression as Expression, PythonValue as PythonValue, File as File, Directory as Directory, Range as Range, Enum as Enum, Tuple as Tuple, List as List, CList as CList, PrefixList as PrefixList, Set as Set, CSet as CSet, Dict as Dict, Map as Map, PrefixMap as PrefixMap, Instance as Instance, AdaptedTo as AdaptedTo, AdaptsTo as AdaptsTo, Event as Event, Button as Button, ToolbarButton as ToolbarButton, Either as Either, Union as Union, Type as Type, Subclass as Subclass, Symbol as Symbol, WeakRef as WeakRef, Date as Date, Datetime as Datetime, Time as Time, Supports as Supports, ) # Deprecated TraitType subclasses and instances. from .trait_types import ( BaseUnicode as BaseUnicode, Unicode as Unicode, BaseCUnicode as BaseCUnicode, CUnicode as CUnicode, BaseLong as BaseLong, Long as Long, BaseCLong as BaseCLong, CLong as CLong, false as false, true as true, undefined as undefined, ListInt as ListInt, ListFloat as ListFloat, ListStr as ListStr, ListUnicode as ListUnicode, ListComplex as ListComplex, ListBool as ListBool, ListFunction as ListFunction, ListMethod as ListMethod, ListThis as ListThis, DictStrAny as DictStrAny, DictStrStr as DictStrStr, DictStrInt as DictStrInt, DictStrFloat as DictStrFloat, DictStrBool as DictStrBool, DictStrList as DictStrList, ) from .trait_types import ( BaseCallable as BaseCallable, BaseInt as BaseInt, BaseFloat as BaseFloat, BaseComplex as BaseComplex, BaseStr as BaseStr, BaseBytes as BaseBytes, BaseBool as BaseBool, BaseCInt as BaseCInt, BaseCFloat as BaseCFloat, BaseCComplex as BaseCComplex, BaseCStr as BaseCStr, BaseCBool as BaseCBool, BaseFile as BaseFile, BaseDirectory as BaseDirectory, BaseRange as BaseRange, BaseEnum as BaseEnum, BaseTuple as BaseTuple, BaseInstance as BaseInstance, ) from .trait_types import ( UUID as UUID, ValidatedTuple as ValidatedTuple ) from .base_trait_handler import BaseTraitHandler as BaseTraitHandler from .trait_handler import TraitHandler as TraitHandler from .trait_type import TraitType as TraitType from .trait_handlers import ( TraitCoerceType as TraitCoerceType, TraitCastType as TraitCastType, TraitInstance as TraitInstance, TraitFunction as TraitFunction, TraitEnum as TraitEnum, TraitPrefixList as TraitPrefixList, TraitMap as TraitMap, TraitPrefixMap as TraitPrefixMap, TraitCompound as TraitCompound, TraitList as TraitList, TraitDict as TraitDict, TraitTuple as TraitTuple, ) traits-6.3.2/traits-stubs/traits-stubs/base_trait_handler.pyi000066400000000000000000000006701414270267200245050ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! class BaseTraitHandler: ... traits-6.3.2/traits-stubs/traits-stubs/constants.pyi000066400000000000000000000032711414270267200227070ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from enum import IntEnum from typing import Any class TraitKind(IntEnum): trait: int = ... python: int = ... event: int = ... delegate: int = ... property: int = ... disallow: int = ... read_only: int = ... constant: int = ... generic: int = ... class ValidateTrait(IntEnum): type: int = ... instance: int = ... self_type: int = ... int_range: int = ... float_range: int = ... enum: int = ... map: int = ... complex: int = ... slow: int = ... tuple: int = ... prefix_map: int = ... coerce: int = ... cast: int = ... function: int = ... python: int = ... adapt: int = ... int: int = ... float: int = ... callable: int = ... class ComparisonMode(IntEnum): none: int = ... identity: int = ... equality: int = ... NO_COMPARE: Any OBJECT_IDENTITY_COMPARE: Any RICH_COMPARE: Any class DefaultValue(IntEnum): unspecified: int = ... constant: int = ... missing: int = ... object: int = ... list_copy: int = ... dict_copy: int = ... trait_list_object: int = ... trait_dict_object: int = ... callable_and_args: int = ... callable: int = ... trait_set_object: int = ... disallow: int = ... MAXIMUM_DEFAULT_VALUE_TYPE: Any default_value_map: Any traits-6.3.2/traits-stubs/traits-stubs/ctrait.pyi000066400000000000000000000031151414270267200221560ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from . import ctraits as ctraits from .constants import ComparisonMode as ComparisonMode, DefaultValue as DefaultValue, default_value_map as default_value_map from .trait_base import SequenceTypes as SequenceTypes, Undefined as Undefined from .trait_dict_object import TraitDictObject as TraitDictObject from .trait_list_object import TraitListObject as TraitListObject from .trait_set_object import TraitSetObject as TraitSetObject from typing import Any def __newobj__(cls, *args: Any): ... class CTrait(ctraits.cTrait): def __call__(self, *args: Any, **metadata: Any): ... @property def default(self): ... @property def default_kind(self): ... @property def trait_type(self): ... @property def inner_traits(self): ... @property def comparison_mode(self): ... @comparison_mode.setter def comparison_mode(self, value: Any) -> None: ... def is_trait_type(self, trait_type: Any): ... editor: Any = ... def get_editor(self): ... def get_help(self, full: bool = ...): ... def full_info(self, object: Any, name: Any, value: Any): ... def info(self): ... def as_ctrait(self): ... def __reduce_ex__(self, protocol: Any): ... traits-6.3.2/traits-stubs/traits-stubs/editor_factories.pyi000066400000000000000000000020341414270267200242140ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from typing import Any, Optional PasswordEditors: Any MultilineTextEditors: Any BytesEditors: Any SourceCodeEditor: Any HTMLTextEditor: Any PythonShellEditor: Any DateEditor: Any TimeEditor: Any logger: Any def password_editor(auto_set: bool = ..., enter_set: bool = ...): ... def multi_line_text_editor(auto_set: bool = ..., enter_set: bool = ...): ... def bytes_editor(auto_set: bool = ..., enter_set: bool = ..., encoding: Optional[Any] = ...): ... def code_editor(): ... def html_editor(): ... def shell_editor(): ... def time_editor(): ... def date_editor(): ... def datetime_editor(): ... def list_editor(trait: Any, handler: Any): ... traits-6.3.2/traits-stubs/traits-stubs/has_traits.pyi000066400000000000000000000174421414270267200230410ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import abc from .adaptation.adaptation_error import AdaptationError as AdaptationError from .constants import DefaultValue as DefaultValue, TraitKind as TraitKind from .ctrait import CTrait as CTrait, __newobj__ as __newobj__ from .ctraits import CHasTraits as CHasTraits from .trait_base import SequenceTypes as SequenceTypes, TraitsCache as TraitsCache, Undefined as Undefined, is_none as is_none, not_event as not_event, not_false as not_false from .trait_converters import check_trait as check_trait, mapped_trait_for as mapped_trait_for, trait_for as trait_for from .trait_errors import TraitError as TraitError from .trait_notifiers import ExtendedTraitChangeNotifyWrapper as ExtendedTraitChangeNotifyWrapper, FastUITraitChangeNotifyWrapper as FastUITraitChangeNotifyWrapper, NewTraitChangeNotifyWrapper as NewTraitChangeNotifyWrapper, StaticAnytraitChangeNotifyWrapper as StaticAnytraitChangeNotifyWrapper, StaticTraitChangeNotifyWrapper as StaticTraitChangeNotifyWrapper, TraitChangeNotifyWrapper as TraitChangeNotifyWrapper from .trait_types import Any as Any, Bool as Bool, Disallow as Disallow, Event as Event, Python as Python from .traits import ForwardProperty as ForwardProperty, Property as Property, Trait as Trait, generic_trait as generic_trait from .util.deprecated import deprecated as deprecated from typing import Optional, Any as _Any CHECK_INTERFACES: int class AbstractViewElement(abc.ABC): ... WrapperTypes: _Any BaseTraits: str ClassTraits: str PrefixTraits: str ListenerTraits: str ViewTraits: str InstanceTraits: str DefaultTraitsView: str CantHaveDefaultValue: _Any DeferredCopy: _Any extended_trait_pat: _Any any_trait: _Any def is_unbound_method_type(method: _Any): ... def get_delegate_pattern(name: _Any, trait: _Any): ... class _SimpleTest: value: _Any = ... def __init__(self, value: _Any) -> None: ... def __call__(self, test: _Any): ... class MetaHasTraits(type): def __new__(cls, class_name: _Any, bases: _Any, class_dict: _Any): ... @classmethod def add_listener(cls, listener: _Any, class_name: str = ...) -> None: ... @classmethod def remove_listener(cls, listener: _Any, class_name: str = ...) -> None: ... def update_traits_class_dict(class_name: _Any, bases: _Any, class_dict: _Any): ... def migrate_property(name: _Any, property: _Any, property_info: _Any, class_dict: _Any): ... def observe(expression: _Any, post_init: bool = ..., dispatch: str = ...): ... def on_trait_change(name: _Any, post_init: bool = ..., dispatch: str = ...): ... def cached_property(function: _Any): ... def property_depends_on(dependency: _Any, settable: bool = ..., flushable: bool = ...): ... def weak_arg(arg: _Any): ... class HasTraits(CHasTraits, metaclass=MetaHasTraits): _traits_cache__: _Any = ... wrappers: _Any = ... trait_added: _Any = ... trait_modified: _Any = ... @classmethod def add_class_trait(cls, name: _Any, *trait: _Any) -> None: ... @classmethod def set_trait_dispatch_handler(cls, name: _Any, klass: _Any, override: bool = ...) -> None: ... @classmethod def trait_subclasses(cls, all: bool = ...): ... def has_traits_interface(self, *interfaces: _Any): ... def __reduce_ex__(self, protocol: _Any): ... def trait_get(self, *names: _Any, **metadata: _Any): ... def get(self, *names: _Any, **metadata: _Any): ... def trait_set(self, trait_change_notify: bool = ..., **traits: _Any): ... def set(self, trait_change_notify: bool = ..., **traits: _Any): ... def trait_setq(self, **traits: _Any): ... def reset_traits(self, traits: Optional[_Any] = ..., **metadata: _Any): ... def copyable_trait_names(self, **metadata: _Any): ... def all_trait_names(self): ... def __dir__(self): ... def copy_traits(self, other: _Any, traits: Optional[_Any] = ..., memo: Optional[_Any] = ..., copy: Optional[_Any] = ..., **metadata: _Any): ... def clone_traits(self, traits: Optional[_Any] = ..., memo: Optional[_Any] = ..., copy: Optional[_Any] = ..., **metadata: _Any): ... def __deepcopy__(self, memo: _Any): ... def edit_traits(self, view: Optional[_Any] = ..., parent: Optional[_Any] = ..., kind: Optional[_Any] = ..., context: Optional[_Any] = ..., handler: Optional[_Any] = ..., id: str = ..., scrollable: Optional[_Any] = ..., **args: _Any): ... def trait_context(self): ... def trait_view(self, name: Optional[_Any] = ..., view_element: Optional[_Any] = ...): ... @classmethod def class_trait_view(cls, name: Optional[_Any] = ..., view_element: Optional[_Any] = ...): ... def default_traits_view(self): ... @classmethod def class_default_traits_view(cls): ... def trait_views(self, klass: Optional[_Any] = ...): ... def trait_view_elements(self): ... @classmethod def class_trait_view_elements(cls): ... def configure_traits(self, filename: Optional[_Any] = ..., view: Optional[_Any] = ..., kind: Optional[str] = ..., edit: bool = ..., context: Optional[_Any] = ..., handler: Optional[_Any] = ..., id: str = ..., scrollable: Optional[_Any] = ..., **args: _Any): ... def editable_traits(self): ... @classmethod def class_editable_traits(cls): ... def visible_traits(self): ... @classmethod def class_visible_traits(cls): ... def print_traits(self, show_help: bool = ..., **metadata: _Any) -> None: ... def observe(self, handler: _Any, expression: _Any, remove: bool = ..., dispatch: str = ...) -> None: ... def on_trait_change(self, handler: _Any, name: Optional[_Any] = ..., remove: bool = ..., dispatch: str = ..., priority: bool = ..., deferred: bool = ..., target: Optional[_Any] = ...) -> None: ... on_trait_event: _Any = ... def sync_trait(self, trait_name: _Any, object: _Any, alias: Optional[_Any] = ..., mutual: bool = ..., remove: bool = ...): ... def add_trait(self, name: _Any, *trait: _Any) -> None: ... def remove_trait(self, name: _Any): ... def trait(self, name: str, force: bool = ..., copy: bool = ...): ... def base_trait(self, name: _Any): ... def validate_trait(self, name: _Any, value: _Any): ... def traits(self, **metadata: _Any): ... @classmethod def class_traits(cls, **metadata: _Any): ... def trait_names(self, **metadata: _Any): ... @classmethod def class_trait_names(cls, **metadata: _Any): ... def __prefix_trait__(self, name: _Any, is_set: _Any): ... def add_trait_listener(self, object: _Any, prefix: str = ...) -> None: ... def remove_trait_listener(self, object: _Any, prefix: str = ...) -> None: ... class HasStrictTraits(HasTraits): ... class HasRequiredTraits(HasStrictTraits): def __init__(self, **traits: _Any) -> None: ... class HasPrivateTraits(HasTraits): __: _Any = ... class ABCMetaHasTraits(abc.ABCMeta, MetaHasTraits): ... class ABCHasTraits(HasTraits, metaclass=ABCMetaHasTraits): ... class ABCHasStrictTraits(ABCHasTraits): ... class SingletonHasTraits(HasTraits): def __new__(cls, *args: _Any, **traits: _Any): ... class SingletonHasStrictTraits(HasStrictTraits): def __new__(cls, *args: _Any, **traits: _Any): ... class SingletonHasPrivateTraits(HasPrivateTraits): def __new__(cls, *args: _Any, **traits: _Any): ... class Vetoable(HasStrictTraits): veto: _Any = ... VetoableEvent: _Any class MetaInterface(ABCMetaHasTraits): def __call__(self, adaptee: _Any, default: _Any = ...): ... class Interface(HasTraits, metaclass=MetaInterface): ... def provides(*protocols: _Any): ... def isinterface(klass: _Any): ... class ISerializable(Interface): ... traits-6.3.2/traits-stubs/traits-stubs/trait_handler.pyi000066400000000000000000000007711414270267200235150ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from .base_trait_handler import BaseTraitHandler class TraitHandler(BaseTraitHandler): ... traits-6.3.2/traits-stubs/traits-stubs/trait_handlers.pyi000066400000000000000000000042371414270267200237010ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from typing import ( Any as _Any, Callable as _CallableType, Dict as _Dict, Type as _Type, Union as _Union, ) from .trait_handler import TraitHandler class TraitCoerceType(TraitHandler): def __init__(self, atype: _Union[_Type, str] = ..., ) -> None: ... class TraitCastType(TraitCoerceType): ... class TraitInstance(TraitHandler): def __init__(self, aclass: _Union[_Type, str] = ..., allow_none: bool = ..., module: str = ..., ) -> None: ... class TraitFunction(TraitHandler): def __init__(self, afunc: _CallableType = ...) -> None: ... class TraitEnum(TraitHandler): def __init__(self, afunc: _CallableType = ...) -> None: ... class TraitPrefixList(TraitHandler): def __init__(self, *values: _Any) -> None: ... class TraitMap(TraitHandler): def __init__(self, map: _Dict = ...) -> None: ... class TraitPrefixMap(TraitMap): ... class TraitCompound(TraitHandler): def __init__(self, *handlers: _Any) -> None: ... class TraitTuple(TraitHandler): def __init__(self, *args: _Any) -> None: ... class TraitList(TraitHandler): def __init__(self, trait: _Any = ..., minlen: int = ..., maxlen: int = ..., has_items: bool = ..., ) -> None: ... class TraitDict(TraitHandler): def __init__(self, key_trait: _Any = ..., value_trait: _Any = ..., has_items: bool = ..., ) -> None: ... traits-6.3.2/traits-stubs/traits-stubs/trait_type.pyi000066400000000000000000000035161414270267200230610ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from typing import Any, Dict, Generic, Optional, Tuple, TypeVar from .base_trait_handler import BaseTraitHandler as BaseTraitHandler trait_types: Dict[str, int] _Accepts = TypeVar('_Accepts') _Stores = TypeVar('_Stores') class _TraitMixin(Generic[_Accepts, _Stores]): def __call__(self, *args, **kwagrs) -> _TraitMixin: ... def __get__(self, object: Any, type: Any) -> _Stores: ... def __set__(self, object: Any, value: _Accepts) -> None: ... _Trait = _TraitMixin() class _TraitType(BaseTraitHandler, Generic[_Accepts, _Stores]): default_value: _Stores = ... metadata: Dict[str, Any] = ... def __init__(self, default_value: _Stores = ..., **metadata: Any) -> None: ... def init(self) -> None: ... def get_default_value(self) -> Tuple[int, _Stores]: ... def clone(self, default_value: _Stores = ..., **metadata: Any) -> 'TraitType': ... def get_value(self, object: Any, name: str, trait: Optional[Any] = ...) -> _Stores: ... def set_value(self, object: Any, name: str, value: _Accepts) -> None: ... def __call__(self, *args: Any, **kw: Any): ... def as_ctrait(self): ... @classmethod def instantiate_and_get_ctrait(cls): ... def __getattr__(self, name: Any): ... def __get__(self, object: Any, type: Any) -> _Stores: ... def __set__(self, object: Any, value: _Accepts) -> None: ... TraitType = _TraitType[Any, Any] traits-6.3.2/traits-stubs/traits-stubs/trait_types.pyi000066400000000000000000000276771414270267200232620ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import datetime from pathlib import PurePath as _PurePath from typing import ( Any as _Any, Callable as _CallableType, Dict as _DictType, List as _ListType, Optional, Sequence as _Sequence, Set as _SetType, Type as _Type, TypeVar, Union as _Union, ) from uuid import UUID as _UUID from .trait_type import _TraitType SetTypes: _Any int_fast_validate: _Any float_fast_validate: _Any complex_fast_validate: _Any bool_fast_validate: _Any def default_text_editor(trait: _Any, type: Optional[_Any] = ...): ... _T = TypeVar("_T") _S = TypeVar("_S") _Trait = _Union[_TraitType[_S, _T], _Type[_TraitType[_S, _T]]] class Any(_TraitType[_Any, _Any]): def __init__( self, default_value: _Any = ..., *, factory: _CallableType = ..., args: tuple = ..., kw: dict = ..., **metadata: _Any, ) -> None: ... class _BaseInt(_TraitType[_T, int]): ... class BaseInt(_BaseInt[int]): ... class Int(BaseInt): ... class _BaseFloat(_TraitType[_T, float]): ... class BaseFloat(_BaseFloat[float]): ... class Float(BaseFloat): ... class _BaseComplex(_TraitType[_T, complex]): ... class BaseComplex(_BaseComplex[complex]): ... class Complex(BaseComplex): ... class _BaseStr(_TraitType[_T, str]): ... class BaseStr(_BaseStr[str]): ... class Str(BaseStr): ... class Title(Str): ... class _BaseBytes(_TraitType[_T, bytes]): ... class BaseBytes(_BaseBytes[bytes]): ... class Bytes(BaseBytes): ... class _BaseBool(_TraitType[_T, bool]): ... class BaseBool(_BaseBool[bool]): default_value: bool = ... class Bool(BaseBool): default_value: bool = ... class _BaseCInt(_BaseInt[_Any]): default_value: _Any = ... class BaseCInt(_BaseCInt): ... class CInt(_BaseCInt): ... class BaseCFloat(_BaseFloat[_Any]): ... class CFloat(BaseCFloat): ... class BaseCComplex(_BaseComplex[_Any]): ... class CComplex(BaseCComplex): ... class _BaseCStr(_BaseStr[_Any]): ... class BaseCStr(_BaseCStr): ... class CStr(_BaseCStr): ... class BaseCBytes(_BaseBytes[_Any]): ... class CBytes(BaseCBytes): ... class BaseCBool(_BaseBool[_Any]): ... class CBool(BaseCBool): ... class _String(_TraitType[_T, str]): ... class String(_String[str]): def __init__( self, value: str = ..., minlen: int = ..., maxlen: int = ..., regex: str = ..., **metadata: _Any ) -> None: ... class Regex(String): ... class Code(String): ... class HTML(String): ... class Password(String): ... _OptionalCallable = Optional[_CallableType[..., _Any]] class _BaseCallable(_TraitType[_OptionalCallable, _OptionalCallable]): ... class BaseCallable(_BaseCallable[_CallableType[..., _Any]]): ... class Callable(BaseCallable): ... class BaseType(_TraitType[_Any, _Any]): ... class This(BaseType): ... class self(This): ... class Function(_TraitType[_OptionalCallable, _OptionalCallable]): ... class Method(_TraitType[_OptionalCallable, _OptionalCallable]): ... class Module(_TraitType[_Any, _Any]): ... class Python(_TraitType[_Any, _Any]): ... class ReadOnly(_TraitType[_Any, _Any]): ... class Disallow(_TraitType[_Any, _Any]): ... class Constant(_TraitType[_Any, _Any]): ... class Delegate(_TraitType[_Any, _Any]): def __init__( self, delegate: str = ..., prefix: str = ..., modify: bool = ..., listenable: bool = ..., **metadata: _Any ) -> None: ... class DelegatesTo(Delegate): ... class PrototypedFrom(Delegate): ... class Expression(_TraitType[_Any, _Any]): ... class PythonValue(Any): ... class BaseFile(_TraitType[_Union[str, _PurePath], str]): def __init__( self, value: str = ..., filter: str = ..., auto_set: bool = ..., entries: int = ..., exists: bool = ..., **metadata: _Any ) -> None: ... class File(BaseFile): ... class BaseDirectory(_BaseStr): ... class Directory(BaseDirectory): ... # ----------------BaseRange--------------------- class _BaseRange(_TraitType[_T, _Union[int, float]]): def __init__( self, low: _Union[int, float, str] = ..., high: _Union[int, float, str] = ..., value: _Union[int, float, str] = ..., exclude_low: bool = ..., exclude_high: bool = ..., **metadata: _Any ) -> None: ... class BaseRange(_BaseRange[_Union[int, float]]): ... class Range(BaseRange): ... class _BaseEnum(_TraitType[_T, _Any]): def __init__( self, *args: _Any, **metadata: _Any, ) -> None: ... class BaseEnum(_BaseEnum[_Any]): ... class Enum(BaseEnum): ... class _BaseTuple(_TraitType[_T, tuple]): def __init__( self, *types: _Any, **metadata: _Any, ) -> None: ... class BaseTuple(_BaseTuple[tuple]): ... class Tuple(BaseTuple): ... class ValidatedTuple(BaseTuple): def __init__( self, *types: _Any, fvalidate: _OptionalCallable = ..., fvalidate_info: Optional[str] = ..., **metadata: _Any ) -> None: ... class _List(_TraitType[_Sequence[_S], _ListType[_T]]): def __init__( self, trait: _Union[_TraitType[_S, _T], _Type[_TraitType[_S, _T]]] = ..., value: _Sequence[_S] = [], minlen: int = ..., maxlen: int = ..., items: bool = ..., **metadata: _Any ) -> None: ... class List(_List[_S, _T]): ... class CList(_List[_S, _T]): ... class PrefixList(BaseStr): def __init__( self, values: _Sequence[str], **metadata: _Any, ) -> None: ... class _Set(_TraitType[_SetType[_S], _SetType[_T]]): def __init__( self, trait: _Union[_TraitType[_S, _T], _Type[_TraitType[_S, _T]]] = ..., value: _Sequence[_S] = ..., items: bool = ..., **metadata: _Any ) -> None: ... class Set(_Set[_S, _T]): ... class CSet(Set): ... class _Dict(_TraitType[_DictType[_S, _T], _DictType[_S, _T]]): def __init__( self, key_trait: _Union[ _TraitType[_S, _T], _Type[_TraitType[_S, _T]]] = ..., value_trait: _Union[ _TraitType[_S, _T], _Type[_TraitType[_S, _T]]] = ..., value: dict = ..., items: bool = ..., **metadata: _Any ) -> None: ... class Dict(_Dict[_S, _T]): ... class _Map(_TraitType[_S, _T]): def __init__( self, map: _DictType[_S, _T], **metadata: _Any ) -> None: ... class Map(_Map): ... class _PrefixMap(_TraitType[_S, _T]): def __init__( self, map: _DictType[_S, _T], **metadata: _Any ) -> None: ... class PrefixMap(_PrefixMap): ... class _BaseClass(_TraitType[_Union[_T, str, None], _Union[_T, str, None]]): ... class BaseClass(_BaseClass[_Type]): ... class _BaseInstance(_BaseClass[_T]): # simplified signature def __init__( self, klass: _T, *args, **metadata: _Any, ) -> None: ... class BaseInstance(_BaseInstance[_Any]): ... class Instance(_BaseInstance[_Any]): ... class Supports(Instance): ... class AdaptsTo(Supports): ... class Type(BaseClass): def __init__( self, value: Optional[_Type] = ..., klass: Optional[_Union[_Type, str]] = ..., allow_none: bool = ..., **metadata: _Any ) -> None: ... class Subclass(Type): ... class Event(_TraitType[_Any, _Any]): ... class Button(Event): def __init__( self, label: str = ..., image: _Any = ..., style: str = ..., values_trait: str = ..., orientation: str = ..., width_padding: int = ..., height_padding: int = ..., view: Optional[_Any] = ..., **metadata: _Any ) -> None: ... class ToolbarButton(Button): def __init__( self, label: str = ..., image: _Any = ..., style: str = ..., orientation: str = ..., width_padding: int = ..., height_padding: int = ..., **metadata: _Any ) -> None: ... class Either(_TraitType[_Any, _Any]): def __init__( self, *traits: _Any, **metadata: _Any ) -> None: ... class Union(_TraitType[_Any, _Any]): def __init__( self, *traits: _Any, **metadata: _Any ) -> None: ... class Symbol(_TraitType[_Any, _Any]): ... class UUID(_TraitType[_Union[str, _UUID], _UUID]): def __init__( self, can_init: bool = ..., **metadata: _Any ) -> None: ... class WeakRef(Instance): def __init__( self, klass: _Any = ..., allow_none: bool = ..., adapt: str = ..., **metadata: _Any ) -> None: ... _OptionalDate = Optional[datetime.date] class Date(_TraitType[_OptionalDate, _OptionalDate]): def __init__( self, default_value: datetime.date = ..., *, allow_datetime: bool = ..., allow_none: bool = ..., **metadata: _Any, ) -> None: ... _OptionalDatetime = Optional[datetime.datetime] class Datetime(_TraitType[_OptionalDatetime, _OptionalDatetime]): def __init__( self, default_value: datetime.datetime = ..., *, allow_none: bool = ..., **metadata: _Any, ) -> None: ... _OptionalTime = Optional[datetime.time] class Time(_TraitType[_OptionalTime, _OptionalTime]): def __init__( self, default_value: datetime.time = ..., *, allow_none: bool = ..., **metadata: _Any, ) -> None: ... class AdaptedTo(Supports): ... class BaseUnicode(BaseStr): ... class Unicode(Str): ... class BaseCUnicode(BaseStr): ... class CUnicode(CStr): ... class BaseLong(BaseInt): ... class Long(Int): ... class BaseCLong(BaseCInt): ... class CLong(CInt): ... class false(Bool): ... class true(Bool): ... undefined = _Any class ListInt(_List[int, int]): ... class ListFloat(_List[float, float]): ... class _ListStr(_List[str, str]): ... class ListStr(_ListStr): ... class ListUnicode(_ListStr): ... class ListComplex(_List[complex, complex]): ... class ListBool(_List[bool, bool]): ... class ListFunction(_List[_CallableType, _CallableType]): ... class ListMethod(_List[_CallableType, _CallableType]): ... class ListThis(_List[_CallableType, _CallableType]): ... class DictStrAny(_Dict[str, _Any]): ... class DictStrStr(_Dict[str, str]): ... class DictStrInt(_Dict[str, int]): ... class DictStrFloat(_Dict[str, float]): ... class DictStrBool(_Dict[str, bool]): ... class DictStrList(_Dict[str, list]): ... traits-6.3.2/traits-stubs/traits-stubs/traits.pyi000066400000000000000000000033551414270267200222040ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from typing import ( Any as _Any, Optional, Callable as _CallableType, Dict as _DictType, ) NoneType: _Any ConstantTypes: _Any PythonTypes: _Any CallableTypes: _Any TraitTypes: _Any DefaultValues: _Any class _InstanceArgs: def __init__(self, factory: _Any, args: _Any, kw: _Any) -> None: ... class Default: default_value: _Any = ... def __init__(self, func: Optional[_Any] = ..., args: _Any = ..., kw: Optional[_Any] = ...) -> None: ... def Trait(*value_type: _Any, **metadata: _DictType[str, _Any]): ... def Property(fget: Optional[_CallableType] = ..., fset: Optional[_CallableType] = ..., fvalidate: Optional[_CallableType] = ..., force: bool = ..., handler: Optional[_CallableType] = ..., trait: Optional[_Any] = ..., **metadata: _Any) -> _Any: ... class ForwardProperty: metadata: _Any = ... validate: _Any = ... handler: _Any = ... def __init__(self, metadata: _Any, validate: Optional[_Any] = ..., handler: Optional[_Any] = ...) -> None: ... generic_trait: _Any def Color(*args: _Any, **metadata: _DictType[str, _Any]): ... def RGBColor(*args: _Any, **metadata: _DictType[str, _Any]): ... def Font(*args: _Any, **metadata: _DictType[str, _Any]): ... traits-6.3.2/traits-stubs/traits_stubs_tests/000077500000000000000000000000001414270267200214515ustar00rootroot00000000000000traits-6.3.2/traits-stubs/traits_stubs_tests/__init__.py000066400000000000000000000000001414270267200235500ustar00rootroot00000000000000traits-6.3.2/traits-stubs/traits_stubs_tests/examples/000077500000000000000000000000001414270267200232675ustar00rootroot00000000000000traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Any.py000066400000000000000000000021611414270267200243700ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, Any, Instance, Int class Test(HasTraits): i = Any() obj = Test() obj.i = "5" obj.i = 5 obj.i = 5.5 obj.var = {"a": 5, "b": 6} obj.var = {"a": 5.5, "b": 6} obj.var = {"a": 5, "b": None, "c": ""} obj.var = [] obj.var = [1, 2, 3] obj.var = [1.1] obj.var = [1.1, 2, 3.3] obj.var = '' obj.var = "5" obj.var = 5 obj.var = False obj.var = 5.5 obj.var = 5 + 4j obj.var = True obj.var = [1, 2, "3"] obj.var = None obj.var = ['1'] class Test2(HasTraits): i = Any(default_value="234") class Test3(HasTraits): i = Any(default_value=234) class Foo: pass class Superclass(HasTraits): x = Any() class Subclass(Superclass): x = Instance(Foo) # E: assignment y = Int() traits-6.3.2/traits-stubs/traits_stubs_tests/examples/BaseClass.py000066400000000000000000000013601414270267200255010ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, BaseInstance class Animal: pass class Goldfish(Animal): pass class Leprechaun: pass class Test(HasTraits): animal = BaseInstance("Animal") animal2 = BaseInstance(Animal) t = Test() t.animal = Goldfish() t.animal = Leprechaun() t.animal = None t.animal = Goldfish t.animal = "sdf" traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Bool.py000066400000000000000000000012261414270267200245350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import Bool, HasTraits class Test(HasTraits): var = Bool() obj = Test() obj.var = "5" # E: assignment obj.var = 5 # E: assignment obj.var = False obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True traits-6.3.2/traits-stubs/traits_stubs_tests/examples/CInt.py000066400000000000000000000012601414270267200244750ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, BaseCInt class TestClass1(HasTraits): i = BaseCInt() o = TestClass1() o.i = "5" o.i = 5 o.i = 5.5 class Test(HasTraits): i = BaseCInt(default_value="234") # E: arg-type class Test2(HasTraits): i = BaseCInt(default_value=234) traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Callable.py000066400000000000000000000014371414270267200253450ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from math import pow from traits.api import HasTraits, Callable class Test(HasTraits): var = Callable() obj = Test() obj.var = pow obj.var = None obj.var = "someuuid" # E: assignment obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = (True,) # E: assignment traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Complex.py000066400000000000000000000012301414270267200252440ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import Complex, HasTraits class Test(HasTraits): var = Complex() obj = Test() obj.var = "5" # E: assignment obj.var = 5 obj.var = 5.5 obj.var = 5 + 4j class Test2(HasTraits): var = Complex(default_value="sdf") # E: arg-type traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Date.py000066400000000000000000000014221414270267200245150ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import datetime from traits.api import HasTraits, Date, Int class TestClass(HasTraits): t = Date() x = Int() obj = TestClass() obj.t = datetime.datetime.now().date() obj.t = datetime.datetime.now() obj.t = None obj.t = datetime.datetime.now().time() # E: assignment obj.t = "sometime-string" # E: assignment obj.t = 9 # E: assignment obj.t = [] # E: assignment traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Datetime.py000066400000000000000000000013241414270267200253750ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import datetime from traits.api import Datetime, HasTraits class TestClass(HasTraits): t = Datetime() obj = TestClass() obj.t = "sometime-string" # E: assignment obj.t = datetime.datetime.now() obj.t = 9 # E: assignment obj.t = [] # E: assignment obj.t = datetime.datetime.now().date() # E: assignment traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Dict.py000066400000000000000000000020061414270267200245220ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import Dict, HasTraits, Str, Any class Test(HasTraits): var = Dict(Str(), Any()) obj = Test() obj.var = {"a": 5, "b": None, "c": ""} obj.var = [] # E: assignment obj.var = [1, 2, 3] # E: assignment obj.var = [1.1] # E: assignment obj.var = [1.1, 2, 3.3] # E: assignment obj.var = '' # E: assignment obj.var = "5" # E: assignment obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = [1, 2, "3"] # E: assignment obj.var = None # E: assignment obj.var = ['1'] # E: assignment traits-6.3.2/traits-stubs/traits_stubs_tests/examples/DictStrAny.py000066400000000000000000000017741414270267200256760ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import DictStrAny, HasTraits class Test(HasTraits): var = DictStrAny() obj = Test() obj.var = {"a": 5, "b": None, "c": ""} obj.var = [] # E: assignment obj.var = [1, 2, 3] # E: assignment obj.var = [1.1] # E: assignment obj.var = [1.1, 2, 3.3] # E: assignment obj.var = '' # E: assignment obj.var = "5" # E: assignment obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = [1, 2, "3"] # E: assignment obj.var = None # E: assignment obj.var = ['1'] # E: assignment traits-6.3.2/traits-stubs/traits_stubs_tests/examples/DictStrFloat.py000066400000000000000000000021111414270267200261760ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import DictStrFloat, HasTraits class Test(HasTraits): var = DictStrFloat() obj = Test() obj.var = {"a": 5, "b": 6} obj.var = {"a": 5.5, "b": 6} obj.var = {"a": 5, "b": None, "c": ""} # E: dict-item obj.var = [] # E: assignment obj.var = [1, 2, 3] # E: assignment obj.var = [1.1] # E: assignment obj.var = [1.1, 2, 3.3] # E: assignment obj.var = '' # E: assignment obj.var = "5" # E: assignment obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = [1, 2, "3"] # E: assignment obj.var = None # E: assignment obj.var = ['1'] # E: assignment traits-6.3.2/traits-stubs/traits_stubs_tests/examples/DictStrInt.py000066400000000000000000000021251414270267200256700ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import DictStrInt, HasTraits class Test(HasTraits): var = DictStrInt() obj = Test() obj.var = {"a": 5, "b": 6} obj.var = {"a": 5, "b": 6.6} # E: dict-item obj.var = {"a": 5, "b": None, "c": ""} # E: dict-item obj.var = [] # E: assignment obj.var = [1, 2, 3] # E: assignment obj.var = [1.1] # E: assignment obj.var = [1.1, 2, 3.3] # E: assignment obj.var = '' # E: assignment obj.var = "5" # E: assignment obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = [1, 2, "3"] # E: assignment obj.var = None # E: assignment obj.var = ['1'] # E: assignment traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Enum.py000066400000000000000000000010001414270267200245340ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import Enum, HasTraits class TestClass(HasTraits): en = Enum("foo", "bar", "baz") traits-6.3.2/traits-stubs/traits_stubs_tests/examples/File.py000066400000000000000000000016261414270267200245250ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from pathlib import Path, PosixPath from traits.api import HasTraits, BaseFile, File class Test(HasTraits): var = BaseFile() var2 = File() obj = Test() obj.var = Path('/tmp') obj.var = PosixPath('/tmp') obj.var = "someuuid" obj.var2 = Path('/tmp') obj.var2 = PosixPath('/tmp') obj.var2 = "someuuid" obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = (True,) # E: assignment traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Float.py000066400000000000000000000010431414270267200247040ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import Float, HasTraits class Test(HasTraits): i = Float() o = Test() o.i = "5" # E: assignment o.i = 5 o.i = 5.5 traits-6.3.2/traits-stubs/traits_stubs_tests/examples/HasStrictTraits.py000066400000000000000000000012351414270267200267350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import Event, HasStrictTraits, observe class Person(HasStrictTraits): conductor = Event() @observe("conductor") def talk(self, event): pass def sing(event): pass person = Person() person.observe(sing, "conductor") traits-6.3.2/traits-stubs/traits_stubs_tests/examples/HasTraits.py000066400000000000000000000012211414270267200255370ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import Event, HasTraits, observe class Person(HasTraits): conductor = Event() @observe("conductor") def talk(self, event): pass def sing(event): pass person = Person() person.observe(sing, "conductor") traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Instance.py000066400000000000000000000025621414270267200254120ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, Instance, Str class Fruit: info = Str("good for you") def __init__(self, info="good for you", **traits): super().__init__(info=info, **traits) class Orange(Fruit): pass class Pizza: pass def fruit_factory(info, other_stuff): return Fruit(info=info) class TestClass(HasTraits): itm = Instance(Fruit) itm_args_kw = Instance(Fruit, ('different info',), {'another_trait': 3}) itm_args = Instance(Fruit, ('different info',)) itm_kw = Instance(Fruit, {'info': 'different info'}) itm_factory = Instance(Fruit, fruit_factory) itm_factory_args = Instance(Fruit, fruit_factory, ('different info',), ) itm_factory_args_kw = Instance( Fruit, fruit_factory, ('different info',), {'other_stuff': 3}, ) itm_factory_kw = Instance( Fruit, fruit_factory, {'other_stuff': 3}, ) obj = TestClass() obj.itm = Orange() obj.itm = Pizza() traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Int.py000066400000000000000000000020471414270267200243760ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, Int class Test(HasTraits): i = Int() j = Int(default_value="234") # E: arg-type k = Int(default_value=234, something="else") o = Test() o.i = 5 o.i = "5" # E: assignment o.i = 5.5 # E: assignment o.i = 5.5 + 5 # E: assignment o.i = str(5) # E: assignment o.i = None # E: assignment # Test subclassing Int class Digit(Int): def validate(self, object, name, value): if isinstance(value, int) and 0 <= value <= 9: return value self.error(object, name, value) class TestClass2(HasTraits): i = Digit() obj = TestClass2() obj.i = 5 obj.i = "5" # E: assignment traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Interface.py000066400000000000000000000012671414270267200255470ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import Float, HasTraits, Interface, provides, Str, Tuple class IHasName(Interface): name = Str() @provides(IHasName) class NamedColor(HasTraits): name = Str() rgb = Tuple(Float, Float, Float) named_color = NamedColor(name="green", rgb=(0.0, 1.0, 0.0)) traits-6.3.2/traits-stubs/traits_stubs_tests/examples/List.py000066400000000000000000000023531414270267200245570ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, Int, List, Any class Test(HasTraits): var = List(Int()) obj = Test() obj.var = "5" # E: assignment obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = [1.1, 2, 3.3] # E: list-item obj.var = [1, 2, "3"] # E: list-item obj.var = None # E: assignment obj.var = [1, 2, 3] class TestAnyList(HasTraits): var = List(Any()) obj = TestAnyList() obj.var = "5" obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = [1.1, 2, 3.3] obj.var = [1, 2, "3"] obj.var = None # E: assignment obj.var = [1, 2, 3] class TestPlainList(HasTraits): var = List() # E: var-annotated traits-6.3.2/traits-stubs/traits_stubs_tests/examples/ListBool.py000066400000000000000000000020021414270267200253620ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import ListBool, HasTraits class Test(HasTraits): var = ListBool() obj = Test() obj.var = [] obj.var = [True] obj.var = [False] obj.var = [3 + 5j] # E: list-item obj.var = [1, 2, 3] # E: list-item obj.var = [1.1] # E: list-item obj.var = [1.1, 2, 3.3] # E: list-item obj.var = '' # E: assignment obj.var = "5" # E: assignment obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = [1, 2, "3"] # E: list-item obj.var = None # E: assignment obj.var = ['1'] # E: list-item traits-6.3.2/traits-stubs/traits_stubs_tests/examples/ListComplex.py000066400000000000000000000016451414270267200261120ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import ListComplex, HasTraits class Test(HasTraits): var = ListComplex() obj = Test() obj.var = [] obj.var = [3 + 5j] obj.var = [1, 2, 3] obj.var = [1.1] obj.var = [1.1, 2, 3.3] obj.var = '' # E: assignment obj.var = "5" # E: assignment obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = [1, 2, "3"] # E: list-item obj.var = None # E: assignment obj.var = ['1'] # E: list-item traits-6.3.2/traits-stubs/traits_stubs_tests/examples/ListFloat.py000066400000000000000000000016101414270267200255400ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import ListFloat, HasTraits class Test(HasTraits): var = ListFloat() obj = Test() obj.var = [] obj.var = [1] obj.var = [1.1] obj.var = [1.1, 2, 3.3] obj.var = '' # E: assignment obj.var = "5" # E: assignment obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = [1, 2, "3"] # E: list-item obj.var = None # E: assignment obj.var = ['1'] # E: list-item traits-6.3.2/traits-stubs/traits_stubs_tests/examples/ListInt.py000066400000000000000000000016521414270267200252330ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import ListInt, HasTraits class Test(HasTraits): var = ListInt() obj = Test() obj.var = [] obj.var = [1, 2, 3] obj.var = [1.1] # E: list-item obj.var = [1.1, 2, 3.3] # E: list-item obj.var = '' # E: assignment obj.var = "5" # E: assignment obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = [1, 2, "3"] # E: list-item obj.var = None # E: assignment obj.var = ['1'] # E: list-item traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Map.py000066400000000000000000000011631414270267200243570ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, Map class Person(HasTraits): married = Map({'yes': 1, 'no': 0}, default_value="yes") married_2 = Map([], default_value="yes") # E: arg-type p = Person() p.married = "yes" traits-6.3.2/traits-stubs/traits_stubs_tests/examples/PrefixList.py000066400000000000000000000011251414270267200257310ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, PrefixList class Person(HasTraits): atr1 = PrefixList(('yes', 'no')) atr2 = PrefixList(['yes', 'no']) p = Person() p.atr1 = 5 # E: assignment traits-6.3.2/traits-stubs/traits_stubs_tests/examples/PrefixMap.py000066400000000000000000000012031414270267200255300ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, PrefixMap class Person(HasTraits): married = PrefixMap({'yes': 1, 'no': 0}, default_value="yes") married_2 = PrefixMap([], default_value="yes") # E: arg-type p = Person() p.married = "y" traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Property.py000066400000000000000000000011731414270267200254670ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, Property, Float, Int class TestClass(HasTraits): i = Int() prop1 = Property(Float) prop2 = Property(i) prop3 = Property(3) # E: arg-type prop4 = Property(depends_on='i') traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Range.py000066400000000000000000000011011414270267200246660ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, Range class Test(HasTraits): var = Range(low=[]) # E: arg-type var2 = Range(low="3") var3 = Range(low=3) obj = Test() traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Set.py000066400000000000000000000014501414270267200243740ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, Set, Int class Test(HasTraits): var = Set(trait=Int()) obj = Test() obj.var = "5" # E: assignment obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = [1, 2, 3] # E: assignment obj.var = [1, 2, "3"] # E: assignment obj.var = {1, 2, 3} traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Str.py000066400000000000000000000011731414270267200244130ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, Str class Test(HasTraits): i = Str() o = Test() o.i = "5" o.i = 5 # E: assignment o.i = 5.5 # E: assignment class Test2(HasTraits): var = Str(default_value=None) # E: arg-type traits-6.3.2/traits-stubs/traits_stubs_tests/examples/String.py000066400000000000000000000015041414270267200251070ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, String class Test(HasTraits): var = String() obj = Test() obj.var = "5" obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment class Test2(HasTraits): var = String(minlen=5, something="else", regex=r"5") class Test3(HasTraits): var = String(minlen="5") # E: arg-type traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Time.py000066400000000000000000000013141414270267200245360ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import datetime from traits.api import HasTraits, Time class TestClass(HasTraits): t = Time() obj = TestClass() obj.t = datetime.time(11, 12, 13) obj.t = "sometime-string" # E: assignment obj.t = datetime.datetime(2020, 1, 1) # E: assignment obj.t = 9 # E: assignment obj.t = [] # E: assignment traits-6.3.2/traits-stubs/traits_stubs_tests/examples/TraitDict.py000066400000000000000000000010421414270267200255250ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, Trait, TraitDict class WorkoutClass(HasTraits): member_weights = Trait({}, TraitDict(str, float)) traits-6.3.2/traits-stubs/traits_stubs_tests/examples/Tuple.py000066400000000000000000000013241414270267200247320ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, Tuple class Test(HasTraits): var = Tuple(1, 2, 3) obj = Test() obj.var = "5" # E: assignment obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = (True,) traits-6.3.2/traits-stubs/traits_stubs_tests/examples/UUID.py000066400000000000000000000013661414270267200244150ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import uuid from traits.api import HasTraits, UUID class Test(HasTraits): var = UUID() obj = Test() obj.var = uuid.UUID() obj.var = "someuuid" obj.var = 5 # E: assignment obj.var = False # E: assignment obj.var = 5.5 # E: assignment obj.var = 5 + 4j # E: assignment obj.var = True # E: assignment obj.var = (True,) # E: assignment traits-6.3.2/traits-stubs/traits_stubs_tests/examples/WeakRef.py000066400000000000000000000011111414270267200251570ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import WeakRef, HasTraits class Fruit: pass class TestClass(HasTraits): atr = WeakRef(Fruit) atr2 = WeakRef(Fruit()) atr3 = WeakRef("Fruit") traits-6.3.2/traits-stubs/traits_stubs_tests/examples/__init__.py000066400000000000000000000000001414270267200253660ustar00rootroot00000000000000traits-6.3.2/traits-stubs/traits_stubs_tests/test_all.py000066400000000000000000000025751414270267200236430ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from pathlib import Path from unittest import TestCase from traits.testing.optional_dependencies import ( pkg_resources, requires_mypy, requires_pkg_resources, ) from traits_stubs_tests.util import MypyAssertions @requires_mypy class TestAnnotations(TestCase, MypyAssertions): @requires_pkg_resources def test_all(self, filename_suffix=""): """ Run mypy for all files contained in traits_stubs_tests/examples directory. Lines with expected errors are marked inside these files. Any mismatch will raise an assertion error. Parameters ---------- filename_suffix: str Optional filename suffix filter. """ examples_dir = Path(pkg_resources.resource_filename( 'traits_stubs_tests', 'examples')) for file_path in examples_dir.glob("*{}.py".format(filename_suffix)): with self.subTest(file_path=file_path): self.assertRaisesMypyError(file_path) traits-6.3.2/traits-stubs/traits_stubs_tests/util.py000066400000000000000000000116761414270267200230130ustar00rootroot00000000000000# (C) Copyright 2020-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from collections import defaultdict import os import shutil import re import tempfile def parse_py_file(filepath): """ This function parses a python file that have been annotated with error codes that mypy may generate and returns a mapping from line number to a list of those codes. File annotations may be done by adding a comment to the line that begins with "E:" followed by a list of comma separated error codes Eg:: obj.var = False # E: assignment, list-item Parameters ---------- filepath : pathlib.Path The filepath of the python file Returns ------- line_err_map : dict A mapping from line number to the list of error codes on that line """ line_err_map = {} regex = re.compile(r'#[\s]*E:[\s]* (.*)') with filepath.open(encoding="utf-8") as fp: line_count = 0 lines = fp.readlines() for line in lines: line_count += 1 match = regex.search(line) if match: err_codes = match.group(1) list_err_codes = err_codes.replace(' ', '').split(',') line_err_map[line_count] = list_err_codes return line_err_map def parse_mypy_output(output_str): """ Parses the output generated by mypy and returns a dict of mappings from line number to a list of error codes Parameters ---------- output_str: str The output generated by mypy on stdout. Returns ------- line_errors_dict : dict A mapping from line number to a list of error codes """ line_errors_dict = defaultdict(set) error_line_regex = re.compile(r"([0-9]*): error:.*\[(.*)\]") for line in output_str.split("\n"): match = error_line_regex.search(line) if match: line_no_str, err_code = match.groups() line_errors_dict[int(line_no_str)].add(err_code) return line_errors_dict def run_mypy(filepath): """ Runs mypy on the file using mypy api and returns the generated output. Parameters ---------- filepath : pathlib.path The path to of the file to run mypy on. Returns ------- normal_report : str Output on stdout error_report : str Output on stderr exit_status : int The exit status """ # Local import to make it easier to skip tests if mypy is not in # the environment. from mypy import api as mypy_api # Need to use tempdir since mypy complains that: # "site-packages is in PYTHONPATH. Please change directory so it is not." filepath = str(filepath) with tempfile.TemporaryDirectory() as tempdir: dest_filename = os.path.basename(filepath) dest = shutil.copyfile(filepath, os.path.join(tempdir, dest_filename)) normal_report, error_report, exit_status = mypy_api.run( [dest, '--show-error-code']) return normal_report, error_report, exit_status class MypyAssertions: def assertNoMypyError(self, filepath): """ Raises an AssertionError if mypy raises any error. Parameters ---------- filepath : pathlib.Path The path to the file to run mypy on. Returns ------- None Raises ------ AssertionError If my generates any error """ normal_report, error_report, exit_status = run_mypy(filepath) if exit_status != 0: s = "\n{}\n{}".format(str(filepath), normal_report) raise AssertionError(s) def assertRaisesMypyError(self, filepath): """ Raises an AssertionError if the errors raised by mypy are different from the expected errors annotated in the file. Any difference from expected errors, whether more or less errors will raise an Assertion Error Parameters ---------- filepath : pathlib.Path The path to the file to run mypy on. Returns ------- None Raises ------ AssertionError If errors generated by mypy are different from expected errors. """ line_error_map = parse_py_file(filepath) normal_report, error_report, exit_status = run_mypy(filepath) parsed_mypy_output = parse_mypy_output(normal_report) for line, error_codes in parsed_mypy_output.items(): if line not in line_error_map or sorted( line_error_map[line]) != sorted(list(error_codes)): s = "\n{}\n{}".format(str(filepath), normal_report) raise AssertionError(s) traits-6.3.2/traits/000077500000000000000000000000001414270267200143435ustar00rootroot00000000000000traits-6.3.2/traits/__init__.py000066400000000000000000000014571414270267200164630ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! try: from traits.version import version as __version__ except ImportError: # If we get here, we're using a source tree that hasn't been created via # the setup script. That likely also means that the ctraits extension # hasn't been built, so this isn't a viable Traits installation. OTOH, it # can be useful if a simple "import traits" doesn't actually fail. __version__ = "unknown" traits-6.3.2/traits/adaptation/000077500000000000000000000000001414270267200164675ustar00rootroot00000000000000traits-6.3.2/traits/adaptation/__init__.py000066400000000000000000000006651414270267200206070ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Adaptation package. """ traits-6.3.2/traits/adaptation/adaptation_error.py000066400000000000000000000011261414270267200223760ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Exception raised when a requested adaptation is not possible. """ class AdaptationError(TypeError): """ Exception raised when a requested adaptation is not possible. """ pass traits-6.3.2/traits/adaptation/adaptation_manager.py000066400000000000000000000361571414270267200226730ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Manages all registered adaptations. """ from heapq import heappop, heappush import inspect import itertools import functools from traits.adaptation.adaptation_error import AdaptationError from traits.has_traits import HasTraits from traits.trait_types import Dict, List, Str def no_adapter_necessary(adaptee): """ An adapter factory used to register that a protocol provides another. See 'register_provides' for details. """ return adaptee class AdaptationManager(HasTraits): """ Manages all registered adaptations. """ #### 'AdaptationManager' class protocol ################################### @staticmethod def mro_distance_to_protocol(from_type, to_protocol): """ Return the distance in the MRO from 'from_type' to 'to_protocol'. If `from_type` provides `to_protocol`, returns the distance between `from_type` and the super-most class in the MRO hierarchy providing `to_protocol` (that's where the protocol was provided in the first place). If `from_type` does not provide `to_protocol`, return None. """ if not AdaptationManager.provides_protocol(from_type, to_protocol): return None # We walk up the MRO hierarchy until the point where the `to_protocol` # is *no longer* provided. When we reach that point we know that the # previous class in the MRO is the one that provided the protocol in # the first place (e.g., the first super-class implementing an # interface). supertypes = inspect.getmro(from_type)[1:] distance = 0 for t in supertypes: if AdaptationManager.provides_protocol(t, to_protocol): distance += 1 # We have reached the point in the MRO where the protocol is no # longer provided. else: break return distance @staticmethod def provides_protocol(type_, protocol): """ Does the given type provide (i.e implement) a given protocol? Parameters ---------- type_ Python 'type'. protocol Either a regular Python class or a traits Interface. Returns ------- result : bool True if the object provides the protocol, otherwise False. """ return issubclass(type_, protocol) #### 'AdaptationManager' protocol ######################################### def adapt(self, adaptee, to_protocol, default=AdaptationError): """ Attempt to adapt an object to a given protocol. If *adaptee* already provides (i.e. implements) the given protocol then it is simply returned unchanged. Otherwise, we try to build a chain of adapters that adapt *adaptee* to *to_protocol*. If no such adaptation is possible then either an AdaptationError is raised, or *default* is returned. Parameters ---------- adaptee : object The object that we want to adapt. to_protocol : type or interface The protocol that the want to adapt *adaptee* to. default : object, optional Object to return if no adaptation is possible. If no default is provided, and adaptation fails, an ``AdaptationError`` is raised. Returns ------- adapted_object : to_protocol The original adaptee adapted to the target protocol. Raises ------ AdaptationError If adaptation is not possible, and no default is given. """ # If the object already provides the given protocol then it is # simply returned. if self.provides_protocol(type(adaptee), to_protocol): result = adaptee # Otherwise, try adapting the object. else: result = self._adapt(adaptee, to_protocol) if result is None: if default is AdaptationError: raise AdaptationError( "Could not adapt %r to %r" % (adaptee, to_protocol) ) else: result = default return result def register_offer(self, offer): """ Register an offer to adapt from one protocol to another. """ offers = self._adaptation_offers.setdefault( offer.from_protocol_name, [] ) offers.append(offer) def register_factory(self, factory, from_protocol, to_protocol): """ Register an adapter factory. This is a simply a convenience method that creates and registers an 'AdaptationOffer' from the given arguments. """ from traits.adaptation.adaptation_offer import AdaptationOffer self.register_offer( AdaptationOffer( factory=factory, from_protocol=from_protocol, to_protocol=to_protocol, ) ) def register_provides(self, provider_protocol, protocol): """ Register that a protocol provides another. """ self.register_factory( no_adapter_necessary, provider_protocol, protocol ) def supports_protocol(self, obj, protocol): """ Does the object support a given protocol? An object "supports" a protocol if either it "provides" it directly, or it can be adapted to it. """ return self.adapt(obj, protocol, None) is not None #### Private protocol ##################################################### #: All registered adaptation offers. #: Keys are the type name of the offer's from_protocol; values are a #: list of adaptation offers. _adaptation_offers = Dict(Str, List) def _adapt(self, adaptee, to_protocol): """ Returns an adapter that adapts an object to the target class. Returns None if no such adapter exists. """ # The algorithm for finding a sequence of adapters adapting 'adaptee' # to 'to_protocol' is based on a weighted graph. # Nodes on the graphs are protocols (types or interfaces). # Edges are adaptation offers that connect a offer.from_protocol to a # offer.to_protocol. # Edges connect protocol A to protocol B and are weighted by two # numbers in this priority: # 1) a unit weight (1) representing the fact that we use 1 adaptation # offer to go from A to B # 2) the number of steps up the type hierarchy that we need to take # to go from A to offer.from_protocol, so that more specific # adapters are always preferred # The algorithm finds the shortest weighted path between 'adaptee' # and 'to_protocol'. Once a candidate path is found, it tries to # create the adapters using the factories in the adaptation offers # that compose the path. If this fails because of conditional # adaptation (i.e., an adapter factory returns None), the path # is discarded and the algorithm looks for the next shortest path. # Cycles in adaptation are avoided by only considering path were # every adaptation offer is used at most once. # The implementation of the algorithm is based on a priority queue, # 'offer_queue'. # # Each value in the queue has got two parts, # one is the adaptation path, i.e., the sequence of adaptation offers # followed so far; the second value is the protocol of the last # visited node. # # The priority in the queue is the sum of all the weights for the # edges traversed in the path. # Unique sequence counter to make the priority list stable # w.r.t the sequence of insertion. counter = itertools.count() # The priority queue containing entries of the form # (cumulative weight, path, current protocol) describing an # adaptation path starting at `adaptee`, following a sequence # of adaptation offers, `path`, and having weight `cumulative_weight`. # # 'cumulative weight' is a tuple of the form # (number of traversed adapters, # number of steps up protocol hierarchies, # counter) # # The counter is an increasing number, and is used to make the # priority queue stable w.r.t insertion time # (see http://bit.ly/13VxILn). offer_queue = [((0, 0, next(counter)), [], type(adaptee))] while len(offer_queue) > 0: # Get the most specific candidate path for adaptation. weight, path, current_protocol = heappop(offer_queue) edges = self._get_applicable_offers(current_protocol, path) # Sort by weight first, then by from_protocol type. edges.sort( key=functools.cmp_to_key( _by_weight_then_from_protocol_specificity ) ) # At this point, the first edges are the shortest ones. Within # edges with the same distance, interfaces which are subclasses # of other interfaces in that group come first. The rest of # the order is unspecified. for mro_distance, offer in edges: new_path = path + [offer] # Check if we arrived at the target protocol. if self.provides_protocol(offer.to_protocol, to_protocol): # Walk path and create adapters adapter = adaptee for offer in new_path: adapter = offer.factory(adapter) if adapter is None: # This adaptation attempt failed (e.g. because of # conditional adaptation). # Discard this path and continue. break else: # We're done! return adapter else: # Push the new path on the priority queue. adapter_weight, mro_weight, _ = weight new_weight = ( adapter_weight + 1, mro_weight + mro_distance, next(counter), ) heappush( offer_queue, (new_weight, new_path, offer.to_protocol) ) return None def _get_applicable_offers(self, current_protocol, path): """ Find all adaptation offers that can be applied to a protocol. Return all the applicable offers together with the number of steps up the MRO hierarchy that need to be taken from the protocol to the offer's from_protocol. The returned object is a list of tuples (mro_distance, offer) . In terms of our graph algorithm, we're looking for all outgoing edges from the current node. """ edges = [] for from_protocol_name, offers in self._adaptation_offers.items(): from_protocol = offers[0].from_protocol mro_distance = self.mro_distance_to_protocol( current_protocol, from_protocol ) if mro_distance is not None: for offer in offers: # Avoid cycles by checking that we did not consider this # offer in this path. if offer not in path: edges.append((mro_distance, offer)) return edges def _by_weight_then_from_protocol_specificity(edge_1, edge_2): """ Comparison function for graph edges. Each edge is of the form (mro distance, adaptation offer). Comparison is done by mro distance first, and by offer's from_protocol issubclass next. If two edges have the same mro distance, and the from_protocols of the two edges are not subclasses of one another, they are considered "equal". """ # edge_1 and edge_2 are edges, of the form (mro_distance, offer) mro_distance_1, offer_1 = edge_1 mro_distance_2, offer_2 = edge_2 # First, compare the MRO distance. if mro_distance_1 < mro_distance_2: return -1 elif mro_distance_1 > mro_distance_2: return 1 # The distance is equal, prefer more specific 'from_protocol's if offer_1.from_protocol is offer_2.from_protocol: return 0 if issubclass(offer_1.from_protocol, offer_2.from_protocol): return -1 elif issubclass(offer_2.from_protocol, offer_1.from_protocol): return 1 return 0 #: The default global adaptation manager. #: #: PROVIDED FOR BACKWARD COMPATIBILITY ONLY, IT SHOULD NEVER BE USED DIRECTLY. #: If you must use a global adaptation manager, use the functions #: :class:`get_global_adaptation_manager`, #: :class:`reset_global_adaptation_manager`, #: :class:`set_global_adaptation_manager`. adaptation_manager = AdaptationManager() def set_global_adaptation_manager(new_adaptation_manager): """ Set the global adaptation manager to the given instance. """ global adaptation_manager adaptation_manager = new_adaptation_manager def reset_global_adaptation_manager(): """ Set the global adaptation manager to a new AdaptationManager instance. """ global adaptation_manager adaptation_manager = AdaptationManager() def get_global_adaptation_manager(): """ Set a reference to the global adaptation manager. """ global adaptation_manager return adaptation_manager # Convenience references to methods on the default adaptation manager. # # If you add a public method to the adaptation manager protocol then don't # forget to add a convenience function here! def adapt(adaptee, to_protocol, default=AdaptationError): """ Attempt to adapt an object to a given protocol. """ manager = get_global_adaptation_manager() return manager.adapt(adaptee, to_protocol, default) def register_factory(factory, from_protocol, to_protocol): """ Register an adapter factory. """ manager = get_global_adaptation_manager() return manager.register_factory(factory, from_protocol, to_protocol) def register_offer(offer): """ Register an offer to adapt from one protocol to another. """ manager = get_global_adaptation_manager() return manager.register_offer(offer) def register_provides(provider_protocol, protocol): """ Register that a protocol provides another. """ manager = get_global_adaptation_manager() return manager.register_provides(provider_protocol, protocol) def supports_protocol(obj, protocol): """ Does the object support a given protocol? """ manager = get_global_adaptation_manager() return manager.supports_protocol(obj, protocol) def provides_protocol(type_, protocol): """ Does the given type provide (i.e implement) a given protocol? """ return AdaptationManager.provides_protocol(type_, protocol) traits-6.3.2/traits/adaptation/adaptation_offer.py000066400000000000000000000116441414270267200223540ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ An offer to provide adapters from one protocol to another. """ from traits.api import Any, Bool, HasTraits, Property from traits.util.api import import_symbol class AdaptationOffer(HasTraits): """ An offer to provide adapters from one protocol to another. An adaptation offer consists of a factory that can create adapters, and the protocols that define what the adapters adapt from and to. """ #### 'object' protocol #################################################### def __repr__(self): """ Return a string representation of the object. """ return (f"<{self.__class__.__name__}: '{self.from_protocol_name}' " f"-> '{self.to_protocol_name}'>") #### 'AdaptationOffer' protocol ########################################### #: A factory for creating adapters. #: #: The factory must ba callable that takes exactly one argument which is #: the object to be adapted (known as the adaptee), and returns an #: adapter from the `from_protocol` to the `to_protocol`. #: #: The factory can be specified as either a callable, or a string in the #: form 'foo.bar.baz' which is turned into an import statement #: 'from foo.bar import baz' and imported when the trait is first accessed. factory = Property(Any) #: Adapters created by the factory adapt *from* this protocol. #: #: The protocol can be specified as a protocol (class/Interface), or a #: string in the form 'foo.bar.baz' which is turned into an import #: statement 'from foo.bar import baz' and imported when the trait is #: accessed. from_protocol = Property(Any) from_protocol_name = Property(Any) def _get_from_protocol_name(self): return self._get_type_name(self._from_protocol) #: Adapters created by the factory adapt *to* this protocol. #: #: The protocol can be specified as a protocol (class/Interface), or a #: string in the form 'foo.bar.baz' which is turned into an import #: statement 'from foo.bar import baz' and imported when the trait is #: accessed. to_protocol = Property(Any) to_protocol_name = Property(Any) def _get_to_protocol_name(self): return self._get_type_name(self._to_protocol) #### Private protocol ##################################################### #: Shadow trait for the corresponding property. _factory = Any _factory_loaded = Bool(False) def _get_factory(self): """ Trait property getter. """ if not self._factory_loaded: if isinstance(self._factory, str): self._factory = import_symbol(self._factory) self._factory_loaded = True return self._factory def _set_factory(self, factory): """ Trait property setter. """ self._factory = factory #: Shadow trait for the corresponding property. _from_protocol = Any _from_protocol_loaded = Bool(False) def _get_from_protocol(self): """ Trait property getter. """ if not self._from_protocol_loaded: if isinstance(self._from_protocol, str): self._from_protocol = import_symbol(self._from_protocol) self._from_protocol_loaded = True return self._from_protocol def _set_from_protocol(self, from_protocol): """ Trait property setter. """ self._from_protocol = from_protocol #: Shadow trait for the corresponding property. _to_protocol = Any _to_protocol_loaded = Bool(False) def _get_to_protocol(self): """ Trait property getter. """ if not self._to_protocol_loaded: if isinstance(self._to_protocol, str): self._to_protocol = import_symbol(self._to_protocol) self._to_protocol_loaded = True return self._to_protocol def _set_to_protocol(self, to_protocol): """ Trait property setter. """ self._to_protocol = to_protocol def _get_type_name(self, type_or_type_name): """ Returns the full dotted path for a type. For example: from traits.api import HasTraits _get_type_name(HasTraits) == 'traits.has_traits.HasTraits' If the type is given as a string (e.g., for lazy loading), it is just returned. """ if isinstance(type_or_type_name, str): type_name = type_or_type_name else: type_name = "{module}.{name}".format( module=type_or_type_name.__module__, name=type_or_type_name.__name__, ) return type_name traits-6.3.2/traits/adaptation/adapter.py000066400000000000000000000020171414270267200204610ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Base classes for adapters. Adapters do not have to inherit from these classes, as long as their constructor takes the object to be adapted as the first and only *positional* argument. """ from traits.has_traits import HasTraits from traits.trait_types import Any class PurePythonAdapter(object): """ Base class for pure Python adapters. """ def __init__(self, adaptee): self.adaptee = adaptee class Adapter(HasTraits): """ Base class for adapters with traits. """ def __init__(self, adaptee, **traits): traits["adaptee"] = adaptee super().__init__(**traits) adaptee = Any traits-6.3.2/traits/adaptation/api.py000066400000000000000000000015071414270267200176150ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from .adapter import Adapter, PurePythonAdapter from .adaptation_error import AdaptationError from .adaptation_manager import ( adapt, AdaptationManager, get_global_adaptation_manager, provides_protocol, register_factory, register_offer, register_provides, reset_global_adaptation_manager, set_global_adaptation_manager, supports_protocol, ) from .adaptation_offer import AdaptationOffer traits-6.3.2/traits/adaptation/tests/000077500000000000000000000000001414270267200176315ustar00rootroot00000000000000traits-6.3.2/traits/adaptation/tests/__init__.py000066400000000000000000000000001414270267200217300ustar00rootroot00000000000000traits-6.3.2/traits/adaptation/tests/abc_examples.py000066400000000000000000000100161414270267200226240ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test data for testing the protocol manager with ABCs. """ from abc import ABC from traits.adaptation.api import PurePythonAdapter as Adapter #### 'Power plugs' metaphor ################################################### #### Protocols ################################################################ class UKStandard(ABC): pass class EUStandard(ABC): pass class JapanStandard(ABC): pass class IraqStandard(ABC): pass #### Implementations ########################################################## class UKPlug(object): pass UKStandard.register(UKPlug) class EUPlug(object): pass EUStandard.register(EUPlug) class JapanPlug(object): pass JapanStandard.register(JapanPlug) class IraqPlug(object): pass IraqStandard.register(IraqPlug) class TravelPlug(object): def __init__(self, mode): self.mode = mode #### Adapters ################################################################# # UK->EU class UKStandardToEUStandard(Adapter): pass EUStandard.register(UKStandardToEUStandard) # EU->Japan class EUStandardToJapanStandard(Adapter): pass JapanStandard.register(EUStandardToJapanStandard) # Japan->Iraq class JapanStandardToIraqStandard(Adapter): pass IraqStandard.register(JapanStandardToIraqStandard) # EU->Iraq class EUStandardToIraqStandard(Adapter): pass IraqStandard.register(EUStandardToIraqStandard) # UK->Japan class UKStandardToJapanStandard(Adapter): pass JapanStandard.register(UKStandardToJapanStandard) # Travel->Japan class TravelPlugToJapanStandard(Adapter): pass JapanStandard.register(TravelPlugToJapanStandard) # Travel->EU class TravelPlugToEUStandard(Adapter): pass EUStandard.register(TravelPlugToEUStandard) #### 'Editor, Scriptable, Undoable' metaphor ################################## class FileType(object): pass class IEditor(ABC): pass class IScriptable(ABC): pass class IUndoable(ABC): pass class FileTypeToIEditor(Adapter): pass IEditor.register(FileTypeToIEditor) IScriptable.register(FileTypeToIEditor) class IScriptableToIUndoable(Adapter): pass IUndoable.register(IScriptableToIUndoable) #### Hierarchy example ######################################################## class IPrintable(ABC): pass class Editor(object): pass class TextEditor(Editor): pass class EditorToIPrintable(Adapter): pass IPrintable.register(EditorToIPrintable) class TextEditorToIPrintable(Adapter): pass IPrintable.register(TextEditorToIPrintable) #### Interface hierarchy example ############################################## class IPrimate(ABC): pass class IHuman(IPrimate): pass class IChild(IHuman): pass class IIntermediate(ABC): pass class ITarget(ABC): pass class Source(object): pass IChild.register(Source) class IChildToIIntermediate(Adapter): pass IIntermediate.register(IChildToIIntermediate) class IHumanToIIntermediate(Adapter): pass IIntermediate.register(IHumanToIIntermediate) class IPrimateToIIntermediate(Adapter): pass IIntermediate.register(IPrimateToIIntermediate) class IIntermediateToITarget(Adapter): pass ITarget.register(IIntermediateToITarget) #### Non-trivial chaining example ############################################# class IStart(ABC): pass class IGeneric(ABC): pass class ISpecific(IGeneric): pass class IEnd(ABC): pass class Start(object): pass IStart.register(Start) class IStartToISpecific(Adapter): pass ISpecific.register(IStartToISpecific) class IGenericToIEnd(Adapter): pass IEnd.register(IGenericToIEnd) traits-6.3.2/traits/adaptation/tests/benchmark.py000066400000000000000000000103761414270267200221440ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Simple benchmarking of the adaptation manager. This is not 'enforced' by any tests (i.e. we currently aren't bound to satisfy any performance criteria - but in the future we might be ;^). """ # Imports are needed by the 'exec'd code. import abc # noqa: F401 import time from traits.adaptation.adaptation_manager import AdaptationManager from traits.api import Adapter, HasTraits, Interface, provides # noqa: F401 N_SOURCES = 3 N_ITERATIONS = 100 N_PROTOCOLS = 50 # Create some classes to adapt. create_classes_to_adapt = """ class IFoo{i}(Interface): pass @provides(IFoo{i}) class Foo{i}(HasTraits): pass """ for i in range(N_SOURCES): exec(create_classes_to_adapt.format(i=i)) # The object that we will try to adapt! foo = Foo1() # noqa: F821 # Create a lot of other interfaces that we will adapt to. for i in range(N_PROTOCOLS): exec("class I{i}(Interface): pass".format(i=i)) create_traits_adapter_class = """ @provides(I{target}) class IFoo{source}ToI{target}(Adapter): pass """ # Create adapters from each 'IFooX' to all of the interfaces. for source in range(N_SOURCES): for target in range(N_PROTOCOLS): exec(create_traits_adapter_class.format(source=source, target=target)) # traits.adaptation with Interfaces ########################################### adaptation_manager = AdaptationManager() register_ifoox_to_ix = """ adaptation_manager.register_factory( factory = IFoo{source}ToI{target}, from_protocol = IFoo{source}, to_protocol = I{target} ) """ # We register the adapters in reversed order, so that looking for the one # with index 0 will need traversing the whole list. # I.e., we're considering the worst case scenario. for source in range(N_SOURCES): for target in reversed(range(N_PROTOCOLS)): exec(register_ifoox_to_ix.format(source=source, target=target)) start_time = time.time() for _ in range(N_ITERATIONS): adaptation_manager.adapt(foo, I0) # noqa: F821 time_per_iter = (time.time() - start_time) / float(N_ITERATIONS) * 1000.0 print("apptools using Interfaces: %.3f msec per iteration" % time_per_iter) # traits.adaptation with ABCs ################################################# # Create some classes to adapt (using ABCs!). for i in range(N_SOURCES): exec( """ class FooABC{i}(abc.ABC): pass """.format( i=i ) ) exec("class Foo{i}(object): pass".format(i=i)) exec("FooABC{i}.register(Foo{i})".format(i=i)) # The object that we will try to adapt! foo = Foo0() # noqa: F821 # Create a lot of other ABCs! for i in range(N_PROTOCOLS): exec( """ class ABC{i}(abc.ABC): pass """.format( i=i ) ) # Create adapters from 'FooABC' to all of the ABCs. create_abc_adapter_class = """ class FooABC{source}ToABC{target}(object): def __init__(self, adaptee): pass ABC{target}.register(FooABC{source}ToABC{target}) """ for source in range(N_SOURCES): for target in range(N_PROTOCOLS): exec(create_abc_adapter_class.format(source=source, target=target)) # Register all of the adapters. adaptation_manager = AdaptationManager() register_fooxabc_to_abcx = """ adaptation_manager.register_factory( factory = FooABC{source}ToABC{target}, from_protocol = FooABC{source}, to_protocol = ABC{target} ) """ # We register the adapters in reversed order, so that looking for the one # with index 0 will need traversing the whole list. # I.e., we're considering the worst case scenario. for source in range(N_SOURCES): for target in reversed(range(N_PROTOCOLS)): exec(register_fooxabc_to_abcx.format(source=source, target=target)) start_time = time.time() for _ in range(N_ITERATIONS): adaptation_manager.adapt(foo, ABC0) # noqa: F821 time_per_iter = (time.time() - start_time) / float(N_ITERATIONS) * 1000.0 print("apptools using ABCs: %.3f msec per iteration" % time_per_iter) traits-6.3.2/traits/adaptation/tests/interface_examples.py000066400000000000000000000070461414270267200240500ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test data for testing the protocol manager with interfaces. """ from traits.api import Adapter, Enum, HasTraits, Interface, provides #### 'Power plugs' metaphor ################################################### #### Protocols ################################################################ class UKStandard(Interface): pass class EUStandard(Interface): pass class JapanStandard(Interface): pass class IraqStandard(Interface): pass #### Implementations ########################################################## @provides(UKStandard) class UKPlug(HasTraits): pass @provides(EUStandard) class EUPlug(HasTraits): pass @provides(JapanStandard) class JapanPlug(HasTraits): pass @provides(IraqStandard) class IraqPlug(HasTraits): pass class TravelPlug(HasTraits): mode = Enum(["Europe", "Asia"]) #### Adapters ################################################################# @provides(EUStandard) class UKStandardToEUStandard(Adapter): pass @provides(JapanStandard) class EUStandardToJapanStandard(Adapter): pass @provides(IraqStandard) class JapanStandardToIraqStandard(Adapter): pass @provides(IraqStandard) class EUStandardToIraqStandard(Adapter): pass @provides(JapanStandard) class UKStandardToJapanStandard(Adapter): pass @provides(JapanStandard) class TravelPlugToJapanStandard(Adapter): pass @provides(EUStandard) class TravelPlugToEUStandard(Adapter): pass #### 'Editor, Scriptable, Undoable' metaphor ################################## class FileType(HasTraits): pass class IEditor(Interface): pass class IScriptable(Interface): pass class IUndoable(Interface): pass @provides(IEditor, IScriptable) class FileTypeToIEditor(Adapter): pass @provides(IUndoable) class IScriptableToIUndoable(Adapter): pass #### Hierarchy example ######################################################## class IPrintable(Interface): pass class Editor(HasTraits): pass class TextEditor(Editor): pass @provides(IPrintable) class EditorToIPrintable(Adapter): pass @provides(IPrintable) class TextEditorToIPrintable(Adapter): pass #### Interface hierarchy example ############################################## class IPrimate(Interface): pass class IHuman(IPrimate): pass class IChild(IHuman): pass class IIntermediate(Interface): pass class ITarget(Interface): pass @provides(IChild) class Source(HasTraits): pass @provides(IIntermediate) class IChildToIIntermediate(Adapter): pass @provides(IIntermediate) class IHumanToIIntermediate(Adapter): pass @provides(IIntermediate) class IPrimateToIIntermediate(Adapter): pass @provides(ITarget) class IIntermediateToITarget(Adapter): pass #### Non-trivial chaining example ############################################# class IStart(Interface): pass class IGeneric(Interface): pass class ISpecific(IGeneric): pass class IEnd(Interface): pass @provides(IStart) class Start(HasTraits): pass @provides(ISpecific) class IStartToISpecific(Adapter): pass @provides(IEnd) class IGenericToIEnd(Adapter): pass traits-6.3.2/traits/adaptation/tests/lazy_examples.py000066400000000000000000000011561414270267200230630ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Examples for lazy adapter factories. This module should be only imported when the adaptation takes place. """ class IBar(object): pass class IBarToIFoo(object): pass class IFoo(object): pass traits-6.3.2/traits/adaptation/tests/test_adaptation_manager.py000066400000000000000000000374751414270267200251000ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test the adaptation manager. """ import unittest from traits.adaptation.api import AdaptationManager import traits.adaptation.tests.abc_examples import traits.adaptation.tests.interface_examples class TestAdaptationManagerWithABC(unittest.TestCase): """ Test the adaptation manager. """ #: Class attribute pointing at the module containing the example data examples = traits.adaptation.tests.abc_examples #### 'TestCase' protocol ################################################## def setUp(self): """ Prepares the test fixture before each test method is called. """ self.adaptation_manager = AdaptationManager() #### Tests ################################################################ def test_no_adapter_required(self): ex = self.examples plug = ex.UKPlug() # Try to adapt it to its own concrete type. uk_plug = self.adaptation_manager.adapt(plug, ex.UKPlug) # The adaptation manager should simply return the same object. self.assertIs(uk_plug, plug) # Try to adapt it to an ABC that is registered for its type. uk_plug = self.adaptation_manager.adapt(plug, ex.UKStandard) # The adaptation manager should simply return the same object. self.assertIs(uk_plug, plug) def test_no_adapter_available(self): ex = self.examples plug = ex.UKPlug() # Try to adapt it to a concrete type. eu_plug = self.adaptation_manager.adapt(plug, ex.EUPlug, None) # There should be no way to adapt a UKPlug to a EUPlug. self.assertEqual(eu_plug, None) # Try to adapt it to an ABC. eu_plug = self.adaptation_manager.adapt(plug, ex.EUStandard, None) # There should be no way to adapt a UKPlug to a EUPlug. self.assertEqual(eu_plug, None) def test_one_step_adaptation(self): ex = self.examples # UKStandard->EUStandard. self.adaptation_manager.register_factory( factory=ex.UKStandardToEUStandard, from_protocol=ex.UKStandard, to_protocol=ex.EUStandard, ) plug = ex.UKPlug() # Adapt it to an ABC. eu_plug = self.adaptation_manager.adapt(plug, ex.EUStandard) self.assertIsNotNone(eu_plug) self.assertIsInstance(eu_plug, ex.UKStandardToEUStandard) # We shouldn't be able to adapt it to a *concrete* 'EUPlug' though. eu_plug = self.adaptation_manager.adapt(plug, ex.EUPlug, None) self.assertIsNone(eu_plug) def test_adapter_chaining(self): ex = self.examples # UKStandard->EUStandard. self.adaptation_manager.register_factory( factory=ex.UKStandardToEUStandard, from_protocol=ex.UKStandard, to_protocol=ex.EUStandard, ) # EUStandard->JapanStandard. self.adaptation_manager.register_factory( factory=ex.EUStandardToJapanStandard, from_protocol=ex.EUStandard, to_protocol=ex.JapanStandard, ) # Create a UKPlug. uk_plug = ex.UKPlug() # Adapt it to a JapanStandard via the chain. japan_plug = self.adaptation_manager.adapt(uk_plug, ex.JapanStandard) self.assertIsNotNone(japan_plug) self.assertIsInstance(japan_plug, ex.EUStandardToJapanStandard) self.assertIs(japan_plug.adaptee.adaptee, uk_plug) def test_multiple_paths_unambiguous(self): ex = self.examples # UKStandard->EUStandard. self.adaptation_manager.register_factory( factory=ex.UKStandardToEUStandard, from_protocol=ex.UKStandard, to_protocol=ex.EUStandard, ) # EUStandard->JapanStandard. self.adaptation_manager.register_factory( factory=ex.EUStandardToJapanStandard, from_protocol=ex.EUStandard, to_protocol=ex.JapanStandard, ) # JapanStandard->IraqStandard. self.adaptation_manager.register_factory( factory=ex.JapanStandardToIraqStandard, from_protocol=ex.JapanStandard, to_protocol=ex.IraqStandard, ) # EUStandard->IraqStandard. self.adaptation_manager.register_factory( factory=ex.EUStandardToIraqStandard, from_protocol=ex.EUStandard, to_protocol=ex.IraqStandard, ) # Create a UKPlug. uk_plug = ex.UKPlug() # Adapt it to a IraqStandard via the chain. iraq_plug = self.adaptation_manager.adapt(uk_plug, ex.IraqStandard) self.assertIsNotNone(iraq_plug) self.assertIsInstance(iraq_plug, ex.EUStandardToIraqStandard) self.assertIs(iraq_plug.adaptee.adaptee, uk_plug) def test_multiple_paths_ambiguous(self): ex = self.examples # UKStandard->EUStandard. self.adaptation_manager.register_factory( factory=ex.UKStandardToEUStandard, from_protocol=ex.UKStandard, to_protocol=ex.EUStandard, ) # UKStandard->JapanStandard. self.adaptation_manager.register_factory( factory=ex.UKStandardToJapanStandard, from_protocol=ex.UKStandard, to_protocol=ex.JapanStandard, ) # JapanStandard->IraqStandard. self.adaptation_manager.register_factory( factory=ex.JapanStandardToIraqStandard, from_protocol=ex.JapanStandard, to_protocol=ex.IraqStandard, ) # EUStandard->IraqStandard. self.adaptation_manager.register_factory( factory=ex.EUStandardToIraqStandard, from_protocol=ex.EUStandard, to_protocol=ex.IraqStandard, ) # Create a UKPlug. uk_plug = ex.UKPlug() # Adapt it to a IraqStandard via the chain. iraq_plug = self.adaptation_manager.adapt(uk_plug, ex.IraqStandard) self.assertIsNotNone(iraq_plug) self.assertIn( type(iraq_plug), [ex.EUStandardToIraqStandard, ex.JapanStandardToIraqStandard], ) self.assertIs(iraq_plug.adaptee.adaptee, uk_plug) def test_conditional_adaptation(self): ex = self.examples # TravelPlug->EUStandard. def travel_plug_to_eu_standard(adaptee): if adaptee.mode == "Europe": return ex.TravelPlugToEUStandard(adaptee=adaptee) else: return None self.adaptation_manager.register_factory( factory=travel_plug_to_eu_standard, from_protocol=ex.TravelPlug, to_protocol=ex.EUStandard, ) # Create a TravelPlug. travel_plug = ex.TravelPlug(mode="Europe") # Adapt it to a EUStandard. eu_plug = self.adaptation_manager.adapt(travel_plug, ex.EUStandard) self.assertIsNotNone(eu_plug) self.assertIsInstance(eu_plug, ex.TravelPlugToEUStandard) # Create a TravelPlug. travel_plug = ex.TravelPlug(mode="Asia") # Adapt it to a EUStandard. eu_plug = self.adaptation_manager.adapt( travel_plug, ex.EUStandard, None ) self.assertIsNone(eu_plug) def test_spillover_adaptation_behavior(self): ex = self.examples # FileType->IEditor. self.adaptation_manager.register_factory( factory=ex.FileTypeToIEditor, from_protocol=ex.FileType, to_protocol=ex.IEditor, ) # Meanwhile, in a plugin far, far away ... # IScriptable->IPrintable. self.adaptation_manager.register_factory( factory=ex.IScriptableToIUndoable, from_protocol=ex.IScriptable, to_protocol=ex.IUndoable, ) # Create a file type. file_type = ex.FileType() # Try to adapt to IPrintable: since we did not define an adapter # chain that goes from FileType to IPrintable, this should fail. printable = self.adaptation_manager.adapt( file_type, ex.IUndoable, None ) self.assertIsNone(printable) def test_adaptation_prefers_subclasses(self): ex = self.examples # TextEditor->IPrintable. self.adaptation_manager.register_factory( factory=ex.TextEditorToIPrintable, from_protocol=ex.TextEditor, to_protocol=ex.IPrintable, ) # Editor->IPrintable. self.adaptation_manager.register_factory( factory=ex.EditorToIPrintable, from_protocol=ex.Editor, to_protocol=ex.IPrintable, ) # Create a text editor. text_editor = ex.TextEditor() # Adapt to IPrintable: we should get the TextEditorToIPrintable # adapter, not the EditorToIPrintable one. printable = self.adaptation_manager.adapt(text_editor, ex.IPrintable) self.assertIsNotNone(printable) self.assertIs(type(printable), ex.TextEditorToIPrintable) def test_adaptation_prefers_subclasses_other_registration_order(self): # This test is identical to `test_adaptation_prefers_subclasses` # with adapters registered in the opposite order. Both of them # should pass ex = self.examples # Editor->IPrintable. self.adaptation_manager.register_factory( factory=ex.EditorToIPrintable, from_protocol=ex.Editor, to_protocol=ex.IPrintable, ) # TextEditor->IPrintable. self.adaptation_manager.register_factory( factory=ex.TextEditorToIPrintable, from_protocol=ex.TextEditor, to_protocol=ex.IPrintable, ) # Create a text editor. text_editor = ex.TextEditor() # Adapt to IPrintable: we should get the TextEditorToIPrintable # adapter, not the EditorToIPrintable one. printable = self.adaptation_manager.adapt(text_editor, ex.IPrintable) self.assertIsNotNone(printable) self.assertIs(type(printable), ex.TextEditorToIPrintable) def test_circular_adaptation(self): # Circles in the adaptation graph should not lead to infinite loops # when it is impossible to reach the target. class Foo(object): pass class Bar(object): pass # object->Foo self.adaptation_manager.register_factory( factory=lambda adaptee: Foo(), from_protocol=object, to_protocol=Foo, ) # Foo->object self.adaptation_manager.register_factory( factory=lambda adaptee: [], from_protocol=Foo, to_protocol=object ) # Create an object. obj = [] # Try to adapt to an unreachable target. bar = self.adaptation_manager.adapt(obj, Bar, None) self.assertIsNone(bar) def test_default_argument_in_adapt(self): from traits.adaptation.adaptation_manager import AdaptationError # Without a default argument, a failed adaptation raises an error. with self.assertRaises(AdaptationError): self.adaptation_manager.adapt("string", int) # With a default argument, a failed adaptation returns the default. default = "default" result = self.adaptation_manager.adapt("string", int, default=default) self.assertIs(result, default) def test_prefer_specific_interfaces(self): ex = self.examples # IIntermediate -> ITarget. self.adaptation_manager.register_factory( factory=ex.IIntermediateToITarget, from_protocol=ex.IIntermediate, to_protocol=ex.ITarget, ) # IHuman -> IIntermediate. self.adaptation_manager.register_factory( factory=ex.IHumanToIIntermediate, from_protocol=ex.IHuman, to_protocol=ex.IIntermediate, ) # IChild -> IIntermediate. self.adaptation_manager.register_factory( factory=ex.IChildToIIntermediate, from_protocol=ex.IChild, to_protocol=ex.IIntermediate, ) # IPrimate -> IIntermediate. self.adaptation_manager.register_factory( factory=ex.IPrimateToIIntermediate, from_protocol=ex.IPrimate, to_protocol=ex.IIntermediate, ) # Create a source. source = ex.Source() # Adapt to ITarget: we should get the adapter for the most specific # interface, i.e. IChildToITarget. target = self.adaptation_manager.adapt(source, ex.ITarget) self.assertIsNotNone(target) self.assertIs(type(target.adaptee), ex.IChildToIIntermediate) def test_chaining_with_intermediate_mro_climbing(self): ex = self.examples # IStart -> ISpecific. self.adaptation_manager.register_factory( factory=ex.IStartToISpecific, from_protocol=ex.IStart, to_protocol=ex.ISpecific, ) # IGeneric -> IEnd. self.adaptation_manager.register_factory( factory=ex.IGenericToIEnd, from_protocol=ex.IGeneric, to_protocol=ex.IEnd, ) # Create a start. start = ex.Start() # Adapt to IEnd; this should succeed going from IStart to ISpecific, # climbing up the MRO to IGeneric, then crossing to IEnd. end = self.adaptation_manager.adapt(start, ex.IEnd) self.assertIsNotNone(end) self.assertIs(type(end), ex.IGenericToIEnd) def test_conditional_recycling(self): # Test that an offer that has been considered but failed if considered # again at a later time, when it might succeed because of conditional # adaptation. # C -- A -fails- B # C -- D -- A -succeeds- B class A(object): def __init__(self, allow_adaptation): self.allow_adaptation = allow_adaptation class B(object): pass class C(object): pass class D(object): pass self.adaptation_manager.register_factory( factory=lambda adaptee: A(False), from_protocol=C, to_protocol=A ) self.adaptation_manager.register_factory( factory=lambda adaptee: A(True), from_protocol=D, to_protocol=A ) self.adaptation_manager.register_factory( factory=lambda adaptee: D(), from_protocol=C, to_protocol=D ) # Conditional adapter def a_to_b_adapter(adaptee): if adaptee.allow_adaptation: b = B() b.marker = True else: b = None return b self.adaptation_manager.register_factory( factory=a_to_b_adapter, from_protocol=A, to_protocol=B ) # Create a A c = C() # Adaptation to B should succeed through D b = self.adaptation_manager.adapt(c, B) self.assertIsNotNone(b) self.assertTrue(hasattr(b, "marker")) def test_provides_protocol_for_interface_subclass(self): from traits.api import Interface class IA(Interface): pass class IB(IA): pass self.assertTrue(self.adaptation_manager.provides_protocol(IB, IA)) def test_register_provides(self): from traits.api import Interface class IFoo(Interface): pass obj = {} self.assertEqual(None, self.adaptation_manager.adapt(obj, IFoo, None)) self.adaptation_manager.register_provides(dict, IFoo) self.assertEqual(obj, self.adaptation_manager.adapt(obj, IFoo)) traits-6.3.2/traits/adaptation/tests/test_adaptation_offer.py000066400000000000000000000042531414270267200245530ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test the adaptation offers. """ import sys import unittest from traits.adaptation.adaptation_offer import AdaptationOffer class TestAdaptationOffer(unittest.TestCase): """ Test the adaptation offers. """ def test_lazy_loading(self): LAZY_EXAMPLES = "traits.adaptation.tests.lazy_examples" if LAZY_EXAMPLES in sys.modules: del sys.modules[LAZY_EXAMPLES] offer = AdaptationOffer( factory=(LAZY_EXAMPLES + ".IBarToIFoo"), from_protocol=(LAZY_EXAMPLES + ".IBar"), to_protocol=(LAZY_EXAMPLES + ".IFoo"), ) self.assertNotIn(LAZY_EXAMPLES, sys.modules) factory = offer.factory self.assertIn(LAZY_EXAMPLES, sys.modules) from traits.adaptation.tests.lazy_examples import IBarToIFoo self.assertIs(factory, IBarToIFoo) del sys.modules[LAZY_EXAMPLES] from_protocol = offer.from_protocol from traits.adaptation.tests.lazy_examples import IBar self.assertIs(from_protocol, IBar) del sys.modules[LAZY_EXAMPLES] to_protocol = offer.to_protocol from traits.adaptation.tests.lazy_examples import IFoo self.assertIs(to_protocol, IFoo) def test_adaptation_offer_str_representation(self): """ test string representation of the AdaptationOffer class. """ class Foo: pass class Bar: pass adaptation_offer = AdaptationOffer(from_protocol=Foo, to_protocol=Bar) desired_repr = " '{}'>".format( adaptation_offer.from_protocol_name, adaptation_offer.to_protocol_name ) self.assertEqual(desired_repr, str(adaptation_offer)) self.assertEqual(desired_repr, repr(adaptation_offer)) traits-6.3.2/traits/adaptation/tests/test_adapter.py000066400000000000000000000033061414270267200226640ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test the Adapter class. """ import unittest from traits.api import on_trait_change from traits.adaptation.api import Adapter class TestAdapter(unittest.TestCase): """ Test the Adapter class. """ #### Tests ################################################################ def test_initializing_adaptee(self): # Regression test: The `adaptee` trait used to be initialized after # all other traits, which caused "post_init" listeners to be # incorrectly triggered. class FooAdapter(Adapter): # True if a trait change notification for `adaptee` is fired. adaptee_notifier_called = False # True if a post-init trait change notification for `adaptee` # is fired. post_init_notifier_called = False @on_trait_change("adaptee", post_init=True) def check_that_adaptee_start_can_be_accessed(self): self.post_init_notifier_called = True @on_trait_change("adaptee") def check_that_adaptee_change_is_notified(self): self.adaptee_notifier_called = True foo_adapter = FooAdapter(adaptee="1234") self.assertEqual(foo_adapter.adaptee_notifier_called, True) self.assertEqual(foo_adapter.post_init_notifier_called, False) traits-6.3.2/traits/adaptation/tests/test_global_adaptation_manager.py000066400000000000000000000102331414270267200263770ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test the setting/getting/resetting/using the global adaptation manager. """ import unittest from traits.adaptation.api import ( adapt, AdaptationError, AdaptationManager, AdaptationOffer, get_global_adaptation_manager, provides_protocol, register_factory, register_provides, register_offer, reset_global_adaptation_manager, set_global_adaptation_manager, supports_protocol, ) import traits.adaptation.tests.abc_examples class TestGlobalAdaptationManager(unittest.TestCase): """ Test the setting/getting/resetting/using the global adaptation manager. """ #: Class attribute pointing at the module containing the example data examples = traits.adaptation.tests.abc_examples #### 'TestCase' protocol ################################################## def setUp(self): """ Prepares the test fixture before each test method is called. """ reset_global_adaptation_manager() #### Tests ################################################################ def test_reset_adaptation_manager(self): ex = self.examples adaptation_manager = get_global_adaptation_manager() # UKStandard->EUStandard. adaptation_manager.register_factory( factory=ex.UKStandardToEUStandard, from_protocol=ex.UKStandard, to_protocol=ex.EUStandard, ) # Create a UKPlug. uk_plug = ex.UKPlug() reset_global_adaptation_manager() adaptation_manager = get_global_adaptation_manager() with self.assertRaises(AdaptationError): adaptation_manager.adapt(uk_plug, ex.EUStandard) def test_set_adaptation_manager(self): ex = self.examples adaptation_manager = AdaptationManager() # UKStandard->EUStandard. adaptation_manager.register_factory( factory=ex.UKStandardToEUStandard, from_protocol=ex.UKStandard, to_protocol=ex.EUStandard, ) # Create a UKPlug. uk_plug = ex.UKPlug() set_global_adaptation_manager(adaptation_manager) global_adaptation_manager = get_global_adaptation_manager() eu_plug = global_adaptation_manager.adapt(uk_plug, ex.EUStandard) self.assertIsNotNone(eu_plug) self.assertIsInstance(eu_plug, ex.UKStandardToEUStandard) def test_global_convenience_functions(self): ex = self.examples # Global `register_factory`. register_factory( factory=ex.UKStandardToEUStandard, from_protocol=ex.UKStandard, to_protocol=ex.EUStandard, ) uk_plug = ex.UKPlug() # Global `adapt`. eu_plug = adapt(uk_plug, ex.EUStandard) self.assertIsNotNone(eu_plug) self.assertIsInstance(eu_plug, ex.UKStandardToEUStandard) # Global `provides_protocol`. self.assertTrue(provides_protocol(ex.UKPlug, ex.UKStandard)) # Global `supports_protocol`. self.assertTrue(supports_protocol(uk_plug, ex.EUStandard)) def test_global_register_provides(self): from traits.api import Interface class IFoo(Interface): pass obj = {} # Global `register_provides`. register_provides(dict, IFoo) self.assertEqual(obj, adapt(obj, IFoo)) def test_global_register_offer(self): ex = self.examples offer = AdaptationOffer( factory=ex.UKStandardToEUStandard, from_protocol=ex.UKStandard, to_protocol=ex.EUStandard, ) # Global `register_offer`. register_offer(offer) uk_plug = ex.UKPlug() eu_plug = adapt(uk_plug, ex.EUStandard) self.assertIsNotNone(eu_plug) self.assertIsInstance(eu_plug, ex.UKStandardToEUStandard) traits-6.3.2/traits/api.py000066400000000000000000000101051414270267200154630ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Pseudo-package for all of the core symbols from Traits and TraitsUI. Use this module for importing Traits names into your namespace. For example:: from traits.api import HasTraits """ from .constants import ( ComparisonMode, DefaultValue, TraitKind, ValidateTrait, NO_COMPARE, OBJECT_IDENTITY_COMPARE, RICH_COMPARE, ) from .trait_base import Uninitialized, Undefined, Missing, Self from .trait_converters import as_ctrait from .trait_errors import ( TraitError, TraitNotificationError, DelegationError, ) from .trait_notifiers import ( push_exception_handler, pop_exception_handler, TraitChangeNotifyWrapper, ) from .ctrait import CTrait from .trait_factory import TraitFactory from .traits import ( Trait, Property, Default, Color, RGBColor, Font, ) from .trait_types import ( Any, Int, Float, Complex, Str, Title, Bytes, Bool, CInt, CFloat, CComplex, CStr, CBytes, CBool, String, Regex, Code, HTML, Password, Callable, This, self, Function, Method, Module, Python, ReadOnly, Disallow, Constant, Delegate, DelegatesTo, PrototypedFrom, Expression, PythonValue, File, Directory, Range, Enum, Tuple, List, CList, PrefixList, Set, CSet, Dict, Map, PrefixMap, Instance, AdaptedTo, AdaptsTo, Event, Button, ToolbarButton, Either, Union, Type, Subclass, Symbol, WeakRef, Date, Datetime, Time, Supports, ) # Deprecated TraitType subclasses and instances. from .trait_types import ( BaseUnicode, Unicode, BaseCUnicode, CUnicode, BaseLong, Long, BaseCLong, CLong, false, true, undefined, ListInt, ListFloat, ListStr, ListUnicode, ListComplex, ListBool, ListFunction, ListMethod, ListThis, DictStrAny, DictStrStr, DictStrInt, DictStrFloat, DictStrBool, DictStrList, ) from .trait_types import ( BaseCallable, BaseInt, BaseFloat, BaseComplex, BaseStr, BaseBytes, BaseBool, BaseCInt, BaseCFloat, BaseCComplex, BaseCStr, BaseCBool, BaseFile, BaseDirectory, BaseRange, BaseEnum, BaseTuple, BaseInstance, ) from .trait_types import UUID, ValidatedTuple from .has_traits import ( ABCHasStrictTraits, ABCHasTraits, ABCMetaHasTraits, AbstractViewElement, HasTraits, HasStrictTraits, HasPrivateTraits, HasRequiredTraits, Interface, SingletonHasTraits, SingletonHasStrictTraits, SingletonHasPrivateTraits, MetaHasTraits, Vetoable, VetoableEvent, observe, on_trait_change, cached_property, property_depends_on, provides, isinterface, ) from .base_trait_handler import BaseTraitHandler from .trait_handler import TraitHandler from .trait_type import TraitType, NoDefaultSpecified from .trait_handlers import ( TraitCoerceType, TraitCastType, TraitInstance, TraitFunction, TraitEnum, TraitPrefixList, TraitMap, TraitPrefixMap, TraitCompound, TraitList, TraitDict, TraitTuple, ) from .trait_dict_object import TraitDictEvent, TraitDictObject from .trait_list_object import TraitListEvent, TraitListObject from .trait_set_object import TraitSetEvent, TraitSetObject from .adaptation.adapter import Adapter from .adaptation.adaptation_error import AdaptationError from .adaptation.adaptation_manager import ( adapt, register_factory, register_provides, ) from .trait_numeric import Array, ArrayOrNone, CArray traits-6.3.2/traits/base_trait_handler.py000066400000000000000000000143411414270267200205320ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Defines the Abstract BaseTraitHandler class. A trait handler mediates the assignment of values to object traits. It verifies (via its validate() method) that a specified value is consistent with the object trait, and generates a TraitError exception if it is not consistent. """ from .constants import DefaultValue from .trait_errors import TraitError class BaseTraitHandler(object): """ The task of this class and its subclasses is to verify the correctness of values assigned to object trait attributes. This class is an alternative to trait validator functions. A trait handler has several advantages over a trait validator function, due to being an object: * Trait handlers have constructors and state. Therefore, you can use them to create *parametrized types*. * Trait handlers can have multiple methods, whereas validator functions can have only one callable interface. This feature allows more flexibility in their implementation, and allows them to handle a wider range of cases, such as interactions with other components. """ default_value_type = DefaultValue.unspecified has_items = False is_mapped = False editor = None info_text = "a legal value" def is_valid(self, object, name, value): try: validate = self.validate try: validate(object, name, value) return True except Exception: return False except Exception: return True def error(self, object, name, value): """Raises a TraitError exception. This method is called by the validate() method when an assigned value is not valid. Raising a TraitError exception either notifies the user of the problem, or, in the case of compound traits, provides a chance for another trait handler to handle to validate the value. Parameters ---------- object : object The object whose attribute is being assigned. name : str The name of the attribute being assigned. value : object The proposed new value for the attribute. """ raise TraitError( object, name, self.full_info(object, name, value), value ) def full_info(self, object, name, value): """Returns a string describing the type of value accepted by the trait handler. The string should be a phrase describing the type defined by the TraitHandler subclass, rather than a complete sentence. For example, use the phrase, "a square sprocket" instead of the sentence, "The value must be a square sprocket." The value returned by full_info() is combined with other information whenever an error occurs and therefore makes more sense to the user if the result is a phrase. The full_info() method is similar in purpose and use to the **info** attribute of a validator function. Note that the result can include information specific to the particular trait handler instance. If the full_info() method is not overridden, the default method returns the value of calling the info() method. Parameters ---------- object : object The object whose attribute is being assigned. name : str The name of the attribute being assigned. value : The proposed new value for the attribute. """ return self.info() def info(self): """Must return a string describing the type of value accepted by the trait handler. The string should be a phrase describing the type defined by the TraitHandler subclass, rather than a complete sentence. For example, use the phrase, "a square sprocket" instead of the sentence, "The value must be a square sprocket." The value returned by info() is combined with other information whenever an error occurs and therefore makes more sense to the user if the result is a phrase. The info() method is similar in purpose and use to the **info** attribute of a validator function. Note that the result can include information specific to the particular trait handler instance. If the info() method is not overridden, the default method returns the value of the 'info_text' attribute. """ return self.info_text def get_editor(self, trait=None): """ Returns a trait editor that allows the user to modify the *trait* trait. This method only needs to be specified if traits defined using this trait handler require a non-default trait editor in trait user interfaces. The default implementation of this method returns a trait editor that allows the user to type an arbitrary string as the value. For more information on trait user interfaces, refer to the *Traits UI User Guide*. Parameters ---------- trait : Trait The trait to be edited. """ if self.editor is None: self.editor = self.create_editor() return self.editor def create_editor(self): """ Returns the default traits UI editor to use for a trait. """ from traitsui.api import TextEditor return TextEditor() def inner_traits(self): """ Returns a tuple containing the *inner traits* for this trait. Most trait handlers do not have any inner traits, and so will return an empty tuple. The exceptions are **List** and **Dict** trait types, which have inner traits used to validate the values assigned to the trait. For example, in *List( Int )*, the *inner traits* for **List** are ( **Int**, ). """ return () traits-6.3.2/traits/constants.py000066400000000000000000000146211414270267200167350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from enum import IntEnum import traits.ctraits class TraitKind(IntEnum): """ These determine the getters and setters used by the cTrait instance. """ #: A standard trait (validates and notifies). trait = 0 #: A standard Python attribute (no validation or notification). #: This sets values into the object dict, so is not suitable for use with #: standard Python descriptors - generally you want ``generic``. python = 1 #: An event trait (can't read value, only assign value). event = 2 #: A delegated trait. delegate = 3 #: A trait property. property = 4 #: A trait that can neither be assigned or read. disallow = 5 #: A trait that can be assigned once, and after that only read (no #: validation or notification). read_only = 6 #: A trait whose value is constant (can only be read). constant = 7 #: A standard Python attribute or descriptor (no validation or #: notification). generic = 8 class ValidateTrait(IntEnum): """ These are indices into the ctraits.c validate_handlers array. """ #: A type check. type = 0 #: An instance check. instance = 1 #: A self-type check. self_type = 2 #: An integer range check (unused). int_range = 3 #: A floating-point range check. float_range = 4 #: An enumerated item check. enum = 5 #: A mapped item check. map = 6 #: A complex fast validator check with multiple fast validators. complex = 7 #: A slow validator (only used in complex validators). slow = 8 #: A tuple type check. tuple = 9 #: A prefix map item check. prefix_map = 10 #: A coercable type check. coerce = 11 #: A castable type check. cast = 12 #: A function check. function = 13 #: A Python-based validator. python = 14 #: An adaptable object check. adapt = 19 #: An integer check. int = 20 #: A floating-point check. float = 21 #: A callable check. callable = 22 class ComparisonMode(IntEnum): """ Comparison mode. Indicates when trait change notifications should be generated based upon the result of comparing the old and new values of a trait assignment: Enumeration members: none The values are not compared and a trait change notification is generated on each assignment. identity A trait change notification is generated if the old and new values are not the same object. equality A trait change notification is generated if the old and new values are not the same object, and not equal using Python's standard equality testing. This is the default. """ #: Do not compare values (always fire trait change) none = 0 #: Compare values by object identity. identity = 1 #: Compare values by equality. equality = 2 # Backward compatibility for comparison mode constants. #: Deprecated alias for ``ComparisonMode.none``. NO_COMPARE = ComparisonMode.none #: Deprecated alias for ``ComparisonMode.identity``. OBJECT_IDENTITY_COMPARE = ComparisonMode.identity #: Deprecated alias for ``ComparisonMode.equality``. RICH_COMPARE = ComparisonMode.equality class DefaultValue(IntEnum): """ Default value types. """ #: The default value type has not been specified unspecified = -1 #: The default_value of the trait is the default value. constant = traits.ctraits._CONSTANT_DEFAULT_VALUE #: The default_value of the trait is Missing. missing = traits.ctraits._MISSING_DEFAULT_VALUE #: The object containing the trait is the default value. object = traits.ctraits._OBJECT_DEFAULT_VALUE #: A new copy of the list specified by default_value is the default value. list_copy = traits.ctraits._LIST_COPY_DEFAULT_VALUE #: A new copy of the dict specified by default_value is the default value. dict_copy = traits.ctraits._DICT_COPY_DEFAULT_VALUE #: A new instance of TraitListObject constructed using the default_value #: list is the default value. trait_list_object = traits.ctraits._TRAIT_LIST_OBJECT_DEFAULT_VALUE #: A new instance of TraitDictObject constructed using the default_value #: dict is the default value. trait_dict_object = traits.ctraits._TRAIT_DICT_OBJECT_DEFAULT_VALUE #: The default_value is a tuple of the form: (*callable*, *args*, *kw*), #: where *callable* is a callable, *args* is a tuple, and *kw* is either a #: dictionary or None. The default value is the result obtained by invoking #: ``callable(\*args, \*\*kw)``. callable_and_args = traits.ctraits._CALLABLE_AND_ARGS_DEFAULT_VALUE #: The default_value is a callable. The default value is the result #: obtained by invoking *default_value*(*object*), where *object* is the #: object containing the trait. If the trait has a validate() method, the #: validate() method is also called to validate the result. callable = traits.ctraits._CALLABLE_DEFAULT_VALUE #: A new instance of TraitSetObject constructed using the default_value set #: is the default value. trait_set_object = traits.ctraits._TRAIT_SET_OBJECT_DEFAULT_VALUE #: This trait doesn't permit a default value, and an attempt to retrieve #: the default value using the default_value_for method will fail. disallow = traits.ctraits._DISALLOW_DEFAULT_VALUE #: Maximum legal value for default_value_type, for use in testing #: and validation. MAXIMUM_DEFAULT_VALUE_TYPE = traits.ctraits._MAXIMUM_DEFAULT_VALUE_TYPE #: Mapping from 'ctrait' default value types to a string representation: default_value_map = { DefaultValue.constant: "value", DefaultValue.missing: "value", DefaultValue.object: "self", DefaultValue.list_copy: "list", DefaultValue.dict_copy: "dict", DefaultValue.trait_list_object: "list", DefaultValue.trait_dict_object: "dict", DefaultValue.callable_and_args: "factory", DefaultValue.callable: "method", DefaultValue.trait_set_object: "set", DefaultValue.disallow: "invalid", } traits-6.3.2/traits/ctrait.py000066400000000000000000000203451414270267200162070ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Defines the core CTrait class. The CTrait class extends the C-level cTrait type to provide the full CTrait API. CTraits are the core objects that are used to generate defaults and validate as well as maintining a list of notifiers and calling them when values are modified. """ import inspect from . import ctraits from .constants import ComparisonMode, DefaultValue, default_value_map from .observation.i_observable import IObservable from .trait_base import SequenceTypes, Undefined from .trait_dict_object import TraitDictObject from .trait_list_object import TraitListObject from .trait_set_object import TraitSetObject def __newobj__(cls, *args): """ Unpickles new-style objects. """ return cls.__new__(cls, *args) @IObservable.register class CTrait(ctraits.cTrait): """ Extends the underlying C-based cTrait type. """ def __call__(self, *args, **metadata): """ Allows a derivative trait to be defined from this one. """ from .trait_type import TraitType from .traits import Trait handler = self.handler if isinstance(handler, TraitType): dict = (self.__dict__ or {}).copy() dict.update(metadata) return handler(*args, **dict) metadata.setdefault("parent", self) return Trait(*(args + (self,)), **metadata) @property def default(self): kind, value = self.default_value() if kind in ( DefaultValue.object, DefaultValue.callable_and_args, DefaultValue.callable, DefaultValue.disallow, ): return Undefined elif kind in ( DefaultValue.dict_copy, DefaultValue.trait_dict_object, DefaultValue.trait_set_object, DefaultValue.list_copy, DefaultValue.trait_list_object, ): return value.copy() elif kind in {DefaultValue.constant, DefaultValue.missing}: return value else: # This shouldn't ever happen. raise RuntimeError( "Unexpected default value kind: {!r}".format(kind) ) @property def default_kind(self): return default_value_map[self.default_value()[0]] @property def trait_type(self): handler = self.handler if handler is not None: return handler else: from .trait_types import Any return Any @property def inner_traits(self): handler = self.handler if handler is not None: return handler.inner_traits() return () @property def comparison_mode(self): """ Get or set the comparison mode on the trait. Getter returns a ComparisonMode enum. Setter acceps either an int or a ComparisonMode enum. """ i_comparison_mode = super().comparison_mode return ComparisonMode(i_comparison_mode) @comparison_mode.setter def comparison_mode(self, value): ctraits.cTrait.comparison_mode.__set__(self, value) @property def property_fields(self): """ Return a tuple of callables (fget, fset, validate) for the property trait.""" return self._get_property() @property_fields.setter def property_fields(self, value): """ Set the fget, fset, validate callables for the property. Parameters ---------- value : tuple Value should be the tuple of callables (fget, fset, validate). """ func_arg_counts = [] for arg in value: if arg is None: nargs = 0 else: sig = inspect.signature(arg) nargs = len(sig.parameters) func_arg_counts.extend([arg, nargs]) self._set_property(*func_arg_counts) def is_trait_type(self, trait_type): """ Returns whether or not this trait is of a specified trait type. """ return isinstance(self.trait_type, trait_type) def get_editor(self): """ Returns the user interface editor associated with the trait. """ from traitsui.api import EditorFactory # See if we have an editor: editor = self.editor if editor is None: # Else see if the trait handler has an editor: handler = self.handler if handler is not None: editor = handler.get_editor(self) # If not, give up and use a default text editor: if editor is None: from traitsui.api import TextEditor editor = TextEditor # If the result is not an EditorFactory: if not isinstance(editor, EditorFactory): # Then it should be a factory for creating them: args = () traits = {} if type(editor) in SequenceTypes: for item in editor[:]: if type(item) in SequenceTypes: args = tuple(item) elif isinstance(item, dict): traits = item if traits.get("trait", 0) is None: traits = traits.copy() traits["trait"] = self else: editor = item editor = editor(*args, **traits) # Cache the result: self.editor = editor # Return the resulting EditorFactory object: return editor def get_help(self, full=True): """ Returns the help text for a trait. If *full* is False or the trait does not have a **help** string, the returned string is constructed from the **desc** attribute on the trait and the **info** string on the trait's handler. Parameters ---------- full : bool Indicates whether to return the value of the *help* attribute of the trait itself. """ if full: help = self.help if help is not None: return help handler = self.handler if handler is not None: info = "must be %s." % handler.info() else: info = "may be any value." desc = self.desc if self.desc is None: return info.capitalize() return "Specifies %s and %s" % (desc, info) def full_info(self, object, name, value): """ Returns a description of the trait. """ handler = self.handler if handler is not None: return handler.full_info(object, name, value) return "any value" def info(self): """ Returns a description of the trait. """ handler = self.handler if handler is not None: return handler.info() return "any value" def as_ctrait(self): """ Method that returns self for trait converters. """ return self def __reduce_ex__(self, protocol): """ Returns the pickleable form of a CTrait object. """ return (__newobj__, (self.__class__, 0), self.__getstate__()) def _adapt_wrapper(*args, **kw): # We need this wrapper to defer the import of 'adapt' and avoid a circular # import. The ctraits 'adapt' callback needs to be set as soon as possible, # but the adaptation mechanism relies on traits. # This wrapper is called once, after which we set the ctraits callback # to point directly to 'adapt'. from traits.adaptation.api import adapt ctraits._adapt(adapt) return adapt(*args, **kw) # Make sure the Python-level version of the trait class is known to all # interested parties: ctraits._ctrait(CTrait) #: Register Trait container object classes with ctraits.c ctraits._list_classes(TraitListObject, TraitSetObject, TraitDictObject) #: Tell the C-based traits module about the traits adaptation 'adapt' function ctraits._adapt(_adapt_wrapper) traits-6.3.2/traits/ctraits.c000066400000000000000000005426031414270267200161720ustar00rootroot00000000000000// (C) Copyright 2005-2021 Enthought, Inc., Austin, TX // All rights reserved. // // This software is provided without warranty under the terms of the BSD // license included in LICENSE.txt and may be redistributed only under // the conditions described in the aforementioned license. The license // is also available online at http://www.enthought.com/licenses/BSD.txt // // Thanks for using Enthought open source! /*----------------------------------------------------------------------------- | Includes: +----------------------------------------------------------------------------*/ #include "Python.h" /*----------------------------------------------------------------------------- | Constants: +----------------------------------------------------------------------------*/ static PyObject *class_traits; /* == "__class_traits__" */ static PyObject *listener_traits; /* == "__listener_traits__" */ static PyObject *editor_property; /* == "editor" */ static PyObject *class_prefix; /* == "__prefix__" */ static PyObject *trait_added; /* == "trait_added" */ static PyObject *Undefined; /* Global 'Undefined' value */ static PyObject *Uninitialized; /* Global 'Uninitialized' value */ static PyObject *TraitError; /* TraitError exception */ static PyObject *DelegationError; /* DelegationError exception */ static PyObject *TraitListObject; /* TraitListObject class */ static PyObject *TraitSetObject; /* TraitSetObject class */ static PyObject *TraitDictObject; /* TraitDictObject class */ static PyObject *adapt; /* 'adapt' function */ static PyTypeObject *ctrait_type; /* Python-level CTrait type reference */ /*----------------------------------------------------------------------------- | Macro definitions: +----------------------------------------------------------------------------*/ #define PyTrait_CheckExact(op) ((Py_TYPE(op)) == ctrait_type) #define PyHasTraits_Check(op) PyObject_TypeCheck(op, &has_traits_type) /* Notification related: */ #define has_notifiers(tnotifiers, onotifiers) \ ((((tnotifiers) != NULL) && (PyList_GET_SIZE((tnotifiers)) > 0)) \ || (((onotifiers) != NULL) && (PyList_GET_SIZE((onotifiers)) > 0))) /*----------------------------------------------------------------------------- | Forward declarations: +----------------------------------------------------------------------------*/ static PyTypeObject trait_type; static PyTypeObject has_traits_type; /*----------------------------------------------------------------------------- | 'ctraits' module doc string: +----------------------------------------------------------------------------*/ PyDoc_STRVAR( ctraits__doc__, "Fast base classes for HasTraits and CTrait.\n" "\n" "The ctraits module defines the CHasTraits and cTrait extension types\n" "that define the core performance-oriented portions of the Traits\n" "package. Users will rarely need to use this module directly. Instead,\n" "they should use the API-complete HasTraits and CTrait subclasses of \n" "CHasTraits and cTrait (respectively).\n" ); /*----------------------------------------------------------------------------- | HasTraits behavior modification flags: +----------------------------------------------------------------------------*/ /* Object has been initialized: */ #define HASTRAITS_INITED 0x00000001U /* Do not send notifications when a trait changes value: */ #define HASTRAITS_NO_NOTIFY 0x00000002U /* Requests that no event notifications be sent when this object is assigned to a trait: */ #define HASTRAITS_VETO_NOTIFY 0x00000004U /*----------------------------------------------------------------------------- | 'CHasTraits' instance definition: | | Note: traits are normally stored in the type's dictionary, but are added to | the instance's traits dictionary 'trait_dict' when the traits are defined | dynamically or 'on_trait_change' is called on an instance of the trait. | | All 'anytrait_changed' notification handlers are stored in the instance's | 'notifiers' list. +----------------------------------------------------------------------------*/ typedef struct { PyObject_HEAD /* Standard Python object header */ PyDictObject *ctrait_dict; /* Class traits dictionary */ PyDictObject *itrait_dict; /* Instance traits dictionary */ PyListObject *notifiers; /* List of 'any trait changed' notification handlers */ unsigned int flags; /* Behavior modification flags */ PyObject *obj_dict; /* Object attribute dictionary ('__dict__') */ /* NOTE: 'obj_dict' field MUST be last field */ } has_traits_object; static int call_notifiers( PyListObject *, PyListObject *, has_traits_object *, PyObject *, PyObject *, PyObject *new_value); /*----------------------------------------------------------------------------- | 'CTrait' flag values: +----------------------------------------------------------------------------*/ /* The trait is a Property: */ #define TRAIT_PROPERTY 0x00000001U /* Should the delegate be modified (or the original object)? */ #define TRAIT_MODIFY_DELEGATE 0x00000002U /* Make 'setattr' store the original unvalidated value */ #define TRAIT_SETATTR_ORIGINAL_VALUE 0x00000008U /* Send the 'post_setattr' method the original unvalidated value */ #define TRAIT_POST_SETATTR_ORIGINAL_VALUE 0x00000010U /* Does this trait have an associated 'mapped' trait? */ #define TRAIT_IS_MAPPED 0x00000080U /* Mask for the comparison mode bits, which determine when notifications are emitted on trait assignment. */ #define TRAIT_COMPARISON_MODE_MASK 0x00000104U /* Notify on every assignment. Corresponds to ComparisonMode.none. */ #define TRAIT_COMPARISON_MODE_NONE 0x00000100U /* Notify if the new object "is not" the old one. Corresponds to ComparisonMode.identity. */ #define TRAIT_COMPARISON_MODE_IDENTITY 0x00000004U /* Notify if the new object is not the old one, and is not equal to the old one. Corresponds to ComparisonMode.equality. */ #define TRAIT_COMPARISON_MODE_EQUALITY 0x00000000U /*----------------------------------------------------------------------------- | Default value type constants (see `default_value_for` method) +----------------------------------------------------------------------------*/ /* The default_value of the trait is the default value */ #define CONSTANT_DEFAULT_VALUE 0 /* The default_value of the trait is Missing */ #define MISSING_DEFAULT_VALUE 1 /* The object containing the trait is the default value */ #define OBJECT_DEFAULT_VALUE 2 /* A new copy of the list specified by default_value is the default value */ #define LIST_COPY_DEFAULT_VALUE 3 /* A new copy of the dict specified by default_value is the default value */ #define DICT_COPY_DEFAULT_VALUE 4 /* A new instance of TraitListObject constructed using the default_value list is the default value */ #define TRAIT_LIST_OBJECT_DEFAULT_VALUE 5 /* A new instance of TraitDictObject constructed using the default_value dict is the default value */ #define TRAIT_DICT_OBJECT_DEFAULT_VALUE 6 /* The default_value is a tuple of the form: (*callable*, *args*, *kw*), where *callable* is a callable, *args* is a tuple, and *kw* is either a dictionary or None. The default value is the result obtained by invoking ``callable(\*args, \*\*kw)`` */ #define CALLABLE_AND_ARGS_DEFAULT_VALUE 7 /* The default_value is a callable. The default value is the result obtained by invoking *default_value*(*object*), where *object* is the object containing the trait. If the trait has a validate() method, the validate() method is also called to validate the result */ #define CALLABLE_DEFAULT_VALUE 8 /* A new instance of TraitSetObject constructed using the default_value set is the default value */ #define TRAIT_SET_OBJECT_DEFAULT_VALUE 9 /* This trait doesn't permit a default value */ #define DISALLOW_DEFAULT_VALUE 10 /* Maximum legal value for default_value_type, for use in testing and validation. */ #define MAXIMUM_DEFAULT_VALUE_TYPE 10 /* The maximum value for comparison_mode. Valid values are between 0 and the maximum value. */ #define MAXIMUM_COMPARISON_MODE_VALUE 2 /*----------------------------------------------------------------------------- | 'CTrait' instance definition: +----------------------------------------------------------------------------*/ typedef struct _trait_object a_trait_object; typedef PyObject *(*trait_getattr)( a_trait_object *, has_traits_object *, PyObject *); typedef int (*trait_setattr)( a_trait_object *, a_trait_object *, has_traits_object *, PyObject *, PyObject *); typedef int (*trait_post_setattr)( a_trait_object *, has_traits_object *, PyObject *, PyObject *); typedef PyObject *(*trait_validate)( a_trait_object *, has_traits_object *, PyObject *, PyObject *); typedef PyObject *(*delegate_attr_name_func)( a_trait_object *, has_traits_object *, PyObject *); typedef struct _trait_object { PyObject_HEAD /* Standard Python object header */ unsigned int flags; /* Flag bits */ trait_getattr getattr; /* Get trait value handler */ trait_setattr setattr; /* Set trait value handler */ trait_post_setattr post_setattr; /* Optional post 'setattr' handler */ PyObject *py_post_setattr; /* Python-based post 'setattr' handler */ trait_validate validate; /* Validate trait value handler */ PyObject *py_validate; /* Python-based validate value handler */ int default_value_type; /* Type of default value: see the 'default_value_for' function */ PyObject *default_value; /* Default value for trait */ PyObject *delegate_name; /* Optional delegate name */ /* Also used for 'property get' */ PyObject *delegate_prefix; /* Optional delegate prefix */ /* Also used for 'property set' */ delegate_attr_name_func delegate_attr_name; /* Optional routine to return*/ /* the computed delegate attribute name */ PyListObject *notifiers; /* Optional list of notification handlers */ PyObject *handler; /* Associated trait handler object */ /* NOTE: The 'obj_dict' field MUST be last */ PyObject *obj_dict; /* Standard Python object dictionary */ } trait_object; /* Forward declarations: */ static void trait_clone(trait_object *, trait_object *); static PyObject * has_traits_getattro(has_traits_object *obj, PyObject *name); static int has_traits_setattro(has_traits_object *obj, PyObject *name, PyObject *value); static PyObject * get_trait(has_traits_object *obj, PyObject *name, int instance); static int trait_property_changed( has_traits_object *obj, PyObject *name, PyObject *old_value, PyObject *new_value); static int setattr_event( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value); static int setattr_disallow( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value); /*----------------------------------------------------------------------------- | Raise a TraitError: +----------------------------------------------------------------------------*/ static PyObject * raise_trait_error( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result; /* Clear any current exception. We are handling it by raising * a TraitError. */ PyErr_Clear(); result = PyObject_CallMethod( trait->handler, "error", "(OOO)", obj, name, value); Py_XDECREF(result); return NULL; } /*----------------------------------------------------------------------------- | Raise a fatal trait error: +----------------------------------------------------------------------------*/ static int fatal_trait_error(void) { PyErr_SetString(TraitError, "Non-trait found in trait dictionary"); return -1; } /*----------------------------------------------------------------------------- | Raise an "attribute is not a string" error: +----------------------------------------------------------------------------*/ static int invalid_attribute_error(PyObject *name) { const char *fmt = "attribute name must be an instance of . " "Got %R (%.200s)."; PyErr_Format(PyExc_TypeError, fmt, name, Py_TYPE(name)->tp_name); return -1; } /*----------------------------------------------------------------------------- | Raise an "cant set items error" error: +----------------------------------------------------------------------------*/ static PyObject * cant_set_items_error(void) { PyErr_SetString(TraitError, "Can not set a collection's '_items' trait."); return NULL; } /*----------------------------------------------------------------------------- | Raise an "invalid trait definition" error: +----------------------------------------------------------------------------*/ static int bad_trait_value_error(void) { PyErr_SetString( TraitError, "Result of 'as_ctrait' method was not a 'CTraits' instance."); return -1; } /*----------------------------------------------------------------------------- | Raise an invalid delegate error: +----------------------------------------------------------------------------*/ static int bad_delegate_error(has_traits_object *obj, PyObject *name) { if (!PyUnicode_Check(name)) { return invalid_attribute_error(name); } PyErr_Format( DelegationError, "The '%.400U' attribute of a '%.50s' object" " delegates to an attribute which is not a defined trait.", name, Py_TYPE(obj)->tp_name); return -1; } /*----------------------------------------------------------------------------- | Raise an invalid delegate error: +----------------------------------------------------------------------------*/ static int bad_delegate_error2(has_traits_object *obj, PyObject *name) { if (!PyUnicode_Check(name)) { return invalid_attribute_error(name); } PyErr_Format( DelegationError, "The '%.400U' attribute of a '%.50s' object" " has a delegate which does not have traits.", name, Py_TYPE(obj)->tp_name); return -1; } /*----------------------------------------------------------------------------- | Raise a delegation recursion error: +----------------------------------------------------------------------------*/ static int delegation_recursion_error(has_traits_object *obj, PyObject *name) { if (!PyUnicode_Check(name)) { return invalid_attribute_error(name); } PyErr_Format( DelegationError, "Delegation recursion limit exceeded while setting" " the '%.400U' attribute of a '%.50s' object.", name, Py_TYPE(obj)->tp_name); return -1; } static int delegation_recursion_error2(has_traits_object *obj, PyObject *name) { if (!PyUnicode_Check(name)) { return invalid_attribute_error(name); } PyErr_Format( DelegationError, "Delegation recursion limit exceeded while getting" " the definition of the '%.400U' attribute of a '%.50s' object.", name, Py_TYPE(obj)->tp_name); return -1; } /*----------------------------------------------------------------------------- | Raise an attempt to delete read-only attribute error: +----------------------------------------------------------------------------*/ static int delete_readonly_error(has_traits_object *obj, PyObject *name) { if (!PyUnicode_Check(name)) { return invalid_attribute_error(name); } PyErr_Format( TraitError, "Cannot delete the read only '%.400U' attribute of a '%.50s' object.", name, Py_TYPE(obj)->tp_name); return -1; } /*----------------------------------------------------------------------------- | Raise an attempt to set a read-only attribute error: +----------------------------------------------------------------------------*/ static int set_readonly_error(has_traits_object *obj, PyObject *name) { if (!PyUnicode_Check(name)) { return invalid_attribute_error(name); } PyErr_Format( TraitError, "Cannot modify the read only '%.400U' attribute of a '%.50s' object.", name, Py_TYPE(obj)->tp_name); return -1; } /*----------------------------------------------------------------------------- | Raise an attempt to set an undefined attribute error: +----------------------------------------------------------------------------*/ static int set_disallow_error(has_traits_object *obj, PyObject *name) { if (!PyUnicode_Check(name)) { return invalid_attribute_error(name); } PyErr_Format( TraitError, "Cannot set the undefined '%.400U' attribute of a '%.50s' object.", name, Py_TYPE(obj)->tp_name); return -1; } /*----------------------------------------------------------------------------- | Raise an attempt to delete a property error: +----------------------------------------------------------------------------*/ static int set_delete_property_error(has_traits_object *obj, PyObject *name) { if (!PyUnicode_Check(name)) { return invalid_attribute_error(name); } PyErr_Format( TraitError, "Cannot delete the '%.400U' property of a '%.50s' object.", name, Py_TYPE(obj)->tp_name); return -1; } /*----------------------------------------------------------------------------- | Raise an undefined attribute error: +----------------------------------------------------------------------------*/ static void unknown_attribute_error(has_traits_object *obj, PyObject *name) { PyErr_Format( PyExc_AttributeError, "'%.50s' object has no attribute '%.400U'", Py_TYPE(obj)->tp_name, name); } /*----------------------------------------------------------------------------- | Raise a '__dict__' must be set to a dictionary error: +----------------------------------------------------------------------------*/ static int dictionary_error(void) { PyErr_SetString(PyExc_TypeError, "__dict__ must be set to a dictionary."); return -1; } /*----------------------------------------------------------------------------- | Gets/Sets a possibly NULL (or callable) value: +----------------------------------------------------------------------------*/ static PyObject * get_value(PyObject *value) { if (value == NULL) { value = Py_None; } Py_INCREF(value); return value; } static int set_value(PyObject **field, PyObject *value) { PyObject *old_value; /* Caution: don't DECREF the old field contents until *after* the new contents are assigned, else there's a possibility for external code (triggered by the DECREF) to see an invalid field value. */ old_value = *field; Py_XINCREF(value); *field = value; Py_XDECREF(old_value); return 0; } /*----------------------------------------------------------------------------- | Gets the value of a flag on a cTrait object specified by a mask. +----------------------------------------------------------------------------*/ static PyObject * get_trait_flag(trait_object *trait, int mask) { if (trait->flags & mask) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } /*----------------------------------------------------------------------------- | Sets the value of a flag on a cTrait object specified by a mask. +----------------------------------------------------------------------------*/ static int set_trait_flag(trait_object *trait, int mask, PyObject *value) { int flag = PyObject_IsTrue(value); if (flag == -1) { return -1; } if (flag) { trait->flags |= mask; } else { trait->flags &= ~mask; } return 0; } /*----------------------------------------------------------------------------- | Returns the result of calling a specified 'class' object with 1 argument: +----------------------------------------------------------------------------*/ static PyObject * call_class( PyObject *class, trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result; PyObject *args; args = PyTuple_Pack(4, trait->handler, (PyObject *)obj, name, value); if (args == NULL) { return NULL; } result = PyObject_Call(class, args, NULL); Py_DECREF(args); return result; } /*----------------------------------------------------------------------------- | Attempts to get the value of a key in a 'known to be a dictionary' object: +----------------------------------------------------------------------------*/ static PyObject * dict_getitem(PyDictObject *dict, PyObject *key) { assert(PyDict_Check(dict)); return PyDict_GetItem((PyObject *)dict, key); } /*----------------------------------------------------------------------------- | Gets the definition of the matching prefix based trait for a specified name: | | - This should always return a trait definition unless a fatal Python error | occurs. | - The bulk of the work is delegated to a Python implemented method because | the implementation is complicated in C and does not need to be executed | very often relative to other operations. | | Note: returns a *borrowed* reference, to match dict_getitem. +----------------------------------------------------------------------------*/ static trait_object * get_prefix_trait(has_traits_object *obj, PyObject *name, int is_set) { PyObject *trait = PyObject_CallMethod( (PyObject *)obj, "__prefix_trait__", "(Oi)", name, is_set); if (trait != NULL) { assert(obj->ctrait_dict != NULL); PyDict_SetItem((PyObject *)obj->ctrait_dict, name, trait); Py_DECREF(trait); if (has_traits_setattro(obj, trait_added, name) < 0) { return NULL; } trait = get_trait(obj, name, 0); /* We return a borrowed reference, to match dict_getitem. */ Py_DECREF(trait); } return (trait_object *)trait; } /*----------------------------------------------------------------------------- | Handles the 'setattr' operation on a 'CHasTraits' instance: +----------------------------------------------------------------------------*/ static int has_traits_setattro(has_traits_object *obj, PyObject *name, PyObject *value) { trait_object *trait; if ((obj->itrait_dict == NULL) || ((trait = (trait_object *)dict_getitem(obj->itrait_dict, name)) == NULL)) { trait = (trait_object *)dict_getitem(obj->ctrait_dict, name); if ((trait == NULL) && ((trait = get_prefix_trait(obj, name, 1)) == NULL)) { return -1; } } return trait->setattr(trait, trait, obj, name, value); } /*----------------------------------------------------------------------------- | Allocates a CTrait instance: +----------------------------------------------------------------------------*/ PyObject * has_traits_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { // Call PyBaseObject_Type.tp_new to do the actual construction. // This allows things like ABCMeta machinery to work correctly // which is implemented at the C level. PyObject *new_args, *new_kwds; has_traits_object *obj; new_args = PyTuple_New(0); if (new_args == NULL) { return NULL; } new_kwds = PyDict_New(); if (new_kwds == NULL) { Py_DECREF(new_args); return NULL; } obj = (has_traits_object *)PyBaseObject_Type.tp_new( type, new_args, new_kwds); Py_DECREF(new_kwds); Py_DECREF(new_args); if (obj != NULL) { if (type->tp_dict == NULL) { PyErr_SetString(PyExc_RuntimeError, "No tp_dict"); return NULL; } obj->ctrait_dict = (PyDictObject *)PyDict_GetItem(type->tp_dict, class_traits); if (obj->ctrait_dict == NULL) { PyErr_SetString(PyExc_RuntimeError, "No ctrait_dict"); return NULL; } if (!PyDict_Check((PyObject *)obj->ctrait_dict)) { PyErr_SetString(PyExc_RuntimeError, "ctrait_dict not a dict"); return NULL; } Py_INCREF(obj->ctrait_dict); } return (PyObject *)obj; } int has_traits_init(PyObject *obj, PyObject *args, PyObject *kwds) { PyObject *key; PyObject *value; int has_listeners; Py_ssize_t i = 0; /* Make sure no non-keyword arguments were specified: */ if (!PyArg_ParseTuple(args, "")) { return -1; } /* Make sure all of the object's listeners have been set up: */ has_listeners = (PyMapping_Size(PyDict_GetItem(Py_TYPE(obj)->tp_dict, listener_traits)) > 0); if (has_listeners) { value = PyObject_CallMethod(obj, "_init_trait_listeners", NULL); if (value == NULL) { return -1; } Py_DECREF(value); } /* Make sure all of the object's observers have been set up: */ value = PyObject_CallMethod(obj, "_init_trait_observers", NULL); if (value == NULL) { return -1; } Py_DECREF(value); /* Set any traits specified in the constructor: */ if (kwds != NULL) { while (PyDict_Next(kwds, &i, &key, &value)) { if (has_traits_setattro((has_traits_object *)obj, key, value) == -1) { return -1; } } } /* Make sure all post constructor argument assignment listeners have been set up: */ if (has_listeners) { value = PyObject_CallMethod(obj, "_post_init_trait_listeners", NULL); if (value == NULL) { return -1; } Py_DECREF(value); } /* Make sure all post constructor argument assignment observers have been set up: */ value = PyObject_CallMethod(obj, "_post_init_trait_observers", NULL); if (value == NULL) { return -1; } Py_DECREF(value); /* Call the 'traits_init' method to finish up initialization: */ value = PyObject_CallMethod(obj, "traits_init", NULL); if (value == NULL) { return -1; } Py_DECREF(value); /* Indicate that the object has finished being initialized: */ ((has_traits_object *)obj)->flags |= HASTRAITS_INITED; return 0; } /*----------------------------------------------------------------------------- | Object clearing method: +----------------------------------------------------------------------------*/ static int has_traits_clear(has_traits_object *obj) { Py_CLEAR(obj->ctrait_dict); Py_CLEAR(obj->itrait_dict); Py_CLEAR(obj->notifiers); Py_CLEAR(obj->obj_dict); return 0; } /*----------------------------------------------------------------------------- | Deallocates an unused 'CHasTraits' instance: +----------------------------------------------------------------------------*/ static void has_traits_dealloc(has_traits_object *obj) { PyObject_GC_UnTrack(obj); Py_TRASHCAN_SAFE_BEGIN(obj); has_traits_clear(obj); Py_TYPE(obj)->tp_free((PyObject *)obj); Py_TRASHCAN_SAFE_END(obj); } /*----------------------------------------------------------------------------- | Garbage collector traversal method: +----------------------------------------------------------------------------*/ static int has_traits_traverse(has_traits_object *obj, visitproc visit, void *arg) { Py_VISIT(obj->ctrait_dict); Py_VISIT(obj->itrait_dict); Py_VISIT(obj->notifiers); Py_VISIT(obj->obj_dict); return 0; } /*----------------------------------------------------------------------------- | Handles the 'getattr' operation on a 'CHasTraits' instance: +----------------------------------------------------------------------------*/ static PyObject * has_traits_getattro(has_traits_object *obj, PyObject *name) { trait_object *trait; PyObject *value; /* The following is a performance hack to short-circuit the normal look-up when the value is in the object's dictionary. */ PyDictObject *dict = (PyDictObject *)obj->obj_dict; if (dict != NULL) { assert(PyDict_Check(dict)); if (!PyUnicode_Check(name)) { invalid_attribute_error(name); return NULL; } value = PyDict_GetItem((PyObject *)dict, name); if (value != NULL) { Py_INCREF(value); return value; } } /* End of performance hack */ if (((obj->itrait_dict != NULL) && ((trait = (trait_object *)dict_getitem(obj->itrait_dict, name)) != NULL)) || ((trait = (trait_object *)dict_getitem(obj->ctrait_dict, name)) != NULL)) { return trait->getattr(trait, obj, name); } /* Try normal Python attribute access, but if it fails with an AttributeError then get a prefix trait. */ value = PyObject_GenericGetAttr((PyObject *)obj, name); if (value != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError)) { return value; } PyErr_Clear(); if ((trait = get_prefix_trait(obj, name, 0)) != NULL) { return trait->getattr(trait, obj, name); } return NULL; } /*----------------------------------------------------------------------------- | Returns (and optionally creates) a specified instance or class trait: +----------------------------------------------------------------------------*/ static PyObject * get_trait(has_traits_object *obj, PyObject *name, int instance) { int i, n; PyDictObject *itrait_dict; trait_object *trait; trait_object *itrait; PyListObject *notifiers; PyListObject *inotifiers; PyObject *item; /* If there already is an instance specific version of the requested trait, then return it: */ itrait_dict = obj->itrait_dict; if (itrait_dict != NULL) { trait = (trait_object *)dict_getitem(itrait_dict, name); if (trait != NULL) { assert(PyTrait_CheckExact(trait)); Py_INCREF(trait); return (PyObject *)trait; } } /* If only an instance trait can be returned (but not created), then return None: */ if (instance == 1) { Py_INCREF(Py_None); return Py_None; } /* Otherwise, get the class specific version of the trait (creating a trait class version if necessary): */ assert(obj->ctrait_dict != NULL); trait = (trait_object *)dict_getitem(obj->ctrait_dict, name); if (trait == NULL) { if (instance == 0) { Py_INCREF(Py_None); return Py_None; } if ((trait = get_prefix_trait(obj, name, 0)) == NULL) { return NULL; } } assert(PyTrait_CheckExact(trait)); /* If an instance specific trait is not needed, return the class trait: */ if (instance <= 0) { Py_INCREF(trait); return (PyObject *)trait; } /* Otherwise, create an instance trait dictionary if it does not exist: */ if (itrait_dict == NULL) { obj->itrait_dict = itrait_dict = (PyDictObject *)PyDict_New(); if (itrait_dict == NULL) { return NULL; } } /* Create a new instance trait and clone the class trait into it: */ itrait = (trait_object *)PyType_GenericAlloc(ctrait_type, 0); trait_clone(itrait, trait); itrait->obj_dict = trait->obj_dict; Py_XINCREF(itrait->obj_dict); /* Copy the class trait's notifier list into the instance trait: */ if ((notifiers = trait->notifiers) != NULL) { n = PyList_GET_SIZE(notifiers); itrait->notifiers = inotifiers = (PyListObject *)PyList_New(n); if (inotifiers == NULL) { return NULL; } for (i = 0; i < n; i++) { item = PyList_GET_ITEM(notifiers, i); PyList_SET_ITEM(inotifiers, i, item); Py_INCREF(item); } } /* Add the instance trait to the instance's trait dictionary and return the instance trait if successful: */ if (PyDict_SetItem((PyObject *)itrait_dict, name, (PyObject *)itrait) >= 0) { return (PyObject *)itrait; } /* Otherwise, indicate that an error ocurred updating the dictionary: */ return NULL; } /*----------------------------------------------------------------------------- | Returns (and optionally creates) a specified instance or class trait: | | The legal values for 'instance' are: | 2: Return instance trait (force creation if it does not exist) | 1: Return existing instance trait (do not create) | 0: Return existing instance or class trait (do not create) | -1: Return instance trait or force create class trait (i.e. prefix trait) | -2: Return the base trait (after all delegation has been resolved) +----------------------------------------------------------------------------*/ static PyObject * _has_traits_trait(has_traits_object *obj, PyObject *args) { has_traits_object *delegate; has_traits_object *temp_delegate; trait_object *trait; PyObject *name; PyObject *daname; PyObject *daname2; PyObject *dict; int i, instance; /* Parse arguments, which specify the trait name and whether or not an instance specific version of the trait is needed or not: */ if (!PyArg_ParseTuple(args, "Oi", &name, &instance)) { return NULL; } trait = (trait_object *)get_trait(obj, name, instance); if ((instance >= -1) || (trait == NULL)) { return (PyObject *)trait; } /* Follow the delegation chain until we find a non-delegated trait: */ delegate = obj; Py_INCREF(delegate); daname = name; Py_INCREF(daname); for (i = 0;;) { if (trait->delegate_attr_name == NULL) { Py_DECREF(delegate); Py_DECREF(daname); return (PyObject *)trait; } dict = delegate->obj_dict; temp_delegate = NULL; if (dict != NULL) { temp_delegate = (has_traits_object *)PyDict_GetItem( dict, trait->delegate_name); /* PyDict_GetItem returns a borrowed reference, so we need to INCREF. */ Py_XINCREF(temp_delegate); } if (temp_delegate == NULL) { /* has_traits_getattro returns a new reference, so no need to INCREF. */ temp_delegate = (has_traits_object *)has_traits_getattro( delegate, trait->delegate_name); } if (temp_delegate == NULL) { break; } Py_DECREF(delegate); delegate = temp_delegate; if (!PyHasTraits_Check(delegate)) { bad_delegate_error2(obj, name); break; } daname2 = trait->delegate_attr_name(trait, obj, daname); Py_DECREF(daname); daname = daname2; Py_DECREF(trait); if (((delegate->itrait_dict == NULL) || ((trait = (trait_object *)dict_getitem( delegate->itrait_dict, daname)) == NULL)) && ((trait = (trait_object *)dict_getitem( delegate->ctrait_dict, daname)) == NULL) && ((trait = get_prefix_trait(delegate, daname2, 0)) == NULL)) { bad_delegate_error(obj, name); break; } if (Py_TYPE(trait) != ctrait_type) { fatal_trait_error(); break; } if (++i >= 100) { delegation_recursion_error2(obj, name); break; } Py_INCREF(trait); } Py_DECREF(delegate); Py_DECREF(daname); return NULL; } /*----------------------------------------------------------------------------- | Calls notifiers when a trait 'property' is explicitly changed: +----------------------------------------------------------------------------*/ static int trait_property_changed( has_traits_object *obj, PyObject *name, PyObject *old_value, PyObject *new_value) { trait_object *trait; PyListObject *tnotifiers; PyListObject *onotifiers; int null_new_value; int rc = 0; if ((trait = (trait_object *)get_trait(obj, name, -1)) == NULL) { return -1; } tnotifiers = trait->notifiers; onotifiers = obj->notifiers; Py_DECREF(trait); if (has_notifiers(tnotifiers, onotifiers)) { null_new_value = (new_value == NULL); if (null_new_value) { new_value = has_traits_getattro(obj, name); if (new_value == NULL) { return -1; } } rc = call_notifiers( tnotifiers, onotifiers, obj, name, old_value, new_value); if (null_new_value) { Py_DECREF(new_value); } } return rc; } /*----------------------------------------------------------------------------- | Calls notifiers when a trait 'property' is explicitly changed: +----------------------------------------------------------------------------*/ static PyObject * _has_traits_property_changed(has_traits_object *obj, PyObject *args) { PyObject *name, *old_value; PyObject *new_value = NULL; /* Parse arguments, which specify the name of the changed trait, the previous value, and the new value: */ if (!PyArg_ParseTuple(args, "OO|O", &name, &old_value, &new_value)) { return NULL; } if (trait_property_changed(obj, name, old_value, new_value)) { return NULL; } Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | Handles firing a traits 'xxx_items' event: +----------------------------------------------------------------------------*/ static PyObject * _has_traits_items_event(has_traits_object *obj, PyObject *args) { PyObject *name; PyObject *event_object; PyObject *event_trait; PyObject *result; trait_object *trait; int can_retry = 1; if (!PyArg_ParseTuple(args, "OOO", &name, &event_object, &event_trait)) { return NULL; } if (!PyTrait_CheckExact(event_trait)) { bad_trait_value_error(); return NULL; } if (!PyUnicode_Check(name)) { invalid_attribute_error(name); return NULL; } retry: if (((obj->itrait_dict == NULL) || ((trait = (trait_object *)dict_getitem(obj->itrait_dict, name)) == NULL)) && ((trait = (trait_object *)dict_getitem(obj->ctrait_dict, name)) == NULL)) { add_trait: if (!can_retry) { return cant_set_items_error(); } result = PyObject_CallMethod( (PyObject *)obj, "add_trait", "(OO)", name, event_trait); if (result == NULL) { return NULL; } Py_DECREF(result); can_retry = 0; goto retry; } if (trait->setattr == setattr_disallow) { goto add_trait; } if (trait->setattr(trait, trait, obj, name, event_object) < 0) { return NULL; } Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | Reports whether trait change notifications are enabled for this object: +----------------------------------------------------------------------------*/ static PyObject * _has_traits_notifications_enabled( has_traits_object *obj, PyObject *Py_UNUSED(ignored)) { if (obj->flags & HASTRAITS_NO_NOTIFY) { Py_RETURN_FALSE; } else { Py_RETURN_TRUE; } } /*----------------------------------------------------------------------------- | Enables/Disables trait change notification for the object: +----------------------------------------------------------------------------*/ static PyObject * _has_traits_change_notify(has_traits_object *obj, PyObject *args) { int enabled; /* Parse arguments, which specify the new trait notification enabled/disabled state: */ if (!PyArg_ParseTuple(args, "p", &enabled)) { return NULL; } if (enabled) { obj->flags &= ~HASTRAITS_NO_NOTIFY; } else { obj->flags |= HASTRAITS_NO_NOTIFY; } Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | Reports whether trait change notifications are enabled when this object is | assigned to a trait: +----------------------------------------------------------------------------*/ static PyObject * _has_traits_notifications_vetoed( has_traits_object *obj, PyObject *Py_UNUSED(ignored)) { if (obj->flags & HASTRAITS_VETO_NOTIFY) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } /*----------------------------------------------------------------------------- | Enables/Disables trait change notifications when this object is assigned to | a trait: +----------------------------------------------------------------------------*/ static PyObject * _has_traits_veto_notify(has_traits_object *obj, PyObject *args) { int enabled; /* Parse arguments, which specify the new trait notification veto enabled/disabled state: */ if (!PyArg_ParseTuple(args, "p", &enabled)) { return NULL; } if (enabled) { obj->flags |= HASTRAITS_VETO_NOTIFY; } else { obj->flags &= ~HASTRAITS_VETO_NOTIFY; } Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | This method is called at the end of a HasTraits constructor and the | __setstate__ method to perform any final object initialization needed. +----------------------------------------------------------------------------*/ static PyObject * _has_traits_init(has_traits_object *obj, PyObject *Py_UNUSED(ignored)) { Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | Returns whether or not the object has finished being initialized. +----------------------------------------------------------------------------*/ static PyObject * _has_traits_inited(has_traits_object *obj, PyObject *Py_UNUSED(ignored)) { if (obj->flags & HASTRAITS_INITED) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } /*----------------------------------------------------------------------------- | Declare whether the has traits object has been initialized. +----------------------------------------------------------------------------*/ static PyObject * _has_traits_set_inited(has_traits_object *obj, PyObject *Py_UNUSED(ignored)) { obj->flags |= HASTRAITS_INITED; Py_RETURN_NONE; } /*----------------------------------------------------------------------------- | Returns the instance trait dictionary: +----------------------------------------------------------------------------*/ static PyObject * _has_traits_instance_traits( has_traits_object *obj, PyObject *Py_UNUSED(ignored)) { if (obj->itrait_dict == NULL) { obj->itrait_dict = (PyDictObject *)PyDict_New(); } Py_XINCREF(obj->itrait_dict); return (PyObject *)obj->itrait_dict; } /*----------------------------------------------------------------------------- | Returns the class trait dictionary: +----------------------------------------------------------------------------*/ static PyObject * _has_traits_class_traits(has_traits_object *obj, PyObject *Py_UNUSED(ignored)) { PyObject *ctrait_dict; ctrait_dict = (PyObject *)obj->ctrait_dict; Py_INCREF(ctrait_dict); return ctrait_dict; } /*----------------------------------------------------------------------------- | Returns (and optionally creates) the anytrait 'notifiers' list: +----------------------------------------------------------------------------*/ static PyObject * _has_traits_notifiers(has_traits_object *obj, PyObject *args) { PyObject *result; PyObject *list; int force_create; if (!PyArg_ParseTuple(args, "p", &force_create)) { return NULL; } result = (PyObject *)obj->notifiers; if (result == NULL) { if (force_create) { list = PyList_New(0); if (list == NULL) { return NULL; } obj->notifiers = (PyListObject *)list; result = list; } else { result = Py_None; } } Py_INCREF(result); return result; } /*----------------------------------------------------------------------------- | Returns the object's instance dictionary: +----------------------------------------------------------------------------*/ static PyObject * get_has_traits_dict(has_traits_object *obj, void *closure) { PyObject *obj_dict = obj->obj_dict; if (obj_dict == NULL) { obj->obj_dict = obj_dict = PyDict_New(); if (obj_dict == NULL) { return NULL; } } Py_INCREF(obj_dict); return obj_dict; } /*----------------------------------------------------------------------------- | Sets the object's dictionary: +----------------------------------------------------------------------------*/ static int set_has_traits_dict(has_traits_object *obj, PyObject *value, void *closure) { if (!PyDict_Check(value)) { return dictionary_error(); } return set_value(&obj->obj_dict, value); } /*----------------------------------------------------------------------------- | 'CHasTraits' instance methods: +----------------------------------------------------------------------------*/ PyDoc_STRVAR( has_traits_trait_property_changed_doc, "trait_property_changed(name, old_value[, new_value])\n" "\n" "Call notifiers when a trait property value is explicitly changed.\n" "\n" "Calls trait and object notifiers for a property value change.\n" "\n" "Parameters\n" "----------\n" "name : str\n" " Name of the trait whose value has changed\n" "old_value : any\n" " Old value for this trait.\n" "new_value : any, optional\n" " New value for this trait. If the new value is not provided,\n" " it's looked up on the object.\n"); PyDoc_STRVAR( has_traits_trait_items_event_doc, "trait_items_event(name, event_object, event_trait)\n" "\n" "Fire an items event for changes to a Traits collection.\n" "\n" "Parameters\n" "----------\n" "name : str\n" " Name of the item trait for which an event is being fired. (The name\n" " will usually end in '_items'.)\n" "event_object : object\n" " Object of type ``TraitListEvent``, ``TraitDictEvent`` or ``TraitSetEvent``\n" " describing the changes to the underlying collection trait value.\n" "event_trait : CTrait\n" " The items trait, of trait type ``Event``.\n"); PyDoc_STRVAR( has_traits__trait_change_notify_doc, "_trait_change_notify(enabled)\n" "\n" "Enable or disable trait change notifications for this object.\n" "\n" "Parameters\n" "----------\n" "enabled : bool\n" " If true, enable trait change notifications for this object.\n" " If false, disable trait change notifications for this object.\n"); PyDoc_STRVAR( has_traits__trait_veto_notify_doc, "_trait_veto_notify(vetoed)\n" "\n" "Enable or disable vetoing of trait change notifications by this object.\n" "\n" "Parameters\n" "----------\n" "vetoed : bool\n" " If true, veto trait change notifications for this object: no\n" " notifications will be issued when this object is assigned to\n" " a trait. If false, notifications will be issued as usual.\n"); PyDoc_STRVAR( _trait_notifications_enabled_doc, "_trait_notifications_enabled()\n" "\n" "Report whether trait notifications are enabled for this object.\n" "\n" "Notifications can be enabled or disabled using the " "``_trait_change_notify``\n" "method. By default, notifications are enabled.\n" "\n" "Returns\n" "-------\n" "enabled : bool\n" " True if notifications are currently enabled for this object, else " "False.\n"); PyDoc_STRVAR( _trait_notifications_vetoed_doc, "_trait_notifications_vetoed()\n" "\n" "Report whether trait notifications are vetoed for this object.\n" "\n" "If trait notifications are vetoed for an object, assignment of that " "object\n" "to a trait will not generate a notification.\n" "This setting can be enabled or disabled using the " "``_trait_veto_notify``\n" "method. By default, notifications are not vetoed.\n" "\n" "Returns\n" "-------\n" "vetoed : bool\n" " True if notifications are currently vetoed for this object, else " "False.\n"); PyDoc_STRVAR( has_traits_traits_init_doc, "traits_init()\n" "\n" "Perform any final object initialization needed.\n" "\n" "For the CHasTraits base class, this method currently does nothing.\n"); PyDoc_STRVAR( has_traits_traits_inited_doc, "traits_inited()\n" "\n" "Get the initialization state of this object.\n" "\n" "Returns\n" "-------\n" "initialized : bool\n" " True if the object is initialized, else False.\n"); PyDoc_STRVAR( has_traits__trait_set_inited_doc, "_trait_set_inited()\n" "\n" "Declare that this object has been initialized.\n"); PyDoc_STRVAR( has_traits__trait_doc, "_trait(name, instance)\n" "\n" "Return and optionally create a specified instance or class trait.\n" "\n" "Parameters\n" "----------\n" "name : str\n" " Name of the trait to be retrieved or created.\n" "instance : int\n" " An integer determining the action to be taken. One of\n" " {-2, -1, 0, 1, 2}. The meaning of the values is as follows:\n" "\n" " 2\n" " Return an instance trait, creating a new trait if none exists.\n" " 1\n" " Return an existing instance trait. Do not create a new trait.\n" " 0\n" " Return an existing instance or class trait. Do not create a\n" " new trait.\n" " -1\n" " Return an instance trait, or create a new class trait if no\n" " instance trait exists.\n" " -2\n" " Return the base trait after resolving delegation.\n"); PyDoc_STRVAR( has_traits__instance_traits_doc, "_instance_traits()\n" "\n" "Return this object's instance traits dictionary.\n" "\n" "The object's instance traits dictionary is created if it doesn't\n" "already exist.\n" "\n" "Returns\n" "-------\n" "instance_traits : dict\n" " Dictionary mapping trait names to corresponding CTrait instances.\n"); PyDoc_STRVAR( has_traits__class_traits_doc, "_instance_traits()\n" "\n" "Return this object's class traits dictionary.\n" "\n" "Returns\n" "-------\n" "class_traits : dict\n" " Dictionary mapping trait names to corresponding CTrait instances.\n"); PyDoc_STRVAR( has_traits__notifiers_doc, "_notifiers(force_create)\n" "\n" "Return (and optionally create) the list of notifiers for this object.\n" "\n" "Parameters\n" "----------\n" "force_create : bool\n" " Whether to automatically create the list of notifiers, if it\n" " doesn't exist yet.\n" "\n" "Returns\n" "-------\n" "notifiers : list of callables, or None\n" " If the trait has no notifiers and *force_create* is false, return\n" " None. Otherwise, return the list of notifiers for this object,\n" " creating it first if necessary. Each notifier is a callable\n" " accepting four arguments (object, trait_name, old, new).\n"); static PyMethodDef has_traits_methods[] = { { "trait_property_changed", (PyCFunction)_has_traits_property_changed, METH_VARARGS, has_traits_trait_property_changed_doc }, { "trait_items_event", (PyCFunction)_has_traits_items_event, METH_VARARGS, has_traits_trait_items_event_doc }, { "_trait_change_notify", (PyCFunction)_has_traits_change_notify, METH_VARARGS, has_traits__trait_change_notify_doc }, { "_trait_notifications_enabled", (PyCFunction)_has_traits_notifications_enabled, METH_NOARGS, _trait_notifications_enabled_doc, }, { "_trait_veto_notify", (PyCFunction)_has_traits_veto_notify, METH_VARARGS, has_traits__trait_veto_notify_doc }, { "_trait_notifications_vetoed", (PyCFunction)_has_traits_notifications_vetoed, METH_NOARGS, _trait_notifications_vetoed_doc, }, { "traits_init", (PyCFunction)_has_traits_init, METH_NOARGS, has_traits_traits_init_doc }, { "traits_inited", (PyCFunction)_has_traits_inited, METH_VARARGS, has_traits_traits_inited_doc }, { "_trait_set_inited", (PyCFunction)_has_traits_set_inited, METH_NOARGS, has_traits__trait_set_inited_doc }, { "_trait", (PyCFunction)_has_traits_trait, METH_VARARGS, has_traits__trait_doc }, { "_instance_traits", (PyCFunction)_has_traits_instance_traits, METH_NOARGS, has_traits__instance_traits_doc }, { "_class_traits", (PyCFunction)_has_traits_class_traits, METH_NOARGS, has_traits__class_traits_doc }, { "_notifiers", (PyCFunction)_has_traits_notifiers, METH_VARARGS, has_traits__notifiers_doc }, {NULL, NULL}, }; /*----------------------------------------------------------------------------- | 'CHasTraits' property definitions: +----------------------------------------------------------------------------*/ static PyGetSetDef has_traits_properties[] = { {"__dict__", (getter)get_has_traits_dict, (setter)set_has_traits_dict}, {0}}; /*----------------------------------------------------------------------------- | 'CHasTraits' type definition: +----------------------------------------------------------------------------*/ PyDoc_STRVAR( c_has_traits_doc, "Base class for HasTraits.\n" "\n" "The CHasTraits class is not intended to be instantiated directly.\n" "Instead, it serves as a base class for the HasTraits class.\n" "\n" "Parameters\n" "----------\n" "**traits : dict\n" " Dictionary mapping trait names to trait values.\n" ); static PyTypeObject has_traits_type = { PyVarObject_HEAD_INIT(NULL, 0) "traits.ctraits.CHasTraits", sizeof(has_traits_object), 0, (destructor)has_traits_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ (getattrofunc)has_traits_getattro, /* tp_getattro */ (setattrofunc)has_traits_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ c_has_traits_doc, /* tp_doc */ (traverseproc)has_traits_traverse, /* tp_traverse */ (inquiry)has_traits_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ has_traits_methods, /* tp_methods */ 0, /* tp_members */ has_traits_properties, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ sizeof(has_traits_object) - sizeof(PyObject *), /* tp_dictoffset */ has_traits_init, /* tp_init */ 0, /* tp_alloc */ has_traits_new /* tp_new */ }; /*----------------------------------------------------------------------------- | Returns the default value associated with a specified trait: +----------------------------------------------------------------------------*/ static PyObject * default_value_for(trait_object *trait, has_traits_object *obj, PyObject *name) { PyObject *result = NULL, *value, *dv, *kw, *tuple; switch (trait->default_value_type) { case CONSTANT_DEFAULT_VALUE: case MISSING_DEFAULT_VALUE: result = trait->default_value; if (result == NULL) { result = Py_None; } Py_INCREF(result); break; case OBJECT_DEFAULT_VALUE: result = (PyObject *)obj; Py_INCREF(obj); break; case LIST_COPY_DEFAULT_VALUE: return PySequence_List(trait->default_value); case DICT_COPY_DEFAULT_VALUE: return PyDict_Copy(trait->default_value); case TRAIT_LIST_OBJECT_DEFAULT_VALUE: return call_class( TraitListObject, trait, obj, name, trait->default_value); case TRAIT_DICT_OBJECT_DEFAULT_VALUE: return call_class( TraitDictObject, trait, obj, name, trait->default_value); case CALLABLE_AND_ARGS_DEFAULT_VALUE: dv = trait->default_value; kw = PyTuple_GET_ITEM(dv, 2); if (kw == Py_None) { kw = NULL; } return PyObject_Call( PyTuple_GET_ITEM(dv, 0), PyTuple_GET_ITEM(dv, 1), kw); case CALLABLE_DEFAULT_VALUE: tuple = PyTuple_Pack(1, (PyObject *)obj); if (tuple == NULL) { return NULL; } result = PyObject_Call(trait->default_value, tuple, NULL); Py_DECREF(tuple); if ((result != NULL) && (trait->validate != NULL)) { value = trait->validate(trait, obj, name, result); if (trait->flags & TRAIT_SETATTR_ORIGINAL_VALUE) { if (value == NULL) { Py_DECREF(result); return NULL; } Py_DECREF(value); return result; } else { Py_DECREF(result); return value; } } break; case TRAIT_SET_OBJECT_DEFAULT_VALUE: return call_class( TraitSetObject, trait, obj, name, trait->default_value); case DISALLOW_DEFAULT_VALUE: PyErr_SetString( PyExc_ValueError, "default value not permitted for this trait" ); return NULL; } return result; } /*----------------------------------------------------------------------------- | Returns the value assigned to a standard Python attribute: +----------------------------------------------------------------------------*/ static PyObject * getattr_python(trait_object *trait, has_traits_object *obj, PyObject *name) { return PyObject_GenericGetAttr((PyObject *)obj, name); } /*----------------------------------------------------------------------------- | Returns the value assigned to a generic Python attribute: +----------------------------------------------------------------------------*/ static PyObject * getattr_generic(trait_object *trait, has_traits_object *obj, PyObject *name) { return PyObject_GenericGetAttr((PyObject *)obj, name); } /*----------------------------------------------------------------------------- | Returns the value assigned to an event trait: +----------------------------------------------------------------------------*/ static PyObject * getattr_event(trait_object *trait, has_traits_object *obj, PyObject *name) { PyErr_Format( PyExc_AttributeError, "The %.400U" " trait of a %.50s instance is an 'event', which is write only.", name, Py_TYPE(obj)->tp_name); return NULL; } /*----------------------------------------------------------------------------- | Returns the value assigned to a standard trait: +----------------------------------------------------------------------------*/ static PyObject * getattr_trait(trait_object *trait, has_traits_object *obj, PyObject *name) { int rc; PyListObject *tnotifiers; PyListObject *onotifiers; PyObject *result; PyObject *dict; /* This shouldn't ever happen. */ if (!PyUnicode_Check(name)) { invalid_attribute_error(name); return NULL; } /* Create the object's __dict__ if it's not already present. */ dict = obj->obj_dict; if (dict == NULL) { dict = PyDict_New(); if (dict == NULL) { return NULL; } obj->obj_dict = dict; } /* Retrieve the default value, and set it in the dict. */ result = default_value_for(trait, obj, name); if (result == NULL) { return NULL; } rc = PyDict_SetItem(dict, name, result); if (rc < 0) { goto error; } /* Call any post_setattr operations. */ if (trait->post_setattr != NULL) { rc = trait->post_setattr(trait, obj, name, result); if (rc < 0) { goto error; } } /* Call notifiers. */ tnotifiers = trait->notifiers; onotifiers = obj->notifiers; if (has_notifiers(tnotifiers, onotifiers)) { rc = call_notifiers( tnotifiers, onotifiers, obj, name, Uninitialized, result); if (rc < 0) { goto error; } } return result; error: Py_DECREF(result); return NULL; } /*----------------------------------------------------------------------------- | Returns the value assigned to a delegated trait: +----------------------------------------------------------------------------*/ static PyObject * getattr_delegate(trait_object *trait, has_traits_object *obj, PyObject *name) { PyTypeObject *tp; PyObject *delegate_attr_name; PyObject *delegate; PyObject *result; PyObject *dict = obj->obj_dict; if ((dict == NULL) || ((delegate = PyDict_GetItem(dict, trait->delegate_name)) == NULL)) { // Handle the case when the delegate is not in the instance dictionary // (could be a method that returns the real delegate): delegate = has_traits_getattro(obj, trait->delegate_name); if (delegate == NULL) { return NULL; } } else { Py_INCREF(delegate); } if (!PyUnicode_Check(name)) { invalid_attribute_error(name); Py_DECREF(delegate); return NULL; } delegate_attr_name = trait->delegate_attr_name(trait, obj, name); tp = Py_TYPE(delegate); if (tp->tp_getattro != NULL) { result = (*tp->tp_getattro)(delegate, delegate_attr_name); goto done; } PyErr_Format( DelegationError, "The '%.50s' object has no attribute '%.400U' " "because its %.50s delegate has no attribute '%.400U'.", Py_TYPE(obj)->tp_name, name, tp->tp_name, delegate_attr_name); result = NULL; done: Py_DECREF(delegate_attr_name); Py_DECREF(delegate); return result; } /*----------------------------------------------------------------------------- | Raises an exception when a disallowed trait is accessed: +----------------------------------------------------------------------------*/ static PyObject * getattr_disallow(trait_object *trait, has_traits_object *obj, PyObject *name) { if (PyUnicode_Check(name)) { unknown_attribute_error(obj, name); } else { invalid_attribute_error(name); } return NULL; } /*----------------------------------------------------------------------------- | Returns the value of a constant trait: +----------------------------------------------------------------------------*/ static PyObject * getattr_constant(trait_object *trait, has_traits_object *obj, PyObject *name) { Py_INCREF(trait->default_value); return trait->default_value; } /*----------------------------------------------------------------------------- | Assigns a value to a specified property trait attribute: +----------------------------------------------------------------------------*/ static PyObject * getattr_property0(trait_object *trait, has_traits_object *obj, PyObject *name) { PyObject *result; PyObject *args = PyTuple_New(0); if (args == NULL) { return NULL; } result = PyObject_Call(trait->delegate_name, args, NULL); Py_DECREF(args); return result; } static PyObject * getattr_property1(trait_object *trait, has_traits_object *obj, PyObject *name) { PyObject *result; PyObject *args = PyTuple_Pack(1, (PyObject *)obj); if (args == NULL) { return NULL; } result = PyObject_Call(trait->delegate_name, args, NULL); Py_DECREF(args); return result; } static PyObject * getattr_property2(trait_object *trait, has_traits_object *obj, PyObject *name) { PyObject *result; PyObject *args = PyTuple_Pack(2, (PyObject *)obj, name); if (args == NULL) { return NULL; } result = PyObject_Call(trait->delegate_name, args, NULL); Py_DECREF(args); return result; } static PyObject * getattr_property3(trait_object *trait, has_traits_object *obj, PyObject *name) { PyObject *result; PyObject *args = PyTuple_Pack(3, (PyObject *)obj, name, (PyObject *)trait); if (args == NULL) { return NULL; } result = PyObject_Call(trait->delegate_name, args, NULL); Py_DECREF(args); return result; } static trait_getattr getattr_property_handlers[] = { getattr_property0, getattr_property1, getattr_property2, getattr_property3}; /*----------------------------------------------------------------------------- | Assigns a value to a specified standard Python attribute: +----------------------------------------------------------------------------*/ static int setattr_python( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *dict = obj->obj_dict; if (value != NULL) { if (dict == NULL) { dict = PyDict_New(); if (dict == NULL) { return -1; } obj->obj_dict = dict; } if (!PyUnicode_Check(name)) { return invalid_attribute_error(name); } if (PyDict_SetItem(dict, name, value) >= 0) { return 0; } if (PyErr_ExceptionMatches(PyExc_KeyError)) { PyErr_SetObject(PyExc_AttributeError, name); } return -1; } if (dict != NULL) { if (!PyUnicode_Check(name)) { return invalid_attribute_error(name); } if (PyDict_DelItem(dict, name) >= 0) { return 0; } if (PyErr_ExceptionMatches(PyExc_KeyError)) { unknown_attribute_error(obj, name); } return -1; } if (PyUnicode_Check(name)) { unknown_attribute_error(obj, name); return -1; } return invalid_attribute_error(name); } /*----------------------------------------------------------------------------- | Assigns a value to a specified generic Python attribute: +----------------------------------------------------------------------------*/ static int setattr_generic( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { return PyObject_GenericSetAttr((PyObject *)obj, name, value); } /*----------------------------------------------------------------------------- | Call all notifiers for a specified trait: | | Parameters | ---------- | tnotifiers : NULL or a list of callables. | Notifiers attached to the trait. | onotifiers : NULL or a list of callables. | Notifiers attached to the HasTraits instance. | obj : instance of HasTraits | Instance on which the trait changed. | name : str | Name of the trait changed. | old_value : any | Value of the trait before the change. | new_value : any | Value of the trait after the change. | | Returns | ------- | return_code : int | 0 indicates success. | -1 indicates unexpected errors. +----------------------------------------------------------------------------*/ static int call_notifiers( PyListObject *tnotifiers, PyListObject *onotifiers, has_traits_object *obj, PyObject *name, PyObject *old_value, PyObject *new_value) { Py_ssize_t i, t_len, o_len; int new_value_has_traits; PyObject *result, *item, *all_notifiers, *args; int rc = 0; // Do nothing if the user has explicitly requested no traits notifications // to be sent. if (obj->flags & HASTRAITS_NO_NOTIFY) { return rc; } args = PyTuple_Pack(4, (PyObject *)obj, name, old_value, new_value); if (args == NULL) { return -1; } new_value_has_traits = PyHasTraits_Check(new_value); if (tnotifiers != NULL) { t_len = PyList_GET_SIZE(tnotifiers); } else { t_len = 0; } if (onotifiers != NULL) { o_len = PyList_GET_SIZE(onotifiers); } else { o_len = 0; } // Concatenating trait notifiers and object notifiers. // Notifier lists are copied in order to prevent run-time modifications. all_notifiers = PyList_New(t_len + o_len); if (all_notifiers == NULL) { rc = -1; goto exit; } for (i = 0; i < t_len; i++) { item = PyList_GET_ITEM(tnotifiers, i); PyList_SET_ITEM(all_notifiers, i, item); Py_INCREF(item); } for (i = 0; i < o_len; i++) { item = PyList_GET_ITEM(onotifiers, i); PyList_SET_ITEM(all_notifiers, i + t_len, item); Py_INCREF(item); } for (i = 0; i < t_len + o_len; i++) { if (new_value_has_traits && ((has_traits_object *)new_value)->flags & HASTRAITS_VETO_NOTIFY) { break; } result = PyObject_Call(PyList_GET_ITEM(all_notifiers, i), args, NULL); if (result == NULL) { rc = -1; break; } Py_DECREF(result); } Py_DECREF(all_notifiers); exit: Py_DECREF(args); return rc; } /*----------------------------------------------------------------------------- | Assigns a value to a specified event trait attribute: +----------------------------------------------------------------------------*/ static int setattr_event( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { int rc = 0; PyListObject *tnotifiers; PyListObject *onotifiers; if (value != NULL) { if (traitd->validate != NULL) { value = traitd->validate(traitd, obj, name, value); if (value == NULL) { return -1; } } else { Py_INCREF(value); } tnotifiers = traito->notifiers; onotifiers = obj->notifiers; if (has_notifiers(tnotifiers, onotifiers)) { rc = call_notifiers( tnotifiers, onotifiers, obj, name, Undefined, value); } Py_DECREF(value); } return rc; } /*----------------------------------------------------------------------------- | Assigns a value to a specified normal trait attribute: +----------------------------------------------------------------------------*/ static int setattr_trait( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { int rc; int changed; int do_notifiers; trait_post_setattr post_setattr; PyListObject *tnotifiers = NULL; PyListObject *onotifiers = NULL; PyObject *old_value = NULL; PyObject *original_value; PyObject *new_value; PyObject *dict = obj->obj_dict; changed = (traitd->flags & TRAIT_COMPARISON_MODE_NONE); if (value == NULL) { if (dict == NULL) { return 0; } if (!PyUnicode_Check(name)) { return invalid_attribute_error(name); } old_value = PyDict_GetItem(dict, name); if (old_value == NULL) { return 0; } Py_INCREF(old_value); if (PyDict_DelItem(dict, name) < 0) { Py_DECREF(old_value); return -1; } rc = 0; if (!(obj->flags & HASTRAITS_NO_NOTIFY)) { tnotifiers = traito->notifiers; onotifiers = obj->notifiers; if ((tnotifiers != NULL) || (onotifiers != NULL)) { value = traito->getattr(traito, obj, name); if (value == NULL) { Py_DECREF(old_value); return -1; } if (!changed) { changed = (old_value != value); } if (changed) { if (traitd->post_setattr != NULL) { rc = traitd->post_setattr(traitd, obj, name, value); } if ((rc == 0) && has_notifiers(tnotifiers, onotifiers)) { rc = call_notifiers( tnotifiers, onotifiers, obj, name, old_value, value); } } Py_DECREF(value); } } Py_DECREF(old_value); return rc; } original_value = value; // If the object's value is Undefined, then do not call the validate // method (as the object's value has not yet been set). if ((traitd->validate != NULL) && (value != Undefined)) { value = traitd->validate(traitd, obj, name, value); if (value == NULL) { return -1; } } else { Py_INCREF(value); } if (dict == NULL) { obj->obj_dict = dict = PyDict_New(); if (dict == NULL) { Py_DECREF(value); return -1; } } if (!PyUnicode_Check(name)) { Py_DECREF(value); return invalid_attribute_error(name); } new_value = (traitd->flags & TRAIT_SETATTR_ORIGINAL_VALUE) ? original_value : value; old_value = NULL; tnotifiers = traito->notifiers; onotifiers = obj->notifiers; do_notifiers = has_notifiers(tnotifiers, onotifiers); post_setattr = traitd->post_setattr; if ((post_setattr != NULL) || do_notifiers) { old_value = PyDict_GetItem(dict, name); if (old_value == NULL) { if (traitd != traito) { old_value = traito->getattr(traito, obj, name); if (old_value == NULL) { Py_DECREF(value); return -1; } } else { old_value = default_value_for(traitd, obj, name); if (old_value == NULL) { Py_DECREF(value); return -1; } rc = PyDict_SetItem(dict, name, old_value); if (rc < 0) { Py_DECREF(old_value); Py_DECREF(value); return -1; } if (post_setattr != NULL) { rc = post_setattr(traitd, obj, name, old_value); if (rc < 0) { Py_DECREF(old_value); Py_DECREF(value); return -1; } } } } else { Py_INCREF(old_value); } if (!changed) { changed = (old_value != value); } } if (PyDict_SetItem(dict, name, new_value) < 0) { if (PyErr_ExceptionMatches(PyExc_KeyError)) { PyErr_SetObject(PyExc_AttributeError, name); } Py_XDECREF(old_value); Py_DECREF(name); Py_DECREF(value); return -1; } rc = 0; if (changed) { if (post_setattr != NULL) { rc = post_setattr( traitd, obj, name, (traitd->flags & TRAIT_POST_SETATTR_ORIGINAL_VALUE) ? original_value : value); } if ((rc == 0) && do_notifiers) { rc = call_notifiers( tnotifiers, onotifiers, obj, name, old_value, new_value); } } Py_XDECREF(old_value); Py_DECREF(value); return rc; } /*----------------------------------------------------------------------------- | Assigns a value to a specified delegate trait attribute: +----------------------------------------------------------------------------*/ static int setattr_delegate( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *dict; PyObject *daname; PyObject *daname2; PyObject *temp; has_traits_object *delegate; has_traits_object *temp_delegate; int i, result; /* Follow the delegation chain until we find a non-delegated trait: */ daname = name; Py_INCREF(daname); delegate = obj; for (i = 0;;) { dict = delegate->obj_dict; if ((dict != NULL) && ((temp_delegate = (has_traits_object *)PyDict_GetItem( dict, traitd->delegate_name)) != NULL)) { delegate = temp_delegate; } else { // Handle the case when the delegate is not in the instance // dictionary (could be a method that returns the real delegate): delegate = (has_traits_object *)has_traits_getattro( delegate, traitd->delegate_name); if (delegate == NULL) { Py_DECREF(daname); return -1; } Py_DECREF(delegate); } // Verify that 'delegate' is of type 'CHasTraits': if (!PyHasTraits_Check(delegate)) { Py_DECREF(daname); return bad_delegate_error2(obj, name); } daname2 = traitd->delegate_attr_name(traitd, obj, daname); Py_DECREF(daname); daname = daname2; if (((delegate->itrait_dict == NULL) || ((traitd = (trait_object *)dict_getitem( delegate->itrait_dict, daname)) == NULL)) && ((traitd = (trait_object *)dict_getitem( delegate->ctrait_dict, daname)) == NULL) && ((traitd = get_prefix_trait(delegate, daname, 1)) == NULL)) { Py_DECREF(daname); return bad_delegate_error(obj, name); } if (Py_TYPE(traitd) != ctrait_type) { Py_DECREF(daname); return fatal_trait_error(); } if (traitd->delegate_attr_name == NULL) { if (traito->flags & TRAIT_MODIFY_DELEGATE) { result = traitd->setattr(traitd, traitd, delegate, daname, value); } else { result = traitd->setattr(traito, traitd, obj, name, value); if (result >= 0) { temp = PyObject_CallMethod( (PyObject *)obj, "_remove_trait_delegate_listener", "(Oi)", name, value != NULL); if (temp == NULL) { result = -1; } else { Py_DECREF(temp); } } } Py_DECREF(daname); return result; } if (++i >= 100) { return delegation_recursion_error(obj, name); } } } /*----------------------------------------------------------------------------- | Assigns a value to a specified property trait attribute: +----------------------------------------------------------------------------*/ static int setattr_property0( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result; PyObject *args; if (value == NULL) { return set_delete_property_error(obj, name); } args = PyTuple_New(0); if (args == NULL) { return -1; } result = PyObject_Call(traitd->delegate_prefix, args, NULL); if (result == NULL) { return -1; } Py_DECREF(result); return 0; } static int setattr_property1( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result; PyObject *args; if (value == NULL) { return set_delete_property_error(obj, name); } args = PyTuple_Pack(1, value); if (args == NULL) { return -1; } result = PyObject_Call(traitd->delegate_prefix, args, NULL); Py_DECREF(args); if (result == NULL) { return -1; } Py_DECREF(result); return 0; } static int setattr_property2( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result; PyObject *args; if (value == NULL) { return set_delete_property_error(obj, name); } args = PyTuple_Pack(2, (PyObject *)obj, value); if (args == NULL) { return -1; } result = PyObject_Call(traitd->delegate_prefix, args, NULL); Py_DECREF(args); if (result == NULL) { return -1; } Py_DECREF(result); return 0; } static int setattr_property3( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result; PyObject *args; if (value == NULL) { return set_delete_property_error(obj, name); } args = PyTuple_Pack(3, (PyObject *)obj, name, value); if (args == NULL) { return -1; } result = PyObject_Call(traitd->delegate_prefix, args, NULL); Py_DECREF(args); if (result == NULL) { return -1; } Py_DECREF(result); return 0; } /*----------------------------------------------------------------------------- | Validates then assigns a value to a specified property trait attribute: +----------------------------------------------------------------------------*/ static int setattr_validate_property( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { int result; PyObject *validated; if (value == NULL) { return set_delete_property_error(obj, name); } validated = traitd->validate(traitd, obj, name, value); if (validated == NULL) { return -1; } result = ((trait_setattr)traitd->post_setattr)( traito, traitd, obj, name, validated); Py_DECREF(validated); return result; } static PyObject * setattr_validate0( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *validated; PyObject *args = PyTuple_New(0); if (args == NULL) { return NULL; } validated = PyObject_Call(trait->py_validate, args, NULL); Py_DECREF(args); return validated; } static PyObject * setattr_validate1( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *validated; PyObject *args = PyTuple_Pack(1, value); if (args == NULL) { return NULL; } validated = PyObject_Call(trait->py_validate, args, NULL); Py_DECREF(args); return validated; } static PyObject * setattr_validate2( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *validated; PyObject *args = PyTuple_Pack(2, (PyObject *)obj, value); if (args == NULL) { return NULL; } validated = PyObject_Call(trait->py_validate, args, NULL); Py_DECREF(args); return validated; } static PyObject * setattr_validate3( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *validated; PyObject *args = PyTuple_Pack(3, (PyObject *)obj, name, value); if (args == NULL) { return NULL; } validated = PyObject_Call(trait->py_validate, args, NULL); Py_DECREF(args); return validated; } trait_validate setattr_validate_handlers[] = { setattr_validate0, setattr_validate1, setattr_validate2, setattr_validate3}; /*----------------------------------------------------------------------------- | Raises an exception when attempting to assign to a disallowed trait: +----------------------------------------------------------------------------*/ static int setattr_disallow( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { return set_disallow_error(obj, name); } /*----------------------------------------------------------------------------- | Assigns a value to a specified read-only trait attribute: +----------------------------------------------------------------------------*/ static int setattr_readonly( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *dict; PyObject *result; int rc; if (value == NULL) { return delete_readonly_error(obj, name); } if (traitd->default_value != Undefined) { return set_readonly_error(obj, name); } dict = obj->obj_dict; if (dict == NULL) { return setattr_python(traito, traitd, obj, name, value); } if (!PyUnicode_Check(name)) { return invalid_attribute_error(name); } result = PyDict_GetItem(dict, name); if ((result == NULL) || (result == Undefined)) { rc = setattr_python(traito, traitd, obj, name, value); } else { rc = set_readonly_error(obj, name); } return rc; } /*----------------------------------------------------------------------------- | Generates exception on attempting to assign to a constant trait: +----------------------------------------------------------------------------*/ static int setattr_constant( trait_object *traito, trait_object *traitd, has_traits_object *obj, PyObject *name, PyObject *value) { if (PyUnicode_Check(name)) { PyErr_Format( TraitError, "Cannot modify the constant '%.400U'" " attribute of a '%.50s' object.", name, Py_TYPE(obj)->tp_name); return -1; } return invalid_attribute_error(name); } /*----------------------------------------------------------------------------- | Initializes a CTrait instance: +----------------------------------------------------------------------------*/ static trait_getattr getattr_handlers[] = { getattr_trait, getattr_python, getattr_event, getattr_delegate, getattr_event, getattr_disallow, getattr_trait, getattr_constant, getattr_generic, /* The following entries are used by the __getstate__ method: */ getattr_property0, getattr_property1, getattr_property2, getattr_property3, /* End of __getstate__ method entries */ NULL}; static trait_setattr setattr_handlers[] = { setattr_trait, setattr_python, setattr_event, setattr_delegate, setattr_event, setattr_disallow, setattr_readonly, setattr_constant, setattr_generic, /* The following entries are used by the __getstate__ method: */ setattr_property0, setattr_property1, setattr_property2, setattr_property3, /* End of __setstate__ method entries */ NULL}; trait_object * trait_new(PyTypeObject *trait_type, PyObject *args, PyObject *kw) { int kind = 0; trait_object *trait; if (kw != NULL && PyDict_Size(kw) != (Py_ssize_t) 0) { PyErr_SetString(TraitError, "CTrait takes no keyword arguments"); return NULL; } if (!PyArg_ParseTuple(args, "|i", &kind)) { return NULL; } if ((kind >= 0) && (kind <= 8)) { trait = (trait_object *)PyType_GenericNew(trait_type, args, kw); trait->getattr = getattr_handlers[kind]; trait->setattr = setattr_handlers[kind]; return trait; } PyErr_Format( TraitError, "Invalid argument to trait constructor. The argument `kind` " "must be an integer between 0 and 8 but a value of %d was provided.", kind); return NULL; } /*----------------------------------------------------------------------------- | Object clearing method: +----------------------------------------------------------------------------*/ static int trait_clear(trait_object *trait) { Py_CLEAR(trait->default_value); Py_CLEAR(trait->py_validate); Py_CLEAR(trait->py_post_setattr); Py_CLEAR(trait->delegate_name); Py_CLEAR(trait->delegate_prefix); Py_CLEAR(trait->notifiers); Py_CLEAR(trait->handler); Py_CLEAR(trait->obj_dict); return 0; } /*----------------------------------------------------------------------------- | Deallocates an unused 'CTrait' instance: +----------------------------------------------------------------------------*/ static void trait_dealloc(trait_object *trait) { PyObject_GC_UnTrack(trait); Py_TRASHCAN_SAFE_BEGIN(trait); trait_clear(trait); Py_TYPE(trait)->tp_free((PyObject *)trait); Py_TRASHCAN_SAFE_END(trait); } /*----------------------------------------------------------------------------- | Garbage collector traversal method: +----------------------------------------------------------------------------*/ static int trait_traverse(trait_object *trait, visitproc visit, void *arg) { Py_VISIT(trait->default_value); Py_VISIT(trait->py_validate); Py_VISIT(trait->py_post_setattr); Py_VISIT(trait->delegate_name); Py_VISIT(trait->delegate_prefix); Py_VISIT((PyObject *)trait->notifiers); Py_VISIT(trait->handler); Py_VISIT(trait->obj_dict); return 0; } /*----------------------------------------------------------------------------- | Identify double underscore names like "__qualname__" and "__package__". | | Returns 1 if name starts and ends with "__", else 0. Returns -1 with | an exception set on failure. +----------------------------------------------------------------------------*/ static int is_dunder_name(PyObject *name) { Py_ssize_t name_length; int kind; void *data; if (PyUnicode_READY(name) < 0) { return -1; } name_length = PyUnicode_GET_LENGTH(name); kind = PyUnicode_KIND(name); data = PyUnicode_DATA(name); return ( (name_length >= 2) && (PyUnicode_READ(kind, data, 0) == '_') && (PyUnicode_READ(kind, data, 1) == '_') && (PyUnicode_READ(kind, data, name_length - 2) == '_') && (PyUnicode_READ(kind, data, name_length - 1) == '_') ); } /*----------------------------------------------------------------------------- | Handles the 'getattr' operation on a 'CTrait' instance: +----------------------------------------------------------------------------*/ static PyObject * trait_getattro(trait_object *obj, PyObject *name) { PyObject *value; value = PyObject_GenericGetAttr((PyObject *)obj, name); if (value != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError)) { return value; } /* The attribute lookup failed. For backwards compatibility, we return `None` in this case, *except* for attribute names that start and end with a double underscore. Those attribute names may have special meaning to the interpreter, and `None` may not be a valid value, so we allow the exception to propagate. */ if (is_dunder_name(name)) { /* Either we have a double-underscore name, or the is_dunder_name call itself failed; either way, propagate the current exception. */ return NULL; } else { /* Not a __dunder__ name; invent an attribute value of `None`. */ PyErr_Clear(); Py_RETURN_NONE; } } /*----------------------------------------------------------------------------- | Set the 'default_value_type' and 'default_value' fields | of a CTrait instance: +----------------------------------------------------------------------------*/ static PyObject * _trait_set_default_value(trait_object *trait, PyObject *args) { int value_type; PyObject *value, *old_value; if (!PyArg_ParseTuple(args, "iO", &value_type, &value)) { return NULL; } if ((value_type < 0) || (value_type > MAXIMUM_DEFAULT_VALUE_TYPE)) { PyErr_Format( PyExc_ValueError, "The default value type must be 0..%d, but %d was specified.", MAXIMUM_DEFAULT_VALUE_TYPE, value_type); return NULL; } trait->default_value_type = value_type; /* The DECREF on the old value can call arbitrary code, so take care not to DECREF until the trait is in a consistent state. (Newer CPython versions have a Py_XSETREF macro to do this safely.) */ Py_INCREF(value); old_value = trait->default_value; trait->default_value = value; Py_XDECREF(old_value); Py_RETURN_NONE; } /*----------------------------------------------------------------------------- | Get or set the 'default_value_type' and 'default_value' fields | of a CTrait instance. Use of this function for setting the default | value information is deprecated; use set_default_value instead. +----------------------------------------------------------------------------*/ static PyObject * _trait_default_value(trait_object *trait, PyObject *args) { if (PyArg_ParseTuple(args, "")) { if (trait->default_value == NULL) { return Py_BuildValue("iO", 0, Py_None); } else { return Py_BuildValue( "iO", trait->default_value_type, trait->default_value); } } PyErr_Clear(); if (PyErr_WarnEx( PyExc_DeprecationWarning, "Use of the default_value method with arguments is deprecated. " "To set defaults, use set_default_value instead.", 1) != 0) { return NULL; } return _trait_set_default_value(trait, args); } /*----------------------------------------------------------------------------- | Gets the default value of a CTrait instance for a specified object and trait | name: +----------------------------------------------------------------------------*/ static PyObject * _trait_default_value_for(trait_object *trait, PyObject *args) { PyObject *object; PyObject *name; if (!PyArg_ParseTuple(args, "OO", &object, &name)) { return NULL; } return default_value_for(trait, (has_traits_object *)object, name); } /*----------------------------------------------------------------------------- | Calls a Python-based trait validator: +----------------------------------------------------------------------------*/ static PyObject * validate_trait_python( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result; PyObject *args; args = PyTuple_Pack(3, (PyObject *)obj, name, value); if (args == NULL) { return NULL; } result = PyObject_Call(trait->py_validate, args, NULL); Py_DECREF(args); return result; } /*----------------------------------------------------------------------------- | Calls the specified validator function: +----------------------------------------------------------------------------*/ static PyObject * call_validator( PyObject *validator, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result; PyObject *args; args = PyTuple_Pack(3, (PyObject *)obj, name, value); if (args == NULL) { return NULL; } result = PyObject_Call(validator, args, NULL); Py_DECREF(args); return result; } /*----------------------------------------------------------------------------- | Calls the specified type converter: +----------------------------------------------------------------------------*/ static PyObject * type_converter(PyObject *type, PyObject *value) { PyObject *result; PyObject *args; args = PyTuple_Pack(1, value); if (args == NULL) { return NULL; } result = PyObject_Call(type, args, NULL); Py_DECREF(args); return result; } /*----------------------------------------------------------------------------- | Verifies a Python value is of a specified type (or None): +----------------------------------------------------------------------------*/ static PyObject * validate_trait_type( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *type_info = trait->py_validate; int kind = PyTuple_GET_SIZE(type_info); if (((kind == 3) && (value == Py_None)) || PyObject_TypeCheck( value, (PyTypeObject *)PyTuple_GET_ITEM(type_info, kind - 1))) { Py_INCREF(value); return value; } return raise_trait_error(trait, obj, name, value); } /*----------------------------------------------------------------------------- | Verifies a Python value is an instance of a specified type (or None): +----------------------------------------------------------------------------*/ static PyObject * validate_trait_instance( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *type_info = trait->py_validate; int kind = PyTuple_GET_SIZE(type_info); if (((kind == 3) && (value == Py_None)) || (PyObject_IsInstance(value, PyTuple_GET_ITEM(type_info, kind - 1)) > 0)) { Py_INCREF(value); return value; } return raise_trait_error(trait, obj, name, value); } /*----------------------------------------------------------------------------- | Verifies a Python value is of a the same type as the object being assigned | to (or None): +----------------------------------------------------------------------------*/ static PyObject * validate_trait_self_type( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { if (((PyTuple_GET_SIZE(trait->py_validate) == 2) && (value == Py_None)) || PyObject_TypeCheck(value, Py_TYPE(obj))) { Py_INCREF(value); return value; } return raise_trait_error(trait, obj, name, value); } /* Convert an integer-like Python object to an exact integer. Returns an object of exact type int (or possibly exact type long on Python 2, for values too large to fit in an int), or raises TypeError if the given object cannot be converted to an integer. Here, "integer-like" means either: - is an instance of int (or long in Python 2), or - can be converted to an integer via operator.index. The second case captures (for example) instances of NumPy integer types like np.int32, np.uint64, etc. Roughly equivalent to the Python code ``int(operator.index(value))``. */ static PyObject * as_integer(PyObject *value) { PyObject *index_of_value, *value_as_integer; /* Fast path for common case. */ if (PyLong_CheckExact(value)) { Py_INCREF(value); return value; } /* Not of exact type int: call __index__ method if available. */ index_of_value = PyNumber_Index(value); if (index_of_value == NULL) { return NULL; } /* We run the __index__ result through an extra int call to ensure that we get something of exact type int. Example problematic cases: - ``operator.index(True)`` gives ``True``, where we'd like ``1``. Related: https://bugs.python.org/issue17576 */ value_as_integer = PyNumber_Long(index_of_value); Py_DECREF(index_of_value); return value_as_integer; } /*----------------------------------------------------------------------------- | Verifies a Python value is a Python int +----------------------------------------------------------------------------*/ static PyObject * validate_trait_integer( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result = as_integer(value); /* A TypeError represents a type validation failure, and should be re-raised as a TraitError. Other exceptions should be propagated. */ if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { PyErr_Clear(); return raise_trait_error(trait, obj, name, value); } return result; } /* Convert a float-like Python object to a float. Returns a new object of exact type float, or raises TypeError if the given object cannot be converted to a float. Here float-like means: - is an instance of float, or - can be converted to a float via its type's __float__ method Note: as of Python 3.8, objects having an __index__ method but no __float__ method can also be converted to float. */ static PyObject * as_float(PyObject *value) { double value_as_double; /* Fast path for common case. */ if (PyFloat_CheckExact(value)) { Py_INCREF(value); return value; } /* General case: defer to the machinations of PyFloat_AsDouble. */ value_as_double = PyFloat_AsDouble(value); if (value_as_double == -1.0 && PyErr_Occurred()) { return NULL; } return PyFloat_FromDouble(value_as_double); } /*----------------------------------------------------------------------------- | Verifies that a Python value is convertible to float | | Will convert anything whose type has a __float__ method to a Python | float. Returns a Python object of exact type "float". Raises TraitError | with a suitable message if the given value isn't convertible to float. | | Any exception other than TypeError raised by the value's __float__ method | will be propagated. A TypeError will be caught and turned into TraitError. | +----------------------------------------------------------------------------*/ static PyObject * validate_trait_float( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result = as_float(value); /* A TypeError represents a type validation failure, and should be re-raised as a TraitError. Other exceptions should be propagated. */ if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { PyErr_Clear(); return raise_trait_error(trait, obj, name, value); } return result; } /* Determine whether `value` lies in the range specified by `range_info`. * `value` must be of exact type float. * `range_info` is expected to be a tuple (*, low, high, exclude_mask) where `low` and `high` are object of exact type float and exclude_mask is a Python integer. Return 1 if `value` is within range, and 0 if not. If an exception occurs, return -1 and set an error. */ static int in_float_range(PyObject *value, PyObject *range_info) { PyObject *low, *high; long exclude_mask; low = PyTuple_GET_ITEM(range_info, 1); high = PyTuple_GET_ITEM(range_info, 2); exclude_mask = PyLong_AsLong(PyTuple_GET_ITEM(range_info, 3)); if (exclude_mask == -1 && PyErr_Occurred()) { return -1; } if (low != Py_None) { if ((exclude_mask & 1) != 0) { if (PyFloat_AS_DOUBLE(value) <= PyFloat_AS_DOUBLE(low)) { return 0; } } else { if (PyFloat_AS_DOUBLE(value) < PyFloat_AS_DOUBLE(low)) { return 0; } } } if (high != Py_None) { if ((exclude_mask & 2) != 0) { if (PyFloat_AS_DOUBLE(value) >= PyFloat_AS_DOUBLE(high)) { return 0; } } else { if (PyFloat_AS_DOUBLE(value) > PyFloat_AS_DOUBLE(high)) { return 0; } } } return 1; } /*----------------------------------------------------------------------------- | Verifies a Python value is a float within a specified range: +----------------------------------------------------------------------------*/ static PyObject * validate_trait_float_range( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result; int in_range; result = as_float(value); if (result == NULL) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { /* Reraise any TypeError as a TraitError. */ PyErr_Clear(); return raise_trait_error(trait, obj, name, value); } /* Non-TypeErrors should be propagated. */ return NULL; } in_range = in_float_range(result, trait->py_validate); if (in_range == 1) { return result; } else if (in_range == 0) { Py_DECREF(result); return raise_trait_error(trait, obj, name, value); } else { /* in_range must be -1, indicating an error; propagate it */ Py_DECREF(result); return NULL; } } /*----------------------------------------------------------------------------- | Verifies a Python value is in a specified enumeration: +----------------------------------------------------------------------------*/ static PyObject * validate_trait_enum( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *type_info = trait->py_validate; if (PySequence_Contains(PyTuple_GET_ITEM(type_info, 1), value) > 0) { Py_INCREF(value); return value; } return raise_trait_error(trait, obj, name, value); } /*----------------------------------------------------------------------------- | Verifies a Python value is in a specified map (i.e. dictionary): +----------------------------------------------------------------------------*/ static PyObject * validate_trait_map( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *type_info = trait->py_validate; if (PyDict_GetItem(PyTuple_GET_ITEM(type_info, 1), value) != NULL) { Py_INCREF(value); return value; } return raise_trait_error(trait, obj, name, value); } /*----------------------------------------------------------------------------- | Verifies a Python value is in a specified prefix map (i.e. dictionary): +----------------------------------------------------------------------------*/ static PyObject * validate_trait_prefix_map( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *type_info = trait->py_validate; PyObject *mapped_value = PyDict_GetItem(PyTuple_GET_ITEM(type_info, 1), value); if (mapped_value != NULL) { Py_INCREF(mapped_value); return mapped_value; } return call_validator( PyTuple_GET_ITEM(trait->py_validate, 2), obj, name, value); } /*----------------------------------------------------------------------------- | Verifies a Python value is a tuple of a specified type and content: +----------------------------------------------------------------------------*/ /* Note: this function does not follow standard CPython error-handling rules. There are three possible types of outcome for this function. If validation fails, NULL is returned and no Python exception is set (contrary to usual Python C-API conventions). If an unexpected exception occurs, NULL is returned and a Python exception is set. If validation succeeds, the validated object is returned. */ static PyObject * validate_trait_tuple_check( PyObject *traits, has_traits_object *obj, PyObject *name, PyObject *value) { trait_object *itrait; PyObject *bitem, *aitem, *tuple; int i, j, n; if (PyTuple_Check(value)) { n = PyTuple_GET_SIZE(traits); if (n == PyTuple_GET_SIZE(value)) { tuple = NULL; for (i = 0; i < n; i++) { bitem = PyTuple_GET_ITEM(value, i); itrait = (trait_object *)PyTuple_GET_ITEM(traits, i); if (itrait->validate == NULL) { aitem = bitem; Py_INCREF(aitem); } else { aitem = itrait->validate(itrait, obj, name, bitem); } if (aitem == NULL) { if (PyErr_ExceptionMatches(TraitError)) { PyErr_Clear(); } Py_XDECREF(tuple); return NULL; } if (tuple != NULL) { PyTuple_SET_ITEM(tuple, i, aitem); } else if (aitem != bitem) { tuple = PyTuple_New(n); if (tuple == NULL) { return NULL; } for (j = 0; j < i; j++) { bitem = PyTuple_GET_ITEM(value, j); Py_INCREF(bitem); PyTuple_SET_ITEM(tuple, j, bitem); } PyTuple_SET_ITEM(tuple, i, aitem); } else { Py_DECREF(aitem); } } if (tuple != NULL) { return tuple; } Py_INCREF(value); return value; } } return NULL; } static PyObject * validate_trait_tuple( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result = validate_trait_tuple_check( PyTuple_GET_ITEM(trait->py_validate, 1), obj, name, value); if (result != NULL || PyErr_Occurred()) { return result; } return raise_trait_error(trait, obj, name, value); } /*----------------------------------------------------------------------------- | Verifies a Python value is of a specified (possibly coercable) type: +----------------------------------------------------------------------------*/ static PyObject * validate_trait_coerce_type( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { int i, n; PyObject *type2; PyObject *type_info = trait->py_validate; PyObject *type = PyTuple_GET_ITEM(type_info, 1); if (PyObject_TypeCheck(value, (PyTypeObject *)type)) { Py_INCREF(value); return value; } n = PyTuple_GET_SIZE(type_info); for (i = 2; i < n; i++) { type2 = PyTuple_GET_ITEM(type_info, i); if (type2 == Py_None) { break; } if (PyObject_TypeCheck(value, (PyTypeObject *)type2)) { Py_INCREF(value); return value; } } for (i++; i < n; i++) { type2 = PyTuple_GET_ITEM(type_info, i); if (PyObject_TypeCheck(value, (PyTypeObject *)type2)) { return type_converter(type, value); } } return raise_trait_error(trait, obj, name, value); } /*----------------------------------------------------------------------------- | Verifies a Python value is of a specified (possibly castable) type: +----------------------------------------------------------------------------*/ static PyObject * validate_trait_cast_type( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result; PyObject *type_info = trait->py_validate; PyObject *type = PyTuple_GET_ITEM(type_info, 1); if (Py_TYPE(value) == (PyTypeObject *)type) { Py_INCREF(value); return value; } if ((result = type_converter(type, value)) != NULL) { return result; } return raise_trait_error(trait, obj, name, value); } /*----------------------------------------------------------------------------- | Verifies a Python value satisifies a specified function validator: +----------------------------------------------------------------------------*/ static PyObject * validate_trait_function( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result; result = call_validator( PyTuple_GET_ITEM(trait->py_validate, 1), obj, name, value); if (result != NULL) { return result; } return raise_trait_error(trait, obj, name, value); } /*----------------------------------------------------------------------------- | Verifies a Python value is a callable (or None): +----------------------------------------------------------------------------*/ /* Internal function for validation: Return 1 if the value is valid, 0 if it is invalid, and return -1 and set an error condition if anything goes wrong. */ static int _validate_trait_callable(PyObject *type_info, PyObject *value) { if (value == Py_None) { if (PyTuple_GET_SIZE(type_info) < 2) { /* Backwards compatibility with old Callable */ return 1; } else { /* 2nd element of tuple determines whether None is allowed */ return PyObject_IsTrue(PyTuple_GET_ITEM(type_info, 1)); } } else { return PyCallable_Check(value); } } static PyObject * validate_trait_callable( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { int valid = _validate_trait_callable(trait->py_validate, value); if (valid == -1) { return NULL; } if (valid == 1) { Py_INCREF(value); return value; } return raise_trait_error(trait, obj, name, value); } /*----------------------------------------------------------------------------- | Attempts to 'adapt' an object to a specified interface: | | If mode == 1, first tries to adapt the value to the given class, and | if that fails, but the value is already an instance of the class, returns | that value. | | If mode == 2, first tries to adapt the value to the given class. If that | fails, and if the value is an instance of the class, the value is returned | unchanged. If neither of those holds, the default value is used. | | Parameters | ---------- | trait : cTrait | The trait being assigned to. | obj : HasTraits | The CHasTraits object that the trait belongs to. | name : str | The name of the trait in obj, for use in error messages. | value : object | The value to adapt | | Raises | ------ | TraitError | If the value cannot be adapted. | +----------------------------------------------------------------------------*/ static PyObject * validate_trait_adapt( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result, *args, *type, *type_info; long mode, rc; type_info = trait->py_validate; /* If value is None and allow_none, return value; else fail validation */ if (value == Py_None) { int allow_none = PyObject_IsTrue(PyTuple_GET_ITEM(type_info, 3)); if (allow_none == -1) { return NULL; } if (allow_none) { Py_INCREF(value); return value; } else { return raise_trait_error(trait, obj, name, value); } } type = PyTuple_GET_ITEM(type_info, 1); mode = PyLong_AsLong(PyTuple_GET_ITEM(type_info, 2)); if (mode == -1 && PyErr_Occurred()) { return NULL; } /* Adaptation mode 0: do a simple isinstance check. */ if (mode == 0) { rc = PyObject_IsInstance(value, type); if (rc == -1 && PyErr_Occurred()) { return NULL; } if (rc) { Py_INCREF(value); return value; } else { return raise_trait_error(trait, obj, name, value); } } /* Try adaptation; return adapted value on success. */ args = PyTuple_Pack(3, value, type, Py_None); if (args == NULL) { return NULL; } result = PyObject_Call(adapt, args, NULL); Py_DECREF(args); if (result == NULL) { return NULL; } if (result != Py_None) { return result; } Py_DECREF(result); /* Adaptation failed. Move on to an isinstance check. */ rc = PyObject_IsInstance(value, type); if (rc == -1 && PyErr_Occurred()) { return NULL; } if (rc) { Py_INCREF(value); return value; } /* Adaptation and isinstance both failed. In mode 1, fail. Otherwise, return the default. */ if (mode == 1) { return raise_trait_error(trait, obj, name, value); } else { return default_value_for(trait, obj, name); } } /*----------------------------------------------------------------------------- | Verifies a Python value satisifies a complex trait definition: +----------------------------------------------------------------------------*/ static PyObject * validate_trait_complex( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { int i, j, k, kind, in_range; long mode, rc; PyObject *result, *type_info, *type, *type2, *args; PyObject *list_type_info = PyTuple_GET_ITEM(trait->py_validate, 1); int n = PyTuple_GET_SIZE(list_type_info); for (i = 0; i < n; i++) { type_info = PyTuple_GET_ITEM(list_type_info, i); switch (PyLong_AsLong(PyTuple_GET_ITEM(type_info, 0))) { case 0: /* Type check: */ kind = PyTuple_GET_SIZE(type_info); if (((kind == 3) && (value == Py_None)) || PyObject_TypeCheck( value, (PyTypeObject *)PyTuple_GET_ITEM( type_info, kind - 1))) { goto done; } break; case 1: /* Instance check: */ kind = PyTuple_GET_SIZE(type_info); if (((kind == 3) && (value == Py_None)) || (PyObject_IsInstance( value, PyTuple_GET_ITEM(type_info, kind - 1)) > 0)) { goto done; } break; case 2: /* Self type check: */ if (((PyTuple_GET_SIZE(type_info) == 2) && (value == Py_None)) || PyObject_TypeCheck(value, Py_TYPE(obj))) { goto done; } break; case 4: /* Floating point range check: */ result = as_float(value); if (result == NULL) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { /* A TypeError should ultimately get re-raised as a TraitError. */ PyErr_Clear(); break; } /* Non-TypeErrors should be propagated. */ return NULL; } in_range = in_float_range(result, type_info); if (in_range == 1) { return result; } else if (in_range == 0) { Py_DECREF(result); break; } else { /* in_range must be -1, indicating an error; propagate it */ Py_DECREF(result); return NULL; } case 5: /* Enumerated item check: */ if (PySequence_Contains(PyTuple_GET_ITEM(type_info, 1), value) > 0) { goto done; } /* If the containment check failed (for example as a result of checking whether an array is in a sequence), clear the exception. See enthought/traits#376. */ PyErr_Clear(); break; case 6: /* Mapped item check: */ if (PyDict_GetItem(PyTuple_GET_ITEM(type_info, 1), value) != NULL) { goto done; } PyErr_Clear(); break; case 8: /* Perform 'slow' validate check: */ result = PyObject_CallMethod( PyTuple_GET_ITEM(type_info, 1), "slow_validate", "(OOO)", obj, name, value); if (result == NULL && PyErr_ExceptionMatches(TraitError)) { PyErr_Clear(); break; } return result; case 9: /* Tuple item check: */ result = validate_trait_tuple_check( PyTuple_GET_ITEM(type_info, 1), obj, name, value); if (result != NULL || PyErr_Occurred()) { return result; } PyErr_Clear(); break; case 10: /* Prefix map item check: */ result = PyDict_GetItem(PyTuple_GET_ITEM(type_info, 1), value); if (result != NULL) { Py_INCREF(result); return result; } result = call_validator( PyTuple_GET_ITEM(type_info, 2), obj, name, value); if (result != NULL) { return result; } PyErr_Clear(); break; case 11: /* Coercable type check: */ type = PyTuple_GET_ITEM(type_info, 1); if (PyObject_TypeCheck(value, (PyTypeObject *)type)) { goto done; } k = PyTuple_GET_SIZE(type_info); for (j = 2; j < k; j++) { type2 = PyTuple_GET_ITEM(type_info, j); if (type2 == Py_None) { break; } if (PyObject_TypeCheck(value, (PyTypeObject *)type2)) { goto done; } } for (j++; j < k; j++) { type2 = PyTuple_GET_ITEM(type_info, j); if (PyObject_TypeCheck(value, (PyTypeObject *)type2)) { return type_converter(type, value); } } break; case 12: /* Castable type check */ type = PyTuple_GET_ITEM(type_info, 1); if (Py_TYPE(value) == (PyTypeObject *)type) { goto done; } if ((result = type_converter(type, value)) != NULL) { return result; } PyErr_Clear(); break; case 13: /* Function validator check: */ result = call_validator( PyTuple_GET_ITEM(type_info, 1), obj, name, value); if (result != NULL) { return result; } PyErr_Clear(); break; /* case 14: Python-based validator check: */ /* case 15..18: Property 'setattr' validate checks: */ case 19: /* Adaptable object check: */ /* If value is None and allow_none, return value; else fail * validation */ if (value == Py_None) { int allow_none = PyObject_IsTrue(PyTuple_GET_ITEM(type_info, 3)); if (allow_none == -1) { return NULL; } if (allow_none) { goto done; } else { break; } } type = PyTuple_GET_ITEM(type_info, 1); mode = PyLong_AsLong(PyTuple_GET_ITEM(type_info, 2)); if (mode == -1 && PyErr_Occurred()) { return NULL; } /* Adaptation mode 0: do a simple isinstance check. */ if (mode == 0) { rc = PyObject_IsInstance(value, type); if (rc == -1 && PyErr_Occurred()) { return NULL; } if (rc) { goto done; } else { break; } } /* Try adaptation; return adapted value on success. */ args = PyTuple_Pack(3, value, type, Py_None); if (args == NULL) { return NULL; } result = PyObject_Call(adapt, args, NULL); Py_DECREF(args); if (result == NULL) { return NULL; } if (result != Py_None) { return result; } Py_DECREF(result); /* Adaptation failed. Move on to an isinstance check. */ rc = PyObject_IsInstance(value, type); if (rc == -1 && PyErr_Occurred()) { return NULL; } if (rc) { goto done; } /* Adaptation and isinstance both failed. In mode 1, fail. Otherwise, return the default. */ if (mode == 1) { break; } else { return default_value_for(trait, obj, name); } case 20: /* Integer check: */ result = as_integer(value); /* A TypeError indicates that we don't have a match. Clear the error and continue with the next item in the complex sequence. Other errors are propagated. */ if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { PyErr_Clear(); break; } return result; case 21: /* Float check */ /* A TypeError indicates that we don't have a match. Clear the error and continue with the next item in the complex sequence. */ result = as_float(value); if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { PyErr_Clear(); break; } return result; case 22: /* Callable check: */ { int valid = _validate_trait_callable(type_info, value); if (valid == -1) { return NULL; } if (valid == 1) { goto done; } break; } default: /* Should never happen...indicates an internal error: */ assert(0); /* invalid validation type */ goto error; } } error: return raise_trait_error(trait, obj, name, value); done: Py_INCREF(value); return value; } /*----------------------------------------------------------------------------- | Sets the value of the 'validate' field of a CTrait instance: +----------------------------------------------------------------------------*/ static trait_validate validate_handlers[] = { validate_trait_type, /* case 0: Type check */ validate_trait_instance, /* case 1: Instance check */ validate_trait_self_type, /* case 2: Self type check */ NULL, /* case 3: Integer range check (unused) */ validate_trait_float_range, /* case 4: Floating-point range check */ validate_trait_enum, /* case 5: Enumerated item check */ validate_trait_map, /* case 6: Mapped item check */ validate_trait_complex, /* case 7: TraitComplex item check */ NULL, /* case 8: 'Slow' validate check */ validate_trait_tuple, /* case 9: TupleOf item check */ validate_trait_prefix_map, /* case 10: Prefix map item check */ validate_trait_coerce_type, /* case 11: Coercable type check */ validate_trait_cast_type, /* case 12: Castable type check */ validate_trait_function, /* case 13: Function validator check */ validate_trait_python, /* case 14: Python-based validator check */ /* The following entries are used by the __getstate__ method... */ setattr_validate0, setattr_validate1, setattr_validate2, setattr_validate3, /* ...End of __getstate__ method entries */ validate_trait_adapt, /* case 19: Adaptable object check */ validate_trait_integer, /* case 20: Integer check */ validate_trait_float, /* case 21: Float check */ validate_trait_callable, /* case 22: Callable check */ }; static PyObject * _trait_set_validate(trait_object *trait, PyObject *args) { PyObject *validate; PyObject *v1, *v2, *v3; int n, kind; if (!PyArg_ParseTuple(args, "O", &validate)) { return NULL; } if (PyCallable_Check(validate)) { kind = 14; goto done; } if (PyTuple_CheckExact(validate)) { n = PyTuple_GET_SIZE(validate); if (n > 0) { kind = PyLong_AsLong(PyTuple_GET_ITEM(validate, 0)); switch (kind) { case 0: /* Type check: */ if ((n <= 3) && PyType_Check(PyTuple_GET_ITEM(validate, n - 1)) && ((n == 2) || (PyTuple_GET_ITEM(validate, 1) == Py_None))) { goto done; } break; case 1: /* Instance check: */ if ((n <= 3) && ((n == 2) || (PyTuple_GET_ITEM(validate, 1) == Py_None))) { goto done; } break; case 2: /* Self type check: */ if ((n == 1) || ((n == 2) && (PyTuple_GET_ITEM(validate, 1) == Py_None))) { goto done; } break; case 4: /* Floating point range check: */ if (n == 4) { v1 = PyTuple_GET_ITEM(validate, 1); v2 = PyTuple_GET_ITEM(validate, 2); v3 = PyTuple_GET_ITEM(validate, 3); if (((v1 == Py_None) || PyFloat_Check(v1)) && ((v2 == Py_None) || PyFloat_Check(v2)) && PyLong_Check(v3)) { goto done; } } break; case 5: /* Enumerated item check: */ if (n == 2) { v1 = PyTuple_GET_ITEM(validate, 1); if (PyTuple_CheckExact(v1)) { goto done; } } break; case 6: /* Mapped item check: */ if (n == 2) { v1 = PyTuple_GET_ITEM(validate, 1); if (PyDict_Check(v1)) { goto done; } } break; case 7: /* TraitComplex item check: */ if (n == 2) { v1 = PyTuple_GET_ITEM(validate, 1); if (PyTuple_CheckExact(v1)) { goto done; } } break; /* case 8: 'Slow' validate check: */ case 9: /* TupleOf item check: */ if (n == 2) { v1 = PyTuple_GET_ITEM(validate, 1); if (PyTuple_CheckExact(v1)) { goto done; } } break; case 10: /* Prefix map item check: */ if (n == 3) { v1 = PyTuple_GET_ITEM(validate, 1); if (PyDict_Check(v1)) { goto done; } } break; case 11: /* Coercable type check: */ if (n >= 2) { goto done; } break; case 12: /* Castable type check: */ if (n == 2) { goto done; } break; case 13: /* Function validator check: */ if (n == 2) { v1 = PyTuple_GET_ITEM(validate, 1); if (PyCallable_Check(v1)) { goto done; } } break; /* case 14: Python-based validator check: */ /* case 15..18: Property 'setattr' validate checks: */ case 19: /* Adaptable object check: */ /* Note: We don't check the 'class' argument (item[1]) because some old-style code creates classes that are not strictly classes or types (e.g. VTK), and yet they work correctly with the rest of the Instance code */ if ((n == 4) && PyLong_Check(PyTuple_GET_ITEM(validate, 2)) && PyBool_Check(PyTuple_GET_ITEM(validate, 3))) { goto done; } break; case 20: /* Integer check: */ if (n == 1) { goto done; } break; case 21: /* Float check: */ if (n == 1) { goto done; } break; case 22: /* Callable check: */ if (n == 1 || n == 2) { goto done; } break; } } } PyErr_SetString( PyExc_ValueError, "The argument must be a tuple or callable."); return NULL; done: trait->validate = validate_handlers[kind]; Py_INCREF(validate); Py_XDECREF(trait->py_validate); trait->py_validate = validate; Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | Gets the value of the 'validate' field of a CTrait instance: +----------------------------------------------------------------------------*/ static PyObject * _trait_get_validate(trait_object *trait, PyObject *Py_UNUSED(ignored)) { if (trait->validate != NULL) { Py_INCREF(trait->py_validate); return trait->py_validate; } Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | Validates that a particular value can be assigned to an object trait: +----------------------------------------------------------------------------*/ static PyObject * _trait_validate(trait_object *trait, PyObject *args) { PyObject *object, *name, *value; if (!PyArg_ParseTuple(args, "OOO", &object, &name, &value)) { return NULL; } if (trait->validate == NULL) { Py_INCREF(value); return value; } return trait->validate(trait, (has_traits_object *)object, name, value); } /*----------------------------------------------------------------------------- | Calls a Python-based trait post_setattr handler: +----------------------------------------------------------------------------*/ static int post_setattr_trait_python( trait_object *trait, has_traits_object *obj, PyObject *name, PyObject *value) { PyObject *result; PyObject *args; args = PyTuple_Pack(3, (PyObject *)obj, name, value); if (args == NULL) { return -1; } result = PyObject_Call(trait->py_post_setattr, args, NULL); Py_DECREF(args); if (result == NULL) { return -1; } Py_DECREF(result); return 0; } /*----------------------------------------------------------------------------- | Returns the various forms of delegate names: +----------------------------------------------------------------------------*/ static PyObject * delegate_attr_name_name( trait_object *trait, has_traits_object *obj, PyObject *name) { Py_INCREF(name); return name; } static PyObject * delegate_attr_name_prefix( trait_object *trait, has_traits_object *obj, PyObject *name) { Py_INCREF(trait->delegate_prefix); return trait->delegate_prefix; } static PyObject * delegate_attr_name_prefix_name( trait_object *trait, has_traits_object *obj, PyObject *name) { PyObject *result = PyUnicode_Concat(trait->delegate_prefix, name); return result; } static PyObject * delegate_attr_name_class_name( trait_object *trait, has_traits_object *obj, PyObject *name) { PyObject *prefix, *result; prefix = PyObject_GetAttr((PyObject *)Py_TYPE(obj), class_prefix); // fixme: Should verify that prefix is a string... if (prefix == NULL) { PyErr_Clear(); Py_INCREF(name); return name; } result = PyUnicode_Concat(prefix, name); Py_DECREF(prefix); return result; } /*----------------------------------------------------------------------------- | Sets the value of the 'post_setattr' field of a CTrait instance: +----------------------------------------------------------------------------*/ static delegate_attr_name_func delegate_attr_name_handlers[] = { delegate_attr_name_name, delegate_attr_name_prefix, delegate_attr_name_prefix_name, delegate_attr_name_class_name, NULL}; static PyObject * _trait_delegate(trait_object *trait, PyObject *args) { PyObject *delegate_name; PyObject *delegate_prefix; int prefix_type; int modify_delegate; if (!PyArg_ParseTuple( args, "UUip", &delegate_name, &delegate_prefix, &prefix_type, &modify_delegate)) { return NULL; } Py_INCREF(delegate_name); Py_INCREF(delegate_prefix); if (modify_delegate) { trait->flags |= TRAIT_MODIFY_DELEGATE; } else { trait->flags &= ~TRAIT_MODIFY_DELEGATE; } trait->delegate_name = delegate_name; trait->delegate_prefix = delegate_prefix; if ((prefix_type < 0) || (prefix_type > 3)) { prefix_type = 0; } trait->delegate_attr_name = delegate_attr_name_handlers[prefix_type]; Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | Sets the appropriate value comparison mode flags of a CTrait instance: +----------------------------------------------------------------------------*/ static int _set_trait_comparison_mode(trait_object *trait, PyObject *value, void *closure) { long comparison_mode = PyLong_AsLong(value); if (comparison_mode == -1 && PyErr_Occurred()) { return -1; } switch (comparison_mode) { case 0: trait->flags &= ~TRAIT_COMPARISON_MODE_MASK; trait->flags |= TRAIT_COMPARISON_MODE_NONE; break; case 1: trait->flags &= ~TRAIT_COMPARISON_MODE_MASK; trait->flags |= TRAIT_COMPARISON_MODE_IDENTITY; break; case 2: trait->flags &= ~TRAIT_COMPARISON_MODE_MASK; trait->flags |= TRAIT_COMPARISON_MODE_EQUALITY; break; default: PyErr_Format( PyExc_ValueError, "The comparison mode must be 0..%d, but %ld was specified.", MAXIMUM_COMPARISON_MODE_VALUE, comparison_mode); return -1; } return 0; } /*----------------------------------------------------------------------------- | getter for trait comparison mode +----------------------------------------------------------------------------*/ static PyObject * _get_trait_comparison_mode_int(trait_object *trait, void *closure) { int i_comparison_mode; unsigned int compare_flag = trait->flags & TRAIT_COMPARISON_MODE_MASK; if (compare_flag == TRAIT_COMPARISON_MODE_NONE) { i_comparison_mode = 0; } else if (compare_flag == TRAIT_COMPARISON_MODE_IDENTITY) { i_comparison_mode = 1; } else { assert(compare_flag == TRAIT_COMPARISON_MODE_EQUALITY); i_comparison_mode = 2; } return PyLong_FromLong(i_comparison_mode); } /*----------------------------------------------------------------------------- | Get the 'property' value fields of a CTrait instance: +----------------------------------------------------------------------------*/ static PyObject * _trait_get_property(trait_object *trait, PyObject *Py_UNUSED(ignored)) { if (trait->flags & TRAIT_PROPERTY) { return PyTuple_Pack( 3, trait->delegate_name, trait->delegate_prefix, trait->py_validate); } else { Py_RETURN_NONE; } } /*----------------------------------------------------------------------------- | Sets the 'property' value fields of a CTrait instance: +----------------------------------------------------------------------------*/ static trait_setattr setattr_property_handlers[] = { setattr_property0, setattr_property1, setattr_property2, setattr_property3, /* The following entries are used by the __getstate__ method__: */ (trait_setattr)post_setattr_trait_python, NULL}; static PyObject * _trait_set_property(trait_object *trait, PyObject *args) { PyObject *get, *set, *validate; int get_n, set_n, validate_n; if (!PyArg_ParseTuple( args, "OiOiOi", &get, &get_n, &set, &set_n, &validate, &validate_n)) { return NULL; } if (!PyCallable_Check(get) || !PyCallable_Check(set) || ((validate != Py_None) && !PyCallable_Check(validate)) || (get_n < 0) || (get_n > 3) || (set_n < 0) || (set_n > 3) || (validate_n < 0) || (validate_n > 3)) { PyErr_SetString(PyExc_ValueError, "Invalid arguments."); return NULL; } trait->flags |= TRAIT_PROPERTY; trait->getattr = getattr_property_handlers[get_n]; if (validate != Py_None) { trait->setattr = setattr_validate_property; trait->post_setattr = (trait_post_setattr)setattr_property_handlers[set_n]; trait->validate = setattr_validate_handlers[validate_n]; } else { trait->setattr = setattr_property_handlers[set_n]; } trait->delegate_name = get; trait->delegate_prefix = set; trait->py_validate = validate; Py_INCREF(get); Py_INCREF(set); Py_INCREF(validate); Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | Clones one trait into another: +----------------------------------------------------------------------------*/ static void trait_clone(trait_object *trait, trait_object *source) { trait->flags = source->flags; trait->getattr = source->getattr; trait->setattr = source->setattr; trait->post_setattr = source->post_setattr; trait->py_post_setattr = source->py_post_setattr; trait->validate = source->validate; trait->py_validate = source->py_validate; trait->default_value_type = source->default_value_type; trait->default_value = source->default_value; trait->delegate_name = source->delegate_name; trait->delegate_prefix = source->delegate_prefix; trait->delegate_attr_name = source->delegate_attr_name; trait->handler = source->handler; Py_XINCREF(trait->py_post_setattr); Py_XINCREF(trait->py_validate); Py_XINCREF(trait->delegate_name); Py_XINCREF(trait->default_value); Py_XINCREF(trait->delegate_prefix); Py_XINCREF(trait->handler); } static PyObject * _trait_clone(trait_object *trait, PyObject *args) { trait_object *source; if (!PyArg_ParseTuple(args, "O!", ctrait_type, &source)) { return NULL; } trait_clone(trait, source); Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | Returns (and optionally creates) the trait 'notifiers' list: +----------------------------------------------------------------------------*/ static PyObject * _trait_notifiers(trait_object *trait, PyObject *args) { PyObject *result; PyObject *list; int force_create; if (!PyArg_ParseTuple(args, "p", &force_create)) { return NULL; } result = (PyObject *)trait->notifiers; if (result == NULL) { result = Py_None; if (force_create && ((list = PyList_New(0)) != NULL)) { trait->notifiers = (PyListObject *)(result = list); } } Py_INCREF(result); return result; } /*----------------------------------------------------------------------------- | Converts a function to an index into a function table: +----------------------------------------------------------------------------*/ static int func_index(void *function, void **function_table) { int i; for (i = 0; function != function_table[i]; i++) { ; } return i; } /*----------------------------------------------------------------------------- | Gets the pickleable state of the trait: +----------------------------------------------------------------------------*/ static PyObject * _trait_getstate(trait_object *trait, PyObject *Py_UNUSED(ignored)) { PyObject *result; result = PyTuple_New(15); if (result == NULL) { return NULL; } PyTuple_SET_ITEM( result, 0, PyLong_FromLong( func_index((void *)trait->getattr, (void **)getattr_handlers))); PyTuple_SET_ITEM( result, 1, PyLong_FromLong( func_index((void *)trait->setattr, (void **)setattr_handlers))); PyTuple_SET_ITEM( result, 2, PyLong_FromLong(func_index( (void *)trait->post_setattr, (void **)setattr_property_handlers))); PyTuple_SET_ITEM(result, 3, get_value(trait->py_post_setattr)); PyTuple_SET_ITEM( result, 4, PyLong_FromLong( func_index((void *)trait->validate, (void **)validate_handlers))); PyTuple_SET_ITEM(result, 5, get_value(trait->py_validate)); PyTuple_SET_ITEM(result, 6, PyLong_FromLong(trait->default_value_type)); PyTuple_SET_ITEM(result, 7, get_value(trait->default_value)); PyTuple_SET_ITEM(result, 8, PyLong_FromUnsignedLong(trait->flags)); PyTuple_SET_ITEM(result, 9, get_value(trait->delegate_name)); PyTuple_SET_ITEM(result, 10, get_value(trait->delegate_prefix)); PyTuple_SET_ITEM( result, 11, PyLong_FromLong(func_index( (void *)trait->delegate_attr_name, (void **)delegate_attr_name_handlers))); PyTuple_SET_ITEM(result, 12, get_value(NULL)); /* trait->notifiers */ PyTuple_SET_ITEM(result, 13, get_value(trait->handler)); PyTuple_SET_ITEM(result, 14, get_value(trait->obj_dict)); return result; } /*----------------------------------------------------------------------------- | Restores the pickled state of the trait: +----------------------------------------------------------------------------*/ static PyObject * _trait_setstate(trait_object *trait, PyObject *args) { PyObject *ignore; int getattr_index, setattr_index, post_setattr_index, validate_index, delegate_attr_name_index; if (!PyArg_ParseTuple( args, "(iiiOiOiOIOOiOOO)", &getattr_index, &setattr_index, &post_setattr_index, &trait->py_post_setattr, &validate_index, &trait->py_validate, &trait->default_value_type, &trait->default_value, &trait->flags, &trait->delegate_name, &trait->delegate_prefix, &delegate_attr_name_index, &ignore, &trait->handler, &trait->obj_dict)) { return NULL; } trait->getattr = getattr_handlers[getattr_index]; trait->setattr = setattr_handlers[setattr_index]; trait->post_setattr = (trait_post_setattr)setattr_property_handlers[post_setattr_index]; trait->validate = validate_handlers[validate_index]; trait->delegate_attr_name = delegate_attr_name_handlers[delegate_attr_name_index]; /* Backwards compatibility hack for old pickles. Versions of Traits prior to 6.0 replaced callables with a long value (-1). This backwards compatibility shim can be removed once we're sure that we don't need to handle pickles generated by Traits versions < 6.0. */ if (PyLong_Check(trait->py_validate)) { trait->py_validate = PyObject_GetAttrString(trait->handler, "validate"); } if (PyLong_Check(trait->py_post_setattr)) { trait->py_post_setattr = PyObject_GetAttrString(trait->handler, "post_setattr"); } /* End backwards compatibility hack */ Py_INCREF(trait->py_post_setattr); Py_INCREF(trait->py_validate); Py_INCREF(trait->default_value); Py_INCREF(trait->delegate_name); Py_INCREF(trait->delegate_prefix); Py_INCREF(trait->handler); Py_INCREF(trait->obj_dict); Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | Returns the current trait dictionary: +----------------------------------------------------------------------------*/ static PyObject * get_trait_dict(trait_object *trait, void *closure) { PyObject *obj_dict = trait->obj_dict; if (obj_dict == NULL) { trait->obj_dict = obj_dict = PyDict_New(); if (obj_dict == NULL) { return NULL; } } Py_INCREF(obj_dict); return obj_dict; } /*----------------------------------------------------------------------------- | Sets the current trait dictionary: +----------------------------------------------------------------------------*/ static int set_trait_dict(trait_object *trait, PyObject *value, void *closure) { if (!PyDict_Check(value)) { return dictionary_error(); } return set_value(&trait->obj_dict, value); } /*----------------------------------------------------------------------------- | Returns the current trait handler (if any): +----------------------------------------------------------------------------*/ static PyObject * get_trait_handler(trait_object *trait, void *closure) { return get_value(trait->handler); } /*----------------------------------------------------------------------------- | Sets the current trait dictionary: +----------------------------------------------------------------------------*/ static int set_trait_handler(trait_object *trait, PyObject *value, void *closure) { return set_value(&trait->handler, value); } /*----------------------------------------------------------------------------- | Returns the current post_setattr (if any): +----------------------------------------------------------------------------*/ static PyObject * get_trait_post_setattr(trait_object *trait, void *closure) { return get_value(trait->py_post_setattr); } /*----------------------------------------------------------------------------- | Sets the value of the 'post_setattr' field of a CTrait instance: +----------------------------------------------------------------------------*/ static int set_trait_post_setattr(trait_object *trait, PyObject *value, void *closure) { if (value != Py_None && !PyCallable_Check(value)) { PyErr_SetString( PyExc_ValueError, "The assigned value must be callable or None."); return -1; } if (value == Py_None) { value = NULL; trait->post_setattr = NULL; } else { trait->post_setattr = post_setattr_trait_python; } return set_value(&trait->py_post_setattr, value); } /*----------------------------------------------------------------------------- | Returns the current property flag value: +----------------------------------------------------------------------------*/ static PyObject * get_trait_property_flag(trait_object *trait, void *closure) { return get_trait_flag(trait, TRAIT_PROPERTY); } /*----------------------------------------------------------------------------- | Returns the current modify_delegate flag value: +----------------------------------------------------------------------------*/ static PyObject * get_trait_modify_delegate_flag(trait_object *trait, void *closure) { return get_trait_flag(trait, TRAIT_MODIFY_DELEGATE); } /*----------------------------------------------------------------------------- | Sets the current modify_delegate flag value: +----------------------------------------------------------------------------*/ static int set_trait_modify_delegate_flag( trait_object *trait, PyObject *value, void *closure) { return set_trait_flag(trait, TRAIT_MODIFY_DELEGATE, value); } /*----------------------------------------------------------------------------- | Returns the current setattr_original_value flag value: +----------------------------------------------------------------------------*/ static PyObject * get_trait_setattr_original_value_flag(trait_object *trait, void *closure) { return get_trait_flag(trait, TRAIT_SETATTR_ORIGINAL_VALUE); } /*----------------------------------------------------------------------------- | Sets the current setattr_original_value flag value: +----------------------------------------------------------------------------*/ static int set_trait_setattr_original_value_flag( trait_object *trait, PyObject *value, void *closure) { return set_trait_flag(trait, TRAIT_SETATTR_ORIGINAL_VALUE, value); } /*----------------------------------------------------------------------------- | Returns the current post_setattr_original_value flag value: +----------------------------------------------------------------------------*/ static PyObject * get_trait_post_setattr_original_value_flag(trait_object *trait, void *closure) { return get_trait_flag(trait, TRAIT_POST_SETATTR_ORIGINAL_VALUE); } /*----------------------------------------------------------------------------- | Sets the current post_setattr_original_value flag value: +----------------------------------------------------------------------------*/ static int set_trait_post_setattr_original_value_flag( trait_object *trait, PyObject *value, void *closure) { return set_trait_flag(trait, TRAIT_POST_SETATTR_ORIGINAL_VALUE, value); } /*----------------------------------------------------------------------------- | Returns the current is_mapped flag value: +----------------------------------------------------------------------------*/ static PyObject * get_trait_is_mapped_flag(trait_object *trait, void *closure) { return get_trait_flag(trait, TRAIT_IS_MAPPED); } /*----------------------------------------------------------------------------- | Sets the current is_mapped flag value: +----------------------------------------------------------------------------*/ static int set_trait_is_mapped_flag(trait_object *trait, PyObject *value, void *closure) { return set_trait_flag(trait, TRAIT_IS_MAPPED, value); } /*----------------------------------------------------------------------------- | 'CTrait' instance methods: +----------------------------------------------------------------------------*/ PyDoc_STRVAR( default_value_doc, "default_value()\n" "\n" "Return tuple giving default value information for this trait.\n" "\n" "Returns\n" "-------\n" "default_value_type : int\n" " An integer representing the kind of the default value\n" "default_value : value\n" " A value or callable providing the default\n"); PyDoc_STRVAR( set_default_value_doc, "set_default_value(default_value_type, default_value)\n" "\n" "Set the default value information for this trait.\n" "\n" "Parameters\n" "----------\n" "default_value_type : int\n" " An integer representing the kind of the default value\n" "default_value : value\n" " A value or callable providing the default\n"); PyDoc_STRVAR( default_value_for_doc, "default_value_for(object, name)\n" "\n" "Return the default value of this CTrait instance for a specified object\n" "and trait name.\n" "\n" "Parameters\n" "----------\n" "object : HasTraits\n" " The object the trait is attached to.\n" "name : str\n" " The name of the trait.\n" "\n" "Returns\n" "-------\n" "default_value : value\n" " The default value for the given object and name.\n"); PyDoc_STRVAR( set_validate_doc, "set_validate(validator)\n" "\n" "Set the validator of a CTrait instance\n" "\n" "Parameters\n" "----------\n" "validator : callable or tuple\n" " Either a callable used for validation, or a tuple representing\n" " validation information.\n" "\n" " A callable used for validation should have signature\n" " validator(obj, name, value) -> value, and should return the\n" " validated (and possibly transformed) value. It should raise\n" " TraitError on failure to validate.\n" "\n" " If the validator is a tuple, its first entry will be an integer\n" " specifying the type of validation, and the remaining entries\n" " in the tuple (if any) provide additional information specific\n" " to the validation type\n" "\n" "Raises\n" "------\n" "ValueError\n" " If the given tuple does not have any of the expected forms.\n"); PyDoc_STRVAR( get_validate_doc, "get_validate()\n" "\n" "Return the validator of a CTrait instance.\n" "\n" "Returns the current validator for a CTrait instance, or None\n" "if the trait has no validator. See also the set_validate\n" "method.\n" "\n" "Returns\n" "-------\n" "validator : tuple, callable, or None\n"); PyDoc_STRVAR( validate_doc, "validate(object, name, value)\n" "\n" "Perform validation and appropriate conversions on a value for this " "trait.\n" "\n" "Parameters\n" "----------\n" "object : HasTraits\n" " The HasTraits object that validation is being performed for.\n" "name : str\n" " The name of the trait.\n" "value : object\n" " The value to be validated.\n" "\n" "Returns\n" "-------\n" "The validated, converted value.\n" "\n" "Raises\n" "------\n" "TraitError\n" " If the given value is invalid for this trait.\n"); PyDoc_STRVAR( delegate_doc, "delegate(delegate_name, prefix, prefix_type, modify_delegate)\n" "\n" "Set another trait as the delegate of this trait.\n" "\n" "Parameters\n" "----------\n" "delegate_name : str\n" " Name of an attribute on the current object with references the\n" " object that is the trait's delegate.\n" "delegate_prefix : str\n" " A prefix or substitution applied to the original attribute when\n" " looking up the delegated attribute.\n" "prefix_type : int\n" " An integer between 0 and 3, inclusive. This controls how the\n" " delegator attribute name is mapped to an attribute name on the\n" " delegate object. The meanings of the values are as follows:\n" "\n" " 0\n" " The delegation is to an attribute on the delegate object with\n" " the same name as the delegator attribute. *delegate_prefix*\n" " is unused.\n" " 1\n" " The delegation is to an attribute with name given directly by\n" " *delegate_prefix*.\n" " 2\n" " The delegation is to an attribute whose name is the value of\n" " *delegate_prefix*, prepended to the delegator attribute name.\n" " 3\n" " The delegation is to an attribute whose name is the value of\n" " the delegator object's ``__prefix__`` attribute, prepended to\n" " the delegator attribute name.\n" "modify_delegate : bool\n" " Whether to modify the delegate when the value of this trait\n" " is modified.\n"); PyDoc_STRVAR( _trait_get_property_doc, "_trait_get_property()\n" "\n" "Get the property fields for this trait.\n" "\n" "This method returns a tuple (get, set, validate) of length 3 containing\n" "the getter, setter and validator for this property trait.\n" "\n" "When called on a non-property trait, this method returns *None*.\n"); PyDoc_STRVAR( _trait_set_property_doc, "_trait_set_property(get, get_n, set, set_n, validate, validate_n)\n" "\n" "This method expects six arguments, and uses these arguments to set the\n" "get, set and validation for the trait. It also sets the property flag \n" "on the trait.\n" "\n" "Parameters\n" "----------\n" "get : callable\n" " Function called when getting the value of this property trait.\n" " This function will be called with one of the following argument\n" " combinations, depending on the value of *get_n*.\n" "\n" " - no arguments\n" " - a single argument ``obj``\n" " - a pair of arguments ``obj, name``\n" " - a triple of arguments ``obj, name, trait``\n" "\n" "get_n : int\n" " Number of arguments to supply to the getter. This should be\n" " between 0 and 3, inclusive.\n" "set : callable\n" " Function called when setting the value of this property trait.\n" " This function will be called with one of the following argument\n" " combinations, depending on the value of *set_n*.\n" "\n" " - no arguments\n" " - a single argument ``value``\n" " - a pair of arguments ``obj, value``\n" " - a triple of arguments ``obj, name, value``\n" "\n" "set_n : int\n" " Number of arguments to supply to the setter. This should be\n" " between 0 and 3, inclusive.\n" "validate : callable or None\n" " Function called for validation. This function will be called\n" " with one of the following argument combinations, depending on\n" " the value of *validate_n*.\n" "\n" " - no arguments\n" " - a single argument ``value``\n" " - a pair of arguments ``obj, value``\n" " - a triple of arguments ``obj, name, value``\n" "\n" "validate_n : int\n" " Number of arguments to supply to the validator. This should be\n" " between 0 and 3, inclusive.\n"); PyDoc_STRVAR( clone_doc, "clone(source)\n" "\n" "Clone state of another trait into this one.\n" "\n" "This method copies all of the state of the *source* trait into\n" "this trait, with the exception of the trait notifiers and the\n" "trait __dict__. The copy is a simple shallow copy: for example,\n" "after the copy, the handler for this trait will be the same\n" "object as the handler for the *source* trait.\n" "\n" "Parameters\n" "----------\n" "source : CTrait\n" " The source trait.\n"); PyDoc_STRVAR( _notifiers_doc, "_notifiers(force_create)\n" "\n" "Return (and optionally create) the list of notifiers for this trait.\n" "\n" "Parameters\n" "----------\n" "force_create : bool\n" " Whether to automatically create the list of notifiers, if it\n" " doesn't exist yet.\n" "\n" "Returns\n" "-------\n" "notifiers : list of callables, or None\n" " If the trait has no notifiers, and *force_create* is false, return " "None.\n" " Otherwise, return the list of notifiers for this trait, creating it " "\n" " first if necessary. Each notifier is a\n" " callable accepting four arguments (object, trait_name, old, new).\n"); static PyMethodDef trait_methods[] = { {"__getstate__", (PyCFunction)_trait_getstate, METH_NOARGS, PyDoc_STR("__getstate__()")}, {"__setstate__", (PyCFunction)_trait_setstate, METH_VARARGS, PyDoc_STR("__setstate__(state)")}, {"default_value", (PyCFunction)_trait_default_value, METH_VARARGS, default_value_doc}, {"set_default_value", (PyCFunction)_trait_set_default_value, METH_VARARGS, set_default_value_doc}, {"default_value_for", (PyCFunction)_trait_default_value_for, METH_VARARGS, default_value_for_doc}, {"set_validate", (PyCFunction)_trait_set_validate, METH_VARARGS, set_validate_doc}, {"get_validate", (PyCFunction)_trait_get_validate, METH_NOARGS, get_validate_doc}, {"validate", (PyCFunction)_trait_validate, METH_VARARGS, validate_doc}, {"delegate", (PyCFunction)_trait_delegate, METH_VARARGS, delegate_doc}, {"_get_property", (PyCFunction)_trait_get_property, METH_NOARGS, _trait_get_property_doc}, {"_set_property", (PyCFunction)_trait_set_property, METH_VARARGS, _trait_set_property_doc}, {"clone", (PyCFunction)_trait_clone, METH_VARARGS, clone_doc}, {"_notifiers", (PyCFunction)_trait_notifiers, METH_VARARGS, _notifiers_doc}, {NULL, NULL}, }; /*----------------------------------------------------------------------------- | 'CTrait' property definitions: +----------------------------------------------------------------------------*/ PyDoc_STRVAR( ctrait_handler_doc, "The trait handler underlying this trait.\n" "\n" "The value of this property should be an instance of\n" "``BaseTraitHandler``.\n" ); PyDoc_STRVAR( ctrait_post_setattr_doc, "Callable called after a successful value assignment to this trait.\n" "\n" "The value of this property is either a callable or *None*.\n" "If the value is a callable, this callable allows the trait to do\n" "additional processing after a value has successfully been assigned.\n" "The callable is called with arguments (object, name, value), and the\n" "return value of the callable is ignored.\n" ); PyDoc_STRVAR( ctrait_is_property_doc, "True if this trait is a property trait, else False.\n" "\n" "This property is read-only.\n" ); PyDoc_STRVAR( ctrait_modify_delegate_doc, "Indicate whether modifications affect the delegate.\n" "\n" "For delegated traits, this is a boolean indicating whether\n" "modifications to this trait also modify the delegated trait.\n" ); PyDoc_STRVAR( ctrait_setattr_original_value_doc, "Whether setattr stores the original or the validated value.\n" "\n" "If true, setattr will store the original, unvalidated, value set on\n" "the trait to the object's dictionary. If false, the value returned\n" "from the validator will be stored.\n" ); PyDoc_STRVAR( ctrait_post_setattr_original_value_doc, "Whether post_setattr receives the original or the validated value.\n" "\n" "If true, the post_setattr callable for this trait (if defined)\n" "receives the original, unvalidated value assigned to the trait.\n" "If false, the validated value is provided to post_setattr.\n" ); PyDoc_STRVAR( ctrait_is_mapped_doc, "True if this is a mapped trait, else False.\n" ); PyDoc_STRVAR( ctrait_comparison_mode_doc, "Integer constant indicating when notifiers are executed.\n" "\n" "The value of this constant is the integer corresponding to a member\n" "of the :data:`~traits.constants.ComparisonMode` enumeration.\n" ); static PyGetSetDef trait_properties[] = { {"__dict__", (getter)get_trait_dict, (setter)set_trait_dict, NULL, NULL}, {"handler", (getter)get_trait_handler, (setter)set_trait_handler, ctrait_handler_doc, NULL}, {"post_setattr", (getter)get_trait_post_setattr, (setter)set_trait_post_setattr, ctrait_post_setattr_doc, NULL}, {"is_property", (getter)get_trait_property_flag, NULL, ctrait_is_property_doc, NULL}, {"modify_delegate", (getter)get_trait_modify_delegate_flag, (setter)set_trait_modify_delegate_flag, ctrait_modify_delegate_doc, NULL}, {"setattr_original_value", (getter)get_trait_setattr_original_value_flag, (setter)set_trait_setattr_original_value_flag, ctrait_setattr_original_value_doc, NULL}, {"post_setattr_original_value", (getter)get_trait_post_setattr_original_value_flag, (setter)set_trait_post_setattr_original_value_flag, ctrait_post_setattr_original_value_doc, NULL}, {"is_mapped", (getter)get_trait_is_mapped_flag, (setter)set_trait_is_mapped_flag, ctrait_is_mapped_doc, NULL}, {"comparison_mode", (getter)_get_trait_comparison_mode_int, (setter)_set_trait_comparison_mode, ctrait_comparison_mode_doc, NULL}, {NULL}}; /*----------------------------------------------------------------------------- | 'CTrait' type definition: +----------------------------------------------------------------------------*/ PyDoc_STRVAR( ctrait_doc, "Base class for CTrait.\n" "\n" "The cTrait class is not intended to be instantiated directly.\n" "Instead, it serves as a base class for CTrait.\n" "\n" "Parameters\n" "----------\n" "kind : int, optional\n" " Integer between 0 and 8 representing the kind of this trait, with\n" " the default value being 0. The kind determines how attribute get\n" " and set operations behave for attributes using this trait. The\n" " values for *kind* correspond to the members of the ``TraitKind``\n" " enumeration type.\n"); static PyTypeObject trait_type = { PyVarObject_HEAD_INIT(NULL, 0) "traits.ctraits.cTrait", sizeof(trait_object), 0, (destructor)trait_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ (getattrofunc)trait_getattro, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ ctrait_doc, /* tp_doc */ (traverseproc)trait_traverse, /* tp_traverse */ (inquiry)trait_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ trait_methods, /* tp_methods */ 0, /* tp_members */ trait_properties, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ sizeof(trait_object) - sizeof(PyObject *), /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ (newfunc)trait_new /* tp_new */ }; /*----------------------------------------------------------------------------- | Sets the global 'TraitListObject', TraitSetObject and 'TraitDictObject' | classes: +----------------------------------------------------------------------------*/ static PyObject * _ctraits_list_classes(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple( args, "OOO", &TraitListObject, &TraitSetObject, &TraitDictObject)) { return NULL; } Py_INCREF(TraitListObject); Py_INCREF(TraitSetObject); Py_INCREF(TraitDictObject); Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | Sets the global 'adapt' reference to the 'adapt' function: +----------------------------------------------------------------------------*/ static PyObject * _ctraits_adapt(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "O", &adapt)) { return NULL; } Py_INCREF(adapt); Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | Sets the global 'ctrait_type' class reference: +----------------------------------------------------------------------------*/ static PyObject * _ctraits_ctrait(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "O", &ctrait_type)) { return NULL; } Py_INCREF(ctrait_type); Py_INCREF(Py_None); return Py_None; } /*----------------------------------------------------------------------------- | 'CTrait' instance methods: +----------------------------------------------------------------------------*/ static PyMethodDef ctraits_methods[] = { {"_list_classes", (PyCFunction)_ctraits_list_classes, METH_VARARGS, PyDoc_STR( "_list_classes(TraitListObject,TraitSetObject,TraitDictObject)")}, {"_adapt", (PyCFunction)_ctraits_adapt, METH_VARARGS, PyDoc_STR("_adapt(adaptation_function)")}, {"_ctrait", (PyCFunction)_ctraits_ctrait, METH_VARARGS, PyDoc_STR("_ctrait(CTrait_class)")}, {NULL, NULL}, }; /*----------------------------------------------------------------------------- | Performs module and type initialization: +----------------------------------------------------------------------------*/ static struct PyModuleDef ctraitsmodule = { PyModuleDef_HEAD_INIT, "ctraits", ctraits__doc__, -1, ctraits_methods}; PyMODINIT_FUNC PyInit_ctraits(void) { /* Create the 'ctraits' module: */ PyObject *module; PyObject *trait_base; PyObject *trait_errors; int error; module = PyModule_Create(&ctraitsmodule); if (module == NULL) { return NULL; } /* Create the 'CHasTraits' type: */ has_traits_type.tp_base = &PyBaseObject_Type; has_traits_type.tp_alloc = PyType_GenericAlloc; if (PyType_Ready(&has_traits_type) < 0) { return NULL; } Py_INCREF(&has_traits_type); if (PyModule_AddObject(module, "CHasTraits", (PyObject *)&has_traits_type) < 0) { return NULL; } /* Create the 'CTrait' type: */ trait_type.tp_base = &PyBaseObject_Type; trait_type.tp_alloc = PyType_GenericAlloc; if (PyType_Ready(&trait_type) < 0) { return NULL; } Py_INCREF(&trait_type); if (PyModule_AddObject(module, "cTrait", (PyObject *)&trait_type) < 0) { return NULL; } /* Predefine a Python string == "__class_traits__": */ class_traits = PyUnicode_FromString("__class_traits__"); /* Predefine a Python string == "__listener_traits__": */ listener_traits = PyUnicode_FromString("__listener_traits__"); /* Predefine a Python string == "editor": */ editor_property = PyUnicode_FromString("editor"); /* Predefine a Python string == "__prefix__": */ class_prefix = PyUnicode_FromString("__prefix__"); /* Predefine a Python string == "trait_added": */ trait_added = PyUnicode_FromString("trait_added"); /* Import Undefined and Uninitialized */ trait_base = PyImport_ImportModule("traits.trait_base"); if (trait_base == NULL) { return NULL; } Undefined = PyObject_GetAttrString(trait_base, "Undefined"); if (Undefined == NULL) { Py_DECREF(trait_base); return NULL; } Uninitialized = PyObject_GetAttrString(trait_base, "Uninitialized"); if (Uninitialized == NULL) { Py_DECREF(trait_base); return NULL; } Py_DECREF(trait_base); /* Import TraitError and DelegationError */ trait_errors = PyImport_ImportModule("traits.trait_errors"); if (trait_errors == NULL) { return NULL; } TraitError = PyObject_GetAttrString(trait_errors, "TraitError"); if (TraitError == NULL) { Py_DECREF(trait_errors); return NULL; } DelegationError = PyObject_GetAttrString(trait_errors, "DelegationError"); if (DelegationError == NULL) { Py_DECREF(trait_errors); return NULL; } Py_DECREF(trait_errors); /* Export default-value constants, so that they can be re-used in the DefaultValue enumeration. */ error = PyModule_AddIntConstant( module, "_CONSTANT_DEFAULT_VALUE", CONSTANT_DEFAULT_VALUE ); if (error < 0) { return NULL; } error = PyModule_AddIntConstant( module, "_MISSING_DEFAULT_VALUE", MISSING_DEFAULT_VALUE ); if (error < 0) { return NULL; } error = PyModule_AddIntConstant( module, "_OBJECT_DEFAULT_VALUE", OBJECT_DEFAULT_VALUE ); if (error < 0) { return NULL; } error = PyModule_AddIntConstant( module, "_LIST_COPY_DEFAULT_VALUE", LIST_COPY_DEFAULT_VALUE ); if (error < 0) { return NULL; } error = PyModule_AddIntConstant( module, "_DICT_COPY_DEFAULT_VALUE", DICT_COPY_DEFAULT_VALUE ); if (error < 0) { return NULL; } error = PyModule_AddIntConstant( module, "_TRAIT_LIST_OBJECT_DEFAULT_VALUE", TRAIT_LIST_OBJECT_DEFAULT_VALUE ); if (error < 0) { return NULL; } error = PyModule_AddIntConstant( module, "_TRAIT_DICT_OBJECT_DEFAULT_VALUE", TRAIT_DICT_OBJECT_DEFAULT_VALUE ); if (error < 0) { return NULL; } error = PyModule_AddIntConstant( module, "_TRAIT_SET_OBJECT_DEFAULT_VALUE", TRAIT_SET_OBJECT_DEFAULT_VALUE ); if (error < 0) { return NULL; } error = PyModule_AddIntConstant( module, "_CALLABLE_DEFAULT_VALUE", CALLABLE_DEFAULT_VALUE ); if (error < 0) { return NULL; } error = PyModule_AddIntConstant( module, "_CALLABLE_AND_ARGS_DEFAULT_VALUE", CALLABLE_AND_ARGS_DEFAULT_VALUE ); if (error < 0) { return NULL; } error = PyModule_AddIntConstant( module, "_DISALLOW_DEFAULT_VALUE", DISALLOW_DEFAULT_VALUE ); if (error < 0) { return NULL; } error = PyModule_AddIntConstant( module, "_MAXIMUM_DEFAULT_VALUE_TYPE", MAXIMUM_DEFAULT_VALUE_TYPE ); if (error < 0) { return NULL; } return module; } traits-6.3.2/traits/editor_factories.py000066400000000000000000000132601414270267200202440ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Editor factory functions. """ import datetime from functools import partial import logging logger = logging.getLogger(__name__) def password_editor(auto_set=True, enter_set=False): """ Factory function that returns an editor for passwords. """ from traitsui.api import TextEditor return TextEditor( password=True, auto_set=auto_set, enter_set=enter_set ) def multi_line_text_editor(auto_set=True, enter_set=False): """ Factory function that returns a text editor for multi-line strings. """ from traitsui.api import TextEditor return TextEditor( multi_line=True, auto_set=auto_set, enter_set=enter_set ) def bytes_editor(auto_set=True, enter_set=False, encoding=None): """ Factory function that returns a text editor for bytes. """ from traitsui.api import TextEditor if encoding is None: format = bytes.hex evaluate = bytes.fromhex else: format = partial(bytes.decode, encoding=encoding) evaluate = partial(str.encode, encoding=encoding) return TextEditor( multi_line=True, format_func=format, evaluate=evaluate, auto_set=auto_set, enter_set=enter_set, ) def code_editor(): """ Factory function that returns an editor that treats a multi-line string as source code. """ from traitsui.api import CodeEditor return CodeEditor() def html_editor(): """ Factory function for an "editor" that displays a multi-line string as interpreted HTML. """ from traitsui.api import HTMLEditor return HTMLEditor() def shell_editor(): """ Factory function that returns a Python shell for editing Python values. """ from traitsui.api import ShellEditor return ShellEditor() def time_editor(): """ Factory function that returns a Time editor for editing Time values. """ from traitsui.api import TimeEditor return TimeEditor() def date_editor(): """ Factory function that returns a Date editor for editing Date values. """ from traitsui.api import DateEditor return DateEditor() def _datetime_str_to_datetime(datetime_str, format="%Y-%m-%dT%H:%M:%S"): """ Returns the datetime object for a datetime string in the specified format (default ISO format). Raises a ValueError if datetime_str does not match the format. """ # Allow the empty string to be translated to None. if not datetime_str: return None return datetime.datetime.strptime(datetime_str, format) def _datetime_to_datetime_str(datetime_obj, format="%Y-%m-%dT%H:%M:%S"): """ Returns a string representation for a datetime object in the specified format (default ISO format). """ # A Datetime trait can contain None. We translate that to an empty string. if datetime_obj is None: return "" return datetime.date.strftime(datetime_obj, format) def datetime_editor(): """ Factory function that returns an editor with date & time for editing Datetime values. """ from traitsui.api import DatetimeEditor return DatetimeEditor() def _expects_hastraits_instance(handler): """ Does a trait handler or type expect a HasTraits subclass instance? """ from traits.api import HasTraits, BaseInstance, TraitInstance if isinstance(handler, TraitInstance): cls = handler.aClass elif isinstance(handler, BaseInstance): cls = handler.klass else: return False return issubclass(cls, HasTraits) def _instance_handler_factory(handler): """ Get the instance factory of an Instance or TraitInstance """ from traits.api import BaseInstance, DefaultValue, TraitInstance if isinstance(handler, TraitInstance): return handler.aClass elif isinstance(handler, BaseInstance): if handler.default_value_type == DefaultValue.callable_and_args: default_value_getter, args, kwargs = handler.default_value return lambda: default_value_getter(*args, **kwargs) else: return handler.default_value else: msg = "handler should be TraitInstance or BaseInstance, but got {}" raise ValueError(msg.format(repr(handler))) def list_editor(trait, handler): """ Factory that constructs an appropriate editor for a list. """ item_handler = handler.item_trait.handler if _expects_hastraits_instance(item_handler): from traitsui.table_filter import ( EvalFilterTemplate, RuleFilterTemplate, MenuFilterTemplate, EvalTableFilter, ) from traitsui.api import TableEditor return TableEditor( filters=[ RuleFilterTemplate, MenuFilterTemplate, EvalFilterTemplate, ], edit_view="", orientation="vertical", search=EvalTableFilter(), deletable=True, show_toolbar=True, reorderable=True, row_factory=_instance_handler_factory(item_handler), ) else: from traitsui.api import ListEditor return ListEditor( trait_handler=handler, rows=trait.rows if trait.rows else 5, use_notebook=bool(trait.use_notebook), page_name=trait.page_name if trait.page_name else "", ) traits-6.3.2/traits/etsconfig/000077500000000000000000000000001414270267200163245ustar00rootroot00000000000000traits-6.3.2/traits/etsconfig/__init__.py000066400000000000000000000010211414270267200204270ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Supports sharing settings across projects or programs on the same system. Part of the EnthoughtBase project. """ traits-6.3.2/traits/etsconfig/api.py000066400000000000000000000007121414270267200174470ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from .etsconfig import ETSConfig, ETSToolkitError traits-6.3.2/traits/etsconfig/etsconfig.py000066400000000000000000000403061414270267200206620ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Enthought Tool Suite configuration information. """ # Standard library imports. import sys import os from os import path from contextlib import contextmanager class ETSToolkitError(RuntimeError): """ Error raised by issues importing ETS toolkits Attributes ---------- message : str The message detailing the error. toolkit : str or None The toolkit associated with the error. """ def __init__(self, message="", toolkit=None, *args): if not message and toolkit: message = "could not import toolkit '{0}'".format(toolkit) self.toolkit = toolkit self.message = message if message: if toolkit: args = (toolkit,) + args args = (message,) + args self.args = args class ETSConfig(object): """ Enthought Tool Suite configuration information. This class should not use ANY other package in the tool suite so that it will always work no matter which other packages are present. """ ########################################################################### # 'object' interface. ########################################################################### #### operator methods ##################################################### def __init__(self): # Note that this constructor can only ever be called from within this # module, since we don't expose the class. # Shadow attributes for properties. self._application_data = None self._application_home = None self._company = None self._toolkit = None self._kiva_backend = None self._user_data = None ########################################################################### # 'ETSConfig' interface. ########################################################################### #### properties ########################################################### def get_application_data(self, create=False): """ Return the application data directory path. Parameters ---------- create: bool Create the corresponding directory or not. Notes ----- - This is a directory that applications and packages can safely write non-user accessible data to i.e. configuration information, preferences etc. - Do not put anything in here that the user might want to navigate to e.g. projects, user data files etc. - The actual location differs between operating systems. """ if self._application_data is None: self._application_data = self._initialize_application_data( create=create ) return self._application_data @property def application_data(self): """ Property getter, see get_application_data's docstring. """ return self.get_application_data(create=True) @application_data.setter def application_data(self, application_data): """ Property setter. """ self._application_data = application_data def get_application_home(self, create=False): """ Return the application home directory path. Parameters ---------- create: bool Create the corresponding directory or not. Note ---- - This is a directory named after the current, running application that imported this module that applications and packages can safely write non-user accessible data to i.e. configuration information, preferences etc. It is a sub-directory of self.application_data, named after the directory that contains the "main" python script that started the process. For example, if application foo is started with a script named "run.py" in a directory named "foo", then the application home would be: /foo, regardless of if it was launched with "python /run.py" or "cd ; python run.py" - This is useful for library modules used in apps that need to store state, preferences, etc. for the specific app only, and not for all apps which use that library module. If the library module uses ETSConfig.application_home, they can store prefs for the app all in one place and do not need to know the details of where each app might reside. - Do not put anything in here that the user might want to navigate to e.g. projects, user home files etc. - The actual location differs between operating systems. """ if self._application_home is None: self._application_home = path.join( self.get_application_data(create=create), self._get_application_dirname(), ) return self._application_home @property def application_home(self): """ Property getter, see get_application_home's docstring. """ return self.get_application_home(create=True) @application_home.setter def application_home(self, application_home): """ Property setter. """ self._application_home = application_home @property def company(self): """ Property getter. """ if self._company is None: self._company = self._initialize_company() return self._company @company.setter def company(self, company): """ Property setter for the company name. """ self._company = company @contextmanager def provisional_toolkit(self, toolkit): """ Perform an operation with toolkit provisionally set This sets the toolkit attribute of the ETSConfig object to the provided value. If the operation fails with an exception, the toolkit is reset to nothing. This method should only be called if the toolkit is not currently set. Parameters ---------- toolkit : string The name of the toolkit to provisionally use. Raises ------ ETSToolkitError If the toolkit attribute is already set, then an ETSToolkitError will be raised when entering the context manager. """ if self.toolkit: msg = "ETSConfig toolkit is already set to '{0}'" raise ETSToolkitError(msg.format(self.toolkit)) self.toolkit = toolkit try: yield except: # reset the toolkit state self._toolkit = "" raise @property def toolkit(self): """ Property getter for the GUI toolkit. The value returned is, in order of preference: the value set by the application; the value specified by the 'ETS_TOOLKIT' environment variable; otherwise the empty string. """ if self._toolkit is None: self._toolkit = self._initialize_toolkit() return self._toolkit.split(".")[0] @toolkit.setter def toolkit(self, toolkit): """ Property setter for the GUI toolkit. The toolkit can be set more than once, but only if it is the same one each time. An application that is written for a particular toolkit can explicitly set it before any other module that gets the value is imported. """ if self._toolkit and self._toolkit != toolkit: raise ValueError( "cannot set toolkit to %s because it has " "already been set to %s" % (toolkit, self._toolkit) ) self._toolkit = toolkit @property def enable_toolkit(self): """ Deprecated: This property is no longer used. Property getter for the Enable backend. The value returned is, in order of preference: the value set by the application; the value specified by the 'ENABLE_TOOLKIT' environment variable; otherwise the empty string. """ from warnings import warn warn("Use of the enable_toolkit attribute is deprecated.") return self.toolkit @enable_toolkit.setter def enable_toolkit(self, toolkit): """ Deprecated. Property setter for the Enable toolkit. The toolkit can be set more than once, but only if it is the same one each time. An application that is written for a particular toolkit can explicitly set it before any other module that gets the value is imported. """ from warnings import warn warn("Use of the enable_toolkit attribute is deprecated.") @property def kiva_backend(self): """ Property getter for the Kiva backend. The value returned is dependent on the value of the toolkit property. If toolkit specifies a kiva backend using the extended syntax: [.] then the value of the property will be whatever was specified. Otherwise the value will be a reasonable default for the given enable backend. """ if self._toolkit is None: raise AttributeError( "The kiva_backend attribute is dependent on toolkit, " "which has not been set." ) if self._kiva_backend is None: try: self._kiva_backend = self._toolkit.split(".")[1] except IndexError: # Pick a reasonable default based on the toolkit if self.toolkit == "wx": self._kiva_backend = ( "quartz" if sys.platform == "darwin" else "image" ) elif self.toolkit in ["qt4", "qt"]: self._kiva_backend = "image" else: self._kiva_backend = "image" return self._kiva_backend @property def user_data(self): """ Property getter. This is a directory that users can safely write user accessible data to i.e. user-defined functions, edited functions, etc. The actual location differs between operating systems. """ if self._user_data is None: self._user_data = self._initialize_user_data() return self._user_data @user_data.setter def user_data(self, user_data): """ Property setter. """ self._user_data = user_data #### private methods ##################################################### # fixme: In future, these methods could allow the properties to be set # via the (as yet non-existent) preference/configuration mechanism. This # would allow configuration via (in order of precedence):- # # - a configuration file # - environment variables # - the command line def _get_application_dirname(self): """ Return the name of the directory (not a path) that the "main" Python script which started this process resides in, or "" if it could not be determined or is not appropriate. For example, if the script that started the current process was named "run.py" in a directory named "foo", and was launched with "python run.py", the name "foo" would be returned (this assumes the directory name is the name of the app, which seems to be as good of an assumption as any). """ dirname = "" main_mod = sys.modules.get("__main__", None) if main_mod is not None: if hasattr(main_mod, "__file__"): main_mod_file = path.abspath(main_mod.__file__) dirname = path.basename(path.dirname(main_mod_file)) return dirname def _initialize_application_data(self, create=True): """ Initializes the (default) application data directory. """ if sys.platform == "win32": environment_variable = "APPDATA" directory_name = self.company else: environment_variable = "HOME" directory_name = "." + self.company.lower() # Lookup the environment variable. parent_directory = os.environ.get(environment_variable, None) if parent_directory is None or parent_directory == "/root": import tempfile from warnings import warn parent_directory = tempfile.gettempdir() user = os.environ.get("USER", None) if user is not None: directory_name += "_%s" % user warn( 'Environment variable "%s" not set, ' 'setting home directory to %s' % (environment_variable, parent_directory) ) application_data = os.path.join(parent_directory, directory_name) if create: # If a file already exists with this name then make sure that it is # a directory! if os.path.exists(application_data): if not os.path.isdir(application_data): raise ValueError( 'File "%s" already exists' % application_data ) # Otherwise, create the directory. else: os.makedirs(application_data) return application_data def _initialize_company(self): """ Initializes the (default) company. """ return "Enthought" def _initialize_toolkit(self): """ Initializes the toolkit. """ if self._toolkit is not None: toolkit = self._toolkit else: toolkit = os.environ.get("ETS_TOOLKIT", "") return toolkit def _initialize_user_data(self): """ Initializes the (default) user data directory. """ # We check what the os.path.expanduser returns parent_directory = os.path.expanduser("~") directory_name = self.company if sys.platform == "win32": try: from win32com.shell import shell, shellcon # Due to the fact that the user's My Documents directory can # be in some pretty strange places, it's safest to just ask # Windows where it is. MY_DOCS = shellcon.CSIDL_PERSONAL parent_directory = shell.SHGetFolderPath(0, MY_DOCS, 0, 0) except ImportError: # But if they don't have pywin32 installed, just do it the # naive way... # Check if the usr_dir is C:\\John Doe\\Documents and Settings. # If yes, then we should modify the usr_dir to be # 'My Documents'. If no, then the user must have modified the # os.environ variables and the directory chosen is a desirable # one. desired_dir = os.path.join(parent_directory, "My Documents") if os.path.exists(desired_dir): parent_directory = desired_dir else: directory_name = directory_name.lower() # The final directory. usr_dir = os.path.join(parent_directory, directory_name) # If a file already exists with this name then make sure that it is # a directory! if os.path.exists(usr_dir): if not os.path.isdir(usr_dir): raise ValueError('File "%s" already exists' % usr_dir) # Otherwise, create the directory. else: os.makedirs(usr_dir) return usr_dir # We very purposefully only have one object and do not export the class. We # could have just made everything class methods, but that always seems a bit # gorpy, especially with properties etc. ETSConfig = ETSConfig() traits-6.3.2/traits/etsconfig/tests/000077500000000000000000000000001414270267200174665ustar00rootroot00000000000000traits-6.3.2/traits/etsconfig/tests/__init__.py000066400000000000000000000000001414270267200215650ustar00rootroot00000000000000traits-6.3.2/traits/etsconfig/tests/test_etsconfig.py000066400000000000000000000245311414270267200230650ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests the 'ETSConfig' configuration object. """ # Standard library imports. import contextlib import os import shutil import sys import tempfile import time import unittest # Enthought library imports. from traits.etsconfig.etsconfig import ETSConfig, ETSToolkitError @contextlib.contextmanager def temporary_directory(): """ Context manager to create and clean up a temporary directory. """ temp_dir = tempfile.mkdtemp() try: yield temp_dir finally: shutil.rmtree(temp_dir) @contextlib.contextmanager def restore_mapping_entry(mapping, key): """ Context manager that restores a mapping entry to its previous state on exit. """ missing = object() old_value = mapping.get(key, missing) try: yield finally: if old_value is missing: mapping.pop(key, None) else: mapping[key] = old_value @contextlib.contextmanager def temporary_home_directory(): """ Context manager that temporarily remaps HOME / APPDATA to a temporary directory. """ # Use the same recipe as in ETSConfig._initialize_application_data # to determine the home directory. home_var = "APPDATA" if sys.platform == "win32" else "HOME" with temporary_directory() as temp_home: with restore_mapping_entry(os.environ, home_var): os.environ[home_var] = temp_home yield @contextlib.contextmanager def mock_sys_argv(args): old_args = sys.argv sys.argv = args try: yield finally: sys.argv = old_args @contextlib.contextmanager def mock_os_environ(args): old_environ = os.environ os.environ = args try: yield finally: os.environ = old_environ class ETSConfigTestCase(unittest.TestCase): """ Tests the 'ETSConfig' configuration object. """ ########################################################################### # 'TestCase' interface. ########################################################################### #### public methods ####################################################### def setUp(self): """ Prepares the test fixture before each test method is called. """ # Make a fresh instance each time. self.ETSConfig = type(ETSConfig)() def run(self, result=None): # Extend TestCase.run to use a temporary home directory. with temporary_home_directory(): super().run(result) ########################################################################### # 'ETSConfigTestCase' interface. ########################################################################### #### public methods ####################################################### def test_application_data(self): """ application data """ dirname = self.ETSConfig.application_data self.assertEqual(os.path.exists(dirname), True) self.assertEqual(os.path.isdir(dirname), True) def test_set_application_data(self): """ set application data """ old = self.ETSConfig.application_data self.ETSConfig.application_data = "foo" self.assertEqual("foo", self.ETSConfig.application_data) self.ETSConfig.application_data = old self.assertEqual(old, self.ETSConfig.application_data) def test_application_data_is_idempotent(self): """ application data is idempotent """ # Just do the previous test again! self.test_application_data() self.test_application_data() def test_write_to_application_data_directory(self): """ write to application data directory """ self.ETSConfig.company = "Blah" dirname = self.ETSConfig.application_data path = os.path.join(dirname, "dummy.txt") data = str(time.time()) with open(path, "w", encoding="utf-8") as f: f.write(data) self.assertEqual(os.path.exists(path), True) with open(path, "r", encoding="utf-8") as f: result = f.read() os.remove(path) self.assertEqual(data, result) def test_default_company(self): """ default company """ self.assertEqual(self.ETSConfig.company, "Enthought") def test_set_company(self): """ set company """ old = self.ETSConfig.company self.ETSConfig.company = "foo" self.assertEqual("foo", self.ETSConfig.company) self.ETSConfig.company = old self.assertEqual(old, self.ETSConfig.company) def _test_default_application_home(self): """ application home """ # This test is only valid when run with the 'main' at the end of this # file: "python app_dat_locator_test_case.py", in which case the # app_name will be the directory this file is in ('tests'). app_home = self.ETSConfig.application_home (dirname, app_name) = os.path.split(app_home) self.assertEqual(dirname, self.ETSConfig.application_data) self.assertEqual(app_name, "tests") def test_toolkit_default_kiva_backend(self): self.ETSConfig.toolkit = "qt4" self.assertEqual(self.ETSConfig.kiva_backend, "image") def test_default_backend_for_qt5_toolkit(self): self.ETSConfig.toolkit = "qt" self.assertEqual(self.ETSConfig.kiva_backend, "image") def test_toolkit_explicit_kiva_backend(self): self.ETSConfig.toolkit = "wx.celiagg" self.assertEqual(self.ETSConfig.kiva_backend, "celiagg") def test_toolkit_environ(self): test_args = ["something"] test_environ = {"ETS_TOOLKIT": "test"} with mock_sys_argv(test_args): with mock_os_environ(test_environ): toolkit = self.ETSConfig.toolkit self.assertEqual(toolkit, "test") def test_toolkit_environ_missing(self): test_args = ["something"] test_environ = {} with mock_sys_argv(test_args): with mock_os_environ(test_environ): toolkit = self.ETSConfig.toolkit self.assertEqual(toolkit, "") def test_set_toolkit(self): test_args = [] test_environ = {"ETS_TOOLKIT": "test_environ"} with mock_sys_argv(test_args): with mock_os_environ(test_environ): self.ETSConfig.toolkit = "test_direct" toolkit = self.ETSConfig.toolkit self.assertEqual(toolkit, "test_direct") def test_provisional_toolkit(self): test_args = [] test_environ = {} with mock_sys_argv(test_args): with mock_os_environ(test_environ): repr(self.ETSConfig.toolkit) with self.ETSConfig.provisional_toolkit("test_direct"): toolkit = self.ETSConfig.toolkit self.assertEqual(toolkit, "test_direct") # should stay set, since no exception raised toolkit = self.ETSConfig.toolkit self.assertEqual(toolkit, "test_direct") def test_provisional_toolkit_exception(self): test_args = [] test_environ = {"ETS_TOOLKIT": ""} with mock_sys_argv(test_args): with mock_os_environ(test_environ): try: with self.ETSConfig.provisional_toolkit("test_direct"): toolkit = self.ETSConfig.toolkit self.assertEqual(toolkit, "test_direct") raise ETSToolkitError("Test exception") except ETSToolkitError as exc: if not exc.message == "Test exception": raise # should be reset, since exception raised toolkit = self.ETSConfig.toolkit self.assertEqual(toolkit, "") def test_provisional_toolkit_already_set(self): test_args = [] test_environ = {"ETS_TOOLKIT": "test_environ"} with mock_sys_argv(test_args): with mock_os_environ(test_environ): with self.assertRaises(ETSToolkitError): with self.ETSConfig.provisional_toolkit("test_direct"): pass # should come from the environment toolkit = self.ETSConfig.toolkit self.assertEqual(toolkit, "test_environ") def test_user_data(self): """ user data """ dirname = self.ETSConfig.user_data self.assertEqual(os.path.exists(dirname), True) self.assertEqual(os.path.isdir(dirname), True) def test_set_user_data(self): """ set user data """ old = self.ETSConfig.user_data self.ETSConfig.user_data = "foo" self.assertEqual("foo", self.ETSConfig.user_data) self.ETSConfig.user_data = old self.assertEqual(old, self.ETSConfig.user_data) def test_user_data_is_idempotent(self): """ user data is idempotent """ # Just do the previous test again! self.test_user_data() def test_write_to_user_data_directory(self): """ write to user data directory """ self.ETSConfig.company = "Blah" dirname = self.ETSConfig.user_data path = os.path.join(dirname, "dummy.txt") data = str(time.time()) with open(path, "w", encoding="utf-8") as f: f.write(data) self.assertEqual(os.path.exists(path), True) with open(path, "r", encoding="utf-8") as f: result = f.read() os.remove(path) self.assertEqual(data, result) # For running as an individual set of tests. if __name__ == "__main__": # Add the non-default test of application_home...non-default because it # must be run using this module as a script to be valid. suite = unittest.TestLoader().loadTestsFromTestCase(ETSConfigTestCase) suite.addTest(ETSConfigTestCase("_test_default_application_home")) unittest.TextTestRunner(verbosity=2).run(suite) traits-6.3.2/traits/examples/000077500000000000000000000000001414270267200161615ustar00rootroot00000000000000traits-6.3.2/traits/examples/__init__.py000066400000000000000000000006271414270267200202770ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! traits-6.3.2/traits/examples/_etsdemo_info.py000066400000000000000000000017741414270267200213560ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ This module provides functions to be advertised in the distribution entry points. """ def introduction(request): """ Return a configuration for contributing examples to the Demo application. Parameters ---------- request : dict Information provided by the demo application. Currently this is a placeholder. Returns ------- response : dict """ import pkg_resources return dict( version=1, name="Traits Introduction", root=( pkg_resources.resource_filename("traits", "examples/introduction") ), ) traits-6.3.2/traits/examples/introduction/000077500000000000000000000000001414270267200207025ustar00rootroot00000000000000traits-6.3.2/traits/examples/introduction/0_introduction.py000066400000000000000000000076361414270267200242300ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Introduction to Traits ====================== To make the tutorial more practical, let's imagine that you are writing some tools to organize and process image data, perhaps to help you develop a machine learning algorithm, or to document your research. This image data might come from a camera, a scanning electron microscope, or from some more exotic source. No matter the source, the image will have data associated with it, such as who produced the image, the equipment that was used, the date and time that the image was taken, and so forth. In this tutorial, we'll consider an example where we have a collection of greyscale SEM images, each of them stored in a file, along with other information, such as the sample that was imaged, the size of the scanned region, and the operator who took the image. We would like to read in the image and provide a number of standard analysis steps to the user, as well as making the raw image data available as a NumPy array. The sample code here shows how you might create a class in standard object-oriented Python with NumPy for analysis and Pillow for image loading. Experiment with the code in the example to see how you can use it. In the subsequent steps of the tutorial, we'll look at how we can use Traits to simplify and improve the code here. """ import datetime import os import numpy as np from PIL import Image as PILImage class Image: """ An SEM image stored in a file. """ def __init__(self, filename, sample_id, date_acquired, operator, scan_size=(1e-5, 1e-5)): # initialize the primary attributes self.filename = filename self.sample_id = sample_id self.operator = operator self.date_acquired = operator self.scan_size = scan_size # useful secondary attributes self.scan_width, self.scan_height = self.scan_size def read_image(self): """ Read the image from disk. """ pil_image = PILImage.open(self.filename).convert("L") self.image = np.array(pil_image) # compute some extra secondary attributes from the image if self.image.size > 0: self.pixel_area = ( self.scan_height * self.scan_width / self.image.size ) else: self.pixel_area = 0 def histogram(self): """ Compute the normalized histogram of the image. """ hist, bins = np.histogram( self.image, bins=256, range=(0, 256), density=True, ) return hist def threshold(self, low=0, high=255): """ Compute a threshold mask for the array. """ return (self.image >= low) & (self.image <= high) # --------------------------------------------------------------------------- # Demo code # --------------------------------------------------------------------------- this_dir = os.path.dirname(__file__) image_dir = os.path.join(this_dir, "images") filename = os.path.join(image_dir, "sample_0001.png") # load the image image = Image( filename=filename, operator="Hannes", sample_id="0001", date_acquired=datetime.datetime.today(), scan_size=(1e-5, 1e-5), ) # read the image from disk image.read_image() # perform some sample computations print( "The maximum intensity of {} is {}".format( image.sample_id, image.histogram().argmax(), ) ) pixel_count = image.threshold(low=200).sum() print( "The area with intensity greater than 200 is {:0.3f} µm²".format( pixel_count * image.pixel_area * 1e12 ) ) traits-6.3.2/traits/examples/introduction/1_validation.py000066400000000000000000000146331414270267200236350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Validation ========== A common issue faced by scientists is ensuring that the data that is entered matches the sort of data that is expected. For example, we expect that the filename is a string (or perhaps a pathlib **Path**, for advanced users), the operator name is a string, the acquisition date is a datetime.date object, and so on. Many languages allow (or even require) you to specify these data types as part of your program, but even then these data types tend to reflect what the computer stores in memory, and not what the data actually *represents*. For example, not only should the file be a string, but we would like to validate that the string is in fact a valid path name, and ideally that the file can actually be found. A sample ID may be expected to follow some pattern based on lab protocols. The image data is expected to be a 2D array of values rather than just any NumPy array. And so on. Traits provides a way to ensure that values are validated when assigned in your classes: as part of your class definition you _declare_ what you expect your data to be. To do this, the first thing you want to do is inherit from the base ``HasTraits`` class which enables all of the validation machinery:: from traits.api import HasTraits class Image(HasTraits): ''' An SEM image stored in a file. ''' Having done this, we can declare the types of data that we expect for the attributes of an ``Image`` class. For example, we expect that the operator name should be a string, so we can use the standard Traits ``Str`` trait type:: from traits.api import HasTraits, Str class Image(HasTraits): ''' An SEM image stored in a file. ''' operator = Str() Now, if we try and assign any other value to the ``operator`` attribute, we find that the class will raise a ``TraitError``:: >>> image = Image() >>> image.operator = 3 TraitError: The 'operator' trait of an Image instance must be a string, but a value of 3 was specified. Traits has trait types corresponding to all the basic Python data types: ``Int``, ``Float``, ``Complex``, ``Bool``, and ``Str``. It also has trait types for the standard containers: ``List``, ``Dict``, ``Set`` and ``Tuple``. There is an ``Instance`` trait type for values which are instances of a Python class. Traits also provides a rich set of trait types that cover many common data types, for example: - we can use a ``Date`` trait type for the date_acquired - we can specify that the scan size is not just a tuple, but a pair of floating point values by specifying ``Tuple(Float, Float)``. - we can use a ``File`` trait for the filename, and we can require that the path refer to an existing file by using ``File(exists=True)``. - we can specify that the image data is a 2D NumPy array of unsigned integers with ``Array(shape=(None, None), dtype='uint8')`` Everything else can remain unchanged in the class, and it will still work as expected, however just as with regular Python classes, we need to remember to call ``super()`` in the ``__init__`` method:: def __init__(self, filename, sample_id, date_acquired, operator, scan_size=(1e-5, 1e-5)): super().__init__() # initialize the primary attributes ... When we talk about an attribute which is declared by a trait type, it is common to call it a _trait_ rather than an attribute. Traits and Static Types ----------------------- The first version of Traits was written over 15 years ago. In the last 5 years or so, Python has started to gain the ability to perform static type checking using tools like MyPy and certain integrated development environments. The ``dataclass`` module introduced in recent Python versions can do similar sorts of type declaration for classes. Advanced Python users may be aware of, and using these classes already. As we will see, the capabilities of Traits are much greater than these type checking systems, however if you have the traits-stubs package installed, most of your trait type declarations will be recognised and can be used with these new Python type systems. Exercise -------- The example code hasn't declared trait types for all the attributes used by the class. Declare trait types for ``scan_width``, ``scan_height`` and ``pixel_area``. """ import datetime import os from traits.api import Array, Date, HasTraits, File, Float, Str, Tuple class Image(HasTraits): """ An SEM image stored in a file. """ filename = File(exists=True) sample_id = Str() date_acquired = Date() operator = Str() scan_size = Tuple(Float, Float) image = Array(shape=(None, None), dtype='uint8') def __init__(self, filename, sample_id, date_acquired, operator, scan_size=(1e-5, 1e-5)): super().__init__() # initialize the primary attributes self.filename = filename self.sample_id = sample_id self.scan_size = scan_size self.operator = operator # useful secondary attributes self.scan_width, self.scan_height = self.scan_size # --------------------------------------------------------------------------- # Demo code # --------------------------------------------------------------------------- this_dir = os.path.dirname(__file__) image_dir = os.path.join(this_dir, "images") filename = os.path.join(image_dir, "sample_0001.png") # load the image image = Image( filename=filename, operator="Hannes", sample_id="0001", date_acquired=datetime.datetime.today(), scan_size=(1e-5, 1e-5), ) # show all the defined traits image.print_traits() # we can't set the operator name to a number print(set) try: image.operator = 3 except Exception as exc: print(exc) # we can't create an image which uses a non-existent path non_existent_filename = os.path.join(image_dir, "does_not_exist.png") try: image = Image( filename=filename, operator="Hannes", sample_id="0001", date_acquired=datetime.datetime.today(), scan_size=(1e-5, 1e-5), ) except Exception as exc: print(exc) traits-6.3.2/traits/examples/introduction/2_initialization.py000066400000000000000000000137251414270267200245340ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Initialization ============== If you have done any significant amount of object-oriented Python programming, you may have noticed that your ``__init__`` methods often have a lot of boilerplate. In our original example, the code copies all of the ``__init__`` arguments to corresponding attributes before doing any real work:: def __init__(self, filename, sample_id, date_acquired, operator, scan_size=(1e-5, 1e-5)): # initialize the primary attributes self.filename = filename self.sample_id = sample_id self.operator = operator self.scan_size = scan_size Traits lets you avoid this boilerplate by defining a default ``__init__`` method that accepts keyword arguments that correspond to the declared traits. The Traits version of the ``Image`` class could potentially skip the ``__init__`` method entirely:: class Image(HasTraits): filename = File(exists=True) sample_id = Str() date_acquired = Date() operator = Str() scan_size = Tuple(Float, Float) # this works! image = Image( filename=filename, operator="Hannes", sample_id="0001", date_acquired=datetime.datetime.today(), scan_size=(1e-5, 1e-5), ) Default Values -------------- There are a couple of complications in the example that we need to take into account. The first is what happens if a user forgets to provide an initial value:: >>> image = Image( ... filename=filename, ... sample_id="0001", ... date_acquired=datetime.datetime.today(), ... scan_size=(1e-5, 1e-5), ... ) >>> image.operator "" As this example shows, the operator gets given a default value of the empty string ``""``. In fact every trait type comes with an default value. For numeric trait types, like ``Int`` and ``Float``, the default is 0. For ``Str`` trait types it is the empty string, for ``Bool`` traits it is ``False``, and so on. However, that might not be what you want as your default value. For example, you might want to instead flag that the operator has not been provided with the string ``"N/A"`` for "not available". Most trait types allow you to specify a default value as part of the declaration. So we could say:: operator = Str("N/A") and now if we omit ``operator`` from the arguments, we get:: >>> image.operator "N/A" Dynamic Defaults ---------------- The second complication comes from more complex initial values. For example, we could declare some arbitrary fixed date as the default value for ``date_acquired``:: date_acquired = Date(datetime.date(2020, 1, 1)) But it would be better if we could set it to a dynamic value. For example, a reasonable default would be today's date. You can provide this sort of dynamically declared default by using a specially-named method which has the pattern ``__default`` and which returns the default value. So we could write:: def _date_acquired_default(self): return datetime.datetime.today() Dynamic defaults are best used for values which don't depend on other traits. For example, it might be tempting to have the ``image`` trait have a dynamic default which loads in the data. As we will see, this is almost always better handled by Traits observation and/or properties, which are discussed in subsequent sections of the tutorial. The ``traits_init`` Method -------------------------- Although you aren't required to write an ``__init__`` method in a ``HasTraits`` subclass, you can always choose to do so. If you do, you **must** call ``super()`` to ensure that Traits has a chance to set up its machinery. In our example the ``__init__`` method is also used to set up some auxiliary values. This doesn't have to change:: def __init__(self, **traits): super().__init__(**traits) # useful secondary attributes self.scan_width, self.scan_height = self.scan_size However Traits offers a slightlty more convenient way of doing this sort of post-initialization setup of state: you can define a ``traits_init`` method which the ``HasTraits`` class ensures is called as part of the main initialization process. When it has been called, all initial values will have been set:: def traits_init(self): # useful secondary attributes self.scan_width, self.scan_height = self.scan_size Exercise -------- In our original example, the ``scan_size`` atribute had a default value of ``(1e-5, 1e-5)``. Modify the code in the example so that the trait is initialized to this default using a dynamic default method. """ import datetime import os from traits.api import Array, Date, HasTraits, File, Float, Str, Tuple class Image(HasTraits): """ An SEM image stored in a file. """ filename = File(exists=True) sample_id = Str() date_acquired = Date() operator = Str("N/A") scan_size = Tuple(Float, Float) image = Array(shape=(None, None), dtype='uint8') def traits_init(self): # useful secondary attributes self.scan_width, self.scan_height = self.scan_size def _date_acquired_default(self): return datetime.datetime.today() # --------------------------------------------------------------------------- # Demo code # --------------------------------------------------------------------------- this_dir = os.path.dirname(__file__) image_dir = os.path.join(this_dir, "images") filename = os.path.join(image_dir, "sample_0001.png") # load the image image = Image( filename=filename, sample_id="0001", scan_size=(1e-5, 1e-5), ) # show all the defined traits image.print_traits() traits-6.3.2/traits/examples/introduction/3_observation.py000066400000000000000000000134051414270267200240340ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Observation =========== In our code so far, there is a problem that it is possible for certain related values to get out of sync with one another. For example, if we change the filename after we have read the image into memory, then the data in memory still refers to the old image. It would be nice if we could automatically re-load the image if the filename changes. Traits allows you to do this. The Observe Decorator --------------------- We want to have the `read_image` method run whenever the ``filename`` trait changes. We can do this by adding an ``observe`` decorator to the method:: class Image(HasTraits): ... @observe('filename') def read_image(self, event): ... The observer passes an event object to the function which contains information about what changed, such as the old value of the trait, but we don't need that information to react to the change, so it is ignored in the body of the function. For most traits, the observer will run only when the trait's value *actually* changes, not just when the value is set. So if you do:: >>> image.filename = "sample_0001.png" >>> image.filename = "sample_0001.png" then the observer will only be run once. Observing Multiple Traits ------------------------- If you look at the computation of ``pixel_area`` in the original code, it looks like this:: self.pixel_area = self.scan_height * self.scan_width / self.image.size It depends on the ``scan_width``, ``scan_height`` and the ``image``, so we would like to listen to changes to *all* of these. We could write three ``@observe`` functions, one for each trait, but the content would be the same for each. A better way to do this is to have the observer listen to all the traits at once:: class Image(HasTraits): ... @observe('scan_width, scan_height, image') def update_pixel_area(self, event): if self.image.size > 0: self.pixel_area = ( self.scan_height * self.scan_width / self.image.size ) else: self.pixel_area = 0 Dynamic Observers ----------------- Sometimes you want to be able to observe changes to traits from a different object or piece of code. The ``observe`` method on a ``HasTraits`` subclass allows you to dynamically specify a function to be called if the value of a trait changes:: image = Image( filename="sample_0001.png", sample_id="0001", ) def print_filename_changed(event): print("Filename changed") image.observe(print_filename_changed, 'filename') # will print "Filename changed" to the screen image.filename="sample_0002.png" Dynamic observers can also be disconnected using the same method, by adding the argument ``remove=True``:: image.observe(print_filename_changed, 'filename', remove=True) # nothing will print image.filename="sample_0003.png" Exercise -------- Currently ``scan_height`` and ``scan_width`` are set from the parts of the ``scan_size`` trait as part of the ``traits_init`` method. Remove the ``traits_init`` method and have ``scan_height`` and ``scan_width`` methods update whenever ``scan_size`` changes. """ import os import datetime from PIL import Image as PILImage import numpy as np from traits.api import ( Array, Date, File, Float, HasTraits, Str, Tuple, observe ) class Image(HasTraits): """ An SEM image stored in a file. """ filename = File(exists=True) sample_id = Str() operator = Str("N/A") date_acquired = Date() scan_size = Tuple(Float, Float) scan_width = Float scan_height = Float image = Array(shape=(None, None), dtype='uint8') pixel_area = Float() def traits_init(self): # useful secondary attributes self.scan_width, self.scan_height = self.scan_size # Trait observers @observe('filename') def read_image(self, event): pil_image = PILImage.open(self.filename).convert("L") self.image = np.array(pil_image) @observe('scan_width, scan_height, image') def update_pixel_area(self, event): if self.image.size > 0: self.pixel_area = ( self.scan_height * self.scan_width / self.image.size ) else: self.pixel_area = 0 # Trait default methods def _date_acquired_default(self): return datetime.date.today() def _scan_size_default(self): return (1e-5, 1e-5) # --------------------------------------------------------------------------- # Demo code # --------------------------------------------------------------------------- this_dir = os.path.dirname(__file__) image_dir = os.path.join(this_dir, "images") filename = os.path.join(image_dir, "sample_0001.png") # load the image image = Image( filename=filename, operator="Hannes", sample_id="0001", ) # perform some sample computations print("Scan size:", image.scan_size) print("Change scan width to 1e-4") image.scan_width = 1e-4 print("Scan size:", image.scan_size) for filename in os.listdir(image_dir): if os.path.splitext(filename)[1] == '.png': print() print("Changing filename to {}".format(filename)) image.filename = os.path.join(image_dir, filename) print( "The pixel size of {} is {:0.3f} nm²".format( filename, image.pixel_area * 1e18, ) ) traits-6.3.2/traits/examples/introduction/4_properties.py000066400000000000000000000144441414270267200237020ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Property Traits =============== The ``Image`` class has three traits which are closely related: ``scan_size``, ``scan_width`` and ``scan_height``. We would ideally like to keep all of these synchronized. This can be done with trait observation, as shown in the previous section, but this sort of pattern is common enough that Traits has some in-built helpers. Instead of declaring that ``scan_width = Float()`` we could instead declare it to be a ``Property`` trait type. Property traits are similar to ``@property`` decorators in standard Python in that rather than storing a value, they compute a derived value via a "getter", and optionally store values via a "setter". Traits uses specially named methods of the form ``_get_`` and ``_set_property`` for these "getters" and "setters." If there is a "getter" but no "setter" then the property is read-only. Additionally, we need to know when the value of the property might change, and so we need to declare what traits to observe to know when the property might change. What all this means is that we can define ``scan_width`` as a property by:: class Image(HasTraits): ... scan_width = Property(Float, depends_on='scan_size') def _get_scan_width(self): return self.scan_size[0] def _set_scan_width(self, value): self.scan_size = (value, self.scan_height) Traits will then take care of hooking up all the required observers to make everything work as expected; and the `Property` can also be observed if desired. Simple `Property` traits like this are computed "lazily": the value is only calculated when you ask for it. Cached Properties ----------------- It would be quite easy to turn the histogram function into a read-only property. This might look something like this:: class Image(HasTraits): ... histogram = Property(Array, depends_on='image') def _get_histogram(self): hist, bins = np.histogram( self.image, bins=256, range=(0, 256), density=True, ) return hist This works, but it has a downside that the histogram is re-computed every time the property is accessed. For small images, this is probably OK, but for larger images, or if you are working with many images at once, this may impact performance. In these cases, you can specify that the property should **cache** the returned value and use that value until the trait(s) the property depend on changes:: class Image(HasTraits): ... histogram = Property(Array, depends_on='image') @cached_property def _get_histogram(self): hist, bins = np.histogram( self.image, bins=256, range=(0, 256), density=True, ) return hist This has the trade-off that the result of the computation is being stored in memory, but in this case the memory is only a few hundred bytes, and so is unlikely to cause problems; but you probably wouldn't want to do this with a multi-gigabyte array. Exercise -------- Make ``pixel_area`` a read-only property. """ import os import datetime from PIL import Image as PILImage import numpy as np from traits.api import ( Array, Date, File, Float, HasTraits, Property, Str, Tuple, cached_property, observe ) class Image(HasTraits): """ An SEM image stored in a file. """ filename = File(exists=True) sample_id = Str() operator = Str("N/A") date_acquired = Date() scan_size = Tuple(Float, Float) scan_width = Property(Float, depends_on='scan_size') scan_height = Property(Float, depends_on='scan_size') image = Array(shape=(None, None), dtype='uint8') histogram = Property(Array, depends_on='image') pixel_area = Float() # Trait observers @observe('filename') def read_image(self, event): pil_image = PILImage.open(self.filename).convert("L") self.image = np.array(pil_image) # compute some extra secondary attributes from the image if self.image.size > 0: self.pixel_area = ( self.scan_height * self.scan_width / self.image.size ) else: self.pixel_area = 0 # Trait default methods def _date_acquired_default(self): return datetime.date.today() def _scan_size_default(self): return (1e-5, 1e-5) # Trait property methods def _get_scan_width(self): return self.scan_size[0] def _set_scan_width(self, value): self.scan_size = (value, self.scan_size[1]) def _get_scan_height(self): return self.scan_size[1] def _set_scan_height(self, value): self.scan_size = (self.scan_size[0], value) @cached_property def _get_histogram(self): hist, bins = np.histogram( self.image, bins=256, range=(0, 256), density=True, ) return hist # --------------------------------------------------------------------------- # Demo code # --------------------------------------------------------------------------- this_dir = os.path.dirname(__file__) image_dir = os.path.join(this_dir, "images") filename = os.path.join(image_dir, "sample_0001.png") # load the image image = Image( filename=filename, operator="Hannes", sample_id="0001", ) # perform some sample computations print("Scan size:", image.scan_size) print("Change scan width to 1e-4") image.scan_width = 1e-4 print("Scan size:", image.scan_size) for filename in os.listdir(image_dir): if os.path.splitext(filename)[1] == '.png': print() print("Changing filename to {}".format(filename)) image.filename = os.path.join(image_dir, filename) print( "The most frequent intensity of {} is {}".format( filename, image.histogram.argmax(), ) ) traits-6.3.2/traits/examples/introduction/5_documentation.py000066400000000000000000000136311414270267200243550ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Documentation ============= Another advantage of using Traits is that you code becomes clearer and easier for yourself and other people to work with. If you look at the original version of the image class, it isn't clear what attributes are available on the class and, worse yet, it isn't clear *when* those attributes are available. Self-Documenting Code --------------------- By using Traits, all your attributes are declared up-front, so anyone reading your class knows exactly what your class is providing:: class Image(HasTraits): filename = File(exists=True) sample_id = Str() operator = Str("N/A") date_acquired = Date() scan_size = Tuple(Float, Float) scan_width = Property(Float, depends_on='scan_size') scan_height = Property(Float, depends_on='scan_size') image = Array(shape=(None, None), dtype='uint8') pixel_area = Property(Float, depends_on='scan_height,scan_width,image') histogram = Property(Array, depends_on='image') This goes a long way towards the ideal of "self-documenting code." It is common in production-quality Traits code to also document each trait with a special ``#:`` comment so that auto-documentation tools like Sphinx can generate API documentation for you:: class Image(HasTraits): #: The filename of the image. filename = File(exists=True) #: The ID of the sample that is being imaged. sample_id = Str() #: The name of the operator who acquired the image. operator = Str("N/A") ... HasStrictTraits --------------- One common class of errors in Python are typos when accessing an attribute of a class. For example, if we typed:: >>> image.fileanme = "sample_0002.png" Python will not throw an error, but the code will not have the effect that the user expects. Some development tools can help you detect these sorts of errors, but most of these are not available when writing code interactively, such as in a Jupyter notebook. Traits provides a special subclass of ``HasTraits`` called ``HasStrictTraits`` which restricts the allowed attributes to **only** the traits on the class. If we use:: class Image(HasStrictTraits): ... then if we type:: >>> image.fileanme = "sample_0002.png" TraitError: Cannot set the undefined 'fileanme' attribute of a 'Image' object. We get an immediate error which flags the problem. """ import os import datetime from PIL import Image as PILImage import numpy as np from traits.api import ( Array, Date, File, Float, HasStrictTraits, Property, Str, Tuple, cached_property, observe ) class Image(HasStrictTraits): """ An SEM image stored in a file. """ #: The filename of the image. filename = File(exists=True) #: The ID of the sample that is being imaged. sample_id = Str() #: The name of the operator who acquired the image. operator = Str("N/A") #: The date the image was acquired. date_acquired = Date() #: The size of the image. scan_size = Tuple(Float, Float) #: The width of the image. scan_width = Property(Float, depends_on='scan_size') #: The height of the image. scan_height = Property(Float, depends_on='scan_size') #: The image as a 2D numpy array image = Array(shape=(None, None), dtype='uint8') #: The area of each pixel. pixel_area = Property(Float, depends_on='scan_height,scan_width,image') #: The histogram of pixel intensities. histogram = Property(Array, depends_on='image') def threshold(self, low=0, high=255): """ Compute a threshold mask for the array. """ return (self.image >= low) & (self.image <= high) # Trait observers @observe('filename') def read_image(self, event): pil_image = PILImage.open(self.filename).convert("L") self.image = np.array(pil_image) # Trait default methods def _date_acquired_default(self): return datetime.date.today() def _scan_size_default(self): return (1e-5, 1e-5) # Trait property methods def _get_scan_width(self): return self.scan_size[0] def _set_scan_width(self, value): self.scan_size = (value, self.scan_size[1]) def _get_scan_height(self): return self.scan_size[1] def _set_scan_height(self, value): self.scan_size = (self.scan_size[0], value) def _get_pixel_area(self): if self.image.size > 0: return self.scan_height * self.scan_width / self.image.size else: return 0 @cached_property def _get_histogram(self): hist, bins = np.histogram( self.image, bins=256, range=(0, 256), density=True, ) return hist # --------------------------------------------------------------------------- # Demo code # --------------------------------------------------------------------------- this_dir = os.path.dirname(__file__) image_dir = os.path.join(this_dir, "images") filename = os.path.join(image_dir, "sample_0001.png") # load the image image = Image( filename=filename, operator="Hannes", sample_id="0001", date_acquired=datetime.datetime.today(), scan_size=(1e-5, 1e-5), ) # perform some sample computations print( "The maximum intensity of {} is {}".format( image.sample_id, image.histogram.argmax(), ) ) pixel_count = image.threshold(low=200).sum() print( "The area with intensity greater than 200 is {:0.3f} µm²".format( pixel_count * image.pixel_area * 1e12 ) ) traits-6.3.2/traits/examples/introduction/6_visualization.py000066400000000000000000000114241414270267200244040ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Visualization ============= Traits allows you to instantly create a graphical user interface for your ``HasTraits`` classes. If you have TraitsUI and a suitable GUI toolkit (such as PyQt5 or PySide2) installed in your Python environment then you can create a dialog view of an instance of your class by simply doing:: >>> image.configure_traits() This gives you a default UI out of the box with no further effort, but it usually is not what you would want to provide for your users. With a little more effort using the features of TraitsUI, you can design a dialog which is more pleasing:: from traitsui.api import Item, View class Image(HasStrictTraits): ... view = View( Item('filename'), Item('sample_id', label='Sample ID'), Item('operator'), Item('date_acquired'), Item('scan_width', label='Width (m):'), Item('scan_height', label='Height (m):') ) TraitsUI can be used as the building block for complete scientific applications, including 2D and 3D plotting. """ import os import datetime from PIL import Image as PILImage import numpy as np from traits.api import ( Array, Date, File, Float, HasStrictTraits, Property, Str, Tuple, cached_property, observe ) from traitsui.api import Item, View class Image(HasStrictTraits): """ An SEM image stored in a file. """ #: The filename of the image. filename = File(exists=True) #: The ID of the sample that is being imaged. sample_id = Str() #: The name of the operator who acquired the image. operator = Str("N/A") #: The date the image was acquired. date_acquired = Date() #: The size of the image. scan_size = Tuple(Float, Float) #: The width of the image. scan_width = Property(Float, depends_on='scan_size') #: The height of the image. scan_height = Property(Float, depends_on='scan_size') #: The image as a 2D numpy array image = Array(shape=(None, None), dtype='uint8') #: The area of each pixel. pixel_area = Property(Float, depends_on='scan_height,scan_width,image') #: The histogram of pixel intensities. histogram = Property(Array, depends_on='image') def threshold(self, low=0, high=255): """ Compute a threshold mask for the array. """ return (self.image >= low) & (self.image <= high) # Trait observers @observe('filename') def read_image(self, event): pil_image = PILImage.open(self.filename).convert("L") self.image = np.array(pil_image) # Trait default methods def _date_acquired_default(self): return datetime.date.today() def _scan_size_default(self): return (1e-5, 1e-5) # Trait property methods def _get_scan_width(self): return self.scan_size[0] def _set_scan_width(self, value): self.scan_size = (value, self.scan_size[1]) def _get_scan_height(self): return self.scan_size[1] def _set_scan_height(self, value): self.scan_size = (self.scan_size[0], value) def _get_pixel_area(self): if self.image.size > 0: return self.scan_height * self.scan_width / self.image.size else: return 0 @cached_property def _get_histogram(self): hist, bins = np.histogram( self.image, bins=256, range=(0, 256), density=True, ) return hist # TraitsUI view declaration view = View( Item('filename'), Item('sample_id', label='Sample ID'), Item('operator'), Item('date_acquired'), Item('scan_width', label='Width (m):'), Item('scan_height', label='Height (m):'), Item( 'pixel_area', format_func=lambda area: "{:0.3f} µm²".format(area * 1e18), style='readonly', ), ) # --------------------------------------------------------------------------- # Demo code # --------------------------------------------------------------------------- this_dir = os.path.dirname(__file__) image_dir = os.path.join(this_dir, "images") filename = os.path.join(image_dir, "sample_0001.png") # load the image image = Image( filename=filename, operator="Hannes", sample_id="0001", date_acquired=datetime.datetime.today(), scan_size=(1e-5, 1e-5), ) demo = image if __name__ == "__main__": demo.configure_traits() traits-6.3.2/traits/examples/introduction/default.css000066400000000000000000000014501414270267200230400ustar00rootroot00000000000000body { background-color: #FFFFFF; } h1 { font-family: Arial; font-size: 18pt; color: #272a32; background-color: #8fbfde; padding-top: 3px; padding-left:8px; padding-bottom: 3px; padding-right: 8px; } h2 { font-family: Arial; font-size: 14pt; color: #272a32; background-color: #8fbfde; padding-top: 3px; padding-left:8px; padding-bottom: 3px; padding-right: 8px; } pre { border: 1px solid #4488c7; background-color: #eaeaea; padding: 4px; } dl { border: 1px solid #272a32; background-color: #eaeaea; padding-top: 4px; padding-bottom: 6px; padding-left: 8px; padding-right: 8px; } dl dl { border: 0px solid #A0A0A0; } dt { font-family: Arial; font-weight: bold; dd { padding-bottom: 10px; } traits-6.3.2/traits/examples/introduction/images/000077500000000000000000000000001414270267200221475ustar00rootroot00000000000000traits-6.3.2/traits/examples/introduction/images/LICENSE.txt000066400000000000000000000007761414270267200240040ustar00rootroot00000000000000All images are the original work of Hannes Grobe/AWI. The images in this directory are licensed according to the Creative Commons CC BY 3.0 license: https://creativecommons.org/licenses/by/3.0/ sample_0001.png https://commons.wikimedia.org/wiki/Category:Scanning_electron_microscopic_images_of_minerals#/media/File:Arnager-kalk-bornholm_01_hg.jpg sample_0002.png https://commons.wikimedia.org/wiki/Category:Scanning_electron_microscopic_images_of_minerals#/media/File:Arnager-kalk-bornholm_03_hg.jpgtraits-6.3.2/traits/examples/introduction/images/sample_0001.png000066400000000000000000103717421414270267200246150ustar00rootroot00000000000000PNG  IHDŘ iCCPkCGColorSpaceGenericGrayGamma2_2XWXS[z: (]J^Q!@1!+v(ņ k ((*6,oXvwͽsΜ:gnP0 䋅Q) T] 2LH@,goW>I!-bq8rSDLYy38o:[, 52b|!N@NiHVzl!E 2sL&ޑ!Jc{e$#PeD=0'Ůg1ln\>&(!)ɈCl qM0 b/or$AR<L+!aCa|!fHc1C}3aV|b pO `AQvy߰A]x{:38b _yQ煅E(edwB#͙#D0&j6bL*7q9aPԠģ`LAIl~tMi],` cEjqA , D e( 0A&Th-r@CFRdTɃróTkd!}-c 鳇p;7tDAl&ڗ pVii2(!u=CZd0G> |gDÞ8 {4r;DܰϞK}: : (%"h{(1$+$VAH+\֥}o}u!o"\%\&'\TF.nTFbGH rdZsjVR3xD#@,TW ZoK~/=~PkT~v^tM%?BO ^?|J^* zih59h7hh[ );FP[#vk C}¥h)UCx+ %YpoHpWi/wN$-?Ӊ~ b|:HI i1rTeoKu9M4)"R-h$9\z#=tj Ok;x3w u:情`-(6P j~p4{\Aϓ.W`ABF]1GlGBP$ I@4H|dRBʑ-H5i@N +-AFޡj:uEhNCYhZ.CJCO6}cSĴ0cs|p,Kń<+*ZZkX֋ʼn:N`XKr|'^¯x@&la !0PD(%TNExE$`~\`9ĥč=+ć~K!yILTDZO!#]%u)9% Jv*Xn@^E\]>\>E>W~6FK] 1 jN+UxhU\XWb[%5%k%_$%2JǕn) dr"YL^F&$'S) J e>RGJy,lLW\|@r SeJJ ~UuUpLեTϩv,R նT{oS?ޥA԰`hkhqQOSMsfff-LBZ_]띶6]DVk1:>:lb=:m:t+u"fm;;Fc֘1Goo704478ikecnah1'TM*ʣQOQ%[/XĚ1g`jjƴٴlYnu--,--[ԱdXYkEeUiu},q،^F9֗lPgF+[7[m ;%;]nN{-PƙKr\˸4'nw vvd9V8^O0~'L`O4ᦓdNN]ε=.f..\njF.u=Fp6߭}_v<'ZNdO6񡧉'sg+gocowS*tz $$C^=]W/`;/)pN BPHʠ Q v |*D)$:CGGWw;v7\~2ISӁޢ?U|j\K_r2_ .~f[׷-=C>-] iTXtXML:com.adobe.xmp 2 1 1 1 "3hN@IDATx.}[֛v]bs/?>֫]Kt~:]O>W׳Q6po_}>Vs]~>n__z2v?XޮO?#u~= pZWjZ~ksVjx.V>,zs[= p@vXo>=mрp{=a|,nZf^ KopZy=' }ݟ Z/K?nZn~?m`zVz[w~-a|lfq97bW(ZeW-,~rZZޟy -~fnVo jxys`7=phjv\۽PbFw^OOz^ȂKP>ܾ8/Jpr|a~}mw_1v ˫~yyx'ֈ u﵆ʗx;#[^-6t~H4.E_|퉽IInOv 5I_/]"pׅM[ud~TΟsvSѓ_c54lio]Jr^[l+t8㵻/isј$ LX (q4Vyy^?i8v޺ف~qwW=>/ ]Xݟۗ39;/K >-Xo׏|=\nÞݲ֤,eB6*ހ,zq},>X+D"T|8?Kǐ]Ñ_pVtIgkn5Fofi}~k7r~խu;˟ ߟ۷z/޷ $?%U86W_;/\>N# mO[4KʿeV'$/m^{\kL'&gTJog.: q%Nl/Gݒ~å_lrqfzܶ=%-WnpՍ!0my ƍ;GǾ(=6P".a.XY.Yӑe}%D^|Ϲra]|Gcc(>eEgщbnRc{d8r5jPf3Zv tǞ|)fScPO"k ,C!%fCnҖ k6[}Dڞ_ƹKH oÅ}N:3J%ƾs:ne섗Ky .`s'f-Y 󝎸E'#HF% H_:Jgrn*LBZ` y T&؆}^v+bu!Ăᒛ/x Z ?tހ'J/޶@ մ]%DD"upv~yvJyc&1WDX]{w=r; 4(KeųL_rq!f/aX煌4K^tdwBf%gDVZry;SYF]zh0; l^e)с|]ST0I hrVH8o`${u{> HH!QUM*9[Jq?ސߊ2znj?Rlw7ի՛@^ -)Uqw$ogڑ^:'Qzu397>">l G#77 2#uXG2ڕr@uG0vHrion C|qj^cV }v NFʣ08ޜ4><@Q ƐKET 1F5enY甮-" B:6 ݸJ >RX`b(*G̤,r fF΋NZ)*0mdDE@pR8n$bwf'/QΛ uz&݊iF $Ĺ}T=\yGf^FG?y>#ohkJ:Hww5%V;+[fR6Qa8wE_ /5Z/,׵*<,eqלFW\RDʔNZ/p0}`D8WZ$i_ iD]\/ ab)ȹ?w׷> 8# 쫞d&̰*Wu8:)rq%*<30@,e4מA \xYe<)Ns0a9D>qy8n&ǯĩ, €;J:j$CB)1|"} GJZXל5?Jh a`䛗Bp yR$~kzr2p:3W +ܘGG_MG3Mx B*tn`eGQ]+#¯e*H H;q]ՁoÎ n5Xt@'p, B:>NsPX^zSCrS[ ^J U !0LuQNT ~95a0P0ғ`+<$^#$ظ뉒: Iѱc _._NMF>:0ɖW%[@S%ipDC/>Xtj}$ᓐ<^c~t)+_= E4+|c.oq>0em0\[5on3xV}ycLg=4z-ѩ}ؘ;Z[ҫ!FĴ|YKź䫙Rvi5&)+2!Wʩ J@!i8=?w_UHʂی`+b$FJJ4 nm*v(Ov0MoMec䒜gV)A@anؓ(&6 P MCn}OGmx3ضI_(~1]$5@L.v$ݭqHLZ5ArАFZ :hG+02ݡ鍼&և<>^a7dz};r_>/2ȃvLD:rpoCPk@*0!xX'4u8/YVZ̠ a r$eDkϛ`H˯q0yO0q ?+xǨn\ʊ5)JA2!'Re"$D^a.t۫|Ԥ[-\~>=7ux7ݵY븸xQZbi(n^xMx"UvqQ| T[ru&~ O<0dMZ>.~߾}pN(Xh{4Vbׂ0.k2E.)q>ѵ^C~m (qVLpSe˔E6\$bB!*}ݯSd=dw &HG?u6#,02y pbPIࠔqy+㧟fECTx S!rxBRk)\=`4ȳHlnzƠ* !:<U+ث*6 z@?]Dϟ3wu'd++yk ]" `wdWO ejq\B4@ 4V'9cMg >xwBؓjX; jq MІ~h~>T@;BF!F24Y(5B<И(õo*QnPc'ew[捷 $CA2#oN |W1%/1 z9,ZJnj6:3t)6LF,~Xv>QU3baa%ƞ?7ʎ?!V+rخT 4%H%dަ@B0Eq#KOuy@nԢfMNO*J0y5dL07^f/J~Ǒ%f5p%IEZ"x E}=T2-DŽΥ bn޿b긇#E=/"2ѐ#6sf j+]&U]imֲeW$mtX(XaԸSL{Őpv֪V⟤l0х.8\ELz!3LV\6UgzAdz_ |5w-M{4MP@)SJ78L O#@(w*Kr~Q:@YMą:Jw%U!w4 2TX XuG\Kdc&uv?$, GhԘؑ9 ӏ! +6WI#fqd|hvuр!!S  thM,VLdf DmR0-90|<01ƲPr#{Dr+0b‘fd1zuVU2&pk "/Aq cқ 8ďwHKAG>IDi0C2#Y9# ef/{ ]r@-ܽZR{,A:’4a` /f Ne).t>WHZ A'X5TY3!.֢7 ;_a|o4UZ(ϧu Wt*.nyAn+R\ET +$2?Cp_KE_+ MTPZ$v_ <)kƋ2/C/]DU1X&:Ɏqoˆz}t]Cgޤ0:Laz ٪~d-V1XTiEh^Ò1v餍Sz\W8pw`DN حr??1_mGkD,c %?~DeLga$[T!JwoA$`q~E_U\韋_^U{~<꾷KB$цviWq 1'kфhMs%h7&zDH#xB{u)j1B/K1U rx%p9Lԣq# "kjE>ҞmUzS2Fov }P)3 3cEaxw1yb̺6 G->t-rfVONf6C 2E{,_Gk2'X1$n* uqDZ8?V-Z(m epn"1w 闲S6|Yo1Hd8kk䉓 + ,. \15a*mf*pXÑ7I^L̔`a^ت-ӢBE%"IO*-ąbAPo$M8-c*N5EC &~G{{G^c;ITpuW}QWj<$@e5gL)q~۬pYl(}zCC#3  ^#]db4# SzNyCeK yt5^? %S= ` <>!~Utb6?z"zWiP$HvGltMi\4~=tBAj 00*UC SMȻUB1A707ñvHkY>/Ni'M3Y/98ٮui ̥8b11^8^N+quU7R(x0V/F; 0QM.?èY4~"rN~1S@zWq-M}ĢYo1U F$lMT̢g'X2 |p۴}uŃ2XMȵ%3Wo)6ЌrQ#."3r|5FuKk&Pb߉6l)*l`DW;@h,,WDV H% @x5ݎ?!|;t2drv)foA};* ._vgxw-` F^ U65ywqx2$%ko|FĀmk'-&"N)D[5$w ,uV],KT-\|^OgT\ g{x٧MQXc~ Bke6͡pW=Wu)>a1&QJ]R K~V ZaP*eL MB֘0Y n734+_(fvK"ZtӰg30˴.jN8:L!>DYQ\NSe*=cÑJbxBd&x Cu?h\N&h=@#IPUK{:], GƋzLQJT$m}:u-jߴ]xW^Eh~r)`~+Zlz7?2Z,iVQǰu,hU\,xܜb Yʻ'6Έ !:`p& LaSz_>[u Wv]dO]ޓE`BZ0[!,F"$uh6AŠW `ӔZrFFzZN|ceP˶ZDvF"mh/7ƏdgX]ꋖ͈(Ro`-,"#DhDJIp/ߔPǞ$J02n1YpJZ9n7p2AwU6+-pV} t`KH^8L /tC@HoɐXT[rSZS6t#j^c~Y]XșjT艸1(‰0c=Qaf@%9:hBz$`'?FL #B2I df:};?$[w\ZiXȨS7VH sأ\r<$āq;MEل=Ӯg>&I1(<>KJ4!1"湑S ,ujJ6*/E ?`!ō?t) Ao5U B|njkX>Ӏh7i,a8LK@mT{CVG)uU<ܯ3\߉Aw|Z6 j7x_F@.F1NOm!̿B o Fd !n~zN24ݧTFZDSJ jNV×\pciF+$rcK[VFsjoϪeӅ}|6hQ'o,ر]h@:,Q7w.T"}ݮ%#WjæUkLf7ߦWi;l&Flf o$#jıCCMFi1e5"d5%`gooJh񅯂?eb9Y#5x Se7mwHᡸ~d=M!s3-]Hh&A 'Lݕiv#e2lp׵X/}9M7ˬ~?2oz"VIړP, NY1A/a,H: [yyM׳4Iڂɢ5-+Qt G0& :ւ~#r%luؑ6O%u:f@ p2v%&>. k 78 xK0"I˜sv1;ք M.e H6yJ5JJdԬDӽN*0`Ţ36V&C<*qTڎc )^p_$:֨O-\AP2%IS/)&围+A,d ۶u(i\2P$c Bgpw= 0Vmq+2ex5v=KZ}WA#D݁=Jz׭=0sP+d[d5f#@f "G' i9DL.wMKeh! ~窓uPH%t;q(P!hwX1E! C4eiP5Bzƹ;I\ n*$Om8-bs (p̴fu. $0‰]mn 䋮ɀފ(U-zaҶ^ GO:XeVZfXlMp&ܫI0I7> Mz2#\4<Dk^9' ]m/nh(rk ;xS;2s0@'@ M<5OǰF^&lTE 6^iM$lΜ]q򩄌_ # gqTWX9MXK.dhMAв:vaK##.#[<Ԓb\Skmf(єH%nt:W@[ {֩5w2{(P9BS髪QU L(*QĽDąKU79}my ?+ب(cA@8S41뗹`W ɁH2wRHZpi ` ܿ B}P5w_b wJOcE N;{BZoVTK@Z* jGgPb[\#ך5qS&-^307JolSK ,P(]A?BhBEM;"$$1$ԛ9$譏 fuxK~ܔAO_&[ j=#42>Jd7#dݍU6R)>NSTX]_fC%!BKHaS1AYv)-xԣLwQv֗X[5ֻWo-v+U# ,xtU VW@oL]A7#HtPr[ۃS6ܛnkz k@s8LS9s"$p4g!S2ÎCIޘ5 !N/'\vtjspיʥ͑Jɻ-X/` gIy{Bh3pz?η]Ɗ>_,|u93[$AʔK:hFd:u$d21N!n_i  rD1]xX8l~(I՘GV*,u (^Y xP߁#61T N |sa=҄S dAeE-<Lk&BtRї M&(&Ơ\1ͅ9<k(qY&G4~#C4'C !J5r56XR:ջkFXˬ!&(= g]Gj9XHWFfr&q7N6H"^X]h7sH%-LNn*)Ga'I-lP. EB"I 1ljT q=Mf8< E~r{D<u"qO 'nț 91/E`$)FxI5V'6ۼº.IȔ\".C;^%PVlMz^9$b}M@+v i>Ky1a\B=~e p /'8!EvlNGMICsҤv]2 BLjmHj!af\^`/:4j⨐d(c*u}^y5-u=ܬuaƙ<=@Q$< mKMSke΍'ҧ[M MVW_~j h/qmH! $벩D>n5?[A8guc؄V\[5:>bc?zqn( Ne Rw6 '472L<g'д߇Q/ ̮'55&N*O6pT+a4.9(;-t ;EIJ?Tag5RQɝ (EV{MAmh@IDAT^"!x)>Hv>-2NiT݄"u<)Qw.G6ODMq X?*U/X%4]vϯ<7:6q)܍v!I>:ӣ^h$yo%tT]]2@AA+[GlO!|ܷKR^ NWf]ྷ8m Q~$e^.Ȗh]ѻ1XYs:ިal@IxkNf/|Ť20$di0mgqLiutW蟛#M#"<fR TO&x၃ |و$7Wtˤ">kh1I"C`pY+W h#w\[æ$]4ᗑjOOm:c]I}LZeفCed#y"qk'rrnO݇^ kPHjFF ه8шmgti&>_ ߳u!_4#k$.GI!֌%puY$ވkX&sgҌIhC\S}5|K:ÓPbu4N)i4SQ8Wm@#4#$> RP'fY*n@i-NFGĀzdՆY+ ;!!QvQ 3S)`ߎEk;։<Ug2* s9.==l2kg6=9v/BR9rA;dB&#^TLoǯNt:0'I_ܶw%~hsо?jfU< **>Fxt*AFQ(>I*Uٴ2q&Bj3 z[0Uo"'改ދ3-KTj0J=(AuTXf8Fc[fclV0 +ʶDqAZk>M?(0ODF~" n'n6?':J8Q%q|z1^9vB5&Vx}b1B;\PҤ74֕G(B/4t(G1\ңwp˛h,ͷ|yup@$B:^HPQ&y֜̈G.B…[q\LO5= )[NET/ޝ`ֈe0*6{ =PvDZ;Vw# +jKY1TGX'طyPOP#d;sSQb!6;]p^`'eXFA%nQQyVF׎կ@)x tMIVgN=y02Ҿì u.[5.`AMjU!p ),"F:vm55c!mSK5ȷ?a'í{1k|ѣ 1)rT2/t},~`LkhU+7dPG\ aPֽ_sDT̚e㥈L{LЅʓ-3debZCymqFHCPjŸ gIhjt3I;Oq.H)A4S!)8'&K ;1`v,dV_L`{TptI^0<bdZO*.( I)@`l*4s$ġB0cFVg3I8׸3 9bD=~r^D-7UC#Jo`$ؤ +8h0LHLSUk|RdR}֓ .il0V!AZANsuLGNcW uJQB_oB>1R6)c k1QѡV2 -HuQGWE ݈[:YM^h!J ߰imDn@UƋ D& S?#܇Y4I `K>`Wad&EitG ǐYß˂4cϻ#C)v ƇJZ{e߯  mHլrrzXo$PGU4~tݔ197wfbU:u3†1,{Nf %6bx#s>ө׸ vC7Z^n:d9kVyJAH7U\?6٩){{ 9 ;F7M0f@ QNp (Iu-BƦB(a4X7(\hb5Sњ C[!FDb 3Qs@$w"!VS ,K,3pѿ%OQQ^g=P" NF'j*P㎞Ci~;NCأ@oaG)+eYy U8QY2"crFߘ q<25D0v,&xZ@nħc'O n0LOE)77BP_u.u`"6h%DD[,~Aט"71t0/Lc:(S ˿ּ"-34?.S7 F5vgz25#=Ѡ6w 2gKdHrZwbΡ_"'iq>z-6㞪?\TcPߕ'R}҇yWF 7ۧޔE nʺm+,6ajH镌Ʀ\Q+@~ ̏FQ[6lj.۶3v4qAX A7C61,@LZ=-8 joS _K?IQl:gu>R`DPm\sP1Ĭi @XFV㺙v;;vzk Lg=d::Tkj@:&4;=lA}jh,nxQz^됦E"Lx_n& f`ZEMFUY =ؽDo }05 d[:rǍ>y9 wmU aZ=,H~h`tm^1M|L[MJk|7AM0tX>eJ#Xe غdwή>Һmu V #)i$ Q0;&|x.mq/a}.(l^߀a]+4Œ¿|y9CtoVF(1(>yqcA@SNmf]d*,mRydǬ4, ']m؂R"vC0$ ѶZ CNsP[@a& DTT#AN+C,x>FEZ# tYDrD]zު5ZgKFc;TJ> A.X^uܶ>:*~a-M4 ֮-]}d(Ds͡%*0;{|0%'VҀP&-ad!@>Z${5ܑ.ٖ鳳`Ti`] :CdPɔwޜg7 # ,hԏF*Uwsa1vgZH1%p7w@H,5"3LlGD2g< q.xXW-H"?^ EU 8S!`m#TQOc4^iOy\2dюu\MW`B$(Œ [U/[,&Y1oO>׃0GϖK~^__tS*!)em[*w/JuD>$GrɝM(Bʆ̭$/t8[wYh˾xf2ͪv=vFonSERů|'d5ϗ iIP|/Y ,'2qG[dD8+&1L eZ=B8Gk:ZBy္v2%qfNr#[Go*`{Q.DhpsP `jHo$T9n8FL#54 ŽⲬ谥dif{R58L/ˮ<@j~Em' Em{ 23$͗5'@NZ6vy1M$WV-;r% V56 {&rdۅ3*.Kl@q=],SW@3F\jP"p!nI~mL03eʄ KE]`,/A 7ζS.$)* 3'Q\$d0Є*2 pbkTCH-ކfд-dtʁw,a ;N}vA!쥹v![6D̶CoAs$%98H?*9g OH3g`f>y8 N츕};^3N9Zjl ' &{_V:{ ߕBO@=OnjJ1v6qRYKmb 9ꓗ݅3N."[f7LQ"6MIlX'^?r_YY8 ȑ{EJbbL; uUvy]ZGɵ+H\9OqcZcNj!$Y*^<0;k-mqPB8-(xUPEB/КL[$] xgItW\8=ԒX>lMxlߗ2p{9myye9av6k-džuΆ JfdK޲>){귂\қ%Zm/h%%ɕP|NyIHaUE$7LJH: x㼊k±)dER|x3ey`2؏o#7L8{ݩ :F2"xCJ= $;ySmA{2"*eTS8ZUE%h̢fO)."[Z}MZtv=J:Oƣ: |`Hj@/s<@\6pceXjIbq@|$NᖖFR-ly+s=LbÂ՛ /Zk ?myqζ ?R>7zٽSj+󜨻=u|c1K7_1- tlg@vS&BZ*|.V@[%A$.J-z$,,>g{6ՒcI¦Śpl'A1Q/(<%?C`\R\qs8hٱ[W UNfzY D\ehzˋ M8PfrdH.n#DYh`$xm2E䘺Nx2 -&b2(Yt \#s0t.VTR2P(;BnYP=Ѕl+0UʡDVE3r/0ae*xI?=- E`roCƲLC3CȤy&OEth-Tq$:+ WQ"LRfJcih~F%o{rG [֊ "$AHبϟYg "^:ɌQzMŇIT\d`j܅2dy7L)L^;Lj8<#ڠ> :N} ʶIȞ a'̃@\7J,s ]JAI9S4(s@^)G)% du5UW=EWA"stj&OTf M@t}PlN"!zdy‹"%SX:@Yo[2bN_7}P_,2cb|>Yho׮.4T]qD Ҿ2k7Y{=Ro$!A{50J2}<.n1tk ~ k2or`$P%kRbtj!]cRBaFkU/kuYj-H6@ꅫSp[ɦ?__hҾ?Woj|2@; Sdnk+X|Agc2cB1%F9N:3LcFK[8ow2$2qF,԰jbӢKQv.E-0S@IQ@c[f{'w@FhH``5jx `6XsåPyȏj^R2<dar Q2~ʃBR'UQ7YҊ.ϸiO 볐UD((PR9n T$ {ɀ`|>4=A'Ătc]_',Aƚ Dxfy *e z!w T 5OLt ?ܰsVy:]j܌$U="3@toD}v%rg;sҎ pų<+sd&B3$ta5Zth"q퀄97\sƶ٘eR֑ ۸8hO cdvC}Z4AV/I6jb?2.jS"8!oC_{> !ڃC>}z:/eGȴ',*/]A^y99ˈj\l;Xl|gds1g| Pam:&Q ab@͆ė+8Gj`b ͛2GoAOʡ`e\l0u#Op5$Ac*a+iFfǝqU F %qt ̣Pv<ɼb4zBقF eL:dq֣YQEHhQ=m8VYBHC+$ 6V,e":frrS~a@xjD\̷]brĘ7*D0k;, n?aA-zI"?J(Œɳ &dnz`ks^_40&"cQ)GF<`J9'YvV KQS i>+QS"" Y<-6 Иi{I\CgmeӀ1ZcAI:ӯDzM9^_q`cÊAŚ_SFt9ʥ.5Kc$te;LGŞp,:ac ٣xTveM63`|Smk<ͽ =м2/9Î 6& bwrB;q{$,#˔sp Z\ !£_23<gCa{zdam!>'0ɟLyOaؗD!?Q^:yHLNh x\8Ra0.op`(CV&`Ţ}:PU\E?pԈy%N+~t.}  H2K4%Tk `8@jz꯴Iq{+Y^7Y`t Qځ ݊єX4])* *'L҇⅛:=ΗilSzA:m[i7SЩ W]sSM(mw^^7qqKzOcczELSCPstsJYE!֝,LFFz;L@ՙ#X`Ѕ0!Ni;;n$ gQI6D~sL#ĕgck)K{67z&uShuf²& }X\ع!ҳzxON.SKC9mA x»kx>#u$=} o\h8ԳƐUMi.B>=j(wJboߡ\B,.+ա-@"\IpAMV\4BN2?\X{K}],5 LI(_yKF7z R3 2X\xEO˔HhY>a - G/Baj?Q:L!{wx۲X9aN< wE`j 4'[WzNvQL|z ps#%w?a<93 y3$82Qˆj)X"STa1'elrzS׉8͒Q8 YL Lc%T{U쮏rA" )VN9e?iS>UX!8iOHȘ%;0{RkDsD.4B\y.\g_؛Y JCf'lIژm4~bqt)xEԧ4.罰0xj|Y L& I!ZdѬÄodٯKj 6]Eb,<[$ht"XX/'ChN1860g-_cX~;NǏC.Ex!_aFV{;K$i/clj|YŜj[ ƙCy{"EܪZb^asjLpH^)%o]T^>9HbR?@^}+ @m5A& ZxoCqr^VjR,zEozCj ĩ0gvCZbP}0}7hOԬ!CޢOC$)q2E)?zTrsY|X'{ңa UbqZيUR0`JLpAD^[#L`c.a1cuT` z6Hkqz߱za4f`sܛvSMr >$)`.z}¡eG;%.XsLKLS^AP'9̥a{pn{e9 O:ˍ+jk$)6pj^tEIA*%N.Z/@$S}gⷜ3C/thh.)Ԙ>4KODoMRQFA H91_HʏEa0}yopQfc—hAci+\2#4Xۆ~٣{fIEV=?~N7(w -?(T፿'-"\tIs[ށBhnÑxP+t+BXBxxkWQ0Wcصe hYXg8<_ůryNۧH7RY.k%% OU@4x!.QH-Sr~og’FقcOb\{ٯL>ATJfҘFiA^ [[~n%իnϧW ͏ Wؘ ?K6Az+5Y:HN;y:㠍h쇢cS'S O7f8407õy˓9׶(FJO2`8b}?P k aEpxp mA9ja@VϪjȘCoaHCkۧ 6m<2E$чQZhϘѦϊ_y?w73p9r¡p?$Fc}t 4 DlԚ#DgT^bgs͙(M#A&`n45(BF.ǽd dFјzl@IDATY`6@R}#7:*}H;6C_/nR! b;xnD uRR=ʯeW HV_o \;P"0$h ~QUFNҳ4ㅭQb-H`Щv)”"F^+_hQyB/!{^QHTQ}*p} 5&e Yhk87\v)0q5en 忌p#qLp@j`ۚOsRxb)򘌑K!- 厇u36a(b̴s&E$cE<2hf.3R%6spBMQsUɜ1c7x|h| &ɍO&]G8-# A%1+{̖W/?z*;29)%3IQ( 5`YĦR}]ӰȄ$[WgMh@?oMIaG3_ \-DkTaӓ˳)Rfwgazf׍"ȠgBߟޘv ]} Wz{'O1Gq*Z |IS(C#^>c_D9vWz{*\g ӓKijCM ĖidqQ2gVMB  '0ā`J,in4e+@ n ㈎_`TV6'5*kcp^#9Sٜ9Mr3wFɎ ?PEڑp+/MRyalw:k6 IuHƽKo┤idT,޾RO.njO_ѨaQ:QWO3tpaq6 Ŝa'+O=@ ,`T9jz+5Q a Z[R`Xwa$co8|? r枏cBlXyޠCWiTz7P'?Y>r&@XyNx j P4o=gl d>|x;7u%Z5t(7w<"40C[Z%6BÄRS[e6࠮2\m6Lcc:fHك` IsQ%k6ǐ 'uK{Ԡ}Z!ܓu720h4^1_n8`y9 + ~k%!9N_s\-iqY:cX|b? %? u;N!78]F]T*!xnNKTV=meN_3(RzÅ6Xo/LkVn3Ik=Bx@ {1xJvy"`N m>yq8gZok›Lӭ@+K99f3.c0Ymí&KȬ ~$\B)f|ZTRO,FꯊNFnYwu#8@pTQtjҧU1YݎGpƷ mc[r;#{-"WEr"Oo/V1> G`̘MGp !Ў L$<40K?ΓL4||uQ!DƲtyRC, â@pR3- v "*dYDŽ_zH)N6c}ϛI0p-9FE.#FB6Ǯ@pP{S,qdJŦ#QY=O~ m20"QO#q 4)morn5HH $"SwF-0Y6F-,Ў^0|}(Zx[Yc̮Y:gfB3yX=oY%+ː刻8.17o$AHYk)!ќc,8N'"ǪÑz\KFOk3\-%<W铌<fEHU8=/k^1pơ%#U^i?Z\niћNA_lpahQ-nqHy_ރ0s4=ZR'z );{ =7.YhٙEs*jT-E;澡d Pdkyv $Ƅw㼎U@ƕ*ǽB_ǯ?g=]38[E〝Ā%mFUR\^H>z9&s?7ԓm&!#CL0O@jKp^ZV&"giSu\%!@I=[$[8<dhfzGIܕth\W+|s$-KDg;j)Kl.x>bR@|ǷY.Դ,k= j@ߟg`|~V.oA&е"㓒'X΅0;5(e$&3zgcӺ;'qV;@ys4D(h]BXۙ! Fs$0ٌHzX&hB`|ǗlThm hRޖhm&r9i [Nd\_aҮQDOk`6[/m*j2WnsHS. Dn/;D#|3uU);bu?؋Mm =jF&q:}K503-z|nZ`k"t3S .Pee*/V"- .E[Fݣ#Bnuȓ'x*Pn=mDcQ8̎Рs`r1FάŪ!G(qxy-@[ˑl]ԋ?=,bN=59  ut͛ 'aztc&$yvb:XoLQ]v޺ּBkQ<ë0$h x`enr=%U~ͫf.?~x,Ԯ7X~zH_SU\$u WJqZf(9|ռ<'yb_ms lSc$qJ"1GȈFRؽolh%GD6?ўӃ@$f9|iCKH CXߥ 4Y߄3hD^BqYH[M7~s2J inדTήؒGv 6fs9>Q &v}}8?fƉ3tsBwRBB66 , `鼡cE𢡊_ZPܜ($ q># +]_rP4-ylGq3i }@׀ ZpbtAS=Vljԭu%m\N$☾E242{gfHp#v頩a k4󘥌$8 [*Vyz8rQ2Qi`Ż<{ Ң$j$ `HS FeHVӫy֬~4uiAVĜ'R9p+$'s-#R^>.TbX!4(6**$Ʉ 1AֹxF d*S#&x_{9FJg'A@̔Vǖ (f]oߍTqikF+H472_96**0?n߫>3I@@X˽QQ'6.8*֧O)?ֹ5&2`BR^ŹNzF\o?xبj'qK[n4PH[O"_!%MMs1"E G]s}U$Y30j[t?si?5n:5Ҵ[/4~4 fi47.Ԛ)=6Tb_4& x"Ц'{]7v)>um|{=rקr@ kX~xd,j߲ir/k|n:MPkgB75Rߣ͒U(!3RҮώf ,˞jز+L )z;[Қ>jX@A!&"{ߜ.E]:1pQQz>Ed]NЖm?E) b ψ0qgrUt3;:5b_VhT;bEY'"ňq<ah߳t/"(j/1ɘ\UuM?sUǩOr\{'3ɋ={ԕ6^Npc2w62T]|IB|V0`J.!%@8HLb=9F%[b:dS<LcfmCh2QïLiH !rUvȷ^2d/eU/1Oa3{T.k`mjk֝.AVmp~.!QP9{{  GI-s'IF9]wsXv 4=Fٶ:s\V,kEHX}v ix\ݵu.+ok gIözkG0ʔ?Lh&9w˸F}`ta2vHFchd7U4B'y%ZXA[NX6jTJ4"pV~R*yl r%rΡŃ8pKwCWqZf2l?ڟհF 5҆Ȃ&*]hpZg1xTG_34dx踛a4V EHl0,;^'w'p*2_Ed'jE"aWsP:Y]ִrCv(g>A%+*"3\8dj0y6bB]ȢUݎAٚ,PfIKUBZ82)?DNP*ᨸݼح :+}3eRrq4=H^؉o/p= {Q8a([zSųL1g6 6.N0,%(MWVUч.? '[1 57qz3,2kmN,[rt}\7ן}.v zpe^tŸ~w}Klj7ۯJ$[M`K;fQ$|A6 6\ CVbHwR>'뵱y g}dC :-@ qqˎ˕p86t.cDd(1f8Dy#/ygYm~/o4c\kSІWNMSͼT( tjք i· v%d0S;Hu"8TУCd-.>܊(*W!HcxѲDK!h 8zZ+)m Ԥ5P"(Urޛ*{Hd+HlӎRL 9SybA ohL=|8PVȧS@J6h)DB^SNty We;yx|u#[[3K( ]( Ҋiq(s?Xt` Y}̰O\V?|.f|R*Ċj sˌbH2#H΄7 ɐ91`ˈtFn"{F6"E. x< &ڿNvJbYŌ*nE)F:4엫uzaPaExkbR/ף<  6TV|(⬊덥!I*>HbƓqIM75z!OM{pnw5s*ؾ&' Z3"; g\#2HKpgER`PP6iV,m}dWs'Rj t4VIc&R"b!O.18ͦ ,x˯"dNBgVg|b!-HJtRH{;Y%āw46,k0 J2Y &NMh!Z3}7b`!cX\ՇW_ ޳E ˙<(aF\v7o (  q]R:xN\rf5ip]=bz=h iЇe*kgBV~S@#jl>D>V@dKQ`[kb'O LzWd25% 1Fsg?6JFj:;oڹ!0iRA D+Tf8ʜdylӺ׹ 45/(.Wh##1K[r *6,eu,CUF|}S[嘽-E;1Σ1x1|:od4pT}T%,h{Hk0LRqؑ БT!_NX1A΋Mz0(eZCIC|a.B!ξ?e#԰hʙ Q̌t)ZI̐_eNn{g\a:ײ3!IXrK X ֳ:$'w&!ց9@pP"VSR48h=rNS( &{_$:VO{|gȟ//] a){MQ-.E{{0Uq! cӽS#\Ġ}GXF8i4`cJ5ϓ$p fYvqFúM ! Dhx>LC [QBWE6CzY^4M<=< uݣ%CqC{/TPE4_34%O/_!VhFޜ'3 t}zu|^ƕ ! ce TӺy:4?Hr2V](h5s" stKzH$8TGY|Mptu/sTq%D7 Kow=˟]Bcerq{yH8$gEa sRj`э}\y˜`tDG -̵X3`DdڱMG }f!.Gu]b(ŸY.%̉Wu"$PBdd  Y4v1U`@R^51PVBDmt77믓V= G;Zu,)6L=t &H\ gXGdwbcxr)=EeVc݁/#LZ_=d:}w<]7\OpoP̠6dO4|چX#`9Ae-T=QidMJ7;/'70fĂ [4Otw?yibP62%Ň錳rm1&Mr<ۑ Zcs1ZТ挲g{hK#DmX $r'Lydu:Z͍Gn >R(  bH0އ0"3P24ß6bT/Jf{N+M}OKh\[9l":I9n(r<2ܛ%GYʮ"7#m f%.' @KMh^9~ŷL1F հ} ]~i"N0HS}GZ[#;MeֿMO4izQƧɀ)tt+ޝP xNDd6HYpT{Jz˴2g/ LUk8+9  d탫P*rR8Mf  C˰z2O9+an#ւ@lOA93z7h4Ҩpeu5nyK8KPŎl  È]z.?>wib9NrF@ fX&2MV!{~ٛZ@)@ԽJ6ˋJRM~y+.Z1,2g0KH(ģEoVqqZP:x&p n7 1m|w+ *g6&6("cwZnq=j WˀGU20~3'z:%b[ٰ0YXqckPp..in5qlz8T0($Zj5?X!H͇7Fpڎ/;'nf\FPŕHYNĭ٧%B(OՏˆ7xIeGAC(S-fJRwB<Xt3Ȱ&bkhGoMIC"NW$CZ?u?L@xznBd42A7߄hzǥ~z0 vt8dg2G@#:^FO:2x Cx/f{C![(2rYI "GUcX3܆ptt^;j%xֳ\yy(pl>3GaUtp2Ac՜t&q0DuB0L bs_fl̑G'`vX(wQAipEj'1$!ru6mFR+`I[7p1j0YבeY$0I 0xW$jUY"dK6x/Taύ"n++ZHOz&qx*x8{l6CNURnJF*` R «5~62z ϴG8QFy<cz 19ʗ { zYOzO6ObbO1,L4 `֨1lBFd?UMJ'Ƈx% Qh yՉ _8囝| )%$qW+UNF1]z> Gh!E1׋h j"ꗯ(%zxuCd͖ewgi'M64-GCCO16EpKF%lT]`ƐA Hfu"5F8u6]:٢o|1+~ uDޙ%5jFuA~ !ޗjI^24DAYkcMjM !kjjZS[v 'ba^~vrg;9d@pPSoLNrOMD@xVT}*m~Q@Pg*$XrLF| :R,N\K^VD 453~Z)y2#*xGRF)xB[鎠 m/TlЮB X4爈1}USX41ǹwX}Fz* D o]e٦(#oętԥ*PV vhv֨v4QMZrB%q#G)e}aF*%%^--IGbl6i Cڭ4J94!lVcGXe8xMP$IqG(KA9.؃=2Br$/@? m{:׍`:C& ^ȝEJmr>Ebbm׾a B4Ehx-2sYST^ ‘(}lV,&ZOuDӘtsDS=ho W=4H* ?CKmOױ&uP€dM!) KX`^,0r4ý0o'iLcX^OdҨ!<ɵe۹c94l 1pJt&aC*n-R9}bNH <-|-N2ŻS 2NPu/R-0Ö_?aӨX>F]?Gx/$I1 Ix~Qhr)C-OEei0. bN2 s='~keZ=zיdggH>l =Px5-^=Ͻie4a/1G͖4_:%o*iHqiVIw^9b'wrr\˫xPI{[c) :u7H ! $=r3Cz]( 2kfoUmrbQN:Y4EBɕ^TCfXE~6ukO5n6V3Dէe{E:6ӡHދ/O%[fOz7/үxq06"ȨG| |Vo!onɉ2X|7ˏ%8]w%$Xf+&qeCJ2-ZţGyV&mq9T vbvbu*oI |DgD_Hz`p8T1}(A<1rvj*mi_#A.Ͻ3\f%ևzk5n}%q1Xc9GaaX̝b"}xaq+oKN\Vmd-G_2DEc9xq.e`jV! =\dJf$Fd^vֶҸ >^|ct'ѥ,Ӱ{/o;|(nO/{kc-بE38:ҡTYy>px8ICWo/iqkx; /l+yeFoiKC66bKpȔ}1c?a)p9[KUa4#*کtc6_ B^7tJrzנ6i{z"4m@aݞJenM(+@) pa-ķ.)l[ILi#=ՃW^ GS9xx֒$32`LڏQK>ϬkKR ĘMJp4x[x>^0nD =#c9ωދ 3^:% iR*s;(ABd,Gh]VCi֣:۲RST=(.)CAűl9)㺾<2r]B i) znWJ켿By ²)QQcȎ[jf|(*a3qNID6XJ=zw0ӒO Aib1#yy`j{0_XlUxiH:jLmm14*n"^&#33U 0 R?P(8EV4-m+u`TpO@!#O$r43.x2Ob u0 T֟ S$@0gqHFasة++l LTAY7B'{bA?˗ta? Zz : 6閦Fb!?`1<mFbE\2d?ZⷅL)htRRq f`7osHQ vVL,cˀnE\A#G6:JZFz=ID)VEx> k%Ԭ|L1j Z Z3O!ȿ|c/aX79x>#lʦpA]@n]$7,3Y\!E6LqdD\X([%!$wlAM#Ӵ*$'Ig˓GK\?i"Txo=wB"iVr5MbHm 66v/#vmK%Ԥ h8U`Wr bPz+K6wR0OFP1"KnÆkѲe)f`ШZZ]$rb|/y%bcXp{ DS6`ђ\Vlp48}lS4r,g3 8†Æ"Sbz6VeQ|sl6N?v-1>lY L_dx)·H1:rpP^EdoFxDqD:}f+u!BGƧhс&)Lr\I<\yU{ ɽU&%:<459)n#TkU"@4gҢ=\{tuVoړ&8wMDm j &VN 7RpC׭P%H#`s45d[k;, ̬p2$e:Mj7ghQLi]<ːJÒ+@#qD i 5Lvy/p({8: T 0S<XShp;8M e:H 6?4#א)_Ve\,'-5%Bm3\|H) ו⺆\NY]g_GT2N0:vt(/j8xnS/OxlI4fD#7FxSol[/Ր'hPVM"=)Arۈ? T63%"@ й{1|-̚fj;:sŊbZtOۅkz\F(5 [F ȋDzScz.'Ʌx"gN}~Ye'K' *>(\oDɸpr5<:b7iN)*@k b w̰]8Z0 o}slA ӗ}]﨨\ІW$ӡ.0t#`D̛3NWN#"QSb$k{2IS \mi#o|g0Tg>mj~g'f"%׉+t`uCfSy򯣽[0:(Ղ:&m1&?%#%QO/5BAp$>lPe#A*o392920o6kSj&J&Δsit뚚hs(gkx\siI_( 7_ܘX߅E3$t$7~M e G. gƢrl!&w?e_o b'sଏ}´!73DyOTU>\*(ܪx`OD6lNPy xK?ȋ[dJ"v#kSKb{KPO{GSC[aGejXQ⌒R5&πE+) ;\jbQ2؛̙K8UUJIlt9Papg'"g[T8c e60ZZፆL$!pgXm O ue~7j^"*uc~’:tR/7t:>-md`WAgyG܂&Ǫ{ ke1#VsCN:ň Q_] K;0-2UbrQ@H4$W̰Jb]]>#`v;8o]P›k#ZJS 0v;LfW%~! Qi:]lڳFllP?3r=?^ܡbv\sKs ud%%NX/[)YzyiA%C+l.w_n+vVDi\`)As ! M)s@&UUh;묨Rtv}mKsUaRQSm%q-x~o (n_PZlƖj(r.MbnLT܊AkL Xb߱K BG݈fc_U}( hY*DXeѦLPa `K,:nG *aқaB݊JtR%pR[wn&t`C3Wmub}$.n351"lkIbs;޴Q>xeQ!\D `4Ip!aJst4C`XxK1CM'of*l}91MCwܔs9Ðe Ya#AN1 yV Nn8bG >,I(s{G0ڣTﶮ]4!J_z OJҷLү Vn;G@-bo#Ua {>&dD^]|ƔXw(A Gd`Dr{8`$ϦQuRU+86 Ά 7t?+֋]^1*aS.%Rs^8X8.Mgp M^˧ "D 2/\odj-\2)1 $l ESe׹Z޵{+sp.5OUTlpZ0 N7+F@5dUd=_N(% ȪrF0Y|Ie^v6Qj*5HvHz'mhwXM ^Ό3&^YMU"1JTԆ ÷QYXպA/|<ыHPyr UŹ؏-C{C)WK [d"I~ atpCim}Q%-뭎K=}٭I,ĢEвsOx6[ csH>|-U =柜Q YFIAtf,FlOl3aE)u^AF5a02"FtDc Kkl# )P+(9p(7qj1izrhN_ !;k0gx: pAz@d̷(b|o@`cQ^$J\HG=DPOcO*c^B 8nJX@LXB_.[`Ɛp?^gd8A*2/D2\ڡ5{a$wCC 2TM R&h`"g[n/tp2@Gq~Ev]#?AG%AUDzND(_ d\U&1nqLI[a"8#F T{2]i% 9ΰgJb}8^M:>+_Knpaoџ.)ð5b v+bE<~M6*v+̘n2/@-UH-؇ }x_|bD#L&2)_cFrHX'[IiA1>>"y Iٵi6|fBȃİ,ua.@ɻVԾAI@>GCSe@lm[YhL3jf>IvrH#!}]Kg16WFjš@T׿Β2*}@c׌hBK~vuư9V=d+KARoWЉլ1ѧ# J Bѩ pO4/^VY-W̥ #b,N-*~l"On ]oK}X#t| "rgd~C|uExɨ|V~-OV)}.]n'䰇o =Ĭ=P?=ijWͽ?35lOk&'F_K)lPB4QJT{gtq`g%F4V" O_vwsYjOFX %*|A/Po}65yگMbGZ؝bMzJ.WMs@Bp6Aoˠm;N*fU\ڽy<@;H89gYXdkJq[Y$As x tlyѱkWԟ^Ntt89Ayq_hB~y} >۽LZ-##$,l9 1^ߣ@@d'L `J89I(Ŀ v5'-#n=>qvrX#B`O/{u"S-:<iHD;Pn~NV:&&¹qw: *I$^8\CB"Vb` 2֮CuI OALY?0&@t/,S2R_}l$|GX$R7iAcA >dzJo]9@|Ҙ,)+]xvx|>=У?90G^Bjˉ@avpRiQvwz/^]U8C-{2f3+U.Y~}[ΘD>틗eo:a4^7n!EJԄ<[gOLC"5g"ϾdX6|ms v~he֎Vƅ:~}=uT?Й4///]kAy`žG6t;p4OtK4r.<.ZW:էEf9>W{'&~c~svԛ# 3ټ\VY*}_Enx=~9b`N^%vձƬSJq#C| /bys%higM*3Òq5<Ӡ#.$lrJ0lYb8un&aAM%$ 1jek`ySF]16Q(v/vBt0}1o9 |$ p䜡(5tS{@w:s fl<[IB]9,hfZ4ߝ*>KR+ T@d"aƿ ^}GM^h? m! [ݚOU3ך-`y|\(<^ULRIFrI@Jb9:@d?>tA|$).I10$ \SJi *O+dP4|mgh(977(}YPE@]SWq֚b>,OFBeZ$\OϏ#i'y252$znXc,`iՑ蜲ā;٢ _)JJIlҜDGG 2akinlYrbd\f;Ҍȥķ拂"ӽE (FHdXd[^QAā3R<+ATSnf0;K ,+.cE5 0y!BY nh.=bAB1cȀQt%"m魝Dӝ>Mݢ R ruࠝH~WLi@3YT'VWyDI5y*֐K_,fk oc '_:GkH LCs 6t4Iw`wQ.J 318 E/o 830A*}?Gut~aV!Yp2Gde[CR`1%9Um)<[`pS~@$10!B {PCy2l#`6fiŶcGjb#v=7h ot{7pDU-9P a؜.ZBu2ND/B'2t U"lhRR3n:XK) -k ]@7ar!GA%xv!dFU# <i(cQx=ّiF%?C)OOdg04C, Rg_\.w߾[M8=#(kR;%j]cq"9N_2e[: zfŪDMwLHL"FÏܤ[hD lwDѤ 6tt;1.EQm?~Yx—ά9;-'D3^Mk)*NE cI4hb8jc2Ga? ގۖ*˅,6~kd:łK7L ~`@=z*uNE-7 d8+c,( &_F**BĦ+ TR*l#:J^6&#wY K|-Sd Y?0 g&BCViX(}ac͋5)vSh 5,uIZLT#27ixRӬng yz^0SR5'`Su?"=>|A<"dboz>d`d3R@Typ>ʱ7e%yy,@D8]Kaѹ=İ$J&C@41bRUi3%z^z7'>Ǵ uDɏ2г")1zE;r`nܞJʃ[J}/t=w|_"C Ek,d1=FY|g`n $8bǺP }6T`>l&!Lvf~l!4si+1So.s*WGLq\$4?H [[f+fp`LlZӵ$ϸdzfZif`uj6jN<:>ME&FEN|$BXY42zoZ8y Zl@lx&;K?ۅqd6'8cExl L]LOs+X't8 hQYҘsMkq~@.EIN궶@4ycfoRa&ՠ km.ATYyj9m}ya%#9\ ݜO墫A0K:)h8~xܻ\L7و&񽰀N5PC*=ֵx뛩Su}hZM$p{ȐaXu3\^<v({Huw6ZRurE*˙A@9XςƢ~{.kL-`sM:9E&Fu v1.`ȄGh %7"~#0R~TW*V8Hp{ < ~YUr:`IY峏m =v#uZ y9jQq̾KN_;UV *TpE=cPȮG, ڠe̓V3sfĜUp$͂䉄r5%QÓfF?e⠎G_!:OJtgSTѱlXQ8aݲ(=}9X4|B`b`n6/&NmC`1]Nn*V {N53 , $UmzwcHo'6_D\;zZ]+DC<\=?8_G G;y/Hy]b|La~PV=%)̓nrXR]FQ8e|G~zg'2P_#2 @&#%{՞㈂ɞ|죈/ʹt<| (Pg`% 9O/cXU6@n8ySt~'UItnc=D+ nJ:*z7lYMi3'O[-6a]\fZM RV*+2J">_PNb uz F˓S+ OuL Td)a5]\HL5 JF/5wbGvҷXphkƦ9_|ٮԦ:wEr6I7ڪdCnZlJe $yX npd,&.#kBW[{@f_ +_(*ASdBM29f9N4Wؿ!»8];_\(ރ@ jȋbYZڂT<)I9R|cCI~M:)8%3)yYo}X-&|w{j~L{d%P2A.u%>šHe5B&f<]¶tog׀]+Ӱ,H;;](~qջAnlt4GSHF"`?/QdG7(V1nVR}3l $YQL"`jtY7i3Tfo9l>BN`p@IDAT )]֢MvPm'RؓeXExzzWG,䣟BI0>LB&CˈV,#6v]41FkVԌuPa/<+V'73m4KAeJk5gzTM{ps9kӨ,E )'pGfy.6y#JGmBPl*04ް,sJ]P5Ȫ)P۶P4Kkǻ(r<{X)R;\1!RK ?;bG,DriUS2ÐBo6FDڃZ{JXPn4jef:ǀ*'@pܙkO‡6V_U/f>Բ-YԱߠ^2/ *G1U,!(('$F#4,nl;Me^dyJl DFcюxrlf\ `iF1v$ueR.nd b;S nF a'\@Bc&g@u|OJW%YT F\~ӄpX.h\UDM72&ZAvΫr(rawr_o[ һ]P;t *:laS+͓N×nYm[y%@|lE XQ_&LuRn/ZOkp6+6] WG''DSU}w,Ǩ2U.bV/pN=v.˘8nK,Hc}޻5P!,o_u_ *J!}HD =e x,g&I7)`6;L6}9 Fk>)Ћ VEBN^LSSCFn^yhᇁ<_CJpciǮ~7Ks.tɱ*V4739Rd<0!^S\”0K,{`S t݉HsV=Sxdew;H g.Au@ՃVBיe9e6`NlEH25,)r bM/K=%ԫwʙg&Z!inMEPB͡oQD`d[8qMa;6Ҿ#4OB AsuSZEyv>[N~Z7|8pS_uns~HɪɭL]\]jPGRu?:dA=Y0E*EkIk,:ip" ^;Ʈp5v|O .J㸢\>`$%XdRKefW/srpL|8#N'iyp^Uk#` JjĩS#ZQT(GE<ʟK.BO' ugbegJQXR4j ;,Iw@56{b` RfLڄdhԓ$Oxښcv(S?;5cD٭SF"̀*bgm|ݲE?|E5Q$Me:,yRtXI^K/ٗxeүuAֈNҡNV^xcDfY>vm ~|n c[7L&`f)|-K<-ø+ubĦdC&:{ m30`Q0*,`Ay[Ӑ+pHy!Cσ`z,Y(hOcO{\Niv1lIRSRJ&~Rݔ΀y#o>ŊB"EKMZEZ|߳0l2:@(okN_xQdv¿lkrKD M1 G$}‡$Z8p;x;r3Cas]"қfW$ԷYo zmRTeYN"a t,Yv~kom{-{F(9Y`IcJ[1!1iȋ bn$709ňpI$1ga Z" ͰC4 I׬ fQ&$FS>sk(+1UˋkT"X"~mdT>`T Aiq'E) W ZV .<{iy%zv0uKV A:Ma,&EA: f#.l|^=Vw..O3B M}{Ez8[M.:qrC>A)wm*:FʚH27Ny ȅIHR;-],h .A֔њILI4I*`/Mbj5 _z~*]pv!|° = s"}=]ˎ ) 2nZZDgإZogdhmpᑗ~yNsGg9D G3*S*#$ c^y<2m x~A>gTDb2EFɹ3oIf92}1Yбr8jcڋLJXJ2(mݕ[6@<} d2WSV}B@\m%bY E28 L^ ;~M@Bg|,OP \dVl,thtG~Y%ЄXLR:5Qϰ:Pc9cDSy-+F T&7k4 )Py&ȕseoM돡-y>z2_-$B]OE=.En}?Zi&Ζ G)MW'Gy)CIT7r`%(h4?<㻊,hvSuiM*ҰQ%, )^Q NnAb^ZN-R"tRj8h, dW+oSQ<_K YܵN3N@7f_" Ikll/J${;JyECoփ a_@ˁ6=HZ}HӕY,t3$ȣS, 9B,`_({bWTIεM"u{r5@MqQb0~2 3!k[7_ŞԽ5o]!Вeef_4lad#['MOڅ S]Yybj?CmזeqӡRƿ9E] BK.[]G/s<5q_~-= Z@*M̯9>r_)I8+~YZtwpT&d$]Ud y#)ұ ]$:=r R oK~ DE7*ɶr"w')n7{-2~>!9T|GqU̵_d8Qaf f$ɧT0!$iSzHx"kO$lX&dFL@⍪}sşei 3BCЌT[NHoJ`QLsMePճdD?j3ǎ箧-kR3)P`x5OS MM DXŠҗr K gHa*}Nr6 wUK#S%njN y"eO me8 q&ؗ@IEzYs4SxhGI^P7j5`dM{ԫ@9Bg& ~'RQewkద-V U7Jĝ^#C:LnW&ݮYa~ r=8Z ShQIRw>3iq3cl<ݞs X܊ޣB4XD*1`OmY*=܊m'ZWV(Z$'$ t!ײT7 xM:Rqhƺ)!mi!2xljNlR/0nl>Jqӕ n/j}Pmb H"гtvdo̱1!D]1&h7XJ"Wn Hx*9'@Y髹&3q(@\̙,S` ,&@zJ7=I5B? lg0zp((mtQ i<- LBND*K zc'LgpBO5# Skek1#a]ceD&G\(fh6 @]ĭͶ,=vPm E`"YMOC5n|H&*_ƀO"t}[VH kj*F'8DTcK.eepte&} ¶Lʯj pLBqeAւc-Й.&y VK(J< HG~Z/n3f{ ^ ={B@^9Sa;,ѫVjN ,vy*A&Z"1ϊYljc8R~ۓC@5xf'h?췞 Fs^AW:lv`h3De9 N #\]_Bv ͜t),V?ʕ~rHݧ++?u ΁V1# d>+P( 76f^t2)KtE܍S4$ձhm8> SJ.L.;<}'O=ZHJHd@l ݉y.U+/{Ԭ'`Etپx͒CHym榹TK(T~<+Œpqh 8M핂Ì 6 ܅( 'BQ1>;i@ʺs?:d*D5kQ6NqTDxGՀbYcZ*r93tJaN^HI# KFuoo>/x#<춶6#xTo&@i]R 3rLukCs3+&PlwW^,{`;*XR\8&ݒsCܧ$|épPa:&9Q}c[n>9E|d]'%"q'{KM⮢ϓ,֕Fz|aIEd c)e:A&Z_W9/>kQ4/Qu(4!n#,dUXjc I.*M@hĽ!oux=77dlB_?H+VՀHwʋf0? `"sEnIs=rw+ڣmV--ZX,@Uº?ca!i}}ެ S9PFHl:k{[YvZ~yW;YG߹sVF&e#HQMhfDpr ^ u K3?NўT1hx >Iw3LJd}1bn:I3@ڭ9 rt]El䨋XGhv^&4(9]68={_];pЌ3?VrX迳(³wx 11Txm掹E$ovfn_}s$k_]Lp>ORGվhAuS2wV=G,T|?8B$Qu:U;Qb:a(, J:A)ώԏw!i]F˝Rs"wTIP>(y\"63^)m(Z _"dC܍ *yT!`ѕVZF|>mh-^zsY=%F85L$X$Lؚ !f\gHA{/uB0e?ҟ15ߊ=!*3eg{|߰B,v9 g{(*KvFN8l Az %Geq|`2x%FN40}Ij ǘ51zwma0V&ٯDVv{Ş魙\u? RwF3޺Wqey@eFutAvN=Dϕ%Z]r%E4=t5%%y$| НL\I1(ԪO -B1)S(d*QgsD"ޯ.$M n4$徻0K#eq>Ҩ}CisU9`MDziq?Q^qȻr}EL$P}?>hOʜ<6ƫW9oS:m&UĬ bC[_:n'&-f$izn/Y1\wܯޢ|\ Uhrܔj.LxTz~? kӔE8"hc)Me945)9uc[8I(B]Em|Oɳ!aLʘf;yҼ!Np)V saTx>@3a} 5-q?fmP#oP03N_`XdCv# @AƱӬ>90A)6s}9 [BV?[؎~CY}ń~sD :N{$;6e蓒5,fS:lL:ϓz%Qx/k4Gі1Fk 1(<1vZ(:38لmO#7]58^{ȉg@iƒoF͘ɬ8yIyQ@0Su`{c*#u'$]B "ƯOG_y߸Ѳ"Czx[6G͜R#@~<ψv_B0ii\ *21!an=Jy2}$Na]28HΐMoviO^IgsnZY |yq7TKDgKs3È]B\/8zSƦ샓 cyӐM-1\S4PU%!˳7g_MyᰑQ<˸{z!%MɪRbuRphJ!E'E:SR#Y3r1(sz ܋׵Exi|WS'ES /3&c9>C0D'L+U oamYNzѓ sF6PC^?:ۍϔ\*1:0Y(\q|Wv@bəo?)9XVG1Clj JFA@'pTR>M܉rqhk$+cX@&GBZP!D<2tY P2eL^2vQ+ JuA݉s~D>Yc4)cR/Ȭ~4c.Xutu+^R77ʰ(F\Ƀ?}dT}1#D43C#"7?eso Gi̔(^>p ,ȠqS/"w4lƇb9pdb9OTO}e&7}0"ׇPΚsi,Ghysj?BҊ]aKrR}ekcB/]'Ͽz,#xgD @Ք" aSm|=%%CIQ]H!jcF >Ž>'žShH. zxemz3 E݇IsV+[^9GY|hgf.r~? 5.9Ph*V%Rb#ٻdhH@ )IwDPeqirQp-Ed8,'3+d!ÌelyxEd9Xy\'`@=2$J;EC<Zy`Y?T9iT$& 'lq1.Qf\1M;tAZ_Hz!Rկ.7f@?~cælP]Ҥw!#MzbύǦ7 ҈ Y+CwԻ5v V.ǍR+g|6@trX`0Թ̒u}w:ZXS4L_P`UCO@c L蹟oPLzހl _:ؘӂefFTL]+Oil08g7>aEo}. 2k?<x|(9 L9`;<)$4G3m,Ãb_8B3olBd&rq}(YJiZ ;Q,wyӪA^=. "uxMDFDo<)ƠxF qq<U|̸MLaF'9"JG+@A*6 lS"P ֍KbMZԎf4wvi**A͢x#tw!X` ,=z>^ٰ,|Y3s%>Q"} Sxfb a4gi"u4 nz2"r<HTkEU/%/C)64HVCw9pyL?;h! +ï/a?A5IGt=}?VB ZMC)Fե*vGmU#Y>U^eL,oAO#ǐe%J5URhWҗȉpa}5n bкA y*X2)mkkl<-$99hqEގ /-PƽEўϵd %ܻ88 qػ'I_VG8CAލre;)_ yZdoKV>Mmt^ِ.Hb.=S~wg^"Vd|;ڱeKb3z/D?c=[Ѵ+ &&8~+u1T ?!<-A>GGO[9*z<}0"SLlȗX9mHGZY~ߴ"t/ceH9 )z 1 U T"3 ]T }a1V dF@Jzlr,, 39 m5[{1k?R#K!_0,«mZs`F״<vDV u~}ObjV#ѣpuqc^gg忧'Q"3T)q'$5Tb]DjggNR.{#G7@Q#a|4U `TJ͗3BS g;!`szt,m0&H<#ĀiCM^l.'6s;|aJ܌TϘ?6ӂ5J%e~a'czƥRz8¤ @:F"GÛp6'jDxF-1NűQ;  إfr~|fJ} ͈n2HO>/0bjt#HK ayPb/>\X1i`i_ Uq4fhf ]D3~-D@GAdVq'`FE=Ad8lydD=jy~4$mJw_`v f_}zHSAakl9phVtgګn8`VVobZƞ,ycz:̜|\>3'85~(SC}3i_>@A&]ȽV'-joHWmkC@2ߏ]< 'EFކ ##쀊=oƃmtd Ui"_?}fhM҂ȏ'K ڷJ[5:.eHh@3|Oj4fȋuRZ2ZݜW4n#NԱ,T_bl&"GQqэ ۞l{tj$ &]z%ީwcT OWZwta_gLGW!GV O C7SmZOXD)4HzAoҀ'h! !ΩH;T߄=T0z$B!h7 %!T̤gA})GԨ_@ uiOR}:? £|K;G#$ BY?` Hja`,75:c cN U{_XJe}_̈.l;yWv ORDƶ B8;$Ԍ: jy;,=Q1pCL l1 _JgѠ0+iI׳ bԲGǃc rҺ?|R" ֧E˷DBeYhCF7vHH"EtwLGY!FW*"=dF2Wؓ /j2A$6<=Ѕ,͈  !s~_-1Υ۠~6zXߏ!OJ~| s81H@8YG/G< 荪UNvg cԑj'pč6B߾\f#%,@NLJ'l톄7 XBo!QLjmvאʩ;S#oe-/vF=|3) 4<2aD ;@IVQtk$[_gґzaL CI` /g|%Rdo͌V8oԎXcBa};94%42[s ҘǕW_0^'^xI ZN "* W!5\=mEԞZg愭I(Fku0!B v\@YH>A8k}7)Y3dR^bYcWDž"=gEX5}`lbCh23hqV1Nq)4#/yg85JzpuX,l4~8! u>>.;$*Qyy_|Pmñޑi]ze4:lgDmxֻ'nr޺ųwcբoo';ݶ^=faU_/aEݻ-~Qu>'|u$b>H6Α`і̇{(fsoVZ.xcN)ܶ KD(F k`)rκhfŚ$p9'7 v G2۷~鷠x5'*l+8:rx*''s4< Zj}<(r9w*յ,}&h'0H:2!)D&WJ"z8<8ú5A +-6ЎS8ϊ)'8E)TcfHY:mCcjt"5yJ_%h8c%vQaĔM.4Y݀JuZn%G-oN_gc KtrI"mJX3FQ@'~#ޱU"n0 {y&&)`{.2r:.(0wj$ٔ *+[#<sBgHBٚueAT9 F#EQ$9AC2CI%po5/} d"T,M=~ nv8ES 4 .@9:z1yd$yr PM. P\V^m3,r=.:"2_ھ5EřF+dI%asĴuCMqz\EԶE*HP97ׇRσm܌V*Es䂎lQلvΌiwkN1h1lkMhkn}ެ_('R4>+trڛ90QKlʊa{Ϗ 2gE><[~Hb> řmKhmZXwOħ߷=.O8E rgBaI& _ol,$&˒1M\2֮eCx?{ds>вJf'=1_X)!t5]$Y8 [)iBpvrduxfcvoJDmkaA8qCBR?Qq901̃r4, ! y(s b^RGt_wN#2P! BzDY-Ѓ=i`1d< jҧks`zA:2~cݐ1AIJW6\ z1Xw͐Cl-R,\.0M9q*zМerJÁ1C)0AWxfe*FK|E(%6UoތF:$EpYы0e'̘ l.ZoZW}q41"Y&UQPQC&P reS8$홢,0F +S*s nfFhN |@nͦG'MkФFL7M\q4Q$s QHN/4٨业{䱾$4gJn& 6*7n._m;JIZZ(+y&CGZiy)ҷz>a@&u7HÄza!2e{CgL'P< x1i&8"]6щ oFa 522tS qvl3\jQX6 ''kLR[_B <1%֤(cyg mDc.4t4dF "RE $p ])R3ns6Qa%u(jtD4JpGiFP5(s~[x+aa E1*_;QaZ7R{ )3ˬkmO Ȩx{? # PWg4, 5KQ qUnU>¢3qi4 ?'D^> "ޚH%YKɪ#AQfhE7<1P3.D1X|Fɀ5 G@8vq50u9!hG0%*Rj/ai(_Mі h67e3qT8Vs< IwaQY< ){r^ AzjlM67*]1;Y]nZ` ]aON@oI}Š^&y%Zf]b_ SUSJ`3;NdhhRnk\ X":ϛ֧YQ'{<͙GW=sƆpPd&d_'(=hc$2zS44 dD+t8c"PL IDt,p KvJAZƗP9L)܌<3gIltU(;F{* ELҎ)6bD|rt &3#a8рAV}UW5ԭ޴zւ4epRZU$Lp{⡑?Us5]#=h=!@8d) R:NbԽ^/4cYA`CX|kxЈPM0)%sq"H|tY5bI2;.ae-<4/gރ*t!4$gA#*jN@1%yVfq5.C&VD ID%͔n#FGxo$.s=ܪXwk5^Yַ7"*8i,ubyPY̥?If'jF)&f{Q<7Vm,Фɯx8=U3"J}AǸV(L43hb86>m~(3^4G]Vj~`C%eGk11=$X"KSD0z`ɋ{kPfJaM\I)"~Z=S꣍eU‹H;~eaJ TuI*3)f5hT[=d`"W'+\,b)G`U:M**bR f|V!yE V0a =Jt,s3T 2!\!v; nף,\p,{ >-I*y\Ëgw^'jWzcdl.C ,~ܣ/FDž" ĐtBSE]]pO0W$Z|YB*̨=ؙYߖ &_(¤p>Umd>72j5bKl6-FC*:A,ӣHKp%1`68btvN3 oG_'DHf`/gx}A^ɳ+܉N: 0 hQ7@VH%D@x(E R.$<*oɀ\"7IAQCw-k tvCD.E#nenǷq(2gװF,8#2X^IHlbeI-aMM( *N10M5/! :$Gd(#d b  w6ŎmORa`SY\Ai{BDc,e-FCi o75--?8 s){ti*BNJzxkvu)<캖EFS7 ll^;=Ѹ% -Zy3A)X=7Jc1MBQe.-MOhyNZ"<܊HX"PE67f=*GvjX{h:6\:.,3saMȠJ- GU7bm('4!gEQF߸~I* 늜bXT4. ;(J"h>?fJgKY^C4Eyi8h(S0%O <:@:*rD.TpOn\rπn%u"@{lВҷ +It:\0]/꠳}2&0(ݬ/Akmujy$N%'eb-B Or 9.^GF6ϐ#D.:ȷ!<2B{:SG$p8C|BP E:sg/yMI x@vo H /.{a ZU5!8gyeF`hUcQon +`F,n4CwήY\~P͗ќ8lgA'Qy*7ۇtOQ'(}4jeIgYF"<>Cn:V&E\3 B7(fsMų=Q^BFȽYg;l&M _"Pzʎ-bO]Lܵ43H7ޜfb̺6tπ\<18(-" %t:_2tQm|AHC!&rҹFYBV qC AɟD{@tTH魼 ޤ=eȺG{Tqpuk >Y6:Ҕ.WjD >&8F}P$`했9O#4konu3;5RYx%ÄC|`V#)09b!kE7 8)I/Q^*zKP%5^asSPo%#x|etkbLz "p?DZLϾ ̊ @vaM{$#q31:ʜW)hƄ2Y; Ŭ"옅8܁<\ fm/9^I DLOcO.[Fݐi^-<зl5KpǗd3dk`R.IPCИj^^ZcDz"!|xW4D`BDLJ ~,'mD ?-m"V?fU4Ek6#4ǑM6TO*::+'ӂ۞l!U4jF6χh$kDg#B E{Dixjd/ch AC-zqA.%Yz2=ݢTS,xC,L${6fH U}:ΓaPHdYqA~ԟnMXtтz[Oz5a37 \>r%z@Dt%ͽ8x:i~T9x e3Z>:jڱӴTUL P7< vvj~k+VZ5$,Jx-ih&LN5kCAXYYymRr^NT6=敠bvAZ_YfrKQ-K{nJ(QY.,bJY#Y ˆA&Qv?ZDl()ŊS+ .2l¿Lo*Ca%˴ /n,fE8`ӻaC&ڷXԽr<_ei5dj Q'z IݹQ7&uq0`Ah_}1Nf+6J3z$HYjhonT,D*Վ=VgͲ/fSa }XOwɦ҇9${,–T^[f^MNp1:%(奨]l(H6E'#ƌbz -2Ra.rzd1Rum2TD8c**y}dlEdC;;p]3<0G>57>f >Y>0E&s<&4u6miG%ٮ<._ BG4Lo_Q)$„JKDˆѽ޹nf!_p(k[&[̭X^p:O1o^4=<\?_g~ZIil7Az60JktN"ˤdgg~ۚiuG-{ Bqkj @2 "2jx!'K齆Xomgk:o B`GǓh?$fZ α吞W->,^kj=d-W7{ܷ)k(fxx9D3͔ΪwC4BC*r H@RZ#[gĖ #]˳v"ɝ̑)a.d2c  UG;[8H:""ڀsXEfȂ6<14b˅d[4ҊjtݷsJTfLt(Zqnqҵ.0=&t@xUY՛NXM0pDHn1C֩WQˤ;;GQw##UTP<  \j_SOW :_~q.{13m!U,t L`1e@ʶ9{k#c1^ 2Nylm^fVCDƟo{T50%H( Klq7X< сyhSfMMLMmX`4dOZlGvױO A-z&^6zsp<8<=/^Mߡ6oȈ*4Vq_RBֻm%ܽvKk](4-?-:Vy1> >uB͇:- ~+tYAOlSN@H:9g䀒t[C{͔ "1FظGF̀O ,@)A^+̜*8/.-QaKo<W6ps9"&U@vPlA'XO`o疋U3g,]KNzIRbM#(dt RصLܨ OJ/Z֖y%O0V?i2cw½{y/v݌ᄦӋv`L+="W:>ճej"!  ȟձ^ڊmW&#?cY <2,,V-#̟0vRS.4;hmTq||*ν7gfQt@3*ȓ$hպWB]F8hKY4=B +fԬ((]^^7dKj#A?Ɠyl6ʹ_IIoL[rPU"'씿qѓaeU>%N=]nժaVɾFt.{?.L|@?\pOZ,}*$?siS,Z*A{}z,X)^t0(8zKnQj2aL;pȩ{ԎY&W95A@0T7>H8t] kӭgfMO]%DXaH%#\}^#f!Py_[Kn ?H_ 0_h4 Iٚ,ck`3v$<$hF@bJ#AJכ X@ۜ8 F#3l9xgvmK} q C⇆lR/¯C,5̿'Y3XpW4A#z.Z[f2dMVx?ʉ?*pdZG?E,FϡD C!z}8G"C*8ZICUyL6ԸIn4!? fOk7uC_xK*,A<s)1d ܭ ʚIIHV !#˄(%-Q۾mꝕ6"ZY:#=Jg! v-<&elN(3MKrdvu.+H Ðq?` +1a  HLz&6 :q4D%T@9GTAzDgP؛]# >&uwO#At? 2bgurZuI A{5vY ) .bn\9 [OJ܇3!fmu 5fjjV)9 9[-q8f}0@w asgq~fM5n(zIŸm(*N1*^'wf7@qu `db-ج BIDPȀci:`~&B4R*L7'?FհQll*"Ae)40m̨ޣzEnŃoW¾l zs?T)ZD`!?eN,AK)ּPFvs71DdՆgEM,0Q"GZh.b>^SuhOTQBq J [9`+?U¹NM^5렏p@3U<ެ"M!Es7|gKFho19U4A-*hD-(}|~_FڔLJSjG ƠxWò$>ph:fV+٢WE ^a}% Z嬠8qvc|.Xljo zpQą1Z~9 + G qAW%Y@IDAT?V !P%`І| o0d /^P+9꣭R k\ElE&SV)$MhM҇1d%\ (4Z&pg/R>n{/4 $$Oj tOeљ"W" &O #<^. @Ё!ݜyH(Iozh"IF'6Q5#f#ϑyC/=ӨRis.}O} !8rJQV3Y51\]i#k'|$>-4ZWf_;u c= 7d: y[sUTzί#5 Cc2?I7;n,A@XȀ|-\/6xRK1Q3RT} ZN@N&8iAd^X@QؒkPYJ_4|\2# 7@!%h Nc ӻ]2k>S 'FCb&y$< >Eb¹$}̻uu Q2TI! !XEQ D4v$J͒> ?qHuArjJllF/kaX`^@>U0< v[3lRZ6Y faF ߜiYZN&/D]ί0,쟫Yb~a?wZȮ1y#D c?HMkSF05d tl_Nd4"-1q7g6*mNM1/~@1& u8a "Xis~2 K Kx5_ yPBu8DQcV82-RoDƀGjeIS)>Y`[Rv' Fshe1hD+r2kB% *crUx( nF>/w D䟑B%М#&jdi9*Rhh%"%3a-gPƏi2q}jQ:md L̛hCZ[hUs{evQw /,ZDOV gF?gqső(EE\ .a!kEdKDm-81RYpjmo%(ԸkƒMwE2Lx*#(SbNt6a &&JGWplkfJt D ZAx^ U;VXUy&vVt|6#Mg dUTjGVC㊑e_;m]|:nV]qE^Mh3,t@ԛC)0w崇?q;V}[<sq$S"ȅ6](,$A`(4S"D.e+Itl=hNRN-[OnYcFiym>eKE#F/Xnڎim^U@Du7 ǗE~qir/>EjW#-g7$DNIr֚`ރ6>,"ϑf~ضnb-w'JlysoA()h_ =<PV"P''X[yA wĸpoRS"E xp_'I%Ĥgm Fi}un&qXV5\*CBjA;KN ;By x9A`sZ)'ph=ElB!QbQIqBț3Ԅ&&4SzO|h{]Ժ sˊ`#x GH@p2$QOf+ SsI*hy c̖3vQSBy^b$o;D#_E~PۈgU竽Eބ=n2H 'Ǚ-u+LGMZoJ{pegnuc{$K9f{9Cg<)9Lao˿;U_m-0LdeV7B4HXٟ̍Z/vknB!̇v1bX9~.֓(j|m9m ɀ\&YB~s`d뗏FӘl#hNl_~^.4d!_~hӍQDyߜl+@XQ?*YPa{Q=qB2OH/䬀pDl B~HJhP|2ۦ4a. $*͟wZC[[/yFθwXq}ur"@-M-3c-%(ăɯJVva3S9>zc7~)4q)ϰ~!l\Pp-c Tlň3g=Z8kx2>|/% _d`3vGSd6L4q48W( |uyWf[N((j=kV#dKѤY
     bhE6ҕX4G8r呔IUgPC6䩱Yv")]m9F׫ʖ/p^\%oJAOx#NvށA/@b;vCbXU^ ,>QziĐrFcgplX{! W" S t{KhM{.aLːˆh75/u@Ԇ/Zl3.TI)#q }ӎ;܃hIE#[L'q"dD a: -B@ꇔvqE'gcq n/4@C> GEh~RAC$܉͆ЦIUO쬆x"s;2ĜȌ 2~ӒNQA>IDދ!v8+{3İV-sHcqp.kkQVjқ~"p l? D?rџ寞P@32H1Ə5_XEȺT$p8^YOa棯TWMvq?t& 0[m!ֶ\Ёz'L$æ O*g8E/Z zJ4 $?p {? _ϯŧ0!Nz \sg_B sJ%fɊ/Cg8OߨPEؤ0TGAA3E"QJ[[N MC ̀M/C3u=U`$ VaQڰ}k ஥)e3Ym bd:·"LЉv UTxfz9N;LKƔQ0 @M]V'ml-$s=A@2Nȸjx?3̝B./6@JӋTg 3eF B91鴼J`8h Ȥ&/2r(.eH0sszgR S%W2Gڙe39v8mzd I4..(Q4$d\, dЌdnt4)N6G̱31C~#L4v%4?7յDt#$bPFg(:2glzr⺁/^+ѵ@}?\k,õ_}Ԗ!@fIa+s2*?^_ӄsK2rϫ}]SH D\~5D0q.M kqr,6= ̘AlԉYU(zFPVllRzt*ތye@'x1Ya@d,ZCXv~bkz9I.Y- 0*4>.j\s>61WɓqE~8-y ݍ'W,h4:Yjp /\x=vv]ilUU1Ӗ&|ݕg؇(md(쪸u6xf :u(CiGy:ƪtŧM՜ My"d#dp%9E6̃MM o|ԚWh^ *.f+Z/cri4pC^}$'w ќqvHRay(HnA?Aw x$@?Y.h:(4܍{^__י*%/Ǔ<p#Tʃ %쩘/:&2HWG"ϒo>!njx0׉l(lK,C;Mؗba.22Z  b{TЁw}g@AG%~2Pk c˩UNAND Fz'3ʔFo[&_/-faHPtjfs5? ymS{)>^_%OfUUiJ(uv(&Ŵ,MPG nLbd(䉑v~ ۆXda ZCQ'Tzwm|=#k2j *i;'` (gVaE䂇E7cL 9D\BXTEMڦ1`\DAzPsˉHر.{˖G(VYXO{4Nk؋-J@S(=V%R>.,RrlX نJN##¹K>}be䀌`8uo|ұ?,F{?*K N[ g6Gx̢QoJM@jIA4o\kq>e5yiF9b"$LOU;5UĚOȣs!o MJm.T1tQ+C02Ȍs'Ӧo()tu(6%U TC#+Iu3uZWulI W¢bDf AJQ5 @TP9`FV(, VGS6:`rbeRbCu[u+ᆀ(Tjɱ%с4)LOهI~BDiǛeo/~^xfm,S&h NLȘ^7&ԡ~Dŏ՚Xt]S=Q-`|no{}g0wMja=n_;i908wLMKP@f 2/4tm X%Xx;1Oѓd.z(iAl#xRoO$1>n!P#B N< vmipfw_UXvɠQm;ua @*:+%K|re@\kOV>sFMݤL-XG>L HkDt!THe=u* ,,IgXP⩌RH)Bωcn֧JUM"Fv_9Pb {A}y5ѫڍ#kjY"ן65'RY1Ԗ[+c]Љe8z!rB$Sg LuǛ6A )GYrؕ#d0  g 5r^h]Opd#7U\}Sx{VBV Ll"jq,9;b=ǵg!ݪ$5%Y8  |Ú}!T:K]H3z=_Ř 0|Ԉ4XE T/9o^Cw[FٟZ%k$L VzHo*!7%34UAKs;ue!XehI?@`xzX<5;J9I`;R/rH3jSPj|vjY V@ppsc, cTb pv*!0`` 8P.Of'AS>kMRdn.lT(Μƶ?b4 9s^%N%`WĿ:/l#M^B"_Ph267RFSjP >p֔UO$ !TDIIB8f2 ( /⥽8=1}lA`f Eh ڢuv}so TAdy"]/b+y)۽:m5 ,8 Oˋ:ل1UC :FГ"~01u>nt[fN9;/OWI;f^}^y~ J`DldDǛ0]B'5}CuK-k5i%3dI/O,˒΄4rs>A 2jEl& ťN8N/F%47+}^E+g/?Mh86N`i|ZNtZ'NTIo^kT`5JORegQf-zѴGSTԐ_lꐔYbƳ0Bk'nhF]|e:Gј aV40qHvuL:9 }YDƪ %$r:,^ÌrnD"XΆ"xپ`(ZitfEPRD>E?kAH.c?ܯ;xf:>Tu. <_ A+4(-nFNg VJʼlܹ%ؙU HWOU  ]7^5ay*ek9e;D!g3ƾ4dz(r+mx_)%CQRhIYE .. n#IT ԻN50v⋻YY ĉJ6i}zYǴx!k@U{oZ,&A^ӯ~yc0Xh՛33Z?Rm]BWm&kqFdm>i*T+QR eAf 7bFft+bH=Gf{?PcF`}qS{׻ؠ@Eb.TJ$ WБޫgJ( ]Ch~rnnǤQ$~|JM )J)iXںJs e9eoU OƜ[i*Pm\psw ]4%<nYإ`2ӋԀRְ}3wػfؚ8{檠g61I/X=hVG;-YgeYlKm`0XT4&`~XqH{g\|"W% yw?#L[K?uIxL1tVj#v􊃣L߈?\՛5ov{ģvٓF[2BQqR9/0 3 Ft'XFW<%k[Ba^w9˵φY9;@g 52o@fI}Ue!d%ĹP$ l@aziɉfta:O&/w׾*pW[7l296&Pb͇ d ҃;7 ,3Kt^[ ACkvUJz/slˠy< ZJ2`࢑v`ys#oeG+`nN -O0g(l%Y^kЕ (;l#_6Sٽ::G@ޝwA +8mDfv MkQXhNY ) $h?g = )=2\1Ɍ4Y)sfs/1E{ь`b*S&|l>QC򵋀ײ tjRLxrO ˹&.3x;SR>yZ|0z%Z&R% gJC!-?.Zj e1Vt2 YVgaLrFs} )*\fF@s| ke떜gGF^8sö G B7?L1FQGQujAؒc\.XW/%oB$Пﶠ" %҉!DTmZ|S3u_ɑ]ق] "Ȭ~뇞AJemy\_U ?bVf~%;eU:* QͷZV%lna* գ8}z˽vg;LXoXP>9{ fGݩV3ӮE'ȥXnm nIt{*D+NfpAnʘ,1 S3dW.D+Xs@MT'(ۖkW &'ԭLnl]1 0VɋL{A log5DEmа|30Ӱfaf"@>"[jɖ!QR?',sCRL4Gr8F!BT|{i7kBPm V5Ge^Oi2Sh2ص61=EDwxիśE[(Y 1χ"(l oB`^'"O}u]B!4;r: E#$k ʈʛ?ȸ A=1S-q/TI/B`qأ5Yv!-@W#(Ok ٌ{6);DV)(ˎ:7-.@GF>hb,{A)/\LrXZ>@篏 _۟${:Cq9 ߜ!e0&gBՍŁ`)Vg"X>,"ԄՕcL,\"oC#e3Ӝj`mN8˂(]k<aeru/ ]] K;<>qEj/]1++:ST`b&TwOt)"lji#]ty$3m8֮PcB?S8L aTirSK_G8F7)Uet3ʣ& 4# ؐf׷];u&'.p%tȵhVԟلpBZ|MA}PFIш-bC콯a)U$IҥѨPd!A_^d1SZG&nyA`.m/uDo<D9Ma/ޙke>,z3U ?6@h]Н1DGz)dN|઼JQ@j> `uٝ I!2_䱒 gD^Bn4RQX);D*ԭESX7mDFLg@JҰcx;hEDeȖ'4CĈ#k,HvK$gDmM1# 7Xdr lYM[!~e\ez+fĞæu ;|\k(y".P\OF⹘A|Mhˏ?^eS@ ׾^ +" ]+H-̞$8C&V`O?_22V=N#H4 q(>N(SY43Q'  'iFk +ʧt cDJ]ȀlҗU(#AI6zӮ1Y !-C%_8^p|82Fӣ26VzS&UؕmFv`zİ @)v]UK tq,$T`Y/]U㈏hӞM*&ŀZAW*<YM;91y0rg 3‡ST_j;JFH49:`ݏCȑMk,nsLա15A`3I@K! =Pr_6sOҽoQvCjw4xZ@(W ޵]OWE .SctwC:={tO(E"䜰c_c x]BBTKOEjhl{E%ZΎOeR$\I  95l=N!01-往@KGtb-V .6E##譭u ALG.ak_V^CiK+R/l8MRB_Di@D,I3vGa'o]STAΉK)#9<!,K2bjۓА^gq 7QI 4Jrt[4Aen;χS􄊍 soUSԡpΨNJFGǸ1-=13āNM >yC9o${G`uR^DPxe\A3 88 B߅7]A=3fIbax"d`]NMA=297gVqPW \ؘ RNO^.HHԢA,x&MC_{V\u0lzCH59 McO=iU;<(NTk+x' a5MJQt%< F.-i9`WGpV)nA+;M?,wqq e/ۤq.ưi/JV[Ҡ;܆%; >YIN tV?c$VNҗ+d݅&yƥLR Ly_6!/BW\SA\rȨ&,2buC7@Cy'b& (P@hN0!Hg\>2Z ]3<zż]uԩ:LRn2S$\1Y ѝ [7a2Gcd Ryా+$[`^8ţLM&SvjTq)Ƌ)s4(vB%גXDbJXwG\'IU412t/`cх (0Pڀd1`ƤibF'dBoG3&.@$<7me @ Ѩ,f-hYn{FbJɶw}l*|Ug[yb6k&4Mŧ%,?Jѕ<1 sӎ¸1%{oWҲ p)Rz|>h7Ft-bҞ."vKߢhAh I$Kbp ,N*&;}H)E 0ErDLnA(vTOnވah*pj\0и~׈\Us%cr&d7Yui@ E9zSCФ&jt&)T=:@9&tQZx_F_}iJ{η@24|؄oXPj+0 Scd~_mܜPrz=+Z^Z!JQm 34$(RsdnDd :<6{Mi%DDlB6jf48r$ # aFjYY T@7ɾעlSS 2C.XHAy*\C53%H݈EC/@盱)`iJ4cAt&]vR,bNphIq B9d"Wȱi 㝲X[ 5w КC]U"ze|r[S:~ͩKyyCA1 ZvڞC*(khPZOI&:zXTex.QB:oOIRϏg 4%LlWU\HES\I(Ri+PsT^t?A>,-[;p*i Ta M<4m!mDJ.Mj"9AUD[AQBpg4oDS&NJj!aPHخn4QE&m`#8IsF+O%=9]fnz9ֱᙪ.HBr_D7IQgϏ*@#r4'z.nw..VO'FZbM!g3heTXN26qq }:*VQ9Nܿ0.$}o`l6+ePo:2zq1M;̣p>"2i΍Dd;tFn5>9#`OCM;aЊ&qẨ\O&3 Z%z0M5[?iJR$ӈ}3Ch_Z%^F<^$9+oo^?k #~aP(/9ҮU0i'q:-ţn '":0A yPhףrcafwbE::2|%[ L$<5ƪDkZqIC=~ӄSCe'f fl0ą[ 2fOe<\|13':$9ea pыTA!:;7zZBPlun#tܺ29ތ\$UK @Wm>M\5t5ˏxC9~My[ +~1%h]'QO+`9C2F0әg;/ü sGJ?6N o=zP}v#VY!dW(ȁ<",E;o 8ba$"wK[.ɱYdtG&ۿyX,O?wecY,ĆG}^vw7Y?[K:  0l\9Dq+{Ge׻q<@G s[&EH!kLsVTYUgrfdzXff?RDk<lc&C̻td[1L3q9I h\E3jCi/e. =X(_hP7 `좟kF=[n1%Lr)f8eHmX@j-ۤn^O1b5% C;(/Sw=W}kMU0*Rϧksd1 ZA*%2QK6'Ekki]@aB*-.T#%ea[/|R&H ۶:IN 7F8\kZ8ma.ߔ0k-%o% a^XfW .Y1%k=XUtD ٟ=c"(ڃ|y]&cKxZ6R.6ݬ_qhc`џpV}f-JE6!Ci\d![Aw)LJ47:)a{3C(38gdC, 3og;=A yӎ4>D] Ul1ڃDA:z ^l>ōg5,̳C@bvOsT bZ%b"B5&bR^sx@<$tN21%*̫QQj4 ( l{8.3t:?竻&8 r2d̪X'U}mNN޼x3 8(}P_4"[׍W[z,-%kɾIAS9H֎?@ to"!q~U'βF*%]^WJaan.pX&/J[AT\!_؈BT, sQ3`{D]mWE/!w|iUX<0}\E4eOT2m`P! bl hCӕ=M5'Lp}\h|q̂J00z]2-VF*nԹ3'Sx$jCM%ݨ[\p}{_u{LW1 QXSUh/]eDμUYJ;BIRESkR0s܌v@Wn,Kw3 PvlO'/l)ʮ7u 5b+h, 2UhG2nX{EzrOhw "4Htp t: ~P(Dn/PcDOaT<p Fy1 .D ~OL]χue69ǻ oHꫨo n b|0)p֠)tNRQC+?/ Sr:v{e Q| S̟7^~77 8>kʆd '>I7K岍53m1V*srb=4*VւÊU68hc8;hɤ()2 "jh?NcE▼;1aR"4*&d3-`I$nGK jR&q=H ,?^K7Ml mc =%<$(G*a] 0q gP&7sNfa1԰dHu V${$SnOt7A͓Z>Q0[?׋KqJ(JDuAFCRUC |EW`wՎzEKتy~=? =UtNR3zi '>KgO5dG(H@[BGz7}^9ki%8\bj}c)f:ڱ5u5;J>*MljOLfGϞ'ؑFL{(Ij m}7?N"^6L^9a3ykJkjZ`ķ26GS~= vB #;$ 25QO R '$ 8a Ր9TYtT7yBm:̗1bg[5@h=ЕauװB FP`-Z%CP(2э y }Ig<HahY2] Яj'ͦJa9xBdR3[}*ǥu'3UuK xGՂ͢ ]n2:+\dd P%4<-W=zLG_GQ<636|R(2ĕz[9 A)VP൩(̲֜KMxXKf撢&Q9 4A j{`CMQnݢI]S1"s[%3c)&6Yx? O6B=*$mfGG3y?<<90&fJ٨8wBdŤavr3)V3&iK iR"rnIEX NHFMCx T)UZJ q =(m! v nP5^] &+Sӥő̠V^DG 49e$Uf84V?|27C?Rh|?Ͼ5<2u=hc1!q*H=ͅ_{KQPT(d4eт{drdr(5DֻZ ^WK_@URcpHLRX`JmVy GNYw!QBo@ j)]1$qݳ:ꂘ>gRP9PY#@M˄w߁ ć-IF&#" h@Es֓E&!~ATeq9HaZK}Ou5rdW1iy F/D|9LQ/bi jwHGf|gi4̰InOXzH@Q=R]hjyNANܙ /`ckȹy2WIbW+QE8Di^ՠhͨhAF>(!$u^G޺c[vn;_8.Z~rL!b)=A'OPty\{[VpLZipbHHǤ(brqb/p޺n,-]>ZZqILï#,>c(@zpg.a_jG;-f2 ('"jqoniaMˍebX&QSL㼛EZglWti,jԖV1TecblDM&B0 ?u{KNJ6̙vF.7ތjc=9\^g B}LHѬp/3<| ?%Ҹ3PwQyXRX fiCI<2lD N蟰"̂x5\)$XU28RmbO䢾{$}@HdO;V ΐ,0jY(T1gpf[_ձ WП L6$l+J$&5#Ȧ6)]&|,7)BHI^WYy=PkG; LQQ!`\|!I53l㿵:XG`(ƙP_PP!үh"R f#zw&v悂C<<o!L-3e27z#w Ӥ8M5fƶ*FNJRrpЧ)7˰Nsɢ+ Z413( O0cbw舄ZR%M 5?g' M&Yx8lځ{ͣfbQ?={?_BC^: b .X_ 9`7NMs+m8D9$Yy5vGi/TPg 5|wG G^ 9- BjY*ݜ`TOTq B23HطͱUdߨA Gg_̣^<'3+rm/,&S"L&(1[(9[i%__|̚ڶhJСG$}n dxeoN 4P,k.Rʴj5JW)&ӳHe41$),DF3 |H?n%1}p3h}'(.c8kqi8 x%o9]M^k5T tzEshT h?ݚnY G웋=h'I:ogaľlm|EğU-)6Ŋ}_,(I`, ?]jux&>A* bRB}â&0T軁FEiYՎ?> c *n; m}MhI|~̋ <[%n^GP'bE14\E1E(b(ҔsF+wà^ |hfݩ@Ó 5[7DV+wN*K1,9$&ㅅ 2]}"=]0B60c&uXX^&u?Jzhw&8`R%d)5 5nSV<|jA͓2Ƽ4gELhºSh0gʾ#ޖlQżf)1,}T[!= @@e2'@! `cF_4J52:crKiɎ2M/%m(G!tm\KF$Ff+,ci ( (A+saI>Y*m׬9rXP꓀9QF5Bco0>C˘vvq6í扲 hԸ,9߀ԦgMӓ:ak.׿\9 _'5s=Rl=3'{Ԃd!C/ʞ%a+h.?>4MiS9OY#X9I! NJTq5Yw퓁%a2UD)!y쵣`:`/-e[H.C͖.%vWihc_8kȳ7UcF/k>1m0P|M#tf!k)+ #vojO*)C\1$L96ij89\|m&e]9Z-TP P;K9tzmE[Nyw\d"˻15׈E/XvuhT};u:8:HD"WtTQIJf^yc͡Ɉk:9:V'` wýW:NdUL!.AcWYNŦG56(cŮb@(i6ua,1HI;,gxu |Z?Drm _Lu{g[=cTH1-~`3qbև?dhQ~d!:Lb%8rř +ٴCA :N4!WHґ/+ݝv P5s<V+:S6)pmY),[则T3InW2/6>,. ńɔ{brRԷ_GAUddrkP}Ȭ'W4T,Ż-ُE+RHdKY'޻]M>LumSHA4mԻ∁̼v;I-]WՏݳgazpf34tVրƊlp ǓAW*6ֿO쐐&|e5^>IٗB~5im3fdEC ۯ_uofwZ-QR֬(Iv5éYkZ4{7n"~PNTB4E[Р IsnHT|S h@/.޿g'^NX=Ғ.w+>6Lu]]iM4.0?\iM*E,8W>29 2/6q۽>0rCk T28AlWfrD97b2nKLJ6Emm0I-zOTKYXx5#L26HhLE2Co- vy2NA$eI{a}\+ծ㢯O:bҊ|*~Yӈʜn{%H#CPb8ѯSԑ.q nyoagzayi߭#v"'StdMZV%YEޠnC;+33` PsE`p7`̾_Ѵ'fm S:xkOY$읣 @Oז'ٌIcRa.K'F 'V,)o019+#z|]o; XoWm;}~")L`/&)6xv&A\ĚFjBV٦O% 2RqPSpd$)Eɚ 8C#!CЩޟ`~R|E&P I " p>àe4LyCOA lYT15DqqN|I0e (TT0%XVe  v 6Jz ]@twؙt#U J<#B'[ߠ1 {\}Oe*8& >2հ`77ȣ{ q{cBXDQEPW=4uiH с 1 qJF_̚w 23N2)%ʇ&ɂ:*}6<4:"LX(U&M YfWcߴfk>< kfGbfRZ ' BZVQ#Z#.:C'"N\@̫"XE#H:evDn.W>";#6x*Z(bHAü /ZFbUkHClʴ1-)Ĥ>ǪxCbc F[U)h4TONoh0f Ȝ[]Ov=iQ.Gq_9riab8z iGz[Uz#uP T 7`Gda)ǿ=0vU_@C)֬adRBbaDZkYћf+NRdDb9џNICd5m`(8AfQBA'Ari#`!`4_t3f>s?в.z]Ȉr13,j#WbCtL"Y72ڲBMz.v$L#n,@Sx *8 f%Zm꓌u&HbO!\e33' G `:Ma}ڱK9YcK$;ʅ5L"(xܝHg+RL#, EFG/Wu7]rz o؋.y\0JL-.[~ DR87xF. N=7&% NP]~W zӂ߾F1W.}nnp` ŷ0MIG3$Pz:@a=Eaz*͉GI 5$\Bt /fs1Izg r["A4𢇽!@%>T81`_#ͦQK]: ce[4lko Ta7}|02z:/=TD~98667/Î %'&%]أ]b%]rĒ!ä2,լN Սۂ`sָəәaI@:lM|#% DPAU ;h3o#pMӳ#f#G5X  ft䕆uw2MK+źw9dLykzjO kCoGID~`@s-`[A~ SpLTI 4@Tԥ/$.@@BB^ѯW @*}旉&^̬a8?s- &3iPGH 6^O)Ť4!i!ZlV} A˴d3b6 |#*Ω~+`OXHPX'z%:92D]0(ws^"d&~8X245b2@j#bjِ3UӮEHl=@H"vp+CA Bѱ:6ċ)>Gc N*>pWjnA}߱v#BO67_s!/A q ptخ@M-7ZgKZ p ~#ޏZ$%%$U-wzatxM4F:E=kUtGF ňftz%b`0BT-Uy{W. įzrL%Ó,׆ \˻JA}4e5[骱I7;SQo*5F*jzt =YGg~~8dΉ9C#%4 .7z[#l`i6S^}1 Jg|NU; U5F"o(w-@,>)&WHd fb7 G|/GmkxȄ|bQ2Hd2}i K 0U?p y {Ѱ! Щ@?|R7VH/7'})s@<79hBn:= vn|lDXfzdƪvpjFU@D'P.PMe4:ڀ@IDATnGj ̮܅=dHjH*޽M~5;fƸ]XVTˢh4xo*O'ˏx Y:2y2՚0d>c &6/ҌI-}z#1QjEj{Kt#P 8l7BhZ˾d./jIc" :h䂠P 1[X8@&^LNyjw{Gh?ΫS蝬Ft!cR9L(->T+2{._ẝ*E:LTBԧvyn _!Kݓ"D z"JQV[mS֩RYrr0u`+6.hV_L:hW6H\d#$13ZELt y@!x_YPw^5 ՅJB۴[֯q\;0"GtlgVFѲ֝CFFx=)o_T1$`(- U@ԧsY#T5mL;-=!5Pn#ubGBmY`<Ub~+M8_z,'5Kchv@e%w(!K@ M7ӑP38ڝ8xe̊ ) Zq"]L2^ Њ۰ C|9[i?n#_1Z\% - B4%]Yfˬ8 @PWϋ9W 601$@Xt$M@&sS>$^@F[H[(@- =DohC_'%J3K&R-eD3&qP~Un*ee--` GӀ/,?Zi'DRpj,^4K_5?: 4m XB lg:^$lUPFˑ8d+ʧIL7P\<.؟@lC_;I,.lr[=lHaRVUIR X=LU Ⱐ UUZz.J{*8{UGސ\E"`ݟ틠@>ږF$O*bPN2v*ϘF3%Ҡ4l\UC-j,8LE7zx{>/ ѻ3#TvcQ,=s#`z *J9# 4 z%8fO{`臢@K.D'irA?].+vT(YWHDP4)¢tIFr`GҺ&ĄTn;41mgEm͹x_ 4Kp!CY"!٦~ |_7Zx 8 r!; $!̈́EZY _YDT&.-`%{wsH+u^ bgZ2ǧy 1k.W qty2S l cS(A<~yzQ:N1(?;T n4gtE@67 +T` B'TKMHiv8v缢GD3FvAL G(ΟH bLlj7[rhN&Jdq1&,lYM$aH@͠.\wZF.uKtHE5P ,ٚ׻^S~.$S$gTC>+K6K9)LwF@xa'?j] 3ܕPM1NAp DӚ+ƿ&|>fwDye Id>R:;jSaE-YNbϗpTǕ(|ĉ=sAT@EP^BdP;]$HEP-L+j$b/k[~"dk\pY#⃒ Qǵ^T҈% !pw6<`+oS:hK>(bW so1 6jE\ixWmN?jEo@rٞ+⩫V+89"L͊ IUαj"<)28!66E!7iZi2}Q z^$lytTnYFlh/01eG$`7,ӴՐulr"7g->ߡ5 į8s&,0`lF$ f[hAZ nx}*Z!v\. Qmr킻7Np.yi~ <݇JuD31=T;ɱhBڏ$$reƠ<- DCs εH&!m$ɼ$5 F4M(Wp:vJ}RmY,8FC+]`ѯW d9Oc](- (57S2;v^} H2!,]L ͖HѾ۟ 5TGۥaN?GbG|7s2$ 1{:aid*yx^n{CbrO;OB Ynp'][^Pv'̻ø;#Vo/07i0)* 3E]Nx?,p;:EdIҕ?&OGwlfZ ~x)b#1gɾLCZOϭw؏O۞ R\[}k Eϰ&y'!"?Ìx@Wb> $QT&AY'2\0/H:ɻIr<2yl0O ?Kh.'9TtH/Vm7)q?Ev6`rt>ّεo3B5{!g{IhVcJe3mё&c\ъ;G,E?wȑIhNr$wLmA@X{10"0RXSKHRx̜,22'L\Ake:RG(c?^?(֦-$n Cr,"7^F1԰M.ڶU)m/Q2̱6Dj^4㚕k5B|_& QcB.-G(aJTe)Y12e'fFFZoa!WF&ؼ3J!LHbv-NTp\@e ]M3aRrd5&NlYvGͻ/DWra+iة#J7 K$O%S% e\NFFf/Pe$(Y5y@$?~;gOEBeRd&Qq6sy9R/ ]zצ*gI=Bn6G>)h-UXTI [\r9>APXn/NO'oҖ[.[\ @̸{1+ρX6DñYJ?V:)Bli|+&E1FW1u!{*Y Ű4ŪZ =izP aESf xzs' shCH '\lw/6">xJnBT!4*rFl݅5~['mF0("$I PAFv7x`yɸBXo> m4|=h,u|pFy0 @-Gps jROҌxH65КnDM=atmOHĉ l: ~bp 9y02˹->kۛI"fZԹtFҘ1Pc"\[jq4H0*ܴgdb u"V6d"8; y٦D>Qo Ƶg zK"F|NyW}2Y(b1%Hw\]lOx SE}zOݾL lYһD iv{^0u݆ b_7>X%)D)^,0n"f`*L#0qk3UiWV]F-1.%UD5HJ ݓ1TQ` ,ƈmmʤH۴*"U s;Yfll@'(mnhL<2mQp|΃&tGs $'(,0qg HjX>3Ih^"C$'Rx3 =W bk/@μ6G&BvNF _v6:¨ur4@bKLahn" (r.$t$D3˫U󠇒 4S4R%Cu=$˒(c*bTaM/l%Ls=.S ArڙWô!gkmqF_ǰUVԨbY7Y&/HgNZ4ӛ C58wc'@'0;(cA OɸȲ* wyvPWN=9a`&ɦ5f L>oVSf%sSAAAJ1k[p/>IRjKJI YԢWjV$40cYKM_{eeXȊy*m WCcc܇DSIEH#z(OŞ[[^#)ye1,쑀Дne.<_6P߇EpH^1;D/4 bvF?%dFGk261L-JϠoCiM.'Y[0A(egF4ХmsF[9ًjl΢2/o?.#Xjz"ds UάI5xol=S2$la*P"2N2PK֏SaRNk]7Z\V'J&^`"AeTYSB/b=TL鸂ۿF$Y0T}|{:l.LlTIsDFf^\fKf-5|1Aۋ.!0!|:pC`UrS 2 Z?VGNE!TB&+)6kO_8`%u#%)+0eI*c*Û銸')-ϰdo1\QTA?'avUX^LpMr%Ɔ8e\zbym gyEV@s{9;8^Lp MFƯ>^$Ak:whL Z)WʜIg5jh=0.e TZ!UyyPj҄y2b+^V+eހ=Wvђ0~)HZ6#H.Ax~?ʆ+jɸU&f:3E y@l- yq=JM!7I ؈O BLU{.!$IgCS<7vD?V$4v e7`W*«rvW?Kj%\qBEv8,̀ô`/ߪ=k 7h\^rB)kSJ(bD&C J@Ð_d ?JNJcM7>ӄ n){/ºBzjwq-tJ\JQ. G~!@L!;.ozK4C'$ċΝJ0qݺ&b%9pKytfNr!ME{`U# T\d3kI:JC˫`yLx2TE TIVܨ:U \rCAԫr+jX$E\hӔil9NQ8Z[/Eֿ$hʫo 爖Y/;K<_t(IQ䂫x'pw-, / гݑ 8Yjh6ϥ+8 GECS1L_vZ9ACțu^A=M.:ʅ&}?+2sOY_=7!e^)sJ'c"nDSWv|VsKWv,z f"Kwr/v"K5:X)mS 2/)2$&85c]NQ+w$f{=UQPz(o ZO%f_VCE8S+}F8**XFj̣Fz|"e^ +X=ڲW'D< fT Pfhq7`@Z 9>UG4$ NڬF]Unp` $ HFSe+onLH铗i?E|diCO }2ց7YаNK찷Ŏ5\Q}acXj77g0(΀i'j')!"t7yGS)ApjuO;J?\(|TqoSeA}gCWb+\u `H`=7r.Ûn=g#HEQSAu8UUUWF\i\kMZ1[IzMKas-v% =k{ anj-2}O)ǣ[$Q+rzP1}L :QԔlj}Ȧ fBd=P; 7( }iU~a >(>(;!_"iaCl5AԨy85@"Ɖ] E1zP^l#bL:6^$*7|{ pC_˰E>i)\asȑp<,TZ"1U&8h)klC?!6R0۷F F!hjq ;T)񤞤-R:F^SCY&MQL"\.(r|\.xŞ?*2#,X^լ@D>Eti"K_b&B G0v5 TibGA!EQFרr̲C̃\LxL4 bPToJ67ub i0"*[-57bBjvcŒvނ?mDˌ쪵lNj󙗝o4h `*/w!smd4u@ š 5/׍x!0dNps&2 Pz+HXCKz/-!*ifssz[z1>t4ߔVRDKN2Yk3|yueĤrí 0!v[aXh2 c"YC8PSKɎr]( 4Sr8r8~ǽ3X[)n{+30AN@G5NժD$R,zUͫB wʷ?v82 kiL݉ĊOX%ga[$0{ }!el?R;/4t%q

    67⌞e-%>o|D;?r_ob l 2Ӑ_ oA0qlfoto&;CGl.5-/pհV1B@'XӋ䊷Bw/W3\,qP#0QMbPge{ &2p&ewJ՝{ωƜ67X]ͳѨ"~iX{HgQ׾`ye1Z!yDiZ Dzͮ AYmQI_a-yL&"!d’?ue!JDӆfos80B?E\2]- 1P'Zme>Èh+*,f T]ReWGͩ Rp/vln0 ~w໦QnIm\MVx˧0l#C]:R4v!TGkz>0RbT"&%sƚ]Ët2CD$rNy#nok&X @3Ŗ tRodGFk`]\38D8$KCHZUL,5u]5;K,3tC^iQn] Feݷ~״Vr@8k_*)1Pz K #OL2uTFꩋ]&M#t ޭ/?%]LJc~v|pP*`>V')3q8ttz};"C{ LCRyBLo0, Hj|(c3qF ?A>YF#uQQSO;F4p#er$,,owWS5'R Rh1eV;wƳU59!s?|ٓJW-n5E'NA! q[2`弪;0Jqgf2S{>7sZ] D eq֑A`x䌌̑ o] T.d ̎npwD4ohSԐb~k1 U r P/臿a[(_iۍSWem"sd 0ې4j0 6I;.AVp7? DM9%Vm] =9*tJ*;`t|ŝ0f1te`/yr"CY1pv^ӯ/hgEq+/kJTӓUIcB UO9 ^B=_@vЇxbHPH7%q|,z н&H/|Ƕϻy4Ȥ ׏Gk,|^v"_Ur%ĐFڬ ~(h4sW9fƕzk|6sQɲ=ŋ(Jm"!=EՆyYn𥤖,(ƥX)d/*u mcю<~_pr2ƣf}d>"߭aQ{zTb;8W} ,9sPa5V1>"s=JnW~/pX8mG]*,aUfzKlfCq3 ,iLJ^[AprI٠&ZM]fce; Q߼?A:&u2|cTpD!z2T~\&Mg#J! QMubTډ%zt>\j UYu%f]>c޶&'Ԛ'76񀙔 J%) r|ك ~"!!y8oп%GdׁӎkfT[g_H>J-'/D{@;`LA+%`^7yWJϐlX=A-ˆCS4qܞڲQYn}kQqĿ>n㗻`˪l` `I{ (zrjֺl5xTNGTi})ۃSIVu`ḷ!~5rcA)lB4ArHD-R4(w򙘎qSli\,Bg紋[7kP.()g6kDX% $QB"flxəFP^jNc~dtdBL Hr쁂|e7-"|ECˊk (m.`rc+ L,4j=oR<:#H,btmV,1Ne}hfajNhFMM9/eN `̦Uī@Y_ ;zK]ƮQ& tv)j]YTreRJƒ|j}[ϻ>R@Skus:d]`Fẓx>D=^g3LI|&gL{dtEb4m܆Q=(ai/|05#!C1?,cLfiw7p_:*mW1`і Ia. }1t6<\|n[1l$=?I6q]<Ț ' XrRb^L<%ؓ|bG-ɥ Ǖ#VŬ}&ObCP^GOgp ̄,{0L(]xȴ!ߵ/b`҃'u }:SCX0~|DXL1QFu;;-*j JQ@΀H5jYOv袌2qI}]>\͒K󑄔#/R"-(GHKseJPoXa` l~ù2%a%d+ei ,&!ӟo6TIo@Cj#Y!OƋhYRSYֵjX=Ep z-! yXRpRHg2$ X:Ymmڠ~l0ZsXzqU^.>#,ՁUrV~.lBojCP 0T^e|r&FGV݊> mr 2Lxh">Z}$r_Mh*kig@%ZXX|`fڑCN4zZ^ZELl;$5+vo>sFN^F%I2GFo38:qE/@`TؗOt7@BXGNP3Ob`?y)cssOImatMF5Ӳ٬:i珊|%bP`\z<1"_R%6n,02vH2ѥb"JyŐ0&^d(V$&Tx5d$F} U2/gb'E4~ECaUǐRm 7O 4 =W 7XƓV0d l:= ?le4+~mGoUku90vxGFT ;f8*=6JPHt</@)놜➱Ƃ1;i?)a"^j#5utD.NLfF$%(^'\s l\) egmDNj6}|+U85m<*?Ʊfo4< 3my3S5ㅐ3jF 3ύAg;Ns+E#y xTDZ1͌XaLub %bpLemJB*Ҵ!F*tZ`y|s#{vC{l[@UfBIkYi41s쏫$N%1+ P A_5aWXJup%= cFx-h o#( t饛xra+ЀRozc2IL9,d `;"nqJh)aUbIMoUq(@xei!fT )qxIGV[)Ԏ)fS؀;cFȄ2fsX&sx+Դo|^y+h:/N?~T+fUyM`\*菛YM<%7 XW <߁< T"&.89;$6ȼ_51O%,S@%UAɮoZPBV(SJsbхqdbm vwz8-ss k$ 12|Q@j|B=Y(Wn"7D#o2,e%ώN'<6ײ"ZK:`tHrTVː0 bS /b0p*fl_oJ#'+&_ܰgE \kكGJ952 ev7)Y y0!@<@eR;I@'Nxp`(@fW/`b=I >xm>,AJIa&t|ڞqCoCu@IDAT{T,=PBoh1bi߮:y%:1(\W)V֫jGW<,=5EqQ)z kb:nR#5wSQ((NS䃚p9_ڿ'rQg_3+5ߤ=E & 9FN)")/ER6ɕRҨr΃ˮ7M+1eΊ-aL_%8 y,yS-Y՜XZـM@q;"GOێSYU'Ya"0'R` `y9*6R) ŋKG4 Ze'(7^ȐM*ÌaQ)In0Z#8 _R\z6v=NFh2cXɻ "&{p^oqR>Vc-#u2D־A+gm&g'@x I\#+cOUG$#zD7NxK NUN ҥEcTg[N_v6҅&j AtA2s1́#Of#j$IAnm1;qҏt`0cȸ)Yh Mmpب's 9/IlT0CDv]Kϼj[y7RhkC'ZsP ~>ѷYPv %t]šu+*Ws1ޮ?Z=qu9ϖK)چ*CK@A3Wm͌B2J_o w f+Eʋ;SQQ7*™n7EB% C65z3XA䨷 (BIm#X<1}A6WDWJ?;ۊwZWuܩR2@US~cbՃ[y栊C _.m|9akgnx TxjpBVzTw^^nẌpQwZ.PҐ}n$c0 H&;:)2 gh*I&;)Jy6pL,8,a KߑnRSk?bYHN6s9(ȿT"$桁B75@E$.#\[$!ٜ)̛_S] + 0\'xFdQ?H}~8+9[jO̫idr4~* E"jE. j~M"`R9nj$?#Hd8䶬 y9I7'0ݥc4$-"Yϟ#`88% C߆ytOAB pщd%E7"ܿjIcK4V* K"".>GP3I>O hQ(5 v:j-M*3zֵo"xy06,@Ӽ c8ù#niۖF?H }^ }Ҡ&ópkOY4ډ_2EAyhJ z~ FTi: | E )@_\ h-@s_Q\.(tQ P`2a5Hƫ]l\E6CTh `P5<1.|~nOe@"T(RbDo/Zl,gT3j?jS6'F#SSbAeu A`W~nr %A vDmE{x!5C҉y xaZAs$SE9&(V>n3qK ӠyJҌWΎQÒzʶ"GɍSh6P6 :. $P W2g1n*a[.gek$z8}'%q*Z+a{vЌCN (KRBjH%3Da~sN<M|s4%&6D3 " SgEq kkg%_8M [;}CQ!kGHMLAPI$I1$̀xO˩Nn_!CLj mV881&r#Ot|ߟL!Cyr8pu>\ށ5:eڑdCi8^|_ R ,@$OɌ$?&x+D@52t(BtQa1]kkKPXhFc2xҷ@f‘=q B}}Ij37 xe:,4~@;lM@/SV6H@ 6舠ɁՈ堒£T~y:cP̉Y%}qV7BQCo/бɋF#k-oԎ&wwTD;L F Y̲Qz76KPuA p bʁ9jnd/,]DD fč0#sX.߄,`JJ-ulژ O@,"/B Ŝ2u<;ay2q[>tUg{Hc, HSu`I2x#/a+'h,gen8O|׺K%f.Nsy ݆e\*rq[fl0 ‰m<%-,S8'x!\6e 5lyq!nD%6^)EhENϖ`KU<방II {`/.^ܩZ.S Ԯ`X"^Uj_!6J,fkeF8G]3[G}+w2.do=| 46_տx.CH-hZ E'|)C`/)a8Tr{5Y!jI@z4v?f81T%w& o@z<,g/@WMAv{pd@8B+Z3ZU'=͈:_ 8ߨ/[Nc?O)eम搟6O XIoe8LN eAsXq- {`ۂE0Pf1N gFxRՂdʠ~婑 h y 3>9P-qW:t$0Q ӰӊժZu r _n,paXh 8Nu'ͧs)io6d+1XA PLZ<fqꇖb`??^9{aAq@ Wmsw4QSZJ?l ܊7bG0>{2>5F J4l1wiHdȯ̐sBQDMĉp7IyGHژYͺVF͢kr]ւ"-@I;-,q]vYa U@%N[dTO=I:DѪ6yN}_/ >ޛWpS˃j)fÍ q"lX \Ih.97XL *p#/ZdS~ .gz=*qlM#F*9O9)ЄyXVem5"WOIK4RW]K4QZ&ď]Fd2뗉Zːz<hv0'σCZD'3Ji$dpb` 6;|~ˠc_Ll[B^q8yc۠xj)>zOG]B<8ED)2E=MOnDFJVV Zڥh3=vM#Cjt]*]}LE$NHg0W. v1 >paGf Bv ? B,Ѱea#LDk-rGIR mǹ'۶9M aCl~~}E1iZJw n@.EGHgц_mt.n~ /8ܽ.2.%7!%[삊8]łI#-t @$pKȗN `or\k=dfAz :Ҩ((ctݑTn~^@P' A<25%'%jj2r^߭"~oR"6KJ,# I5.EM̠b\L+_֒'<X3M>"qv9GT6\7H< bkzR;8EҢWRehTAk9Ce5o {ZsDNef~k!/a_]W^1mcGMbStac='٬ \'-(x9^ͺbn!E83N7YT@h=yìIX o/ s}'=^l<I_6D)a,B?Ovة时@s)~:}lc5x|6.`d, qR8gEDM4A xd[1cOv_2/z&t ӌxX9D9Z P39*ވH> YCq М0)HP(O- E1 #G5?FJ9ػY*rږPt2;/i5QZu%k0hiҘW9>[u~jlBּV lFuHO3$hJx)C@o"w]tpۙ yA7tI<0AЫ>`̰@ЗJݠb\2pph!|AySew޵t6gv/\qt?&ݦeTQSm(g6gI~ʂqfEEPL0@שS+a8lOSdj1Ә{^{>AF.Ƞ#`hT[ W׀Aܶ - P[IgP >05cuD€ u<'y"g()B:Jշrqb0#a#`#(?!F'A uVOer d[p"* 2]h`tFa*#gpMiG(kKJ4p5ܲ))"?:#kˤ<p㖨![![qڛf(?2IwCGPq 1[$3FTE^EbiZCMIºiXwL0#mDO.f}ȟsm-xj>"6GkEZFo;y|іN93~Fԭb@{ɂ OxD2^n󜶶h\Y & U.XlYepYij bUϣ=NlT?M ɋp׆ (PaKO>K!lPDFz+~F?C8m18p3Ʋ7n^xhEFfrzbmwvlwQB$S=偋 xTPBЏfb`oK [FiKl^#Mymg~~䪽Hp|s댣Y1'V48#eZm4v> AR1@tΌQ!`2% -9?։@;M1pq?~s ٶ[sy&ߍP% xn 7MťΧ 6T$ qUæ$jk &5?0i?P8+L}aX %-TfM3Hw?<ټ/e2cf"pgf x2\2 } bڢ;c =Pw|SF _M'coYoR~(А^ sHLI6\Znez3k}JZs~)  Qy I'|ƪ'ihÆ>#9XGY($x3'Z'XSM5e' )O[2-Lmx=設o")yeQFA !559' щv KyX#=-l? (RJ5󐥌 b5x|=@7Z.K4Jw-Vx,Lj4 rΐ~\vGZ:=@G .ţȥ+k|uOLQB#K7jh> B2BP)ݡfm*2)/)O%ȉ`l0Ђ"âlw'6cP-9;x2 tiq&بwsM1J %TAf zm:a5[c3}ܝ6!}cG䢬=.G6z݇ `V+M{7Z:Yg QT a`d}(GMMT,· tI h Rl j&C3*CZMbF. KEL,`%rjKE,ƪ"8)VMM&K߈\phE3 HhJb(Tѝ#t PɽA+u`vq#(70ݲMI&z ]ywG$o{ o!5;%,2w»['IF qS]33ߟMS4n @b꒚F`Wpweܨ/_lú㘈4DcZ h\_wX$XՋI^.c,䫱9(<v䮬Z&i{ʪp4 ~rlȋB&z ) 4`ܨybp´Lb{-LWbi m |ʮ:=ڸ6'/g^o-ċ̋zBT'; uSK=PBJbwW=%WWMb%F{bE~I>д3>k D#Ů_?Vc]wJQTKHգ˺>: ʖ,lJq=hEkpqDcļA$yc+mm f;xFU 4%f,vvEZCW!M 0x1X)RᆵpRa\955ۃ.XT\T@^YUqUu5[ (LCNӽvv+б4˟Hc͸DgH֠ߦ:\׍SN{C EVhF= 7G 1\n~&"PP׫8 D>g"7\jD&Mc hO]W;U@D0" >G)e$hQn%"U H-|5 F4;e|K2a.aa~_zRnHz6i>3G2FSXK?ꕖi}Zh0r0,qA$Lo`,3KqσGtJ-FGH5bx&IsG%t\sLʺ ǡnbˠŬ&hf^0UM1֬+3yd,r^Xywۅ Oųr" یӱN\t @H6cqP5T]md.@s c,T-Ї[ơ5|;(gê"$S6eJ  m\d(1_BnD͆*6x-LT20^Km- QcWyr`U\32ݖE |i07#xK!:sTM1쐽^K'{ 6)V9A!)i SXk> `B*4D2f{Wj8q_ ?(Ҙ6q5Ֆ ;ϥ3^Tg6Ef}%UF t-(_ 7&["~8i؎NgcVc9ER8!R!T.աL#^]hfH$SDMmXږME1R//Rjz *&6H}H4&R2~U=׼o•]{\1ʛ샔TV?vJeՌ3p#/,WAVhL8S%NJYX 6t* {h!Uy`E"ceLGB.#m ѝpl)os4.` ǰ 7:PNgnA _G71Xyb ZLy}9f-jelQmFČ/nva!®_I Sb<%pK`KQΔE l^:N6ˆ+Ӆb[F$wNjƗD@y<).IwK+ki-$obg*ս9e2cl|60Yٞy(jNuIk20`+L!FdJo b}W޽+hӞy1sHz@ʋP-<C˶+iؚ~Ԡ$ gyo]y~X!@r[UBHtX\P)3'_mșM0S RyL٧!5q-`u4͢ ȯ~q 5d:%Lnxҷ=?4!:\1_Aqi |Z3aAz Q<*id5Br(+`h!w8a LyesB+<7s}&=,sVְ֜jQ-r[fe];m DTGb"cX{cY=Λ#a/ܭšEU͵uhniRs3ZqKru Q@BKb*Ql_ЍG%7A"Jjv`R¥#WPkB^VSώEn,FeoH}~zJR;iU_[Z4S Oy\xtJޭKzm&›!&>1n;a%s.|bH&u[N>#a™Еhgo]iǿou жwXIac6q#t&ѡ-@q6[E|WI_-Sb)B-f2S *ʤCyaHY*C(==h"S}B_ uf-ƜC E}{˳|*6='3$Aκ=8tto~n*Xw1!-TGƮZx.Y~wt.jm*@:࢙sԚ=[rvS6!At&bVDKETl;zԅ)5=y7k)Ejg K.=A9k4JHę6 5")Mznac {dG4+3BQo)V`$ßAm܄ k%{={S;|G4J5* 1:4Ʀ1mGRx~ Ʃ39d?o7*J9`Cpy/_m[X]?nw[]V=Gd4)>>CjM3(S( 儧xQםԲEa`%>pRtD;n??浹F]&I g :k%~_i}SV~qߟm?& =yŭ#5&>c*Pt`=ɯIW2-z]?wO؈\ BU}80upe by!yZk/2إb69DSr W/wS`lkr.2 C0!P0O~6K@>!er"NuepF1]ľG@oćߥSmEYfKM};S%5gGRt +5iص٣wS~ij.&d*]rUƞF~\˲ Ńr4 7%lBݶhp.1mtJ( VL<,R@7PP>.] eiG ڡ1r/`E * Go)FU7T6 7&$,!,/JӁ;e{ϹkCW͚Xhԏ aQD9FާG<rq%2hQK9F+դĦC! MHW! $v` {QҪ)]K إ(=Ҳ@{*iĬ@> 4X.Yzc'j1C_Q*`d?:A?vhN <\õ"1o63f!eK)▦ @1MEB>Kȥ>6Dd6ǧAs> >DNpxHR{ώ'`6.t0O;xhJq䗚/s|MAE埧 SޙPι-0G&I:HGUk2PM4†> X;mٯnk>`)%%7W8;k@u68xC`E6E5ـ}fizt 8^H6T ˿p<ӽ X(9mMN#)Y[ؒ:?8%U.^52PYtP~j~Nb1[A]}F Oi*b{3AmX@{tT EcK\*`G0Y-#9MfmEaGyX.e%ða'펟2؅o-Iiua d~ ?_c0:z\M`s2E+3ǔ#IpūrwHa?4+J`{L6׳/,,=`&k72 \^X?2ِV@f?%P\e{9(!4U=~l3h300=LB&ip2T&s#}ptFD!yzyj PԍZS>0vizwa|l39!~46c?~aj}1Z[Z^+JZMᐿ H+61hÈ_{XɄ1Xc@s(#&E?a,DnJkY*o䶎TR&B4G( B uuh@16 @ò|G ]b ȄyټzOF/ 9Ud D_V4,B=KNRcwqK-&dzaЀcoSŸz+NKIZ,(i3/M+|\[.55B^'(1pŸ$!pT{s'@tt,j= h }xBMokg0ThZ2?N4PSi4"h+\|kY8r94]LCbʎvKQ=̔R /b08g*/s ?y *p^KEHdi |>9H^*s0@mG@Po!r\$sAk@gm#-,b/iЍ UE\T yjP?@T,An;s" uKzuN ݸ5{,gym64%ׇO3S?}Wsjh2+iwW %M(뱊m"Atq!_4NhPze!aa~hXnL$d:T2 . ,pWbexvOXQ1 ޝzUJf" <W ( ^?es y7W2\GPHY ʪAGv#TVS."[ M}"N)Ch]`@쀮AMp Z!- OW ]}RF8\&^x#ҧ֤.[bK2ٝoBX )1zFޢ)B5]A-~ӫaK:p9?KQOqHHE[2wt. N4k 'WվZ6K{W-I3lqM ~ E-jL|EepJ4{)04ax,W8m 8%A\_Pd E? b OxFx2: swMM_T0DH$ ϗP>** Ҭڋ&PaffAaJ b!r/֫Ʀdt]5iX`p@Mdz=TrzS1(Ѫ'kMG%u/LfziUg\<{Y Iј嬻?ښ,Ba; 1@./K:tEdZMx|>Ő+b#Z9c(X@]E Pa1\4r= di-\$j`'GTvmu]q((!7q:h2H5`neOMr=cssK*ay{J=֎V{q >y9DRDbEE`eAnr'g9tb5v2(<$^^\Qb23jv1w32>Mb xbMۣY\,NMKi_l܄>{ŷR~fu`!D [\eX>@҇ydDKei@W(bSOlixF  VmT*lGߪ1.Ҿ)h(dR;]n,I3J 3gd2S}?=ݕI P%T %w*OYQŎE Pۀw'}(/5@'W~)>)<ɂ2": S)xJӭp̽ trjtD D+@ 67Mr]t6G5Wn(p/y)ASpdE GjpmO6ʥn1hxMː z2ԦB R)2 !AHhOqSqCsxQ^rw͋y\5j+Y 2vU$RhqRptݕd%5ĄfkQ1'ш&?ȷs?muim9Ş\9Z!U,iw̒eI9aDnjvV!ԂAq$I>f/fBdzc^#]*C:&;b,XXvrHǺNLfھeǜ=oUzeIf2xJpq&HKCOI& )" 3"p ] < / 71DZ5N8%^U{͚g=71[[be9Ki ҹa:j4)'+-$mt`-JRF] zlk,G/68"B^9@,"N[O|;LHQ$#y  φ葄*xV &6D( 2s7rPV4d=lҤ4]`jݿ2 )&> &zF|CIxqaiWQSGp:1uOb.i;x\ x8J`|P(Ϩ2qk_ҏ.~Fs9nHMwz~$E M}w?ǨRex0o`+g}1I# hԟ]<:nPXݹ}hW#ak qijN!EXC!̭@̦/n%=m f:u ~* 3&QkI]䵱_bT5ZєCFQ}<0B9(=7o!eȭMO,v0ۥq ,۳}T\XiJ [S<kS0qp@PA<ǻ_" q8NT_v5ȼ$7 8ڹW}~lwO۾vjoP̬Iq #l  Vc 9ԎɍcBG:]D.scTDUwbv9V/`r2 ^'qJ.f}}Q5ז(IY0Ca &rcN0q_boZe.H&S xT,[џ!؜sBDR)%z)2<3#ӽ#XS#0r"bW\:`hΠl|!IS>0暌Yc06#T ې^+\3JyF!;@8?KUċ=WqCDR2&c5{A}3xqKmZ:X/Je-gcj1ËM;A򧁴dh7e>9-Q]LVڕ?k >iO{ӆqΙpq&G+1tsBk}}[e@@?W9@ Djt:AT:$w| Y`<*\uͱ4,ptCg(ॵs/էY 1y=o%b"Dԅtyp{hatj&m5PDbqB\B2 #F_n\]2"/ʅFmZXѾFT 9˲s- ~!O&b+[mUx8a` X@BLyV}O aH :g-&Ck,'%NvÏ+.ʹY &5:Rl{RTB,jM;ZбM[WE \A"L1LJ=kn(BzcOY`PFNܛ0DgƒY qiFAѤ?GA,ЗS0rk)3dw=Ν츋CHJ[;v/R1(TGF)wi<=*{z3$D{G=4?snB /PeYgdȖC4RU/4;9ba?(9Y3ĻIra kEBh^@njR0'?-3-OH)F(r׭o:mN0=hQؔjw~;9>f~07ӎGz XC1&Xm3܏ 8PsA[onwhfq, q6HrA t i!MgIG)C\MGl v!v?8{m1uxzͥZ6"o/=H맰 Y򃷲wY(|$<^A֡62)\۟TJ*D{>(Ϥx>re_&kޣ=$/ Z$6''pdR! v)CsufO wc}i+~Ofجu:]~x RKdXGҵZ_`^Y~ ֻsZ o̳ދUD|T4 [27v%.p_~V8;BYaf IN9%˜ Y/δ/'zQI#0:? Ɲٌ oR+r] djNi{r9~4/Na؄:D")vwejNo0kDaxAëf,4-tձ́Zc9RkS8.VB~նFiOV lg)yaԞ*NET{{kFS;lFq  :'uc'^WqY"_\Əoiv5ݚ߲C}&t4^5DXBoY-a;!h;W1a05d.S9Y1HTC+'F7621f%!LQ дy* d !HE.1_˒GԧMޣqa4VHGi JzlJ,9|U9;Bn9l  J6N4STA[^o}0C[1I|ϗ7(C&ȔDP*+ų[* z`+j>NbHhi lSqUv.8 eB}uُ{~vqWQf .Ey{k\nDݧ'8p5 F'ckrt|29Yus" !Oz\|3'6|Wf zN2"t J7~s츆=izXշ#<މ啜q=|{|vȃzFt5j ve%߯ecn!2 T;GækWGFj!C6/"B2`co3K8wrp:\SQh#n\?_I1# |\%2Wg7삦 %Mt?&ɣ4w4CeR됛szKvm[Rpfbș >J&ӱb JY,*6{ ԑrľ"%7d{$?66]^`!󥢖>%NkŹ"LzWsrU PȪn{5K*9vZv́:P1S&U4zK ݖQy4ՌR;1L Yt0*T6o6:O:W,=GXi-^T"9uC'b E-g^I37RO.IRCΚba8JS%e< [@gP.x; |䑾+t GBSMc{Hu*85jf/S9_[KK5ґ>rsπe ea( ٶJxs86.9/&ximI%Z96r'!@U a%x'%nT5ݕY 9MTlS QkZԿB1X/!S; a uh$'0L}uGNϋN")2A xZSئCL,\*Uŗ͗4<R֕p&U'&߂ƹFh&aQnLEx{p"3:ۛMm"IN6KPY("7)ooV.,. k18טK9oaUdBn$ekׇq+#0sȿ7Te6-i^ql8PP Nd;2As;@7xb;QlcW-cE]? g` J7DZ1[Q֪>cAEm9 =JN9Ԋ%X6Am7{)a(U&#ִr Cz/J\ }q O"{1h8_zT72xB#Q"EQT+ Q𿡺ܨQ ҙJKiߞ2+Z՞Ѵ1#ԧ9Uo!G*\nc,*VB!9fVFߺ=AQ4L>a&mt5h89E0O=zL ükV_W|uʖ,rEnwܸ\dp֠"S-w@H8yU2Nfm!sP;$>?Dmh1).YrPI!˧+/ۭi[9qQΚN[g^S7_cn]ڳrifxUP8v2@qbNW*,L,^u]|l# _X=>i_n֜/)AYBp#A,E2RP68 q `IMZt\lxHDHk{c04Q @NٽO~0PL/{}.O7Hu]s"dNTJH`(&`OKbƛ߄MO0:tF((ѣ"!9,studyrؙ\El[hq1Le{Te*65l 8Yw5"AoR\عH#*hsCJ=~:/R٤d]ldT]wsg߃b>#  SDJ"/GyÆ&P%4\G@-),nSyQ<$9b0PF! &n <]`U# 3>eFPѡGю1f +Y -f^9I09ڝ_5!3z9>㦤BbX 5ye,dh>{WNn@俄u/Tsn bT/ȼjX˖x])tr+h)}"F-9YBEQ_(Y_s8 ql"`*jc[& /n+TAg'm+^zK8z߾=HU;X80I똲S29M& '5º끠\kEo_ cv)q"B< ')xDôI]}׋+7,[sU1PpǷ .qTFr^msٔgr Ys͌1%@aU2/B+〤".gĔRUV7`j |+-Q78QMޠa' M\c1$b\&:•q7,;EIYD3pu`,_PcMAGu(s)@x3?[yi!rm`?ugV E6:-u?^ ͒ա\s4ÇF=9s=EN=Eg,>(#TNI:k 4,b f+ß1 AێiⓗcqZZ^w%C61 ܾ-墕2* |4S'4E"]|k a0HR|[Md<°6IYZ+W5dd xh+a鯙+ `]]X \۳nJ ?Ptu(kSI{J5@H՟NV' Z+ ZbԱ'FXF )CEJTq]xU|EÆothes/lDtlPE*XԾ= -UbbG\c3 TߠpvO[`?A n _c٣؎p>zpU?َ@ԺI8EYZÚ h[B1?Zm?eh(kT,|R66@ܛÀ.Ջ <*xiyk#lMg?d Cдna"Ipcgf{Z<3i-5aU?/У+hM`TU%*d=S=cM5īHoFZ~=*@N D4Ja9Þة21XH HYwiZWc.?/MLS<AB ёf)6iۙO-X$֞iGB32Ts=p7m HB4eR<-2,Dz1H< ?hg8i ͏i9:;'8xbLz J\3 Qb\wGf'?Sg6Jt5\0b 1a'-3_Y>k=IBvnKrf7Z`F\D ,¦ @69_Bs86P,]OGB|4'4-8Пw`)A}r.Ll?[yCT/ Z4=iEV y3!$žQ)Z-;` MF\"δf$%ʤ۩:x*x!ђ1R?ѕ^jtIcId [# vRA|iI( s׵d+VY5 Goc0 o= qL-h^ M;Ql eWND[[{ 1¢rT ƯH5[;W#JI5^%G(~}11A`nT/3G*lrY}J̐;1XF" WIi*Z̲Pg=SUckՉQGză b㡴/K V_) /%.y vpAl8`7R*$`vit<6cuǭ@`5[)CLD cw2EJrE)6\i'e871ƠXse N<`˄,. P &4<Jx jО+ɘ- W;,0YrzUG%S*ZH?P8Ej\^tb#Fkŧj/]uu4O= `~x  E\脂 -Ie2ˀ\$FzNȓ XR6SY)=@6 _?> HJ!V⊏ gRt}(@GlKGE ė uy;F!!hSbqdS]fTbƦ`n`V-Zaq~TD %f,!w"&iy)2YQNU|ˬ4I9Rg(G 8IFlBb /0l/-\%WlhB\L% 1ִz !Atj؎5-,-h X;@h F ]6L23Ӧ`U:VB *$GFO-_C|l=ă@x\2>UP\T`ŲE+$H.uqL=? ڰq)dhM)5a{ZQ21z8vi=j4$GݤeFx~~8x ѥֻ?S^!v:j2d.`)͡TJ#zt9߷ cqs{ہRprƖ|;o\*Gh4yAqLaF}Iɶ"l3Ŵ%B9ұ)vhKGYBd qC~S#=3 #Dֆ,l!ɸy^n`ШS!.rZ phJLJ)7z\1@qTF ΧRN\,,̰,[4o@62v`+3&^{3Hr. <@xװܕ' 1p8{f[ t2D6G4!s!1avO Vsǰ`*Q Fhrlټ~܈m" Bv͎8!pbs.^Tf콼 -sL\i+̠)g4A{CzGTHꇆ2,L`_aȚ^Q?xEopb_oFVI6f|uV<W|#\ôӔh MŕSq v6 (ESLyQzgNJ:bM$2/̂"~]P;53 }2On1DϕKUst݈J7 2 [拏;w_Ag*  wI]^a؍򄃵P[cRqPvXvaL T \fP q82ϺLpHB c/x17w&'}b9}=TA!%ZNjr>6< T;KhvtZp˂taTr\Sײ*ϳf{CWn}ypxĝɠFa2.%q'"6R619~#_3f ۤQ5.3q}6X-7 ,X14ϓqi}=~g5!LI_&5`Z\;zIT;2+"I,jA* 9/6X0ߘ쾪k6-, XTDS<8t:cZ8P֠dTp C jJ#/1JirXy>)\Nv]dtڎuNPp3MTPt@w/j"{{: Yd7k fJ- L/V@s ,S2y3KH#2CHAof|0̯ǩj&%rF~ H d` Q8~z?nz7 ۘ4GIo3 V#yMàWXbP|oCL@~y2yoNys::p DzHRZ-ȖyuFnB-;1NfnAz(=7K]@cϱIwb x38z[:_{0kNyH7!d ;DG!nJ:ly#!lbqv>s,̇ 3鍎)=u#p=觝bQi( s8>7[6’Qit 5 &b0q0bJή,;ZLVN9*.B_Q] -@D6_ %E"Am]9Um_m)|;3&fZ6`b2d~]$Iû9uWLܐp2,&oi5EbݍX+MO9m'^̈}<߻b|Q8]SRqN uZc 4> K+y ~L_ )!}9@i<@ph L,aآα_]qn/E]6TF_QAMT"d@%Qc+aSp T#?=p^TA9܂?d AcQ%U/iȆFk5@b62 B]iȟ.pչ??zޭ~ l~S '3lb lcxY (z!!~EoѓO]I0=ae@&{KӄعOVsw5Ozo% V7Hʬi!QUxh\A0~I 62is=N`q@f!qpS4Wl9~+1j9ߚ˄W OEAC*9w `.GOߒL+gc(3N9"#$1^+#922)L>zkݯ'c x FаR ,<&.T32# >B;2ƻ$=ypGa(k2nf\ɯ擂* HExAiHP:򔧎0 ZdpXA{k=K<_ԫ!↶3ea$0fZW`y8w<SHFX Fa(D]8bA!%y% 4{-(~hzl#LkYk/۫Mh(6(ڥĐZqCjofe9_QRSV/4.cȥ>WA~u*EC8&"zq3>)%3i6*"7 zb{o%Q InR7]F=<Kx́\/:5ꚡ ?O&8 P󽡗6 Y.(<@g j:'>O Aw*| јtLNVFbߪ6ck}.D6W֜y\8d?Ż Uw4W$gB9$J )%RyrxNL:ܔ0r޹5l}<e*<3zj3NH1M:\He~3$;<(#J_7SeK5;v28H#*pxYDJWKiTeF!Kuz8m80Gua LOz M]U/6 sƑ|8 <,®G ܱҵmDƔ`H)k>푟IVCw?k?vBdۿQ7OMX@l>ۈZU4q7r$6gI5*z r.`K0"1Q&6;5K%A̸s8v8^pڲ1.Abb4'%Cfd'O^ ,BuPg&b5/ơ U_Yхq03i_Su}^wTrô"O2 < ?w<W`l &É,IOq Joʐ[ Oj]]wz'4{S5YfO8R-Gn7848A%s?ˁ-Ǔ'ad-א^1Pw!7E0Hx6D 7BÑcj\8ц /D< 1"3$KKs{lϧw5U +5]a"""T—:Hwv_iJ :Tז3:Bla~1T]d TXRvAvfE|-y $ [ka}ЄA+Jy5̺frHZ5S4,ʰbFor< ωЁb[%lگѼ͊@ ]쉭TOMUMgOeu˻Nν"@4i8>tr _@,jO;)&Lѳ^x~((LIm֟FN5 [ !@:4^rpkB LFmU!Ӭ-w3Oniñ^+F]4c TszvUR`0 G@\] L@W-:V&"G_m<ڞ_:7$Zr po0/qe݂JѸn%V2o‰QVkzOG)5z3EpƳy}8s [fk'鎓Kq؈0Ч!',l-V < #8,vmɞג/Nq!\~-V]PJ["M نa1JmZȸؿa~~8JUkT@I].F)p(@S(mb>;#.x>rI,P$ԤW>Yd;lb#ePDGhFhkyLrx@fvpBQ=yUĀ*d]K>.Ʈ&oyZ`zB\j#tj;GLea=#<K9 '0nPQ( } y7EjM ~deV6Ց [Ni) G,s5[Nk;scݫZ-PV8v<^~t}&m܋ 6|ؚNl;"(no䤀eFvfSQJQ F8L qJ1Diݫ|<>LUI*ڞ9{Uo#8%)c~ _'ێdb [U:fɉqph ƣE;]⸶CXSFx(>BҡH`~_?i)=/3;u2z)fy$Ms΅;AthlɡCc{\5S9dvN{:qt"%oNQX*^Af-ʋ=v{s߳03)L.sɍTE(At'HC1,!$fE?p9{ Y(*Jh/<)6ш K4 &τeuwk , |"+)rҵDU B^n!AZžH2MRpB嘔~TWIfMt^WҳٜNKz'̜\e(:ռ4*4f)Aڰ0#$,E;25 sum W{`UOE~6XYpMc+Н ̽\=rLi?0&Օ: ZRߨ`Kyeî~HٳAJl˽Iny%i|QVgqڱ ^Q )럖~QVLx/8"Ca(:]'~}yF[BUv5pƶ 3TZ. ̐~]'u ׫si}k@j\2? hRhͦƌi4^ʰ)_؆HCi%1:R8n vu-E_&X&bAL qa3FttXu Ш[ռ2w5n6dRLBB NJ)~E"G4U<8f^=%;[z~0EFkyAWUO %ڢ|K1N "TE -~L]v̩OoU /:]M ~ވ2!1傭?<:Fۍʧ⁼Ӥ僲A &Q?GPͰ 8<}Tq2||GYTIKP`N Bx:'/'p[R}/$ i/wM@x#V==J ܨ 7z`e ڼʘ/hEfLo4.:$-M{4\NC9َ|ې=SJIDxPxg B,qnr,L< )^.@#z 0;g;'Jy"a2YK'q%>7рl t$v$w;g2DV5ͭKAYV4:ۋz#jir, /s:)QBQq Ԑ񇪒{-#H}JAr,YN.>ΨG3O9Q$hP}tW#u#IĖtoAe9|j7h!fL,ǀPO'U*}4 mw(Vn8I:qxC )!vH Y:ŜEU , D`r/{1S .>xBDTX6Hzq4(v7S EM4Py6(3GÐD g3։ʫ[o< ez$@E# SRjasb8H:L3&Lm}h &2 ALzns:_OΟ8R/CF}܀Cx*t}B( Hrкkœ ?bX({+ 36Im7];"z&IdlXs$ WXL\#)]VF0t{QZ АQךH!130a#3.F2%2:49YY#01NiO/IQ_~eF"B%@:|Nn~ gE\V"u/Qe6rQ_a3xzba!KJU[צhl Լ#c$ToK 02IfkhMOFSI&+)Sٖ3\ :d7~ &qGC $"iMoi;V1񥮲 3W7Q-/9(ݩQ'hi7 `0Ddî LCpofqf#2'Z#x3~n K7 Yh-cmâ_0S4eViipf*d3't>P`' `pHS?FDo,RtzJKN5c8X5i..`>ڕ,-% ObxB)"sG!`!)4pfjG{VxA!UC Uay (_~`Cb#6D SgKdVKɒ%< B,lUB`(,T*BɪQi6}cҌec XuZs# wp8&m'8cLz9=T~ a%cxkk߿%9;;g-7*͠P)T>0h4VoM=vu*<)(K0ؑ=*T%؇îQ }>GCi8\Bkצ sfxf3c^M4| C|sO_TvUp*'^irY]Q# bG ˄t}b.+H@[fpÕ=SsXe4DmO2e\ܶ]+swuͨޗ)j9NN4_/%) oM 6""&Jy*R7E=X2>=Z@$3U7 ~! DuOJd5idѾlC6Pjp=f{QtT<:-,R%CŸ5iWkÜd&3 E냔e7}$YX Z Z^ xyyI]XKJzEG"Sc@-i/VH G;YPoAŒxyheJJbCSREt[*ٌ͂ ?; ~MB5:0w_TÊz_/$G KT!ya`CHĄCׅqH_ˊ Ew~s%7JVegcצR33rLaR]jw\սTy,# 5ZRӹAՊfm[B2h)v;lm i-)NxuDroUaX㗇4PRa6Xhfuϸ_XˆrG HLnbUYA-tyX5"H _Ȱxj7I6_-$DĹ>0\_XoJ ^9Y BxMS:>RlqU Q:J\+Lq\kcS"8!ʻ52pw4pQX$Y")ZW/ovwʔēHcfo$q@0#RӠ0dScz̪8.!N0QmoJ04"*nbTE Ζ7E^zk 3=OE&BM9hTMy)с~;2BҗT fJNZ w|3ڭF)=6>kuD:)"ȖVCIc!b^Oi5XIٜ̜֚b`(zAA$5P9 _Ty[jZp0 J#]ڶJZ:nYQ=pPRkrL$@t{ٙ':4IXGA`ht4J(AнBlb tV0k 6*NS஝n5:I×e"6è4/8LuPSEA5PEը!8H0|1 ؋9Ibr=l k!l4%N4tA3y 行0 D\bj4qf{0_(h15 X+O"DpumW.I i{0wc A48NRq:W`GSuW7Q 8SDEDlȐڴ,pKvjkrU#8N4R/hQ{bi> !>oNlE:;06L1VHyš&[1/,Y0ٱdu[XY4 ЃR$%se[(eDIB'bp:2q"6aEJ@_y5&CMtT@?JX `QQ=+`~IX{OpnY湬Jv:"!pF(PP@hK+5~$LyOٮI"am7`ȏE=~M=-\67ToF~E|Ѥ5>7?$ҪYpn'@Xbw \*_Lt'¥ \pgl79(gʃ@OviXĩA/Ҝ*N##e (?DZն6hT&!|K{Ǒ C##Fs$ю^~f GjC;_ۼre* Ҧ@K\R>l!{UXac5y<}Vr 9(9vɚ&@ 幚ajSWL fa+tzyqi' 6D &`IGU~oRy'ޔ^,p2'V ө[̅/1g%3y\8;)3M)rW}اCvl?8ۉgV}otpϷByN8^Mё]J 5;ەKZB="g'l}ܯF{`%),%UOVQ{j)}V3*?VI'%!ėP|yw8stMQ IYQp•tRAvSa^#EnJcDK񇾅j.vU|'; 28Uo9z5^8]'Y4lYΐ m"jt]E{<Yǃ3RaxL/0.Ql{瘌ay0^Kղi f4S0lWiO3cIJM3@`OBRd&Ƞg"`Jo9 _ (v[ QBAηL=ҵ !=2"zؗk+&(J0ڦ0YpP7BqDI3f׹qOI"!gFi- ``ڱKԱP> Uaj>Sg\2ÑH՜9e8Oh\?9axY_?9dft#` #b]T2N{75< 0тAW^i[~  @̇Ʒr;<(7TgEIƯ,^t_9G)܅r"Jf3V׿cl `9j쎊PE=JnO型kR^V?j 4?떬yo5c|_d;HàgG=e9Y2$Y(UظO=τ}Բ>77u[ed 9xG'`ONlՊ~ v;d񽒭G(y .s+ֵC0\:q ?=y$5j& QldG$JRF(_ S/.JҨ\qfS|XTm?Cex4,9-͕1.!tv-ymf"%cHR7c*fg&P?n[}t@ݣ~@IDAT1xД3yL,9"ut91D%~¡JϴQ7fd,)f<#A2t 2hT/` 9=.IAV5"n7U~:HF1F[ h ;S~a‹|q@ɀ\(SJrnI +F9̻fK95,w"o?'n,t `Eιj? !Sh3{]O2߳b!;y7/C= >#`vPWf )}o s)5L оyXYZapX,/AS›$!jGV6fdt>#$|,zQD`!T|ovHL> ϓC toLN-h G#&zu P( j"}S}XEln-`nd<2IG,!/61Cr9[1< tyӂ&zS.Z4FSchpI{b$T.mzsNp M7n&K)NӐNy=9=*xlٔT-g)03$rՔ-|k 3 Ysc31[(*TS+Lyr~^ڃBĊPC"qhJD۴0^ ^(w#03F(\)Eа},ll1pck' ;hz>6BtpB i,u'AgcMS r^w_RqZjg8+%wO4e؜_Aj:H$So[_\c2*`ܞ Jd έ( 'HѤD/H('tɃ(s3zP4NBl76zSjS'1h* {2vbS CAZo€$JC+ GQj9H4H5*m@O$ƫy kS|xF6LzDgHv'@c)]Me嗸cTn 9|s{AcQO$3Q/ҵτ#/o*읰.?ߕu9ǃͽBw6!t=вCjTߤ >.t ]jH#Ф`qҴ<Ljh2!,PS|mj{niVy T;Uz `B-e@܍_!$ŋ-H2V'Q'G:_=N{HFHX*JUnKL⟟_R%"MOe$>s_UQY9:&$9)c9&P+n. vSYv=$YSW3¸0_<5z#0$>"8Cv;)s!<=L7Y;SH>6 :{Y==쇊*p?"cCG%1kbԎ*F P#"FUvQ-+tsl9cc)ynjimи8aJ^%i@QI\)%jIc[yIʥpv #ZMbwS}n*B->faEk -'BlWڣP[;SQl"Pc~_q dae5#,dOce>Yd31|i6&A@\oJl}]fz8q82Jdj~Od[L$bq@F\7?NUTYzAlTOp2POp?e'/~%iQq(޵=K9$=Iwq# Pk!NԪz9Cn ݉^a8MX_("r8gip :c |սj' nЯ&44ea} G G›a1W> B֠+S!jd Q $1|TnsSXXrf#fL5 fߌ3^ G5' 5|e].0z]-2`c}HH>E1EF(> !ހjk ]e;gap #}@ʱpRΠlP=jinluqyz2vj.IRp%`) W*ɳʕ*Ճf\z$-ssJ0$y=V2E\(j54ka 7HwlrXwTuwYs '5 xiVv'!tV/\ہjr7J,夢-0ou,C`,/JJMNNb | :ic[j;l8<^cc/]R08,g4,{)T vE%_ʀjC=(~tX3iWj8=$b+טX#K?D  ]FɻuaEFEB\Սٙ߃/ȢE89$cY)NtTUP#58qO䀋`HFẛQ4Sn (P;LĹO,Q؏WN`*ƙ4nE 0LлB1zS4&&~FE|N ۗ*4wXJ6M,Oj0VɰP` @,6~"e<1Zăyb> 2'D\@- `H0M|8@j\G#h@ ֠.+riJacaVAhs2-_47OSn~TmG7-NL?j[@BfA`#'iU 53'*>Yz6^-ӵLD/Gp\r&% zfz|OHOwtʞ  ?GkG3| K_SDa|@0ǵбuTOG b"pG3x %c ^d˿0z$߶6 fdf@2B Պ AֳdB͜D/4JIlO7Dعj,[.2U +ϔꎐm7}WVO].5C& )H2ÿu7A21.h1q 1DmE1)8ݩ@U"/Z}MkT cb cq `Z" =?0pܬ#Bŵb%MbPz}_ ۰PYEV[?/VOD- J"IQ +͈!4XȪP-(8m9+3ԏG? 2ɝGlHbdD+<\JX._1%r9GzK>߀ХhRl@bc\覚*9|0#_2@}Jt2A0pJBS,A`"lL+ +38^\EF"#S1iNWSbx }ҭC%6z_u01KE=P oV5L'ģp#HLPCL6\ARh~0Jx|BXUAd(](Qg3ȘV) ;6~>[rKύVj$3 aZdRN_P8L]\p(\d=gS먳,p ^$cM>ssw FY0g:'\;Ϛ8np_.+pPWĩ'LM !OCd_W>Z[Vö~wzũ|8 d9]@?L"C QQ)F\DU+ BDpcXN"*~tZ"aKL p̨p_-DB^#wUߎʘYm20u=c|O֒aWcz% ).=i&9jI6UKn,2P:TeHk nju诖?sqJ."glu'`|߾ %& ~SRsƓpz3&=D6w Djıib Kz:B@bį8gn] q}>"+ZxH`wƱWpRtAsH$-Ů"6! p qpE{~/5M̫V^`z& N 惿Fd:UQs}~ȹVg}M fa1;f1~by.BAHlFD (AsInOgӵbdӷ 3QI/0hZ r ivQNo TǪgaK 6eܫ&ׯsmp97Sэ@ņR+'5%nkn0ưFԾ)LAK"TS;F97fY}FxjMM/v8T2}M 3Zj8JU92lTGr;e<BDT7Np‡HWq4=<-*Q؋͘IQ`H]s σuvʵ O+gGc_p,|Ec9_|%jfMPc&u2 1H^k}NއUQ0j\ zL(q%%p+M c"pngZϽq]0}9ߢ[m?{u+Q,}'y)1/:Sɯ۵Ok"L!TmN 8oq="#%*h{vvn/~ ϼ"Ͱ|)a(~oϡ8Z1@yR4'hBa~g~͓h:1ܼk5 GP*ɭqnE@&/H&t>QZ`FdEY[%6#߶Bi0𘧨xJjoKCDLP\S?65nVdavM gvt@ay]^N#2 m)k6`[iqXJmW68 9{krzlϧc:XRY_REQޔwݏ?_RvF<2)Cvo⻒JئL E\iƴn Ҕܸ3X;>~}- @$r8|K@\q6=1*J[$%Hv+2@y{Psp_ȔJn&_A k%u(c{6T%p Y9L^u;yzqAawto:ӀUy~ӧ>Vq_tGrnHſHGι1ՄI$jGzOn:<,>N*$V-JL,#v`{㐓l퉡'btjb+Nߜ UvV63Ctwٿq_xajSyIjj|Au)툵C XUr4HVEzgЎJ쭌a`Z9<_NYO:9jm>`b\O.#3׆6\*P/g* }}ۓlçOVش~xI% ׶qtǬf^ҏ HÈX0iM,0cX".)5=b tQs0U7`d`z-ivE,''d`tN4TqxmHr&`A9*L cƺݜ StϜyj^r& <7h:J|o^xUgX LN0Hj0qDezBkT.QJo` "sJI+Rˁ.Fm˝:6U x<=dE 6K9% OYspt87 ߻#*bA4SCLϥa13N+FSZr hw8p2K,`(P:L.KބOgF9R{XUK%./V6?-jfĬHέWqc("]=.8Hb#T"W-j a" Գڬ2kݻ# dw_/m~rZ / ?ɖc>!F28O{$7\@AvӚtyeF'ۖu=d*L6l\`K'o`t1Glc ) 3 dAmгfZ428Y-WCY8&E 2M751*ovg ybɛ M,#\eq݆VYӨNBVP@Y*07&MejoWl'X 3V:v ,\i @9>%M9u alLI qawR-548,{SXo_7$Wg ӐU;{ Nh;Zziذ~ 2ptn,e 0<,yTՈGs\3O͇cyz&&˘$ izg٫@chm`̵ŝ;γg8Ҍ0kApkf=AMHeҮ=-(Juȴ_G蝻QfH5)1üxa.LrB”J5WA _|ev$"d!#H!$l o LciK'm-'Uy:kJ^у? 6lꡇ_VUO%మar4~A,+Rl̜$ED/Ć93!AznP#rJ#*ǭ L/EK€sW`3~Iu8:vq [ (  aB`I>@B78[~j:T2c rFIN;A~V%0L㐲R2qUO,gY`'#Ԣb=d`C':e&`C!/ImQC<%X8Y*nTkQK\[p;u}sH 2sEQHk-I6cks`h)XepD! hFc7Őo>'q}}.diJ: $NɊŧ\t 4`lDMpE,Θ#x5M0uTg(̈/pjz _f"ONk!\,:Vڤvmmwf\.8mZT6 t$m O]1^~*#; &=((rJ#sxs1R\ƼhƢ "Vn[?R5LW!y-UH?L*Dl(2A5N`#c>,pʈ F+<%}vg: Lټ(b`n)VF0qɬ\(sg4xIYb&_SBk8x$22w[Vݟkl(e[BsZ[*#'Z;3zA< 1ǙHJ5B85rФxeQȌ1w1Fu@O8K?i˦ 9g2І$ +! M5 `Bf3j? |% Ŭ5W h:}&gCqBFi=LP=-6E{]h3/j½1}hdgYBff-Q fbQzRnoй#|bz'Vn?}~o Ev!AT?LA쪠[K .[#쏖ЙHNv2x/X ,Xr>Y]i;>C Jp$ 0FTЖΒ`Lf6t4|9Itdv!yOxڃÙ cD]p,yQf.B[6oKbme|GJ-p ,i8 / 0ݲPODW?Sb&(G}Mr:ыEH22w}Tg3~"_c=.4 }Τ:*@ id&^Ie}T_H#$ \)DsP/A" 9#$:$ul1 y"  TVa΅P=A鑸"!Z0q%z\ F?e*1'~" t_ d *w޹C)Br5U8\WU38b)vBQIUN6yM^6-Uuz\dsPĬ@X]V`mթH>Z^u_As:ɅY4Xg\yTH e H;ITPA p7Mon: ^萐K$ILshHkY?hk`^M;{R (\ʼnJGւգ =n)$$g&4KocIy\/~weo`wcu,Ol;t FpJ+[9>bE HFi M 긭mm'γ0!I6XSwE1+8`;Ǩa= :g#?wĎ\̯/ZA?\dmMB " - cr) :Kٍ"Gs1UH5x~Ī9|܃ 5N'5Nn%\3#bTeAǭRzzuOE/;ч)l*q6Υ(tr咐'Pp kp>; oA3 k9ʆaIl?h bĖ,(,YUQx#~WɁ碯\񻢟x\yt[^Y9|EU㐴8Lj=g^HycI"3 #褈nO>̛gۦ$6Hη[CxTk=JRq>1E# xBer95ƶ`E{ȧKy &lUI! \\xWqPtDŽ_(=x}E`1_*}xCK^Byg`4+o;@8>ZoK FeH|%-x*Vz.AU?v;&ZiTb`07 _?\j"c=űKmȵy0 KNjvK"8`"5Pݿe׺U|G#K]Z<]DRyܦU]A9cE*D;+i+uPr#XUҍ6|16|j{c9)-09 'h [4I|Rf>(͡~¬DYhz+|\GM*43euK~ѯ?|􊇦衞.u<+4KCۨ@$o9JVt`\qUc" !F(5{v1{gmM,I Ӵ]+vҢe4et+:{ +QWu9t#O53KHMF R #(VRtPy8h@neshb F,^42+CAiC~8T٦XBn"`$Ou#|ý0w&M/7EweL?͐`h XG7OK^1ΓdkPF#(lk"lfi/]=?:-zhnEW1S"έ`NTtxzuj>NlթB_$g\ic?[ ;DFd 5&j舧n[M Kփn`@@o 9:ACجpa"HZ8C#P*Pu 4JW SFcDq3G1=_R1xџuhj % zlX\7bЄ0 z7v2I\rBiá4R8_KX]G'Pb6=b0*1Nc ClAɝY>YW@0MKqtKٔ;piX?p(r݅ NOl0Kě憗M:SDB;$Eu2F!Kuq$~.9 "OO,rI 7%f5:0>%ER^ه,L[Ӊ#D&Z6ծ)͡3RiTa@@oWϗ żA6?Muq0,U [{+K>S!F;g  9 bp6={xL}{:\zH1tD~⧘۹(//l􀰧5)4]~jcЕ*i*f62F#צTG$8Js0GYX|PJ60VGdBZ<1Z2,RΝRA3 `1Gp]9,vr{::66+&'{Y>4j)xV΁mvyz¡\'";!o¢' ﲏboaz 'e=)il"-/1(aSm6= B5#i`{ !;>S9+UoҮR~au-,8Q/ڳ]. JN!6&}uh0H "05a3ĉH.7j}BDCkk7t3ik_'M^ d.A]E;r<"˛bo e"N%d_ObF=E pw$ W*u:w@MlAX_ſ@ƬJj&7,O^is3w/4&vս=RMF|rX٨Ny輌 |vowoX1#RNNOoq3iN -9F1sM5__'p'w*Z3~]~<Οg'w^ΟCl ]E~8$ۗ-ki8<ؗOiHM~OI׿HelY*v )Pn@zr|d6C:=dJ@IDATDIo )zK)&wt]m2|sY&eW.UpXrr By<+x>نs1ÀB Jx/6bFlbG2ry2e7֣_LEBX6^@Pq{j6I_%M+d5$t(ӉE9G|9,*ؓ˴Aif` x#+E$Lkȱʃr_i %7 i߬bb.g@ )|qTZT!3 63/Vq4Ny1fo9LKp8]^E;GGc$ZM[,AmR0q}n߹ОD#Ȼ)M -+Glbs1Y؄z Iy_7`H} Vyg4 k+MdvP8;X>yP_*Hg;dj epJ!sJ14Dov ܪ•}8_#+Z2v_삐ԩ9;/u `-ȷZ;?p6Ƈ۳,,]=\>|{۟=aR)/,^F"ؠ,^>)܈.uw6'ơ8 ڝb%LDu#|2! >ex?]Tt~ Cn(vKYu#uצtfuF%AcZ 'W'֏oN/"/J?,$uȺ&Ǐi ]yK'~7?P'Zsž-AZLej]f8~ !J)/mQgt0[˳JYxmr`Vy{wu@[6-, bMu5}rK5%<RadTK?~m`i`NNҍ Kγ wSdhn p,7Nj㒌y>=eDE~-1)r2C cЊ^XCF XBUJ-g"4?[ !٬˩5WgcX; 3} r}>lgcE^*O㭪?op(1q/.Ҵ UNa*# ZoUHn):$˿g>O$Bx4aÇLgVP{3;H#[v\VG[pۖIčn-x+d!q!t*Ś<(vq;1`\V7qG?W I\`$%\r9)fXm>897)S|= X.o"{m.LmOGHc m~JmOM#f)Ecy[ Y~ٖEǀ2rHD#ynf%86+IM3N=I綼jI^'B],m .%׋ Jv<#`KX>?$bS{Rʭrmɰ+U6S uS3iF*[/vsQkCG\$HT7bb~b ZT|WA"Q/Q[s'-d14G;\ꯋ ި Ԏ.A` Fd:Uq<גPaQ*rJll*`i˂ut` IVbnBډ^PY`$ 3m,J>+$~VMic]`yc3g:xuȅ* *>D'2+-68PeC?pFOGecФjk5|{ `4E,3_",&9r2\q2*^/\M0uDXjfMTpK }=IQG!'?A/7Vj} s c+0P܍ Vb0=*4+ sPfUBD֞4ꃩ} [@ǎֽq#lS!:j18 ͏ZFmZ 7b& O`<>:Rj鵤;@R7)cA}0[}Ր~h`$*_^P4"SD]ƫyXak%,E\80svbdFLt6KRxtzK#%Uj@-H驒]I叡w<^;}z9t "3\uYc>0MXfEm+2kg7^8Roܰ^96aצ|a,Œ)8l{$N'I|R{zzQdu}$1ep*`IDpy6uww )I/͘j F3*u z6AW7>L%(@ r $ǁEY E5+ U!hHix :h25x"oš]3QС54Vjȧ874P_W>n頾u2X,h @4}?AޟP*섪F$?3a_y8Fo)D15`MkuTH1n$%.) O@%Y00wNT4̊1&˕Q\ϟV 2qbX`>[F5dl=dlH!1$ppEP\UOZr+"/{#cliLuAxuݔ`=!R%e4/ xtmmCn|xL]TVN}5O$D'vx^S +nGu4shotܘ7G9y@be-lVQfby3uC;B16-r8r̍&frJs mn,=0vN7Uu脅k 9NrO u0͛ՃBƂ#9l^`Fɱ)h6Ђz]K4 䰓%!^6 :NrZݫEWMo.D?Rx 2  v aJJC1n\-0)tgi[Fb7*P l@m9Be:zz|RZ8[|J՞ iU?O`?R0Xi@(<~pY+O$F6s3agfȋ/(>wZYAỴW8MX5tlى7+@?*Yy D@rGG'W0R~ǫڐ%VDcogz|#)N{K{./K8j^âՙ&ma޲kLE&8XOFՏYyH@6q-., Jkx(B@Jޜ?7S9zjr |  ^Dm⣏a eYT~B_MG=x{56BoyIp=R][@>!V.oЀ!< F  3zп9EԦy.41W]QY%(pv'"'R-tR VI~nHZ`2c4("pbqDD?}~,b"5wz/.\߬#Lrx9TΫMQU5M˘9X9qTċag D cD j1µt5oGhC\9YPaԫ%?`:XLJ]/i1lr "0  g倡&~z/,`Ɣf1czL-+e#e9/Gpݰ(MLo?8>~I 2mRweG+ҹer/E5aRg/E)AId uS׉Y|RIEPD6%RF˭%j+Y$S;-ÉqJ1j#gRtLݲ #Xz1J\fJ\@%~=(L-Us#t=[ >%Gm#KOGI3%]!{(5I@ZJ* $RuS@`z(ɓЛewteY .S^Z LQ1fzH y5}.U זq?[σ6JvHrdNBn0mM!2K!>Rw'Fg"$( Ҁ;=?;F@Y?0TUg$&rwϒ̲EfGs@ kW)RBGV/nua*;TcB՜bfSu8XZܦeqrie*[u責q!;I0ر2KbqR0&XZ)߯Ht#莒<Hr=N/|_ fK|C eޔ`T 0[sa|47 (swIK"ݜ_* &R63V]U/^ezH ITl\VBmc>F9⹔%DCP[]SIM8R.+kڻNcIf-EZ ^m%/M(mQFJ˜m/ɩRؘH d5u 8r{FEwIE!Uy;_s{$r[ZN|˞PтVWBrWʸ%*sf sp>(QHxvZ}]]`E(/sE1q_z"\65uJy7:j;Б )5"V–v}}r^wDR&P3k4:% 9?`Y'"slډxMvu㙌" &C[c:}"(^|<=K{'S>3.@CH5qC 0@sGQ?ZVD5|v|fZi4//Om5h1` (Ѭf 1\8H7E[K=s aQ9&7f⟺)/HFbʦ勘Zj|OIQE^,5p%Lqùl~mzqR=nV$w~W |)|sgbGsdzuJLIm_LN:AρE2j}=1 x߸0']*nmZj&}08oC\=k-ŮÒi䡣hAF2\v! \펔0lWB]'- tkpsXbitI, R! CK,q(Kʅ&㤿~+TCaa<{OCΑ\@ĭ ҒHd%`iIƈh0MQѱB1-8:]0ճ:Oղg5B,[!V}(+JjPSKܗYahZC:S}*v@7O/g~TႠ$#,Z˒Ŕf 0M0dɿ .Tܪ Pu[ t P<)}TLOC qP2ҥ0A$a2k^W|X$PC$C>os;%.Lگ>Itޮ skI5;M+)$-K()neqjEU^[ah4Ii!rh$(IA¬jbs&ߺ"0T:[u{@oxau'rPF,c8E6N"y g|cQ띲.&?9ѐD0SK-pȅh3Dx%T[[`|op%SG|BQm%z0yD+]hI٣W>`L+ry\EAqb  rTծ*y~e$m͠oSN9Xƾ +7bgan %|H}$Puq>xzQK^Aѯy6b-C(tp{ͽ7 „33OX"x!.n!ƹx(~od}h NF=K8Ijg!J!E9-8ymK"(\GvVc 9ŻiyKK'IJ!2BOkpnV G*+E {R%ʄr nut|E;2mnd$\Lotz{anm g9 kϪM.@:A p.\ee#"_NUmXfbZ RVg.C5JgfE[K !qzs憐V[;AY/o}pQ7H} ?ç+IrHmyl_&x®L":a987*EA$3bѻ%iнgYC:9~YaOA$C)ۮn:;Rʠ;0%rqw)JYJ,!:86J:Pr5.m`>]-؟tsZ'HF9&>-pwE>9*N>'?% Q (Y yk`ݮ2$Z=j^d+qA\[NV;+, HDyV}U/.dAJ>޳@C?2y~O?*]6z;3 >un}J*tcDzVHKjzX><(CqRn8J"1D [9D,ObO}jLL/yz}kyup[eƾvKޏם#ϭiGR&O4 (h8֭ E_}`(! \Kl a (ᅓԦ\t}ƫٲCu*;L7>\Z]"_8Q~Y~.^v 8O*lhv؂G[o%.l߼mziRTy۪3[^ooc;_0UL}Y(we[/O{ ѹ]]IOFx8A@aД?~Yÿ-ʥk_e(DĞi* ɠ:YV֟{BisS |''B^b~*>.^oy?m1'bTklS\9P٘\)Z@5bfIGy 2O׃WA /=Sʓ3KzZ= Ȗ=9m ~*%DHajcy=]B KZt.7mI#c / YSx/ҡB#SŚȏ FY'.p$B^b@Quh  ͼg?_yˣʹ浺j)n`/ԌB?u>K qA:^ i*r!W Bk1cWR2q~S\;۝v,N=䗯DWLGD{LFь^O򽟓!o []y5#:!c T]LV?v:o%U >9Xj~0Y>e8čE:?ZIn_JDRd׬ ^WP7jl;7"]EUӻ"ͦOPdF5A~j֥'N"Ԩ_srd£G^Sȟ$Io=PT<=[^XzLXahz"u Z@Q&"kKh*S,lp! e1*h#K(+Iꃳ4zyql+AmQ~L|=[r_:}&i crOPP;|Z1qЃ8tøhLVٽCi v<|~oNIeJz=4 $Ğf)͛$: n s`Lr rN)>wՌBwH˱%9<y&M@q~28U>09Zx{aCW9-y2RIcF H_1ۗqpy"j-Y>"~%iQI 6旱jn"T<Bw5!w(,x.ZkW?Q'. ,h Y4V BF1e 2h--${Fс\/7b ",ƣP:)c8>||vB.rAzT\;a,Mts4^60j33aB\,/C]qg3"a'T«1Ⱥs@֐Jj`ef_U 6SIdS:1dvB+tCդH[>K(bA+%(YE*% \$B\ {Qm<ື+a*/83?+̰Q#&U¡P* .|7DT8'I$,:Rr0oU "ٕ'> 0VgUKY&>V|BdK_6ٛ<Hg ,F0ÃMTHq|Lb[K3Az{@9rTN/b4援!wG4DBddw"ռk1C5J-^Y:K `&A[6 H[>c\: C)D$Y  aa@q42ЏBJ1NcR$ͫB]Ĭvsg?.ʃEd/c41pNg꣏7zKSǓԋ0cUp [-aљ!jf㈍OXoiE%HfLP:eHя@Mվ<74GNv5TShaL)IX_*>oNdB5$>FSttϜ.ɹR[q<^E}‘z#Mً`#FFZ,"î=H3JzO怺 "~EB8nbҷQNtqSb3,az4.uVS%9r1Džp՗<_69o?:j v^$04EZH#bc(%f7#ΡHּè p=J%H /_f)r`_FξJZc'&5L .ː)l ٘i$rSTKUiPH~f*=DD y3F>P[1J0i)C顑8䁵%طӡL9+i?y7y[N!Zv:^P:4?z 5Aӷ!Se,9JPZhwF9 :PT=L<"o1ܥ ]7ݢ/i 9'Al#KL6!Eu&8kjoM΅=̔hIPu % 1Cp\^Djkn]U\Ptnј9 ?!&wO؟'M%]69(^\/Ye*b`d6OlI+}҇o8/ɓo/eP1QBV ZmD"" kk<<TGXH p!o˹wajRg9:"hGyf8K2=nux&D^ꃈFt,1:WhQ/u7;P+ "\g+>uU+Q1^~MqlxK@(|uq'eW숽6* u}܁.ann ե//})[ZqjђW׬ iXA Asoc-= ƅVG/1-9tPلe|dr5Dxoe2 nnNϗ m VJX AYDc%YL:2KJN[U)ns$uduM,05h=DniTAÇJRj=l ^Bt b 5~F#҇@f*${;aY# E'M >tCI1-/?Z2 dg@Ch)Ӝ)U R2 LGmjAG א?*7o_-?/8rvI$cɮ:ٛ_4}I3(gȘF =vVd I@>Ղ~`M9 Ei:E.2(A&ըl,=C]aL`f ZČHms8X鋂3J K m(9ahz.B_~c&=ǫtA<_S>b-cX=S2b-l(`̚y%3 §6(PY}]0#gkZ3$'t|N`YPAFFo{?/= eqB]E8˗E˿zQ_yke"3e<Ŏ:Xy#vp!m ?)[.* 3˔3a%8*>I1;4(3`mub&=sA#{*48$ dTJg~]aexz X;u㳩!>)[ӱwLZ܄2dl ^Z+-rG~K ͓9dzS:.rOК˿aȒ1H~e [*]\C+I8r$ gZ[_;hO{|5Xlz&C@IDAT/=}q8NuH­1FϓPِLQ%omC>Е %:AS" *U(Y͚%Ȟ'jGzrHv; V;@ߔJJGPLv%70_>r`1ӜBX O hK- '8Zk{k-H-C\~XuR?{,Ui'-o/@MVt*R783Tތz 7/pbš9)iQl f a`Kd[ޔ`Qgx4 `ȦZ7}w Xdu;F=w3jB" A/OgtB7_+i{'P;WQ㣣\s_` }=b.лY;啀fLůP K>aہQorï,t ޏ0%EG#(Le]R#zS[j:1G5$R-dzO24i t؋33Aq֞x0v6P;rE/,;8mr=u:YW|uػ%;ү_?~`ե-f tCffJi5]>krlÔ;dycpB*mRMԊ4 x󭢣>>aMyl=pVaFjeć'EoEx.ZNf9I OYq229a!l:5مâm~5ޫGݎ"hKAVM? бPYEx^R5vq )@Tr&^gqI~Rk_:##Lg)L[3[p?|m<Ӂ&Af_^e @&٘/&[,0ͪb,.m+\(P"qu<<]>N럯eAl$%.ݼz&40s󶷶isg+Uҳx]=drYsRZKkD=^@֞'''Jg]5X(Ŏ4C*/J㳹X2Ѡ! !-(UQ[p=y+ρ u948`q.+ JcucQG!/G` Dxu-PȴDt,0RxA̼`,|_0$q/GHxتXZMN"uW|:܃̢E 6ΐo=mI8QH"#ڧc` s .JZbs$~v$ aŌ8n0$chw-Zwɲ(rl?Gt=woǟyW~㾞VĒGݥSgh/9 Q"1*h$bޱt`k ,YFNxu(7PDl~E tR&@'XY 5yPYO!,A5nvsIP22 #Qbq[c\meSo΂ϳϽ3mɤ6,Ŧ~wyZz,Ѯ` 8y6tm+ OH437hԣl l!ή .qLEN)".XKQ+Hz: AaRKR@!6B._^ ίW~`h.UOqLK#kRΤX50cmF6GiXo(DIK |`V3 V?&)OX*\4if090}ʹoha!;5a7GHL"Eٗu"/n Th9!<⬫ (lRդ-3XTPvBD?>vS%.\)XĹ?.m.BC,Yp^~Sf{MAtE 7=DVz=f=GN[ul]`^c'J9Zɼ@a$qے>cBb_f!fz5y$A(=t)ב7\'ӗ !yA?ΞcŽ#q] ZS8qc<{> ß>mU(KxVoȈcZڋB(fSpXO /|A'S@dr׈wid@ӡ$T]e\jiQ O?v=~Mީu^4aH kMy,ac61罶a-kZ-0).C'$J(ZxSbr QGL{,s%Q + cPK||ȹ/iQ 8*:#`xlS;|ښw@OxNSSc4©OU([OteՆa;YHq:Їp:m[v\5,;6^|C x8jg. \Xni@865ld4ڸ#!lfkgm,.>i^ ߯Uup yfxݹ@? < RK!Po)5#)™W5eO^zF^3zU=Bbv\Z *rU#j7?'( '#b[ԕ?cYʂp?>90ܕX.ȱ (}Y.')3R\ ~)fa$X] .F 2 A,iyBo_7/A4i-!.HnNC' 5p9߂#S.՚he_WXZ$}+",_d>/ oĥ]1q 1,%>|5Z3][)i[,SnߛC  (ʪ>fvF+xa*C߼y*m 4^MZ;WfFc걸p:꡾q\K'XZHvbqJ}UN[0u&׫z^dZΝnc"'Mo(.emU4MNנMarBȀQ$T$3c2*Ŷod-g9ޫjߡ&]>G ,n"fZ/QzXKX#wփjf(,n7@|SqI/*5) 3 RL % -eyiliJdx~.G7,jv{nA%!5Hgaq d4Fp 4Pr5Dj̈<~a7=(Og)g` >$CRUIDTr6b- r%L@?i79Rʆ!Y͙n4C4/YUw嶯i%{>\?gPp"z֏e|\)(Goɓʃw=6]Htn=Jgr0 H .D)($"cMYLѥ#14al“4L[CWe=f2~3EJ$OY#+Rh6 ^L'gЛANMZ$D{&&g&#\ 3Gcs5i#^k  *SBa Vגzب!2DX`ƞ {І2*@nEz],]4J:^¡|KiIx+Tпri5=T t(D{5OHw  8L :K(lX?D" IL )R? 񃆏InHLDC+kf<;pia`Ia%RFwts,^ئB;+NHmEbw # Ixu'!",py&L])3CA-blkm†iBS"31/k?CnIjTŧnI:=/w_B8]G:+4d`\b8m92hhЎuñqRjt"y:AOLOX CɝP>!G4AI-L`A:7jvMc}˛(?hRgG)ƺwaJ3`AE%vVu0#0|3q*ǙGK0MT'o8٘Ms8a }R,2$ {7evޱuE)j:0fL}kfCIA g>Dmz]B}iX+2N~acN/5cG6W-Cݤx)s@g-rpȁ_& T&>Bwd2k|6E{zw|wdl<ObDDBCeerPocwI~PG" 9̝y=FioG! REm.#qs'&ql~!9GӰ`VhAjeMC'{{$;KzzZRi.;b/Om;VOt2lCH益e҅,(R# 7rKؿa"2)v:[RhIHQ/;9|kE9Q-V 0uqDBn!6&M0]3ӵh")ƛ4@8L\;˜ LZ}&<ky"ezdgfĤ^>K- 8}X>^f|xďyVE~ϢtvT}8C4G {ԑZE!ڠciql.}Cȳ,F`8JR7 y/5*mag\i>cC%Om *InJmD>z84౉0>: ^TgQ%O6Xj  c bKͩ j$Mku3G֡ J֫کS㐓UNW '{q:J9oa<7$-_|dvx D, 0 צ h'!mzhz![ݥASzۭ`7p~oq?|K HWI>q .ayO }4XZdaӝ ؟vTOݗ9Ha:EjM}aAueDL6Z"Cf x IdHfo<>&PpNAjI΄E)!o&*M7hJ-̫GtZND'FR1f@b $i˥{G0WKM5)[Wx;M>/w]Ф{ Mk< x`aށ;)N,O};W+鸿OͮH(]y~;rmDw6敜}Ea>{2v(uIIƴAÜ%$4/NP;}减K lɹXH1 #~D%Z<+0˫ vϸ8x &KJ:$vx f|aul#t43pTsL.F2 8!ymⅾioU;c/Aa1_GCv1Q .Άw(~o^wby"+ЈXvO*rdD4?5*F4]Y}T10s|&iO̥)+oP5O,iķfɯX9.%eRP< j/DZ= yW 2~u_<G9jaxTUo#n> #5Ѧ)fjsu,6f.)vbUQh^EкT do4!X"DIQKRH"y7_QHc^\`6* G7-SL-$aJ=LJy`Hёgh -m`:*c5(x+ WB'9BΓU:LNARrk ialzqWk 1dt%9ILQ#H`=IS{j|Ve uQ%m+x כFDg%ZAF\#*TX5lGrP'͍I\2/@:`sMjEPWE')HWdU1ofs[+76\ w_ 4kgu5P lF\X ޮL 1`8HݳГ<66zm>fwgPxxͦbӐ!]uA:[><5.`Z>Bjd/`s{VN]1n]n*dxbbibEXnJgjC3vP<ȡſl] ;cg,'œ̂ !RB2d p龤x.GEEZe3+MV`&Єh?E@ʱWuPv+fXX9#>XPU)\K62{n/G.K sI\oUjU@f*y(#2Hd-{d_n:@=dũATΛ! hA 8Q譡HH* 齸ૃl\:a0O-4V"[דt5.Vy /&\6ch7yw ,k~N9N?d!tΉ02f,FQ~vjR4 t;TVR8IegB?-Qxb//}7kJk(#*o)?RgqKrLo"@Iyb.$3^= >Xߠ 0:2`sgWN"7 %Rb1ţϪ2_1tH:YZi wG#6{4Rz?_3N;qo'k/»v8i жزsQZXDll% *wzp,,R2(G 0WˆE/Kgߙp='y qLJ֔{f篆3O'ghIǐ~\Uw7E"S\)ۻ4˸Hp\ dRgDrt70\yЌ2=(΅q5b r&eCIЂlG/8:ONJ080(~,OokkÚF\ÎS #x'4S_lO 3.԰E QONXnYN[j 8RڊyUbVveL)pXCEӕM>$u$!2| VSWXg쥟 S[&kX݈RcY9E$c#?-FʢQ@hP_D7J2?9q]H.NG}{3 kyuX8)6!rO \OL7D)2`z _)4}vbFІgbD35k3]IQM.Idx +O ;=bhO"HvVf =dևH]+ƐjhU<'Et&,I̫MN9Ī~peh@JmQ'!iV >CRh3qS 8׳A,zT/O3NP\RA7HCOO1,ttyҕ`D,Ncb,}5;f~ ^KH "'zxdJ-XM;`s W @.^VRqsV59427Q@-QC_HtK%bک˿ 8і?VUneLlz&L:&Hs a }%M|-taӼS#%MI;v]}!LlȈ-36E㮃d+{࣌p t0OQE# ;e.ួVp%}ypM/'ۉTLFa%wC*=+EpLjruu !*z裂G^5K`fۚ?zK!e .|4W M0h/5:9S>qe 0Ȗ윘?JWmGıs X6b4f Wq Bl<<_z sꦓueP: =7[f{TE^WBkhO}G\mhIV# ĆG F~qpIv>s  ̮ڹ7Q 4@R*$Ff\r*5??GtjZ.2ugB=l89[d?vvr&ż憔6Uˁ)PmͫH>d`4@I&FXITje>L꾘(MMgFQ|q>S"YJ-kʴycAt QG IC5)d !)Gj9J~ l~3*đU:BthOBx^}"S30Xo.Ib˱0Nx((6ƮY%cb!Uk 80Xy>o4":bVw0 sQ= Wq}SX-Dz<8qNH"mNPW-ŷzԯebQDw1( qr` ? FJ@p$>6 #9X |/SßJ,QWnWw/N*}~>^fwe%g#6߫ݾS2"3꺃)/*'? ,15"Qbit ((9&.R̘hI "lU+"d 0a@\.U6,ЎԌ@h0hXHāsw`XT^>m]k~hfT|$Ϫ^`?˱235I`"[$GEa>D (G-iM`I<)#2 `(ޣh9jk,NF" ?7hO8g_5Ymֿ1d??QY#N2f\|_N4bd D%]WT7, M+M; Nq ؁2hϕ0\^ƀP:b6uHԎW(Em8`NFԍϧ.^3Ds~:X U"ܜdx,q%O`$<` HmC4SM'򿌢ޅXhywF:Oo nae-+Pޣ@aZ=w]?!`ܐaCXDG!_|$+"e/d@a4&3'e/HȺ4 D*Cg1'l]љ g/ |ߩOkW!#$Pʽ) w2&\j+lے75p`.͗zC/"o>;: 5_å3'?185]]JDtqH`n\loEK $5]{oV܍D9!;zsD]a bDM;kc M$!8ٕgSqb'׻*8o]5 E&`%%i=0G|,)K(`Uya_ߨ0rcN3䧩RVbR:w WUBxեmkAv2ȑ>03F2 K FE$9!NXL3edQ$Y6X`$ZX‘v;E~0(3 q8]-kOpF<:q6&" `l Qش%Rzj|@H=4uv;ztHr `&~IfHTʛ}VI<{؆rFEzToLƔ8tzo*T6-XE{hfQ|mZP `g|7zBYPzϾ]ys@p8NUaoߔٯN=-M.Wtm@3gv=0涿㭓CSƟn2/BV1yp\ɕճ%̟Ia<[W:}e=@w e5Z$_"ps_J* sdژ-8t\ޙ/r; |Dp2 \6i.< mɮ#hEgW =b'w_t̛Y2J²*1.P/#r\0{m8](Ù&&UWGC.)Sus:V.PJ9*1-J~o+@ Ws;9Z00{Y;jnBl+J⚹&_I:pݮ%GĿ;pHИipgP뷒L0+o`t;ںDFԡW_WǓJlWu%!?#174͘]4#d^U@ |2A~l@)7~m:W,nz"O2f]}Nne ,;"Fտ"]Ϛ@hx2o$ax :XOcaT;h~m.(Ê>hŶ\1I$=orF%$J~,mKZU8B2O1#^lhF\KH<=+[HdXݬyJSmEћ.i"ʨ rjZ+*h*aEy֪(i2."o7E^-lsBVh۶dz-Pڄ;/;f,݂T=_uN-Y8( B(5jTfYWR+v Ftb:^wDAz*DM<Qh ꒏eT"']Ned@2Wz44lq1ә5 Xd晅XUV|\bR 赑M H̎x>oŤtk"1K5z%i^bZSmO@/X,KEevJcҡȭe2+Iw}~jKpLdnI$ 1{1VԢl YP\yn/A6BD0QcxEKyٞVﰬ4zS0 ̐]K Q^Jd-ͣ_`.e>g [yCu9 瀢R3U6FiZ >7A#Cr "ObP k>d}l֊pA92Y Ժ,yޝ9׎g.7]thjE ZՉ1 ^+Z뀂>t06 oԠ6aɏ]QbZHaG X):Fmpw-'(t.nT50wjVO/`#Td"2x"/[:Idf`ĴF<=v3SrhbU HVj;2(FmUUdCHSҎ:ivi 0̴ߖg0u.Hґ.*H1y F!9g|4cX"Ʒ J#5L@1 .y,snjزmv};&/O4W Z Uͼt ||bTSl"5]] "!OgAShfE-\i9h%1'8C"y:;멈d>7 SVzd?IH(̪jO/[019#8Qy 2"Yw`yY;&UH)J&=NJ0=wsL.j=j22rűC;OlqH\T%'~q(iN b{`E1>s>(&(;H.a+I!bf9:.`?>E3j:?YݚE_[,e$U>mxw6,)xYAYҹz62lMx¿!#VCU3/~UTu]zD[U=*r% ϢQW&gzﱫd&`#|PKqPoB=sδux*%C]WkW% I@3,3YW`7yEUH4XiH<+0|YN^ᄌBQ : *-U2a4vԮ3hEhut9# <>No6lcEOS&;d\qKgӈD @_c8<.GR bLIb;'eFwӶ>c'hiǰ/?EbR <tS0^Q|šjd'}<ƌ;ϩ|qY֮C0blh+2("٤2$ans@hPL NbYX:0'<)kC;[~hc VG I29es!*Ai{ gJHq *75h(L[,ZE6[`Yy>2,Z ՜b=!VH0C>pĂ"oxJx#rEy^x]^ Be[g(!'Jď1X!CM@juR@+NWSܦ_F̬"M.Hz jKt"R1ky(PAo aYXG| GJ!C>=9:o7V ]l "U%A_J;康I{/H94$e$ >>X ʀ0VޚfgOfUeF0ڮ|-\bֶ*!`]Ha/e#PG#?[<6m2)I vn"Eq Od (\\ fi~{$9]59 y~"ŷL_D%MidH9/&,Tg2a38~0!E{oJI [P*xؐ"$ϻ.V-bae^-<> V7gNoKm n3L.\|>+(04lق~]~5j"XKȹW&Ϧ/ua%(e<,jqLa/j`"$ hPy D`hB>&Y26@RG{)zSOsEy{[! t^1>ƭ㼺H}[=xeaɹP` ] C܁L{1<2%eO`1"6d`T~~`nxx3y Edz*j(S-s3~J#R! 2z|QMU3@kKX35'M6Xs,I(Z2^ʚY3aa~KW*eA{WHغY=ia%zc Й0L& |h^BGdp:斑ŰTt޾8"V̀!0JG4&4lO&\/룂= kҷ h/3*?5KIJx8 x-敵XF/1Ս.AnR`Ŭ0H _0zA(JSz/*2dZ`RHH$B y1&{/9_ n3$iQ4,_(U(b~Дik!O_zBbҎw6wU{9Xx(nTЛǏRls3'zc $:anCIfcyVQ E1Y4I+\^lHco$!Ra>T"|*2Ď~ye3 0[)}%eܲCЋjOS6J64`4$/vDՇ!(%0d0ϋKx'7pZ9sq^R2TJ[tO[ gRXNU!a b \A?ΛDBy50ZF$4薮{8AÈXCB2+$f0LlUEIvc.}F6 ʙ 5d+"7gO-1\Ziƥ-R`t*ח$XC\0O} F3Ϳ^%HFLm1i##m myqfyC-&A0"t m~J0{OTphMCӏ ,bj*yhГTuRG'T |Bnod=[ DX5ᣭA[#z?#M,E47"U ̈́VMXA1\ CR5Dj 0I6nGovSR;ݨm *j\lv"VZ.#Cጭk1B;5 4Z~)uz `8*RH0cofjC|X0o y0\Hj~u&D1ɬY_(i VYg$^p2g1"itTKICtفOHO϶pW'#2| J]4:-޻P]BVkDSJ`M-*6 rZLߑ(A_O8R9N-krӜ"i~&T{VaSǒ@4Tz/CYk{㉝YűF+mp[ )ɺ͍TPS貣Aϋ;G$q?ӆlro}+('`>%)FVUP@B*T~/P! OEJi>rkDީP5r 6|l]Hzq4ƖZ"-, IбN'9ۇ~~d}G:P_2riV(DJ wJd!^ O+T[UD_{-D\6;}rfUkT8^AEC?3? 0hI9Ɂ6'ŅYu/7OgX=Y ~d4Kq U /}')hU-S:{w4jՂ嶍,,cV[қR}H1|K{YPcut:$nww|nl`4HIë zn4(OWGw#dش?[\ЯLJeʜ]fO{9MZGUAʲq=E^^Ů'Ty iԽ/㏃\~a!r %?1LuQ;kI>z!_ km[{)v24QlMɡvG bGA#l'BaZU@i 2:'ԇ; A>{Xi[?є,E,6tk ˜ 50P~G'GFVOcK招vweq_]/y틤){Y[k$- <ڊʈIꅉq0LnfIXkųe/5Ja"k\1u B]Y:G# |1pTXof1tp$2_}9VIћ#R IJQ^&%zxI]&^Aem+5axűG__ĥB7A Hb[Y곰B1>^Y$O={yt \qQ }yAvj-lXHa:?th8;R(a'`߯<jKBPH$~GzZT S.CwVw0ȷ[F-nɇXOWv{VwOI_o)q1~1h͒"!_O}T:p~~}5hn=4OC 4=޳|NjA,D_n9F l6oJ@6w>_r6DakU**}5ӦO9_liZɚ5ycCۑ<91|b0GvH;_<27 ̴IE,F#-fwd' 1@V+utcc<72acxW?2P 3k~m͉dk/^l~QNdޓOEzټg~c EO; J /9FjlmdjF]\ f3yanp+09YkRb+;9fԢHTY|5mw F~^%8y7Llc.͍dx eO<#k *˂z-Z[2K ph>w%(2YK9LJ "af}"Uq J1$׋$٦jc Hutuix cKah$d21 ^x0y1$:u֮\DxI@~5~Xg SN6O0˦]4/kih>{+c+ذЗtYIDE*{*V"STPJzTO|+UMnѬ 'qA)P6 8]BȒKq5evV"\wjIgFSiS,qߑHt!ei=F6dr'Da(J_S3XYXEpnN4UL|%m+978s=;7ɏzr 'ER׫]rqt<$֊ 9 TsQ7szk`'С1(AfՏT4ڢKr]2 w , cnW gDcp1Py5/+փ'7E)n "Hn9O+ !쥤@GM@LwpVDS4fG`48SU35KVLJ-@F$ !>̝] <qW4 VX2@/. Z3o2%oc bگgJ&I!oqG_)+\Ae 6'ҐX3EDw <@xf~Kr׈؀`DEi$'. vKgtm*F4 ~42z]DKSSg[J8}gP y@Ã삜ԝ#5nxDenZ_B@&,| $#ArRks<(דr䋕?2yA 4_??+PM Jx\ LsTHx\x>%rȅ`IZDDI=N6 u 6HLo(8@ș |!7Q#zZuY soMT\SEA4F#@r<ʁZK1:b1i^i+8b!ȖKRW蹜NDbd? kod($1?6Z,f*w&N^5o{%! (ڑQ5cp7`+aؼb|R&)_}R3=IщOm4~"5.CfD耿 iTO{_)rSe:)D|3(tt.3nGchT-W,l G.AqVHÜA~B#n7|Z`S1fOBs6ACn EeB!#敆,苃Ah8v?l蟅2a6K ".T1\Y9a:=M?edr`cfQ@D ꉥq!f* mCiﱌj$:!iLbG5# (y.DKm6IieZi$w^) 90%T9`C߱k&(&00D-^7ZoSt(<%f񅑓)ioVSRiy?;}^Vq tƖ jcCE FR>jKL1@nKie >M̙t JF(+@1{[:];qvkTZ,u(T~h p620*=_{ bs>tpηWtI~hc\yHIB&ILxXdz_lGExUf*8ü@?5hn NJz~3IO ɿ#0AgD~WyfEq>xuZZfVH *ex6PY+}X>ihr;uM4 Ș2#sҩ x+xo͏5Dj[ w8Dv"gL<:#^cM?`mX qkL#R &5PxEj @ Aþ8vnc) feQaM:a:$T!'z%No]S8Y=#8yz1*vW.33{QYg$3G "+a؊"| F4BcY%`oT4JM˵}4!XQf2B:/B數uveZ[or< Ң Y <&yIQ o׿ VCZ,s(2D?>=DEu3Y9~:o)ǣP锼b3#d/'+l 1:y׀mBq<|?t5.˜hx`jjY$#[iA/X8)*E% e{\ *:9œ@T1Q o^:W4TL<Ocmmd |L埽c2_,I P ţ<}cp= QLÉ?{XQUdb烤͹?m#Tb\>_=q64(" Hۀ"2]y7Db, j> ڞhJ_P 0C OTkO$K[euD@W 2̻)K0 8=@4[\2Q|aHn4*Me*ŝ.u`@2|l5UBnb1>PֳGg; 9$.Uu'?rU]$50eqXQw* c2M* 7BS~^?N/wrZ1 ⲜZ5䒰U2*v!.bb蛀X䕟ryةAq"Д料c9x=rvl.:ERZ^ʏ-UPCVs ƥ$Igg%crЃ}@gf+I.BHeAEkM,Gĥj&*6H 0|b5/Jgx&0\yA!Z"yQ7r«1Zwذ5C0Z Ifl2|YPJ$#ޤY Rb)]֐uр+{tM61cvɛY/F5 *wɂ.}ҳO L =52ɬ d = lF3^.}рa&.:# .0 &n<4f}ʽ-["âŁ&FRf#4`zOuI'| Dp}\ @3nSOgYbrDz~j#>EL })VDAd_Z977*mjȏu{^V5 .> X/:E[k`E^.e>uɦ!G C"#F%EEL>[d_ˬ^2TEӥ? /WCFXT/DE^ұc_] 64) ${ol `8ql=>H4z"¬o_R?:Wa{&`l"A5s ]5*lZb " q:U( UV9Z,u>9`[rwFM:`.J@?J=c'4zQUuWzU3G[?!Kϰep3"syDJ{ ||,}jqB˯bBu7_\KO;.cIX5On)"=R +W MBC?FzbJ' /g*xş{+%p5 TA\] %dv?*,fEڲ[fڶ4XRеtaqXuKZ3솬cE} NX1)H/Xc! zD-m,6͔ >ƕ|ؘ.TUf-z8 Nb b*iPr?ZΚH#n՛5"U}^ϯxKߎ? ^GƁW%\9߶0+I $|`G#$˘9[&N cGÆhk"UD ӎpuGC!p'w\l0;@məx#ɂM˓1mydc5&~}&G֒ES> m1q?xAj9!ǧ);q1od#y' &MoƳm*W|Q0Vd^8UAN:'|6T2h4iuSzJ/Cw/ $x_{rQNNMID@%,G+eckq@ͨHO!c("E׋X36gkv%3fi@]?e|%tX!7B# Nߗ ++PJhI`.ZVѩp5yPPlǑY*n԰#9 4YJ5u҉,NM>l`j0tR~K~5"Όh%K2}"KIZ Jc"1aXaJH*yRB^ÙN3SC2z9v]FIVt9v>yuLʏ<'WL_*3I@67ڏTٵ]d=fL߷,2?]Λvgk >A:振Em#_#WeF0DtngJ8;ǞLX:kjO᧋D";^.ArJRӫ\oi5?ઝCYV)N7t@JIY}s.:9v#tpn ٱ r!,CZ>ʹV:xX6D=MBWIJ "*$ \!6RӒ眓ҵ\1Br,i c v,ii~{.s?TxWjmeݢn<,V'KX|zJ;%plWu^6GYS9FeBrѹW(&%ś0F̳9r?Һs*Pi諵Ӊc^HI5}[ m'OUAc9V~ӛpK3Nqű}v|ɤ ;ѕq/&SX_ $7">3ӭ$mvX'Hԩo[Ѥ '" aH2I{>_rLEսТ˩3xߚ;E+9  n3 N"ѢToFے#M/:~fG,JIncY"$dԏς {Qw 0a^SL&W)9[T'Ɣ mc_ŭ"gTc[Ƈ"YKI etBfiqGISZ-ڲrEBŢzۊ0- BˡwiJ q_@μx챆.$ ,]'AQlEWFEjGO}& KP/ba G5V6GO LLHNuVMUj+!>8xP˃y84D^@U>k#l=ҍ(FM[(tFyVTciXk6mȥo4 < WrHWԽ?7MG]ŗ[N< hY$0 [2+` zi4ƪH?!^zF\t% )v ]ʏ lDC#`<&"c_#M;arI{,&xAcHe&g5׈˥j`'%kXBelEFG){eB2aeL"CKX!/̨v0-ҡD\ZbLS0AiL nڙYZUgv 3KdzÄ.Wn^ ڨydEe1lOd ]E6?)輆%@ߗŒͧ y%kC*227B>U8I[?ŧKQwV(0 A{^]赓Y"3`|Z!&z־x]9AJ!ܡqt˫9̌"@(pbhPy ~жYTeZl䳗J)1T[+j-ݨzlHjێnH\5 \Q1AX_ %N٬ eDm8rۛ1Cdd0%Y#UZӵIhYBV Q hF5(S2 ÏHʴ|p>s2) fy;w,[=5f A,M$"Q3 f*Xl8Nc KWh zi;bzן) O*W?[U.g7GpvE0"9dFUe';CSDBA5FlExpcSB. cØ~+epi"DTS ǁ$!>oAY=}鲩g-#~%4|H!z657SM|psW='VIA5b@ ]y}DŽ ?T{2/@Y$OؚJ(O^N[J/8Z6pO,}1hiF@ z.Lh$zkoif݃-OAҞp$ .$4}niaA@!|+O?!6Hwh6OI·:&j.'r =v wuĺPnff oѺ %-moZ\iIiSOA곥FlEZ-d҃C&I)7e|)H̕|;^gYIw[lEAiuhKt;4Ľ^\Ab& 3u C"K282_+T-$z .H83VKVNjcTS f!d?!l)Jb-e4+M~#@ۙ#cfr{ss ^K9bdU}b14zGH֌G`T+U2SU8+ hwt`TAqTc - 4=@z,R`g vJN%"ήNU(#l.Wm*T츾g_ZD FJl!W~\Q-ڍk+%ځyh R.IUe ;fAs4gRإt|4(oγٱ4ٻ.kЬ~hɭ|ՖN!Z-ؾ;U*ΓI=rvP-8X4K~eCPaB?vjy,, K +S1 h|A{mࡊh, W%@LY&1t XU @e8U%w*9f%(FN@Bu"hh ;څ Rr/eZ^\,)X1~z*BI5J 䅉D> \PfEz2s~vxul.l8ʁhU܊{8_.g.g)X ߜTdz4L`iH1to 3~']`$PCɖ1F.E;Ϋ,j[(8FmNS0{oz3c3a}VHP*FJ?ɓPۘNwXT@IEaGkR>m+3OL>̩M#&IēDf;:^?`&;<[EVQRe'/9\#)_BwDsctB D36יXqAjjCVk%5F Ú;]qÂ[94>^?//IT dT} 2a54ͥiH3>j^x^N^+Θ"!`%Ci #f+U1$N+U VBx̟lr#E?y "t9A(Q{{Rfs;PS Tި!;ڎvƤ9Ak$RކsrF`p$i;`2v=m%]mc|'H=ǾZ}Zyߒ:D9XZzEY"+kY= OS,hhD7:'gQK5MrqjS &ElHC=dkYwXb{5}}}SKEрԚ젗Kxtv$F)tU(qs+\;UZO9WOkQ@ɳIF`|/nKǮ@ RYѢNY6/(p':;r>$B貜>'mb#91``!>ҫ{{%8̔Sjd 0Gs9]YX<7r)PCEħMJclYuw~ҏqWo2j\rY x;,N FפjU|BET&^V J*g&5AA7^|𱁓?A-5&C2ZnhyͦYKH HkX@IapVVv%STʟMo Vrz%bxA |H 9iqK3FJ`i>ǁ n6s#-8N(aHFt pOi|Ί2LbaR S|G5h8 gg&YeklR/6a #ȿ`V|!PX1ǣÎN45\!6*d3Ef_Z=C2b69+Oj1F D8Cll8̮5s:w/Ơa{eaƀ(Nң /@ͺQXuAR,;m=0I$1,7m:)&5LOZU1* 2yF$MFtk>ǘݐ򛯝nlY"ή ,n/vm ֪9uw&>"`Įo2{k`tЦeʗIzCeYV-4bl/%h>Ue);R}9c`f Sʳ-"W,AÚZ +. ,qp|%'Ҋ2eұ:>)_sElVvj&5nVbTWhԄM/P+X#bgdz7ٕQNºb[ܱI釼48f0L SNȈ.R`7qs&_nϒ qEb _ievn}a˞G0(IҢOgKO?^kx@+R%:-sLjLe(Fl`,qwdnJ쐗bZ&-|{s!Wߋ1N+2"]gdNzc4@X6lİ E7U,N71vGi~mDGǥB1vn)%RKɐ ''ahyPͶWϞ Z/bv/%d(b.(V\Vs*Cf~h#<+}tpN6_n^uY*:1h-Q cW8oǓE W8_s+l6 ps HіSRU(-3IKת&vtxКC0d<u "PdZp)5H]0jFf0^$!K] ృT2`i-5Fc ԘfxOT n- sH}y n vJ.Dl}Rh_>ot򤠣8~JLԑ}̩6 %9+٭)'l nє<_ P(,OH"*Ւ*MC' QEɭ?͍ӑQǂcaJ㭸n+` f9VxYr똂'_{mtMr^+n Z(H'OR_N6_"7 w_?YLB`oֿygRq%χT19~hA:Z)Sd%P]5 yn%)XEţ1>TRR&dI y ͅe3boea '?yxrɰ! $tpjm:u\dLg 2 aIFw,tV:a;3 8/%Ս|)\~(hdr!}81Udj;.1͓ 4h1; B:@ -zg #P؃qb LeZLaRZT|6Xhm"w>ϖV 3գ4I DZ$hשtrKeBoN~x3NAx82\Rv GPBhSWts] %%ܛO]:.ۿ(8;Dz?.[!ܯ%wZSGKI@)&ye+ʟ=Z A|;;lNVD"DNClgv2ΰ3PNM*2B㧾 *_& ^M`' ƒ>&)a%!!fNYm0>Ky; xٻǮT(\'Eһё<۪p?a)~p]Oh=@l vS .((yNt*󞘡/ݸ>5ۯv¦!.f~J"BQuTj? ?\7)K*:|rKKK1?x%[&CX.V? )f1/+ˈ"; 1G!J, Y t^ v uG , j?+VE.=vNfgf1GidqEI uXF\7PReVیjhRb?)-2+R]%;{mA]P<~N. 9F:7-6_mo7O5aJV ZOW osܷ*RE[ѩ«MO7e9?%{΢'DLc :K= 8y%-/_vZnxa2(l|H{&?{lM ;ҮK͌nzyk yCm0V"AS Gi^_||8wA3c{۞cqyx9By2P_q&Of!z1BlfYo'YM %/'-E^_9#DOW&".$lErDkebV,9a5#_[ B k)4_#OBe/A)gٮ& m箔fBLl}u`A[f,-qjMyQ*Jl2s*Ȏ6 -׻e&_(z%VJsay]kVߧ"Y9lڈ<]$X9"fw;oK_鉗@(btm,fyj, 17۽`ZwSe>/~'f#D@{ L /m+Bxq-q7tK9X ƅ0yK b"Hβ?,!g 4[ 2c?_s1"A)łr}xif6RY!u(EH 3fRݘ`=aB|3 ߲+ ,rjbB@ñ8UlBS=VC~ r^Jv8b5*Y4QuI(;gZ ΈuDo!&"HZJ1"IɣCШdi=셴"^PբT(z,V?,eJݘ PTߋAYg (hu=lX Bd5p/O AiTAݶ'3B+c"!8  Zhweuy)`+?͓"beᐞo+huī{62Bu 6]GQO9:a/-[u}(nB֐s߮?y!_ڹL FəK,k@+iQoJ]$)AVC,TwJ;nNEMY¼~deY*^#C M2륟I&A#M|AU(#B|1Hz d9͊ HFE 'rACXuMwB(qȨ;L;iV=|v_.?S3$D ݞ4DeAgn$:/W!beLE-dC};/+dH"3J n$h=9& CX!Fnf졏D-IA, IW~$Y)ROoulB 7J{(6(œqQ5CEVc],% UWHnfGmuc#xӠѽxC= LD*ݕ8`S>x5 QmM&`]^|uO.0  eJ6͗\QRX6bm 'KCHAhH /cGIKsܨu7 h&:T|W\Ŀ1`~ =Aܿ^239"*%>rN Uzc6mv)#lQdo!&~|2j̹҆%k%6ҵ"(HnxtIy"p6)80ˈ3g0UEgd5(`$\&8[ !ww8r rRpвWZqRIٲmrUigZ/RR3 }RuzL Lw`7rDn fDk-3m9͍eظ D3)a+eP9tChrD hEBwbc(Ye!-Kӵ斌" $_>#wڢ1r~j=5bn#X-o<@ZB25|Ӊ/2#>GS سb!PtYRI1)@ȎOժF|!AQL#."՟F9"~B /7,?^-r[HmdJ zԃ$G[ M 6̿7 P18Qϧ6'J 0o: @|5r0#ޒ " K=-mUAb̉ `gjn&7 0G7 P bQL, q*qNĀ3^C[ 3{D^B9G}K~ƫƞLr|-%~H:ݜ}=ED4A)Wn:,̆^ h- F˹ţgo:l^|Mb<+0 vGhci9G1ݰ1tq)|)k;mSr(BײO}eXsVk]ܻ8^Z@kfU$z,`n ՛%Lb \ġs5g'.-3=F./]*ur;X&ڷqnp_IeJa,=[(n4b eFE?؟D ħ5H=# aeܸQq$-bq(z:r2iџCTr$1 WM-P$ȔXs(f2ڍd>Y`4]")*-Nj%b};Ǘch[=\Q=#p-{yٸnqAO *,ɫf@ՂEkeUСsQBEmnV!tԃ{|BEGŽB׫_JYdž>{0s]O=5(ᢜTW"T@YD=p93\KKtӆfm^)C0%)wϥK_?/g)oq'դ!¡xttlsFX5I;ֹHh*c`JXqR|+S-*.mӯil"*N !uwNվK]-p%dZD:SsܓѨyl_.2p%W>a{Z_iL@r{ﺰd4~G5> RLbü(@2<1n0&ćҴ5Rg=f.Z Z3ᔄgAsD5? Frd>&i?Sdy5τ,L~^jE'ط=]HTɶ`TRTa PcOn,yrNX&i !/&^[O[ k\QS} OLp4F_Ev[n5&VxHY[4pm&mr PI-P/Gxk$ч O#Ma3eBjdZв0̽j<H-x~1]3^:! 4j[q3?,R0gL/K>2%n):#?<6z+*CXz]*nbҭBJd5EKQzLADŽC_tޯfq`yɃ4i _厩dMAn m ^ti*pjw$Q T5wxKϬ?EKmxM|\Z'x:hMly̘,MTy@DGܑVKeXĠ8 6a< 9p,ǧm;I-G1"8#Po1s, YIxfGq)4*ek;gy1-lϻH³q m>Fr|ǁ s%tt?}`q%Iw<s2gbyxØRa;нdTh,=i0s%?k-6̬x(UH K)’jdHqj%wٔ* n(7n.?M& 0C)4#,R򨚷W ژ+6|K&,ܦ5L̯i'pmiT5e!a|g?r!.oX|©N3y 'W).?rϴh^)My| V?h{ec/LH{0hjpܸ,S7mwTn:t[Rbd'[ΞV6BⰪ5<:8ЖEDAZޑ,r?‡R[YPG(6`bu*2a"%nZL\'o71YX5DG!/qǏo.t: \+;y ^6)r /z!_JcoZ+6,]]fc n uG2mCWnF!%lF)c=@9N%4D~ t 1 .}Bh!? 64ځ;t=-/GD,|uvZw40mT2/ q '#|* ĨBÓX =}1gdKsAF۪9 L%/Tf'xg4'|!b|6r(#Г5Ӗg/qZ:r3D=y kt9tiNRl3Qr%ى(1%S7y-#E"-rt稷oH7ō`J>|z&(Eԏ"Rl5^Zo$fx0_C,TpW ]A90B'Ei&VgQwI3{U_#N6|U_SdQoYWB!*VP[WxnKȄ)ܓ:w썲׬(=0x=֧8b7ai|*t3vʮr{ў(Ei~1n -{4A]fY<ҺK#C>Ik\4rU $w/,qqlҒa \ -}"vMr1(ttLUȯC\m_I&CS]ngPٺč?&Ac& I$;).C~>\]]NGG3"թqI> [j?\Ҝdm/;1sUE@77^xTB5GPo?U2ؐ Xr-qbnDp+P952ؒoxWGnO{jm!-i-qUw~m+Q Ol bOb"i UU';mȒ2%v`m^OmU0 }>ܟx:LajJ ē C&BEp2 7Ąh|yAt,̵̘l+/bgٯ_J6rB4 #i;1<ȷX`b'L Ejip ΄4Bek8}_5Ǐazw-+Dlx/o\3D)|:2GvBzk,:N5m6͹Gv[[Fֆ:a\c|nb6dqiK41ԉڱ!Ay.~ì4(S9g@! xFOV@kND&)r,GVV4 9Û؀B,YDI(vX#[}rUV f~Mh'<)jA[F8&/}*҄CKi<2*'t$eO}ɪUJr)XW뮡-4vwmu^[M*ďL^hqДDʸ)8!vPF8QFeCƷq]R @UHCs1JȨ}Ң̍b+Zx+JqVtk~+5KGF|ϯߚ\G%Y!e;]΁pEԋ-UIσxB=^q\pmکpCpC*ߵVF&+ Jͦ8&.jL[he&(/z*H^Ovx*=~:9gM"o BKjQWfg|Y.Aʩb\ G%$ ؆Z77&^O,/ŕ)Yl!F*0#:;~$2m$YT'BAv i8T 28̬P s|SoH&7I]St .vV#] ;Q$cf4$U"<]kFaHQPzۜ<YL'1) C=GP%ǬxRHLjFM;JI4<{*eHa5A \? TuL~wg@0?@@",@AXPgMo6Wyu,xelyj)~.ckI'9q4sc!7!vy]X |d">iޢ!߅E#Ii%'=U@`/{ٌ"BQXFAopCM1B(,+/I1JHD/c"io7q!Qx)?#Q M冈E$tO%n7懕t*J' {Αs#giZd(\Z(" YU.2^ HZpH^V> S8FL&>w " y*rs תKBuW*Hx(R1m̍0|,*j}z^Dqs\q5TaM+t)K/(<<.ga3AJOd .cTZ֢x+V J& CAa9x \(d ^c# RCwvq) $O]".ݬ[V|A:toUˌag =cA2V"QIrTEh9"3=\ ]p(9`XXu|_)$s$k/W.1 @ bg)/!x򙹏s0v^rٓeؠާhj -mUvhY3@eZdr#7'VvġR1pX]=ŵP8wjLRϊD.ćd DDK2,|/GxBZ K)L3@r.3a g"k-<%i:z)4)B5rvqaz6U5$&>nMc̆פ^,{U#{Y<G < ʥ:2QA%$0St boa\pBQVҀV0,RCV#Wpg!_m* F !:U@ut%ЅRk3'3c@VޔBA1W.sZwv13S @yIƈGk8<6?見ɌK%lMyY8ROwe l6>OZR:`VqC+<o`$s'j0XL, @IhEQ-X"rF B1Bs*dBimc8iuSpcTyqhGOh6k@YfW?pkYfJ.K@E9^"gk.( KSbC.lYd,C[j}ECbG+ tdJ+l[Z(eTfKi*4 C (i`-'(epCN%ꌰuۣ6t'3+8(j`=-Ҽv-<TB I3Y7IY^[FqÏ.Bx EcJqpߓJ@7˦Z{?!bS!wZz55fK ^4d1cDڤ㦱ItzI},jc^M4 K+ `j-dRD #圣Z1".ˢlTXOw'o]`֥8g"ʿxQ]` J Ƽ9moM̄ޭ%噂Yai3lCG#>ia\\j D@U=b$ HV:v\9#4.m.O7 co]n $nC~1ibA0b{p3Oq?f4 ʍ~|S_U;\Gq]mv:$d? v#|PUYWoDuM"xF=[a8qBo^Y}h_ Ȉ55M, iͳZ611H?ܚdIt  )W$qŗk{ןٮj.2؀Eh@9[L @&CHXf<-7y œC&T&E8 :aY,T~r.i-R\g˴N=G{0r ص} BB~?q6} Jh19nMF&\RE3;AWiX1&.$s(5]p8m^P7 )odiVQ"jH{ώ"2ZF ͓0;_ĨS0O>F@Z:5KZJچ')2{؅. >̎Q@׶9 9?5΂tI98;m!T)B-98ki{]!) y8spCkzJ2,5q;6'g\oh#`cG_{% .2`Y- ߶u;Gf9, AvVE *\эQ"Id\`BVMp *^֧.k?S R֪I%8=,bД,5}C1Tqt GMajG +,˩4,_, ){a8mW}ioFtq;Aޑ:OVs M4i2+c)((I@א恙 +ulzF-b"'6E)quZ|fwb1"'5'<*<(avd #ndHFfCE+'LyݜT rh > +{ΩV &P=Vi3%DkO3s3Bh\1u,LR#=뗋A6$ A؈R!F:B3 hُ#񉊾CC8`Ͻ|QL?Y9 GV*6a |@达^i=[knQ(1RPh,E\hW"}ƳZʼng%cbcG,_áI#@'v4$Lx x=Gv5h:U߆AcK|F`H0j|ׁ7KfeݺԜmԤ)1 o$QF[5thGߜc|6BE\ y '>a%(ȯ-CH| 8JChwx!!!?̏R{ ƒTV} x=y<3Yh Y*s+1Ϸm3qd&k( /m=&meϷÚO¨c]T Mg Ѝ@q/0h_S&|MM<=,eRk?U3%(w֏D6߶qv &,@a!CA> ޸#M&*gpuH#.bzs4yѳqIsE$aW6txdW`\&Fm!h<3C#Ī)UƼwg4dUnZ|mrdx~fu6?Lh68>Ug+SLyZ$ruZSܦyN'2E]p: Y'xg:iuy\ +7VbB_<&̜RH&%h ׸g<81,CiA 'wB6V[[i+ <L%/J0 ͡psāZTC-Kp\ $0 .sZR 5Z`|Ic ,(<+#RAi 3@#UWKGI:-_'ț=@m2!r_n}38Mp$/ %XhܛO[ieN<[35i}Hs6IJlKOKIr>3ȶcA$w2Ig0v @H Y0_%@eiK?'U)!s[,$^?%}hhڤF[@:frW#Բ< ZyC_B+4nީTDۓ!)\ҩpdND(I*+K%P|kvJ[( lx%a;| ce,T .H<9$W- CMU$x؊Fvep2MYL(MRl&pD p}HK<* BpQ_ޒ0M㒲 8RW-zBA̦nm_,d٣) {!Ziy# B2 rTƱT}Ħ g>r)[?RMvwmܲsj"CyFTj#df4D۟2Nэ< mʠ I\4?c.g\ 0u *U]90M62 ƣeƫI ϶y!z:|P cw|a 4D|IaŖ|wJagʅS|nzjB6h6#wjч8PpCh#>YìgWQEIi_ϐCVQ#F4Ft|K̏&G8pj+TЊg0CK2MܳA8ԗVv[$""b%~VDskVќ +hPӀI;ïaK^R49EKb2D~ߍt&+52&o(R8ȁ )D#wL{ClwgשzF_Jzܣz$t3P7p!ԥB0Nz 뤦;Bqf,#iRQ l=r Mm,2(@Q s6#8>f>m|YuWA^>pK6˭! !ʘ^JQ\!ǡۧa7Ɵљ7?b|:{ix(: öbAn07&Q98rC޽4VU&o׿ Xi4K 7$9򁲶VRMTMG.F*7E $j$ȈVl 2OSؾ ߇8&ƍ90!OzwKllPVl5ȹ^[}K9l4#5sOln@D9J[Yq|WϷ餉v?{uOi2=6ʬ*ťJ7 i9:|~nڴ~lg3+a0Fć ?!c?jZj-vwVYA 2x[{5fbRzUh慀n^Kjvt s$2$&V͛C^S|AҏL+̉!o-ؚ M>O"4Jq*Ї7+I+JD#FX~7(u_/omm맔:ϟ4G#܎Eg"j-&@d obZjsnjh#biKԒ2:a5rݾjzbaOAn ~LmU4-%Fx]j kFῈ29'4s Z8c$7N0apn̏xOp}o\3CINPIZ@d&H-6[<ԑsIE 1Cjby@qH_ r|Ndzi$D3m?N^ItQ~2|3},28+u x\o}<~$@ݴciH(07_^O}p}i j"[l,AvGoY#MLO $wwfce xwj;< hQ6KuEҥ!tL!/ 2Ӛ0WFc:yҹ4TM1 2V* [nѰr؜8j* jK9.N7q,6oNw1-A?X7z8x]akxK ="MXYS)[2L>E@G6r}+:Zi./;<`luT%c̵ahJÒ^&P+ͻoJmq.ʋ“YnHgʊY@ `L rI~> /ro qJ'Zn=oc^bng x*3Y- Ͽ3zpzfH) hDjZv.F;s;G/!  Y&tt0"uÊx6;J#g< ؔDbUR1Yqsf9L MkRsX| h-,B\bf."-)A+ ":Xeq4h hmRCғ})42=d6*G<@@IDAT198mLB5C\8d ̩{x~;iI8Lg2DLUdĞ{\"B7^$024j*cPc-auqqW0DE$_>V Ŋ>p%KSdi|?>U!dp _E k*+$D^ZR6aчPS'+l &8i&ͺye2oqpT3 h*Iy 1$,1[E;&bҏ$@SaeB]}hT\$EO= qfSQ@Mi5셬ɭ-g͓[C—TqVE>,Y9|^2u/%KprRD !!Ӧcx6Iۉ4T3.I%lNY!z@ٯ[Nu 9uӵN#N W%ZHU>C:%b}. ihvm)H6[Ōc- F22ωŠ~0d¼A23 $E2֫m,&R}OIAL fh `$k/tLk;O&L3 dӭCAŖzS ?grekņ!g9^V fdm\žjԟ*2 y)ز]QMBԼ}֬oppKwK6Vï+󀀲JwZ90+ 7*Zve%.4pЪDhqIo?xs=yRJ,wFW~˜&c">廞;vWxsTHɠX Y=Ov`Ǘ9Fb65GN ,s5ظ ( '#dá5֣Y! Rt~T+cH"[@Oy_\i`&$d'/͓Bmȏ1#{HY.JxjV!J6R# ať8-T3ZƖ3s+ㆶʹr\oc#E4cHk)fڤ>e,m$du8yʹR~pu~"V۷eU:%|&2N\0(Qf\^&6a?2[÷RmHnɘ9eRTJg S辤dï噔o5Rxs?32LZA=ed*!uo5MY=X<ѦLG{^Poןa;giɅ͚6q7`]sԌ`5[n{,[@W;ӡaAi d&G6 )6 EyG ?J^cūhU]cn7e 6):I[kjH n|'?2+͸ pM%[e1Me0"Rlp J&p o6 lXP}TH?H `l1cw?D8ǰ9E{!X\^wyYm!1\gsȂ/k7%246 *CW*~PSLg'Aôvf5/6 9q$FPx&^nu3n<] v ̫C97ݕ`tz>LH7f[6H&dS OT)2e-DZiDz ݨ>W,+DER5qD!GZ2&"zϰf)=mf˯z|^~+w5!İ"+CBkưUY\$YB|1EIlKDŽg`0@@| >ûq鳻f*ev{`18!a}ƴ"BvpJ0gW)@)䄉3pmWY*`AyEZ =d1>~Rmgw)W5:bi&6kיVe/AۃH^c +ڗ$Ɣ/rfΘQǴ|3T"%oD{j<w{1~**<:bp׍ y۞D u˭ևCk:,t> ΢$ԁ0C$VmJRx:Ĕ&^w/†pTE_H>J>nԙTιnNˋE/>nvGXFoЖ|bCnzp~ZHO hV S(Dաllhy&aȑtOv}c8\z$p\N->K/A-k )d @^DJ]+q?Z"ZMփ3kq6 L U9]\WQ O `Zkqݟ=KxVƥt G)greb`jGPå=ӐpK4L>'Bb$RCuq^)K[l)l2I4D ~[Qͪ^(=5%5 bRЙgOs7lxG$Sl8H˴>%CZz^`ha9Z)x^rg!q6LH[4}&bXHB + KΞpȒ0k)<*[B4#p4Or-wL/`\ܪna[H rO&/o"Yg89Ɍ(-;GG?p'/},́M RV LG$(83FvOtq! q$(4-psø!<VQIVGF53ӡPߓB)=h&N@A(tXɜOiVkEh>ΞŠ|1}AKĉ ,jҰZSJA9jVAAyT:,-sxZ BX@-v!D@s vN!=(F7;O4O al 'BwÍ}4le3j7[VR`Ue"7#Q1 "1YꨠvH*R&z0~aQ̊UEl j12l # g||,ӗJBv-x_=?l+]ϗȌb aoa;/4h~rR'pZ.V=n3>KL LzNJ|^nE5;ߴ"7 ֲ҉1'CfYr~;"ݔJ'52IB<2֧L&yy~?>.t7Tq#.5A V*y -/,.}S^q١_]Wgr5ad9>z$3WO5X)T!ַFXT U[kXo|n,8Ƕa\  O[MpV̟fsV0=t.9@;DUthkx2lv}z(0r'϶21g&Fd1J|G"tY۹bĹs$*vƥ;a QU*WK:Vm; @%gR FK)(VLhg6֘$h z2)b@I“0cw~ /GJ }jOv`K[M}˼i!@IMhV;M[^v5,%18!WoH;6R3MR3cBbN*;)*5Hi vĚp[WJMHs2 p_З|9H7G Z"SNpmѕ }n)Nm?;Yc[,IatLREAhB$g߮l|n=r!99){ao=&^5Wnu? F68)Z9k;z[2 q{wnr>Ğ"jɇ ZH~䘷" k=A{ouXAnhռ:mؑoj-YJp:)jDvtیMa03&Cؑ}8nFEg|O2^dsgM 4E?CC@M2^.WzJLR!r RY)3SEqfKѲޅ:Dt;};2V:ֿNȳ7ú PDd1 rH'.uk x[^G_T4]-?7r\mf8mXvOt3_߿߯J\g-q~wt݀\vM! 7)AnPeX-PzMUe/z~ʲ}ϊe[8_ZGOK} rnDt!-KgOӴO 96[m5h K&Q uJyI?zakz\۸>;K@ZtΙ+`NJ]׏7M'K󙥢̢$XWTې!ЗbI%QkI~gV|HGJ eQ߈c ZUs>zQeBuQcYOi-JRּ@8@v#vVvsZg(!6]zy&Ȋ5Woh(X+.&Z"{y|2ק/-Hץő@S|3I1>V0%O2X&4Gfʆ]>~e.O@makr:13u6 A$9,W*p[sAbjn84jM:V47r@ N7#ֻ u9_djBc!{Wt y9qݐΝe51/8\Iʄ:KK 5($W  'ACFJV,&v|VI:ipU3P|Y%@w!!>,~u~Rkxr2a~fN_\Frڌ܌O8O: gʹW&XI=r"{q~.z hv+nn,:yVҧ+IB@i!yB^MmZN{vonPϬaqKrۡԄ5" 4G9'9'q@ۑC}jÚ$1i,jl_nYKދ@=Si)8-yJ}8vEXzwm4jxkr;׳bHL5lJ9)dEr)xdgd&c-_}\r5KDD=gĈf(qkd/ݳ1:EjhmÜ1]oO>Xr\_=aXĉftMFuF!!&j*ɖnkC?=9.*IF1b6*я+Cpz4lh l) j }Y e)nhX̕M5KEbAgӻ[[eS}s-24zx:7̦0´k8FX& CR'N,vuII*:ovN S^Z͸"r)GSRGICR?xZn}U[OqdʦR2=/Nw+X%~YLl2!0 pBWh3y>ˡ'-0YiˆTӐ[ D9 K$Qz|aҜ"'p(S",n4sXH}_4_DQJa&n5=WLH>s 7:H%$] ?#wő)8]yxͶ?4~)oHJ_UaMOBT0ɹ{.6D`YDK*XHT7KHy-eB d3,L>i~SJ0`?9):W02"d#[ * x p))4x3lbQ){0>-g:Zw]{>; f9FCvجSXpdfJ}Ѝ Qq/{J5#/QnfEbS#5z-2x0>\ח>~؆n&Pjʴ^v-1|Ƽ⮨o]ߧofٴ1A~"2!%Sj8riGyK F: %"Lka>`>Є3a׌d5X%{K0ȔԉMĜ:?kvGJ^ l9e: uV6VM(4l;G=TbieH oAH2 j;\#3vGa:2Z\@2}FHF8 (js@z8WXYyz+) UVShSKxx ,H )1P3~:b>ܠx LdڝSڀ"ksWH= mUV6ZKgʠ(Ft #W(ٷ:4+.rK1 dx/^i风0Yy 84@ w^ 8U}o%9=gYcEhn;TkB>42'|h6O=)/tbs@%6 &iؠd22ՃƒxsF5Ry57{~P"fo] 75d2 q8Bwm|8mBZ&+D`Fb i">aZ2Jdo7q`%\)eh9NGhݚwߖOȮ! JRQX.T*"ctVmB&mc5Z/Pqj0Qȃ({(lJ9k"%Ga<-qw 7PR$Y}(2z9{OyA-AXtWCF 9.۫}9-t@h@3OB&OvZ,Z"W4gtP:O͎ Mwؑ, v-&?#l_ͨߟKH$pNUVE&8=&k{T˳hIF!! +HcX;SW"T*P])3úe0]f'G(-]Z jH "ITg>.'J&58>LOYZ]C##`J1 ),8#2=K45Mψo.biy9XDί+aBH Wf {~JV+twDwߺ? 7㇯y^9ʔV*PkFP3gᙈ &^. ?¾|^~ <տJ^m|h0D-A HY(ʽ4d3!wd_U1l۞z[v?qL+mo~I@R [3΃RdlD;N'U1 iۥ xe'娤f^0y2dƌ^WF?ؙ d<4ΙH 6IGҧ Ht&֥L#)/ݵfk櫾h^`[tM,h"sFJx\ a aS=*Yheag%To|hcԑ4kU7ڌG[GPΥGiI'YQROt4rc#$1v(_PʹnzR;6tOlX4%Z͙_?M7KO ط]L6v8 5/6+҆@ΰ5yTlqWZq^slݤ ($6y8~v\vtT}8YASPd![jzR/drGsF/08]iva͜.-b"T!A-m}-~FnjPF;֥~)Z*<F8عgb9Liv 2?_hg.$kO)S`F+WMy(%ZʡGKK,P~SS WLBۢ7ȉe.xÕ`̶ifˆmzX5?ڭ{ϟ-}JM[q3lvEH!)R|gQ05Tci~B0nXlжc* pqxc͑{NYcHCmJ=iDӨghyw1ѐ|X+08 Q3:'2څ"6C \WAKi,&c u?b02,WM=nvPZ_]bI #X/.ͮ35U*!VxhԧV@02p438_}ny!Ycf%G잓mP$rαtj>H+dEqJrF&9 GxE> 0%#YPvƅ! rВϦ"Z.Pa-,}fPq)&fZz8Qʜ q.)vQj8ա޿ʁ$ mQg Zxʀ91T׍xtxI{>qGDɂxw5n6*Ut8)~.Ώ%Fo)8m xEбЋ.`JHA?,a,3Kz,p2'X%-ܚǿˍ[ n`!inqM*,`K!<'xD0,k${+(.wSKG z+ptH K{p>B0ﶊT|({A3h Z1WTO1NkkL(.?h3|+L G>?a0&ZWe +`OQhp?gYB#Y@{ >ʟ 6;WlG1!o6}n 妒++ EQJjy+W AU[s%|RcWl K Cx$_#Yx\`А|/̮&L0䧰=eۤɇ:O9: mV{m*z6N:Ap3mͅb?RFZ_H^0vBfy۲BDzjb) |W )sm[y$cR%dP1GV{8tGp=H|JJ9V0 LJ/FTSoTgLෘ%Xd`콃5M(>Xw5curi\_|ߩ$LMr`U`:/BVpe;+O";)cAӔЙϕ5Vng1#c ~ /`#7\m]w`Mfs Ԅ|`aJ{$ o~Ox@27b @(nBNq"d2 UQ\y=%\K1ʭ Y< 5vj/)MBp~Mh;/ 6b46B%3L{'a0Vc#r.{YP9T2Kp?i!{PHPd?`Px N8 Vӑ~J{S\D5D *κc%yJNhLP{L.^>jcA܂_+WFُwk`(t1Jk+]갊0=,Hw˕,WF>n(Xi-OdhDק0*]%P"KtqDx0 %FE\ 0v2g *_g~uōeS\tרUqn;b6WgNcc?6]J'k 7FSK+_8 Z&uVA',}c\[-]ө ߎ'H:P%ؤY']N@z;cY|Rp ozPD-CzG{Zo y΃Y~P18m&b9㩊5g k$֛ "\V%W}ssN 4hg&ol9-т ;{KȚ?D$ӃNS],~Q aB4O4HW&}a1%mfv2D/eE_+2#R4nk|/&4v"[;8O+ #̶hğVL'dv^DZh!]KB/,VULjv-}Z)+U%\)LhhW8?KIN UZ+(5qҰhJ)v DBgar5 UEgߑMT[qt. N!@ )Q si7tןq\Fddw JNřs>x(a\+˝5Snp{-/`^_jѥ,i.'.B_uҫ# xBˣpA&/Ah_:#h"eMst7sY,@N~2|oڡAtHe#HGbh dbj`RP!T`@Rx|qcΰl Hf3pBCP Ij\sF0Dg+^ץL2ӽ4eTϯnpU0Sat"ߊ=?qin@ 0\x陮&V~ΊUD(Y%cd֝0B5IW-J,73~ꆷV+u@ KbSJvE4A8`:aqǴb%lv']bk4hk㢧PBx<~he}=xsr[h]]?fwc]r׊mfOcAE%ozA9dLRD}MI]dL`n~:YFo r-yɆԛ VGB:{>~u4"!iDJ?V?:Ubqy-}q W]:~8ā"Ovu䉆\7!dřO!W#11eC+_۬ ]2hXpx_Pm7:"؞2t-dsB?1.e}|Ѕ~j^&eϜKy.彾]@I\rVu#g-{=n˷EkŎoJ yG{~|Xؔ.Of[ #ejKܨ۽:q"Z]zX|,Nt[|Rp@IDAT=-"a)1($?obw|LV2^[S| ŌFi5Yj H)w몡5?M!K'n\Z؇pk]^ N/v+IHEoQg%)*,뱵6愛a-Z3j=EZmՐ}(0Bt,G겘"ϊ'R[dQ{zy,jLBR / )u޵Gq:4syЬl 5#>a %Q GH?p WAMd3saR6A *+nDnqJ[6Juk IBvFae<ٹ8yH(EE"8yvȉWz(9$FL2)EC>D)5X>pH\bw?[ t"gP~r?L1 ̈5|ɴm<^O$*F}0^cU% ~"1HUH )ai]~ qn2yqиQ5hOm*thJU>)I l(/2qLzǔ@<$&n"zެV saE [ E]"E!{OZP?g_#&SGGs>6vEom#Rexο`^;բP !dLUA]k|R`9|6FVeCMѨaLZ}B`#u ^iZe#d VӞS9'1RP|o5c\q.eF 'Tj$ֆdD縄'XB`2m7e> MY?ILm?=fDܘȸmΣ>ZSqj[@.Nq?_Ot=>uɌ姏_Tu:#e4 ~!e(1H"&E䬓YYťB(0$Juǃ I'@W+ _[5&K?T/zRЄEba)68h;/4rqOm a _H66᪸dS 'mAW2bES3ib22*!,ƢആňiYZ @Z3?αouͤ6M(sڱ}4=8mxzr+bCU/Z/Nqlw0# }𮑨'ԫDaT`,j'|>|V&=`˵7GD]m̏)-Eԗ2}d,/fĎBխ,X=:|i>"&.tbeEubDr5B<#`hR6ɜZhI)D+%1mƓݰYEĬ+ n-C5uL0ż2&ۖQZV 2D0 HTu.1BF.Cq7g$wCӖr ݂!Gb#ץŘzH&.qMH1vD!6~@b\E 89D͊Nbڂq-\]l }[5Z/*%CxCROi9"ÀufKBgf aǚCټ)o:wP/GRLZb;*:e`D Ņj=$HXįnslO$]l4Joqh|BgA8'Z7 YhPBm,H3+%"tںL궥G0ջ| 6{VMJH"|)Nrْ<؏T}cdp. ^{ɰ l=T#_yS < ߊlЂxz; zT` 2l/ ǫzaq,/oA BTI@BKv'aki! #]G86Uk^qPEEd1ybK4PbWNMrK!W;nӟ] 8QBQ]TgٯXSQZI2Cykހ )D!|L!N}@ ylgVVXhr4/sxS+{6I))st#)(|qۗd!a.cZ=zp%\hoI"xA)Qfdk`8s2 Cņj'FenM-[sWjd*>{r71Dx`N?ma~ (ß9kޏ;L},4TK. IIpx99?eK.JWeGk'n PcuPl]bCs,r XR|D~Lc%eѲl9)E 1 o^ʈ=Mq̔VDe/Db]sw~Nfյ&Bo~kuݬe- LsJs=le&PU b~Tp~/6*is1}B"SdIǁ'#NGƌʰж|o\V7"i}F|ݭ0(z-=Cn&ؤ4Il`4.`4〖82ZU,7?UpMa/v P!>"ܦAjԎbF/8^BwobM<@cr \GT3 VmF XyTgD+(˟D94EpQXΏoc ~kNKy4C|N1((qjF|$yh}Q^?>~Z08` [)OץRJ"[0w6&w8&@JrDˁË L!=ƚvT8O}9kr+ &M=췚#B;RLZ tڇA$DǑ "A 0BPbE /gjMBNXe+?u]8 1tc*AihM0l d8zq)%"D׽c?48P;/0R~x˞,ETe m9wDhaF|9}Mg& Q# LĻLOZv|uEKͰ|Pm0b_'A<}GL"nɝn {q6-#)mm_<򀗨D[p(d !NУΠ];cJ  KU(Mͱ |H뺌RvXkW&p 4Br B6ٗp/umdވ~Qn?(~uAL;`*ײ;Cˆ{-q?SDEp\bRl۸2a#˴7ʲ UHCr2_F#+!Z;'+l(!7[ǃsګ6:[j0 l9:$D:6b*Kє)3QyB(̢ТFRʳ:oIV> LִL:&Jp09Oȱ(w YvP@T@1G~|NM%8T|\]pp,P4A˜sV:ql7r150D6Ce<BK\pAAKr=)ı[tgh?,j@xvg#) ,7GsXLa`/\% <5]c>["+z<aA)I!㮬VSݤAut4Un 㯄P R_hϵ|#*A\gO C)|Ъ^;A(HmZ ɋo᰿!AQ, LO)trXMdMߍy 1s`Ťj5;O4E"k݉rpnKEpsp%..N?-ߔ &> ݳN%u0GhpD(<*bB5|n:-(Z`U8E*)?Hx#hi -_lc^@.%RޏXj@żJ&ܽk#(j^pp3K O̫f+f49Ze؛ߌVl9Yjg!#^|.E1YV]3@sŲ. .ĢrF%%P XYĘ-|boE'` Ym)W:pV,A&ul ދ/:ّ%OfBRoǛ2,NS)ܖD"}NqeckqZA-IW-V е%#hHbCFDK=n5UkT<=D&\pbV&2<&2T'hP= FϑqBݏx+^g-YERnp`)1@ҚO3qo8B|(yWCS|7eKbZX$Hy=NU05E<αIZwic08AY8b> a+4Q.'rǠ."JX_Rh7Ud1h'd[ܫ^d(:/Ix!2th# <7}c;e Ę| ~E&Y"h#T8VRi)&^pS1KkSW ywU\M)#h0&䦓 nDtz˔#`67.\y$稏}/'GiTUG$ "0 ʁ9[^ Abi=@A1E,kLBqR\n~zb9]ZΙEti)aۢY2E|=?E ,N"g9ҞE哛}x`Ak,}vC)`M|;khuq{vWcۀ -~Txfg19- ԸlO)&(h8UrSv[>g0 %rMp> f^ZW _GަSYClqm>,e%"jľcqL. Fe`'I`7=Ƙwun15i yR߾׿|pb} x^׃=Ԫ%,̧}EN-pBC;sL2a#Hܐ8 6t 7:{S^9s"2f|a eW܅ekeuKwzӯ369~˨KWaU /j(‡6 0@YIe=uDpW+r?PB֧c+nt H- An5d͢)ݰ P6JD|c)/u_INq]^M -e@8C#' O}9Qd@<4yXP\zYNtT7bƪ6\+|4i_EVxPuh`~V7{Q(BWmɊan*HY\EiېXIvbo܏tlWC핖K`WS ò;WD3z5-Og$#l |e1i1}?~W$~mJ:ĖOnX$xqYҟ!;]C<3H_Z#fUCZ-"4D;z_vpQϻ_!$˘ɹ㯴fcäODLvəGY5u~.:6D#q_DAQ{(zhE[m}*oqaN#-wH'Z/&gg*.t%;(!:X?I{)-!2H O}Bd\)aPTgA&J'CfsQ0t.<-=ÿM).-r1]V\8u|Y}2?bt\ĕ 85ؘA#@峖a,@a(u`s8  f?EzD71BM Q\jSxdJ(+%#`Q->SefkZ?K-y۵0:%^K!\Ի]Q8"fޯ)ɏ&yD:vDaӜģ尿6>s((^8eux/V44vT[fNTꭙm;ԊxqX1_!]r&rfW,'=ZKdVK S'_pD7} eZzuUrBZ_ځ luLh2Mr ПV&UB .WdоLIA_8qlm_$ݎR`!>cƊ > Ev,96B?. 3ԤHɢ]#&Q#3ey}E[rԧ;RZ+KYÿc^Gm|ALl;Rc)}4C0 @ih@zr\x@H|%ɏXʗ׀)[J#0tbLƬ&f`10Yأɸ.&+R;"Ǥ%{.&H>h@yZ?īLEBjgႡb ۾c :l\% IVZ j.Gwꏼ¨μi@Cv \_~<8f!i&l.=Z.'/)jNJMZg0JBh`)Іrw]g`HQ5oϩ g\N|6\ٓ`+i̪E1**y!#) 3W"~JAIRaOZ{|%:lns [S[@Du8*1Mߢ^1ʊ"a+4)JWX|M(r| g?Pz'R VJwz*K( ۭ7c_M9bRoMVTᔎ,GYܽ^hB>~vo2h{c@a@k&p6cH@+@OUht4'TBx'Rf>%Њo!H܋40Wi gOUG> #itDܫ쉨ڸYcmXD;!Iĝr*x=w̮f3,;2NLanӜ qO\d7ebh]5GzV=#@.Izpz6) 8>NN=@vY A1 "mLѠM%x hص,WqѴX0l+ x' J3("]!'#峙:J J1Ę@e:q* \4-eٍ9),oYLC:<"EbmL1 ZhDB`ahqUGߤxU)ޏ-ﴙ]#Ar[.*`0p=C(/hAK`Q(s4*(y2/^i[Ci/|}(F{y&ÚyHQ!#TOW335o3{!U7E”\'Ɩ?9 '?,#@02[N-*Â'l 0Tj7 >}SY@M2!pĎ%9V/4>>I)UAVtYiPlp-mv8Ff3m?~Gl2tLr1~ !h!QLaX]#*tD49B\è5z!ȦgFrȝ P$1-G*H3mKr$b.?riAё&e1#dS\cON"ĩ&uK1 HJ̧y$[%0Ba,}"̃alra$rqBLjk-2rlYOn^A&q6uT|1Gt,2Xq(1 O&aGx1!aҙQqO;O) ir3T^/4^<=Uϴ#jypLy%![W@oUbS8^Q[*W'ihw0eE g@[k@oDED>G&y&BUʳYsZtv󾥺wϪN~* 47 b;zI VѫfԌnW*A\?ڞf hpXփz u㟸r&ɉ>+[kPȜXx^+~eQ Uc;޵<%&@Kæ2~5t<K `RYf,"M=AA61 Mvsd "27(LXZ R}4 $Gߎ&W,A)pM,ۄKsŲgHEm:$gD,Gu ҝXy4hgO-Xqޢ1r,$*Z⼍jfa;nc >66O^4'0h hJb<%xiaJ|'xJ͛\̜sx8B|JZy74CHѷ40'V53)|XZQcP3HΝW6CDNa'Ru#t0Z#"Xqz=|^P=AQ2~BJ[}1,8AJ+:7E'_Dv-#:~6[h:'zՄ_m^:90TA 7*ih#fq\Re(xe]G2˿2=.-CF[g~U]c𵳔gu9 AjxMwPZ "pԬAJR1 ,GR Jnpjڽ"Dp7˰ZJ{.RԠ1 x{Uƶb#h/CU + |0xȮ3""iI6)Jw=}̀~`cy&\-A6 _n:8I`KХW'D+IJ|´uɧ׸R̵N7E.G48e!vUr:3(v D7Mb%uppXr~.Tz( &]8| ?fIӕn=eC<* Hq lè(i3Qژ_qKVe~:Mffixpu i_?]Շ pPK!B Ҭh##TDRB;֫|uRJQݭ̻:s{`qd{Ϗx}^F6n;Wa8UtzujJ2Sƶ'WRd#)ux%= `8!C-(;B=./a)En!ăI9 ˷:DՕ"dqoSDA7JPu 7ъBǷXȍ$ͮw>Ng_= o^]F@IDAT\,cvEHXog([=ŏ7@ZK͐\η,6VU;;Ts阋NKJ \b,()ä5΄NZ5|7V(*Ug&GɸoX$&А6ÔO/tq'tda|уS㎅[573!P"Tl`,">Q,+rVNGW΁)ƒy~`JXʟxߙ DQL6P?r~f|ӂ[ %Jb_XvQ'$g90#yH4˿vZF H$HsH3X5@32PץTUXWVI b8}i_)w\ jaR`v;muVTt|??X&^%#Xj>~saq|n?ۓ$bWN +`3'bmK8)59h9pZEJpo7yE<=Ay OW#%ɳ4B.Irh1Y{}`^y]>ru=9[_=q/Ⱦk'R\w~盖&sMxۨRcEۂU*chod"`_epA:JaaHq 4K\!2Zc-@n 7r8)aSBda@U&»N=zsp.Þ<ݻ e/6N*nGp(k\YQW 밳WoO~L&ˇ_//Zݎoowiu}R}.~tNdS ʛŖ+ ̗nKlQwlء[7_ "i\\i",QD^>r$W溻,r6<mТ{ܬ6^6D~i_knq^/o7wtvq'xn뿭0TJE>ݯ!gp_i?H`/[Of7~,”靌uI-\6[-Ǫ{OgEA"9}mmy7Up@qx,È>dw%Rۅcupz9}^WkE0\Ձr"gW(Zqbj$ rOE&zzNq?af#Yy)(7UbAktd^K$>)!SNY%J$|`8TBO!& <%YuF~Z *q`BNɢϣdc: pǘׅʔ]I4g9S#$K'jt4Cɉt,/}>aM#Q!w[Iϯ۟ q='.mӮ m~(w{@Yɑ9#_4f*|4#E|| 8%2r/ٵo1¡~?Rh+Cc5 ,?IE+2H[X$֖jqv ]%ڷOq;(7a$hwA0yivO&,Wjٷ"5ʷ<@WeCӠiKgv<`Tb2Hr:htYIOY`o̕VWC'=+#x좨 r;2 ʭl~b|J妯8>Q„"15DQjD$ϟ\[}춼6Q=~x܇Fil|r@QDw#D8'ZM[!XwtG^=kɽgJzfd]b/ċvU[%f9w\5LLVWBG!Xk4|, = Aa:Volp("߄ct$[l_tmnQSܡSsʊʀ:\i>8}q ,EUoFYݔԑH`QV~Z|3?hLO[(d|B#yHçmq)Xaҫ;Gnk\A4tѾ(ZpBx7n !ByԞ\=*EC8?q;LuO\u(Xdܾ]_QX ^2! ӧی mLJט( γ rpKz*r:Z_ݹS7d)H¦mv2V)#jZv.rY;fg\:V5 ?Z ~`fEz-Bc"xM 'Ql::! C*uiRW9V^nNy=}jd*lh#vۦ }+(V+Q/J`KIíjp|JJM$tO+f!>pnW *R2cYϲ%&$Bj7j6ך/' [|ܸC8h@@k,߷MxWtn`M{mg@Iƣ)*]PaEMk-v]I#SèQ*G%Rr2I\jǂ8laGYDTz3,EGK ^BtF]h5(p V6bP-sHDv-NЃQŽx[+ߙ;ČK {uY txAkdh019O63te?ADx"&/ c:#u1N@2p3C0 0e[1JΡ0ŋ>$#5X& &b$JJjx#>2w(M/{1*bzXQʝ O)2Ѣ; JXsy4 7fhpub[_300 VKqK bjR F&K.F-Q ށ [͎vYV'DѾ'V/&=t0ZFp㙬|NMdm6!bcK]%CMz74pl W&կ> nC)H@ʗ*QSo4qOMS.qQk-tߋRGۓiE4)7^&ǂ(" MC -. !:藔H-$pEo{v"aFp"9&ŭy[toa)zZig7gBzE TI-SB)3~BU mSϘ)5@[Uw#1TObr)ׅ"@3̡2I*{CCK*İ؅SF`g&x2߿~>N_Vo9B_Nt:5CvW:0'}[&\_*hp@pd L@$|Ԑ`]+[0Lwv倰%dz Lb7Pŝ@y~Y[56ަ* APLdGFM|R-?l7ya;kTW'Ӓqkf߃9E/7$bcgS$x3X2BMYt2iKM^&Nc:pTKԞ1C{zT1>bCYP`:BB?P6姃:gKz c~̛/_Ц@!6xnr!wY~\_|#Skr*9E`K3x5iCScG<(@bӍ509 ho(pbbGIScBU1= :n͢z0XOВ ᲗBsugdt f9@X~pk~@i$η #=c\3=xL W!0-0?sJXRƿfL4F 5t |縮2r*lA $;#iG8绒􋍚Va^Ɇb 2a{de$怋=n^Z.€OXBEJ R§oJ1_JaIE[ g~Hț#k@~s`hOݓ6yPOS0EVQ0t Gm wl&F3i/a`I{hGY<Ӓ(Ψ{$5*Na9HvVdجi#KYS \(3Z""gMaqd.eZքiܹٵg_Ԛ)ҬH,8(x#PpuVM} dy/9 SGVEȅo+txGl6zQfS9lCg"@=5=>ϱnnS~Эs#ÿ"T~O(# h⡙-M&!$#_ pۉō nvӀEg+iWmnLBФ" O2`澍U(Ŭ֐P^F2ql.qaօk[3yr4`Uɝ#CC][ D5aRA@4$R66ys[4.mA6ao'h6hULcf*.Q XE%ja>WPCO.0_6hٌ|’:#0vLd`M66N/\ߜaf73s_FYC/!0#GWGE(%JtJ'Or[)@v2^5#W!鈺ƶx:&[_ju_eO"*Z2l@ZXad^Amq-hd@Xm27GL2C]g[eeYB@Gw^;[s'cE%Y]%/2]7E^r0ڨFQ!;JQJVC[=șXϋo/wC:v L0HZ-i$b_7OTU՞ vz(8Z[ )P^t/VKʉJ|'LGfuo7 C^(w^K\-n~."L5YvLS~#!^&F,mCCN‡$** 7C>[&g{aD%fo</F[ˬшggMwd7E(B *=߇;4aDԐI"254q/1o;L7 "5^d:Vȉ4ӿe*O3Xbc }Ӯ}@0j."VD.Shp%9kМfhR)DꁁS /ѻy$WiAp)F3 B9&`X*#Ԛ$yeǀ(?%-VH) \亼+"{vf޼xj 'Ig8o'+}WJs6̀0i1hL֨A 6M^o,V`Y-lQh b'.''˿/|}yjD2ag8o GBGct3Lpfڐ43G WE?d6r7z.F47X1NE+AB~DJQ.۽O;S6UaP(!(δm#뼎rHA (`$K#0Mb D}O80գHR3W7'ii퍝|B}%z` xc@$)N\A(Ҏ}:Xyn[R Ay{9s1-!`"KDe&ՌhtD"bI83y$e([}-(2^y'S=:%_^),E:]OFdZ2[X$`ZrչUMycahDfJcD d&D>v4siE &_;?&SILdk>  ܜ_AW:KԒ8*p(΋B(z &:I(| x I0&NJT dv1.'՘](rY&bŇʞj#@jjr}:_\8Jc=̝DڑLy<hЎVV(@$&t f<={dʳZX4Ba02boصJY5WDq5A*a!޾=0YϞݦJuYBNL+˳.{̯Yv"(bvV>ڳ@cz2WE@|jEd88ZN$fk?שxҬ|h" P0 mۮNZ`#7JMVNaJ۵,ZMbJ!S%;Yċ6emsk&(-2pl$Iw-pgxGO-]4հu|_m >s\„3U 'PlQjЀ}jYbbR8=Ky$$[HAłwdEC /Ƕo#*qQw ẉa:tgLU](: Y(3^'gK+C҄*qr̼?̎!V3g6nOGoMq$-Z?S@ ?E;ݓKz\NL9(ہ'3̙U=pa!.iV/`-۷:L|'Y@Л^q<)~\7P+i7)n_aoOI^^.=R/|j;dUgsNUXEٮ;.VTIa d?B?9n`"RQ `bMAS&IF+ḠEϫz+,VĮbf.Q@(]t6Bp=4OmPXД1Vȡx\܏%ٵ>ݥY#S9B)x_SY\CWN.Ll:5]sI jM'kXabWA_DTLhۡ>(zo$Tԍ.Sp73]1hG}&}06J}m$!_P&Nꘚ$#,\ m8+YQM&.ԁ%*U;%< W'k ingeAymfUO, d7R#7)Q4WuČ< <0LC7foy5B6?0OZo2.iwLbs g@Eh:'T[_5rQ#5fEh @` `EofiD%vVә\ڴ7/ZCL9}]Qk "d1lj̎dXdƄ*e0!^d{g(3R oge;09 YaR=&t0O֙͵,5e@3h&]&t+csU h҄KQ)܁(ɗ1zUuaB}+1OQX1~Z~ [\] ɶg%e;5E_tϦ/{G*!Dgba@6+e*3qH7n:L3J^^^B#nMLVȗ[w+Ġ"4!>1H}d?[[Ubs @Wl%VRIЖǭT.u:To"i!m?~;۾ȍ Z?3/K g.1ocGtfB璌2uyӎ>l7*cǬmydZo%Y3U+f4L@#+[ )6y"ࠕ~_{*6I]5t7qu))x*zq5ݒ~Or(pJw^BtX} 6:f#>/ @_0c Ԭ쏎sS9 nB@!RH:nW60K0}P.ΚMs ?$a'4h5bDzDܚ7{/Fh6e'N6+|50  :y`.@)f|0'[u!aTR: + *A -%(RMmBUخa5ٶ;CFQ/š ؾ=% $}neCY)_RTǂ,* ;SUrMSOd?;R&'䒉0røB"'#nN&1O i(hH0]%CEו17izji@s3FGp'1l5"GR>)F9?FfKT.~RR9^)n 8rU|d`s-f64#Uey?(r[k~SR *ŸuXm;_wsaV";SDw$Rw_X #S_ϟ.#5լSPl^Za1X1)/_V% Im&L@7*M/ͩ\t~67ڹ{;~oߝ W'F#kVI{za"EĻH11yO%2ִk2&&#c-)&Oda_ 5P妹E,l*#%BtSer |}$Hb?YF8" ~m<*ݲ ۱mŨʣx2 "H "s`t<(?VDw+œOS[(;ϟkCBݧLCW1q [%]9+z(<(y2AU`lZT@D c ," iE">>Aу.$n|y~S7yvr\&ڷ `{Sp([^DKwvls1fZHg2l$@ATk7EAdr䇽洒\Ti@Ee%LUÊ~Z;hat`N@%*Bt`>j)Jsfx#ȇ(5cLkD0qVoʥOgNΔ+Io$TG2+gC$$zޚQ= _-(=EYВ"kKmG/GlQKze8(g@L,(2׷n'ъY!%-[/aVߏ}mKF[Z2@BtOAP(_͢v7Dsp6xQFhUp!r$\ἏN8ԶC]XHiX:yPG4+G2/5<+tX\|{K=]Q:ƃuO܉cSA![Goj~q"Jz2(*SESHG2E\ƚIlˣ鿧$gӺ8c  b~c(;P r *uu$hg \FP?] tR#m{Xo&XuM rW4 樮B%ݙ?oE]1cƐR{`j{ּ뽨,Y6\i8K<`4pb(1p \iQ87 @U#x0쁹^q @4ioL/us&6Y6NPSBm4uONuXsy`X& ]78X8TnE<v>B=*q M`,lòWB?2cW+YuH Lwk.#6^+>~Zϙ':w' q|;'9|zm㱐%3ϸOi,y 3A&/,Oʪ.gBVf֭lkMIIFsWj5D[64UzH!TLIOS 53n%G p/H/ Z>XVZep0 'P!S%ψlt TB·RpI*%@G'=35p/ `B Cjf8qn.a@Q |@JUBy)RBFK#)?IőU0&a㊌yB='@ > ]ס0r$L` ,L)퀼1dڧh57_Dy cz!t4SM@sw/J:dy&o1wb*] ${ r/P@IDATEy:(DRDR"P@3̜n8obB0X%ӏjyf>HB1\$oŮcъH)MU9x{j8xv< E:>{aD^FbDO(tF}KE xP((U1TC[ЩcdH|”TA$tbhuѩ$kuC /Խ/wzxVy+T!ul ta)!:P+dEel@O\+ b+RO΂Z zh+_Q0t47 !_MaRBV $B}J'b1'evS. &O i:LN?aŒں!ocþ5Bv"j zeL Q8Q֝0W׿ ';^5%Tu9G9y$Te>-%/J"^_ߞD8> C_k\sv܌S&Aنek"$PArRg[mUAg9 10vw=gE/$Q ̡(o ^"%)L:WmPtg͞ CC5qKa(Tw2Oqy4 u4wc4,;n%3E5_-q)GFڜJ;-Blx9l\VE3I`GL81-pD ʪ~z ]]dx"dѐjin%h@ ͜yoD > u0/^{@hr |Am1A& vc 1be^xM n)YMe1+sҗ땔[1UhBVgrHĂSp@e?8cIy y|Vֈ>>efVLj#@'?m>-v1QWsfY!x ޔ޲~;suPN3Pd D :em*r)0OӊFbnѹc>LجpY[z(3$v bM)+ dN`q1\w896hۅLJ @iI&#<3a%85'7@/?| 6pr(L֧C/ v n{/).$\;וaG(9"ONK]_;agʸL)g"3[qZW&/>vQ? wD3ΖoObajInB ]`ܶ"-U=|/Zg J ]2t I,!C]S%O!zx 1}@76YpqVew#2CIS&Փ C֔p<ݱM/Q ) `%ǖ"*_rQʣΛ+OeM m,p\zbU<PGnL S0UbTYE+3>Nq| m'O0rnd>i v: mf{ُ̚o=Ec?U 7 ܛ(v )Hx=} oFڃ6R8< Tk4]c Y`YٖHZ7sh]"?4ۉ[<:lZДԖb1O VgVE2=|/߬eڷ qT+9Ju<@=:=~mf5\(Byoo=o J@?uX=!Fқ٨T^zeU:a294BЎIe3OZ_M4UJԪUߎ|j7{%YiCxOT2靎l ԍ2up-׏=.dHqL>=nl$*kre#w*~Mk$"_ۗ= " *ǃdI) DBᶵwE(s_%G$Z"yÓڧ2γf>l0q.טX̢M/)7oxFH^h3Ź#)z>,W<\mDnb/?>WſBSQ;G`NVHo_G/ek~E@q>GГRNJJ(X}]TR.[|! ny/=]ZzuJJ o&D[7QZIyA G[QL0BչL2I!yHșiHlFs뎺@X**Q{)MU1e+&Xsݤ:TB!!sL]{ "'s*:E]DzGalG빝jnjǓ2fyG@0dY9E\>Y{>,s|4𧨪cĩ ~vd]HLֽSB'\sᯇWnt8AOa,y6gψj\8eQ9U)_[RS11Y0X{}7`Év;S*KA^J/A>Ⱥ WRj +oGTb$A-6 ^B "i R'ZY,os'FmUjtK:ᝋ? "^(eUx1V nУl.A s.5ޙ+* e&4* >A^GDEB9-\U7wm^+jPchcw<[7!x_2tNO}0)ctp/{Po쭭0`XսEl/*axN4>K=2wR (ABCB]r2!C " f43ѠJ\ѯFr۰r26x|CknlZV.)QLbk=40uM^zD5=JNJtSW܏1vau BUG ,2;_ Ҁ+۫҂+<,;f\Nd+rNF@0 4ac,A 2yjxMc#6&HzA[>ups-@{#eԅ#{9MgDE.&dJxf9ߙEs-qug=OMob`FEB45c!OrXj0.5(jrg`¸9BO%%>0J#rpBe1xD\0rnaSnBJX腨Sˣ{DZWqn(@a6N,A#P(Mτm1-5مBϓ h 5sO;%v+pb[0 *폊&ل$߇  ,|cx$5豣˅PH1'Q\UnTaXxQZK0ClhmAKRSL@ܦ miVh6 &[z*kȺ-r 9ńˤ[C*C$:q15{x  _Gj.Dvdd q8w6+(-e,ۈ l#WIRve*卍OXnP>2HNY$LZt ]$*]Qx ^,aW0Q~hSD$*.Q(ԅ'F1]%T8}; 2l.#d%HBbdjٔSBR *X2Vh)ظHo<QI=+9,h18ƼU^Q 3!" :bH&^'$'bdL!Ңy"z(Ij1$ JƆ] /UTi |(9-RDvBzh5R#,G=ѝo WmЦJu'pP `)=J` uP! @OW0dh 1K3ZxHI tKrwh:]#BH#hHd7 cf[c6BY@%a\2Ts<\Sj-L}# 03`j{O$e:IUXQb:ݪɧns \K]<'6&|M"y*&9&[KBѥiEHG2y Ꝃx\B$ ¥G)3cIwfn3Gl`nA>`[e*h J%v#joyPk #Fu(X(u+]`A\4'CQ\X:63kfgffeOIr;$U0L߸jنo4Q= ZkwF>XoߵO"2ӯo>Z~lEABϙv9J7j=#T)*"J~[RDQ`WbQ'+~L/}ANg;R $r Ix-c~j܂%mc: Q8DGEK#Sgh5SOK^1G(4`ª/"5m %ÀvfhrȌ GAPsU bO5ſ~vsDnYo\iWcBm*8~Gg#@zfD ф8')5S Y%Q0c`SL7sRzYb~̶Z=e{b9*5`?U6E~HO 2sE^l}xb#Pˌ#ikdY7 5wMlC O!UtG$*]I1qI>k?8gإ9e ;y<|WY}3w؛V>TӯN8 vQ])"!"ŵFmPc ҦCЊeܛ<4,Qg |ktBEd߄FcXǭ|iyYaFᒈc `{N'P|iT&Gk':t[HpdaZ8(#aEV?ģ걉 HGB9;Ôh-(Vr|(EYu햷'`d,PI2LFM)g A(H57R4 Glg~`$*$$Sw2] T ه, 3YEX g,(D.怋k)osş*PGκЈ_fߤUQɌReN#~ )"pm d۠t4 aJX_f℩um"|8 9Z~%#o|~)(JGxkяaDM13Y%˘.p8!@ͦgNib~A9!#T <{:̧@.e(;^C5HV?*<^DiJDT+JDEC\k)߅B^< fz4\f@lnK UhO2xMSg-`[-ôz<`*6WU{8b^c2 Q!Q}sk2,~ҽ,8v\x)"cW f{RӲȎ_$όNʂS[خt 4ޠz9be>I>zyY9EiӲ#@<ʰѥpGpq1Z+dZ/.bsw=ou8[>`MYa`I]  Wā %"V^s7 }rU:5t2T6nt {S@*eOT,QS-z )kj;DoIFx4l"#;8uB%LV%|jpI1F ¤8J Ҏf,gX{-x!hh.Ss z091LE-#[P󠬅 m#Z)U +24"C"FȦM&xRL۽<+t:4xz`“d,]Jv_8e [C}#  %VoNc-tX#M_ۂTLU+5ACdF;%L<@ H^1b*sѦܧV(Y kb9!"p,SSm83[u 27hdDԓ*TJ^p,$!~A̪y/Wz!,uһ^NdE a;9m"GL@DB&!_+?n!c/,MNyCdsǫJj ʁ)lϒc5D6TY(W~ fomPH>Uӱ1Ө8bu$) iŋ.kc/ⓨ$Ͳk4PGCːyP=>6e+3pgI A9\Y.Fyq2|)wm "Tn/o&/#K*16gSt4E_\ Ao:V;{d{ fHQUG=svxS09́7rY'!IJ.0YΌL :z# rA? 'Nq A(}V[8#P@^{)tҪRѬ^cxshPuXX4P%MYf/TChu+,JA8 o`B(sČϔ@.f%r~O/mjJɆ9!I'"NxE |P-&-k/j9Cf{l&1ZPYB 3./U*꾊ro\}h )tpNDok}i2TR.!$//d-`haPh?t0LtanY#U Ȉ*Zw1 *V#ޠ9] W.[$4tKb)Q g:„- LhPK^0рowx~>)6?`=O04w7q!t}RFLAy[70mt(檪NE]‰u"h!7qS_H,`M+QVQ]Anѯ=.v FW/udP f4#|/+advt!U,Fd)|o}K=DA'uEt(+NwGepdQ [gECѪU^5l2D%:vW3ȆĆhhn,Kpoe,1]RѿQ k``𙅨f(f F`b+6D0a+E؝ ЧiMb\?CV9ǐ Rd儮A2.X&D%cțLf`&qY gb-ʔ#f ^Ƙ. =}XXy ϧV fsYo|Irڐ =[ JUSLY,憸k(L\F8OT[9KÚI) 9yO'jCiDoPd8/tj!:HRI#oy 78NP#JQ)T!AP uM7ť#S}!hJbMc8+Kuh4X9Y \ӏ;#?IW쩴E<6BF춸0?n,4|C s M˺r.cĒr48ktTEj{kﶸa08ַH$l&GBjpdzǎ$T:@x* {rʻ{2n:[aiTnpqGHN{z9ow/oVfXx@#Ⱖj.t; L$Ow3&v1$)mcǘ6H0AqIuOо\[oҎU m"e׃c >Yr=ڿҽJ^V%yaeN/xda[ џF\N9gt9 /qZHvdh ܝw3<>? U`'7‡S\ZSfVgL!8ّVpӣ3j5f2|'PᾜRLM`Qr=uZ8bb4vj@JoP. DJ6w:GM,zZXb:Pu.KD> Ah:裯,*;ϱN|fho3(~^\QFiDͫ"N9"p4uu t pG4q@BەJϒ`th8hY4'rwr w3blEˍ}E3$~yVixS9,̙E΀_1 xv}nv z\z2J]7E'/z1=A ØdގLx ,jF[4`?>|?;8d󦃸}EX6Ɂ T]TYͷ)?Ko`]d=bwoD3гL߅ (4-oX utEoqSbG g3auʊ!٥} z0)X.6hСR4k1 Je=`㷵չVnuKZ:TaAZ0{t3JL*H;,`ͬ_MsܷYp/4koaKFE& ^J7'j`D3{!"XT9%B&At侬NnKl_W'GgDn !e=#ypCr7v'q^:Ttj.lQfnJgz{5/Q;gH^|XCg}h]"0V(C R>TA{V=~bm jG.7~ZںF)X;e̛UMR͊!^XȋX2ľ;ў5Q\AFW Bw~ xY-ğRZp12)IA]7ٴ0a}N,TV%;j{f)JDb(xrp GĚQdsyJwn"My}$86Oͽ66M:<뙌7[YV2/描Q-z:AVcw %d]6yjWh,h4.h_?u&Ud 2NTsiqA;?wߍΈH # 0UvCd o{ǣ! Imn8`kqY_\!}H&^44[[#(5\bp"q{Na-!\=|#7R{,$RҐ6'@a'T=R}ZYʷ Vw2U-4b4Q2M &`=cheRl&@Jcם'L2Pxqٱ$KpV@h{'UR!I@1&/Fyc9z![)Lf-Iܼ@L}+sU윽|8 ;bfxn!,ꢶZߎpbSߎKCOrk6au(S)RD);MbYYڨ!a VKX7׈UWԽy?]kEqRGW){9RkSG Zf\(q#AXwdC$5,Hu{vQ6k2؜IIS aq1a= 䲈68KwE<6Peg-.W5[n)P3A*B51V2⽦D?`#a+wP\@$&zSīe*H@,E1$,W\F9r;F3LЬPn3 ]͙0+ S_ yϻ % N hY}mΡZ={*B,!-e24PKۑMs/mgC&aषyB!'WFi1v NC o4}Fh|JjдD&h`e0@#U%qF!,?^4).%F*^UjBD2Xnbʩ>%1~UQ;Ng|iuDrfInEj'7q $|y^U_F!Bd(.DwEY DzS Oaa7_\H^s{`,>y&af.R*Yp9f#w)eKчj=K`SEr>Gə)zFkCUnz6C,[Fˮ#o=M'v2ذ@cp@7H_0Cu(@{t+ƍEŮ@:+ g-$>JRڮiRf)p84]ܶ.'TD8/T5c à&ɘ$AQڜ\ pUŧX"~1D6TlMT&tJU%>6F1e$ᓰ<ҁ4]伶AFTEpgRD g>_tdL.;]ds8SFX jS۝.MY [7_%RPEGfy@Ђ?Yw.| ߲^݂ggoj]]$h#Qp+{j=Ižx`5 $ß8<ܿ[6x`K0<&#cH @we:X~Uc+.IՍKBPTSEQKl*6^'Ie#L17g["\DWaJH"[ԯ.zjeM M}Ff~ճC3;ڈ)!l<-.dP&s<)]9d(s+=sی;}2ǡgRseo ap:-fl` 1iD1nAܾ#93,LA76'8TmC, &aL`w̟F 'a`uRi%Y+?_ SXJ&7þuBh ||}UӪкpF~nBdxҤ u-n?1j{ )Dttb#W>B9xcw -6ҍv2/'Zer-<rD6,~ ]:9Kemfe?B;[&@Ȃ=~I <~*XVvi+q (?^fV=1HDR?P]q$^D{tf^CHX-6G񃱏O1Ŀ`~Q(EYLָ{St~Bx>Jhk34zLvPV@jb $?xqkmv<bQ*@t99#H{TxhXRSʌ4Զ_@EnaKP2u"T35D5Qz[('n %^XtN1=_zu#`F58ec mk])q;$f&šp2āJv.ͪ>yWԖaQSnpgզBar0&J7NȈLBbBf&*BV͵ĻF(B2(R8BtT\TM<~<Ș4[׈0q+1Xv__]fU`EW$*e<4K uEY҄Y1++'f]40#r#ϝWn*9Ĩ4RVL Zx)h"uK ch|ֻts[}Ӻ =$ nvj)D }Wl*>I/`Mm(Su.#͖3;C Ѐ.\,0 迨iy4CǍYy_u  4;eO҈8;J)ypBcI [,BW ="&;aj3c]bZuPv0ͳ^$#nè-S]M$Z.n -&ѓL$8u:`70 C:XE`-S%@aag[py`J]IaY!߭0IDž8`-d0I"E%`[3JPb.!,ctI{Rz8vb㲙b$WdGq2RwL\sܩftpPq|;ԂP.^lP3mQ =7Y--@\ } */ |9Cyy'!>eUrF6lD;FAȵdwv.lx N8'(TP(:?u*lrn*:4a2_Y8OkP,Y>|"z>!(MR+7{Wqy|z$4,z0+8HɻjA A 2?ffUu0K"ND17#{'ް ]Yx%ՠL<EQ Ir5ˬ5YB W1{|/, `2,SJ;H.MwGkͩ.ԅUB 7S}"$ bz`PcMV_] $u32mapo ϭ|⠳=[>IsWMJ8ۻ=")#,1FVSX(i9y gs cg?İb*J:WFCz#\pη$驃am=1շ?NJ!( !$1/s(\adw;*dA@IDATݐ7L"H*Ny /}*TA_|(teRհ纆X W =1vX1)t.3Rdn\HB9G$wYղ gbuB8Tjf[9EdLm1K*tdxD& IVͩļW}ThTV9Šy>{BI|/p"<,PmoZhIBJZf n(fug9?\M ,g KRWQٔɕ*_ޕO`svO#Y%u7faoig8oo,Ykned˸4YW+͞g@LM=)@O,"Bfh]1KA)b3>hdhCHgL l6錞f|oWCƨ!fO]y[?qdP B<\ehB\6L#tD\ikPCTm(cHy aٙDlJ=-y!n)Zz@0JN`ZL1=Yj_ s9^zn*J5"q])udI*b<,KN?H>$]VC6F`Cbq :xPpq&4ŴQ0y۠ P$NÜR5:).Jb̯r35(ӣ5BUgK@eR)W %>qy  AN$t]inY7g{[xBR]6o&Vooqq#M z3l[7/!8,L LGEOcnR黮7^…*eZɠIL=-Gl]'IeAUW w{T\6|&:@$? ǥK39`%bVQTFd<"0bT跟#GqV6Ś:B!8L\qT~ȣW!g*I?򮵞 rJbI1WN]"Iev!{UGN%/E X~l{jj_`+svՌu^(S߉Sa8e(&ۨёlϟ;gN߱p7ٱSK|BAu3y3J[y}yt|6 ǁ?JO!D6AWP=!m82|-Mp~o/I5hlC_+ZYo_;u{M;n('z [d߻ Oqq<)d7 LگSi81/^@)fHvHN!wF6Nl[#@?G#AtqXm@(b8Y9=m_lWoDI6\M.a Jw߷ͻ CBbhPP9FJIo>@/(mw9u87r>BR*|;(lLw;E~mm֋qo{E />oGZW2\+ۖ+b*1Rxo[)%S?(nn- njUZ]LH{AEǧ4/{ \NR YL /G;Ȉoؐ 1 auٽS. J)EDflݽ]KˍkKZЏ^󯫋{vflwT( 6{.Ĵ%{PpKSQuzgۊ|iw=Bo?Ļ6)!ɛBH_R`Иqޘ 稵zW@$NU‚N҂< 6f2 ؚ\>K+R+n%=qnx<^.G) CѶ'LA@]nݧ9&I [\61kʘf8]+/Pݟlf8O Bé͛#zzsy/d;92&*)Vg:RFZ&EzkDXѩjOGICS Dܙ>\ }EvCl' R^-(4Ej<|&JhIYK k1XGZFȠ/QY{Kd` +xb!MZ!bٌXɢ_]6EQ&(x-s+<7Y(hV0gsq?W{kĀ'1sC}@Mo](_<&X^{QRgPf{J^'>:^)6D-X .\,6tˁ&efO\Z+RcFKqFV*gN-t3q3}h8Tc}xlIv )iζ=gUNt1y`@`9t^żwsiIJAQK'>ň!d>, %_Agߨ܄\D t' fT.&3>cIhKvofpOWX)$ė$+8yIkf[+~2GFxLmjTI]#]+A1Fel~So}M1Sh ;rhW:;K(d# (8ʐ5\BǮUyyNE*=&ť=='26J4g\H捱l5N %P)|XHBic [\Ͻ9$ oJ,qz9&$ΣNiQ!rfbsx&N62.O`gsV˚1YJ]>$E4np9g-H69DENX5zBo{䃨ҫ] pXcgHW$7J,%5ږx`` ´k9ٸ7h9cϱ[P#DX u@H$Jg)"a;/&r3YuGcC~` 9a)V/ogGT·PB%vBٶ 𩉠} e%/CEsȏLb`ڼj6GSϫ+5qڔh6' b ߼ᅃQ\K#UeEv+]] ^Dߟ:!鞖P39_vC+VIG)$igIvѨYc@oZHh"==џXÖp~tNݨ7kB6^6>02m'g)FH}vv2K`hGiVZ2 `/n ''GRدZt0@\|7K?R 3ռP %VX u b*YCY$9%L?6g6m`@Ƣa؀l + x\yÆ X&WRY"aR󂴈hWN96&agH@"~C/G:xgHʸq -@*KJ~PGA0.2$ bbJZ.]2B2:Wx?#`YfUCaK}Fѭ:oQr/pD5dA/K$椹9 wfg2-QOw x'1_p#\Z¥fYACdHLA7fpbYB'p.O@mh۞GEOo9 _i]iٕ]6'M";: g[R5A&7TWǡ|i$[/: DkN<{gUfs?Y>sa WF4tfgUyL]>H|yqӮ = =49Tup庴>_Ē6JBY9*))8+a@ӑ졨٧1R丑3j/XNRZmM*b#0}7WO0C)PĬyrgfMsGl\˼R3q̄0K56 8CʈaaH^Gh(#+v6rЉK+J.WӶx,8}>]H5Y+p}20"VZ${0Mx*m2)B=hS?H5QY{"30[3Jd{k\Z拧L7JCF3"_\jxhڗ[}p5MsDnBM3hPgc!d'fwS_#}S 37cC6cȔ`qV7ҵ5鎊(bϷx Xi ]-)C6G `yJ4ĈeXByhWDii6ȡG*OR-< }S]OJXҕ0mn]:3WSI~4=)Fud/ŧy܁8sɇs27Tg[Z3S!f]Q]-PQC]x(S;NY)2P1bu *)r(?C{nvLMx ;UIt=y$AyF*lyS ow^EɀH'?;kA4ZB= cR,S/˅&􎯣 $6oPEmqX*҈%d'Jx0<f 5ccܓkǷ8:c[9&0x~ ,WCo";2PSx>ǣLULS$.aHה9Y)􁸗נuS-nS3iLzCo$Ե :/RA5UOQ r,$CSp8:1C[t' z]<Ҩ~ D"HP:H5gHH ;xCBuBJw7DQ( T̙чMQ\%hgK"n?y:tdʛ TPF\U;? ΰIw}afӯGXMTB83HrE=ԠU${X2BP9943(!Κ"ٱ%ͻ"L0%꣰|2&*f+v  Lu6F[*'*lf(5ߓP-d/2klE4VgtcS58ŠuxJߩZMe*[=G^s"J8Nɠ0agN0ݥ!c不L$U6** 2)4~3<9Erzpd(;@xy"c9vf6+ԡXq ,Ůtʙ'g"0 {!0Th @HqZ; 4*,:Vh lT YV‡0nϘH&ѫBeU(8 [ LB8gr/AZ)2$&ҴkZ_'J&\ 6 J(Huc|kͅM xj?=S[~$Fn2OZʿo%\:K5yo KW[/YqzX^> >gsJ}<X902fXQXc~(m夬 9ÿ6l)Su,6Șx7cuK"Ϲ]t\dTeNd"ET,69i;+l-H "ݢeWuI39M]7@pgRסǐrBÛu<4^!CF:R$.*o@2okw@T7f%$ [gn;x:rRb& LJ!(RCZJoџ<}L,zyBQeK-~8nbyGql'_-0Z:ʔ#vW~d$Eۉ^+GQ6YZzC̉Գ* Jpat~Q~v~ߖ:0@?$0Q IqF‡f+pUuSJ) %EnάG,.xr7fh tcZDcH,?H"%.: ձq^ $-v%@4=a9|H,QG,XqP6t}Q E*Έ\>Jǯh E[M|BO);/ ,KdjF(^/4O".>#8IԐv3aF]r|hJ r此v)l8K(sO/lp};$䈋Aw?y" =0Eu ,Eթ1` Md(@=a|^Pj6^b=I=x9(.I~2؎uO}фfVL߻k4֨|WDZʍ㰒)Y]MBE| إ׫-LdәIE%RPAےlL$8IVQGPe2;!J@0Dqfv]KoNDNi΋l.U#EP8ȥ=us>Ǭu -y>ebOUwWk}gP]{_֔jP3yUdfnOk V%yʟB<ֻ?5`e1u=q5p\u$mXE<v[r_U >ʣM!XEzLn2us6y0Qd! .Sa*QG)Bw6MRԒة 5O8?qa/!?#fZS8*)-p{޾:'r@_t\:;3唄MPˀБ}!Wd?Xkұ`9@S[%plf)*OҙBv)~ବZQuՍ($\R)=>TM 7we C0V41#M-6Qy|fMB -'ꈶ[bF`tۧ  t8z ( z v׷ @ fWXmR\Wo67 !M7p6~!y b[3 /FqF})0.C^C휒PTF*+Kۊ{?RQ#4'/&J8\#meBgˌYDkP-ҙ>9鍮>5!{ `PKȣÆ/g\Wr `S߯(3nִԆ oyy5ɯ8KIz)‘F>v&_|iU< _PuB=,WV*uGK=g&7'ֿ:!sg{ԛ ށ &`kŘe;d|Jޣx:Ngq OQFZ) }K%:~oRw+]wV1ϐ>e?+8LY.6+!3#YA~[D0@)Oǖa šiй,_IEp;;cG]+8:͡/zD ᝴:\a< %{(R9{.-e?2Iz:!htǗoʤ/_oK ǰ]n6Xŷ?,6gLZ۾/ڸZy/}j_k!ug9fD=/_v<̃çOk1A9OJv6QȄu|Ÿ_CqVRr@G5VfeڶXjE] ^_.s)K%r᷵LP⭚|λS6,kmdH9EZ]KHede꣫g?%rB GI^Qc\Y}SWx|]珣#)LJU~>}koG Ѝp2 ?Jإe;FY2|D;i+˷*]¢8/{Ub74l:ƭ ٪|*! I tm[62e/7[yIk|UtL*{o(g79rMMow.>m(cy򐈵DRDzPuR )ORn.a)勝ڦ뽣VwWrv@3\hFVyL@])}g03]h*um J%DmaSdTrRTS$}H`YvI@<%VYr~D9IMa3?1fD^< jC0w'Lei7Q#zMInSfNh̢Jk m!_AꬒX[ôIE#x|Z< ?}ݫT}u?ՙs9(`_TڒCa0\d@wC>)S9mnc6FK-Wr\)0B3ɩn r2kI&<]υE߆3rjdY9@9aiYP%i9a=h B&>1DDɔ`;DCT*GZo\5wXW*H#jL&./my<eW+⊋*=>tDP@(޿*R#ٙTxĭ,2Vd!03#r 2Pr3@b*.4A8ݤYײ b $\Îy F`e1hV~Bf{gĈY#BH=Y<:HlξLV]XL=!>2}X#n{|Y1wdt@ tDC'cϲZbz)VPE'<>^;Z:Ț<n\u&^7lт{AyطJ,V0.6-u^ hk2_#>ɏHMP":|po4y^NK^Kf#~28NorsZ@wV5^290'~1^L%c((7ء7Y&u;8R#F+CjP hpʟBA.ayD3ЪE?^Njtu`GB(-Gf$]#\iȆJҶ$l5<=)wIfs CATaۑ:8d"9Ft]KRdz#fZRLq:H"eU@N~# Mœ4<E{82v)4EEsr"j74x(R-%YeIKwGWɁQѡ|[P*0&eh6_ ݜ$5!-k9bB߅l ݄{;Vx22O>dƩ lc*6JWH$+e](R,GJ{g:bMq-uadr 3s;dNSw4;"c }F-{LP2T -k٬a1 ,7,wBד*L-tK7긋7qLͬq6Szw^Q/p~]b鎸꯵%%!mi{o%)@n'1F'8Z`z@vPjX urUY%q*V26O`K-K=Ƥ" Z*OEZxX+4'p1Y}<<*58~e(JWd>`(P{dcسe//c'e@LB7 uDB#Ó*mL:Wl6vYa{B#)wLB²r BKʫ'?[~!RWޭ&J OisTfD(U+bI?4M@- 6odd<(.hD,aa1{/x<6iK+=>6s@Qe &ԁ@΃&Ov |0S:@kιQ=j n3菞o0 g>YKpZ5BDR /}^rITZkr c/-j0/vDRgg"LͮefQc &Yzȫ S۔,b}iT;^q (x1 B“tr"\P2@+'by^ttwv;ozi( ~ d/F OZ=O3i0iu6,FI˚%.Bp#>dt;_i<&)z֪΂yPu!4FG oUf}: Bԉw2^}Ci5,RTq π5nI^tl>g?|v5RO @s LGub4km΀ލ3xHwF+-_f U(: q/ߘX8D]Ք:ؗ1K: ܃H ä CDQl_ktDHm;fu^:gCr<^lO#=%y~JU/4w@IDATA6jJ}b8s"piiUKϋ )%L`ߣ8YX\.~~vbS{r;c^~5? gٿR<2yycEFKD:5_:p<8 Ow %n?EH4a]_[Izm &DS72<ófjEM$#㫔7&1)l.7 -9QsUߴD|>T4pt`& !n9X\lS-uA1]DZ$(atE=8Лq ܐ!dt Q3a !_B b&6lcbT0(cH "9䍧.f5ȱ93TƵfS1q(d'gʁBC o[a ;b,"Eh>x(UpB*]%kk;-A GTBpiy,kaQj[Ten<1m1 ِ?D `25ZʀG;k=Z3I/\0,Lfdԣ Dz ttf'‚8@0 F '?J- ?bSZ,Ǭ8DV)-Ԙ+ _;r tZ}̐Trtu!T.pT(k>L 2F?Yy(=i; MV'ŒϫK*m2mfqxَ`8,d.fw%n Q`[[s`M H#F(L~$XM-5{k~M{(۲T jZ.ABWId a iS T$۞+&"i;c|1_bDFVݽ:ez%Ě= 8Z^FDhĉl<."ƐÃ7 9D6h>8;:ZXjS0}S8bVPFެ6RwLdzC(MCN>I`\## tKGX`gI]}>]Nl0wvDn]<U!.;dp!%cZNWW |+҉ q󯟮5r$)7e=ɐ΃1em19m @`ˋ^hqg]o1ɸ+/4(, xe'ހjytq:Z(R `Da+:( ix-_GQuT5[f2[TJVoNar 7٤33.Hz֫laSn̉Ha<ÊzhvzaW҃YF1KV"x`"\į楧<kBmy6%<4:u1޾sҨ#ʱXjfl qձ W-eIo .35&&pL(bnH V 0MsHY:pU(n5/S~q"ZD*5#׷|*H2ov?5as~E >ͭY5 m}oNpg|]_@p\82{k!O!^pQ_vO\CDL)'rKVM)?/9&gV~(lTVAeu\E>?vBG_c&yJTJ0P\on:V&ywo PD VNO,sd)cZn)j !JtN f]'d;j2`]+D/̀FXڥFb0 :1 [>VRbمk8OzD5o& :Ѣ =4F:)\%ޖQH3= JtES~sGdxX(6NGpGNW<cЮ5U6!51BFkaS+\SW_c^I 撏 D:4SM|i; etH2 ٓ>nx$ |d74<*a ^a4'm/͡Խ @t@="XwtkĞULa" Cܓ -M)/Z̢4h _!u/՜Ox<[3_-3ƙ-қi͂V$J!5*DM~>6+)TARkjF\t9A|{Ɇ @OEAfYPt?jg/Xy\S[ZRmBVc= ,6yvtս)37.2䁚}y{e"J] fsVge蕟KDur7m\IYiB MkQe0l=b},DN%f`{#Sz޳=lUJ05fN>ȴQ,3jٕ&@XY*6_gCj:$)O r&("XTru{l`nFn(h8hϡNDI:xe "2 )9zT;?1?og7#.'Q4B VA&oX,6d QZL&`{Ai S9)>Ií)ytv1 w0ҖݴĄvxZ\sCXВ9+Д_l/TxR"\IXo@GåCt%`h;h8Gy>9SEʤ]A$^oJ!;4dxs'̄le^O1jv1sAzm;| {I`SXkc,$وy{X`ӣhLYQAuv}VpoHB?(2ZaHeOl땒ϖyִrpA>B\÷bGn12BGTR;q"#qēQ|6_ͷoMFz\#Β:6OKIfz  l'PW{t}ι=Iqpux>n21>]W_38l´<1I <@Ö7=; yRv[mwA4])+JWbs$-k5'0?WcŭY,:ڡfMcNWmM=$_6y9B<Crmƹ2*9s>uÙa PndsԆ峕4u<_?ϏchЀ9 R<) JJ1ts3>ȯb:;Sr.LEAn'_~'"q-g;kRưDaʨrN !K5'ؕE $ lSƌ|]Bi5  {ZCr[{ƟΎ+|^~;۽ l}0a)RV[~ی8l=pN߄TH:ygVb#+z Du@8/f;aio]ӍDs% 2>AꐑWeLwÖTGE!`zwRK.~p |t#x[v+9@YF3vFs DOGau'= ^Hιgg<$eb4 ,?cRCI Ҁ@Q'/'y Oz5(iS6gG8oWE\F2v:%f?*XYBSfj:V 84!z^3ݵ@ .]?iS25'v_Y NgwCl»д}}v'atY;6;(QuC*|UxXsi52%N8 ?1A~Ca͕59l?0_ui:҄T%Tqߒ0g|S=F|i:;[d qtA6kco8ĭֆ`C9ϯ\3%b"!3W7"RħrUPӥ]:X~ba%$ɳSXc|Cܠ:}tfO>Z;2S)[Re%9R!ZNN+T+s5ɨwe"J5g!T-,:vZ r𣇖׸7?⃴Y|qcWeسd JL⣿3w 'L~EL#q9\|[0?iyuB#U35D x .[.a^vYTcm?PD?iHr׫pDE 멖 ֔{/_Dbdj@KxȻ+ +y[rL~6шTJWZ?.XʂC> cGHSESB K=qRx%4 (, >ݗ0EPbт `pA%QVWG!hfTY=-k柧@QJI"3b gZ}B?$t bWmҶ5J/D07CZU;<ާ ]ÇvrVqu]{IB_OLbX IA1/q:L2ܝf8!C{؆ЕCLPDH!4+-?՚gaCJ|̉&b^rg3Ts7P(rs5m;_>jPw<8f.]F^~?'QMӏi s7&$cgw<2%"Fء]sLY&SrãIp2W U5NӠ,0G81ܒn *dWb t]#;i}KuVń!ejt=i:K-14L׃,m n޴_,/5A}2}٭18v,ҶybĂPd)5!|q 6oDXY-WhDm,HխNƫ*cښO+n>!؁,nds.";_a;߲`eEuVPߥXYK̰)F}k6\ -01=c@_#4/nV› ŭQI1!`iIMہh,K?&HoKyc @嶲!/Z[#]5=-h$ͺ523B_y,AkJ,np':V/=M.sFڊ B(N\泸c&6&= @嘾j@mRd#p=oaeFw\o2K;1 F"u7 =z(D(;Gܕ7UaZgCm<2`kf ~K XOd sd:OŒ$KңԖdɼF":P,/fyzey2,/۠q:U\jh\B{d)Cp.O}e@+TKd"8.u͜((_9s|y`55@3~n5,z]>cd3W $=qVňf1gx%$Sy}a/%0ZgFoE3lj@`2$4q?XRPl5|g~-r[T̜|( +֒(,5z'X3iyP!%#91[ in.afccm*Zt2ʢ'pVGFa8kxt!;~Xmof/ۄ}-Us-fZߺG$A:.9$Šԉ,;X1~h;cS__MQ > 3a3*̤_+m,T84,×l5BDh m3=қ01>U;E@cDAq8ðϩl+Z;F+n͗U o1Vvx)n:IL4Dht4(Y)XEiT@m}uxž"o] rLbuzeZlR|t;\߀7tD.S \n[] B8N3"W E= ǹ|c(bw00&<  *K? =k"@Tbzs%M}ӠdRwniin02 f $m0b+mN)Qf4CݕŚKXk`S+zFoo]B̯t#brYs pv Gebӽܶ s'p_6~r( i2̆B6) 9(eybY,H' 5ti7àF ghkmV0 YģKGD%_p-=,X`\J,һ @~ эM>zM\4&$Sьlvj3I.sjbj͝vh߼ąhp g_!*J QNPISy|/%G(܀y,<;AS7}L+SjC@Q#1JPS H4 YY*iG#0y[G^nӨgBW+dA1,A9d;̥F-p9R#ehк6ZEH=oL'RD̄҉".8#4mʑlXۅ+n^,@nbrU=53h ^A4YVqyY#h.  o'0Pdf44˟b P-hn=.E꽖O-4Uh!ZA2E ?ز| -:b!p߮7*G":lbѳy!O#5oGxK0=4J.(IiCaN9qԌD6BNf53C<$UftoKI W:R.9!$-ߒ@NSz깛O,1F_ЄlYΎM=5n'[鱗gƴ>o=Ag/3HY&znpzFhRO4^xD;Bf>V0ƶza Y9);`%>Z81)cPɬ`OP)΀  60,9+D~(t/2݉_*Y{%8e9] 0p {8}4A@{|oFѠlM I|٫kUnIy6KV3=PBDH(I5R[^yaO lu97\;RfeP"%aǞq=Σc`#_>я& f:?C/&.b6ksIdN룾;[/z7ɞ);D(<;%733[Y ŤcF՗!Pm|B':h(0fl=xĪ&p!{+s/^ %0n4:zzD"_pѾRNϝ0Z6@͊Py-igzJyԇ0@veϷg {!V[xsV#-m察;ż׾UIKNy_~?0$`1Mjk\Z;)jc<8Oq:#<@!>WFAu9p 0<1嚟`hjZ. n;d¬FVc#ϓq6-;2^Lx1 %N_/ 7@# gŷ- N KN1 |@ꝨpVPS't"NsZB;+x2˶"sP T)(Zfm3 _N)G Os``j4,8L%'U"(g<[?F(l/kq%$O't~{T+gn@?.$Sb#qR!1cSڈ2onKkm| sQ#E9d 0t%z pDG.Hpn0|җC2s%*ӕ[) 5Z›^\C7K6'qPnmGfɩ /psz:B g! HT26f%RqpI(JgdnT" O bt9 Q3T1MI-Giѓ:aD_,Z{>*c6]qI/Ef< ՠIh&yj?rbiI__ ʣDwv>^wCR a_ssʖΕFD2,s𓿲%V {1c K-~,ΪA(chdy!5fv,et,kXJn#Nfˠ:09rSNMILj[`rj~NIHT!P*,cOC>I}odAmJULh輪㯓![|~5&Ĉƍtf4sp:JkǓd mT4_xF?7B-z_k9nC(8cK> ]< ?9$hWnbA0m!P #I:cel\rB~YЕ Ĵf? .]Np1"[lү"vИ(_Dt88#T?]H Cdm v3y,RhT {U#( i]Bc,^?> E#x!wF&HL(%u)^r4}#c5B'b6kmS=1n<- tE&f%4|҂ AƸR>4g,FGor(αG +gHIC?Qҷ}$Azx[V >C4DFHCEvcRv'zқk!-! hޥ#ew)3I`^L#fC`W:dWțk]/Jv` 2etҢa~(-h(9 hMHaOX*DE, -0;|kbȬ%Nɑ\KJ-yLwSFVSUG %pV|_$f` &, 2k؈c:V8_C-&вV][U̓3G"IF^_>-EW'+רCq Όm~P\"ci&)dи ud9,iɊ8!HT9Igr7\MȊhVr6..Wyĸ$8tCuϲt6)_V>3Sϊs n,(nUO:ybͿȅvƔϋèbyؾ_$ "Tr&m2C](1P۠4c_/~1"z8_4lոxLgu Xah Z=N8uт]ho;Y)˵ Yfa>IT i=w̴c+][|QJ>w=TD  ?Hbܙp3)h`bSM%@zJuhG΄"! ])'T1}&\y՘9kI֝Y'7=9Kd r;֝TM씶:8)Ӿ1͈9$o!Mz9 FK)OvAPrq^|[u$#}8e(wKdE;y/C0+ir(y4u[ANԍ_5HI~ V ``ru>@0aEp`f)V6?yNXa]SH; J {\ Ѯ>i͒IዓQ6bA 16 2G 'EV!x\qCq @L 1 ~g)v`Bvkn0j 4Rj.CY|Wi )44 -gjΚu C;BvNGg*7S]4P@U$w[aRphɅqWHD7P"0m3a]fMX |8P a '.?Vi5I=q4W92!.Y܀gRwyfb)|JF&Dk={(_UeX0gj8 o=Ac#ƕ,+FdOiyAwq:6Yuι[ŊZv¶Y"o1CĦI5rT YVGaCr[0myj?&ޖmFvCnT:ۿ F%RhcMaq׻b˦v\R{Pިqa4yW\-(bRPMl04P@<2_ |K@ t~n FيG0-Bn7a) bE%(E.(`>-+T,wM+bKtM^u HF-6"T ON{&}k{6ԭ&$'\5ĝ)/.yl^ǚ J3?"רlnBo#"ZȑBo[9= T!oSsV1|h6X<^ cJ2ZrLp뱦%ȉg5K@jf `y0c3EO:e\&B:NN0axgԗ ı ¢QF+B{B<8sSw#*0tuZ{r:l :y͜\NzI;#|3;64%Kn@PeFNݭ]{`mmX# H6qb ^URgM ՄuqK{sRe򧩣jBf96'6 2%rlƅ":|4ZǘrP8b6Keo3Efz"i@ ca|%0wn ^203FT)֋ \!P5eZW\aEr^&1QƆ+Fm.O$ e}F@uY1ML;9^^41g{6 &cښ ܥLlTISr՟QW!<hCuXG=xrƦ`s-sq-_/"  1sJјKX1A3,\=v_~ן`uL}}]"=I>ty3X:6I2|&NQBD_Ieo h^hJEx0;g` Ѥ85~CY$!6#yGδ@q "_f}pEvf;KY4LJ 09ZA.>؉/يJ(d!XQuD u29ǿyc9jJM10V/ɭi1RCf.0"rgLx>->"1?Z3I>ЧEj@յoX(蜉@aD͵E\vYS ۴;8ڸl cҏ q`8VфmΚ %m5GaR@;Φ2Jtל)( @e\iyF B НF ΃9DHCEĩJ2F]%r޲$@Ʃ q)JՠTpÝV[OS`6"=.0'HG$MxB$ i2\K޲<0wnu+bӆqbq#aj/CzSw&y%8Qd?F9!L$á%`z&6ITv6@G8?AE1hsAW#*Za-45N9`q r# ?]l6F|kizd-#عŶќqCaqMx+8sԴ=&cXFz9-}u_rv-@.m> 3ʿe?)6ڀ|rRgE0rTLhx:*KaQPʵfr1E᥄s3(#l:Y*4ibgsz .^ ;WwɥK8BuOS(b@ >3Yj]WFS [4 m=4mў)"2 7 .qOӔD\|wSK2$aTEǬ]3NA* ZF4KuЙ+r喝zAJ4C.!Ǹ"@?OLJeNdU`DХ03{>CL(cZ Mv-3;\NSGj.u[qE A[^Q8e;yU ccd2{ù`0yd%@,zVz_'~Ar]22] Ɩl8(PŲIVƘ'PԌ[Ӏب1Sv >Q^,A<͙xkm ]%As|-E%@xgyDMW rPekL><$MNh2̊;k ʺ(h\4VS )\$-)WA*ҥC?p w9Ym.&(T́O\@\Eyڧ qŀP/9>݅cW ,`..,@f<S[5(x+Ya|F̷I@ U`wdŸ&i`Q!¦,qsꝾӝ{p30Т3!tqo5Θ6P4Bć3LŅɼ){@M7[ o9.q +OWCR>ST߾4B(fG}Öh0QN? вz7 zK٫Vo[YD ҰA3GJ4?-wئ%Ue s Mݘ1bNȁPL%pοSZ\Y"48" `F<3VFtWӽqT!h\xj̤'M:"h|E3˄eo~ǘH G +=X%UgoQ'׋q"n"0'ԀLV3♋h,<H`NM[v5Fy9\}r3mxtH8\͇--f3& \K>R$ֶ3x8M z%hzXHCsH4V"apg#lGađDTShfZr!G^yٶ)Px + {G%,Ndȹ 1]ʴ-j10Æ9G vYvk|Y:F>ke(0ezrԬ' ͔Yf9G#9w":)86t cts`-SZ(wp'iyI{2.\Lus;u=h]jG) kV<l9ơR 5.?˘״2 CZfe8k _;ԇsm;j~f7Lß4l`]SJf6 8l:y͖$qTPif*yuS770jLߋ29`UYᩫ/F !'!fIzc5t(77{ޘwOIrNAӻ GEW[[@elRWO?n } {zIhД& M(8u*ćh#:fxAɅ pEIB,c .U=u˂ӯ|r쯕F".al[U/@3@"+M$2  ]ofnAR KỊf<Q!a?cNַAs[}u/g .L؂PsަX*j;ViqLٸh7bo_x|"8&IՁln^4R9L7)+# tu''6ipʗg4XGD:A!vGk=h-C1!PmXB,HO1" ly9 r!th&4ܿ9 r;0kf XXVd*4 8ɐ Rc!dJ$su8rbcp1;*jX:n4eGͲ4|q*)(Zg5%;HIs}\2ԋYgH0hRX]j.hГd(F)YC-aLt!I ep 񬀂\favVz -(Ö"^&<˃7 ࿹G C`KTb]߿ގGvY5jP+5sPO&˦&uJqb}s<N:f~uz)"?`R9#*X1 "}Sa+csx@@I]9u`ˮֿV:+Rz"`l)6 .ྜྷ?v8faղE9n*4vr^׌t(2.i3/7e } ~xwt9 j=ɍ|3 99zzws!cJ4r]kν0M*r٬8:5A}v4ČWnYmW<--kA8)soMma0iiDs3b"i)je.¹zV7eOly:WE~~u^~}[-\z.jYIynWݓR=#OOhzx{=prޟ,#6ZW.O"ƾj gѮ]<ޣ MsƩeǀ3mߤ6.,Kì@QAU\بhKxT} (ÖןOZwyo>@tT&+69jq0}C˛Ua"C,RcmBlu }@ނRKCX ˌڄ=H$Yd[}Uûf.#]M,7eOjwF췇BYa9pKVpleI8/BI=SzU))}׶9cMx3bOS_h̵k'..^CrZla:_)'$hԤV/>DCLrԹ&B`8эmO{S {m5BG@8uLi~Rft'6KO;؂fhԚQRLFXqwp"׻4bx=%H|J  Lo@ פfY7?; $8a0AGC_#ņIjyYTCNrqEHZ18+>6o*6/-m[𡰣;ՊD][vug˫_͹c`@j :;LP 1R)3u,{S{5l^ʼ;8!b2 KAREJ-}[rNp+>Lđ7)苼ѣ5Hw 2V7SGN: $cNo?Y͠c>(k$v8oA|;x^`hM=f@SiFbm>].'LSw"v,w܅j1'|lco8{~԰|? 2hG4 8I1t4}-@` *(FJгbN%/ *váBlkZ*"acgU cAG_ʍϴF>xgő"sއ ഋ BL׻=*%?\F4J\^Glx*6Z U'@Tf^0qI+YQ0̊'i 1YW,] Ȉ"Y񨰡c N2~Iȫ`WV1\Z1 kt'! 4n`ƎXOBlM,Y:;Ua@ 닰L1G*z k{SdPCvKOu-'#9T&Ții@F7q\K3Kޤƒ]~3AhR0^YxO};: y3%!LA Tt4RH[vܓ|fTȹ?rlRV^:8OWr:mhH+r8X6iMeI$A7|le=W6;:Rx ,I~Q# .aDze,W.$1kPY L`zmnM ~2~E TĂef( KV7%|"5Φ#QX1#k:5K,eL">1F6jQW+,rU+06FF,1}ߡ"GP8lRD[DZ2XiӰڥa "^ ,iKhMFӎA%q*"qk !zlNMDR h3w T(+tPV~ b8n<ο ? 229P2z"@eoH\L_FjbdNf3aLJH$"6i8!늠Tdqb=gB8LR&&UH/ԡ28[sl_K R6`.54EYeq\؂(BwJfI5yJEr酢-zC\Pfd4 `r|2ML*5_EKƉ<~)XrwlL酣:R$_r7-sp wj@7LR)C o)0BO]b &P 揊DH*iIu'U̞d?=!*CF~5>ō8 Β~x@ɔ4}+cuvb8ri}7e9ɤZ׮/Oh x0nʩ -qgtaBf]M$1b62mO_ĖOCr~t ZkG[]Ro!͎(fqzÁؐ?ꂷINBhI=G6ԎTMlݳi.kzeT9wS@mbh4!POdQ8ǀQl{*J;SF& euC*hW@3 uZtˤZDč4Gőeav}Oݸ>⍱OQ߱6YS-ck]X/W 6=Iny1/fFd=@* JD ev8w"%\Dm@)zc4-""IO)i BI9"tKEiqнy?(9l+g]g^E]@0Xé w.e؆!&c\ 0U m)+k KG&(^AnIA_x)aoP&0wOV+JsZ] vƘ߈C"`VP~ <:a CiC׆硲0X*\Mo3Nf۬]'i9>LۑWpB霺cnKijh-%P0 0 iQ !JKDZm@1%$-~S]6"*J^*#i,(`?9/o{kdz}&R 6{F]8D(U?.FH))OpMPќ8PHRI>>?'wQ8f[ f2-~zA e'$/=:'Lrcj oIBBh\7B|,I+$+h.i/Mtbn u8_1sOuYh==+p1)D$Bm!Ci8žuۑѧ&1DaUkЩVr)9%ƺIB"gB_G_ ޺GIUk&+~fMw}Wqj(00(4 Kp|_x7Q [T^ 0[t9 ̦?Z!6>]$-{Y!e[*7:`ok! Dd 1ub*9W8s;LnrFr4B6bG kv}%t%1J' n7| fW' Z%H`Y<%n? k\rH+Kǎq&8HAFT\6gϗ*pxEIW0(ڈO4-G koֆ!( ޔCCVp LS W?/FP KձC+9|W :բs8ѤQ&xHEWć ‡,ohOS8LUjIvKpaaP&_8ӣ- Ȥ,bJs-ݍ'p°RTQ2Ŀ `|X"J4ESY/ހ No<~(+,0O6b6y*)UEЦL&Ζ0%gYtzcnڡ,"VVר@ - Jc2I y? .T 2to? (2uUz\ F]X #MF8ÉOcT]y^JFيj &*xp0 /I`3xłp;W7p)b(ԢTL՘ n?Gl0FӴMP29 O5 / Gcw|cI'dl"~q JD<1AcrF;dU?$R '$IsTvy)OAekƗ@Dz8}9H:,ެfU٦eC=S3 /CL$y%kijo[va~FY|(X[#F(Os C r6CwP#QfJ%ÈɩeMb1pl^hD5!ZQ{rO%9i!4 !nicZYG[K|MRoRD3|RT h !zڈeS3-gU1Vԥ!hcH~ҟajJ CN}*phMtq8^ıpQtjyhMV(fbhJl>(ZN#(;y zfuX}ɠ%ͪ!Hi6C\op(ӶDTQkڈ%i [#V|ؘ(n<*vKІ̥Bz߷%)ݧf5r41sl{gC<04S*a/N8d އş2g e WY$#{ ͔=TNיzF93twT7r1FltRadؒƳYKRX g8֡=ĞʌXxY a4ǐd08~wl/va.%U*̝p߭6 [67}W"KyJĔ˓A3nobw@ MbqVϝt67xbI(\ @qÚoiXٍ2@O}ъnĭڡͧaYz]#n _,y7+zQ5bS Aѿs,T:Ap6]0~|)NJM"f۝nT FCa.s}\LI *he1|8YgN.=7i|tnpnv)Dm:~(ɱmPq.`|f&'`K74YBcepoJB )u } mbKM~%<*VVbl!(W'ȳ @Bzo14Cܜ* c4R\;/c+TRXw2D"k<ǎrA4fF.NR˚m&&/]x@f%Tc3pB} -+ SKe\\^QL:QF  uIqNKV̔u![)&:4py.]WSn ߚJi9 ^-/N3YXIoK[Lz8PN Ɓ47BT+AH Ž XoϼqDD@fa6q:\:$*<ɚu.͕_@ۻ< Sq_ūvLSl=kpr _@!˫]wb4ir2W jUKG8c%84VFfXSKY#$_WF8b!ҹ,xLܾy gƑmP4)6!xfރ}1kY+F2UsݱZS " *$ΎM{$t-It:}7OݾgKz+1d-}u'%ׯ M=L "(XW)EYڄ}bzuᰕtXRITز 痫w,b (=zMqy6䈠3hmJϩ2S,oB ޥ]NkķԘ4!!_ji[ދrxH3hXb𚡻j'؏P\rV}<27Q VH*]$ynOƂтM#[ Pvw{^),eRIBE)Q% NkϬQM;#< Zi-GNFh4H0RhEW3r9)!f/hCa& Ya'0 zP`G k󢡕Ў8TUuD 4J@ %򸌃3@fRMQs_mv=Z;R (S3"}/(byR|-)78^Impom66 }h sC<)5-嵝{q:l:\Pv$193'`B԰tUE 9ݧ7Eay 7ۯ cF7Q&_2b܅CDtՅceKc=UaLFɡ/1>;ۄ\]u+?!*q;^ljʊ wp ]n LIG7zl\-MPИR  QrEHCV!;LConB˴T3/ȱ> FsKDxةȻ=M&>!^ihCg@~z[8&7n+|sD'1@f]" ZTer*ֻb Bfԓ D:t0rtY}PgYq`8[$i!ӼI"VDib@&R) St z!]O%e 3Pcm_pp;d#ޤOG4{M FJNTtwl6(6í|CA$WM,7N2]bRFLw {[7`p&*} ţY$dɹ3( MrX+]fK CPd\I+=rhQCNee:cGd,D tO@4-a+qYg 2DZH 9I4I$׬ 7%% ~_o']v:UTK v-^9SĪx4MjӷaaKCjܥ 560$P6%MUaS}E]XaGmQ`'@a"m{:h%繷#Z4GDp"ɷ-RQ _:ȡUXkU*&;q;ÚzM-RaHKS Aeȸ߳QO G@k{P6a$4v266QN0bmwEB&4 #\#)[UmKtQ?WwT*7i@Ba0U!E>+ʹ_^yekv54;=Y1j:M|7iq"AV$eyf0Z+!OIq녣tY2Ӟ Eԙr鰣iEv"\z1-z1yPN{ȯD2`RObڻf:xfȍe&~;l&h~A`MeHI _P|"F Z%Gp_x;9RVH׍JA[/"=c<0+.PFg|$,Ը"KI}4b,]ms(/ aY٥#O+}}U%占>vA3]B*I;5*wW *J/<[(c w:iނp$`ﳓDԬEDpc^2Fiqs.v# 'k4QYL^`ʛ`ukT층 qV FTVgbrhjbSH ·R?#)zPi N ؘ-Դ|E1ڰV_T;<KB 4\ˀz>i%-ȗS%#erOkDܞ"k":jZm`4D"I9TbĹ0x='MGGIb*^@ +QO. 'Cڄ+U2cd B1z\hz,p|dV2*_*"Ua+*{VGI!Iڽ0 `ĨTc N0Yі.L¾-40y3}fTzNqQ.4Ra Hu5+_#N j, iр L!8E\P)SNj yyESOx.˯J.-{&^N 56g9ZHSnR҄Mo"GkFif),|QSa~Gx3h9) }˭DDj=qþ$:Iw<$S7s̬Q ;@4AUCj.i7ı+؎!5r,my&Fӛ[j 2&~1Tb qXZM3RnفlG oÞ `٤T"_{Ƹn@noL `GP,䉭7|v:^`W"s%p*d$c7)zeE \13&rk12|[-9-!5EK$Р񼯜hMP&~M8y5G%N…[T=*61ݪY6p&1 w:J|0V^d3)\hrkvX3sSX@Y+Fc\XRiKZ:kfv0)܆Ĩ $H)>cTn]uV`s{8jMK^&j%LB| 7 =¤3vд=TS1:k2#fCrC!!DiyTPMrk* MܮxZ"FX DPcE XX_}?'C%TʠZ.BPb: с!=0ْP s(B("?NsP-ï1U?2nb8$~W\Xt/ud#nzq3۲t h|əwCl\-/!eusen(,X`NB ~3W}8¸@t.;EV,Qj =1ٗ^`͚*Eʯ?ڭN2ɖp{R7q&5he-Fg@ӱ^eSIUO)׉P0},֖)7(mԅR_9E5򓪛3x\ IG6!3VUSS;zLB1͓?.Z7\l,̨{afA.F1g\Ox&GzI h^ossݐ&5ؠψޙo}k:Z ȔšvJǾ Zp#̘we`GGtS #bT%P;δy;;2.~ ?_)aaR[lg-M~? 6޲N&hA@ATd/CW2/xjyr p:J8iP#G'oPܥx<ߢa! %ۨ"n$7v`!?;JwZ!P{EP$6-d.eKJ0ܫ/5@g܂E^da%~AZx56u4+Dj k q&Tƞ -G,P/-!b'lh ]ۑT.1cǧBPWf14ۍĺV80`,Y{Iu %6ч]ls:ؒcSt*R-.[acZ Ÿ%d T4Mhd@ !DވufӉfץ2Ԡ>(8F/`SeܙpF~ ,]s-Uor2*w v J7Stux,J(095X9\%7r.c ]AYZ^h:C;-30 5o-Ң`jpgKxEOY Jǔ2Z/+r!OP}DEbX!<N;On|n#0Io過 S/֝_AgΙ 9iǻ8ʔ7W@Q k~ٖ\X+)$&nI߇,q{lg9w&H'ೲ#ٿi0W"R*b0fr;4%aLmodP/ Ӟ1[.i_oMxSJoꧬYNX?paʬ=^A2H}h;JILj9 Єڍaq% #Xp!b5 M,~B `u7}Qc2fFs?S >@6llL`J39Vmxg߃h10Yt  zhCW# l<=Q_aY\`4Cκ*L@ء }촢צthQOA9;d Y'1 ac/NgzPɍ pGLv ôەT;´!C*yUCi2Ijhݻ0N _onnV3&pИY᭡/41P~:-T )S_,(C{z$<"1b}HeO-4e rwH)͔` afCdsLMK[ᦘ(.YF% AF& rH[ @hiNJ78ߥR0Ak.52\ ]YfiU([+4!a\mR殪4y-!࢐$ |i\P?4 k ZJ$s3dLJ>\Сes`H]fȠg#pȋgO~C7tZaҲNSa/SXNr-B"LI'qJ㦋s9l?s*wN 7c#tUHQ؞A̞#T'se(9G[I2qvc[GNuc4TKޛ7NDlXwnVoo2{bkSҞ%ôb4/+BSpf(%c|,-tǝ:u#%H_CqPkSBHܨHj%9nNG%?j"K$4Q0)EWk6#3@EkRv{IRXɀȝ k_}$.4MƔ}=_@jw۝߻;cP3O8)t;d)FQN<0k: q1m-LY͏q)œ◟nW6rj1h x y*z@S\ƾ:D`%78_B4U 3;xR\`Ou7D3"}VsRW:pD<<8:3(^Na,S L&&V%\Lww3VZV]*Kb+[Зx[D[W_cfW\;)Ӥ_{8TQ7YL#q>SH}?HVqR 7cݶ )xCw9uY-=2*o*#-uyˑ h8}Ep傿NbI;#eNRCPI)ƭ`*N2e>hwCΟ_ȁkST魸 0ڗCC fy *wc#X:/Y,n&A2~Owg!Ö sO4',G4;݉d?т7+{} KQ-cl EA+9C2K,(? E\^8N`@hQC'_ 7N-@a4>@o=w&AdƬ-E>Wv"5:EҰ;Q/cȬ0w{-.x4d7tnv [(FO> gpB:@*jX{ywZ5h8\3DLdP"O۔E!+ɩ" κAs7o37J[hͦdtjnY$8`+;INI2v",fR!@:l4Sn咤++$UtJplxd6 #V }؆t6,gA'nxjMI 5NI6Fl)`ElaQ>35gD;XROM+"E6as/WlHP4+X쾨MC[ހIk.7Aj.:iDJ1vttqۊ HӠ_k|)"MX"[&ằ S2 D2eK\u s[VcM&/´"`6IQPNij.6X%dX_;ljAq]hĢbRtJmc2iPjJဥѷc}#8oҟlΦeuiaHE %E`D8{ /OS2pnݼ0(SnQ(e?љ;6@Lh#V0&Zyȁy D| cw(6_ltl2gfXDq1s.v8bhmOGT~`k(} [W#*qxuy]+M&i21";3Ɨ'S-ѐ/t WIǕO_qh! rys{%(l~]%VMv*AZX+a} $6oj,f] `,5zM62*^I>kc>RYبcO+VO:7O֫0*D5ԋ ~l*( Hl|Pg@:*0m@LO$.!\rJ3dE.pF}řuo^3mnp*푡LDݤ||1logKhN/(\|85HDUc9@b^U^"z a?o/W 7)r+%KNQ.e&`Ҿ=|D:*&>WIۛc^uD`Z't,xi:NgGzmB7 %ӊ%M ="@k \h2;"a!|IGVeɳ]AmF;絹EyHCwM>ѳh6/@EhF ez!zۀz$- 1UgSa?БJ`"U |+-$ Tq-JG OzQ'2E.e'z`Wm].5`~l5 4TMk߹\*.0sڣBPSC1Ad"!lMRh!dʖޝHj 74(&=+`Bv8>حj^B'gT6nTV8U9s]TVCWqЩ&JJMyאtDu3m}˩ɹ _b,953"ZF h:c5Dg[&"@LvYQ߮mqCLrx'$DhgB;LpPb~s9yst74&iXlJiLGx95(u6,$/|dqͩwȜqZT]MB(MDZ?s-+ R pBF|ZĆҀjFjcx鸯} ,,W(=GO`XyylBd5u%{4s঺r @| FҡG+|WcBUJhhRQ8y}gnPtCqo|Ý=]Q|&'Slh) P7njc:^ΧJr1 MI{9a:rƨ*N"Ou92fCt@)UBn! <*t2}ntb>/ۨp8$fq1Vx&>&O}x "xȃhasLxD, J&_P^`Y^GP:`,Fh8&̹i)ށgMgGI|̩#=4o7o߱ܕ 8Dtk6q֠:x:4Y jBYy$#Anf2 dgJ w"IC5EFxմ.ib[vH*<O<Ր~ggjgʍu.P+4+}RIz H69p)!'^eUs&"7{o('GmgJ"F> g ]9.Mϐ!0yI ڡݹ@h&$o NhY.DD!޴iD/pVۑ%m-_9tIG%,iPu>qOvοƀ1lAI|!j/y\< oU`zT iߌt>m@YGgbrZ 6(_??o[7{oc 64dVD/k5L _u Zpvr{Ii%TFʺ*-FDژ͐j4 b <#bY5rB:rN=BBMzk (T<`PKG@Rs0YU:t|8 >}JЦ-~;k 4r:ԯ.r'j] z[1uU)Y&߹OzphG!H<; ^3IoKtD'N};Xfqri/%2V/96͖PFII@rV3L9q]ZnoɊuDGSA^>pi,^TaX7>!>ݮlI Wrqx9- d}9ez"` br'~~S =cxN,&73[_irQ`Cwrg!]C=(#_ 4IR5I2T~*>@Z7T{`3隔SU12k9vR$)u7 tUtBtkOj0 3=뽪`\HtD-Ҝ}]< b`S?wV5'DžlS1\ +Kڑ"p[mITm, Vx=ZU!XlQkhyJ/&D6d!1!`elV2GTK]6pr[@IDAT_& JbJJAur+ $R1+eDeW 2_ A0d~+k<ࡘۆ#[zq6#:gCaZ+LqȉHpN_v٬T/#'6z] 4ya*'~xb@@{-57(miH6-PvB1ݐ@-FsufԐ\'ν`1dY_ac\xj?8^PGD41JHOU)릀TGJáRnUFc#X!5f.V4q8t[B5Z/ g>CcSk "NsR-q( txFiv |}2c-ow\C*gcvڄqLԩ9̆k0f9GJ7, ~TV5Nfō8 -ZhdQ|4*zo +@ HР{a5e] x?# \uo axdjHBڸ''R}XkqQ|zۊ#Q%VX̛u(CFxd|eqS9W}S+@2ONQ<` Df&`/7vIJj!m 0yr`2xĈF6 IA7ynl!QU3S ԩ?BT )>BK^*Uß/t6t= S{ySLj*8דW4ËپMUNTT^A.NGTh\xg)X $cޔ(u*Xe*ZۮdƢ豸/nj Л(o">Zpysջ?|-/6I_',fz` qM//GИɓl.PY7~M*Ɣ Rvm)$Z,=|ҠF7[}>8F푅v(5JOrO-ٖ( ! R_vaS`8 z9^:?ifRk[G; ˜61XLrGţ0o7(zF6>™%\lO<0.xТqƉ^ru^N$ #)Vkv-SNpƸ6IM Tfw`2ގ9F lmƍҰěNFF5i<67RІq((7T+Pfu~BQڲ%#Tw F*0BK@ʝη.# )\ă$#CBi61@t!c&%_'4kT9 ^wV!@~"g?vҕ@3bL>vȑ(%f#/֛j"X77:W )#ЂѢ CC'bi^s>4r&dx1)>aĥr %)6™ FanX(ȧe-MZ\OEx'S*~}b1gK3e-ڂ }d0GѸZM\wz^v™! xk7K V|EHVf'RCvocS!87 Dnj? #;Zf6V3,.Nf%7ĪmNy *&@8UG_)ʑ*KIyM`ߩ1%kЭ >aiDD7񍥍/7oe)Em@\>mNϧ +Z%v肨ZX\Z"<^.@k;qgwhd i3w6Б*`0$\M-|kj4Y|:|h%Gb %nuu 0 Mゑ oNZ QJڎxKdx/lT2 WavkH$PD+9 Uk/4hc`L0C4x)E-*#0h#sW騆ϊ BӮP< Obu50!=ppjF JY&m3LW4;Sz 6I;֯rY4RR @^r/P~<%Ī8Ex 56$S2]jGH_C2iN%*,UnKr׌V̥qpE,&ՠ-Fxm~ ;)+j_̖GkTnDŽ4*I'S\^fȇ 5ax+b_J~,ϲ7F 8 1:Ө 7ߦ_ŵĬeECU@@`-Eaaa ҤR*5%5aӗ}c@55YGe*{3v{躡:HQ'ͣeӆY\(uaW7DLPŔFZD$3<}DەDN3/b&Tc\c$;5iamr<ϡ4ʹ6' AaY9RW"O4qY69xpjXCR;E3:N SEȨ%5:squ4>M*eSr5;,E< 9K@;iWOEh`dqtQ@vd&:JM2-I* DW|_ԋ#2 nu1`;>r)Xk#1R}RvVK!P|<?lRT<qFL0h0=_`(}f֬wn4-s $S"F2K,j ) Y)㒎Upzw$@rSPg"<,9&-c>r^OA "ԽBbwU#HɓX 1.=1F' I ƒ)Сk y;lNx"7ѝ0 .]D8JtgolOES/݅ 0Lx 3hU k!yWCb=hMK- GT셯cXc8^pǐ/G_p 4 gLeyh,Pn4R;hc4b9cZK V 3),ÆhB2o-M`~.**0-guP4$OǷj-8<+ %R]P4ln8>70Eʡ `I 9Y~ĐÀ,D[1e|d5T/n[u"i qoaqרxJۈz,npQSϽAEn =`URz}`nr4 B(@1 .Iv~`}0%Pyw0voV_•h S5'asD`\X$nqx@7@4kܼTBufFԬhxB M0x6ܰ(ĕ>1au^PCR#Gf #%Xy< w!M*HJbXb\BO۩d>&mbN"."*a=p"Āqu_bgV 4% n m(1p˒H>$jHed,5ɕ3xcKia- F[TCBwggZbWaZvd ]R ݙ VM1b]a}\RFL!b e j86HOV RS1q#@ 73u|MlSk. Pkd'uY^Z]W;NJ[ v9,T41_e ʸ cg/omeN#r>XKQu飌 };XZKHvU&e8C~-AOr/g0:Iz#28`M?eF\L0i݄= w2& !8"[\pM>Lp>Fo0=dczׄ<|k?_Jb@,؞ ӓnpm$=XD:hV;#0Ǫkʩz H@KƠ*u3ɚzJW%ˌUѡХ}Oю ҃"u `T 0FC"ÖI?KNeLȭĀدM)S5QgeתȆCҼxwUEb"̭Yb8"`!9X TO!do0<)$I%ǼƸ^)11VǑL x8Q7<Tw0.. 8Lڅn _L6TsAOyS$DWuME l(9<=Y´RNeR%䪻{zCZ5}v#cd.]fb\5( hMVǧ~ $ݠwBI6KD&/rC =nƑ8$׸cngzD tA?Џ>PX r~D03z+''{rS\<{[NGL!x2cZZ>~!ɝА;?Y! ZB˨ХK+!?KN$ ߏŸ; sQD,weHw~D|4d.Wq iPY[)|UbN[.?(ϷAJ5z.\UwA@*|K [qЀ~RSɖNe1ƈ긭uh!GP[xqysYvp˴__^HUT3uE-6$q֏ @N}LJIGqha]ȸVWfֆt < !ǡ_PiYLA17%2TxfRkFzNr65-|@9d qڈi{Vv,j |t}4L 7H6!k&\daWWҎnEWܲp`O ( x޼kGa!}>c7/_w07àCTjT ny?}T^lL|'oWYzÁ3D@'C0[ UaeRZE|6jlH~IuK@x<:ִSEPq_"C?:qgo!;j}:HAKCD3SJ)8E@ ES{lQ+P*v2ቸWpEHfHCD^|/b`ߏ* ju0%{F>:]2 V (_rȽ-_[M i"\*2x8W% )=+jBFBV?FC]~Ak0,lu85=[`AADNva`G/A gnŬ#qrb_|ٓԏF/|S 5DwQq:mwx| x #׃ ϐ׊yɠ@֎񣔱A,~5ӑ`{I.ֶ(>mv<5,q4uư?ޠ)=|kHntj? gu~ܷ@<@S'LǑ MP\H #Ϣ:?Z:6I=~(ZY ya fGeyYe=ߔ7!šN#ʆ|JQtjc3l)7z ]"|"[xXn8nL3UmLL2aRN7gwl(H4-TMQ9Ҟpu0²xfsxm{o~6}Չ"|aQe NQo|LA|-۞A c>Pw8xw-]j`7{"!%ۃv67DOzlߩm_QRp-7 tޚ7o a_xXe}ϏebCn=k+QUlG^֛woѵzzk l*'^*?:RDiͅʱrθg/`Úliʚ~Qkq#yQiv}UZƅQ 3e>yte x0hž*?3̎n:V%RnFDSg\ ѱJ ;^O *9/Ë|xh./BF*WߒG!0#K2RaJck̔i4 ,`15 Id j?HH S^!)o+ԍ-Zyp|x̱|{X57;$);,+?Y;=w#FsfdkPt]{N9Y|Hgʗg0J+6 *M@J-K?U@T6#K EeɁPƣm5)I7SI!z~Fс%Jh CKmĴm"AVVp.HTEM".{0*r,|(t 8Cː"0r,qy`$qo0t>aU$g< |s18S͞uerVEC]#2 !Ta I^L\^0 ‚28> -qBfӱEsGh9?K0"r5,Dꖞ|!Ɣ2ZΚQʰ#(ꂛ5`[@`׀ 011SѠ$T.kZ#hF`bjGEU9lmq$e\H@O%.bCzc;J 21FZ{et3Z(#\eM۸-++sYqvyt^OЅ^,%PQhm~!Je=ј6<* TB]jK-0%K6zjL4K+| k a1 /,e`@1 8V+Ƣn28oY/# U*Q1H?YCX.s5 g) + yOL,xmE2bdF%c&ûژ"ʣ @ʅJ!L5P.e:"zi\?(Y pėmm~igՕW}CY2ϤU Eil"cjW2zE3~m7\F=2`ƪEٹ|$ `,3-||k2V?;pg Ќ$/>˒@ȢWO VvF ?vѢm֊4rcBa924C,cY.yjqF=Ú۫QM) {rRafȽd U1r {Lb[M^&TȞ4WPou;cd؁CٟaѬV!V?A@B؅ )_d+$#7| VhK[\@)AoksɷgvC"c*sLm%($Lx0ƺQE/:ZdRcJ[Kwcp( u` G OSIHqЋj&M K8PIhL~0ߨac*-ӓi%Q;;yP65NY0X "Fg,;~ 8ş6BU=bk+Ml CġL]BUH T[C+J޸ܐ>R펫5}Y\(-^O~Rr#$zÒC !Q(rHgOAa\˶ %5GtwwxHreV %JKJKdƛeF)9z] |t@JcDvvɝ x?ibM|F%y+H߮Tq8tX((^~.S_VB$9 ceh`IˤgUpXA`} D؏_pEHB4;Ga1ml !,AwAEfE|;q8yC6J/źI<4ZR T9Ykf5h0 N KpPO'}-&i#. M쵰PNz0w, 3Myv4h'JPV㬩}>/y>u֖͆ƌ0% hKE`/;5-͠S(JX4U:0QTya)Đi6v PĀQB2_,V6yJDpS}wkLُ5Ԏz&Wӄz-*q`4XYMSIJ#6.Nl#ʴ2y`ռy"1p!ds=bK)6xj~Xtv׋Q 90ʉPs(dx7Ӵ ??$bN>A~Se(RYH5D4Ĩ)XfkOܟd%f4 1M֊@9;M /Rfj>CP{Īm7vqfJ{k6HP@z6WYu0θVbҊk2{u0>`hP)oO{"hbޘNd_ -UĖɬ9,BO9LNaA:- ^!6 ,B*1x'2B=т!e/WFQZh½Sf~Mq`K,B_2H:C |&f|H&@ )B<‚0̆'>Kt?BXq&(}Ϙ95.-AZ:^&!1 xb&t2M8e(Dsu4a Jrx&]D2:LB!Cc= Q {m},f.3 sfU뀍䕔q6)IKvHkP "?UX+*ڈ7=p)/f |"˟PS~*LwJ1L%ta6Sk`7gM)0#Ҫ,)X^'/-@X*. *[nF(Gն)QCQzrzZI!CRI]#S:pg8U&iCVE0rK׸"A^u;qF3nH%!"a`*}*(.o}8bpck -WxLnO~Wt"9xa;}b%֕HDs11QWob5/׍{6DmeS S-WВM5o7p d4=B-$q#n>wד3%@/1 ҰchV$8ytGz>RF<-fTUն4J]˧w2Y T}7˓i(1r2@agb_`/ T6ٶAd}au!)+^QY~T|a$4 )!y[f9FiNp )f5oU,+ L07U^S& rfh4Ε ]D0p4*60Ά9ў"'C 9 x0bOr:] MOyܸ |<@RMS̀Y/zzLWE["Q )~ϫpjn95Y~UsVH_\@ C6" u8!&AaڪV3BsYDL"Z-3Mq 20nuSEA'r1j,YGw*EqSw#{8P \ܮ4#3DZJcf똼tt':\:ʇĴ1Zr0񩱵 LܴISW$CFd("CݜM21X*ɅMAL]7HDn sfIv&-3^P D叚U1qN /ASb,=@(|!~q٥áN3ɔ`2e)wK%a-"jj-0T˾9y% +fk!mSZc48*Nbw%W3yzcjZ_X0<=5y ZaqcPr9kx @Ed{Nrj ?_S>v7 !Et^R&&eO+Ϊ]%`7rGȋg=w:s#o,`QYJ)> рvKb^!"`UKZD:BYr Vxv0P@+*^ԧ^J'™\Xq9]St &cOPP%EF;pC] $GQʛڲh< KV6gM.qM1Q#<󢊼 1f"=RDW ACiMjrur@kGO9~#_Q?VhumMX[k~80fr GQTŏmɼ+i2^q;21_Dl߈L~*a+9 1dF)T`m>}~~grd"lCKxXJ/~kg~j3tP"$|JЍqvlW3_sv0XiyiN55M,o8Ӽ\I~5|Re~4Ijjפ( A;aNߓDd-f8򊲉1?x7k;GUp4%EiM~IyXReƖk*=[z\|tuN l BC6"4p,f>oP*: '+!-{OUSH0/['~U@OoM@IDAT`ծ fcSvqdN5>~iߊ 1['^)-G$0`y'Zބ*-j\\6Mƕ=]6sEuϓ-k« [rs~p H n}vd5.AwtG٦3;սJ r=̙o,CU="CT_o?2`;fCo 8p#N4UꆭA.wƆg)Z"康t(.3iZ+)3-kԃ4Sؙڥ;h}1m6mF(M/v#d ~9 +@I"~ v4dКHY@ =+of2D)ϻ O@yvmv!?8J;xWq)Tk'EFp!rL7rn<8?&m}ۢZr2Mp ݜ+J;̧hJƣcV ' PR, 0h!!/Qj#TS @aFS+tW2K2aN+6AJlN 11L涱ZRyݼ`q`4IN$%mE]UJA|S*j>JEF/VXFoNA_ G )=h6mv9o`\gZ>F9:&rS(jnrE%Xv2-D)wY]X%uBĐem\~診5ͧpflzK9_74C4Ytuw򆺞Pع4Mn` -b)()tLcQΝ=Q ˴}&a /b;L륻 <}"OQ$V},,j\p$]ov5Vu?_>Lo$X2~I{<gK/Y#zA4FρckY {WR>@)|U3CvǗ>B!CJCS_*,c&([aO7ZޝB >5[9+ i[.a(avgvKx<gMF%QͽkO@N]L33Pn2T-,#%s:zZ[y}0ڷX?$Cp׌v{Kb\W54lo[ ڽNFJ=$/hC8\#b!>vc?Ap=u6P!M MA]􃍪K{J^PETf(\F[9Hj2$J) RHTpeSTX2pu>]#$H1t;rtu]Yӽ@*S $!qJ q<ٰ2'd#tRb=]b.& 4$1pz׫-\ ~5i:孳b~%npghN\0α1eIBOOdrKtxﶿoQPݿ>,q_#phԾ@ǛŏxM] u'oN0D|Iyqn0"/Cz^Ō?zkXEQ" GSEt9%u #ZS?gJCzn(r$5OPetr8''L=H$c w uEEqq@#r 򏜍{lIr:Y=:-Չ)=V#B%EX+KΨcg2_y;kf²R;*Vk+ϨPBLJa48`Nx'D~ e3 bcV3\EM?y$ZD~Kۓ雀ü?4f-7 ҂Oy@ӭ ds8'k͘*a>LG.~: l>I`1ȞbB魧FSxYt@mm\eq":s%dV]sDIVLe%81||d"3(c0Ü10A*\ [&B/M/f'b$Hc'ʙ!9&RԠ(!mfWx%Nyb=*+A y(y=%vKeg=Հݣz8y>~'YDHC"+(rO!yr)2dt@Ukc:gGb[}!Ί'„c;*iF;4F5PP# N+Xo,0 paږ7KFՕ (8_3ud914.X{9h9>`Zp*ep~hPC㏣fbi8_zZ41 #n"maBu>K 4vE 8 q?0XF 6cl6<HN+NH`0\ GOX_,˄EC[X};,Wm]'ّ2[+pS3)uR1p[?'EQjCp SnHREY}v- =HOJ &;YtXTьz06_cdBwDE jg$32g6ip| zH񧤴()T6`-1bzkl;ᤆ$L0s88%iQ hwS8[_OdT'!6Rƒ  U 3j"" #Ю>y-N'EGoezqKx6X#{eE"^UQI T+e 2_2TQ M`1)RV⪢.wO~~khAŴr x/~=kBɫeOMxC=ⵆ&uӋ̐_y"0H6OFtSdНت15 aдuA_}^$ 9 dfjj(-|&N_k?oXh}$?"M6%tgg̕li&bE!1p5b)b!t+#Yku σ!НSv h^-v8Dn$ϭ.no ޛNvLHܲѼؓ6Q C9|NI5:aq1,z{KBCA xˠ F :GA2nlu?hj~0ĤPdsV Z>'l[v ؖ0ICLq22{W[kؼ=@w7gI5 tdr^~e4.`@SrT0~-5԰@.G~D (y4$pXT,cNZAAMle;C,#Hs<.8C~Pq1cWlpahrr$&EWȴDUt:G;=jz,0r>Mf)B̂g/[;rtX2巓3OnDq|'p*KT5ɶ{i㘰fH/KjVKk5$~ 7'/޼t0EGE<ycaeq" 00z:j oneɠt ;pX#" <4la'nfһg @*`le(X2!rPY<cBxjlYfU *Z˸ʰ,]`:=z,S9]sg%k'۹Yˡ!e<b|hyѐ@Bm-Jk$QjbXX}%S*D!*{eOIEϷ2Bǫ-\qr#vtqyA3 yoDEgQ\Vc(CQ(Olq 8ƞGږ!Ϭ|9kp߿cљxj׈}h{jn6R e"= l GFWa"5iLv8lD58{ڤsJox[;K:7yk'xۡtvfS8Ds` -n&1Kk7Hbz+$ci*tpoV4cwGR>Xyky{nvJJ#$cEeJیk.`FenJ#|d0Ç6fOXioW`YA't΍B^4VrW&pzyʰ~1N`|Pfx PbT9/ŧf-XTA>^OM3I`Mr }H#O*)4w9`>EOkPe؎~١|z)BQ}{-)?T4 K,6x{ϟ_d#'7f oVn.Ͽ7%9@Q]*RC54`U. ʍrobV<;;*Zt.G`^"W@'0;xK~۷c^Q!;9 ::2l+m^psd_ĊLJgucKi $ktCj#SH/.&iE&k?=N'Ĺ+ ^k1  ƪ"aZ9q" ؠ3N;R?˨lZr]9sZߔۜt lz "R3wp/-u'XR( cN)Vt{] ?%cWuHޔ-r03G]nWbfv]yRv&QB[qSFv;$q6F8w\xIi#'[q|}ͤ쩐~ ,` ‡,y-Zj xmU/U b<Y%AҶO9ᄢĐĒgc7CgUuLOfï #hNXȈ)(jogY;{-H@{q)i@XK/wDUdaqPQ;x?V'O)/hުFd6U'~bH.Ɋr T@-vp!X 8Ūk~* o*kP9_XK.2xL @jB =Sb ݱ++p"r}Մ"N% fkbT}"q)Jmq2 I L_Q}*,W'Gkp ~# k0SN=;B1 {K+#yTb=|7Ok([y_#ȐH@BQh(h\;jkXn_΄\#45_D߂_Np).wվ.f3P+AIӚl)䑄dZONljwr ;ơ1pK#1`oraG}4A4UP p6u{DIeQׁfj:A!LXTzqD聁D0NQu=wi0ya&>hcmxl)4vEotS{`r"O?@<ڏsD2nD<4~Q&7j[{L(6JKtklC<,E\gKI0 *d LƤ?lTf_֛Sv-# "E7^2ׄDH?7hruj6T,>ȃm a/KgZn6N!> m&wժN&ÒbgC(` :`beMay.6K(gbz4/ qF(L] *qX B 3|n2<;]5;B{uRei(D.%㫱({`.  ]0FX3bb'EVF8/;w!eE2믨/^p8KAqO/!40 FS]w^GOo孳iyĻ0pu»LD4WT2q ,H2aVקiF;~ {L?VV Yed-ja`BMB$FV3f?)s&ȮzQ.:vփyCZئ:̷,dREOjJm~8QQ J1fH<$MH1UN:V/O.*8nזe`Bpk4(09}L&Ĩ#2HO+7Q+#e-ViK^Bq$Mv wIUWX9ݥ6^%`EqK>'wɳk*`MmbF?` b3[x/1ilfW2vΖ X kSFpx/ 3m9PfƘDHuy]*-jLafFMK^Чqx ?]G()c'>^ea#҄$G* @B>ד-%=Jf7F!\K`T#c_>6)8i꛹3Lnqܥ6cQHՏg5*zё `{[2 9>$}r%V):"UEN4QOgYT, 7;fYM)zoi^')Ghw~K:óJCd4ld&(}JPm->hjmCG}E/C13:*+,mr!hzU.!-3%Le1j ǒd{.f3h"3PKձ-~-36 H |a(nCʷ[e"5b;d^*ȸx2,: zբX4"TrTtaBdoP?E ,9=khIQj;jBc|<1iuP@!Y7/WIL \Pkv"# h\: ٦(4 h 5jSEɃ"k k͔@ӯ GQ,yba"-4NhV~32/@[j%N rw)gm omK?đBi$8!hn`6<7@ G[t0QS'Y ~zp%CP@аf̨Ĉ\sl-R*FkH5tnֺ@#4s$~=E #^sv."0~PA. V* ƶ)݆9xn't+Ljٚ5:}ar [gs[Kbv)$9^#ό @Ŧw?Lt4ij4y, cai[ W+@ hPb- ePŅ GK:$V$1I5O7BOh5WE0&R> U[*^ L&ӑ~lb1FeJD JDh{Zc^qc5ublJkaB2|ʽ%7/MRQ+s#!Cċ0 yM"RX JQVq..1_@ C3.JAg?dF}š+0MK=K{.ǡEr PUb^1? ^ًTiVV0+ *; x )o4?n ~|ȭ ,)/cW \Jqc/ Q.#l~p]ͅΡs+ʸmlɖJMr㵶0AER6 Yd11+$C"#l[" v$zB'Whs/{Mf_aișbXTOE}7E({!!f D00^|4!Ӣt ˾w, :wrfE#.0"^mIø?[gLDA`/OtuKt/ erך'{ w$6O SYDcRZ HZF )2{8_Cm%l9ęp2>nJB vJdň(AТhUR!FeXms+zsc-1 p LN^hnf:,g@k6?JIJ&K@q/ƫhkyҧV:j IB29^5/3JE 쳢r}^Q=$ x?.˙) 鮵K S] ;uT潩XԮp:$qVo/A 9v"o3Fkg%60 .@ ss¾j(U=nh*[%I(,h"Mf1vs~@q <Ύ‘I|"@&Vri?]\X-my퍻9=s`=@7qDz 1!iBIG0ӚEm''[P$"Dϣ *)X-D\4#^7БN[`)T\Q#sú(wwLuJ_f4o Fa] Ww,D{T`͏xɩ$a[K P&h+wify-ǰ D)a> -|D_gp+hN`x+=T)A&@+H0bQ0&H BO|<ӆyXbwY%㮀3}>`FF38n- gx'_"2lO}i.f*n_mbh:@ l*BV3E^P]zL77{4ɒkӎqH C;#+A~EqCvHHf5ںPfM塵ge$3i ;tfN9 :2fmvNUeOҴ)c­[Z$)WVC]nSٽ׎g~ٚy|شݽr{9Yɓ U(Mh]"b =k"H)x>Wt~}9z9v]7gTqtqihDwqLŔTsp>4|p~Cc~JnO\p*#-k*PQ"ѡ?}, J3[P͎N$dDѻ7i)|Ҏ\ z..{:߈+-Bo2ٿ$by0E9Ѷ/i. Z~ooY}X>EZuByJCDɈR\dv|uKaZ6=Kl8p'=voN[s:~"Q!므#Kc<Bp_>Pb9!9YP9~le_Hw%zJ7AנaHTU;w*F^A|> rhS (xTxFon]bggI/["2f9 }8z^N:@\8]X&=QbVV;X@рdZ;d;iP> )E`C EEIm Mrq4 iTg}Lc?XLXz'Z{\'J-]yI߬ym ,l4Ky>ut L?Mb ,WAfaE~Z~RHX{߾%#%"40DeZ/w˜/.nz2KOٶfcOD⍅9PԝgDvY.q*(fo=՗,?We-@A|DWF[w^1ێZRdaw?햏`0:{ȼ˵DL !`5h{xJ|A ˗Hs ^0" CaVs>H+p 9}80˩$Sī${q9$I[cQTID-Yo%EPaTfua4? po$/XB ݀&DϐC?PF_ً"2'M|@މTEx"ܑ"gg!V0S[RJHV^{̏y0i!;|n%<ʈK3~*`yE'e-ֽmae DH.%~^)av/SVgvAt A1BlMNzGiIװ:B*D&P TC һc4bjn"̈K)$ PcqDXuO.5Of хXV *]yGHyUq"- d,F R%g2^;'BR;ŭ萃 a3[ KiqM(|K8=- GP|R ^F4\ ֊' qK0BL瘩 7 dK\K ؚ .0&"@j,Gn\+}mt* 72љwdGd]z^{ŎiU;nUU". PM^dx0cјEJmX^paPdc7NPܫe4mD\2Xӥd*ú[3D;&O՗yCȖ.-s0 b*][ld :91e,T3N8Ypb{TTHJfDLuLUxGﵝi{ % 5n"H8?::4ܪ:Ajd6*B2 {}Ln+͞qVrIڲeLvc s+? 6s;@0 ~$S\|h[EՏ9 kg?$*# Z:)r5(F_VNP}jW<`?c ]`_s >UBFjM;s'O p,PEY@1bhBPiP)o&%L- )| D!8!یp̏B{y%Rиh"V|H{]B%zWz4@ :Z9tKshbLA A$5`^:dsݜ\, nĬL& q"y ^CdOXQy(V+NMq/r&^GXW|00RljJ? `J3݌OeeMfٳlf@)1&Q/؋ॾ!䩜!S ފX .sƿRHթ~aQFRUh.AՋSH8YҘ!Q. Hc܅R˛´e0A5K=D!u_F3䙇C2xK- >"|_S jV`(AmwV?u$u1~^lLGN*1/Jnua&"h*㚩w@ڌGjeaXXMs\K`,ꞆT< ~A)$h$J/.QYܨlK6uzo9z6)5#+^3 ?@ą#{ SF?J#^w-@͋ܪo+(OmfDb=(D?2lϰ \ж[#)8Ňx6& ڿIS*xߘWݙY(K@]m#zMo2+5k$xW026@ɘJU^}kH;(QhD0эW]uh{S̐mX$}8H߃teZՊenJE1qr~5FJ0g`ܜ 77l.E(˶ |WDkHCs.V6Er S„g$pZ P7oUHPqfTQ{:<#h%FL׈&)oIhI9IQ襼B.xV-mo9`aH: 3IE\%2}V[ȷUlFa8,/6&|f>>X yf׉q" _PW-jW&8+ <@0{Q/{/bl'YfF%,jx7({?2%S>eg!g@SK̅N@0RCPam^0 eAŽfõkS#ٛX|-{idΐuh^H鶛|xl8=@e(95g)K4wW<(ŸY(Z,TYt8,Rԙ-{E1%IOF48id۷}em~gg$Ex3/_0y)[Kt̑Gcd`rdо AɞOcgVHq&@C4K ;]:pĎkn82؀7Up|L -l KHKU!~|cX SjҪxD.QrӐYh6;Icj`~7ㅟ4}, h p"N*Fج%CًF+,cކ"ڵZ=([Z,b'# ATȌ- df84{ %tJx|ixvRՠݿ_.JPmxףg"٥c]>sxtCZ | wC=!۝ .ΙȐI:Q #aRQLAL[oj68%DcDIJc(Hңoϫ3-Hgc^S#*UaE椎;.RMΚM;)DI$C/z~|ӽsG§1+d?v-y:`Kb$BnQbUDfGA>(ktqp3֗<\ Ƃ["`;BOI#փmL9tn-ȑjm(O=-&)|1 } ڞ ͍Bp563d0p@Ŕ$h} W1B^;F4(g/O!O[lGeV%Ƨ+/DDZQYߢC@'Nb8$UU7'mֹ`F֑4HPΘ֌piQmbZ_W0fb\`ԁT d#Qcz[Di1$< '3SآvDZ)q0@S-, Mk4vUy )-߳Grhp+kJP%TJMed<+nDaLAAoʫy%ܝM=##2 Lxn_EǣdCIJu!4ma<$WDvxz[.ōԊ.F(y sBՖ´wuDM1 K=KɈ?HVzr~!5HeY; "{wMTE%/pOtI#Cs)06>P`bVEхhdu<т?DCQbŏ,ṷ= tVi TVLE8"2?kXiEQ#Bk["ѷ52YY{IJRSIZ"Oevt2g _btd{9˰V%65F\ǦA]+W`̈L3l逖p g4}vδ.R3KAއ{]<;Q˵r&&]E3cBv"O֌PA42Te64F4`zʐP)hX;f"&D`^m- ,ad^xi&dB(P|&lעp B-GĒz)tAńBJb#P|ybt<(*DC1(dHxӛx'թ/̣]ґ*?Ҍ@3'IewBUU/DCdtR S*Y-ĎJ,ZMe]Xk3J3ryxji 1=T2IˆZҎd ZP|R+ٶI۹Px}.gqMc VX'3RYZiV˾x xq^ IyAu| 'ZZ%o_̥ :oĠZ#ƂZE*co15Z}UZFz:C2mGaʶ?4KSk/`1BJSrSETadN MpoEґX-zFH-PY 21R\l4?0G^-{vX20 !\,3pRیXڞU1"uf!\8?8T6]PE&Tęf'Fev>ND~7G%sx(=//o/?|6;;Luyvw)Q 'Y4LO dF?@pᄟBJeP-(>7'ۭ:4ZEd(pY[䎍\X]Vc')% k8jD;xkM1W35WG 3eBIb"죎QҥU:?Ӣx]ǻOY-]$#gel ' Pz %(ROlA2n \W~T^XI NpcX? tB*O;zixbmfQ@/{9%IGF#{io@l7!7Gr$Q0V?iI+R\[J.ClD;֎zun l~y:l96P*m5a, l!ϚY)S['@ ;q giyl*lc -{xz*e'E )jhV0BWUacw+o*YS3agߊ{RuKA"vԮN-j˔I>[@V{hXr}F@W̒qY%~"zo0)2)3#L D,l&҂Z{1@C<꯿,tPU"u߶ΐ$2O+ě۞8Ƀ kpX=3$cp| :ݽ@6?T\{z5rV!捵3!Acdɋ3WQ/H5S&ѡD4.Kԕ̇d046+:3HO$+ӝW,5H}5 rTړ6q/|Ko'WngR 'b ǜv@H w}<~Qن4F#\'rHd䂂CDŽ[}lQ8y9ŷw<2EUAWmqV,RBy.]r287ݍ7r.}sb@[}渓L\-V~ۧ%LOWZzr#K:Jx:WީdttM.~* u޺,!W$0M%zb mrv!e ߲IK\Wv>LId\'$쟫yǟvPIڽSiY9҂Mvfv6%*.ƼϽ z3f/Xs{,Kʴ*oIlKgz`|~-TS@a)}gyYn bM`33gXљv؍-ψ;*9۽]`w}_G2j˯_Es&23[33ʐZ9]G0F#E^h',]DZx[ nqXUg+3/ {~\/^eӎ LJZjwRct)'X9Ee40E͵- ӾpHEC22Fs% Iy0W.IJ8WyY_'(?BTS\ }&O$~֓`ɱ]"R ^ݷH:)CaiSZlL0vo ?( @P PLd'T~,^Q7FrF?^Z$$~ ["ņPTQԍQ`0ld*)"D3&1ԊIq+Rf_wG;ԋ:V$ S +\EX ,ȫeY%5zک ”GI·SˢpwӲXD݉/2d:-1'> gd$4jX<;FOItUAѹ^f,Ǥ+'#m" h,i֤7=5st Cۍ$:a?pgA#ފR-거'e3*6y R(睔GULA*N9)xd2K'Ujl?b\3c$DefӔ*QtZ͘`!i߈/9ix ._ (-p$̲"1b"T5G$&qh紒Pv)Z&åL:":Y I4Al |&gj0D\ ʠd1fc {fyT *mK%@g sZ5PLCAlt], # >Gá.^irXf&Mau TuؑJS1M=ʋ[W,J|JHJCgx;;T{0wh3A舿Q!0/CX_%ctֻ0YPٌ4]cmF~VG =p|k/&팚bDe39t- $%z5+ːjRl 0[?vŅl,qJV//H`GHX! g?kdq( 0Rl(P?2Pʓ]_iͅC[)#ڌkC&`IEԽNPϢqi M ਎%_ƔwaJ2ߵwRl]R:nXebsP$+i6 kZuu#HV:zpPHq3 aC/d\5 FNm,5TkrKaݞO q8fH"q!AySGqH*U3 *Dr= Lm`^k"uM[Kfu%b|*5̿Kd@'՞ivyiy9_1qdfD iG=L?Ƶ"@zԐI[ O7=9aG*B",^E]#'1TEL3NȰ iLlbylMjG{m/dXA$N$Iw4%RdLef9tMΌ)\>&#cG$Ox}X2||<^ka1*y[-qH(:p()_~]ߤqP yP=X,^\fw6 AOa;s&p V#Cc.Oe\یhHh"C8kPADC@zy} wFvz=9_Et87A鏔*F1V׏w / XrJC%:Ҁb-$g.¸/PIS#J,oHbK=6ksMU\P.Fi-ۤGqM#JgxoAz:e O1"lҐ os0: T^O舌 HqcxMQ 7kql.j q#+ڕG)( ɣ':Ʋ7-!3#1/s*@{D{m$ķĝ GIu'Is>O*{ * u#̬Ćhӳ.j PNCr^,aO%ƏI^2 8utXʤag<` ]KRJ|0A] 1i l[R"H'zi~)+ 9P1 $cXuf@JP*0 MLՍڤ9cod\BEmo6fDEK2 E~l,' 5ZgߵDtNX&fb]rJQ֞TY{F h+-q* EvUUUQ?pa(Pc]u"_o_kɠcT .$v=϶`g _Yl>]R ^oH`;hMex[տ ߹VRMcYeF x}ВI](N7iE D*J֦kD|Xb1`dH"J$V4ة&UfD0ٚs97&]/$f(/ظN4SumZLdQ@y>&>}o]SU ,.;#XERZ&ej r*Z#1DnRH\t6[oLD̄s5x\1-h5>"{< LOzBvt 1F(D]`WZE S@IDATK:s>&iĬi13P3kZᅑPQjoZ32]mls̿S}Hց%Š@1xX+V9W&-9$zL%fHC&΄ [cN1/0{B\LQHK'L5/+ Qœqh/NuSL-*@Sf S$ycns S!I&z:՜K*Awo wS`YG&c : gE=Ivfi ^C[)de8o-K_íڐ' Y~3)6Ke$ ,$ AdK_FMȅqSoin&հH Zl"LR4HyPoV2 ɲj&H\A|qFTT=_A1[;:śx |IXv<9֬Vs:#km}U0# L֏;>T)>%X',my؟F{y+3Iqqӝ]Z?/gلԣ׶A5e ZidVuDy):-i*7D7\H@g>ms> .&sr m&-Ћγ26#Xϓχwi1^AQdzBTrXenNu胮F/}(7|>س,EI s[h0ĊL+)1W|ag*{*!i: (C|GOxM~,YE/L.wU_>-DY#3nΞRƸHNV2t3Ǚm|("I .!x`,= <.(H^<{]?H;I7-TzF(>pZO|X~f?15,4$@Nd4O3q`}> Ed17ت{-3aRfyp˫'ϛGq&@de97jN'̻CORf #=1.o;=鲖ɀ!bđ-,uDi^K6.kG^ϽLK_`+M."TUnݥ"hzşcJ3 dg4XN%&aѹtu*bWTVs`hf #7^iyHq ۹"*`3TJw'0hye%_*V4CWp% @CA䋖 شq{m B]:':O_nqJ0 8,fٌΫi'HQ|(;gz؞q ?)G2 r bU~iZXwCFvn{:xzԛ"HV_I瘐$PülS xĮYĂ+g`Z4"TY'F["Mõb;^9-Ok&D}H/ *2dpK!5FS:;FƻN|dCE{ܳ^.v߾<o?ݹ߻2+g>\~IT~BpJaw[g~;;º}0E .FThi 2-H:qeϊU'Ak9֎r;@ÝVnTz5Il $ZqxdrO}of_uF#|!q,p\?ޯWќY*p>7#^Ttu hhL :̀ZNVfns)u^u =YS;勏71'{YlTD+ZVBW#\D/g+%H+(eo_UPk-jf$,^Ķ IrdeRzz3k~y~?Y.2Y=$n$j:FJ̧`G`qG [CU%YR?v;/ VY$k2 -3Kܚ(1d#<m|߿K]4kq]c|WS,d~T!P4QQ%-eeFu.IsE,%9D "cבvK*+'res['7bnSw\Uu n~{ͪ#Wo氱h a? Wzf#68E`+c'(g[n|nܷ /ŏx(&pc@T ,i+fM;mx:`v 0Z߉e!0SBAs[o?]:ܟܥN.q7Ä?Ȕfc㻸trޗ.KYEtfMVI|WW47WgdTr4-X,rBR: -VM,vEC_)zΉD:r`4Hdo!.ghy68`.)o}%gy͕Vٺ~nWrcRֿ_xpR./qr-8/,HkfyΊߎn*^t~m5_N]/9i7c ǯJSa %Uj:" ٪&H|gMbPdn:?}ʒJڰ  X0yjdj7GJ7vk9P37'wxLǾ}>r37 /d&S4501lqteJ5ʎ4A:[#x4QtCvF-tDeR2[+{:2c $(pKPOp grc,%fev)yfsfRl!KXket-yM= G'R+_r) 2%r3ش%dt{Dk(OTZe/ޠKT9Vk_fR`2j1θCP4$@،G?fs-8AvϩK:ΩJO}.ba"die!ӽ_۟iUrɫ%6Z̕5w.KMʳ#~<#uPK+;}- /%PM@oF N.$Ӑl3G-Z ju2AA }x%#XAw~oN )e7b`QLx/"3 (+X>pe4%2eۣ}X56nÈs8MҟoNtg-_%q e#Rq a̞:T;'ߟ'2.F :yᴓ7fː⍈AQ&PQCz^&S$O*e67\cO%&5 * +8XHb}twˈLQb.n#D&<}ˋcb(P95߿^Oc|>$EfmMYdq8(ao#ce&>v{Vo?Cr^a關z'afg`' g&HXdbaqud?^üAԶ/ HL1Uc*L؆v̈ pT%yĚ`Sڂ뾢❽$]s{˜P ,K[OLI8b)GŷW>W(N2Av/p CBE>Oȇ~{K-?GyS}뵇20y"8# H|݉-)$ =f *c\3,JK/'G.or |k)|Og&sxVVmLWK "H?bG蜱p]afoPX4cf0Dۏ)3˦L͑J=1)bH jĚ_'ݵ BXb"9 v0ũF- +9Ȇ VNC6kaH5+9>/"<)NKj簋*NI&S>io51ٍd [-:de+ړ@HLvfPmGod]y7زhwu7EL|1=jRtӼ;aUBϳIODn[IJ}/-ph(a;S!a5(~feT|W$ pQv·ʾ/_l8d"hD7?.Ω{~~3I;͌^c~YK~+z",=rG½[ l+Hrp1uOW@Hbj/Xi|ceGN  Gh3c5f,D8(SvXW6))仾{F~}maP]=%sg:S Qr@z]F$& Y&RoM,zdWV1"{~]1s3B+9zjǏջ{75U,ZPal2٭B}@D)ihgl/V3_Zh;rLY)qf21Iƞyd!4(Z+euhn)d ,r(uؕ*- 8gTE;OyyikƂjdCCe5K]E Yx_#1HE*; }ףe@bȈ=ΉRk_LkcPkXd=T}boXǜԪ#x`c3ۥFu6(zZ9N `QjV튘 [K7JM|5kOh8/$u3erc$Wth 94} r۲6I:*QПK> I\=K Tͫ_Tړ4)&%Z,z8w\H{J _pj2Wƌ f0ѽ/?"h*Qa {d_kΠI]T u(#՚x<#8:9x&&]d8kqeHj?y& Ur;p,k.pc4l|DŽ3T4שg8Z&1W o 0طU3K)UkꨂǷ;gUvB1x<:Fق̝q-bcr'A3֛ǒı0>XmҶ- (YϢH!FDu:h">'$@4zGF4TH-JTc:W_r=A!Mqlo.,qjI3BڙF}Cm J~],~ׅ_Y pig[:rHLELV4 i{T&;q_1SQ_\Q[$}#u%<or}g+>m:2 AtT+U8`6~T#x;JW$֠8aZBI X?15jb/RǜK~=Ox\_rtNaGo͘[@fu, 5|)'q`p^짧女"NBz5 6=ö[JR~ŴƁ $?UZzV∨t}NΕzYWcdqUAjAB)e6"Jw8Bi-vJj=`õ*Њ4&68W-abKEz \GoVEHRU,);qhrOQYjE<5.X2V'IVKErP ~=مP`tADDe¹p!f13ULNZfLx7fb0(HEIEo+8a>T?w\t)\q1z.M@G }+aAÀ8@thcF "s-h7v7$W>k"aS4d:BTU5ڙ B6YjljD=4MMS/-MB&䄍3 (^G @L71l!)a8S-'Osz0) vR9z|":dB'v d]E04$TњdT Jx#Jf'UObMִc\t? A-"$S 2껒ᡈ7?8AR "lh̻> 9R3?a&ė YШ&TtQ +G9dz&6u2h+h1a c(9NwUCG&`:!`r9O# (\~e@0DB8'D,H9G19Q/{} Dn{blzhG -i,R|RWDcqׇ 2h=@;x!B8fA=HƱ 2sH$O43%`T "R$-+AǩcHl[xxkcqhy~dԦm_N(F(-">{ Ecvw@</0 gyg%Gڻ"îСn+Mld:i݌qeqEƉd_\>.VO3 M?xc?ώ~HQ أ&"ثT*c 15,= _f|⨤/sK^DL(vSE *RJ|cXD[ͻi.yYY߈ú:uMZ$U޲TԑRaH;gE¥pT+Y֦G GP%E4Iَ]o-x?ly#IGt…er'R\d@"ʄmЫ,WB(#/Q fJ5[yI?e.,6]@mWBSGQ L,s)x, |8,O*?bƤhϰ0*RhʤpkҦ9H_ʦpd,kݭ;rN_D1xko*?|$H*v5@yiRΤd !j29`R=AyI,R1D8f>e],Ap~a !@hv FbDafk@+ؠZqy9q(eN 5L镪@8A/?mJbXjcT0YFpa1p>A ˵ *f,d~ ;JBCaU? V#CBB,mAt!YZ_[ m~򴯒n!`E]S~2d#RAlPR2b`* I8q,g`9خM_@v{ӹkgx^eQci|ߥIDB]лڥ6z\<>C9pgfNt,uNv4 p֬H#fBcm~-M+U3D^x$NG?b@@֞v&Mm")"SI7;KK*W5l4ow> bK:p?a t|Y^}t>t; <}k^w8sa= 5N\áVݑ{% DJF?_J$5K_NͷM5PǍ̍Xxv0d(Aaw.6)ntuF"c! ׌cbqiuw[ 9!Vo )x(>6/gLt5"d2+IԝZHqbHKє4Um@Zo̎Y$N 6ǖ9I͂qCb?o*-* G )]ަ=Rb?lRY)ݪy^ٟl_vX4; VR͚J$'S_r]^%Wɪ`/LlQٸ>djٔ5?hݣ=$˜2,qށ^ lMHxXnN]MH#\ 8J1x_n&L+Zpb iCȰޜ]NLUҕ.ʹNpY?<y N>vn 4~\T伿F$zY BqVgn%/5#7'jF绫"LDZjwGxX{EM^eL8z!^nQ t*P<ޅUgR ,muqBjVp9AUg'V+1L;ԥe[":S8G%[E=mO F+0ؼORhdSB6Cc|wO??~|;f`x-ȇ h_Cscrsf/ɂ/'˞(y#1xiPd:.Vp%τ@S!wV7ТP0˚jiDr-}=Ȕ`%Y(rX1osbI7ELk%9muYzꁟǏګmݭ(7$\HO1ME= %ZߙaURlؚ;^5c 1dOBu gR֖MMQhV׹n:e'_%^]=h/@ 'l`Jh;8cd*P4˰[Fv)(ϊ#L.c ۨ:]\pѵx'XT59  ԉ"A2VZ>)Hdlil2NRIQWd%fsi*Slc& !|5's(VG} ]҇|~ϞOɡ0k7 B#z|tNrpkqE+Ҋ6M6!xZ5 p6"0yͦQ 碽%|ξ`=;SĖ(@+增~X&-SgD<_'fSYLQDvWpЌc9SU;`H#x=Q=|4Bj|b!HR-#O7r4u*TX<4وĩbj^z4=D)켷6)A\sx}-5f+#b7徆]Bx X <ĿD6|O9]l|vDUa_(x@.kc]VEg!4S dd Ȱ>0&E~i4P M1/LCF㎿u2@X3ZZ1I(t;yZ)4+j LE+ӭJ'nNϰ9Y`.]SwSq*  lK++v>`r({ӠͨBU” s%tKɏ3~3k]=1qIkC'fl<8 \6joSbaf ˈI;W)w .KyXioxN1B \C^V6t|DC/rW4և0 rĪ?YJjmY.yn[rH'wDz.q`vstX%)acDb|Ǟ(]~δȇXXGzBψo_Se]T^;O@viꉖ=Ro(]rF[ L ئ܍aR,>[;X>\fOFdQF};4""wzBLDZl3'-FPz pB)z WfV1P:^^,WI3U 7:ՈR≑cG<+f_CJYY~"9 j}:ĤFT>bP7U54‘if(z!ݢI=łmh#2 ky9^ߘp '!/4dި*b#j }H  ڈXᆌ.qmp𡳂h'{iRńzo'LNA 3 3ZrqqS%_% GhA{k@%ɹ_0JX" 79 lLm܆AĎ- ;Ğs P-1[fD{'~*/&Xb,&3V꒩\J,Khc^^Cd?53͔W +. /ka[\o<$એd%]Jp8q6Ćͷ/yÅ &_8G7 ҬȔ 'eFM&5bI{ۅ<̤؝&5Y~W[;% \n $ MgzsIpY|pWt !L rq'#9mLwdZIգ3;r\.ȦB]9B t 8TJO&T[pu%0/i3:8.5FX >hG!V_/"v]8'ia\i"7LR~M㯫% 44LNJE/"gqԏaF[[ ØȑDmbQNx4h5\$.;Peb(=p) :u O7;w.$ Q@3U{j'$ <~IN8on?=H񘼍=d҅pp3ys+؅ Q'X;+<-?5TOjA`Ob1)EuEOl귶D?fp`6m_[D"]m  1P(y,}\OC.L*iu zl ?J:PN3-.Yܱ@D7=P+Ȥ/1'{vUQCّs11h%m"_(/*=I+M?AĊ*B'@ ^=|?yPeRؙ* ל+or'sӻfb1=Je jB bַaTˣDtGI|F,1YP?+jN%rd1i }Ō40ȴvvFrFJqaS.bQ' ~19f*yx:w\ڨ(c|۴tz55Xtvt;fC^!X[5ۢ5$E1f#zRF&g@IDAThu-*X[WOzϯ'[#.sϑuLvFόw̦ 7/q3)n䣳 jF-ۿ0G +V2T\"Ƃs-$N %UBEtO*ɑ)묄N%ID5}ަF~6U'bX= q.xip]! Mu2f3PkZ#_=.`^)}U5:38ӂ2=6LHPAYXE8d#-F|% 0%Q-%kڣB4鐳 =hv{ ]ׄ}.5A&=yrd\şطF12C*-s(E?No&m>d lײ!gNE%!1 maΖ3Y9dY g[{sZJahA$ųfOĩ@NKW-0VL#aQrzE{x&'FMG.xosxK L"iMM>4o0y+ P6Rɺ.wH RWV/r2O3*t֓9dQHR|%RR㗉5-J|$2 ,CRD0V`4f43b~ӯh wH8OS34hIr.%gvcвﱥkak)G`P":A}TYlÖBNn?n{۶?Tn6".FI ]wBUDmwPT9@ G_E( dy㷥D2@P4Ho껊TX~eW[iixb-S9/)x 1E <}'tL'ϲ-mRdF0:q,aDOqyc׻6_q յ4Xc&v&b0N48|TFH .MCݍaV*Ы|s(A`%E O30ɼ ͍|Y6Bo4X~GXSPU̵@6L6gMFEɱR9n<rOP )X ףX5тL$g PRǁD)jlRNTR rU"'  \!_휤Ob)W%N@?{^m"Ev*C3%mO۩ebZW}}9y013ym4;X]g96$DkP9DW.n{p͔7ӌ F z<^o_E';~ȵݡ>~z)Ya+W: .*RBLdcr|ИH̨d-" UE;ZöP £PvaYue/7 eQ%p։ߌg njEYf:-6b =_p jPD0('3*NϟzTG؃k0)*d2B|P#3e=+MRl-ptvL# !<2C |evO׷N1k hLzXg2rw"n=S9[{];9Vw*< ;2"LE9Y57rzޭ'H᳼,*}]q+Qx\QI'k6Z,(oFPC!D,N"x0;Icyg38ctukȩvbJe&h`0e|QW۞Kweu$\azllIXP" /XrWUgRm/Rf'9Ă ٨yhaݛ0CdLka>ϟx R; ɕBʃMyvf9ơ }9jiuݽe>0į̏S،ş82ӷooqKLvڮY XHaJZQv sX$l =NJ^.6𣻽#ǒzAxlǏ蜗I,%"[~_LDL5P:M :$ ``~m;2wGlº]=RkK6("E\)׳S#Ifs-V9~Gͮ:'A8LgZ-hC[^y[z٫߀|$a&Ob-VS#'8C 7R$"˨C"w&֙ח%{tEi ud,rMPL+''{EbdĨi97㪳Ԥ52jd| rz\ }vg;@]R:SǚWfSS E,jsRAC؜dvVSbMi~I5ohtBᐑAA L:Ndf f2E(yJ:vv7!,a>FE LQ͠mPT YoSB[1Emn-N˒)Gl*O?,73@ܸ YXm*ҥWa<kBt+8)+C#rr pEZ:;,-mȾ[/yuDn-B43 (Ss|cgWר onlwvayV`Uv :۰3FU=J:,[@r'R޼I@=U2 Ī!#(L'@Ucx24r#uJ[HqŻBX!F,FL5Jz#:BI/`5lΕX:5dMÀu᜚iB̏Eu =LXdC2Qqz4ħU=/ˁ4c-'͠1S .T W dJ"E. 1s(\p Ep"S#D L('H(5q8 $x -:˨;qI&bN %!K]d^H-Ѩm550no 胔صB!QJ|JG4˅~=34|%'y}s*\byG$? ])" /H60FT0SH) D9J +/@ v"佷p732 E4? ^?rEr3 =r,َf˭t>)4FQO7qTX {AB .bD?V.kM $9J|M?awQ9R:c9QّS~x±9I3:J9!l| Z}ADF23>f=.ޖaH_nOH_ϚT ag.$A3əpJ):Vd}Xe!}n-4iYeIgi̫f1`s5j\-i}1g؟X02r@L*4 oxSʮͥ}@zO!OT$W('%25P  J΁ HDm/ȏ*Hݲ {:fG5&D@pOr' { wi@>b&2 D4&OG=nٙo{c ;hA =)91hg r>,"YȄx"HJ\c=NvW^=l$c X}^ UGD$&`Z<ϒ˧ݺ1`&Y0l jkm"́QګpaN׶Fii)_:K6Na;}>Uo7~¨L䁄k}Oa8_ f$t|[K:1(Chlǰ@c/Wm YUbXr J&G. zӵ28 a8%e#6zQjdo>{ hy\,D#з٫gZƘLc6RjX`ل+C-f#EoޖڥDj.Em",k"|j FQڋU=eeF`Kv@/֡@}xL;Ԟȳ X?L \(H @œ$#҉=b̰2JN&c$Z/˕,>$3{GPꃰ[8QHm HST1j @rH0:_@[&x&ɏ~'ޝ x㑃y hǚnc\@p_; 5a@UA^1jP쎦L~+nf*nQ *hiOa v/({J~֭VTwsbC8CevKf0ՉY B 9JܴM/>}Z_:{]V4VA&o¨oW&ˌ['9qVŌf覌8M$1Uq8Fw:.Z◢o:xaEiˌ/A?ҹD%iT`ܬ5&(2\Y8KXot\J_֨<-M c68omg 5`[[=O`Lbn>BTĆ&}?Ca0 =or Kձ|~ǴРM%\u YOV/j&:/X]F7 P#HJXk%qŃt5XΑiFFC,Gx:ȟGg<3i\t\O*[I\ (&2D'EUL !?!? iy+r\p ^  2頱7h-F#*G!/Ș 1S+:‹Zԑ6Eֲq?|]ۈas'z}8x -VuohY:BDq2c$̒}bՋAp./:^[&n]iFOC V}X}=ϧ/K,%69.ұ,lPڵTcRb;>lP@A2*8¢\p6N_6EES5\҈,F}z@T053 IY8-=߯|)=Q>CɸU s$m-%!pEFňuKPUvr.~3zh͎r z(ݜ_k:vO2^jqE|5e%4$F΄l}㱅.I dlgu\>d3= J ҝмTbe^:Cf?٣s6Mo7I+tk~lICP hs:h>AZ ngU!q@`zw";ἱ+8^_j:B]+1%kj㏏k;2a.K@˯S5XXdW|dQ7,60F 4Db{4fLi nd@ȟ /bdUuNYo@Ggm%6"fD1!"^L:dMc1$)~ۜh[kFEHIϣoAG 26c#" <Ϻ:aMvRLڮ>_O"H>&6|r "zig;%eUk׆cR25Xa8p8q!&uJpFH3Xid9u Bk!Yh [9P0&ڹQOS茓@,I7\/EkȳEB=w$9qʣf t _7ꖏqAy @~iΕi?IT9P^`"ƶ-na0pYz,#Q3U[7P!45tuoXeܸa~60 -ep@Ĝ>#P<t +8³ZRcMUzĸF]CʡBc_/D<৲t˧ȴ)DJ`JqAFHOP.Wҧ>Y+Ns:.gi6- n5EZSJZ#k˂B[1ڜ8>Z6%PMx!cN hK@ 7cאf?varhxkMcr 1Zp2wzÃnnjd/v'&G#D#WO^>W %nQɴmJ@#O: Tѹ&z @r|sDt,\J8v><`v`4s7 m!! ,Vyb%6!_Dv[qЄ|, @>ՑR̸4܄\Xl>H#+#!FAEvnj׫HNv۶|B}ookR5o.\>DGLJVPDbuߐ+N(i,JSf4sH-.mTP,@ \0eN͍hGzp.Lz_z' ByMT'mG.nc'N?Fk&?O0V@Q1xL*3̢G!NaD9m3luG,3a TaUMDNm5d X#bFu70g>i0'_3K6&ɠt4hkRHJ&}Z7ϠƫI/O<;V:PDVFIDe <~x~K)cF#ᤤ ;F bӌhU:xʽZ`0-V5Q-$b+\yZtHqQ:%/6q2 C{ڰFS]yrցO$I+;$rV>V^@6$1h <z{&Bi:޶5 Qޞz S\>-7HȬ @ArHȦB+0[^ƫσ9*8#v#U(J _v/R=aQ~i:_v~ g[t|Byy"ZKSXymyы]+ ;r<%=[ezm#Nn$1ᝯ(9]TW#&`e--֤K0?^'tB!?]dHrqkyx/gn>]L^hUMuY3xZ#-M1jtXg2XkX xs1 J{`!P] 6~xSkxU=<痯$@`G,_slۖyϒޘ V ouEzǰplR(\[ uƪkaAav4+ţhUq56|~^RB: k\YZףk4`f07d{q{ksOrD,1b$ĤAk*ar27@eV HlSXh LT1fX@rJqӖ.-X^OviexuD0A)fu|pweL )jxV@ 07D3qtAC"95"z<7jOtD R/F@ Sf%kPk4c]s4QΤe*ä&$SGӳT/ tC'k*2+exaThz3X}XK8^ソ`9АL{$X#[J\r݆BvY"rm5Fc !:խl//(u*]jO!rv<  LwyF!C gJuEZO=K*/`Q \dWX5t5.ʄD=$mZhR@J]?7^kP[]$R%o>/p TV3GcMZ5 j[(9f\'ɐLam#Jb0Rs-2 Лbɏ(\gG3_f|`_3yvm˕grLh,d! jv̳\ټja,G̏Z[L^FWbl}k睔3glӵYٌ٘G5kfXKFHjF_ WcL#:0Al梃{5c*T7S(e}<P'E[rd.:z=~OdT?)ojܫ(+ i;dZ8ձ-h<#^2(E6;Ƙ 40`h T^fN0֔jj"g *>/lH2L/idYP]. qgk|o*E#v;Gک44M55Wj;<ɦMCWJ#zj"2[^1vr; 'y-aEG8#R%zEYUU(> gj{Υ a!bcC&XDƇ4fdU |1hQF7g #$%ث=ȸVzuQ?# 4y}pgecE1g ,\˲_o ;wr7J$I=6ċ?mqeչZVV @i6_ȃݵ(h"3QI&ގl$j;yq1S2@@a>X~89ǸzCdM #aM+""}cNԩ,®lݩwN]26eUUoIxwá#Fjr{»O6IK/hWTdJEzy DP1D`:) v 1H hzi[wPM~oZʓщ-O`I.Cq5ulzGN}])@>Z\C\ӛl耓~c3i$:Bo I*Q{T^fuU5/ 2h$ t_ <"O;lky#%YDyx Ԟ6vQkbfSHje+iW5Hdzg/#?7K$O7O^UО9SW2U&-ߘ_ХHQ wR9IJXN(PTcePk10]f iܭZrs"aMjc5S~o3h^YvO)Cw+ <Y;U?%%&%y<^ 1z0_$1'ݽƊ%0"R[d}tΑwkE M&@,J_2 (7 1 uU(/uA:IoIvҚd{E4 &-ANWIl}.^d8hW=5t3lT 25En07îSVx5=jxjI(j/e!h9SoÖͅ(DyG.QеCo[Hg>3jʥV杢ʒ޿~KL:LA<-m@T+o3Ӭz EY[A h 鷌p?ϗsyYbK*W[}%C?[6#/]*\ucTqs]>ײCuDZ1^NZD^#>S1 dsv @əâ#ڒ H8VBOD֟gFn$KNJXMq4[4Bow ׎~8:1tmbvX4=2&ÌtB"ư<=#@8M`Na e;ɝl;e|oqv %xgeWS]Q/l$W|4ܜ%#/o 5_嗒2]M1/MeΎAD@"\cV")@8 0i͐$RJ1572,ml,@Cn>:K.`n}lrJ4ÝJ5_E{zk3@vzjֹ]iA e]+Ɩ"?S3V Xc]Bb{O#j#uD8J?-G[c4gz"$w~`.+PE}0ЋCs=RdVCln a>nWKO0ݢ Qs)IXo5A\FjgSU5aӦ #GE- g.8( HA*hL5BOZLa&Yz7H܇WatM@sǝ7}@ن`,Zo|i5 4VhۍD9n.޴Y(?#Pu]~1W|2.BA i Rl/3z1[wfyȈ,V2ʚ3r|5e~oH~^W@$,~Kd HV8u5 ^c5ۉw}F4ު07r8kkŵmܜ gXBS5UA3:>vgo`$֝OFJ3,ڲ V1-t g#;"=.& vNliS0"sy9YҶ]1.12ω:f61a \h(0W.'ϔ7.ߎ|Ia;OVK8D4زM>eO&,iu( {u_/L6iD+ԫJOlB҂6tٳ<j(h7fMZ"@eg%8Dmܴ :z R6=O;tuc 'c8uc,t8pޔ7 Z+\Zwr2Ua 5i'5cʙ&!o;I 9@ M`✊; Vf#9e]sʚ#m֊S.i%SK^+񙻷jmR4r 4W,$7k{*[ҙI&!Ǫl |TRk"2\$S{,YSl{aqi $0e1)Y cF'wD xd @~NPy +vNo>lu;Y=Xg$}?T៕3=Ĥ\fIS/]t,g|3.xPL!-}342M茳Ŀwj$㺵OEJPar@E|QnS~C}jIN ^S(9ę`:^u;0{h)y=GoݭO ߉A>7t檅Q<ȉh#){Gea}@- sKƷ3j^MCޮrjK* 1\T5_t"뗿8.~^6;%~Zxk&8}`-J۝,v]6UtEhFpQ?=SSKU`RĻWSL>mê c'4@1873[TlʏNMZI[В9.!II== &K,G2Qaua)%R8GNqimQAQj?99d%-@[xڢYl%A򨟍'rj;N~{MW)m8f. N\u E~_nua ؋~0Y'syrVр?\NT0[TK?n`RL$`ubr^;\Vhl fi2Y&n!)7;0jưPw(},&k"!o8R8|[Dz~F__پD"!ˎkL6,dߏНA;MxqRt5'p{o-Aq5l\Ӟvzgq=/ =5Ek(8^e/5j)#fLv@&@|qWqM,c6a#o ,Dz G5w/Q=j˄`K1cejGKjQ "&V5{&GXMhMNl^9 @m`lP5/ǛA 4z)|[1â7zAoBKV׫M Y= ZbVP=!F 謍=Ci:dQ +Jڀ Pk,$LC R_y%YA`DRgYɊ4*'AOL/W#Lb>aF_R&ʔ WE0dBTw=k`AZ2>K+NQ=O -{M Җa0RG.5eE:ō1U4(- mƁQn>mXSڿƮ!ՃptPb8`T'B5K>.q%Q$ }ړf(Ѡ!:F`*qdm%LqXF$;Od$j1 ®xBǔE ~YuNIl HǐU']$M9ɫ%•т@ 4^'>FWC[ꚵipͤߝHw!Q$ҡzIzc b?jCz:3ud&}CoSW)Q />#a1 sb`0nf=2D~qIPEƂR3 ܓBEܤD4n5ZǪ@suI(OT=W0m:`Eh0y,;x,^.nUcI`k"Ű Z5')҅ |z~4O1=7JJ \3sf850IY *z)DwW3Eb.4b֪@5lu>-0w6>`JM=@xЍF)UP72,GʽCdV,^Ơb OvM# zvdmy m>(!6"ьA%&k6dXF]|!4r@o-)! q{>On{Kپ]ZZ,TFEU:N%!YE`9=OQ Z֠m˓mhaZVw 0s?~0Ů"\*NO@]ՏҼ(Gn"r8%#́!u}`Fi@~T#SL[e|dKbn~zH+H̙a6*[B <:%B-Ul'AK 3 yTWT3+v`Yjb DƫqI%UFIcqF>Kjy /sDQȈoc 1{K;N~B%W:E:JXp!B\S'Z&7Ӥ'> {ɳeQ)o!CÄ7A涴\ Q>~4+FTfTv~6ЍEJJi*F;H֥`IH66~  jFw~ ,c|Mɩv l-ZfRY"o|8"N\`"C>(UxXaMֺ6RB5_ [ܳdQU#Tb dE &_'ꜳѾ1U,:W <^t|w)^)4%T6ՒZRyś^ha)kL3EʹlGY7"lU,)u<#vo8M/KSljp0/c)FEeV_dgzQ˞SPCz#EQswŲZ/yicu$CNY/;!J"Ф9_6<βH>PEzusR‘'54%{f -ᩩuq7k7$J˴O"4;2\=Y57ұ̵FGe]AM&RRJsp`dZ7\"39ϸCۢ%=DhYu)3k!M@7`51i"m>O8-ٔIèԔC`"h#FH"xa ꁌvPq=qO_aZJ=/2H5<稧kAx0Y:9^׮<dDx pqwӡ?"DN~vQרJ[頹 $JA* C\[U'b."9vG'l8#cg'?0Zq .Zի8cYMX7C1_< kDQ ! Pil B4$ECnx1C("o2ܒ "@%1B'#hW+4 'JIÚz#,}6?j|RojBSYa2g:DF sJK!]Sd;K_vQΉAFu0(P+VW<2u-}UEUiq tʳ#*d#zʍ95V ֫9+/(ny[M6.$Q C…xEo;zi o A=זY2l͟cYl0Wn K s)a^d"zBi"#s!F?kR&<CЄ(7F6R=8Oz~6=6o<:Eѥkm~!@}כjm䫍/ꤔ[^W?E4H8);݈*ڋ4 t蔔XbGez\XCP#7&+J>& 8R"y"a&u$A ѓG `r))+yOD Aws&ă"Q^cGLO0J' 79Ò5 F}}];c\<m9Q>.nGӸ6fO%5@`C.7h?{psً鄗pNXYibCS Q`hd'`,ToJ99#jpW+(Ȓ55v ~$'pc^nG#S"u}7k# zW BufZLq9 ܦ2xir5huI10,lDf/[:R#Md!,. `BC.gΌȌn~D 2B>` `ߒ IiVsRb/TQwzv+)_] DBqd 2QB̡{ e2[ 5P=.]{,+tg5}/*Z&A T*jX1V]hAa/P3\Ya Wk;E4Ǿ@9S\^p-y:x*6ߜ((!`GY[j{p:;`dF xJMB, ,fh*6K,K;WoLDRy; JPZN%vG  jvĘ?{yQq\0k߅Bi@-[|h{  Z13#'8]"C0~݋"Ӫn8"*Zz`մiMxÑmäH e%l?p:-JBuiHHskϖ BߍhDyFRoNeB!Cb).){((6WCtPGnJ46"Fp}8'v]l ZwRtUh@yko|kA \!h*(*KdY-gM=SMi.PcCʚʼncl# vXv'!cjepʴgc!( 2l&HVL%(F-ߘB?N{j &v`% }5 NM*78Dg ŪR [ fz<~p]bo_qCÀn0eyMO*H\:1I:APQKґ<@0-_PC~H'4L#LtH2MGc#m:,s - w{7qg, 5ocDE{3SUncGQ $VK]']GAYfUӂ[=\R\g&xL✟ hyҔJ;AՏo8)A/c1Ajt'̜EʆkhR # x#bs|*"4sdfƶZ'/+媪LeFҊ˒,"@Ť`#0%Ƌmoґ's '^j5;2풎x?xU~BZ8yMhl4fgR,/F1*AC({O8 C5*EßŰY5qȧ(.KԯaHc\=MH12/-+3D<-zAmHBM.,r$SMkH D -}L( doT~pt5‚(L}i>8$ksfu{{/J@ؒ%FY i'Kjל D-aOQQ$2~[r+<VjIh2Bi<: DsuQ.p>Yo\'ek -ԫpX,'vd&DB1Ƽ: !\oP'J=`nw!3OŠLꝸVlIBfMJ1&q#Q}$*rj|b`= R}Eh /*+xh, tY-lGQ^(ZO+(@Fo25ΰzXbsgI1z#OI}M\$p(xƮjUõXLSݍ^!+$g ۺAԡ Hm<. it;Zͳ0=NAM=c$2N^bS4#5[j٤p{?4`&gPIe| ptUCqdaet8 =z+FngC֛6ʳ0|R) t* " 5B -68Syjj5,<&B,"9'#X tj"לtp{S[YK%ep^1֛|}:7LP0wR'i*~b6=Ի;èp)z*Z\ijm!VĝSΑ$(^9Bq )rAE*K^K U[f*./5mXݚ|zuЁIK#(w^N26pִ4ot&aEXw0֣(o6ca9lfS;f&.DeCE_^εs RH,:/ţLLg"8ZֲFnytDs@[3S*n#)Pn[r V}\Hz#>Fʷ)'mK<;66ĜmF22n{z{i\}+A n-o)YjF%YwAd#Jn@pm. @< co![H4tyo~E&< p1^ AYJKҚ}L1ukM \0ih8l$ޓ-UD0' (|3H01֐RN ߛ YlrJ0*sXL Wpf:x`-K.H2{ Gd2@qq11) $bQ|d˙"O+3 | ҆Ulp zSJ+ٽҜAj~8xhS[꧃9STV`P?6KE&Z^_ v LiY@QGlP-6uMۚAW;4BB#2%1(1l-9d2>̝X3En#]~n?v1~H5!i]pLύV5lAvY ZnoO4jrsNQ?!eĐ:׆T>J;{σU@1Wu&Xg&]N:iu~]CbSmlG`UzKE"$TT-n}kxqVڡn%G|#4h$RnϗNuV=ܝ?U gr^ӡNR4p:U"YJH6ƨ1Hu'%/-8%:#! a6݂3Ϫ\FMHn^{pN9oei*ފKNQ +-oݱ+pceoƒ?ql4Kg7umMW]^w춒-$=Nx}%KAC%AyXACxgTcVW:$ƴ4ӌ}ul?xfdT9Zhe[qfN{Kb6 5톍THEHt,nCN/S*]eHQ&lnlxqgQ@CiZrAfN"!EXRLfG-5~=˺8{+uF_EFX}wҪrKsWk/wV0'pҤ$l _ ˉ,i֛f p;+_GCdWC-YDֲ:A RtsQawW-:cyML_\d-IQc9c{Ӭ3Gcc "g#IdqK(~e? P&X5e$&WFaysNN(1{ڈ٘l,dY˲7. ;bN޽Z"5xZL~? CRv\'C1Oհ$o:U ,(0)Ap,~|>b-ɪ䗛c-+_s%ܞڲqmPbΞ@M[W|fJ[IW&cm\iho:?v8Mķͅ !Xm /RcњjhֶkH>123ז-mkఽ_T9٤3q.MќFXI(; ~+%O7'緯m[|?$? [EPNJuLןy8X6# Zi6K%)GJS]Q= ~"D5x4)UNꤽPIn$%?},*1`,^آDKv}Yql_$aڎ&P|bqÀT,~mڢS^H:g}i YY }6,dl%~M);kΌiEI$IzwsƅyP7D1A[8bm2Ъ,#nSD "}auO%"/}-ɻOȑ?աپ$Blݒ0jhށuaeYd"{vj1$u?6V^{gXԮ0 }F禦ľߟfĠf.4Bk/8ïx}&'z "SkݭxK KMvݣtV=ILlV9/OR>gb24#t*30LG>bHdVI!O9(YT6#j oTXjHlO^nDQq.h!ռ 7s+) 0 |&xERO@ YYω2$2b >2MO,# GıD弒&bLx1m~)Eʘxߎ2j+Lվ#A@JϱQ5l [s%w0k(_zGfP5EBH1b`(! @yig%0*~B(;,e# 0E bB9bd.rTWG M))qiF`m($؂ޗɌ &h o9N Rw<C44WI5\{m^_Eث:gRLRSa^|l{"A%9|f\S|kY His]T(k[B'@?q Ф&h4Wdž`iCJ`_-*ϳKeyrQC~5t} s$y(d`^̲@.<THN@9B2 փiCu̠yoΜj={etӷطbE 7G?<;qn[PiĵyT텘 ( Z]om]ⲊyŮ&3$i$ۦXIԳ/QBf\kQR{vP؍mnh$~b!s+ {e؞%^Cyi(r%3KaL dre 5M""w2r W$ ]PlN^OY$Dޒ>ZXYP}qVv/Fl|B:N N'6@̣-H`FXʥ!5EMA+NdE3 \i?A'UTHyG͆XzD:hrC_b{ji;4v% :$n&Ond@&@@IDATcp6 ?7Ir.RNJP}`g$nXH8i/!&z؇*FȮ+zSLϠo?22!OmPE5XC4jJ ~^>NwEPLjw!bfc j^75C>SSޅy%n-!LQ0HHĪ&l c}ZfV 4Ob EL FjMF&z6.W7 ު*W.Ҫ"pMyv/?W0ck[?m9kR壝iqC7C]Wv+.tLY*4:瓡S oTJ]HxQ*T2_1Ϻt#547z>'|n)EAeid($i:fӿO')w;::?^jP5,VxPrVxO/frcZ<+:EŨϠ8?蔩bd=u$'ԳB[܊94ZmR1P R6eؘԺe&p au< C]nIF68ZM +1qW5j٤C@N2q'>(^ԙ巈6a"x5@*jH PEZA=9qzgR8S|S,|4?+,pv`QW$ΧN"<,Қ0q۴coFnS<i4‡N0fE4YGPFrܪEݝO v٦f`-Biڍؖ}3B\G^ H$&pjo|^b C%Vv8T@:ha@AHy>E1ْEPN@EvMRYVjS}5OWT/toFjtTZ^bcD;d$ԫx6 䆦YШ*GzW4tL/2c̏o#0B-!2:{9 tQ"nbAGpzГE de%0oJ+$2qmܶ @5b }(uȧ\`h$]y[UVآ;2QGU6d7l>mzg6byF + 4abv2h,izTn_.*gaZnL鹼޼2x+FÄ"p3i g^ꮸ1H7"*__m#Y 㨎|0PX]b{ɞ.YSq"c7Ԇ5b" m=^K!dfaMdЫ0Xrpd.6Nxe,sA>`  ~YÀ55RaDtDˤvRybyb˨yGۍj6i݆ ,{H\r`"_'e%3\E &aJ1%FIE67kDA^. JE4Txm&m,Zw/(HItMPlߟjg v"GOpy(KXKa4)BVe"¬Jm.}7,mփAZb > z: )ÞeS׼9Du,"Hlg-d}*-4&cP(j ӥRi1.)Uק1p$Wx{@,Lzʜmyˁ)@;C1Ryz?㕏z!Z7cFq`7\&<ܠ8J? ,¨qkcrzB tD>yVǻ1%*44:+#8R, K`J#[ S+1f2hRӡ#s-u<С[6PG`Ƃv擿N)jbo5 ]k%sHHq Va&!"lpI%8NԋXF%%V~V,5>R7Nͣ[!?r GFMknh:aina."w:Rx f+H#f8O /`X;._>UoSR{>E͙5m0u*EQ1(SA.v3HCȴ 8% ԾoS ${5ZRHќX.CIY2=@3σFMy-Zt%8Ä^J$Ɇq\ IC x߯Ww $çK ts.> dJb 2311,r0#7 0rbAC;lc B8&<|eրu$UMN6hѻyi<dzڐ,*,Q MW-Pa2jPՁQ`Pm/ x ׇ/d-! KAO ҉PR Ċ:;kW"ו#sdMt6޹^ncσkƢUgB^0-.XSB.U iop-c?:I\^BFlL성7;]p tMÑ&pF%S҈1Q"TiAfdJ]L3S_xX]%~ I1Gdd&;`d62ƀE)Z%s pP/VW~S$G$a' (-Ĉ2@7n@<5=UkG;-_T~^S/qd(%R-4ȧR*ǤbH4i67tFܞ8~7k͓0vi#]7[ظF:fE]-T*#ndY\MM~[98X #|yn%ց鬺!:ZU\~ר?q)2T8e6Up~13okrrq?$LIZmY5‰o,*kd'[u8 kB%AJ =zL}*k2 ,FuZ>d ŰV^/V*BBPx9 VY$on/|8"al;w(> w.W)u%ҩ&vnBNx>}j9~o͞ldA2K|Zj@pC [N->.?_Y~a"q|/o`ۤ WPa)-ϔU&/T|^#.T;4$ Of%_ ,l#*ʝ9ZVsYvd^hGiJ%JSNulgq;v,]#(GsH4Tzv2轷n;z~&õY9滽خjC}5Of IjA>^n=2f4 ,DZH!)`?^2q/3!]h]u;.We< JjTn;!^*ڭVx _<߃dxq%VgCp_~"K{& ɡY8gr8tm-&&Ϟ2fe`$Fm#Fe ?ҍ[Gm~1w`/7/s(~LDN{WeO#wA9=r(_׷R6E- 1q[|_(e8IKUш2}̽ ,,fGd +rhš@Dm %}[ljK736 y{EϽVRW]<;b^9k7䗪.j .qo, 6!<MT_V:yvb/b}2'9'S,6SF0@Lbԍ-])Lf;h)7BdA} 3f"RX#$1cI; kFsjٖT5/c`=!@, \Mƒo6KPf=D՚Uoׇ?֋𐡔Ae(v!S^BS'JWԕOSE/\QRxFZ3:TL{Z !9>wƚMu''BS &(lXIQH,%RD#j5tZgX U7Y6vۻHsyb417KxaMu$*R "'#S%R5v$;t[ /ahƿa+3e-ev u' i, |Ў[VLV+>ԘJ#>8H]j,M\ս3v$\jcx:jaaTjz6՗j]cWhF]zZ<'wFH݂0c?|7~~Uĩj BZ>F{TCǠ[1}x פ@ %Rv+2 %mqE7B&(7Z"ekݞӿ>P#ˡ. `)>f~ g`Oڭx 9QQ5@갠h 44((AHa3p_4.S#P@^uY1Œ*N7sLϏ|UM6+Nto8R p;gG >xx5y;&6zOkh $њI; *F~wPLÙ}TBs'fUe29^ MZJ5 Ba͚A!싖Z. \_lX& 0$(EhHi;u?,Pw<䞷|b_HV*ģ땞Y Kh ƝIɒA;Ck( x:t"{TNOLy_0NY-f#|rF떩v0k>i9r@7嶯ٞg`MRe 2X5Lܔxϩb5X)t)ԓ0 [(%P}KNeJ;A}1uYrz/p%c dHCAhcb.*APq?.Ga&?~%o\+T/w @&? 2a.B RU 5-kJ T@֎礅 YP?FMga P{}Nw<*,B3"0q4c V@6S!RmjRtaJ'gTq*ѱM/?;{ 7x20e`/ IXv8-l K6sp9Ɲ1h-knulڇh&!qlU+2*{'R ?u(qqE Hl~)nt+#3XRlP;V<7+q,fkr8XʺpX1c$ &IN*"8bfZ7F ϥ.ZlY2>Ci3Y$"s#MXA7 PW1 U4<n9|@΂%kxPB%/o{MB@q}sP5 M2;tT`Obݰn 7O(JȨ˼7@j T,)@:ll vB޾2KXM*!eׇСR}5SfX*dz%.6o]|L+ lj"G[% `׶moś;ЗץTC5\FTWCv~y(*%>p3`\3k4Vsy҆f#^wGRY( چ%aR>z0gf> a\@y2mشM=FA uK$viPZ"mljі [BOp{%ox OyNc'byC_ZQȸ.NW̒ p T`KS?5kv^ALpbFQ@#El53 d1ڽ)^2;O.?S$0b|ь{o[%)2ӏN ʶR=. }[.9mRh4֙Zj@99qeh ,qKB SϔHIs 7rV4ޅS^ R/pjA(qIMHDR.h= ffw./J&v4m60I.F'r LĎUC`7* uGX8vߥXLZYh0DHh A7GRd2svx᏶1iR?@Sw躁.rv}T[8&5D2Y"*e}mDwVvQZؗ#x9fm0eϟלx*O{4S5AF'2渨&8ev.2P4%;8A{WC?2Tdٚ?+T٣h Ҹ쉋_8 ΋œko:$rl-C|Ym@ CislcnC kzwסY&"偍P9#|~Lq0C3КyX_k_Aa =J>,'y*E,`cs3oxr&kD@1(6`ۣ$.Y?`N:56NB:e3_,9EXb* Pv%[M52/08˘J!)'Obzo5ബ=w:ȉ65`ZO0Y`6X3$"P@LLx2(qZ)2^/\;ѾǕ]w۫6M`֝B|׸@ݫF_2wm+n;gHo4טf}; vJ!a\LEI݌7TQU3Q_nm6Q B+ds\W"{v-B:xnKuYq9Ô%즞p8_ӷ^PO Vv9ؼJy'R}0NEc6-#!?q81%fԔfXr2}+Nx\@Qq nt$Ej Ư ]j2}(so"rh1ͣ211ȅ*ʿN"yT`_> ,!(֐`=RFi]";&[4sV0`m[F#O.#ޡg:s8FCq{TDBt9#3>k9cwCH̱E9('`Iv~חA,^1cp/VԤf=>m[d"#k+dx%}Y P\!aU;8Nha^֎l#-.3:C#P^ٛ/Aԫ 1"-oMѻ #[$!{u$-rP2oqt20z'{$J{zP E4 JUoij: Z"Q q/B $FR>R k+MGMWʯP۪]#Rpɓo%&mw\/0*/]dFSjm@c=P?b楀LPo԰P2E:<ڂ3xQJ4fRRg3^u lm򡽬Ja,ƥaA dCFf%pE&[% @_nU4I. |aE52{s7ViE9>cSV]A9>&~CA0{wǏov Պ ǖ0"^hvDKt(Eʟt{ <Qa*;){{Sd$`?8G22 goOuFYC1Y,QB"Y70+&jk9|Q*2:{QfޅZ6!W vpI(\Ic_?sIcm/Jy2\ɴmzbr=t#Mk[AG1"6HR80N@54H6C!/ em@t- DM2V)=1Vg 9aO]ЪƮBm@YAUSFhʖjܙy6q=ކ_]=Ol a7vGd9@`lPzŐ^zM `H?nyJLogpd6׎k;lkKڪMkBy fw3OQxR,lS HbE_ £nLIv4i{dدn=.Eraly8GfDhi@cϙUkG*M4tj5b(ԪVq6JG؄غƧFqndpz&﨎aMReQ4lŃ$2' M^x()27DG|*M4!O+o4TJgbtԜ?8, ZZ Ab#l~4a2tc-Go0sF[F.-IXKfj30k9Nٚ)'&'];pݔ]i|3GUY)5#3!Tm@^㾼xiylaW j Wqͅ\/ }Gzћiv;^ ĭ$-y 8Y 4WTlh;NmTjyU~7N.D%ogpx>_oY %0cIe<e7U89<8JH>9us-bAdGG&x=%uװlu8ޱ R6f^}/ O QA!Z7,Mn9:a&iE a$$ܣ#ڕclXW޻ckhh|SƷгz: u+YRatTi8?q ?Z&ٹU⃭XecnՆA56+pStHJfƀVJk4+w RAeSNo}LAv|^M,opǟR J.Send~Pzb٩/kPr}NN(! eHu7X\s.OF%Biy(151 jʠD7'i?nӭe*K J0HYrL:8["@V>o'9,a$>Ec;ӄ+'L ͻ>+57Nh <7'2@ߺ(h-,I1nW7PRD4!Xs#_ǢH~-tФ0 %N7̒RHL=jݱãy}GGR P;q :xG'su}[2FWA}@OCnWp $gtwcF>/v6Yn(QcbO]R5*ZeE;WUOqsoaɤ"ߢ4=[ъVբTk[rB@&(XMBSCh]9Nڞnu[-FutodḐnNָ;^-P9qz}{:4ERIU`e+B8MQUi'%5_+-%\7c Kn.?0-AYۃhʆCTurt]nlSp`Zc.3~87o씂ͣ_#ϷU}a-~'![kv:*߽9ȲQ*/.@͞,ઽ;ӄm }+t,݆e>F[TZQjJ &10Yowؒ"1̈́J^~!$# }-ڝ_N]c?OWg }X>͟EWG˫u& ]&\R#*?vag<3әLt+|UYV/3R_EG^7H1{CRBQ7n_v_oٶe/jX43mEs\w} vL?wtѽ`(J~0IϛB)%|;Q a\)*tq0pAͦlvo& wlx$> @e8'(3Zؔ)a39}{[Evl Ϥ/llClvJ=hy:13~jy,=4"4NxWz fdjH ݅:y9wӖsea YD73U?YlC U2X?Όʸ3 ([:˵U&e̕57&y(Yfv@ȵk̃q%Om٢QT{⌒e`htZ,8jK@|z$vjӴ~ "Zzy-!a, RX@Qh Up ;׺!4g lPY8D\"`KդNT.‹|\ ;?dZ>\{ђA @F J̓@Oc=*MKrG.v e(v+sFMٲ6nZнaA@1C <;fR ip2_30ɘғ>yR/O:Q0HTsh3n_ybpoI -C*/7Ftf1SdiE;ыfG v9@D( r[3O+FBZGF p4?6h Ԭl'OpRkQlAVO?*xۿ~m&\CVQmL0δ-Dq;(0R;ӟw>ݮdv\gDhPOPPF3L>,iM{M"eh]fTȗ`BcjDv1<[wPBLf&<ڶ7]åSo,mhJqYx c0D#H\H UrBNƪрװd@A]d*Lf0jBjpjIxD5pD6fW$ {ZķW{-2J,i?G E0QPqLwz#M9ZD4b9 9HBR~̊ıT.P!jWx %0UEzM#tEߡW9/3xxM~c>]փNE̾|]a5W>Ȟn,+vP]z<~Ǥtq Aqs*w4Zȣ8x#|Ҡf5|q`VZ|:9͡%SD+>ڬYw=5kV.KFjl0)LED%P<Iፆ\jv2״xY`o(Tߕ0hKe;:ĉ]V2>έE#țzwVE[0VƊ:R;V"~=~hpUU vBuUg _؉&S˳:.Au8rA^ǰ$$E1EG@=>W*yΖLJ艌Ih1>7/Uf345 =0%8b4\L\L6n#ϴZLj +(^\ځPI>imtGlO\[VC6'gy V*/x6RurMâМPyԦsD>la[kOջ]DwH_0&_"6ɱSyl}2ly MU#b1n3Q`%g3TP>5 m07^:Cܒ"CRwR h<ژ 6fz+eS5ܕX; 4sckcpi0<9TX:>08P!T&xmѮu D~Ny~7e DS"0XNi #~uVu4Ŧf<`cQ }y7P)ߜMHH[ȳinx9+DNgs}l-I7dV"++ўwnsdI`C'9 [tH5828z"R;\c"N;ZK -i؍ IƝIǎE&:05d.t>k9!"8/g#Y:wь?qy2)S'&@M %1=ƫGK%mbBAR3[[ܠ4ט2B?%%WWSGD@0`-Tp*^)낕Su߰ ֳNl}pPF%vƙ+uw' b ydxKy{sM޸\9[h#$䗌a2H)8Y HTPEq>q:~axKC11 Z)wq 'xIMu?@O  "!~Q}X-+NIc sOY+=y2]xEl`$FPH0b`u.媛f<I~ ; S 3CeI$يr>N􉖵3#$q JcXE> @BWs 9YT:h6d%4 h༷4GC4-<:a07vnl HmdJ0$FY]4T2`o11?ay8 oO}KBOOq0)`tvX76JLL0,2"Ǯ:0ɧ|ؖ1Gprg8"@ VG D b壥gIaצn /.o-וG^6C9.TD gk@IJeXOO]g<ZFbms<v?gGH i8Y &yK FY7!x6?„ɚn܊ c(P&&*?!ۇCLo=j*ZZx 98T pۑ-%Y;`mi 1f0 dTP5̞5Q] meJ]w:{W'A^%pH8Bȣ8$.vUnh96Dm}H=z[fAWP`*C'c(S c w#BXLҜFqd y85Xa=EP_4,W*j![AAɥ`$-coʠgnD3irem3 nC+va:!MGO SrUB88ЀTb[b!?N?NN-jgu8ۡ.>m "3GI븲]N2HrtM OnD0bz *$Sj|ʣϺ; T̯BtD Qm![@dT R*RuCl,^ 6/)>pjˇ{J0ؠաD٘1>1Lj3)tyA S5!@ExvjMz,E'JoڣbasvQ"tK) Y-c79#FBaaQȝa WYaܒc&b$)E젯B".."h(6~`tu Q|)Z%Ҍ5~ po8cݦKZ$9f@Rewŋ 1L}"4Ϥ^dgg4Kt:mJSw}}az *b`Ihc)تO''D<!J?gYţG|qG`8…)\ (2'onLʒFZD0[2\FVյ=\ 23I?1Ux|kRvX#u0;l,Ɠ \XjD5][s\;P,zDskA|J1C/o /RL4yZº·Ti04T.:NF*Mpr!ɦmEʐezG/>5^ Y'QK.ʆ~ rd}(QS:s!LCE݂L?}E=om*+RXu CqgPS~IH q=fL[ޓ2.PU%صX"2k@ .hhX9qsL.k_l+OL˂,NTyf|`i܆%6mE +fYgz1 Sbq!TQXmթ 헚FD~z\`UdR$^t48,!B&=A9teeJKQCk9R.SeJOQj/V+[sh{j ^I'NN|1b{|Vn\QB8.#ΉX,+<^8/kP*޺ ptlO5֡v6e r^'c) 2XpW4ǨqF"1${(8:mF<o1@",LnOvڴsV"#B\ ܗ8[F/ӛ^%)?D3^({s6[1gn0"T|}s(#z"&C2V:tp#btSQCmZDעzӔGIE/7WcJTݮwio*p6l:( wS΃7`*3Mv]Ůpc1IXN7yi ӳj@ԈS)F%{hFSFo^\s̎vq7Z<Ƨ1Mh;ԞXф,a<gԣFxm0TQ'Cĸ G{w˨eiȬ~,S*qTFǜ{|u]- c09z"Mݎ1F#H3 @$"Wo7seD+pgmYH xzz>}Y _fs8y70[ kWγE'6UyBd|yk:#܋vwUJrUTEN}73z`s)pe:r1Miù )"A d5&~}Z(4j0GrQYvLOTS1?N6yaW*\eL„%J%e&tL |\|ϣ P؈bv 4x'bwWLm[FZ |N[$Y|h#o]@cgV>>X,PrCc ,GR  gBӂ|/qlZb,OLvYd%[$&*b- q$CAx׊@`$#“Gקowdfi{;oQ(̎WiJ]IUZθ4ǚlVv!Z'Mym}CEq$øG X3acw$ZB%k7xd(b(h~j.1)!渙7HɖS-{[0|ܭW]#-gl25Uhu\Q-M$_Dr~|]J.Dp#ՅWkY Mý!۳FҎ.(Uz4?f.rփ6vÀXE7"={OH.\ H@%Fx"`Hςlȏ-:YJg{<+ )';gҢ~vuC9LtIe`=1sZ윀Gy+gjU`xFn>So-\⌀XmϤ$50C/#TEs^0~4ar>bq_JckCn'V>$'Ne炲Rt+w"Eeעa6*W(H&tSq C/SGUaG)oO7$ lDZnT%x+Itnĸ~Rma64tB,?`&2 = IzH%4.L*M@ !klbY~TPt#&'4/z4ni`v}Y1u[wP5ύEn6d<-Rޥz0&,cE'f o?7!?>7!d N`||hJNU~a:Pi?G$Ժ5n(5mdS;<7ؤHC%X|s=SO1~k6'U#)HSh ,)K2XLi2Ob4ڥ37K۟tԃٱZ*ɇk b)LJv0:K]O,;`zCt"` m>gfǹy#H-F1bӢ0AGŊMr$UAiZCL9aPcL~9sYMy{ZNTf+\A.}]~ϧmAUIGagks(z}}3 v ,=GזuG3#B1YNu W=q|>n+Ƶ_c>6Zmp`%sGJ] h&7 4IQ3Lg[('''AL@7|9jq)Uփf+l7Xo2r4Y" cl4 {G7*Sj, T˷?$e >H(Rτf !꒞FJ:!ҀkU3҂S([FYk7FiPnFcJ$2g9T fulܞi5F@/CyscN1X9w/Bԏ+J?hy]Hm@ ;)SJ(U]doB@-ff!OܰM(Τt4A;. 3ӧ4Q?hBb7w@U>o"0BU k2rasHj~6|YhL ԷR\+Y\/X&6Ѡ nKQU@#%@ʐ֚~#a.{ci؉{xjL,E @c:mP瓜DPSiz×zi@cz#wK"qa+?ri֔=.h7F\T  M# bH$]\~p;5]Nlk9!#0#Ƕ,-ȝQuQB6Q]._9YM 5, J)q|wWJ{BzesA>6gZ9E6f?4NY ,@g#xJo%y>=}V{2ȹLG;3'eoZ68"}֢Ξ'xVo,sli.=7TԼA3X^*mN֎ :T*1Ih7NOߧɫy˳@K7aOQ 57Z&~w8P}ox4g啧HV򹷌ԋ:to*U0ڦ'-3! \o(^Vvlp ~^ZٗC%-k*a$ڎָ3F,qv`Ș%z] }8jIBen:WL :\uO|&{35[G~i 2T"_'}mI_5/˺mFgTb/[GQ7TV?0.Nû' e5M'c ~],v>M]0]_<(S"CkuTU^j#7i@zLU!Db/'4i6'JAЇCyPJ/`FhT .ʐ)vi1leHvX^UMDFB#g3JdQ c&γm̘ /Ņ Ln&C2h*)K5t©gM~E4`׶֦d^Gd #v׿~ e̊U'EDHOԆuL7O5$5|T ^5AT$SP2E m!K?뚈>1dWQVe,#JTfsNe`IQ>_ Ldh }}| )^D!(&`W[s[%Uc,;v"Y?($Q)LXxO}C|hj5=!YP9$K7bd6ՇBifZM,˶_)CAp'$g6ѣζFȂsz\Gnӝd &/HN 2#y\=Z.>k )F*oh<.e& y*pΦ,췱;C?99hmOh̺ vA/s+6!7 .^ȸ A=GG!PUz_QWBHLT%]j7jf8fi 8RZn닫TB2kk_i۫ߚ$@7Ub& $|sζ{Ȳ?NRpzW> <fEԜ<٣*(k 8rtϙ1ea#N~5D;V#E=Īmyo^)ȲVBy5q)咆YD>ίDm=R~W9KNzƫKo%=\):iNe?UV Wh u v^ EƑlO`s& )ΨX}) Ȥ1{]rttLP@RN&% VքfDNu=%+xY}{F<Ѵ*GiJv˃ApP!L6azw̟Ͳ:fkr=W/ \\(숾^,")0m8iIzFZEn 9p5Ўhu[>r&P㹪\fj@.s"Z+j3,_ tt5ͦ:,?H\p4lrTwP?j08N>0ݜCضny]X>ucrI|s%Q_v^aw{Ü7h\(̉$ZD?xs:]n.y7=W"Ӷx>;GÉ@zt}UKg)~e9B2op<ՙbJ&}KXxT3`5R嵅6=n_|)2 O )ҍ^Djk_cx46-qfi\׍cpkCh riR@<&nFM_[]&8F=XT,G6)"6Έ7xza!ULɷ'+>]wXQM=LPe2cgZe)j˅lbIv{V,nYb,}K5fcs qfp7B-膰gp^Z)]A8YzW~ 9ҎE{^9N{(~Zr!}2%h;[H)ʑxPc{뛽6{06tnbT\OoP'oFFX6f;%s5?d0zD)x}55lY)WL?|ɾ_CrUXէ]R%P5FžOƚx)GTU#A"kJ.x>`mj쥎 =Yd!N<ڡ_<b"pcѬ=w{ :KL*(sͳ!}1%m3=xK"Z&#7 +^Jy0ʞ6mEM㦑C"`w [;pƤ=WͧԾ~"m]uaJ-$c: J.Ց g4@HG5}%`,/É-ŭouU;ʨiC \D,CJg>2(O|Hm$YvŹ׺7gc FviVV!7FWV-3J^?HmEdy*ѾW2*4t2ן#Aʾ +L4]J.Xgh|Q׭Ԣ&iIJNP9*̦oD}Z=2U3,g :`?S=:Y9X̚eR" Ne̴Oܤ&G^l^z b`gw9y,☒RaqM@/!7fo}BDK.)6[-6R!K1.f=ج:uoMb+}Phuz@q k?LF_YH<bgP:K[܍59}("vZU;Ll 5\3m$@`JANE:}S׎JDQ{ $BëhYcv jҸ EƲU3R I7ư:gknE"e|4\?oIBs-+P%d{ )L&~PA[xV˭JAx\"Si=YCxhD͖\|S^lRk/nHqSMAo= z)]J "wATbpZN3]*[`R$cw8[|Bhrb{l@!iY>39ݠOsrK v6ӉQ E cg?<9H[ޯw~ӵc}J6r9;K1XQ|^BDsAtR`\NliX]ddš{JqNfL^ "puH;~)讔M dHp}*hJ'>N+Tb#ж̴fow"˰~wyf,C(Әq+1#Esqv8l6 x2tkrU%-7IԡZrm/豳j9w*c )ՑShEKBcݹ煷p~zݠ7;KbrѤ[:/1!40ց1[;H8i2V!k7~\2RtU|3b b<ރiB5Rf%3QD-(KU.kĻOB3i:eQAax.V1_I>ӃgxmR_4\SP#~Gq^mK]97xM͹bsZCe'~e=o 1!8Rȃ؄־˄FŶuǿOx56㜵T]?<"bٳq*zr~Ajg$&13:۟c栯̞;g؝3|Hx?mC1\z[.slhMGwp=l )9(N]Tlp).Eҡ\ FgrM:fwixhDU&1xy|ρd 4 _ć. _hh+抝XYaQiu3/o}챳F*C0i}I't =V7)@)2.8pZNbNrdv ͫQ"hTmMO~>nTP'_BH>j&q u؛˷ݫ僌ݯ!fJ {b(p?x+>xv\vFflSiQg<0ـY2<XK ) 6pˢ^B9@s5cOqm]T2S E2͚HjSѪwܑn1T1, Bf`;y\ƜVmW.fKseVV_i8(Q )ȴBZ3q9h]陾).T*S+V*!Κ)zaɇD8Ɩ97C}Is:IAE{^<@]\95L]ǵ}L%áQrN(m6մxR ?]_9ɫ&Sod¹ 3]@qrd PU1n4'Z& a# >*R>PgLXy .؆yră ys5NG%t ~&F@8^ʞ+IsUY]}} fׯJTrvf@[w'u«>{Xf',ьr#a;h[ h !mv ;P' "7J9"91PI/(Nj!m?U ed9ܥIL׉ C|>J]x$~󚉪k74̼suA Ӊ8kj2|jncH0`i9 K&@vfY+6%†r<kW[NfxRMϴV+Yd簭DvYpdQl?TH05XIpU /- cp|6D>#9˺=D: |)eo-vܝcyO4v1TIX< yVo]*THШZExj_u`/!3rETUܗ4L՛'Ztd5bRbx7"fiyw=ZwRx9kC'?ɻ'}_+&43RDȃ?Rwt/C vnJ` CWp$9 3 ,.bODQw#Se ʔh52 $ g'Zl,45bP\sA h8.X,`CZe%sƌhhd djGt!1H*m ]}8WlZ[A#vmĎÈL .cm˅8o UxxՀŷ5=%Ki?BZ1 &5K&n#I vϋCWWMi0Hldc 6S ikgzwA=TY9ɥ6m8N(` ^mT H@6[&k . =1=hpgo^Z7y˳5U3g"wdUH ]+`O`w5: x,EIӆ#3m\W"WM&@xBXK8 tY ^A`ص );/#k$KԭQdv=&d;Q#)g8}0QĦ>|i1cNqBf*"?q͡|֖kꜯtPљW{)lUY_l?Fsқn߽*x[Ghf Ti ъpО3ӧh5 ꩹9 K]fFn: B &zw3w X4m‹ܭ!tA M^RwBK`Y;c>cA.w^N^p&iL@&_%5\Q^8}p5y8m{Ts.̊89af;MP{y9;So ,(ĭ^I6qth%Q9(c}kcY=h_X+;(.# #`섒DP<᯽8ˤ&Eu3T:`ԎE1dK7ڕvV ʶ'ʄknh "@js|޷_J%ՃpF][\p<<9)cuA|DP6A1;V#tԴDs_#pUJ2D=FOV2/K2Q*LaDiyqv%]9 Ff Hxtq ҄ޙd*0FJ+r) \+]an 3W?GnOք6xzEDIfg-JޝzdyF^>*QgVW~NH,(Ίg&/Ýg g')2E* G{k+K, N%!1R/#*0L𐋢,b HiEO}üG҈6DQIz7"6ѶmΓѨ畦zJfixPJG\my+Kx<|CKH#~8;HTIKfAf$o1Dj"6/RK&*jb6Gd%wW2}BaxE2@sgNL*,O6XGf2|*BMnJAZX{1%̴k僺"{~ZP9zTD@2*2!y4@3h/@,C$#p]M+5K=ܸ(Zڒ:8=yoM2qX"I8="j KKfw)g-1(`>+A:ZlZRQ%.ζd\>嬅2f5.Ћ$pb2n'kz٪s8Cq6γ?k\cRfxbv]yE$CmNurbCkEļ>f2$<tku8wsw爉?̆zH ;kӞ||41vhI7"删?ד\%ZXw rdf+hC/#l6*|Fx-`_#8PB HQkG~sCOヱrCkr!;CN2M"ۀ6yt$5."DZ& ym_ Eϸ|Af]XFPEd$ &/B~ 1 dG馑ёyk*E4VgqIj.4983e 3V.E1A~)#d%9rR"lL=iB푌:}%KI Cև OHN`?:{o.7_$7wyfNjT `0'5l{]%ljc û?3N88D/ͱQ0v/v2vp)vq5g̃W?[xxvkq>giMkÜIX!0GUy(S8~Ջr5r>cU^-k[ Q1M<3"IN08m^9~'a(6),e6Zb5_;t~!WP0DJ.і ԅb z@FW(r>1o\︑&f>ANP]|0QW{HFyvYBՇ7xU-G[b݀v>C||QN oc敦z Uăǥ_S| ԍr`&#~vLkKQ x_8] 'yuۖ51)HhJs*V,.}y /`w Lf$Kyb6&fz#ܴAch0G.='Z)X"ԝE% Cl #*֜ѣ ;SD 瞀,=UT4uW}}<'clZTr4Rϳ`c/uSo` 8ie a2d1܍u,[}MW|f6i("2\>sv9]yfC/7M cZMr [6npX[@Jnx@ } c=SX,ݛfT9$ +8M'57G&ǦvcLҕT lJ .ZdGX1gSgU.<]琐@ 番8Sa;Yq'cs` #TJ9f>:3r" @?Z=S)* °G{ys1m#-nH5mCK"٨N S}sAmȼlqAF)(!Fs f&s-鶧L.BYx`Dy\*<2/BH͋*sq_Z~~IBٱ3*v{Xa/Srq5#w )C1~TG6(H1[?8$ɘ4?u8 r|RgS,cfЯoVJ.pQ:8P[,hq/0Ԩ4DŽ1ΒR+G{`: )p%ò`譩 S*gl3;L!,Y/ℯ -KɀŎv)Usm)5 7賘־]>ʶrş~m%Ed Sj#`b8GkTdw\zE.I=R.9Ev;d+׆tfuM+:&f 3%m3\/$ߔ1jUD={Щ}C LKh=m 1l.4cA1C!"u"1V8Yyf3j _)b0tRX7 Z8a1#>$ n#יH$ (Ia|mAP ˨|lq)RkrFF<Exm1ed[/P7 )t>HA,=h"DS%K^f{%t]>2=p-yY:GKj;2*oڜڊc%38ZBčɔ$Ơ=c ?9G3_i@#~K=`$,7yYRkr"3aY_=/cmM4nڇ%]]XNIkDe+mȼ)ik5r\9cfd[J+hn˧VY\ i ЎS'rbQ!@dO507I}:|hR۾H?~u]zni  ,+4lEڼچ%|sد&rh] `"T> HS^vfzet"|Y2_It}{y}qRSzn0ڶ?>!Xx+Ld?S>X*]LHUdBFmLl![ٕRhн_Wɋ FI NFykJk'e}!dK:b\j쑧ƹ 3Kj1&{rkǣ4%υfM^E>zO/Fiϳv̍{yU{esP/9$0o9<)=:V0K˜@2YY'>ۼJHb=V eq* `}ot]3X-&ISJd? 0J̠[ʰIΑ[ԡ}4-ŹC$t9s81 aԭnT;N$tvh gh%O @OQսKfc& 2L pk2֓<S@cs#Z~)0x3gk_6q_L*0\1ҹH!N":v1۴QZ0! 9_tJ<4V-^Y7JZ:-J4R?)i&tMCm6? giO+R x%1pNV4ţai!KJ,g뼬YuRɌde"aCX(̀ A pFl9pNQ/q~{*^Lw!O;~ Ȓ1x~/ ѣcVS = b,T!r-)ztar|vJYqV1O[RД]ZY)jkA,#a; ȬOfu9lbtntSxryr֓aܕ`sCÈ:Te4Uca/X zžwVP5LGD GTU =&$`nZ[dT);)a3I&)q2{ds"be˳q2ʘf9B >z38~}:SLW8A "=ﳝ]LUS(T ᕍb@ri{LpȎA3(8M J < øwt(:Ebt>zp dp_@x\_MS1NERd-t z)9LK+^TKAhwOZ}ۯ=B^iɊӻ7]LW s 'UVLɥY dZnP*4HEI{q0]Q)Fp4Zq*Xv$p{Ṛgp^Kߐt-5^t ij@;[P"]p J.M3Z@JP!ċWCp2^2Y'bilf>-+R#CQ (c'rAT:e2j1EiK4pAFv!ɘ$)f4Uc??<#H7P)_ˆPAUQJ wieMf~y*' @, ^ _IYIJ?pD,4Zur?3?Q(4!K>!.$j/Ty7Db,Q <I^ Xʺ'Ig>uG#ޚ`>:+`WOx-tI4OXDwIk:/L Ą4d87PSLd46(,#/quU8SP <}4DKF v=nӽmsd!񩝓K#XVxfUmX*4%_CijwEYX;i4I} խs a>xZW9\ ὅ4 ÐXl%߀rD(*5:x&#vYԪQ?9Uc ^GZ`鲕Ȕ!Vٓ(=?7G.4 c`YJhfU粼UMق4xeѷp{j_pcvYN0CLJ6n)@2[ `ɕZ4\qn&1ֻR-sTGgT豔J0I">scZ` z +"(U+M#JÓ(#@,(9cP&m߃ubOR ; -42-Y?7pbBJ[熰 ,L=i> / `}r˸.QnHY_0)f|mdcX jd5N=Ѫ,P ˌΔ*Ѩ\9ݵ ^p')i`{ f900WxlQ`&>gdɞЪ2TJ'm#G$ AՔ}svA,؁$ Z&t$H6,$=R[8NOܘs- <ӗ.χKfqHyHL "\p4iAS f`ʚI xbA̍>ogA7{ޖDםHC%Ng&7[Pw}_ /4lVN.1E) (1\&dK2&vv]]k!)Yag#y Y` A1ͱWkU)㚎$}LWL(AeÎPɤO"Z[+`_F$۩AG ҫc2s-TM(7Vv"l Ϸ2;%~y0Rn<_GRcЙ¤T9qWa 5Wq:lo0m#%`JC$ޭ+1A&3|dA~<% jtN@c0t[l!&ɋ@:5,>fc-(RsF$Z/vJd%^20%!ж{ ;>@Ÿ0A{š@B¨߁TIg9RY|GmA08|=d# >bzgj]LN5a_3PoAt4i ϋ)|ddwr᛽jdBsr+#sozBɨYv悔ka ؼPJܚN0#C/JJ(.`"|anF:6~2s>&lSo#@QgC.Qw䘉Z+LQ,-SG7lƕk^T w]ѩ ̎r0mҰv.UB 0EP`cD:ײ.3n+= 8F0X"Ut92e=;)tv@ -Œ{!w<+"gqN(]EΊ9.LqnJx9ƨjZrU1> %YYڣWr~ od6-T"4)_"zzP=BDAܟ!KX@*ёqJYHR.J *ټXa 9n=.V Ւ` y3-ltg`3ҿUǨ;J+ FELw\m /A*)iѾ2}Tў ۷P gAa.R6(Ǥi$WV,˚SYH֨t tC^b!~<;YiLLΌ9<{< &P Dܫ- ~E ĚmG鮯@DI)9d"b:?ܭ >rbZXYgC=5M<_]o^-Rz}z^AF̦hT/a# !ZOɁ0jMm%n9 ԣ\"u$m4XiEFl''f&e(i(_;VN,-B,#ه5m Y*qLv}nr^Xnqusf!#/,y%YY$>6O4F)|hm37dR`k.$>: Q@M'A RCgxЌ[RB+G ~CIJ&ᏘG{ޕLTR_ NT x+la\ŷdzYs4 Ꭴ(0nBBU61Vs}s>^ *pKPĄPz/2>4 8Q"Rq`;kB#F% Or!^ c{,Qbb6 8"FueK[Լ1lu.tnó-+9>>2!nKa[:{TPcX'O<U4t",o&@-!ʎjڋuq 5.O9?w$)jcyأPy sA,'㰚c)4~ys90%r~vpl$~wCe#g^A!A9uNzh>#S3ʴ*9߶ˠع/&Eh>nƮ0Qjj ^Y`bMC8<fx[t2cPwgDwnVe@L"KMaȳCDCHѨ;:\j5 :'G芒/QNL'1&jCRsBtff9az~;ILψOdH5x2=82ߵiüJ=̎bA}W%[vԍV ZFƆ,4'TCZa8~bTpuő|!&sM;i7T=%6zYnk2@gll@+Pwl)0I@f_YjÔpPbKM :{.o]4Yb?DA @Cj1+rStq@*|@>J2pxt$o[蹰G,.469 ! eR{Eϟ8wꖴ!"OCYʂV+ 3ЁFHlveT}nOr$CĦOxW {v`XW>Upƍ\ 7B'z:t ?WNc!Z#)dPA Nvt[L@WGԽƜ94gYAFtKm2&L'iɝH.k"RmQ6_12P]FXZ jߨd$4GK rD u/gyK(N+ aUeR@ fK!4HKt˘au3#rBudBA9d`)xD|ma ~kxh1/כz=2鱧[3,aO tuz[0b`@#{ڠ~fGC[>z0[3!HӨN7NR+ʖoN>@G_, }ESZDO" NxXRbƉv޵y`48w /O;+J]XߢEgs+4 BKM;K\8q̉TG@zW[UP !mNsҋ>˱ӈH떠?Ҝ16c"-`5?!a㾎Œ$wx(#h=D:v;EgFݞx6yv>b`ٟ}u\Eo9vr`RC40)B.1CwQ$icu/pZg pcv6ezƀ % 2FiĩDQی_5pX+Q2dKײ^.]c" VX2J^VUiNnq갱wOL06l6*d' i*J|@sQd:)/)cI3=]IFv a M,0ahMd?xao ٬ʝ7T׫k[sD.D}iWض7STȘ)sƸz?LFJG\9 5(!8fN0!bj$`& muI.nv GF1Lj"Ar]!6}Q~j`XRXkUa$F~ UD0|?閈- xWZ(iG y9^pb|$?|KEl,S1HdzJ%j.J.敻J(gV= :# <4Sgq=7D!,C:c?Yۅ@X=JH- [z1G[WпxG־׶M ?fGM Z9^ н1 >Me)@apJzRvN&#܍%>+6-m'4sqwOTك] {c4#*|ƒсY 5cI"#0(dǨ9H$.EQr!Az_ zv"Z\r0 ЃlkKE_IcKxl:OaO  r" \ n]]_Z0XG5;"g I(*dXʞ8w[E!MoHU*+f#Vet,xFY9,Gt,3GkX|p}cd˺W]ݟlg<[oxԹ!ʮzٚ4kwe/'7ksm<쐛kL[!΄1O>dgϯc#w$[&|q:9g~=k`nQ?lv|v$V[ެvߘϫu=؝HQlܒ5(@bZ]I4QP߿my`(X["1El *Y\(WPi8rf ʸ=8$[h*H=Wib C0qp p1n)+alg|].B쫸cLc1%Y)L$(%/Wv`c:X*'*O$dvqiڎ0T1ZT{jLVODVyȕ!=.llp:39@zl8~ƒNLFf6ٯGRK ȃF駪XPӮ FJE6j¿xD袶Hh$鶵^j^J0ر0e:EȚ=m5h.m9!-$'Mlۅ_+n(+'l{\Id XDu{>of8jX1zk3駞gS?Q@~?Ui("6Uf:38V|շ9KەB,{.I= %,F0[>KҘ*7"DƧ& rG"#@+14 z\5@uakum?wj h'k#xDs(}c@Jش:!{$t؊شQE߅k#G[:fTnL&#:٤;:ɯ2:jj9MGi1fj[ DBOdT8 '?߱76=`_B IMr*ݔMW.ʼʷ~cʘ[<dMiQ{B'F Hb]>dV<'2(Wb,W}`MNLqn'Yz6fV:DpdQ>uQ*vLv;vfLx!\DG~4C-͎],ahP95#ՠ?`F((850d׃5i(Hz#6 M\I!FY<;͸Y@CÂ8.t)EE_*Ǚt^c;\Q5$,s]>+cC֣m= %72 D>!Ȥ/}#~)ӹ@ӔdHP0")r+ gJky6wZݘ# T|pzh|uIk (*Ť$2yJ ib42k°'z+CF0R'!+ήӵcs&?K/i{Q$3RIweos@}5 Ķ$[쐹VUBim{EJJ-T - ['$jr3YKxHI{Z |kwJ*k%s7Vgo[DPĜy$1 ڛ(5z>^GT⢥ܕP=L|ܖ1$̗0ǪugoƧ +(ok3X2i`zx5. $⑨D!#e{& mdeӼ\Ֆ]}4lkO:�Zg|x\6S$@{E]j`}X 6O.m)SD",W#qY re'wD8U) jUJNscS4O1ix1_c_Inۘ&_f&~مB:7,\35#Ƥ]`4,ҢK] 0>O\hj1X[816)ĬMV0jm-#!Ei##\@BFX Sz:<3_%ܠrA*"XQKbJ8 Yl,F}rWΨ80p-鋦Cƴ7$˫(;:߿fԪ#!*hE&7sYa!#H DB0cAger.h1;;+I!JHyA5CՂ 4k"(zoʊ䲺FJDt 9QRD( ,! [YiسZi#>5JD9炯z*BQQ*.f,!$Ke KCWi(G 'VH>k1WSrMK|4ZQ &Y0CI׬v#BZ*w]< rdFES>t.x~I Ȝ5QGA WIf GReVJ^4cA@}?yFyX(P&LzD2(& vr<~Nne2f"3~z7CQ@b*GrnkɤVoq_FɗT S4waX%^\ЋN;(43}Ӑ(ϴj64X&`5 `p.k>5`!dEF#cfepc:F[^!$!k|?kB085¯jy\uQl ֨|t^ODMǧ$%aDUK|fò)F$.vmQ8 tEAkf5![ˡ}":hyD%!? +$'MT|%j[KT.2=/ޱVPP%[ƕMC sZ͈pɃxA1ֺ Io/xw`YWit jV YN,o#㑡rDeA}vnXd 2^lկ`AI4#X}OU$m^K׹"mEOYuijhV'NfupFÎOh_e[z OJ7 t~!(Σ0ߣE ܭ$, Cu#y$*f:1PESp3qlJ?W+r12!NWJ !#=ܛ=%%cL|*x ޕ?zFGmoȋn5H,-_)ExϨ+46Z{;E)/&7:Α,8CXdO6Rj_OXqh?eMhQ1]}MZ5Bxy3cA E՘TÜaFhh0'T,lPqyt _Ga&)Lu5G箿>X; 0bR蟔!R `:99 *Z@epR{Io뗣я߾ zRD Mga̶DZl3G6Ԅ(Ws.-7Eƶ[ k촶hU߯yՇ9g~Zk_v_x ㊌l_18 B0p^:T?ZZBڜ~,Dj{.(yH[P|el$53'dPNV3sp&'SB95 iEc^ang% $3:] yT2N64@kL1P J_MB],4M1v$w3!]4nuPHbĈu7UP+sdP1xoa?b$*'!m&P+Dq|s8݌؂M*uC0tsIHQvLhhnG0utI\Ѓ=>8:p:ŏ %gـLd v&wrtT)&tAd ג{__ͷb"okt7"5י3BC2wAן£e2$H<P}ܷlWEcFZJ  {ܜ1*eaj=bWӺ}2yU5kkZ=c48/HiRǮwҟ(9\!j!G\a$uaа;GC^ty"SJMзj]*&4z).e 3s8dHM@B1I@32buWo]A4 o/=Ϡ GEL5!Xb9'kHLҹ k<\ם _,{^cAB LjQRpNw7hM&0LS:j^$^`a@UDaCZ2e_Z([ m1 iSϐTülyZXK3k41]3Фod1~[֭wELpl{H4ϑ:m8թ* |O|O}sZ@%[* $nvx}#GʠEwOv=Z8RT>eF"=w3b]awĻSG}EÁQ0hN\IbUd1NQJgC9$c!zԚ#kL~_p>L?)hkL7hF %!hWĨ9~3rĻSP zG]ҐK_mH!{%G.m+S,qRic.rw6b/$cs8|;9G%!;ԅmQL)6?SnqJOybfN }~N1!v֠b>j[/oaЏFzz%ˌ҈Epd# ̷IPBOݪW=CN)0sXZ!.B6Ki$ |f6@ Rv-G+Ӝ N 4v6[FL xkƀ ZZ*Aw UFj|(HAB6T$Lɘ_.k2UpEG/Dv|ГDT`tbB4Ş_7QkpMDGbǞwܯ?sM9hA+lYxÖ:4 cD.$H=*1|^tho Ѿ>xxi"$Hm9)dto!U6DoQZ:2RȆ!΅s`Jc$e@<dI\pz_m9cAA>,8rڲ"1t g8@slV'."*v8KsnB 0g&gfO3{Z_Ycc !y=t*V|U$Vӱ6k1XO𭘔-=iYLGgG uen_w,*,Cjl•||Q_p!]oOX{~zYnv#~x:m-d]SA.V!xlKڬz t.<okapŷصڕA i=_i{%y^œ|,JT+ِdpX- 0@^DŮ $%E(PnJqU߿??~WgU GK>=4sNm'Bkwۿctxhj촄],6& =e -+9ޣA*<ѕ%έ_ۖե4NBj/ҹ|jtb=H}YB:&w0UK;-07:{8hc͏ i*BHZdomǒ3,@ 4Y"M5ʰ<YEu):T ` rS1<#3 Q(dh"͕4c,Sh0xƅƧgSȌNKDKcAGE N[lj 7ƫ KT稑öG;C>U#"1j8lArzfr9尐M˖dO "cGlp51t^V˲pNN`❴hYTFbWqI"Vi {\M"IQ:d;I{N  2o dy@ZݑBFJ1d`lW0bÊ!H}TSo٭V*n ~$6cLUcRkaC:$|z~zdѫ rS`Ks:?Z=o?"diKgis1GxNc+GxE\< F_UmDt&ɻ+ D)%z)fPmoBW_\Ms%4P -Ny:I 1b{R_ӯ>*2p(b8 DIܰIK9XӪrh͂F;P]>cH[ !hR0 䶏edM~ _B\(Pi.DSxP-` ??B2T<0j"d> 1,EZSAͤmXl-CG33(Kdv   _f_{=2!A<iuV*0Qܖ~%Mel|P&I@ltN'%OUǿ~#B2l7iyvG;tXo>JL5SO *DkM<Ja1F><|G6=X}X!DI4Srt#3߷?m^Jq|ww"W4M~jKc?"䈓y Ǖ hUD ^5HQ= 2ڜ%g^7DR=2k>}(0"ZyTl(d7̺<;J"+|XAI|80,$A(.LV##އ-e_R+:"$im7!gV X"@Kh ػ<ƕ"i.4 O(cq (Z[v(R(Ze6$\922MGlȊOgq ;2zf8'˥>Aڍ=z61~qzH{#21w>#4Mѩ  +qA.9/ִ; ]UTΠ2~vElkԅ>AA6u!R6SK ;jB t,ž5Hll;^v]o p̈́5Tm U#NTVxcl*\Y)-MԐ"cׁgZ>&^lO&[S&CO)JOE~{ H&f"zP"Gd$$KϷS "ec8Tnd}'"nqmT4ƠxꬌpO^.1bA\ vST24Ƚfaa Gr:BS^ Y#, \P$cr$>m;/!FR4zkbI*!pOﰾ7 I·m\0\)WȷHh4b@e^:1FD]d͙%"o [i+L >s_Cn] ;6$Ǒ Q 2XfL0UԐ[aF tF|.瓬}߅L C8gS_8i~8cӶb8T%9F;g^K 7շyy7+I ߇۶ tN~bG͙c䴎%%41qy|S=ޑ { $U2* VA˧_?t:=qml{QQks_!&NJ\D6t+-:1L&5ZLB_?: mW?'L.M#,D^3~ n•C Efk7+!lS׷%7J6\vc%Yݛk*k]/K=JcТ~ 8z4叨#K,< "}FEd8[M)N$1(YpaJ}+*UN3;0'#)Xb82E*XXya;SJlL5j>da!qQ;&@ZY,F/MD]s噳11bUOs b_MnʆS_Rzй xj `^m<_* dxݸ⬈O911Zll{g (\|JNYJ?= }+)˜{^J&>pLK5NO<ìNoGv گr!nF#ֻ Ŋ@T% %9hI+r3HR jWB*9OHNDU$GQ)Wr=~{ ]E$c-y]q=ӓ|1jM#"cT3pmLfۧ.6ɂdjĺn&D&_E/qmU'@Z璣T%m,~pO{.:W"J5fJQԴ(JW$fK2D)gn&BPv?uZ {B/j A]VǷ?9ق]W+ucLJ~wpt@3utrOqQVpѭ*4=ԃٟwAϧJXEXȅ~-1(TfQSY)K^38\셲DժqcCXjCee{bO)i^8`H>q\AѸT7ʿ#vY w;m 9qn, I@dLV›2UPpUkp'³%(=ђAIs]lƃ@8cE&p .E&`f,䵽lgATAhޡ gW|$eu/[z#s.rirch$P2nfgq>#G u);!J\)=s%"+՗C$qF \ϿZxm7#^ ZF WeV>9T5[bsR8b9 F#4A7>BKaL{ c:ݥ5ZhXE,B PxI T=<=nU6} %:Bd]0hGydp#CddA@ljZfTGB,&,H:_ZoȈqĪ`xrv2s7WO ! )]3&諣Hcx䈓cFGjzK_]5ZDN!]2зI)Pbvcz0k@F(k9fmI <.ȍcݬ6aE"JqN lFvO㪓h$ia<6Wp]dG!j\IDWj'4ŠdďGYƇǃn'%Jw&'~pUgMﶵY @dt2LfkOѩ#i'I HꆴFk6?|쿗D ^ 2+er.i &D&l)r I1޵eSб(/P 1U;¨DCwX*h  P8HW&C(jw\&2$㏐#FqV&!}dj[K)nAIe}Q&̪gŰ@UWC =@׎uͣC|d'acݓ4pA~ չ<诖_zR`lvqgdӣ̀6ռkJE%d% !Ol%'Q/T؉plk ` ~lR?K`1iH9ߟ.Z* `єyIpuc_G(@ Rb$@0}&tzkd)Rd^2JƸVh1?5M$,q}[ޝ<.Hr(PV LgD139y!(cyp)p.摔ՐĎ\%(uCDB̰;8Ev Y Q?"EAνHI%R嶸'#:nKP1bwҐ1NqȞHfmӲt@݇AZm=̧^-b 巇WYrv J.6k_>-TMNؒ1 ,s4ݔN9G4Tiy:zyhǸ)̪puaPAQM*[ X9eb<ɰ(~ 6& DSP7J)mPs1yƝ+V钏9 ?G8N@QтvW:':Ț}Ϭ%ESޤ%2U1Td܌is3W8wl**_|,_ [ r)!!xH֙]逋@9 50a0~3'{W!⪨1OwcDeM@M8I$zcXWXt]KcKZn<&'͑J0P88=mAh "&H#x \]]*(?{o+`t&6x׌,=o˞M )"cKEd`ج1Y\V (=8U漜 iρKMI"J3ҋs.*`n]8tmZ%Gx(&A_y7ײ /WX4 52#RqI4+ҺFo+c0lCA1 r)X`^ lK[1<7WܙXە*t Ztj`k*Hcl-j(h ^Fn$*l3Em֪+RTc9Na78wPF@IDATsFʶ]M .ڈy@ŀ[h'jrFH kV2vQF>.c5hѥ,xuaA' Zq#֭g Oͮz8Z%UsC}tv}RЍ=tXgW\wRsPetGG X=r )}tա~4< #qoGQnºn6)yN^R HCk\&L"h0[ rLke1\E#F!1%.#ch"S\o۬ 5$]uDD;_*nx<tʠSf^%maJ&{bh#Z,O_9RJS ʬI?²~4@K-.D3[[wKrQ8QgIA׃4FG,,,ë0*:O|*y"`0"Jk}D7[EL-Yy8ʚ2cAA`YG1b$@&5e,\뇴r?QoR*;3vAEEr1|S۞""M&X$^JP2^r6 e9+s|w77hӼg^_"ZxS ,2rAC/BAlYև;^A@ji]܍ ڄT\n% шE;;HקyNY٥D%ff" ƶ}~l?ef$;[YxHH#8Ȍ;س%IY|DTvƉnӋ%ȉaN!'H.|#D$>KyK, dEo0mxz$vNoSn?+ZިBt[|mzP[I\uӄ<9VyY'_ٗ("1dNIgc̍x=WlU\ITi셃t$7BC9@3YSWgG iZ!m_8[QS"VLֆ}Az[B0i{"VS`5TrJK$J*˧=PB9j#L]w&AduZ0 vR<]Rd7uA#m?M=\*R*i -sTI9/ ]].vZkEYrw:H.M=e4i_vq1Zkb+G sr9r@p$yZ_+i{x֎ sӮ|ڣioDg ieLYJ㏗mO6v#ǏVj8El,`# +JJ2~H g FˣfdY Ơ m#.nO/BT]d Y,JaC?KN^8M ۠ͱ6$vHɳ٬5o#]yeWqhanhuȾk,Z~09AgS0(r_ YAH1}vpWYGȍ` SGH>y"QtQ4vsK09E!\EyP#R|u87M`[FƔ~]; S,ٙ[_aDu_XV(?/ښ[Fّm1(8ڇBmk"| X99 Y#/3-=(= Fr^8y|G X(l\_ EoߞߏVX<kr>5jS- }&,FKԍ P"ss!JJ1"Ï#Ą]__AYw1kXHE"漯Wrvꠅb$oa)EVNTuw΋iV̵/4Ɛt\ k{< V׷ձ|1]M~ȧMiZ `AcN0"f:zÀ&z-[MaIjKg8V0FlDt7,>=($ +[%Y #|vBBN{^st'aʰ5q0,C*~,TWA懗#TޫdSU1P2`J]ݗM1n_7'v""093S _Mc,ܟ8(9ׁacYGZW}-2gVs$(<ޮt@𘊸$?sB:?#۬j"jkhHeq4pdqgG{]{je0UǰW9btu=8'eoh^PA2JŎq*Zx}vWblpp0Z->8yʈ0k08Xf(ȀB+:&ć]+w+1IPaa=Pud(zЯ04!c~!ݚW({n(JzgBzJz 1k ͇F-7 mQsnaT~'"MM*9gHtEB t=LTu2qvZTt5Q5DQ;ox{m7J.1X /s9i.+e6CTI;)eV^eƸMrE-"!7Z6'|\=|NvcC O Hڠ 0pA%f#FH$$`mI̢9`m}5QMnIVL=5F5\;BȲm|][\ ?P2K}x)SA'V/$ ĖRU | A`c(O;@|5 #D>][;V\A# x$iECq%KJDJTE̤$-:h!l-Jj0ViA1 !y!94dWIyHqG]䱒O,z%e =Ef"P[&h^s:VXU 8K5t#:47x x1R|k} U@8Tb)KjMe.pڽeZz2l6 8сYI@Pfu6cꨙ. UflJbZAɒ"lTy)aǸH5E#Ҽr[b?7;7UF/$Zxi)of_vW˔zQ^TA$O'煪rX#s3TcsBhu2M&Sh[(F%gcaieXd-/ǣًr&fdvziyGŤKLP*Rj{8\0dv!^ R^Zxx҈fNt~1. 1!OՖFc*U<^l͸.*TХb Rg Nи'6f*6I Iy !^xʦg>A0M"0Z9:rEodiZLX8DQC(iq8vQ>bSE7 ԥs{9to]hxNj[k'jF`ˮꂢHߖZR}߹##ƨsjG=Uڐ^܌UhUcQ51<0(EcQxOB<<ظ(ыq) uuuŇ_PT `,)Nq`6\,@S$) Xi/D$F,eەK':Q[+|7 L52TL@W1Jj@G H}hmԻ EHF|+a/a3mI8mޝe(DYuG4>dG&pkyΖِ96:d&OZw8l?+3r Lݚ#)JpLB1Ķ49f"VKvDo/O'ٍ'C>ub|crڶoed >*YڲOZ- <(eG6uRL* 9Y/{ Nr'YyqASO ,p$/z&J 'rue^A`8$At"_xFmwcqTEm25:.svg]ʱu,g[IBŌ=yM]W5.%0A0`IrE>'):."z+F6\3FO X$^1Zma޵iA2b:_mk$gХsfr;xWrA#j_TY>3db4w\0fg<8yVL FjP#01,)8%U72YJ,Ps_x$v#;>A3 k: CpXHLyr9?"z/ \RRܻ烻 wW|%%UJ#MO9@JdK\DՀwcC!hd{ZY:b*Rutw|C}ۙbnEA紁*-Հ>aO?n<./A4vБʥ<ô&GdnH0y5\@9v~?cozi%ah"5ҟ˜3- (;6P'#ST*/z̥ѠZ,5N9Nq1}Hd"u]mȰtOڱ,_K9 (N:2EqJ$=+Ϧ$,b`GœE.m޲'% N2P7' 'u-Qr"ȨQ["! :vj$|#](bd7=DhC˦Z~>CJSXcFG^TkdoyuD[hk71x:ZfF uސ'&Pl+lCMcL{Pͧà 9=U&f[GS(g@ 21-eKAjk0h)'9g}xy~~qӀ`cQ傤, ®x+fhվ[3/`8s.jX/m 1<%XQc  J@ZK]E mZFjDtpS:DC5*Em /+u)5o-RU1(LT=5Ȥ#l,2eTaIGGF͝\yGXK5 (g,µԿ^YJ(Q:KW93xARrܝMq0 ٶ+ߊu 'Hz|6]#g&Xz4Za&ɑŁX?>Us;%]nIJن a-F-DZbzc>bV A<>72:R{Qy0H=eb@ʙmr]:Ie:CB4.uNA P2w ?2e:&&ZF#i(@T+ Y3LH:8*W,,,P-AG/]] =7֮NU1R%P!.h2 .koi5hTW^ΏY#@E&sq=* E")W 32:_dGǦdTX"(6 @sVAQL2JJӓ2ːZ?{nm,轢_ji]| VE6 [ &otsS翽ڟ"f2Zz0'G^ʋu[+@>vxXc-$$(aǤqelK˶oZ$d HUCU =#}68T^h=w)j{t&+!ehD=Y#~gQ`C Ɋz}$0OB/[ɉO(\eDQ9u{6DCKQM3.Q|l15*s '"/XPQ~[yYU(2 mۻfU쵢_];3_{ ub8H"/:Rir#ù,dR 2AQtMB0<0d (R]r螽}S 7~.{pG(2'#1}S:aPsڞ?NP%+%"C:;'삍2@fL7O M\*r=ݨc1[*<Ǐc7 |41l1Qrf/*-|S4|%ďǧM#VWzĩ=f0rJ{ŗz {; Gkd1cƓ*7RO w}q<_tWYЩ;tz_EJDy}fdzނHؤt7Ɉ9B=Ӟ7ƙ+10O#4pxq.}P rx2L+³[JI@"0?J,0،;?fK sryt1i30 \hQQ K'\"\;dty"C" "1Gp ]Ȣ9Bƹi-0Z~ʰ[8 ;L˷TpT!1 w'֋4QDG ݉x^'o' 7]}UTHVT)8b{L kȓ"f3yy-ݯ>ﯗooC},E6aR*F)4O8ob&q!6̣{$upj+Q6N2n6ZC@Ýq CmagpoTIˌr$OɉBw$bFct(# 5i RlcG$'ݽFAEO~x|#AG$ SS#RpV4Q`8 iF`C3`o=#_,Oo=ae/ kT3GVLJh%Q6Ka,D{358#ʢC{c xVFV<(O"b}n_WKqէy iRA7Z'2>4i5"B^n }->p4is=x 5BOWep{#S '%J>j*|TԊ`,`r~BӤi Ue^}$Wˑ 'Pt>*SMy}C꣚~~,KM8hhG^ÝO<椷U ٕ~%ct+`F~/4P<^얇h5~Ēk2ggBS1lĠ\:ʒ1`rz ݈B U9#5dÖvIDPջ=6;%Ɉʺ8p :xbD]_oߓxes27cϫC+cnrW#PY4x%F{jپWLш6sgx%`,_9 qΣV8Q^r' EN J(3PuŒ;t-oZQ^5B|΢x*V=,-D,@I(>Z25GC0g|X=XDo @J8"JCuW'DnA>P}LԹ PMDC\at |۲P&Tc`'M荧?vqk_YxI  :P,׀OMNuN~4o^b(}.n^-H FQ26z'ɨH_%G'YYvM%+Mb`a*u @oKH!67$t+ȁZS7n Efi[l@~>^!n'W:! ٩W 4d:83NfU D"1]Љ ?##./:0{~IR`vJ"XhlY΁B| ,Cg@ " bT-hM5D>-5w?tnR/ ܄xIPaa&B'r ? g_|Zk!x͑a iaLMn>MPE/n\yu~o}i~0T* R޹S~Q 4 s|Y~o],%@l\F#8Z)Gs[Ȕ5vW⨋D6Vr!Lb'$ŮF>2ܼQ D@=amGQiRtX?;bxCAס=(nJ`)vUf2ȟ Աd,>_bA:TuD'UUC5jg>򣠀Fr"+Lj=T P2%;{,[fRZÑt$p 'hPX68EqHˢmupŬDUKj!DzeY/]S+@,~718__ rz$gr0P-Z/_]U^- P4{/MU܇bG C e<*fKn$75LǦ0<z=LwZbqn@EKeG4f?Ðb%~˸~,ÜinjV!xq $ʡH3nLBH"?7AY0E{C;B٤B yŗ^UAi^gm|:9q譫٭c`̷J(bl5у*wğϰEf@mc-Fޑ3S1f-bcdzvimH"37K~$!_u1V 2d3y#HpD\'5X4,b#hXKG (j,XRfG(9uŃ0e:?[4Aj)pM5E qEfq!&kR;tYy\ݯ׭v@ʒ&]<]&qıi@&×֬<7tCVά "MF1])9$J@6aV$Zz<>l?O Sу?0sgs^RV >++6@r4cGQյ(%v4裤ήNvb;u( aRRnRd*pFQtf=n? 9&&Sb&m0FqV_(WT_;!8]cF!U66PtTj^ ]G"w 0U bd @+Qw#1;/Õ)['w6^%%]mZd9LRUfD!йC.TmțTI\'0t_u;3|24%dib9c%rxw[:XZWjÓtU`jJDa H'jQ>!. <\R>'+rёX@d !NFXE3MI/hC:daz~zױvV9t%CmQ݄Iy#Au{Eu =C,as>{_ն+l]H5V֮n=+g $Y;LTBknA0ѦRA2Cxf#q+0| )IuA 9!?UOjfiFVUةt$ V u4w T|ܵۊ<bŧDP-L)ų_=7)H&rd#\CU-ǚZ|e;&4ŠkAtHO]xZ2e>x=:\K&+^@t3Z #(S& .`F904鍋,D _fsh>&&4F%]Gچ&50}a*`k'm&> 撗 ے>} Y[v^R&@rz#F`0(Oa}NK׌abIlde:΍>@[Yav_LJ]Rr S< Yy+qBt*IZ0Q nL!<êeD>e L]?E#*'MmOjL.5=+ 1jA5t(NhĒ>~=9եHˀ̣>)s¶].9E?@WHF!ta)+$#}<%,,u5]Iԣ,hRpOi˓qʟʄ7cvV]#0s"h yÐ`UIF:-!ABtם>ԈN|D #i@{G9c(@IDATfxM(anhU'"P 8B۞Ii+UrmZ~H!LwE-o4}h"Z}h8EPiS=[^8 |E6-lqx_";% >qo,r(ᔂˊVMT`= ?߬ ?S}}dj;I}-[.@Q8ó֟ٻ-ne,d=q~Z.oj{BuZ.pz=DMŐ[T44B#Q%+:>[C$ ikI%wxnvubT~2;$0()! '8Hm̅HQlg?yDǢTEmߞUJTڎNI(BX EW[:_>,CbE8 1$r%4)xS}xx}eaBQ?s z?^d-ѧ*(**) ae&|=ぇ d99vlI8+::͏>~zZ[xgəhrU2Kl*s^W>?x^կ_4!%ɫf dN1 !8iygOm6Qn"X+;5Xhfˆwp@NJ7~'G(#pޭM8AA"IG' mӸoOa h>Ǫyy,Qo돵e#qϛّ M8'i5 ,-w_".APĘF"`ql4ۭ_)WK[ Q| V$0 fңf< vLD6|nP-+/X:0KĆ*hv a% EٙG7@88Oտ(+;bL1P`Զރq8#rPσEu-ygI [!'$K^IG*+ThZɆ6 \ "7&bʀlI1yPQzQs\ $! "h@Q_WR60ĭmuuY0 ڀ@;ķ,8B܍'/wI #!EYWL&cm 15^˟xQ^/KTcc O%JF C[, ʈ*$RUK8o=Wb5RU(o#þgLB%5$vj 0{j$H>`]` p8q Uw@?hB$0LASI#6׵YplMtn4Pk*䈞C،zL׼@kFkL!On (B%xi}ЉUב5C8pDZR9I êanes3+Ҏ?q]"܅ MK3)R%W7翤x[4QC ˛#02/AR*z㧡ޠ.(@$YgWb&a([MʴTKB'/=ZBЏ-P\$V^/GI6 FTAp?XJY фp+k7D86b1h:͡ fA=vr% Yס:XQIɲN%o!3% m}Rx(p*ܛAG ZZ૙>&|"?+\si:)P .|+ե;5!derG2S mޢK[lb|t̛=OBLᷔ1Y8!Ot67ާ"'('qbvQh㽸Dؾ}qBcGtb?Z2ZFժd1a㦈RH&N@Lydٗ4WG+m n509R6 7A2c XZR喡SOQUS)|Ҍ>fR@%{)di^rz~but.Qzp0| md`T,RVb[ <6dP3y Xȴh{oH@NZdC"$ˮW瑻 g21T=J=Z l0kO/kS geܴRyʨa1L 2R[%ԃC,d|pۏV9ֈXL |{ҐRjKs]ި^v Dƙac'aXġ&!A/aBoB1Y2 Ԍ tԌ퉔|h#D~G;^W>Ci8`:TqѢ+S@ yᴶdLs{&iF; /Q_FIZ@y Q_Ra,r d4-%(a2GaJI庌^ٱp-3I_a{9'O6$^7jGrl_N}W(=+!kpDuB49,˰c֖|(5}͎BBv@nL|2 =塭d=s$)\A?E".yO$tnDĉtdcpI{Rb`ܛE'7ƲGnE{X eJi"w Am$#`³G\T#[M\Sx>q}6fYmvyNxy.t]TBcU)s]4W4)`_kߪ5"+NjEe,fS5HC'K9+%ߍ=tAjZ>Bv/#i#5 >B͑y1]߂Vȉ!BF _w^E(WOoD+IF))vڢ=Ɣ*Q>?*4ELă‡s%[3=Ka T1({ '9W[{?(]]}_UF PƥTwOqt0kq|O.y!!+Gmj⡏%v=㾖Չ<٢.Uj1QL$yOE3^t)k3E #5jg;My2'T_jC8PDqOr+VrV"@1ȫIj_m Awj!Mx]̰,^1rW Wxs6ߓܢMսJzа߰ &2`Gu'rV_?3*[檊W+]2Kx:TL\i@R%ݨ/ċxGtiV_^j JAn="qٰ u{k;䣰>mj$͖خ/Lsn3ĊߖB~h,h6'A+R<IyT̳K' #C6C+ f]sY,{CxkM>D!s%;/2^#(S}PrR d]>61Mx\lFš,r mE/"gd`|J6<5ؒFW# gIs_l/F*Ss2;޼)U/@H`m=YyߜOe éBlVz-*1, *]ĉP<ty7(o$9n .OHyJ܅᏿؜4/ G%-]y ckuK\yDNT hy<|z-j޷)ƀiН!驿 <ӝÔDEebOs,Z~Id}s.J-M %`N-cˇ_h94OSOZx33gu&OGbd

    Wůۖ)2 }t7)2Oc`w&PRy:Aw= `3jtab:YӢ$2ݦ $ecq{sY,є fb`@_5[Q&Z2|I@?oQ߽m nZ@'ZS*3Ip3KA{(ӟ'b'/apm[A%kϖwY If9(6 f [$*'ҁVHbLh@.=N ȽGLYLHˍMyb}6u)vcnn"A( =>L ,󤝃q<=p3LJeEdMX b^W{#+ڜz'A\:LZNf0DG7WΧmYmhm7I@cW.5ze5UIh:uw&+f{8H&c3yǵnf(I4AJ(Fp@f UOY6R~PQ_-/ΖN@4Xy xC~Ҡȶ%@scj""e 0)Z2ݖ(T=@3E7m\Ȫ5Û$C}!FŒ}gjIϲB@BAB9* `Iz,)F#SdAm2l`0$IFgՌ 9*Y!>p7lT3g= tL\&`u!ett&>[l ?Gftd/J!iKz#cY\ZFKdM(Z7@±0 :ЧqdStI"nO[]MPE 3<챭MKgRo.ǚx irn# UhPsXDhQvAHY|3{83&ȃE?~W?}U984(^{h.dMR;0! 2,jթ8[Sp.-&~f^}9 TV##'5^/#: "ZsGX߯Z!S$zZPiVQTü%^eף,v,oLQ9n@$[0I}ŰpH"'˼[O"[堢/z=e ZNwOcCⷩ\. sוSj.*WZJfզ[jP r-ˆFRtߤ(LM2s,wNG~mv!lZ\>{4* 9lHb:ə5"=HL`8iC TfQwE*%ʄϬ<qŹV/~U"O\[Sl{[4#DwqLp<7Cb /,B_q G\:}~M%a@tڲ iΖnYﵒTj{c&7sT w`m<6A~ҘA #5Tr@ (RDeMDfU7b;<){&KP菓=w>erA8ۧ4hv^~ A89Jeҥ q\{ыk2UΟi |NX*pX*pt۽(pA+9.z:աkiٺ6H`~=P2Y 88,$mL<"{0c:1WӅ^ty;ֽ eÙ^m-<:>5H곍Mx,\&88f8LXBnbN"jv:&MUXPGM'.\*Er|.E`!-ܴli*zi9 C)r¢8׿|&X0\mIvm*wQL|k_3mUG ȲK-%w"z BnTjG~,'o;m}]UiuO:#KFݛ[7 I~{+ݎJ.U4gOkgJkg0gd `:,lOdVv`%ʤdODnxUkn3|UyMr VOmW n1W"Š]Ck|dٹAD$ HP*0Qs$_[,@l%`B=+̣ yi8$K<0 0̢_QiW7NtC4 ; 6C Dy e|[Ef$m,A0jR#EYZ4Fe\} Ǻ)]Dδ'uB*J W *#0px3p3Tj(Ag3f}D<ܨ_j;b/ NFBH-R龒35ɟFJWX4shoRXXFJQ,R0Ì ,Ö|3 X̈+-oއ?%ۼFI<~T8<Ȝzr7Ꮆnnq~:"Զff(D696<ڴ*Uc.mSi=iW JhNuw9gO9F!Mֶ%jRNx_dU/o7LNe\:J5f4#-V(#Z@4>hzCHyZ'Ifڲ%]38S:14"Bn'ڇdśr88VH@RazM@YHgc*D:T̮oFA}s 0 ڊOU3 ([C`p¶z/g@$"EnLrZNN!E8OCiN;NrDh;)0>t!d3\Spz3C˳Zu%4'q䳝VAeJ%pMUm.he Ol!^afM)xA2r$1w|('-dUWRG8J~jRe>Q%og=D0 21~N0ЄemٸQ Jn(BkvHRi$MS⅌N w' 6RE213YqbL*(aR|4R䠱/SUAd?ej 24ZjdˀK+l%_SHae5\I 0T#N[QYꊷߜ6Bz#G#ahN'<Cy\WR}nkߧʰ `#ҁ}2QDfO麳#4jLȀׄIjb$>QzCᢘ#+Bbx:QVE"B['eQ# 4Cd&s:`ѠMl?(B]) .Sa qFhcBh|#\*8wVHVn9=!Œи@?T)i$AN20h3A$#qu DEv@p,vkdi;9aC#LNOɆƁac4gY >fҵHzh cõ匾g۟ uyao"-L[e29eg"("i3)xj iWW놭RNܣz!eZ9^EEhB*?5TJdٛ1;ePQ3&>]dХ{|1&VOނ3N}`N(b כC4f_Va%я@Ω*2B. ˨&r;_WN$wzZQEDU$ib޹مC ,ާ8no'Gy dG"oVR P86}4qXG9 L?#JXm,qiCO4~;2D vpL0FFBrr 0 ɜ̢,:*n:捲^&+F΁*B8UhxGU Z*&bQN*P22ڒwiRy~~#+UX/JGǖzLVP(X ~JO!l'"QgrM|1E+HRo\-W ٙEð|[ lx|-H4U"P;A$y^3ɲ) ٝ:M r<ԛ`/}{ !2$Q@L /dse_GH4Zi PnN+ *@_F:nziH8m''aϲwGqӺ^,Ҋ_ B  -2A)tC>GƜ)Y:# jcC.6heȡRRέxOθTcUCbZ3L UH'ՈKby3O:C~F9vhm<04lC,N3ZCm𛭾7 fDw(hiRر^3`A ud|]%C {n_{yxx^Ηщô!w#*u@@G \:I z?_ٛzR&hQN4Pw't M.r#bx8Pd7Nz6 QftkdyPa27+Z /d[/a<Zfpu15^n$;i dQ{ŻgZEDD\ 4O@!-a S>"(@J:pՌ6Kmk3De1rͿ[KSJ0t&>~y6%Zlw|m6B=ff1=8|ah^50ZMucjL_bc̽̽u;̃?İZ3& 2">~O2ƔnzGɤ%Ļч`tB"1]2|QyCWx͂'8`ş,gwm$0혩9!u6>/g@Rvg ِ9. CA°KG G9cqQZ2Fqv=|Ts<9oQП^Fl A$W56ָ6@ZʝEM1'o1 z|-\a*-L $r +2o=q].a`a'2E㷆$.Vq[TyWbD,>Ϡcl D#-ǘ5)M- Y3Xl&1Q):Udw{oeDtRLs6qeoȒ {pOaOkW@nR ;X䘬$PjZ9tVEoؕH [x(30! ̬-<&4LիE]Է8Q&mxOZhwt@H#[OH T[AHޮ$D7'f+˚b]̴s©rU#phQ 7uNKiq3X3! SŵX*bNz#>1N3H|_<2̓}hRITcJ1:HVk@s%wm+/ M[ k#j*L_e5,<;VAE1FRRxOP CLR^;ļ]*BSt:t%K$[Lej-7 dk9:U aKК Iu\+ɵuᜆ -@-&Æi!nT!&%px)IꣶiBMbF5a$&hhKT~r8Of*-T!tbw󦇡vtTo 2ct B}S>;5r+~ U\2- m "17 a2 O{5<]Ѧ:zqa!%ˮYPb Xm {hM@{CT,0].@IDAT5¡rVԽ%Baw kz']ׄE6D-!2v F}SW?+pf^N!@T y٪J.(15ڇ0~aG0 "3Xd 3$IVJhɖfde  VA%x`)C tbyd#{?T [>^$*.y cF.7ga{u hx#z[V'l?`!J]LY`bsf@Q6zgzf>Հ9PEAA6 }iXN!VTpi$ 7j07!Š[h^|3$*q=ySCA"oqݞJdSi UBt_V]^d?k;/aztr+dNcô5<:,8%kI!JN8ʔjA&"W?ڮ0S] qy%}9nӕ.6\Y\hQ RYA>d1^"}_r&t_pZȆCE>-}B8P9 o]G58cdWɠiUj1'{W,L, qү)A"N…3ǜ_Q%1흁c3&ZIƑ~e0i2hdTB9lou 'V8XӣxKe}[gx$MU <\ oYVw6{3uFH qi9o aD;\q_081)8lA,/.b>ZOB-CxliZH8\;I3j$@ԐC ]&S# $monC,X|RԬR1"=ţ20W,3@Q=HI(ZarϘxQHGƯR|:o5L Mj 7(j$ hL>oIgl*R^2v ^pZ=;l^ߤzޖbF?){OiYѨCkk.颣 c7gޘ? =(@ >AfM;m"`<`+,Hf$O٥ R;oOƯ-IQJ@rӊ6VS׻CHōmK?Hld `4d5iчL/斁*#,\Ev$_g ѩ)E"( \ܲ[-781])%&ݔ[G,I%b/q"$80O?85 e5. ijSG+ɭS o,DQrr|?ZO8tu*F_Ųe&j%׵C0[\ {H0F v(8Ln(v~^7z9d}H$q_Ik+` |]ud hgkѠf`%]mocO2`qݓQCKhQtbكKp[w[k2Tğ̕F 8̈`-RbpքA*ȔMg[5+!FA9 5\Ԧba e%V>o%NmaejNER:E8hQ,&D>"5mv}ȥ͐8m|QXUw CxN@@w@}(&/CNxġPj:ʈvtCp`,ijٰ'Wh%p?/o PNҺJu+Wgg4XR)_"w*J i*d%i#H`$o85` ȑF5)T2CF3)25GжKX+KhsA q'nni 0! 6*UR,F%ldG9Zxخ@#|K>țd3w_#zMPP0{6 X m˂`ILf$8)ʐJ+!0t'_V;YF )r?#J*-q{(3iy˵cc;%;+bmxɵ}Ă<L ub8 ^XBxG*eéadD,EHV6kl\~+W `~>[^a`\;-s6E8|{D&c貭ޝ*@I`rJLLYWVXibIՔo`𢨥&̫w`ہLuJ;}J8B~{3#aIL!g5n h~'JURu??:(^<.GjQNvx8KH(Nqu:AԚ/Wj'R򷍵1\xǑfLHގviPoI4nC/'ąW83Z'_ELPx83y'4=;v:UݟaAM[zj˹ݞu΅!s cU$gj Ԣ]&,!v)Iʻ!NRRRsTicO$Zt{?IȮkĖMh@C\{ (j( ;VڰDCL?Uwࢅ0k :GDHd""?Z3µ{% ˶e )5`s8؜5z)1:x1J,z'-;猓[CY5[8M~_~_e02ݭ.?r.Bi&%)}϶mK0$9[Iri+rKQX3^!T-&3f/ډF 6_\X :SDl3:I*2~:>o/vUjGt8do ?sG[!YNk ޳GaP0R/nsN%Uh%MхjO,;ڼ: aBYrqFǷAV<tovz1g$X) "}|V#*+L9^qb7D}A6v)>)_F b b; x0ۀ3n? ׈Y S (@.`ᒍj<+Sg(!-z0X2Z0'!6B1fS62h̵! @҄ ABFQk4 3t=~~FƓuz᝱9b8Ya|"C_)y̪^KXRD`=sٞp@y{*V2&wɴ֓î\Ramqze8d2i\`Y- RٌMbBi>Eo DZv)Z$F,gj(.Cu4RkKŖ,8zOhhntC: i; 蚞\n}a1SN4IxF%Ib1gfqÙ ;E rEvM YXg\i]4J{_Ʋe$G4 5x8ll]ƻx:na<HJFK^/ϝTkgxQ\E蜖݄?&ĎeQdjN~u5 DZ Nrdd'Q!$|f8è#Got,&ՏiqV@~# --'RꦱFd..u l.We(4prR7*H!a^A[nᩀd'wTP`ao& s 1cW)a܄BU6Ϥ0ms]b269a1\RMd#9)C(;kؗ7FYBܑV'xkl2x5^ox&CU,KeRL;J#u_VcxoLR חuf_[I%Rsvt$DmOMG|Y%y1!F΄?3ߝ#9l$4ςeie&g)N@WޔK7)M B=qa$2Q%yW/}X (Vjmn軂hv&Y~iND+(c/C;f@y.*j㭺)-g&aSO&7"?S*xl.Ld ˓6'i`tJf6`Jڞr3Š>We!nl.K䪡09 2YÊ@LqIT|>]EfZlڍ$*g('/Ok$&DkdR-੍bcڐdoVpW e r zz%$MjeKiz4(P_*<+'md8+s*MٳP1f!{wm$ o\ńru\0ѯLY.kx'tb%ZEc 6}N&bw~] @1Qy#ScNe! v#nV;\zWZio`r-\@4St7൏n6ǟŁ vvȬ.}<'WQ X³) *OWs#HIB.վ?^~[٭g)ȦjY"ӾiX#ZHl\COH( W -1aq xr A93(Tp&$YLHo㑽_ $Z*MKLR9.V #ӽ|c66g_r쟪 3aABd]ZLR+ &F5:O%< Y06]a$ w쬭b ȢBu5>iPI$BOcix|٨Lt/W:B]45`jI-ge&c!`U ZFh?w)-i^,\4UIzWM0Vc?!wOKD7*rU4eF4RoDڸ 2@$R*(`nc8Gc = &}Oo?ܿ~EQq34-TPJ#{fA`/볍UsƞTP f~<F6P3E{/P% FM=dɃ>{aGBΌs8GЧ܌HdZHQ[`馬 lJxv1~8"^FC36!.ZIB 2^u"hֻ*l'H[s}k$Pup4-#?EvkLsQe7n?sݍK}5x'5GvDi";f @ἓ@bA mOuŜXqQ3O.#}cfKp00ԲF󑱶VH*$0V -@l^ /8$q%摟ై% w@PD HUwS "v#*vpp(Ybbx]44 .X:f#+fFa4bV"w:Րmxe]tg lhiNX+*wz5^}fZZ"x<Ep'Ǝp(29cGLv(iL;7/η& 䛒l.:9pFRΘC"num v$(MZ!"[ OL::ůS[O_#ށ$9pV^*灙o MusBxg2"H.5OFEH C4ӱ&=M= ИɊүJȊC,JjHj1Ilfc'-t0S*=1[m|s:"IRuˆQ4FGi4.e у~sVЃ9:?s3{"UȆOZFvH a#Yڠ^hLkLBmȱ"~ s&?Od# b"Szf{ɨgNxB%{Ӏ9v4* 4|ѠMVk5kFJP[oz7_^{{D&QD9,,"QiJfN(9<CtidFC9oGVB&:!U$2vPX\I/ihF]Y48]֛= 7V&ʥOXO:5w=g51?ԙ_s%ƒQXহS6Rl[˯}hGЩ/'ؙwe1˨%*xK%2V2$$dv,F-/y握aUX.Vѫy|-PH2i*(ZI7cTp]~M-qo9:]ztayE4=S,YoXn+vlXm#TDfh'Ъ4% KBt{7M-k 75Hǂ,RED7jb֥˽IL3 E}Q~_{SbȒ%.A.!L>'Z{Avg2㳼4bp-ViDTG%vW!{yZF-0rPHDh:CXx6܁ޕ?G Lc02v,y(JD JZz 6lt{X /Zi -%Hn[c\%rkT=kw&Q*-P$SD;\up`LbVSZ"OPG*1Ko򬫁mR;sJW$7k?*RO#nO?FF2 *yGg;+oG k 89(h^O&gjNU =E2ͭ D8ZBkZ s#V}G_6_+&V,3\[ߴN3}mH=VźGz8t)'6y\N{\?6\-y20% *IR䤻g ȎŕVkdS<6  41b^d+vIWˬNFэխ 9cX^L5l-d. [@lmG̠sUhcMf N7H\mD+蹉#@R*۸6VlƎ0ǻ@_AՓ_-d5r(ȷ7U,ЄMr=йcx5$]Ufoo(&+p8zb$b$sS&tv-o0LD_f^q=Z$)RD!,cVBlsD=[# ^\ƵEXغzl9YCeam-&[ZKQ!݌_eYwuX, _[{{^،m=(K;cZ{cb3g]( Va[/O ,\TphUMZ?#lIxlDDq L8LScJaW Dʱeas: aL&MԙNW< u2d>DkƏjc9;;(ZÔU'Z"`V1tUȾ4]m,vV~YVQjYi, %QA#M T^%i2Ӊ{<_כ?~ۺv_xdq}1Vw$d9E΄4we* <ҭ tg.ryP F iOǓqu])f~c;šZC=ʴ3S*B!7O1_bLR{`nbۈf(;;EM8G3qV! Bn݇uw">E`gJO'),Dlyʰj0L',y ̀X\c&ϙdC:,87ZUZMV20«nV1NM#cK{azlD] )a@P۠pm3ؗEAL+ӏ-ʰV9(2؉SL7&(. ֝k̞Rnr9]H H2rdFp  ?(%̹E\&E򴶯 h*yVmBPh~{bd DYDLC>IxWΌxĺiLpM@*N]traOOϯpG0q+ٔ,2έ ,F:?P#nab@{ʵN詍 }`"?`-)kv,GcxM2HYqIMP=ûѼm9g\Dyl]΁'S.f z7++F`V/*i E Ex-~] /BS( -s ̗ ؼg F5`:Ms"YKnHjV/~5 pI(f L/B6* &Hb0,>qiq#"âԖu0VCL]F%jObG\D$,ϒ&>CX0Erj ZkDpvs:D?GKQ=}j4' !Q i!Յ[+yu c!̥ٖIOtS+^ B- 5%:JD҃!?ڌHF|Gbh}SV\[@f  g.e f_PG3\aA|F"q!.!CzQP POfl` o\ Ze6)Sjn6&+WSLwv׀q,Vt|}"p ˡ8y^#z̔bز0/(`$v1HVԙOM%&2HLч-//hDav}@ V}7*сG40!`l  )z 41Z 0)pTfT_d3U 9ZU(oy"@xIjӮL սt0W61@ ݙ^J}DRηd N _g9QƗv T]ʼw|Q#O?{,G&"i04;A쪭$! (xjJPLnm\ȹ!:J hX1b d5u㰗LFsu~O e0>Oڡ1<b_i/ XX[l%sR]^( qY,E_XL4KzF{[K戀f1!júX(LafƵѮa<9,OpaM" )^q,lTrGZ F?-[F#\~Kr$LK] ь`XbT,m*L&BW R 'J7sƇqC3.Y+eGlR.oF`Y3d7|c$q)h|.P"ɑBDqN"2n(ލQFd4"6Щv!͊%aVHhk[Řdq>X6Bӵq !9 pk'|@'U7g ޱΜ_ZcL=GB ?<Vr"9[Ru`H89.1n,̒zI2oRYV FTʠ:OѪ4kAIqU0qͫcP ԕVA^KBT܃ء2u~.Q2&ÿIxq:Cs~y}|dzA֥)LTͻSo t2s7,=_w'E4\F K\, SKExSmrS,X'8u +y-E]r$n0adL5 bޠR/duy6(*WZk9~nsT 0c R LN7^:ViU+ ydFW1 bvhrª=[:( m$Y`o`* bllYs1OD-ԫEz^x=Tu>tKx3X=9E e~'; Z^sXPoѭ[THݐdYi3@\O *N6C'C`gB}A-AkH !fe{^@H{Za-Q3qkmM1Um [$٬Pd4OENR.~7yx&5܌\ȓN;R4̹g``Te7G?>焕M}5r}c1\ΰv 02ZvFF YXN%ady+ ?a3*< ņl^< .oeĶSa%DFo9VeWuT ]?Z;9Zϓa g[s,؋h0E2HlD^6ǭ RSvlf#4H_].*=\%ߎm5T'"A3NS椏P%N9*oNAJ֩NQ~5Ѡj![>*,0 p]@&<#\.Q^%ߓKLR1wQnVp=ˍ؈0 aP3GGl` 7L+(/졸1сn/ZRs0 窣H 3w&]N&(%b_X~ Q!(]F|ᆡn?OWQJ\FQpu}@VHô ȃ+=dRKvR?j9qb@66S XI%YU1/ IfRS6t2]| ¥{3W;et3;9&*:0`Rٷ%.&3i6PE2iy )hHC܂MCV[m#M "8x+ScP FG_nBTxI <v >g?s{7UJ1B0~(m/xݲu5H_-U!xLIRDT?0!RR7YUb;TIIĻrNU/̎9(Ax u{DebO-Mg>,Ǚ!<9 SiT 嶌R KAS'i56 Xb ܻ$RٴdS#J8phL]_vC-.1!GB;*U_u"i(3RSwS W0B}lϱoQNzcS&ehzw6$?@CK~ ;Tn:x]y柧?M_v~Bf&B0@IDAT3ذʶ/vHM_&+ 0xrP6=ϔ΅z=^)]&(=;_³zLW ma'ވ}兒N_G2sKI-dH:;N8yڸDܦ^)0hZ<$~E=ݗ98{Qhj;9 .@A8=h@sXrV( %-uOB zt"⛒uhX:vw)n111s[IRH.wmD`I.{ŀzrg:~FsH$J|"N|_]*E <: ֚2OhfjLƄ}?\Y>l6Mv=( CSthH %'2#Ϋ4(# HB \'x\4lgJҼ*fF[$bWhDJ*"řǂYF0CqTYK.ݙ3I"HO(TS1՛ND-.646<QmGʧ!"-d t -s *YnވLgkm81Ɲ4}1x8ʅJl?"I,1Fy@[-`8g)$ӮOmT2\;]o,G3,q'!|~gUHG3,I< {ZqL̀fxdl4.-ģ1m:CX~#"ߕ y\0b֘w&u+{yHB:ޙ9ʶ2yD'/I#lb;PRt dIaE?sHK9YAizqї,#1^DŽJC;4'Pu L 0bx xt*hHnCc 6@IzBo~\KA29Sг `e[)6 >N!в?45."T̐A(׈@8&N@U@5 ¼_gUv&U1gWU2e1,݃jrO_ݬ` 1/f ׇg!X` Ms\9-[--;͘F3LҰ{F08o`a!hضK@b6ѰK 8>$ FsZUfzPNDtJ 36FP}1w8}:'%IXr |~O*}@o6ӯ?Б gՈ?Yyufk(S@Cw<\p'3xԸRPYۛ~DPmn@z)fzj9e5b5?7#DiβAR`Y,SDQ)D~Ds[V%UguP(8()K)l- ?\ZR=xgu 2"OE`h 9bxE4iMZNq5SO7`(ݞ֌/.~šD\x8_Gǡٔ.4h޺ 3h)R P쨚l٧ZCdz"TrQlG]I'FG&ӔTnuW b+}@FXUD8\~6ߤd<;P?ם.&q"EeçtVN+gB{rk Dn=Ny㨹056:u u-u`Ga/gHY(#!Le^ɿ TƥZ-HN3~ Mln,bTSAYΘ 3CD K73DI9) S7S^j'à]o|gou@Qs}A]?iʌɱNϧ=EJp\d&Yx˕ˏ} $1 SxK;6t/̔S _ 9M`^>@8N%dFu:0`َ1ltLCj./l=nqlX`pbQqlqzC}R4x]ABa 8+mGi>Րf. Msd@\!=ֺt/^fG/)aіy \[6">CQGIZDjn ; N /WZj&Zg ^mJ7"CiUJ9Џ-޳IIUmf Z~ȫDZuіRciwꊝP_~?S䠀w?6 /VVܖF(k']9û~Jϧx|>REڙc쇈 uz W8auj~bj$7o-R&!@C Ox6ZptdXs.Nr#ƚOS$1ʩB~m.Y` g(\Q7Tؚ9­XOBe#h*3 E6`$Nܷ@roGZC7VOXrX`rtC˩b#`(j9L W뽍$xǓ h`l@om e?v'@$ȊYPmeWj+% &Kd vs,Ʈğzj x( ^z Dl@j!I^ `'޷G5/ 8a%V~gU#^&A( #,!@L#B /gV1%g."ZKFzHY1Gq쌬.VrT?O-k hAId˱Nd(7#KRdS S#%7 i R! 8+kmM񗽢O)zʺl/lf~%rV~ٮIjb@M@ !!cGf^S_ք]]M6*8Liq& *gPB Ĥ-spKӏy1GN( -7[6Jܩ1Dr"mAEC =ak,5خy6⟟bl6\3+pi2AjVf@C "߀,H-'UPHwr OlNȐ0q{z6ןz?5R!(YIc(zSEgcnL5 F/If ~BR7ѼN_HCax4!K =/ik'5J=ȎpcdZ(;B je@I(]Ԕd)\G}CSU.KK^9%9AZZ.,G޷.v6g~=z,% d(j3jjGzH$j3TtyzukϘ =dף/ܨBCpʍe8uamIbt(GpH7O;cJj0X<8NJ%Y( H]tY00Ɯy nC<^3C3ץUHˇ\-LcP`uA8m uWvS]q1 fC?,0@*:6A38]xRȹdIh QqŔ K2̀kP3LatN}j  d}A#%oj5#ഡ< a3'bn-Y/rokNv{Rq R_>[Ml\Leuq*7cOf9Km(x w Z +>XUb 4 oqf 3tc1_ <<[m !~c^Wl E5+35IJ] {s!\þ\ty!0DE 4A1#FoK@[qoQ6 3q29`CTe8"^;H^p8z.SJQV0_@O8p *>xw-S뇞ڏ$D924F°r+UH^\3: ~GCH67U Nr s8O A6&k1Ion[ab,`6"Fl z\%:/eyRa*zG~ hC;Ug=@Gf橶iyp"m1P@v0TSნpӢP< Բ@%RKO&3י %O6`l[ȈOTq- NDtA?`MXp/Borsopc 5#q'Mlzɸ8oOm1X-O:#0 Y j21 8nd4āiG\7oL b`A4/dQaGɦTqV㍏ma`wM e6'HE;ZF'3 URTkN*'CcZf9W.I7R3*wC?i!U_l IvnZgxښ$O{G-U9d_]s.3FpiI̒^2P07=QF)D.}3t z Z`O}d4+۴YOuYN3%1_G'y8naqf ІBP3{G֊,4J? / 4(Nʛ2gPHZW^"iBC>fFLʚ] B/*Ax>:2ƆU1gy#Yx|t(IᵚzvЃթIU@gl2/$#emI W+& }!Lc|P(d/PhN|T?Lhs#z͚) &뵭2O@ZCj0 E8=!yDmOcTNڣ`*M-$3iKSaS}`j n5Ly6QTǵ3"bT͛}l&;:hB]twB2.ϓ9l"[ B/"2DqiRNsf~KCf]-zgQ Qg@OK@~i?MW@>IB4iXzx4}Xk g( üݏǏ'^r R dSOn^*AzErw+Be:jgh-e" ?L` S$N_rͫE`(0/ˋeٰG\|%y#ߵ~h-EiEYr3,)+m`idi Yptoʱ䐠ցjNDmP1$_eWR Dp g2!:lDZ9 4r'`+s#s7#OWVMgf댵XHOC=8mt92UTcːM Mq-=j,PVNhTAAbOF[A1LJϗMYì3DpdN,ʕESÀݶD˖XQ4*U*XvlZ[ ;>$jc{0܉rHbxOL _ >@9ˑVYm&l;y~ˆGY7JУg$W s~@#[Z2?Xe$܂4!ƀ1r(=ɸܶcy'AbEK^39ZA 8Sj|;ͳe˷Er0]㩙!G> gUFK2 X&FC(s:D^X4*Oz]Gf0x>RWNSeLkȤW^`?F $j3`NU~ݭd\&$Iu!l!,ۂՅSzȩa$kZEp.˔oCL4(V?hD~b1g[3_J5Lv(ԅyfUM2ueGRC.Mtի2=m(j[ 뇓l0<]LQ C &'#&C!c$О@wδ\jp]K9ɩSGԎ|l>򯢦FSFZcQ (/4/!YnaL[d1ϥH H5wNsFMLa;ɋujf_М.6! r L*'c%zD6i< 3h49#{Yc Kv\@b!mҀztȆ`c(C`Z*%XfR]"xk_LmO^7.(Z (hoexB=7M'x F\m4x(t9j1KS[U;EzdTW`>,N9o` xb:vQοjhо[d3 t$Kni2)xm>x.<2p!;;YY-yN_92*3^z<^Ū/ָ*H r@(y>cI3Vgk4>1RQNM(b(F)@V)1+ݛsHqld' CBG75{[ ;Na.n;#%({^h毱rVS[;E=KO+&Ež'ݿUrsA%Rv@sN3l#[= h:tÒ$#zx7ݤlk f~@ {Wg[A-Q e?׏<_5zi-?8HiiARM|F7j-H: *d'Yuy(1y,^50ds1k>b=烙2(Ju ՌM(h #JJUJ̯t Y Txa^ў!p{N\ >[dtT>bX_",AΙ*H\LoVѲDvQ[EX4bp\,=4(`uU4:]ˈ Xq BRI"H7n^djb:#Ub:N#Q7>@>'|ms6qTT9c;dXcs(7F"q?F.$Df w1Q)p.`Uu#֚U'0.ygD'[pJLO&Yʠ4I*k#b=/ս:&@g֑jsJB{?uS[RP4VowS/>2ᬣ!Ÿm ꗝ T_KIUS]KaI9WJGu; j& 'I1t[&`*wzum 1THq h7{<f S#Z2 mxUAL_Mnw."\ ssDRPG}Plo{u4GUz@| ՘"8KjI-7zzivTD:os{oAPVےgϕ#1qJ\ N ):bjrEr?/]O@=ڑ%;CM [TGУ ozae"}m93 ^>/۠րh 3_#C,wb6!& fS(*@=^2Fџ`%ȩf#WwB C-ܿބ/L/Wd#0(>)gNp: uMamO>>NuMeX(Ll(A9J_mvqJڭ\BQE`0CRg!,DŽ:S"b1ׁh8:q*Ѷ>|$B6S~#rpr?J-P|v{}z͊:l,0L?'5)8:KjX=&.hT߳ϘT&E:2d ﲠ%@@G05Z@m>+n 29y=̽J8.Vk7+0&A*&6 \!Il6[{}f/|g^{)dؔw vmæAX-`AHWEhMR|UUr`Бo1{%xDIl3wj1 N!)ǎy,Z"y4zW%i9[Ɨ+ؖUD^–Bd6IWԤ! q>MΫ VE! pbGoXɃɭC^t[_حQ;qk>&ތ(W5C kjw3WTaKRBxηQD. Hg%A=9 xpP1! ( Ь幣> X EClǏw6G?4"瘍^|"c]-a3 rBׯ뗫8 Ȅ~ۀ%QTiwC傾GK!fۂ[/;dmTo{H qsS2-iʈ95FaޣIzAR,;ΝBΟ~ZJEz(E3m{:8d_RyHW3Sce ɘ3"¸v@wz-r3P'8Amsb$jYǪA d\9W3s3]׆V_l:D! [/|lL ,4RcsK0=Zp]o)1#d^![ F)@I:j )Em6FR Sf5ٔ)5Xl3 bWdrmQ|5G#x;@ J x|z<~?6R AM,bEvd1hL6f=og9Mz]Na.""pQƜ @?Z 4Ihޒ_czU*2)ﹱ$>i3@iS$cZS FOӹiڶ^]01ݿ @47s8&  Wz ݙ}w `䶑no*Bق~0h D2W<IrIp[8YIo/y ǛwjK#S|#iD!>#-eduD7#7|PW`{[EVW)Z 3Uťmoj3YBĴg+#(U+F|#!/ n]̒NܙKjLs%DRFѲnXS)y-\"}pIj)<P>9.Ȗ-boSXzP$ VʘbW>2>ta:֐"x̂sc'XT6@qA@Kڋ`q%:\_hB8Fwe&NbVg yW%hx_O/T5 'ZjrbY-!*sbz"WK0eA@@!)ٹhPh"ejh@R ?t6w0,ݰf>W4UJnȥLTrRo PbS "KL2 DMg= OLT¿p477Rtji3i9y񝊖+O-k/ eH d3:n9O.i&eAErHz QVvKvEHHBK?!~;~z=bJ O`"ئ!x6}Y5mLSKu9dҢ9⡜\ O#OAfb4LmoTgCJh-Gmw`P.Za4ğFJ~'뤙7K^[2~Fxe4$(ЍHS:ut֛j@I41$Y_!9mt7X| GG~:$0`CboBݦSz_y|XPn,*7E6W d~%࿤&nl%νKi*xACg<`H8BJ#=^,T``R O9 S=K MM+U47O8^5ki!FvLJ'?h|Qm$ ]]fE$dF,ǣvb#@1c2B#8#"UՇfdBG[ke MeTDx*IE pubRE O?O`7Z&]B Ig8>nfD(lC+wN/S7ЮemFDs~-:ߘՇ ʌ3 v)MuO6j9 RM.)5ѥd.=if!7̄6(*AIp,1@)HEJE;aS+pFE^tL ttݣhrL?;fHh6Y.V cs0f'*/eȫs"ox!(D!؏\8y2aG'ɕQ@.*1dX %G~MB}ѿ>c]gVtc}֕g5x/ Mt8=Sj̣Ku \;˼%dfc6l焒4DӛDO7aXq̐<Ն+Wx/ љ[J=PZO`WYU>Ťo VlG5[my-jGm 䑟r,ڢCXئ҉'CV2 yntvS(($aPRa(…hA狁5 S5yXkziPn"壭kV0Z\"\p~Y߾ȸ|x׮,=}[7H:4)^}ׇ#D(p]o8e2`0֍˪ݮ'u9@ђ˘y'GHC|Q#˘Q(].)b!r) cxJ+0A(]A<2?oty\2wXЕ:Br0Gh(Ԯ0 $hZߚn%~'jw~ WZjlxe*mxD1UEzmqvyhTjM_ȡF/:>=TtFvGr0/gc˘EU'.3H.#2CVCF4Yg΃[+mŚɊ>VNDʼn)CSV:a11g&ς4~r9R5ܖydX2QcL:a0JvhCJ2]+UóJ`8`mXPp} 3qw%Z.D="t}Hy H&a:UyZ"b丘uW y J#寅74o՚ |y_X~;0D Վ1ϡ?Fv8nXˊY+hR )q+ #goMw!E+ 'x0հ;2{UkAoP\DnUvӳShLZȘmKk}s0KKrF}0D)'P xpLdpFQ-D ~HlAָupQkPCXZnU uGLDw?mNmA {>!^Dh>mS.Sm9 M=c>|;$z#?䪞I^ RU_g#obT. -Acq^ #`wo!(N2Uܖ6+f jT7((KhFg.rlM ARKT<~ew'Qn%&k5uA#[+c:u0C hɂ,drF@=l_t|cKzYAF )iN?Ón~MG1;b `hK:xF c4kwі B*MǾ\O:xBn&N`42t%@L%fWD>F-×Z:eHϯ^1օb"F G-BVW\1F3 Y-s\MBC>  zֱQf!OޭKqe)a#XIEzg8'`d4{ː2a„1ȋ? 0JxK(PT(ݤԮk2As^V!@dΟ`CHC'dOQX[ʕ 1!\#*#`-B2k >k8$. ˗ cR ?͋ m}Z^q0dR'NԌ;b,;:x%"W#PЄ<`4Ckފ^Maѱd iC0k{89n~5]Xt%} >#c-WC/ 7%0+ cgw rBE õ!c#|2>En'9jv-n~vZޛQ^HNU ,hE;r C=u(22YM7nF;h,. D0[Z0!Sbň16>%Cji8[? HbYn'6>ש^|MYZjd<`8D^#b{@zk\ 7*z#o`F/2Ra\5ȳ>tcM>K{JYǽ{ؤT^ϻ}K:Z'G9I ArZpdO#a][y?[ͱgC!c;^N o/ՏURJn|JV}Mmm330"|? yvd#s?G=DfHbEԘ6w(]K߬WϟT[wƀbF#μS2ݑ1sQhn6rM_v.wLPV 0Ne)Į7O[jsTw뤳)Έvi` @nwfEƠUU"D#puh<:)}jƼBG.L8Hq6DP]ҬPcyDŽndnlƟۯX1~k ڜ }~< FiF7'W4"NUeA nv/^[T %±LׇfwSuoNkaGQeu=C"OFX"㐛~r}OQ/iVKN`z=#r!zߠYfRGw}Fޙthlg&cJ!SȄK; *04(y;-&ae/ 9!q tD`ɂbKz+}=*|I}9v0Iun+ao Y/&ux=قmyNԹnl`q<=/ݓXVf\ ҋiusB|{e)奩+u7UJ.b<՞+1+`~[p´ pYl\ᗽUD- v?OEw;3<4y`=q=\W; xeL_[WWX=WN}j v$Y٦+ >z1'OMiA_Jc iy}|~oAeڜ^ RXٱm/rBV2%s㍱Ayl?2/}0%ة hRlZM%\ؒ\~ƽ%A`{5ZL }8]BsKIY_Ȉ9ӏVj t,"~wKMeGտd0Jj)rɓ$qVf}3?>/JN2}R ^3篽}~֟K0-LЩ|]݈W_Ϭ PuT {$y]'EgPc9!kss3UHpܜTVuWX%SP_G=Eu~_)L 6$N,%[G9׷syxaW!}3NFNr><*T Jl C[$4U@nCk?bDܛ!H10V?*\Fy fa$fÖa.fpvë&HZH衫Pvx$jp?5= SB +avХSó6}.aGX<"4>ien0*M*Uԡ_A(,9F$1/M0.&yXy uD)FÐ5wOPM{0a!&PP%23R,jkqY%OFaZTCt ٠O(E`wɝXވ9RΡ:l9/c\rǽk<떲 u`/~FoLhۚd#wZln`-f ?Ql%ՋI~+H$3Uqe "agVxH.7H#\Iz^ =,Xh `lD-jp?Ϛ NpCJm$F2Rh"&0Q37+ґW4 E-7@0@h Ue´ICv,ڪ u:(n8u.'$Wdlh \5#hӪ/&kfR8p 7t\Z%~fb솟Ѫ8Nm6zՆL^u3<?,13_52)7y{ʣa+:g庿V7LKi: yhFɐMY)O@ Y6PWAWﶿAoSӨ"^FeCJ<݄EB(cxCDA |& t5Im9:hVqXnVBO Z.Bia^Yc$ǗÒW?)tu$яQ\}2kp:4)vC䕤!$Wm+^B s,7ieX+6qv\9uZz#fpPVfT" i?+=瀣|Fh]bS4;ª|+7 lg9XW2Hnkl%2 PbЈr~{&OCt8/;,ٞk!L5Uw5L?>A@#>V2(g4_+LX\K5sw8BW>Îa(OfDiLϘYY0ȀHвm %jf% JoeqLm BC|Orn2*ȹ8|(i4,45J⃝3M- o L\e'ga)šv` Qh+aj)r[u!>wAõ&o 7"8l"Nc 0ήknwAFV#N &kzVL$, }17:s9Dވ=OJB5$2{9/&y=ؐ?{j0da|p=JY~wk2Ro˹iRyN3}5Ɇrͯ02n"I >`P=6&라fA#e6}ap\Ȓ(D>+$# pCԮ|1y$r*"vEr+eм| UW_OoMD꘺ pPTS8ޢP%QI4Xu!Nc0rL:dL*$eCq3l<4Ctqr)M@b؅>(9+uH i 0!ᦎtLW/U2=b%F*搈/dLWy[syP GƤb%]Β~%9I+ #щ^kĆ3_,ɩ'6~yPn[5/ȩ(A f7VY$FNpf2Tc"D՚Q1i[j*DJ 5o*P)DM19zy(":Hdwob-mA$RaZ;.&t6~?ǔۭ>sBJ2u3E8ᛗp;={  kY٥f? P."G3UqUGiVCLa tnU1JKE nTa>KY-K݈U73IoQ<h.R]hd4!С!`TՋX}rXf{O@TfǬ~C° hiHu #gsC I_a~jx݂[p(~V_5BQ>߬}} L|ޟݨV{HyޡS:}R_ºg=d(#1T4Qn?4Xޢk6sÊlD=Z…^?W% T[pekQҔf }uK#K k"i( xW\9)h HbPgRm~,C}=s (\S(C᣶ftl>Ck4Ҹ-)?UnQeg Ķ@M=˜:1v׼bKvAw\&U]%JCvgCIuIR'i\Hd#<7]MyyY7)×>[6,!(g?} syX`m1`ꝅ6iofH 0H0r81xI֘@ dԫ #XYK e?nwGCI=Lᩰ+#P5M0wK%25 +cM{~g38/V%sbSEUI'hz(w&ws ИDٞ^d+7H["L I}(n$o#;ϙF˰4^_vQ~&gI."Kt)|@, {Ad3"8F31"C)@/Q52=ڄe֡ 2|I'Q*>kPw)9`]'ls 3 2 "_r'ƃkP{Z&fWHН x\]ă.ʪi I-#@ksCM0j #DY.t |n68U$NRPPii$# # U`DYD.F-,StnDZd]C?< |:.W8^Lć鉞NE<\XY(/FYV$D7 YVEHrl*|5aʯm5X1iV`+aqR|^;15)%;.,$g i2LDmq1X付\R͙ځsoܢH4`[d94DȻZHMN+`/YŕA"}QhUmb[ ^dT!ŠA>BL&14vT:IceFr#z4X0`Co 8$:"5!eϏۙl ܾaNO9E_{.><S" !gj o+y;T5Lnoݰq5*" _"ꈝN8(#|ߗC)f34ޜ{\s2p!4EP 3 Wa?mgQɱ!nk8 |~?"^GqU6{{}Q.lpW΁_wO.P!࡭w 1UbXédKCx;I?qCDRoEc2dypvW͒LpyK ,YzCKЩ(pw)^N^֯ [rqYM7Zv@";HQ׊3gj&u s ˬ(߈4m|@$Cb)k7Yk=S a[pEg)_{T.j<Η/I9l>VaK@ @ЈiPnt3 @tL8v imZ&QMNW?"\萔'#"ݭf 1IpNRn4S-cVK$;kwۻmZPV{3*߱a<,YS.Q cW 6&`jNO]J9(QoZT&U``bd<ќ&X/kb;+[I]2("CJLVl@B!bM!OJ}Iy!t:V>j7Ɓp~dMYFE t*bR 4P]vs;)\Fdo4r( /vDQ3]zs͒ {Af?I8d0&j=t5`GɎcNmV=R^*竱eC5^U% q)΍U߉o@ .Q\*rZJV csqxG^} LhGXU`T]D6 5Փ&@g[ e,0*dnb%z)< Gj4=ͱko@@]c&AM7 #֣Aw8bLzŎ4hG{f*oŒ%[PO5vl87*TG p;>&> Q3沇 U"^1IIa:FUxf[;OC=E^C[R-Kr=1 ɵp-WFS(A{dʩА~3h`0Q5q (d~Fjco誩!HŢ裘[5~#y- D#UEŸwD2[QQ3roe䑬) 3 *znMCx]gkb*CY" 2^L>_!$Hೃe]q 39eU;Q$#PcN`MG 0ٖ>:"!t]w\mhӭ:(pMt߿Wi70VNveS[X} 3([QL@ /(#E9qq]\-fcP '8 1hOK$xmIBNY)!S\)fͶL)i9y4#˱ye`ZjҷO%vr36`Z3{fP$wA?X+oN-yyCN.l7Nɸ9P6ReJk4Am+(~sқokl:SFA0ɞAOߤnJ) ?J|( B=Qn76d$yAz]j^8G.c?ȗ_nr- fTBڿnU@J"&r_v @LyrE~x8U,W =1T &G#7ÄێFąwq`TgkeK h@ (ZaN>Km@RlI쉿 zwVkdL \t*t5QTJ́( k⏷;yp-{퐈B ;2QCWOƼa'GfM2>}kO4JqǼP:!8Te37l0H^|X|1̶]^jcws#&? ,Wա؉ O%3Un] rhbMa~oϛ x졼vֺIԘtW3cܼ#nP Ҹ< K +vIP/_bY͌d#]؁2S)\sglFWx9nŸO;({umG/d w4`'F!oTJfu: $MS)ҧΗXPly ̋lzg(d3'[_F}SE3D78BfR:pMɵQ^μq]k5n.piYӦsrJ[TU/q-Ts?KLOc#t7~Z|JZdZYaO\Ż7ӯ$&.2S {;v#H_61T $֙8 0ȳ~ADnT~>e0*v%cNӋWݜ .s s(_CWyU+&BWIJu-1#lsVЋ&`B Q'hyـ+m[ȦiGnf8=5I}MDEFߒ@-Ytݫg*ozOSA'jRҚTE]X+*-u? %tՉS_=>nޣ#+o,YaAZ q3vẬ`0)Im䐷Z[9j#U1s;ɗ-DT2!ܜ>-f # {Mas[xPCgx\<.AlHq EPǑ[`qX0<,t%c/4E_l &ba=d2qsYK?vEhi2葮aaQ#.9_Q1QX~[Mq(_z ,QAjL;N a$c̭ۛU)bĵxp}rY׎d&+dRiTZD7glȈ3rC|iW;_kI B)gEu MR5wX_G.Hߪհ2O9K6:Nd6d-iCWn;*B\=4n1C6%OR}tol7QKA7I5Lr1V}qX4j֮!&m($'k$vM_0,,TtP M;PanLOtzrl/aסY+cFs剌]I fȖgHgSg8F͝`;?F@$V IFؖf&b!EOY_ KַĤfڅ'QO˦~ ;#)yk |~8#S bBG_=I8ut⤋CN˂FhI }!p-ƶbʇswȬ2#yn}XHc5 ٕ(]H8x<p~q(EOFf~HƥI2O6,ͶGdƓbƘ5MpqH",#Sua |M( 픫֔cЉ0 WdiQn?8=JFRvك 73lecdqNhqf V(k31g2 ֻ'aBf>v Z<5#5DPHV1dS+Fsb#!\\|vbGP_'jg kX)-!S*;=.@*mvȝ{VׂruSh]%!RbF ERe$ÌUDԪ:6I|qE8B^5x1 SÊs_z`0hxs@IDAT& Fbb8krKh3iɜh'X+nDOv%I NtU#mwH"l'#-, j-h!֯7_/JU"}EǘG,yfNlA8bTEWz{l& #M1h@Dr,H9Ҧ!H?0^1(K,@E7 WN/4SjR_}*uclKDKBnM"+A*^D G*,:0Y3K# +RBXy:GОM.-U ٽ:QԳ}xE/uf#m]t{f^^CU=$tz]4T3TȦ% teͩ%ZDu,MH,_$zXf4a,.c3o>acԉpTk!@DjYK4! i Y ])?`eV? &?R؈WoRVӀ? g47~x &p;+*e,e|bS24Y(1u#5IF1YY0h0LJqtBmM%˝,: ^T]ByKB+9*q.i[, gMxVKop"\cpfKQ1jp+[nx06Tmk7 \ѣQD͸$_v=+B6 RڔdoZ? I7 ׌T9p^aHN5cm'\<{pgjAM`余DcAU-ҐI+i :e1C9eJOWdEEQ (+?yj6 f5yHGHS\Ww˾xt-FPO;}c21vCt :AJ%q4Xa=lJjH_T[OxjLy_b3H` ?&A*wz*2Cha]-R<(MP)14=$^ْܬ)ӕ찞= .[$ɡ@׿h9_ xUhdPH7I3x8>qQt_p3P9@mpNvSd%$GQۀz`j>FӉhE\i5rᝪSQ23;&Y}^X62gۆ2G64A3R| sLFPJHp=1h'KjZ/ƅ bnrIA <'ӥ$;az4}\xr!x_æIsŤekj]绅jČeWDK(/D_Z8f2|v@jQHYNŹRCUJU7$]ig$lD#Ə!8Ȋ}Lͱw1Dž?`PVJ WY} *vX<308Rg_"[9?o\ܒ+6 V{BwP(h~` 7[H9$ IrI)0"1@&q1h1gӓLQ\;2[ѩb.W(T%_@ sJ[$r$S^u 333n+G 8LM'ͧ6 " 2f$5M4rrcxj9a/΁Eq)ֲX=6ځKYĎXJt< }vB65a`Ǒ!)nEÙMQ}8ּdAfH9){Kx ~E OdoM"lx|Bi/t,;5UĀR V(蛩AD7:Ҵ4V+ھ,kAcJfv.Z.0 1>Q!(<d@O unFAKaW/I!{c~'Uq|zg65dӀ`OKILJ2`k(zV5 1]Ro|PERj^Xp>07݈L%jG|_qks]e(X#WlM8x&+ٝ!FUi|PLp+|1Qې \17vPlFvE1 uVFy$>ّXst\z9p->ͱ׏E~qѳFD# șX^K\ff!ć v} `ڍ]38aϲ+MJx<A>5Q^SܜKљǠ c>YSOj (#b FGF\b0>DQ&N2qb9~1WȡQzyU@p+w$fϟ M5((BEY92^.O3-:l:(/EB,oF?4a%RqŴ"`Z/4Cv`:vet gb)sF% xx>hz=Bw Ӊp >{X\XKyGRtvmE! N2VKx2B4.Z3 " m#/! #^l WX}ĭtyG"=O;{23֟X$ :̵|cA(O}l!Acyϣ+O`Y,!)q&U0dzpRI“8AO_&[P^ 02$={Dlz^RcK)5vljc7iþӪ^’>AK`1a t  \Η s)*1f\[L'_k_"p)ҷ/oa?Zsbm.Tbހ^ˌ?/rrA'OƸ|A4I1qwi:3RCU]+=&)p*]7tI~faPt\'u 6ND;_3 g+k'6WgRڝPRS~ EWt?t"WBF[%wfAg9-8!'V"lWfZaω[2~Qft1 Ɯfof*OrDf?e?)a1%Ngrk%] 5YĢ,ՓsMʓq"rUm!H7vAs8>~u,"u9[RZ,}sQizV"`nS&?1irs-) TP8]BHHߓXg-oJ!Kb/| Fmbf蘉KE?c "n5CZ9I/ "cl}H?N6 ?Vj(2+-.ּYR*ot`/Be =L?hh8+ cK^gٰÝ,d!d/YJ<[wH&8"UM@餸&$z(P!=i3gdۢ^0u*>&#T$9H̋._@WS'c@&t*@-20Wn#5@,GT1v]Ihɼb+#ʞܽmL֊qoxQ =Y)}H bsuL`zxM![:ɲuۉYmJ\=Ȩrp+œ0P|.xalSC)\ZTyV&8 =_e3T魱0m8Aկ:E2Ҽ2&'H"fR23z"T{CAPjYF 76;D2`6_,Y[V,(p.Pz<Y R hV||`fhjRh>Q'&oɁ:?h:ȉ]Z C V iZ!YII5Xk%3(ۭGƀ۵8BI{[4feQ;igrH,ʏmvGj,Q $ & g6vq 9y>)bI_&ZK-=W>9+ɓaڹuAf }n WQf~,F}\<~(G&"\ZN!B!4 3؃ "\)AK>fwS֯W^.N :7J-d4c&$6Fv|8y/E\ٓ! H !)"0!%B=^a\[Ɯcaf72XkTJO&]U&f>2Q8}eN.8цFJN1%N4J/d`\v dhaAqץ E&vٹhQ{1,%x^6{̑j\pxQl=@4ОLBJr`rYAl aޓ!A Xw474qD}mVwy@Q:#uBZ)OVm6|wv<WN>h~;1NߢHZ?;:s;"!KDq6w/dLC uO%nң"ь[6y {3bj ^9in# F`[@ 338XYĻT{ 2kx\'OőFlriLâ c@+3nR-e% b{oP3/$ eEBzp hMƱ ?43] f؅. ܆,_ 5,Yhn_=O%cRR<Ai7&-x1 "/[?Xl:wPf. vʲ ;aTڶ)7DOYj>6xp)pv|,i8iWdI!G1"'N O.5Nq>hƃhu\z^{*%AtDD\m38JWY2I}^WLH]~#l`{LeYl/tc r+_  L~#B(C%f9-т<-IḟGqbS!}֗5V(-; b/ /.x@Ӌ&5#0j B%OIfB8G> }܈l&y\mܭȬi2L|Ԅ[LTM0, wLXb!eLR[(Q!Oj(E`鉰1Bp7{&K{iuAC1Z26ra-#bj9FM[҈6-& V4٠&HAw]':'f6RɦЂMrOe?jL͝QӇf 5IdQ> ʦ äNthXGiҟi47џ A8-3QU[1|) RM(:Tj5 n*Htcu9H17XjplkrK %^ԓUea"2%C{xBlvfJjMH(M&O!Z0u<3pןS SC ַR)E7=ީ FtP%Mr5Z Q`sDӅ7Ȧ dߔI { ㎽'R"E Ƥq8Fs96- mLIe ERXpa0 :!WV)z*KSt5L;݇Mjnx!CnE9D4F1&Lcv}WL`kc4T7Aj`0_`,aؕy3@$ r=9Y,`e4 E#0eed413=r롊T&8?$&61<23nCKƿe'N4aIhG>I8Kn`jt]xA4F#1Ezj `Ps#4lz+?#E)`gN^l] a<> I؏n ! ud03]jr(S}dܖ]<’[hv5;`nuiXBڐ[zO2zT#m0d=Ts4CuA+~OX@~GqOåa3S;w"B"^)7NKhf=7e֣5A7ׁmОܠgw/U`!Op'ɓKPbȈ옯CvaqJvA \>Q $kD.!"kڅN7h#u(= joZR*El?d9A#s #,d0>%6܆1f5hӑe9` j CFW N +]v}e<FCyQp澥$2CcmB3.v?WsNXRz-;R+0XPUKbavc*9kpΙZp2%#OZRE@9HZ5ɝx\I YZ{pp< E"gS$+E#׼!$H$U%>3oE5IRQ1sGRAWt dYͦn.v\OD3`v8Nd^(LjŰhɰAw MDF a7#pM60(L6}-D<^_C`הMg%1KGZ0Kݷ cZc^R(h%0,LC,yiPF̻;݀ h4")D}- x\/u@İ\$>yRCYd,=ѡ@AJʶuR.Ï&Fi ))E4a-ClpƝP9d'.X,UUҐ\Q!DqzX+CPC`l(@K kc&HTڗouUuIq~v,\t.8_ bE2M 5R"{s@A+8hSUb}6Vl0`R+m@5Ď@أ?s,GGmp(/VlX; @ *kWo5|NAoo^<0'5Y(ZTp(d(Qhj T xoy"G_k<$`  Dp.-6Ja5{&KݴAYLMl tK$% *mh*gdh",`%IT(9.]#wG$ntTk4&5D: zLaG+N0zK 2TQQ"PO.)Xxr>5&8MAI;=03%2Cip|)@MBSY4x  ^\Iyk;C3:e4M` ffÎQ6:ynWD72 zFDS!;~`"i@'[(tTwxO#,Vd5Qs,t5X6= /@. EHyU ]KN!N` E_t jB ͔gb "5Bp1D%/҂g/>cp؀ !%ń8Ƞ|vdh=8QtF՘q`eEp涇sB"Wy6ᱜY 7I5M ~. J@;;88АVMp:!0A@P5yXQ8X^RQ">z-\>ʅ%UuK*{~$bN.1z}X\OmѤvP=ٔ}Q,.B˹jсؚ 줙yO0̺rMękrfG|~%qGYvB>C*! !RDRLM|W@LzN| B@_sRד~^vݸÑ!z1 10qB(%@ۓh<.0RN+-<_T̯$uM;ЅC鮗p`땣 Ь*a'ȲjHJSʨIqp:XgVKJ,v5(2S!ra-"'#H%'[Du8IR+wX#"=J"%PHJ$"*OכzmoJ0b%^큞Ԛ`\"چTGBEJi=fK#e$vBF#ZOIPg'*'jF`)$sJPӮϸ6^Q%U6$A,Ԯ<;t7 ._ gZ۞0=o8P@@&e͐0 LOg"&-1%"!j\1o8L  a hZ\ZK X`,ܵjfG1qUP&PᠢL)TxsP?7d(4 nm'd(!)@5-_h.i_:.b,"z\>f>hoi5'1t欩# %|L7Mk)1)Qt#98)$ˆiK" !K$(FRy(f4RqɎiҴF.K >Bg8i==(td3)P!.:e`{T6?7{ TCDaxQ&P.Bjh,\R`yy/]brތPĚ6MG*mOC3 Zwg iHM!HPt詵1- h2OpAܔЄ(Vo9]OKi̓b4|W[ 8;0i F3v1%/{v3o|o@s{Unoʨy ϧɫ׳vkZt#_/ف&F,d{rI d*v $)晇~^܋ b$Ι8De&k8>lmҏct kםUZR>рSwN0P ;Qu N Co~z;8{m}kZ9 EAH ƻuT { <!MR:uvKbvO`1zo `bڷ$TDH2?au|is jkUNUgtEu}Dࠗ̎6 XIPzTSe};uiy2hwx+i J՗(E*R-6>.*~Gus<6&YNci=21+mtmiV!N5N.DbDA~7*m@hlІu8py|Gg7T tU.GSS,U+.U,sS.3aw%GPo,/P>_TƆ ̾=.<YuM[P+i9a\|:I@۴sc1a4gDV?l,/$'o=qHs?ѽjT&.|L0֎u&Ļ1u},u|K}=fHNHlb|XN*qDaBoZ& i҃6^`&+ӷ"[~ ӗXl#hy;`e;pA)23r,EGT)|dl>;IeGSqCA27{д}ѹb^G8CӇZ?a_&8!a(R\D=L4/7Ҝ@Hqq`D')`u;W`P|cv@Y\¤:,2HNgfx+ *l"7\d0ASɡD53a YFq"W7luœp,~yzܾ9⭐s9z-{8J9Ipb̐EP394*@;#)wKȒ[=Kj@F *@A]v˃̠@r<1yDbl_(-dACȡFЀ9t[4gp;f7F+oz)vJk!2;ICIR2 WZxuT#!l dR)Mzu&{)(~FAcKl IVǎ; q6xFd>*x/)gԘI^qKsnQ&Z갠>IƉp{)oZE\?zt*I\K_Jf.aڭy#;\KyTw>^K=CKQa"HmU @ Kn 3΄>|I=Aѥ% -O.vv>y%j*|A%!L/(#70t`jE@qa~חH#z8jrp%}H@(u85EI47Up=}~!qdF/1 h`VfyfS|t'am\ #pJ4[nW_kaIp$yb9FqhAet.S%pW#Q[z$oY CIDѯ#{x #Lģ> P#b\70P JƟMiЭPt,/z]KUYZx0]Q e0XHDX7# GBƤBb1]b"S`,?ZE`ma.йt :SWQ5{x$1i`ʧRֲy,OY5,dIC$%bA=d>  }:=z>yDc* (-G$b!\[JVķm hM%ڳM$[ Pkh1Kn֐TyH̎-ǰ&_1GC L`ܭ9%B#zHx0Nĺ=4v,H8х%Ed|i&L0MO{ПGVA2VQ@)r-MP7vYb1jz (1ST !wgL D$N]|_7sSŇlĪRxƷ~ QoU j8@x:ۅO&G%8D7+9AKXKFJr g]$8KqsV[ѩ}=k}F- S@4-J ,l,["pxZqcXzx7>0BTqx\#z5T#~'2fpUMD(P֜R&/ꟍRJP ". 17AP H>h=0r/Lk^!',bOYm}Q^Wŧ9&Fi+q"+:"d/ @4 .D@IDATWX!tJ&? $`9{Iv/EOd'p-ūRB I.Oքa"VeX_PBރ8l)%);$!50 asyИ@3֩]tVf5Uzoןo?@E/RU7ϠX̆\YS2G)AKB}3_X$&ae$q&pq@@!Kf.8dCF7fA D-\TzFN>R7# JFvp=2cD48(@5hyrk\~ ;#߾=ÄÄ(ѐER.&`f<RvXu>bn|a` zO4 ( ZKOzӤ"pG/M5&/΂f.FqBF  f0 ENky֞`Eq.AB<_t3ɉ`O '@�du阑"I&$&+{o*[B)YMDohjNroK&Hcid,Z/gZ;8buDO8-OG2C*E*P!"}MIGlcJ|6B79m3-#x:A Q4uvt]s5qn` oɨɕsVc /hݍ Y6#ޒxa?cs4r/\h .bf)V9Jco!n(WRE*FC&U ͮe荅aI%%T8HαKp=NéizҡD˳5m+"^-r; }܍FC8m{,Z @|u)1غG3Dʥ,@Qomi8*o(whd`gaGs)J?nݬf'"*̙DZ #OA}ѬQ|_C5!k.F@Z1L(A*O?SP`8,2 ̆i@FW,єRn-d.x'h^}{IlD{a.JUe!CpRO$,(HX16 vԬ҈>2 MA?1yǘs,_CgSSq'Wퟰ [gk=3p,!P+xŕԐ5&Tñ Zxm UnOۭ|[E|9#./mT3 e=nMa I*<48S/`M|*7t"a3сe7edC/pgD< ΄66IBAnj$y SʔR\$Iej?8<(ZdR\"37ĩoB~ D{6 ]0i?/Ee{SSS(YI1ME:.HL/fT8].2_zV@ku'tpKpn_'yݛ*^@F񔌨-B;G QWc7.OTeQ# zFG 2@AH=7Ͳ[R3CcAx4^^poZ' D<$;yR*JPȱ!4 ?ըҋ$hZl$b)f0d9ʝD>is XH%pl.K ]5ur 5 b1?,|#q@yp:EDdť(0t_W%(Pq`twCu3mZYW} 0<9!=vTJ4hCXRyG3i@fzPtp_`-u2Ex^={,pҁf+@!*t>3ݦP)zF?s;2,لǔ6 "aЋ:A Yj׳Хb2x@qIӼOd"EbFM0(u 𿔴V(Z |װ6\a腘!{'.P tL*.1@, be3bnRZ}ܶasL'GVpH@RlrYL:ywƱ'pqW 9$5sRwzMNu;MK N~{+L c) QG(k[ʝۥ6ءJ?aFF[DF!zpsrlt6"HnJdLfd4j*> |F=Xl稙{qXu\ֱh$sSgF£#Gnڐ'֧nXqz!DZi5|04v9nKە1bB!, B@(.fP\s_>R7:Iuis"^9k.Rn)(V}bLm&Q6F8>l N <; e\m; D(QS]Lx~_~[|6 0G"N OءEC Iz:BES0ᬐF"+…Ff\D5Ek)5燠ԣ~N*;ig@r~'9H#X%-2Ձed _ՙf0hj]lwILbPZaI5^:S\:J K(/CeC\dsXjҠلmତ8ļ432M$NRjZ5m쁬WX7P׾(#B9 2A|KiLič8qڞ&+E#/@W>q2DJ 1hF0>TL7QIمX1"CEX̣PZO|Zb[֓^ NT-iP6§u_; aHUmg@iq45ˉ {#mbM?8sbkBÕokroNISãF4C 6mG@՗ 7E ')+7-M{+w]@HNʟݭ: Q|!R]s.#YDOɄ1;;4AgbHJLĵ Nrv"6yq}A5O)GDh֠*kKd ڶI(3?-EIXmA%ºZ1,`,G)I"MnӢ1Hʜd@d0xnkAgAHueFYR9㹂 DTM?PGm{Y:gAz#F&AD_/Rctӂ";^ޤ%*ek=)|NSKyo]Xܗb4=`jVf?m[I]$ic9 _@շ ?*Ak plQ7(>Gd_{.CB1nۖ2,Z[duU OS(/;Rw/*cbly6KW'5sdhs\d,@`z+yZwf`8,S䋳CyTh7wx4d!Ithlz60qq4 םOQIZ ~$xYC#Vw~t7<mkM,-R.r& 88ܔ @yb3H GHbL o Jz!Q6zH4Vo_~:?PhzY(pM%Y2y}'(.ϛo_fMJ=k/!xkmvlmO'k.gl~}_Tjn "g+{@]IOKh8yH ls=!o *t ,}'QUm??wm4%QF8U`iEvM O$uVz!DdI^Ai4YAPpK>twj>NFnTg#BٰA pCmb!iz4ah3rs{uǽ!Y6ZkKQoCbfIEX6-0c(9&&cw۽t@ oxKi0/;4qq+A ȁ:1A(L|wIq,h!=e(&zK@?ρVMtXĪEKe,k<򢛶!XҪm6ƉɊMh2.1BխaB@)8hx緳OФ֠# rECȘqj@nZj&pl4Rt&:j c`"j|q̦(I \s†?g@:PP1!@6FPtZ 4iv~Vj>`Ui""M[. Q$abnrh돡>!ZOq"(L&R ܨE]2=Ȥ'>hʵm&ݢ?s8ʁyx,Q2Ø <hjNQ+JE)ڂV:A;+o<1#94&I!rR% 'Wڽ TT%e !e[b[2Q%U-15.|-Fmr;%n6P:T)r% "<\[Z)P֥A~[SoD/bep aJ=ZǘF6b ^2|v{ib޿ƭKRX ~n\t#/oKF b뤫;?^g'vyT^BrD+ :#.I" ТGQ#L1 AȖ%xVV.AhaWhk> xԝeG$Y (`f'_w_Ng桾 !ZLpbqq컛b(UraKltX-,6HڅPP.ĒDg3ԸIXصA}cQze$fci+ F3\j5DnQ32B"n (vA]j0=Ò\ dh3He,u㷃t=,jf !< 6pMJFXk@`Ltr. D+Pw SG8e>_;["XLzHD# 1z&Zj',RT'ʥ[!Y,PʫqD KU?ȥoJMLnV227+a~ "ރCGmVq)qsQOЊ?m-[C2@D7` k~5%kEPJ` B LPt@쵃[R6j _ eU20yq=}TҦ]T:Lۭe`i}w,"n(Lo]HfIEmjJ*[-π3}͸ŗU 0;ɥdgRqhF e 43&v$bV5mUnRch 0CdFHuK 'eM)~ "Bׯd#p%)MboI&8,{0!R \v$?DaT ^f3(6[> M*@"=fQɱ<] Ik2(FQ ZLl Zq^W0ڪ;)kd'M)DOF9VYnEĭz,jXP3Y9;rL Ā>;ӎgo C32j-J[XP̈́ȷh#'iG$ 'GC!HLp\= zB,JJ9O[@%֥fqnqN/xF,\7w-yBVgo=ymoM̊?GVVWÝgCuP@c5yVTD$eCq2P9r᤹ jP-ik[,0TP""\J &X/c_1 823mE$c$Yglޮ Z.XZ3Y.h :M8!$ofKT%^8|rk\4/VPrPwxGZ0@rQ9FVƩĮ?3k|oe zN]P?v6`dԭ$-uVOrsPv'_$KDU2JROE+oKQkF7pb٘Z j8O?^\GcÛ C>6*#u]qwk['Ege]_+Znd1[ xbaQ}ؠ-RYH]L&MƲoJ6_E.mpc 9*hZȕ6+z~2+(ܿ;Y| K`aHa;A~+,Uuѷ6V^=S@L hȋ١pcζf:R OFw!15$wRݯߞ[YJ/fSèveQiZPᴀ3D5E);V2Ϊmf) xZ,p6/LzV%kFD%b<H^6Y32`xMbl^$ӟ&1Jl_4HX_oO]"q¥9]9Iscvpn+䥸8*1j~'̇ gCw2R9_mayXbʦ2mJ~+&r+kD@4pPvXa3ѳj>i̞ܳNz7&1H#7 B}SEIfd]4EQ eLj\ {}DΪn{ YT&P21ah#K2EΔ0P˂zgJ5RF'CD,J7ۏ+ç.:kW cqSN `|Uq1oI'mst*ؘ[PDpb_dsxq D9cLssOL9DLfP$`vtBǑqz?#nhzo`#'VQ& uV}RScDz, a=Qj05ť$a> (W$G@شQ!AUAҵmwe'(#̝i+n+8 |U m0z4<q;;QRD]9JU@62sW𑾜w{>ߍPjsq J(yyqS{ 6e ੉OK 3P$':T"Kˎիž rȄ&+s[Hwǔ ߩC[86aAr 9!0W!N8\z:ULM@{أeMoX# $ H[I9˻ۋ?~u䟓>ݙFy:<2V.ߓf"$cN6R"4P TpL:Lb]YgrSU_"z$ nㅿTҘ^~M$P ZWfפJ%|Z{O(9GaD"6G^`|hR$.^d T2 PI 5l NeHfihĘQ +\{85(3`#eC+i2W̋GCOgGf,0 ,ڟB>jyiU"e- hb4Q%w=#c#{x. >D}n clQ60<a;o1_b9Ӹ͸4C5bxs ¥hl''6?|F$[-Eh1QE9aVUĥr1\32M7cKY+n @]WG. ~a#UxV`&VabF>K*n|{+DzHL?:^y<`u&c8˭z0g~Q~;8<ĩ*Y-!YfsAHt2-!m[$Qof%Sȫ-%6p7nPCb$lӱXe jJV6r!DWNLe;ڛb'G?i[RX؃ѯ۱l:a" cDrW;[57Ҙ7TKa ^. %V3GvyxRrB0-0h!ɔ`Yj6}e3ppZTw?YLIr3saGmW&_B߫NO,Lhxi5r b4$k'hk4?s@&^f"MG H92,xvaNGw5G}&ͮEXQF\ͨԒ(h4xo-vv!ȪIz#-]#n C21O(d$[U@h9 ebg83/vhzҐIrlcU% `E=$r0@"C$bZ$"A<Ĺ463K j[1ɨ Z0MQA<]/h:6V+ m)BMOw/f6J=+4[Ï "&<`:Bcgr 9}輁_.b**tM 6u Ô3D>Ut`m} 666gMYu^|TiRD~9hS]_*)'K[R)R#CMGC*50Z\8]1ԙD(,Gn\_nnT .o鬡+#C_ bmCԘAP ( gBHp[p]V\}ۗ3JQ $REip!N\]݋rѹ>sM֢\^eRjm(u蝙zd˅:хষ%,?w2"Ї`<{.yv7w4G^?#3)`]zyPO;j@IPth6^$jA|b$!pHln5cVFV%Fj~qs jT2.xB`;J]Nsz=2-ZI)6R3ݧˈhy;g"<^i!D 7֣> '%d`ԘEzBV?Of$ Ǹ Ke[Dnj4+J˦LnikG2-6Paw>SyU˳mҒ>a>NNb_a^(,AM)u<RZ0m 0u2ݭX Na4jYzqD1 +go©(h̔aB}sU/%1yc~*Ӌ sjnZ:5wї9if>)Hr91RAՓ''9ae@R:h8ipx, S` _(hC&^xH/_^^p~p| 5J/gL5UR8 DENx+`Gc՜s*E8O?_Sb*JDW^Ԣ`S,$w[#Dc:mU2͞QttNQ/|#[.Pj\M1T%ج&%1`ߔBik7 װ1OhZ1I@^[_Bdc3B nMˠ PwT}䦑/7w.MrŎ;DB_ T A:%Piacoe4J߅3eMCb`a+f ǻ;GŸ(ΓJIL^Y'6g)2ׇEwPJ7BIy/gwT8W .^;caɗ>։;58tI4fZ'T"Z) HiErO^#ӋdIygf3$wVj06V"p ؞oO -z8}B:pY@@Ut?=gy蠂ɀ?]{W]V;aPAj[ d+Y$c"xDJMz?MVjʱd/H SEEFxkU2͘'hғ(j5ӧ)oMTKqeqMRحg9z>E4jʪ]}h;pC:t4`+3k)eNE 0rNeWĕ}6t5: =CR;ӥ^У;XoVedwr.1Lװꀨ ]A/:;B.I1f7:QXOvC,.Y >TFtkRGUhJUfSJf3h˶!Teæ*mSOzRjY:^= zV;$A%VLݍ;| A)[1a`MI)J&Ӊ,'Vj-\1Dg_/?m Fn>HºȠED`gq:9O3 ~YEֵ@@-BSQ0?BܢђGX6q:Iv)]ZFE )k>hLڇ;⽐ {)A6Nr #m8>L-4K:QHIj2ʖ)kDY f)+ɬG:Mn,K`=S`v$=؆_m϶;l9Q,V80+0`ӓz/)mQȾEzA|I[.=ѶPS.=M\qm&qD"-_l6qR8բ@X)CObD ;7PRA2'_Ȏ‹0t&gţE:NĥY?ÅwcI2g>a'/[dTtg /8uj@pedE Mb 'q# `h7V? M"]XdF :ßj@2RJ87vT_\{ {Eb.@IDAT9e \禖 2J}V&K8WjkꔡS%x)ͪFV^-dӒ!Xgf;$!}`p heuO6+ױ:vl.O^.Y%5nN#MAw>e6=׵ۖw["/NdP$ B9#h(mS䠣|SYS ?f XWŌJ@8ThMe]F8}>B') h} .Vq[[A 3Ps043Clkt\.jR@#a|RinPیNԛW[;ZUKv05ha#:v+ UXRD \:4/ʃ@:%pX IR.0Zp1eQ;bgs#ft }9V1ٖgV[̚O!č0ZOKj;a3bhXQF8iX #"y4Z"C{hC&ak5\ϠieלodLtP<)?G 2dO8Շ=hR?AL2Igܐ4^V qd^[HKQ 2.gFsτPU=hf$A_qQ}14$SMrRDb (vo^Q&!` z|""ёNL 0gƤTc0Idv TEj>Vz*Z߹Q+96zL_HbOYPI)H&Ĉ)3ڦ.#C`dB'l Bieal'D ,j|}~zy̠"o{nȶ*G_lmȘ@ך l46VҸڛH9SŌ\!HH!lKr///<Y)ms" o3-ܨkk Bj2w9"PT6!lr@_W 1rMRlYo^ʩ,M0*&C\b53rD ^𰶞$ a7W?O?Z+e#}dYF<p /Qs41s\?m򙛘З(#b{aJԍdJѾHr1o4.L(0+6 vұ,fvv4p@zbu">l$fl`Zp ۜgK*>b#,ՙKvmba:A'Sa~>Gj֐1*6$5"iA|RRs]CLu"w\Ә ^D"d2›zW^OtP:'7uͺe?ؗ3Xu+֜u毃ϓ"w^w-t ALq >qsm >rHRyڎL4de0( :C/ {U_WֵTxfDPBT,g‡ Ε[:1JyP*70~bOmrR/U)Vr$B.GpZ$0__{ײI8Khdc-|(CnjzdJҾ Nsp %Pv^^ fGRx1BG<,՘&F|1p'rFGN :S.-;KxҚT_Jਟ:h=ʤ_vj1#"c97.G˒SAb`"ٽap1hwP@@q2L84,gě$RPg"L]Ԕ>> B r\3n+zf f"VO+9+Qt%PgܲUBb<(CDρ[(h5F3"γ_y|!^ E̸&'XPZͣ1 ,(b4m\nB콅_#evG,mtN]Vki?: c(O `t튶`!tJ D G-w3 ٢焆D>LXU-Irݢ@Lbɗ`xJU,>謘5sR>@?b.0U~I rl* H=ލ.1Q74@xsG &!nh伤_}-PliѴP,R=XpXt§'#hfy˦||3]6\Q!AkS>#Qoas9Є?+", 8=6f!BɝLFop؛X0dPn݄2Xb(i=.xБZuėwu^we_zi0b/U6 2>Q'rQj+:“@jgy]KG`NzIw8$#V[gjb%,d,AB>޵Ϧ.HCo8Fl+B-!rz9 %KJ1S7�Mjأ" e佺|- eiWBDkKv8 AӸHU~%_\*?(ZH3|RV&ׯgy3Jɮ/W[;1aeRjGF_َL}y/xB;Ch)ԱEb){@NaJT=%3/ il_XG! }gN*yX>_Yg(tJ Z<+׉ROD"&nٜ-|%׷&&Ft:Nߞ_)8o˅t7v`&59  FJ5y~M)'{KmT]$^|P!ȁڣl[em3o//_Ϙrn@$jxcV2ՉWNB8y?~?8pf$9!/a—k?ɤDֵR ԃvK y#/ Iܝ,;5heT7,U8s`C3O'1 |BR":3$%ٵ.`rQ~DTB4mzN>n6HR#{oڅ g1;a )Wziˤ6ɈKIa42ӏ g{n+˄`HOnN.~w#g;;Y7)rSc/T1gL͊~+y *k#Փ0H@aPP iELP=hԅ eP&W_DÝDF[8G-2A+{(f#x!bV^Cs9"n'0DJpLj$E2O9kRϭSF lmȆ^$[Fmqj֚[1Βg3ZԜnD s#@jH}Xhl߸F ݵCڡ-]4/#h>pYVvcGFws , $@p~A.E./p2,'yxY[V@O t5[}f NfIPM7[dkDܚFp2nt)$XvXjAqJDE3 )[WÛ ׶W5z۸i+ nK)H3#O $pIxDӗO/'KwDhFmCȓ O.4zɑr/6`=ΠXRM]O7^͆h-asD''?~k A%FggZk2uÏkPGNkynwoW KΒ=b2} 'UmaR}T%qlpIkX-f>)w6?We,ȤLx[M+/~R2 u{SZyG.X:=72IBBB[_ 8*2,jiiqB{Lz * Kb-9F`1 i6eCԣ!%h.eN]„gW$T R䤃fNC*kB tԑ<7sE!⭏((ӤtTl=MgD]1%HhF:z˶KMAFHb@G~ত@݈Lz)&nApV ]>/t2Y+*&ߍ]bAF%()Ne 5 Y)/ S |^_ @vd: 5yODpٍ_#}q P(+ћ| j  aM( PV^PN/#1N̺|~Sp&3 ZYV6ɞ5L2f /JX=@@OZ06;\:rs@( !u\qK>vsJbbTL uG8C%Y=9yi Xl^̾R@UDdr6E@!qvvګj]FA@%>M.r 8%պb&9|f #@yPa DB45{qv#:P0*E]QT6B\p_ <9ЮCΠUOD\gDPX6|HULLAW;.@6QM P %1gP8H0Cwko"Nray=Y$(B1a2 ,ó,B#M;& 6R4dलj4::uYWZø1/9k @sr2D#j׵4g'G$STl1Nz]%?(dZ߹ 5sDjU?SAIɓR%4RT]rD$c(Y[-nh@D3 k$1 ~V bDCƘ\<߯o1l'go:MG#҂I$33OǛ`*2 MMU?D,[?{ΉGC}@N^ͺyԧɹJћʑ|{,{A,GR+4QՍf|84;$?Jh+IQ 1\Bl ֗-KЈn5!g4PLP;an!X'$|[qRK2pX$$^XUL=C4 - ZI_'vҁg-[wvA DF+{#t\C֡UM@z<~ ¸K@29)6".d&>k&]FDT$:2JL*?J wteY*4Gk vXVT NP2>{>$<%< {స a$@Ry&SYDHؤ%8yDojAMc`CFqQ&WH,oπĸ&MI1o≛_ fҦ|,>uEsZ?ju@f"HܿXޢ#pXL- ts >K9+t4mL< ,ƃ B%Wd=Ϧi؅E Yɝi0x@Z3{|"@blDd M$Z8g-Ϻ 4Xkpf +8.//m..< G ?aJ[Dv$ 51DNr1hye*g'z8lxYwMD$mտ&3Ua0g=6rx~0`uRl#okj³cN6xyaQGkJ,ZU^6%rϴHB 5⍇\V\!.|Կ@2/GBNm! W.x@cv32a$V-`%cm t?"YxM fR6Ҙ HTEwY;=X[9沽uRp>@)Bo-nu2r=he0?t)|'Q;k41hqkD"V6IXA^ @A;ECmiwZ/9_*&gȭݝH15h'jTgVYTw;85K>$8pa׈rw+]Ao{60 / M\/KM"PU8 U$v (# Srd;s`L(XoW>-Vw \wFP4bP gω @׈/i /RؖD0R#c꯯_c9Ӫ#lpa<7!WU<ޤiCJƝ4'S]=/0!enW~)T$u`Ud)*x w (҈H047Z^B5:85aS]N\譿8X[d#vBf 3a* /D7͏-a), ag ;SVXթۅh7ňDʓ d@~( NPnGHp>gEÒ F*FC*eЋ1&aՌ O(1)2fDFLҺ{h|0aWzҾ'ֻ1A燾jWMD:nڳFq)!ֹ ?K\UDhdXs0(ծZ3+$Eo|8Տ=DrùC@XS##6̞̈́#bo?^I[ΪDL&Km˞Z7JZ$҄?L$E~Lz򣊤ܛl#?tc+J7ެnƲ˺ɣȻ d1#*8uZa_? +8O|e?rg9pGtVy'+ c& !J6C. dhQea7v+izԯ7OKU}WEGfdr{7E9#d٥@{wO1h=MZI *)Yw$i$DX> ΈqYMƓŁ7 X9#8{|1!Ɯ#HWVy`fgyr<3zkG~ &\LԷu% ؎(]mZ~ah7_@3 T=+L;p f3FLTE;uB$l-g9hԧcmJ&8z3hQ9Sk00=%_\wS`i!vb0顊%?.h+BZJp+-T9]T78 ¥-MnRDTh6Y\a2r钵zmDFwe F R/@0ad8 F؎tVE7oþanW$W;WEmu9BTsM4:F4c;:ȭ-دOㆮ]E>]5i L-ʍĠKp.0OhPvH$tɱ7j%AV5ԚQQӕG[vz #}QS๸c4LyoҢI`@-p$k£6Fa/ğP-w#-jj-M2Y/oOՙ?q4z9r]3O7F\&3u RVa˖k I(޸8,eZ-! /PʭH^o5hr˹6Zd@]dw|=2+ 1Keul2mUٹ{gd9cګ+T{ׄ^^Hf!c o" .5U@QdE: i?n~O[Li^%v Gb v+2o,B -^Ek)QTDFj4Âk4txhqp*ԇ2i]|%_ 5>zͷ wȓymw8P'tj ;{j(|C t2q#+;pMGMSYIJ НVT\h׵/48ErI:q9[bGn\tDŅ/-,㙜dE#1 -zEȵƛT2FHFhS1֬׋;R@gtW$ɈQXKDRvv6wRHTq l7쾿[[i1j($:;w@b&p82dJ )J[NLPh ֱFB[=b邹ܡsƊLb&2N/ٮ$ڐO/ΰg(nWYY[fPqٲGR&o;" dQ?GLOv+8ޠ-@ ;dwGfۧy-l+V  SY"R ѤQ9zȲ +G8.cTy4O=.XOcpn~GhXI(dͺe.iD2%'gsڽ8Qa^P2@y`6j8>tl:ADm`s҅4≂Wo H)9# ̝.5hEsC8`1^5o1^z3 -vҾa X!(Cr>F'G`r gyۢ7> \Hl)U`T *xC g0@& U*U+[cLzEoyaOZ{P׏i+/l~갓d]|{l4SGz[:J'X(Tf<+($ii!H`~HC6Z0]4u<[uO=]h7]& jSe,2B@ڔ<!Vhy :'˵8Z;; $@uAzq5Z::@+,Sq5J%!P0=ΪW!V@rf`\zG*ӘW:5 : c S\ME2Cq,D[EpZ!uzqCkR)jjw͔-~ '*~~1"ă~NYWE_ ɷ|"f\ ٟNOO)X#XC|~ћE޲8_̑_*i$ekúf 4$B23Bh8ZF%B*ЂCL6ӕ6D4ITwnxRwj)LPrtcK|n郾{˲;!.Ȣyf# GCR 3>$a2QS$;/mmF`%mk),nY WT ]Cg e5EW1.}x`*-Z|_:#a..HC&[|bO7@IDATDQ$|ii[xJ}G _g8PN*+DdVveV(^F ut=1f#\Ѭ= YsZF&_)=r' 3 ' ZMe9y;vCҒK8aķF㲓Z Fi_끀=T 墙VEP&4ט>\HTmsjKFs(&I&sQȢȬ<v2""VsHcSK"'F'%3 <kah<ўzv,)cyao =QʱɯYLE[7mWOŐQ<HQI=Y"|ڋ(HA%|"̐m Z1k> ֍>jnO`IqiWk2V@^sMtY#jWJX[T6ƝW26"T뗓ylY醭X7Ѐe\ Rx7 GXPa<FjC7QL WD6K{hKܬvutotdhPaYj<g Z568к@ɜ~/٤6 CTQrxXG$u d n$;wLf VM |/D; dDc~E^{6JzMʵ] |p $ddBP|IyRLd9uȭ#oߞn%I0+Y&ztAp՜%;q83`fE56$deQtDT*ߗFY(W'J&=O>0[oͯ抩lWSu&lC. F`K1e;֓SQJs 4o^yF Ezu5*U81a/.D54)\t)A4qTK$u9P&g( YqJIJf)v~y(eN#,TsZw:̉ч.ŜFQ#NH/o̪*bGFq@OQd# sR  ?RMFu˝\ ~^j0fwPk<9v`"S')ZoC8ѶV_B x"kgCƎ3ߓPwda_ qwfͥ ']k}lBAKLd!eyk.F?>Req5x SNT)`D\֝#45Fxh"]8/G QAti-iJ/I=#0xnpkL Lw:G̻gqdNJ ʡ䑣*vH(RႶO٩D0֓D|L Z%k ,JГRx3'N@/Ոc NI5\pa ~OģkJ\]ugG0Ai[v0x%I}EHUG  *nց9؏߼(hCҁZOT$J{Z Fɶ܄u  0 ,f+RGs]:?ͺY`JvֱJ2v9DGOTu#nB"L2κF ?(qH?-{mГz"IZH̕y5 z=,Pa!DBIVtwMǰolYkJ [[c35e O??,V0T?r Ȍ0ؒLVt%4?U3kTUl $u<Ůq\y'Z% 3?td{ur:+ `B6obPy"Yn4c wME'44K~Y =!kJ@#IMM5b(g@+PuVh" $/],WiR҆Kɶ&XPlzdiu:Uak$7` ?8@N[\M꿞b,+Efbb ]8VZӤ,nE*]S! X d=sTgYvPMkAj 7Rd>M4r4k}5g]Hyo}O"0fҳ&w _ vk %QqY0@;߮TÔAN:B7cE&;gad%9?Lir$Ia쁥gF(<x#q2V>FUw[tW5-yt@7k<(AJD,*"y/{x`&b! C(d-A3L":'M)1A!U] 8Fh]q0vKفM%uԛԁ*1I(8r$`DL]WjZc72/eB?Da";0k֤D6]j XRJcTidSђI:aDڄI{YR]av$)mK?.%ZBNքg/9e]k`@Xͮ`&[tW_Xgu}0k4ΊHBWpFP'<6bE-NZe7EHM1 ^]k4.&Ag;p1~nnTپFhkpu0 t@ӄ" 1`g%0WhV4.̔F $dlku`d܁!,-/ #Xid&D;!ˮ_I ,k((pTFWRW\_4bKA‫e/AS &"+*`SIg߃r)ݵcyҢ"*Z%*@k8;ݣuD!ej ??82½[Ŷ),03Wa "|(L0Z1X@iZs1{ҁw-*#h4!=ɕ9UuC}ZLZE)1eGt?ި@5ls{kR'0R/9;yui NC"q@rN$ >v,C! k iIlhi-S"R@9QCXeMEzpMZD&[Sx"wƸ4qADsiԋǻ>Y"dI&:9НG ӟ1"|IUud")FD~z$v_ )FqgA>=B1EOc^˻ujoHrRS Y 2M4S >tZNqR5sKb:Ob.zցt%ZbyWjWR5Y&FI%zĖ@=kf0qT/u YKLm[MεǏ-PA$ܾ\R!%`%0 6] :VFXfn#2 NH9wnm<,eYzl{8f$4A?17 ui`qm%'߱֔v%(e?RXC?ț#rTCNb"a)D歔Y#k\apJE*HlZZvO% + hs!QdTW@ٹvK/)wvZ@`+QSNrz߷wɥȈ? }D#q?$Atcvhc~n,TJ@qy *EQ _wn rļiC bU{So<`(r/U#l-X_ P۴8ֵT)bi \ }}Ȑ]3H? &rkojBՈ`L . j "7hqMGbvr1 u_`kb>kV˵Fg(@ުDl/lN1!_Wɉ^T,X x{m@ů̪y-ƗzQ)#gFb;sа8͸ubi9)٨R-HE /LA<`Y'֤%™vӠ{훇{J @q"G a}cTa.@1l}wtYy]?ޮIR{ 5 nuYE@nΰ=v/Re0BHgE* S^kzP " ^~)DGg,ˑ|A_t(G)w&Ncky{_yu'2s¶h';ou3HUM,̸KkKЀq Zl3͌!ٞ&T9_[#}/'B8~%TXVDDwk>*}JW/ФHX?:"ryK9muZHZaf?wξ.?NÂpGڙ&IF@F_"UP0j6SOKIuVKIV ]mu5y7|M\TƍM?xVa0*O#e8mOq DO #LJo<^rW2&Hks8GG #7&P>\(apAY*V"I331I(xטIEέ$8JͭzeN&CTQ1lP8cIwГĀG;h ֿK5{6eê5f(_n0)u%m8ߛohĩ\G@TlfC0D]nR"w,+R׻se;ں\=уV2 CNH!jjYn,}h׆ ;/?\Зq6cQCeR_la.(u#3 9֊8ih'X9tgQON |sW7OΦ` %]Ħ0y-VwzDVn'"UV >9T ja}_s%l\_~Q`F#(yuHMק[t:C!3K~9Dlr-]'s$ίҎt V7rd+l0@ȳ_2izlڛ- N@Fi\tvlDb<./q vy@8-?by5>7a+y'K 8bM^)C/ Va*佬t{ Bb=;ƥ t6پzs])ZCumi}uؠ)LҥoJgSle@&=핃HkYNoݟyX,zĨxHd)\# d^y謠_!2 :"jD7%H-a(jB@MK

    /Tj) i K t<״Ex<^kS!/%Krp!Yo.4-iʣ3[G-p aP@+i.YR@3#5# R @@\)/%vH)˥~t1(,Vc nJPԪa9|np V\LWj6LO=H,|I)7\ faC{C>>HO!-t~*N_ҝ` &*㢢: V.K t*o2'US('! ُ:fryo$d2rEҪY%`*b:mr($"c.!@cze=! 3e&C?o6<dcv#,z >5,}X%Crp"/"1ULeb%kX X%BVf.ycD+DNIlDu yy оjȆ@MhqPWv" ) $+1E?" t6o)6g+1p >ra):q,fG V YeqA5?|J.y tcL-&.&*6Z-z@EAq=Z8DzRڷ=)^& I%9I$XdZr@HEyoU?Hl"GS..Y-) Vbj 15Aq܊E'~_ $VTM9#q{).,qK h접D~Dhn0QZ915 ,b.D e9Ar1 ŪX3X)ͻ^TU OSx?ZXLբX+]y3mhD֚]\=JNP8l{ Jk 01hόi Td^ \TGRQ'iB}O5rP20 oEub w ú/(6W+Mgt(jRMbŌ!4B~46[BR0[TSV iM}x)( XMl㆞w]7P^^Dx βOΊ5U, iBN_y$ ̠X&A3N4G EYEVWc$B-3_M^G4B#:i&K~n4Wf9S؁>/$y [grW&3IKSo XR%FDv nvљb}ԿV $)O{mL4Lwsj $XO#U,@92zS(UaXRČetd/ubNK"}|Y藛z9RpJzHN#X$֘iʼp06ėJ f:3>#Al! 9jDSdo`D<\LXҍ+RNi/-P1BLXT RZ|␿')Y?Y0$ryv4~ fʎ} C'hBzVJTpOsN7 3}2NqOl`-ˎbUN %Ui@ɦJbKy0OVum9 0_0] Ui4;aф@6I72cnHT`DTK<"2=GQ$"OD4y mY֪o H6Zcœ t!!K$HX|:&I/9""l dA .xQ %>C0ZlM6ŦIH!^9ii@p[@CDыk#a s`Қ蹓2{O3kk1,#kݵHqK*y@ !GPԪ7u"9`H`B?aC[\ *U>sjǟ z!_$^1|}h\ͪ;$*S?= Yy;ydab*"G6INx>gԓj3aԼgOJS6 7>4gx3H"MEprKc<.7i QDvdYgs=H)BC 1zpF OdZj,眽oEKq#KgYY-e\ņqD#jK(।nr{mCg$"ÓσGˎ]njEϬQPe5 g9&Zx fR MYaրR(5U ^O]s1ڞ^LCSrDWt'py jmAl;?}'".1Os4Em׎.nD>ѧXh*\镖zV.HZ"'_|&Aw뜱W:P6F"%rr#bTIţ &Q'#Vjqb>n65 njV[x ~&)Z3'jҤ0=QQTJYySYHZK&p5;/wG0k!"<)'V7AenpͤjĂ ,SnۯW.)DdE-GzY>oiq7mK܆tEMP}:^ Jn)z싟ΈةRdj*k"vxIn4JjNPJ揤iNcO M[YQyX*YΔ7*M05"YeaRp$h$q"(}Hvi7dy/]GqtP~B^G\÷M׍b# zO@bi$!ZtlS/nFE976x?|`q h:GRS>"1\{/\ ÑS7ߪ,~] :q;]fEo#Ѷ>Qu@PJAc)7J.@(FN3~Ol4$WbW+}0Ao@_$,H-s"f5o:Ѿaht%G`A%?bT8 H"L1&&N1N@ד 7(xG3?s5`)J2$(]vl7@aKYLj29̘h JD?p>PqHP XGsi fIj(JL*v*)@ oZŘlH@ 1c2snR)h}@IdlnLHV]bOȽk+h@P~tR5ۧV˝ F3!ѪT$e[G5]_1N-m4m|!g'2BYf g Zɜ(2T>ֈ^ J̃BA)io¤aqW)Q3GW r[}V@azP5d_ BcΌT {=OMmCv#put`j !c8h_6 vzmDzb$y]n喙i(aFB7}wzkKqp k:IHw6ly ]${~+SYu4D5;']ȷ0lHH ="̐=$u&4\_ȫ|TB *e]xAw#얮\Qk"g#!$_]kZ/%mOB jIB(I3okH w(a:`-*~Wf?wo);l/ۧ҆n ʍ;qCa/^]j qݪd¯K{Z4٥k%H@p'>7’OY7p$l51V1!%ޤ:~R0? hfx,8e#me&*ǛHj̣sJiQ`ሺi6JDb̂fulH__BȚ2rAd(pV7 [؀C%YLkG巳aOeYMucfg@9xkOXQib_":P+|"01Ga>E@b #_y{j; T& =2N:~JqU0ZADQwA~&ӬH>`hckc9`Ov >LH{=bb)c $ B48ՆzK +ڻwVyFcc97OeJiT "T@P!A4\E(90TC35zG]pZ"A)e13C'lxmne3*ej쨙.5%zMHۢaX_Tnڄ6%DhhkТGrxS vEP~_66G$ .:7#J&FDT2Ȉ"{{gRy怩7JRck nf~ XFWOlYӡC ,j}lW _aTЖk[Y^.u_q`0jM UĔYyYH}pG2:8%D\@Ѝk\h5TP~1 , ^qgiK$ĶanoNOwO7OvjwdhYʙ(֛?wb@lg8(kq2ҿ޸@3!Yl(Vp1f1ܣKG7`@c19 6dNN|ɿt4al듞`93MO&Llu CK>W~g\otev M `=Jx^Y9AT$5b;RUuPCf@t_NjI"tTH^?E\0SlqN0b(#h-b9aĉ25X mJ-0s aգT@)]^)[;-)%AY1 2ST0R 㒼LJy0e5OO]OӄUt탎+T$;ݷY)AEOrL#oɑ[.|T 09TyJ+w6;qH>iS67\yOS j5Rc`d%ꄹOl}nJіEԩaݶ%LvEſALPܓ HbN\ C~ġ@ p.”?AE,erl l֞}cxfJ@{j̽gpU]S6`IJF3A+gts,AqaTOkvF8[ÀZUtϗCqCw%ĝPwsfR,%FHaN[A=iR|qH.tDŽב|X((B@mRc"zP]oQHI#`3e|>DmcQL݀.oZ"mlQr OjUG^*47.t&Q%DFn d{ym<3v켫|f pƓ8܀6 pa/}m݀ #tFd*Ukoj!uQ=f *9 )u 4Za6 W9Kv/>xK%$UI&|[hB\Ÿ6(q(]qE [GYP-.J9F` ԊWq5<# 4P 4G8R9"ɧ,HTӕKRsx8쇲/"ʵ%)OkuZM _VWZZq,CN7Z = `>Ia& "l[#c<>d xĞqRp!SV{6,`}MSi(zh7T<)za;6LY?NdMp/4hpdŨ/aX?K1ЬNN|Ͱ{\+W^`zM&# _QSx+ 46o`SBv>/bT=չst$8zB!l͵8_ZB-DJ {݌jcBڳyyPIu jÖd(9g?o_=ϙkt޲aqRƼZ //lY T^_BG{r3uqX6xk R+.. DŽ)YwyaB*f]M%fjz=E{^Ӆݨ'*)XA1l)C`K8{UT2CYX_}S<ހh觀HQg]I=N סR74Be⽑!sYPAFM;Btxb]ȃ+)c hLO : E'5 E #w#b?1N6@k7l34e0ぃYF}VPȯ ݐ@WK(qiE!|D\xLB1y$uX6?tpqTCPO4u `s:2 nRс\2mě2Nw~,-֞x }X_ͭ$>rWKT'H)A?M7bo)k qZ0&g:bFV 5AG 6rE)Pgp|MF'a`6MyF`eA8 L_y9_,n( = "JY5ZU6k (m v]*J"M^v}b&j^sap*wF;^fR5uy BnM~'UdK3P]eӭZ :ZdmtԌyR0ڡ%JdVӺ.s8̙{e{_ѕs32uδV\Ž[,Lt QJ@vqT4YZ\GԂ3I()Gi8:Wp6J=SQAerdw5uWtV#BFD(KѝXWZNovTSFfs!'|$ )tȚ> `k8y٥B}R/q*H8 Oq#@L|7ɟ4qa DLMx?|*:R ]\#'ZI(1SYRt}IR7!i-W;MQt/|w{EЕ#8W/K(zb2eL8 a.H`)zݳu̫2KsC4-14XfgLǡx(u#dQ5KH<hR_YW9jD8DnWpA6g=K?L}eDJ(c` %rMIvR~6Ô)*V`Ԁ5Bj964#t?~RKv,C2N~|3ʱ,6Y(gE-r.E˙}YSA? Iej B!r&87j#Z V Z*'ͤ`l+}AS4Ek-HT K;q>hBUƄRfyQ&2!b2~'\\c!$nD09RهlaKÍ8תA ݚZWS%*H#ְ?R(/ )7 ȵ?5z|lC.'dV^ᖚoW^_5[[wY qJ i G4gcAZ .)P]1W?sqKu&j>(~jS2څNV'c0M7[7s @ [sX` 1HeMJ~:ΈSɭ[E<-&*I5+{h9(^~2dBuld1w2*K@P(ƅzقuA֜X-PA?M&b]P#NߜXTC,"կqh >\7}"&&2AsWtl %MҠ!%et\ VۀP^ WTF_154i>^2e<\J>[#."z^9$_ߏhL$qicD(Dp'ZL0f|1G1a^ }] A#NE~:%/@(TDDl?vg!>.wH-77ufOIE)]b!%) #rry[ߛL{@{aBR ݲ\}\G.i2(ۀX˫'% ˁX[pDmNG~--4Q(@*%`.z.tFQSY)fPiMޞIkm7w`WluA P) k[YǎOsZ6D "7$͂[.P,`)NyI{=8WwiOlQ0CC CHsص1SX^ `N? 4iyy)GA=St < r^|p/& Ҋ.J'% 4Hoz 4T ܅nУ6i(Nz_;5tgW<#h8Ґ_9( UblX4ܸ)0/f^XC0v4vwKA1k v,@2Pv¯Ν1cE,p`EP-u1eӷ#JRLg4MJX6>Pep)m,iV茖B,$wSRG( |hS36->vc""||:]& Dqz Phy̙1A; $ԵvՌc]/ '>EDfp9Y>{fpU}; ll!-vtl,/ەv3FpmN6ޱvQFe*a&Q$ŮP^Otq"C{G*/h)oD!xzږdŸ,U^Uz|/l&v[lqDRĩ&N",tLCZG 3 ,9 s88|zYV[M,zBp2+O7E: $M6vԏFٱ)V,@a-LßD|FdƒyRvPc)IM``ݹ/CWmW-ae>/_c[2S{[9\3ΙfR,hvqD3 6J[̛ҷN/}bm~U{vn_s;te E;i"Vd8h5BAfL|AY6w]Ѐcx; l^0bTRYDvtz,nȶЇT$8=|<;*,ّZAfIb.lpO"OpT58ˆ| I]ܝ*9̱ypZ0$#8ΰE;=Ŋ=<񣹝Y3,n$|qg,:@f~9:GA4N̈s<s:mI,zWsL$Q 4bah3|h[NU/a,uN2 l]U㩱m-rH s-`Գ*XRFU˒lLckT gʦxO{ 6׈.$c(??'جǗ[! Y"#,Z'4Dܙaxso1SKnŢ"CIO|uC C1~>f޶J_FRP(2yܭwv]zʠ3d /4ɾE‡m 1z7Åd (h1δJE}C8G~)MNBdí0a ) !EHxN5;8ȃKeتEF%ז'n \2$0k7F50T~"udY&on5n ??_Jr:\hȭf7z՝> F`e쌘vNUxE$ ~ :Ao`Np; "kXR<׽@V u@nx@ՠmz>| p- 0%f$XԳ0 DlDα.i+pr^,*V9v~f>A%,S@U(9yeL'M0 _TX:LűA(~vCSqePf Q|EnI=3f}C\ 'i# O>;܇52 cPL\/@Oo.穕߸=]AP]‚UGƶ'r#Hrf@DP"󒪮2Bdp6e}nZ X 6ڽ.ɓY4q5̲Kt DەȄ"eV}8hjq<0"̺QASjï6FYh)4HFZEdjt@`jwhϢmqPo.z3qBWxp~Lv2 W(.^݇Ox<ytZ;ߵyV)'j 4{ 00 L Y;u3"O2ZFFYi( #tiɄ0tX~is?Yb2<9k$JypTq{RaEe'E9Aq?쬁5jbGTh|qt|ѿS׊NQ"g"'=k; yuTxdErHf\?'1J:@*ugEdXGyhtj/#Ʊ v`hww~S>"wBt0D$)f񑅔aZ# RTg3">RPI_| B*~:/B! pt3{v.,ACѶ^e+ _1cl!e^NI' ا%ղugpǿQ(&_uLL4RofqQG˂n;VFu-UUx&HjJ; |/"e~Wo8p|P;QD `f˞ra;}4˝ͽlwLEF>`FSzU@)#݂ɲ-\l%(LrCיj22;%ÒP`O#C+oXur^KNZFPE'M,[kJ? d6JKNvDx=b z.&Y ' mLv Qi^fҚ`dT-Мa;HLK-BGykĎ$(΢!M*h?'zމ:a~6&L3TXOxf[_$?5C-9v QLLCQRIL3Q4QUf'AN̵p0EG1Z5!A,Z3sEA[I`pQ… zMRlQXvDU1Ҕ^b!TyLJeFրJwҳ)Pc)=>.-݃@ˊ3[dBz9OVk~*..`FUDrOC @JF$L@LVpL{ISITSϷlճbyM_l;E z| ;u(:YRO(!Jx2G-Ԛm%i ZG\O|rcDm{,W.f1ZO"0NeIb4.mKN}ߏc|-Shzg9M68Sҧ#gSzΈ2{!7B$F}cx%of?^Q)70{(VB&fG`VC~ЄOxEVFȴ1"&XvR#q.?8ɋo` G2Lq*P|0j8ʹBd}js$9T`QYф&(WXR,r=(P$M@8UVg1$`oRծ3d/>hװ v(nK`*u({l R$Wy5rmBj"fU|cz;>yK 2::666Ijp1o`aӧo%S tigj=iR4 r 8ofrȓ{ 5mQt@0YeGȖt(L-GP VvE陼fP⟫mt)|P`F`5LqzqMC0h _5yٛU q޸m}z 2JXe, NONR{zrN>bdYBȸ: "E)ю휀f+: qNG{tt.^әԒZ3@ #X?EzdG=8tQmm#1#Wz#~5*ZD̽EgyS\ևڒh*\ ig& Zrݝ 3~@^wҘתbl@CBx,w1RP\_:t"d1`DN ~Q ͺ *(_ݜ^rM@k{0ptQP %gq%@ʆA<|[r9,ܰ#Ns6`xtAL Xٝ8k 2] Mu# χ@#[2X+ P &B2kGIAV!!ɵ}@תQ}z} Aoؔ6d(Px-$R+EMԌLlۇ3Hw2եU1d]d2 z ͅ{X~EZ(3b|;H%)(XMƣv}+:"'1l,PA (-(hH̽"fsdzAſ 4b;t+DH'3nhc3Rpnڌb"̶{*AniD?*MuLp'_r/\#\W``zG72?O`J.' y^?2 D@LwљTI͠j$J`,#7\~T#) 2ǻ-8Ce ё;13$dU5jĮ}ꀛ: ˀPHfZ0iDή/_^#p!# TZd^Y߲p5:RE,O&4<`Fi;KIlRQP9b,U즘nyz|E=Q$84*e/Lm&^q%711̕{L Jx: U~ eJ\2Fp?  mFxF򕇤[19#u-7!GDJm%w0iܡ}<\\߽ H藒Ikd&eQ3@Q#\đFRY`ˢ\jps8s6N^/jqU5ƞ =:)X<5G/],wsTmj@%ha?᪏Y Μ0 Z34gQ"o9t$'ǜ݆2«Gd퓐cB-}N0wKo[ŕE1Y* / "W.!7%3%ԲfS|d,mRss4>qyg?_w# L)P1]c[9m93e:\Ŏ҃ׯM@)DaТT2M=rMv &h+-G~'&3+ %nk>@jS!;TAWwVT 8%3& mgwT,: bs$!%r붌:RA(#D!x3Y 6& vdS\Eb 4ZmT( T;H̆9@ܠaK(Pa{w)p!ųG\G% d6tM5I.|H4'V7htQwֹ+1s#SX-`Uk621A;k/6/a d y4u"Ǘ}MB)i>(y5Gl87rpݶ T )&3 ?Ԁ ׇ^9pG2Uز+:Fk!}j+B ɃS>Z>=voDG p] ]謎0mE{dQF' _ ~K# FQ͉n9{(L髩| )Ȭ7팚>E m!flE$smVDĎ.$hR$!C(R׎9JZU#) 9;aQ<sfvv'.0lVlvx=ZbDLD oS$ujhBL=(QiQ!T1 7;XγZZXuuř :ԒӰ0~%F=)2`0O= >ɫ%b}¿3_ʊ3z~W6pojC: 68$ Zޔu?_߶oן?vؾ2 Ac '15HNʌ9&3ȲZd˥6hF`z'yṞ"ep2Lz"mI(b%2*(aw:9 ЗG;3   붛6j9ïw^am~oH/7 ʽzcd|hZ_SQ\$'!? :1mka6퐊C@S WR/kY'-T!@iMI9guSF3z.D4.X0ջy+OvDK3vQn3F85GB64|2 Lz8Qi7,3 PCfv;@Li!o2BR\4F aGh>]n4a=oJQPILqA-ѧ@DX!;9Հlu LE|!2m/[NÌ(ju/l(W O߉+\EY=[V#&}lKڿV|̰z6/t 3Ub#E6Ip}?ݶ O_땆[2¥V;QA{"#clsKх28U+/K6<>4@"w _H`qo/Flr1x~KnęZOэ.ø:|nL0USQ\i U!=tf_mO@ /RR;(j?dc$!hsvy^B4^+B7֧ ;<%8)_ma[L.GTgkTw+QQ1ZwBIѾLJL@V52Q4^NEMcP[~D\Oϧ.@IDAThsRl(> c.$zrb /?&цY">?24 5jb%? lhRE!/?u1aҤ' c(2 %N~O3p#*QԆn& e|qq/wmvzx^9aҤ nRWgې9G+XӕcyEU^pPIZKv7o^AjdgݏzHO8,AIyLv\6[l!}poTSw-0JD[%;GQJ{$1)Η9ƪg<$mtiq4y:XH$,bT4Sc&6e)k^B̎m,t7޵YS},oVyԄ\!)z骰w:}H H@f\5,Be#9JIRaVT fs@=,W~$pz?*dÇѥqy.qۋ,Q3B'302Ii"IFcc]lwn{&{鍮ʼ&1:C1HKӎ{POѭiې&/蒲Rj387q2oߎnGʁ* -Ѐg Cו=> ԋʓGVCM;J%%~^ERnq 2^ yHvL|ύ}&F؊*0幆u>+{^*{ Eض-Heas`jN[mv݃-M=lFW @0bD: D.|VqiHM} rq!񃗆U.)ŕfAY&RtPSҨ%Z^W0cadv}*!ÖƓBh ,~dnD?r jCؒђ.!/>vxs"9 tBXHCm-JHH146ָTuP۠H:2@50s!1I5: (h wX'5Ռx:)(r0K%h1>ԓ2²^=0.GA0a }'nak u_RdhP ;ɂc4(4.{(㪢Iv^'|,I W|Vt˨KJL^Ɍ>'bCBJOL Ez4t(Wb /5)ZdpjDvF$LX Uhx)cE|h:tS$r񖜋 oN-_đydDv:Ad2N 'sBv3n+9Ƽ|˞Յ9?5=;."]q69F/qWM}a b-~@޳uzfI&T J{iBes hK.e#783cݚhTnO x=IX~`[P`>='Ļ!LAp2rUdg\Rh89YX- <[䐭MPf sD^D`BV(SDI=K@+ լl$ܭg.̤ Sm_׳fldc2|oF^47 . rmPrn C4(.A)ؼjN05vpcK;C8/H#JE]C\y8H 2I`yc)x %]_- Ղi3* 5J`8l:.}1JY\rCF@"i{v#ltbԦ}4!Rb  0bf8$~R/ؑ71GH鈑AiOtEghFrAʃg7вi)~ FoAIZRʦa'M$O=h5Z4Is3r 4ƐH<:rpJqޜkM O0榜ܛ8$pPk 0^z!:?|Y5GGd2w130M2)Q<*J~vz>"9]2qd̘ Ղ OhX\E!| z,7G$5h > aJ'Fh7)V)Z.jyďrPNtHBTbnCFw(N|ՌZF"_*"`(Z 0w,<:[*̣UϪtDNSZfZ0'`nFL[Yă,y#qL[F Rؔ 0C?3ΌBN2J)#axggav+3c -Ucl['G(늄b~zwRi~.{"<( J>'(2z-.r602C$Vҿ?y鍭?r߶t?Hvgm1>uUn YL3TB*zJԨ䦜gdL 8bhsljϞ$C(Gw1cVA L!{S*WVgbͱ%J7?Hmf$1v~BFf*Bl*"X#bOd~[;B[cjMIfO)! |KHGa>t%j0ߕGhDa dv6h{1#cl/ [!?e5,}ʬM~!j'o,J)22/Jm2B ^sWrB|Us#7\0(C$aEq:PFULkl.F RR>Vl#LG$PZXHF 0f8i3aTqˍ@18%ȚV)3zR#~ Rid[eF=3v~h O/E ad2j{fȤ) I^FxNbOgz)΋GpYBG8lωuE@;A >2xxa|v{̳eTaQ%ַn"!^wztlfh%ߐDzrX!FG"k"Xr*jh}g( ilSɁa 7͏')2^<[n5]$)lRMh]D'`1*ȨDmWTqWka5ek)*SP3f^<^L~"؈HABT9a' 6[0*AXN$43i3 ` o]epd@G=7:-a*va_9T [@7)ҵx 6 *鑤yQ:u< ]rdvr1rq5kkl`OF/yolZ=n&)C[[ jC)ے4lYk3rP@X=L2DΨh NѰC#Ce 0f/0G2eiHT2  KGṗ5"Uy3MFA%dBgK5m'{N}75~*Cnɕ (j®0=RE&I-Ofя"a_C CE景 x7u`;PthIE~`#nXߙKDMb횦j'$ଙK`EnET`LQps<*Mi| 4'lL3ͭ`:6)OS3Mɴ@Ѫ>*rm~~L +V'A[bNqICc'0UC/$CAzP0UݬY5"蛒2{'|,) ӫH2\Nu 7֥9' ־- . B;"R#;:}\YD\+Ƒ GI2GCo:!P)VSŲf{D]-$:ekwr(C=_C]@p$y#2)qj0de=9s;yҘrYߴ߂Jq珚aߊGdNd" \ +[J6?+=/9uw^:{}H4ƮIuv(')`pWr$;LK^XckH̗Sg70 ۫YpMIm7?yoG 1kG9,2乚3]b݁P[W*gG>S}|SZ#j/EDKlZ^%`Jeqn]'Tss{|37X*T00iÅFF]M=u;2[M?Nypcj?2RZ xnɴ1„ keՉ%!K{@r+Shi}21}(2IN@'y ڔ#A7jKՊEH8W- q ?ȕFImeu"!9:Xq,pN j Aы"ly5Aՠ񃿬3*Y7Y7JPBe*2$<1{ D@/V"S }>4&$((ioOhy)߾W"˩Fǿ -=XZ4#a'8iU`7mHbl%Ԛ1Rl<8E V |Y7a|1;$rtIڀ!;kҚp$ ixu[bQE^yO &9Ү囙[9vݦ25}#8sy)nfE#$~Um6!/w™+e+Ӳ߿O5R8! W'uC3n|AlZ3;~̑]Lwܛ@LJV.SQJm8 a3ΘY *Q1Ʒ1m/ɝ/l沉 8˪ZK`T=ސ3@৤3֬_1"tb<с]o?}7sVw?~+}fbbAgx?h#7MomhA{eWMԑ:.]hER\XFUM7W_J=jOs^AT:G͞EF+rL.S؀fӛ A+.y, ^Էd'P6p䍞J3M'bpkP%.lixa{҆-{'^ܸzwkjs;wm |/`_@8@1N\L70a?#"n9]L"{E)bоSw CF61P?hz'\hxd#d̔8Fu5x48*TeCdX>x4bһ8? h\$}%md."e' (x$8\Hk,;)2N-Mii1|D [bhlC.:#yއg>qvbf}66}' 53VMQ+*0LÉ1ZÈ }1M/-"Igajd=E^$(t] Es0Y*5w"2KxIx&45iIy AtRXHUnQ/yn||m Wm(S=(`?dp*в$BF";WhdU15+YAFM(Q K_:Ze 09s9xPy֖ݶt>D&Ne 1tmV99GLJ7uq$0@S" ^Y3MMI #bWoiuO5XފSKM+X o1`$蘬e8z&V1*Y#2IԈ[m8%7{$ O#W$cJ<BNpGľ۾wj#؁7 xY{fAF&# QDWP#(qFnKj&[ rItM9tBcl /,%L˅X0.rlZ$ Hڒ\ymXTd25E^P7%@e$T1'cBX2`7֋"慠K&/a ƙ-[ \v*R47BkJE 8aLH:o[f(uhZJLK2 ™zL:5& %{;qFX\j NE5E yQ&) AAS7?`&_O׹."SIp5zL^Z[-yz^uC?))<N@}ZIMc̖c=T|y2"Ip Ì@(PRgo0@$wHrюQIߚnzRA9T?ʲHXS34. n U5> x""?<>#$fw<儀i+WǽHe8~TU}he*ng}=^<΁m|PjW`0؁8j"|s?p]IzoDK޿ުKCwA?i Obw[+\-CTX.K$1JL3[]#/'owCFJ.ǧob^sŽ8kdl, f-qI]꼁7'ΐH9v ku*#YC@/_(.Z#aIҫ 5;C˝$<&ڵeg!QxPm>с͸I+l, J*˖1>iQ2'sqw@ǯVdan/l5d `_'{_oH@8$%LZ҃ighTޔu{sX@&!U9nDr͋(rX36^P釽%;G@OJa !*^mPE μEKi~wpBkZmM0h *rD@De8uNL6&bnR#ш\RtJܿ|<5H4|HltTL}b Dܾ\"ä^;!"Ax8?plEêxUb€9eŊU ׷'4SNR+V]K-,̫ć_v>\ԡ-h@h/sԛp:7Q>JRP~q#S! fh]0hQ8~ݙ&XRqvίuZUj؉GJt$&~r#HP~=T,3ӋֹFȞ{>ه:F Q*Ke 6-c7FzzSCtϗ|7E51T{14sǽ1Ó Ġk=:Z> *p%3il.h`EԚ V\d*0Mޥ^&{nZblEQT0ա~Cld>ܠ?KmF FYi#9T ;*jYu^;sl+Bsq:\w俛5:jXNe0Ҟ$H$#0\h<*/Hu=sMFW Lxۉ$H)]̧ l<|d 8 I]J]Fr4kc%xe6 ^4K!Yv/ _N6J֕z7YӗiMZ19I(~. G1y@').VzBBzLO|P+_%vS"C%yKĻ':[fg[I`jvȶJLKYnʙ$ڋII&̾L>{E1 F.v_ײjThLr :27yoR˜H?qqGB܄ hW| \bϑSQUwk'Rـ`|w$*eDWg'dٱ=& KXDy]X$ RfCPڡ?̵CfuXRGcȀ86C~3ᵝcC;EaVo( 1Jo#n8(LɊ"M; إ׾rԎP7{:"1 e 2G1M T߸ٚ(t29!#3zYds$^i0oU^45ӂ2D3PSVRE'P![/kx]5?( fH)::9(\ PDX*m'UzLv#z 9/5C X>aI`nDܤ7G^{6EmUA7Y9=u%-kFK" W SW8N'#ygBb4U";@P E#Ec(Q%e"4(B#5S7<wh=bXƓ]T)r&X^Ad[Gzcp'9ZPm"viIel 4Ca+-@ ?Xu MDdV%ǻUyP+jkD҂mnE *bGXbDő;U,/6|9fݐRciG[6#n~U9[j4@o2er?FÐz&{ w_?6#URsѣ=}+kXї0FAy1k:T嗂`gR+12alDv- H7@ќMM7&-bUE2D!>2xY2Ag $52 <* P6=|l[-sc˵6Ndyaκg"EC9H-txnye[m0΄nK6] z$ MδS^ȗv4F('#3|iU N1D(00ܡ꾶I #;:3blD 茨z&4!j/c@э3}+ar'2|:dA4̀ţ@^T9!( ]D3Lpd1?8s'ĝ<QП1,?ղP3leWYqh3-TO$mftIpaSw(zZ1kCQ\yBERH^?j `ERjlD:KQPV9JB܅x`M+#)ɥ?r3k?Zl6@Vb> 3TXN8w#:E&2= ]0p+y# q#-=jT2#iCP˓⭯VyW|.qlMy g[֩n^΁.zR1U*v\D ujj\IgʉAredBKX! {R-`.,=i ǒ2^ֽ)%If:gŵ w2NWeϕc`.i;孷 yAwM8DlrͮHBQ),poU?oڑKewc,G3 m vyo5(_PŰVJh( cul3tA HS:hV(t4T! :1u'VdKi/KOCAdVѾ\" d # r[P->$U 5](> Vv# 1j9e=%Ne!p? H+ƄM&^v$ k6}/c>圆| d=ܕ_;L%N"arӓ6)^ } 4 ~GowYKm]od@5L(gs%-Xjp1 NdxHQ&F6?O.%_I-:ZϲQFhJϒ!O8SOÌ qz:U2yDWSy(Y `A 0\P}m3Lǃ Kcj\X:~d8↴@!8xЕFnO&|.Fƙ>Ό}/pZYs3uws Һ 3d0{մr@i:r3B+#_҂hQXݯkpC}/3gP tѾD:Ʃ,Й!%79j=~>i (HMhv~x:yz&p,sd&)D!y[UjF! 2?S0t?QFX96rt#*:a'B**j2"[U: d>?ǠWg`O%B؁Xc`"G&@5TU2CRS iCԠ ?d<"XLlQ^5kWX9tʆ4q JeRP&I3dcG [:wʹ6I'=J3gDb l]Y62dUx>|Gj9m@0gmSV`!3ԎI-a 8uup68CF鏶As,og4'N;/0"Mbj>4u4#}_g2|5zƨY䝽%\ϲ9cGB㿎{6ނjA9 vI0ڱ_O{&r4D+FwM4.@}!ڀ z+B!eHiq_~e-x8kODƙ k)tb^kjp0'6+0DuG{*MIEhUJK*I^(4 D`t]B y㾒Ni(f@iJS Jx|DЩH,NHS%>=dz:_$y8 'fpo~>*8to08 ZsCo̬܎GBqX ɐ}T' KKGxm.t`SZ@Z P--:v"=bIȉxdج~vl3Lx Ȋ)-".yjHmK/V5D&g>?QudtZ'5GRyҒu*bA+=otnYtȳ2 A*v=ڌ#iy,kId@jfgq6T}m\tMaQ̂=cH:,!hgЧJ1n̈́!,WI`O&b[BfAg֕K_PGqw<ͣkͯkM0`rqSɫ󸱦 >N=]xy6/`X"RO{xc: 4YPX1s[y1[ Ά!HL-3| ZC[2푲|rw{3 c ?"y$nS~yPr=Y(\mbD.`JL]3 `wOlw-'ڮғ5DGDorw?M`Da?yP҈I[&ch+NxA1,Kg YfF!lklC?)d7A 穦ᇨpFrwؠÁ̑GwzΕg4Zm֬`=vz5K$oFjx>~+##!C^lPpOXN#E >L3l/'RU4z^/ÆҘ´58Xj%r E6A"snen?n?~K\Bʬ# v=IW w!F$M֠' DԵ}Q-n<Nvxv3wJT^xA Oj׾H{[Y]8zrr^҈Tf/:G{'?) 2 }sQg8vDav(E\+0]v%_[=]f`|ZR[ Z"x=#F-*Z+RɀB\F"̡Un\C|дЂ| ȑKy#+W82ʏT7iWTW'@:UQQxh1h*1ȡtJi,B٠ @RA?t"ʱ!M싦͵HVf'.z*C Vo"&9ܺ G\ )H{䍈OLSS6i țw0l{5H+RT6f1vC;f/(: y `Cw D$AO6wЌpDeΘB,o}|F&l%#ϤDЭQ4ܦڙz@BZ6A#k$\'нHOI1nv(#7)4e!--4@w_X̦$TxdDhpl=GV)W p쿘]z$O,3tU>:ַW0N$F ڌFolV+u%J"jekʗMhŤmtc)0vpgAu3xH:uU;Yj`!zu-84" .G6K&h3fa}pګeD6O]BJkE ]20eBn?dAB^"/ Y4?} d'.@YӦhm\HU F`HejzpV-O56F )$SHT<3L DOQa~{\6,73y/q:lgCQRp!espE̠4i*T~]-M;1+UM+0r`j /ta"KiLF%B;M*ǜqtPq~ac?yqctTn/5k0k&@D'% t3 Ȭn5%~"4Xp=Bht[ȦٍЂOQ L21xi7 4dfd<'Z 1Y#kFx=]k _Ke(pT62l]vX,%˕]41 7#u>2V=HR4IEgc<)]|ۭ1?dICk5I_:dK3AQ.YvLjW -phB{8B`BĽVd@xs7B*|_){;ڡ`~h5C/}MpJG+EAXg&UJ;yF$󠫵!!kQDiYg&2T^%ðSs Jml7,qڣ\8!#?#hh{yMT!~^!̩E=- jU j/t$cl= x<ݖS16zD3_Lˉh_P[[sE9 YʢT%--=_)JDTĈԿ Vlmɀ6?5c5J3p;kq{D xPvbdUq4>y we2&z0<,,}NPb;N$"1X GtXRڼc"NңdQӤ>! Р]kTL"N3ɿE6(yRr^:鯽U Fqn&c_1 TQUXG,L(`#|h(Ԍ*luc[]B5`T{yDˮ5!1чW ߿AZ{d(ϐٽLPS٭8q_l* (۫zU!n4c81uZC.;U8Mdh-Z{7@Q2߁uP1ly_cȑj$S;>겖G]$_Ҩ{~Zɒc-LR@w%Oh d ͉͊yR'CXMhcn*ʚSΌ Źg'Zр71]?VH 4>3HʍfV&U&իx_TM FL9 ~Ɏ2* R)TD?39?P'*~f(}w݁#HŌMȃx6<ǴX!fd %34#,ST=i^YϚ;&%q&xZxȉ/@򣈪\KXFƣOuLJcR"9^E`emcp jqH%$&Mʑބ2E&z' bT#¡'y#qLb|' q7j*74jF% :(r?p{D'.5C&Κ0sgаLPISʼn~% Gj?#QL/ nD4F{w~[%~*$A:DMj $ 'wOLFKiTgX"ֲzlzaHl]^kH,z\ByFUu-_"&X L*% D:L 8v{HQd7٫pz N/s@eA d+?XҺ~V3!x YmI)'Ա ^]dІul _az:Թ"hV;7Ecƺzm$׼ ӈR*|ʯd@hYDF b5`{p6% pj@YK/VlqƄ4G2TJ-BS!,~yuD:dRzǿAЩTz3a&M=wST4^!bpFH-8Pthz0բYr1*FfirS?O%M*Y^ |9`)l%_Ur$F K*n"|]W\SY#}O}Ϲ7y2"r=Y&D>\׀O{LBEϪ#Dsxz2ēM-% 9;HKmE#XȪbj:2 Zr U;T)Q/:gȡ߳"htB1X0Pjh7: r0=c)؍ Qs;DϔOA15ňlMD& H ǓuVUV#n5 ը#a0%95 GJ s̽m5H%0! %㹕,PDxSIvvف24*r 5JV#QD:*KE9 v~=#+a<2d_k (-~P̉3^F(?0i'M0 1 ֭k8ڬXg>!5v(.e^A$%¦q 6˰eTY! &Gr88͔lR Y:d7FY\-%[{l3--Zz3% m[ϭG>Du"Z;IFsTZݾ7%TZqyʹ, 쏝y| )C xMLӔT(I/ڰE`tb3!LtM[Vņ(F| peߑu}Pm'@՚wL47{ ە+ &@ ]C4>\@exSZ$ P%ӈS#G1B5UʖB"Kf&Gò}5DB؇cM I+ 2/W4áV ^z ;RK\{C?=txQr Bdf[^ҹ*ῒhqޒP@j"XD(8.6Oer62DaB" 1( O\gŐEu 2Eʞ5#i6qEsD*" )nmfGT0d [{g  )Hz-?GӠՑc VVּTU"$Juf\0)cx/bZ(%#儧8s\mXiJ ^ 'C2chD"h"Zw2\Mw<'dP$ͤNzܰ~@_2Y╓i R:g@E("\o2 UZ^9MC%( fJI8:$./VTh. f@Qw]i*؍ފZ nCَћn /h`l Rm5Y0A5kpGƑDK u8vfC(ğ9ìYQj( \HHd.k'qc ' @Vti9Y-u |yϊvr-OyVZxE Uؒ2T%WeYJE:^#DД^bo5 |!%=5qAGevtNʝ0{ˤwaEgQ=;/V+Catw"BJGH<OޛyxA0#uސC?g3*fۿd{3)CZgC^Ҍ]hdBi Nf8,!.rd$8bR|Ӏ7ZzF٩7-o4fCnQӰ{DEE]P`QZO8BQHvzIb"IHF^!TVAs jD)WN~BfTQH q:(Fz*Q KN5Ugt y`GAK8FMBUӓEGp1kqBv!1G-Hyi)!n2b/_vƞI649^o&eQ'5л P'P3t+Rmq2+^i1œI|ђ"> YEc(#;򬜠䟆לQfb$2A`g@zްpCMJuϷ0rl#}>&ېarsxy6.NhV(ϵr/lR)Ù@FJ~ uVju5H<1Ԏc31("5^!}Z;:3EPt0ѻwTMմy7`o!FK U#qƷ(R,WvƔ=d B u wIC!>)<ijDi^38j= U~whu8<3{|[TXfɳE Q?IY>YE0~pyb':ElP Gawah*)PTt*I~CEi1aMѦ8ekY@_b(*Yvy ч[TgiFDٟ2+8-/LVꢙв}Dm[n7tdTA cd/IB:O)Tn7jn0}Uϵj)! D; ,}JC9Y_m;12RrK?j S>C!.y1 ^ˡj'9Wb i5\{ĉghYuK%lJ<7CftbCSB/'ojJ?R4G8<,pC[!GLjwBlWwͪJF^A8qqLIE*}r6+OzŁn0T>-et{E( @dnpR'D1K]P6TŰ+JDX{4jV[e4rjIqm6.Bdӝb^QÚetqoRo[PTہW'_D7}^β*I3 fsZ&ܾ[~Jawm;{ "Aϕ#P\R3_"jYe܎U͙ TvfdfFNϵFrn+7GH.vq|Ԕg1黖j,ƛ줪㥍Q(P0UYA[H'/5ϓի B(ϰ!B \RjLOzń$H=.?Bp=p寒6yIlf!rȑ+EU)Vorqv*:z<&n3]zЪA\RE$GnP[k=H8TB`fqoVƥQ/'8@WHyhCq!KW5M 2?Dy@Re3 lKhWI B\:HPLxچ_ ;E Fw{EMX}dr8 ACG(giCv0ym 63 MڀqTB]EkM is4 '5r5mig^W&͆6 $6GwZgqT@ץoh _%-Bl*$ d7?|Z|f*LpQ5bgFex16bA#!O;=ܼH1$[[$D= G1ʖwADw㰾~Rk7 Άe;= ȝL%bۺJ'L\RV- U鱶s*P'\ax,AP'F7pйB~کW]W'D-6h9MN6MV7_͜l~"a~!&J26Xe,E~iMC;:T$L=V)0$9vcµ#d0H{}m ЌJneik\zIWRBQ cjhw1?zET3DaJuVŤeVܳ`0u4"xJk24E@ C:;pc-r%KAs<=}qJXzɻXe%t{p\9}ad*%xI'+rZU7䄍82xl, n*DqPcoCXݞ#y} Jvɨ$~ncUH| ؚv@nˁN~};ac#G4 bҮ'9qɝ/qe{^<룫M,$fPmL3Uek j6Zyzg):`A0Q戗ϐ-4rgQpF ^ {&@jJ!5"tcץ#iWRZBսnkK02jhuQީW;YY3RT8hHcEU߬2= y"[qa{ty `VdX+"ąWE5T#`zd@ HS^6 S۞Iy9 ԃq,wUS!2ww3HX "-eFAI4 3Ǐ6|hS|;myAz`Ӊm'Fa(l8Guh>'^!9opfɤBYG-K Hp 49j EfBNZiq܂?ɉw!ipGkmֵ] Y( k, OHbJcFIJpɛJKbH5o]:Yς/jByiqLYv[raAJf-?Cͤ?oH4$!M;v)聵tHCGr /!sw^*[}l]y_ٱ7?0RA;AKcuEHQ=VJ[X|;1#-B>we9zV0`+~E|=H3P"G aZjŝiC4G@u^\(Bw! zm_k1s#])"Yo8i| s x4@2wbbZt5jΫ:$~Muw[hsdL h ^nH)m68\T.U( 토2_eWTz1P{;Hى P& !+."@ %^Τf=3Ţ18^F9=}B: XG=T!:%7ABuBOGH0_# r0h6 :-esI7[Dž0ñ :+c+Df{,n kmhIFIG K@3{u*eΚ2I4\̗R1d(#93U?T`'LYm'Q%qTb'3R( ]Y.^x.i OPnV+>pHF( aԎz374DjMse}jb!J_o~L|[(4c?3KpVQ+sN;_!E"a'2AکyӦח ZR4ddq٤ mZ'T4b  B*1@M:@6RGb&4H-`MubMg8$Qe1D9tI{@-G`5s -Y kbm5qVrEm?Q8|zQ&97CoN/MWh5i6j |G-Te.Xf-,QV2ښm]h6~"0G'cݎ I3afSW5gIjV`  R *J"(4am'( ) /alPy >/ qa쬝H3!BLou'{ hA*XbN :Dg55xqYoE4."!r.Q0 }6!0/ @P>"eAUhR!HN >q,(ZQ(B#d"5a?tx茢h8\& Uf\i,K!(0M1e,S1LV2IdNJݻ?zL"hinX?b2Fъ*KkϔQU#ԗ=$'o كlɇlm% [mj)dQ?ևc_U3؃D7c$;2LF9v!wn~CMwɊ 2k&*J c{2\, 7{ 0.+\0sɈPeEHiQ8+brT,)I)jPԅcX >Tk-,ۻ|yN-3^ 2[glL sU[-vV{Hg\M Uvf'WT>Fy6+xXi& : s Yƹ;#N4e~[WaHǾ9F1&ujV6@H:VmXMDb.N9-k>@*Q m,6˽G^exXjrj!ȳ& ;Qfdݖ&&RY/ɖ] E9sWC#xzu ,~ҁ.=eʀs9ʙ4bLrH>}R]IEBda9ä m;Q8@Ru1Ti'm1gT].$8H&hE?^7PU #3"4\ј $L  >*gkIx4Vb_QsM)dj؄31#}@G&@U:+EZSwiqEXp@amZ8{_ r愓H"Ne2ʄ7\ǝK*yx;eQW8-.j[|PŃ!^"E_Xe‹ Pp[Y)lL}56,VezED,1)-r*@)slH-7*}L{uvxh.xˎdԞVy H.f[\UO;ҷHsF3דN5#dCs$\)Q0 8֬/s]J4rX*ɐx>fA\ Y3EnhM'ĊS>m4R-ڽhA*lCG+V$ `9ʈ$V`"՟;4KcBa.TB5iY)%@go44&rOVӥ Neøɭs),a? _=Qj0gǸ'ٯ55l~tw2Xg٩[D,rPxo^T3I ҚQRb`|1eːj8 9 l yP DHV9NꨁuY"y-R@1ʍ^(4 sv̿2?~@T^h}W Hy(dJgAhVfȹNww%r1"EP39~:M7|T:q:[̹M` v;>ȸ:gY^EZ# \lTI.$yVzwk1uP:V-r8@D[ B >Qht@2v(s v|EjvP`e{H70"cb+ڡt-*:0(](30 t">@mvd3aGdw?cnIR̦ÕcAОYab!ʋBzU [-prIfA_Fydrv%x ֐`eː{\Sihg`6fQ?6 Y-Vq LHp%7axº @aGkaF<.sK_cr6W)>Q;KZjdVVrfI{ I4?A:hJxbjM7 eů p},ߙzRfGuhc u3 ˴oAc`y-ŻeTQ`}I& 0ϚI&-d= r\G?hb)R0C@!RXuß畀u1jGC) d`O2 FLjaտwݽ%\ 5s+6̱LYTGofo "~N} f>UILF@׸2 i3hPP6M=v%cWc S_#,xiN,1ABHrh "iCb$ģ%|Je(Orl-Fr?s\fDlq Ω,؀_E,fSKTd&zl0eL޻3A[,"KP{_RaY( (}U}^V6V.BydkRjpR8 vLv#Zk$.lM$!PJ_x1dz*U({ݮ.@mK-'#54,hh%O4z1/"͌\)& \2hIL' hmĂx(y1fD)5JȑĄe?%@) \!?Ž\UӾ*J%sȷ`Q"CIE'ZȚo `8():o^6WX|e*uԚ q**zfipXyMCl#sRiGkiamC:eYJhkwxBLFiɊ/O' mP>p/SJ E~JTunjp~/["b_d;ڴiXs=J Ʊ`3q"lXAkx,ZKsG!ɑJV}n"XEi%=1=u2ϒ"ZMuSW*+KL;p^auQu";}R 4UjZ2i`&#E C]xdP>HІ|" .!=Vn$%ث%<,2g"넨'D:RJ_c6H䓜Uqiff2kK\zAU7+8U=MeC>d( i5ziL*81 =:,fl (5>iG\WȢXG`ޥJvxuPbO$ڐ%z'h74-nXO "UR1 =c:tgC_Yf%n¢pߘ}&& g6jQ?Upqj Ƈ@$&yMDE{U‡y˨s)d[\ƍ2a\ q10gZ.Tt*Θ,z^2iv=LM<7<LdUVXC QO񤉗i$nVũHɺ/K Ǐ&$x[sg!j9K4P&]Ly#./eL_3#JR`3s>wY[R]Ck KIn=<{$[ 5L5C:T{r<#Ֆub}OErXJR&u`C)N:7m䫅p&DBsi!ׄ@D%F2U҇wvEeiyDDؘ! wpl>rrcTaVEGY˦aXqbZSeڱDp:Q6I=/=Wi瓾Q%fō Qט>_mb/6X5+\TH $PN {0縰-Q|a$mE4<.RL ,2غ;u8*2=7HTxdoI~ ̤0\!+CK6G8d,M. ߓ*-98X?chP\gD%YU¼QUn"4A.B^8EGxA|Y l% 1YGr߬PdpHZ((p"kJ7Z3|͡PV!j8 W=p@9ƚuAmiؿnl \CNLA.VT tDRG>XYDF& %}aeHؤYIgt)׹3`Z2SUD K[ bHNo!*ҎyxF%P<^K=à;mlSpV$uقgM ټ%6,Ld's +C$a 什rk`o{5:Ҵ9B:-ބ~0~UM7F=/-ndMV%.̰$=ߎ[w/f˔$LOōGVQmuz;Mㆄ*1f;3@k{rLb"x0kJ@)3ݮQw7;yk^;:z٥JrR PrEoog#HqZw u ,XLA! KhӜL+`sG?61)m 9yԑ:W`9")F9|fϛ83ECbSGp^J)[])!h d7M*g)m9Z /xn7TB>0+` 7/uR(a’irleDFZ%((#G9/@g!sq1s?*.2#+zx5ΙC6P±Owద0z f0O6 N3Fg@JV O:>]=|%d49$:T6~g ;?c{=1ph$&L 7q %y?YBDEE8T $+O5|Ase'X%N;'˂I2l-R]mCPb10 BX6yphJ-G@3V|a!o[T7VEZ筳e8&kMЭ,}<#MOتR'/LI)sbI,TmEچ"?\ey[6s8ļ}pOa͔;lC"$2 -aM[ ] <dhTP.xSs"xqz]rq96Bc=|+rV~`$h:?ad |ԴqWD[.T 9t@`lߌ\9|(6?IQK:t 9ك&щo! d#O N׈]-^R-e|Zy8nц3LtDDG @k nRBd3%Wlr#"tmuD e85I̶9yA:X0O_F`EdY#((?M Q۳ZjuA(H^'Si<_y/|g٭M %"yZeB1>y.Hѽkw+=9-.&27nkd@fauQD:Vw-)‘;"z+XJk` eQ7EQ=.%v{C)9F$5AayjY tZ/a'Ψ WR'qDŤ(YQбm6"+s+59i^0~M㽚δ^=|n6Ȕ_ hBá`QbńǑezr-Q0!P</pmFE`~cPyE#&Hڸ#Ȳ#٧ fz`XLm+ö9I2zJOHuF ۞2B#9obF-@¸~,zb@QӮvd&tD9W '|<V[}`\~P I[`*H&M=݃TUtKzMPWfȍs)\ :SU7,LwmEad F,>UBo9Kx83dJF=J`ctWċS;Q~Ptozt=R Qj؞gȖl7J֋1c Hl&0 fְ-S +ѽ~T F 46p5Hk[>!NfFkJ:@Dpgx pD,W0M?$dynKnm WxA T/u,jYQhmxHp@D_z0qQ`Nеgj0Y)%W[zh PECIo_֠vWb2dE>r)aF&\Ë$wX׊Tap&MD9L1-1Ѭ#8=Gu jէ1J$>s~ȽS "_/L}z#տTp& ;[uDI8ci3 d~TЖјBRDysN-3+ _1?6(xkymIAm΄~>p4 (x㕘D_)>b0wDξ,l#v@B,#6,B -կH"";0**X `[_ōl0ɋ(K6\;z*_]M O?!B1& -8{;1FOXYKUB7l #IT m+IVCHКNU/rJ/9[  gknF:2[k<Ƒ2\H;EWi ]jZ@zn6^AbY_F/J0<(dU??sXXsDa*N>X@-{5۾=ϾN _%5 wpf,EO vdJr|d)!"ĦPx#͕5r`fEێUANh^.7!OabiҜ^'bP5`PԸ'VĈ$f{y3k7j5":"hؚӛ9C:X IuK&uJ<<!:#W3x8z(o!ȥEh5TQ]-ڐҚTiHDYzPP N vSdq\#3G 3 yygPKjϴMOn4CMM4K@S2R @CPa?Е[a_lnJD FBrc! W,uY$AHO8Gh⌥MMcCO L$DϺVDRoD\y"0/;uNջH\aϜĆHmfI$5K$W}HZ A)覐^T5]ժcqŖپ=r bP)G c*B*3@0wDs;ٖu>C|dZ[D-#-('H  q=.,(:BV$m5]LeU|Q^mP'vj<["m1i$đOJU ndZ¬ct#kKUkSQͰlwcWi/H)6(Ė8yT)c{).~Mhc48Ip1:*04y]˒q,F~.@ អ6lDak=51a"j&P֬eW mlA;+h\ 85[Ot8Gq-q{z4Z=V"ge>>ș T.ȝX%@G9q& 嶪(D G/-̗9x'pq]*SH?f4O@*9sP%5 ؊&L̒P^i6OεnF tв0O`< QįA8UYS?~)$"Y!{oSYYhF+qЬ^Vd)"Ş_@4iq }v8 5˶?;ȓE!&HmE5ge*.1 +r BNFi/B:4!Atnii13.)KVAcW: -Ix%1nyHBZA}] TC8 m2i8\s%#箈欄#NÍV-r*}@aBKj2f jYAq7'FIGOGa:DuL!@2>H&DH O/"IndG&mWQ%oGE^=9[?qRU9[qqP6&Ѝwأ3 ڇO9sF~Ok>d m㰡n#]wBHIDT͇S9w__$ zN&}v}>C7X\0)l^.jYNTn$:~ehBӨ~D~/LH+;I|Y9`cK>6P":4Go"7(>IDW{(6޺W;봷?~qB#0H-O#~o+&|l ϕ5<8gIh`f; C=kd ]lt^fɭ(;ȹ rL^_-1Jvge'9C NN^b(™6r}_?@J /`v&x-q?XTR 0$Jܠ2_J >*6 'RC lAYt+`HjH9n^24Td3ٯkh'OO:d"N<^Q[J} a} tD>#-O;a8 .+ݤa| |U`༤CUӔŬMHn{>┡F[l٭@Hj"XR%QQb"\AD*(5L.t6'I駐!)C^u3x:dUv4;3 TSso:!0d1_8zr]*qqIcM#nVmMRWaK$oy uw 3I ~ <,d6]&;UgC7(j|LҥFԔs!S/kMvzID#ԀyHr,c@?(`>Ac3mmc-B6|Dq`7`hąCP"b*o{ءEmA4wKp1fnq/YtM=p\>6`g`]X# ಶ9j03hk+* D'Xؖ]Mc)g8dObga)m ^5+^J$YTZusu|<~]h"#e JGd:'ڞjhoCg+lAV$d*> #qa4سKQҢD>:ܳX?1K0YJ&u^).+i{ؙ@6'0@H-1Jc\d:c2KOWHI/3 Ͻ;B77 l wR56wS[VuWًv:MO4t}aþ]\,n3f"" l [_gdpi9- \T/׋vg'([Pĩ5=g4'@,F[ܢ|˱ s$$h$3df{<\ N-"A l!G]nC7A7f\}I'PR<qC(bO##L@Fm@гa'2cɷY9ylxTN߉l-)1 Dk%'h3Db+k?%9Qbr4~Aiѹف1%:^"r߄-5)P9P̈!=}11\x9XxdFաx}0" l 2=?q T ą$U-2iJaXt' z#^'4>DLV]ǃ}IBVnl{eM'μ#D~pzU*D2h$9f#2,ˊFJk45ge]wY\_ߌs_$6{-Mco;Ų75-ۧFb=@mk!Y۴Ҋ@d!7ɜPs%vA1X$w %}9Qe[]V:^PGLY c%0pg -9J O /"TqbX%V1d. &%jcO8xT r2 42scd,]Kyb,&I> 7fN ,-)7{m0!q*?"3z;rR#Cd&5QT0_xuEm1=+~4EwI_ hXIԾ9{xzQbi{c5<ɚ* s}W`Vuw,Q-5%H0{DI$:n e\\Bh<N}/y 0R!Ϡay h,/:IM0zhlKZPRY.PpBmaC[[lqm+FDђhH#af^J%ZA. @퐓bua/m,*:+К} CXO:W3G~8Ճ*O ;π Duh ;ps!P cT$o 3m70QRb'5&x'J@'I|.%¦~bEPFb_:zio 8ݯVlZa,#$ymӈLMbd)A'x[o%Ķ> `8#dYvz3<;W/1>j+ictќIg#6Pa5زז-ezaЁCT< K:ކo(RX€bbxT˼3:D+߹e֬pΦ%@]6Ϣ~(ayA$3yv_8C'^<–0[ TDPɏ UBc@ hg[10.)!@S@?l:ఆU ї#`DXz /@UOCarGq0d4s#g2C)K$PXBChCk>PqD#t̀ p{S7`籸'aY+xiu0?@uz[Cdhﴫ3+lI*h gFU]Vex6- kz}i%٭QE64yYak@Y %fgzuwrN2|ZDW4ÜRrkQ99ƵHa0b |:@ץõ>Q4|?" dKaOP&]Jc(oma&r+)zLaRmK~цQ5& bXdfPR/y^H& |E6XBX"jVrLv@̌RIqy.c/i2r\ &x/Ld }c1c'Etmڿ.&9bъ[^P90ڬ9nR=R_6 6 6U97C*GZq?zAP'^UmZ\1#9ې%a̎W3xm qȟ`w1,ޣL|S$:GM"47d]U)F5ǖ@hP]ho {S]MGu" Ane܂&rQÀ#)e P }F1sS|ԥ qOFFH ;h@,/HROoF|hCy,:xXVӁ2ƽ'wG>0:SyD!)pȵoc'wGIOAj~ԏ건? BmTS%Hԓl@]z}W`C })ïN| pVt 5Ѕk>[=UN #/<+^|diF*r%@}IJbG*YiM0W7"eŨЭIoLu`9"Sլ`faNBR4sy#U]Z:[w')5=92(KIRt& } ;ǢM`]ͨ„1l%V>(je?n'#I}'^1퀄 {(h,u=eF+ SS|*'ꐵ'0:fW Q;٥I?M),A`0>h F2} 9›A&#I_@Mt D#]6)uXI=׹q&M#fOg r#:1qV,2aIb]vsuaOG $ M 8[lggsȄ4a%ebY62&rؤSٛdZE$N= U1cli-X;)9avs~vStnb_|dqzzs yÞGjȞ5ҵ6_ɹ%[l7#tw La J1Wץ$vA $SЊ6?٦pj(I$E bg60<\"PU*|>QQ 3b\D]!u$geHQ+skIC7@|8u{8WE )3o;:kk[Ba@D8HnR|[lO`yQjp "ȵ[5#-aKT-O-JII̓#Ns(i7lIK.0W?:iQ|$Pr<9H"L[ (ZV"&{0& 1xZz6kg>gML\)AU#lI <wU1ai"74 H '="1yrY _;G"8An"Dd&$^ůt|Y!K슚A&7FD2]L7Ft@&Yu A 'l ŏ-) lgIej3OCi b񂮣l\)ؑpC@.1*脊db ё|_3+丩-$G#EywCj7Z2`_\@@c*~pK:hgB;ǂHe?2\bd=ZBCuK`YNER2tժ~_m?JMBƨ:d J _C2ǙdДKRfn0Xb`t"C1 $zO`Vf(}9m~gN(J@f0jm3_bJ$ZekmE< /U*&F4 ݺL7,/BD܂q[1)ٺ=f\&A$\@aHplTFe|G2d@ rSy!TᨺRuD"P !h"z+&L77l(QdeeEV[4m v<^g4?2Q(((B#mZ:$`2y<[LȈ`U |!~ ߅ 6b=:1/1;Ñ"(T%|8//ÁN@??3CAmEmⳎ6E$gB*]3EZ D*cSp@IDAT Gt7YUYi3=W)Qo(.uR4tFNoF[haCshGz=tƸL"SB,i5찋іmыFXG ɟh @DJN*;:ȡB)w6?J(`R:` cm%\%vL zjbn2 DQ 0C5}OxSv:_639  mϘ B+ '#b!-校Y+J&Yt3k홂#*<9*a @aUXLDk]&$h("s.'pЏqƘ7~i@~Ssj&`(3"LߟkDrw_})Ҹڿ"V,ym7>BHly1Bi@ۺs[{.f<y=ӛӺksd`VZۣ܅h IKgYmovo?eٜ6Ej:-*4pƒ‘cDK9.R}[]:\TnS@* Dz oVdff=u9sȐ`5L2Տ%'Љ:.Bꨁ8QY>iTi4%6֕8dSe^,촾/Nɹd8+0}8d+?Y9?t|u_ hTp8\ &P{c;Wfoe0qrDFK1CsE21f\Rr7mӽ*޼-rx:A LiOl!%F|oFnMD&)ϷÛ3bRq(i`zɰnP%V7>hFQ6' E򾻫0sI2N9)2>RoGƈaGk!+f;YaCoOk{>L-F.fӈC>@~YM'FcA,;qPYg Zbm?:ԧ1VPPcD0<'W ]ߏ A}3B5鍱^.'g"F65HMt~z?S +66ӚV"ѹV-/-¬.Fi>OXVl,1RV;45"F 4­BS39nk3?uPcnBjd'Kg$0qTkh0E:[c7Xz.M2ƌp%Ҋ4wvtd35o JG4[6 ET+$Sp8IO5Mr6'gJmtÖ Ӱ).RjlF-)$eup"`p4qvE,x8u6}94d-#*%ݵpLy>sT"pg]|΄$XO>~ c?aן6G2J:Qˬlw{g 'iX v,bƦ ٘Ґq#k#f(~mJ1ri&Y H Yd Lcm4pAH5-T';Lpuk-\ĆEY )fsp,.|&QEQ(tZND{oa5vqU ӜQLzhK,;$*dvQwAkspv%W#dR2diA<H"X?)Mi*Gu#' ,VT GG;` _j*# Hd%גfbkMd,Z9??ޝpp1H&W=9%zɝTZ]X̘4f.A%Hh!P9V`ːCj1YUH[U |={BUj]X0c:(dUs6Q@]AumEM&xKF 4|dO;GѲbPԐ[F ^y'9a(pzEbfvz9 ̅&\<%m4`lnM8O#HJO1ث$C{&>#LIX LvEr&,GX:`Jf;K3m:Ν%HۢwT0>J}lT[ƿzl}ULZ^%20pU&:@VK:nRqyw?1t@ouDrE h&67.Sz>G@jmڶ@i WUq ~FNA+ S8ɝ'(P(#f)5r ;25Mi_ #zdB?SRfrD0At{/ȐcrE>_k:wI= +6D&s,|ZcK48U=@s"""ƒ/im\u&Ld,]bz>B;*ɠg2kz临=3:xUDr]RfL{JށPwӾ [fX/dX;D?w?̑xCLd!IӣNѧU[VH+MPqb^8O U$q-C8 <(NC3aͻ5/J L`!9>]}DȈ ` i%Z 0؞D #thg tbc +Ōh8nSy?;l)qLE1֫)gHviGT|wsD.i$ Mm-up=UVD%\ٓÏoYk\L4l"#@3k}usɇsN!j!V >Y,w` H t4=B(P_a9M\AiQ)uD.)&X`KT-{g5"&uEm :7/'t MF=4jH_" KW`9NdBAI!W,Prby5c@J9O\Dq8I%nF8u8bbщ@4(H_)׍2-F]*RP^I&( "Jc~ 㷌alK1"~:…[V4aֽ b%!Kf3T=+N*"ۋ#w[nF.ʞŦ-|&d G^‡HoB ü(Т1ڭnKP϶Y3K4I|xւ>\k2DjaQÙY1]CՊ{kliv#"ҷfֈl47È:z bN N4"Z?y?4RFX[~l>-YNJe Ю<͍Ye!۩԰!4kH5Ij (VD(˒aѳz.SwKLtLaX9jFa`!ѭqeU}v_D>%Ŀ]8!F;'6D$u=`_Y.ab_N ׏{ m(4zR[1:EtvʖbQ:\2Kp$ReL0" w';K|dmgx˹Q.ߞpi%+u{fMn aq7@)rg1U ckd)%;fxDsI,l[ENhMLD&)Ϣ9#p9a1ȫJ/s0+fMJ B88:E)PaS T#qvQIf).#F2WPdt{],˒-9 3 ^?"+ʌ2\jnX+AX9Sх>PPXHh:Aj IGh6kr{%FLwKDFXPskVSZ=FR)T-4zuA]U=w 뚄!XTdV ` q5+bNCpKm³@ٹ# dMLmhȬmZU'PqW RqJWQT=4]chJy}\5pK37z8mmwjL8aScۮV=lɮ !-]Ii3/Q*5 rQa@N*_Z>g{u>={ XS9;rď[}϶DF{٣2|{0mX!$R=+w2m 9IIxTCHb.3$>]=EVԄmM4'*[>]t Rxj @`ok: h!ìL#okgHX'q. 4 MǞpƀ"'y< f >?9K47$SK;b`dK)JZTǃ\pUx@O@Ӫs$F#xnsՍP"ealMDsncyo&܎7qҿ˒,"@2M$)ڀJ:X6нpr1&$\}V _p'^ ɦ6RUǶFTLZ {L#Z0) VgsYiDH;wuFߒ!P{k[AE5F`pK243Zi Vp жvki*%Zvr}+1(|d^$m m=#1@Fh+뛛E(ۗnux%z5uÀ SH56|ZxJe2rq3#0d6urDjBJ5Pt w~YDqJ ڛ*NsCJ 0C̦r v]`ɤYԖg#-?z5鬖Jd>" -S{rEUbMvY\6DMմOhcL'!^Jp"O槇06ڵZU׈^A2S**lu\0 ܫK'!}LO< SwP 6 7%2Z&e:1*?v( ̣~qyVCs'-V,&}_6=$lz낪 uމ5 HpI4- F̔s)ӜЛ‹0 JfKBݷouV< "q4?K@`yڗO੖^}$,ǩ%3٘z7mof0Y+jJ6} 3$iԀ`8X$Gd)KJ bIwYl鍈ٍY}9s*cQ(5n`vw'W6 {^=Raac-wa^g b,mŷ{Nc/}Ҍac̬CgN`嚋N;5ƵJ4Eo&xggʶe4YVǁ&E~=~z9Q čI3έ_ۄi}~k'}34m'[UN2.a 6 ΄g/vhŶ$Œƃ[<ĜŀRf#04޸F.44vqQuG̕[ŔG @Ӊ0/u BޔCrRq9]7Ѥ2%Vrˑ}!D2|ӽG3*wٯm6۱ =ƙ4=2+η|9ڣnD:63)X9F@bVIK>X_F ⑓bAA|tB)|yql۽ؐV*0P imMr^_fږn)Z4jvP6fS7΍-Fy!g#&ʐ2,| R?,2uS׾|L A87?=߀u{a>̑p-cv/P4zD U)/l\JWvkd\ CZD-ѧTh$T&P4Pr0g x6p$'"@ ㌜6r#Xyׅ}xEW$vB$ Ck#%+'W&ϝH$i)sJf.,. ZN S #8ntpuM n:j(l.cC^8"W`ŷX@%ΡU?2 ̧ar1_(z m;aq)UcpI}qAK'esR~*#ço XcQK4`\ߺDQR)qWfxg]yb0S87~Ԉ< bhRLNEO,h+ OPx,25O^]HtcLDb'LKǾ}0^Jtؐ&dƞU` G4h֭,#tylq&#` &c%;WXd2Ƃr1#3sTqt hCm8 &`#d ORA#6GLqA*&Qxn=A[H txYS,h|[gP`T y-H&FEm$$')ߊdH[ZD=i`Q;L$D\4qrTs퉼 .bOH@xz a &f M1O6-a}F׏T6ؕ# %-RN((uH' Ǥ$@&%#+L^yP>fo,. `~L,/BRdXGx (tYo,M|}Xb꜒_p^BnR Yc8i %۷GsZad3ԾQ\@é]EXά6R ^Zu 8#.DD \g=] GVy`8榌>"QtE<-< _dB%}^3{뢀Hto94VڵL T47RrTC]I}]Yv!"r|\04%B{w$Z&AC"3dH_bx9Z/20"[.sb$jℜ  L+U`ӡ,L:upCa(7>l8za+/bS¡h:8(+bB1%iGcu(v)Ize! 1v7ADvP,"g:K [K >$;LUq b_P|3z+hjg>_R;JN2#"_h6N Uk^<ռ7pm j ~mܧS-ygc/lɰˆ11_F7pa/\]f/(} ΢dQNA\]z5i@λhn |k慴Rb g%uL!e..nڀ}G0(Mjhl}d\kgN8+UgPZ3AkHk\"DCnnPy*hCDOv_*x,}3D:|o_rthI 欱aKíl#v,1 kD2:a!̵%/Ӗ @ Ii̢n96 b֎jհJV[e`S_v`-Y_FITݯ,^s:t5~(.E\T8$!! -څ)@DEW0O`Lb`5>=AH< 2>r Q `R:vW"]iSI;޶8}h8GL~DTZPI(3'H:6 ,`&RaU_"^IYk^v@cJ=U7Fna6x&W& dCWzĔ!cvs uS|Opd@`# Q׍J~҃&F| JɔůL( 2 <5,OȄ9HD_kY4$EIdY-p]`q%Zl6N.u f{1ѬFv.ns3'2&n>,cy()c 3r|KЉ)ˋb0usaZT'ro\th\-b~.Yΰ + }otaPۻfM/ yZ ?Tq\]*Hçj ,zxd ^e\ʞ&6} B(|lː.p>VRhzi˯/A[2؍{T^+cøILV47]IHk)v.HG" %'pD! T"eP~0;͋[/c\,v9=9H!H7#[L@ⵃH&24|tgԆ+[4c/Pg ڄ#^m%G0r]eNZؙܐsor|Z1 D@.*B*kI"V^ eRR["|j%<"jOK[91)ٕ FiWEeTcʢ[2 '#^^ Dh뙢[k\nҊPz"gtt@,v:aJ7Ca u@\e]%y@,:Ed o =Q pV;E]/t &$ӟ$# <& ժa8qmVdO~Qɿ\$XnV{)Jq-g:HXϊXi/MmRԇYU%Hzzy9Q:1(5AQs~I)F/@!#0x/VpzCłGdqI9"nU$BJs E"fYA]..%TZ>P:4Ի DEἷw{`M+-dpJOU`TFx;&x{0n a@3qG?"w=:@ rzFg|Xjf;{<+Iw4X;aAcL#Ρz%^=4>j!D1:t~-z:=L:5LMNX$/&h$ ~}fn3 ($H칏VD0Bw(nn2,-cQ"+T6@ʐ+N*tO~H$|Q^cgK#(%ׯ挵"(17rO6/JdmlL̉kg :LU'5єnPƽ ]qm7t\va_FrɡT31N'i7/\ ϏmF]\iA ϑf-FZ 6Q`xmbj]@ K)ՒGAl!)G VstBB՝9LO͑*!fWQ-#WxX%.x֔C-EDָ!6܄,7RE=DC0Tu,N YQLJHQEaseTH3>2S=RI˄z8Lf'`Hp;8@ޅ ! f omvxW6AR%[0hZRxȕb"4Z ֌9N3-Z( yx$'Ɣ-I`PB6xgFyDBO/!lXp#6^){BADB ҋkE 0Z:cuL/FPF bH19 (nbi b(DJu;2Y p = }i '9)82SlM@"0J,Bd0Fφ')- VH /mBStn`,aQdN,,,w(FAXtРX=<6r'g`G3cTd0 Vyi LVE68L$~jخ(g-Ѹч)&k3Ƅ<88XAq xA=m7kQ8>_4 lKjKߌ))Q& J2- (@54"af j/r޻5-:̕x:Yg %fAa 5q ;-+)mЛR ݨI~' !+nU%&w+$zB>6xst[G+AR:`GxպS+1 =>^{5FúuĖE YM@!̨f!d\dpC~ ϣVf@φZ rHoi~d~9P0A ~u~b5 Hd*l0lܲSL;˶4Qsi= e%]6̴z=CUbm=C%>Rܣ;Ǔ@Ӯ?lD J2}H+d;`'@IDAT3#0%*3![t}@`QƤ<:Ѽ}!$W$Gƒb X<'`H ;{P'@tH(Ѥꂬ"b`2 i2DZ}"R9"[TvE@ѧQ6:5Y#|<VElBXVaܼ, d|c=F>2Zez $lqL9! e/!"`rT7Em7if@?#򎪞|^4e6G&E)$Rh(m2Gԯ ZmJDو:#-j&iJ[U%-{P"n3k%QsU!5*Ld b,  Y:hDJ[4! HNAGfFb`2Ah^4%UhsyIjL)SQ_",=@n1-l.(\P!%9=qfh'½<耎[pQjrAVsy=r⽀KdR"MNf"eƠDzsܖ/`Iw'`㭌eʩ7],G}Ä)r],{.׶ݑ 5/pw윺d v@# @V|T#iǴ>rU{/>t62cT!K@ztob-:f$,;xs9.Ԍ0"-.5& y#rkX?S-Ep@VU/WR̢ 4k~]v~nC?tj"]J.Lv ʑ  ! Ztssk6@+A{ r;I\%'\(P_'_t2)?Mq[f]%o}nnEJ°Dxd9P){6Q]LD!.ܳ9RsvIfrŦm%qiHl1k/8nOW fsPSCNġ@>sniےԵ$U_wN e E޲KRpiVg~8sj{ͶO*ePN-$PK߶]"u^:h$Swv!BؿW "Z9\#. ϝ7Ԯ_ 2tmt1ȊR3V3y+.x\D)ٍfQCӚ bhA¦:rdS}c0xͻhrV#4~7\68upuї-ޢSyvb Οx-*zd$gXZEQpmS΁xEMlQ9ڳZ$̀>Y#CoqNzN9Y#nƦ:LG=|#cX0\~'BA#SJLO[,Q;S~j܁A|o |8 K̷uco?*qGwNy3B "x\WfgP( J ./ F^z~8Tl쵸 G+عtqFpti mWlNg`Ţ#q>B eIpLkH +0V8fOA|ys(d3-HXp}\v &T?tHm>&Xl4~ 2#ol?gvcKMZA:˯Q( BtrޘVص\t($:>cm*CpлF̃n_4 l4R(C@C8Yft$1٪iɓԬVV/ZVϗgwm`ۑQ t- Xʷ>P2lZ? =TDED c'5$!LҒEL{!T&rF3|7oA}S92|\eS7]Γu)Sd@NNh|hXn~֯eS*{^x{J֍sZY D@3j.{b'S$&(v9H1+ P+vz:eq6]RYfHCp'̽'˛CRg=k6@ @ le+kR_ko"%l95e(^S+ =!48FBc|hnKG!G{9&aN1ZBJ~Hہuܵ!۫9GF+rkoO?3;(ɠ@.Ü`&d*v`3$1Cv̧5RG=t^('2VԒHELd$ WN&`g%M=R15;(n'3ܶÉX,?x[lN.;y B5hbaDt)#{%MA6=slMv&Z`Rw5]$t$ C\?f3ly&} $37S 0> :{;(~a5R@%3͉fsZ&dQAjHx^C/=-N+ū7E ZO9ESQjW#m=xVp!Nj9+ lmB iԭ4EH6h &2>h؂(x &J "+h"ضKDG-;lC{]g ]{UiǍƷ&Y"tWC%zwr1e0 & 0݄v/|+ij+!tV_>vߎS ɯgܿhP)8^[4Bl'Rfd^omT FrP' /H'H=g\7ȹ(u}S" 'P1UeZuNC't3[8Nu E;Ic{6{ONThM+kޗ̑k9.zCRWK}7(|J $ l'(״o4-HO,èX3 w-k64X,\xJ;4lTH;,#BZTC7W2#+AMrH9rODP4)|~BSVc:bʿ]Zr@nFl;H*ǖ/*2Y]A ]nIAbʎE qPIlJtC2{|%Qi.G""BjңQa$65F-p*P-0cѹhe*;n0\22}`<@ & we3Bs#Mt4lMU|pljQ&UMrrLE#CӄWFCLb-U,Ub_;2KSO mw 6Nmu" Z+p/d26IAk,>NXA iV'XÇ/SGŢU壹]4ҧ,T:/%H"vL79є6KN3ŲX1+Cr59 ΍IB5d (O3j-{A@wޓ4g@ k,;jYڎ2`E=%B.K*Ҽ^Y` )khdO&707Y-ȡ[PEJD OH b¾U|# E<ө$^TNg폴 ϚP4'MPG6LҋQ%A-( Hk% > i @Snd] t/zt*JBxQ@!9IXݗVFRnJU)vj5W낢I?gݮR󑞾9YWmaa,B~/CO3-@3:@ϟ?Z)WwD`bXILh+ωH9l=xP%WE3ĊOt'Y!J9:FW~9MC)"uk[aAX( kkbAOFK z85.j<51?~#ꪩ(%;/BZawLcjŝ×}`qPaCy.4.%b co -(C&L8"jgf4EzV#$=L֥NVM'Q8D bi3rx}p'' !C !0U1t];i]zI.k`}Q&!B0u*W0'pwՀb@N*X)8m^쾄}+u (f>AA vDM"iƩH(Cp V .2?%WteʲUqf~RȰ42JU0yl0ab5s<3U5&b&PX* 4ῩnҢ%'bT)meton60f2a*$Cr 2#; |DsT([ k H/}+sǩF"f9vp ZѪ89ЎS-> c892I'Zhŀ5t"Zi()b./A gE Cd*S"c?r%3j ˡ/T3rAp^<|^к3Ҳ ǐj[oζa{NCr-(IC/Ll,kzh&Ob M,g4P> ީ95Pz 0%2 hC;EWg+'=H6KW2iݦJ%} ď"&є3˚ 3 ,yGQ sY*K#@9QuMjZ)fFK$.P] @yǾi<c\Rdg@u3p4[r4$.JF2MDD+rm{C_'S)wkh&-xO_$@& _pP[DگǸC 2Q&3ً6A&t/Wn-:\>w2Ltv;^__[48l w g5=jx{\Ƈw[#8jE]b#=x*[ ]RѪIYrC pi&'Gc?1D</Zә/v]dek2b0 z>Sm9b9vQꐈ:d\ӽcqHCàF0MO<]P\}7G*Cgt~hk4CrÒP+&u/G ?Z^SHz\1*ÈꥦtĪ$#'db4 @W9V Zl8B6Ê/He 0<st)Ntf: ,L]KfD#ECș̡As&Y*B[K!Nz)BG?.郁GgۍlOx^ܷ/͓8ar^lqi<% C"Hy @ㄹM |J(dm{ )6&Od:^7Q)Լ1`dë9d-"*aP#p}ꠐkFDVȇ5aQdkX sH)ѣg?l No̝ FP.æ87& Bv0z((s#j7x aAv(*4f.-& wm YJ$RBth}> >iPc7*!ME?H27tLp(zx{rٮ;9Ae 'Z [Or? u]+8HmԮؑw%¢F X+xxX`pͷEqid1T^%S:aҀ+}NcPn.;[JlՉC8Ҋza5~J"%iׯ'S`(Egw@dI hq#땄hN8~8슻ϙ,0e۟qnN~9̚J|-ժIIraok&d J{ y}8 ī7 {0n=saeX,GvYR϶$u:/hNJXe;>кRwt#B(#|\ umG}L^/2(&RԚH}z8}7ѓ>J,\j4O24>/.ԣa@:ky~g˕7}ZpvPFX^0G+WwOACOܿP'2ӕE▬`H杸ywꆑ:tp틳-=5ldKfʤ-p0B/wΠ`YH7qx~u =o ZHIxMެ;Z$ֺ-q.,Nk a1eM(CQIjTAD\9wVV99t΀p [4ɢkVVax6!t@ؠil^ z$R_噓W8a{ք~{Q_ipt1s$ >֬``/M.cx#h1rx0JzIQєuGL!xw~<:+pbj[FCQM pgL?l@-ʣObN(х |q/'" @"$UxAJ,sP6I6/'v6OJZ^mxX#q~Fʘ)f 'j#:~WN"5ٲ볷5aJ~QYwPH9`Rx^JN-N6-bo;F./kQW/2^~6\6~@1GGrE!?bݍMEL !g{\7R9E[l?Z{/ +GlBӸkԭo o.;Hq\LI#+K̀g0ֶ]:~CTԫJ'0DLYGN'T T y/rMN<:TOIOd+Ũ$NDC6t kz|uV8S4zy<>>ޝ_\ݛ99bio*Cƈm6).I+`>bWiVJGlGA VȔ:i :c+-uiVjPH  lI 4Hgt $IgH9&JK f C G15D T~DI}[u-Doq)G~$%5 @+e$7`VB[5}6yo' eA^<  RVq\iܞDR)PsQTj]G z3LdFH*u^SMGW,F[bԂΜ0rcm<+Z(>C.؇k@S9jEeY[b܅~eÌx‘ld'. %}C I`u'paƍdoL!jhR8-39"gPVjE52j#[KMBKExF(j8Ʉ 8>ͬl٢O~CJ4p-=4'!IFWU6J Ix=zk_[ .53](N$31myPMb*uzz:ɿӓ#bVd .&Y98é%2{X$Y^Hf Ԋþha:K[08m RV>BfIn<""uYyJ۲[+ڲh;~"ZKԂm[o5 +ڼyT";Qda 2f0fuF)Ti6t /{|HMݡw qbcΠRT>G k~Q D%)`JJqU ? OcmfXl 2oq)\U"x9 ` uP %o]mOVao@@?%r/ iÄ̮&MdTod|E6In$8IpQWSH|wv?VVշ !9jU|cc4Bq]r`DI*o_DB}H&{芯0gE KEXD-Do"PE9+k9kh:nD-C3k1˘DaF0nHj%g/qPl,^QIy['eu^xEAyrȓj$oqٗozK]~"㨁IGtٍNYo.}r;,ej=<\B[cԇּRDkKdf~ur,5)3o= i AtiLK.)o.c@8|o-:p6Klt}D-WtH)_vb+(|Ҏ^e*T K`CPDk^91)\[N#Z%)xZ% _W &F >wll"h7sV#,vh@|<⵮ k'-'5rT30õp "]=5J@}@oVfIgl4t*6~0Z9z9|5g$U8 T LbW+^ i Pq!IU${A{95s[mc$D~.(#jFg퐳-K뙔\x¾ά>s0L]3R,, 0"&ܺ|Ht>";xH,Ҁ5? Vv`# :sZՓzUiz2I.`?_D/u"fFK@ܮޡw~bL+ !JGz[ԹCH lRUdZg= ) |7MhK,be)!NZqݢ+ ,-KAܴZ% ֞/fyBYQ+ڷ(u銊jfh[#-(jWYs]qPA4j3VbN g G@"q\sl;5a]vUC;Vll0II#p g-Nku't ] tiPtfmtF,t6C(⼡A]qDRnvsؐ @m_GډXS0= j)p# c#;M28_Ng,֪3rlhvg!!XDI+ =.^X֊d}  5.9clB!:D|az6ˮ gh:&US bƀ .  9JDJ::/jUҘ,.aξy $G?_9TN4vi,ԯR  zIзh+Gֲ,(Ћ8d<8DI^jLC3zeS} Pˊeѳ"_qϷ05|~ T]gӃ鄌8*$>XIz d~irWB =:fp)^|#:x&=͗W=uA p$-I`&/$HIზY#~稄 DG$5RCj9'0 UVI|n,/C88?g>*3>Yk6B'FZ/愴I L!ӭq@ ltD ,ԯp#+c[Qu h`$FKL1b9؉+Oyd;xU4P.8,('%KIW 0cT щ~jʃF ^*T>CLr``+8x.$51p07t(x(gMى37k252v G9eJ4pDKWB<0E"9dj+ kE) VX[p%O pSw Q]hE>xt|jËeo׺ҿyѤLo.Av>vye-_ܿ EH,/ϰ* A]˭7,YYx9+ZŹE/ٍeF'gζ#I =&9:s3lҐB }ⅲd/J,[hMIz"*H>pd3_aOR|ɺv2X5W9| %ՎOт%u^ (a5(U*r^s/(h_)j բ[Z-T*¡y+ԣ#grYG.)!Ft$ ōV!*kHFٸ\D3 Wf!BYCDU| 1a\˗{'835P͟8F51 UP)KdU]}kl[yk;!ŴLзiΤ[ ɤHs:ԓ93 STKHyR#s  kˡ&I(h|$),3mpե$ yR 0d@QR>P#E2؇(Nk(Ԏ} Wm"ۡ@IDAT))[ UqB@@ 1ׂG|w|玟;ӹ|*cp^_ Bћ 9ɤZ즏.^}i_LÈaS=j# S6)()m!=I2Q 8c2qhJ%]`н{ 5ήVʇvH-4Yh3 %lmYۖv嶯d{C%sWtq"84*2&X&jCc,~!K/"ЀI'4ARhn6Qph3Lc6bYbŞn6 kADOY:6dY nƉ'lCՈZg V_ɝҤ!_Ư8Ю&E~Ɩ8*_G,ءf,sh&mNYF dl F\YԠIbGFtkq)#vi|)y\Gad[A:КRG_6!c1kħ :LA+N:v.*bT'MU810G|ӲFFd $_h"';!  S$T/\X``hh]\ދ(B膣X;ʔ q6)sA _]Ymjq8i Tvx#+Y#˰ER(3 ce $Y3P(e2Z%)M%ESZLw]V=2T:X X[:|+BBV+.q%"f8[}Nj*1@+7sƋ<" YV[Ymi/$L+D0nqّ &q"w"`wl"fnOQ-FhmmvǤItǀd=$p{}U||?TB4CEгT$B<`S+v^Ofvv(tNgN S%ҙ;fh(e?T6qpi"FdLB LlBN#l]2i0ϡV3 d)0U۬xYdb2R-5M5QK,ŬDK6cv<qVU*Q~љ-ܯђA6ȺNOtz'4t:>z] +;vu*\7az{sF[.sOCha4(UƊ>O07͗ҳ7l匙8t7GRVMZiC| b`pP,(@asTc7+JLD(pdriO^tR83۾tv.L_-]Z4D/v8tr:noPQ~0T9~c$7M?㌌aN,Oʝo$x_쁬L'kV{QЙ8>́MߺHv.'7Y:\.HH`WnGicF@CoWmcr&Hg4ٓtIgNؾD9lcnlsn/@#!L6 9'8vwxY.\m9 3;ӻiߎ, V'hbà_t5lkW{>!lN] Z7=/Q~L^99Y|ZR FsV yYmuN ^#O<'H̓ɭIMl+}bƓɇoև>6> ]bYAfpI}Yjn|ƛ(îlۋk# _ Qj,!b$3sOr_lhsTU6`kDy&O-4#Ԉˈd?lgڸWDP[dk"b =.nA 1VDX[9xZDșePgvZ'X8aM9w}!&N%n7) WkA9J8ѝsHǍ.V1E+8Q>ab4#+qO˾~>d*æ`?t6YFƘ^xk+My|@8J9aQ C͂!mwPdߒzU_ 2%)q1KN ,Sq"48Zhdæd c[ 6!W!Np^^=|M +-N}t u\Sj.4Qpb#%6rgi3m7ٮ4!ؐtYSK/FLK 5xLK˭8#IApͰшHիU!@u\ ~!*u8 @ZYRmx&PH' qlt<: V^)3RK*0Q;Qc8A^M֭eو=!Dt4l:8k7,2Kbј=D2_eYB"?%BF4t#[da$Qc'N([7%Cvd/t!.%%p=w 1Swnuag.5VcXvh#*4dUDÅHt&y%E qiLb`H ̴G3 (N~|4fF_iY-X&9!Hv !V [=,GBRnL9%VR$=/(to?z^ co+[ S&"CtkƏYXOYJ8d2:NQ`7I6q$PNUT a;>7mpZ_zTgψG'Yf׳ 22HdT(.RVq*c,@M =̆n="7eaۭaUA҉@,5 WC,~tI4{ߙ9 y=KCp/P>#\ZbJX &ToUb %B2X sCq |I\Vb +\Mڐ*@ # . av:*aZqsɚft.Bլ /LŢqzٷvP@?xL!6XnhO7\LXs3"3M$ 3?Op`Ly%n2¼i1}b)%c8|[k -I V.o(Csפ U:y-bosuiT #bmTROq)y-\̺ǔ,+Z~lg`(U'zY_3(&nW+`[6 lD U7юqUr?F~4k8 1}Gpl/X|f2PiK%0MЗ0;N<-zp@臹;kK483)!@V:Ы"EU.*s4)ı' qi.Ș"KӲ+H)SڢhwF! i TՔkCRC,c0 o1OYF@3>K7:GºG4kFHRA.NUMG3Ic`dβ2Rk(hLٮnةX|G$E~vt)>=^u绎iCÊ`U GR?-,01&5^eiu^l'R@6' ,P_ s*-@-QhյfwFd|A\ÄY6IXV5f@Xse, Nc鄄t0 S/:8Hq=8)`KCFȡ)GzO~m+ˢ(z|>w[G+N5 ̵mj A"L|lQ Tc?lZ&t䃕{R!mGⴳH$H';"]& ol6"O &'ڙœݐ9ӇBe?{=Y|:Q).@E dc0|x`hp<>r xJ&h *q$Lk&FUKNjqd6s?O5k% i%p9F{5J :K5F,b >ܱ%$nJQ~刧T} >WYrez"+c,ƄDFW-:( (QLA.Hg3r-CêzA19Wij%g&Qd䬚v.~?1oduY5HF9 іVB$1^zᄍ^ Afإp- /)XsOh+*?qY;5fiab_AZh<1K D֏J"2y]oW"0 h1Y wv1NcDž)7S`0Ha]uZ鴣9Bh2GdU-ޫnNRAS84}İN"pi No!DrEqo.&Ro"Aec(~A.@pALc$Tc`Qb,sQzL”l _T7zoЪ&idzygؙXn]xR4N@'Z vK,^^v"@C&noKh+)H\D\P>6|O&5T1$'RMH  ~6X)FhEqQU=At35LRpZҽ$چwLqpdf1bVH%9ZN\^%ogqjk0U6[W?XL’j-E4,|¡xm7R ZTiD!S n: ~!;!`Rhzz0HRl]1NfqZF5&R"T,gDed F.HΒ6œ9̋[ Tx z=ZT雑tBu D%]&OC yvt y̬4wLЁ.V?;jm=2)Z'(=FӞX&Xg8Ȁqx)~STȜ -Igrl!5@ V$W4uc0|@;KpE?ΟZ>`ø܅`؃=Y ܨיJ[,Q=9OR갩]Odݣ?=e3-Z6R 4B,?5| ‹*HK%c#TѯeVThZB{VS!(ڬU`k>09iϯ"11Sٍ9ۡ#dY$H$X԰xy FnF\4qTqJV# 8&L&x X5VN|sBK-)->h1z]4GOD K ro`hDҺW(!4ݳFZJ5 wWtYp1KK虔dtظ%--k*`_ 0:&7CQ dos iڭJa'(U3t(!{gB*r8$k*9|Nw5GI@,SW;^ES "B .EL[ft 8'mͣD)k@+`+w]gcBZ32aO*?t;EltJ|GGu==cpٙ1BsO5A(lX';,Lئdȭ5: 3_4sp1U X3[C~Q4ˍm4yTz5o7g>:9 TgHR5v$g~햼ɠ$ebh3Q"X־ѵ#n}y6% `aCP#m4 ZA#Mߧoa=}dW6z@SYؼ3N ԇ K9g%J_ K:}!l Zt$+"g5 ]ď\RZHvا!V!7+ `}Tzz:{KwǒvZ~u1Md!Ѡ600-&WඌIS[v;A CPdk]͈Qט oQ$,A/#̩,Z R");j\Lq\䴶㇎A;P؂.;ܯ,]|vJ5:ŒvS(h4\_ k ܥ3RC]RB]v[(}Mk[VSi6Td3o/YMWD$1rVVӸɺPR"4~jv.S7Vݐ+~d\^+-5uj9w)L;':7Ied+ <9 J^E6v@ɽ&Vv-6^dl"v$zMYI֮PnߟǵUj_B 3ɛ >{z]sl<+{p+ѭHη։ȩ x\O,Y-}H1\v丑ЬE~#ȰZ$ZUv=JZ}>e}Z5EǃbjDܔ΍cH)>2e6Ƅ m2r!CIO ![4{6-_[aF3 Бz$<:e6Dؾ\PK=OZcSğ.~:Jqbjl&O[T,1sF߬+Us@ zl"52\6r K'dH%\/D'H YEjjEϛ_UM/p=_fyU/__W~ډOMkΧ|*rNoO8ۍ\'X|[V)Bӳw3f 㛛DyXKIMn&s9x nغ\R1]n=2yv~q|a1O崹Hb&`c?H) *;"&(BT?njc8 xB@\k f #JȑOˀ\[|UiE:͢%5QHϢ0q1멨]tc$z tl^eoR #b<Ĕ>8Ilͷ+Kg]BG̯iɡO$tChm*#UL321H),:l&ת꺤ԯ.v RkQ1 $ \ jSc<%Z-Bo@x9M OV iy6X^3NC@:n?}z~!y3TB,7 ^NEc̗LD'$J=r333m%Y.L?/Vs%CE!"#zyY  c$O` kSӉtshH$!"Ӏ!XƉdc(K1`@]lf% ˀ)*xKk,"U \/T;F.f5S+脟/yDx#!GtF0tD . ȋ1i#:!(.Z*ٙUra($e"KfkMB̞-wl< ?&MG2AiakxyjXh4 ,q1^Ě`2xvw;RiLUk8u!( \쮑Vb]c}(9sHz# zx~дز=Ȏ5&]0![3T% hk9Y=4%(۴?y_.R z&NBچ!QDSN'bo96R8 I Fҷ_d(YB9:`aje1[2*"Ӧ"Qą 9?8ŢFyIFA 7~|l7ǝAX+}ViNLWAaAXneBڠbrˬX͚#Dw5bH 'i'[H8!Ypr4^m33# 'xhe M $+j"a1*u6U{igEZj|!ȇ<"y6MC3ck X!ȁIST|sVmqٻb- Ql3YJ@1>ܠQ5eҊ6U RH`T plH37"k/c'dG{lqMؒ<}MGA&kD;m/{RTb R鏑%!P\ԕ[PctpmOb=/ᷬR5אHg[ˆgLNT×J~xe:$|MzowYI0@3i"Daa᎟'؋Le |WcG'X0վeM %sr/5 ġ OH鉥;Q_*ؘ+I `2{~?.R f Unķ9Ъ~qj#w|l&~ҷh{MĤRe/p9=8v= 6E{99ȫ$|(Y5HuaSS :, @.EރGSض Ur&=: SYRyCagXЇ\&'\ UNz4T-k?+I0$acqQ#m0Qj"(a2ҬM`39] A,-&2U%[.tfH+GZ&+t}()3 X̃V]!T=w43ZKDJzĺ5`F1scz6O!Lp"gXjS x0Q$@+SJ^l. !Lb: 1MH'8S>n **g鍅7W+zۭ A?ڠfqꏖ#-36tly+P BmGR-(#'j4StjÔnR{yJ*±,X'Ԣ|PHC4T4e @jQskp3&Űg(B0ą!TGt5(~V]^xN# ,Un ' МYׄ9`Q|7$ai|UJ'A7]`U  w j2>#_|(*&X]Vcx5˿<U^/#RPrqkEƼ!CmΌfNJ j=d8F4i(G5ZHDuRiՌҠN"Χ/t[} JBE}Ro]Gť2 @t{+[S#5W/@ Oaj cuM]:2;GLaUB ~-BA_S2FIxdF|]$1"B,U E!eX,8 Zv9 cviQZLDXt[tr$o1,5 ޛ01n`LqmQQI"^&̅ yˀ`u::4d̑tk )̎Lk H$%-jIcGĺ@`%E)z~#\vH'\S!x"|5 v|2*uIzr{{g8i4m5ʶ(/Ϲݴ3nLqD%2}"'Ne PX_ ] 7'Ĺ[aGT֚R#*2Fh+(ːkAu!٩v| Pː$9-$0΅$ll~n+$Y&S_K%P[$ zM$ᒕ vJ1F5hn-#+ʺD <6Ua~(&Kq uM=jC{)9wڶ)oNEh 1m3"{"^@|.cbPU1 Գֱ+gVy2][}85@3)b/PAw2t-RS=3> h5Z"Mk($_k ؓgV-R@ڠL*¼\OڈH1缡rLy>~NbOAx`Ry+"17O6|GsfX Vӷrlzf,TbV1M^O֯Mdjjl2S5T1ѣ@+OGg)Z aasf| 7e2f`R}-ݟ$Ҝ6ΝoUEO:uEq)9zmW_?m0[-/NU7O9&7VL "Z` ?vױ38c{hEYJf H?.pX[pYJ5!: n乑 PJ!࿽kw\7e%(! 5ZcK<@B#֖o8t2J)5RM:3hήyC1 RϙM+3 QDnQ!ħ>VALy$.w>KZ%MAξԫZԣonR\h~"fC f|vӁqv#C +ŰL"4t}K *!rxXXGdF^Y/Y Je&!04%R2 !Вas#o IS7.]@}5 ߼$b{2gH?bYi5EXD-8B@Rc >#}@+#2ۂеjxAn嶍{ R5' pS2H1jh[V 8} 3y`wEmt@FXYvj 4E{14U3Jd6ZXx0&H&}cCfm̧ "^D5M:@IDAT~&m9"hF$3Q A*uɔ()ʎȖ\mI$QmD$13%^VkSiѪc<;`)O2&KJu |PDU":FE%<Ìd~^^LJf얊<>1KFZ 'zM`]]](09 wAKǟi3W!pB) 9r;g Fog;'Va%OӸ?OO Q.)NLB]e0l[?{=۽J:9ʀEnM =KJHf2L Y/2mLiqQyHKЁv៾JJ{[JbQvZ{jHOy($(I5 i5.ދe~̯]MFFdl(3`@,$Q'N=X\)'0AG6F`g C"N~v&4% &_KV$n9;Y,M%5R$ZČ fHЪsDo2 5PˆWVG|ޤf#Xh cY6ғExÙƧ)d#پ{ ڧșVhbՍS? Co`p,֬ L_9++~d 죏\cMv[6"} xE- ]l[uمxS dm)] ^.p/%%-9)cc-XOE*AH-񕄺4t=W Ҳh r :y2n3XBR:^Yߖh&c|?JVNSr#P!9 12`<1lY(ɐ03z{zݤR+1$AD2V2Cʚ{r%$vG72ovǏ_?ӿ f\k&-`1"QTtB)(HGbz\OIq凫;gZ.|VGwn܉lR~H6KSG lwwU_hdcu AU7}T43j]I$ụ7v!3j;.fɽ^ퟗJHDkk6?dw. CfwȌ3`=5{3q$А]pBQ6c%˦Z7c`'gyF$>( Plන k{ېZ|3PCMo[5uc5SNZaV7j <9 O">%F!H~fT(r)fqk]e$c냍ǃ۽ &weFXe/Es~J< (oЛ>lT$i]]oB(Sbޖ~!n\;#KMbB+R ?_mOސdxgI2#QgN]7V,oG( W48~{] 1uh!W@uN JK6rAtU| οV'VvŭIzKfy~;v}*gW ξN"%Ȩ&5)r h#ZFde4l4a}`"n_ 컹X,Fe rE-XS6W1l ^tab8iE~r~HЛIqӞPuL~_ޙ~ϻ.x~T.֋4SA(hp-glIE}Q"vs*fV=nG }}/^}^4ޥu,^]LE]cvkbR[Ej8'edFEh.qGyX44E8pJerJuFtkH㛝5wΖe@x|ߔUflS.*zV.ՊR?|ІoGL掔f8a'x)`4 :f̻JA_3r -)D2gD*qSזh%C4k&.(B Y#ۋ2|pOA)2ёGE(Pm6E-jm_I q/$uVs+`jbwФm-$! hv9j萐QlBǽ铬 ͕ߺ''{)npi;oY`)I;"](Cdk/lI3 #@p3 / ?ʂUĠfkM$`7 #8d\XjV*.it)Q 4Z\ϟl#~Mu@uQɋ)5cF<ÜTqY q2C\Z[0H8M*ۛ FnqfOZlVXƌvL)v) X>a#j$P>ff }1{2 «^Og̶^< gc^C̰Q]AlUx>CaҧiE"Aǻ@氚)=`8^ÊU01_w5-3r}]J#o$wۍKA`O,jˆHf<#LNH`&swdy^~)q$lfHO 6,[ b{QfP J0_~RyjZ_/g󭚭!e G8=YV{^'҄@_f+3c=9'5r'FxK(_Q 8..k6.Ht/30<װo XL;X͐"@@ꮊkh-ӗ(_# Dv(l0|g]^jGq^f_3(ywҵ&yj.ڨq6'Ap=M_:ܔІק'Z5AT@>ob<drf05Ar9=HDGBW"g~Tv;ӃORTbOtq o` -3Ժ~pMOG!#Ll:v%8ݒ>$tzZ5inziP|`RXل]d̐aF\cV E* j42:27[rXj->[r:O.`;z> u ~CJ8 GsZ3V/Gvd2QW*?ytU /oᘇZ%[wL(hjfͲbN59eM,b>#Y{gvuH zL3 (WhRLhw$^>S,~'J%MhX@>| nG54g&CJ %ۜ6M}M$@@mӴfiV3>Xx1NWm!ҹ5|IP9;$S|ѓƮo]v JOߘMАJD~$Dr7T'z/y  O82i1S0mVKH;`U*cjnN0J-DAG$Hb_M`Ԋ- B(&i}:MpqG,!kSs\  F)o*?Z(+pN"N_O0BƏ t*/Dt庎CB{&IjޭXNamcgڂLOÑMYYVPC״0 J% N-O侭q1f/XR<3żtY5*PLR/lucLif")Ɖ9 EB#(i2&BLg#tCmF, $KN׃jE4 U3GA԰ kD.@ y Kϗ"#3ܽ`\Z[ f&9B5LTj2+8Bbxo_-/֕(ef(jNlRƠqv;-8}~liFz#I~L`W, jVo&@'Ś&(hpFc%Z*`eb8j>ySF:BuBuj(qVG֙(0G\p TȷX=RT tLP z~& ۽2>-(>䮷6 2a#( 0+jbPDk}\yQ5\ 1TcG׻i(꛷-. X"F'XYTffdCMOT촨 `v }f̄Bb=DmQ4Tr#^@ uIu&jdQRSzq:< 8专1G+B!ZbMfNQ$RF`lv^:/n+0YQ0Y :F=:Eb hإO=2tDB\ h:QBH*Pll_Qa$t|jp!5o[z'g0W&pQE*J ZN%?$:x#Tn+wNfќN$0dNA@{QsYQ/s P ˋfd. aXY]73nH<#7eYMnX!CYC뎺Ab*@\婝s`ʁzOhzGLD6yQ:5 S39܂F BF.x8RJkKJ5$Il%( cIg-cT{*L:&$"-@&,U`eMɧ qv /p_}&]j^*ӡ"ၪh[X\ KӚt!/Ƃ갩ODNb;WQ4c6'$ 8dɇج0GLp'Έ mJ@\4JП(WѨc5ilOMF~Sb%2#:Mj!@uS3in?K2]1M|1A.o7GL?iq}5ѭQ;a9 dLy1VpfLEn$ܿ(Oklkfg-kOTۊ:m3dde T3\۬?Kf`.S?x#*ɞ&Q)}\&70l5Ta ~"UL'j_ǟ㰱"%:3RCLFs #F:dctҏPT[dG ?hÌj\baKHd"6`؝焒,j )m,Z=JpU9!ИVf%t|bnTgz [&z>6d^}F^ }o'ցJF4~2ǀ&&Uu 4pu@jJ/jXC(ƫMYCuG&cv$/m.6&:%D9g~K&jlbm}K[D\`v}6`h |~B_*, 0To@Ā= EFN!zxtlg2xӆ"`N蝩O9Z3\ry՟% Arl:Ar+SBP!@9|s RȧyOkL|lGnJ:J*@5M,gC FhAl|6-[ h'9(W]D[q HC`Q.>FEue,^_-%GRIXNaI֠Xk&@O,jU.{<+.z@XΏ+̤A/?AZlPf֝r?t`ĞqB" %^];,]snS~ ),vʞdhӨtS bY,#]nP*,g`̏߬U>oNofl8pJES!Y$!=9m[[s(zcHHtpNfOd'-`W ǾbPvv|iscqa+ _f8GHI\y,8nb93+k9^x$ x8=K0H cbEۥ~: M J).v.3MEH9V4fQ|IVE ͩ*jexc@F1e@X jCELW B2;R3p8Pk& _~|}8?OFQpaEǶ#j3v[T:L" L./r;pQ֫Yr3vX[Jޓ yiX5Z\x "q`9DXH(A%\_x}?9߾?ĭD@GPtM`(FEJ iiq 2vbl'7TψJDž?W5 ho8c3 2}6z} Y~g[?!09R0и^u9-.װq= gepTyW}[S+,*-X z֝Ab} }FWڮER!p GlTzв+ٶ0_ƗeˤOgضApB 懿, a4>Dc64-lh&a$ 1r%ˤ ֕*N$4FW7n OeZteR!(LӫmH =#< !;]nb~;ZPO/wCt@ σnl^d$igB:^Y?A7g,KxܯxFL$6mP."N,KDd3:I')>Ms?$au|RAG|[V+>;`4M#ȄjMb!d rrIzXLZ4 7ɇY2k{{$1pK2@$(A}6'E]0q:zo~+:uClIf ḇEx#Lm$0JPTFx(Yr5= J,)i*'mr_`4=¯f#q9ƉHƊY;Er-ńۏ30$"oAću^a+HxiC/h(է+Nt3MLj-+pEWZF':Lj_%!lP]Y2URD[ RʚnZ7Z “#!~>,lB׀YG㧹\=CDΠhpq>d/&_QC+wSayW7'"N'Ƃ%r jH~B@0}RO @E\/{n;!= z%]_Hi@ HQDyl`G x dpH[b!w!p3p,1!V^w\_C4Bm1Xq8Ω} I(TR%E!l?N0ɭz74>,Id84A" $b9:.̄F'L* I\J,jb0a,{+̪vOs. Hٝ Pƅj:I~IN=r 8h0I4=.A Xt6ZFը^knw3:W;ZJƵDZ$߭ U}F)0کSG+#`% :օ%]g{A\ikIR(bπ$i 5ki|hq% |Qsb jiɬ%ѦpPLZV'Uo$[ @6#N^.s*tۼfOJ_/VqI2cl1 DeQ"qP% hXM3ٍ3 Q)Ev/!qinf@_4j&=&H>#ktYN|MәO|ú2HWUԋ;@2G|׊!Vča^ 4sϤ*jkҝfN-21 s?hhXq;R TpU@&GuHFU6QRkɃ[#ßOI VOa=n0 6 AS4jZwH)RͶ9q4^@EnbwG&޺] Tx?)#g=U'8%SNj\P:K%M4O~ȐfvM}Քpl.}(0% V(tjMwb7@WXZaor7jC@ck]J2!=>bzNkL|섞R/f`N6֊$ np*&c1DC[amk1'Mpv{#-U|nu9+д@\[8luXU<(2L-Z**x4L[zE/(.F.hb}x0/~R;Jv2kH` !-3zaP1 kNp3ԥ`W Ti2P#C&}$f8%%W^kVb.<NI"bR$DiABȵN ~s.fpYN`fVQ 9ys"?VP!Lf,X-OEQ?傔q)%eHFu6}0r3 YRB,H <yDW0PȆsoFSI';T>"|;I#T$YYt;B u]5p8h$9~Q t[hzL҇!5Pc/MhVGZH{&#h )3:DawɊ*LMr).no0~L,ҘUVZɜH m.";teR@B /*.l ?E7EUq㽼-^s(@hRPPB=;oDHe&44CxЧ 9"l.8 O֋f|F9XHc2qB#XeRlZ@k$%;E 9 Mu%x[*#pXKq]]t?t]K\gX% KݡP䐘;<2dDQ@,@QӶln%]Q <w d CeL kuOv׫_-`J8³h*Ћ"d ^0#_K<YZ0Rb]W½(LP{TA(?[pO]okBW"ZgsG-G2U?7ga,8\ƾ6$rCGraRw<1;vS%M$8N43ۊչ֫[C9@!NrPnC@ez OkVdWp/7͂0Dp@(̣8K<ʾ_*,X g~jV<4FMU(԰ɝd[L)jyO59b8xb|0A AG< YӐaTЈWhuϔ ^kՠ/EDuA\2gSAlaPT6BĀp1C6ɬ;Kw1cU yO[k2j|[4R9)B'vFkk剺 \ @nWjħ hbd-Tgh!Qt#ZvÏՁjdThSsz=Ay""ǣ|6Lʐ|l1'3 S[261 Q!%r<;u{|F[pJkXf{zHE؟iCd6IZj 1§1@5hVX -c7dY!|B,C7uW~( |QF5C/ɡ{ Ύ|\55WMv`;?Zh5G~|+ڏƑ?;!ِ[xoR=f x=ahFPbBoeG ܭX]g' d>%pɼm""HzSIaD#`MLd<Ѱ `:F^#zWoLC^lo"|lVDq_4͙.nfGkYv ӌ{8"c$DWL)4I`jP$0*aP<0\ǡB猠de|ڮ`ƿWXUzqzH nb:a>Mte/gpu (L*!:ʥpҧh$0ZPE@;as8!cXj2l9pgNMt vOB= b+GTu2 ]ͧfB Q {\f3{1) /@K!>,ǭaPћgb$V ?JPɼf;Ni-Kch@I^h8vg`vKa@ɈQiyD!Xk:8khEuV9be_.( q=dH|I6I$uM42ʓ'efA2k|$1xXT`wMu5}`ԕ!{M%ǏvmБاe7G\ .G{U ܬTܢ5)wSǭgpHeYOϴ!daJ"rmt9I,hJ@IDATZ]s-2#JU#TI wO:H]/wP}]HdBkX42cu`օ5.Syٸ'RE~F1$SRg QXn3gN Yͥp:e)(|$1Zsm} p+̮ky*L9H;8[2-9t|odF\kɺz3ds729X`i!X}JjD@g' ʕ\x92ƁWgAQ 9hլ!*<\O* :}QYTL4*% |h0ӌ%MU#5zF@܊5>-GoWF0Z%E (E R mv+ת+5cxCtE1֤ڷǺrj :Y&I WBY,4Y#]yw@;p+EAwȑPM2+K1[kZ]6Y,Fcz7xhLtD27xKcb: _AT^-w:(o9!Y/`ͫ^}rGFrx31H" nmRDK0;$ԣ5`lX0,-jD386 y^$O4 ؅&"g}"aXR\&p g僅/ۣeTavZWqY s 1bhuoYKQ51 z*Q^R@:U3 rX?yKR(GN^LE{ MK3Վrau=:lDg6`gnx6,7ɊWڇ Q_iآಪNĤv̑ lBΙ)XfMƈ~]m81-eikA#P6ٖ{59D "|=ГQPbw永ϏMw^<Ŷחǿ2[7k/o?m3vTB8EФjwl_J5m^.=瘀O\tggmDKjwc4 7 BS#]nO6Mv15μ㱪%@ɓmM"k ȓ$=l7\rZoօ Ґ4%ζʤfyi;a>ݣʐvuQq8ʢi")#k1vB7:cZMYM C|j̈́zN!n/e7aZJ]:w ="+p 3ed/o_Į͉F#HplA2†A=){m1C؝͐a&"ףc !3idv,97:  dʵ~ =־3Hqr֑+L Pz"&ͣkhvGg ^gS`ݷe"\ڍ낺͒١_;ztD gLHJm>U>oiRQ#V i ؙw:Id1I֌G;| tۃ$ȊqBThw 9ixʜG7 teI \ghʩB.F'DAwa]ҘSX)~}S=oŎXoCcvζ~TVTtYofYtA NI겫w}P1 ՍJrC{Ӑ7y PFt]e!(e1ZrRYrdq>cJ-ECEJT=5-@4 .]ML\YD஗HPh1^EZ5+JڭE;^W)ľz<*%n&0NZu9^͛mX=d<1z"LI)q6);V"g4.Avtb \"وp EUN#v8B\Ll2 4(BB[ڔ0Q:f/w`k L 1]`=OU&\KvU v# ~}GolH# .)`Qo#6.4 vjjpH@a<ш&(e'܃t[,VUܱB绸E7QKm`Mýd = 2ŁXͅ}㎾rJukeLޠrbv)Gb%oҥ! WxB (cay)u{gՄA 罘PۏG 7m +:[B$c%%,ivPQM$eᣬ uwFMͧXiEʡW`uǵy}sR, @*Kn$kmV?ϛG9ƃ!8#Q:|+NjNQږmWY\w0 B(D )U`>TJQ|FKlTPr*"]H3t6JX4Baw@62Fh55}Ҡ-M͈uye Z/Ũ-CԎ|^=/][ϕo ;I :œ7rށƯ&muaVc4\\;|sL5Ehm}f1g&' +`y;y &NGra}4^??quy?Lo2 viFz  %ˆ7v<`N$KprqZ e꽗kebr)#rh7 6N0>̻&5V9^bI2 R!b&QUU*bRC;ӓI"A<-c\nWL<˚.yd8j!:'Lybkki_cg&[`PD`eFu}N赐ZS?$0cBL+UV&92HE\i)Uk@Yvj;cT^,)?<^ ؎)qmoT{Mo`8BS4Jva25HN Sĕ6'B(JTF[IsV^2Ǚο KBxI2>IDϮ" n"B4o{OVX݊J OU]~ƒk8EJ&rbn~YoOݑ3 4OCm8Iv|FH7z{8 ",%1Mw} J5#lc$} p^UI)c#Q"eXŗrɝۏI0WcR`MF;F12)zj/~79 %74%g)z#bNbyt*Z|^SX~) -qܩ'5y7 ڣrmPi@$*Z p(>國GD"ԣ9a -z9m`1gwM9tpXR; Zyk~ˇ]) !6JB =ENZcNC nV9a5̐C l#Q `QGS'`cI`,_5f~*Al-g*$!~x+/B%^wWH,̇)z' "HO\aIGO뇯A? 0#5IhIoͻA8(o!\ؼ__GM.2LJ>xKF3@W O}ݛ듰AMlEjF2ƑV$ym&<tn%~-8qƹt4{rֆC 4Xu#K 1|Mb:T>9#2,/L-s U=EAewG}ÑɹN 9RpuqrTTAh*L7MNv{>u*T_>C1iK"nIa,%CP 錭uAB2LRa 2_=a87IŔn=Z5li肶'+HwHS231}:ωE3wdFzsUV\(J".Ar x>\4P~(7U&D!rҘF0C2|xGxZ qIMb(5yͼggIP=VYKx+P$g}`c88i'd\ ! Է[%E`uB$/"^.`O cP~-xnOO?~xtu 7 :ݤX+GrŊyS&B֙&[q`['CZ/fUM>7$b G۲hOJ9U⪆ߙ ~nZeIS 8_iFto *tф i>" 0@lsBed+*-z1 vji&N 2ыJq>).Owj9+b.a,'-L奸zi+v˙`RZcu?>vY"m"FrHmݥmYLiJ.P#SkMHYGQ5+~N~]VY2 -5ã;u,‹EMnNEwuYx:$-8Wp/{xȨs3so%uT̈.i`Y?nǙ?RXt!3֖~`qqzyN sb7=A/ݱAcB6$b ,/R, ,nc\k4,K:,FV9 4Jf^4k('-D>6D ;O7H(2O(ɾmt=F2N)W8tً[ 6GnKc*<5P#<4=&}X>}4A̯xuڮRQOyVL$tf@JZCb]c*/05]`I匶OYF.FaP)Yh=\0\| J[T~=*bղb7IG;?idNX w?KyU\t> zidveS$-&!=5PAG92c̆Y4Yi`tvp1GGg >2Ա=C}t;z =#ˠu dr_gvcCGԣE`3V%M\ t"=ucT6+^6ھSk(=Zܮ&6zOrMu0(әiC@ǫXZlF$QHі?'kz|w3,; qU)KM&rTh~ik?'6XF>D&q㷝Íz1sؗPČqH" Kgši)BHL_vru8fpsdeaii.dP6&+Fʽ Qܷ_Uύ~݂̀ի SE%nRNdI;.9|DI1*8Ȅ-(^{Ҡ5U5*5jnhDžu Ժ9AA\L,mȵ2M"0! ˲ 1f 2 MlI<8JKxJ I(h#@} ٪H4G-݄[=ȸ,QI;8\'pq*\hOxЋ cmnQqkQali`_!`5 V*ʰKxl S[l/D3Km;}Jx`,Γy/&A=j꒱w?D6CJa]6XmXZrL zD&Y@->Px2k|z`RDuLٹCt2juј>c 0QG+ "E$LZardT'2+|Wg3 8h4tIj99κWK™I 6<$3H=t' TUZ]',&E6mmF ŞmL3Vm /!R dC]׮i\%:Obv[ Z+"Yg:#OC󸦯D<dX\YƉZ*(^┟a4lu=7? += - q}k&Z25ۺYQO0BL!m}AX~}-XP-K/mO`$;2Cd`r~x"Z%9g>=^i'~7f=`;ơno{}؟?Q7yy3e))|lu'my/&N[CDL#\gf{j I'LuEU~V*_3ZP9*VeGuz:03uv>&4nWI_p 3/mm BVAKꉂsK$;ifoEpL녎c312ӯiMsY(@܏$9HX Aj?i/1G,N8BLťXj1VYo_ X<:a>M 6*a(y` OM~q򸣺_?8=a(E7r]~jۦ-yQ6{HbyojtvpA)G-=>V|ZDߋ `gV-&. {!XC 0yY>1CPӞӓsN<[^UlV:z@')˨p"0:+!uUꐬ)xRxUwbv܆ࡈXs6F "G!?1H Yv6w ~@{E4+f}(j~2E2\'qR@o<XBV9"E܍F'3dDi>->#O|i0AM Ͳtײz~Ө J>7.c0L Ӱ )msB"p[Ui\W {`E=\'bОP7^$;L:k B8 M[ ]Tfؖ,nkP6xt46FiDkHVkv4 Ho7p` QMPCņ^X?4,Lt!䠍q[&ZYֶ=CƆ[V0ܡiax|#>6ezk0`x|pXh͢-Өͣb `@J"ҠnfPJMA m[2JWJ}ø|LxN[ MZB50-@`,\Y i)QZR"p:h赜F_P"YERC54ȌD̴eӐ-BP B̉c &҄b7CWK(<<6o?خ_XfJ=ԅ8Æd;6OUZJ7q*wAsE%4_ǭA~x'A* A';r]`7~8 YASyZ@-@)d'{Q/ʱ 4. j{)>CY^\BiU%ؓLfj3$P g XeƲu/]:Xp0`$a55Lj{JJCfg79[`:5lU¸Ѯ1M[ 9Z] z5+4[鑔0r? t-D"^&+hGb =AE ]J»y|QwM"՛#v#D>N6lJ9vϔ-a-"jXԢ"c:JDupD/JLA. >Hr  #qء؟4Zc$[y=EvK=iί?5GӗG8rDަ',G[(y2 Y-<M{_V9^8X}x$!XL)(GuP$P!h 1:2w\Vb嚓)12Ej:%CDZn-Sk͐Ĕ`͈H5)kk:p+,[ukȠBČFь*Mr|9%4r' G<(CJs9eBk7:P˭҄VV5A_ђUdj~X2blxiv<CBe`UyMB[fxYH4]vB*ڋYD|2H1DZ&vpW )B?̣|K&Nb(Xii-]HW-f!/1֐FݓW ϡ`VGSA~4:8%0>n]=(*9 JWђ$Ʀe~+kS֕G=D#K$Ňn_I87aGP5\I5+7耆\[<slT*&5Nq.}yvtc1]BW0a,v-vޡs"h1!{-vFfs;@|Ͻe P.:f= _fb_<^A|hYAӰNY8w |-8کlTĒصZ%`P1f;3C) EYd!m*U%p1`&j HB?#Aջ\KHt1%N2ah92~A@!9;1"{`YulzƲC*kg{g({3!+EP-ducMɂ@΅A4 qfz4eX9&g2S._tӎeQ?R# "< B?O689TU18G-廧FG?bąj[or3\lՊ/$ S,y UHR[sN62%EcwɄR鳻,i5 vQ EjpDph8GM`DI3p:C̩nq혖ϩ:J٫kζ",h2@8#u}N‚eޒfף-Ӊ/̢p==[ONLjŅ (XB[J#kŝK'v?=sӅdNlv2%,-)h_KGs˜xuJ:M"=e$Z٢ #z8C p =RmC~ḧWtlq$~8 <;m;mP*GY+xQ*@BB2v+qiT]F*WS8 )VHbhcSqV?gJ^jnSj6YtV_} w<zjSyP.2VV(`z)_rvoʓePRN7DӸn6ɸD#}TL$d%w rZW1(Ircaqժ,zN Gt8=94{5ڤʰC;O"YRaVVk#7a}4+0(!T^n'jlm"ЏV9%<9C?-{qSa^,KmlJ]/xY\ H@#EրpYn^e7)^J Yeg;kkX?;'S;Y5(, ;ى=A"Vv(XSr* 9R`KtQքq&' V&9uupջcshJP®T(K/ _ uIF=N"m,X( )3>oHG^PK3[g7ƙ:~$Zk&fa˶y~QY9sw|"u>Z cR%r:,;RXcUg |P-T%Cmq GQ` Ey4?j=70pa!@d3~R ,#(&$Ibo$Ĵ3 EcЫL2V'p~w[ q)iZze(e][B)6xj%Ɇ"d(,-Z~`N$HH4hZ0UMuּTKuh,.j#Eatb1T!»Nt!vuY=ָOb $7Zٓ=.%t;i ټcu&:,Zt*a=c`lO x1;JZ_P:r7he +iE@IDATt&tٴuU>C#%̑"Il]Y! `6F 3^3[ o##zQ oRA0kۆ0JJ V%V/vH L$_J=\]QGςktR3{e[QɏV"d%ʜ. lxTm 2/XYYr0`&݇>\%l}z-N&"IꠑPIRlHdCؒXkl֝;0* a`JFT#8H&:@OƱKd&"{-2y#F>NG9 {øLR}6х`N+d!< Mm ڴ;<7Ea\LD$r50OQ ?Q/=̗b]#$+4XH%'sU4Z/$q]?ʖbiXZaX1˱P+-2ajz%U 0:7u#E7WKFws 2{cM_ ]ttAnIrA,}&^ )s X?.fv{K #x ,Д~QtCOkw$|0Mj3cD g 9*6+$XE~ Ͷk}`U@*HOE;$VBq9E|aLPH Ǿ Si5HeEp]Q>4ZO\8O"3?z_YEf fm/"pe< ޚL "sR=z* 0{smɰpo8jv WUABL5||=C K5 3tCn(sFP\ţ8 " >cs kX <߹8ӎ! `Zߊ, S1ҶL$g^he4yR @ZbA<4:wj :^{*}lb2/G鴮$fj>.[V 6s##}iҧWXTt? HƴQ n=;GQBx!YQ>KYcH~b |dl(FleGZ/ێsXt| ) ;CNmxq@Ӊ~2Z2%ؔs"l|{Da=ZP4´pb17v^I% a"׍=(qNyLh4$9JXDjun0|!o3X eyvrOP_=tb;mbY{ I%XBvuڿe6Ӛ zN|0xTI,;$d[-\i: HM~@c, ]k-ìdsTzsb{q,!3:qOƚ]֡ڦbFZNLtZ3}fKE}0<ڼHH*CN0 iD+2!Y|j5.5H0]dLR̉F6D&Rג;z\r*mR@Y`.ۙ*hO3DkIR2O'c:Hʔ7s=4jzԶ OuC!ƅP&m'~xnw&'0B%R˘noC$ QҶ[)VB`2GdqHIyX^ O7URxЙ3v "x:dEpU00,١㟟N~vl"T,ls&7RӉeHDs& %?_=\]^?@I4'pEN;|*FlQ0% &jG4 &˲t^vńINt]'8&)BZqqZjJayuւf::ľV//y%Q[>8BI/5q-@tMیbƊ'hLUjbTN0m^:"Z0 oZFOX%ZJ~_b 6+uwF ,k^{Pd͌d_.h#t N?(/Q2Ah1=f'>nCRՑMxQGsj,=I%@6%Թ#/8PͺIwOב/4 "B2>5Td @ s%gB"'+e# g]EПp`!?%RsbpP Ae84!6jA+z~>=dNGB'LDG(}U16@DA}IXb R<2=^ MK؊sy/v0Onsu0܎0qFf*d&k.O( 3V4WG%Z;7qa: BuRYn%>ٙRATdif-:GB*-Xi6S)@ r²dH@:*hl_=ynE*" EJQsW") (MB g;%jJzC2p:c;ocb&S[TU;woV޽9U^KLF])b(<)Bo7PM"HZ8>s#1ܨ4[ЯWjWr_JD0JD#uu/"\fxٟj]u`)(6"k7:۞0ゃ?;#!CA}vSgaț3>cG"$_O20bⷿE:ʙqwnX iݙ4,ߎɗtl‚[|X@0A2T7ʹ_y9DzHiuЬ1#B L4&""XPQJ#c`WǚbOk٘nhDXU_`PNgw`_dDIPVNBopWÚb9W(l.*Fy+})捪ON 40Et˧ߴص$hMz"QD{E#lԍb>F'E]PUq&!~+jUtը!{3|שo¨T$n, 7F k!ZZ|~;↲|mR_Lus3k3OFTXe&,|,is ۑP5ϵLcHE~ #f{i΀LYVt!rPa}؞ ƙEj).2#-tqjQ@cj.:aś(!T?sEeo`WZcT f ˡ!;YR󟄮mñrKWf}D(P_sC UW3T;j8HB w^St7B}K yQ <03$ 5!L"[ZrAfR`ZwfD!O<b oo >q>F3 aF u > H],k:WLG`Nv PL y v$}joK(rq Q`߃SCQ=%tj>/`©+,˰ʅvPw8ixY=䡂 i5 mCRaX$hPպa/%]G(sDr<Яhs\ϰm?4rVS=B j!L7(<*v̾bg38$t".KKOhQ.rv~C&0kRJKs =t;6*FIӸP1) p& c%"U|} Gt}U,Ui ܪaDz5Y-q:lQ΀vE2#g2?>S\ LS6q8d")ܞD%,XFcn(TVn^ۓCi`8Ȭ\WЋc1%2k]&2a.lLhJMj&5RHH.$:CC(b1lp YPcHX1va*~s%Ra( td4-l>)H:CZI{,(R\zݶc( ,#? ] { xhlZ)E Zh"d$,BDdr$ɒiyS D~F3eVKQGS" (zoROY *t2H#oYW,|,"4;>)7)w>W[P=Tt4E`R]E&}S:RHKv:VC[GÛ rK0yRe>dn3F/WvBɋD- ,d_9\5} x4җb HI, |aS^"zB[//Jh*vtuTRɰc^ w$J*|,. Zc;0dB%M ]0xK' ءe^YNJ|zF)}P}tYV fak Nk7k`DC: o ;uʰN#_^X@(61X ;A^ܰV'3\O僆tpՄz{0`Rw,^f&4#nĭA'`s83Pjq1zsEe" %rx\AKjFp0+<۶I ZKi >ANfoLd4縐NXum&3D"*;X;H%5|9AWjvb<}Q1B4,cJjE#LG(akҷòP܈u>.#Ԥ2 )2 iDB]; '1#؃ Q=]{f"A)Gd" 8gYx։4ܳUF̚YFRD-0t2U D2%]..wjU%jF%T_V+u]ք vF+E^ "/hE(ffld=sn,2,Z1u.<"khYbgkRVn]G>S5䏲d+( X6B}ʢnqdXuz"C%GXy8X92G(5Ĥ=<c2Lm{YX:* 3 [Lcn'0E 2J B3[W~!$0&1ʈ"Σ!b49kN;2CZ֘~Hj(A4tsfr g0rћ}Hٹ,-n='pJNi+<ɵ/\և/`+)Tua1ێ@Uú0QχcG?ACěX>֫z)zOzmэ] 1#M:iqUdi\Es-aEC0F783F3-mNGH 1;&ث$nA$Éj|qa%OO\oT}*I3 ~+i7ZY)(`ze=dFJXu!5Y Dhq,e*S"*Q?Z5ICL4D[mָ:JY`3F,C[`o 7vp@z i>/$,/5c~Ѡb`dW'Fq_9̅ytʚdErsnR l}"!MXwgF|py-\_\"IbsKh6S,_!YZЗ _gNǎPi-ZL爢TўeJRhV/.F?F]9'XZlO# `k1{P 0bDʄ ;gdm<#1s2ClՋ㻨P;$ :W\xj &b{l;Pr5s4L06Cqffg؇ {D9+XPir%L}:9XqE8~҈ ?% mEƈ|tHzj6Eo[p!qr$3X2WQK.)B.[1Չm"}VV %2 QRSָH /V:}j_+V't8.c{ FFaiHV|\6(FmE"U?ەYYtI)d<.6Xv1DF24i+%QWe bb| NPxޮ (qRE/ORcTޫ|n\wX$k\=X ʖV-r]2#DxЛzJ$-#CzWu 6{PԱ>bvKܮZ _"[}B@?Sս-p~9(*n]_Ԣ!+Z!ؠ'SX3f)IZTZ@+"(F#0N m d8O2Z 4F6pTU shp_I hMhԋҚQ`QЮHR2#V:# 9֔#2%]iTA͆ ]lD䨚|lABH|8o!>T-RO+W$6ρf.F3ڀT`dS=h! 4;FEV7ꎈ ' !+c?Z$Eʫ|N 3ǢiIZ,+6yIb%-=Y :E2|]v|M5Gk Lftmh fRmcR< '1[I, Z0L4p5=3~sVI^ߌvJÚCF"H@E!vIMvϸ̕᫜XR.+m6dYꬠ]+&uWAvgQ6f@GKz̸'QaPTyt1u;=RB(38?1/Q :bDիöehJ ƠZ]V*a?IXn:O$1КaNJ{XO@ {߽_6Aho_*D:mHP '*Ѣ='\'x L9weves&,mX3ՑU ^b#}۷& I#_6j61q{`DATUg-/,z χ%Ti5M"lp-goqE6ha"\ou\It̞!n2|7lG:R #?gSɥ55) 2F$L#.FIzG5+Xj`$xEhQ@ =W٣V 'oRpH#H> Y*Y:pMfbb+ܦG 5(vZL$j!ѯ:cx&I6m2B~#tkB{hՐm q$:_D'@/vy4cw۔:aa/Z#m6Ft6WHl]8Hd-;yT'hSO<90ۀMQD1w>z+fzd6 iR\v13qp8CiFr] 4S)jV?ձ owmwnآIxg8ֆn$vɽ*OOa|8OGҦ" >}s-J&1V"yveנŒBrh® '`! 5-\߾Q3iݾ";wgqhsKWY5  SJ qb嚜J_T}B4AXkkU8DOI<-,y:*TĎ/H7e?QiO] }jJzZ:,͚ f5~BmrqNmo-2]!g`qsz4P*lƣ+'y/م4J QqҢtK ӽ BM-.-3[4j*ب:zds3V.>vᏝK7F ܓ;ńꪾ9b:An665Pkŗx "jF NRTC%RV#q m&Db' xvr, r¡揍ɗ ?mBBi$`<<>GJ9|!88o~<791[읽#?D a \b5k>ZB!\.&%ߙTj̄/d{znM n.v)k4SO:Hуe> ϳ{ebT> *P:/IcQ't -51"QjƄx>snxVs$漺KsPMt!8(ճB1ȭPPDFty;=; w<:;z?*>HM< 0t@%=+6þ0he5XM=f:wohg'a[ 0غʞ.&Xں OhQ@1옶P$G',aNF-yAcε㡴|R=! ف,ЭIi~&^//=u/*Аؔ0M9ᖳ2mMa}#PH6.4n-m9UA]?G?/~< /^& ¬eN/ℑ=57K~7/;3֛Cx~ Co#~|ţ0/+#C6Z)gTjB[B>Ka H¬;ڃ$2/AEBN L< M Xѫ6y_e_z|*u@ݽ/,$E V>DaS iv4h? )?( h$nbSCVc" {)ĩ$]\ =PكsAVj@'H/FKUqt`իVwFp^nђH \|_a,P r> jB+FBDm#ذcԨ &ha9 =Q6pʣ)\ 0LHztah-ĿZܦֈKc?rfsq 8 )i^Z/V4f J6[[O-sCb~O=& b--}.] )%Ę?(jhhia-u֓FM&2 6+H`TûGD NQ^ z 5j-CuZoq^k+5tWs^0( m6,صmi똠tM"Ky-GBRI?ԥuYbj wFqȏqqTq i>rBہ;?M'rVqaY"B9(>9ٰn(f4>'GFou\RL="n 6OjeL"Tcв#DI=AW^JCw'T{0\Cm. '/K M`@)):C In"]G:V&0[:۵ԗf&"A#RR{5LY#e7MjOet]c1Uݷ];S|6]@vu˻N+Bnӽ[`qCaI J1a @T+UcihU)"xF5䐾/5 ;ghA(2{jky!X5NFmXotM'!ղY`ݚc@S e2XaS؈VhMcKUf -"`V-%b\C~kg(]Q^< l!y<>CTvrnjU#j[6EgH b!.B5}:*}>ruŖƆ>+XP‡J޾PsbzC}  KQ?jO-bu}N&̣` X5$o$D3ķۏ-jHy[KS[zՀ?]dhjV72n7 o̷0ZцVʑխ=&= Y̚޸0`A]9bIcsЕ !7@H"C6 OCpB,Ȩs&uUr\JNf!sK0d {PA=DIbǾ\r7O+ }d_!?c`dXG^܄K7v"[W5}Rr} -dWeɔ(0*$z !}Fʴ-Q6f UKviȝw=F2X}ӕ2 L-A)%#'. {&C wb< (A֏8Xr9Ch>5sXOtcv&C%Dx~sQ0R4\;Se:!o][#8fA a5frG%! JDVf:%BlT|.7䷻Z3ք=$VL- +T޴$@bIʾ)R}`0.RɥN5%'x0w$gC2{Zθʻ" џG lX+|C0f_ZWD0_`p/sF 6~_IQfSi ԌsuTGF5I c@>HO氣@J`$C 9{%QH s5Hik? yJCydži.myHO;O%KځCbEb!2QNS̲'qx#W _s |8>jj6nid;S0@IDATRR4pVy:A |`?)Bh@r:k'3@gȗwJY PͲ'RoQ 7/Gr^[$eְe`4QK,n(ª)0F 6Eٸ[_&Ol#m]R"bd]>*߫5Y:iḭ>gx:x&v9jS7шLQsx 'x0 f|m{|l* tĕ(š qJY 8[ yIt͇ԡ(d$Ҟd`PlΚU\ExođBdBؾ]u<2A{q9S#6Ϳ2 (|5"HRCĔg[vY<,}ê q'M6w saCV ɖ-F7yv"@LiЏA!}`QEE- L#Dz$bKƛL Y+О(a`t2ܸmM̸3,:V3M!: 8U ɘ!/n2#GIY@|nB5mo|8>'Bvf1@4_U JjF<5~GWk:ʰъ1;|l4_?+ MR؈1~Ag. PpTЕ\V)~fQ4v0lfO{FbL-cAkz0Q3&3NSL4zCeb5ܨ "Gq<`>YdxA-af^*PepֈT4rMcGKaZ x(B2,BCRX > =Di "h[$jG0nG PݔɃNNS9dM`U@g?}MfX _@SҢ@b&J t:yl#k's+GK0X$wvR:hZtЋÿ|8vG( P$!ŧNTG3ŧ& OtW uT"#gn$ .3") pqv݆ u%k[|ƫkcKb DPg*O26cPFX!GPb45$iϬf +k$Ԩrpx1VuCaTT PcƶoMLP1 ~4Fn{Ԃ35N,eR<`eЛcO$TQY "֘ehGcRe@IƜ8v6E4 tmݔ0;>_%!qۻJHttc:tx')v2FC%ݑR&2tuFSCvtRU/ݦbEf2r\Xӛoߦ쏧JߐٙgI]p4f Ev Q"PHDb;j6΢w@%+R ;FU=Ӧ.S X󚬩 x 8´ӄ`^Jk5 Qn`(:f<N3!A'V|wk}] +Rv1l ,t.U zfhp0>!<1!Pl4U8ΎO-ͤ'G"e6#&lqHaőb4xAំ dv ~]#uO/"oNA.>ܗ%B4_OP3A**R2':ݼ6̼I\d!a||p2`\!M; :s!ltT"1gt>8bd`ozLq8mt)>X4t($SfI~tp0Ĭjb̌Fޠ  FOm0`eY$5&Y'm|N9gAyM0|7AI}Ro 7=ekJGk/eeTUؑFR-q':BM ^}&n< .B!ƞ ʓ:*>=/#o&Ev%}%ɱIOh#_LTո'T6@GNd\}HZP|++!7-! FlK=& !ք.+ y@Qɝ]x ~~%@IlKƌ W簈zv>|Bvh;W!_ wa)8yB|b{ M7 ^JgF0yYvGJ4}zm&)L~GffVlAHTL uowp(RHk1|lqf[x,||y}^w!uFWx#EH>eFLl?LWD\١č0a%ę/`.~]VMv?mwѯHqMBop v`DӃ$ ]孻ЂrKɑ4Z|Zy&lw>t:Tx{.@k˘1"y{Ƞpe}ظ^^)@*gE ? WČi`Ln~HdHRD)ϷWe?>ܐ͹ 'k' F')VΒ$&?s||(\Ӻ߯4H|z2yؿ\,*ѧvҺ$Ɠ5dRO8)xQܶamÀ~ 'Arbfu%_կ d \!̥料D8 T0Y@N̮'bpt?yz[ n?U /e~_\N'ukε A Ӊ&7)=3`Rf!ɑEr(jcn!eC-o^0ac!"\[_#?fє#M&n.bQ?l ?ksGWd7 ^@v:ogl谈y' $' [n0f? t8${zZG藋$hIG:kwnoDI@{O-'=_' #($}"!{w=әdh9/Hiɛ7ڿ~@"r~z~q]zCOv:k{܆GηjJ\rjYa Z;4AzѪϏ7Za1#!R/3>[vG,E,P `ɳ@2e+3n6@ɗ%iֶK촎i25g+ؘ , !%=O1cb%58M63Ag$j Y  X,*Ynl[ l̀23UK&л4F(h$cGjRlc9 0•֍*j4t@4"}JudžkIΣySHFi % Y RkԂ kPrI# % E$g8ڨlij|K.JL EәaJe=:7sɿH~Ox@M طH1h6EUZ "D,[( Z4Jb:wd$F5dg72lVa[bV! I-~ >XP ?'u fN8c-(@/Œ_&QYv%Erq ;I ¡sT j"ǧ2}FČMtN!pY_feL޺=9 ކ/{g|bJ_i[NӪb7C| l&CՋ# q4fO)đ*+P&.?v0R`["6P$:pː*S ߓ>њ2^:r 'x*UOS>]lDD͸ lk+w,j9VA$wud$\z#JGm`+YUIU2ZTSGd&B]5 dWce=uV{j !{LKɠ*O2&5KI .cLgx(Lҋ/%Ȯ ŏ X5, ÀM+i}Ge?c`eiy# @@td M8|xy-R#eVP QoBԅC ?Y0P_U:i0f~<=Z"ψ^*?!5L[j8ӯKE;hHc j ղV1s8#0(HNKybhbJfC1aT^6ōT͌XU"gL< i< Յ=`vw-W~^RB^88قƓ#̵z)Q(zt{*2Lމ1 ɼw {؈M[t4 6:%>-~[n|?9:.,#t~렼-pw7u$k*$gMTfcb[[EBBm!9SB؏"Hlthɦ-"ڦ3^ bwB=rLvZ$l7.&A)\hk'úN"Q}*5 e*O 8~(i:Ɋom"646ZN=*fTa0只H/ iQ4HpRU|u9+#PpGrwB ZI5ڪEF⤱䱁0@8P}7 @DNG'~ ڰ#"Bg&:US!+X ^=KđV(-7XS,zo5p0dGPhƍ,r*BXE1J+~$-G{wԈ )Z;-5eϨT4yh4Xo۵C;5uw%#^^Qr0#H(8:bh6KbGleH qs| Bb^*>?ޤ0`/;nrU{`$qTE͚0vʺGؖʎCUΑ_z |$f(*b㽌EhM\Q+k.0@V+0d2fϾ[^88&y,qilǫ%eq;%Ϗ)໵OogЍfX"J Hg_h|@RW[R+&ٰoC:{+\ޡ_^FHK-M+Il~TOV9BLa?6{ aQzٵ]jQBFXr^EcL&z~)`?Z0Z_f171ca&p'4XGզԖnŌ{JŽ !lxJlA GyG -rR=SD(mƜt0 uzN&҉+MdzAo0P͸CFLts5NLIC!OknIc)/mmNˆrv!G@ȑ/?=#%\VomhLinbf) .[2jVH} x8bߨwKAſ{XD׊!h)pgI <㠹#jCk嫉L)Ȱ RiSa!FaeX[mŋ]F'\AuXttE959.@4xuB$b `ՁMK]3:Li,N["9kdz=E'/qjA*wy" ˼>'Go !#+ _"ˁZ`F aTi~u{b"[C\5uB7f5KXr(;f>5B䥻UlH%#F:@&oj`4FdsE8 1obki`N 휫&ekIDo$DQwmP*E%Bl~̶D2ΑB4^ӝ8P- vg9߁--RvtPp9-POAO=֗]uvz:*E -b8/l6cR50`\ h6#Ki ٞ<96bSsQytPV JU Iַ,j"UН73x@It~ {,m>DہBЂ(acGP~LuV//CWFEJ}:˦qwF n$] iQy[KH~F/S̗$=[\%@21irLU(HbP({'$W.=s׏ /Xji,;i-T338 `f,WXJ<"L{(&Q# qʀ~g7b Z{,K L-닒*fiE>g\3cO"b lˮ ON=dB%h7h {ZDv6eh3W˔+ t4>Mr,!5S2Ey0!"nܶ2pȕ,jGO,Yy_ô'QwH'z)U?nSK@< F;FWH(*#nӝ ]ʌsCZ۝oډ x ~ {S'R[ A𙻂@)$u®| Ӏ߲c;*$nQ`2v81"$>L=~ebݤ<6DaD好6MIj&s}G`dED&5IkS۲ xl5X"xmN:Sx X 4j5~hwx.ϦT\ d:j#KR"\ASDs9ԟP`ʩC rr\"%M!WT$k^+ RF6M:dãKvs{IߵKPrZa pt P[ʪ:Zث`3LoHt}aοT.oRS A% B||&"QH%0>\%Üjl1]xEͶ2ӫd6'ye c;V/~!xO+]C ??_pnD/?\~ #Hhcpl%rht0ǗUZfT q0yOB=&=Dª˚.f%A1%J[!tFCKwS V% T8O^xg9L}?o?iB,hDPJj+|U=Sg)gH~f=h&fa۠@߸4(Q4,S&D#HQl;c7-Pxui E=u FHq)@W3%n腚p?]B ' ?R5|tl1 /S rLV]x@h#guBl$m 6;q{:/RdՆ?d3up=HbQQh җOOfxKNOm+dN x&xvtF(pkk<+0..M}7Eq6ټ8J_O?bf:Ruzz==??]ʩAXBSoj{ېA/̳` dTQL͠Nl)ru&tgro.J=eb ?̋ WVy(#5CW0oXǢh5k'TSbT)֚^bg7-c9|}u5M7>=U\qر{ySL*T?5GNrة/W@},BX좗b"yE _pT^^[ceGX)Z{' bbOgg a[L䉃HpX-6[ڌERvM d:[FZ-8)ea0vLIIqL:f͍ \StZcsvBw6H?vN9$t1JTOaPæ~AThh)p5T$v`ՙB14V]_He5yxz`u1; %xӋ@"7!hǜ~4o_ / z+O+.(&"o-NOp*vDulzhS=i7Dى X1>ʟXw("}gghF֤'7^թ%Ls,"5i<5[e 6Ϥ3Ȉ)Gѭ_ 4eCAV2SHP|u"ĬTMR kuCS`QUFpU^NC*A>XNfnD?bqjlW3#;1>.kɞloRKR+ (~vH`UĈ{YL [YѠFXjj? bJ!ZМ /x$r9jU][~ȥ2Hk_jV9o;HȒѥ`…*+u Xr4-tlO{#TO*`UqB%?ip没'0\/D,0&KqcK*VY2zSQĴ0GbnI| /h\~}573 \$clZLaA&YD7q蜀%/E}ݠh̤9+->:YmJc YՓOb!|w7[ҵXq6炀{C.?ʉñ͋7bb7i0H8mei{T"wR_z{?0&c|@HX۔6:!ք&HK`D)U2#tY%_`[X˿/Jg'&IR.r->*q#AMyt "L>ukO}H]~:CϜ:1`@p|;<{K}mL'Ȇ7fD-M iM>{fG/XhZ4YR]׿tחaǺ\TjƔQہ5_&a^j*!TFSZ.?ΥRp-&7iNt9hpN*cs#Yv ${  25(y򩳤Pi+[?] tRN |LuCG^ B$XXXl}OZo' _b?Ls`[U|>HoF4M kػ i 6ZY 7 p B$'nAigmn5-_UxSE+0cCǒY#-Y:W@Сs;^Zj8K_G"  eAjrIB&Zd֑gX LE1Z`AI/k']T>ѨA9XUl*E_ݖC,V)ydZ՟ɪyH4> lIsh 1>t>"74mr񭡳`_b6+)Rm LS!BL[ôyMG˨3` &E qh%v .1K?'&?,j*Yi'(\T9; 6ޥW Kώc~ь.c `#‧l.k$51o$'ItoPEIP)L"p4!P0K|$],3Ξh7 Q0X٧zAu$kf(SOtwF(-h )AfSZݱ\@ qs+\F2y.EۋcgMYq_aڝr%ò=×GvJ-mz:%LdO(M<% ~"~f1 r1[)j0U֣;R܄*Jȯ4fGͺ!^ZNgMJw 2=hTiϐzMC=(QgsdbIIk[ߢ~bbAʿf},I|i3 oHh2?kx Є. ě=oc/$#[5G *_k" r0}kE81@?68laM6 H5f-7~lm }̘R`L43$_M9óyL,*!އfcyjB>˜~1DzM'n$|-᝕qO.hِ= Y#k' ҥO(H*HyL$A0 S5WaqNJU$3SU;HY@IDAT:?W `O seݲMAl0d{ =%c=p-;&p0K]'J&DД8ĊK :!dAО7@ut F9iߑcXkǶʜ!.H:2HbUsNb҆D&E{ֆ)J[UNG( h7aH%s@Nhs*Dɑ]K1t=yrfЗ8 Bi"ڋXـs 'iـDB >HMq'}l+aalYF^,d%N 3A&1 83>o:ՉD7A|GxY"f ߾7śe϶y(V X*G|8P@'^P}msm} ڛLR:3= \M[GHs“?Oz_JB(X_ }(0 xI#hu!1N;`KlYʢV`I^BDe(qM:H5q=ΗTáķ$!΅,@h|;ξ"_mЬ a5R,aZ`'E'ĢW@׆ЭZ %*#n8͸mxהAj# E|41cY 1!۔C,lGz2 Y8%FH_lMY,UEx䷉!19<䘰q "*nZ.l!:t_]DF}Nݭ{Qn#3LRIw@Ry;Ud׶x=&- n4q&:cd`=`ed uL\}n1bcRj3:TpU3mbJAV<ZU7}+c(&Y44_7 -C =b1F{b0:fA4aD6FII1,Ѣf,h'06D`M PB l͌_bD=r2?@10I2+d>"@fJ7Jm[倬f oҔ*3@Ig۸Bvg\)Su ?8,!+ܪ?q|rȪS6Gü+$%Fv óH/ 2>EPn,b9cȓh&pn)$xƠYh_5) 1yCǦsRP  Ԥ~ j M:L ,Αo? Qt]}|fv=",vY=`) ^x򦤮7G4֫8ó Rǝ}}A5LW{M=ue/y%y+և&]SV c9@CB9Cht14<,h><ġe &x=U\~K8FmtKZƟv$xePIIJAA= <#I,)ѲY.{kQ fH2Wiy0G4ɷKyM4JciO3IR>_Ht$=ǂt!]؂s1ބ8Ӏ,n-nA/ym -c'uȡisD7a콺Ydyv> 2%@lAo+>hp[2Ffh쵒8!~ Fex<ėF U>_^)_^2Tzչ2=..j!#yNzieakǷo&uZS: ixN[]Q6.^vKpHȯ5wؽWd+XcDӗYu5moXU`IpM pfc@J`*?Y+<5@0z飊 R/NuOU~ݦgBGgcFƇ6Bs9՟ϏMf}H,^V"4G8{d*r@RL*/&7>ΐ5:rn'EV%k@lX]X>Sr|5k-IN;b+; =&d&,UOH>,&'bSQšZ5|'s5K'68uKn&I$)k%]L.Jĉ^ۭo8rlsӎ M~oC qT~tr *HS˼"ƓX2 2`& L3 $As8̆Xn mt(==S^sY'qJx^^wdM\yxHM Q@yu։lgR1|A:8BKe34.s+qM| 2~@݉;<;tTcoqN:WNAwf>n\(lshE)C 1(d,+8Y y })!SҒ$X!!3[z;p;J*U;0q}Ё"*f Tl^S i'"3&gJɰu mM}Qן?. 41򶾶Hk!˰wZfNS1aȭ)QKKJEg0FEꉞ3Zw2yKteAY? XӠE)z&l{lm Ԛ# NC*a @A#ױCJ^V;TE h+H), 5QFrW} ZPX|-AG'FM*ѠK "0}Gptڥ̱f %% U,3liӾtnOyk[gڤ- O| wOӦ0ǟ hLE%܋J;9$À^HZk%(A|RğE콓;lYb] KS52D*iKOې0A#I 0^]Y1ww'P# R.xz]sv^E6Ȭ:cU:WlE1E Lƻ%)_BvSG2VEꚠܰul XcIT.a¶ " *t+n`rojfQ8( -d?y~R2QPNY LMkY:9n 53GňRNkX &2d01Y讧i_P/"rKS "@2oUrq$HJJNT{8dT\Yߡ߾ $­9'lֱF˘g_Jӂe__gxVxe-JHC[>p{R0T4DNܓ"8sB8XuqMaS\|Ƀ;m M"}0qw~E$4s|CֱJnmQ/s{8Dp(eB=/qtCi"mFmHtY"J2i "O/gxk&:+QК1A8SB#3u% W:L.Q %)y6Zd*{Df]"C&=7@Ody_3eKRzq pBCe]߮⺖I$5# E1)..sk/쥷0 b-0ȯ s5 ?d(|Dzp)XK7<.z 8`z)?3T`5L]^"McaYQnϰei A-0xk.]QoC~E,[x#w$kA/$Pdy X9#8?oֲ+t#u[rݺh::hst\y*'ҪbE Hu 3 M&!hPj հ5~ Hk>h$| 5ymbR =6mZ~1nOdX *DJZ6XF, &H39`Z)e ,<: ?MB3]WSIT#ppb+mf£ Ě&aIe8)IL NBP~r*cGqbG%l&pkO9dSP夗wbqB V/OVN,]yq}]- ,4Ӆq){  ƞCOy\΍IAV0'ٔ\y.dOk|̡q!s?s4]똙 +r`WL*hc&4Nhxhʁ9| j:e4Sd.4fic@њ/RlP2sn d?<կu-]ujMz \E7֗Ie#9ٲ9RW6? kn t]yD߷vfH" :5m Ʃ5tB ZLPE"/ Hy>RnK#| -rl,BD0jG)kGD\ RշA kmoʎ\d$P^Vг*<*']ʻa8H_KשCxr}.CVW1,c&,h&.,du"lKT& B&"H#ט5gLJ!ZjDztT4YD$"E =Cq4AI` t ,rb EJF¤!8tX?b({Ua?W v  ˺pN 17#1| t0QL]-d4nE :(T?Y!XߘߜwhdC9U,QR)f V6#d|"I_0`XLCqonVX'e-ŀDsr 30%MFq0vLH8 'T;6nɨ߱NcޤߣG4HDU ~ED.dt$ ΣBv$^_^ H0ɩ@Oɧrw]ɔԬNY*i6Y` W3#*=K7~puq;t eqWI\8 8ܴA"љHWp+8#!ﱴ?Rl1V]bM z $B 7)s_B#^➮WLfiIGu7@NֈĎ7D2)"EUVp^yy"yѾ%]BIs3kܒBhMbBo_ΏdSZ~;?2SgZV@< G ݊jEhybaԹ86Hc켙h?Vkj&}CN|@<fW][I T4-%hmgDCaQ#͉{K@"+3D@" <ai 1owoه[И6.*nZfvqfngbI5;\[D"󌃑;Y?g)nBA(|_d21IIUa {s1j E^#zԭၮNie2Xe8ۥV"o΅k\< EύKa㖱d5c`y; \l[HCq`Fey3B"]vFwSk-.:n.Q@X2x^YS7,YRlDcA3pE-֠n@ Mrh .͍nsC=C`-(:y3] n /U _3 {qDoIJ8yX4Z1bCpobd@LKބ azpnMfc 9Ι6.  AWT,9JȒ X?flx7/,Q,dOA= ]wb)xtZ`&e>'" 5pq3_a$gIzpRnljP@ƷM:&ZQU)7Y0Ai\ _Ч~ rlfFehAC }x7p&ky ף(s>4T+L|6Ys}۳DǻP!TlB wGu_, B!!Fĥ Y4$/7ti9,[{bd;mJ( 6 10BE$uEoMllΥ%nF\!BՖ&$ mQA~2Z A@\e q6ő?.llM5 fRV?!D8ƚW^LPH sr֧`;6H[4K47X-.Eo84$:0 ۪Q3C$ `uR@"5Ltr$/j\m}f:^M &rT+[""l6?̭g^)aN& Bne8E_@5x fo G`'!($o9 %8+I `43;!7C 78Au]ɬepfvDvε3 3g e{:ruuv7v' tE/Ř@m1c|ow;)HqG;QL\P9xldgT[7 f}4tOblTEp ,lB?h&%`ۜL;[@!-c UNׇ̖WDgPLsh;+rkp)!:7"zf^k&"ÕɕN$DW|QfXBlyG!a y͸}C1p<<>t\ly } Y4!(zmKcbI3I71f A҈r9ԊP< ֿB7 "y!(#g1^M@x0I<I WaVHE3E w1&^@L LPnexb㮖CZ34Ï~b]hzP16i@/5n]Di["!m:i-2;dXb3@^(e*J|q'+nղMk \*Vg>b21rDF7T ֳSS{:=ZC ȕqnA$6%bፅǬ6hQ,Se%[v&K3d[G=ey]ͺz ~49vT;E{<=e?)rBoQ=`l>,,8t{r_1o ],f #3աD)1l`N:azthTƈJ Fhݠ% ў&,=̔y:qpq!um x{ߝD"cY*usͯǪuFut"-XT$J: ;Z'9~_MGTӇ]bDh8xμ @Uiq㻧kf?<}n12Tm"9!hĪ-/v1͠V`&i)y I⧢R{8&M_PBTAj/EpkJy q=me_^U:Ec=6DŽ>GSf8JLc{S^;(B A59h^ݪ PK:A(T)U3t *9 P҄ N=㲏(4a|s~@vWOc 쾿lZ;fPCRy1i/ĺrfCdu߲ X |1$;p2ƯAnWz UO9cXx&@_@&ju7_Gsۆmj<9fӇ޴:Va1s>̷:Ij1-N&; ɂKQ3<$?y%HVz R>33J  iQJK]=-wDRRo?T+3cB/kmtuWKY{Qc`%x* 2UU,c31{܅&H3Y@B`VX(HHmh,*RzEnj ~.Lw`SPBVa-.0#\:!D5nl{]@FSfWZ/@ 0( Tّ)GX\?v=03SmG0﷋"cR܉LLbT:sl\1oQӬ TiA R3*˓7rH9BDإAufKCd2HD@'Nq b]t DA@Kæ^a05YNG.)'Vʓ447i S!v" hR"\HߔFik, a+Q*)RF"jԱOgf.x;6Ĝ.hgТzg*GK3CևMؓꗂ4dJRʅdev Q(I9E&D)XsF1tv C}Q+XP?WhuHQٝ,ed!]hWս{3Irahj8n@2i9 Ʈ<2,f#)|:;$vJ ffUO-XLGOʚ-7vDhj1gUʵ)?;)=U x6q߉w0tzD0q>5;!ej"%b4^z]1c¿4J08$ "U7U/,yBd 783,}ŵ|5R`)%aQs DJ6%7=D""HPPsRA ȋrCOb{mWMgDy`VQ3MS]NI28* o2COzvy ,]csl[ʥ`>bB,<ęi@zah}) kqgb3%h$ $άlaU.GzŲ,GRPc&3:AR7Klh0 "zhkr@ qo0]iGq Ly_HPw9k7~2ZXCt3tL @f&P7v/F=^T .v;' VQ&`yk$j(AsX=i2|r9B_G?SSV*0|_;,>TH$!hnj9\w/ #;6`v@%<01-qTl9i!R]_>ˆ ٬QLBzN%=,#vt~ipg!O[i=9xTNb,\-f w<#1GC"đ6Q)N݊æ1r!uP# 2'YaaЍ#'*YREdi6 2dDB7NC&0{X$ sżsCً0B"3nB/g$0$FNw(AYb"&iñ9}4[q!/@K͢wY/h<7xd B¤Q93J7@ `ե;C! b1j-`^w0]-]n1Pn2 ;w҉@D"Zh 3~c #N\ d=҂4 t k\š"J:pa8L:S靤&c}J1)ԆI%ExmO]#/nya/i 2T~Fs+1,3ɜDY02&q U㈢?|Fܞ p2‚&D63R)]0+hjъV.&x>ao-=6 qH R36`dNsQ>zUCiy/1n?G{ MMd=ujY(Y7R`M7.'_My@pՓ\/Hdtݖ*3u') k%+6bH)/(&8A-Ef\z)೵icyۆ0/IQ-8ІyASup.j>IDw_?qєRܠW= t?"g qX|7aQ}ÿ _TרS06; 1Dw)z~',EX{9p+Dݜ? ҥ[0eb($ (_PR.JKv'Ɇ8鞣L6jz8 \`17."{@aa%ĮKeOAI;OGb; , -(E0q12*;e+4:C *4ZT6Cri-J_]!DGVQf ~wEHHtrY@fN- \- e4$cy^nĂ ?"nP@>7@'k &"h2Iۖ Yns<h<(od+ &hYN|DJ\cB8ԅh;[O(=y镭)dѿ|M }m9;L[97QQ`9U 3)n|Vs+Ä,q{(\u>I{Jtea=izl0Y^Tcnʲb,6+EQJig]lFKu͚ɂ|r2z+J=y?E/iNURJF@(2PHIEEeR cK}@DV53CKv^N5cF$>6vy03 y̷fmǴ > :IV yC~:]oV{h-ȥfF 䛮xȍ,\ `&H=E&]2Not$B0zՔ] @%qQQxeȘLݕ#iw# 3`'" Yz KG{j$(a>&?Nڋq1s?Z(:]+IPhj3Qi|<j<1S.*6;I?8mt86ow4g%zB4LM kYQNL֨wSIE/v"ҟxkeQOtrmWEO%B*s{Ē>x#8B&+MeB7)L73rwҫ}Z#2$Xq A29 ͈јGv/V$+:HM@ixNh 5i)nQ+TΌx1QuVȞk Sz.;ϴGdKcYL&OU +w!"1'|uMߦHv.5 t95dh?a@*:m)k }4C#@2|O #r0g.49tjNMݫh*V*a[ % {U:MC3sRg"1b@wx"C3Â+h{ѨZkֺOf isi v斍O/ů8ke"lJn0(:RMdLt䞤ZN1!J3)1Jwf'Ԡh_G;/:;s 1;P-N˛ ŎZFt#˕lKoJ_.@k<=%(=ӱ@RI6d@~9 TQ*TH ^003* @i3AR&@H\snEj&'slUU3(Mn5! C,TctLUlT7I,a|ۢa| pyеɟ=0WW,;Mg~#E~28}Zw)-Iv3<e]F4T.1 Ga'GF4޵@ca+5B/Sd@\5L 5;ZMžw|\N*&ˑdHocygU3f+RSI546a1:v XK&. ,FA!B7ha3t"$jw8*,-2V#瓌Oz!P2JƝ#ޒό /|XR`oI[Әf q"nKQH8LlnLmjd+S ?i)9 ` o"d Z}<*C^Go=FxUO }k-p%=<;|B,_!i0,N8Erio"Ӕ7+Ǒ,AkZش,DY?|$ Shx8G,}H zI4 GWt1B]6e+0ӭTsގo|_[8}IW{4I[gLW@@,!n9"Zȅs۔Rp|L*8hG<P,ը\߻7WN5sLS-)KBe2137ĶxD99a+'ĿN62 3Aj  HD5l"mE)h{`Nqp S ۬!6f,߸ S܅ZGJT=@#!t%KYJ>Εk]E=2 5&!n?EO8ChLi2;_sx)gI릆3#zZ3QHҍatiX,x$BAԶMb L-B|a913DR9>Qm]h(VO`i><65¤_,Y #X٪4G p_h!ot&:J,HV%J|^;+OBu1N/'9$>+O=)]tۛm12;d[`4Q/I[C5Ma)36 w$OѥX߃$7K{%fG3e:Љ2 9Xo[Kk7xg4 PM#*ffb]=eS*IN^cAXlK; WM. Hm!'ԫC~{lJ0Jxa:#H)oKRhU1m,Lڽd)x8c< 69iIrA HT׭likQ-͓Ḫ𗨣}jIbA =, v4NE,GBcG} 7 tS8T|%0__O6 B'a7B4%IbJq? ͳw@L_ ˓ 72K{BE$ 7B`ȷK@QT Dvhق~M4[}/O :yXU HDf:w"UsR-HրWԵG6OkccJB)j2#S|O6V}E1mS?>7bb!ko/x\Hi->{GwcGO8Ac'卑qxI` 뎾|ZƜ&z0capt {Htn6dPrPŹ?YY_@0ME4:-] )3Eyv\췊b(zDVA틪>ˀ nx}Î 3%Ba_#-NǨqqΨ1L;W5_[1O3P3K%:iHLAI8P8UDn?M= [l~2Z0 J<[fK2a(tͬE^M<ّfaS8vVAA{e4"*.ppKԀ]rBq3k9r݀Dk00=6OhN^o6|eۓzJ>Qqh+Zk$cXU UtkN\O%,r9c -\fcW.(""njh>__jp6 D|ū.O\_3…O&f+MjQMC,S_ƕJP1e9(wyZ6!af uv(>>4I>gytsLF'PipJlݔzwɯĄJEdP oQɶDP3FxL.EF5VNj8"xҺ % C~{ѕ]O9FiZ<$CJL>48Ȟ7prQ7>2_䈧Qƹ|> y11 <L7$ӗqdGCh"Fa#a>jSJ(HU~ۢۏݡ΁M `Hp"/OIjb6DmEuMi |xd> -  >ͳNqpf=#@@.qK4*=4քuG*WlD RFWbU, =WBX7#1o,f>@L93ۅ_pځ19]Uc=cu,#$$yG` "f!N1.:H{٤*1mdR)mj`l!#dts ՍG|י=_ OǏ?I탠;KK-HxqEP]sƨVن,_"ƨ>Cn B7A*,L^;`q%qS5c4oQ-fl4.],3gw'eLǓH&`Dd:oVmU VJaM g$$$//c}SBRw<G* oDV}Jôt42Mq[La#ZrѶ\(L-nL6# ~l|@Lz چ_\1>.\-OR!$RxݶCNރqA,bQxU/"d¿L)mOE/躉D͆}d {SwcD19.Z: ޿&9cP j=dĶ_e ^$tvhyL[,6ĿE=c2RF/0,FZ _T{P 4N5\o1@i'S\ciKYܼ?pzOKg& 6;8A\or0J, O(m,|jI,x4͑v1J tuDJ9X9Miie*eU  e輀s3I6G:v%i~ɇ,bb/pu([D.v,c6|OraW ,F8]&>: @x$]bԲҁ+CX u@UJ&XY U^\c lwbJM4KPF [Y /B B >X8B + ¦onߑ9 2# Ė/Nm%=qŸjQOFؒ*$6ѤpǛ O3+,u%zWL 41,L7N&Ӽ3(9|+ffݖo(ӱޙOg)ߞW3+Swֿ 909DO &4`aui˺rXTL1\s_X#yxE @;?*5X/jP8K%QA:;v#_R7 p!Fl=BZ-"I M{Ah7zr CEk@3rDL2r*3ը.>Efw13AKrZRZ)S A/A"I>kquF y+cHڣ!Y;jPC^ĎIm%ӠL#,1AWE6&Ej zsvFHto^Ʒٲ( miQN{U8*p:L k5#IkQӱfUӔDw;oRŠb 1 u 1F5P%0i轸:YkHg(ƙ޵W|xqC @VڲQ\U&*hk)d@˼V4Jշ;erC/?!Ufe~//L_$m~ʎ.nIt \”0:jW-6ZƉXGaU4FZΛ 1:FZ7S9ԡ\-Z 0YnF!egc>ObaUtk>GAH1 6Vk!֐C= GPMXͪ\iS<)@N?bMo(ƈ@1)H?Ω:61c/wvyKP+B'泶~ ֔!FAHaD% u19`؉d54b=[=Gfibz1En(qXҒ"7{pBL {`9P8_GF,EB08[2y@U@mQSHJhK G;;tG1 y9SᤎpY cjr{X,S k~.{~ϝM @?if_iiҟ{D6biWGޘ,ÆV"dbh ؋K`U'_Enno[}!A2"  w@[ټݿ~ߎ.!( "s9rqF>P syhrUnLz.qQey$j$} I  k?t`P lyL=,N' CDpkq t[m{\Ro(4 v;K2:`AK3zc[rwN Q;Zn]t\J "Ataji 5l/t9\Wn y0Z2rC&6q|Σ.AI M @m)sO2fH3D?lÓ*/Ye~(josaMEuy$!ursFvL9qwqi$n"  W訴 ggEMbiȥ`d: 2CN0R]5Ya|o0WL^=$̽ȅgreT_N}vfi}cR-֓vѾ)C!(\&Cub.|F1 ?Y 0PSh}ͪwqhc \pR>fdeD)Xf;/tAª@}e`I-.LhڻEddƿ:oF:ۙ0=a [@CPg3CJq&sŝy Y )@cIws!™rWrEwF`_/`!rrBr۶7/?޾)pvE(jnQv,ڏ,y%Ja ,5UK YTV^_?U'j{=|{&ч4W+LiIHܨl1m5.Utc>U+'h#Ƙ嶒d1A ),7~s؞I$6Q1Mg=1_W[js<`n-o5e0ZyuaK¼{o wAnl{6Y׺)aHP@ttమ[MQV~tB Wj`N0"9 -c/԰Z_1x>2d&"+8R]!TyDxچCaؾ^kɃ?VooWI73 ~"Fz,~4=9jn8' whoH:<{ӘqnxGmfG481/oJA^͚F{>9<`Gc;df߹ +^UC^s5c[2XL4rD/}[s[b6zbXe7ࣉi2(zksc9M͍D;elfgy($E@ 8%'xԆ|V&{;rю2-̩QR"ЧNIcwXBG!u!b&RY'Lծ;e_Ϻ0BY2߭u:p9WK4*,`T(ÖipIiJFu—d,| n[8 EuAK\nze't^yTp~xu̹17[cܸ#R Wǵ(59q-j %4P7TTmB~ `ȵ5ތE0cZiz$a7KWH2%-@{3dF4E`RMF6ڀME=0||~M܌6уv8#Ӡ9}֊7'i`'>NWȖrD ٿ*xTCg!^ Q|SYZ/ _'FS(>0 $ۓ)6p/Uo$Ě'J<|\lL谘z9U @' { uE ycȃOsa %k(߼*ϺJ9LCPA/K'$WLAa"4 FԂy}.'R%PO˟4/f*'gJy/8! n7HMLHiYćK \2[oQ\-CEGzZ &ѫ"#Ac|Ak`BW S*x&=}u֌@e jp@[EЙdӫl, =;32Ƣ(q˵#_GOr]c:ž鄷4hٵ4rKLز S>.Y<<3,`~~:tYN)C,?% Oho`,nj v4WU &f=ƮμJĉ&"e'>UoO3ֻd@NV'@xkB? ]^}[6b{IJvctXV0IIO;@ s (وFTI 8X\DTK;;.\$ Wڅ I( \~J: +K)IL[[E}/ 3h REGp$b MZCd|3&x8;C TK`Ucr[l8(O0lִe6ҕ5dKo^Է|oBct6QcG,dzgB<6wޘcZ %N |2i3T vP~mQ|H9i4"v!S^FbFQS-NBĜTz쐘WPiȰ]H @L& f2xm8GL\MzQIa pX Z2\o@⋖P.TGYEPu+mtOq?t#VyL)58 AҀ< {bӏ}6x`={ 87S-U_$IYQ Q-ņ$9H/2%nm%-h<*關]<lP 7j[ h!6T~%诬|F=sNI`/ ۡ]ZmUpV Fv{na *赑$a,01 !\Hl25rэ}{UC~#4"b?H ?ߔۧ qC ܐޫF6!`,wA0ER 2\n!$[ X#]itv8kjy@\*;!ע&f"D~:ڸ5Ri YA $$LJSNK`'K(D B\=juØsԤ#fv(h57̦qBL$? P#z'l,T!9pTHP4t3L{f:$07VVYQt))Bn5_HIY;ɰ h"bJaZ&-%,"柜m J|1Rzǁ$1@Sb$w7 3kHĔ[3VbRyT%K&$,XNdf?-rjA拉`J ͻ֖e:#)՚tew3.^rCkA^x_O@L&$)oym 73ȇ$,L!O5\ ~$ m{aCCpoMc(]\J .{/S ah<;UYjȴ۴n@^KYMoE>x`RxӋ}<_ie6,2D9D"5X# e(=D qCE+=W=5'R1ph**[NDw6 Y`0Wwj?4`[F5÷|3w9xˢn!2b4$ ⼴ (F" LHPuC$ZӮvU5aRF a3On|ÿ 3[r.+W.kkt%YNՁHpmJQ-C:d R¸bbp% `4A+~>߳KGt転﫳L^M &إ2;/ ˞~4o${jFx,:XÞퟕ/E=c3XG˟\uƛp:=8PI|=|t N,kYl}QR :2)\rpG[=Ӧ*B@vлv iSo g!tfy<^A% ⓤU=}*Tu0h#1v L22SV- kU~ȴ=.dU!%z)}r6(hYj+]{ַbJNpª=0v9:U͇H-_J\5y1e{P4X"O C2 x?soq,ax&[Dޏqe~ PӪшF*񝺛,@:n,KO~HMIE?P- (*"PteU$5B`RO'k0EL&T+~ l72 `8/ ::[~ xMCe+V-e C2:Pr{ki~I儨; !lpMM@H】]Ɍ,xX+BKPr2XuOƏjR\̺T{?o>8xOnTrF0.2, r`q:i6q< NĔ(i\kbEi6=:\`6 qhRqeI? APKCGpiCFTy;(y{nw=oE4޸Hv;]W9]象{H6"/؟[ 2-n OLOKYM ( TLDY/)xdd"i| cjTm,xQ<M (5b1fX˒Ұ1?.;LJ]OuQ IMrhܮ9Af誠^JPܢVt]Q4*hdL?`Nlڛ nvTj0fKZG-KFV%v`z)Jϛj $~T`ddW=5+{O5O mGg64 AZASWF5jj7d&]{$ʰ;BsbSb}=%^ G^\_cɁd۟cgl=j\aoiYņf00A`}bOH4X0w{?s=<)fR$Mx9=+ EF$MtSz_iQW{ x)b.Hh|hUk̨13P,fճ:!4U`.d @iD8IIrλC+&Դ]7:z$03:]-(.!=0zB12"n QQhNOgC&AQ.-^CKO\W `V7_kba>pY@Kզ}]8[jg̨N-NUd*buj׻|v TvWHU,J5E ky?5i䩞 |)%gnhIJzZmAhМi:/ t%72C.bcW)5Bg~+,馬UEOw7q]!̋NӤ8:)6XgJ t%Q/i(a_cT5h| F**m" /+^ ??v7 ]=pAa{Pu("TQP^)3)f%@gSs]]mp./;U`£ [Up7ylmkO&npxtv Z8A z̕i#Ĕ/C e0)5`$K'j>ѨEfB4hIPԧW0p~ھq62om&?I!B;: ꔬAMh|LlKq~ٚ2v`*1$m_ 5͓!}Ƕ%OgƗ.rM`-MiiS 3#qSbp#zN݋ &UQOx:%Ry^{wbHMkכrHqu*mџ_d! m_ 8U"FnueLİϛ?ۗ]A݈o@@O\7(:mfTK/)EU _kaH@F!-o(0(p/?2,, 2qFY zu0A& QȿK2I &)T\)< )luցVH<$9rZƹDL% &" .ȳ^0,x$%4Mm6(>YhFpPfz_d2@z7`cD$aMWp$1#/(VD!;L3 (1c o6*+ `e1\ $R Ygi]}A7޼׿ms7q:Aq_/緧zr(sP:n&@2z81wtYjiw|n M)PR+a`܈$&jBs !jښT#EPu+cH 8>swՅavkcvNU#Կ?ƽ[E>oHp-&T[LAحge4tz\ VTU4 yk{$mRof(k=~b=&UEfxv昜G{u| /[+XY3"X{< #!֘m/v&^_pkm)BrfD_qOd24sK9FKِjVq1e2*1eN>D?P?+tfVڣ^҆`W.IQjhQĞwybaLy~HYA&AȎaޭ]SQ>Lƃ6 %6Bxp ͒!p$JBt l|/AJ8.Ld3" [o/~ \(7Db~] /Ѓ)Zm?PޟpTDX+D m>6M^h*rs"^u ~j*n莀$83ucf~}"Glj<g93*aPnG9PV#D=/$D  Ӿ7}c!`O5VR dry|׳TE}[#7LN"E/3dq~2plْ|25R.g EMcא 8h#Ԁc$E <:-O$ CKM[AC)Wrϑ/$_SވI w4ZvZݎTXK"Aڪ Py`ޤ .|L{O2 6B>iH1-9BBiltFeQ1h}JʨpA 6mX,UA tS/?.D<#eXJ[úgD V@z_)ˆ9˄(}a0,?r:#No$ER*!:nshq*[r<%CHG'&Hܞ.+z7^>;bǬUb: ٖkBx1߭[Gj}JoheĊ~Q-W 2a/9K)|,~m&|t%a!Aoڃ3,r1ΜX M9gY_W|*Z-lk@/ʎf+s{~"[ $'nZv'ڳ~ŤRv>9s6BѲV3&bH;É58%JhVDݷf|HOjg\OQ9HliY;$-%bglO L]H=~y¿͐߾ E!%b l.zc&jimp[B\S7+R&ࣝ;Ő$ZVtf01I~fe\+YXJB,&A`)Ba*?c XsEd;nWjv>w2%eReTIk&R KMȞ1Ac #b7D!R,#C(LM/3&eeu ,|w2e"EaSѭl#4e`U j-$nkq"ict?I=NL"'֠X³.XxdSysG6y&lR `azRQG_[ߗR|fVHw`gd \Xcpn?"ؕ^NOҧ2Tg$ D0V<#?`4הSPNZBtBGyX za U@3l@j:+)Yca=8Eɑ*!iCD춿i0R]CsyIR!\u%3%G<Sڬr TLGc>=5 4%^O}ih!!.U "v't'FaVEMC,8&4(m(V,E>-q3#h(: 'zn}M(tO4OtQ*,B1HY7a$ DSܞoZ)QT7 t2t^ޜdZ!b!2wQA/C=(_tb7HE#M,lE!]tq Q2W/t2ý&5l/30!N  # L9Mk.zϋD=]AM7tOۭIP-},(1{ptS8HSuB76\8NJxSpsTpz$$ ZDX]]HnH 4ҋ%K :s+Krê^GKfjoΎک40]:L.(K64E xy Fm"lP7L#x+zc'ɷVp*^#w쩦IE^-,nM2-]xvsB2"5rLwɏѦ$c"<tn@g>)D<1rQVgn d4 6ρP A.Іy-3 &g5~hkÊ>su= hEXو-VvY 3VjGv1sr*yǾfSQyW<E()aj, . -+=6Jd }LV 6(~9:,E,ch}{{]9䱸F8"Xr.4; s/~"3d @͈ғ̀9J{^G;CLR/U֘bFkkzǀ F zTi~HaxS " ocЗm#g~zi=8⽋!O1Fe;ƔB7-I k,t:ZJ6g[F#/Fp4_)tbއdhFqdKX /ikѧ976:M5 pO25rX7nJŚf0;)N60ڇ%D[꼬#v,*6]mlY="hXET=4H'H {jvzxk FՇK\ˠQs4p7.[i֩ЪK]%vOpd aN8BkˮD\Ӥ@7@Ρ: 6מuaPh&-;WOIH@(hbw#{&ZBf.A!h)% 1cl|{}X٪7bGbz9rx/3B*?b)p9w0?OWocG먶 xz]w|M-xu88S @<^Xf?:r=rR'V Zϴ*K?^h F^n ןg$|ctFap zh.Si"Pcrzk3L0 8>& dy;RQ@ $j~ćO*mv@ dqb);Ì >L+5y,I)OZƙG_tEUl 2Z ~$obLJ4Ub}Hڇl)Ӕ i\Irmwܸ+ѐ2bMȘmz!r̐,aKy?3DFgs<Eyp}&s-=Hv+ՈԥE,1hUܘRD|j~zșZhPD(QV46 ygLH@tC' G1g %QSr _>O?Kjj 3 nN2&Сt`H\˧vw-(F"%Аh4,h!fZ{Y GrEs'Zq#79;]( Jxo y{{> 2F}/" 75,00)O-pt,n.6$.8REK@Pap&p#1 |]NʕP-'@u L7/z| -ʢԫNh25xGh0L 2*G<5\VS:xwZibf2YaaumGπ+#ה^.fv$U5rjFTIrIEMlm*96#R$U.opud&Ѿ y I.[jTC0| ݤ#%! Ws! Jy5-S2^kPdGJbr cۀEM E8>  9=[>傞~T%5|cl!cE4a{p]6C 5e@S1D%ji3[}">zuΡ&&tjxG|>]Wt;@x+19i0 0RԜR-  r3aw!;G(eLpoȡ8aR9u-rtNIv@ #oq{+/ )Q `n VX ;xDv4PrY*%**oM`T`r%qpZFMj"beO| vCRȃ=3<➺jy5.JX[+e4Dp<ҵK!-%ǞjI[>%u6o(Ff2Mj,~̷5ՇYg@&Us܏8"0بʣ.:e@S"]%307WX#_Ee` 4r垼' @DL_u$ғq()NHcdDh{84*ӗ=wjɷ;&5:8xWodƽLʙ$0h7f ̈́'bxXa#H(G|8"%@Fc.ky"Rm[y 4C-bf&(P)ݨ\KЭdSi"|K(21 A~f^a7a"؂33GET C m`YNXƏ!FqHq+ dC]Vo?G6S}#' ?*f3,G31'"BAܔ!҈F+p  fh .%(aSi:4In3K8zqS r4X;u7,IB\/Riwp_$I, OUWE (ȑ8[B.rڟ(6 TYP4`"38e hbEWjҩS9ƑmzcZ,T=$ab;xɖnoߞ8[Tn ҇`ZR,+ fW҄QPv5}ڼuq̢ ?NZ cvyWbeb;3r~Y%_+%iUzhg+Cd0W06X=DEGAeX{!}.nr`g)XF`&r-If>T\Za!eqDɻr"\jd 29(ρ5&!z`b^fAƝy sƠn;[aB A xu`1H]J+\pf+2ఛ0#ǒcB~>7|hfp#:b"#]r ThJ ;0fJeb{AVj oāaiu3%m2X1\ '_9-B¾.1@DC!N:,C%15[緬l| -xU˦$ I7m2:өĘMG¡HfK_9zT_,nAt ?6a9=K<tübu]iͨH s$l#I?ӫSQb( @Fr Ėe&Ԍ Õ4@`"m ~I_Ԏan`Aex = GIlE3T)~FTGe՚hH'Y=Li SƼ#X|AmkE> g ҈)⿔^dB/@l9aLz6$BOVQuhfeF6Pz&]#a-bpy z=QqTdr(7ƖU#MVF8^9%Mx:d]G@2;<԰6;xdm l hy>;yl}yo/.o/t94ڞ&𤰰Y|BxU Eo[uP рO~'HW4:"9?2ZggEl`NLHotV^jG'KڅV4Ze`|&,ya!Éb!vxJ+]?0sd-<Ƕ7$& 07 `Uf G֞) /1h"$*jܱ^,3 RMCYΤT82.xoO ׼P_⢷~/'ZbD]cFGiB)]x̿ug]%x?[ktmx`vio7ڪH"l uk{4*Xocӹtr]+U#ݠݛvپgtƨWT4-nTD-cB |rxoKYwyudZFı@ڴ"$FRCCYRr(`,~V@EiiVd>?^׳=.W%Ae}VƣsDџnq'[Df,LIp n}1$ PZKI{^%(;Euw噦 jʀ [)5d \P &- gq#2F8Bm-x3 y Gcl>Ol,fRְCuOFZev+F KvUVHy@OZcifm?߶9:$6Yh5D@D8 kS,sDWuC.ֆzّzIؽcK(("iX&-4r#9+Y/^N2U8h2>ˡrF T9?dQQjl1_ek FxAx ([ NjLux'KTb3I1Dvڤrڿw]MW .+D2\EKlB jh EihLõZkr MVݻ6աqUK#xFL u2hF6٨Rݣ?:ʄ\AeFT9:1$ sӠ(3*#܃!ا`Xe'Y?fkCDmpШv)8aHg:Be / =j66!$E9(} /CCK0F#ees"=8pT <%֞(q:@f0$QFǕ ?IHC_{76]F_ڨ ?, roN5J{G4xm hW%=it @NV>Yg,*bDenF4ZB XhcSFM m" XYFDq#$mU#i6d,;t&. % '~Rh8[%%Ld>NǍC܉! GߵmƬsĻBj) QFI& p-x"r[5w&O! З7an0ΎhIO߀\.dg2ItLsdQU)r{h;)" 2r*Lݖ?54z//$: xdv mu`wyTŒlj z&Uɵ)s_O!Rii6(eLe7UsoH #dP`ڌj#p-~-*Jݢ$}Y#6H#FMZais$kVeP,w-C㮒Y*H;lzA7P}[,T]ZT|n\7V%2ʍK陲RGᴞ[AM5Q pv2 $ь2u_#(姽^]O(dƯ#úo dëp_lP))dɬЍPP{ % tT>ࢡ )k#304@}c.R&R/ ~_]xa6ڟu{WU>C N Y;w,C)~97X.*.,P@[j"Y)n?I*VB1,5M蟜$E:MDbDx_&UJY/j&n7b+ /Q'6Jr~+]yA,V̑ƾX48B$|Ar?FE"`ɫW! PӇb0v{J2;G;Yz! rBs #6I4ߢ?ƫ€A avCm,K06 w?nm#!9pyqE8݄=o{Q ĢHm͒p?dR39Iz *oMJffڨi(v|+Hǐ#uţ? ^|V@ư-#H4תs~z˵lCoچEF@IDAT7-2n-!keB'oevXβp(cFh4NQtVp(}ڡR3I]0~eIJ9oH68  62=`VM5>C+֭oJ7sbm$y>N^ˠ rfмO)5c2rQ+b?*9Gq2BV/Ne 4}Z/I@!H/`@4|,_vD.'ER ܼSmEU4C Qvt#IQ!V1khݏ heb'L9oFR 8 ɣ@_z.Zd"LT"ICѱwLB> P*K|s#֤@S:2M%o8eJUv I:q/EL (UwYl4`h\/4dYVw4g &HĀI.QM 3l_>.D" UoN6f}J;v링%&G2JW^qYwF)*5w мƑC)iit 0ɪS`).wکSw|bĺN*-@q3H^XM< V+[}3W/d*x{5-*F:c|<41MJ&k)>1IWCgQfH }3դ*@Ăo|V3BQ KnkW~dB;+ Ee1dܣ}/6B9$j J[y4n8ȅ'# ua6SB{~: UX.C$>\$cߜE:-E(52n54 [e$XC6ϣlQ매9lo9EO-+]EtYl^ɦ+֛"65!jy{W^pp1U4ͺyxGa rϛQ-i`0B){.7)ɌtEGe长{빵^b–)'ވHz0#IeFq,3UuIZ's=o/AUPV 5x2W3p-RYMXS@Ƒ9v' ѓxNK̠QY uVB6rp=E+z9$I+Ȃ52bYideNk^ض攈/;qT*<BAPڙOUD I̓a=ZD 2F|T浈 @ICLμѣpm`NskLnb,I#C}.iWMX kc&FQF0UQ7{rUtzVN>[u+i]hѐ)RP'/+'UP1X}dyPБ$:\%09'wChBOp"T:g$~{e98ࢿwP&֥a.@ (a/EY+-\&*ͺ0']D^ YIEB W}wyd/"1'}a5Q>sjB(D8sm)FYO9p9)DB|~8aqߪ^\ 9N+Xr7*ǐi8jI!(͛NV/-(ȷTcSY^J%r~Mu}?mͻ:|XH 09ǘ ۸phKLVf΀}*WsUXdIb9p/[Sq8nENt;3IZ+(Xt9#R|4tHN{T jq"]J{}7!!S'iqn_(BQ@sOt^^N?py$ٙ#M04p۴ EO)5 +)A! \Sh-d3Ƀ;S B-X'I[hٺT*zYaJN`#䶼(cuzcfg"XT ['MPO66رf"x0zޥ Ñq=sMHq r#֟lZ`*"1tٵ 1=y0\.2 KE z,+5xA:rvL> qq&Kju?Q biۥ-~Z'c6qlHW)$|\6[xd[`J.ۺ`@e23Ya/ "wdebF|a5{αk߭\W-WS4,/TE].B@- 9!~/z&rdaI27]>QHNe?Uim&V2&Ͱ#i\S 7^[s,T%`&)6a]3:tڅ̓~|G\kgv' F꣩-S$%#hVDG9L&]-d:DHeK8M>Rm^\rPh#S"{ lT`۬'`& !q7 0^RTT1F 5GErs-eX&K'Dsc\Wg ls|{60<^"NVe3-3UsI9dH%eŸrA2@uphW" F){h ЭSql{=dj?oѐVg~9G{gKi5I5bB2U";,7ULɷ0ʿGIE5$RRl^zӷÎl%+Xzy ӏgs+3R  CNLӣՂlvCqXWH Ʀœ!l>2d_,84rg!_oaZO\N>MGr6zZz l3cj#C'A@r`aNO,2'وx'8rniHB\NÅxT-1M|o6AT܊PCھqROB3 31s @o~O:l,7L`7Gka9V==KAÓd|=% +X UΔ#IElj ^j5"v67)ƏЄGt,I͕Qk\yv\$O 8k2 /F}]E EY$J#4cC(tƩek+$'ݤa,g `YvV%L)Z rbbfv[!^\BRBmlRdɼ>orbNHa Fa_8/ t l",2V9וbauk9ЉTÈ0Y^ATj9P dࡔ`Ƨ֩zb9Y%8qPj/:#W9 (zEM$f9]FkQ'[9ǬZ:SM0L@lM"fɲxc{cw643'-b2M(<*+jyQRHҰC28\IEÀ lvȈ[~XtFL45~H㍴\*Zcܭx'Vwri0z/ը݀p&I@E2F3[!U8ס}jq1@7pǻr n`|6j&+J-C޿>C? F.}{=.cD k/m̈%a'K> ]Unku3}HQ5?I*TI/{T#渍* k%|kDm~'>\/E%BG~yք>_0-pߺ%;b(ڿx?oplQ= Iv|un?w*,1ݲq*N|>w -L Pc/~TUYX/.*f="a"J-= $fp5U5E& ,2-^ OV5Cߺa6τVv!+0&ԍ[Kyб̅2Ņ.bP#"d*Ec?ο,<+{6 F\%Z{FkԪ7vJ7,@Z$/铍pB #LQAAĸb4Q{QHw0뗽D=} ZX0j Pe [/G=d(C`?Bnm%3LD\IrیxLOQ[f<@$g]Z|C`^eȲ9E\ϴ,hlhӁ"FK2=܋d#h~LN]m]P80.O 12Q@M-+Ad0DHMpO;kA`m0h-BMsFrpGuI1nmd3+t/j"ĩbS .au0sqeS1;o7R gD)>}_H#rh ۯ(thhLwBhIo4e]F1g|2: MAᔤR@MgcC74`ZM(OfsTJw՞f]cE!vGw,Gm}xTٝjO/E~(oJsznjP ݬo|O?d؝B;q$8zl|~JG#t"=K²/ָZ6zhs$]&xMjZYah*ɉ DЙfג6PWܦ99F`Sg@5`,$Ez;8Twz3z Y4SOw+Aǥ_e^ yj/RVz:͟Mټ0Iu 퍆'FZkAY/l,nZ|/jGLIvw83ՏJ|]V7 e햽u5z(#s0,[8>_1s`v ,.qcL4ivuSܵH3ȸQ1; @Djx>5X$AA:, aV3}(4(fqo,o3(0zb5+s|*  Xśu`04q!,pֶM_!bwp? aJw!q Pu߈TS wY`hkI/#"Β/k+.dqTH)Ke"o&.wej fJ&^ 4,צ SD.sIjlU'gm^1PgS}dx^DZ0/kI @%|d  ϰd#*i/H%sk]_hXಈ+qAn_C=mWv3Q= -hjK](say:Ur(SZ& ʌ3mѲtY,7E/YneoChrbJFL*Ԛ$<9q U%.-oEv K#i(zR %!4sv0jM' DHՈf@ޒI"aT >^ƫ J~Juij+jjIYE>/u10[c qO:ظ n6u":nSVsHq_*Ƿ=3hL{5g!H /??*-達` VC@r8eBF4U} %qV]jHy(\y*Uuo` ;L-e*B7<*8(Mp%QFVGlJhq]rDP5, 'WOkW?[^E0kЩU>XI+Ӏ疕< (Þ M,8 'e;D(.%A`/`gx-XV놱D ѝ)=Vq'cp5T80X =3  5Ж>ibk6_X ]2EP nA4^HhcZ/I~\`W <@*>}D>N?ߕ̶Wjq+Cv'w*Ca6u2u cmpP\.j(\6 3bB@B_  Bd&js4U2 !ߙ)̵dwA?\Ͳ <(RqF&WP@|aeT|]c:ߓNӦoMbpl!bEVolcrw?AQlHE7k6 ^'h4ˍS&OsP,a2Q->na Iv-lIjdϼ[X$DHS.HQ EF0<`FbWVjZҸWehp[Ϻ^ tiGd$ C\'wP5};.0:& dJMZDZ?ϨsDV / u|QށͰBlYOt >5 X&c YBJ$hCZc*<[AF:[bc.ABD|rZ^މ]1,D@sx˽`:d@۟0`ia9KPZL<~ZiJuJ*9P<m/[D󰏱m|b-=/F; n 7LX] 60}ڙ{jEc>F.0Vb]TG9/,8H: ۙg<rd 03L\ `@)HF>,هJ)7#Vkv"x VN}c1OȎ띑Wt"`Tɘ9aryg*Z-P1½z=S6I`ô PKPE 8p5-Q#dg%ҼZŐ\qKgXR202s{@%Jց?j{vP|3 ,B^w"X$:[|>j@?hyH%1/ϝR +_fQE< EG)ۗ-2`0JɁ"lj<ܷʥɜOC{  eVIϥP Ô1Ѣng$W7q-$[4M! x6sTy2Ӯk%dgDZr)[b{1|IO B9o8=% E4\WX_z+r̃wHsޖ>f=&驉bK(앰tK:862HnN n/OI{Y[vT=1RNj6w=Cex=E+L-B+a2d) 5߹ay7/;wf?̳ '0a&%T[Ԕ{ NY ^:1Lz+iJ LT Cj1"7dj1y{{$LBE8ʙ[j3G:L9hqCIY:}@~9T ñ.5DFJkEeck^Pj`vU\0h7\>mH.w8p2F.' 2&%%ƇaQCFOgɜЭ$\~j81R%OhL-" I"BJP#lj8be lX&u ӜEWߩ{NE B:,ڲdTLfP$AJx?^bw|*B!pξN@T&yRb1:]KD:\)^$26Ik+ׂcLaEMA{%  م"{e t^@B@4*[/0;kqWLh< YRq4w0cZ9 OE DTBպqfȨBlxshmCY9f(Rw8 Re8CS:tyXIl_FMdئd!ohsi ; p8룥9R̠X|{Rs19૿%c005 5Oz-H2MG3 1ptb(HtTzJGHyJ i '4IcaM~BH95b2 dpIFg, Ɇ^ #yS]|W,e aNnUu7hB&9dqK_f#"BSWv?&<`', xM rZ"GQxC1~% k7&L: Mrw&@1o}i8nC(,Ug% -O"cOIŔq;\ҧjs>.}ULhyZ-J8-#50`r7~,N=4$;dU4Po%e"NKp/=Wi Fg 3lm0L8 vc>d1S&w|}]pP)ŎշU;*[;+#z7\kWt 6R2"=ÉtDIak ya<<@4NFFy5F & sLzy8eׇzq답6ٷ)V?| Mғ-- KLNtFQL;燳Inj%[>7V__8[>ҟӆW.Crh$0X8֌vo{~TQQ◭@1<ܒr( i.؉1EGJ39G/V|ˡ! 'GzT$o>\[ٴRXaFN=d4gq[ ȍ*N APG1a 뽗K5tzi-~J,`0| e*:K`RNz^{isԥ_P IjshpOAbN g14"d]7f' gZYx)T["]]g++<[]=Oy& >ɩ/p'98wܥybG}4 e4"Th￶qD˕י`d3,F__D7[ ۶4?-Q-euue6]DB@tcq~?\tޢgU=fK7Q]zXK!~%hP)%2:4-RA .!Rε pvr fPsbg6Ip$ŞM@hK%#h)p~NҌ7h/ VUҬ TIx'?m8˕Jۛ/~u9Oׯ_/ Nգx?e*;f=SuÖ P1xOBϴz:p(~xm($V. Q}0ԏ!9y2pQ J&xhcYf]je˗.ub/*9+W u )_rg#|ی\mp ,~W*;#}< 1ߥSbu莭F 47q9!@YhDM]l6cGA39Xl3CZ/1U&R/>53d{3QE˗2y~yub<AG^o?/旅ıerMTQ}u q-#jo"'-U']N,aj<1@Y~t ,ͯj fuRBZHSѐNiӑd-G ܼ*=y_~xYBƠ$Al"Mk0Omq?l.GHp`;<8ŀk%å֖KrCEK?7[TD:7`)US gG^o' PV{tYxtq}{~D3J.uA8Y_DT;%v8L@Q" <+]?̥ pJM"_s_?0L@wUs@<+/L:RXI+cx3  Ap@/}ުɲBaʣ] @OݩDVIW8B߶;FĐ$A_YW/.{jVZ Wc-&!%`m \s+M$& F M`~),LnZ/Fs-xRZC>[Ob[!jWß_~*(I1wmaS`P̴ Cwv6},1A2:Qלn:L\n?]PSQ x#"Q(,C83#Fl}k"+f!R"~ti8=@d^^hOq韛+22.Dͳ<VxP[(}摯.p |)[ie[*~&OJث eCHjV#Pc68.&QWjwG-,҄4)j;E&S,"oũ.a_1VjE86-zR\W+1Z+Qk3SXx6Ae/d}VxVF( /=x~6~$lFf,{p7+W-dZ҄5X{74xH+$Z&pdž6nDL&-HxE2$g`@ 9cnG<"=@J.͜c5!rWLQr) mcIkqk4fs ~K^Bńf|t;¸1d<Vyzj{~@ӊIf&/>j^܏9Pޔn)`r4O(QWd;0.3$we)E BdoEXн]UW Fu6@YrvsCWۏAF2ax˭ќ乲cC^"Vfь`ېē=Vсcn= E3p>U\CIoDE (!?mJmnU%zw!Z zielr1lzTH av~hLBow%a6yn??c 'F]ɅnEiV(BN^TҰm+kes@j;`|]UUi)4{BXuR9p$ p7R5#<#[i 0Bd 2._/JdaN#Ԏ%܍?/TYV#yG.ӡac`c<ȿ}KF?Ym;V|C녂 [,P~57]ŻHGֿ{S }m#Yx6#PFmMtO,իZ牁GH=sJUc`Q0B!N=l!S2`v-x[F<@IDATUk5 -j9H 0Zo E:x Q5Ն\`8Ʈ wFن+5c ӇFH3# Z*$͊ t!"K06+}ƴ`bĠ?`\rܶ\ǰ Q ;? 9ðCzȷm֕>ʡ;NTGB 筏5$Y֨N@w^J:1:ll]S}2h;0YGQ%jpTb<Д]* ͜wȭØml?O(XkH= Y6eRx=cڢwT1e@x3if"U 3@ղ\7PF:ůcFMX䦹ؒl[Wi&~Sfä預{-6f ihi-*%Vr 8$!ї8]&CX6gH/>0z_-+ WA6eIi \)DWxҗFvMނ'TNEBAG_@ 4 A=@a`$JCԒ =G,4030ctT^W`Ey7@g.1qfrRVpI@h#} ]7uk]7<7i)(<*WI9ElHH.HPIGRaeDau!#] c%&AN=.DMKF>B|72te`Yd5a>Tz0/c؃D><* ",n1'{Y6Od0g]@3e[aϺ}~pB0bah74?HľB^B׷S"!9,|tB0a>KTRm6L‘>1;ؖs:1ԂJ{; xӀKƍGSПmNЈ=)ΉC^Z9OJ *{:NŠtdto1._} " FE>X?s$eVL!k (V]bHb78Y.}%BD0%X2 _N9PB9"2WCX̩LUU [lFĢE i>+L j !̉_hlң iiś_ւ(H[˾xg"R}Î"15UӢ-.d *z?Lg7G"0dmB˶ '2D4+ϭR.^KC8έ"Eݔ Q! SAy\I^5MOgCajR 7N6󖘦yQ4 @ӓ#uIS]ͅAw&zZM}d#N%~a-ÇRPLQrou HjIr!_#{fZM-0/ܒRJoF ` 5;L _бҜ}3SN!Whm?Шٞ_1="hĎTbtCd2a[HNԖ+a9Cی`Z0n̏*N\v5!=rvhi/=#F_,hQ1NQcߊRZ}jIFqrϟۭT]l~'*7mG,7.7x 8D wy .09eI?a,Փc\">0}SC8F0E{F'#$nآؐ>ؙ0)O.iߔe{΃`jTY`&A0?2zĂ4Į.؋^{1e>=KvoCJ^P6\1q!L6LJ3K4!ja{Utux緘2+^tI\ x! z9tɓ !$)nw;ai C9TYb!@sfZ+^ Rjs/J@,hῦb4zWWTYt{(޻[I;Tڌw .}ća<%Sk!91UɚrX᪥VvS%RO(ρX%\>ԣ͵1uô.#ٯዡo˓%̂}!@%ʰH␎جF5#g bX>&x%W:a٫:)K2n?cp/S@/:!N2.1}maC1Н5h A< hOf^;t@UҞ߇NŇ5u]0t3C@lNwM+h K`*|b#Xۍ:]5,IŵR* o"y$]~PH҄Ш/h*9~AUCryކ%ӦTB27@<2bԐ$A:Hx6x- u2˶᭍i#3dloWO:9X҃G,a 9[{hIM`"8[Riml2#kVXFI|o4!JH'LH}-CCzj6Ok[wgP !Uٸw+Cueo=7hy B;3ONwbdC:be@A` 4W@-{h~AH1ϕ!KKoN >k,28P7˓Gq G2p"g[ )~M}KnHP1d^,G: 'Ny_;TB`̗"Ih(UFLG[/8}T\ =Hǡo7'&TbߓiI[cǪUy6zhA[}Ppl7xR}JՋc+x}ClX# =C$QҢUPoGxr/ULgˑV-@q@ PL&ζ#4)-y_>5iM.ShA'K1@G|qo"лo%ԃ'_0!IT&.`S VC+@A_FJ,%'P>UAh,TtΓ?U*۔5wBX!F%Zv8P#?Ɓs{B&/R[rc&X3: vBf3-ipMH6vJWHP~oĊvc>4ն<J*KsV*7L>O!S\ 6$)"/ثits!lx85fˊϕEԢjqP|epcDLg%^K#&q&ޣj(/ T1svSP|腉h&8Fa}B;j;-SIVk0N0.ڋd_f@DԢ=jbXtk3H/f5Bj'ǃug9AƸ½ЯmYLߩc洉NF [C21NDa:E@ PZE;:CxL֡da#S#aJAͼ2;4$V MƇdDtKSS*=T{:8rh8[^}mBbގoo擒к9RZSs-Ͼ)jm?# @R(a$d7YtSRri y9'ûpw>&3'+FP}r;R JBԃ≧G)?ŭ*5tEԆzMOX>'t*'Ej ? ǜhI9S6U4]j1[ _c@Ҵ9>E%w~T7#=4O&ỳSW\5kmib[ō67Q3!l ]ע#dKf=X8}y~mjt5/: !50 n P 44.nW׌1().ȳ wL\7Hw ):-CW6dIN5ȭ˝m[{ܕZ:XT9Q(Z_Ӱ7ectH@²y9 9qy^&5Ɲo]74 0c$0k8=z{0' (a()r "5hJ]~\lfiɦE,cۗݿ$O^p _M۬ό3y^UwD>V`,R2)˴ '~!>@nꧤ+m0r=E0Rqr . 0OsV@sorIi4ӶG yKoNXOn[@Pۆ2G0=eHɶkC[qSDdO z0 >wc#iICk3I')ȻĖ}D|,):ZebDz{"Hch1 nf"i܃y_u!N N(a9qz#φ(>Y* Jqt*rh[=wxFLm &З=gž..Yr#;e&Ip:ɒq<ⳠYCV݀5PA@y}OPqx<>AlX,.Umlc$yrOV,ILHb ŧ#0Q"*yI!6wUR FaTqqo7rᣈDf4c7[m/nwYY&!,T w>Vm_xV48CHzr=6wq7tM .Ó%*7oL}~61ENJr6$yU:"-fۋ*m@ȓ7=3DӒ40OW b"sM^gƻ}(cPYZG%hJ""M6'&_<cgfsjg;;?TVͯgF1H_d_^Nc ,r$Xq#6=}5@`j2,.ޖhsc[M_ў*]H?h|Q\ Y 38bM"y=X74fȵR]׉/R"tL ߤCB4k }먍Wtb6lv L dbEfs=q92zUpq")euw7JH`FyP2<Wb2 ̉xU[j BbNFi?!// <[aL8bh&Fdel4SW[ c{ރE||>^ܼlJ/ *7ϩܜ0mm4&" CPyE%q穪ґ-ҳ2'x-3Y"k_e9tNV$ TrXm}Wj=e'N3݆kÉ_ĩ&IJ2ÂH-p813|2IXM$ \i6[Q jFف^72CP QkЁpD+oi{ў / >d<dHxJ` U<9= Oӯ3q<ѫ p팒[4lKdZ)>Iϸ5& 5eD)x&m^6?v B.g JK(o:lRRDhh#ra:8jtAE5=O)Ю w9&vXΓLt$7"B|%6jcT?5 OcUg-%D YMR8"23gH ~L3%:G_Zgĉ8X&')r 'O3AGMWU MvO$@ߡE+7K0ֆ׌g4 K i1]t)X 9ّz n >2c3 Qzfx Q:*5E2Yn0(Y֠LV"ula;NluذGt9&h|[n;I(C4 q xCc hQ .n }KE \m:їj/dt!bu"(_yĊ?cSQY5EًZ* T(2_3Z)E=otM̈́v.8La!U) @yJK :`;zdcLG4ʣņ 0@# S0ug0WhzG#lɜ٠b=hnHCV.B 翍Pn @q|p1@F~!%/b:^#v m}sD BԂɔ1luIIt9mj9TJFa7?I)Bd0*A #IeU ʶoSBak|,y$j[EyhϷa7U0zԆ_o}b[_ovmLNѫgryAAR`BwS̠-ssڐ!;}<y]$3GjʺDU?@S& oGrJm7~?6p$s[Њ'&`+6(TZ8J݉uŽۃߔtܯynp%zi[1%IsC7ޅHJ5S@{qSRRVUaO$pqS^:^^]󇅾0)HY))>Iom \ /vd<ܬHo@JV^$\o"FyWhA1Rti¦kSvj4 OR`V4ANR)'蹔YHgXT,Y{hPͲa~8_aq>VP^-kT t@LvP\;cDPaLc)ݘ>C5HR0,SBlJ{-]<k.`{»\Iѷ˒ef,I-X,:/G#N<#?Ak$v<Ä\3 IVL\8u~"X LKetŇ/ pȯroUW0AIW ~1Enkԣj",c@p@%`Vq(\; XXW|;B1hPBj8W(3Bnq*@X U @Bl|籑n]CGgeJ䈖2}|2A8`MWͿ 2dKrSFyHor'`?η_gIA6$VI2%2oKj2t1݄izl4z.(WLtTL;c?jVppk4Q*$b'nnTn\},œYi?хȺey2 <sa>縎0j ٝ70>"54t c}Yaò߷EQU'FԞ #$j d+,lT9$1sCnǙQD}xq88ꝕ^Oiyg>cgGԃ,* C؝b1]-H6kY ٣ [m χ']lL(X<݁) JtSx L:ExB0dD2GZ70+`@ ciDrQ m`OtRvBëYp=i$U#d1zYca틐z@ VN+e囤# <ğRw\ 96l qA=?{zF~}͠Έ*d8Kf7G[Ek'QWb;cg*Aod_io_ Zh"44>$_*8m|ђLfp0LjB ƀIa歘-Bkr)p=f)_iN9d06 AE1r_+5`M!jڅV$pF CBojBN,Nk:NFfn, eazXkr(6E{(:#H܎!]P "X8(-ȓwJ)zG\ j3$%Y-a \ɬ`eSMG [:S&-gX31. ^$,58&l\FM8{F/#1JL!lHwu/miXC*̆{Ք"j-Tqܹ5+`5x _ܑ=2ɛ-Lf"'D;p/ZV sa胬cxA6iT7)&]%J NC|.6|ҟӁ>ˣȓoAB>dٸ~+UZ:[6[G{/ӇPˋ5;T@nb "AA )KRu>W^-zȢ^K5N4HsL(?u '& )Fm&Ƶ٭JȨġ>r 7ҤXh[,zge\ajSLLTQ+=eđ+H\ΌekMNcO1S-BTmrC?ɡۿٝfB_񰿮ţ_ME4Yu"֞ `+Jq޶.遷?GJNCQXiԤ 2K/4x یzeD 1ڟ<,$f)F6FTdGhEgNXP@&(:Iu[Z6 M- x̦=6JL)iڇ]ś3ߩ_O=~pu>"2xd40T ]&-(CsḉfI>ҭ9?`Ҽħ(D:EwXf>ME:~J.&fFmQQ,2b`k;(Ђld!H1RK7DU5 q 1U 8#OML dĈdTed[R,+""U&,]*Ыd M/CSJɧd.BPF^ b(B Xg+=3 U?i3(7gD% sn@YmqtOcg )fz ,ٿ J!P FȈ.k-sS1:[Wt}?+4J ,ۅA%OMϐ®wO\P[DN/}mⱸVxjGgMI/ ǘUl, Z2Ѱ`]ߜ;z_6.Ҙ/{Xxf)b8v(֊-m0PY\qn+[;QAXk'ԪÞGJ|pØI3Ҵ i.ěL_uGHhW(Ň! HTcPPC^%!3M 5ֵVt)AxމQ–_" l Vjqź-*j=Ք3^$7SIͮtkP[WgfGэyCܻȡ-N{~y{meyј4!f=@R _)ί'J K4^`Δ eqN*["n_ )-kQC.eAGXכx@w'7xj Aφ4A,fKRFibP6&t.4ю]tq.3$>Sws93a?8q#XA&FfUzC ]P6oN$dPӚvy*Avh`%qYNa)9ٿqO7} ApO/ڕQ!ǹu @.C`Q7#SEָ/V?2QAG4)!`{J{>l Xoe4Wz7Ngm]@: 3LRJ lw`Đ: 1 Oa@'T گ՜ KldcsMM"~5`猃 {% OأͲ1"~mm(Cq* Y[Z*eUBide6_BT([ai\^dLDDVM$׈yxE#T JEc9QyXxΊ' D_x u䑏+|JkG($Vi-7O ̊!0W՗ꮏP;ƄebfY<% Gci!cU2@t1> `f{O9SZB(Y(T7c7 @E|kRr@l  }vă5.n{FtFZX4 &nBnfrNA>յ>[?VB$mX`G[|HizB.֭^l۷|qrէ?ew)ovǚA)P^mG(&7v4CW Im:5jn R-A:;:ґߥN76W._AI^5QN;Χ\lJKo66|ϧ?/@nF<!2@(8 tQDȻxaSͮu\` {;c%W25,|!:ctso?CZX%|dg+aXk&DύDmUǶ- J$#d#)R* XԹrNDxIU}ۗu--#ix)Z˔2Q^jD} 7 E ,Bl PxmC N?}_i6ÍM'3Ɩ*i)1o64j?W>R70tZ7]+m.sɁ7;D.}жR!$]jdnA8բmL d{I㊿V9|ʗVQ{8 rw oJqn@ wXy4uN9mÊg_-p=Dܡl}G7˜UzY 'hDKQW89EkeyFxw0 yjsQCI|JTy_謣ثe Z)J\Gy͜76Z y%H`cT҄'Ӆw! G~_&ߔ]_brD[3N<Gp~ W F0 *iW`; w,%|]9 ٽxYaPJu}ZoOyP- nF@RYlG.2ƻE9v;# X f7yls*^x23f0b"dsmU޴gM;cM&-NpydfkkU\ϲXU]DsAW"dXOs}(LmwHqf޽]ƀ+6 ?F2k8H ^drl j18fK>V 2xXVKdhA垂0"BAU +JH&n$>`9ak'g7%_OC/ɠEh|T p;vț+KH%h蘿ej-FS3GH SRf@2+QCI9L"H5l 4>]f-ďx CN_Di*06I= GWQxjr3;NVgOd"f隑a\з_(l܂hvl KÖQ}{3HiLW)d^hSi&$u&`_b-m^HSKnoQPnoJ, Hh~*~ݟ,Q@hs\67[QUm"x\HͱMB_) 5T7^,(KX1=˞'TudEHBw"OF^GcpP@ `m|qWzk0 h@8,+]tͩ0pTD24?‚QXLgl= 뙧|`s6l rD\jj\ <>^F!/= %U)v \A߬}e9w~((ȆLpS9r: HSZBaM[ nQc9\ j1JCjqllWvg!H ̃KcO XMzxw+*p+Y7L qh~0೴ ^ ZKqIwq2A8(y"T7k)6sr3Ga#!0RiƧn,iL|@Fȶo$67*1V(QlcA% Y!_wY' )rbĦby!-wOas44P{UGleL!Uq;DBj'! "!N5NGAV[f1]ȇ^[:#F) EATA*/ .EP=4@J?Έg XӻDQE@/{ځszuۉ=]A3WSCG\g2 CKw+cmQ@1w0KhJLbRc;|p( z=e7@Eaz^wwj#xRCPdq:(1qzs0uw0Se}8v H|:# b7evSQe?]?9CutkUIG!t+R4 b^H ,<=H6N6xҪhJdhI >m5u?L`9"rAvCwX.5P9eSqE'?g9a ܰ' eǒy?qdEMՂl̀D{\ﶢ\F>2R{i|ڂ|%1o8p{3bu(c7_[H|@SS̈́fU$WXg~g,Ġu.icԩޒVLAXLS`||1VDlCi+33U W*ۯ3EOE1Y0OsFPum9&ILҌS>oWY8Lx껾tG@P%%X'Q0īfฌMEFaG:mIwҳo\50s @jU 41q|hkdL'/XĆ W0Fb'Q%I:N)sSטspjÊ_3% 49U6GN'CG@Pک~R)Yͭk pNuv FHMoꂭHxXsȞ68+9#R4)ʮ͆!Ibwxԓ׽}Cxx$'NP͸rai!L"g~H:}/KZ뵌1-xɃI*WD،&a$@$,N،R# ~W"BϾLuׯi1.pf|R46ԍ{FH"3\DŻm^N`/liGE%ql +rjB3 BeѢ0 E-FvDθDV2#2DiG?`sdEx6oJТ,e ~#^<^c@UYBr7l+뢉WHV%IV9}g mh7`",h E`̉i2ND68f va<6iQLifT=kI2TJfjUo_螠Ugť;+$-GPpL˪*%8GxksX'$kxC,'NEetLPMɑL@B# Hlj6?(:(v؂!`rVZ"\_̐JR]j Z>Iw=dB CE4q*̲Zc^@1]d!P*R؞rjn/"nvc9m44bmmID'Cܧ *B#~yĨK"lDžHj Ln4 ):N2"U+"ayQ)x~,9&?"]Es37٦9Ir= DE5aƿɀQމ<$c}}֏NrBhG)Iy弒 0U(1hKƄ"㐸 .*YHb`cTyp-@IJ874h(0(AO7 ~zE؝=g}z!p,R2--L,:J-pFuf}_jmr)w8Mj߉4A_6vƱBXtx?3 BətrFGbYW4y[&U{f<~I \ڏ:f5~U S+g-uZJjk*oJhN5)oEG@8TN `_I@zBAO/ [.ɬ,Gz&92@!&w6s&>$BoT-3f٪]Ǽ(RHѿoȽ7(Ay7yFTZ#s4%*X{+g9Y;ŵ1SRGJw3o\ȲsDUnO \YNl;e=jrN #LnnG,[T6P~+O#r=w (q{l ,m($V+ L!JmLݢI_A|*Aryp@ nN浕g'T߬~y,P f\; @z:Ka'Q{}wT>"H H(ZNW +Þ1[=XtZNJ+9|Raj.DGio vYFЈOHF5}Ÿ8t@C9˚ 7eIxꝔj#R&)TgFQ$C(0i}hR-eĘ։ᝤ`ťduU!6UEr( WFx]QhE ;|ba/'sB?N_i& rnB ". aH" 1TX7^03rF?iAg qD"rms*Tyreai?3`҃:]LcDg0s*'c,u" zϬXG)FiNhO곓Զ58(&?gue0Kg,nM)פPv0X5zPC v6;h|}O`#ɐaibCI, -ul"c 4XAт[Şܨ!XRT[.KdK@f~ƤzuصU쁵4mONr*)tRo)s4-$ Qe]^׍1O: fd>"Kuk@LMCK,^6|s?QH6l: f졝kG2_O&th+z81*Mbwg$D]ΖBW>R١OyRm>]!h͓<H6t 5٬ b44l[yx{XҥbOA[j$M.OH'֙ɟ(U2qIrQ1'k(-9ĩXɇP>z8Ԃyj -U)i3?5ć18B=4*@v#^Xˁ v-A\EC|QjV<тοNi܍_JKݓ-skdyLFfU v"hĄ;O%5MiƓg8n-(:=2ʏ8afpd%H~ZnLXr茛@~K{ ,b_ф;pmEM}7W)6(|0=lu/[MpBl ~hZy]x]HزoO m( X(.OT`+kb[nc97Az~Uj^፧"wd`]&Hf56Vɾ2h4ΌuWDh: V"qQ6ǷJ~AZ&INY94/g\ [w qx09Iź'?-4T:'(8CdpO>Jp^cRB.FɣP`gO"-xZ? D`е_Sx`4EԌ8l':* P8B&,J@e*.e'KaU6uM;1LnOM \"HRrt1F@bF!H3q% ) 8@ `Ѷ3DzssFT1eăNP=Zx8{[6/bw1CEjN$393CJv\Λ"74TH&b{̃85e)Sj&g,57h!KLĺ+B숎sxT:0T~z2\9DsmG;}h0fFf` $e7 Zqwas +d7uJ]6NBrN\$)ۇ6nhjjX$dAO0u䏂-'3{U b/݉ hKŊ|1&ˤrOMbLTZ.(ʓ1栗jJڞd՘1݅UY]dyjND}jlɍA/ N66rR.FzM^f!P9CPq ƓcLCPDHglͤ=>#0]tp= Z@.XWmA\@x+hi|:''},JF[5-Lz@3! IjҜm8r,*2@L5;$Ў*QZ[#ix@NL7M~L:T ݍW "*d|`\ժ\F+=;K Їpr^g*VaQ@}8.qa3f Ӄ%˛u̓ vpfq?n~%<=eb!~@Y5"z(IJݸ1nuZWٵ6GQ *V[1n _>G_wmc\ZA09X/W?`C4xKԵwIZrHrNQȢJe|oC8|WYl(3ۇ›ԛE{lٳ I= 䨌z(%tE8JVd`3QӨ{ (i#uf 'd "^E"ºGn8>JapS R?.|CU =\OﳆF(!'UW A3ICr%FFXnTd\p|~OΒu"2/(pyH6Y5KO(̏RH5lr_[aزE3^.mCH//|D(!LEDG82x 6ky1D kl,R5{x Vmd4|G׿pb(dB|f۸n1@e(`yH\9gATt9[kKZI@B4d& @\l1X2%]׼*4Pi% f*OB<ȶs!% 0a=2MnR Xg=elDpcJLb^-SAeǑL~"$y@S  UL8Z]'06;OGyjG9aVzWJ@=1iJhoyI>&@ȑ#jo/eڂrP.t Z/x[f&xfliKl n5j엜se; SG(+_lcA0DEYUA. B8[=͘"m̓ ﴤ|K`?&x=yd^džmF[J[#ނ}2RxIsYN]LUJy^f cH4 'C\sWy*ʰB<= W_.PJ,^H, ]0 *N)H XCr2=`&7~8VL< V ϗ:C| N3_~T %}*$~!Qlk8L H}a Խi)m*JU|?Ì~3Cmj$x% ($u6Xُ}|/l PQQW]Z#v(Dv_J{m~@бj/.fӤl$'p BU;Ô폗/v!$QS13a>]fjV:Xm`d4ȖV8zyمކV.`FuLC5L+?đ\mWL/>k4+Y\i, jmeW}NbjpْEp еV' y7=q_ŸIZk|R!؍z2 A[&R:1xW6z>BЏBAikִyMQ*`F'؍2. #^tPN=SԢ6h vl7C}+~]Y]g; {z+ NiP^<1CÕ|ώUOQ3_yjfgb !1Pur#jLN$F2}i65FT3qbdp:#~`O ƨ82 '2)Zkp8`83k݆l98g] =#A7auZR^G\\!=ӓ"b]Q+TtDf << u[֊ TJGԕ& Jh^=V"Ro&r4k aEfpI0}%=6%EH$Q񄮈cfFz~~3ٞYÞ3PZa ]nܣ!u4WCC/&}x19VzsF 2R&L%!Mzz+L뭈ڔs/b+wFŐ~i{65ķZ'J}{r)bKL>t>-?-MYWOE . ժto8f"ve%ׁ]_ b {߀Y-B$&:.Sk㉭s'`e.kaj~;9T/!'vPt?=7֤9X5)M!43|dtՎB .p;£mw<0 0_vkJ@r1 S("LPE!J8=|[sR` m2q_̃S2*d3aAZ$+hч|G+y¯qc̀nIf zIϢtJJ@C8 CYR{eȕa0gE+"^KhSgdy3),jK2I$Wj%Q 4)N׮#>$c 3հs4y!jӉǝ[uy`oxߺ,07BO|MW*XGG#7,pCHVݟ$CH]#f6\CZQ!νM fw  Mp`HϩDl=5..LiMRIw;)UXc-,GwervJL~F;_]>;ע?p ѦB)>j)/cwW ц#00RMz7" ^iNҤ8Yx%8UAATdE3`&؋#9Y9MOj&|'p[Y"v|?]͓-6hV3[Š۟h.{Όe|L$ccABT"9PB0A/ZQEOH&'rWd6SrlXA 60~Ia3bU._'<!k倘 |al^31gF&>}iz#J{tdCMm> ) :NS0M*,HۆAuiik#Ur|$vZI5y 1#~љJ-rym0J mC+ȨWeo2 >K9^VP#G1z_ai|-]"Yh  ~5iRE=G^E-SCxO|!vg nvh+9bQ"FN͍o ЃtUow>MBɂO|(MQ|iV >=$2&ґ)bKǜ1x(&kS{->Y!d0*)ilA2o%zXK<+'b}bN8>D^dDɔfTS1$@~E&;:Yut>$ب_D+eʡR,JYdx;%r "sՀLU>skIWF^ K +uL*r G4-y=ݤ_n_BTP 1$ #fEf&@ls`z.)5ϗwSm-e{D5$fŽh&Lj !LjBb#{%o IcqQYv\X\"Y#U C#~>ST &U BohdMBzz\C'PɢpEhP~c=_^kqBO}w҅.18u /A竬Ҙ/Q|gJ4B'ZVm/?^7xz Uy4i M@iEϧΓ^M=Pg 4=H'aq}Gўɉ-6Y}W&DŽXV SXՆ-UЭ}r_,n臃vcaqljVD<<7smas?y;=Y'6?gl%EOsӐf\ T?6M&ꁟ!Vdȧ:S姾q{|Yoݗ|8;' Ov.t+[E?mԫl8AXP.qBx_ l3+fZ.X` VZx9[(1ar2fuَ-?.=~h#)_} h[B9묂:%-˧s{xK d C!:x"~38~`.hG1YGZAx:!'P^f&n샸d<ź6 xI?A]>m&(fuHeiqe_Ig6Xq%鑌Xv|:0g|$6n/w)ՏzG.ĉRo|Eiz@IDAT},QbrΌlAK4GQ K/A8ܝg{ +ڛ{;`۫.cAe{rCTVHC^Nvkٕ֑#O0=zƐVGtgP\gK/@L$'| AßSh3YWZhe@(/ zwlO e?UQb d@n-y.Jeˣ._S ecW'[zeəFN MA"_+kYteH?gl"N$&c&Erɲ~Ľ4Zxs.VXE\qeeJ=X<_a%ktz_@-8S&VX %K_:|냰LqyH:bFY[>s7NAFd3ȁRUec ,kc[zu:[*&`z3i1a@R0IZ*c'e$OQ=(b-"GsY\w#bCpy[@72+MzOpF6=y2JӱBoI} C_>tJ4cc\MQuon~Jq14=~ nωI=/P u$E-^MP`D\`P 9%L%dU:䥺_YBM=ܺ8tJoeD"qՠk羚~x3kPFIsIv<"Bi3UtX6Qs7֍nYLmR-PVB"Hny{]NvZH_IEYMy\ :L:bڠaGZOzjW6r {y]X"Ix"+pc^oBke{V91t.2 䉅@v|y'Lt\#*3@41 F[JlPP K [U2f U1C-pۏu`JA=> l #^#xeT#X_D(ܓYBc *9ѫdܠIs, Z6YN; uiM݆tLdp#\f_z71 -l'٢㏟/^,Wi/(8@87BM|ưKօA;HgΊCHkllK[S3Oޞdj"w1 .u-`b*kZ9b "llN*aWeP]XP&3 ,&j"vڈսVf-V[VNu9n"PQx9g7v3RfPk0M`J⪦BQZ& QM0UT-PkW+)}S<^ACLI'Xzs54Dgf6=hf |S,nP6;t j T+:,x6!2\,ȝ)ăcLd*#v>`% F;gHGsXK|Hk,#Ӿ`i[##I8ҧ`JijM?T˴Nw%ҫ IiY<\ٲYԍw~YEL|2AOVO5e2=~倂1%V3t쌘_Pwǖ[h6Z1 %H:h.XR615 \2'߯Il$w<_ſA4@$kEPgZDe3D, <|:ctIky0 'MnNc({Ƶ$dU@|pП1Gbi΀mKXa176ӥoNӡˏ !Ϭ:/n~+zl`_^H^8V3dCHe>{@*IԿ#_&/C7rG.Oٹ {N`?7j0Gixd4WPl0kVmVoEw}J*7ƞ49>SՎ5ܥ74)|O9kqJfa6`aMIݠ㲏A +MQ2y7Z"Ip ]`.#TaNڡ'֙3&eJׇc7TN uTS w،$6:w: WE(aNxr;_LE{,Vf? \nHۆZGXEY^@H(fNY,#g\>]@tY8R)=#~~W3N /PArH%s߉K2 cPmU˺eC֭# *zL~e))& @"פ,tNnw x A 싋mYcGA w)+KPK`N_s?Sb ƕ@*_$/cxx3҇x `eCʏ 2iOht!exZNќ+Q;'?_`6vL=B`a<ġUoQIVwԊ^n[,JT#oHA BF'QƪD?5yM%mho"njMpicbL {8YTLezFh.;64S:c%LhmbUf Tz j(^'r/lP֤+̨R@~¡Ӑr2]-Ͱg NbRYnRA fSfbFN nN1Tï T٢h3zp;AFƷ 2(:88 E}8::KvlzGHgYaf'9U^&vAR4hF60$lIv <)PWdorz4$P0,_7F+Wr/D]x Ԓ3'ŘM1P '-^oM@P-Grbayoʧy}T傧}Mk=-zy^O.M@J̈́AβbX5?TH"=i8)\DqjGJQaNjh2!?Y3Pj9 .lT֖-vXn$ƂI:8Wyl, L)D|?GqIij0!C"0 Ja6f(T^a+KAe%CԿZZUDYHo4$zQz_Ĵȍ /FΒbTwh)b4H3 *@v`Etti($ Z;,8v0v6,XOCreH(.t8U79%&FnȪBS~uGmHˌLC5uQ6E/XD@>[Xސa/`]<f9&˟ֵRU#.,m$H1EOym 6 3ь4L@H'Rђx 戟KIA/R^ 3ÅBC mu9ً*d ]>MF*`dt'ϴP3KckӘ>4`2I^@S#);,\"Zk .@02Bp}6r7!V|Iɦ,BPzlc^Mڰ+p(Z/Y37񭳵 fcGqZZ,f' o|ŝor+YM=p]ϣ H$HfpmUmD,J: ȋI[sOٺ L>GD)4Fgl&QЗڪU*]"h%wD#4s&~_fC LhH:Ĥa!vv# ӉT&'kVEBjgAP*b#d,&䚶I̿R VmIvq`퉙Г Xy@;`jz#*эw!NCˉ-~rde&l.".3#&w({3,vA",)dAAdm{)f Ft\Wn< N J=o^b hʏ$lK-""3:pdJ=">A.~boytRw`PGi雊}+]ZHKp:jQ45R;pָJ$1SF>Gyn` * "\= ?߀)R=CkK<&7%9z 4| o?VEՆCFS @Pf^B}˙Rf18vЅ& pOQ4 O#I-+7K[$4!H.Q$&bR"dx@3而xV`T*2r/ֲr`OS2a*y+PaW ~Y!'HGBLM֨>pW lûqr@M@a @a,[(9 Ǽ=ÊƱ +L_fV6+ |?oNAIj!ub- VQck4σ,`2Ar O v!d D&5kͩ3c ?S_6y({usF,\($2T[gFVةJҫUOvK>ch?4yi։o<7r.$JɊs##fԦ{n+R&dLa4p; M [:T0MOL,4c"~$L<%{"R,eӯ1x (1%Jř?řdt;:͠U$1b;,2Hrc&{\u"g*)P$6#ss4IFlӂOu6' "#yJ|l>a?B<Դ_)!OͶ]34;2W<%xbS2-)wj Y,O1P fmIι' 嶳=R9!'n*Zt4q$6zf{#Q4lD {+&~ut dr?w fe/aԴD0Cۮ4EZt0Wy^TbND\& XҦ^lL;{յElEa_b,5GXĻM7$1dQ[6ױ4DV9`6BĢ],4;_H J$wcʅ A8쏶ϷcrrJH J d`("?14ţ:x e`f?P<_\ΈٍfM`&՜O*~lzͭ7'(skC-eEkzQR}y_W}0 ,p\;D񈹗ʂV LA PxaT#4Ǵ.ߎA.64>$(ܴz,"6Ȳ@{ z;#  GK;EgedYMipbO*H(Dd.n[r(HaYr8脴wO^UGԩ([!1tuu>+! 3|Ru4CzI}us]t\̫Cä܄>CIlWjH4+oKj-VҴ:4H  nzT,_>30%cI<>BA'SGCM\pv5̈mnN7UPў_vِc㠠܎to/4=4`x"X R^PZo^:"l}@)yHZ"FHߴcmۇSGMQz$LW .-ddž] 8&#T/ol~iaJo{*660Ajū?Fq:CyNث# H HN3zKCኇbr྾dBn~f,2öRxϿ~w;%??=쭗gкU[?|y[vD8"2J M'QPzIJe#7hjTTmr;}:JVoCl,jI=?v_B޵ϓ݁[s lھ 7~<mq` ҵɗMHdϐS٬p)5qFvkK빒8tʉ!D;:dLkqOQ{FVgqףٟb6b8D-/EA++.ǥ:?0H !)VD+zGB. oH54ʭIl SY8r|ݫx7kW~inYR7d^{LydM; icr ]%|jc !&r:ڿ]vlڀVī}G_RG,o #$C%*@Wdf((@# )2w۱).>-V99'~ @Ae[=r I01l#uLt!(4gңD <>/Z2=/ݕ- u)'IIB0g;W͙mi G.th䎐><:Cv-Ri}q|'XQgH^95$C;dP~*LiV'lc+o/@OA%<#WcQ*>7sO1&}CJh ):K3(IHr_ԓ#%tXE[+g2WhDN"jdO"Hk9Z+XB3Dmbg tFU>*##xح.C=~!aQn#9)aPAvPO0ufR#BOʛ2$lO ^h8qkL" #$Ý2ZLKX׊W7eWs& E*w gDU 06e[H/0LѽGX!WLL :UW={N @$ K5+.rԼTFda>Le95:K14'v_Rã\?@1\QmHUG@Ǎe0R 58 $$kG)ezo*EI]c DD4I#{f! ˑq-H<=L=ѐ l@S] Vޜ"v<ニl>1[\9up0nnG=֝ՠ(~z_NWt`mqƂϳ61mf%a-m[Pĉx8_{Ft#l~@YKm'@gHIPw,3CaV_ 9A;s|A/IRe 9@BLL'mzFGE@ v$s}> UZ᳨ps&\p͍(Qn ii׮S~g'<{e܃.j߉c*$+oV%)KM5Z9셰gnܽ1%]>9Hw]4v^RU{26&>3f H8 Đh? _U >zy2DУRkm[!Ha@h1Px3^Q$7L 2HDh EF}@ f *Ba߈ib_#3 MHSɤH$\$2gR-Y8y{Vx~3z C*߰[Ͳ4HAO4@9fV`hFRuE}&!Ɣ" `h^!61vhǓI! M^<"h} ʖP쾕1 WA ^FHb 1&@?3qXfy̲@Fm9Ή)=L3kyJV0ĺ(jjmyANe]#} Q#; (V@[|eFw3_˛ g9b Yډ3Ü7)TḵY}(#+xܼơs(h,V0ƹ4zI\tYPsxqt*Pz P?Fp.6ॅ| QԄ,p_E@WAccPsLT7M>m݄q!rcDsm &K'Nl.S B0VУ< Ulļ%Q[<dTg;;)6rkg ;i8O[ۺiM&7t_杍+ {cn|![))! .>q 9XQ߃^qz2 !b}8`U6]VgBJW2ѭH^X~H@0(kҴMFPFu{cBNbk3D ~1D 3Z\[9Pbʠ>Epj ()OnnR_c| 4: b"/ypi' SIYӐkj0bs #3Qޝ PU5&* ,M .ۧNf_[*L>[E܆惓Lfu'.bw2L=0]y  0SX[Zf=¹މY.;;\ Gמɍoߊd<dZYBBZWȼ-M֗gLh'HBLJXY(%tR zHݚV)he1SUkeIlKkmRy!xka}?34$e10j?M 7YC>垮L-\kK3ôs% p*i4!/pgM3d|(A0zvw`qȵbf:ai8W XU!vH_yBV::$LP[lP㒽{LALǽ hE wnHHO'@My1b1)̈?݌:W#]e&dJ`&<>|6c=90f!)!OIF(,P.)WT)XN `xҁLbZkȡyIH2e4~kiRۿx5{ٛ =phXl48蛇y;*[S.xt8G)/Њ?0ahYV_Vvb t@;kҪ۞MȘn6X!|fR)kboҿnSF7&֥F: +^f\RI9T[i@lqauTUUC*"W\G Txtreu4nM#-M!"p*S|ݘ՘Md8 D@"@]jt!$b~C8*@0j,=,u`" 4Iu>@ !f̻ V4d~ Pt"mQU`"4kxPzĖ]Lztx7OOvC'zG86ԛBCs&Z>pIYqɬ像9/^qOz1iO04vo\JDj^c@p"UdX1b+ ;wۻ g*ICur;̋zE-5 }_B^b7Fadqnw:PExlX0l\5[B c~n0P.;9sd%#mot*=ƥIc5yeU)lkjpٙ~_Ap%/"~fkx huS*IMda@+R|xP_pT ;RP0V5*Iꍘimdܿl$l^X2ira^cĬ#!zO 9Ȍ@©: |&SJH5g0+g^5% lygT ,wL`%HCf{0TP{?T݉rcGa 3ҵK8&PR{feeUJT&0!AY4'Cq.#T/[ZI; .8T3@GaM`D&? ˘>-R#6D JB*Ҕ{ۢ4Dƈ$Lbo8+!K^˙ W(S*(CGFX=@řP^oD4&/!0J#Cu*<ѿӾbk8#!8xOexg! !AR][h4v F$Mо6w(T4neWt?ZaWVbF&g bYI2J) H#~IK6|ɱ*焗wȈ4kFMt5Ũ[zWD(mTvUḣiXIOCǏ0wo֔#r\ʾƳ e 0Wڨ&sLc:XvPoΦ~yymۑ<[~?N vLu ΰ5-4XR8iᑅw!N:hZ"DLtY|p@#̜$aٴ[9X < jk 콘K|D-D.םBASv|LIWĻuIkfn%ҖM$:zdD.d/}A+PxlgGltWt:B,\ O*5[؎BP[ي 8@ $δu-A.D3Hq8%ԼTeQې=?}&= "37 dS(d OB_7!.!pw[ek#z1)Xhv[BEފ23]x֬k@R9 ? xF#^ rfRŚ=bA&[PI#G 8"'BR+n@϶i!#̄7Ckd!V̮췗Vm" u=cn@A'F,k#k j87J,2Id1=lL-C P`e]'R} ꉫb3"&aWS;7ɴK+1x?@}LfWm'&70,H/헛ҙ)ܝv{Ԭ6oBi&qj uHNcjE 57K%vK  S3 Fkk Lſ@zJsɏя NO͘ͻh_=o+Cϳvo XnVoݼ5e2M >D} C3y\38kjDIɤ*>"} @)C$T#m@*nʴnťV&msEуz=ke{I&>2/ B6+OYTmU)B" W58;Dh2@IDATӖ`˫'K6J\z)Uۃܞᬗl)6e% ̴jƣFUDc. \B$ 1W\?) W$m6Shc 6O?wbh3 2tAJ)JGE f9}[h!kͲ 7ε̻Eμ|l'`Gme0\!M1{uW&fRyaJFŦW)HQ="ԠUof'cګU͵OJNVkK%~~2ώyI=nxwfUf HzGe iz03?y?L}ጃ d@8ft_gUBBKMM%4ΤlxPkֵcv۽f4eBAu뼸 ܴB|2UpL3"o+ٺU*H Avj|L̵K;M 02fQتhS\T<*K(838ϫ\=y$(aR]ۜts 5 X+L/S/N-$/ Xz),#ֽG0;,P;wL1 spZxґ><>z<^l9Y/J=clRmgN.RY$=GV\Vǀ!Ga"  U}!v2Cgl.'K:DGn@vVáy144 E2͒-%5qb [o 'ěhOwXW?!2 Vq\ց{=9 ̊N8wT/<o_Nzw1x\Jsv8U BQ 'K_Xi "V9\ag 94dيe`*gX~ϜAa;F^dv=/L2;@IgiJG4d_Fe]ԯJнEo[ƯvKxӉ2H z#ǠŖ'sh`QJҊ)P%xV4kXdOˠw1| If_JwW eFRzfB>ߺl, Wx*iy )5 ޜ90#'ljeC*`k\SXā/:"Q6@q8? $a &@HJgEjMX 3ec@2~I9ESdVI]&4褎XdZU:buuS{ѱ(Ͳ/ۥkBX+ U5t30rxڔz't*u?d4 cy-Fu+X膊rG4k=qO4Qd)Wg: !6Qf GSx%n%<$2Mbb!!˽a: :kwUqB1NJǠFJA#c>K kf˂`BRrkYL#r-Qig`иƝ)!1Ud) 3vf<ϸ- 2pPP,{\$tuk`bHzځ-Ƃ @c&7f J1y *=M-`mM8ý6$ӠsH4?|T.1Bx#ćSEI4UE&4:8WSL܍PGo R.^ijU~=#~Ė+EH| aiEGHh!:QϹDBuS2-Ť>p)S@e$8:1sqn6O\Fh *-N 10MoCրs uܳ9Ll苍Cr] v!~A9kwЌrԵIfϞGeTQWp'tMy0J7=>%E0Ӎ;MlVN('OnLJ0`t53~j(o3=T6pXK0bdgYYy76{O+Q$k:4i y %!SGU⪑tX`'x4X-SA!i[鱉虑's E".sh0m Ưz 0c`j&^1xk"q_íDl5u)b̫4aJ?`a/;~SP$#_QQOqPeN]6mf])Ds3bJ@.C=R&Xq;^l~TXtd+X5/H|0NJwr֧Ih?nSY8CF7O*Ȝ" PF>:J:S3h+: q}0~6_E\eApk&#*2Hse lUDT:-[Prd`6‡J'9Exy :=i;N/0)n͵ô+2Dzm r&icDJsYRJV$4h5A$8Ğ7jXsOI?v}LjL7[?pYh=R`+pV e'w;PGH6ڐƺxCaB, 4"\/q$ara2};6mD()N1,n#*D$0_Mu=sQJ>)ha~8F*aDAoRz p*k4D# >]Lhh(`6 !ΞP&[d ׫2Eك [RǤJ *ǥɾ0-,æ.D ݁LX|Y(Ӊe}dq/CID8AiR79¾{ K1'Q?wFڵ,AtѧM9FL=IJ'nz"IqJěa?h>V Tͺ&i{2.]lX(w %@6aX.y{?7R-bDlO>?toԍlA}/SX97_HzXGc$ NW3Dڮiگ7[O)d/9q78guKX_ Sn_Eӏ_͘ $&8m}p&PK!@XM.U%CBRˏ!"MK@'H`'_ro x:=]?d8R:No o=D8e@4y_8"MixGΐ?_Z:H5MRiI_!k͒ `C w"1ۦ]GnyY䃇3cp@lA|m gvX Mۦ| YyKC1N VxrȦ(Wh f8YTR:YIS _^Zڛ4o+):!G#FV5h$bli1|AvZM>e,B%Uo x۷ˇWwU@;:ɘܴ\y2hT8Ȟ 9 elSjGjI҄ 0ɯ:Gt捉FR"a7,s RHyi 唒oQBҠI J/rYɄMSS<nfY^3UHWo͝{WkEeX-$ FaDf$.)߽KeJ4td)I(8ɳ8vT\ba! [D ڂ#<=Pd#9TCAXPVt441[z=}ܫkNZ" MQ13qw6L Ԇ`VbdYrpVgvW ū{^SdMW`<(A <Àz DzSZugB(`ZVGPeu S B%p?el\IzS+3^_H&w_:~70PޤI>N`GQ bEt9b5Q|6/?ƖHE䏚e}QfOx(%#TpOn.wwhڱMEmŜzݲGDzc,ދȳJ%i-,@x1IQu >^^#@9cfHDh<`؀dZHAc#ʕuEJ$ҡX^VeGt[e0+@zNr\xO򓑜Ar`H^I:Α`bxP^+(O1Ћ@k. NئH ?!H >912{qA~30clvG I9$p"rwn3;'㌋ƃj3ۖML83cԨ57)E6eGv#na揜4n1R /E d|0`$fpW5VcZYbT`l;SbzoXGMEC-W\`#pXc)z #jn-QI*IEh0@G! v9 2H2C>smaѩZ|J2}҃H 򠝑5nzȻ T<%酻H#خ49s"^^u>yPei!1XգwE,j؈uyqshc#)xi0V'|T;lKA+'Q$-<)@qy˜ %J8OV>f Il7@K4`ğy⮮X3~ 57_q@+d8vPZ@ϻC >w<Ub1);1,/@"F$`68L(l ״HTH#C`V! VgESBi A2vmSvclm00r579ذ-M-yA<%Hn1r8W `f7"iEu(^PځXEKE^,}1ْ ~;ή0с "ڑKB((Rfb1, A#"}@L;U{cI CH \?ޘ,OFKɱ[h D/8 nHX?ŭ(?'8X7xE(FEf.z*q40bv!+ekQ~z1ݔ1PO, x7LFf@hK$0/%ӳ.2h:in?)  d.l2h'\LX@~^6g7Д;K P2;]'JԳh p e ,)f (uq4(4Z6Ml8]/M5|0LW,*& & ,ڮ{?>N7U4_%nN-ƨxIYRq~ٯEKg[a2{5@e󨓜4C=QE6EQ;h/Oռ |Oex6H9^(yv0( eRq$j-' \D]n{)u8sm9L,th^0Q,N(u.eJҿc繍bz~e'R xK&2ȸFSM! 2МJ C(!)ؓ%FY֠\/8S))mVP΅~h(K3ݫU!&̓_jit_ ]*Dbޓ<1_"-dTBJ(R$Wyz臢Ǥ+z8)F^um,)L+,T.+:S%ρCt {sN:'H\c$=D=7^bN HۗrqXrfES:a o{0(|QD{nQӡPz3i*ٮ[ ȗ5ZKQr}}b¶n>O֚$)+_tGx]_\Hì0[8)[0x>"}ICgu_u)̧ p%U V7kv.3"J2lKDl %luusPWjq< yt kG4MMHpJu5_q?/'|" ?Ms-p,g:QCOår9R"$"sM&2hvRi#j[ѥv`bRRqޭ<Ú~|C"ǶfowNGCr ݉шw4c6 ,(_ui֑+9q;ZCد]Y/~zZ0q7J ]0цw{I3 5WmNj~T@zmJ>jU9m&|@jf%/4j@\V(?6{k@{:s-&p0Ӹ_gQ/3}{]Nb`]ш\,Jã %,Pd}tTÓ{@3o75-jmʴeEJ$E.@9VyH]dOLJRZ,,z~7Ex+_$3o O:d8\Y^mE!hc4%Md-ƥ&'edq)-ȸFiE:fz% C/]"2Wc ƔڑvHH=y| fY"rtڭ`Khv=3>wK"j~#+* bAXrhmyR#O:#n إ,L3"cҙ/b9̫k9 C/W Ws9qEޏkȷ5&蒭2q KPW'+(n,E,)oyd01P¥ 5}f,yQJ@Dr&\4&fV=!9*^"BPS^<(eӌ'< @cee4fc#:9'@Q&mr8p7.DQ-$ֿ% 7i`}? NlϦiF.ѓJ$d"Zcvg4^ [ SŁiD୔5CŽA= )ק% ^,c$6<)ON%Mjh`2 +ʡ_lY&h~E78DJUqCd 6fWƝ1(k}x U}%烝kp#4NVm ;.9MYBx=qgo^M Vx3oT} d >%&MEյP@JY즊'B:R3ƀoFr$Wc0I*Q !?ͪUmෙD,vS6KM%h䇡O y7s1$懯K}24><^,VP⊬H^hFF49]. =QðwVB^%.'g͹~tQhfEo9)9H+NLdf0iW}aaX`X1%^3U sH^@;ڔD$V@LL :-=4`89k:w2=|e<͛&L~4_D/ v·G 2M#*cj(4Z1/Clr)?QbbBh:GqƀH8!9)U2j"?)ԝ`_L#g9rڊt!{muu8@&rC,nTK&8*%'^59m%>qL$vBۼݘacZVb,bM/(W׉UMK5t6͜/z鯈 LK ^2C!I:'<,eـK 24HlLO:0?g9پH*CFRz2Ha FuPC~U#kVoao۴&̱/$O6MZ%Brcz&<VQ,-Q|'jxy:MPy$Ijz^ɫpV"l;j8щ,r 0Bo5 {\ -7nQ,ө "Vړj$}Sw5eN0lPayZ,( 5HxA #Po Д)l_px `2eQ뚽0SwFa.ub[h;.hh'Y]*(NOsdFch[3hz=APD*x[5v'#M&§=`RX툁gvdlNb@i-9:Z_7J|H#UTWWM0`6&蘒ؑ. ) j_8OJ;}ZdT>iPPaQ]? yiNPnѝSA' y&}Ocek$] wQv@S߅qŎ)8+D(c#ĠFG1 D,VĐ5ςFywʋxW/1UQA~d;#\Hi`*Eћ/)a1#w6M xLښREAyn t5 s.eɞΩZu  u>2.,$3I> *"?x NdIP(?J#' f i\uߌ9p?}$xʸ4eBrepl/%NGb.P/ig/KHClUGV3e0 LzI{PZrÅ1좎`*-HbsP2_wbz4QخD7,:m&dduixa+>,xh¶71^Uv"ҿ_Rgeb^BL?8̉7gE1(|ObR>p\I%KU5E p$#OR i6BIc~5 +=zJOHCtԣJAkƊΚ,GbQG&كw վ8W[|"KE':ڹld^Ll4޸"fMc iZHӃ@Ft^Y}  JW3j? D6>z}' pM 8G r!j &TXQRaԖvjhZK'埬OGno4nGŊV_1^~R%k`@2޽hnڴՃcTYeL^$J@1 KE\.w-gsMt\P.%Tްx'Aie'p"bSN1qѦq$X6.X5X&w?a6!T1net?^ICpg ≝6mט&0W_2Yf?Ӗi96OrYFrM!YX[p@(8P⡳*rdg&Hb7s! eژD(QrJ6Ki2Rybt'\8@r@,B2(a'>#qН]Q-m,jq3@)nDEb Q,/<:R4-]}H[%щ'ce<8큎eډ6a6mY.dQ!j4̹iKнKm^5T#5 4?Sev0vpĹ^PI|eGb7(ү}Ag Kv!Ha朡3R M@P@\1 Kr5}!t%oKPM[}0/Cf6V`+psR G b^*'k:8]y4o,^lQ%׌0 .аOtH6]%sdS2CYcxܻN>؇a )>r"qMl6eZEZ%&bxaG@ ׊Vb,31>Ӗ$/fcHC[ h v݋iK`qjƈ+bxKエH"Ӣ^H\Gm]$7W΅FGw)E%8QW<~鑘V?"6U5jщ {%#,uu*fEGP갶̈́)C҇j׼ ~qbRY#'pQGϩ< "m$в aA=g&O@8`f8\9vԌ\B=iO.5'~i i`MEZǟ>*k\5>Z.3-A\ƪHյ =lDUdK Al?Eu+%[\c5OUGo$ Dа?@I ؙI fl@|d,GOé`SgN )G^m|i_ 6<ϰ2oe%dAl~ ҪH 2 r`P$84̨Pe  !iQYe]^X7)w>)+ OفN֌1ϸфQd >Q OGtaTU{5HusȐb!"~#0 &Йd${|.8^Oln;ҋ^hl͐K ^dB>ZDm\Ocs]lY$4g]D}NJ0!8j02k; eNv$] @vm5F[H#x@k![*#ΞJQkPi&4Ҕ?$~gӲ>tx ?Nu1n4gv̒@IDATV\@$L``+&%ΓHXHq:ddxJ`SrΑs` DZbҷYz]5?U)4:@ ,qơ\@QXͳ<"=[dM;2{Oumʡ @ctJJ= Y)tίt; ud"b<3x:z]MdK?k!N⨁ E\#WobpfER EMJ/b6:/`lPWGQӴB}#{899|?.0VҰۿ:Scm!P*v҂`]_gВf%YTbkt3-4'Qm|6៝?/ 'ez @]-n`>'_nYX54 l'q7WD~s>x&;2?d?2a9{^;w޾~xUx)ԘIpsAmGHE$X`7Av~K3`N .4)=%6[&fteuKy}e}~W.?9.Q!6vܧ $)E=Vߴm~rnqa^u ɥ` i"vȵKjAaʾn~r叏q˃6*ĐDyN}[ D>bDI TQuCx$g5X|>mcM/ 0|ihdF|g$ 0e*0|=$YW=nv;It &y2]lVs&e_+]?|)d^w8NiϬabo!6dT*"o~T^1*CZij%Qqi$6.f:k%h>o,.sGo7 -Y/AGæ Z}khgu6RLQ;ưGSuS]ӵBPޣ܌$ymtn#YyeXd:Lp~{֖d}E7Y4Z!v2? mc!B _AѪKhDϔRiiKlq%Fsv; c/H#t@Pߝnk9gÌ'Apy*k&F ]2QR[ tNjVo{ HTeR`yqFvG6LGnjhίw4$εSCWec&" @7@مj"n l_"f*zftp0k);M R u5(%I>dȩ> /k tF!IЂMzR7>Y5 ,1ՙ\d 9,*ZlQdO@b[/CjSF(z/6_չ4 LvHSp'm,2tbc:pRJPN}^RD DVHD&$0 Jl92BDԩ?-;m;zg+1f%Ak{m1KGO>!i({|f|=cP֘GktӀ4ZFlҐ?P5Ըdf OJ-˚xm H.n_L|23{GBAO| mT1qȟ ;]P4qK^|@oB(ڣZUW k<@d[< 'k|,ToWA"AwnRM*'/ %wn'1)cJy]?[LM -J='v˫T8DZJb+&죮M"Tz~F"%hYWT /Q T;z8R/4ߓ덇@B>i`1~-,LA NhI1N\`k3!L}Ic j$ {2x\ 3լ7d䯕PJ XMÝH oA!뙅y~w-miONЙ@/OyǛy7!D@Lsb]i 8'i+H'ҏ[ѩd_d(m+gu; p=>КŘYOdx? 1c樑,Ǜur/I`!}+qBˀyȨH$}f/?g7'/J~f[( ة容\͔2ITw=:ȏA/J&Uni00I?b H} @d7z}V dHsRig[^$ؖ30GLKJ\^9 92-[?IhK.|64IQ0QMS#h_cװTp9,Mk{@ !`D"ZVOa&QiZiB,;m(1r$?hϴj=ɛEbbȀJK#$(qϘr㓹'2'*Aʷ>h7l̢X*$ ŠG$-&'@+^ifXTЌ V Tt0٨*Q@PK9M{ ›C`o_J$Y3n#QfJ0@N%\,j68NJ:Zi$#$ =~zlU@Jτ7#uAaK@.f^d>A=_}! evJAᖚ2|VarjȶM 2 ɐq:unIنybw$Rg~-Ϩ~5xvgRwfɓLohE @TF"H>' Lٯ Pl=J&|ʌvRҥ˄'-Kkuqd25%榇cbTj{ x9r*Ma&\%sĎi8(R% P`Q cpD8bV I`{GTi8޹M3qiR*j{~^ʟ}IMUwNZjH3t?5fEY;CN(yE1=0vq2a-뮳M(: w3R/j&ANfXU\\grdmLP7ͅlYt{D#F1(5\z bl-e!kJ2gj{SkgfMw3lL,4#@{^a02InQ8*FgHN=kgyط1H]ޞZFG 1ɑ֮Q pǰ57/++,%~cX< ݜ(Hku>3\~&>M]842ä~he'N!C?cKL÷dB^ d[.|:K 03~ _(MP֖È/IV6Md)z\cc;li)CR>~fPӗ“L1+y>>}:B~&R0d+>&$l[Ezҗp"JR~0a!q+t@#[ aUKq%'7sF\!-"~\zBu8D%*&JCM2`哙 #=$-m ϟD@ 2.O<,QҘIQ|dB7k:WxE愆I7)1 I -gU(UD[ס0"Jอh1hpdxBJ\&pE 90{Nlģ*Al h+#jSRmk՚Llu0S*"?z@mͿ"Xg_hY2kw`]p(Bp.zmzrAv#C;0K:f+lӐv"&#V嶶U$U"/Q*RsfޥJ 8h(uRMoz!9`b`3b 4=-OGm38ju8و8XPP<($X| 'OAp%A'C%VЪLjI<K{.vȳHkHvDF8h%?5wYT#k1rgYI|hc@sM=WH#dB2#MNQ rAAx ]hxy#31O$h&愕RN%`DOUxg .=vӰ/ɡ=p=?i#)U{8)IF_>0ɁI=ΰHd ]̑AuL(eXL\ 0ԯQ&ߦ)GbplSkJ,;e"Cvz C-_WM I[`i$\4AJN&@WiE:f)8k:69T<~8㩽o+d痚$ꔝZK lF ?݈}kJ50yiB4Zʶ}T+cƟ qAHSmg @@f ]68w  sltI1NudMMF,a{Xehi/Ht^LJD<~hR+'+[0+uЁJr Rc_H:,F!Ĉm_P,ui-E"qmɈ%o]&l\-g4Q+b8_L󫔸 <!I{\4^ܦ$48yH´H4k^.5-NF/NFa/lk·&x3ҹzcRYivJۡ(a$]KT[D@Fzr􀣝!e=i(0oH]-q^bS".354SB%ü8Γ~/UnMzB FR(+nN-f-T T)5|<_J^A@ S}pUޏb$Z:L ̾+6Ҭ.!Lf-ߨQإK(:okąe@21v n6-Ωi>M YKr X.'lu,5Z{4gE?F`3aޜl& 0K ' 24sddr@j8Z Ejq@V 4='RÚ_ cYT9:}?/Xi?]xzipZY{HS??@U `P )e=ȥ{pQ;$h-~%Ec½ޒR!1!Q_#Wv'4> Yf,è3~ ~"Jk JyDcDЈwqzOjt>Mmjj O< Mǫ)lբ le4(l@dwIp4$ǩhDc 2}wOߐsdD*qx^&Un&oC\VTcHmYZ[1n3|~ usL3 vߏNUԀr6ZCӔ8P{QKУؽ2'Ƅ!:8qHMFF7^BlYI?[Ԏr p<`IE 0vůOGNFhLfr!dTfġo4E][^v;>b)b~zr` (:ظt{ %l>B*Cp 9d|@E2N7Yf Ͻb/Hz*`m\ĞH??; ㈼ii J˺&8Gct5ꓘ_urk)moM Ji`PuqgSԐ4u(lI0\6$S믳 Οj$@ґ Lܙk\. eTp+>#6#?Q,>$Hw-?m#wvg#)ay+Iq,nR((i6鯓ЖU-|]:\OCVEv~c&ڮ(0w&E P.솧*,R`[ǝN F|m<8Wבϗ́Vl&ﶲPJE^fr}KDtgˋ~F屛,L@DAナU`v&%&^R kɹ4$,>Y<ߪ,1+7bSwJ٢6n?g.mtbU:O@J|I{;kC,F>ؖbj7g8=~8B=D%Tq~9~\جj窯+wѱ;Va}=P2x"L^M!]-W2IɲLmŤߜ:w7g`ڣP Tywo=Ʃ? N-/nRtCѨu$aL_-q{h%bH4 MbNp`xBTɱ|gVuw>a$#h)L [vegjO*@ܧS Ǫ]/U `8FT_`[/;^VǺjvw{#2t>܋u`'w2 v?^lMӁ$ <Þ<9Y 4mܗp4$$td&)b/0Yb8:X |}8wT3f \ÀAL:];NdB/v|N/ {ԣ+PciNgKJIV4sJD{,x|{9ȷ 㦵3S/I|42(Wu pyt؅HLMiKc)-B̨M3ULd5fPWn''[ڿwyvq,A~dT0_b{}3M}vcwp2~3$8^w>:5!2p*L6"&%>P̾ \a;:R =`S<uMscs`U5'uB@\q5S>]`~%Q Gjm~{^;g8*?#KfGqX3K7tzW8x*S2CfmA+yC 3Q+fQSxW<(C2 OYe[AQ}d̏}N|{q̺  eM~0F/ʰp0%2T]{ݏŚeA- 8vkƚdRj`&b(kBp7w/YBK+uV#g5bwf4xl9t5MU"k/s/:tF|fWL X( br7W(jaM(>V m֤O5 ^诩R4>=0BذVYQ9eVÑjI#KPH- 4 ԛa:CmLLՔ۔,xI,|h"S\N8L9 9tl8BpiyyKݣ\;z1`|;x0^A85dxO*=b8dx`L& ;RK>I l ̍GrwdN"Z᢯P@c9 ߀yӤ]PQ 8Bŷ0l1zxIKf%,[n*X,F#:Ok\*Ke|ik]y7XTr0K0Gb eF.+w;kj׋xk rKJ / =ȃfoH+95xܧA1DhI'5#:$\Gƈ1T:d;r dQ0* ߉!u\bN+乻JfBLh;K`!83*~pI2lx\+My8#,ե(ی*rvu~#)f(,Cb_=ceowK\c 7II""Uy( ԨIGo%YqJC#@#Bcw"{&YZĄ/fFJ׶ģ}{[unCSЍr"I ʼnOaڔ3?AM8JuD1*LD/05e p7dj̲%R]jr~ .O ?7zqXꝿS `;7?#*ׯӌaE_VHD,1{Ҁj Ј k1$L!14bzعTags?_:8 rbV93`qE͔68FőN*(TR% /@{'U8Z.mCdJςj$5]S$9@ n/VUzL4[7,)hf(uhQZ[a7܌"f:t` bqe<ΪxyMY$)Q4CZ@-Y +ȺɡaxsP9o8=yao(KAQ3PyYݜRÁ B~rW|W]JIi}[Pvܪk)yzD׋Evf`"=pD&;$#_EB3<}k+MEQcN+GI| TҍXs2F:&LƲo uH[_|K&!feTUR.!KbHL=z0 aDaF?[n4Ad*à@#IiG.<w'nV\ ap-SIAk 2sѭ[gi 8&`,'`a^1SڢY|acE],; x2y-y@ 5aIG nI8˧0EYX7v:1n.r#eG{)w =L48,ZfÓU'-J6+x#J w#qj-T6ĴJUȑFG! sp䫖$PGZdqQ3J93iޠ`&5幄J-qg ,tm&<"#G$/u(E(]ۦЇM}* ~s P d{t}USltk7@fj<3jOʹK|u\V|?i_ؤXAys1狗nhSemV Ҡ Q3[ó!"v,@aH&uloģ8u@ݗM T^Gf} @Y2mʸ)v%UZ$[,p. hj͜Rx9G;Y$qZT=-}(Ϲ2]fPQ#z ::0,/tRlZ!`qqQ|$?/دG̖|xC?4"p ɯt#Lfpr` 4_Z\d66,Z Bu ˧&&·H 9.N|͝3ٞr%9HF }.C0m1*@!"T޳ixk[П :O2z/ϴj80LDM1fehL22* MMqsQz̐$$kV JMPUKJ?ò)Zlb<"nJXɃwvÚ3։_'7k̓r'D=f|hyƢ`*ET>uK+l "#?\]v'"g3Ê}z=qK`y5(VAGҬ( cx)L2>%zڄ勚q]B}-Nv`HD}@Egk9R":d f ͗%O@318OI!a L𣍗n}NRm011i!G\`)m^LJ&Aq6rIC*`&$nW*IH1qrF e擪^X23H`mG8sE37}|=d⺸A/.L2N#&vn@to.eN舘;8L "ɤԪbkW-gڴ82C@c2ci?p{ ?߮3O#!$}"MgOhr=;$۳x4]a??dKoҧ9"_FbGL$9KwFV PLXs*h}㦦F%KU^Nd4/h8[Iu?Zu9QJlin+J(wZcw8`9QL0OvJPUGЯy䳆 Ce,i/nPYsVIA1QzX.PE48WyLr8٥z.qXd- G\lu I+NOvIg;1g &Yyޏ]ߥE i:99n(w2}4xfWW\| n`t5}046Ф~:Yc"cHXH&21*9Nͳ h_#-&ZG)I5| ;^>Ėfl_M5@-`FhёY`hM*jVkO%C'ǼҜ&q6Af)^Dox>3!YcZE+gE&t_N#k C^ -4ap3|ڜ=ycs%a, )YkBPeB]IMF=Z5S^JX삑 C6T, M`i&{{R$I>@yMDuKp_YeDv P'眄t?##Z3/zwp3mګYrWم :ׁB}:ne̾'1`6-qY"_j:= <\ U&CmXuRܟ̀a'vE(Io[Gb. SRp{FP g >NJ0iD4Xxy0\V5ԁ4Z)bg A[J=kvC z6Æ020 c)2_MND*<Д 5:9y+wC,3̒G=wG@IDATL`k+lu0"2j8x5'1Wy 9'+-:CC2`sBܗ8rzkYaV y5UZx/lB4I'mJPlCr z8Xq9bAEAcطt;BKuDd(YyЋc@Gx|RC:hAU}dxkām TmY\oy Nϫd9m^ÎNa`{Կ\$T<yi@+7?V2YBq.lr ,u,l}ZҗhQJZIta=7;a[7\hf*T}^3Rg ï. -:DჍ&!LhR}JG<Էok%̱oa.ybǙiVṇu|uU^/f/h `s",:NIyNPۢ-˷X}^gS(1lX.CQ*|{v$Ç6Lk{,_׏_oBwWKTCƔx|LuB(̠B|-hK̐*(bv`pon]rdSrmqikq&]|mnwټ\7?ZpϹݢA,`)Jd6p\Zq^Vq>?1)0|P^Q~Yy҉,9|LeS= ɳ_.c׻R[Z-0"@"ՙKg,w e9 P2rvc}^0-^\uj۶u SaW)Ywn~_8/ pZ[۞͞^=䘪- [ɂjew~ ?}#Bf@fopuN|0סc'uqjX3 <(K{cc>WwXU &';Zl vW"pxSNRRy*i`{._߲o@sL[r``:nvR56P5_p@E~a%sQƒ-RbO; wNDPxPF6lvq<:G-r#`E8w揻9Q0hE:iy:k"xɯԘ " _.gA@A,}dm(~YE[š1ev4w ,OZ=RL[“j9*u}9Ŷ%w|V]ލ v}]HPn+nyqvbi-l_aumGm FMg,d7R #W S x9t'r+Y*]aoB'LB9,0levˈ chc?*-u^6:qTՏ/3)z~Y!Ϗ+-KE.x c3K;N@9LR4gX#1jx}sjvxu|qþn>srN 2}ax7WZFKETYY^+7Ǫ]cKqǭQ&9tLFa&?ّȐsd9ٷE&ܮ.@*CnAp{.!CCOCEaаV36 ʮ/k֗C+'Un q#mi6'vs5\4HE7oYֺKۭs/ ",{hr*8't]GK3уqL?j1vMQCU/lG]uV%w8ԟe mw."TaZVcwJsKOuR]!C ,6f~f tjcl;6Xfq C+\];0,:͢l2L$jtu:#W;VA4"Gm,߸=Qn>0u[~Μ߱cl(S~S:Ӷ"yu*J VDhM7#. pNje~8028^uQT/+ V4B:dHf0p,3`6*؍U]\ @B/)3VNJ쑹a!6C zw D7hrԝg.Ù]'xy@xI~ }"K.Ji ҹt vk67jgSI͋AkсLTXxd\r`_,_-Z; ӶE -cRl4х^hiQ3cK#iMYj$po-̂PqY yF|Xڇ'm KH"6,Ll,yźma䕡F6&"yي7ai3Ŵ6aInzw[Sx*6Gf"-8B?\ӄ {TUz7 x"#'D^@)GZ3m5)pn̯ZYVU% &|Sr.9[f{3ߐu0he6zj]'1fHJNW4f }ORwx|2&Vj6J6Bw"{XH-\/ Kf6XbъX Zfc٤v?Вc.3 8Fҵ|2ף3@`l[wrԀ>nqO-;j':9V,$ EvJO۫V.%1߄/=vF-j9(y:n PM=ЂVlm %H;qF8t̙wI\;CP4$uED]˩ug7adv;*3h4P@hd{ ߯(ffPMM1U*fQ(%T&,Yy2<Ĥ,4]q!0q1rNMgN/0]B:},ɭ'8&ek4 K fKKr6T _ 6,:S>ȡg'ZwJ$Nẅ́CmZo@JŜ/{befKeV1E6HhMJ^ W^KAJij&a̼<o'}a|u6Q), <(v'sI5>hO~]1c4=_J*`"ygAbN<%B}K^jmxӨ6wk*Я(`١%FSJ'Yg7r=]]ŲB0}a*qaYW>)h-*\yuA"А8-r U^g&!( 'N(W93)IG}:N%-DRMnZ~"E1D-ORڤ_G0dBk9,!uU3e)L"r3(w|MYpRvB 8N=$9USHnzZ 񴄪z/%sQXY]a|!VI׽{UŻ5yjZ {9c07 UQ 3xcO0y.ÓJv--yfu%wS;~kUi-X \3 ]YOՑHz(,0hnirrupg2~',t$'tSR62i@5)f=6ݮ-tvp#}J%ųYZY^A/AJǭlVP5 _S-#p5E4=CD)VH`oUN 9LNXh}p(x& m>EH`Бon6%5oiׁ1}NT3@fV] 0'hlGEm4~LZHikǏf GHxa9L?PtrM~4*hhAV=翦Aݠu&]~2ڨ3e-𻨆pf/LM;Ɨ cf`@&ڄa.^ ivܒʤBGfMQTnje(ܫ# =m&G0 Yͯ)R0u,kIqFƓޗISg}r=\M!{4rT+񷬛Igt\Y W;l'Y#KX6G(>NzL1uJ95\&^B>Zm5NՅmac=Y*/ERkUVH9(e0mH胆hcA{G ՋL{3 3FoŗlJ߹?-@Y #$$w{p) )*19pھ &d (8v<9t$I Hew;–Nq4]&dr5qvX`ƜRmޣ7vfX=< pdQqp 31^EX%\%&k 07Zׇ\"emMPL/7* 2m;4 !fF4JP G3a#xܗ+ЀFDsHRa{N{==P[PM-j&06S?mc E`3˛rx/a~`0ݲ %#ej.Uף{j 󲆓\4WgDu Jƍk7m?: `iOCDKXD-Ԉ0dsm[{§X^=amq#7AȾ 4آpn4Gc p]UБFN6 0Ahm̛h)Ld+0㩜鬁'|/V= eDSCEɗ?~Ǝ)_CVLk ]|C+NPX-40$u\KwecItp5@oFC]*M~vfv$#hP 8x#4@%)uY* @yfeLZD.w eQGr[/4Q~pFYP_q6D5#3e_^~^@ٶ`!,|M|̴ 1pάG*_Um~DPKܢk(E+!ex;^ ͗s Vr+kաfe#TZ0hv֡f?l{_Ԡ:.|"n\ܶKK. == `h,fYA䗘 ^]b',V+f9M,$Ȟ31;"̚")钷~<p^7uw聐mHak'h`il9=#b_lb:TeI!UPY^aO?f]>2O9ϲϫ;`rgh($e-?Zai߳=ms jz4j8L+Q㹚TIvH*Ջ,4an7_IA[l!A)bqZ?Z{$奍zz 2L]P;yPO<%Z/8сq7z)Dޫ\6"34.WJXP27}QWOR1ӫfb%rM\xhy$<êJq[.kEezv,t7ؖ̍ᡲBW)XzpOԨ2)0,4t?,~EN/xd:Nf[O/q -@N2(U+ˀ`vr'&/4ldV_Kq`:{~b\Ƚg9T0$tt? s͸mŝ"x+ZrHo)㸌,=Im8]]0=8}U)GjPx]uKTcA0 =ts[ J[#xⳣYL@zz0`#tҖg ӉN8T2-BTOӦIP{=Uh.vMo*!G$19qQj_a?6}^WҖ)H"rۖǞА44q~ K,>MK!Њ6H wk 508Gk7kD{vʧQ$ IIXV9̐J[&VX9g".T<BS, ʌJy5C:00sL5Çf+!D5rTof?9^`_*sƳLTO8vCTv͑vǁ 5ye}Af(r"dM:C"xxq/4=&pNG ttijˁXŜ3'QqrETĿ]*4 ~X!C4XWt =:!j%˽v7cXO,/;!KJt,f.d:cJs }gʗSuq֛qX^dm*O>gUu!-Pʛ TC,A2ofð1UR䔄Ar²|za42oOOU*径$qxd~Ap(e?оImҼ`bKFB$m#?޴r sY5FrE|4#aҍ){>7)ԭc+XQ,Hٸ3R2nZ큱 )WV\5 uc29^18 Ufgd='{1R SQfPqgJajY|Sq&H8԰d2+;FЕ!2>15 ="N;9Hq@Yt 턞asT! >Vd¿ƿpI6b=Zw|vgdL #TYKڤ0Mï.TqJؙN|I h X4,y.3*zk[ŲĂ'u2-a 8;Wxv & $Ya>{|rڠ7P"3 UY= };{i!/1ok͹ZbCpq P̉|!8 dNh-_ ޥ8Fנ4Q l.WC6t}| [9B^f_"| @r5@2?m1/]:xׇ{U qW65S2-5,Cwyxk_J!4 u"=>Kw 䟉sNww@/l ??߶yUVy`i\hJ`Z\%<5 c6DBYjbTs>Zdq{A|GBdS;.%&YLMR 36ύja+}gv)#A,5&!DTU3&Í!#) pt6i$P*i;ˉn)7m-϶biÒ" Q|m:^NE'^~«HաǪJ2p DJ ߟ |+T;2l^L<`loyے(sbYF<~vt?,:CFxڻ20SÊ'_ +vArhS؛puQp,葄af0'TnH\*Y93a+wKdZ 3pҩ!p#/!\v)4aAFp=.t)ǖI 4e U&#;3|st<7π:AS$TL1 i&_r|'8z cD~L57҉qt5L$9Ucӿw"7aBe4UXY'0r>c`KF_jY[c73c4iR IE2@Mp gIr"վEe?"ɁB暨y&D PuOM+SZDOĨPA.9f7vPDP8`P0OE'ϵ}",E]کƂO1e?=M{.,鸺m9mO2Zh/..d5 _4ϊAk#=f|F1wHMh[o8gEUېT( }ָ%N^cև0m:~l~_=SO.b+A<+ Fv> [92k)!$X+G`!D66N4'm/m 'tĀZlD~iIPX7u%eI+pJ6<]bMϰIIz,9ru?EF 9(DpM ~X!--Ed$ߛ ب1D,lD.]ӳXYLOn{ǖ>zi Ll z Ӣj$WIF1``vx'U#ȎؗyzK|_xDIejyHw b miD~ Xӭ .Gh4KS)bFj)()sS NRg(%'5P%՟P\b2ѻ4Ve-1?`+h꿠(=Y@v$"APZO[* <;',98HN3R| b H3y~Al=2DMov>&3nXqV`}_9]͔^?AF;=BtޑI# cg%&8UPTJ,NKC!($+ *DuPn.W7uN9tV3 17XwsyNܣ/{*,oN0菪d5:Фg|CIFHw)\ ;v9j3tۢaЖEa)u DȧDd6xEQ{tТp2Hjg I_ᴪO4QNv*]G(m S?G۪}u ‹'ݾ| ;`})o-|@rj:s“9#Vt0%#LN>PxzeIPFs3D+ J"`-du]eyH )xvD;0'> *_D)O'"@ׇ0+QWfk=L x\M/$]Fv iT!>~ta\qD,!큍Aqf=%9ryx6vmW}dL>62n[`, PʙF/bfH(tĶ(FNeT&3 ] /uoqR9sXh 3_^]EIlgxy2_ڏͫ뼱g]SCS<'JHZ3d5>x_C:\7 >&O1=uI)%D2~Z9=^Vť!`<t8R)eF@36 E2UStMq:aVIXߡ5ُinHX\U]GUHfJR/^Q.)OGPxl+^%if}JjTPгL{./_zIYĶUHc%0DZKCCyu?/侎`h% "fދ2%%~t[N~^.%+z>\++Ð߇>8jXj;6]PP~'{yR55$M>e,#{rˍ7T\RWf5| Ŭ!8 ^Qlc}/Z3R&Q8F̧ih_?%vf?1Thm?ζˑUCZ4.O1Ns tph3N(VPWkpׯu3b@=D3Wlb~j8aՃPJ\~SIYnڒ/UU(r:wn~ $B&Vh[DA VݨTy sXX}(QߴssrN3n,0[D7K/8BL $>K d!OS p`(o-@πKBzr,$U)W/G+0e#ږ3/#c褯'>%$~`^of {%1.Vu4@3pvsTCHJ$Sba^%Š M%ZdgFv݇e=3PcUy>K_ 34<dT*\ zh'@1ym˪>Bg_#a {5tA (#͂:]ĎLi^̥˫YƩdFa5*%2)ke^D\xKji|s{+zH`(*ψ}PMh9n+yM=qZưM[$.Z&1o0Rqğ.- bh7dSBQ^F29,xj 1\ ͔@IDAT"Zm@OaHt u JD,w0jzy DJb`9w떪,FOV%5AfcQgc=7[d:!ڕ@e1̊`.2NCTWaF" .B{7 «ye㎂Aƥz^n1>]~(o֗46XltrH/h227K؎tZ?CVv?'@)w\0ed<2RUÛ!u[ B3QVdT85[²vkC4(nGl$ࣟd~*rwnAf9E2, 9pcՕQs/s}|܁3^ \{G_|ZbơSwl >"œ؝HFzfS{_*ށE9L|tQC;c+.I~353&~7!ؔ! 9/Q#?ZlO'A0BIIy4ihNL|<ɭP~%?gt8jƿQa2)d&(tn 7>א2 혙e<,V͔|i5AYNۘ Z 6  y,?I^f_[;aFջbЯI*hR8vK|n,2t NEaE0bt 4 T$Dăen(g܉1c1=Ei [k8`FPgĹ-YetϒkEwpΟEГ i;Š&[OѴ!OKs? ڱgk#!CK!9u9ZKutͭh9DHe$] ĬyU44o[00_qi"N5"i { 6EbO͒l%v`l#2,Eb=/ki.{B/ײm_m1 >?l\9O$Mw[ˈ*غ\J}AdCsP"saG 䱻=(WE 8I3?e~((W>egGvji@ Oaz]S'S!vvv>]e8ϪjWh(oG_%I+o$J윾I$t ^)ӆ*\5'ZP㐧av&C8&صlB&cYwN="KZşӢ~|ZFMFausL)R[>(pWHRA")c]%Jn̶ebQqSӂ2"ie)H 5I<aGTdΘZ.$?fߡǘS/LrG溭KwTfQ$ ~wp@| 9(AVSaZsYAAEi+σ&-dMIUyVb󅚆ؑK+iq U'+!6*aŎۗnn}")D֘s]7栟 %]V^m_A]2F2av!t#%n kI d$iT\NKh->,;ui{!ݫbK}=^,)&2[M]an>("t,ST*%vb-D_7ĥM" gg7@o^ޭM5V !\?Gc )A[wqT-I?V7X;圢dNw~ҡ{[A UgRA?NmKv}99rťY}+segI`NF_\i|y1EV]C6fMh8cpƶiz?y0~yCI k.jYH*]V/DB{ף1 8676JKUy$,.3˿v]_ƩN rےiWӹ.!/Yq$ <`>xLp"? }@,ˡA7?^Z$LM2! m$/?=\;v]04~\|ZZ 9^,vw~jD9Tdť*RCHv%vvRɱey2 ^i)BIUD,_/6r-[s- >k8e{20 ]$RXEP挐$pXΓhCi1s ‹٠yjLwcC"/߲}4bwQU7ES|5Ԧ&XVr|q<%َc|7J8AsH\2J-YW,%h1}lQ L yrT?$8/bvoЇVCt;7< BM}e[Z2:) _gbaxY8†yNɬv(@TPt?UD̼H/P1x\gYbb=ϫ#XН^vY-^q.H*ģm:kұn/~w¬~?V6*zC1PݟhH̃6Gz}"0t70D<ރqiP~#I:oB+!l%@GHS*rMJf鮬lve\S# *)*O33؛Ē|m#2jڮmeYҗmnL!js:>>Ҏ 9BCq$ f̔2xyLiF*3֨}-kh(%xesSr0l /_C'F*֊q[1lN;˞{y2pg8r\oB:Ei~o:/<?SH,$@Ȫ^6L/]B-3.8V@"31(5;ДihjeJjoCgwWtئj5:mHK8Cz/VrU<ׇX e2 حS.vaQOTY#7}Q!zE CN:$Hٰ+-IͷBOm`vpth ;ҴȅABYE/tT$69@&ۺIQɶECU@ q!D?"N ݋Nv-aǰg3:x\x*yldJHp_!R*5~Qk1 \wwaw6|,r.n.((DN=Y zMDy|ő/dٵfV[۝֌&vtF 0E:^X1 =)]ς2ƽ|^^Ol v_I0QᦖEQP ߇ `/&z7+&K1Ԏ#|}xXCyH尵aX4H}Vhpf`⬮ V)jվX/>r:cV_u54o%,Up10=UHz=NJ,%%\JFJ0HAђ5bWʂUصCm^eV7NcA&jf҆]Qҥ&Fġ%4>dҁɃj;F,g`m!r$d;⏒G ߓ2J=B8,쪎C ý>JbBEosˤx19о?"299&}O 'ULJnR=!癓)\+R@[=d\`'}z0R,Ћ*l nNM5}kK}P x9e_ӋUa[v2B.}P80S5vf3N9:Áš*)hHJ4})yyZ}wdvZTIl"UJ4MACi\ :F?I!N_V`F'9fzGɮ$L<|D#s`*Yzsw|yKk†LXw_t2XN<}l6=oMk@o#* T{JU i 9'#CIX1F :E{1=$!ȥ3eB2j.8fc :/\71:"t+ cHޕ[c f/&$8t$Z-dk#L}zfp-p˃xk%CG1ͳ"no~>3Le96[8j?>Ӷh i C*$oZ 0pMj{V%,KY<8FeոmNs %Ж'J@3 Z RqΌy㥸% S@;_Ygm  {HV+%IAk>G9T̥3HW6t!;y ѽXZ&sXY*hi Y%!@%]q8 Yld~jlK1:pCFp:wP޿jvg>l,j/6,4OclNnB]lqgfsT!TA1+9`dsAME&tsìTvVk+֑ kאð~q9U[6@ՖT&BdI^ KaParoXB\?6Ela(4C3tL?9N۷F~bNy@"kH1݋lqœq0Hbe18\jY9)/q3vǍpNy,u2瑹ŽϠ kmPK$]1< w_ukVnH+:Wl]_` 35CQE[MhNmt`nP bo,+=r.>R|=x!^atg,h}/[؄G W7e:κkAk@'YF}5S-̤@466Gt 1Gm7㱚n겶'IW|Œ*[idtkzĝ'N5˓: aʑ%[`[ID_5mTeė͠/ 7ׂl13/Eh3!ep`j;)ײ#/R0zcT@yA$}4<;$=k)IJBt9: ifEފK[LPk}]}t=e_#"Uf9#Tj;>nf쨁ڛW7ec jm tFQZ+Ju[.wi#+ Iÿx:(nWf}!=ܟ4 4_Tʇ Jv=8̉N~ &wڞS1I R[$ӳz N㊕ծ։;aA/sq5i8KGW C*`L' 1d֓={sAǼoߔQ壿s\m;̣l=r/Hd@XL*8EA=Jl0|(4| J ovAd5"r&۰[52UPiT U!V4( hݻqU^5YJbMo@FO䧺<0Ch831K( { ^ɅJCp<ǐL;IߺX *;N"q4O6X7H٨vëy ><#r1}H#!]D4þX5 V08ji̅2¡ZawJt?,Dīu*kê'~^\Iߵ)T YO<8l"Ge/U62b Gp,ߔnIsFHSf1Z0hpT*vFq!Vboy.Nk"OC}[Bz$ ) "l72z[ȤՆ≍JڗFhQItVJћv(7;R`zS%nf I(Tg |9[SvW]z4 2]|Y_(>I T.9y@xXi;&0k: Hme;BX̧{QT7~b6'[;64I5*pjW!I amoO_F,.nZGߠ;d8hCƆpDQpHiNZ[\F} vo;,#K3I#JtrZ½%.* ~~V8\|qn> /< 3(]_$aHy/n*(k=5+Q!VM7+7E}QIf S4 N'T0@'mjJWZl2\z]!IƫJdp(F`OQ5{g+ɔj,+7%I!)=a5'f@hf\ۃc k.=ok#U/ׯy's`Lچ-$Rhn8~7liSԕ/E"e" '"^r2Fo)#,t&<1PY #;]4T@Nw+ig 7FAy8ZZCi| ovƊ$]鸡n%]i Sx,sccQWy;iD%bO֬?1 3yIodGY @ O,E%8د񾪙ӥO3$@ YX6Fwœ2\/+eG k᪞\=omh|ψ鵔L%ʺx4*l9} $L-3MPīPBڛՕK*~)58'kD/";^;ʃϤtj^ ?J O#hTCf UcHgzJ/l%Î iCkMnjӠ?lv~|?<}fFO~mJEͤFK [Աs}ĠO;_"Ca9ZBK؟@pA*XrAQ iY"qgh*_c8I?Z_y`w@U>p$MЌ)Ɩ" 8 *镶S ujZ;4 MإMs;!j8q\']BКT"($A ;3|n_6[rUFđZv õEyf0c- Y~™St6]Dseveh;p$}ܛ Ѻ gK=>8<[<#뉑~2sfbec7]4BAmx([(qRhaDA}&9.q!QkAO-TgwF&gIN({>rS8\je4QY>AI&oqsf¢A|QTA{+!ƨ8۸ 6}++- Sb rg*N=c'Z՝x09N*Zx?|3ӅZ̈́mΗED}9r*l<3)jaK ,( 'Wn/DOT #A¾}Hsulcq\l\>RFf%W"Dv< *h5~$Xf /B\ysPxxnXlMψ,g/?0eO{flWX+@ΙFLHcyZwO+ޢB|t~-~՟g4NTmh/ƠnQv _YFIK!k4Hb 3yI ϜgSVU[#hslA3}F׫L:ad)Y{PD. XnŇi}/#~. hٲA ֺe<lXvxܼC_9E)abI-{[QѺȦ-R@ <~sΎHN$1XPcS,3B$*IO9}EudQI ̅<uF*o&&%MhGF }*V?qU@06`:CTμ>^鮏 L]v CuR!$Q>2kr{Q:=Bm1@e#L e {GG*DWٲ #11@ wj)^cՠQ~]ƾwߗFq\ U=Cp @*!UG8 BL=>ȠV[ \V=sqh5o,vk?5BmEJHpw-4P7#ڭֱaPz&>3bawxЩΡkN/iषI{ (!ԨrCͱ[3J`\LY*k8W%019Wn{y{&(%ON6h^/1*x& a fӿmPJ+k2+EXm6h2_Fԣ=in@gO< t<9Ȑ;SO8fFmgN:V4\,53]%jK;rׁWeێ(J6Y&k9Y8ZTڶό&3;hD|4BH){Q%R-LS(_?oz9 x{.RY9f݄(,~fǡEJs+Fw :#,^gK0Vl7,E&anjxo7\a!;ƄW]8)VZjS]kfEuz4Ӯr8O##H+Orkk#MbfSX<ސ)n2⠸S 7S uDhNvD3nXߔ"?޿TU''U/;E,\sLVkjzYRfqLJ:~Hտ.K%{1CF.S<HE.d2ZSDa+8oؤ.v???,~v\ dzM",&3KGiUy+WXI9{o zp~7rɺZD>m{{%Ze_{@oϘ֢3 CUp ۡlq-H_Mȱ%򶻻q'֚ y AոȊhhT'dS1/6#A0_̝k!V\@H mȀw`@gۜ|=lvĖiBR\SNOY T>)3!* 8${{^' ّϿ_7Y%#}vo;-foo'PDYɋCF|IC"lnK\n a؋\:;zmA[ke{. aVWE(Q85LS8.| ImB7iM<ǪtmvJVl VklMh: g dΘEiRTSE,.t𮤱kk"v;N 4(\/[s֐_0nH3"FC]8l#JC CD/hb_g%;D3f>`)j3Pζ=s!?hLmfAW(mL\4*3_z>(Yݔ2F< bJ)6Ǜ8EM[yv2@QUw#  # ۖ>͑JPjl< 4E)TImYP,PBv_wUbWw.?8d+Œ|{ }׬F2Xvg #QԠ/Z) lŠ*?jīNp?ܔ_֝ 0M.$dnf&M"5Y1O \4 / l,H \i5y.x.h8x8"MX 7ZJ7&V͈E4z~*#[d?=S~p"X&Lflc\5%Y $Lwܹ_n4=5Hڧ1S(̅{?{YRij-/eY D(@Yi*2Ç`l@#ӥ BmzJphUTfjpx@_ޛ l۾?Vdpa#?xE$Z`_3C33?d0[P):7J7ͮ3l\dLª+ErF C:K306/ 6i/7Gi70<ÚrBq ךA9~墪xv3n31iRȺHh@@ `1o7Ŋ_cR`BF+ՁߣbLq,T<ۆH&$E@cpAizڊY,%O!Qzoe6`f9f>)S?8|?q'O%rh_fYCaܑ֜c[N,2+>r@E :$ʨDY䠆0\|?WQ0W. Sը֪ߗ(]L⨆xJ ;O`Y};]}7Ɔ#O>Ab$;^ɠk墔BɿS[!dO5BgUjGT%#5rj Z r.1bs3!fLqg)e T(8[U!l DԡV  >^_JDr"wm!L Es,&޺-ef! oRrC+?3 :ט>0k¸ ;ӨȯT={bY @eL "Ss; ;?<^6(gGٿ!!Aڙ('\WϠdߥ: BU+$vB3U@Kh3"nMܠ! vQn$qf |ٲET_ %(]у1DfHs2tG Ȑ97F ct"} |mW {_1#{c.uδ 3-J,Ч/#`f>8pAQ"=2hY|)U*XYRrEHBHM78F 7F'̃12ٳSfp4OMd/9s qW?0>(9"hP6J-gD7)%uXk m.A>:EC?v2$بӁ0Y/V=8wDta ncP< ߦ`] 9i:@;+SAaE4@IDAT L]4: ò<4 pjlrԦ[ CtV lt;`UHC F\b#aGa(9N:f&alR  j. M^'oWk-0_o)kz6Q9v0o,)x.bi6T 220Qc{Vp&Cyn,o7Yz @h3ҕ,0JZ)*0pm)'{vY@ 8+UE< DVITP  :[cJDU7D &D/){%T {zS;ne&-vzd]?JX~k&ӡę\IQr>5?$'ɾ ڶRyJ񩇤 2R{3U;wsCG9DuE%v/a'v@2+T"bib>aq@شc_B[&x=1l/=&ԇSf`L1"7ll 3]X0V#LnTR\ m~yaVK@IWjSH2-ȭb%')-Sz,+Kz0<PjYWCa$(qoZ6谮 I35dONt *>|\;*\+HqhsV ~QabAQNNUDw{DZZF@%Xjl py0…JCC<Nk!S0Z)Nqdj Ec@nYA2yW@f1ai6bHFX&-}TQ;ߦR U<  vusibғE^a/3V c*!ׁ!0Q MEy\xPB\B4vO'[=ANU9{N =ܺ6 B_jb8R x0EB3ERډ,3+ b tsp#ĸ7KMlC5W)^\>TxGBGX%ȓ蚡&5H Oz,&P`oƃ<%yk )"C.`};-I`)ts<E>iC'%Q(ՂL8*jT}޼bw6P"3Vo~f ^̑V#>k*Xh|gz&]ߵr;)&фsCKxJyn1iKfwKI4@ٳêÀM#-܁$%n?.$;8Ov%9+SWn`,t87;l9lk;m  N@Rh0\OmTp`RphVOlzy#K^!"tjذFl5Ƭ[)Q 'qv>~DҢ|LlU-C$Z1j֭60}Tf&٧[%zAO:~?__=7_QMF-Di$5䍳%O &2]]*hٖ7( &հoo fx¢U7 b[))(sEinK#f `Sߌ]2#1m=őL=*܃C_OK1Ms)i@5nE훭;%zR{8s1CHwܻE*n '-AEZB\nQ>Fp8egȢyR{=u<Ol!^Iʤ d⠈v9Xq5, U̚qg|Clyeģ,*uE\,Vnb,*__,TeSQl 9Wbi#?(tB ގg1#,tEZKF nY[bp4fe1Z ['2fyÿғ?.6<?Pf ք aNx̀a(a$ >֝1ϩ[fU) JCHo 48#Yp0ڐZ2Iެ5G1dv "?Å!6II}amU]1EDypmAVe(cСzj;ʸ}cuw{ފ6$:+8O5wh_,>LieXmKQ(i4dF0l2:rvb^~24jzHj1>79ra%%}5 zFWtJL*oP_X|"mnp~!;TDuZ'~KdaZУz}ŤH=wΆ0' *z!PIӃ3B܎@ 5mQm2bqSOHBO [9,|~| tc']I aB2cHQJj/N9Ux}:h Ũ \<p"HDy77_]ǭ?o\g_pNb碝ޔ$ 640pK;;:åkۓ`$Ix9|I "&#xKT9e6*_Z&8y=Iۊ2)vnsn\6[SOc ^ߎINk=Dh['ɰ;D hLl )3-LTp ;m)FTpUkJb\nO<7k)}cǧÁiv`^*v@Fc5LDv0U2Pqj;J7cB,&,,*2;ӼQ׳-20qRCҔN)ʏSk٨:ڴ#SࠂNƊ>AnR7<_=8I}8@sbx(9 p, k $h長S-S++bؤjw(J.+1|Q8)Wε<ۧ*tS۝[i[6gy}5glTҬ.kXuL*HcSPW~{󯟼|{q % UlVg^V(9"RQ@cvE)N!hx$TS}#c-^0pS8$if,2D=fʊrĬX_Ag%mM૭!xyЕ/`;Hemxt9'vۋcD>0#=`"+k#\V py@[IP(XqrNY%g~]w.**W>Nr-r)=ϊ D\j5)r 'u~ Wc~"1q}a!DWLрRtD-BsJț4yL{T\|҅vRHrNnRfDU4PC޷BZM5]fe1,'eU[||{M)hO4fz)n3OWHgqoSz&v Ǐ/Tp֒BK'aGyC 0Y鿨swxr,W ԣ[ѦnQd[)1"A[&nѺ?uZ&J`^N[^c3Ruࠡzs)vL۬N)M[N'vKd\"31{Yeclva܉vHPe g FD836~T ӺF <I 7]|Hrօr"flP,|TkK[V^x O5l4mSUk04+ۃ6G&{5X~W9ŰyA$J2jo?hC loǞf ~sɓ=B/oux (XtU̠Oww$xzyE-3,2f\d`V&E4L,(T<1P S0 dE/ pKʏ|IE,w"m]FȈohqM\ fFP$go̙#fj"1cԂdn@խׇowMMtWj¥d: ?*_@h;\f|M((LD4MUC6G扔5go^ѐ,kƁ˄xZj8LA,mxB=iQ3x>ɯJNG66 q, 7O/{؃ צXJ|WPRu(2JK# =f'bT0h3F"R L4wCvS.fdy竴',O*`@`^ĺ5Q:8Wp=_ms}Y3)e_Y -UQ@͗F.,y~"݇%: t}mzJ׌*1@.IW_\U7IA,UneM^V\ C[,h5wT*Z߀H9# pFg!ڎ0%IF[ʕ73jM~|osᇇ^g@e;qaHCXμOzEz6DލK]"Ȃ&ɹaQZĭ0b 郀4v;'g.VbZPASBoǧ»pfl9;cXr)<l l_Jb ѬB!DlNC6y$O,GZrת- ࣋ن}g)Wfȹ$ h9Y`&,2 hgɥ&2UJI zmލɚ4xZ U " 7HϚ^aL0Wk)a_Cb"pդlXsqf$Q 4 C._᎗+C4J)tM4v(^QR g/:Nݥ1O~6aD$f(su88(,o Rc4|m` f- Nde^z?QXjwD-0f8΅€u/WFC!mz}5T^P=Šn隥:efito<-o^d[)Nn^(=n$vΧӎhdA=۟*&@30x,urbJgqXB&ۙKoC$Pf!±a'9F'%InyNߤ(Ii{QbIsթs]p)홛`ZGBH2ˈmi[zr|=Faڋi{#,ur oe#ҌmDܘ9v_IS,(]HƛՏ;x1(dZDK$;B.EҖy+9t3j^+cMcm}\/#wTc+d$$o18R$0*`WJjw]?I)){PߪsI:"ng"xə.5ld+:@4S4q1  -̙2&qKEOMUaxcnĞv+4>m/̂Fwp%Ooo;!"hVBK=a#Zjkze1 mbAOIpx'aq;;C_+:A\وXd2p)F¬֨>C(' 2ƕ/.$5k1ٺX9S" LOW!ټQo]H~2F"է 5:֜BJX8vL] 6݈5Ȳx5۹ug-8t$ꩋT;`pRK +ucer˼aOѥ~?O='\RTyKj!Ʀ༏D N'M9"zjz2CwU(CYBᜊLgOXO &F*8rDEO5=/R= -I,{_ is=e q3 h[M4uN Vԧj ᆞčd/ d(9U]Δa )r7mo(T di 6`W{Y6 TI[.s*rtnosKoG4Ӣ1l_K`RjIij,<y$S%D _h4tIG*H&20Ƣ=mAq (Xe}їHR 4r{;o' J1A@C om @YR; JyuC < 6I=AK q(5ޅ-7(٫ts 5'ޒ p-\qś2TXO^T[]O*QpH~~\噎Հ$:eGXf9! ,4YFr6[\rR b RL cjnpjֳ/ v&z_=t!sz{lf/G%;`3o+i.SO^4k 0Ȥ2rl!AxU3Dzk4Ͳ*=pJދ\L9,à-[R~>Wl E J|;܄q.w-JEJ >Kxdvs<TĔ9 7,nuPznRLR]BA ɾ2bz'^\@SMCLɉs'RNEqEi=N;\:mř!L# ,Kł˜!trzpA&-!f@`.zB IC˱P2 <K=B!$4*0&ӴZr-r'N}jWdVO0O;(VF+Af1]h ,XsP z(:8mĀxC]% 0iתPf_R9gmwT SKrZrfĂ.k8L"]wJH~QXP Lf,vQ!G _BQn &~)0q BthRw%G~o1DL"UXؼREb`aLN#h,(}+9#]c}bKh. T Lc <r^J{|is*=(<.IJFe|E~Ҩ_'pi)qDڜdߵԌT}S &SDu3gGEn݅j6&&P7x9зpn ĕKtVnq5U$SD؊j~%X!A0<j99j{Hu\tA1nΚ ߌ0,5: '>ʊuS^TJK@R"'hЖv.8JiESxGJmt:N2  @YRZC뉰*F,}NѴ3ɭ ?yI q12=.9m]my͎nDZPZd˱ר |4 r7JYt ƨ≙DoCO?.\%ީY,,'^_8w j3kk{ЊL5Wa 磓/% J)rCF D'dV,cRzťDV$i`[B9=/`/>l$ljT}?^vkHvw;__nEqX]"z9 c Z(@3E]Eo[dK}/e{R ]̻E$N8_oᦝ~PFW5j M{80)شFXO!Tq]SnjL_V갷:@Xv\ ΦaF6;eX}r)Ow^c^lG+~f*Iк-l_O̾28O뮄`fl'~媭SO3oM%I6z}=p 3NL8e[p<%4]UTq yAU*J6 `nDNRZ(ToLsL3ӵ>X`-ZȌXWlEVN]A?fP.#–9$ ep&E~>##hz-qf0,/m׋b?#Yɲσeec&diHĘ&^ y O;&))u"8j΢lv/PHՇM !A~_*̐aΒMOt79;I2JEAy3fؕǙؚiw mY JMQ6`!p gd L~ZM=ecO ?qܘvGb~/XPWDHoVV'Vp+y))đtPpq4D8 PN!Z1 %>nv$rlH*y<T}E(#h/b/&HӱIx'H[]|ǝޘCIvFG!hK&jĨ<}D)U?^ܝV,d&%1J]|9;iq]$6DJb; _+kqn6 V R!WzTd Fa;@~!sFGհdߐShU A#whc[ 2qps8! ~X锉to ΘrVxe=jM* ɹ[Y7tsmcKM04lDi{&U$jETIL 0ҏkl;Pf(s|mF z~H $C=I:!1oS=؁.E J옇(>bRfkJuS+mrENJ5##u[Sb!÷t`%,<כ6`hǗo$ӯOBQ& x\E(Lբ~.uW(v|xdğ"q]p{\m{9[$ANk<5/~' ӭEB&U&Jh\?obI_@c TKUqL%ӃB'svef|#n2k=S^j! 7:Dݪ}L!*!Mp7dÖ́'I?AkkjFq6YH Y!u.CTk X Wv\\Wݢ)@{5O.rX!D X7P8K4 H04=pލYᡑ'@Jj_ͱÁ> &N S rCJk[>,IFD9# å?{AWB_jkaӿڕ@ ST[퇑TSZvM ĈJWxynzi/ކC7 hF們w7^cxLx+[Oatǔ/'D7+ѨYS%U{߱ U:#lCҫ@: 50G!kϋYϿ`r P@enF P?_3KYSxƢĨsrf0oʱN5?yQW<Ӄie/Ӹo7QnSqc*jl($)BϜ Il Sdj!"b(DPJ}AE57s?6HM1yZ=bHyA=Mb\˶[l(GaƎe2wP.Z6YTR}b gd;K#:O{Jp(x/Tf”pJ{?+.ߌxcÎ+/*L(1ޔ#drȒl24E;(o83 ~Zh1B(xa(3= jhO>*(>I"B.}p ` WM zNlKc Ä,CdqSmI-A(8&Oan'.|d]!Ӭ?kxV˰M0/E`IjPjI! !5F)LjҖX|LQdx*~Ms.3'XFDi/{r6Hyo ^w1R{y}Kb9`W@~hyؔ}h<]z2 ;ve|\}X>8Rg;yd507=$~5+3`l ~jBM(MY 6}0}h# , fLc(I Lͷ%}1X"*\L~QliXxa6l4 ql/I<}:[ւ4H?ueFɑ6LX<Ө2 GȋWI:U%*rzA GcYfa4h~ - 'Aqs望I@DIem}*ߵY k&0`&[&AFwx: Y69Y ȃLkoNfa҄iHLGmsPLn}=;` `0 ʗrOTR^#&$h0`@j&}閴/Dx} _n U$+"@&FT%͑_AÜ(h4sQ f.>G-#|- I.$Dig3\೾fwJf~ r?d++|Z8@臐[ nJ~a4iI$& H?C+Tt1E2e0T$cR揽.!YA+k#- /] VX7-^'[^XDTOUEPX.jyT5ѕ9HGFΔ4N٘RyQR ﱡRƩ?\`Q㞥o2aI4y5C"dSRL9udy@IDATөjT.&iCs 饁Fgx9b}:4?xLiseQϫqT6>\W'r>~mL\ ˼ -NP`pDzLM`BS Ipy%~aN8l7A|&n/}~#3qkC t>>,4O/|֞?LeAzt}u ŋEu|!E[lm&@&b+1#`Y荃e#l#&}[[-fg Q@{ ]D 2`= gGv6C.Oehb,A},Nqbi}%OW|wT[?hE9bqZj#\!$&f4<1wJh'sl t"^❅@xPsMg:pi~`hkK]Й0L~esloګ?>|?LߵR.7<{ NH[Щ`3,J: (w | ## p+]I"MO=ײ́4T")QvlFzYH5y5܏ݪQM5*DcS/VE-q<£ݤμz@ڲ,A";lLj1"2nԵ@Ox(ڦ Bup8\:C/]6†p0H(=쵎{l) ]zD#i5ct_2T*ZNSiFrQ˛:wEFQ1j\ٵM1!WQ\KA'sc73C!DH$Aq83iy: j ('T[$h}MňM֤o,=ؓI mn# ȣLBޑ@OF! 'ًM%Sh=kOw% @zC 2j8jr\Dh2G 4Rʤ?2A1lLIQjjHDǘ]3AcT3Puq`*+35fGk%o5S Qj0̳ӏ$i:}/韟'D13|yH% ECF q jT`ehhSeH3lrj#g +٘dNId9lZ 4 Z@UK 6g!G :ɲD#3ƛx}vx{SV1ew_}s(բVEE?fW!)U^ɝeyʽ4(2z4^Pl 84-`ИU$Edd&Z <h,X *@~v:23z yd|N`Xy;ilh}„QP$:h}߉%5*&l`|ZPCT_DBї2IeSKr ~P${88ye^0&s-A]40[ly!)a+j՛rةrUX# ;lHR}*UJc YJ=6A+, (UܟWGȌp}4 &Z&%n@W;fq/1+&Նe/o{務pV)7 !{O1C~mbSq5en[Z7[Ub4p+&zLAI2LXJHS)g"/0.( `a<LxF+s]@:7|FwւNmn/V R;̲ڛ?/= F˩AI:smjߩ+R22èֻ{1)s.La I!ῌD sAlɃ 0~^}M11 ѳNRbш=CꭹfOrZ/p% Y|O*n!i*(?+vi0|y…ӝi(!nxϗk)" 7ZC+MlOS<[zvˀ)d ;H3 ځeUXzVdVhZ@d89{Ar00e#_UcK+k 7qMa=VԒi\_Ϥ}4ǒ(DJݰ)eӇlB2cנfnI?o;khV!C"/nV/\1,j2A88jLˡ߂k 4 zAhش8w5Ql߼RK?b5L>|+9ғ I e?d—Xьwۿ {`f;=3VE,Z~UǷ Us7Y*w}HO^\D!hB_IOngPtK[9Ⱥ04(qf^* '/ ʰ4⹊8?SL-]%]@fLMQ üυ|Zݖɟ;IeTPviijFHSrN茼V5X@mU[hh̀S0KN V N-Ļh-E j3b0-P/g,)%io@!OfuN[h j[FRy Rlηvn%{ּ.Ll>QJÉ]; :85 n'2OY$h9wZWT H_U1$P Ɖ~28iƴZoVgEN2B@$)&KI)QE_k-׃1*q>_.G ؚx^|i-v$!jf/ZӁB!!|qEl+`% "Icl^ji %%9Ȏrg8dك_ j \̔,CFS\Rz&regu$e7WN~kD}muQa̰2 &e\dz.Q>O09ݤh~G @X' fZ#R"?$?9>9Ϩqzw$ p\o{vbbv^%_,<DB27u2w˂bJ /w Ȳz 'Hx혍ӷqll('P˓e)D.gg%dntN _JSscLP0$Wr';sD޶nWwm=;9 `뻊ْϴ--gcuZc\~2 ٭C{-08dyZ`"}l8d:XhXrP¯9Z~Y [!obʧޡCq2'zlnI8s@2$'h?a2r(zjgwHc˫ǮPϻ?O{Sbt~D6k>IpGteLq:K2P'W?-f'6V=b.('K7c1u# YD0P8|b{ݗTrrQ9$a[b (P१밻?Zu.=)2 vyM9moJ1Dzsd~WZ-rh=l9k*Y2TjGw}Jd XyVIn Hn 6C5<>x{Nk5.+|-B @I%\8>ͺܖ5/הuM`K ι?@SU| X@w vl}22u|G7 { kGJLw !NN(W@·d.͢Y$"K?/kۗ8z{>X1b!tWQjInL9wM^/P#TeO[0L+˙,Lg?` lFhP;z7+P4D̄Li|OO 0:͖Rcg);*}@*hq:n!XxMԑ/>6g>`/ ,Mb7 l߄Q]᧩V!6-9q<=4۽^qi&a{%0p/T,f5_pY)t+Ad,$kLS!aNzdNp rx{E[Jȕ'$ H0倲dnQ,# N^k`3\X53eJU" .P6/]Xоq5Лڑz0r\z&\&bAE/& 1 F j &=%=#1GQҸ2+?6vU$-Cь5Yd`@w?ô1Zn2E!NtLC̀'g ˲uW(la`elUNXK2%텥D.S.< qK2[| Z?4.뗥v3A)\MwG$Y@r{ Y"MA؎X*['^Ĵ)'C%\ "+p|E:IVH;9cA|\V"e1 I^DH"ZV''[nx+Ln@"$v "WF:y&úi)/P4EH_Slmq=٘?iYL*P~nN$8ΐ.2"K[c \PFɺ-rk+(<4 ,1=?!c66"0v:-))0%8n54XgSyw)W{!1"C9@ ;5y/pPd걊ȉoFQ Ŭ=W̠[sjR.?0(oZI `EjJ@V-QP1yKP6vt!-Sjx|Bē^+`İvGc[;ϑh4#~{z^eLVߜ (`L.x$ivn&-FeEUMNW5j*(GJBЎm%f95YH:llNߢɉƶE$`@+aFT8(uH ]q^CX>R78 o-aK)f$P5$/g V6"!4_$._ǯj-iH4hGŌ4ƈ>Ŕ}AK ~Ljqs qui/8[6 ׇ=:tcLc\(9<:hNB^D0%yd4OrG.,fqڪ$LȑYG R=LԨ)\6.E=Q/qC,[7IɪS2nX:ӰVR$kr ix!;iԫ:$W2&MC&F$N3 Gcꈩk.˘ InjfZ:qmjc?!tmXF]`cEwus` 1-јNnOSY:!ǹSdD96$L(lG$ RXvFILGe&k| #Į;TRC,`O%C,FJOų=33dkVC/[J s@^_Mzŝc;BKF|,\D.`%;2)& s且hʦ$p & K 3ij(7G)P=़6ul Nq! 9*$uT*T Ur6VF2MEXuV޾vF; w7rxNiN.@BV컢OA`lOqo[mTSh!{H@0|{}KP PTjhnDEB](@ rz(?ֹ7eɇyF>2^H([澲m:vKn"85sn P44l$[ :m~ZLX#ŪyХNG9`hҝ D\X~}91ԌO Ҕ6f Dbe{͒(4x@ӕ'ðDeJOxR xJ  .C4el-sŝzL%hG8RIi픫mEP4u%UfDȯ`$(=@N/J@ An5l 9+N}G{zץifrNC&|&<2`ufzy\ f.nL!Ze#x#_ּauӈ9"u.R"=51O^#% 6l&'R4_@HaFܒ4UIlm 1ten0}5,C!:z^ $攎hYgc;$;hv yQL &KwrK^ W?@a-ߢn1gRaQdNh`Ț hFj~ my*NkzM}/Ϲ6<-}%?1%Z ?mKCad54]MpHa$(L``Rp@ Md9m~ar?&Y ##Έ|0ނ0H i{ 9*L@TmsGQKƮ?Ij=.Y%3Z[!!Lt s.hocZ"yEĹ5bJJ@t]ӫ)dFbƐRUWuhB^b+sp:$E,-L6d(~pZg29OGQO=}mӐ`#'FM`rnG0ު~#3V*.y=̴SN$MK!qn11@r) Dś }O/IՁ|;0M򔗥ףƑT)ᭅA-3C-bm`UObC⍴Jtx$X=wLAIVQH,<vRe~%EaCA(}߰VʷgȪyW1n): k,$_Hۂt!Lt" ÿyp,eW9@d $R7oҫxSVז(R&[p:_7Iz9sٍ( oQyW"@I4HKR?B^GQWdR ]^h$j8r<AH`H fJkɩ>k&!1}f<.S=@n|MkQCڣ!g [b+Չ6=ԫ;*G[8ȮM 12c# `jbtQDUR<# IkkGA< $J~ (F~OϴK^ʀ1|u뜭߄XҀ-se%MhBo / ~ʞrJVq~ sS]8륃\C\ drF2oC%%s.#y>śzgIn_]PiYE*=K g9&)@:`ʴ4@ŵZ:/.E-dfGTae1>R`vClef{"Iwv cW$=@t?gnx^ (L) ڧNZ CCNL> e{l ZJ R~a ǰ@ SKa` 怍Qz@-$QXrc-WiPܫi*J8ȼdum#`hRLQOw:[UgF@`1cng5b7;ɦ8TP8 ^l]qtl'CHم_?f*ÖAyfE԰D hy0.djJ o~-1B謄֯c 6/G|ǨzOJ:9#|5'SRr$ؒ :&xD%b&NJ9G#-LzOxFqูZ%R\UmL*J1C5e8{ uIgq 8b R H0t WVxj4'ֵ]Y0㐦hcEuO,^\_r rdG}A ?jhQTFc1Ԗi!pd h)P) J>""k۠u.øYw2#-t*ďpC># qDJopǢQ^lv+sy ̫w r$8}`IkAOZ6*7Dꁊ]Y}p"/X7@ECgzϪc'YͤlЁiW%_c:dlȘFR+DYHPX l)PÞlX:rx$"at[^4xZ\6FúkGWRCq4:42A5ܬ<)Us~mJ̏U(~}` x&YlrTzcz Uc)\f21 C]̊'_\wNWNѮ!{VthL4+m}}eYw'|rFcrS)Cs/hVI4^,pi /ӊ:%#*h-(,X?m&g*zވX)ۗBUX_Iq`Y$#f,U**]ƛ \鼄ޙЖ5ZZ2![?yTCC*+uTx"U{YP˨CFg =A}HdQzg{MUEհK$H=H͆,`M ܮu'kpؑ%LNMFs P{,:,T}L`)^`]9gE3EJ^D@^ >2yPE o*CRwf>O'v'yCFl/mٺtvOv(}=r|ȘX;I"b]%-}k{pev(oP?y|Z( T2,)OXP,yhΐC1Hv8ϳM%f &FGIe]t`i.#Ijݢ WB$OAx:bf&dlP`vWK ׇoSk} „U0HH4+j8hWd%\Wְ!7L%/ml!\YWٰ{ ۙ=lR5D'aNy&X0/A~}ݶ=^eDHiX@Yn50ɴoAn2_F3*j.4\[qx܎elwg'ܷ-JX;w?7 i}i-Cvy뉍<1p,جg |3P'#:˾Ƀqa '֔iK ~g唷Q֘h.yo/N61cmAVάseGNSѢ$vʒ_۞(%MV+@U/TI N)'%Y6ZDL5q/ꇊJJsD:|Ȱ>4{w.v9ЮɓCv {#h7:ѳ7ntׇO4ϖ(E/ij(R[~ko9=fgƎ07?q:\ &?@Ӽ찧<**հNd͟tcC F+kq.D1ī0a~R԰Mt uh FdzS7qIZ"\L}CHN`EM;/'ŀ75ے4'!RUo;xRHC-/D}׊bV*ZC]jH^o)xI6:kJJ]MgL2)Y|&}gx>̂ Yh6HV&>=$(MDu}-!(RPѲI)\5.3,asC ~ˬ]\jUWvLWWYC)'gF"~_~2R5XFh4gg L、?' 6Չ^s)SGfO_o=h*MYA` 2UmYT1ypպS,Xw%;F ,pcFj}<,!뢁90S˞@2`'R#EU3Uj0bC?[i, ΉhD 1ih szjmP%#PR:Von4Wl{I5 odn8[rܫ4y3JU6~.UӗmimG]uOa!R^1#Pbҧi5U@) ,rNCDxYCud^ Tc`H[Fb$c<.h&Ea*yiYR7EppM D[b;X6GVtZYPĬcMj@A`XЕ,+ : 7P70Pa68=kcdAJ YT#N0EwkX9/xWbDDᖘ҄gEWc0eDXcxK`Jssn(OREzA R; B J$sGxzm&6#oJG?K )(e8+:t*M%>L_tIb HΌ{(#Zލ֬ȖXI ڈ2?Wgc('Y"%O@6Fm4l [?Xw"p!O $@)>[9CUh!5|A%vv9$遒%[qLۥbD_L\Nj]7LHz4 $ n"?M@b,Y΍!9 k=>1fVuNq;')lRB?IP  IIfc\-MNc7*ƂU1,9$pD̉X)S 8} %aXx I^n;өDXEVWqgMCq#8DKv#hb>@]!}Ҷ⑐#+ݛR)a.cti`uYjVwn^P(+o1Q0DmĎ0|Wd`:Չ@2&-G}hggW9εSXdʻYb7v?I7XHmBVϪLWR^'FmVKV. u`ʲ~VpXb2m( f`\QN&Ynq:.ѺgZhݖDh)Flt%LM{nNbQLE0ɘ@")Tt473?h>KeWa}Xh{=am7qD}EJzrDĤ91b窚$Ĕl}_(wev/GQ_}NɌ;5DOܑȆӎ4cy%<ډ؅ IP4bPYGTi&]aH>`U#Wyr/P?P2C EE1G@H4baiSJ35h 93 ;9wY,%8k;#"+}w%pӝDLu1&4jS`YX!huQٹgP!lYc j 1H$9蚆L9ؘBL&+b m$_ֆ^$eb2풹h( Y~3,]lx=q`ߠXDVf1.1?NmrE4x .پn7h.2PXU!Udk[CnC<ʐ "E6ၧ &g..~B,Ɋ=xQ 5֘AQP̐#87_돦) +3ԥ/ķ>!W$$# I[y8Kxkɱ:NJt)L c BJs01"CPCgʫfC?R6ETw?n$O=Es)jNeXr<+ Cdg2ON)|+Eq~,|Zf]cvt!{aS]>xdjN{KZ)VReܽL$:ab0!!{NFMFxO xՈ_WTNt+ 2;E06h A+7HK|a(wYj!S~˝ENc@r hHx8~!8qPʝ@gj`m,;LH͝Id6q+H{(-qbSm6PpF|2:iUCɟub^*9D*'L.*nDΆ)Ģr̓{P/ Ȫ אORO)QtGZPjjO{g2GY⳧q+Ho͋@+B)P ܍\؍@0ۉV7+/4@s D ?T|.gDD SQ/,MiD lqG$ABy:P?k (9xoʩQeyD`JKAJ-29 =^ =K=fԨ+-*̋@'K)QmM}pMc*D-`ɢhi(S_D /d93n趢2z y)YKo3M$(9~5 l|1n.v%VXyip[#V2 4i j:wr $sS8`&0FkŨa$rF\Bĭt h3r_B?v6)& 2u0U!߃: 2G2 Py#2RΤdhڌֈe8*bS z cBwgve@H"%{cͮ2ݤ2zMyTPᵓWwvs;*(+Ü2%P`vƌUpЦ pgƈ59 !.jUvv蛰6Dǘ r*.jVp5(q. T>E+lm%C$:dhS 5j3K5$Y3+)59yN0&Զy ,Ε6"jo[N`(#ב8Xf<4$IE2F25J=w) ZP1M-*'D78Ap3i!ܵSfJ MUzL R]Vj=ط1A P/0!(l`Ű80|\L+*M[N|ŽF EL-OԓD+'Ʉ$rɥ${^}c;Qcԃ~r5agYHYszjv2ŷ:YMqS%>F;39wހȫZ(+8ƁvV8;Qzd^JD{߳w,wcglj=vǰ##h Ahn\$EbE7e(cH6w ps}CW$ ̨4fVsWT9AR3R]*vl+>a*|@FH ZUv@bאӟS,7ck{ړ>I{ C9c8U| 2L*!ָYְYEТ_/FmmN~!]EŠT{jpM wZit~7r;f9Eo lhňY,QW6L`Rݞgvn zAȯEؗ3YtH'ՎG֓s|7hZĉދYH~׵LsE;~s:Y+bteh!&J?J{U#52v%qz޽0k7ƵwC7D27ٓX֖GY=UdfKU>q[H q"x^w3_t J 7cvI1dN|vr >[*B,3utJ[Ɨ|3|*| #Mdz_!g__zd.COZ)_:ƽHj$ݺ>%&n9Dls\ⲉt*IrkPP0YO,B6.W[#8h 6zAc~Q#Ɵfl>Ilb hR }&EdY2?Z$t:5K2e 6OIXp(H)d* ;%( S@0 Qe\C-y!&$7ϤdJGa>?1J-$M )=[pZflj(ǣm]3lD4ŘH_Z$ĝ#MzNPJ}*bP &&?3I?+zd&l c -Lܞ`?M䇛~ݍ T履6g F ͤ2TG n =TTF^Du8' x$&v9#Pg+(@cRZm: hH`?b}7O:yڽj}^;ssov#Wh,S iBBUFVCTM9kYy +5s?1Q*dMf# Ӥ-kKVQOʺ64jsvBiȋa>?&0&*۸l^^zgM(NAҟp)jl&q8,袑%CqC>9Rˠ}j,;^<kVE̚6 Nc S?0jC/G jOd,L"3\ϋn})C5'+Y O խ /v'_"Mb52s:I)WF*-P2m՗Kt@_~e Jw`, (&[ %L*ɾbFfiZG-ifVؔd.C\9Gɜ/;YG{th,CGQ=!yHBg뢀dTH.eht2_g.0-)|J1 55·+nٲEeԹmc? d]6OƱR# ?0KmQ1E<ݏ#qS}Nwaw1d&4%Bmyh|}~%56԰0؜/?DS9I,-,ш]RdauARBZH u)jG Iz{RgD(@w fmMG>%@IʖxU,Zӟe]ksH h*;F?ј\OR3"N61vkoH)̑n) > Xn=_%)`k0OMo{[ԊV$oJ65'M$8̦OQگ@hSpe\(#{M8-w#l7DH ;J=GܪyP{77!i(IN$՞_-o OuưB3!{4Y!QYmpaxvanן^ᚧ8H4Ե E5ԅw1dP6\XжTnp ߶DMIS^$k#uIk!\WUS|AtZ(*uϲ笏lrcv:QD]' ~PT]П%,$a^zV%@h\+JrDhrN~!uB"M+YX%[pj-Ǵq.sBNSaX|P! xǿiʅwXG-:Õ9oqBFUJwo(Lu@({KU/@G_%DǹE[%0#4rݙ}_=VLnm:"UpI"]̬GZ؊ KRs8M ےxUR#2csP*G}a1=DR#j=1fr#P0X4QC Sd)پ8[7MkّVbS=}A@'Ęf&6ĐaR9My"`WL$++zȭ`h-.{rs f0}}cĝ,#1_{z7ϛdU 2ݴ7 /3,r_XՔ?SDT"M@[FnSh Yv16Xs1yo_OIE5nB{El(,[^F༺w''v'C*)1U# " RDJVpUD`5P0 q H`f IK㓙ET*5K~0N9G5VbIXtG {hPSM (PG5\U?jOC536t5##xj iŵ1%?fjy`Z2_RWǸy0$~hՃF)t}xPb*F X5h 4B<&— ֔#XE'|4PnD̐괤:& ._EzMZf"'@Z(zy ]ʳzisOpcr(b=rxz~jjzMKi60#o\Fb)k9|6L_"PɥTQd_ީ<>q1pf%ë>ٰ;<کY0\C1ǼU9 a)۷(aʏB6~cp#8',wcE+5 L|Aܞ>іFNEoVZ?.F,/neu- _!)LÕ v,LoEq'QJ+whMWg lQ ۝_spֹj;<*!w^)ypA w\=T<ݙ{Gj #ax+čP v;#rʺ$ 3nyԁaQx=sxxKůĶROsfA2F EKUWO9Al03xȡ۩ޓ89}4bupĮ_I(rȨjdpEh^j5ծoϏ<ՖXqx mL Sf9F)txQݻ B%8,B-3H%¾w3+DѲ P_&N7hf,R^N !d.ux?~VRwhlwpY 0RLj1RÔ˼4Bay*Бt?Z:bE/9ۋ!% Ns=3f0Ad,6u,zP ^--Op;“==t?zx"9q\Q fm38fBk5cUfr aj]~dȬxtDXhu{?_7kpߏ/k=iFpAy{|fv|-)XuBPm1RSXasVntO:Nb ]jxO)f)2afYj$YaS?e[|!WRwٟJ()?52 )R9@/HKĄ)PꃈڟSiU,D-@zqsrVGkP9N~O*{{&ı/a 4`@lw?Z&Yzl;&_cOO+ȤVNX1` #7pƄJJ|?W[&>*_Ɓ58Z:K^^?CDk g;$HeD"ԤGUTĤ(#D=#s5D!cҔV4q3Sы2n%HC qF?hMtLu9♮v_m/+ 8f/~jޘj3ƴ!N.k5H{i'"ljj/+D9Xae9gR¶[T[Y4`hUdo "a^bsI($ (p⿦跳| ;W;I'}\<{5A.鮜\Krq*HIOE7O׏_6c9׵L/`pVcP` GyC$-Nؗ Ժx/Aw7U8!g+Lm߿?g{v{SZ,rskeX}oHY.~Vzә{شAn||?hz"5FHQ?Lz,zi*D@e2cd?X\ZjlHt*0bji-WAx1ߏ?<7apzc#$[Fo YT(aU/W z.lZԔ 2!( 09tY@ X#8"&ZfMJ IᳱX7E#8y5^Ft2]R >?[TkD/lP@f2Jt&Wli &ZO p2Ej{TGD D1^ܛE9a27mZ7^Oej='J.`ʳF9hJS|@IDATXxZϯ.JRYxy MnqqCb ,lT7i6ri.+ZT7-~ Lo֖aWM4x)lZhAmN+,)om=r$`m|0 Yl L={|d0 p,_- 4d\Hkj 6i|Q-ljٝ Ғb oZ2C|ͱZoS +_F󟺵AId^AF%qB=:t٘b D [R t8_oƽjBSJWT@xĔBh[5-f`4 S`S0I3edz ^2@̒H TUGm" ClpF$"Ԑ|Khe57>oRk+ Bkxd*궶䁕nta08+B]"Hpz #4KCO|Ҷt\F (b4׋6*RoЁ ͏꠆kTZؠZ.& 'r"8_b80 %My64\I`K:#i\"O<3S# Z-Kԥ6t%}7F5&w tpf+vfH7NʛEa(=,p Z90?z Od`W~t +<eMbg(f%*kNX2f9bM76*bΗ^X`+5-n9lpX4?1דI@O[&(Ei~@Qt/b=yglx⻯O\\1蕫u.h''hIKE3>%ZF&"rF`rm+=- w AK7dgnvX-A Rf Tk<yL:Iu}|RN(-iX\~>.ԯan P+4D~lܶseL4a1ؙp zUIL`9Xqwz7%_Q+Xsͤ0!1-Re L^Eq*e(n9d=xS8k:qH* ]OH :w˯g{ ȪRژKc1~نbi#0J :nB GPszi?tdh h\6YTu%hKQc:k|Ujsz;G"c33^qnru}r˙,ᯈx Dh>͡O%Cq\1 `ui~ !*Ib 0#ĦWDaǴ J,E=LWa %M&ϷǷ;-j5 /frBm1v|$8-J` CWL))>pEuE6 [nͪ ''cP]WL$bwc]ڔ)!ߟØUQDh;9K­4' ޚV qZo #R FΐECnj2- /+рS̀S1.1Edx:Rّ&?3 ̒Rߕl$o;am LK9/|r;#B(brLgT)d)DmSfq9zÛ!nwBhrq,`. %' rE ylLƘ>&2u)Z:緩L7Y174HpA-3< ;_keq`A%k"?T1_oq#)`|IH`5 {X1ՏR|~/de5ԜV(a(XȲ޵jtMi9=t<=;4,ijak7 ~ %}J+I#SZ9ҸL8A:Ѭ"ORp0`RSa""qcfQzG2r:%h`IX_Tmj5VR o ҉D,iBQWPOt uNyw6݃X"E PDLIx(>.L)3f'RMȱۻmkpAF9 LW2̠~hw./W=Tݬ7hĕSIR H9cw6@X ͤkXHR&)ˠMqmGf`q\,#t"mŷP"riPrxdN.gR) 6}J0j[J'ô^"j0˹'g#SQ1P;͚|R0kiE#& `cOl^ቩMiȉA{$3ÿߖ%!D+zXVXyQ;{kiln\8bVdx$gC,Q7D9_F~SߪN :**8vE:ȏ)x<.~PDf4]ʑQyңAֆ" XCFC~`A`]P02'l!F^6 F/PMzڲδg,om'v128pk6~yI4nE1 V+94't }lٜoD3O u/ j~9+,q{PHeQ TO[@iHlTFDߥ3զG}DsI)>EHO^\qJMabTdthv ._iw\EWpiOk$/+pY#TD2v፤nâD.TM5amHƃf1[W S&)S!d>x1ɀoMleꙣ~hogi hj ZhķlJ-]b?u.'<82mfR}R vP7.H䘐 ߛt9d ue>2~\-hjD:I+:.!C{B^ۀ @-xnXoXH85$_=8jVb@;NcI434_TI`xj݆>-I#.ϣԭv͕纇~[i{o-KLsaTGF ",(.#UnhM]B8!c6Eͣ4h\m@Yy4:+h UHiE dR s-8|gF0?ï%iZgD~O,?SV9[k9%LmbK[F. 1MuA!Y:P- +[(625Rfq۬ʐguaFGE*Ѓ#\5 *MNjl @8]'bXD=!<`iʖ|H`WbJcݐLFv"YuYBm͖0}ģ ߌ7jD΄jV(x&^oNiS3$MjWgcBYg hO]OX?"!c@,`dȷ+,b*h033 (2X\NH-ylN saNi K7%-gr*˵R(]J#x<~\^νSݒ #(o@0:8OC*/ rq\!5HHL|= ԊFo-BujhVzl@t3ǎ`Y/YvʶZLDSW[y4pnZ,ľC}e\y/$Mbg<60/,-r滽DdfP`{&OCèQ,ltwS$j)Be +#%.1lEɳuvK~||~g/5ϻhA% %`n Vkxw"B;)p&.| eLOGDƜ'7M|F,I(@=̧?< 8,:鐰Ef;ln|SKqXGG1I܏Dt0'B4]ɕK%@TU^EEn,&! 9@bJeVA1$ڜ7Bø`wkdLQrʖhӔ*YSsW.is ލ.=kxW-/7r~~qS'"t;wrxV\5X E 25G4϶ q>۴V0RȦSqAݖcG8`w@ ^pKFf25cԳ)Eٚ>^TǏIahs&N z%ɖv'S: mEUzvG0E6df]flH1ؠS+‡ǭDNr~;Bب5ZǪf*` cXXXIu R^'3jI.C5mG_ۀ䦔-r> 6u|K]*beU^iV9u"]9EUSr6t?z\y6&= ɜܲ\(13̡^cH%[U9t\]|w,*`#V)}nGx >(x2hU-G'XfYoݑ@R`^kI-Ј˗2=wZc1)\|&ɬ% )oDQ@%"95f-ŢgTIqѸ>(Xr9TDc~hܖM)Ƒ05veHֈsD鰴wT|mB_no՛'N{eˣI4fiZl_ȉhnÉ3냈>yi{ۺ \O^_5fb\Z%52\J7 OH!R<ܰڕgVrxʺf|AHR>z^\Ј9CAh!K%|ְӉs:b1b$)T=,cGPZ˃m .|? ] |83ѷP|^BrwZ*'RWƕ?2 _6D.'3,0= )yy<4(DCB95$gTzsԠbqUGĔ1Pz85E5"2~U[1x%)mC^ᜨ+) 9'zC@ ) ܦBlIx"i8'^9^D.񗜈ofZExxW-y )KցJ1F?+;)PfZx2R6 c(TF%^<&)tѩ_}@ O@Y>YKq+܅Y=. 3Kz MEA7 qX~]4tORiye@k`%T,J\gn#xulY,OK/cwcc1E1̜gtFg?'/2+{|XSK$aHx_͓L!r փw g9\.h- Br(F}!>gj,e+zYP 8R=jP!u=8KK;YrhpuSy®Ѐ; DviIoE]px芋hHZvsy& t0< /泱,ląpOmEG1J??7JP7pH1x9]EeW~Dh;)Jj xP{1#^dl믩p" ""( 0Y1Sg/~K[ Ch~{?H܆yN BP|YfDdP(l7{5Zv +5~! Rg .սReV3אc{C  >Cѫ 8M?aS\dšzF?&4(y&x-*|PwtQq ill֦wO/;>DhEAqqhQX)rzP\͆f9BY_ ,;x`Bʓ3eD1i#%H鱢(T1zSߔoheo]{)H/I /!́&5ϩ",2h$h> ,f:zJ6'x8V;IZ4Jк7SeM% ʤ&z$ZXTE]>IrS[8v*Uյ) reC)JaNеONUSOAc"PraZ)_@zϠ NܙK]{7bFF):z"-xˈL̄ Of̧m8ց.9W8Ial^딙Rz6ꖾlUEFP>SA)WNQa ‹S43 :G:ֶvxYv %XG4vĎ4f4loͥ-;?C0juMoٻr- Ugb(Cs%i"1$AE7<ŷ#=]'$&4}Wnف[4`O@bhZY^5r4,#y듃Vݯ̄ ̳ sdC٘U.-v1;4130^(iySh|5nnYç|`䁠gEqOSƇ;Zv MT5% 1du==BڄJjkS1X{?A>v Me Z6*lfU9ֿ٘诡wCC5) d*3h>!ƙH{\lT4Ҹl dJ4Azph.Եg qvѯsG\m""`,h@.X8In"0S}Er L#]6cbml~/F -kց>2y?@*bc6 ATȀ Sx9WKCo201CZPVX;dh(x>LbOIDw@H)+ss"Z.6X\s2 $ „e-?Vߡ`mPhu|j)9b3dUi9ZeK4Ot)qٵ2a(cq&[ ATwjKYq!n(S ?bgrBE4 .ŔC㼛O~BrS|k| ѵKO]Nck}M_ʀbp%'Z-O:lH{#Ifzƒhʱz.6vy?nUr %V|rdyv<H^\[+{\ :́|Y]&`MXa~0,P QY -R<<-[~u7S*&C" E\| s$ʰW{Zm#CFtJBM{5FJ!bZ_p.W(p2,aX*c ugP_=j:w($}+M.x!I՗&a?ְGCcwg<|:mcjdžXkG;H0$ż ]9!1Lؾ /yQ 1,>:)nzN0 +:bOiL8z>;>įlX*N!U96Z`2v]=9qge$.IM*Q m / 3@tX1f!qfdG7 FGQ$q&Uµj[<R D׶8WwO<1vi grl201C8lm ƆtilSƳk&ht2q7řHB,+@*JKWo7,g t{C<+DK2%Op8#26QS]\9D .?Z3(ixH.N)j tM=X3jd"R4JSitz1P.nl;6co#/=/Xyr`!$uL -mUD32,:a]iXA\16P|kkc rjn @Co48V]8z4(Ƙ6 "JM<R"rÌ~9RO|Te 9>DVK-Q#U2/fZU4;vʌęywspfb<˄^*fHI03ׁSH ߌZ`*Ц19YEBc(ۼX $n#zh$OԃKlAȩC(S.`V!RzZRm@(x~s8D>V Zj̖8)\ԥAN7ĪЈ H% J|Mp%u C]Kh'R9VJ>-\'׶˟W,y:be,VBq c[Qf3* iamܳ}=$oīdXt؍xlKx$jKrxaTT|CG"+]>IJe5IECv.)x Ir_ [PTsL'Y& m+"Jф,M'.-@iyuʷOGWhI yc S8m iPQt;$tr1۬kn"n(t jLSxmS3uWX!p"Yx& ?gB#aNdJZdbxn}UpD4PS%.I{mM4hFUgBL1pG-g6vM..H'ϛ4%@;cymvy  %X!p߿ll, P6jYYNY|k>YjjHP4)c ٟ B^QI}F))$qKI1Jʒщ 8SYJF*bK-[v@5rI_^DfԱkddS!{kE-! ǧ'F(3~Hs*׷UKB>_$V6K`Tv"9(K ю`C'b8<]kNolrZgEth, 9g'&IQikf"8FFC#@1>-";xf:}nO.V{S}csbC솀5"agaʠՌtSV5zkK /lX35ihA 1V B,u֪ۢL>vX^Vx(+[Fb6un=_P6$xxvìYQ;Ք:YA{2 'J-.Z s:8쪆$ ?,smM~5y=qqRr8qfzZ0,P@!Z1=I;yo<-i;\~=G &+YlvJ>H/Z  #SH$0V 8i}yH]VӴB몒S͙v|f *NS;EJm%&x: T ׁꌴ/GORV3&TZ;7"`ÍbLWzF.ײmWbOŸȽO}ۏlFޞCݐq`J@t%hcX08( : ;B(\Rw!vsDiɤu<2Cpm͓CIgQ =x3-njVڿE31sC` k9G O3N#Ûµ.Fze 4XƦ:F"24Fp:8FFv>roQ9^+Fj豮翸n$vl²"RU``oE)a[S*KPqJM jycѝ,A* C+Cp 1"2jg4c"bucunzэDIe?,la۪}EM1/(8ppܽ~ۯ̇<'LOyek-n(>72oHߏ?A.EGp ܆8#6pLAXW\ܦ3m.Q^axܪz 15epb#;{oBWؕ0EfmΖښ`6FK_2;rZa$\u$p AEhϞ"7uyǹ >tBua2C= } [Vl>0D@Ong=`AFRK6Ac474dTs,*@j&0mpkʧG$g-aITek_fcA[0iС^ @ӵP! T̟dC{~V i0pz_ zʦbBkh>~=#8N"kxoB1N{vq*BX+>VRZ <85oaْ9JR4G<&@Fߕ*-G^? ̸H~r`x䒞]Q* vBMz5>~H`H .4&B[>0<gtԲ+v1dX9If,8VYnUGJ~ [Œ`MpKCt8.1[9K$SX|H)B'h0*Yٺ NC٘v*ïr_^ús&ZZJTAM)7u,I^#HŤDl-ʾiL >m $K{["1*dFx(q+]OZ&hmߠZhָPGٌ0Wt i6L Lqn@ToxCnt-̚SՁЅC1<=$<L'h1Nf^[ ¯OGcrnuی/?MެAELO1c$X1lGJ ` hRPbQczwR>? FR9yVf@n ـp׈29fFƤO*sRك+״cĢ$<(Lf#z`1ѲT ؐ ;!'BbFCQ7lDtpԛzˬ 8)1ĚXf{U:sB qB e 5V=fM_z8Fp"8·OfҴF֌~'m%jd,FǏa,/y`tb:E0>z (%]rT^شj i[+կ ;`:T'.Fֻva)l)cְ2~SՔ?H#(O䯒:D˥-7)h]h&*j0 XiIooᇆ^l?ڰp2 HL$8Lw$ِtwnU?sD+nTƊ=™S IY/7O]2 Yo>[Æ֌:f<*3eu.;2vi,'!װ%ص;h\uL"^)t'9+J=?1-T!k 4O ̦%ζ `ݙÜPx{T(]GfGD^ ] MZ]'pi^55l>E9_)@juBVJ9),9D4c6hx-q`{ Z$&7ʟͫP9G#nŒqn1F0ϯ)Ԕ\ɥ/Đ (v;5p'Zr/@pDu _'m4|.4ǻaj߉yfC<{r!gK^˺F Iwa#vVv?n/tImjҤ?{L}Be>IsJ3 4L5AsأL@@jw 2Ji`Á^r7l"bd@YWmaԊ`?g̊5:O>յ @ ֒"$c亻<Jzu$b-c~dSplN.L|d>i8A2m@Ќ ˣa8 rɉ3$x@~ٶN %RP =5t L|Y?R9~ux{ϻ]yaY3+ۼQdiX8Z]ś.`%*Ppa W0šƢt^a"L`QN^iK&`mq3#bv~ʫlHe@C{Cx\8ߥr 2;4hJZ"WWy\KmJTrOޔr O wgFV{DCa~fѰ-( {qED.d*kǵ'؀aB,؄Ǡ 3m0ˣEG [@ 1txhZW9A eǒ02 eQPmc8I-;uH<RԝIl Q_KKyH- K`址n gyS'aZ ,MŇgzbD =.sj(T BܗT~z CX-839Z:rKj: 90z]{x6:T?|$'Vv k3/Eހx\Z5@:DqPLsVt=EU'{\;T8 w8}ߙ.ӂA}uIAݚ#L^Ol0|[F9$!ailGL)o;(r?| GB7ʤ43Z{iF*dI&;<[_8%79Vۘ°|8 Kk3SUS19] Z}Ko).O2kPIUr j X4 ʆTgV.m#Cqb~ibXq^k13䅁%Í-Ѽ Ey+gL$FA ]t.Xq^Cbtkta<E&5ĮRM ^BB=4epA{b51zNԧ) ǟ9 n8VP#lD lus > e^x!M3Mj[3{?_+֓|i9T=ӫ2y2UIinϙ0g@{|;M2hJ&e+baM*+hǩϽ0BaX?3]"P\9xlxװ4z{B*=P}X>Ԗte QӶN$NVǫSIvR󶄶t]Wpdj zY?"i/[Q5^{ߐ("KePz/myD.6z$?FPs)`p& B$00,c:%Ϳ wT9XͪF/(6b W;S*I,<斢Ŀր`ٶub)蓘Za'~*BdnYvE\%(VIo C`DP8s"ɠXEYVzK ,> Z݀"|zs IJ7 ҈!2\fxXm8F7;X/Sթ^d< +uVEvaŎ=uBm t:-OꘑhJW{ }j"ԒdM5Tiw 6x/<Ͱ|/hcٹGH{1hU䨶B9hI._k Ȥq;i @pu|7X:dn ?v|2. nq ,~~vw`ƄZ5=U.Jpy5Tڬs(䈡XiϾXp;vz-_t # .$Cw̛ӕ'V;{9XjkKE;E9z][1 \H@g{=%ޟUca=^ZB.Nxˎ^Ml{GojggE<.`|@T{kp5%)a%{hXM]pH5HdkGBMtVD %Rj-'VEM%@jގ:=-FL^FOh\ OWL"dqz<v8(qI<OA VwD륌(*2rMW%]v} =i-5Y S[jTlqS~D:QS^v>A(@Z'CDL׷c W0)q\ѹ R+ՙ * #G 'J,ȇGS94HY਍ɬ_t0aX_9"+^/bcku3J6Pu?AiIU/#HN/jLT#C}H\N~Kcuk1Fe]钟 M!9(bs&̽LL}D랙T=%6˟d.%n1w$un`ܕMMU>F^DqB x~W/_tS1=|37q0it06r߷ Ji@ITM-n_5t[񹲴(vS~h${ xn7 I\T5,\fˀN!rh!wd;ZQTdF^,3=6O)ly9Sό.x:>nL&<~JW_x>ln 7>7ȢKZYqӦ})ӝ=YxgF%M0U,k"_x2oJt8ɲH߾dhTF;J˹#TfDZ%x=>ݱCBt"}_ϽdSyPt" 'wq D4_d87cc80"7719|L[r8DOm|bA}:U/XRFP$EY|kgROnrZNi?c!}`K3g͚|#oPWyjȐME)La!n27c>V-%?5\r#&q-#N ͵iKЇQ`\["}0\̡]7=ҬOP6=m*sV2 &S@mn*0HAA߫AX&0 "@ŝW5 o*Y -7!(6"wow$\OB5Odkk!RQ5(ﴊmm\3:D.Y[DgvΘ}w^d 3}Q0>o+qh6zj׻Py F^Ƙ#I*v{D` 1S蹘10Cߧ'xdY< f EEB?CXӨ ]<՞Z~Q5X0/ <9hM=f)S~RY 'fj3O@ghX8d\#H)d{-}h",άtؕ܈U!'*-9pg?Ied63J. ͂2$44Ɓei_D401|^TO#p|T}7oA;H(:mooCؐF7J_Qt+ҏ,' PӺ2fR!IU5}5\R,Nt HNeLl#w8~5Gp4$mvԜ`1k([Pz kۊӆF4ح4R]e7ڒRF;mG ؎ܲ,s$a(LN F[yf C5Z݀NJ$m3Bd]r EMS?4jfmW6th繈`Nx|% ?c rMTLIWvrٳ)}iH;Ca-*ZKfyo=j͛$!!\}"?+i{Ž4QޤrY8K aXgB e V' mf28(%D,N:(@X%}dΜRIBI/xs/ γ-:J*"/_ da QiX2~"Lg7zÞ,A*럠ԔEGY$e߁#"n Jx \EUi.7gl$H}h& ,ZV$c/Jͩ0Sj7lQ ԨR>Hj-$H׀Nw6$qiQʁp<-z"B2 P_aaW LAl ^OТFN!bAz}rBۢNa;89j0yI_ Bajuu6tEKLۃW 5]'pʸVߦӮHZǧA{ӗKtEI|i)ܨ~0 Z%+ ejSwKf]@Ȓ&ݣ̓`i)Mڲ9LG"1A"W@XqCQ|KApW &TQr,l-o0anjgG$ռBTEpQԐ6.R 㡏W{=`?mֲ2c>Dzl/2-PTȔpcXKaZɨрS*﬐;e͸jyQć6hc,d+& .Tב)Oh 2&KyjS;rQWlKjPе=`LAXY= %,PBZ4eidThNC&XP:r3NFe@3ᴆjc,o%M9WN-}6ΰ#ALhGuz3(iGpn^(;5Y@Q@P@ S f;X9kaQ-:ʮXU1$$/C [UB<ǐD\䠄p_IaÑ&]-LpE(a;MI%3@@NE NX&>)tb~\g ҏGUA0RIopLbX"?Mo8`Gf8(6 DY$dnڲ4`4qrC?kg.X1"GŚK^$B>5E /'fm'iIlXX=GIYw 9LAMe8}<C?r. lhpg@UEcM#XÙ"f!c~?3sI@Bص!ukb-˸6H45a}-F7 j۷ۜ}>:DfUWxm{udϗѷ—ac#&MU"!w8Z$)Qعq Fmo"zG>Xbc'[BK#怋pbh[T1yNNdq)L|IjK3@##]X}{\X蘇BB"yS`vѫ~Jީ21-(=^ g8visx'paVceNgD <7IL!g7F-Ө 2ґ'-! h&-f$ȶM@ x: F.Dh(g&sHʈQUnG} ղgIJ8n⻙oW[$$ECH٧oo:ԥZ%d/~.tpbm[IyP$%c]bZk! bdTHUN (\v#q=vΛ`pg\DlS0!xF JjR@<W+?C1 5X e&@g0 qZϋ SO)Vo#W0423jIRs3<^?2:Jf!k\fT5 922I-'ʧ a< 7m!Z#;2-v[D[TJY-~$>zZ)9 OU-uE(g!E`V-U/Y'2ۃ@mtlr[6&M̮.)G5Ht;CfZuzx䩲I>$7Hw*{Mf}9E\G25]7)CݢU\&c~h!(Հڈc)H_sp#moNOEcCtaoFfaFY_wcnc|S%$6 [,zxXIo6Ϝ_BMM!Rj2P8%'j1Z>?w|:j000- ggxK=:~sXc=ڨ PQ:I1O֋S>;sz]o,BX=8 J,k" 0E}H%FQ<IES#=j([D#FY2a ؈/D$c/4_Ċ_n$m!S8D-fx"TD>CcʲnE&=F+/Dm~4L83R7M<]#}t(fya$63fi&'Wh)0"Np?& ,;oU:?mΝ`8yїˁ;NhqȷA:$gtC39 S޺_?co)3J&7Ul/ 1g=9\:Q4S.R4ϻlg䠃c[1C QjC]L JT79so;enC ,dlŒ\35x7N&82EI Ӱʰ.(cxH&HƲp7`>(afc m)}k'ߎZ2ɉSZмeyv%Z(d8Yfiv`QiB\QȨ fTlұؾdUt 6O,=?7P識AA! (aM/d"[B1=7xez_j:6zșOi 2}ʧz_m$!vgDYq'rT'_3 ]G} ,p)yVvP}33]SL` Qkn)dL wE߻rnSvlMk2g4T'ڴg8qg!x1bꏈd(dcyE"#% &06#"'?4Db4cY޻πš|iVHg#+銓< u]h:mЕ F=ocǪ{y9o*[.xt+6%;cD(2#:#y̛38sVҸHT]i(Lvi$g܌g\Em+;K֪w@մ.:} /0p$4jyӻmB:~9^eyC #{b -+ 0i0Ejφy=f,-Ebk pX1 N#aB {|"H~"!&R cy $2XP|eLi)RBTvp)x-p[bB(Me@iJ \q|ЈQ\w.)l5j2/Y_ևSt'HFXz$"j,]OS(8g *AҔ RR,ջJ+qulS[Ň8QJBЩ VE D>Q1jAd"Z2clduF"iykx5cQ#:"YZ; HojnL- {{@h zH䋟Ɠ:HsGǓ,#@ܶx ~Y Ȁc*FFp(\ ׇM:k=}9 F4mdIS"#Qk$O^.ng 4^^1>O;Jx\ f=/*[Aj)v,5l _+s3BNe5fT2eдˆX0%kQQEV  6 i9Vl-9nic9 ƴe,d:&""|c(Cb! >l&#TKxˬ:kɳ_.|'a9l:4VI/bC~F-$D[#9 @rbUz+brka l~au8x!X8/H4o\D4.x_438h^~͓!smZ)k3篣E6"a3Z0e^ K8DmimF\ԄJK+o+SmϾm`dU]Ω=lIkij+'?8qXaq?E zmogXuca<&j6- IgYۍڅTflޤ@`-w[j ǸڽAw.u蒈$ahAYԐ&R?x~̈s޽ci2j(^_)ޓ/&cAVۃ'.9V~(eFj;|=*Ϯ+ھZ:Z9BY'P5*3K:4 :EVDgͩ̀P:3=?cEn/-l21hQ;K@yjpr8jFL &8] 浣3波Y^f-%<0dm3VFd~c뱠U%nĹH+b}iyEe-YQ'-Gt !2 knu1-# 0lWz 3*%'x3V}C&Gi\zkdXP (v*I % &?S;@B r&eҽ؂Dcz4Ұͩ# Budδ`9uc=K,xgv/̳uoJRhZE#@IDAT9Z…bQd3a4y1cUF>N\xPdLh7~=8'b`Seٲ7IɄ my ’swpLFTʶ! 7-SZMXiVU@*hEt2U5!puM#קY;9V.4߯oG;u D b31G{q t=XW/_/зǧeo0i]x[$*YvX{-9~ cOD|\fq?&gQHK)1847Nuӽp):}Q[`Uǹ*ԓ˴-OŃ__bE<=.+3x0y3c2p Èj*gpdSRSi?ɏ7~Q*eCO zijvMQGR]UP{T5[O=N˵nzuQ%cpIFV#r'ȐUTȞt%O{ *C[0{=סvBĬׁ- /@ULO`֊KbͶݦ49&DUՂ(Mݐ8U$64*FQT$An@W ad'b'o]*#kFpԏXym>@ ,T{m^+J#'J>-E}3,hM:WSdtؔ2 Oi+8)8XxCm?_-_2YZ*oϑA*'C u O"F@Oo#~go4PgW,)HrCD[գ^hŁgQ/>OCF9!tq BiдJ6R }"pT0).ң=uDnf"6HIxaU^y9I4<,Hon$G4q!V'E0 \ODRGsN*VB'/xW4)d3fREoR(AFsɈ vTD#Dޱ&VPU' \ ړ-r;!vԀS˄9RB@.FR=kcZ ?|HU'\PZFRsJe׃ fƀz;|l (.qJm%Lr ,9,`)}yܫW&=b;Y >HA?vM ʅPoߌI蘼}be .>5@٪P,#'$vfh1BEP/HٖKiΫJN:w#Tfak?>…l _½yp%(`۪;laUC`<ڃx 7>m%\h#nZ"ۘN$d0QXV.4]+j0SjijQG4Vx*6=f J[N =HVM1C]~-QJ q!@tS;\lQ||Q3Egc_iIYh2!O4[İG4"`KR[O.h"PΈbH8GjKs#"(U1FT1H$qMz?*X l/ X`u:ṭ;SSMٸ ycj<&x՟x qt~2)AYCwq*w'0bV,mЌ2q v $HE+5֤T} 3G0A=Py>6R5yH,x .:/$`}C꟬l^hRH&Y[ 4 QX?y09"ax%FNfG@t LZ9!D{H]!RPfSŨJ ~}dq;,Ɔ,5B]*yuP%,G+Cegpo?P2x>0]eM?9cɗĎPkAO*EZdz*g݆;(G9)jcXTq?[IB6Yjκל%M{b"1|98@J|g+:d"D!{MXqdJbL?nm|;LE"Tl ; 2!`RLx+IcG|Й ^ b m#c1%jn8 9rGש\(mrB):xdcD[n'i{ {kKr[/ Yi& Pؐs+I[M;eh{w~Mo,lB"tꈊj˃.\e#sк  da+41%T6ZpM5U-z52i 0P_BdU  (4V6:vJcb4i$.݊p?<0)L9y|^sKPDM ek\e6С2,QE?crnʁghH挵7`$=P?= JZ|NhIE%uiB=P;|O➑}!`]LiݥXK rF;_N5N Vkqc6+ t*OPVC[XM)єK! R _Rnwwͳ$G _m${5`Vv@ gBhFKš4uj(ۑ7n3**%TMn :gcl23{w#'!4d epʘ  77514BO?veL#}L~hT(j($s1/cf ΋ ZY2PFZ+ ^cC! {!-uN)eEo.^~x1Sfbw2.b47J'{2[ f=bdB`I4e Ib4ML3'Ltڷ/܀l(J'3 KfmNWC 3Bd&l #mI ]sg s;^~YN^;g,{ֱ0٨G@Wui5p[]QWo?A\R j*8UCQ#n%xkf RV@S ̾gby cTLd"9/a!eۘWdՎA$HIKZ`2%>Z{+O6+>S?F*)V0eG(DjZW#z)"1". sI &!z` CkJPY('N*FE{dNk2&ӋZe2vշ_^uJǬgCifD )^3hKÆT.r^{'l~a4Bc 9AvqJҝ&])NEPu&Zq8_pQ?K~e,[Q} #8&fL\2gUBBP+Q5E547d˻fjc[fC{gnJͳdj]5YLLvGuUS ԉ" \BOѝ&Fɣ;ɛQ6jHd0ljQEf&) .&!jt\1ZhE< D 49`A|bFz.iqpN 5ReLX`XóCk?F `3=QG,\-ԜL["r@>_ւ2i|N{t- }= V35)'};#= @e,֠ #KU"!(53VmKgJ1A47;hߓ^-wN tu?k?zlFfyOo _=;^ #N턕OOy.AO,7T1тqHTa0RhoA%hr'j=B;5dnq`ܔC%֌qL=ȵ =-!?(1 cD~񟂭wfJA6 :-V_Φ+-D`b: 9,dC2tsĸv7h<9oۦsbF䞩ތD"5z opZ!43⺾'x.z1 %J̟MᇼKlu% ^hHBI?3R|^\[}UIڿ&D2YQxW٧DU# Ij&p/g$(rD+3AfWM n%w'ADxӎ^" q!Iw CSD YXF ,ȂKQ %$d_C@]ʸHxe3ijc1,mi'HiN~j-q!'6dƹxdf\F2i)RO.Z!K PTd%6'&Hn*rԑ")zSRH쵟mBʹOx2H`H[?nVE1j\O~2s(HZY)Ѯf\^]W4ûZ/ y9[c;j8ukM !c{ 1a!9$ @*0F\^s/-l9&fA(iBh ox gƼej= BB@:=ro`dhJ12C(1*k\ɈB܏Y/-OC]KD !-zmEw͖)fY_vH7Vk1Bk ; (磑#ڷcP[T8)I;GzXtϪ@ZDhMcaWH᧢oxF a \U'ThT^Yn_\L~QԥyU_ ,^uhs/[>mL}ʲ8y2,Yv۪Y/4 m͕&*j{6D(y I\i0_QbF@t k#QhP6v")خY㴱038jbDzTP2sttjwULA*i a)r˔憁wVSÎ>Ń@pHvo*x_@p=[uN;JKcȚTE6XTdf1#!e:@@\8oJ[?uţS!'aPn)9%`:e8Β]&12lJivJ%,ŁK8xBV e+DBIEF9kk=-ld( +RQ^?myEnJXhD;[壚 ؖ/,J.hA'ȟ_$ 8N@Ai$=*O!>r\yYl+3&NlP%7^dz$zA oiO;Ak5cc)S*CQ ̶3Yp sS}Y_z&C^tr{\|uhc}"Y'WWh%С5ir!^#M΂D@H\ +IqZ':4FOکLZaҜ{7wv */EjC 6ظLQ1L͘" l^)E-QI$I)cU' Tdӓeci֧_ PFej}(W1ikx9w #Xs-Fw9p1 iv2$OldEs71-bL:ڷ4}U0M;19[V7͑ާ "ڣKao?NVmOG3kFۊUmfJpxIc'>kπ<ҥ%Ivmx=)KO2j~@\rIaǢ^}[i#bxhǡmVU#a}8 IcU;oFיQTlMa07؛mЇZz{:\Hm_D~Ҥl9S.~+=R +Sx~@|[ [kZ,lTܚݷ)xKB6$yPvƩ>=7YQavD\)eī J֍,f+IǚL&Rp!_ŷxq/ve m  -S9[se›x(jâ9dAhB=?ĝnG3BK%-z@‰ d8:>(CZ: DvHhդL@mW:I)I .q./eY-ʇgcoYf[%ak(^@қ-T-n>qp#%-/Rikm=gHh{Tア8' Xwt QXF ?Wjl.vUp{Y Ԅ9lN^S^ZW \r9fj")Bni${!\Dk9sɜѯe!$q8u+ "&\uįDV3#Fr]DtXDO !Ҽ8牭-{ٵgmsj5k'N5ڸ$DtϞ9\/YK-x-8ͧqdƤfwL>K^>U9p!{}Vm[n^I2.F_Ēd#rp3f[RCS|l+^nCe4z?-V1bܴsu=lffD1z ˨f sT|S)|\S JH$?-s7A2cu3PH%gM;t8R 0Tm(4K^_˨mkgt`ֻ>#0nƗUGIeIY ^;p =#+S02ǤMolȮ1 M)c@&fW We|1 ?HQvD߆y됲%z POJMla'k$cx/LB'V*ԍѠ؃ϫ#fLp5]bY3i:ϸS2[ ?Q'(VTցcEЍu2hH򥆵و-6Z>c^&fApbGAWP#X[w|^lQ!5? f_޳fx AHpMA ˴U\ cflEy<\( ոlY&:ɐOkm̢_@H q\pܣA)Ӓ=ː"Ԫbr +̛[QK2g}FQ,,]IYz.Ӊha&}zywRDCX2olRjTDxm;A8 4J<5 T\o@-j{ÞzeP"&FE>=C ? |~Z#7XH-,}OgQ qP ж8jhh'EMpa'FY"㈾;1!D>#C(!8899srx\46G*a7@|z*yIJ?QOd[9kFpBs5MP p j_i3s [ c|,J}1Ģumk$Id(ai|> rՅ;[9wmXhQߓ'mOf)Zgy6%-!!vyGSyي ,3R,OhY&Odx, eQ}j \5Nx:=`tdw%dHV䣒9Żd Qb+/@bF@.r*0]Q+pȏ+ap|Q.搋\O(>1ƶ> Sn=uCyWOqmސ t_GfBb e!~\;UBBB&eaN].*"8!Yx\mo !p5$)[O8cf#ߞ%g5k@2]ƔmuP#$b ̤!jwήW,KPSi:[vs`8Wo0ZEJD5S>1\lyf$!q ˗ƠniߌMPc=i#zF nGn{AK)^>ZROh6)]zY2hC3&͍e\lUi.deoD2'΃cH :(-+)) ?HrtVm#xCD"T:n Phɹv!+Ld@`b!$Hzx/.tP/oM/Gu7ƘW&$? 95;VK߽e! y#,^|WmU>+ C`iFXF}I?._QW56Ű!PBYمGsE \&.;.JIxxiX#Ꞡ1_QQlZq)8)@QZ@5XBNyFSZB2&kW^0f1e_'i zrk־v@ Εu@~W<[?L:4 wGHoBԽ8B?ӈ՚I6f|*dHMLz¶( VD(ʎ:C7bGQiVJLa$*ҽv3;?^euo K?+b6P!$?g3rjYg)0Zm'FD:xcֽAQ!zOȒsMDf@KHbaC%/Px*LNAk&fn#)NӄڙpQfz0a`)q7 Q>\R /@)~zl5G* %ƂM z5*\|[`?[~QJ-$néErݨ8>~l1uHGC]&cH!ȿXօ_}Фs2z.G2D ilQ"k1PR M$\*ba-_+KܻO`xyҁjq@NoKbWHV?K"Eۮ-em#y?ktRlj}%~"cD}^kt`$*[Q(n^gC8PIM;! ;_r#1 glH,f5~ѸRXyFLT!-r ߖ&YգF)_Kdc2'( $GHZ-=h{> !0;pYHrҼ3a3 ѤbQQzC3W)fOE2#向b2dn+Aie<~#*NF.xE(R*ǬJgORU8u~n$ q̜DSMx~D6gD4A͙xymi"FBwO 3M1r 3rn(}|r1c(!D~@#|Bs, O#qQH$E!Y?C@t+rpc )SY/_dQГ&0br)sCoˉH6cT laX(ނ_4$lK ߚʊ@0MFdwhdz sd@TjKF+ץg\Q-]TQJ 's-cš1ZC oL0)gd>٬ըWIgCWOp:ozDAupߓH:Nrynݩ:_0 b1{= ^8I${,vxoK@`(qFI{N. t/ɅE,pSz/3ucl֒Y_Cq ^ .oR7x 9 lSIOerp%/~f;S|yz\nL&%9 b*;VJ'odco.&qEATIff$>q1U!h4ae)śZ)#X!H`(q*%pk8ȷCKU%O-:ֈxQBIͽq_,(<6. &&'f/Hf9v >ȁBi~fL-W`\z&a3ʈ9$|$_!Hx%2BoHqq:"x}F(?,Jh x6xt;(lX3_v2JKa3Eݝe6?:m#>%X<Wά;BUn@ _2tB͐٬9ߚ0hZ,q᜙k#;}EdFATq=^D.?Ffhj" ki= JiS,5 SGA V)Б3"^Z;3~Jm.uPwx5eXc(!v1C3t+W ^] 9R;i:=6YD-=iE 8P[ Cm) :v%m#j\,IZxUr{ZND.Y|"E vaN14?؂V@ e$2?0`.J"f$Kh[yW Nļ=Tĭhlgo"N :qhLFЮ pш[]UI7L d8  ~N |R4[2Y8>:Sq.Ҙz'XU\16dp@bF6* 2&T]@[#)68;ndY2lkݛt[,~pwZpNYym[*UeV1 i9P$]t"fBO;f:_wW:gTҀ28$53{{Rp.ސj&c0ШH2G"y2$2PwkR<>cI ӆI B_6FNJ]!FJ3(0Q`˛&b/o;$dQlb}9<ؖZf7Aj!mz~9@O&J鰱,`?ol+Bb{55#Πzڗ[9&vex`KH ,I%4aVng Igd, -gl_Kq M,T?k#8Yںu>wT9i#: q@w?Y54[ܳg(1 9폇Ͻ,KFH0X]P3,IׯBq]S6mA$"U)H0k5KLmV8E@ =5Į#&V6bǛ ]vbC,Qmė9qo'dU 3A@PyZBKzVK O~HR*f~ZJRTFH p D ycPgr?BMաE 2'^26C) OIndzhSLQf~XƳP~j`4%!sԡ> !_q$#WO@ ޖ{Rx? O1 !GC lKo M6Uu/ $D=}N\{3sT pkIr} ,zl`N:ɢMttEǘd **G nnPI5n͗Pbf5^UQT͕c! HW {^GaL)#g,dj}\M%Vb熌716-GOlVfذE5=dYE&&7f ?z@RFOX8Bc"'} QQ@ J# ;[UB }ELqOBmhNF0ssK}ndRvh uPqȂq#_Ҿ34P2 ~+ujSw7wQK$f6".P2hmO`p{驨S}!BzFt5Rh8̈=;C%Lx]ЬYꆂNS77aQfoU@`PfsCJ wuRU\ʕ>}VȟL{;__KucԸ{Yu|u2F~g J'e1H.e+5T%׉H"ILݞflՇUR@_-&Y:ں- e=O6` P4>W{T|\fB#0G~$, DSbZKE[& dӫV?$,)fŖX kHH/9.FIH=#=G MA6v*' =MKuP [e\j^ݩ5fEKTՃz"~%k6<*!,B QԖͤ"XPۢ^+4jDziэEdvہaF)OA OGBH\Zo>~'/Z5{YP==OT$ &L{ɄA]A(1Y;ep8|I;z[\Sz/ ֝8JW 1cwL[D}7pG}Ҍt0ue/㶆/]NMܤջ(@=-\cȋE9iM}`O F֍"wLQlݺrB'>#ST{j!.c/*e"+ϒ 3aOVS,O1x@3e(ꘒ5( pZ,A<'džHl,@p,6_O^3Z'D>j",z*V,6a$Q r5&ZPbxƄcA Dm  T|Ȭ*ujyDyh#, uۋZ0 FD(F5_}[y.q0M.e~5rbEGdSW8z29#[JGeF$.(J0q)_'e(31,x5/ +M㉿d4vdC/(i5\VNFKʋLSuR(Gd"fGe* / PQ-RU2d);@^1RpBUm0Z+ZzR #^홥aXRl~1;Pu$eRaia4=X+1?EQ`!7n1 E>TEC-g1 @kSEP{ރMz8ʹFZU˶al+Fٸ֛iQ(8O%Ł6[pRQY77fQ2=QKê-_SpgNeH!̪k]9oRi$;@A臢θK>޵Fhp^6i̦X Xn 7pF USEKbNb}aF P9!BR el~ 4%ɸ{Y4_)8ѭt9 Ɠ0<ͮk㙝 KG<+:,`G4B1dv>iGĨG8,W)P5]*_|Og5`ǙʐC3P"YĖt,dY7ɺl/ o(VG lMj\xYDm fJ&ipޭ6 jOn~LiC(-\hwΆ3F!;P|?Q6COˈ wKj (:KZGZ\ D\ 2#:Xa/^p2USL)rV(UҵWBrc9R]ᇎ>#:c?"HN@d6_P)W䤽 /A$w?8v[ZJ3"2nDJ. g/?=tc&]l @Ƒ -Zpq`ykRj N|aI&&[SZf<6أY}QCp$r & He$pܴ xz߅prp]ӗr|hVFG+v~aG=jga/q$de1,ɷ1VX3 Cw~Ŕt,mJt Tj{0 dɟ)2R⃰* G"VkԞaEuH#R$(5 K1֨WXX7CWꁈ91dmQ?v͝hsRvH2 `̲:pE5WMuCSCw6"Qtq86`$L (" &b"4HJ߆'Jf#!pPFW;E٠vBיRaNq0{ǔhi?`p{ݩ.$7Ɨ"f<X;zlhֻ4K0Egz^Tu+Iok$g}pO.f dŀ%(imzyr%}w="ȡɯU[ILbI\3#$bZ^vG4 AEtW$5N DU6sqjd> /{10"YEJcCTߌ_=29*&c&mGg[6~5^?(+QuQVdn_6g}M1I56l8<{#[v1[Ф1b^[l #4 =_;lҎݗԓO1LbS̞ ʦ5ls5WGqicI:i;2bu^? ȝjGŸ\oX&EѯikHNʒ4q2 i7Qu ?dki,M Wt:JlB/E4DugA6lH?C2׫M(%mk ?F qqqyQ$ nB: n* JI*?T,<0AT( 2?O.kYl8wqB;76gh^˘590P@jD=QVb6t$ݵr!yU)|ZbZA MYh+~rTΉF2lYD2, !s^%@YIJU'&yO*.h;(yH>c ;tq_EFh$CRQGW)yq}\(k4 ynOOT;pby'"mU9A_@qk#q)h"*(af/7i!e+z\"X=k,PZ^s:aƽEeL@ӓ[=V6X^Ԋf:YE>0Qr2ě_PpgD x^%@3C0\ESL'a[C C)FΆ\κ.񐖈!] f泷[}!s#ỺdiN@θ}PeysE8pSQ++aA^@yAb:lωf`~TUYӞ=jN0Qvdf!DRpQJJ9 HgwaVxԊׄ2axGe *̹GeF0X!^g[MjR奎!.I傛j$*.M@hv`'|g ܚDk[NfP1u82?F2Mp۲S$%(Hb, UHK@K,D3f0ZJĤpa*+JTB0Q <ᅵ %nh°:A (Órm ; #,;R!vRJWLbK*K GXCąTFMPNRИDf*yrGSnb{Tjv܊\P6s5irZ -TK/ȅ؟LJxȼVeм2~ iMp#PtNBX9Qc#r6٦$EsWq܍hR;%@O#,Zj d_r{L#cr#GS2^`Eܣ<JW)J(V qֆ$ w ߶⬦`H}G jvX=G}BRg._:lE:`͕BC71ݟcv3HT?3jE4ʽ=|Q8Q-azv7V4#=I2bq(ț NU7aS*78M}e? 󀨢zg\uB, YDV P8 (򍷦jI' L0c$HAJ0NVL5&%e |"{m =^5ꩢ.Qv [Oݕ Tx6EzoCOS ,`w6,7AFl.c}RTABʹc1yTm6miAS#Jb @\p'=nc{krgGz{3D1"D7/f.HZݾIS@J)mXZvO0J6JDfN7u23_~UV5 q3.x"ZXO5r ܒ:V{fM*xF`)j&lUz푋 @s\; Hgx* V|0$s(aQiL/ 4LQ8 %`H}5H/])M]X~>F]ތyqt iռ7z, aKݭLV!I]M] ޫ3zEyы k2<2>Aiԋ5, 1_Ƴ4ա$b0!]jN&I([|)kQ%ڧ«ɣhH2C'"nz䱙{|!҄Kг[! nM\%~k,uEi?_=[$ לPaf4; v\z,+@Z)O9nF__?nG0K@h(YolOŭ. *ȣѡavHĞ%i)ldIxp4mٿ-_b Ā%B[2Q$$wljpv\-w}|\ۖ1/kzbnS)4$zHfJi1&kk. kۮ!/ l=a?!XDELn=츘5$0ѯ#i-XIP]/Ua*#mlDEۣ9&61h(Z)|s.6+/RkZfEN%&xKSh/i|_r?ڡka r"FQ<y}azo]]þ198ӴWLQrE#!fQa)ωCbDeG5:WLݙLl϶VoߧV,b dsl-X̘Xydn߅+=Xsx7_(Z3Vhb,STt `3)Fo6pH9#-A<_ p% `8WNW%<pDžZ{M M>,-3f-{7d6uRI%lZ}kw_j  yk>u fxH lД!XT*Xx- d̂e[6Nei9i%*)FGL'bm =Kvպx3=l$R6>"ovNw|N"k|)+Ť[Hb6Qe!%`+pJ%5Ctm ^Wڙw57EQĆIيXع=vȮ" n$x K묀(3A4] ue)MKiMed/#0eI7 _Yg0772aOl,.Y6V )g]FW6 l F򬦠Uࡈg3;PRļ *zIi)&=&-ԦHgkzѴ-S*t_Ў g?|nje=_[u0&\/U;B ]>֣ؓD(=Lvv!mu痽qN/QFyu=?w_1Kj.n=[tJk<_gso7X*,YDXק*aV7 ),y~Oр$>"EDE;O–&aKĔҩf/ZVbaLv¥P~* )IIqĕ}"w Qr=c9_ 7M-`*ڨD<үILsB N FږRLT)CXt|$W"5سY@X㝎$}D !M;@6zL0ðхT?)6ΆUF9h6'fO:ݲar/>1"AujSx ;ƿ3eDA!!sנ~XBVwoeIق#>3{2""7D!>Ș:wZf@u8[ (FDDG)`9 }'#t]za\vPC<}bl'ujDC'D %" r6nGcf_}|zbDvAGiwmi>'ꤼeM2N%TTP@qSɛr3lD*7u+tGeG<|;ȗ~i&R ;1&)H%-Љ yR{~eb O%J)h1Mf|H7~]|&NSCv jtXP%l67L7y{ i7ŢOPĮETLR; Ň,@CAڤJCe" nB-ēKqT'H$:E0IIGPoGyzϝ^[؞ $gFTVnk3SsY&^{aآLxҐ eZU Jv`7 RBYS@ƌ2L3®(9da#*l?`EqQ/SDJOiZ%H)TJΒXڦx6On"&a/RW;zN AH:LL0IШtdN8-LcC)ѕS2Sm 5|/ZhWT#"Ur,ŽoRE OMX3oͣı`*5g ϝs`%|]5v(/|Sȍ_b޲wڕbf3YRz?2X#,(aA_Oz6,|x6FKlauk$y5)PS=%jx:}뾥Y%7FILi웮d mMD¸?:7VW2t A1r:H,p&1v{?̿# 5+X9-#ZVoZ3T]6'~Y&E$IdY3OxhM8j&Pئ١*NnF@Yf4l1BߋO?D^:rMT01@b޽ʶL}Ne pA:n+V\3vM$8% 0ujF޴,:ǧL4 k><żAn﬐scU,t\X*iY\t T j<'NES)O[|g,}=EzѽBh 1 XPrY 嚳0X@O B骇2P?$r'alΈPT$$EgRmĩQa〩" +BBx}Qb"JB 5Ӕz>Ers ucr[6{qI&rGoBF0I @H%HdC('-ʲ/U]Yr!xHߚ|9Gxe? ik"Y40=1S7z1qnIr$gR#v`t!dkF;X-J}#* 4Vxiы=MN+ZI4!Q q4gNvu Im%p K|\Ez,"m7*lP0s؊ђz,)F6u!iݙKv iFC7}^H0z$Yql/6x)y^یQTr#I`0De >Ey 3 Zly[);HhTaʔQF Zlr(T6| P6ARE&,Te6M,MmoQTb rgĀe &hk!L\o礈2[CQ8B=غkbalLc _]hyyԦab* F&oYP֋b/HwWu`:R\C4h,b`s0BP٘#: }E`H2Ϋ?:rjK`[3Cu L/J+(e;3&ոL'8tљ-;p"]EbsCg 9FX[ZPE]70ẑLAbzwϖW"Z2jW7Q0XRaU(Q4\Vц"}ej?&>Ԉ ̮6 K%0W,H3:*[9WظeULV7oa_OF]򆛲zBFQNrLoﻵa1`\Rb/( bI6Z"5ZE0F!K֞vFڌl4 "tD>T+wOML/1uKfPJSXh&*@bFBK׆eO=~w_(W~w\IQ YD#5KEk91m;Tvƈu{&G]E"ϴ#:9 b4JcLueb02eG䕢XͶee%yu)&~C' $@ DcZLq -tc䟪th9ΤXyBf'/!,e`#÷rS$%OS臚UNq\yDIqϽTwkBz<-j)\cy&li|]tsd LqS(q`W鱁d 9yx,EeoHcaDUz] ,FGª6H ^-%fa%#C#*OZH:G8?,Qմ KZC.fWYECov0Mwh,и3Ex>6k2N,XPѲ a* xOdm'3c 4gcH|I @#yM`LP2?]0%]2GbETa F"R_,St#2ܶ3y*;!V C;v]gH'oYf-v@Ю\tlaRxx gs:s+i|x%iQ_~=v%uŲhu6H jecZQet5?h&KFJF\Rӌ'M5 2/"~j:5@ vFtWŁT(Tv\>،Ima '-(NKaS({D+lX͢;h<+pA\X68mW0umҖ"Ya!U8-glН򃆰z.*[y}d 4fopQ\K^"R:J7,/"|ni(<̀iLu{ Sf}>?1-{c\C֍y<дf w "?IߘN9j#Qc߫!ET$ɀfp\`a+Zsjgo&#YMOWP>qDh^-$ |Wk&f)1O2c.I8PCHv舰AA@I"r> ;+]Nk !Z22ӹ*4#'Os;$Ƭc/Ӝ|u5 ! 9I$IĤ씀<t#xHC qIO;Qrsl=,1 ,qJNGi'U6)ۗ,9Kq{4v8#>y,=)> "RmeB6( ) t$ F`5-;kՆ)W`AgU,RD=Nzql$1$491XU΂^N&g*lu2LA*heH%S2]hMerbKp]yz͒8v8YIBCszIcX< 񽒆0K䶈޳.ENz0ejAHe-kC91_Evŵ,WhIk)az*ښySlfn0F.9 N#W eb>Ω_B_܏CQ]O_'cyrmr~V߷[Ƙ^'08xBFbzf6|ck^;@IDAThhgwz>=>Պ ~ŝhX"U!ِ@?B\NԽ^~J^7K4#dHh3^Pk$LծZ|5'Nu $؁rc`hJT x:CTdPUr\YlgN\?_^HQ,dN"Y~Т\ԓ.8FVovgd[ < P8AeʀҡGI&n"phfg]`aϦFzd'+ZMIn/Sa5] ! *[#vj$H@dc/JƯ, (NSo ?O7ܜR D@B9T 7gTMg*`ke ur=ՍYXx8qK'2+2EidPi^M,f-^W_dZḪS?Hnp`Ka_Gz|rZ:9,:5,+GwA%)t}ZFP,/49,THس%DF ZԮo'v`UՔoMH뼛iZQ9奫~Gz-̷8R|Z24tN^hYnsq x~0>c1e(H\#$`UqߏUSsGLBZ:! f~/L([W>͑&.H z.vR/KkʜjidduQGm|c­\2rV n_NQP g9\VvSrf2O' 9MW$3ie;Xf=.c:ﶅ[n[uq:|H#< eCgm{V{Dlac=07}Lо1.zN-*:$0S8Q IghJK" KukD!e &"@bJem [PP`{LV5S!LN @6Z}H"n| +zfn^W3~ISvĘR%éӬtf1L)lg+)ǿUN` J^X,Mߧv3΅@Ϡ_ܶlnd9<1&I\bFRW7 fǣhF=m&b䒠C*uAUh6ܺ bÁ2ze?2DczY 9j_3B>ܧSb2>=r2;& *]jM͇G~v8Aڷ L52 <9@2Û2i; d !2Fb&v*u[$F/x{ eH 7iQR\ Xm*\m'pf|/tܢd¯mgp{٭q)?f Çق84E=B|H2w~J|Ӈo߽|T$&DKCn %}H_D)Hkw`ED`@GV6lef.o,~l NM e|_2u#Q[7lr x0",KG.&eG=Wۈ]bDYET/h x0-*:r{ ӎgtg]w?IkO7Tv31 ImLπm!Ep B{̭p;3J+'Q?0ō_\EM]@Qf#4\k{`gP7ό$cڢaxdѝ,0p:Urn1nh0⊃mw@i}x WUO~{ -?"tW>h @a!HVWRAk(@\M6ABut[*U)?Z5%`=vS36.Ŕtg 6D@A14h{80F)yf&#dDṿ؃XzDʊԜ DUԧ'9?#v4鈉uR,E?-IסJ߲ q;L-Y<1h"7t{1& %q[6P562{Mx(a&}s]Q% 'gcӇgS0b{IZ(d/]" 16hгG'Sr4 ̉%2&-~pUeC)ncx6kQ\@&t9hԾbgR䚦5f|&IFʀZ Ēu^I ,SWnb5™Il[~ӈL@g| +AdR:U&2[5!ˀuL /3: $9J P'^'4xؓ {Y ^ݒ[ }$lR`kb)TM3%V2M7`4c9H`[y7&㬀۷iل#8FY]B>0 .B$ᐋ5}u +Нr\|E׼lL"n>F"#RF!k{7_Lj[I/72eT"[D{h'q:3밮kg;>J fa.Z$!HR uk&hI+G[>O,pwna~"6zpI.>lx@Jz. bF;U?׭IلF-&IoDuexe#AE=1~F*UT>`fJ۴\BC8'^ܟCEh,q<(>՝ i#ʾxoAE,SaLWiMJ"1k7j@禜%IGz2L`=FZuDÿ9 X'l8Dd\5ː%_P!AhեQ}4FrD)y(no˗$ cgK>-'(PFB~LvokߑaqKne' X9 Z-zW / v K)`ڣ:d~1,Z[I 26ݫOqrtLCP ^w`0!"7` Mrc !2E:oYޯ~'G861QuG()&g -bO}#ҝ5W(.jjN0@f8`=uP͎hW2x>婸E8u~ܳ3rLCv%4n*V+=l̰V2\Y2JIjN3i0$xlۨ+9&GŲ*R,C@'5hQ 5]bO|I\a'/\8)R fٸ4\Lښ`t_oqӗS ТM=sp1gT1w#sYz^#rdbj7N2ԣPvU&S>+`?em{y=Jь3I#9r>=OPkbqrRڙ700 9j܎:!X"W*5^R=Kcrtv{/vd/ Ҫ ꜱSt'\_:o|P] c](?2ɵ1Q"X=6lvq'CW=xToX"υIT.׃/&G8϶99nP|v퐪V̆xf Gߕ "p\A%j=}&SZʡ^TNfYQ}ѴqGx2׽@!m",S) ! k (Lhl$^^1,Q}oOJ?Evq%k&9¦޼GCB2"OkӡZ)PPi}(2 Hxc,TxcR m:T\ kgLt959o>:>1̡ۖmnM2Q QA"l[7Ty^m_Hf!تCOxWAuwz e 5 k(DDI*֤pǺ T 7xX)EsɞPzg |l6Iڱtڄ/^C+ziRPJ#V2%QiH{<1 ͺ^ ]O]R- KaPְcVOݯ(=FPBMdD_yXP,9`]kư==XDF`+=Z:@1ib{#_,aDA)BhF.S(HSf=sA^c%V&<^#A/aƾ~Ҏ&tBSi+Ũ3 ;h'c81 [&\+ c a0:,f%,R#S{`'~ev$ƋR #=ؑ/nmz}bA$Q emlA@ݴDXUǨrB -|iG.a"hJ0Kp=1f _M(>da'9 O\@)>31,>G ^{j| d&H-krw?6f9 IYFM!;)-QZe.!HiwV$8 %stYl4lND!BrH4\5?׾djƐ(4@;Lƪx9WpM'ƇD±|LD0'ۏ@QF $DcAu^+9ݭe 0% B,ʩHx(SK*ZeY=b Yv_EFd>W "ؒSfXϰa [,{89'DAc$\?ؘݚ+B"dG)&s; bWEbP`Qze9 ֫o҉1́A\h]u>"b 5+$f O.I:,>]CRJx j*i68T=Fb 9T!KXĵ &c6QO--U# 800["Są4ƥ8Ɋ]*֒:րGZ\IgD %Z$j|bV*&и3Ql(d h|Q O dǧe~ h:i{Ah.ZV& .|wasR֤q"-U´_1 a:G EoҊG8}Y9x`DY,&4!5`S$ D &qw 9GMS1V6m#8!KҮѢX>(=M—)IĆ=Ln7VӮG(Џ%|ܴҭ((٭0ňM,G 4+]eI'R+bsZ;p8uU%ĂPs<(aX3lkS4D6}vRV.ZlDiK.{ZQV j'FC/Q-w*Edj\?j0>7x,A# ϐm8R7i&:-%Um*I}jNQD=630j. "҉OuNٞ/YPl $6 nJM"p3&$) -.-FPR M`d 1kWq`l$kv ,C WsT# KiρSayM&"i]sF+4š̢Kqg`೻?pڱf,0p0h RN&HT m@vLjb=6dNt+Kl-ȏЂ깅niCm1*OWҬ(+`юOǀmyx#]DUwþ1-gL !:8'RYl!s*bMdx#]WQ9cj879ҔB 5=\s@&7@7H(‘ \)rc4B4!ۗM 01ܮHܶfJ[}ܖ嗡v!k:φ$ykWpLTI{|ZBEo ;Ppq'^j +6,#( ! /ek ="vxP@ .σ{? q*N[Rpʄ 5ehn37|ҢU~.0?hK7ND=yU lͥMYDQL'y}i ΐԡ)7;9%Fxm<|֪+&"Q%s!TL1 b0OoZ&O9ġ1 T+}G\u zYoNguv<P i}kZ&NAeuJqιeTXꎗs,7^@ "Rp&lx[B hľw+}* G7P%vN9v,80} ]M8.V6Yc)>uG(n5Ǿh]jb,t*!BZ[CFSvuwwH3&^e=osPcL,w2rlԈ)̘d]m r( !=-֤r^HiQFkIpi IF\0Nj8bs rAb ˔[ܺ\B* "pGe7/z[)шԘqk"NF$! LP)F=1Z\r(-UIK~[m,z yHʥm&UM8+㶣BQ6a6S* .®slҕ=C?cٿo avR}6}q7H1Z~!&bP^caZۃU'ɖES&(kEW҂Z8X[&dە%p,Nqt4<@gE>~ &e,gx",cZn6ޛaόf3 hD4f`\/rgG\S"h6gv9!s;=OUt|i@54isٛ:WiǾby-Jm[m 4ϰ}rg>5[8g`j) #,Oϕl7bu\ξ4ک^27!jqGцn) ݝ,3`"|ڒCL\ŭl| M1Ԇ:5xFTas3TW(?/0FXĬ3&ٲتEVn+8?o/-Q$#*!<:%P~3)WGN 1*?uiO%!tYa0P|0f،gIC` ih_9ky$KԐ!Т5Z:1`~v:j5meƒh`BحFyܖ%>x:̌;yxZdyט[Y>Iz8Sbl2=A!LGX5QXfv'eS-Mom%Ļ uko.4d1D@Ìkb)VH&o=wN[ OJ˔)(8BQؓFLݥL.XANʀm0ԉ31<G?HԬ.QfmW`BTdꀕRy,8`Y/AdX9h&maEg+cH2"wtJ`Q ^h!FtPEG ?>K\тFnS81cWg.|@pi?b9KabI=0< ^ğ& 4cn[G0c| 9OE2~vgTjmٿ~:(iزqDU@¢Ɖo_ ZeJ-r3I -Qk'l̓{?~K bTP!s(=_zp8 4\Kt& @QK<ـŸmC SXP .+ާBet`\ -}*tl0TE%Qo"8;$VW,nD2<|8$7j69蜂&6Q*E rV 1ĭr~T́TIS@XfT]f ր ?1R>F?Dp"k`ex9 B0͊ǿ,:T!'` $LR&J0oW ,#TqOtF(Wpi\E> 7pybX(zuWL%,D\ݙ&6cZִbg"Fnra# @6r2eN3< dBqd4PsÑ`!3+ъ;C>C^>-}n,xm%n+6@VDQhw%t֨Ci^웄vy5V(H54p_O| 5bK־ߴ>4o(`hf# ?d cL]iN`,c Jk\4#:-!T7k[{fMʰ!b~Dd.u6_L b9a!\U{>U%HMRD23xG lԫ>"و ~(24&$EA9x(O㛘 2")';fQР @-KODăZ.aq,kcPKb43r;}r-V,|):,1*8 G`\99>vFXdtCTхږO "ڵ,03l`s+›4#=ë%~4I/Cnt)[{|}E<\l9 =TP!FnL&P3$\,@'.h[v=D.CH){TLChVs@4 gE]w0O] 4Zj۪'M&:=tN ũh1*#)$,~%?4.݆6cH5/(w)`3ZU86 0 @7wB>e̡e$2I2S.ޅeL#O uJmAxi,Sd<y}j jZaLkdu}2aș }J+"&թ)P8KI_jÚ'9g1V|xO:ܙ B.'>Y5.I56nCk i~"_$ ȾWs>Gԉ \R,{ULԋ?twyIeϗ+|[P5m\L!f\ؖ։4F^H%E ZwNk۔ ԠmA2b\zqAqX!9%;~2^/>'7~05'Op7H́-)_ZӪsc3g^K&Gy"8 A6BTEM0K!)&,Ǒ&Ud3B,P[vbLvt܀A_ԳS&~xNoGP6'0@l t#1XPk*O=}bQ(˓JQ0`KNB6JiqIௗ0uI1*0tאD Ddz̈́fAj Cܽ4|"pr%8110i˿yBaL[S0eqoI0 "I1S]$ i.& p$)P.vJDTDj9+a- ڹGBP0dDWY^B!O"%}QuQ1*~"8E(Lk[Z:kym;{xltuawU hrDOe:6vU%/5"5%C}LHQ{=g O-c. nM%,i@9huc*B;,q(~iCSe+jw(NF)@Ń{z<[+ZT#|ԣzrrE8e>T1M@n?*5Rexf,4[G֛=F9ƒf$~ BntFQdVA3QU9Fݨ7q"me) XGM7L(˴L?k# [Z:RDþOZ`YI=P Qj TIWd 6De ʔy/ƪp *yRL6;VyfݪRgK*Q|9 i:.qKR&k4s "=01˽u`k|)PXݨ@{qP글>ktOuix ~rUFc\jO4;\S6G+lSB_fE8F |, e(ɵ12@:!؉A'0ljSm~enX+T$[y0&VohIX81h`|ǵ$(We7p5lx1+H*/uIF;:l2{|Zg#DZ5 zLPFNDJ=[-=aGNR.|]e*ÕX"!6Mܸ6nK<u F#'yQl' p b$*gf,Z[a$Ƕr~ϣ?E?UmWp9RA+-ϔzY$:|=2%MU>@E&;# 2HI B>0#}ɫJیͭn D'3RM#6<;;ՃhA@?A4e V kWfu"5 7n+$!Dœ\bw<ʧ<dwˈ2^qG᪟<֍}V0^Oc!͹IZ##ꧻd8(:x0P}>(N6eם7~R#~|VSlJ^O(Ӏb͛}Y$S3C SCmP܈9D5hb;V':e1X . :S94fKG%=^0?SK S`'T66O$Az<;]5(El7/3v)M} JXza !=y"d;i(*@ 26\ʢw˖ *~Lx6ў&9m/EG[|=8 n|i?9Ae쩯EFkգs&Rc? ao:j`opzgC,%{w/Tb:@QBٸz0YQ'1'ҨSe.g] 2(k6n< {Y=ydB) {D`cim0\|DHa|w,v2"!]3@IDAT${CFB屉Y[7, h ^+6@ȵeTxJ^ f ?0ڠ #{i5U]Sp?@2kO%b\5J~ u%ҪP[PwvFI'Mg'L'!vˆdEki 2˸C5|j.a1'ԙ|cYnh KsyG{:!_Ls"ږ ߹D:%,7~aKASo}R6Ws2o.XeסO^sS~9UrGm(x-W?.HL^`ۢL'5Qxt (`Ct `D{\ϸdzPPU˞NIKHG̽Kmr;~-E$u\Zy>aPӑx8_ HZӧ09 $@~K]JVvm#׿1h%o+PdяN,\_*,y%3O=;{c~QRaM] qMh3 iV XJ%o9i/`,<٤Q=G {8$~8(zR18Z׾4:K<%bs!C`r Cr֑(NI˷Z}zPx>L`(پOqd"[&;ɢZm*[?e ijlr"4L88[]ֿrԄ !a:MQf^M5%FB\8 ӿg%[~2eF4En〔#?gn-UǢA ;Iwe2Dv:'' %Q,zZ8^xLBkſ[RӄֹA(̋.̸A"oU zt͔TPE'>7n'1cGsV|ӆLIάLRc &5R@%iqr6p]AHm طѐ"43^L1с$<C7v@B;kZl8r:3\f^^~?>D2ڵϏt?ۣ{9wzmޓLqJ1IT58hUttTcxhM܈q-/S%j|ElH6^s{sM.܁O!(Dt9-47GoM 6v4Ʋ1k^R`EJ.$ELKi% 'aЋ}-4@`cB!BYɓ6؀0DDtQw)gmWc#Sɇ^W( n& {{M+5"i>~^6O[Tr/ݚx29׉$o_p;:ی T]>rŌD(_ݿYFֲ}@}NF+2Ovk)C9{ٗUhU#F;-c% ]<Vٴ֋&mJgPKZf9bC gҍ|@3nR4b !x3ʎHTŖ+Fy}T74@Vޞ[rܙ )h䆎-#%C&4`S΋3'K:-8- VUVHҰ ϰwgadJ"G|bRM^F7㜾sBuRgCp e<=+⋣}}@BhͫwŅzdsI")ha,ʞ֎9>1E?D‹d$+RQt6V ɡ~? 'ވo^?f?p \uNbVvqRjv7y2 NpIx2 w".͐DʤxF)N<ds2äm?<ۦIT =:J X4 A[_P Yv+QL['^2'y\ )N:Ir E]m䊧]]!$`~--Qh̯|_qkoBAgu9䵟`O# `Pen*=h/C=)5mdC5>p'R*7֪%໑D7Um5&3I3XLwr*EWt|aD9o>wOt*0]?^h[wOHN;mtCӺxR ((C"}~AZh-/#u6( Qr-Z(v@xo.1pURdwakoP5u z #iUGGNJ8ws8ud9-alMXl5Ys=K1+.U"yX jY\8hJM7+Nq xr"EN΄htxR^{ R+s>piL"HVݼv&YMF +.Asv%2H"m+&=shOWA>Nnk1Agm9uail3|rr8K//t8/Qz$v ]Iss7v8ÄV/#߹5,\`́*Li]|0s&P#'=BJK{RX!\կlj . KAw81:PAXҀXC '%5"b61B):R)IbQrBQx-1ʺ3&8x?dNi8hxrFEDv4fx"K#5h8IG#q'\"P1MFG 1(1'^ FU6kiM4&kfeݐYO};ٕd @QрL(8E80iOg?I[">ct- qw3Mؠ/59`؎* %&1 ' ؊˟ hX*IM2f)@b;6uϡpvgH\c5zA-"2r 7hM>szbUG+d7YuUVpcH_S[Lfڨl0E\)k5#!ȜmA R 4hj@nƌ huy`rOV!`k;M`h}V+ȹ c$H~>>-CRnVF҅A1y^~mdgD!e1@f?erA5:{x8hSmqƒ8}Jļ^lhA|E$z92/nU5I?gvLdW1Վ^7]@fF&_6 ^ͷϙ,f&;C4px?< xl0 .{SM‘0q"xRJp`'g-+icE@fA=r7Yߑ;iJ *g TTXs ^0* 3G9n4|pSs32ZWR^$]^l(^eMƛO &mhS?00={xq٤Eǰ%QT*lh_϶83Xeed;Lq.!ɔIdb(W.NUPJ*q]nK3Lb,gAG_{hpTC:d˱Y~)Pv]IvW& z>RȈa_r {6 b)T2(/wQe/D^޺~)L Yjx@M1ԮD ~LL^Ym~W2r&gfKRFZ, G=kC@!$\=4v\cȾN椙={LH&%.GMcaQsjcgFL3GʦL<]05Hd /?ͤdf2%}h#C{OzÀT>kp; |ddߨ{pf/%Sl6Cb "\L&cuiˆ :m:FXlܨ땽y3Md5 ׻ݣ&y]]0*;OrQzjxQ>(tۅeRak$~_!zI9 ` ᄗj _^i^ӚIXf|ls(IPeݎ-Z=ΩDH[;FfG?^zΟU=G4z"I995WTe{)\ x.2F?:%>kONϋ4 xFYX2ί6'<"A־~_ C{^s꾻@,ھN!PܨdCW~J2%y;9{5JHQ $Jfp(|O]R} 3lh2.E6df&Xj" ԡR, @Si]1B$K2Jbh! >{;^D#[HO6+2|+*(!z'q^-[l. C\g.EHxlXmd`B rh$YhxؤĚa33ௐL2t%ghA{'482-1b=!%s)̅(S)Xnο6thmXZng gL@\rw0!o`_CW{OSrB xJlm`Qշ^=nD;;Nm(1WGRgf ^/z, (F!l^.bգ!t,0zͧ|\7H{\=*w%dgH Re]*tBi  Pm_MNǟ4,ah\ai*}' _os.*BP!|3+wIJtZxMnHH7B7ξ[yq3Lv-ӤQ|3=An!rpӒM(ܮ_kdIU53b[1.2n/dF$ @0OX*e|ʶFFstؤ4{֜Cƨ\z99 \NGF:/㶼lf(ݦL+vM]g> dtȝ|@kmp3BP0AP=y#Q~Ȗ,q@~WrtVwjP4OF"`Gt/NjQ}ժ-vSJH{5yS bX@ 9( =F@:J΄n vfuE+n[zl1hTx1$lqQ%i~/fmR cxl}@)ka%=8^F vi%Rh=0mE&A/Db"d| 9q&cL^/:\e$ !ήd/f30b?1مWAEHKԾ GΦxHgyIm|En9ceS-f=r0'WiڢMg!!EaEړidCp.\ku8#@TTƺ- n'W8' {: Nu0$+ն"؆k Ab ُ3JތB% agPBO O~ MsiQtx [dOKݻ)""GzF9_tS(6m<'h>LZ%Ø@0 K1 ܀0_`Vy֋^ex (.#fqC@%$g5, QdhN߂=4#j`(-b]2ҿCYAбe b9@863wD92Ĉ2S|Tv'ێx0H宑LYv;EQÖYpK 9O39 щ%U<'v`|=KXw'Lͥ/u3HUh> d|ٞn!F5<Å]:EDA٪N7VOȁ%t]ݏ:86_=0|!2Xp0T YnW?%{x`u2ozĿ9ǏpVתy>׬]ZVԬ W i"qM-S)]nܠBؖP )&2+e^?ZF,}%2O E*u,Nұ%/q 2mh 0wnXod[%p9R xP ҂7Ul"k`1s^ЌD{b02(IC̥Pz1'bu($KFa{h G+Ic[: Z2qE%n3'FPy/Y ֆca>?1\JeT~qMD8͔qFHDAB_( ٸJc+ [rݼ']ih=Oy?Ahg +V~ۂQrYܬN2DŠYlZc\ ݄U#xEiGjh]SAw+A(#a:#&~U_j6,IZA`"^(~0 !RB*2$l˪%aQ ÛvDhtWG|пtG?A m=%e 2DӖ;'^bzke B)GJ.ɟ/6PӅHLB~N&NP90N˚0y*{㦮FrɌem`.<E($G]^֟I<9Mnh~S̯gn J&ٗ@> V[ vYRM%oϛ(S:7=Tl0g=99ct QN}i`і%nho_삎H!`O#~͊QPȈm)$ <_lO&$F3ڸӵT>nR2֕o;%/<)|j,^٬]gމOA Lo;G,|tfYo^^Sңpx`Av4 +6 V2Bc-ڠ QP'Za"d X f^# -0OQt- ?mw[Rs9PFjKSg/;DJ·(zP\OYH7&.N',S$4/Z YT[T fI-__L=*8PUcs^|ݕGK%/{Z^eSR"T z ' ?;Kn|+̥UX[k+dIa `JMh=:݋|#*Lmv^ `Ro̡@?f9BV ?q]xPP7<߳LtWo|wjԆګW oEjLeqH$a78ә3 Q+G׏/y?;*PDƹ])\ldd!h Y(|U:Y2 ^q{vh ^@!'(r3wKk Gc5eōx#}22jq ;MŽo29c&ЈH{T W!%^koPgDu奌 > mPp4Ia|֋z& "\ qZ2l:XSҚjDȑ,ӃUCjr*O;LT!1Hqq"֍ʎ|FPzƯPKAr">mຳCLNp.pZ_jDŽ0P;'}՜=va9{"[yU` ^CVN9Ty@T^vL#Iot>B-'Hlew(@Z6Z-޵DG9 EC;[q3C/%fD\*Lbq*5v: vM4i}rrD)rr 8 嬶Vp{gKo)kSWrIF&EB9`Z})f;hCz0)C$p!߂ # Rvxz=IM<]E}{2 Lq:4*3c:$h%s 3W~gZcC^vhX鵸96΢ƆrppAH;$CXW^+ nߟ7P05>v6Ft?6#iw.P–LJр88*el8%+)Sb:cHou/xH1!܏Z5X\Ao쫑 QedF|:\ KJ!2k|{;2FVIq+vr-~vegTeɣ i%ɳL@^nܶ8kE;DeL Lj$5Ac(/3}ˋLiZ0 ֋5ެDlke7$W<8H5XɸS" |LòdB ߥB-˓йޘ?A4NA|c* T^//"EbIH=tw䭧'd &1dk|,v* Xe/\vڀr[I#jtӘ?yfJ}S}<~;ܰ7U*.b|Ͱ`~aopv" ˴ZD !\NDrCT 7WCDk>O1׵^SG'nEvl4n|q'E?$ì*LkJۄ"ϱFPCxS&-Lpw1bCd2Nە#I@gu>2] )s5Z| NA#i(m4;4!d[I%CҦȼ~}C-I[,Svx UM\g#!᩻0!#k9 ʀ\WNf6Bѹ>a0Ê38A,+NH@|_'Zr4eBL'IoB̞L(8\WrTI-}b"_0ps %8ۣ)Pf`T^A"k7׏aDS8n5xQt@zgO3"F.ݫp=GʊftuC 2+uBQ+V){n V%4(ĎR mx=WDr7H0RFz\Mg##ѣ~{pN <2lc^=,AB 3Z A&G9 S˖ceG,]M PL[~#8ry.l0j.f7.n' 6R*VOh}ڗ>~AL80ktG/e<([sb Ue\RACdXA J!2<N'ٌDI&+6@ b'y اAnɌ\Fr#$[Kˀh*D֢T3Ai2݌@ʒJ膦23SI~ڙ,YTOa=+S d S^$tz!6GLK$4\(h֠ۃTk&M 1w%D$p.2ԝC::>ZY;m-5 *:9^_mk2\f˜?q|ԔcM_^c.SL>7dEf)r20HiF.}(pcq vk j~}hbmx{UHUԠr~k7T!Li ;$fTv|o!mܮ8 mJF]О^Bb2 `0Ǭ. @X5yCc@F,YB~x(fؽ dǼkP_fcRpuX'knl^TS#T™/UL屢W51XI.\2]AG"ƞ(g7F$=-ã $toWˁzA&.ʈdqXZyfꠘT9UtXEPbleqPPA~H0C)mQ'&P;$%ݩQd(Es-JpķptF P]5qnWgXqR2z%1?e8 ͥBv6&,7*sV}`=ZBdh'no^.<% ?1hJ IQt89)kȺTRj~/GHyFj$=$ EN߆㈑Bzm8cˠ]35 06bHv -)90b nFz:naQ3۴4"**> YXq8AT'Ԕg ӡ,џy n[giqx$pׇ>Z:qn:k}yz"^@xr-۟hwz>4a |\bBƑfn#P6w(q\0;~愜 LRufPeTv H.zaC2ɌWh۷D $',QyT+m Uyb$3[C U=([tÌhF6!iG)Cys=P.FE߅Zc P'cuY $<D]c X @&#xd+f <)v=`>B h IW(0`!(P%R!?CP"NBLDk[S6&^T[:4>(0*$NCN?riYG#(]x;,(5~CЉfwdyj7:\ C mLy4$ESܬ d nQj-Ⲭnn(S,d .;B2ZJ:!bi9* ̰P| =4t)B oiQwt\3zScr)ւcF_1) P!QG>[A'ZP8W:&EQ\h*?( 5@E΅C])2!=jܽ757.6Zr FѯfysXP·JfkHW'.]F $}$y٬l|3Ew0bk2с WҚ86rmة5dF@sW aezhCQ?wU`_ *pN X1a֢hy4b"2 b(*ib(Af#S`د}ri~%P}4 r:.9Y3uuop #̐,FsckLXP/oePN")NgTl?1n=UyBS"p RNwg!*+~hNB\?dy} (r؉2 aQ0iA"F=Fn} I5($x, l/qX5"pdsh4zQz%BӞ'*N-E7&XhF1 Rr1˝:1B)ɃAչWw;d$B"4J| mňBrP&E@uIO2I|M*wL{ `3@IDAT^iB_@f'=䢘Ibd,YugIeh y½RàEh:_h94?,"$)7 o@W|4YW_$]%@fqQLa$ˁQ)?D74m;SA˟\&kS6 t6R2+X'ޅNkt]nC0@ZKхf B~*#.k  5ZJ/H$!5UڹAE.Ct/cPO8P!WdT J[K7Y_M"܂ 7 /~ւ[=Fw߇kGL#=)u7N HVl\'kIcЊ*\}SXߎąK}N/@1# K@x4%=0xp^oTRFjn\Ԙ??VFxd7rƖXe8`[2AqrOVХuHr1EN]p@Ziۂ `q)nD-;NSxC:14$ wQjO̬Zر|GjFM}C)xVN!vőDALqɻpC,wk[ DRM ENKdFr97!6@I/ϐk*#]h[a^ҳH!c=4^u>}kipyA/w'3oV uD)Bca[RAQ`YF7$)3$YY[nkp,N5!  DJL^Fera+Džexֽ(D;)AY8C䅡3wKLk)\JN`ۆ&o(l aB[ Q`؟`@˕Su219<8U4iHB>J!#,) =lPӪU /yb_G+"$ê(F{|Ku@r|#9T^7Ig̃ >8-ˣڢ[X6M/8 (8/ލki`^DI3P|S (P3!0P[ׄz2Ƨ&'ݟӱ`PS>+*xr8Ra-/0d] /ʷ  ru?֫629.I4U(Ә-ol3-X }Z^t9#.|emJÇ3wQQaFX^q= dh9u,m2$-oYЌe/+/{n:|C8ЕcxvG%{21YDkKHF= o3] @\zz5'_I t/e 9T\>fPIp@6r0H1# z*btG뱣HᚭF FVI*3㧝sa zb2Ö6,mᎵ}7*j1\ dl3s聄{$WUK!d֛_WvaWLëŏOscmY%SEwT1jfb5iwHɜ2Skё;5`w17UE8Q 0{6vj2@ .`h­G [HRIbgج@Je!"v,$ \Lke6'N{M~+ 'D6H^RsY0Z' ,nP l-*I 9d$~f|S'"qC!HiS2œ>,x@q5i@nebRxo5] e-R$)Yx#(hr'kUb%/bq0sX0QDlU!gU8ryl/Kw!\fy1#ik8:˦ zr Fa\G<;J˴8Ĺdtb,ٶN62S~6mu>ߑqP`y/m'x"eǟsic}0`8Ki5)Ȧ:1țWGv:od`(%{u\&(Z0I5G?4@ N2dLP"鿎79@d䱀"vUƞC4^,ښ$F1Tp=қ9i6 NƸ, &lV4c,#Y~x dlaz|7t\>e8 XK iaa#m`,i/pv5H^!}O?˿4`Dpהz1h$O.s|eX64 q{v+ H9iwm)8mnP-3< `(Hq)uDggNn5)E-*\hB爮$hq"AdK>=#i3 hj e4ޘXTd_`zgdv/_; ҫOt~i+[yeKLyUb J` nֳEԀi|T;@rX!WEq,2v>8Ξ2S$jSP9\ArvlГ3㷄5>0ؑxN s,ȟ f؂ƼФJcΆND"A˻eDݟ_rIɔAI3TwV/vvKGv\Xʍsek1eZ;'5Yz\n3ſ{Ё VzhW6Qr !p/V֞Ii n]b4?2;z_8uH{c bR$jӜFQ3lI3N%YJk4"Bu ^ 5 F }zgϒX>b.j&AWDn uP*1_M$Sg.˷r_7_8DCF\,K iD@)]#@AXv/졖t5NjDqxc;hnQW'mntnγ!`}rF3j{;|8Sw4"MgIC}X>N3t rneĕm-dk1.W fR;FaaIid'՜+S[a ^a@-\8"n*ۣB}(d!CE2+(4CW[5^2 cR0` Ķڨ'^?<4f`BƤ.R55@ s%ǹR8+."O$V7p'ƈiTCHX)N t@7U ANi̓u˓ۗq)aPm (E<NiLC=S"X o ʫƫ+1!dڼ- ׼Bňa"=bszXPHx:xԽd܈ UeGB׋ C*>E9^ 01҈ʀ7h3Tp*8d"hOŭ_V̈Ҽcgg-Pt묺h|1df"m"G }mO G 59!m涸>t$Rq"Gr0ibߨRz_pxSv3!rbTy͵HU$ئ7<y|YS7=ӹ9*ŀyDN¸ =5ܓ*L; D^1 2H36*Snz.?Uuҹj^i!X&*:7,pBnS'2sI!0'&<7'CV 7N1J~q?G!I;HA %E\(xW;"O ܒ.m܍e|3EൎŔwΕ4hڑ/]OI[%L=ʇĽuG 06H4&xdӼ8> V?bC[B8uE"Ma%Ѷab=EU^ ęTV9OrVeM`5/W] 'y0dp6;_K1P@" nXBd}mG!Ny˙痹zbC&B'èQƣddW͛  Tr􌶡QԳVCu~16Ț&+>1@nF6emdDӀN32b~WP9qT1sBL)#Ivd ߄OfoF 1<{B\QewΎ`3xy-0`פ(t6Z?%2W]bv[d8f要 .gʭ8 R![, ^1/B.2S^ =̱ؐQNRTkŇ2g&K3d]HzZI3T.5"24jHԈU38Ŧe CbrXԉ$^NJԧzz)Cd i3ܕbrR`d˫Fs`i|֌^I~:Q#H\^`i*5[cWsK[6,Ho L_ ZQ:q *T|Z'r(g0?~g+ݣS+;q96~,RA Gޢcap :ZѽHiYm,jݯ&~M $yhcyQh>ˉzM )zc|l1߁7ߏs(¥CPDL>\[;AxM1nEQʑQĴ*muLs42Sa5d9;{#a7evero??HV3k#&fw _WC\r>䉛1Cdr鏸1!AMv)@X`sZZ2_ Cf\&"]##=<|%r,7rïo4'kC19&1ŁZ Д^MrOTwRƳaU~#jҳh)AюDT ,UM4AT"1Rj$Ã|o9RŘ0Q^'@Tref1vuh_IJYH*'d>.e`hB;Bn y灭Ǡ1&Q&  <6h<뺀j*ʀ2@)@}Ci/ o3"A#; A<:h<2܃=- RFK[C/kFH-Ⱥj3r- L1Sܳ߀@{*IS#/cD%fLZ암YkԵQGJ3 4J!`K۫ '5Tm5t w2P~e^KY&C̍m*M6,^ud#8bnv#'W.6f OirPvuf{B%Tȿ'c%fE@+G(ޏ~n׍gtv^%!,LsC|'ǩ l]:$FB]&7|&cf )9wYFԀ`qtFƨe$_Fb9()5viYZ# bÈ2= vQ|ß ҭkGش;!#~ &K34|guxU9IpDQC.ը:4DjD ?i)m 04>UE1R4b-"E t>kn,C3YF~_frtalٟ/"'UK:87s !l-t6QحOllR%.>DUC@>1P9$>ā>&AꃲUA#*=Ò )(+'\BF3t rŻ 6 `WZXh'h uXf5 @{nN?ι"%354rƠzTz= 3d3UqO0f]t0\N2!DPi^1^Փ2WQRa?:|@Tü R2ן/b}d 0l x`K1[E3s;CQ` mj)FڍCO q$WVZIxo[Oz,ݢARo pG4T{WMF\`# |3oSmF[ZVLn& fEI<"dxF:$tNTLBA(vga{i}G肟Pc "|Jӿ:ŶDZEÖ]H^ɀYG;[1G8(b-]Z!h6-CO*o <?m ӫX4A$5`9maaPeqT gL|^ˢ, Z4M vszzoQ?VF! R]L|jg iƚ`k`u"%)A5ޢJR9'\(O] e|(hH~}"K Mը1lLVv>NG;3"@{P]J@5#Ǝ$Xl1duC]ZAA$09&22 L]kl%]JW ΄ҋb_kMw`Ħd*M1_ԥe@| 2W^fijt>gUܡ9]gUK璊e)a,֒6jBކWd N9mZEd \灦Nϙt@zŦX)Eŀ[ެ:(ImBxb;8X(y燶HR,r†e+t&Tf}%L\ZYLI9?`;h1p^MY׫yś)35c&ֿӌL-6I $q"AĜ=[G~O[KΓ_ŜHLm2v'bݝ6-)AP͚C5;|-Z 5ODBl 6NJsK)Jf܉{eU?OߎV̟NYjx)btzHldGZjtz!!`9Y)L.g0[l WNVKB=ˉYX `)GPLj=^>e_y+dI:˟s/+Ͳ ^e!JJ77{?^/m[KbAF,|/.!XˏkRwkqmNxruQ !U?7B٢k78ॅZ-n"cLannf>oj"ϳEApBpydZFcc^T>^-%~Isb  6'Y@r'g[06JNqYrE2,4XB02mYEWsT1Lqa,#OKeXI"A}~8"r`@~uNӒ޲-Y++`# v#iʭ>)(y-8oV8 [mkӭiW `i w Qz>=3NęYԤ8`$"=:\VpISKoy9R1WTz;jQmDLz[rX+yJv=N۠zvUKo^(,݇Y$UV슕#:[XÁ@9AmhqvGJGÈDRlrĥ>>=wiU[j)Tyϋ>YN鞑uL~z{E`S_"A|<D{{Nٗb=v$)_Wh`XJ猃)_P>N:V[R,=_(_`kw9hz V$ZmoE+i`CS*9縟룁y!x=XKyx Z[xi/\ݍFS28fۅ*ɧ5Ej>?:B:C7;Q9\GRnB.? V}n^7]o6Qݛ&G"5^9XL-~hml9:N4 cO<& ީGqP690@Җ 3R=fۇ^N/p61R/-X3}hņ "v_'O,TM8(dt(uyƱ2Ww #/3nBCi1dvq8&%yG0xnX*6YM,C$Y -6A9B.뾗ul~c(?#c %7`WI҃~<kfz8,|? :v=Cd$-UjYD?!f jL"a>#cA9tkpA4B tz@;k+mTJf3mY% ޘ[e)Jb4f'F.>՚/o"eS7"+ML 1K /L9jY@pQe \H}3@> xqp_$e@2K<:SV(ݝLpoZn4Go&j!R9|EJ# rdcȵ-Zg(䶼R*ܡx_:DC*0 ==u=?pn+x5G3H6WIb,Op4O`B{:(ÊY5٫'V2 sє }ah̒Ar tNJ7ݮFnNh'D׏q k4& Q#'p-e|F$6s6K_TaMULD֗}LVR7:.0=Ӊ0Lx =EkE\S2P9woC׊]$eP<1ƺ٠V2#DX Ѷ*Q:|6˫!-.6ǴsuYzbv`b0^"}O7>&CC(ݢY>OM1NPeSdyI*)B>ZS;rNB̬_F>JxPS)HLA, m -c]`\X J\IvS^Fy,6*wc}jP@^ͺ@;<#d?OLS0 naùu悽I} YPB}JӠE_nX$3@' ^7;,;WŌ,H_]~t=`"Q=chM;Y) hӠV/D&9Byrc džO8aLL07Nj[c䴂O#>oH^'xYz`3׶͟֊4?M^ UH"D,9._ ljJQ8`&&M`gXi^w( UE /hm )F()Dkʽr5y@chL^ $2{dǕ ^yV(uQ{Q=OMAW OÒf,hZri`sŠQ3F1Ԁ"KT:*O9)W kU0-Bw acٺ`ш P "̌ 3x+d^#҉GrC=d?1䁞Ȕ.}\O#;BfqH_=ˡf׆,q 0dyOF:L$.rjMUrm27K7tE M"i@s_'ɝ̍vmx6)-MS^ ? m7%r+]X7@*9)bX{7ڌ14>pCe0e5rx]Gn%G< c;y_F87ю.8둘X5ɑ845)*؇6n/.q!˼'v{SGr3vMh|RBOdL95_O*e$r -5YTs9LP3[0/@GXwY7hk`ωW-)ulV5'/XPH>otrL!Jm@Bj eJ |(5R[6k=\DI;I*'ȔNI|H\0*`G -HeA4d0=HTcAGPň/ZV(PuaqaAqP ?pY{<-jÛe Jƪ ԃ\ٶqwo? $ Pzy"oX$A8v@($ӧ=ϵfZ7*e;É^fT,b~ 09?\=\˱L=ASS/M)>}K\pݹGdU 鉪+3(!"M !R̵( DXOAm3kTsl +*4o} Ϊ#^Ld8V)-{N5m3HT; 9e׎e]=['Q24-կD|VbTȑyNF9Ò.mJsp,sf(Cf G*P  s%\?!ZF<h:'5ܨ;A:1׶f]S Pr 7MV8a;儔? )hZLBv&G:RC_P85R8/>& ̖!ؤ+!_2_c(\@IDAT ]2aGx6 F Q^`@Q$BK[KҜg\ցdt萤4#5~hϻ=J߳lca;;%{f:Or& f(UԒmPuz;=ؼʨi\&s#kZҮ]GZdtr7AauP50x*(P$&K^>uj5G!>l6SՅPYtL ;a٭C-6<3?>tWf5RԨD"T]SzN$"d. Iȝ \.[o`L$5fqpg`<߷`DFL]9t>R,جPL2L[,r.wVQM6W+ECy~5Tc>\pRn& )V+Q5D䕎 E%ތU쯀THp3Gt_`Oܓqj0 1>Ψ#iwh?-' !Y%(B$Thl䕩x}#n/$$%\Bs#XKJ0cm9]q%{Fm7ȗe,"ŏ͠^VC)ӗb~=ZL ̓2? )]W$,B%ENJ+2 qn`(rLa#5e=ZK,\fLq28F{d)D5\Q:~Յ]9Ϋk`D0*dp0 !G \~xo)8f/Ƃ1<3Bñr#34ĪX\uooH3HO9[O’Am[dBp,4bHU3#N/ǢJlPB6o;|VX34yl<ة|1RsLBLepD:|xFh&ÕH20d ;:lJ.7]Z 'z$ FIgX"2+52@%7kӵl0"6%\=,tL)Ƅȏ'ye"B#Ǻr Hq/ƭR$v6=QJ O 5@~V JNpEs6hTcF@bhd ; VΥGOr7)^;rm6F#mBݵbg9@kx/p2h ӢF}+2ų'?)<<N(nf(Аd+5 CJ&v u|+ (j GVZiPq+ xeѰ3˦|]Duk:!yW`BrBqK Kiӂ8Ff(qEr6,TD#5Qx'aĠ X3yBߣz*#!LM`iKs#c&DȍExtsY ^G#%G#'뻳JO(ՠ|_e=>OTFӜ #4Fѫ<f7Np-nǒsg2 ; Vv>xo2Fo*#ָv8y=_.~/q"%"(&A{޴+r VᤀAcd ʍi &{RM b\{ )ݶ|ytN9WQ|ӝ h-> ܠ0>Py /Sbu`^ifl?%!SIzGs]ލ6bYAdO;pKtʐ㗛>d*̌Ѵ ^emU|SmwLY~]+F3e͡^s8UrR0,g^\]Z)j 4Hsp"3Z{twkY}-(RvvR B=I0ܴf3AJ!oá4UJ#}5a۷Z֙ #3r`Hs2@Tg=7ZNyJ4ykvMĚ\v<=/un? Д[$hQ4`u&d6"<&V5M#Lex,9[B\<#d>mMmd[C:jfW7?Qӟ2~T2w73 [VHX+,bped\-*rjϴ`g'iTV1ohg0'bPZiχ_?8z?vl؋p4?AY( w[F]ŧ.ìd\B0بUxϬ40򻀩9.'ȆUk սg~eTsebC4lrف3&f>FLN5,`+0K d"Rtlm't|?)ߒM4h9wf$5yZRQgE GF]:ƞ YLV[OjsAUFU8_oIa7j@P 7XFYOacť:ޝa%Hn 7Heythfaiұ-dQڃa-D܆2U~o#JoӖ[K_v~^? r[Yg=ob XOL+cǶvXbA9F__CܐYF?LvMw'rċflp݈d"wI>H5m9h]PJaCi{pѯƦA)S:Y of>\CTE֩uӄ)|15)J/f'Cԭ9n<cg2^ҍY :9Y+DVD9ls[20ǠtZ<[)dݶ ZK$#t~+~Gf^ &(kJ.'E'<%vjVW3 0D`H_9>G5V07Z)3l.;J1euWC]iՇ=~N)rY +Kj}y>q8aԣ" \=&IMX\]'kŲAa2dm ! juimA4$p3Mzhl*NEaWgsisyi6ކ*p`_ɲ@uS B vwC0Li~a6oJzc+L UCbCg;$ @S2P-`#@b")d"h|XEij'߼Er]hDԜ{e0 14s*@3ӊUHW2[M>d8vb@UW|$Ns"Zp2@} pdƅ؁hpՄd_ Odn Oujʿ"]݄dgX19T 0jFHib ^_o 7%Ec].Dڅs$نLR>xzHdoZ: [8l&kK7 tK,(~"t9d`PʋZb5Ѩo$`_ǧv \ #T|F`Pf晲ڞq H*6|F>֐o۱۽0NfN$e̵=tnIOۼ  yXiدW"'k),gQW8@OD$DYrx䃼т{/=)ighݷ PyR{k`WsQ= $BNˣN3FhJ†Pi**2E׈~viϱ0rO_*ii7+gNJ6bPL(duOXŠ"A! A'HpGY̾ fm0@ .#76q*lj9Jx [c;NJ0q;#z2j Y\A$gl0FzmC%gxFkC L,ZLKMֺ/Ñ$%_sQ`ȄDQZAD?=Y= $ #]WA6UGI յ)6-T=Z_!ʺ@H,ǴN-?hs(;!ƌ3L,b$K&kaK/y:P+ Ǣݫ2&Y/,>dr@Uz>t+% `>Q]1zJ#*!DRH8pDt <c87+MâXW6&|._u5{'v4&e#>S*;8@SH&eiU,yb9wemd0+$Ms"ֽ(8L /5:JP "+23gP~DLHc ;74 [a(| e1f<[CPD562[Vbžn=mYlZ:gpQjQ_eޡPA5a3V4 D@e-P$vL:)I}ʸƛB`.3FbDc6#6e|F|euc8 ઩=eMuY6 NU 2gŇUt˚[#(,ɛuPh{TiMJ3N A+I x=!W7".陂h4},۴B~CиH3Z[bАY=LP]`uvt'~B"RlT)rc >F$ gJMt?ߟLq8)61.KR9Iad#}wMK4`NMAHRFQzT6h_WhOq̔?ˡ[a1dPJAHZoh B"'y[I1G_dT]Q(?(\B4XJ3/54$!KP' mV9gdZR\0E < H@?4(;|r34"8YqC[c}Âh VyzS弲S(vdH0hG{*Ld jcyPsdNk-/_ 竪 Glp[e]T[[Yt%l.g)HDŽ&f& ksMT_.u(s-nηlotėP~y}FH/L3I+P*[@RWxlL(MWKi@\Cz=͙0[dQEaLY4M4Lɲ P\*@UiJn7yVuRdrCijd18Jxꌝrg-ɸC U!!l1ѵ]4 /o=Hi.;GVd54 G_n61Vjc.gF㺱\O~aJLBXѬd5ej n 7.Ӳn/0& C`֑k7ao6WeLz}l3H z䯠5.SJ94IH:n_19eoD}C!vhz dJDŽ7Ƿ_OR 읇-M|hh@g+ͬ{غ#v B#3qFk2;Q 7 ؐPDDDXf^]/^ACo>箐qw9KɂzJWxvy@mo :!+%4P x.}qcX$F&:# T"d~?>. >-&!iβPhYAo?dlF3'4-(ƿp,g,Xb+n'M"|L8/׳NhmRZK%O]A3yTzp?J?˛  }C4H{ry!7zjA{Gucc@0'+ܑ,SqvG_he,EK R;[EUV45ϊh{lP Tr :Z%#IIPL2! i tX{Rn:hR PA!DlynyW,8[zQ5G?%k!VF.ᕗ:i8~4X/!E:eKw@rKk Eb`M&vSsp re4/B &ah/|G$^񨚎7җ&Ԟ}" (vN x#W,{NhS0cU=-klui>Yq ]rDNù=n6([eO! J,%4+u<`ʮ]QELrN&P60TejJܷp@>t0V_)_舋z'$ dR. ? HB"s{pVQL #91 %5fjfϿԌRM&A+;6av;:T:a \oxMtݯ2qh`(HO? XD8Eqhp`C.n5Ctlksp;y vʺvOE\ 豼U"Ք05m؀6C>Ĭvr ҏynE"E $@PKP@iz@C15Udқɐ,雊UsȔ9- _Q}jTSl}dBD Lst$>g8P2 }O99ImtH`Yk]3;7uDi.#f75ZsXLoXȦyr'b0ŞjEWQpfmQ߮,oq<*,Ui8jNT;iߘetGV7t0?`3/DÇ[rh&bUh<31i0F7O\*_y/Q8JN@lzٍzhQz|O&'ɪ !)+Ѣ:lЌeA[E!̣DWl)!!uT} l/ZˌZ}2X$L=ŽJOEE8`3x)t$YLDhyqdT UӠFzaSXu` ceh.PL"9,1_2jd,d3ԩԈ{E:AN7TCF(x3^/X9&Iz"a'u߉ ֚GLFy>[:bGew)!}+`54 }` 35Z vCG5H@A4C`""_Jk\BLc'1呥 `r * .tjCx'd2IƬ"HӒ_v=VJ0q!-> dlCUEc#1} D4g{VTFu3*搤=[ _~-:-f>;ȧalD>d dYס?&뤮?XEm g&~^;%[UԚ"`S9F¨C nlدc7Ŧgnvnъҧܡ+MO v1xscdR|K~Eρ֕y,{:!Jkr#کGj~ީ4I$;E˗߈p2(Ee8%,0DF^Y kMԆ@L}Aц"n؟I Qi09lr/+'7]|~ E+mzbqo}J@?Kዩ9c: !E##_W˴7Xmę'? &k0@:}ݎ |hV%#;@'O&+f:֗N1G2a5bSXDӑ+1B1dH;"Z2ǝ/ Xd`hApOfw=B- H2K9S_aQ\v`,c3>#U"YÈ~WQd ߟ1NIHGCSc9-I8E/{Kx"!߾zxuBe ˟`Nĥusb I =$R9JtqJ?[5gmb&g5d+Yuoc3!7u.nL@ ')hM<::\Be'c1R2:Q噇ztIt!ipk,.ͻ>gn]I:+,-@$8g)\xl",p7rX8RnѤSEk,s6thFAWcȵN Bx8y 9HEbL2I3P28,JOXx2kjf$1 Z|Vb֌]m8?:;Eǩ!.9E\/+Bp%X[Pb- 12`ĠlKyn/g蟋idfX )XbI(I?GaH"+djvk$@E;^gI !ֿ4WTO1Dx*̘贘gV_ٚ b=4եF P̰V n#  Wa\+#UvFl806iWAp4){3m|0>qj xK9CjFkKEzÎ:M%eLU&y+ʙ}7_,T < {fƣd4 N he)m3 (\=z/pmч$86 |~Zu2e1ā򒕹r 聚VФ(ESd\f-MZdBVxZ>=rRR̛t#hD0!5="9Dgi>9*)$Mt(,[>o^vd2l1XȂFM+z&oomL܂FПƳEf(>c;K@A4Ϡ\D[Z8+$NA.hϰ;1$|3-t)#վ v0Huv/а \U{b֍~wF  ]2 \ W*(v;tWz]RARCdAz?K>]H3%f:~6n "bmYcL< pQ~yd%>@_֔[-JM=^wT_mr"d9@8H`Xcv#<j0B)5nh8='֏u'Y|9oqhnYg s{X$7@w?H8wض§YGMF(OQܝ'kVGĘ%1'-1 wO9b$p}P|2?}xsɯ|f2r:N``@'[3qT9b8p995,Z9Ob 3T**ƏCotģ'`cE0_Yv^ȁJENoGz-7 qK3WHoR`91YJZCݥ,Ҫ x4c0D7xQ~n#nk+cݓghTY]<*ʉqJ>&R6.P\y} :\L < i?2f*f KymQE$r"z*[*_VſMډ[VWZɹ-糨?ν6ZtXM`KISn"~Ҩ|JutIja$h 'Q}YP* enΎGj]>Yf`;l_"SsIv7Ne:}Ob|cD C%T*}go V~J^? ɆJiFوD8u}BGSF"KoԜ ̂@>:Q{7I,Pa>Ǐ\!™ ׻}U+Kqh- HR.C"A)qE ѧ#|{x ˯(JD"C\u-bFX7sc3)FQ6[2|5YEY(=~ɂ/S7ɮUWq[!c6:*< Y0A\F\6o5Aaj]vh_ߎ}L_OQF~FRQdKjɦ![̹g/B YF=y5U"MџjJ~~ rJOcGS PˑfRKY+da>{ϴX~XĢ4Jʝ XC׸޸Z6(^w&x\GSQDB;[.hcE#o#uGNV-r%g&#ivFT/t?O)HKKwߣbTF M3}Ix*Jmk!]eG[̔A@q{OYyʕ0R$K:tfQ1؃0队pZ~^]i ATP 6j 3fڙ wӜm qCr (Xѻ,$R]{NJ0ſ†:!G7дI|κ Iؠ|IpG3 Ч$yC 77*g]):M"ō"&x:"8_Ն_;flȍӀFQvۉaS?T ~TqZ' .d^P5ȂT" ZU⠕-`s )yM΋xL{T+}Q Ca.ٝYEI WEH8V:tKx% ݫr…פ1&'Ӽ˗̰m5ލLG ׇu8W^ZOM3}%2"vj@\BD0=>ٮӣ-6jB Z ΐ8A-_݄l?p)I8gVg;)|bZ3;S-6$–9?i rҴv^ݢfchE)n`Hz5<*]&ᄸ皥e ⒈/'A(ՇԨ>N7 - L~㉗?Z9f24Sɞn*1ݵ4 29^Sr(zg0 ۰&%k.S4z)o7 R2D\h@ppHCE;M eDv 19Bo|cf}9(og8rLuw6ͦT#6,9a$X)}wbaN rb'~n[}sZ$`Q @V3DL8GOdr1lH9js%@g[:dkv "7q/̐%*F :|7|ԗMF$ߗ}ϑ=Zi:E_/#ڱf4#ξizGRm%UDk2=SF0f}9(PƵkP>o)L)2uH,]0Y:"xH/IsjiV[;EJ2$9"60Up!1Qߖ!g穋9e JT1oeȔUI0FFK4,nN!83ZJ^9ORt0[I{a0Z/4 @oQl+,7\یSH/BZZlI.;D*IDFSk2C Qw";~w/ $AQ #婴ԞM@ MuWKuZJSeZ2-r: 0 e#wAMJQF}\Yb0R.:@l1}_zzQpZI2\MGz8da>qAdǝsNFxG7r-T(WXB]O5sci̺ٞsPa,6d\8umC_P~S) 9|j8:᷷HK 3+(>*Hڞ~% njR]sjOJ#$`0|PRkcϬdeL 6̌")Z ŒYKep|qKF5~Fu NEt9"(42Lq&L $625aA(v~ kIUՃCIJB IǼ  d!gHPf^h ΩT@ V&Q#( ݲ$q$m-d4+R3ffvRN~6@xj>@Pp\aQel0}Vjfd zXL0z 0z(qFz"I"3F;:&=.iCm%O B8(V\dg_+Q|9حvPc*eh!bȰZ ?HE}*QDQ9a4VX r! u']`.$yaFПW-N4A=&J0Sf4kpzo$2Eby}˔{7{D&LE}*@IDATk[5lVmq}hf$I=h --S!L=w_M2 ͭrE:Hkag-վCFU-5ѻޅ,@@g->KA#>R Sr1z_Xy;{*SuD5`W]A V y!2D兞*Y]ǽeæu"["'qÉ`nB'Aٽ} }db߯?Njŭzsk9-B; g682 @[joϰ^'Y#lCvym &H ӊbU_lp^-pA|ѧ{SѰL1 K (. uX<8a}Ip09#UV;3tFꞴw $Է@DxOVݼ޶ mq@MN&ŘЊ @:KFYWCYW =E>Dsjm+mƎr5wCms37J~M`:VP׭%XW689< A[Ce؟IYLᑬ"]S&ZSbT0ɍ>G-K vbLNh5YҊgtfj}tmݐ;KE $dJįwׄz{ްhCN#q4|& A{Sjn{^q76d p{م"in-fFan+K#O3 E` c}9J&bp-)A .r\u#qz^E˚Pu%&irC x&!֤ aqEHCK0Z-B5bn9:aݓLU2(#l"a=STԂJB-Y"HL3$ yn!"^Tj=RCg.J"j_TßUp,OJҜM(Zˤ$kwNi&O@օŨ;j=Myc끫iK艨߾㐃8#jB!uIJ];9Z>Ӂ/Py R@#WcjMVa] l&I%n*}OhI]fгb6"CR@8^XS+̈́#=} w33FTMj+MU5 ꖉ< #LRlPl+A9C5dNS)],0hi#5Hj̳}ȸqCzb )&o JRX4=U`+dHvXz͘wcX& @CjKj uRTVa_naIʆdd HmVsX͖-2ԤW*#͙Hna&&/m-(,  t fxE$;90 j$]οNlv]D(1m0VyݴTK YBK暌:9 nApF ,ט>RސƨղӜ_ sŐ<9ߝo(_4D:h*X%eڻq@@E7H@ÚwDfE/#we+&NRF.dHw~ ٬7ZP)p% 5SKA-H uK ui {GPfRזufu /x&)H ]<@"ֻk,ҌI;Ng}2ɫWFuKv I~-QϣN:`< .{mndI ĕsƦv?3ieSEB׳d6BI h)+]ɿ t"2ni7>dK:smڧu3Bqɡ ƶ$& D| XY%vXnVMuP-\"x1FW/I@R,6WNp &n} _ v(F1JstN'<}uDK/ODfA›r,xÛA C6+FfݤxɮxOq]rw:5Y18 9v(mI w PPiKyx%i Q0܌`~h a-nu\6h 9 KVǓ-C7T~tƾukǠW? 8^]զǝi#-\LBI" &Wy|aEB+o8!b-8CUrcoXY;׏é$Io]'`bb@#Ø=KJ}CZK;꥖Ô%D)՞n%ϫ8nH|9_h_(%c鮴f4*ewCM+|D\YE)8%݆YM}NQ/ g8:B V_@gQ|.&m*о|Z*cػf*ۧ]?l'ű]0doi7|}ǬѹzŷnJu@$:M /l[!·`q Oׂ)p ߈O?H5HxF7_ڽ%Hz!~M%w"Ehu' ZdSH ?7<X'? Эp?ns/+JV\jqc%xQnl!U-71æe؆5jI!g/7RGU|nnHlle}U[v|A.pO}i Ubx_Z\ $&&7PimZ,B~f7Re{sj@yn*n A/q] <6&1gcC~1>V~SmߓCett/'W(u . 2 3bSdEr>+*yJrtU|2E^UTI{Y|XСEQW@*;b4TO os2-Ϝa̷|Z"٢;H3b(z ]H̏ t+jc nϔͱ;l~HE܊=10 c@V} | $kx"K8]3#Ջd 3<2nsU=C-O6Zkސډ4S~vF}<5 e% q?Je<wqDjͬI_?O`QmPtP7g=ErޏL F1mx&;I&78 Is~bc'n3f$RpB~[2A?5%aj+[MY : rH[Q $ #P19~u]>S w-e(m9rDs$X'K"xYOX*G֬\%C3AQYAwUnjqꝏ\-sz_ ΩT L}r5 EɄleET~epV0aVMXTO4A 0/#ڬDiW96tlFk)&=5*w4|;b,1 fHbCđ4? jҍ'fl `EaߗB}@Kn)B^.LV4i1\nPp-:aCFFWVeθ ִ.h<+*V* ZV"7_ZoI@TRwltڮjbV¨~ͽ‰3Dbp-vY2IxlY,zYeu&ڲf? \yw(AShm>Kqlv%x&"i=x{tlөZƏrG+RgB j Ư34Nj$+S +Tj!Zx(,ܜ`qFrhܒ9LRI# CU3[CcqFpۙu苽[z:0_>_-ESQ,QP8j33W:1y\ۧi>/?1ۏFe/9&﷗9F2NҊ`ǽsrW ԤUT_cgxtqe:LM@L+F9|qaK P^~Y蘅#cm뚊M.6u̶= 63tZwC`X @l9EB4kb(vD]LTݺpAm;5%#?!*QJ8TFѼ8%9|/F,gy/C 8.#a4ՠtYiZ-@Ӡ8[q!za!8yگvӍ0>F!Pkj$C &BdBQ%lDvRs Y8j+(1u4C"^/0qrc$ܠ B;_DMM2}@Ѫz's[گ. .8%]K0 M8HG,tIoU=ս~ 5fsj0d\ _,`g]XrbjKA{IP&Рu8x3VKX Avp=`M[ĎYI2P8_GEk[^V $A <SK!ڰ-:ILWe&&J.*/VU}jFt~ ~Rxhc[RI\7iX܀?sඦ`3n#evYGOvǹy 2EX4pJd B y61XRX[MP@ &9;JO-F4 ڼL$<v{I/<}p~QJYto#R%QUpPU;Cprfzy13DmflLz߰q d$lw5ӧVSi⓷.:QW +CD}Ch'fH0F.=#m*Q,17ؙa e&3w"F4 =GýW̳3Ȱ2k)R%S&7ZQh_l9D}Ac 9`ʹzI#c^0$&ZA=EPmt6fv~@!P`^mK> #H;jkQU R8 ʂ<lz[)0s֘)]OYLINquwkAi?ģ|Al KP"tKZ0k#t' Q/μ}dj~m|!XWH08RKsP tR扮/e/\b>@$TSemw6zB@BU;9:֒V7c>l:AL̰}@Fem0t6DO+a ʹk8Y\2Xp97D0uz^ 8]"dpqR%kᾌ`$%q.jY"- 8@".Ou㑘xHϻ8.ob J3/Mx/D\L+:3:0рڌ(ysqfca/K&Wս:lh},.MEvb|ХE;G.)9C˓BwIUp?YRTV_.Յ9Ad`ypv8Zx!7\~yVɼg'^/]Kh ꚵC(OHгhV,]`ZU3FMpun\Ǘ$AcGHc@'fzzc+Ld߆W GqbR`f]2iӍtn |d2EPÿE@=cy H#ˤI8 0eO+;dU9` w F< = IfAKP]j{p.Ll$̀Z_|6۵8Jx2Fl5L;l(7K gSMM3ld*y!%ɥᚈDyIIAyg\=6mN~)c "m磿i!ފS͙bđ |L@P2}ca(|ǥfdNLEv2y#&}(),.z:HjC Ze{됉Fƪn%w8:HP1N6qhSSqzDzcQÛzKτ5![. ?ƴJza疺f24,tԁ$̓p"M A L<?"okiD1Sq8Xs lWT=?, +T4 Jf46bM]#kR\t" ٴ& 3_em5/m9ԖJM:%w)-oO:geW%yADczM)eh3vUvuɳBha7&a/Uq[M"2+3߂(5lֈrHLl7GH_ϡdUe41 " KxeP ľgB\%xVܫQ$W@ҠDZs0_yi@dQ:<=Yl^ iI>qOL10O[ǘVg#=­Z"nՄЀ, /+ #W%Ky x֠aZpady`vŹVF5}[T Ɖ!=ʟ9=(^7*f|&`4ꊩDpz}yZԃSZm(54"%aS@8(>RFc,mϸ5g #35 ghNkw8r=<#}a; 7 S*(Ntq@Ȯn!u"0 gEkx2'$)̙#!LaAnqJ58;ޏJjNZ~%EãgۆpZ,7yAT1:Z 3%u2+\HJ!ǠAkJ=lxJ֜3EATĴޏR,W> JYD桱w30w4B (l5Kn4 yt?WC)=OƊ΂Wr}{7o88p en;MH7t#(kқ;H4!T/iGS-!m%%O$Lfrk$Y \ߊ7^ 7?m_s2[JNB/\6> m@-Q^Rx1 78}Nm>PFUn2ĖHqWʺ񥚢fƀ`6G2(oE?`kvHy4zdڵp1¹]83/̀r'Ar(}]t'/Cg~k׎uHþ[L G&bLLNS*UR1'=܅4\? pj6Mμ6j!`>7Qɡ !8*"s]57`L#'p@|spXkW5M\rj4{[D)jMfmMTjZ5fqƄ[:iJ,)"sJ1-ftV2HB-|n j3Q#yҙːޜԛKAw"/yf%,024q@*D| C69+8%`}¤D wxE)|Ro߫m BoLXMzE+8cH 2**STƅֆc"wB[M"Q|ߜ-TgB)ZE5&8g#\8h>L x9"7lq~B۱Dfu K)[o;(,)әhxA<[<B mh8wXie3=:5*ؑZw糲_thѪꗼ"OCEPSslߓ MK&fC oT~dfIx) E[ĕ[WxTsS-b*-$iؤ[iJ;0^x͵%hCQhՙcXAB/RQiċ|srt,k>n!uzFcBCL7nmxMN=vlsbE_ҩ9mInh:Apu\):(1wm_KMAIMNG9u,7kn'=4&F>R&è5%wwcfdJf.hth[h>ե2wE(?pQV!֗ Nvi9=\XF CBKoa.,Ѧ/0 O7%Hm4x&A[͠5fsau9~8S̳D Úi!I=1!$,5wlH:Sw$݌VN^EB!1hb@1mgE3+Xo/}6' U]3C_ot*#l b1IJ)>Lk$Dff;,7 -رT/N}:kk8` g=oj4"6!G7!@2i7{fT*ȑ˼jrW^w7gnra;CC-. :װ/!8YG";(2r"RfE"Uˇ5. AM<=~2)g LӉ֔G4{1Q$'@f7VhIm!7G0G*nA4雟_B:aN&Zϻ^Xx5NL$:뱏ޱ7Q2U=ue<pX\(5b7[x h芗QC$~̂]We : "#,BNaXtG7%@F-rj8p4{X5Df?aV>}j#Rd=JUQJIӧ>Z`M>N )C;O9hPdSy'2Oďn tsR_'>c ;Kࡷ}MŗݭW\Rֲ`v^+=kxO }cQqxO>H}s=rh[#ѻa>I5=*J [}N KnBꊴ߬2ϿtΐM1./p8$+.u"ЖRe.2N+HUSi@T(̤q>k Y WuTS{EثܚyK>נB4lPnlGv!CGo۹!*DMY>M,[bO"b2D huTYȕa5ƙH# ??9XE}(#cS i&m'8"=/-I5i<>AFJ1VhrC<*G@  n,9YA6\1|Qۉ웻%g]?e~ LJvK*Ry1m"R8soa#]z)۱}vegS(7֟U #3s~PXJn7I1#0}MlmL'= z}KalDu`6 +ޫ<7;5sI5;cũ4#Q^OTVq2]|U{'-8b|M cM~˲9!73DUWB'K;t/bT^J=|hWm"YVĐ`B5j=/L9mf.[Uۯ)&#ϧ#k&B / 5@vg weFY. T1&$bp5ثN[[r§Kr4`݁I%6?c> Wϯ T"_DkS2!']-)p]yl#yvF& xR:ΎMn(6qaNlƤOأB#y&3"C:dՊ}4Çp1զApZfNYey جBcJ y$"B3f!qo*5 =s۷J ] mbL= .9p# ,/Zٙ>슧0GXt$]#/Z$NqB2(죱MGX^vQH/LAvxr )0 sDȰM:w0sfw1G D+ }|kI@3RuDA4f\&/VVP % +MO!VĊ~^T}P l>$uGQP :޻q}g @m].C@D5V0q1nF-Y;vm7-Ufa )(Jx4Yfn Q}&*6]N{ R1(夏 Ƨt2؆sg^.#JFX `КqDk"3aWKKY3FbXA:W‚`@ _>V3B2{YtY|ITQfd>.<2R!C+9VU5dN s"Yt0=>А s8tF8'zA!0֬j{P{Ԅf_=94<)88>y<ܝ o\d1L[H[k6L53^qEe>fGႈt3oGB~J`c*"^#xdHL&_$Slu^ӱaP?5\n>X:f9f @זm`^ OXjtMz5ӡ}U,/HM5)7wcGJ@lޙ2̀+r#|D֫i3mF8k@ՋX|,%@.I]7;4c_ah=Hj9#Z}G@Pq9H/Rb1 d;Iqm|ؼXª7#9'¦ת}Pf neۣEDI2,}+]g++Vڂ NyxSi"= Kve' vMS]_"~:|cqGr}P$Nyv\` [ :s:R&޳X-+ 3ܽx1)ش?lH5T_IZ"KScE;nh%5ZztHp3kg_fUdb[V'F=v :ЂJN,)M3-S:1iXaHIAfZ  ܌K\3V{LxCq]n0d fHҽ @6}4`Y)d<v%TT\+]j %#R.~ˮGDG'4Hy,Qk9ܵYfPV,B'{&*w%ċ` tDQߤxhy*,%.v?h/ 4;b(=ۚ0J OF+oe w,˩޸Qg'}UŽ˰u}(eJE'w)cL8ӎ]gL5k6WD*Tĉ؅rnfX͒ʘZ2=)1遆D DP_/G}EU.[.U)n0h-/C)Wlo_1J6wEBEH@3/EbHRs; 4K'=ds(>w$ꇗH^|lV7L?9bXZy%t2fCidCg 1Ę3mz/Ǣta5|4ZxL8y\V \K,$˜HHjLA c8c2Hk7ްKnlD0 0p$л _:)1l%9>CDXfkBA3UޔƓ ^lō `G)kNì1A΍+`9fU"3D`՗~`ӗ:c)y`m!/47lEBəcy Àf*48? &ɀpCϠ5fPX<:$ORȦƄƨPOG)qa"?kΟYzg!;%9jSk1ShQ5HghkYbs;,4 6S9%BlWIdɌg[2fJ_X (ʒݛHaU PQfe$:3YD 5rd zi%%a=d@v.sNCܮ0FG +[e4we4>w߷c\ Z V MkiΏKk4 §.T2R-#6v]qg'!; =5'*A489{A_RUrch_hpA` I4#KPvK ,m9C B"L Jz9Jp5B:9;@EM6Ġh}j=&M 6I.!-ѥ T]f-綟M'fʁΉ.#~K ݇dñF4K=rp@;#=R*Z΃p ^©Oe* >ԏ'?4itt%b6I*C'ú@'pџWa9F6˜`Z%(7p;4Vwdr b5E.z#1}[yĨ7Xc&AӀ UhcDpCe'*+,Ό@B(4S.7;-VX 持 Y ).PX* ( X)2@-Igz?lQlԅh !,/;54-oJϙ멜)QXւFMVlp0YA/K|M/#m3eNhM&yOֈq{:SZ a\Vzɀ),ٌF_ yE1J8 z7$kzr sfa+%۬8npTkAA"A?N|S#Dũkj樧^}!5ښSU2j 9I.EkABLW̆&&a 4HI)QC*@ՎչOtr #|aby)&ew%reYg! V|vlP .|_$F܋cQd|@_j"ojvb>7bi)(5NMDrfV6R|GQ:$fkWblX8 hpsQ6GKw1 ڨ Pm5h ϫiG[CQe!e#r; 2DQ Vc1M5S''%Y磮aCCGp'[O-'w9| V%?~:rȚyh.1 @h,T"])T͚9̧v&&,̇Y F%g3]+Fa F C̚eKB?#{T 9A T`l0e`W nQA#zl%Ұ1)qKKѯ1SlWOKĦȤ۔z)!]o0A1`5#qCY~TG%#m(sdB }ۧqӘ3⭫&v14V߫` AդؙFdLmQ*E{𛕡xQ9 4)lYzƯ)fl= o~f>)E?e:)Pp~Y#'H8ě,D(xO<::MGiyңjy @9. 胜C3~حժCc10D@圄:'h!4פ,~@ 1V[Kvyz+aoM78x D.+]z Jv҂Iw==o wT&0L"G]MdR`lM:Ȯz- vV] %dMsrSq7p#o|:tP'x: >ҦI&kDpBznagqirdQ+0Q٧on dQyerUC?K/Cw6N?I3s`cwL%#zOY(^+,9,_p2_iCxuXyMzS #m3NVM5s^5?^;ex6l9GKTϔUv1sZNL0=O_XmB)bjn%D vd!+MTa2jWzp en{8/[w=L##C f셺7햽 WFs(}ӕN*BMsV>YfmZ%1/rRh-EG_vUn,Z:_?Ij Xf?9Y?}kheGk92}P/9aka}lSգ`|wVK.Ԑ$Z 5Hr.$T'x&b*Uf BUn\DݮNaX6O9R:Ǒ4ҝE+{̤ߗx\"0QH#*WyTV8[g+=C 4i Ɵnכ1_4Fd)oHx&%W!f6tIb9ZR?Ww#QmGGX-: /hNo/8Cd:]>?.IC!D$)kp&g&F  ۢ9+ńϞfqRżKx^Q(1ƞa 1,8i >OȪ:C!hq'L_Sfx0y3\6,)]#Xo%DviV VGWWh"a^eTHZ;p-cS&Ixy_8|';9tsdZZ |9 ̱4=ąL|,) Ly)Z!y“ⷲz\f Oe;CB_'ežris@2u9*+"[uI"^uK-HiؗD0 F;!A4UFc#ȂpK_sWi+rᅬKa(_1߬-N@S[E ^BdTV E}(sr T̼ zAXR"h$#[6g@ r~+*56 kpM |G:[dy-(0HN3)8? Au& O(Rǐj:7ֱ;qbt)?h74G3p/ bWL./'h^i"tCn"?p~R))~HvZ(D3:)M\6F# gk`I@h{sjs&B1y*Qd x,B1 sTEi}str̠ĞGBzˇ4(Ct |~EYQT"@p'6<z}mw5i &`:l| Oe|Oi"v7)oAh:׳ Ay(rک}0OٌްT#gW5\yO ^ ^x`E<(Ҏl#DpLdlfqX7!5цh2"ߔ#ݼïkcef92B~l3*]i%f~zN[e2z=$iߚq5pM1q4D"O&_o,VZFKRH Mi͍+qز3iF ay7饓 CސhM4%P0Kc ܂v8cʛ5%*3dEmD`{l,e4kc`g8ě*afl7#/POv1pA!F:AKc{\L }y & TH δeV,h֔?&9Ȃfɳ$p" ]0̈5`vW::?@oW"sPTY pC|@k]3۠>=!"IŚɭH'w<{d.T9BY(A*IÚ z/KZK/81?[)̝)=Md9P/[OHqS榶5#D`X2ǨtO?S(<.'x(zH֣G'fEZ)(7yLe#dn?^Bn{aͶ#As 7屆xGf@ZW׀N"OrW&.;2XZΒiP=ߊJo@4wZR"gW-d*%Y)A;g-MQ=D\ӴPxD+d;rsx^_ ꑨB|@'`QK?8cTE")fͰhcLHxQPKf`W~x& >Z!xl1A5J_K7.bO+Ha$i0ި> S |?/A~gl/5„aa-^IΆGZW()AԞ %S)Y#%aMr#9LqY޺.osz]c:$}V#u|#2ԋM(qF6Q,?5ӿc;aA%Ave`!$Ҫ!b{Ī9#BA)4-ym>/+~ڎ;.d@{,!SҬ ԓnAkI 6DS*_TL$LZwIϠ %Emi@6|z{-\ \[j'vAE9bȶrh3^"5Bp$N6Rq,ц}u:*OCvqRsJ@) XiHr=3]܅ ՜V4oII"4LX:܂PJdEtf~ţeV 3;)ZF?cT'vtuzr{FiL<B@eb!V{]#dk⃨݌陸/t$(=a,2f` /- fޔkzkkR3yl nZ*c8(4*!L_w R`${5BGj]՗ѵH[~w "ftF쳁cigt&=5!Oրq42}&)X rhES<[%`OV,AXŨ}`0,z45n <sxwSK43=9C(+yt*}[iB觗W4@s206 "7ޘ8x 4W?&3-.$lD0=r q]2Z Źqf=a7~DK@/A `LJ Փa\*V )\ُS.9Q?wNsLO{IDž?qUM,YӤ9w!0؋ஂLEWN1TfS' '}K}! [94j}q9t5b+0! ,+Lw GtBUq:R/.Eqd0sDo_f>G c  ckHYPe-$J7aB}^9')q2! KVGx*Q:XWP|!My0{ah% 6\m6-K0y>;i34͋ܙ3LE6Oڸ* [ur"rXJ_Oro}KףD.r;vP`_4ǏQDQ^0ݍv95vc4z Z) =%Qi{T-ҠY^)3  !r+Ǽn"nvŠ_V'?Vn1%#N^^s’ 5РގՀ5aeU8ÙX¾X$cG ^6&j@Zm/*^]nPR(f@XDr ; Oz EzKH|,HĄ=}t2'}]|J]O|Ɗrwfĩ ޘ}y mɔE)ˬ)\ASrFxn+=hxqB`RU{H=<4+˺{ ߯ ;l$Gs,&͹ު%gSU&ѝ{U?fSGOnۊkrO >2|P CL`FȹI1^:1kwp0%*SqW- p |yeҌ9.^pgSn9Vb c2P,y 5T F`' cDpn`U\ 3Ӂ|5)*4cr5p!gA1!D5;@a9#񓼃n)!䢏tM- Mj*X"1cO8T[ꏠO%*w4P3Ī e4y#VA,0!%yyٿ^_8\9(4TeS{\!kH(`>Fm `ceزT*+ݙo7'+ Q(lF)16df%(sU L,M ȶ}ڍq~x DOCYZ3Pe;GDhGagHH.BJg53y]ۼ"I%_Sh,397o})L"/̬/;bXy[9onH^7lH"&w'2}]ѫFW஦^7f,|kI0*iT@GiPxPnT^ R:EpDiY0ݐޠy^K[,YrpQF䏁]KlF.+/M#w JgirDZ]3:ĕ>6t#q_vpL;b2mbZbw(OoosIjbr3U*%v(ţ/0+ crYgIяȀ'{Ȧ)iOvz3SH|0cu˓Z``3-NSօ6f@~nBŵ=[9Mh.݌Ԅ3,җAo&zzKW9( imCi146 ?bS u)Š1%Cg롎e-zRv!.%]Ou䖬_rQ94á_sdC1p@A<|x"y17>Sh}v$6޼&1C&C&`+\$.hnWKڬ}1[Z9N$HtXL)F4Eku-:`_f歁W%t[hIRl ׅҊ0cJ`'yuyXJru4l`Ҋ(hPa!DzJC />Fw$1@?1`+A[Y ԜӨ_Vj ҥ^.arnu_C>I#FN5Vkb4!1AV[0cl6d -^^7_muY;jm4MfRiJnHHC.oa2.8M _0dY|W4 [ZΎmFm lcHwH˱@it6E##čF%zV2>plYLD# Im-7pPശbJOקf;C1E)^&HLD*-ثٝoSNV2'$31NC~^nʮZď/}J|PSzKGm#%s="bsVXW :i FFjE:_pD.(4uRSFg "p֍ƦDT,L)`M2oT)ըʜQ6R ,~`4,_ G䇦L;ƌip ޼SD#;GZwBktl;%?ʌK-sVUYmZPNouu~>؀;1dmo׌ߚiƓ|GmDt_:(- ӽ3%۽yn[")J$@%j-QkUp (K6dsDadޫp#V.^ݏ$F;| )#ۿ~p+0@hpEb65P㷠`6@|>Ȳ>F$(gSƟoh̒}6_-q}.H~U݈#]ܚ%p2RzsX?1_v 4`{dw8vxٮ/i `jٍZ)r G3>]p>|] $#)iuyZtf_:O/T*O],\f N*nn{Ԝ_Drq K^O(db} %Ɉ0q䘋1תS{[UcT[Y'>*S#SeӘP|Sy2Hh{Hrs`=*[x~|CҴ^=fERvJt8]3`EmU6(߆.uVtZ6pwM^||ݡߟJv&߲=X@ SBϏS||~ / a@/;[&#o;;dls9mg;i*ҾxĠb tde 3_<#S3_W N\E`~+[GjecS^7S0 cY/O!}J9GxZb/:5jqXvTQbő"/]EZ̋1T%="^7WW7[G::Åaa.`F]EE>~>=y"+uOW,F ~gxBj- 2 6uuX#V96mKT*RO(DOr߽6JŐЈF9ecu}E[ 8F1SjVW5]u ]ntק˞R; ]G$#a* z)~^ ōlF~kFT(A0&t(#tSfM f*++!R["pPMf;caZČ =nڸJ ߪI|L N 񀔷(S*VO*۔d 8˾L̰[Up"L{'Z b[y~t,#cp:EIxR9fɳ_?UǃZ >s#@QJ1 ekNXNl^7X\'KgE@#rV5[2?Cu UdQY;}z|CίRJjR\Er]7 O\[}^wJ/R;b Swm90ycl_oQ{ףMhXykQ\2  l^J68l~ XA8iV?g\&Ul P8@y3(ً(cG[C~YJVݎjNN&e m)(Go/"`tK.G-aKbI?(v-⟺g1y@H&amxi߈\t@bŞaGxCWx7Z*8}o Soa Ek]LiP> GUFө IJPYC Ÿ"jk>#yH|c RM'Jk*h Jy/H RA\=`'X)ۣ+ B1j68֓y Ȯƙ9w( Z-ܓ ȪRĂbT(C]+f/&-llůGWf+ϧ$o¢%OiD]=*u;(kLܾJ[z ~!= *#I#Jivk(?CνGW- i"ЇIAy i>(<Â0Ah~t6[>gްAK !sjn2\gm!E(Av xMe +t!CGVHT):\&iNh$u}DdDR 2`q@w-ߔpdb0)}QfUVG#pd a.`D2yu&1VbT~{3p Q v4jd=ۘ2K BӐtPbw$so^ڛ0k! FubϵijKT0⑖`53yrG*ȪHHKΩ )ϏF]*H꼾SUO"Fshf{#.ӟ瑚` PZ\ Uu8!e C1e`Q#pdDbQKHN#G.) 7mk3ӊx?HK'}oStEA-O@%{W8 TcBq,qV+7%4:?=CµsDUJ sIg$#M-~qd"ƒU鍴\ FZGFqe5zlۈRBmJ'p@=  t͠-cM:Om C#/zښh])9J>w4&8)J'֗b:T%{[|XL @=['؉q@YYQyї~ %p}I !tyXѤQ+=}F7uxj(-}0aW$ДфM \qe*)xLqM`!rd!bǡGVճX8@dPwݖpmtOnx=ӣR@lNL  Yp2ZUW8ł([hoGVd>0l{lJLD1ɜ Ɖ;ՇsM#iN|k) jTd7.%n^(;$ Sy159 kQZ;zZNIs3x8B,/m5bm_<|ڦb^ JUacEUlCsJڷZQ.+dM:,׬}:/55խqg2$lZZ{>?{sx>&z'yiDW'\ wĎ KK&cBDOUBi^Jxʥ䅯$(&{49 ۪SqF霡W94TD ǘ`/߿leٔJ$MABo vipgY⪣$=C)qg`̺bSͷ3wC7+DEzh2u0m(ntB/g@hbMgq&4j̞?^ޝ/O٣e(勪k] Dwh #qKɊ3eiC֎1 V7oUS>|Όixo؎b8 һL- Ҏ:k:0.ƅm쿹.Hc1(5]^]2)@燪`[xXKLD-SP`R#Os}tD=dFf@T8l~Ke4c4"W.ق6e܍!"QOTicFBc rߪcf|*A,(QbƔp*N G?ζXTru\%t W|DH̯,}z+ e(n%vhvڛ1opȐR<6ZYs:Y|0?MEڙdd'[x4:97ܦ<3Dg&z3ű5HѧH@_gHzN5Al+=.ޢ_"+K(?H`6qQ|=ޮ5"Z=8e#й),b5)eWk!.Eŀ)ee/5q(WaVÓ)ӝ_KɨC'3=> HߙS%,JxOpe8w8eP5lsF`6- =D#*>ttiOnՓmoZDyeIro#fs'xu4-M0;o]l%>Sf/QP:A8$bӤ8k\E:tL۸Cx1YđyȆBo ǦQRzQMJՍfrYa؋CSwC4<h!']g;IM2%E2Q&d)tE8o,O++vHI :'NkC@V?FծDI(ZpϭBelB*7䄻Kb.;+'ۿ^c@ '0A/e=a~i%;7$V9Zؿl5״;P0ZBe|h%$Q4K(iNu' ݃FjCs:d+[F&1 hc~5 /$ W4^&mٴF ٪rXrKm{~ }SLDəҧa2r|0'=z_>dB|^=/i`3d t4y|5cZ@X/\N]`^Sp <3U9OIp1Q=8XL,+0ގx1#C9!rޯnP ^3[1:^+g2gDt%HKKO$m:=8Iс5 %WQmhKXwl#L?"'-ԈZR m &CY Pg!DX.h>7&1@g#^gVe*[H~+j)}7d=Rڿ0A SYnə%4XøLAef؍ha0kWd12~ҺBuò$X#aW 0/o+%~rм qI[eh)8]oVđ27#b@f೚&JJ1;v#գPQS1Yxā\-GxnqEX)GGH7-Hg #ƋSvʖ E3GoFH5EV p-w"E,K8Wg_5q{X(Dt#Vy$ Z!ϋ@#j{kAqHRDd™}DOwVF:5Zٱ+.u,nq]g}wrXHѧ[-rWfJ1_Oj@]AB+F/U眲ĪIgG ~ .c/&Af8y(=R E@0.2kd4KtMlO22F"hxG?/8g*!ȱ4HAY 9kDX.:'2Q˴'-Җщev{=bxHfr'P XHizG=_;ח [w)J>ha=0!vj3q-/ךcMx1~-[8vظ֙[+sy꿻8B8E-껕ZȉsOr؇%t0sX$7iB3rxPzƠcr$[kq>ctz5C.C"Z@E o܁2L#|X5S=xhӝ"Y `w/qTx% t^zLqxgFRsre=%(؟Q}b,kLjO$}X єǝ*L(WL;vQ_NXH\14Z}튈WQ$ ӷe/ge@E `{aWwVJ2%Gl~1ʰ`Bݨn 'V.O7@I 1 b8k4?cn1#-G]~Aav50r,;pG9BhʫsAG ~(]@޶/cc~0UAn"E]'YD6t}h uT#T<\2uB[f;X#8L/X>G߹c$!LN="-Ś[+wO=7 $csVra) e.ɭr9V˛SˑЯkKU1$1^e ׬?>hNf Ht$8t'Wf Ykgq>nz 5@:H.gNzиEN6N+8.Vjٲgv{mg oVɲM֎[œݩwQUp6DR}]sqyiPA*C9x e=Cp< Ŗ~N?)|qI-]ś=glKY)T}Z)OEv12wHk͘qc 5\O kӽ?H#rϡ@ 啼fOzdE*{XQ Ii ʓ Ew:7s9c =2jٴޑ0yJ(Z>~[3' Rk=b[ zyjleY^ZZ2[ʗe8Gc 1iyaXOe }X+E쫕~{*9/ܽv'2i ydO:ݸ_sEC*[z0m8QUdY |giecҗ#\iEc/*;ti?ig9Xs^K-ENr}/A&K9҄rV!Bpu8LtuZZ_ψR S ҙRM۳NdKq[TQtJ6!qU9\=:>/mj|D0!Zl?{k{'y$ #5<) [{g -D .N6t_aAv&̋n'35c3עD$*-ӎ|Vmpzu7=I˪w`O{qךz"D'F+)HفDR1?:;[<8v-ZKJ;m jTc:1L $)(/vցp2,pگA(6xUS;m0\_<2pL@Lуl {Bn#``}ҖJy5cZQmp H4w-AbBkwHbG݀6O#gERYީf>~H ` 'i-5 ;[\\؄ 7mvn5)dC` 6DnK텔k jVs_*4@$2>. ,ϱQ31" 4q2+tBQAHszl6j}WbsxI głd,i.9qM^Ѫ d*ZÑy8Ը@5V8г9|{V{U~A'0dclG!_d@뎕^|\*J)؋Etę; <蒊\ ye/؁?u\m_;dWf՚e28X+$<Ƒ}Mx&/xIƝVwʬ(5Lů8^|a(P[T\[hJ܊ y&4G-ޘ CX9(&JvHCKf;^$>5ƶq`PoƐ( ~d=VEص5s.Nu=p.21*,R$oХ<cy99_eq'c6_nK]9wND_J-PXf9C)4cSEkeɞAIAP _;WleDxnQvc'JKas,9XLћ.FOiPqZZf2bv<_ 1 JLBG4+ TlS^Ҭl'9fQ7r rsCRcG G?Mom!:Yj,! ẕu<;L' s衜_9F`NMֽofBA?/08f~M_"vŗ\:rҒ KSQz1#7[5~%xsz9ٰJ}0JCۄ$[V e_啳^L(+k4*HfYf(e%2dx44e'*kK'ab24H50NДʩs,Bg$`A,q6-#ڊEUg-4|QOuV&o%H?<=lj) p"3L )V2\`$|:.,dKA3a/e#0O5ѳpңt 挏9!{aA99ƲXHnzLxX?0ESoXV>4"'{Ոg6xibX?nhgXy;m.`C1o g}ZO`dB YLӷϢLC޺*2buA3p#NtTq;(ţ^;n:bBx!^cqQ`E<؃t#eĦl4{V"yZhn=},Z4""@%@zddII9D 5#zmcK˦H&t?mUU]MSj|U:ȟU.Sik73 qpHP .3sRt aŇ;rqAָD]vC\yٶ&2` G?gD\IKl&^}4')B񼜴 ÎfޤmvY^3|eFgޟHvтly^x(ox4 6a۽d#r>ޫ/NG#z^MO\5p`̩W͙-_9A/Z$G HȴC2]hm=6o*/2jBd}n,EZc J(۰*hqZvq3w1g 4ЧTJde┮ }Kcƒ6pɞq #ߌF/c57>ńϳ~Zz4n.u1T,R4AƭNS`5C ~+MX}? Q0D 9F>aD|PWR2.2-}&'>O=;[ ^&[YT_2v%~Y Wd@] 4(A8+ Xnr7j.>' Ai LbD)կ pFJBryK;8S0/[)12\Ą%Z5N{RgZGc%jE$KgF>/O%ɺ$)5}:>N-;CHmm)*mۘ\5|y:,PK1pGCMcmȕ9ȑWЦ~Y^E&V;x-a/Vkv1,.79r֚)BHQ \ouH;y-.Z㏥K_2Z NA`v$voNSeo/ۏO#p5Ck|;xTgWҥM-Qm_ꁊlC.'h[Z3ecI*5>QHc9TP 942I.Pd6GpGӱGRf݊9qiCI` :z)X1| r;Z;)/􏔰p%nrUvJAr?QjP 51MW\$~H݌)b"pn ݹ#a7fg-"!jӪiI<"P͎X}&;!8EKJ\^9~b}DT8^{ ext=r|$):yT̊2ɆL`o~=4촅tNz=v޻U^c@QA@Dwq{F>֙TLdظN.5u'~릧1b7EJm#а@7e1& A^K[HzܳJ2BGIM%a80.Aw[ȏ[-w&VbɧyU._^ ڱmtiqI mAIb)@ ;+1[3z,n˨[;%S5:QҪI[aBUjtQ ?%c+bc<_4V+0sKL1rp\[!iϴftzg!4Y{(51f'VĂawVl4 g0oKFuuRXmҜD/r[m!HR~}k5LS5Sh,S&\F8YNxƵL{Hb\*/o-H;(PCg ~ KzǗN$-{4uPujRAq x8T`aQ]:T/+\XD&Pɛad!ˏ @h"xh(HYcf&LE ]"tNsXj0^e4Ʈe |YH)8F犞i܀ > xSQ]no9Ċ%0s#Gz]d#8$^t@ɩaNg~"Lٍ s3LCd>M߾撦 ;ZREovkRT>$ma=-:+* Ƣ>zΥ {Arg ܔD$ qΟgSS"c]FvpT6Zta3t8M>Ŷ2WVfl0cv.pjH{?|WQ<5w̴Ñ )G1pʸ8PFKxkNY# R|LXxc#sb v+@U*/G5}pxJb2|t - 8c>7=؎G``<,mMJ\&KAxcYȘ ˗ĎIKBꈖǫul\@67IqYAD$'w[a NAxȔ CH|h8ώ%" l/0-1/M/C>װD<ܯR#"Wmͫ$ &&[ dyVȕ!L}ꩻr؉mk~}/)zVbAY-l1qJ_r|REadrb`98Th86 g' VC XӮo؈/\gqB'~AjyR\*\_ W5[b񼹬ExAPAkY$+o<3sO/6]9Yj/Ar}Ѱj;&&H΅F˪~o/DZ(`O蓲c6IxѳU&av}b&|)'roEeh4a:=KjLiw {+>DOm1cb)N॒"ýE#P1?`8%70R~>CVX@WE;bRHh"f<]=M:SQX舒0]@~9v[۳-S,`a%R 3g#_6ˍgI_(;0i':DT(6/z))RF(yYL[,@dKSM-N-ӮYj 31P+FuuV  Z@-/x>^GVK4YwMӛ}ϵ˔lrtK U)NDMcA8vVy}ppN^ԧ">;e?O#xHJy{>VM-$t5+=qTTJK8ﴠ=ytʧA\^%XDLk8*J#oHLo{1}o!8Ml:W\3#unqb@M,QdlhcΙGtiqsɊ)WC ,)7@ў G~i9lմP|P6Z_.t%|yJEs j,~~VڸuQեJroG%Yd=ؓZϚw|5bGOD%W ! QzV6Z\ZJnTY<{ض:y;*e~T,r~h;!\J>W}z"?"dtT9B<3mSyY~۾~vxybv7N/^gjQJߔF6EXYvPuq;r[sðI g J~\V?㳴RFOGLGsǯ\%糓Z6\۱<'ԒO±tKMB Һjy:P˟VJE#zbeث7 ՜{l8WkĀ=7\a\4C5-6?vyXyl6x|^j&rltZƗhV_pQF!eܝҠ>x?.lDcuC "6XXF0HZuˆ@/9O QsJ R;izÛksPے3וu=~^>z4^rQ'X}Tkw E!d>S #eYtM؍N3e/ג˜n'y,͸='H&W~tȐTˀP3dcŸ0sCx I9M'h┦ ~n"{6$ڳ͒2Hj =jѦ dz̕O&qao-O<,w V?ri(X`]DfӜa" }}zcS)^uԈ훊\.ǎw娽 /q;̧Y ,eG)#Go )>4!>dKtr&^%&>~nG8FNgh"FäKY3Nz3lB34 e! a^^>$^@;V^QzĶLچsD<e܇؋Trjy;GiՁ"=Mx@IDATp4hvP(9|lH@.n5Aް~vխ'vvG2:z6{|vPA=?/|חQZVLk5Yl_ Lwf)>{m+,:faM @1,+|D- X|+EŠ.J .M0%xuZl/?I7{Ϸf27G9F%=@Dz*R&"4 1g34>s1E/h*epjgV42Vm\Z5K1qg2W\K `$; j?_/N9gjtU^1̓VeњIgLэn' -?9X_= /װӧq~xñ$ 5D^9ox? bX*2A Ҟ%4tol<,J9brYs/V(|JK=Ĺ[r 6z>RD I8[A7ӂ'0*H^7nԀ1AY 1Y|%ehK+W҂qs},Mmo̭'53-NH]>Nd)KeBx4b1ȷԂhibI+K3}aac$pZgA[D<G1 _QM xfNA宁.M@tcuaxIvd.1:ukꀪOr'!8,HS\(ɨ3!s_sNОfuQhPλw5%k+n%|$$4=m[ aTL& yxS"CIb IGߊ3ZWQ%1y,1P59KxɊzw%G<Ȋuk2U{}8 9sP,x;P11'ZR Q_Bj=Pw qḭ%BavK,L/z!WS@QRr5MU+0ŸS>Q8A)^Zp,XYN$w f5"PD6HE *n)%?L:@ +a;\X2R-pFf+7zX8,j$4v8n;?Z7Y]:oIwq>8,~{ؙsA+A*д]~;/.cg4W 䊛Q*~b$F?Mx`5X A Q0 >s Ÿ́,[={0erU{2nsY}2_FƖX6'v+ }uG^ĂAߨ>rM>΃bt\@H {ꪺ=2N 9K \#2Iޔ_(V7PpOԚZO IUC@0Y<>\hJpc]pb2nGFkLT̑ !UΈ_'2,SҖ >]j̯=un79$ %Rt?iC݌Q.m2_lH [)T!J=âTL;p6% r {V"E GƵ ?YYL[~'H(2TU緤[X0EoCHek֙+԰GjT^id(7 ?N=D29M'C[<H´s<=/3Ue~R3'?b$zӞNEzFY|ҵ i8H(lFjPL (L{N q5<ٮ XU| $Af }y,XK#T*&AJ A2^2MOc3!>LL[c4ڸ'2B0l U3C޶|iTR*f6_fysD' pa~Jlv_~!97 ]sBgWlUflTk-i$ΤqAAdYqՏe2I气,{<.4Zi_^aPjx"-Lor!#rC@,ZO:ע.C;2<&c#J Okr,,v% o~$Ah|K 7OUMd: ?jcڼsRi^IR&0쌃ࣁVJ!9kjKrв QbtL~dZDNjs4*rT/?,.}\V0ȷd^ !` uG;B{gF 䣔e>ZtŦbuNhn7sryě67-a=8~٣Ӗb>MC}P paf\vUslQ{Q`)~X˕U%׀#أ@Bf APԦw pBCӹ~I%U咈!`.ɕR۶dق'7J#S 5dxE"zo}OVCF,duYm7V~\Ƴ>>7W(4Qe[vP`>YfN*VmgJ#(wMeB Sv GxZ[H L6.!mAk`z bIq_( b Sl&\e6X#cDq"Tj>ό'm;`Njx5+R72CpPx l`AP5DӜh¯WXۻ?c" Z@O򰕾6puS_ xhBd/x\ 4??ӦQ_ AוN:@OOgTIđ/],ldߊnI)벪ch>Vu݉8 ǡ\Ka}4D\+Uh;6g LC"Hp%J/9bU-?ZGr v҂Bx ď?`4 & |碖h8Ǿ]\[ VB1|pUb,"ֶ3 t4-=#Y{g`H2-BVxٟ( $C"6g|1 Ã6hxv{ϭm4~edeL}95C@FYH,:2aSN|vKxPGzS4>NJ[rфYzNMI#܂ DSX )bJ2e[AXIO JK*5֋n_`&poNUF9{oT)x;``uA`N7Cn -5in]~',-(B/uMpi)!Փil A̠4ǂҺ~=n&> %ÆZMD2#E11bG`@VqU*PYьVٮU;5YCgإЈJr C*'?J.1tb\E2`ɷTIE!O_n>ǙvÓ7ysNkʌ %aӆ~mӾaNI=]'۪]c0R _C]q0Hp@|l! 1/0Çg E$O4[cDPds󸱲C:P_t9ƫw 0p.Q>AI-' ,@UPGƒR-kM0f(c9rTJD9Z zsvժ#~>l l8vWD@38GJKG/⠎Hx3 I4Ȭ Nk OZSžSu龯nQn&cϑn8-N*$kRH0Py{;-YA)9^K[ԩ tOb9 N>|"Y&1[n76Nd!`J,L`- cSvʐimFEa>B"ftiX&` Iz#W|_~bO-_q*Џe]*x@ȂP|UEg"*beus55TeA) l1Dq݌Cn_J|=<3]c2J0_wS 嬴oʏqў 9:&,q=R.֪݀ 5nYo*ちlAr^ҐuN)Y+ 'Yɹ}0 ~v-/Y寿UʭnV 7  J+'Űeؚ6q>zS6Qn"^8WbuY2%!Xݥ0^ۗ! bbQr)=^¢_;:+(4{kvr\]U@i <7YJҔ1`RgqEl`Dc.q "oC,f0cAIb0cG1 0FW65Ӓ#" S`(O"3fs ^坁]]a-_mpy(2S>]/gYf>d+w$&$KюM) Q+'|t U\ d gS Рf.vr#]QGD:%cQԘ!y I PLp y.Aƀxcfx[ Pv*~q}s@C i7ͻԹ,?4]Jh_MmJE.`8Q2v֋RCV$Yx.O(O\̈́d*eyxYE4cXh #]>٩ qKP(: ]jT G9x1k .2<@eM8=;Csyk9:!rz8c6$EbqX6&79h2b7==CQXWw$(E% i<Lx8n``d>4t JUՎkq7]DI*j!и-|VRQj3;')cY}ԋ-Iu۞9a~׏oױ(>)CtcXYѳ|-E[d]/>~2D5uW#Xʱ%IJpD+v?vfD=/q Wá[0m1K';33,_0mwxJdT:bb%}cϛ rN-"u \B ٜaPtr.g{Bb'5^-m?}hhc+ ߠսкٻQhYV?kՎY<'x]tZz{Z;ef mXnx hA-u0{iU}?׃j4^[y#bm<‡"]~ƎJ-<ذEize4 i] ^j[sUnjZpX21/eE:pk';Rl.[ßX?, Z4C5,*ù%#BKɓViY]BRh:T{{b?b̫5vl 3/S$zGj]>mGM  qtRƶxDxYls-$=9xY~ڿTr| tqMKrbiI,Pj f[Ef~`*"B"OsKj%%&|3_%^:AAr-dK!әu>fVOsd'j9ТstD}uΖw4?]aKG鑪[^&`PndeXg">tH Wo/=[`$bMbϜFC i?sC褽h2"`EwwNJ*4;_vs ќr /LvB+>CMOc=X , VGM1ࡇza#\ =_2 |l<Ѿ#GMèTsulȠK՟\>E$*VpwV$}Sަ ?vDrAӟ}8h\sP@VA͚5`/~gؑJ*H([R0-~! ל:!=v,Xџ\>z`C1c%tv$Oržp5{piHFlߏm )ʉlHYP B$Sꀔb VSlU)ĊȃsG6wh6)q*u@tW`&/4Z ~nTĠ2kϽ!l *+NUS1x\.;H5B%ETH'jQ;41Da/#'H4 ֫y%U?2 O(:agV3u'm%aAb%8vDb!H0_Wh!qګءE)4|8-uPW V{snyyZ;|;=_NXpA7$߽r~!ra=eXO qQL(d mcP1>އc wLD voUo *lP\:"M~X&]|)SYjM9,i)!u~uz:,Ea^Ƚ`RDNOO4ך~X:0`OuIӽ)XCWnwn>z9yƝKvzЙi|z5Cee4Sze: ZZ^=(fmA^=P׾ߠR}6Y$u<Ț"NHDbC\X~k=H_swW؍<8.X $Tjƒ3CkAfxN@r^Oɧj|n>¬-5 owT&Gƛ""$<7&(د~kaUf i=dh p:1c pa~4RD5d!+,I5 o-XpȃAj9YUp2[$L} 8Mq0{ѺX}7Ʒm" 5|?h\a-u64a]e<":jxE*g$(":Ki?WO9.ipA䐀Y8 #Is$녻]cUR#}7u$׿.:j̎?0 aK+`߰Tq꼁_AM=O,inpNa[ K:e:$!o< zDrWh:OPmpNsR֋ Cf~hfVh:5IYִi 0Pt[|5HcNہmSי6~M6qp伲6 dn lgHx 5{'S"XfBfT]32+ ?8kv ݙ5\<1 dڶ$aXJ4rY޼L$@6hKR)^KK1KNzvoB)k ='q)[H҈(&ҜUK'TS}s#'e8׎5M5oZX`y.Gs1hxa*eʧlWs!^ĔP"#S_h-IPvxi/H7.Y{E-jNOz].ƝRmVqnwdd()0U9}o'Я{eEVw^mFgˏXlҦRhhm-=VpE+@i =6IgmqtՒ܌K|`+oX3hɌ9xzx>HYX-tQwIF(ᛀA_RMCYGa-F4ZĈ0뛷Q| qf|/5pGn koͫ ϲc^rja)wg ;Kn2;qK3>xȧQϾP\{ƐIDZ0Q G 0 dvdt7:}2f?ኖ+ 0 ߴC`Y`vmk߸8C8jY"(o⎞$;H;RPctT3@tn%aLפ;_46nIIKAhbX?w\l!ʇ!9M.)dU{Ҏ P @bh=}ңV$ܜyFl '(e" U*mbЦDbR.‰ߪ(y5k_K2g1bn(1 7/ŔbUQH_2ƄI OۂsyGlF0BVo}_zpQVҀJBDba(4)NG5ݩ8,=swq0/ǰ"9Qoq{(cOd`&-w?. L1 E/sK:h!+dF'? y`"E7|GմUB0+Sҭ|w<G(67z,!u\ M4s76kl*}aCE$Եoc8?!6gcU+`rx8<ֱ@4e&U`xLeAYup {hLjDp$0k EQ\Yu/:hl')hSiOZQtwӑ<*m[tľ9(W4ISa=hхj{>ZrqP RI>h,=z p(j/U^>SQ-V ^p(Kj8K?ן_IRlHu 8dFSxA_L2$W['>$V3cG9M hk_x4҅34kN ҐU`q)6gC }>ƹT5S!`4P40@=:X/-x5f ZMJopE$p%@H *" ]Og 1qI1m併@5w0\S g^$~uKH8C kh|0 sm,>,aoO | jE*FMI+)JOkϺ ӓe!ѨOҚLos% xjFeGr%6R$4,\ck D&})GtPZāu%]:Ӻ]3-a@ 8o]$0 k,0hzêv 5Rr6ԉJ11W_s5YC*Mk~S9 Ixe^ji@Խj5 R Y8~ TkN1{CgLO'y^3$mԗZ8O"vP 6HRSKlp.5Tٚ 7&|y&s4떢 =BWC}=D;c~isA) nuh}_'6hH,΃4Nֆ,AJt1Tn7=CVg-!z* K-jG:Am.=d*&HmV)W"kxW5NҠ#ۄ釴=tҀHI?@V0P8FV|)J%ez!K1JɧvBӾBQζhۛ -yoVW1`L8s3ک} -csup*Qt]:]^(P ݚ Fz婼NՏ7+SdC\gYU&eAfG}a9=+:[9 BpTwɥ\D.ya `C*0oBq41ɘA5#Cg3Hz%$Z2 E3ș8PrnXMFFMͬDEZD4`T _AƉZs.'MGH(> S% <$wu-?GV)W2r,"BTM%sү1 BCT14`=6TˣhX92׬Ogߔq|DY u3fF+ FT"%~Z>\<%V)e\KRݴ گ/ =&jde~#/^Iyf10мﳊ5H5k&l2/OLF ^ݠ9z,1=6$C}Oy!cx3$/PIPkx |ɕzD :: [ gaʞm/t+.NEcoQ-f FdD0DxNI bH7VīCV犊C |*MBGC4`͡6piLk3j,3/_9B7б)8S_Y|"lBb vMGh@1QY7_oCzC2,zM&{DHn-LhQ\$~ 7 ~D/F${^;Ӟ a !,pD6y=ٝOIAr4#gQ)nؙ؜^B2GbsA~rjsǫ P M) ߀jaIwv/a` t'sdHCx&--e6mJ'M4Gqp:f7 (4xa#He`fbq,LUÍ#`BƬ5%>=6QJ2'tj6K)h+!2H wl&o ըYҸ-zN%%Z~TD"Z4Ligmdc;ɛZ Y΁ίW#+937m+@$ik@\\fзAcbuX&q}IUAS8m C/h(? M]cbq$D! p<IB-a6~%@LAL֜{@rxK%[3$jI [u]'{/()ngag@IDATT$YlO IZ7n4Rtne~ז/sH2g˰e>ad=' M!:~-AnIo)Z>S>F#^g,W/NN2lc?pR֫ΛяBSϤ-dy:bZ,"\+'jKe=T kZbIRĸp$<^v%m|>8=yOIuebe6yeÌ=rং 6wcV Im?6w"FI w8qX椪 مVRRuؖB4ڬɦ!-t'xr3 f} 1jB BRN(1Xs _/9<^:ƒ^LU 9RRhM #kL $*vo8rz\ 7l 6`Ki{ȲL,<+߈WNަc Cu9 *IîmlJnLE;;~!APhFoPHR>-T!)V&ڲ_UC!RZ6<2Z®(Ţ%ՈbЗ1olsq9)Gu~DIjx/LGZHfu _sg \MmR4T5dc y\Wj&JaR ;̫YXAAJz';d_NW0^'tfU1oլ_ޟW;WDGf a݌ѬU0XzmoD`NVe}kbR=w 'jf+ZL4C6>XƏnY{KxZk ԃQfU \J: !;R ({+$2d0I SbQgc+;1R帵>J|ܲc_#8ME^x`grTf<bӯ<||?Wo?O9Q zcyXۂ~ĝ/g7ra *۞vOB8>:VI qLfAZP5J9甠β}[)lsk760+m&]qbQU'ͺD`K&Kp%S0g 2s|x{X zM_%IMlfo#j1B1Κݙ)d[`09)R"X {NLd&h3c0C:)nUt2OU̹_LgSbR{Q$ɟ1F'tN@Js!&[j7(V꾼kJF>¶|zWE<؁o">xz^PTx`QȒqJ>lHީ1izX1'Fx˲RV} ܈C 0kzj2k<(`ʨ$$.}.M<8ud`$ϙ݇@G<$'Y{+۽)6AG!)D"w In-bT+R`Jrk60u1h 9@y`.Sۀoɧg.g5$Hu25hkmG^[1ؖn: ?ٵ0[UGFj~e rsʀkKBPTTݓ:^O{4Ԗ"Bĭ t)F]ؓЂ}1"@ X:fs~F+tqe%Zh6\3)]ŘG1^jk!fuVdqՆ!6>Hݦ(e3=1}(jZjkZכ柜$p+8P[&/TQa5BuwA;?;PeDMYTg[EAHG,\ʔ&"C1gMC /-4B4H1n=mԽ؜r1TH5E149G[.$!e'|{u~h'#r (r.j^WS$hmw#ck7|3a)οqe"\g%a5 I4w{jcQ/`27rXRI`!Y.׌ss{S5ER6աkc8+LAۨ)|E,&ao~"Nɕ̠+Zy O\,g>~3ai[V<2Cr`LZfv2*gMs< D~-@j߷)OϜJI ܳ2MA640N B3.bdC<RrLٜOx_N\ "¤8VܻuaSxQ.xFU؅bt*$sMJd T]WHᴑ,dҫ,7*VOd JZ k=M!nV_A` 3mN. V/V9a u*"9&ءTJ&k`:{gd Z]3[f`Ka&D&4CRqQ^ 2Bې1G%Cw +Cl&E`;HV G³%)(z7-#Rnf&}YDc,]0LV?̔?rĒq0 .``ƹl !mCFK۪tL'̨K%S.& 6 DH{ ӡ7ؠ7{BF;Pg$A1`L܅ˎcEz@Ėބ4a C&T&_RۀHD&-JON (ÝTlj95(n@U{Q*ET'7QsΡakHl췅!{>;UMK0UMneTW$u?24U5=(2Ph[itUXe-aqپh[0R C"I!B-7n9lVa AbUYfI(UL`,_}*#^N0{&>@4Y܀{pMe<ɓ8}QLAq}`|J;X"=EHX:+!>M2WCQ$ +X~OsSlH7?%,ƳC]g\Ups;{+ZMLg-,<.Eb$8\ĩI24eh @{\4B/? 'EnZ#IJbn]?w6OI bh{sԻZ|F-; HP%=lNTk)-w{V/ri\XBXBtC@ϕj4@RwZ"sJ;1kLݥN:)":Υz~ 'Bp,|\$O9tqnl8[dXP*Dn]T ۤETyL. Ұ+6-An2숫Y^ =.xCC,4lYMXOյ4f2/u`j/TvD"UDU=N얾/|಄4W,ï津8щrNl{çshwb a``ê,blUD bX^! MK%0@Q%u4%UOz(]z[3RZ݈EL KQ^"͓U3]MB .F0k<)7P_6Ui'7챆).0=0r2)wS$ٱȒEAU\ .k#$1aS̿㌁I]. \x7G1D^Gt?hPZ %GdmM5J/`r YD٢1 ;Y%(:+z9-CaJ8)6PC B*;$Ãb2SNy`̵_Gp4IffNO ;+%Ni{wz,cJUɪ8IzZ;x {<s)Y/% ]V5#eŜKPM9j[r0L\2-M/^Wٗre$owU *Uߑ F 84єm,@&3%DM=Տ `DP\yū8UgNC@:Z0%iTUnRk(QQKQA1O((+3%(V%O .>jtQg Wk,?.p@ 4`ed"bK;4M@kD @; pK⁾nd7j[!Y2/fx3l-umd1By"L7,ؚ+4:0–u"ޤV?43NP^4)DNaisSq|/qZFP}v49언bp+iw ljVk@NӢA0XcHisN0\=檧Da;p͠-ET`̧8q&r)li~uٙ8 ixa{ȜqVoCBeI&xKT*Q@q!jTA4K uMi$#E,A  K`9$иx/+2D<3ӧ =Ulc΄!" "fEwR* M<*q!%q2N%)\ ǡ( 9 9AY4AУ wЌlh\W4H1 >V&e*0^;T"A3ըhb܃(_# 6)CJɞX捂a?~(Џe&CGXN }]|7fz*k{%5p4%fEmUe8=*uqٚAQU.G0+a/-ZH^bD[IW7uc F8zPeُR[0Ӝ?@gAOږ:l@@8 q0O0 i/M?PaI0w%n(OqSlKqb'rQf܈+3 `SΰWthT2&T$dݘnNoض=c!l,.6eh-\#'$ϣg:6 e8 0ZS acS?5sP>[v"_Mc5Lf1@v4^6,XvESn2z 6-5 4Eocy+ހcKV|2N@~-c0#I4QK?3#&3fIX5|Lkdqg(8||O[≢q0L$LUڀ4RVaDPR6~b9K#c(\zzodė#RE r|PiVHPzuL=t޻Bl^N .?gǩP 3'?:NSm\A`1i^ͷE*YJ"B7ZA8.!zG/I.~ |f{YSt%ТSQ'u@[Ha;I8c?>7ìuE"1`JP K9#tnA̔s@h.Os>aá>}>f=~-T&l㎸dtU8 `LY$쯧k25Go]{`N"%c zC.:lu0LB'-a-{XҮtblQwJOV6SHbJt~H36 ̄8Ez 6bhs4 fZp7L5ڀxO"hre%~ԗOZ;q]Z8 Tp|<pd]I9" 3f2}E4ݞOg_#T^GjgeX<;KTneNI(hBӎmzS$"8}$aRv4fͲqՍG^u[Hu8oB7rBPJR0 D[;N-gOi:KnFcZ ,BRI% u̘xU;#A+MiC*@v ɋ+-qm?B'K0`nNZ( c-fUDt*zdV[} J`(ql&ff3jR-r#xA\qxt<ٰNO̝/Rk~S~c0#v{loih]jUo.Ɏu ʶAӖcT5YŧE-ylx-gg_׶nKQiX8͎2D Y_چb(.@3ԨܾwT7_^=찄C|nPv`8B_!u88nYpJjzU=G|iHgQ.YIb#$0`k`En_Vk93|ZquAt챹nMnjLGHsԕ=Kc+ _qxZR+kybeT7zІ"K/RiuL;:Q}i>Z-??iͮxߒ<.dd|I <ikX"l}[%tǾt(8hDAW_(-⊐' /,ݛT{MM4ѴhlP/.zT^>1V%hH+ RT,_#*)kU*r1(N.ف) 4?3Gd]_ֺo~{alD^҄>{y{b}#aa4q(hVù+d͋g3]mbuXj~ ~z6/R=] , ZUmf:ˤEHi2#FC'ՖT&H! hWBn<- rl@{0n,iu{2 ''2΀XU&[%L *ācYnd\=:3oqv9mpjH$TDmXP3/>\;˼ θ9ˇz4@p\)]D`?x U6}' ;,H>G  ]~XDŌyj`,z>?ƥhEMơn\r;%J'=-0yD`p `Z!CHbG"{T^-` 0eSbWbڒ|=t-XgVer}uljRH]8k=qe$"' 48HvZR6X2Vj KStjutx!xQ1xek2; L<|G-|(4lȦ:j ..=k^9{ٝ(JְFJgoSqdVGjdo.ZcG<·bP$K [2D{)娔e ^ ]W<jپܹ-Oab/92b/J}t:.@h`7YG^NN/;0-UZF"؅ M O/ .}`z܍d{:)6S"q""^ⵚu l+qZ!_{ި%7uuՠ4J[= Ɛ`lW'lغk|YU b>?y2{f\^W-ecklBQRDS,e!:aQj$ 9-yc[FbDR YZaQD2A`tjĥTi /~t"=LИ 5|,bF=j"%@R$~)dY(usфdk+r7]$>Q:͔p)>crډb;d__E&<d繤7ekp ؑEmʦ3dg#}(`-O!CZJדEk-ެa`}~o- ܻuY8~Υ)-!z-PiIR>;<ə)\a Fפh?E.i-Hlq~xrjO_'Jx݆Nno>SK4ev 8OW ȅ]AT{ǽldʛyj8 ȼoZDQh7~OH`0{Q1.>J &o"cC8G׉ȆU(x 79 Y]D O1zG0pf<?^s ?g L[&N-=f 4J!7ߖ\jO8 \G:c_`x  Ud|l炿+wk)D8MKȀdM P+,~:ex^sp4n2Dfa4#4ÝE5ǩuE#Gs3p<h(fO'I<Q &bh #t3 +l^kgIg: iLfT`E @ &M3)[r*A]ØkM|Qw"sQ{a!'$Fild܌"/88S`bvs.lrkYp@ӈa_ox*D1f)"`r +cdݢjVA3 y3&4!vx6TkS(mǘԢC*s9đ<߲LK}i:Hdddo9xSǶ.V7xO8`a$WK\[jba4"Qu7K"b@02ϏHZ2+8ʍ║8Hk˱10[GbKHFM@ȣҌ/\ΚX `8ՑF`gL11߼Z:# e!,d ]Z +)m3i :=4,ؚBtNvF"G*JP)P~]ښmNE1k+~k|֪"v^gǛ Bs,@A\J1BHQonҐzW3Pu1`'$N]dF5+ [ *S^,f\2tL0z$9TV4G; 0lil}rQ1̵UaEԙ\m a-k#OO첓11v%*!A$ҋҌ&cib7rL5|RE=P[ڋ]n4ɘŒXz7U^_([X= hK%ZVjqB mbE>%'17wՆJ]17v$mZh%ĭϧ2%Qt[Щc*?ŕBB5h]`[T*4M~D] %$$9'AKdq-1h[ay$7X,Jglpx. :d$1l:l>-QFsh%0ty52QYH)Pci}QB_Vہf/WՈnAW&mMM[i 甴T4ݐK.ú!tԕwc`Patnc$%$ȌOqzaN D)xOkFmclw4 DzUOZ3m %3'"~)QVg"Ab2Hhwqb8)QuBCPJ ̈#V82 VBQ# ̴/iVm%Cʨmf.)}~mLhp @͗׊cq^ޮg瓒 AFbDR&G*\| 0 {^כRN a6:7Ja/~!)jwv9^Ē*2xLuXs0Dh#bc8hn$SW0_ԓ @|1?3= -G;/?mi/`"sE۬ kubΛ\nox@P@j!Y#:CQX?;+o qΈ_5+pTXb oc7p$]Z>k丣Oy Y_ >&,ln r4z rN~hor#ͶB;DԸp.$Zk"Z^p0|є7߂DVda 8|bRa0^D*r7V+2љ1]PWs{UYmĆL}@ZqݕsoCO:>NaV1bӦ)M~a* j-VUgtڀ /etDA1BKQl?p?/ѪqzM:v $xW%&:Jxyɔ NҖ "O:>f%fq-!"1]FkYAR穚{w)[0?>N{Y$4\J\UIQXwN2)1}qB&^KjΚi4)g(fsp9 V!p_in Z[ws L_gW4 % ?-7UY'EQ= !(/F&31^^ jJ x;`tf\_1,-y@"R6NAQ &c'O25z%Nz0Q 0xIJ!*@UyQU`/@o|6!k݆Sd )&*p,xY N ;WA8ձg3OE!О02( Q r DKSA XQMGAMgIRXcPJo_VLSP o|#^E܍cA_mWչn>/JqEvB른C# Qi' uZL5?(')wLdjf([/t< ܋7 GI[ğrbZ&IK*+kHm;a%4oF1fRV__zcjRȚ8 \$$5S_ ps? 8.%,! !M!'R!+ 圐mM #iI%Cc~bf"<׈H,ÀI‚ yC<Ŗ~'&%f/'QHzF^[LuoJ Bexd TY[}-(뗞ʷ9y$b`|I%i543ۣ~ =LO4 =dhaGxf#(q(Jw5̴V(yUH0V4Մ[{+%Z9# ЁJc5:%X3dS[)UÍDnިGe8⒉IEh淈Ә^@IDAT 5Yi=N&FJy]şƵxN [cMr v $`S2Pz1K!Ps҆d'ҥRte5\* ̔@28iKg\5#P `;o&ӺAdb}B!WRGR5|84e>{5w<4N4nlOFڇESV}׆sK +ve)8g}<-![z(I-PF NhNPzPM(}l|q<;{W${P͵@zvd>)0=ʰod @' T°\Ы3iH`~ ėyeIi)h Lr; 4i#=*BO|HAUILn7,8!Ѽk-~| ,LӸ:QΘAe XE0ٟVL/F?&-V*?DGp! B[mjjߘ#UG;t~mNōYĹe)eׄ*Ii0 I1U NìHJ|X瞣uU<빕v&AS2~RدI6b>DHj Z%D#yle艗u :ٖ\>I|1XHiOZ[6l6bz8LmC0dad>xķ S)cIlHwyjN ghg5Z" %I+jp&Gzt9ׂ9sVMZrU-L Wa<H-R hqv_HU 020f: /TH1tE6Jahv,4K벤 H߀'BOhd^"7m!%ZÅDt")t;0RSNbT1}nP.nep63a1w=l4ctA0~>79s11u!2jUUDDhrwxT|ִP"췎4uw0I Y᠎Fv5]PQab9x& ڸ`q 'Xh pL[w!?,yG>%_+)MAywMq,`B_׷$@7{=`/lTy0i9L-Bس)dl3aa-ÂTݞ1-`y\ͥ0ZF9YI%M(Bi:<x5Z3TqXy|ZsE("?2@O "*v/EBq. y0ƌa/.\}8KMn~qCbGU|JacGP#JeYL6 86an e3JAץ؈MDO#Ö$biHZfTLo:lf5ش"tigQFj ]g{QWVG`/7'QWYlRF=S#tJcCbiKCs#;;ǿ~ k[~+O^xaH ލ=?oZ9lp|};|& W)s2mGkhi}3)R(AyxZt *OJKl89&s ݥ\VO,KȤbud8͹icպdN! h9U uLW_UcV i,eV $q9TZ`ȳ}{y^.;uu#+O?6x)()l 2# 8IY>=XEGdyw7';&Rm,3_Q.tٌ֚mB>n Sm?p#~b׿ldSTt7ovw^?T֎ pLbԴ"',jn9)cH9+E+w<'X%zvP+!v\ mU>;YB_;}Vx \BNȐ#wq6`:VÓ|S-L$t愧j/`6 [{ː}, W#mu;_kU(a> {P--cm{DŴx"h:+&hő}2<%F_aw:fAiE;QItD; \ [ O^"U=Q7%ć"%%j)i4[vEcc;p u :tPSEMeF<Ms[p3+44b{[E sL!Jk]eOҷ:E'o;tH}su¬Kؤ^Y3szZ29@ e8U XVp읝/U-JrBt5̮7!Ugx@i+LY=T26 <<؃&{^!=|.e^=kzeZ# n|O"D_<{K-{;N)/A yy,I Q/Ğ$ɄMTS;^?'>AR]L;}Oxtqǰ7=?Oz6f,MgMhWTyJ)1|B.QN/y?VYpc`u3z,. NX5hߛT.l$P< I+%W1JSs}b5vЭQ (~O*r82U^DNwfUo?R[v' C@6 WU~ioP^ԂE]@b[ZF$x1i[Wu-M `1 ^h܇p'k5%ojLm \]!j.*N[Pkh\KPWJRw=|3LeIr,(QTm-pj2J(3 ~N@" 뙰ࠆҹyE+/61("lt8u&6t]FTq1Z,ٮx_"BU:$ /[)l*E'Ls%G_#&JWyXjjVFCI5*r^GcN3ǖZ߼BmS<>h5pf=f ! P 7͔-5b]$>18^(R.\5šߨ)DXb̅a ^}rN5ENZ4s g\/ُjC*~f&ݝF,G;ݴr_+'2X6gAZ^\P>ZM.6rǨPcFy%!?JnV%|e 6۰ZË ϔ$N܂BPzΎsćN̋nN3!gdgLQt葌g5+t);I&(JQ))6WKMR1[ 8MrSby{"yv|]s2r+̚JVHE/+ |w7˛Xt Rr  UtC0b 2tF T8K W/{:]:#"xh/v#vHM^,GPi' ѳwq17{-ә$s:ǂ-s#m+Τև:W%Bv.o(l;2j\xs~{SlWm+-UFٟU 9orJ,V #`9̙j{ ,J"OcYoNU"[U?Ӑ.ۑONꄃz '4ʵ Z&Ҝ1,Ǫsss|4tT]Xb`>FD*\3D iD&3v3SC'3xaZwzwU]x1z"x.ʬ>h;@lZlh1UkfK*Kp~hgc}AAx'ZgXΨ*l^*ۍV,CT%97&͏.$2 Y9#MZj>0;mZ}#k1Xi0b,c^;3fO٢.vBS{F:^D: 55 ܼ]%h3=ۀ.xM #$Oa}? h6kYbx|2L]bgDj/ǛdrU' j yR0,} ppWgA؄m#Hy}mA}k0RNHB,I]()]dp6SBT{ԩ*[mm) C\mШȕ.'ar*6RX7Еʍ%) Gy393hӐƛo7m@a9pȬZ["I9*$G'ڵ׃ng% .Oኽ1[$+Bb00բRTqa1p; &n6]j~zeB_y[H1^{ n es̽`ZϥSr2_2xfURȉ!d*Wkސv:5)*=`ȹF+F;f!1N#/)B':?"rѣ?r(w;Qd- m4g~AfLF?Nqј"֍HER[_Kb՚pC٢ 3B3\5̜iK hv( B&g Οj9+|T`7U/fCwª~=TU C3}~c[9pRN8V3Bi.HWΦ< KTp|nq65+yPիa JʷAuC+b~#l0<.  A&-@ h+њ +Zhl%1XxR9Ċ2a`a2r4@v).>c2=HBx.[+YAhƧ|v7֯~*ENk>jU@OVNYX Q7F1(&CH"יho݌c6OV,{'' BMd1pc's"~ .Zgfk$݉ 붖6I¶ $T3! H*>f+^tYЩ-aT9sܺ?xb11|iG~yuX#p)F35ӷ (]"r@bk MyN[a2ƪ]9@a) CsIuYqE[/2 ѭe< ?V> Q͑)a܄'ӭ!3 -fđCdp .r %NOɯЄkSɡP%*b\ćt'd~Cˡ`r%"0StFr_%S> m .NxxJ̍g*Ē8H&lUaǹ(찱ÈF *@ e؋v0PΦ)(Ӆ73Ѓ{M.[\J A|\5+&3َ"A坹bGqR7M eZ8hCqE$Bh98@0:\mE6'}LXxmD|x 'ϒsNr Dģ U!IKˀBҌߺ7#=ߦ?̈=ML>hvM f2b-? -w$ uC1Ų>pqWkDayTU2dNl jnvVYfq҃BI0LZΩ*M/ }uAbcV!.G2mT@i:i p=҈}^/>)y m=53Vq._`}k((bal>3(vHI ^=.k.GZЄo9CUMm~ <^ț'zh*7Kgobؖb _Ƴ<KSb N,2N#p>⣎n.fVWF_]6)~@>X fm_Ep%?<ͳ>ިN Vgg=9naps?>CtbaOJ,Ƃ# K.wXRC i6(uWH}+L^LӇsྜJiRoX;>>86 ziҰ~8duh75 FSOLK$CLS#B6Aֻ=Jr:Ô;Q?l{2#oeEf$f S/Z 0&eL,"18}@n'Bm%yP=Й9*!Ͱ0 c~v_ڿm?7rxj`iDJ^@/وUug*ЬK6m^c#(.G^cbExn.{;4m!l+tݭOgESYo^l@=~y 'O?^8H CtZrDU+1mzZ&a1޸ x?? hփ吰9pp_%X%ղ'vPʌ r%5bzy0BEMծG?XⰌ}ß{Dg{tr& "ǧ9D5~Y 04]=x1HJB`TUWbvYDrQ,[p }/v _±\G=t@S KG$G$s5]9ö4}s$rҔ_zЃS| 3Je >!mAJ@[_1g9 ~0T<<\?0J2abٯ˥0]K}"&xKZEHrƉ__: *c'=$Jγf `H xOlIn.cbͧ1:sq*Q.Ĩ9,ͳ)8LIJ%5?U=ċ98l#\RyDЌ8f&G!_S@gR!Ye'gN7+?|,kR+*&Jsn_ Y菖0b6}GbȎ /:jc؏>)np q ;as47+7s& +nY™6DҔY5Lz ) 54Ndu^# hltH iTRrI`+aj.:7p*d*㿁;,rlj=V';&0P YOzТ{hgsbWx,+ې8׷RQE,ke@Gdπ[|"I_@QgBiC:F2LD{Qq <(EXg,Cj؍g$z&kC Fa T͂A􃈦Kkup/=Icb9}}8-}YxQq{--#' C{&@4Nl&Ko;{4i}73;k܁4Sn5JI2wf׉l-Kj!Ɉ01O6.Mwj-ݼj(4Kl үJC:1ajpX2!PO4R6'mK ;m-X.tB bMmJ$}(*a藍k|!Snqe#d 4oY7ZCIU RVϧz5=*rѼxX˜` KfH0\3Y84AODwoT!y>K)WS~0ɗ|vFL2|r:̒^ӌ̺AxqjGYMVZ7/1cw\R Z>F6aOċ6XǑ _y,[ܢD ]Kx.)V~YISc$6$]Rz\p)xpЫQBX:VHfOpV4]|צ0_9s3ӧVuOv/%!:R*bgYAZwYZ5@Yth]딲S7Y4X?MMg #b94L 8\:Y78rox0WeIUBMҀ&sLh앑XEη+Zk2L6TS% ̐T[>/mqDŒ9ԒU#1cIBݢx~{4%M<1%M+2SƁ`荽n0&3b`4ÿafuIZ8 bٌ1-'H ZR:tՃ"ϦbTwL $KoFVUilkuH %!WN[.` @GQ-F"6t2hI G)^Fo+aL1Ujk^|i1|HPpt3xvdtW}oGN7ߟ-&YV~[o*5Sz P8E.Ğ:.~ECl!ZUlu/KƢެ_q2NBI/[΅w8NɹY ӜW#F=_B>'-x򍣱J0`_ɺ̽&Y+ą mT듹^1$T୸^ q a!eTbဿ~>]4P8i0??UcmcN+< x?863~Ox5D+)(Q˄e's@ şśG:)DWg4K}ճY NhJ+BZDt2`>9gYizc_R( )SDG207O⥒>V$tl_TlHG54SfW|twݧ<=1j6 P÷$cbYbiwx!\UԛoB$`GXjH@n$X >FRB"tMҩ%f(xvb kHU#w4bx7bFœ03`)Pv`4Ea8AbU-v94NJD2?N"^Rؤd4-cE;jp"W~roobPh0a#X.i ZY`1"@Zx̉j}yրb]$$=t?К3esnNK a~"{34nt• .=&y›Yh1ҒJyUsRքkmrUzN;kjY%3" 1, ro[ ]Ι >&1;`F}ul5&u!n'ǔ\ۗ(}?tHN9QI✿آ\ϼmvڴR +¹$#gT}78 HY%8)U<g|aF1"rj+oĆYfgKWɡ;!͞ DYrS ɂdr=H;IqGx"  Ʋ)Ɉ/N=+WY,g0g]`(ďa?p I~$p*:] Ԑ{P ffTs D)Ϳ3O /V'ޚFr܂; `%A\,#bZ;܂  NK1q F H40by`FtUaۇVqDWG^o@1I;\qVi33s'a-ͲV%KwOD(2F,6wG,~-4V,NuQ#UVj0ԣRƉ;&ؽ}9=\^h9kX` 427Œ,OT1u\Pzc^dATK!%Fi xs~|@@sU;h,0J*0MpGaDѼdLhmf?^.6yH.:F5^#/>!"`!a"N$%l -bNt3J R$1&Mcp2=D*Tt+1!fp =k9R5a9P`7ꖒ<%NOF2z/ 0U LyNtw_det r3PD)HxWD橒y*0䦼qqƚ襉Pak@!\u qΣ )tlA ~hEK2@gEcI]k`C~>8Wqzj\3^]A14ũ%\/Cq' 2J󠌄rM`>)v8R.l60Teu'>Τ 7dq&6;l7n֠ P!. ڰɸՔeQ?T[m8T.$ N#wAߚ6Hml.-LriM''%SI}[ݸ;)-ŀK9$Y8>쀮~K۞L< Ft/-^ղ3I@iRܵvk jSp{ %qm:-L4 .övkb7J2Дc#2lhZVQw.=9*`rt0tc+qHo84'4Ɯ6F4zA8 63b'藿mssAaoQb) o24OU楴 ò !ҚJ2lhJ>^1jZNLp6F:[?RlߕYP^2 1[\/jν aGVh8xl=o7[nrXz=Aek#``Kh!MbpΣiR[6]A|C*m#o!$a4dec-YG|K*3ت?s_S!:o !XѻtFZVf?nНG Lc+{hӀ^ 3I5qRH2¢)Qdg+HiH^ZV. ͛ÿ2xo7JG > ީi9|M+4z6 roau&:Sm"H^#-8bY=/2 &~Lm"6]`o.J33+f@ *T$KD1j# [8I/0 2 (P[(<ǥp+;>SMLa 9"ٸz\h1T(@ /3bW iR¨hXD=UIyfvv$K!ga *H7w\mRUexJOƒ)Sn{qd(&;f#ֵJO̜cZRS9Hsi!ԛ KaKBB=9Øc91jn8_oLMA+epb /!64F jG1><'x/7%ΒnStω4{w[O!L0JQa{Oc&; %s1w-5_jrU cfiR#7*^WY.Nwm&4F3ןe:{S1^Ǘu~=r-B4xP[f@\ Mmi ?L.UpLd41`Ptڻ%G'[pÒKZqtΚXGlx~#<ƛ:L ɏxdfXw) NQC[\j-3ON+t 6 T6XF?38t3BPm.$ޝJɶK}j-:AH:)46Z< /RVJn_M)YϦg;na!R 0ϺGȉ@:Alqʘnv21ѾkYt6 '?7۪zG~<$8Ҫe׷vlSK"7áv]VQKYCMLQ$Jl0g:qm$yqL2a8r*'1?;}{ b5۽n_\8Hdi*w ^2vhG= Mab,XoKlt!?Vx3J_v;o똋F/QF~g*%'1T2AlWa ߺg dн-As*ײ{fc0~Ml@bnz~dh˯iS.O ܨ-}wnI]_? rAM7d4:b/I %I܊~ !!*pWk觘YŦR=S-NؕN~fNWcN`*G^`*IΨd ޘlbrdzD;HegSb= Cfc}Foؓ#l?wof`7"&SO%&ɜSm'o:PyBel pN ID 5QqMyl>mm;!Bq#;{wgW >[>pcCzCBBIFT2 l 3WkD-}ڲ%UlFMn.*A(cRE7Ϯ6+pq& i<iK2Db1/D&NAu,E~nzKP%Q@-̄Q!=r  yd9/6Woim{$ܹN3 EUX\$Iرbσ*,OғÝֱ?T/DJ |d@]ISsWh >?}ZtǂVg]z*$MqX A~ݪ5<+{ֆ&j/\L*$ҔE/R@L vnӆ3+Nqhs78&\ŬwQd yЍ(/8\!/@<_hfaEϣc\u~rF @FY(,7Sw"kPoBhbc\ώiM]kԸ.ˏ~hř -;.S핶1"p)v:8g%s7#-|mw{Lf8B`")cw ՌAۋ+-{3=pX7rnxИubhJD|HfpCoWTjsPD~b$%0| B 6lɼLz94uHщFh&y寐7|t< \cX_dctke[ TDnT/F/tT 68ppb'Il {JlpzŇ=<%ɩ:k'\i(pc$55R &jIC){k d SL1 ţ49Q<")]DMe w{\A , S3nEj 1\ӳ9VBBq1@A)bdRw$ rP.<d?#~2.A3uw;~p$ 5W$?=';8 N |.\_\DGuKo+y] N C~(;KA`oT's$CxaL0cl2|n7%&p;a"pԬDUpSH `RQk. ըgWqN[Vb)f@b8՛I‹Cі$`LlҨr}" FP o_;+KP, ?s`RxQ#=ޚN$81`~=~B[K |@x_n4+S['=)#ڃ\ 0zhl.& .\Ҋ8ӈb匱J/VhWU 1vc[6ʇxvH`)4YV5MJEkkr"5o:3ZQGf>{,L?Bki}/=Xj@ݎCwkTJRz+PT X25&/|00t;،]+cH-qވN9BY5#j-}Mpq8B;_tPw_J]jk FЎ,-1(釽8.W/*r̬Ѕs<4G3+Uf `a3cc g T`ݣ g ڳAcYVOx#ZjHm\a/LHŪ4pv|ߍC9 |$KR.#;D^lU%ҩy>执N]C|-HƝJ8]B}}!"aUv' sSy25),FE U βťv;kA 1f>t:.r~~3t>Ll"sIFalnlLJnǗJJ&Q=?[_s-IıR,V!jQ+-D1t Wf!˗!E.̝0\>&P 矌YyR,~ ?۳p؞PeRΜ6QIҙWIFD<^ұ,'`Jƛ!(h|:ˤVK!g3L,Ng%ɦϋQ ؎[As~>(Qc%}F HOбX8 ƒd \ dS X6;ThDU)$&z cQE{XJvyy">nϠaJ*%Rj8i'6=4pB(@qɭU6$Ib*"fM?5 >_4`ʀ֣m]'Y=M K!Y!ݺZ69ѫ](ӵ L `hαNJmD7[MR f' csUq[F/x1׃u d Yʕ . Gq@Y';tPX[ 1 7H4X/yCQDMJ4p-%MbƎq h/ * |>7, (!m7S<Щ8qYd x|HVJ35< le3L+DXfGC nw( pUMlQVK.F=@J3FTO2kʨ>4(NZĀq16W$xV@ $ ճ>{H seG󜾭Vb47$ 1;1F`v}+Z, #{IXVyH6 7,V^KaʲE{@4`&QRiC!E+6ZBs6 1A!騘:D &B[A@Auuql,zm=.҉)3[ԘH)h?&9ߌJ":_o_b7/wiF< ba-@ Ie`g k aa; 0>rtH+M tD+qj_H`8^5 '&)1h]9kYbD>O):X\lQ![[Q<Ų=cTq HY3OpBRy$c|"%pY,Z~fen4˽>)0(b })1xmX̀=5H"&zԧ Ӯ9NQHP½ʖ)\Or% 'e #`Qaּ\ԈVg~ؐ2iyAMkx"e{ӿ@͒ $0-G fq.!M#!1j~d <`2o\6EE%n]X `)2ɣ#Q~H8k^tzӉ^Dc]<IR RH ՏY 2P ͉Ȩk׿Ѫ$2n)(<ag(@%!վ{5k1EܘTPmؚPiUG*>rQ]*aJUGWGraF zWb\t\dD M. qBiFO|fk,(Qzu!^\'x bzG&)ǧg1,kP`թO@H rF!8I%=x,%^LvOCO5(e #ze@ Y2h^(xBJ%>S_j2]yZ|д4U 0."=R;ז@Uw[c4p?'C.&8F9ᑈ~8Şp!ŚZ ~b/{^ĢZH\S\Cch'?6HcQ?4Tc8=W!:͏]!^@7]:Ix=)#km~Nj-S䙠x\/F4&X G5ٙIs\tY$\n wThgnN zUY?ubZ]=E=ZX^ oq0Ebtbh_Ph_$ \X[RmQ.Agzl&-c0"ņ$|F/0TdCO4mAHX%Qlʃ~8~R8DĶEbF 14B M,Uev@ x񊨁Mu؍a_nE~hn<F#Wwk\o9+l&EoZ˵ic;)Zc#Iİ8QQ,`$3 +*Z+ Z'cxP{~Bd64션I=a=B`hXb="Ut%^dc ;/J?NO r9pu4Cn yߠr #P}`q9H4G0/1y!Fvau @X"&1\A@CvIY}Z (>PčVRJ4h7{rr؆9 SyޡV$(2~e/''-C957HMyNe G8gBS!Ķ) =`a͸򄴉)-%?df7'-#[5s*9c6J=pKʤ#s*FnaF,~bkl 7;^E{- 0UFzF9BeB^&))I\>=eo58Х3y6X |jHgL ɺܘ7Xa/zԔ v9;9ߙEwe9t %L[R"T l_;Vep_6GCPKvډi  ^j sCEHKWMtrC@bsqYI=4mw?(K% Z-Τh lIxn6]iQٓZ{AƳG@kl8_ Zu~ lzVBE^Miciɖk3U?96,SiZVWo|~qPB8r'2*CݬLf%V5xGpCɉLx+lm[KC kDwi@BS+I Q_hc+XF%SY1@UI5^/.1>USt`V{u0bNqw Yl :KW DE)$q/ sc{:/WdfaQ1P( 贈W7d o$Rx5j 8M~hZ+Ko_ag甃sa膜"Սm$)qZ/OMl0Nôyj.֎S5DHU^ޜ%~Ɂ{I5~(),]mrDr3uitqŃZPmeSJ<˸h4m if֕\J٠!_)X kҴioyMr}eO#$@žu2I+"r!buݎI)~m 5R MIGوfC"TfHelq3䑾iKAQ[}~~|r,؉9&%*25+;3X4PTKZ9r󾫆^zX I.rܜ  kdl bbDXVIgk.pF9T+47.@@U dʄzbNLAR랭˶ŎS 0γ )xl_-%MK͔ı*i/{ͤ&8ߟri%mQژ@:֑}nqqb=y|V#ͯ>",<[˦Yk(iaHN?Oq~{ݯ^Xd9-XLoo bN ۹ta~M_e]*oq]10 Ώ.eB#96hw:{wFDyrX3'"h?̳YBe9ۓ͜J.J,7ǁΗb;3w^_ݏʒ/co _L`b &q5se\hَ1<:HtU_,#I|/z&:\1|.VIWaF,]L [9,(+jw{/] z^on?OVEw1;lpiy4X9c0p(|le]j&G#uvn+XS,Yi}>Q˗$B&u>k=NVs: #mMw3lK/[%/"|&uQXVujJ6{mu"N۬4{פM8RIeM3 :dwL|Z-EK֖wP#͜.Kuf2$ 5r]['Kؖ|>D,õ=cPZ%SK5* 7hƻm_'&(Cf/v@fn 64MaW rM;VGR>&ƛxb8:>y!RrF|*#9M-nC3*G泿upF^J.J Ea nK n^o rlZB } s=rT܈ʎʱ\Mߛj4SiBEPzvJ H5D>,E{;QV]iqLH<'r?]Og+",yȺ}ǛѪA"DJJ5nLs-La#P0Ohm;yg+0ob{;*(I?D4 6)!h}jJ ghtL w!"4q4`(Aњ"#W.7`l|Xr"K&L2ᓍ3%'`< !Igvpmn.='VLk"0L~6R,dO e@;qicF\f;ytLЧMk0-LƂS }1@hd<i=LY-rgSWO5 yh21`ۄr$ ;QI81!<:'SZ͒r:Ҕ;"bm]Q[LTpM+$(:zخ*L %j)#wW8,DLϧ󴆊]"7AbϞ=_܆] evZln8j|a1HV-ydp0o7Ĭvk.@ќ{3e)Rxt_* RSYhEKBPRS{>S.KE4Goffe"<%g /3Na}zIV?Pee5Do&YZs!R_PH}Zy#Dҙn]Ҭ@-$("s*ԠhKD#3~15ܥp(ڄa܄uG+|G+Cg-Ƚ 10P uxAJD20Mh[ *LYrqlhະeJlS&[ǗZF > e),''LrS(#ifs٨(:lQi Ks."TL˲ʕJv``7h z[+ è|2^QplL n }X࡙V(ɔΪJFSO# ;\ٓkĴySm5ZbXF4hVLg2'dz}^bQn;|8TdTIL^JLy+5BN囏ޤymg;Bڷ##mf豸Ձ"Д,$H4 U 9E-OJAk2)U}QޠI톮ڣ!ɮXe\-UGir4k+T A7 E'oQ !H6aktQ6]KߚSu ɍJFL'Q)D,g ^h0 - sJOzPo Ғk|YێaƁt$G K(MakX@2F+%fK}~ z <'Q@42UkaA}d9@89p0MV`YVָ1pz6'bG/y ۺ>SmYcf@-G )*l1:+9qq- LߐC%7PsP1c6j6I4B >Ir*<74Nh|pnb}=΄2mu[.gmHDCU$@NuܖQ& Ur|{msުF;9-cEO\B~ΛFBۆXkuˠ4:V˶NDaEXOh-Hg_xWwر#hX")nR펎yk$Ag˒HH$2*KYeyRم#lE'`0ff6 n@IDAT>jjUá0%q)JaNG2ˮ-J<{DW&YUbC!Bg恄~2OJ@,2夜MRy#Xc[[ɩ||(X AОRd,/Ž_lZ=6'#՜"7B;U֬+Xy0ӈn~a˥"aZlUF(PGP&AR7Eg*Oi>z'vFmdҠn FYڑ:mhEc|A;3uHfr9t 9$n&@z_&.sc{LӘX+DuAqynV^Dz#Kzh ,9~giȫrmb7%`^lD) q){ebY̧FndM]8 1rJd=GYboѡvEۗe4M2ʧkloE*+}dO854bPf %yC ]"hބdύjTAGݨWu`8(&sPmR䋚0^rsF$`qRF$[+Ss1#埚RUʸCR&sw2cXD-LI AB*@"{%|С@j*2qZG"PM>o#K3z/sm6`B / 0G53+]fO&XKU~[jða2{y`uއ8ڀF&Ѹyhۀ,MYp ٬3WL_F᮫\FJs* µj 6O2x!?.BSkک` c2&OgwtKeqfɯTuڟRdVx<>('FJ&{32o~g :R /#/a˷*,ud"ty꺿&q6l^xsf8}—UwB(ta6 'S"W+EH?zNZ5Jrb=I1n2A,5F%YF6_`I Kcl Vmu0T=k_Ve]O TYbjBM/g2$==։(Yf\k]SIJ 6?}_í M즦"/1_NZI$poշO$}duLOL) k qW5S+kP/GGxȪB)*,Ern^B{=&)XIr[`j$hG:3y4%iIQL'11 tG̟ny@RpxO3v+AVT P+ZLW LV0 Fc±WJϫȁ 6<)@ V/7,;jDj՝pE"(-vI|߯[o%,a2`0@۠)w #'c,=CU %7ՄrUm( 2?4p`\ t3Gc T\Gb==F5NeOוS ;LCq3bE\T#M#+x縹,/T`tLs涾+BA qD3.W Io_5։o1IxvbYwFNX8G(U }i<4B67}a]f[6yM#_;x!nKiFº:&K.av鑜"&uB1WCZ!N=ߘ)WKPe V]bқr011hZ8UUo~݄$lO|g{ %# - %"5"SiW5J3$|pHqx_?w \(;36>#1uUX;{>k}é2 &ZB.J͕GDƎ@<_^}0WE NշrK,Y>aeuw&/ڀvBm[k TnDYQ҆ϱ30P+9VFVN,P#C@J=B}Hq}`5Clt(M~@7h,5uѰ`7~gk" ^3M[bepj)?ELqJ!U!'Dz;~'c]eoq IHTJ˭\Rƣ>ʞ̿.O<2JEIy`E€Kx6cq[#8d:GGUT 9eA}@8"+px>xlm°b#a%rUx܉LӍ_Hh@ l:CH{! gG5 jm61}Jh6Vo Cj+ MіoK f2kF Q̶#F)lda6ry3$A\/G^ Ccd%W73v*?Ecb T6EW/N\W]'7BQ.ʢ]Y=˕4$ )L{pVVC񥄐-9PLkd=7=e1Vص žY 舛H)~VxJgtM-krzs7SÞ']5nU[$`b\:]_'KJ|(ghI60󏐅&:ژ YT5ʅ)%7z& "~d2"?l NeZebum0ΖWs[.p@Np 5N'=1:RNk.&3uW~w=ܼ!̣ѧ֖EVs; sRHZwdrsۃMDticU4/iHkyP81V12ER_HܞFq4ei-zeg+q9{JIa,QEe-0^ǔKEfu7k}eKtaQU=ܯ Q9md-=ȳw9Q3!_zCxI<=HJͅ{ҴoPhܜ ̴üpDz5Vw#' +{>->aM?,r)|N<4=EDF0nT֢X2 /w|%svyиCy)5=êOCo7j1s:* am*fnk+OuɐFu[w=9aH a<܄Fr=Sg=Iuz9SnrO;|JgL`P1u̮Ft\5pv.9IEy=La Ym]V~v.Ǣi0%*??el=oT]QP#EwmQMĉ)*`Iw"/{woIxC}auO.v/6V)%IYKv`F4N$,݌%A{Wh.0vã|Z-(}qXHOZ"p2*Jg,%Gl֕}V/{;o#BgUx|tolb7kV:u#B{ǖ׎]!0N>b3+^ ~ŏ"ߗ˟.(d@ -VJzJ'á%(ߗS-_d_/?V=٨evuWb !V3fUTC6==iT҉'LO'y^DWOY}bL*Fė6La(cyd I8yVp -ub<^oy|ܸ$wr4sSE5 ψp_I:ܱnTygty̢/Ed~M[lIwrx <-6_E>lߧmj _3_\`ٵYueI޸gƌ5?82ʭ-g:'{"%toIHbоE(P9):Zk=58lqdncgza}7o$CCI13=dOeP!b+&-KDZ4DhwB+ث!.ΰ[l/:N"~x6le.\>q =it!^ G EH Rt%t"GTa,b[[ k4 V<RNDz '>hx9g߿ÜvCY@Xa[cN \h'UiS} ]cD C &X`a ~* b+[Ks'C[!!C/!?Ň\Eda/%NZ OR6I#y#"^̑jCZ8n$ }׏RCOy±yJt'*utn3P x l=04$/G$0׬tb^C<Jen#)Eᝏޡ,5̟#ꅺ8揉s$e﷣Mh|$=]cB(T*@!7Ao{.07|5Pq\d2f0'C]T\u V|3[+Wv+ u=J|D?m#9Yz~yFB>2=v,isgjXA)Js3XňukTk vDq ѢĬ +)KzN2 (iK5Au"@' HXٖWC SQ,׵dFA,;9}~\;Hut: ,RsC\U퉓w&ݔkANe. $&12)(8%A#cXP3q,J!D|"uETR?43*})%=-k{vo.y$dmujr&~^qzyJA cxKXꢔ}Cͭ\U93l`7W6_O e\mÚHccڼ1ZPk[)_-F%5` O0Y<͔Np=eE\ )X(-D(Q:< !^T9uIL'L%+G4_Cnm_=qKu$`FI\kWJlVQ%Xf|N`V}Q<"-V Ry)ydi.UQT+dczMѵz+`jH8'fj)תC6XӳT("rgJI:M sđ \l2!pjj~K6RV2O@<ej4+wD hI]QV)M#02AAa|CոD<`ǛLZP)/QRbMwf.ᑟɹGp.]Lc49za$)`M ZzoW8J պ 6SdA3 Ci 2IւX&H564Q"l0#d=8 Vƺ =K-J58+E%┖[F@<Sb`?-t@Ur`7UUhadY7VXƤ_NNqZX5 \Rqۊ-[P9O,iɖPkHc@r]y:d+e:Dƪ mcX,?-5`h+f$#pVI0m];yY 3u6x8$CL^}^-a %(ֳ1R_׾@@sʞ+WM%uΦ2YS/r.2cdAZӒ(NvuzG *2H!K8 e}ņ НEOk{F~`P'(x1Se4I˩!!L eC2l/ 220`fx<`JC ,76unecH3Z0k/L%0Liô_9}3yǭY8!41g`SMUޚꖯCC /lskˠcZ3LҔf\}r沢|Z C51Op8%TƮi^A* |.PܿJO݌`-~$HK*Ѻcd=[ 絖@F{b-M9j±1R4/jaP=Nmƫ'#nѼRgU~m8X%ME%Bi4xs_A6V V2Ju#\egǎM4L#<FQM3Y]R++@7+⥿ra&O,wh n䚌-IFcWD:ovhڴQ(7 P\ '_Z##4BxUȣF‚@TͮYl;nK2*.BYfqtZ#1`2pQП`8SC6E͂קuA_U !:`^vՋ8,s5pPԻXGPZ\tLgKqt #'BXthmV|xBS#ISy2bxֺH"efVTڢ`j%Byg&k!s$sqhpg,cOScs*%K+4c#(x_ԘlƋNAn,!A bs#kqݹG0TK ':&HWpk}q =s$7VFb'R_&M8fE7tbYM뷂B&tdw&v (=WnP3c#-JS24]:J;tPÙ6Ahy~mfaHMXgӍlc+³&0G+B[Ú`/(:n}LAt~xKP <34(} w+WB+4sH aKo΂NA&^j4 VU(}ɶ!Kp-hv8dHV_+)r@mK!rbYPݮ]s4{s3"vo<3.@ D@A|8.67m};M K.E܂r!p@o\D4@Wר`=^'GTkR1C[N"HmIcf#;QQ-eJӞSsE(e'I;XYCCju7=xX-e`6v?*L-dN%LDH! ^Y q+9fW?&+M6! UR{Lh`DJd6Wx͇kSwe&@6Gp`w@TAS ̀l$Oz@j^8>Hr&Xat;Mgg1tp85bv|rFa,*ދǒeNxvlη0*nyr޺W+l,y!M hկSc0|,2 4]V"(#piPf#yy!d}kMC{R]Ҩ~)^v׷ԘTLU/$#hMH1"ĉ&HsdOe'ߐ;?l9E!u{ǃ}ͅjt}+uK۹,m#.0 PhX ddšg2y~^aKmfqʽlU {[arv}B!찑t`ЄiON` 8.јeB=P՗l,eҩi~z?ya{SL&&{`5lt"{&IzNi = 8*6Fz) ѐN⓲~)Yw5`1Nr:Cu%%M/}g*QO oy2+8~PmiJ*5^bo͢PiI\k{LjyHaUcgӥX-\Oق˦ƨ iRt RnlC [&;RDϫGE4IW>-Ze/9+ld2S3d/|M&! Sm&E;&h3"W@5Wj@܎_N"L| 1̯^ƽ5㦀9u pSxFCS,Ǵe\PL(p@}FLQ3$"+ n,s ahY\a|,S lRzO8H M<6O{tK=N`o++Xq?r6LgRqߛZu>![῅vr:Q/ l|,&CrZN8¹"Bd=>x#!zjaUmz#QŪb5Ub\ Pq'0B:8MNe56= 9S$, Q1zMEuЉ9OY|@`xw&+ GoP@AI^'_1Etݠoզ2cx<F-!c`sWZ3lI6Lpe&& R4k pOnG5|4V3R78PV@UCdR7A4k;|ɪu;/h ~Zlv]焧b/] yy!S d"0RP@pEqb0WzF:I yӖ1dZ߾J5f܄&b Pn te?cM#*/eBlCR2%U+CɽY=m+mhߘ$Ej%! -z 5isT<ۻyKR2u4 0ڡ%@6FW"rT}r_g"q Jɚ,-%R}>59|;ƌD"12&NkO$*drf,%&͑KAÁq=NGRi^Ipޗ~+vU2@~qta,ݳ-b?:-݌lߕ*,=gri _'_|^W6 &S$XKG)}Rf\fcBP6\º?0X5ZUk`;K 0g'Xpb!˯q~mٻ\rB$l[1ɓY)dFp(oI꼖T-Xa(Ĵ Å$K8IB=[ PAߵ}F%7rW -Qs2 㸁$i_ͦ μ}P[}Û>oe$a8$7|nIzv}e n\-&G||ՕUZ>Gl-fzpZn:Q墶Hteh[2NK`iNZw8qt/+ZSI vwӣGJP{>:b#dրFO38l|GcRg󴠄@yYpNy֟r ;A9m!U'a)ڐ &@nSк<$?J6*Zƾ {(TQ rF.TfYdw6򎔝BAY,d L?|`zl@to An87&nkX %jNFVcٞCB1S縩;ㅇ\l><}et:? qZbC>ؠdm^,NMdcnE2EߗуϽ*:uMŖk[XNɘʐznGAIoڦHv*dwy yKx;8:l*cAm?=IO^ "MRzPkpS#h}x#<׍cE8M8>1\Ɔ4svMV*HZ᬴'`l !,Hbr[_>ҶٱAPe<*B.w rdK}qc,n,>'MG-˞X˔VJ9*|]Efˌ֍W`S 'i)8FA%"ևghd<0ƱLqQ;^QckAڋ?٘sTǟ۟__ I)Mɕ |!2Y ެ??LX\h|9k9?R jLRP_p_|rc}<_E}g#]o[FR鸅&RNscPh|a6rճ /=aG#X=AB [ge/YsZ<ؿOmpD K6Øĵk{^~JO>LB{dZrTf HuR&\%C$6 8zg&N۳';ħV,u8 $cƔ;a-Q<+VҤe4cЫf- QTF=#YHug'GX1y{WGϣ\{ooZA^6< bvUp3n6%fܮ+{?/Jq!1Ӣ@i|YpeHKIl )AqD#ub.TZ"k$V!WZda!ID+]A`z?d\bTm;X.GS,`%y^HDݠN 7c/VdMQW]l͗7_}|/`i^"3 \v@iD \&@Ifle=y~8យJgiFgn;~=!P 0o%5οOcW `Dk@Xb0n Aұ0O?X1=1 +zZ0HQ *6vsScq4-).7 #c&*90M>7){Ϻp' r0]AיCFXlLg0 JJ2h VRΤ7Wحh,jKr0Bd$,Qg t&<p8UI [8&kƣbMƕpX3{މqL+ RKGE PJ'R22OnzUYSՕs9htyY̋JJm4Mtc? z;W/Tng̤9Q;4,% \,(թ/0vkh͸lVVc@gê>۱^q Qa⎚G484Qch^gnE $y**pLG8Ӯ_|5#1IiJT+SD+ٜ0(zrpF2h=8{8go6 e@4M؊O^[ubJB$ڧpPRa`:.lE˿7iհ_o[,7JmZy⊡|<$2LqN dy֞ vA"3D3gĕT-b}+ہ_M^[LTjzg /QNnY>\C!iDk͹yT^i^~ qG.,R`TaiI "@tFgRsb£uZB}LlIGKjPC="#9C2xie.DwUZs9@f-0)LHż#XlܒNEr.Ux\ p>-KK.p?oR+yQ{7xK#yp) VDVS4(Y SfQ}O] :ڤ%ޔn5]uY%O܅ª`{8@IDATXr01tp#yB%5\Tچ;1{(gВω[56gvÝ8!Fh(uR~wZ0uDҨI904k.ERGɶS,ZRFl.0UST@&/#&[wttRXQwB tGZHƔgU ,0⦙^ X"Mcg<. UVFP&H",r(b}Y^L c ( ъȝ @kd!l{F{]bG ya۶8ȾɣBKTPf37 Į |?y,c1_pj$OIݘNA8k_Y5vIP@UX:koZV=ק1 vsTk٤|[ jp;3yh|8Sk~V}7}tbc6o)kIi CUof0?-jJ#a: < bm펚Ʊ8 jL*Q`9 Rkن6_Mr2,*Ke*<7E㚸8?juqRѧvyO* J):#ã0tK CqCٓrgo(~"ס$I:r)78c:HKw[ejYt3]퇣~J$DTrmky?e1SG'Zi'YVu$p+k )Z4|GL<.(OCS#t8ishA@o"3 W|$ʘŚs:ALV_CKr+JS*Y8x<:,><9Kv֣@ʼzAp2xbZl#SIxeܔZY}+qT0m)ht Sur ѽOpYր$0ܦ5mF2j^f;)c`f4<]O=t!oS1R:=42joJq[QLh<&(ieq|ƕM0sE<;"BJM5[[< ' ݵ?"]+4Tg|?qY[~&uޚ$ʻ%R+)5i"'T]\2d` qs5n n1T(IXU}O=ijE8JvNKH&`Xker(9BuNɧ2= 1b PJd0E<~|G0dB=nAȚG0MphgL.8.i87*?`"T&y7,&Y DMk9&\b%ULFÃR"}n0 ZO[S+ ,0M24PLC֙= !> U}E'95HOK D[{*@MVD\.~IVi,|z5w4)R˗1[!l7X_?šd_eit{8bd0e jx\d@|E~VofBiXK%v51`:;WXďF4>*e8ܦOhej$cUag3Z큶`= Z3' =ݮhdZ:uUN[)Ed8#E,,1 nG;4ܒMbɃ3FJ޼y3 m,%~YGm+c e(xҬ$W(pH7i_k!k= <_/TqT:IBIɖU/:J y>`8cp6s),#P? 'ҦV" f$_G ^ y]s@1 !DRLuIDu#p`I }(u [Uznq6lex7k [ [Aad [ɴuUݴk4J>@'MDO~Iܓ3cJM%!l9oib=e=~`З0&?yX%zZbse/gnLQMퟵTq|8 U?w M@/.6 Y ՟r~';8꬈ YOAޫJItͿɠEύ)r } o%c:B!V= z &3ɌW@e-`a1[NQcU;:%T%l$Xᫎ`&=G6CL 6i3 Kpߝ#򼕕:dNdiI3|MXm8Wέ`!ųo٩|04T[% 9 -lq.2 Y-C쉉Gf`e @'ɒծ" C3&iVpňyò>@b|7(IXtH&vۘKy 8iJn.6s~̵}}r+iEBo9c 7 ?o-{O;+ǰ*y=jkS*M4rFy2g2lr8ְ%5Ќ'"D|\p[\~YP«Y ]F=E80;SVhm㇧ :QaO-qn;;v/!kbuD.c(XlKǢꗭ\[kAk?jO-˘~}!,@Ѭ(f%/Pv%q9o&ҥR/#Xtx) .g)4'=")}KHRB'lB 5@4 ~ج ;Ѕ/.Gu@-ɋD H2K鮤ۏf ˫Y.]yN!C8gRGY 8T<͖򴜬r"0FIG|P^1)9x_AD2G,Y &Uuxܵ)PQ[6]r *}q0n=n7ՁW*>(Ǿ+!j4x|wÈ-*o8[|côtݵH@uCxv/5!}ֻ̽8!ɦ׳?_ HJN`Y4c<ejg 軘Ћ<8Y3R4LĩRsF<_[r)*o۩pCBRn-ڨp^jN KO:ySDr1ݏı(?45t KpeH άr$+B(결٫ZU\;N>[v%TðG7#rcܽƊq&nEXt&EQ1O|xQΤ/.{R^5ЀNuFK22`,-T c;s(!)(pwV0^^ R= YXI{`r /]ɉ |4Ux4m00phVG]"N\)rdKs0zJf#%BO܋̫҆ֆPTa|Ymht3 C3٤XKdOW[ 0ण8mnZ^dsTol@dS'v\.6Q2Fb}PD5c"rp8'<3F|A(\I}ă5@'ӈ njpZ[8G/a#2f_]`j܏)+x>3,2 ɘUuस ~/H@k'r_1#qr9UeYMj/ 'ȗK&ㅱi&jŸ9NAz̚N񬸱x>AJZQ-/b] >(RWLMçԕyŋJ^JE5۔Ad+d nxV<"Goׄ 5xf/{hS% :ؗin'2ՆruþM ozgOA e`~lb}>T PT25B%Wf=O}7Ke,/_:7D;'2"49]\zQ'+{rsMMiRvj$3׍sT2-͞n 7ȣxk`(=T Llm‚ c]B oK kLdmYz Ѱf=v=[SN!iqVoZR2e~txLb^CY0H'(8^ݕO~JTqP@2 jAX13[a BCҿo%IeRĪFgӇ S^/YFsq#WVpoFY)/Գ~ij6|PÖ xbKzB 7 s1$5wxN]vp?-1u^OloVfǞb;]"t$mev1^ޮ[7*;) diT$ĜEMʅ P'ԛ?; ]hsС۽[S1{OX[JTkξ`lcmc5v hdh-@?.eu3xOei̋Ggk8~w.'$5SS7pZ4Oy5^f}8\H:=c_ f"";ɂ`~֒q[!v[|<便pʍ9:;H0,VJɄm.28,gfS)-Xx(,n!{}@uuZlƥ_Gv_^g^vH 'V#(Ե;xS/ڒ޾z-KO5Ie .\ɼ8ϒY=z W_TvkXHLPW}>gPaI28PZ?Siz>k̙=>$"x.nGeu i>X/BoYb::8O)z ̢fn [تae2Q3Sxy"Xk$Bbů 5{3> STJ-Mꜚ$5IeNni+9[TlPp)$? }!z iFM9ګJp+Ϸ]Q6GWͻQ"H+oo-5/Yˊ~>~T& xg'$%\ @2ӽ܎ؔ2;o"(L9eI7?#|n ;-j`5pYo_'.ގ-&pEx:9:+chjumUs!FAW+&D&=rshcYZCc#7,`}111^'m }Qw6^P5k+!*$Z-=Wj8q>@hT1 a6>Ex's q09 CڊضceIv),&kI2QGA-q8-uWqppםMcBS[Py'1 Q>E5KL?B"F`IP,/Oj'?â|CEFEYCSIVss51֒0NZ(PҤx2E6ШVVHnTV! L< ً $s>2t)>㡤:QPTk(`FN ssMmKfm@$ސS ʦ- _8/2 >30x@m?6ۏ-#?gC@#cQηgA9s"Pس˚pd?7Sf25|=jt!5e̓Mc1~5/5 rT@֑9*IZ i"anvvf2݃qYt |y9}S,-4AL>͜냾T&;]p@ IX 16۾i_ܛ28E = TJ0W}1(:[ :J,AʼضR䄬N8Ma͸ztlŀ0:T<-ԗ2#6[r&C8VX4lZw4qr~"]c[ -r0Kjt -i~-xYUrHP ,!cUīI3?)/RVLQ*cG-is8OQĪߓP6yrRa*ƈԄ2$K9? 0h8 Sf]0Ki,%ۛ&h$*(02~S JR`Tb1M# mA@ <0:[30;~\Q4%a&_n4!5zz pjC q\,"{xFAh5Dxk>A :eL[/pƎP\d+ jQqɫIGC&ʼnc,LRt8 C*|>;EM 2`3I1eV\"WyݒEC*ii7W'B$"Z;߫?aPkg2|bJ s^VS$[1J4$䟦]w4%eb9 (/yr6LqaRxͮ)4_!]1PVc*U?|-Q|#k?;7(זzoؓT=gDt%:8I)kT`9`bب #2N0DBwp #|;DLS0 YD@tLFӟTJmʻiL;;>sOB.@dT8Zq+sk.M*r,Ȁvac y)"a zMuZI;qk< M%# oTo;\#-bQegbЮhY8[eVa~ϰ'  ќ%d.EbB` m4ÛSA5oFƈ0\m̰\~R'0`~h U ʅ:XAʶ<~S p7b2v3ߢEfԷxqtW4/. _x+wܝl1aYR}vrn"<=x&~f FY1Hg S;&-<Ӎ$Ti 6_|3oV]06Ń \@JFr9 rGQމ}H ّq4勘E`LR`Pިю zEyYx MPYx@L?YfCy墌!MV<šZ/g'rI8,;!RCEnAdmPi0^Y,jh8xᾥwd&uEC1d5v`TM'|ϷEQqj0@S3KI]QhdSF$sтPU&j1 w(uᖰ߱Vb`s|ja4O䰅#w"0Sj+ҳ͏/mG&*zQeO&?|Ċڍz@>-΢=hcmS^W8Z+8.09dTWo"odX"җj ;8NWިNUxBdN`5<)6F€k@yݵ5 Ai 'g z.ʁsԀ.T1Y^N7JtP[ҚۛD`bZJ :0J -#cVPH %($ǾH/) dcyK3L7pS b{hV[DM2v洌]]2P0z ҰLȘ Z[+5S:!QЇ\}N7)0#&b˂ǫܠ19.3boLgd i-zB6tXS; nRM[հ,rd~-k[+7koGmU9eO)K, O6, M 3t3I/1N:g,JջZ<71읱ݱtK1/uʴlZZU=@xn@ulb\48!V$B]nj|~Jt4z΃6cŠZNnԯ!BuaὀG1ds6]K(F)vṎ+ 8r d{k[%D-x0z-m=iF`"}0KPĢ&1?0O񽫯KU?"ģmnjL}ү2 Xp X8=9<gN+EWF R]ߦa677ǤmOp1~3n.E $K'R>zzU`:܄ F\E&BQ9^Flp7z_M{-0DHҲC2Uf#\XD40̠wA=dֈNc'5p 0(,ȮV U1&)K|ʇ)Z#J*[`Tmn&q`2/z\+' @uC?*Xajއjd^=_ܑ z~FT O5~`_'Arg9$ζF ;ᙊu䲙C 3mpμH7'K(2MӽJ $bPVf\E*:a#ԀJo"m1΂X0M# $90둁OH~YK=.nx>Xk]$Zv]z"24P^;•۰66gBA (.!Xغ44peռ:>i\~.}' 氓\aQyphSPڄ>ĥ9X`ݛ)vWAeRe\].殯d/7蔲6Y4 Jp8GN2ri_)g_\ZJ~(-_L3T!Cr 5SĈӷP2v 7e±괓8N^^^eyz+h2y@{eQ&mw!)JԩːPDՆHLɹNytt/ȅ-#lI ($h7;MRihGN'ZGlh1^إd_nX;q[P ]2>Vp-X"E?c-Q74ˬŪ2#$VKӱ20t%65t(c0%}~6vJJ 5i \]{%p-$S%Nt5k4l1.9{E7k&q ˎ\7\(zۈhs6Vj\3+$j>S(4\0`H@x 8ҵ){1R#OH&D&<%ek{)} Ax9^۩ TJɤ 32Hl䡟齩i Daнh\/\yyetWt nu8=m%^J)g:JPi:m9c{vh*iTLbMnQEHG P0etjwx/ bΌE @.$F=Vv5dBʡ'$^laH *T6rC@f]]#C3 +%i~iNT&sW V=Vğ r(-h'O :\jUL Zji|mLv" Ӏ>PXvV"iV*Ei5*y{VIBH_ ZIb+pCy$1B둪X^<^q >ICe3' Q aaPo}'fH$|XEmt)>FtAiQn巵&{DنYҧu Q|W{"xc'W9 N_륈޻=x vM7,s4[Btq!0iaFfBRcNd@%˳;(baYCA @ (N^{afi[(վݽ {r7ͦ5MI@+8;fVQM*{!Uڌ{8$J g&i4ލ Xaq,;S L-}­1u9\bfiؔLBzYĭW:!E_DDɢ (?juغP30c5dMB;XaէgU \ز|']bJLI~Ѫ_9Uݎǧ(Ge_hT&czL ?yB)IgN3T㝭u=Qj)/58< Fa:l)SD[nE~#xӴd^l?Qx4u:KPu;壨j&^xra46=*Ю”P. E pl0(Aj!`5)nb5SsO% 4칋X/Ϯ4\#A\ H|59t&)ZGG9cǓ(gz3]17Lzl缧)(z {RCPD L"c8ϊI>[4&yu KhU/8̇+Sw0*+͒з*$)IV:N62:GX`hqTa`@3mR)0=H[ckڋ@\D\R8-g{@:'+]ԘP V#SWu Ja>J8''Hk__~uت)!]>z`WTU)-)'E` `'^* (2u{9: źb@XQ~͛.nPz}y^CUMeK{OB$_Жs!!glhKdcÞE cX 4]X\}ЭֵVVn~hn]*-)`c!=[?+%􂟤ַ_g!)E|Y ~"/.6V#hWo _~kE>ȣSAGq khO'_ғݔⶱdӯ6ӮQjFa,OnxcBUd$D9lS%8S^ś?םE5\t2U !eYq![ x,b@G3v=-BNdRĕ䜭3ﱦpF"3#mvKMӧ&}9?ދ=x;yoz DCt"84`u}SGiOVUQFkad;2 Mv\]SŮmw#S|}Jy,'g^F3+~SzB[;F稤X7j?2$_9FE RB fMx{C ӏdqg5N9ge30YE4n).Q̗DHa >۔!,GG04~%YZϭxQev6)lH'BF e:Vmsd<Ϻr4OSjA%nr2iRIR')g| aPT! $%t+`&vݾim߄>}*HQ\+5Ѧ;$)hcqF쀈~Pn?DR;uQ]*p\Fg?eT\ 5͖QYhnLrΘϺgXcNCM!=NsW~f` /xB~7w((KRSBQ\-f~V TЭ1 ˛i= kC1|A Qs͗URcW(knF˗>y2$fCQ?b&99л+5fm]@IDATv=ma5߼#џ׎mjcJ\1q_uԭf"A& -o88{BjZʄ0CTEh\}Ƶk3J+XߤԒ9dfuKYqvE2fcgKe{SqKb0z^^S02/,Mt>oɩ+ݍV/NhP.v=@8tk uzE gJcUJte1b؞gfrp:U+UfCr ' `\Aw2dKM0VѩѕUI_lnI1 u8hӥD : T$۹:xM WMۑG d@ˇ4“!^]V[ W8/Ŗy/`0y"Lz|[~'%3&z;vyBǻ.=Wf^@x@J,u&DQan(P!.J;a-D!/=V_]X&;q,|O\ $2\z/ME8CO CvW;Հ]Yf#$IIT׋-]!cs?7l<Y[Exzkzh^z)Wqd2Y֘L駲z[;Щb~8ߓ +`M<{Zd*/<{B\MF^([Ȅ$͛AuOXΠ]aNCH4)j ]k [s0x BNjz1'$h+Ho$TPLԅƥp6Kb48lV%ҚSL0bE>aH}řNyB%I_ 摃hBm씡LKI)la @뜿t7Ec0(Oy#KAT- Mnb"kZSC.r 㶈 ʛcj 1MUSi3wNsAIfm DlDbNI3,n]Om[: RTV{fwi!E{# WaMA̞NEfG#K5vXiUf*fLS",2aimKzX# {Q'ESե Lol=^hձC FnR" jAj2 Vnzu}ƾ{Hq%YL k.Mo33<tP,iZX uo!l{!k c,H2LnWxq!H%_اDht>,'1Eާ}#{J,?Y6qB9Cjg ϭ!bG <&wt~X, ߜfQd ~sEh/#$٥-)̆f>'24_I2!\Cs,!kQ+jcTԕ|PV"q&MhR^-|#j!Lsu0Qش'& r V[rivxX}K4zCBݕgL+J~.08NCU6J^݌LS㚳 M cxJiNS35?<4OEf.MmKX5X&9o4˛8lGyZ&k?=7MBNǕ-b(HStY1>-+͢$ r/ ~j@X?-}fd &@c_ }뤑HP5 vǣb}e<݈)e~Ȳ"^1(xLS~"ܨ ;|y*!WFӈؗ*`-N.oܥjfϳx)؆8JF6]abHDJ،1A r&jT@Mr* hϡpky?;XR0wտ_nmr MDS~ ߏXoLs6t9"9T7SƆyZ6ć{9 |UW^VWDwz!v係.JO6Jr7JY;41<BsPU!ٔ#7Qg;!4'oE$҅j421cZ+ CnY=Pc=Ul Lz}D4C5V!>.b"%iB֌q|(u@nwi=Ν7%?e*Cƿ3˞`hA4;1(SP}dpDv&AD@kh-Dt߳XZ%}r"֦`iIFb6:5v04mܭ~21=ZF*AaÐy b& E:Lˏ0,e)/o ]YF7kr\sIe`9 r諰}_'X]IC&\w9F-:%Q)|5s3 +^ v=BYe'p!.wvw{=}4y'F{'_6ۃ~RWȅfo C.WX;xdcPtKFT&MH h Z7 \I1٦A'Foq Q9O;Kmem ,$X#7̢7c2­w0m}RRوi[i%h6*Y4 xw hZXt?6t\SIvX|7miZfUx"/ G}2P?z\&Kߚ Ľ8PBmFt_Ba ^EXK{Bdg؍˔MuFuNQy\#$xifD?]h]Qˀ<30/痐e_Xۤ|,%UMሠ1ye(9TADDF hI\( t)qUg2. [>8EǶx0-|}0jpub $*iR WBUTS)/ttmqh&Ե,R=͚ߧ,O~&]MoR@]%:#K1Z)#syUu,e?яiYwLBh!;(7WĒ#D"(:X nd%Y++MnHgxſu!Qg3 Tǝr`Il<gVq1iFy1̫6<Ǣ)- ׀´cSc0Ɨ]ɌvV   DeSg1 ڑ#&n&x|lC*# J)AYmet(~(W8=5E;ia>5 2%^K} V)s< ދVny-HfpR,wh7b']:jA8ìϰ|A=<"h]{vVC9On׽(B`rC%%ҜNBBOc'h;Ӊqhx$Q^CZdV ogwEc-eRJKX#2\×hi/~H!ө]79,D-Q\ݗQtS[>vn)_ftE@J#M>Ts9V\,A'}I6j.#rKcS:y "M֫PH2rб!; Ҩ)'?vh=f,?pL˲+݆* *:)EPzzʔ 4U8PV!?i> #3 QO!Q~ MO} X6f"G7jc,lT Wq(G  @J!=zna9P3Oo(UCc]6bl ) -S6,E<R$Q7tiVC,+(<Ь2 T<jGMlcduΈ3c@ρ xUչS<@Iq ؃U64l{dKBM4ҫ+xQbs#/b"9&Q\ z1A HzU{Ke3RBáUiQʜHcߓLBHQNpA# jFpB8(.TiG<\=_YPg0rGs1Q"5EA2&ax<$1|}Q&odABnns.wr^ ;X`M *i6&}O_ꅦ,l#)dPLKd$qg9XgO< <[4ͬ;H_^sVO<eDkTnFaAZ5d. Gت3R 9[N24gj'g>]DÍgkj}@>:8n̄Dtَ̰MS(>NgXCd`i'ވ;OtT9\mOA CS*<jkف#kk?nsOJxӤ$amVa,>$9D~]Nn]+R֌j5vفI*IYz=?9KzYn~d}b{Gr=le&3nw[+I8y{p:/~ӂR1:6Et§:G,%\QPJ٣l.ⴤB"'-"cGUїzxQcI9OD\;[6R*ъ앣a!naƼv8-?tE|ƗqssE"3*T,APs_Y$5B9D4ZV|Dp+Qjn=u^y=%Fyi,Xel_ϗ6bxz>ؿ?;g;U,I4S9ު喭b+˸K T }'e* 9,6XgA{lTϨe捯#@ {i@w1lϊ0KROűշq:h(RlC|W#cWY_vL2+g[Buڵ3F"5D*FqՇb!7G4kjɧSьUC"(F%|SEsb{c`p3뮠}y?yxN)^ucZ1zP05wS7q8OGF U;8_s0p% ~o 6Y[VX%iPEyPComC: n7RRċAsjYB.enGP.>x`4 ' -8YƘp5K `1KE wٰ ,g㓫ZnfAK."%4BFX ZalyXtj6 un`0h:$ R:uxk*!YB֐23]OtC/Ƀf6_~mYr@TRRzE u VT3 2;,r4wXߖGX*x6T-;kQ4,[t}};l~y1"vG((YFB R@Zq$`ulGs05,hpgGT~LJٟ?#. yV-MsWUl͜j4>f;őB{YL4ep֏ATDآ8}}爲wȺ7P05x'A%MO@jh 7 n.ɟȒ5g_ %WX4o4J~pk>#aCl'\䙊"y81N5v85jS`p\1vxG"-j9l떐~mK3.s0! 7킞B&8[(P /XrXWW5e9<p d`r (ņuCc%mz4KFį<.<^ُ9Tښ_2(;svdHY?ycW%]%' !thў{ɀD%R B 4Cbfjcbm.ߥClh0 N.L4W]j":BВ i&/nDɂhRocP*lBN-7Um.&l/bMzzƬ gR%b'F^8|'@$S7Úk\VͧtY\dA?rDs|e $ozZCmהnzg|N 38SUbBr0@Ev}dӥJvDdLӛF>2MOӝIh#CźG3+|3Y:Cv$ҘcMh2lH+5ų(X锛X)u KȠ ̡w♱qMG#QMwo5@3Ә^o蠉2QCECڐ+]-DGDާAsETJ%\JqX7Lw(PxSu,0,T?@Y,%Z4>3N|$4, n6#\O9el J p&L- J26xcxr 7RZ?~≍UВqRҎ^4Z0R!\29hxr/cm4=KcEfZ 36fAzy51 ϳbcT}`38s[(4HTS#V]RJwq=oB"(8ƾkcOO|LN6lggV8نz5 #ܗ@ b%R/fbSZ0nIMJ(Ӎ?#;2t4(0zFEJu&V00xBS$) Eqnt`՜a@li Ȋp #H\paPR# 1"ڜ la6 Mqs !j02h{^ qyu8[e _1KB\q Y.K)垙7o.0Yʞe +PW;o4`,R~ec|^ڭE*!_ϖiY9ԍe5"9/1_ʄب-E &!< S"Ld22EJQzF9۳}9l/wgֻVZb銳l0Qv̉ʂ^j~7U }㿚FP0y~, &Nej=~[}iDAp{pLGʗ~gZ'KfqZ!8 {ROIp25`کV_YoRSvvNB_5H/G^M%sZ uij8r76Ҳ봦\>ާV;jkFc*%Xg uc\و z Z\FQ0TU+bXGJ?$ʷO!D:w4Qx4 HDK+Q˃m74G ڙ' -Zqi#s;< II/h&Qbيgȣj֜>GF__7Ρ'vJFVctZ$%~"5#)irfٳ x n-,j\ e};<Ƣ4_a8th$cքib4tQP{Jy "G 'lħ9蒾OC5AWT:^!s2dELù'6'1Tx ͥMFP'yV*$)O_p:+e%^E6:pTL֤R@va rTuLzۚ3f$ s'nì]f܊7D3:xAsdrCL 9e\N’|qH}D@Iضu3Jf'5{ {sDYgwXD/AHciԨYPɲ\a$:1/:{(WgI jY+ ybM*[Cm§=dXjY٢Bx{F ub WΟ8ڕ[bTdP ?n1[\;0h6ʼnwtZwwR~͍>^V<׎1O5 ckYMTv$, Pʌ|qL|T#r&9W m)p zQhG.2g L/k܋g.5mS>%(ʵk!6-u7fE'h2DriDLE(֛@ !7$15h`xfՐZ&00S:ֲd#E"[o\Xdɡ9 | `)KDanAՂqR 鷥M}!-2Ŕ8a,PVA r҃Xyv:w04c-AGAT#)j&VD9-tdA?B؍)l4(CDSoJ/D"UVM=D3Oſ" N!c԰zOE"B=BZ)&)ȝ)`kV|K'5XHlR:i逧#L\{'V$֟@!Sli?(UM/V*Ǒ[o[gJ4M0Z8%mE7@nA#tHT~=|ܧ7e3Izlf5JvjRZ=kWN4ț$F9Q/9l?7 IH#YWV;@-=9hCr]ZB]"{q?(h5RMMskuIxr"΃60cn9KEıR`eDmk.xl`rel"&lʦD@'͹8~N>Ane09_`2Pj] 8ְf"y/kbpL3L3pΔ;UeQ)/"Rq!,2*nSIo^a\;xِ"jnxX"3*F0O9dpC/woA/PՋ#"zwRB@r$tJvs')0RZuoj+n~쑗+gWj\gՇ"j~*ǎw iE :Vjz9IG `[67 n!QIkVxa[RMhqQ7cqxk,q`hf'uI4ű;TX?v 9oގCؘow* k,EMhg8x4D0$mGUPӼa~r,|'.̓ꂚ"sqHq`ilEf0H_3d&WÍ| rI?ax Ϣ2:*&;bΗN{^l|&c+C\StӦ e-m6N)be߲ =YD|fUi:&6mu>bW>V'rE]Eh;9e$%-S!lO'I[-IdKp,f{7qNQ0Y7 !*GNNZ" IjUL :q^a-}nI@IDAṪ'yT-W}Wj)?UṚ~=6;3u>Ar~R UiRuRkӇ _I4rP?WoniQ$eCN%Mm`rvf ' ݤ )I]f6ULeX:Ӱ .!81SG'h\~<_Oo C)0`*f;M$}^.ghS~e7@XhWd[S\瘠q^ΰ 1(rGF3U&'5.˺HpR__GES-nw 1)p;hmZt$a[m N=ffv.a">)G&Nat ]Ik}6;(]aUt* nV_B'WB)b{b6^J8u4P_3"][܈&+F^')~&ddſz*0 / !<G7CtW{q9[sL2)Eoěf{Q %nuJzQv@S24/`#:h92rZ5C/>.7u5LW<*>yI1O!y:_kMj˚vdLJӺzzN_;z:Z)"0sbw$օl{zlE4ͩȆG_O'P~(Gkϣ\+}FֲkWwxϺc>MyY!:Pu 8?Nqm_`t `E:j1[ZP'!ߧ_c1uN t0Y~=tAi]CzpΧj#3h7 +٢faEcQL,v`9/~qvMR\5ƷNT}VzWګ]: ϲжl<]X!.ҲsUt3eob MXXFD5QG.lѻlK)=ΟugCYQ2P}Fɍ#ǘ zzTҩ0Ə|21.l>)*;gXYdn_wɗpȑc1"i#p搗E- k~ӛۺ5wcUF Cp͒vޣp[", Pi<7|iJ!+EqqW(R}״m*ωQ>mg 4n?@_y\fyH:ՐCPWa>X̜j^!7p~`𴙥 l/,}94RQc h"4t^Br؜Ȃa '͗bbVfgO6?n矒+|Y ވqA՜}f;%qzF(!g;fk>p_r&x(ʇ |*Wegwn{ǁL( 3[ 2hHD|/A.=1L2O?Li5 R G*Ze wY>nH XxUyw'f.hX޾@w zܿ\;K >?ކ \!@x JYxӝOaJ;j{~= .!# WȭM]JxzFCGë1d4Q4>EparcȖӦZm! < F~x[IS&~i?NWa<&dۃraY|DϞevʘo*!>g8iE6x7Trsxvk4:yiؒC0:Qkib00 x8uuT0)G␬T`g g'phF*hRVxۖc(c# ؋I@v(d Xw/(!FXo9K__j!m [!Woycxn(mdr&O߷Xzy>*q XUnm+FR1jcfU'4gь0wi!<6:0GCI2& !tٷ-,j 5u-Ѣil8eYF,uߊVNY}RI:`AlJy eCǝ;p5TH|;+hJ̖ex#Ln#챻l8 cB7]X._lQyOB`Y)cz6C)vB9A4Ԋm) v r $Πr8}qɷ^->za i5 ÆxqFw3o=@!.V:oYAX0sIJ/d$-ɨ:W(R6Yh\⊄]W.z>ƪ!2FVS hm8Û\_N?? 8c]*pd J%22iY^=~7ܥ \&̝;~.FUECxձ ZORX>]p>܁Z4syĘ#Ky⾹eTمmz _)H|urĠ.vBO[J14fhe[½qi/oAF.JmIB ̠u`" 3}=J4N ~ڼHNW:s9͠)\ y*ڥLG1ɖU͖٥^e'ݝ7º,c($`VYDgܵdtǣka cAӁ`*[k[ɺLdKMha8EpL-c[hD0J&qy/ + :Y0@8bSuy;ʅb3Z?!0B7qմt>-1;͉*-?M76.ZB*v4Il;1F\$t_|s|SǥKMebؒ\/^lB]Ԛ+,,ڠRޖUHRS'8"5F;{`&ᡮ1,KHU,)\ ]O*`K J?h4,g91Zղ,l6 2rv.\Q#foU ФPUynÇ+N!]ݓ&ޠ`s:I+|:6fG}"4k B͌PE8@[օlwr*8L$vD٬f)%#R8PP\r7SVtI(m xq0-6QUD \6C癸{,P%;D8?x@DUk )`=[K&#+9a')ȏcIt&#*VХcW[ c/OV$24s\^1EWzLϲQ?IL{0v(A.;@T\0Űߖ bKhWw9ƾ-vcjR=IT_.'= T5_`323Mg"{s=U7jO: v ;υ5o+Qj |V2O451U[;pEqUzsbgNtgVv=x|Y鱴w6_\>;{%Z& a8lӀ|3o C_e]|[ێt 6 HvjSD+l+rl FˠV+[eBZ[d7UXocbvg(akPl 덣x[KB<*br"*&>"`Jf{S4]]j(A*7KSbJʥtʉ .yT;BJLU_ŧQ)BgP<~)K i{q2dNMsm!zeXփiT`A7nIT'rN3:k4K(94ݜ2>PJO]ͼ[fίV5%')>bB>vڕCc  @i2fD srjW$#_^8(`%AK]wJgRƈ6;WlYBSMNS4Fe.`kr垽Ҭ0/x,(3sdA-΅p%m1"/a5!~zCh,1~ش\36~{yXŢ u-Uȹ!MG>DfN-O*0UsF2PjY~=2 ^XxWm떗fp}<'q6Oȏ8e8MXוq;*yƝ]SI_@@_ QC1E'6-3bB1 U{ 2y]27"?h$A'ϔ$,s6Sjkh!QԲ \%1 3fUY_Q %Iӱ W|N6jrTOuHiʪcx1\`'=!=}` ;'EX3"%E! `yY_ CɘP%lOkIk y8$U:|oϼ Lb`r)M4OF(^VͳY8g2:?=ֵ]?EILR)+{nRk prY PC"B|2yT=er#ꧭr~*ZA"O5z!o&X–09`jpsS"/x6/嗫גy/3 ] cE P;˒/ӆbCOt&pSv[(_mefBÿFݕ21+|`x=ƙ́Gl6O[W]|V?fL)xeM(tjx˨b\>{ RpVNAuuae=0Oz&`H03w+:CxҪ-wsa,s];'M1 6*g8ö2)5p;Do5nZ Q%y.ب夤͡HO~3tGGtvS\eR4=[g" =:MRT1P6L8T)uv,pM0*7s[̘Ih֫/Hˬ-[zr.S)T·$-sHnư96`(9JJyP(/K s"o[&`"d"&8fz?\9O"e^a(œZ|`J<cRC&m|u%;Ӑ^%FW~`.p *,ئP9?Lf4Sd4Z/ PD3QC|@^aM{*M )ѣZ+VM,Nj;ZTO-NS"%>d%kmy3)0pdjGNMJd8q 6l5!s  Qדo:2dau\q|Xsϒ -^í^%NUl=U/űjFK1Ł jd4ʧ䂎ǂ;}l\;An$4,JER|KaY*%Yו8^E30U9(gp]Hf Vϳ^ƻEh&[j5Uќd"je{0nGb;I(SXY(\9b[pQpY<:!rX6<+A>;Y*%/&J|1U(F&)\L#CFb1Қ#Ho ;<$@:▍Ocۿh/rLǬ>vXm)"2¸eϓhGG﹌SN?j[I{ۦ'܇fQTORMy~B{= jq@&0B gGŌwX'6 MMu=H7q µIF)F亣%F/6D hdGBTaV5> L`ѿtvрIGK[Ja @b6lF(|$2$)cO" z~;;9i`[0{}ƷbYmNp8\ppKXaB-4UWD (F "SN_:t0peOx'W6@W\>gdqYZ8j\3wA5QCS\'h~⒗n\. A.ځvQC!=TȔV|Ƹ  dS^xV&z?sG", cq9 U" X aa_sBs0‹L*.t^FϏ-&c\{&2^2ǎ h6c=kQb #*]t:9oRqz'L|6 E Fi]D'Ec{GԎ3Fđq}׎G38.Ǽ=B"N&jQ! pNNh81&](LD;/mgA{&ŔQ"5|?]+}A=NUOTLB t c,9`E\X'>ްy8Eߞ`P\z(A 'yp΀bwd B0aTi6)|`6=22R NE\'x̔-T#' ?rU(p4҂` Ƶ['"s e" W``J[Xr#5G^ޅE&"^|"+6'@lPȺn *Y=h ,&;N }nͱf,zs7Q`N\ӾXX/ %qʰkyI./X`1N.#?Dej=DnKIʁMW6RQt%xE^HqDzk8rምC] 7rfdQ7Ab~1 Ms:87eX0L nW}'sjs-87^@/0]E gcnZ~G5 uG)w¢&W mѸ'_y)I9R<8X/'ԫN'V !FȁXQ儧3h5^i˵T:$M H?o czj(vn ZX6rZr%3  (E0nt AV ˶$y #TCdwl:*Zɺ @S#g?0*b:yUj'7癊.4NLEąb#ٝrp܀4sL4zy)ՑlˉwiR4')XR𴦣vC<&1(}+L/j{0S\q7tX>(AF!TϡqE[eHW_aI9'eBSvT|! JQ9D 9ÜY2u xO"]hٛ'G25H]ZqHf$j(sc;bg#v?~(Yr89Nqݳnc{/2 j7"\"q L] zZ.dJ۠eP8:5`,.3M e-ʻ*KI#{zu?|2,2u QKBnj-T7유PAoHJ;V N?ߡXL#hsz9XV 89)Lv( ZVZN'"pۢ>nfWhgk vpډ4Sٔ( CWMHm4ԁk8#zm~&.š u:fBRG|W*? 3^=jMnLŢ;5eBբ:5by/򕷔+*6g%1?Ezr 9t=vu.ig[ /o6tE8Q<*_d6OzKx-bAj*r9BtspP/CӺ0 qn%,-JQuRDrfʯRpjWVxkDo[vwA@} I=?ޯ.$*ܮ_?W{te'1ޯ"k Iر);_֪myf~tt|;9AK%SzM DX*cZ+x~{g=6 \t/P ;֪bgSiٴ`c?Za{HvygX#Vt) qWh)4>q{,kco?mJ(Z~=BT0m) #ĭ9Ʒ`av7[ o)m ۈOOBA =+L=u.DM7A?xy?fBY*W Pg?0Tg!7YM]@,QZ@JȢoic~qI(vTMO{~H`ڲbڊH"td hBu .MXp%9- Gm}@^ck{бpt Ҡɛ 1%>fDjOG2 'F9!@!/HhgyzxpI,9P!؊`R<c¬Û4F2YOH}Cݞ5h }R^E`~eO|eG5 Rn$=F^L{`,SԿ^Q~n^Wҡ (9}4 j)>m{$hCtg %yd9m) &0$Fq?gW1r1! ɃYÀ3~}cr7͕1PO}@.7!GWW<@+a,Y9JS\feC O72bhcH\ 2,Ua(2T/H|^hGr~qph'2kbp-# ((X}"giko=.JbW! >)Eȋq^aSő'mdULa,Z_O0c#VKxF&" %Pj5a;TCt>$6, 1#I͆3Xuдl (3LhmvS%^ HГd_/V0}P6؄%t媿>d^N1 TN4`6/<;? *&U 7RdQOZѳd'!eu}ND38CWM9r Uy@]&ZL ]@+iFHtSS"%E7^R~bt <78R5pV20VWiG!]^j>w BؿJ_DәzSOo:l*B˨XEK!4SkTkpGaHXw~N<%pvz^Vq lWJͫB_@9xt~^tlڬ6 2 Nq3U8svRT~8EP(& C18 tyG"BPD7)Nä [N hĩ&WH[tsF '=rP(,C_ öL8 կ61aAc+ C_v39r_¨ ux,(+o&>v|,@ŝ {07R)ըn搶 ʺ9 ?Ê^z*+qaޏJ(6u' 소 Qh!`Hm IiХ[+N\_Xj 'Tyx44c|}ZBhsy>>^fWPAAdV>(Bm43/Ao_0O`/PhVq`B5:ĤF+*'lխ5]깬/J$2`( CSӹdT< 'QmwX#2".7G! BYe[Ψod-AWO*Khh{͢J3(x L3e68LZI(;Jc=ZN 2􃨒E4G&IQt ;t`:HT}| SA1ИS鼶U|vLP&뤵=R==Ds dl\~7RvkLviI;wka+>%bw 'F"/4) ܂`4ժİ7&~,zOz!A"4pP) @M:]zֵċHݰ9]y]`vkb:M!js@Ww#(I=۷C] ;mU#pD W^}'r< T0T&pY^;M_Hӻ5GQ{-VkeNl¤oP/ axZ3RA6]bH+ l#aFtx]W"Xh3 x99Q;KDރo/~AΠ9+*c:Yf+ R9~EZMVmy)Oߟ=3 <@ZKFrlp%>Wipy't@_%D"!yQǹķdKz1eد-X>ү԰ϲ$z%k D.-FF(α:Й1Ltt ηt3%H tZ BS|pc>+(.HRbPN=I9(}Ao}[ Q&vs{J [1w1Ӊ4G)/ vXv: ~ tY?<5WPv ⵧ:omI9<2hn(ZzBK>=ҥ(h38rpuiu&|Fk5=*:r'l)Z#L#=DA<® ޚB!4->"y޸%-w/#؋*EAbtͰ B/Vk=\x1,tY[KjҰ]!06.ɫ*qM6uꓬIutE a'"0EH|lWae|Q3g#D_:q b&Azk&q7b(|8 `X7⟜<(HݼN5J{0 ' 󓾤FIf7*LS=k'3mP@JJh"2m{̖+@sotXYAԙ$M 00h*j'S g /Ouw d$A ތɐ*a3ԐR27bУ5ӰÇ=" uC52A(}V8qxsk[%8ORr{i EIJ6ˌ9![yenjf8 a=RK>=jԕB]gii侑rc{c9hڒI#qRJ1.i +frs z&LuᰓM'4Ҹ8%k$>;TS;*T um5"!w+\zC rlrV9A)h^BW +c|،hGoEz! gu5E' 4Fǥ&BLVG얼yvTVnU`.sD JvRWX.?6C]1 Rc`)Qh`pـ lj/BG%|K'S}}aL J͏8>֠s,8imt~8)밍+ trw`|Po'@M9x 8 |6!o~C::)rx&mݮAcC9? k0Na;%=!ZŸoԁXm.8fiRbw޵\mH1 %n|KAy_>A6i*iT=9.6fa_pQĺ'A(\y]lEѢ a J n,lOl%\G&. Qw"wEWV cu@$kWլ7I֐WGT/37áG0_IoǛIt)Ĵi\x쬏~BA[++w 5w(8L`p։ϝ60n. t_C^ .56S9mEy{z+ *Bb\YsDC ` pZ?%'z Yz ,{hN ru~ / 'x3oY} /iPHNJ$#s/Fī8 j"az`We2NSnDQ  }º8%_ z@~c;׼񱤸-A"Dk"{<|Y"BKtڠP   J. 2{&1rWa,bnzfZ}tfdTr\VK2FY`Xz ++sH%eaMI6r51>WQ2󉊴Bql:֊@[~V*&UjF3KzMdaȢP~ՙg>+=QM% RB2r.781[ߓpK'* 2?X KbޢzUB38KĹТLYj<5٢2Gc^TR$Cu^5d#A3H]"Ml%r ! (\w9:(m@>¾- VaYS({m68M6lkt\^_;hD>IϐMb`[ݯ̩ӈJC/$/h"XgjUn;0Cy;@"ҰlZMP'ETؕț>ɂeh=%KN=)+46Xj9 c]2bHЉ%%No(oEV:+rTO )2<3<6^hpLJ.чODq \IW¨%^FqF=9@IDATx"lg*lF;%\Ff~9r$mBiclm0?o6(KƂkK45W|*to0"9Ja[Jm&ٯl2 6yNq -hf`a[$5'#6͐BEw{rqH QRA:xo1j]'a8'#JE Hh$܍ &=n 1~5!|~ SOd SBpr 5`jiGQC_ I ncU48}`n[ >GG k 4_-a @P|~ۙfpFe+=h G_J==D& R30ŷfG(KqD9O=i'[m5xB(\h5<S.=ɻ!xDǏ48W`[X3KP~{E 뵛zƇnJj3EA9M&>{pЇB >3* ?qD8HMx@\VF8/P,\={GqIy/r\6 ]]އdebt(~HvdZOY DBR3zi`;=."|2[*=!# k7ʒ;T=7 I SM<{Ywsr^$\uxc!^o FJgLt:Z (n.3q٪D VpAFjG%yR)QT+󠂏aZQ/+S1R̚a٪щM=p<.PB5e(H"bHi[3Y\Cf SfYDW tir? Ԍ>-ѕ`۹)l5kNɠѵ,1Îo۾LӉ8[.~N D@ q+˹ nxɃwKeNEc@ n7F~V[Pqv&!P+d^TʱefͱjhKc`LzpnHBS#sY挄z\/%RDU`s,#˺˲]K!Aecy;/D4h9RJA:ӄM>rwzWdC:,1!EoAUI|G]bwpѼA/:Wz +P@t#2E>uށb&\L>itN/k;5u'&t81¸ ו!hvYqZHVaxj\̽uyt"wݘ *p{ܑ̂LGme"heVU^Kgݴ:|.k9txu{zu\)Vśnegԝ.<2=Inh!c+[|`cj<8}~&}7SmaR%TEv: ׮? `fY/臥p=_tn]@WL3Ga`TrϐĢ"դmt}uVEդ!p%aGN@T}>*Kibw5!MvWcl@َ\?,=S8^^e\MrbQkl7Z[w }){h$r۟ Zl!N  7j {B,I 4Tn_LGcOpfKRm3$׏Qh["~,tߦMdB Sn/YN eWGlG< =ߏ+7'Ȏ8 ܸSBE:w (іzx]gỸ߃B 9z8Sϟ]++kmEXg/zv[ tep%tI ò\ ŗ:xVhʹ/PxC)`z9#R}nv% gLjQDV&ͥ. KAY g@NkcՒڌsd!EuSݰ~钄rB<=^*<"D8F\ t4/ (1(Tײx,_V3 x}oY2}*HaKsR$4F1h.? &{ѽOW5bJn5a?4B ،^ #[Dm Y Wd]Yg=fn{QrT 'C%]k?QQXOt.|Z9wUWO 4@ )L\]\V,$~B{ئHu ebrop[ָ) 2G'` [ Zgj0UTfzaua4Ic܅}k=" I0'100P,.ijxϰktms*KeY$'{YPkg$p$YOkN}?< $Ֆ_ɜ̆˓^Zg oь-Ğ9Zsonª\)ls\.O.^]f, UR7yu x[ϐf}q]DzU4z+iJy ;N=12ؕ ^vf(0WC%”2Ey4/,~RަF`",| _M eFI57Rw"ߢ 9ǨoSBP<Y?1^~ Q뢒 &bmw @?), Ѫ* z|~NNt%%a Zw1b05-EZ#nSz`5)6 ,)@{$:7 1dhYKi̿9Y,x)-#0/ڻֵqiNnlLTW{YH, .yhJaPDOi AdB 8JނXK*YgOE{>juPTa/,8)e~o,G!" Eԕ/N; sNFDVq^ oaL6*g/< l./RZԇng(XPDL@/wҹ)$Q aj1f΋<d, :ȉT\ 1l GVX+0oL%O4~< h7G4c+B &f߭uxPvzlwT#3hd:eT7i Ȥr^Sh.[L/vI+ uI: e0a䉵2nc"m68I)p|OOD\!iv/BWrW+DH2+$fј1\ӇjELgCܙkCqW{WP*eU&kt%?WE%#b'Y ;/AFhbr 1v0|k4 H j n`i)AL&莾0ücj, ʜtnQk4׍Co <~h$n# I dg\e†Ϛ84(v}a>.m!XF2z(_ ?#X،rwRGWZFVD>Ah0K{0yQ@Nr |z?,sORc<>զ@%{TCS-A/ dfDNaAm. Hxpd|))2? 9<7(cTPL$g85*3hG1c3B6nBٔ G@kpfqueۻ O`tD5Ee|)ʀakȌ1y`LηD, =Fe }P^gK@ucVB~/R @WۖiAO "$8A7(-D:_X0=zk d+JZPՓ?()_`D 믎̀2<d1X 3(xݘP #A=n#^!?r1Klq6(3]~M)}9#=DXxXLIOVӼ^FLʩ'CItMKUƋf]^д ̑ l+jnSGlWXOmI﫫~yER =M cB2TI C J,Xvr"9%a͓a/; /7BwBB|$Y-ps!wkO6;IDOaB7rfkQϐa,xZu( I EG+&0PGpP==\V6\:a*ģx5,}~¬<.zə-(ph:&ykBi'Q9/je47 SkXA{ch 5ggZtE@ 2$ VʲfEP+c?UԶX\:hj C&5YFIW^p0vicQX Wx̳}M[%*ڐhb)0{4I{j"@|ͽ͟s¥i,JYaL+) >IiG猇PFRej;A`02{kDP9eu/S`n Mn^^:Y`dΛ jLyDì$ ?pL晣_O5 ?o}m7?š'M|Z$8C4? 0ȆS1 T?e}IXuse_b;V )kux$(Eeҍju&B/JlP^0B[.US`wbHa,s2nat(zK4(W1ˍAhJ d/p0Q=*O'}( R1*5'paye/ )M Ƥ6$:)_8,' c4 hcxPAK g9QGsuML m n/,ofS=,>Բvr qC~ BȲ[al$=fI'gE/hsX1/0L0'v|nTӟVa/|D/#w&'+s ́sR/ [ijcI {Qp5@¶jxxl^*cDR^eЛdBb@>Ua,Ticm=L9P7Z7p4 LѤ3a/;Lq/-sDA #e$"@S6L3qY_b4~2k /2$9* m p^OG ?Q6w3V`T#K#aRk<FRCXTQca%XԼM)IwdiM9" niUgN[r\9#RKHHy6sU6?{|QuY}M-aߤrB,7"157NP9Gi3fgjMeN DlBm iQ; IXP>|#qf<ZuKKKuȠ:=٨ .})⦙`2Ċ[6c04  $Ȇ>PL$‡y*/*3 ~ukK I(Tf,gk?hN KYZ*Udc(DAzU::gk2=oDYM{;i/~0Te+>l)S3'hZ3i<1߷ 3 OztE-P4=Yib~D h F^5JS4fZ'utPX[7=R| 9_,'տh3kn:;/FAZ#JtY%iXl%Z6hI9v/8fFZ0@%pY86LGe<#9 #BrYF7n##.6 3 X!'fܔB\6K)h+Yl=`j+(ũnv៿F"utn_yONjsWI>:ҪRb Ƃ5|#`TX%ւcAT˓q ;;`r7H49I=-0ǎ$mD8么#ѩD8d^JPKsC[ޙfX+Ig>ck e̙q A7fgK^aN -˨@U3Z5ci.OR}JLF \]".`/ԤLF~--_G: "fui,A^ 0㼅הPEX);G.1*qDyr J(cfW &Ң1n]OҝXhkgF2|BG'{!`rĠ6zGvy>=#_,ݮq3CQT,\2Ӡ \i䊜o8`K[IJWo>|=U2WȒ6b݂;O.Upn)m0H{$g;uca"6UxHyO[,>ߍ"ɟ& &p*F K~;FQI[x'iR.:Cs1ӪICje2KP%HA0nb~cO'  x*s^ܢWQ A{Z mQl8F-Uli2l pժLl {R,MD ^]-sS=Šh㼍#穲G8qrnt?lμ\+,{v CعI"ty3&W۾K׻qSt.|~|^sO FЙ8҇v-:p #ۤ0tp0N5 m4G Grŵ]uIr)ttk~V<}e@ ]=q渺y=u9`S u}g OSh޿5 `{wwbvXU טoǪ`0tr764|_VVAT|(6nUeuSR8S兩j\ :}aq[41.7)-R&gd;•imx?9 .E`9,/ۈrYcA dW:4a(uxN52΃Z_ylAXR\K)+D8<;>rOa_X0SB #T$K"Re/e̅Q6?@&5ѦUaOHCI+- 1FFFlxPjr25^$7 YV[܈[m]$4q"(A"KmuE8{gW|5HZ rV?5D,9zG jp &  %;v8h>|oO]3;/Ab10[Go~x'Ih3.7|缣@F6a`tlE/j U0X遭E;HGQ:w/2^2xsAkl pG> l7m^,.sGJr A|[HSW9›#Hab#pFIC]@>8v2^R}7(' /^p)̌ i.~E ؔH89aoTn@ R )cR$qOV( XN5촕Qڠ&_'|a%+};>"$x;4_3mdTR,U(Sg.Pw~Ho6m58xjYPh-+1ŏ D%BbZ=ێ}{5Ʀ8 Fb%(! ,1`YJ%VKI(@``KxzIP@%>xyR2c6qXKepfGyٷv$] IYf!& nI0!79~6 sg) Na |']<~ɪE=μTz𞍺muTM|LeYn2FF:YC ْ$/m~xD(k( "91_ﶾIX]m?!mWg"{Gu]^1I Co}Z 7B9qzK/' ~NB2Ìu߈ #Dejz$R-Qh%\5KνL'mK9|c`hwIv^\J L^aID*MIIv쇋Kʙ ezDGl.<0|}Ʋ峩59Koa1%}X] Qd8Ĺ᜗9>j~ y _kLO*8,Bpbs ^Yݻt߲o_Rrq-FYx\1PU}0R5ve:yv O#SF/s=qII„Uh%6sBryr:)h+ iy)=Sg9 +|sq0X3[nXj RaOAijRН\fZ4 Z5uE2VѰ"GA:i[ h 񰟅R ؗf_Vh oO[VHBaqik ?l,'`C QMKplk<(@Zx6[FZsP·#R~] fdgkY.G>9fDMHQFJB90SD.[i;M\R<ſ3c"I~$ P ']R (,a#)iG0cݨ%قeaV-]j?-#p2y7f[0dV`8E``? L-]F3(N}7b1QK=(uIy^X rSo U\15jDT0;29-d"A-9'K?.#@ mfZ"S.nD8s_V}cI$Q NcẆ ]3㇦{}S-h0Pb$լBvrCԐ({ؚ@̹6ӧ"\EA/8m.>*4wh(dB$N'zPXZq0H$_a!F}{6|bw*$6pϻusW_ {#J1ڢU z[:A[%)T;{M*0oesq>IJ;^*Σ8 7 zUng Qq0\\>)y{dʨPz_*d\/fJ9:;*9NS[N#6W]iUH*bDQEK>E` <쪵+n_4?v"awXC&j"۷W]g?'91SZZaᴛ? fn0'~BzOa֋XgZ-H2GQ)&$hX~"McLƋH QUJPrL9t`AK5L l`ʊޑ,M1 I@:LSylGca%Ҍp?'?6nb9GzwYħNs)pG2#j2aDh6vH׹|THSN.x1ËI'PR;`a5(\P|'ɑ -և1^`Δ=cLl~cN-G^ћ+I[OI+DsBLM͸vb*t{e[~A k9 6w 4Q?U1EL17x51@8 /o)z"*G&Ĭ%a쀚 4yQ=n3!C 67n%Hi lF:! 3 -; =J;`WVHBwmr ܸr>A~cii6^&#FN7,W\r{*UqO}26ϮU&,__ӫnٻh`7QYzC/r ig`=+SrI-VwS@,dqDhog^ G6gq<{_v #Wa > 9Lw rUN\p2L5H7.A"p}F͞bS E  ЏA!5 |Fȶ%d1q'Sgl$el jO,$i ꌧ3Ű:aY>*xEoHr%wdV"A9?U܃7DA E\F3U jI8= 1}gm~`ySS h |>t7A$}/U: [}ϛ18h_0]Sz5uJ 26)zJ yls M)#Ԏax-9(قׇa۞N&[X;~se%0I8~F[d΃Q*>Xl)%6ߍin n7$u, _QˍS /&@IDATRn ]=5ҡZmwpD6 4 Aoh+252lQogߛ}ۿN3pԼI@(wXm6pb ޢ4;9Ӱo9! N88fkbU)C@P6AdDLN;\R\HcR/-~|dt ن=m)nJ]QĬbm*!UsV;o#O21[R ?&Z]Iu'0D9$|7[ ^dD`-}fD5Thh-MVi G`B& D RR&f]”=M t{w?OnR`X#oˎ9U*"V<'Pg!ٮ_7Z@ j!䯕(w3& w@=txQ )ʬӒwٯq5IpN$mQfZ 8$@;ڿmk aYZ ̅F%O! wЃ `+d5"Q:glSXo 3g фl]37o{ϳ u1ɊcP@ûT QF$R8Rpa?_Bl´ugo=AnHQ(iFpԣ8ci@{ )2y@).Wx6{/a#* ,p~졩pDƝS2g?pmB?yPl$xy_PG4-yP$ t u#^<^y  pblf&<ëwX/[*gGitTMVkx@xno010)zUNBr $7QѠZbns10+H,U h^+mFE?C%]⤎YRTZZf =0gе=J<.9K"`m>D)8Q0TPI%1 I|yu엫e/S@+2䨉 C{8:rn 46RS_g+>-Q;([g@goF=hjObr`N8 88/}.m6UC+)7om䧸VhAC;7 oYǍV5?-#_9$go?Ӿb@[-{FLH) %z`7 |WJ ^90`d眨[E DcY3z!nSseǹOqm$HԳNIIUs0 a|a۞*I!&TtIwjqfy(EO)DYQ.}55mgm_K^-k"55áw-l#j;Ӯ:$Q Rv59{zx$f#U5Z$AeKa`UMZCFLr88$r\k ckikCj}ei;aoK'Xb KSKC[[_Y UNge0:F֑J;mwM:o)اeh m3+"C ;>e<PW*~$ϱ"^6VO/[&$-q=3T6. (N-j8|VGyCb?+ll#B0OozC{͹o3]KwCnwl My}91rT0;.Y9йWp23ȍGOE:Ga.oN4'  ak0cQ$j*pfM'6f8G+gšf6s=h3ߴfrRG8;3:w_[l{@0{? Thb"Y\,_* 5f7ϱm'ͺ:}ܽ=~ϖs[7bvlP}o]y}[?grшx LZ9jǬ Ǭ%{J7xẟlpe3XMj J̯Gn!\\A5;B-P9gS ՛ 'p233*{#ڝWCUj)SkO ihޜ'PtfbwK<&KY%ڛ XhIi4T.}e6.3pB-iK?#uLeuS,mMYhsx0M8_o!sQ_MN֍U=8мehfF?=`W_2b/!猏2C@'M`r(h\+iF3(LlN,hbvlS%hT)c3SF2H&YTHF)I O O6 3CIJ uS]`2dQO|0Kg]&Td%S~Uzȇ)ڼ66.|6 ^6 EfYlF n>:*ҵnvccuV /w=ܗ q"ʶKe*øx\ue\u"PF3XX;\,MD@#Evw> {C#l&] ICQG 40eEI[EE  ŐH̟?djb0hzǍԡ>g}TCh1+H/I`6-Ju&}VOi;5Z4Cʯ@ 2HPМCmwv˄lڲԂ\w' kVLU`ZGvᄿ.x2a)NJZ90asH!;-ͥ|0_ :ne+8jKƭ j>)Cn(' S4X3v"*1"?Xp ?cM5"rm%LwyURᶻA+6ժcRBZo|XSq>kvuh 9᷸ݷ w5RrJSy\WPhPV4#>5cS}5'<bcjr̝1VyTp6רgɲ-@MyB&9ޮКg|*)GY)oU8Z`=@j 9 /Dpm;Lq`:-HA\k!P,ܾQe3SZ4+AlO4Vu3tl=6NGeP#9u/&~0ʾ 4vYٳȀ Ū%\fYc)dp3Rh MX&hX^ntAQcN<5LJ,h2ͱT\%S8ϱ@H_!AZ a< Cϒ,HH)zºC%pJҐ 94 X{5 A8/t0p+cIVKF,vLQ2G7bQ#/L.>2)çw_nJx:>IHϜH\p{N6>Û" 1qW]Ҝ׺;\[цHwNA3y'Y8ԬJ{$6/ŚMӲ.q٧֎[lcYZMp`*|M:$G̺Y2pAe_̻]kf)맜)BBM)r[ CӞJY~RR54x|vN쐲/p>;ڱ,K@z&G=b?E.c p#EgIT4*_BXo_e^ڴd_I3Chxi}Ms]QnT" gSDTi7SrId%z5,Q6/ɛF^I{WpNacuHKT C ҇Fڱ fz^iR2̂rZmOnMD$_Vݸ.U{ F)2h% `\•ACq>S<)zq}w:fjGU\2L(l&OFce I5B*:,_H3BmUm5QIKH$K_DFPRK ژ6л Q|̸Me/HH \J&aVW>JtTqRɎt5XT~7ROeaVaXh7X3I[N_`&J` H i;R31@wàj؄Ưj'\JvKƾ`P!eP5l/eg9Y(A"?|#99$v pZ ~UlpIpZH%il7^P2plc{ `ҭ'ǁި[vGHՏh+ۚ O}tWk19m7 d朹=/4P?ciR!3dB51WD?0e hg ͬ_>LmFnO=KVzi2Fal.YD; )FR/`@j`;AvCdYxx+,;A(1NH>Kͅf">{% Mh]Gz4J[jGdY]x!+"Bbkst7-dVɰ ã2˜$c9jጜizOFiaye u5*fEfsжl2QV:y7%d ZjB94} m?`!jgC$zTg*(R c -є|zNS>׮C:pBlTrۊ#W|Lģw( v6^.tͦ@إVwh;$> dz5l:Fqwk@9@])$vW[?靸QmEioG>SJ&;•ju 6Od')i栃坔âHjd)9,٬bCi1pGo/~V$:*ǾYnnfT/?Ft2wԎ?kDTʈ4=*4)ΨbW'`Z7ęQ#L *L.\/s\auS c&j@#LKKdߴ4Bݐx, efS:.ULo'sN´!t)nHm?Z3|#CpE) Ohh.z˚!J(~EΔj$-2 6DItF.Wi-#F\X=݈&3gM^) &, jKHU)9@_8.А" @_{LH<s"(QyN@Ref@ߋcEmBueir:fP}XE),)sFka &4Cqe v՜1;k pH:7SfCPR=4ΎrN!b~8YFo0ez{J>,(,qtC;D" ApA~1c~"G,Sp<ٯ@\i'T3l5BbVcr'K-|Q0X@|/ PG*~cop<SҞ?laB ōஃ'Ɓj1”PԈk4FD6 i|11r "msPck4S "H$H sHph=.pm4k\EEa!Xԏ= \"0`ArlAL\I#0l PgftQx~|#PcnES HnCm`d  &T7V#j8;HL>b{3 6Dԡ c,g2,wF ].T[ 9/@'0GF6O55X8vv+|W`k`h5BLN/ /5{y$X'`:%|}/gy Wd\JR+ln2!U,f>KD2|$g5Akc3%#6 ;G17:عOL-!gԜ|0nŸmM}lI*T@MŸ7T'+$@4dPh< =V-7uJ1Pg{TN\GaٷSŇe\Uf\HȭP ] ⥸9G_D%|-Ҏ)B784 z~aZ *.E>Cit ?X*C2Y9b}uVxcC?z>&VU|T9WikpT k5IU\l|+ZL*7(0şJFbHSH|KMSer=qΕ4 /&Ģ{rL]1=8FL{!2kJ@d3od[doPpF{t99Qrd`'ҕl>.5PZd e6 us-/|"kccBׇV2dV<51 )gx:]]1ޘr(iKF bLPu5^jz5J:~OR\_W8)Q4 !}ڂn/M0\oI_y\7md{Al$k!4gxb'gRblvf8BOttOEHG+Ti+98D9sOˁiq$F=d=^*FglTʺ޹b &OK]s@6]A' C#Dp̊I~rX! c mÒ/ \ڤC3جi>~;73k#6gN'o{X ip-$e򳌤3U&ծ{1RWz4+%nxȮOeT`y8!">pFܮoN$B 軪J4)o/{h1{T硭66".<]f&{RS%IoD\ENb"Y/sx5AX!8U‡1)pn +z=pan`XO*9XCq00ev~o>IlL hn+uO(~(膻]L_U[ `)GOijZae5|V[H|IC'piyՍ vjNjƚCRC|"_~{I< 8z|vPtt \Gem_غ72Q3UEa%*:XIꍝ[f3J>"lzNc<>ol6OL 0mΙڸ>vѹ]UG(y'4YVᴃj$T=k7ݿm^eߌB9&Uu3}hN#̩)! w22z U$$į<}f/׿Ȥ4c!ʢ卮U%*.4kT%/YRFxLJ:_.6Do~6o^-'}:LfMǧnlXڼn}hH.þD1VIg-ѠxaCvĈ-_"Hpm|8-ϩ&t;f>;Ŷv5 X ~R@-avN1l15!r+?: .sUMx̽اQ *E&b{ O)$!H^bDO ē#u%ܛ |wy' I|(QӼ嶮(EZQہIE Xen-ʯI3j0Gm-[aC0?,%Ãb4c|#{""AR˞m"KJDW,-ubjmЬj}R<䜓"bHQ"%Z#1TA)bu7&`, %6nVPQf0 52$ UlUcː=1g! W9H. 0E/e嗮Ϯ;LyrˌNGxU ii?  e90:AO_0wMHL'IA7&1RH&dj:كijRBHo0{A'Zf*4gVt{)"=!Iu^d u}UwmaE_Ʈ H '`%l#lWȢUV\fvX:sY4ֵ{ ;kh)`j NQeHAR -- t5ĕ]ǫyk4f[/G B1~l >"_|!i 0c`$rc &G>)btC j pKH.x>f<"NL* 7_j(]s99d VCP%{-  ήnʂSAmC0b +v#A@|4?I,2NF>p|hlRcQqyS , ӢZGXP"7wЧƝ!wc/aV5F ]/gKn:tj#y**moѣ+rn&d=^җkLQi$t |0zLj'@{ngK5~045h0w%$bULU*mxse(=-Weqƒ*SU >:ܗJ<A"^vC2zÝ9߈{4Q_(3WJض'6I "odUC 뉵 OYD*I4 6L(Д}j%e1J75R%<]F'W=\=A{gr߀HMUS9tId#z*{vn{H kN*.2`%I;pOd̳St^)jOo!c;}1NZơjB16od*QFHBYʽ?#x9%hʠr6k؅w?JYK4*1PmW uH壼%tv}?[2IF.'GFS:JÂ1QHaw$o0׃HK."D0NAMw?=׽#:^[Jk@Ƭe鉾)c8=:5o3?178q d;xJS܈EDѻ r?F7n'B'F{]\b L94Qa|>e`YiJS!68Kko');fоjllj3'xs5b(~~ݷQHg ^i.?x(9?NM7n<*,%|1?=G0+= 28Բ&~hr4 tl $i2M, I߄U6mqCP;hLσZ.M;p(Y'f-j3JtQcߝ2ddC3[,hl)HgdvKr@@IDAT@&jm g xV:1!Ud=&kB;eYv%1C@;xܑzV8Aخȵ)9&DJTAl('̈p7⠊P/O%Is1Zw'=3f#VN0 '"to4Bbe 3ǽXkh7q6>vnTy-pMm -Vů A})`ٍ,$>V!6q ej| ۇs`H,-D5U;C3n}> HkoYkXPJHN(`Fl*br^z>D~l(6|sW/4e)41{qHK# ;P!?htlUO 6U}v(īn7].&w/f}p|Nwݔ `RѤ9H_^J_̎ 61-1Uu]LtnQc-@ndjqGY"`.X~@Lϖ X9<Ѹn_vw<`hly\dUϜPnOQb3xс tHcG̱FMw\v2 p8>Y:;)Nu֤i=A cP`}48<.ElS> b"XoZզ`nH鷐mn~. GsY )n.! x2\I=ñV 𪻥y| q?SY[TޱohyBC!_dsDI XKOpmmIģߚGps]c+pjaeY CΖ'LDžJtq0^Ȅ?%ȊȉOI)/tؠy,J,{“934x®SM;xUbHAR-cYHS+.,P!Z+2@{:ǩ$s-4@3!`BUXդš]/7-U!>^tJaLOa*i0VGYa?Naa4W)ąSt@,lYXڗ-t K8ӂ֌al&.13U]w !XM`(BftGSWm Q3 R3Ef#fSh$H`'{Գf, R*56%䊟 zVЋ_WF\<Hα#".@U0bؓtMƚ~EsxErc(j K[ƭ(4ty=\",7#黡y7rSʦDK&tj#`0rj7Fk(laIRGhì|jO#&vV)`LGy^pa9Vxű/j0g^Ï\^$+BkˎIn"70RSI$[t?3aY z;0(L\/ElZ#8*5`JW硥S@5Sm-K5FpoO-)l]{G!TkZM@W.{'yBDzyaB4ICo`5@cP9)ǑmǪ]0>πJi_.qabKKGr0c4XĬnD _> _4"y taJ= 11. %:[}% ED:D;9ц 5gDsV(uv_CIb"-3ϕ06iYO78&#PO-{+6!s[V><%Ӝ-N\?Ы&()53}D+O;x`㼘)g}ۅۆMw{ٯF€Y{ uix#I8)ZT?6Ps1<"ߝv{1+IsoƱd[K+JGwB7Uaj4[hPXzAy Rjv :W CW5.puܹ" Cތ)TQR#{.pE׸=M;%AfmhKfhkrj{KH ~ ѲӆRd$ Cw< ߒ`.=s:j Ӓ2"pӥulUFԯӔm cZQL#eB(.m1!A$4!(̻c ɵu)0], +~4ҿsb_2tAD /̘[E:5 gI!|fYhv 1G*9SU9i3?}x:u[ 4&Çҹ&2@ L\JQ;H y (ȿL֫-ta7A>W|LNh2Rus)*\!2ߞ,P=a嬅0pCGt67`V@VvL-*̾4`&[!3t8n}T^߸Cz=ǖ0O?:O ˟ ʌ;w^ %K62LbzjB Qr<1B3+ZɵMRBW+juOO5_[aQh@qpj 5 .^6,o0v9xljjȏdz bc_AvП 'UQ8pgUqrX)m;2P55yKű_`xr%.=mxo[Ld~L(p}J'ݨ8<2VYN\nurg20f Aܿ X9t8NO6YoT~#f -..\ѤpeU mR|Z'8dr ڰeŮkyX-"8J`7F2[cgYw9Eݥn/O*: rz@`ϝH r; {A;o6UR$P%C;jhG't̩qcX-B*4̂l:F/nn#mrDՆk<:"Rpw>{\&q?aIqEeMPIaRo̹*ᐦN"(v9vkN6%DؚZ%,B T( qiuC$$~~>gU~+ǡWv[+%S!c"}RY$pf@̏P&i:çHzm9W";׹R1Pswf"<.iE~9z!sL/ΓGTFks9L%rr|l6so4I./ɛ) (( L D0N?F 96+ww;j1=rJVwצ*/nu aJ3 X,Iy.,AYhR1gf!5 9az/|MQz%ДTQ%>B2svt}ܵÃJy{mE=zt\Svk'E@P3 AHfDlŀ-)\dKK0XPY ܵ,@J %v~O۬ɀD}o{S::GMq XhݎWm_ Vl|xK."7iМ6|~Az4Ģ!CN=<iEN~{O1h)([;qd] hδyy+3#9ȳ&C%c: i!e`bE ib-bT7\)R Q;FEW7Jb,x{-.'aoЍ9[;s YE)`@[>׈+ܹJ9KMT馹%`6tޡyDwpZm`yWq)U79ɕS dTu/ c,nf%Omisr7=]Ep:-"ŠSH=Ͷ:־ DɆgؗ <\"-2"Q3LKLAc0ekDcK) !kϡy RkC$iqV!$FGp`G)[ӕ) MRP,j m_2-bSߩ c]@d؎>LASSQeMMl? #!Ml_'֐ƾtP<.cLs&w޻\&4o4QI3/f|OֈF:G2s6A,N;W?(Z`a;gS# `HxM:"G N8>pvCckx kE<q+eE&TfAIldžxNN/ +Rcv*ٗ*V|n_0ZR@J^qo+køC8?kmSܙZ%֏mǤ䥐7&0~2PS2ߚc€:Hdt<4r7+5-*xj߯I}{k࿾7Q8#%n$W髶 #λ<~W#<5FA_](d*# 0CxPuZYȶ->/SCXߺ?[@EۦQfT{U3\®LO8CJ 9 IC?*;2(8'Uubg掆Ϟ̣X?u{."!=N((K)@S6g2[Dh|l I%6Xk xW[gԖ4{6U@Jz=:1L)yScLIYN#{[j~Uoߘ/ ?R  ڣs#2hRkoWȸ.F164!\97p2(D_ P@ԓidu:X(2@ڷ}m8rԜ>cJr?>Z#6~` ( M)i-ɐ'F;ϸIbjY})0&t|<5G8&6p Z-l9k6tR?=њ]Mj?lDu`J7;t%2?"hPf NoD +ժh6*>lZCsOc:tp[G%Ag|ڶN߽}+'e(ZogUx5x=<6dXDx֝_ E@)q0Z!9$)㭗M<(WRcF+[;*28KZ!p@)LM09M5Uug@xxz,ԁLDeFK^71X "]nw;vjFp%wDh`g>7EWDqPs E)4%x,e%S J/1F0F[K;8>Ge1Ιc06Q-Yh_8YGEo@q>0<{~iS}SDT* Zvp" ;u Wɣf'x߀^$.'Z=O-a^Y [s}gqQsCH/wƽ' Yl z zh˾ u0.43j̉ȿ8vۛ+_!#V)-6R_ 4Ca 𻯽/sl}uUjbqcjҢ_k͖ "]HhiAzt t@;-SKpi{!5%;Wb"qnПaH,d8wֶKM-=J;H\j9rJd D{svM[\rtyTL QHķbC9 04 5b:qk9SNLF8;O-"W #оSY˵*:>>ncy3cC1p0"J" j 6pqSW!kt73n"JeF|.`%++ ̱hܹ!}e1|3oVqHv2oʡ l_=ce7dl>.i=ٕ,co03bEuxq3Sg Jl.H+dOV݌̐ 'w]l>- +4 a<*#ekmJӑ- Q[ICxrW~ЄiW40kT=[]kV*(AI(׍SUVfj<4UC8W1ae[,jOJi]yow!2iCkz}U ԍUj)"a-Yx+Ć~MUH1H#iFz?G}AWkg^@' V $. ~yy~x~1v!he[pGj-50fLM@Ņlدkwk.Wtzy B1v|>w}>ezمO@ ֝^nK(Fv-ף/8faq*D ݜEh2]3gUj>59 F'X!3 ʣ?-k;q\Zh1,lم gI:3cbfV :xQG˞ j)uVP- &n`EW{p)=N%~>(z$D8,ӊ͍XހYGf %ڲ} 6Uha]](wE$[봵۾nDN}(QilDҏ1!X.>uc *Dp"Z$\ GU`$慐ЮMEX-7Îz|/K)9 (F=:EKq_),TpyޜxtKb"wCe:_:UxƠ^3ɇ Tzƭ츥k9! Z1݂-)Bm|-v)#P=*(UwcB@A9tggJ4axYmM)9A3"5"c;߫_M^}Xj* W h*qhQ* ʤDI')@e 5`QR:E}^F+ 1lhu=WÝdZ 2Voֻok ( t_TCcEoT]vhH3R )y0yBO1(\{vRpMF2U1ETGDS&?@gj̣2 #F"qWu^*HF-K'y2f,@\ m,É*47oe_M%uc6;߬^&%X /FO& Y_e8nRO{|kYN`֥BVp[ M*"ӆU=Z(۠sΏ/6B}k'z+ OZ[x/MS"hӧKeOhtaBam^6RJx"SצD-]q!-`o<ׯ33;NiGn S#Ŏ;QzYŸp9#(BCSɺ,s42[^B"1s%$ijKKC蹡+ ?W?l  P򣢅&n[!Ia OgWȵ=HFJj p7VEN_o|\^lg?Y'OTZio`N:JDKu{[mrMSAW+x yݑk sT٥@[V+o`|Oo!LM`#IEQjPG0Azf,&ndⓧ'{6/~#e?ƒ|@~Sjُ2i7ec4N<L5Qf#VuM-6sa( ,+WILzL+ԡWVZ3%(3P`?~,w %F)2[i `,khH68YB>AQI:=D/ 4hun77 NSql:'zʸN/Ȣ3F̈́}Lݬ(Fc~(Y8DOA㍺ZB 8p;.BEO:BE[C,+}pߙgzk&wO-uez#z4O=d&x>(&# NzlG7/ HC"^)Ʉz˰.w(j8X 9\H߻R>q;-uoI?3F|+9buCwVpALmBy[[&ym%Mv=_ޣ2PnT%rGׄ s/B8ّČJ"œ갻gl/|[+yfwI")ڶY%Lf8G #. ɉ^?,k~95- \NyIcq1B&$'aID:Ir>ՋzU/#)$FV>f*`go{B`;i {j4B #ʼn8 \~m$ Rө^'yŧԳ9QDsD[I:@A7dקRF2oJyA;1F E) ѻ/amSTڸ[An\(}b#0%$8M{mtQ[Ӿ" UHsvBAH#x=&ֵa8-@so/QcE,4M;A*#e ֛jJٿy#lqÞo8ֹb^G!\u5@k8Մԛ!IJX* \ȒWj6bέ"j5@}zc RN +fGV{FS\4!gԺ]ݴlhTk+)I!ZaSORORC=6{1{~~um@Cö5 _Ƹ okW=vĠt,[mmG󖅉c\ X= mC5twqr9NDY$oYY٪ |Yj3W B;܁B;p5uT?W^80r2 ҈33Τ,Kq $  ppynFK^]hch߯zn 5^_.ܘ¨3=VKedhUgeөh1WL9x]KZ9n%v2M6;wt>cg94=`wyu!pBrL+=M3&BP ""GASmk:g$3:s$5vx> xӚ+ -[5,tyzTS_nM=-5W]7%Y&JB|1)qX<a.=s0UM$DgG&$Bv > ,wRL pfXXsn#'JQZuVDA Q _I5+(km(]ɕ3EB3"iy03E~d1NGªӁiԉk! x! iEJU37).*+ɅfZ%1@53v@]m2%𢝰[^m)- a,(HV 8;JWC3.[:z.m IG%VxÙ0L{P|ΐȀ<Ej1ˑf!(ItȈgJbUɘ8Wˉ)J&)E\tRwM@Y?})6 R%a@.]R<9Ky|qBLn ]\E_D EybYkNAh5BC1-EҪ2`r1EH@ CM(,kģXk%6:EC0A2$qǣ eh+"dOT'/wp管oA4*>Jk+%7.O$QaO$OhIFusU"&뀅G.82 *F$mN9XJ~M01mE0[2h5GTbv( $4BCa=A _,F@gEOJX\M]|}d/{ub._YVk Xd2qm;5A_6byx_O>hᢲW* .o6~i!d` N# !h,DJױ~JWTQ(mwhH0س6L*52àכ^0[z#ڳ0ocxhpQu/(z;3@{JDMOvI2ʑ >S MI(՛:Li*2^oyFW5o6~;ʬlH،ڀlDwsvy Trzw^CBp 78bxs*3g~"NF4 U#iE˜ P6 ;PzX> Q&˧pƏJq1]<44>[\?^-REچйyD=^6?i|!h5ǫm&=[h%ʆeMb0-bĮmdH6/au /Cn[MG&doS"fKѐQuI#1X=Fi u6r1udQZSd<(iƑ[kR1-&HOL-S@ H.df}틬Of(d'/A>&M$4 -bĽY:Ml>)zL3r“yȭu>Qy 7FkD!kH?#9KrLR4d"gHqS4B$Pb5%}у.!;T;?/>|hvW%*d#_-p++j5@Q/FR*?y `MCz' O׵ǝh! YƢE_qK3>=oKƊ! LVvtSqNᐭ\inw!f[Km}5 yEͼ]d,e;uiR~q}"zI0)22c%QvcJl=Ng$2`Bih4?3r1bqo PU]S- xҝV"Wyf: z]̪#4pB<كtsy = ֱ Bpfc+hGK%Q<= Ɣ8eNw »Jkw8` gɏs#ôLrߛ/mk^)n0ZdZ7($(9Js=#\V jc+J^XzjoTy^++XhkIh:hFpcb9Jw]ajy̝leM|1G頜Ab fbkC?LaR4xX ੌK}H!{Lڪf@(h#0'F1Clǐ=Jxn$H[ջL,'gE9Ɛ3lU4! i~ѐLyz0rV;HI=ꓺmC|30WDWJ62҈WWSy+[r8ڹ*1Q ܋|Dq,ȿ ¼kw e syqŧKEڗR1.DC튗6˷ 0cYLZ-RU}a4x;gm^Ah3jBL$|Շ1)a$j K<8M:w|<,5B '=M4 HJ[CPmT/55EؼhZPީ Vg\U3MLrDRG$KU-x(M|TT)ωˌG}3W\5 =}0chvpU ʅ@a'v)bL8GQk\S]|ꔶR'U*TE4&̄|B)Ms0"i)&uj TJ㸲6XE%)CE'>R*FfiJzvXP#Q#ShAL׌Nw`B\I>qsl̆c ǪfI^UM_J5m%D tV)@scL 2,9ScJWq [|i3W M V(,<֦LIm:5yQYruX$zdQ,.ufd:jvMƀقba/s^v0t~T|>Ĵyd+qH>lG=_VoN>2wkQg˹W2nO3$Kc}T)r/zmJS_xkx[;}~(SX-e4tnrnBrzsLcXh:Ѡ1Ix?Q m2u3 2GUlrVz cNyi^V0O^B*`{yWQ+u*@\۸/S@1bGrLqFwIzse_SĪ?(7,USZ :byYٶjg3<3eYHj9N[B3nQ!.:|0\)V3Arud*@AEYڅ0)/8jj<"f< rNrs&5&c2x _𡲀O/VxvlguݔfSKnpѢ,r$z,1jd"X5z*qvyh'ftrSCTu\Gb-Vb`ɐp9RgY=c`N)U-ykPKoe"vK.fD"' $.JY+7 U73pgP>Y1 #"1[BnVIЪ50zc=Dv%>^>>c wѴ#>Z}MP̿}*p䷍h^$Kf @y2Pr hH+Zaap@uݽ#JiT 4EzB0"q/tKMg ڟeB9,4xW% HS賎=mz'ם ZpxAS"榀+\/ou!Cr!Tg1q}8[k\ iVexG:´:-LbӼ}z44J_BNT0|//VZg(P) \`Ҋ6P̡,,:Q~TS p|^jt;EXPyxeְl:E}[%C!|Z¦H|rQ~ּ(CapXYdq+g>m8{JLsPϢ/Ɔ Tmd0x,đK!O\ǟ)`΀-Fhz]snqcwye2DE'IXnsȱW#@n{+VtJCǬ>P2U'k/nV5;҆^y @EOMnz>4g볷vJpjU4Ȍ<тArk P{Rn[}-8K )%-}ld͸F8 `:S|4/yxmÿAhD2>@([7יf D~Ql"[!0)"⚡8Q;Yr|Ok^ Xa<*Aɒ:U4e>XKC}$j󺺜VkhӜ"iG7ım-~Rt4Kqnq:ySLj[xwo#lQ тPgֵ9~xU"vqfF^ =| P􁗝cnx-=.vY O4Ajë'AےLl-묔PaK`1#Jv)>-4p>UVG+C\Zzh,p͜eq7Agp|8$ Wޙi쏽u8]˴s)X7K3k)$pfpFS4կjau.r'P6Ӫ3eQ؆QNժ3;fw.֎Ti{yWR9o>_?-fU9bJ&9IpvUJJ*u~K@j ۓ}ڞcKor;+6pn6Q"gH?;:I:Vň,}W\(deY}^هk.p@*x~s.Yb{_ƼnToӧ+{sZ_!b6X82JǦXr% nɱ>:':P @DSP+C~t%Y* 'f.].3A &JOb)o R>Eḇr_ڳ(1k xX] AiĞϖX:DϠ؁_Mޙbux 8ƖZ\q&:ҡ0J mw{}zb`9SIN6{: 1S0d¾}a1Q6(ijAO,2&u.R|lOYj,uavxTۨ&6)Jy6<3 I9ʏ+ @/@JwT,L-"QPEf^ǘl S2`+r"s_=3m;e7=- ](bo΋ע"XpǶ؆aC~)ДHܼ]S~)g l3O tN#Ue] ~%$0&U[g%I.E\$1l~hg^7}ScE|P'y- :%gQB."'zm;+ԞrǬ=l|5+J/x0 5UZ%6%*OlP 1;MYcUf٭צOo\4vٓdhٔydq®HY90Lɒ dTu;inWaGS=>/r;//\#f "꺪ķ_rzʆ_b]Jz0]Ӄf sPxLB®`> gB'g `SJՄCXXfqh_05ӷ2)+?c3}S~a7^jG=f}c#aRiєND6pS)HDrR8쀒1jM-Ј1=j'2a@ZbTn4̳ 4pR=|KAy%uΐ eW͡@ڈ ͟"Q3jFЃa0u͇јb=n ڈC*ѤqN'*k5=:Z>I1̦}&ZUςmcAKy4HG?Nbhh`liݔ\'*DW ۡv 3 \lvi[H>@__j]ӶP2'gach -tABc*>%35vKl5$@4DZPM?#'8t\t; >H8E덓 4Si i-9`lQΟ o,gDc^xu4#Hn@  E,5|M3;kTĉH%-0ؾR水1B4@K2fl8ȪʙhoVEx~tMd%'4v'T $>U[. װ oR>@^R?Rev\l"1j=s$$-qv⭙h=>/*E5a;➋Tet4jxt nX"wñZ-#^2ަ螙E7 mT~ ȆD!n g=ӋoiVђZ.0KkSShݩq=Nyݺs B!`2&M}у+2QWSQjK8޹:Π7Nge'TuC}ķï\ ԱKk"f<Y)<߲WĄDJi *92D'ǵ"(tNdҹL~[$=Tz#ƃ]3Jr5pio96甼8SXd֢>LJriqxM:m:w]VHHLTҢ g4O|SS]%c~~]٪n,1w끱`(&4km{a]nmt(jΠHXCDq[^7)Ŝ$Xd:lKX?+jydItе ctS8؈ sǫ M)jj–Gxگt,E0WJ?iq W Frix<~TzF&a3I,,k a`BL8JMI cuf+e-zDq_>v,IH|[=ӎOʎJ]OŵW3q*ӖtsK*8^6GSdw0 Hi*eĄBe)R I,D2¹P/zԵ#lM&_qshczӘs#LX˼p`$yÜn3xSf4$Z_:1j¥))aXXM|㚊{:f*O2FrfŧB"k1oD_/84Lq77^k:-^>5ED*M[W9~P9!7 и£ֺC+3̹ -r"Ҟɮr$wr9Qtʓ,vH{^bD Le! n,hj?6I+huQ#XD--mJ) ( 0f8/Z3>fojR"Ӹ8!(AlDz'LPSh mF /wi8P'uS+ĠFy/lULj_^͒O|MX&]C@ -޵_9#miM-دIq+Қ^X pUfVo\ %K$s%ȝ6H%'EO\R̩dA hqe`g[>ޘXDT^Ke,Ƭ|vUTJe H.5x5bᑁH w Ydc#rwuA8j7 m)tF_';_#)xCR/QI &MJ[ȴr1/0wh$L̀=<$Jw *\'CH9DvEbȘx 0XL^.jW9*e{pƌSĮ*G8i4C A6&a&dLd”a2x oHlNK:laXH &.dO6|qx}{iw9ny# ˍq#{ط7 ;bck0ױg;"u>W(e4Ԃ34C2{f.ŒQr6^Fd[ENBh/1FuYcs,Z\vTx DzYLiH%䊑m|- 8X;[fxJH#I+#H@TS:)i;ŊYVa>. ~/ >V :lSBDBaz\17M$a~zzoI(݅w\J͂)PrR))z3Axn=(m7kcgl}SYuĀF gn`\ 'y3>i!pHH38p+hcJz."tW$b׾q޶q23S.^"J/YNgE- dngmy{5;/Y.@>@x3MfB{Ϗ+⏛77eߟum73 F_QX,̌!dfcĎU9RWC13+JY'y=m l3Ҭ\®kyc PF3rXL_b}|['RŅDB*~=""-<zr5O.#ͨv!7@A]g̖!R`uZ.gKFxbkChkG) E8h)sGoKj'r,;f('2Cu<@aK!"6Y(~%2(ju;#"m\AպNȓenk[om@=?8hý~'!(`/(Ȁ<La8' p"G#7/Ϗi`f^iҰ<051Ys7n s Twhy$'W# [{|ݠ@h7鎯)xF:MR0x)boc;0AԠ+Ԍ6hc%uA'Il//RǩVcӱFVm66"j.zZC6Zu>K(cSW$E-lxƂZBSR]DyyEĺ~cPj -7YC ,ء԰ 9[4EEn6Lg$cHmNتO־-p tSnA6ڀ? L&-^|(8`,~57|)w2ީNimn5z5Hl褪`7,@=WK(r#4i&贁VZnmkE=2Ǘ̙"LMQ?V :awn<4MIP^~PD*j r=>cZ)Ru6楙(xOFpS//Bi@2*ES1e DמMaı<{GP8AM>Zw)-@1/Eÿ!*Y6+%.EH'q#||(b//U)/RCiO>bNw.+0dfjw6qiyZ1L]yI :&.+վ:UOvyhu(FI lmK(}k Ӫaf8޶$,JRT:sLC@毑=vÏ{//c*AGy~gdTfϵ+";=ǙgCq3%e層B!yLZ",zn9 ]itOLáaEp-N-zwian4py)6WyIHQãu:7Se/|: [%s0bogˣu^m`dS"1>=ҏN{RՏ77hs+Xnpc:Ar.b;2sJb=G?[>ļrgIpomU4.~;b'1{ܷl"#6,>^ 38h6E* ߽mӬ= t&w5 ,z0XKcgǯQ;W4`ZWZ$3?Q26#GB*$`:@VĐ eS꟮`֕wr _:{B(j ىmh.ķEدgG0I ן  ?D$Oqֻ' |I9m 6q鞣/:) p@hW4Dxiv. hV9i]rw /VQdϕOl kUpɭ*6 *9Мf3Gj&?iO|-FH88[Oj 2O PskY6ȧp\,dj 4ْd i=p!]7E憿3]/_)gSj{ D hZ695>b5AίSk%g_ ٹ㭙#o I!זNfg$›VPKD C# !"--#J*].\3˳9Űo8 z' Ϲ0GCC+CUۤ? Lc]굨s#Fe Pss_7 HGz',59JsIh2'%[s\"^Uaevys>[CAzwA5+1 Z;4o")Jr5t& +/cB?jKx8&D#dq{ .E%"눖aЄ)+Hv`$Vb(9ݨ4EH":H+B)ɗaLi읖LXؚYIJ{btؘ|괈hf̷_}z92/ qZ'Oɏ׀{Ź镹a7;Gy 3{J?EIts|>%v?9tbW+yty-.ؙZIG|_}H)S+Jz$l/M]>GOV-~;Gz&#* SH TnJi^E&w(ޝSx "Ki5KS?Y,fNaN C^\nr1Ӗ7[&4;柧{8W<e4r*|Ƌ2 Rv&wo)m_YO6e F %k1deEpztHp˔+ _JO-|f'3p';[} ~RO\CK5|eH<}Ȇ aZ1,HY*2iH3pN y`g&1:H sH>0[qi @k}X:tL H=|lWa~v@IDAT`&&s ՠ,k4ܾqAJg4F"lf@c93hgݡ?δ83TxVqyֻ8|LfK_$ Vj yإTں 0`#(? | ~4bH*r(iPN5hqa`aq?վ@a^xِ̃xM@N`za[T*7` S_zDR 7>0q=#Q"Gpc](9i؄)=ac7o8 5KA8 8 ͟DaA'(}y;۰\\tX0 h8nvQdԊ~RH/e7_GZG3Hx`Ƹl*&ٓhKCd;q1flZ90E5?daR 7Ci+$.Dyp1Khe.>KHh7$1QJiD?+mS#U -e t;_p/;%eM{7auvvlZOdԢ+|"F'MѽC/_ģYfi^lZG0 ~ɲ5p#0{qebFSqݬ 5ߘDfmmEͼJC }TsQ[Eij#؆0" imɖT c7}p0l1.g b^VE3< qp )Vy0X9SO3 C0x* 5qZ{h3b?Yx0azqP5ny̘V)QwcQa?7TA#cZ89jKstk+RW@wweGmfgTA ^^PUh:/ 焧Xb)>pQ\`S">etBRZɱȩkK#òsS솜#!̋pQx,ϴ gXa&>;ԝ+)>tQhk ǶU/@bou6|S_)kikmԒ^fG| Z]fكx b'[9'qdS8pG-^;bRyTS$X t9q'`?@ؙ$>19U^!P)Y+6.=GDlZc*@Z+[n#$^5Z%Hiί5`~?8-  #n/tiW!9e> H&Zh*n̠*ag5#2AiB((ͅ$l$vĔiP;H6-&k- qu؝%ɹt qN}ooZqbƯ5epNOs98;ת ծ!' *+߄`\ޔiڽ1[ScFj˹!:tͳdbIDC=P"0$5kGR7;*UP5#BJzu+<J)pKHIr-'[~1def⬄(>jdA{Ttf#Lx$hL$6 Mvh.k.!0maDh#pJ"4Y9emKa7OIO7)n-2%i&'BzD?E׿[m_P1[%+]DHqF s㔮OjS5Ѧi?116l-!{ih#S` *ܑM W6;-/ؖA|# j̸q3mtKң0ÎݮȎf92]J&+B 9!Ců1Ȅ{It&cBрx]>|*x>iC}͊{nPHl)g8ajOo)wYΤ!*&FW܎;'M%[?)rFBG7!wR cnmHpk %Qbzݵ:CdL_Lʜl&iwiAm`9g/5Q@umg{97&vW]4S13f)9JS{kPGYuH8 &O4( '"U5VGhov2RR4B4Pp&)ܔ͒΋XztAKC*e%z-0%aic#D (n$I[ڙayA|sS󮶖5PWXf'ekRbt6klEh .rn8ġ!/631@Çّ2`k2F.)^_]_ PW| On# _ OMWw%h3_CHTᨆщo[8*wC d?M71 '*]D$ϑVRxr7T9AF> & %8_֚Ò%(Nwkvq]Ba Xhao8#4 U`c!.ƺ_aj9$)̷%a-cI=9mahX֩vV66OYpY-t$Zw']S6nw玢;r,T% L iԋ OZO:U)& xs}h%{qˏTgE=#8'O7)bRëZJx[Rb>Qt{ݝDRz0&cjh.3+UA9٘uzݝGT«-$ x%-Ђ\ы_շ%G&ȥ7Ibt` 8yS)#xqgpý@SG￐;YtmQcm'0÷|3Q)hlI3(VzC>(ăbnuٛdWI:vTi<]5q$?p[zth]q%Qzi2{⬵:Qsm:W5BpMcwR$Z}i1&`U$a)j!E~dgtq+p=6M$р#SQRn!by UZbUѹ853=[haEc`<_j=ݏXO(rmJ܌E#ȋfAc&AʉE>YlOp(Wm5H)E ||L$]虾s/x}mE..y b5{u#KCK =1]RISTD&E5F+NNx2}! =3[L-q 5rtnD~oA8H.ADfE2ALp)9iQc,J̪QM@?svg*zxzA8)Os;io}l}{)Jvqog> )?bkR}:Qj>̷EC2sXIMD?\$gp nK&x.aXyPmǪd@\ٚ s|MN/mCw-_[DhYFz83d'T@1yYvvu?Z9g Ui' ltKHY~miHc7 4Ɓ9:TMҋs8"6Ǜϫ]t<@Ӹ\?{}ڶYCN'_*KIV0_Epl ֯"H=.}.NaluGpyI똺̂d&诊F!J7ψ-Pܐρ竍ge$#|ԲPR]Ɋg){#΃hDi>ZfyJLqkRx}V59Q ,gL%lrÉ=WH3)m{<2Ud J:J`bE2Rz6^]OYRj@ ~?`O5ٰ6[(LZ={Hj[uua$MdS0臶Yj[F-)DޅU$~hbCRAS}v\4q*+Z7g}?/Șe#Gȱ ));Ƽɇr}!3,U7nPe;>XǎafO8Q[TX siך/ ֚?O6+]A% /QN" ,DmrH۫He%WQuX|`Yeg^zeC$c_^~_/W;!Rv`1 {4h/c 68l yT.V6[1Mqb强aUdYQSW & V-Zʄμ8{U#{۷?]6W;`/opAV##X4BJ2y[s%& cVR)KFܻD zTzD}6w#dJYX=t-؇vah?"n_-uSid Z[rW;k?7LCuP/:-Jэ-~q9 "̱az2278Ij;ij.}`Ǐ~ZOۂsmS>v( ן:`(Ouz+:~0}B1r[9G: !;P*v2w+IK)PB:>}2d[e)W[+ƈ211[VV y0u{ۿ8w8Xꌑv|l[QXNj ?ߎe*S٘U` &ΑJ '_&Fډe =*X+*t)=gs lZকt9+ }VUX8N 7P>fzB'N\l29dH7#CC"*?vDB1ֈ "P.{Fѹ!lm7jǺ"FV pzhOxRf3HmV'|J0e4Ir2՚p,Mv]7DzD&MvHngM~.Sr< X͊Aiml(ΥLOx(yhs5]fH7EXt9 &2ð@\nәp AwTQ͞.o&n"w)6Ý<{$&PGR!CÓTOۆzof.ߜ؉nQNNjr2ZY6T,Δpp(YB4ӢN~Zy`~)X+F=XX>..v/i.va8'['9CǵĞ DEyѦQGi ;F p*x SsP^:)ȷ7)r^`UCt6pa+eqx*# mJ??D瘝L_4ȑ+EA@/=|acfgB@؛z*DgaJ ߍ A̩R ;mpP۱ZWe ??Y*_mLsUK:xbh: 3x MuQVLOp23PM+JLdsԬaYQ.'`.rɭf(j>m?'5u|a] T^䔵lh>]տqʮ2AIQz zpkYy<[ޘGQH-l`>r͞]S/(wwwR)q/>oе7$-)|{iFq=b}$ȅ|HujA[VٽiS 8}ꐛ¾P+41ף&g nt'z.åwv-2 |R'fm!)/hC̩Q⫵%,̡N B)*eBH\rH̷ Rh[+J(=8U{21P#u}8Ț+͢Ŀ^/<%R.5])qt.FIS=-͉: *tabѷ,J~'o깅+Zh]P.8uuʱ-ܭF\c ijw)j\"L-у%謣*t]k)ܾ R1܂PA dE'ۉ6J c[*>vVѽiy܈p1HD#_dB8D}=>694NsA3`\-aĂv$R\g^'#;pۀ3a2`\ mu'7#ǃՉlV?j]<,%ýY MŨH`GejA"Z'eշaHHR'ґ?iLY7(K`BρqăSWz&Ccm"W|hHHz?C~bZ hAdv#xuAC *l^v4@9ڕz8[6E6][2 O^,q(U¦VRܩYxhːn, 󡩡t!Fj T9"ck9-9Ά-oxLa*Z/{F$KAQRS^)VMqS20ۧ7OlKfB;TO!M+eц: E '}}02yӝmG+ z#Ɉ̪wZK]HKu23Hݩsf3 pVnKKd9P0aQ3`=5QSPg\v}0Uqp{Y CHmo 2':7 aH2EFxeadR6`HRY^j ~Eȥ$/&))fYƇ qS]}'$Myp?uSO?b=z֞V4Qneȵ BUB"{!c X$"ΡXs $MnXGE2^ , qg(P #ᡌ[LL8!fv'"=̇ z4/[pAg$\duzښAnL7XXӳ.E]Ni)u> 4DUCăMmR@>#R5 ؚ ξZ1xջLC"zт \dav(Ae^/ P:B<[fP-N댢%0`@^5l!ae뫼ˌؘ?w̮˝XTn|c#2c,i{`+qe@{h#Q+Nz4FOp1󑟗U~D v./#pd*Fs$:f@)e4~X*>%^F3͝d9ps{IEK)=z^46 F%'s*zc??|hC\o0X‚ EmA0&vu9H˨JeK}RO~#/Ɔ=g,0x$1v)X%@SKXBSe: +`g1V04L`f0sP)\QX Q$ęzkNi+:JKcN=:tD-d,7H^Ԋ`֧!K|ZI\B&}2۝*Њodu;40FWXVᕕ}a1ir|JmlG>:hD9zVFVh?:헗Q4%݈5 6"!At5Bdǩ7D\c浙 ̤&lT'"mS6a-LDԎޥeaKm`%B4̰Xөs)A)J! 4tհ@Nhm4{\9ݓ ɏq1c;RfMW㤪 aa +}(yl[&%|P=];]3R|y`{D]\Vz}-9&{SP0.6&QQ/KE!@"1.l i|m4 lؽ8LfV[8UVkܐY  d%F (Y;|`ѕ#ו~Bk]Bx_LzvFLH76 b1n5ڢ6X.m+WH^xҟX[fbAe?Nq(MŔk@.Em5‘H?:!lc3#^x\6[ u[T뺌<#vi= GIt|{|\Lx.Ah_FC4 f8 j c) +7[vA#i\&0E]mmTӖט Zf!P/҆%RX*^?>>޷4 jb!$ذST"QP{$!=VXWd#O5Ǒ~mhތisJ2"1JѪFʇRX'Cx?IJ虬01ʤ ~ޒ%U-6砰4` !#HГ#ȚcUQ0e`[eÇ=M/3 DW}vj=BaFؚA^W@*qF.n_iU:L;hЇ2% >} lvE!gY6㻝4`9E/TYN3E`ő lUnjz=} Q3q ̉l'Lu/=3ctJ\⣌`(Baq~no: 0P'G`&vl?ad32x4>Ct`YAxOrgA@Ak†Ҙ 2MVr='` xz>n7>܌Y}d>'lDĩ8Yev"۝C4*C2:Tͧ|и8sg8K7P/;P-R6Dwb0-Sd$$< zڍi$Q;T3sr%vMf"d4`&|RvBxBmXLfS6Ar7 w6:_g]3f-4rheb0 '|Xc- hF1;*Dӡu@$bLzbrLI_dt,6' AׇuZ)(O$mԵVx $O?(d1YBÅkud>c,{ѻN. g(.D%r>+^Ιy]1|Ft2%^% x""r ӷj8; 7}?;lE}n(`nRD׼]£DG?#YCi&S;3%o)2;@a5x()OL5n gt}\>ISz7guX#mQ[??~ZKkTB:]_ x6sgDCAnP ǯAX,hq)`~=jvۛ.( gP팁[{ŦB9>{Rc b@H@N dGQA""Lo/ԅ<&o|5A*oC| Qgkd5z,t⠶ *֥sv'lˍ-5^VHȻMvɔr}"Y6v{ 67E) Y?3NN} 5ˑ( FXH1&TSq:o"b[@L~`h# %93%6pS@1E%hz?/ཀྵ Z)TLGw3(l]` nqXm,\u<:Gؽ^Gmz`?gc=Q wVq<z_4xG#z#4c.F!"IXRd/bf^ iJ#G.fu5cAҥKA x=F[D#P qH(b i؅ {r.흇>l(TgytK4ٴ$ĜƜ"3|c\u5GCwU[Տ\Ĩgs"FC%m+rmy<4҈dmߘ_B2Vd(Sz 0?(h%r۲t S.WDWarif}Nif&<|y8 b ҷԊC/KAKewABo ^@ÜSvMj?l(t&w* fRodAJxJ~c\I"J( ). ?Ll=Ҹx ^o+Ds;؇Ԕ0OD DF5p2=㌧F%hT^y@)QCQHJ|š]7<1<2(Q9~bԁT:Z7Œ>YjlPϫh#9-rh ֔rzvTsN%1H9Sm;x I|?^r1.4T% yKGzRT(Mʈ5뙶`mH01l&ڦ 1Q8m [ ˳Yf/ u p(3 ?/1131rlkwZr qWtM?.<%@-)gJuM"`^9gxЃD :aS>AqY iQ(* 5nmqglZxeTU&v"uYkpa6}`+[qfg!gGݶ_}? 8 I0R_(KMX-f0c)tSCZ_ȋqb_3H0 3Z'uu 'BYd*t%ކ;(yQ+4VM%xj gM bHlQ$(Yfv"פ.g;B2-yP Nl"Y>WO :$F8M< Vg>Ef.MZa@? 7}.nLP)hhҞ(~QL]2C4VD3C)#Jv!!9Lu*s/Al4I}"ˤRlkg0iʌT3ىe (0gJ尥Ox̛Ϗm߆;589;&'5hF[RME<>hCxۼG?Y1!*tbS ˥#kߴT8r!S~-̛{{'T@ڈ4KL`V^KV VdFNPgHiU0trB' &ӻAt9Ib-!QI"h}{ԙ .0j d Ñ zZ?bK>۠(@n'ffwj= _)P;c<̌x {&@[Q՜ oxŧa1SE -r e5AQTL^܋ µI`Ai4 Z}@.+ )h:ʪ}jsVksx`zTs?4 h,'SN\.FFјt&P}Ւ0ߣrBԱŗ U[.RZnuzXmü]\T1F5ߨcuoRF,o/Ahr K̏ZkTaj)BIwBdein?ϝT$6o{$o+UNs,l&'ٲīDGD_xꜪ֘]$(U(D, ύ규2|~%;t<[ݣh\Cr8CjHy8 |W'^J_+Kʚ{ r]pdOʰE5^{X MNlQeg]k<8 -=]$2jNfמҐYZH !;>3`.vT5ItR#WL g 8pMgLⰕą }*61{*6'o27: q/޹<_K>c Fl)Qׁyϟ`' jOr|z?$dym/S"t\ Cbt&۽{owE:G<` omA=%h2@O1Mֿ _}Evۏ9c}۽<*?qnjdn%决q[oHfaN,\Ӭ;ct3`uP= PE|,d|Yh֔:H#~νq@-˜١GFͅi5 u: BӶm\)훹KˤviO 9Cڎ,rݘĚznU὘9hD-ȳ2sHQ +k&%!j@.#[+& MIqc/{rz&T'y$TQn(j}r6֑4װ>\dcyl>+qO7y^PunX(u{+?e3AS6֫,S83v5_= 9qYնȾq)6Ъ dbhioéx_ɢOuDªDr;aa͇s#rkdkL XNY$~F:^eket`m|LϢj߶eTHnZ[frx҇i/dO@xp-߄T]NOm|{I{-w_W2+tܯN6'Ϸ?,[g{k(PV dC!G\:S{3?WԦUeF-0+Tk^ހ"B4}XxbN/"SꅡM%LJ4YYT=f>iᘩoGoUąÔ cۉ276o0 O/;λL,A Ӿ%gBTj1zJ% ˋԓP2ЁLsm^m9Y#;꛵/ۿ] iB9rSs1EP#i59)9e*-g8\ I B8.ѠTb. Kc2Emξni[b F'BZu5h`n_ P#e@IDATWsMNmV5tƙaғ ),l8-2hsHetvּ9~GOĄP1 FVoTZH@_2BM_&l9eG&lVi EZA fܮ\cTGuIW"0gzcZ1\qE֬+\3{x( ^#|<'j98H Ue1 ̆&ڕïM1w0Ȕ9(.,.DGE}?JypZog(U 7AHE85p('%DKB{ u#4ť 2dh DÉ%N#$T'o GuRQbo !Ebk6 `^W"lC͡Pys*sp%Aʱ35/׹e~6MkߥHC- "P=+e. 5Vf?4"]&[;V7<I* *BTꄖOOR|mAP@2;M5a`M<<5i?}/c2{<^d4;$e p%'Uw>l+)u1V/d#GG ؼ6M?Nvh:yn"gI|mqsUKهacO:u&o@*R g-`Pk6~&mC` z2m+mW0;*؈xNP*-:b<]0P]1"#Y:%dڬ`^\`7C0ΥB"f0 .4U/-cҪ/6G 9ơ 60L>:7 Ճhf4Z3{*$`sи!02m5DHı4_%.S/Å'K Pu)U 2 jǏϏ?6Zze OC~q>_!"p' iu& St#>e^Sc,Dc@'?كKfU箤hUw'ah}C>%i1X۴&H(4$I(t=9%1mLJh%FV;Wer!\EGPB5r8#{z^ HAf^R$MQ H8J1E\sf`KXa fqj%/Iw?(8fqk&`:hID9-K UT$!a[q0Q+u:`s-Jb +Vr' VŽZ~2,E$^JFqpa1$ ]Y l*yg "7Zm Xf y 5J+u HE($\(|Qž5*eoiPaGNO 7H& .rqiX<Cb:= + C{H1Ǽ~0/[s^̮pωN4yKLg^"IR3 y rؙVkI$q<ѳ.]G4-@XxL Щ{^kj <$f5 ,c`Z*vnA_)qɂ,0ÓÞ"~ 2mp )diDԿuH e n5bw i+D >n;O ӇMtQVȢge*&Rqe;YjzƋ# k]"ƌ0q#)r$w{w9}W+4mFml"{.y\>Y'Hkc (b\* ?oB]eOe8d ` q]~xzk6oAHK FN)GլHy@)( 1C0t10e!s]uelgrD1ve)BNth\2v-"2c.y"8T5yY~夹L|a_]e % *QT;e sG#|Nt%Х<$~X KXWʤBReY6Lڪo B87K?}5p 0;+#8(wb#o@k퍊z@Ω;?P>Cerpt`Es -S =OFTOqwE{(0;+MLs6x յHȭJ7#ojЖDIS#ƕ,ѣ\˒jF< 3X!]I u,dzyl>9߆)s㟦⎚hcq/wD1b7 /IT)A1kb(W{Qg8ۭ-C,:{x7:h~q+!U2W!u+ۭ,Ae>J^ ,}b8^dhh)Zօxw@، s&ˮ>aơ'ٮY08V6Ji~#InEp!`fǀ9b.~($|/A`uq&ZP:" R[q;?[C%۬bUܭI+@H -- Q%p IKqvXWdPͧQ1m<hLb8+uZ`!|6!q[<絇}%F1 ,nɐg*U u|S +͸<8ڝuhǘ| `bC}_pfCs~ʹ{3kt1tDT ķ R֜BBojX~j -NB<U  aa%Ji @ ǗHOF;j4>?Z:\W[)mp 2ށa%j=WO0{F̾xCTY,ːaTjFa{p{N ;+]7IP8`T@!0z-C5Zdby]|.k3W8?‘-l2,pr G3<إs«p'!O|Se4FQNU|(F,"rЄQdW7ik˼LoQfA3/qt؜t͏(^GQ#b5Vu;}̶2Y8,ޞjTJ$Q@Ŗ䭂ޅGm㭲\OXPqc Rz" ':3jҖyTCuiGO/֋K; Qc hGms0,Zϡ6&,| Q!%*Řa٢ASGy++M,#c bl=%oy1y3ÆPdڐk>&o xv lhZFɷ 8ЄEO[ JaV]z.aPWC>r}h*f1^ȃRNā2&eb *G` ^&& )nTMry)yɴ jDF"ɦ7@I}''/b7\&oj\Že-S7e r 1ȯX9_͟R5ez Gף !m lx3vEg &sIefC5'^)JZ@Fk'K%`D涡N'lF>p,sW`)Ѣn|`(qPkȴ&{ypӂ1AiqbIak>:F-F]f_UVLCZ󘣎Fċu;mkqYa:dž0r,DZ;Wy#|V7 LTع{Penۤ.(m\áᐅ ?veGF' dW&;^[bֈZuc|BTx:v,攅(M~C`2mƞYfͻ1I Q rhI@I".!5)mT«:YJ RЦF&;wE+{o$FusUD>4KQQm42+ܥ(iJ;1/B՟Tǻl`“BШ\0/-H{# 5&Ԫf‰$S\q68o`Ys/!JFŦh:cHJ5Hd coʛdbv{#K` /~J˄j@l)> ?s( `>PX{bhT[b RzA"zYN3Pbu>ڐJ\7h~ Z)a ; Wj2K Dↁw38GP4cJ;3+$zc2|~{,# itb">hFIA؀ wba.m%DDDL)R|zxL4"nλ B߹LkKZg5UC Gӡ˸G}5˭,Nzg-1:`v 6HW<8 d#d]]Vy,oH8q'ʩUssvt)хlҼe\ $P*ZA= uz{ ca푓M0ڻ3! K䌎0@$ V;?QHi2yth"PVĸ10ZMZ`)Mʈ8N+I2+еgxte [6IG`eKnR 4 P^2 3f'sonq2n1aYƁ:F~d  ٟq@,MLH:7ojxyX: WhvG04F )n5 "})*M e|5Rv0|\sѱw:0Y~5N yѴ^2&5 M0Rv#2W[ ]aM9I%C>r}$ژuP |6\,p \9LGE: ^B)U)XU@#7ckV>po8jdU M&>=C\K3F ւԵݛaCn@;5׏:| 3X>+(j*5y˥{gePnzt1FwQO%$Cf~!*T-3Z#rT*E e='"j MKIbxh| )"E3]3VldǼ{5(L̾!=WSn8#Ԕ$~ z+:39j33cI>2k,N̳"N^zWgDご%ϿNfzb} yB?Yk'WLB;f@F.0FowEu]Ec~4 Vpە#Fr b`e:}2EFD} )_3^h,]bbG FEE][a{yxQ%0WJgz]$aq>L=4L MM[F&:Ru!yo&5DJLgx Es,}Vʨ6[B)[BS*3^$H4NP[S\ $p|k:eZa?fGt~2hۧ&C {0|rpyz0ЈjI-fl-Cyo\ LtE FF=1;o3"Eit(GF_jQkxM8~eXNiɝmKpDّ`o]qU%#-o9Ig P-O,:~g9iC/'}[-p-.iOl8oR`䤝ߠr}چ$K v'D߀Vb8aqPj,/#APC5;UjOaPƮ+Y~rnW%@Gf6Jn ѓ JjO5s*UΥ?;w=m/7~kWjV;g@e:0)ň;p6Œf1Э'PD[mz.Ẑ:XKǥWHٮJ߿GV[8?YoC%h}.w"p4}"Mʅ&E[Pn/aK_~nKNzs`] nc9p'=M2JIϨzZ~OtNŕ2:1YmwPgAX, (Ѭw~+e)F:\Re ,mJ%hGA o_ Ȑ}/L28; S̄}&93y3$Cc#ƿ0Mo C C)Y$_Fu"@թ/xF :H>Ui$KED If8MѦWbՒUuۭx_&DFP#}T`vK' PXG^ۏ?_$"\ Z<2c=N5eJkVhz;r_+g8lC/ɱahZ4LHl%T&+8+Kvh`dNl X C lZE#ScR7Fمj rBITbš3^Z3~yID̰񰰰)k([= ˱M 42vĄQ?noKc.R8p(ڡ5]3vIlJcayoJtgDC S(YSNt`MXx;|9پAcbG46 31yTH`{k80 aaF)9yMł_8~zr9PbMXmCa݋v Ѣ (XB'k#tDSYVbHH€Jqx #+0=Co[ 9?HV0yPGF@PBJZ>ƠM- s k/bTQrۓ'=)Ц9ѦVʑ0)Ѫ6'9 Z1'cycğWuBNͰ?@ԟ[3r!S4Zq=&(S[gLOzZ֥3ygу72:[[,MP:q.VvoblđuhNl% h'h rYB#铄m&H"t9/JkAص;34p!h|<(8GEƹ->ngqN31ىҪĵ^) O(o-[<T KP& BiSRm4QprbY0Mp13{] !oDRcm }n`u )qmDzVV{i< =_Q!nfZuQ4v`@Î?VS!ѓE]4 xfЖK)]-7^݅"6A#y5֗6Q772͆OZyRa"[84-1<QA% VIp %`P~G%S ,7,xKP A5ؑ4}7tJeZIXbe `4DDnM"33-:5jM3F c( *\tO5sk?#B'K!4.{~c9q3\S[+0^) ZO eJ:ڌx$N`ɓ!m'k6Hȹ)"x ts BHPuruXz`~le@k^v2ܲ.Yϒ0%Ǡ8$I5fa=x>b*/d!qv?|nSh5E"޳yoᶜ\WAFPBTU</@?A1]S6a6B~vǩ4x-@aicZ 9^22'S6Z;ҫ!AkpݞgLbl8-J4_j=YEXS@ό3]>}N^tu p[+8-\@pCHkv[lGmU),O@K3R'־M=Ka\)lC\.Ʌ\0`c61Iȑ#D[_#ۡjחuWQG]ΣRׁ_lD>AQyZ]õ3nRqJʿv+y[lTE"1T.PtCW r;kQ5ߜ=_o m7,:M-nЮv"V Kp KZ1R֘li0?2cnk3\Vg ݺ ~/ ~v ̉őO+9"E2,(5冋`5-ҿ;/y ҦZ\ ~9q`s#y Re. Sf6*v^ MHev P,O&`@xTd6}wbdBLj9 a *񐧽dr'#Ckש X7m %WȠJi"0:~0TV3˕Y9!7a*Y+-12$H g% )p2V:JlL:VLK^0{7l&"m՟aUr4k9v7IT./H?Nxi 3h mxɵm/VqEQ8@Q]o=F7mFV4_W{3Sw)tk;NճJY"&ڡVVjy4TPrS[#4:UT j_F?/  A| ,%O` F;5O%ﺥ- LyȨYh ϯ>OgЉNmP)'v c]w G#7(Sy|ǝ"iK1d0z: H0}ۡn0d"n"9n C $=@ M-fs%;OcC5NOQwv{7Z{y,Ә|}^iy>^8j@FdDŽ0cN kIS՛W 苭c2;o gl2lըi뽣e%~p6fϙ 1F~޶ [bXx;(Ta4 GFV)vUBN8Jr.JqptE̚=5 Cf^]%ҖTC /qx| (%mQ6*48j("wH$L˷A6>R Wm4DS/`g@8P8U C3psD\߯mf%= o)4Ad17y,^ETc `(D,g%Y(4- 0q78Rrn[H+F hCZ ,7 dc 4faJ +% d}DK0"]'HH]BXڀVZPx@v͑ ZV2uCFUm6>'`+x~Y3vp "j8 >;v}P΀:)DO^<#G!-#lnw?$M*3Tnc/?Dj|+8/Z9n^?XX3#PF< [um8zT]\'pmx{t8IsHC|O~kJEyQc:jX0f#@(^|q(֜Z}Ofn+0pd+C94}FF|)~Y] D w"Jud>/+4c pbHEOϥ8.Gۻ숆jۗi{s @^r))C} D |VԖlơ o+fQR DQ@{E~\_ zU2 HP%V 3I{SG ՟jюäK)+Ck"pqn #{i5ASW%Xs^aו-eA7#5hHԐ”D+l.&w9BJu6u q)_-&BH>#8FV^R$3-*hL5"NctXHeNu޽UN}X5ic0&+^P5&ʗ-ywv)~Js0x$S P{/B,AR;?6R $~4UgrEhm_(tml!C1X,gئ-dog-KaJ&\[ l (/ O"l &4.Jv6F.1"Mܦ}EW.4mWf5LA|J+lĚ3#!1iC=jJf_ Lw6geH)tGSLp"2\Ja0;Yu`vN$j\Nދd9thKE)t W`yU9ϽaDx'/m9Fu$1ӌlb5H1"'n[*VŒT/p!;XhO+B#FEȄ ^ӝ;\W`$,hmF /o@j|go Үhi-z*$]51[Q1gJNm]c@ӹ(9tVR]}'YjIo1b[RI p$AtVx?tlj)[-~ϡ<@h ^Ϡ\Dpk|KDFbM@d,|~*Q1V(h6g ȁG62(+,*Rqba+iJ/*!bY"hB*CK5 Ѧky o;.4$Vc쁠 ֶ!m60]Ŀ=\,@e5@$`s(-]OUK5t߸W>`21YK ڼ4E|^GZ 㼬Z_͏",v?em\6)އ6[= #*، vPʬzoz=8v0ވiMkƂzŻ Td'\}iHߴ? zkg@-J>uc4'#F,?5k;?c)G5!!`$n$Yr-sazB(C?SjtRo{R;ޞ:j%,ֳJ|LFFFu Av, Ĕ7h" Ţ0E`ծ)4FrKhj1"XQ[K宩 'AC%7gE>b G6[3`aq xr!Lhq!"8`|_/JZMa瑺aRh^NEV%$ E(]B0\ě:[dة a+ۅ~`c(ms;eO Y%BI3İiQp@<I|"40CP-5OE8ɥ@Q t/u}qwE!kry0ۙdy,Lvkw N.é1/UXW$Le C%!D-XX4Bk_/ҧgH"-ޝ@m}ltq);Ǩ`%fc| 2#ąlN%S4A ݥޔӑ2.^n[v璭4Zt6&$hk'2 *̂+~6kTo5#O?Y9#}|_N&h 5djOlsloMU@V3"?ggG=x8Xwu8Q4|:]ؤ|n:{FUp qW7 GIźW+#v kh] 5AS$?RR|+fZwJ&l@N./mԾLaŶ^Lrh"ڝPҘa{DOd۔KImðZ o6QhIcbId`<F|6UQzX& YCiSv-us茀9Du3;]Y`$Ag|ORڪM|Y>OwmnhxM;v?zgDs,K#FZ<8"a>h"m(tETj%/|u W_Gct:M6a3O<;޼\{JZdDϮ>sQ- |z@{l: u8UfΩ z X8Lh%ygXD rڳZf'IhOcX15IOg&J$KLB҅0#fn=^S QB<_ꠝRy ֡ Y> ^A[PI5Yi21(tek%Լ,H_ )Z< oeRk$o1>%''P&NO_4?r  C@VrL4(`1HaiB{d40 l38ۼi7Kt`[]ms{P[{L $3v-} M4]KlR/!\t@+s؝Ne;tdVL@5P̂ħppL׳ 4$2 2"4]ğ79CuՓF|O쥂)uy(`it^H[q"9ʜ;/d ,AKԤo*Y^~OH8cA3^v|GEwsjS{ɛy24ut =g,϶<٦gEnI|6'?Oӌ 9F $>RLچRL÷[=(i4v.1wII Ý;?vX\eTI2 ,( b`3thvpz'D +aTŤTQ3^E}2pNFt3r`|8Fyȩ<*ِ >Ul46r9Rv;#W+nbj\W4"<#E>?(6V a*?߄{?~-V1H@<[4f ]h̅Æ@& U V)LIX7G7mRqT<7ψ@ȡ8D ǐξF`BHu9=iyW&]<@ۥ3/<״H=TXDKz.XDͽ0279,\&;Jd&}})djBν\`t6o(!1zd ą; &rЏvY,#˒5;# q]>XG{"N a/$$|?^ >NQb&(v=hU:3xSK/2rIwp%\3-F?@ASW5޷SH7~Ӧ<.œy(0/堭aRYD|Ʃ)" |$:0Sy0bZDl+\05fm8ȹؾ8 cNs&ވ GSXpqRFS@΂) Px> ĸ `Ww$pMa[R4F zMhZ,@V/zaeyѬK`[dR`L$)b0W8醪Yo2'n#ǫanseɗ_KL&nT 9<ʝ(<(I^Ҟ[/΋Q!s`E hu8\,(w!+y|irP5L=AL*)ј=Fb>'А-J8^FNY6T˼;uaΧV8<"Buođٻ'W7W}f2nvܵ FW< b<+Dz+ݍY j$P:HsU EO9!SzQ30ګaf{SkU93҄B-uٵ%wsD]'EaXvgC 9=y@%}dSn-jV/, $fR '&7M /B$%v!qom/G[86M.+)"MF\-r-4?5毤u>;te$G %wvV_1 1erT`*HEŻ+g)P@&Ƈr=n=m*5#oM0%TYH{ZV@@T69CrMU@pw$Т %[aۉnȮeW[JuǜΠX3mD7tjŭ?LLq$KlTY V2*Rk=>`$I-QnQr 'q|Ю9 1i0!o'ca>+s Q3 PHYt2AKRGj^ )|aDW?oҨv123O->5X8K`c:^f>XP5n M򈽩o lьixvЮx.AP{,#9w; õDRö*Gs1Cd5pYSEjQA_G IVaI[:D#i+Fut#n?f,1t3.kd90Mē*$5MA\^\6X &vv%hwN =)oqX5X59Wu?i( oSܵ.ߒHrϜT/?+iIu ]2$xnE[i6-*x@ Br%3梁KZvZmxaU[#sI/X^xKӟY[7 $6hZ;0eh lK mruˀ3Tg 2씈II:Cf|sp:PmGgfx3xq:4gAw=}{ۙfP*CHFTKW.";qz"JU5I[6OVw8U2]P,]nO0A=-ޓ6'*L # )/юğƙKŐ̾lS FġٴHN%FU j.E[q1ߩ0t;JlHKM&Xq] 4e+'9Ӄls*TQ ͨr& x]#p s+ $\zC~jgvسhZÈE0@NX'0#yl徖MUo{&lT"񂸊$tOCh:Ga0h;,(I1n'F0R/86Aͨmveӱr5upt&~(JTDܰL>[鏎b%oSہ'w6u803y2XjLr lV N{$&R/S@eS q0UR:p'y|7A6e|[c[0>pHZDAd3B /<97x6PhR^9sc2tcs|r%eXB]UcZJuXo.aҊ/MlS 玜x)-mmeLQU$8…ѓ@@Swke4ˆ͖ 23yD@y",&Gi)?vx`10VuD >~#;8hT"QGځJNq56m{0}~6JXLc.o Ỏ #rInd(!$w!}I=zb`3U$b%3e[w Fbb5(N @4ux۹-fv?wg|W`i3!V=£I:Y6淪;:+|ݰCaZ^!zN%!MNDl;LM :)PrҎ(B1R /xZ : = ^n^RA&Jd\Ӣgk$tOB}"kÔ h^T z9x{b!` ž`kD#nMixc]3}sVL1<2~IE_lƅƉY^pEiyC[kٞ{='It!3*+O%ͺ~=EA+~Y6$/jh$H2YRgT#G(d9U J߄d's\Cx+@ 6 e) P#iz!@7CNcv7zHӿӞ&i2耻t-IsVkb.n$iUC(3vMBQ1 0 [UY{ h0ǾD!=V[-h~ Cn& Lrk{`HۗhL IpBmM7!|eGR9j\9a ̄*F7-ئmAT>3A "M-.  pjm}㬜&Hw̟[A$жۍ58'N "w$Seۙ <KLř\=h,oJӺnie񮞦 (D8v,r)Wx>wfOxs N&p.k.&=l'FiXx?[+i=!3 @0 +4Hw\ HL-{m~?7NmG+ = ]Wqngqs޼^UD 7,;ц}kQǯ3_0݀,Q&bB93byHb4oS} POlj _,xhH#,r.A}<qGOΊRTG78d%Әr#n:< * egKfCoM4y8 ]h_V|+C  3J.\5sRnL&p&Q `ٓ{Y(!rd|6,RC3fN`k׭ErqUcsQTLCp씘4>Gg6.o,T0VE$ +cr3pli|;|ԟ s.V1Yb0{Oj{6ũ™V֪P7YCHB(<3UV; Q9V)^lYpʯՆ+}q4YN_jK[9 dX<3n_ }3׾>o|x .1@Et4Wlf4l(9act42D^Ϭ3f|ǔt|ЫS +])!a/8a.bbEǖ>V59u  \ﷺCW!U3AB\huCtRBgttdh$!O[mUyvs!n=Af ur4: {f!?U;@`㋾z03$7;6>2ˮ@$&90|#OT{>ÿGu% 4.#d3`Iw$H^a(sE9LE0o"hj3!Cd֜ '+./;%qalkRMiUp*6hn0azNQǩվ !$<(ͣ=;)~c' Z^Fv:QVe$O֍MU*Vu9L<;R5w+fԳd$ V Sr˳)9f _59ªČ4zD Ʃʗ)Yvfl ʰߎNJ>Rfd,p |Ef+Jca~UC]\g:o;?V,O&Ɗ:lR}3Ktm8[)ǗWhhk$_A>Xv@f}^]y?a}߿Lðq&ʭ'2_i V] ddX]/y .1 &QpV[c(et%K̕ؤ ӗba txFMmjndCc7 Of!Nxn?ɂEd*V^#+.{aQeaQ(js۲߹W(Lud`@=)}|=÷YI)EKm91ыc:87V}^A jQ-"=AٕQq#&*n;`N6WVst M#^]JPttniw`Zjdž-yryNR:eyS}4Fի_EO96(C#)ǟb/"X./ge! ÉVV^܁S)n Zw)ns 0#gˈHTUu1a ٸ(Q]ުn eߞ,, [l%~~(j Ah6gof4i|pI#|yg5N)%$gԕKnv81XvbLѧ/ğԩK)9u^f[;c pM*2QS2H4cZ s,d˜">Zzf6pLPY>8%zly,DxFYEq)Z3 C}?9tv{ͼ"ul)0Ѐd̓2.Vcg{XBq@ Zji9zcyZ~eÜw_58",F) Ҍ+Z`پłWevʸ͋^7 ]3\uJ=?[ o] 2mulăl?Mw>Y\lvʹ_㣕G;o<'-LJ.OѲ$m̟$FD,BT݈zR^ȸ2X7Tsuq!wGKq2pv"jDWƚs\jL3 +{㷹.V΃$o߯Ws YOcizk59 tU[~y>^w @M_ES%^zX`<@2\G^^I 83r_[0}!RS2ex$dCTWR\S,qim/?MA_f;, ꪫZx0D; $ndJkISmu(8n$»&WЀKi i3V1:2/LS̐i.sģni K أuxu6\.Hzg.>vxM-"iPՒg?ď C'%q\3%]j˞46XrFf5GGЧTM!?e9Mek1ׄ&e!B$&ū/&:|e`W*<0qh9FjS` z{DŽ=SQMpߜ.),('<Aq)9fXG4w?L3bFҫXZhJ;|9ߠ],~ n6b": GMǀ94GeZt :ME:Q*iB<u9bT;4g{:ш 1.hg$a0H 4\&_Y1KҖx.u2)ݺdIf_32 ͐Ѷm͆mp(^<}[:=5N`ʗGjM-:?&PρXGl@s$QQkW)Cl 7k̓ix=9urɵjX0 }b FUAFQERMvLiKb{qu/pn4^Uupk1豜GinӸVB d<7eqCݻٱHA_lVr،Z ~GS3R|}9DE 6.IIrm_IK]9YUD5YA&  ac,h(ͫ9Fw=o6U`~h8]c-Dxz⣝37/k[9fuҾL aϞ$gNJX8".-A~,dN'+;⠼Fi-R&>h[P< xYOΈ6*ś }zSXV`a4ltq&eHȰ9-7#G`Ĉ`6!$hx4*Cw.*umC# 5zXJ#w:/H0;uӍH{.lAg΅rinLc{jD=GKkYw6˝3 ^Lu@kytg0쓱{Xȱqr 5JcDXZWzJ%tK= ^HzsUW_<@ZȎQoU#Y0uq/ YdEQ􂧱IhI.fŬZY/iq03OѹXAU xq⸠iNNe E2URHܱ 1v2eZ-#b6^#$lЗDj4JDɉC;0F92YH&Y|jl>SilX}t*a OO2q~8vhb?$Z"LuM*F飼7;iR 5b ZDUhLYil<P?1 ܒV0?E@\ QuflpxejCOڠ強×d8VƳHhtʣ*pr*8nPE5`n΍hCl!9b_n#qpdr@3JؠJ{$X+R=]wZu31Bs'- Kvpg;Hhf,j XB'ˡKd 9D6qڗ8 v\ǐaʼ1՚)"'4^#/{5+m3_ )` e):-ۄc I Gl.θ6ujhei˖u zWal#g_ܫMn"R$}d0]`~_ YnVڭ{r)8E0B ,y@ЍJ9im}[k_3YOBbvuH S9 }ꐅ4Pk:ӠEƇ?^Ls>K K> 8NGdaj/|?d+0َ sc ;FVă8XL1 Cמ4"WzPvͱ{1O2 _K_iQɈ]%?*l!l qSF+%ͤ8d] $SOG\Io=( ٬9N͘mRXK@dH _H86nޥx Va\|p<2&A;`sy˜}MNbV ~xüxf0TXsЍIR*'A~ y#,,&8Fָ'82aLwS<~ HA| ijYs+H_C!';'(_=vVsEmo:$>$j%k|;kLTj8&}_vxze><ޜ1@sv2 lMMR\PCT͎zU^-́u=0Q05ϖVKxY bA*)P5K*ou,ۭcl;9>:"+*ye,hC'יy"O H+3TA]W9l8 ٲ 7]alʴvc6K8Xm#cٴyebtF`>?2x͈u@Oܴ%h'|m:$X./*`bl㌞JGTDŽn 0 GT(ޣh)&nFp=HU`xU\ NSĤ %ՉNm|R <Ao<P)^Ѽ!9bovd$4qM[hN_*"X{r ;c`>7[Rp7C%36ןP{'LNHr։𓹶ɐI^ QbTIl6 XHcYIw6־;UxU/z88bt:ضTSq[{lh1uifJd_ow޽n_^Eխ2T+wL=="cmU ߿1' V"S 9!\<_\V6m&,5lT]w @Oo)D_K0aAn%3׎MNيУyzOʞXi cf\ҿgǏ͏L;O{Z8)Ǐvo<8ܗ̙VSC]f'8x"fq+@^-ݬ 8I䂫@&O2'gb(Pf؎C]X|weVvxHJt&Y*V)c͌.y^Nh@l$e۱5LU T ꐓ$gF{dvXOg\ G!?)a"ovQ6V="򩒎rKY٘@,ݛ-[+QweK x\ol¤%7ט);v˲F*7j щ[v͉P$Ȃ!k} ";HԿfR4(fN+nڨ2nnF W8&reG^jy}24.G "-C.LjRb,ReYfa񣿥6)Hh!0EFpRsrԭOأX@Q+!I*o[gR pδ$0%$!tn\@:`{[e.S1N[+!ޕ zH|›6v8 s3R&V'S {' @zѕu`YbU{_-_ lm }3{hosrҾ]ckR˼im&=0.ٜp⼢6Ǻ$ҹ0:p.=6wz@,+AQM.фO#nV93,wte3Ԛv&B;Aq8DB c:7< =Tٵffr hob.CKs+0B~Y 7 Z96]_ XpQ+ Мc͌s?x ~fƘՍ!ДQ#K 6JS& St!EF SQFa)ց9>u5pyg 4%'aݵso : /_/Pn߃"V,PLFߦGc4LޝYb T"P̱_i8Q-sCs3 b:S %+um<܂\wc $-\AS5iH#>zYUȃ1OVjBަ^cN ͝ ue`^*7`{H"Ʃ7Rm󰇦")XMN^(=O CXVv/K4P\rwڌUCboBUw˫j??{Ĝkw }[uIE0*"~F4^UAvȠGw&PbH`AW7ez{U$>塯x&2ew^Bݎ8[zvTjS9Cc4hqƹn F}6ѭmEdj c/08_H`ݰ֪iP ]p%ce"wez4\JX)|b) U)4J#m(qTy4Kt1іDp~&VLToA%dM6s@(qBlrhTӯ ɱ:6'Y.A uVV"NMv#LUݷzX-a`wG/|w. lQkz0=8|&YFuYcT|J7}x+Tl"zr8.%-E-hV06JPxN4!6}0T8mꞮ{[a!%Iiŏ@ŧEX"8%"ARfE/G jA*@&֜0i@Ug_lEN/~t_<|B-܉FJ-g+K"<6(3]Z>Z&ـlŒ}t9k3DEɺ~#DcH9U x0sXB !n"ێo Kx&%=ni3ƑzKr>N܀}q%nX[䋜T)V'|1Aoao2.d86xKPv@$HjxsΡ1lοkjgCR;fP]-OkY1n.!v,#7+ElU`"r5XJvG_:|_z )1/{j[/:kR|Rї=ڱaK#ďM}}[y [Qd9G}ovDC0B]t; 2}f1*ؚXei,ceEUtʊN51Z_>'a;n nbpcd7Yl^C dZeUnEN ы#3v//ff[vtt-c1 bU-̠br/K5ִJA90J .ONOF>2l=T~|RD|Ry.G rc *s&X-j5Mmk@Αsc j2:]&ڨd.^6SB3ؿFœ_24Y4SI @.w;ap'}t:ړ\_L)*4$p|\^*8q?ܽ2k+sqV6:br@6Nb9=×S`#\vm=!0>hT'^xP]PG3m$NPn %P[SBt RK 67Ѩ֑a`m":O &6GSS;1oEz)'6x+bj2!81͟ e I4A_ ݃v*<`ʴ,>@_Ytx҃J \MOH 2;E06Y4Pp~]FO4$9Vh-"!X9 y/~`^xҸHG~Qq :"V =pcLVcH uW6-2_}Pp>Մa,rR\HTE?a+K䍪\k;bx dtAE{˨S%u#)[nBR$Ir񓔽c) Z?np SXcX6K}THfv|8eyQҜI2`WKHP@.‚iWYg+)\gV n~l1G 9Vfݤ:uϠƳ>ﰲJ?td7az*ccq#\!Rn"r/NQQT҆aQ?tA;կ'Ct>2Սed_Y2}* J!IX%:^ާD`p5I[ƻz|3{gU!;^K䥩, 쾣81Hi"5Cw"y0 Tt'` ͢\N9zN_4xM!\B~AcXW`HiWŐ5ƽ nkH Ve 5fP,8Rt̴Tj<[*";pĠ1o۔p?_3ԃ)@X,U;\ GOI: b;Wq51ΚAaEQD 襍O/Jyj>2ڍ񗡂f6?buz,− x_V$$q,s ˪ K+,3=!'W㥡آE@.E ׄiۯ粅.Α2ܖ~!gh;"n—*v3)rl2 ;l'i[aA غ$Ucض_ٜm)ؐ4:@ۢ- iAWj/>frx:Kp~ux`UUzU<`9T&YH25Fx;p;КJsD,Kl"hCqǾ֜`Ж U 6 kJ>$O[Pa`RbjȽK zW*D |xMU T :]Mњ6 ؁ꖝ4Z[bdڥw.vE_294 c#.E|pdHrӒ9&gi<U#poJ Kޑx)v,KF}X&^1[ $}8e1lor c)77>qrpԌE%~@[M36 @Jo8F}n1oۏ>& ,l#8^;dt lY1Fu{IP1>X4J| a:ˌDyWnf&z W|qȡ g,Fn뭊(Ԋv2g{98+?˻B ũNPb.[d-ADvwN($y ٨=Nձl[Hk W4quEAt;Π:l$I"nv?;UpR?1Ɵ&(:z~s.Ee-bɒDSíȠ8q%e˹q0xҘP 9xwA6aX =Vaۨ̈^y.\moDRN`[A!A"ǚ=o+@U`ZCj}>Bkt1zGyn%(,;ZVGdH#r{r ۪ɷ~vj~[,y{;:i0uU{x4e3JsߝWEBTnㆶ3&"ug }_uel;g//(ȩc9ĸ͉~ubDkL4|Jy˨*-JaVwJE[_?nϗmk1|yr<5&ϫ=l^;L ߔ~k,KiߏLܺsn;p@y!ܝ Xjt0>c);)Qi<_?;gم vp$yֹ>h^Ŵ,eei7S1qԨR'\fq֓̐=ҠzQn$ G?Ţհ #: 9ꑀQmbl\rxURj{:_7Lᢇs=/5ayPetā~t;9쇹{#6Bxx(8Ͽ~m޳V P_~(N=W2o{o.;EIrQr z~=9x:b WeIpXiV j^fJg%q}"XRw=z LU fڃNW,e7IKH*tcs^QO:ǸRHlnJ~2Pǖ1oC8;7mL*h;o@'~K3/7H|G[ha%F51Ë:Y8j6ؙ)m9*Sw (>ԬʵpFJZHzۯ]$XH ,c ]|RaS|g$A#2&Y-r7~f1B pg):U=޻|yL{tg381DD!0[b@t.\JD cLQz3}s]w^?2V=l,BK2heƦ}O.β>| js.%YrDԜ`Ƀ<۾^ȏ:pz 7)yӥ)P*=.*aD( }ÃxOuMyXZHWn6Jw5qPUedup<,vnaۮI7kN8iS{gRCO 6f*Ɯc`;V; dž,[Uwa97AE, iSU'NěẔfym]$ӌJ/NrυF\!k[S~qLA 4HKL NCضV8֭ FФaGhǏHZN-46<:CH5$3<)"jneXec|"a&;B9 P9ԥD *Pdv~@ ]SjD81>H'M mSGme7d/ Zq^hطrZn \-Ԟ޻.NJ(*u^HȷnQe45>u/&B_"͸*afb ~ y;<ށרW7 Pp >m5H䇤&0ܕD!32ʯnRN7vxgJ?-~;ՂYm,n6Ls%!­qB͸ KLqJƒ|]fR\JURؒc46RM?VЌ#ZLkL 4OzU^&6k]???mC$k~F4[Jb4Hc;>1ҳQ}@vhi_A°[pL9S!Fka)\>ՋuRlߊ•yV6gdv7mg,ŻX aוG7D:9Fۣl3\DL;˼Y=i^  +bqj3ݥׇٲXv:3g܆1\zz fBL\`",`/똽r w͎W2kͪdƥghCPQi(&SL(:KMOLЃ3'h*85P32S-z((zvBr-%ILL%9 3JqW[ƢO5hp&'ʤ^WJ4ZlXTT=$p7JdmX }! bޣ%``H ' iAT仱%ŗ]F"[@uY)ylU0wjĶ ayڳCC*ݍ#q&Z/@|pFnܢ9zAzr&& q}#pxF+>AqcilߖEv:q$5sm 7QSn7|"*kӵ'a]b.RJoD" %Ĺ50di:K,AC@3pDzPt,a+A&̆#Pn ћҭZ* 6ezDc{*K[W3͵(RRJygg@"U#t7?)ALo$te~Pa%N`Ѡ7Aj Ȉ45krÌB5nq$ '@9; cK{bYۅ,<$p1ѭ5 F AU dԵA؃-GrȑD;Pj%;E2/bO(d2I[Ma-S,Ҧ L͖!ixޭ߬`Ib sd bXYT(+&ԊBѧ!ƴQUE g&{WE-DxKF"< U,s~#1`r1;n 7a[Xti\FD0+q`Jͣy{A\\GWgf@%=3<ܪ!V5᮴㽳bD!Jp&nljCJ ϯu;!⫈,ҝ8|61w.2LՅLam;s@Z8(O gcvpj 6+Y ]$ i Quq-E;d g:'#e8(ttR: blkm~.WqiF\VDE @98J*J: '3MQ 9(TYygLݎYـMt._Pr+xJ}]B_iZfd^#t-4YAֳ`b%@j[%`G,OM#EK:u)~sL\X dh؆N 2.z0 2nCŰ{QN=* SL!> i:i<ί%5z)%b5゗&n .Jؤݾk-ex6O"ԥ0iiubcN#b@  3CL^ւ3"K5I00 = Ԁ-CChU.nr;RAR8͏ 8aLv:^Pd2Z;z*2(xB"T=A0(&}&AVv&?;,vYyl`}RSrqXLݓ` qBp4KUPw g-`-,6C<98yAwx̨'elw}[ACn($y~y^.0UFd~ Չe,V[,t2":)I@ H>tNVw{iJ`=徲 >@t NHːg,#*| G83H*7Tir Byp`q)K+ǘE- PTkg)/s#Œ CԋDQZe" W1pjQ~0@-WO&t( mp 1YA("nAw͙!C8tdtϸPFlv$ I-6 UTágZO}~)Pm/<{iL9ݞJ=pr.o]lY5JfB5aM`oȍ0`j1k:1Z}z?49Y(sYzZ~hxuU'3I/UI28|v٢Sv\]S,E, 'fO0p"9 C+5"Q7Cթn&ͬ!ʱ$R(BM{Tōa(5)Q<lޡ({mm 2 ݫ ĵB=D,Cl R&|,F,^>w΋`T&9dGsn'wL 8z>n2@1佞R5KyQ<mT _LHɽzNj<>me)X#l@IDATtow֦yW5Ab (K4)\`fZ "k8P)I1P`%HSYvjҝ 8L}G2{qEDR@qj58܇H|0HnژѺr̓T35`ueSOEs,Qb+0r0,YקLlT0U c'mCm!KTrkd˟d1f@P{3Q쓽mL'Te&-Uqa: ^rg L sGoUBf$N6:Ř<)n䙡7Drub9<, tBJCe6 ;a}G?EQ,݇ra1Tz'R)8Ro͹ìB}UMQ$l{Cr %-~ y4.IJzD$cn<,l{W}Yľt& #0) Ge&K:$־i tcd0g)p"f hp-I\ P8 wlpe.!+i5jQ1:U󩘉*˸k=aYhn A9#{{T Vx+K* ҳ$(| #bWsjFΪ-su O(:ȲNGޯ)st(- iNQLQZ R L4Fnq:ANdFf/~=Q ^(Ʌ>r(Sy}[J& 3?xG% (2 l<Ջ"KWRec6'E_0E4dnP7"J@zO9 O %%Q8Y!H(VBIHp ^Gp)i .AV4tAI"w#N HAN q'Ya"˃U:}| ['U p=Lq<8m:lOt\+{:Qd -s.`9u7FB:\ʮk^s|~6A VE15آ @XsPnoSb}dPbS!Gu@1-}+ rEvXɮYAL91: n,+-ʑ(n!^щGZ%xEEa9ɶ(\GVJρzܓ! }FF>HcPdmu$Nn`Bh>ˣɫ竕.zk7DW6$Oy@Lfgv}V*o0^[4 g ?8(N(K3&I5)9:o5g:0d/b!q>VtJS?ۋIG-$#Eibڋُ$B~榺jJdKHdҬ9Q͏A3DR,rᇳ|N$ ))By)UdVhuB!ɤ[}~ɖihәtB!JU4L9E}tUYlMJH>.< 4N҇[ӾY )Xk6(E.zxS{@HJe PWO `IcQ6q+뎜F4]A.@ND 940dꦑ4p {֖cFWjߐ!R}u}ZӨOɐo h,c [68)Pnvs˞kJLitv5R"@׫tf'z*]\R# P{/+f+Ho ϦmO@w!alvkʟUm-l|g<+O@7S2.Q$$=;^a gː( N+~z[o^a+||ZVN*;+L̏z3Z'|Q`~rK.ըfS.P%N.# 36l6[m~ѣޢ>H]s%wO%QkYfTzyφ>R)BeYWt.ڨŇK3h:~RF^آm(Yzd6ZW,,q^+>_:'2*-bjD_׳pڐ`zڊdpv{3-L rvl=T4%|mPMc5ɡݡ"I~6B.4؟PI-|sqځ\G`qdKNrgD6u󺻝~=vy@Zb8Bnj>Á8_h,0:۩fO:)%}[(uRqVhCnpfl/4}J-<_((beB]P>(̤(zn3toB+A |'c#{حW{8[=@8 i<%>v( LSsO/^.nYa&O ý0'- J 3 ,ӹp,ƷV9'Kő7N{&9M(ґEbbmZɸ$|z}2'3:l륓'i>mɫAoֻJ|>EAPzMl u%p҈#R"eyJȹʋJZ]: a`약tw'<"ds|魍 ׶(6!4Q |ڜbN[\~.NB\fֲV1ltSGp4,KJLӴV*[gTWR*.i:jayYQP)47ԎrSSʨ5 )oAIZյ8+M]ŞUWI ԆȔY('1 (Ī..1.e YI(b jeK,6_TLqˑbl '0%gVGȱ|)kFOtE3m%`@mg v*0Yݶ@덚8x!e`` !^ z{2T&$+А` *xmW0"m|s)mvfƣ]+bM9-@4@Zk$[_yi`j)p].j7AF:Q{RslmTZO?1Yۡۉ E8 Nb(&si4D. d?e(}&mTM4v,RQѪ 9.[e5֋!{!NG:׻~5z>ϋRo`U'!>f+Zqj~y+k@TiuL]nP//4(T$og$?M VصaR-n&ϭ"PvTe826ME4Cu;K;YT)W h$& $!LGw-Uϣl};E1 ETw/Vp Fu-jRx.!u -8RUUjnfL7:JWxHnC%?:E"XT' ;6>ˇCDt#I;c1\GFGivZ1F]HyQ4I)Y44f;[iQVs)k0U^JFq8藒38'#xw<VM;sj}h^TbU"qn_O{Urh-ZP&T,(ArZ0|_x洭EH]`#c77II$ vhl%/% Iuo{|d]ՂzTPHp !G#nUwFG‰'TfyXB6U@7*ckɉ!}?rTЊM1iNJ-`/`J<)w`Z0ٖ8<_Q.Î 8Pe]߹Bk|~iM.6RRM44}SRa!0~I鿹1`qEHX6@&24n]KVhFiM\GN&Y]+q-t9Z#Ѯ`ɤ؃HXy^ve_c ӭ2ZZxAH̿+-@7! u>^kx#_s?ݐ!fKÁgn #h' %ͻ778xPɣ. qvC#^Z Bg8e;>IxS[?Y!G9UfXmO/YS(r_&Ԉ#{nwz٘rnIcΪ+>٦R:*AXȴ ዠ&P]S_Lj2TQkȠ#.M]XWGrZ٨SgT.hPb10w۾-9߼&.rjdd1'YLX)L5,@Bp"YBX\c_&f WaI Yca(>ݧ~ " rԲA}vK|:<.Ԇ=2d׫[y*r=)(e!'* HcM5b2!z$CDGu!_CƮKFwa}/&[.H-^]>Y}Sm{o8˒iߚDNE༷St@ @7zܵIq}x;XP92znC_jҜ# WZTf}2c 8y}|G U(5yާCGV#Imk?٤('`v s>?^f%\!"Dc2Q"a 81t4,|2vjfZjfѼ~(j> ^뚭[F#qA*EmRME-Uz;MV?6^IHiG[i#<5-^vq+% J2;R׏aG1dxOx91x |?B lgHU^U -2 paqyAWފdk\CZ"# 1bY8ְDtousWsÙSMݙwY2XzsP:Op\3͠uUbk)WKaLj_LTߜcqB`$lAJ7BYi$}juҀb'Z:36]v@9؁ѯ:=]J%ѐ~eL y(68 n4~65uU?p pHZoeB7{Oa""3Y@($V"l4F~z704)%UcOf#[G`?`XѴ8s4*XrZFJC!R :M :[*Bc\8@7HJA aȍ!;2" ).WY U 8hAa i_ĕ -0JK[Wܐ}ZXw>kɁjwFwFD#U-m+1]"u #w%ܪSN`4³Mi] x^_kvlvm/_{ pq#U2?bTHn8 &m~9J+0 @v2IVd - HWnE,{0 ڒ,e^)5b\i ZRh0dS7ȩ=|%'=XD3'B3C9;]}`,'u|iyOΪ>bXMQ@bρ@y z@5x 7? # <( GmժuLlm?M 07V7⓯A ʊ9#4vC$?ˎ]bh]R'B{f,&Huj|Q? k8 mWHAYgc3ɛS[브k?bs(Á)tM#g T]Zl )HLr=4%ռ%C.(\fxb^x _r@<<~ gO<q+֜F>S{WQ.!Ys1btO(¸H Q *MNF ` t EL},MKK}3$QgFEz;Qv-=eJn&'|68+*T|)6vG C٦cjwyR>V8& 1eB>شk 0B(tNoq8v혪#1]NC-yT%M̈[jؽ `VKHnkX^{[Q#F~U%ʝظEW"bLLj81Xo,xc)TV+sxr 5.`Ncȏ9akڊAld|O1O.dG@Zqj}rwRqN#v7әIoi?\^}K~Dq<3nk]n^Dy#j9L/ƗgFON3U v4R,s8 4u>/,z^RKqzh QE696Pa EQ_Zr=SpXAg%!P)~K`mf Tmz_M(#Y 3s.Yx7 En Ԝ #%\Л1EcLi rcSϿ=݄&PiRu^r0"}ex>:VP(J$&G >ɿU؊!Mc\dl ]($ۼcBLlvd$|xɟ`-о64a~9ർ`K~iͬH`*3>ڼ6;3zS؁"*o2FcMM;0(@,d [[0_Bג ! |:g}00OZ;Դp(o+ġj`bsL YU2>]:Jjଓ*!C;Aيt\ډ(d ?ŇyĮfFaRixxZw7as[&f&pĈ[[AbJhxQA[KWdR]8c53šP% R-:RQF ZvVpPwh0a_b3廭oʱu6 oN JO̞ES&KJ(Aj i-Y'X/Aggݻ4$T8y:b҇"p,zpp~VB%ѶyJ Y;iIt`brz]y`Q0Ck! GD@)$[̖ 'Z%u=fz}p&~p~IA moR_h}35M|U{"-WD߀f$_6Φ1yֽ8#sp4&M\@DX#Y |=`ƪ 6OBd܀S-< (<(24fyp+vslGZ V/6*Cbht*$F1:kRA蝏LE=ZYPv-ӣZIx0<نjHkL rE`EdpaCgm mwJ`^hyeQ:+{3%ݙ!F C6吕I@ {z҇g*Jaʅ`f,hu6op +YWg<?1Q}+_\?Vpk=@wrY YyY< &Nl GE-P\m&lEBo2=2,pg.EYGfWWdgp\gRL`2_!:fkp9@T8|4\_kIJM4ai$Y|pr,j5 US w3OKw1k5oĠˮvTbX9x.%tS%]?|dAR]솴zػ E P8:=1B96VT?'oί\ެߤdAOc2dJ@MWcuĖAR|krJβ_~H*CyxT/&G8a(?< 7b^L)aSE1)C]hk#j2^dl(4KLyDًi{7_YL9,oOf\ `)Z1V撩<[ l-X H,41Qz0;%9E~XZWd"s!U+yD2Rޣ:[VNP(`X3˽=^aeFK^}6Pt0-qdɚq/IEqag3EbVX(r:Jyfp8K-3$JnWXh2A CU<謜!ylXF4o1|wAP{ +䁞ζ;:VWϦr( 1ZMA@@嗴˯.l`HD*M{rގ:%}Ls qP3$G+ihC}bҴCHw.=}6ò;TL,{DFJwH FrBBAI;84MV=QV5mX)F+Q %n撁 *T(fpWg@nVpaal~ʂ Q~={y+X$z=#6ph)\pB@$u=@䆫N ,1l\Zailql\DTx̴M"Up bm\f*88zPSIXuɈ+f5`Fjw:BВ:fbeva<\MJxtă4MD[C)cwI*?r֡+qR9RRgL |{ =GBSE_П7iIFَ@+;PFJ͕V*DX" m@"͵2DBgM@ց2W/6K"A`iÖ aZt]Õ Ĵsl7ە8bL+)+S0j C.?#fqN @4^N+= ]3a3tc0\AT-Ct'x;80^WM4B݅™Be#r:8ԑ[V;rqĖJ! %FӚS(RbPeg1/R9݆c_k\ä'H37C; 1u^gpyL"HxvgS/k 9]xIMa&t9d{ Ǘ zSEcS[qRFd! Y#e ,7H~8_ZKuSY[L0تA)ϐ+%_ 2<[\i/!Vb^Y5z[irV->2uZ䀯eЃT_`QVsv)8i< A8T JtV{ 5a}\ 0;yBl粜݉ڷQt4)Q[xZ|OyW-G447Td¼j/ TӣL V4@DL>Xk ۗvbMJkjZ= ,GI~| @KrrA[c5AbW H^a0Зjc6viW $Zg@f*< 7jtK;_3= r`֩qC0RcOɭf)Lj-@c_'ҍu#?!*3rͤiO+i.ɉp^!6a u(h4@~= X_L'7Nj4ZCSwtD_Ucg Ml f}s}"+f8*,9 Z(բ"|$M4}$6KuwHWCΌj#n԰0T]ֻ7'clv1 el* V%JNOX=A?XO2aĻҁ- UdH*j_3{*9p#JK Iӏ6ÝUQa|47ʱT2OPL{i= VM6ҝ-jqw'6C<40sd/ɇ6-㦘j4Ef0?90ד3ɆhtF4&j<[]ia$(]ڥ3P$5.,| i"/1tjƄTjhK\}=g?-V ^(RÝٞi{1e d30✽C8V<h5QMÍ$4&J0uĸVDs qvN74<)?~^O*81y>OcP_jx囚,@OpFdif|NsäʖԊA+C[*)[KK멤9B!ևF0SxڊU5߬J6qxb׉ PŌy1ÔD~¹ڬC3'##}aĘ"6tZ0lOBQt3ItZ㔈 4;~Fj- ` rtډȅ깘^6[sfOVLj#G8`tLƘfՉ"V<ʰkX(Z4r$20ERѬ]( `kA"i)!@IDATċ JK*HZQgV9y !EmApV~L;#,ōȡ]ڬv@~,p7c|ѷJR}b1ɨ o/;+FX"uGt3Y6 aTV:6Y,w]_ҶIr)/6OuXxd52 P s3" YyƃK$;VQG؎Ж bؿ`qk7©i1=[{8g;+!lzCcYƜfldbgbQc3*P [G[&vZG<.FnƴqpEJRIY;Q:CєPK(mxEDXC(sj2.ẠKG9j?[ERlpP<~\Rnos똡%zJWb+;YXNJZPOoigשruC*XwzOec] fan"7т9R#]{慏6GS¬V5B .G"| _1%Q IS`lB:p@E;6qy6)B( ۭ_ȚKՐe={es# | y)%n3NqpVCX͝H͡" :tӘ UT&"غBzs'1U;u}?b}wpݖ}ծeu-1˴aÆM*TiQ$kv!'1o^ :ˀ'Cm_:Tk=)~vXNk>LM2 #t#v%prr>;X Ӻ18o{&(RRRh 8lFLXu)<Ǵ/CRʹP rGN=>_WH}SupVL}+1lGi7q,U_b% "Plc=DG,xa"Xw35ƺ*X~1M 7Dݏ w{@Gy#H4?s B, otJ~^7Kiho$zOޓ/2$6!OtHO!LoOvmR.񏻅 ,Ea=9@]ڎi0OKŞ8?Y/k4&?)o5KwOO(ql՗ި! Ox08@F*ϕԁ"`MiK`$O!g$ӢCgQb+oU⼚krC87`Lv~m- DL胨X1UoR6 =M[1w_G)m=V=zF,iP^`uT.؎@ ^>"@;;0 hNlJA79,o'nj҂P,ǰV~Rpn|>iSAY[FN RZcU/ZKJUcfH7 ϓJw&IKuTE ౜sAL"9DK vvkwrq΂дwZoX)VU2^)P!p-תq0]Y>q>!__׎"ܓ`J`!M9.ڭ?H[L/@Go *dG=杔Ok+֠ X`eEx@)MR5qvIhBsq k^nb17MHe@AG[Y`G-'F =g[Rvƍ]]7Wv!#^mlRu9#e:" 8-LݠFJ[EZjA3Y *MDz|f&>dRqWVl >>iq7?sm:'9kFH9PD?~Y$-DKe$Ҝ ~zn;i.:6Z;SI`X;Du2 %jW`m _8DnjrF9SkE_ hFˡJ-g  T1Mx}|`ZS`!r. .J'ۛCc@y}Go<b rASn~=$Y}HL4cg 5BNδMn>3~VU9eV *f,CRL:iRpLYn,ċ402չ(/o- -H 0_eZK:iP\CY>-sٓΛ&),78Byi~:YEQPgDf1nIYد6isk-fbo673Y43A(<,tڄ̪o;gÆ{Zp!^6tҤ02Gn`&:庺-f%W()mP2;yI>L7Am˶IJ1U}?S@ݱ1]M bLsQ"0k$lZJ\va7 Y㪭S6C(83rB5=llK![CelA'Z6P'?6Qgv|'eִ>2)NVNڊ!G}0h2s~(`y  R4Fb{On%૷A92j ]13&'k. cǫ8ښ >[NՖe 1S ǧHGiZ%E/͋%}[ ' Im'Y#4A؈i#(h?X(ln^M4~Z; ]_uoWm .mUwt.%Za0P^*<Iķ|EjZb f?~9!fG3>NVKSEZ$~?+ wa;5ĖҶ6?mIX<,L U&e*r{"v n%nY l+mR# 0paEbq0հ/F4)ז ݇6s掠f F5lfI{l^'VQ1eA٫Q^&LpwpV3~+Xat&6`t6X&r<J2y0NΪa|R'~;j!Uu얺+'\#c?>@l 坻#`j 9-t|g_oRC#_zo{LaZam~e9s!@Io%kOI{ R|QnE~R+@O%| \ $u4&?9(y*1:t“ogd86c@ I%!ؔx<|\v | x~w[b S8j`a}ۂ[VRHr?dȮ>uH,9*~LM8w0Wfh6*Rܡ]s8d_i*<@uzPO$4ߑ2|z[ 2#-=[;o&>_+[BQJ̺#U\ ?JS*oR78YZ])DK^4#/NSv$. sj@ 0~>STtZd ^pڴUD%m Sy](3S.)5x v H>߬~S\Ev=;oyzwF䔂R{a2Pt؊?nw<dڧn8/|$ͺa )ΰ^0rۗcoB06Ҁ̉'ݧHeLj,o,&0/: 4ZQ֮GdZREC$)Zg2y$ !`tTstBQ+[>uȄVbi>zRޤ\#Ef߱NdBLJy@Pba⊇傮찢'dCWŠY&ő^䁼IQ$gC6|uJ`WPa& ch4X"~omO3\^q{ =]*l]s#ـTź*ܖ ^!=l47=@Yߍc}{f qF/r(qWX<6@%=af,U.ȗSmqoWZSF=^YTiYi6Dϫq{ ҺXKx1H6!~01X_mڪT;5Ɣ@4S^ kLX=.;ؽupY $x! h^8$tZqdt DT鄎E4K;(/3*FYh*!?N[ڷSrK̬6(sS@,c#g^JԮ؋3ӽ^@e,!CCS%XF%_+#>R: $o 'j 9|7A/x8uHST>5f yãq2\1\).MOXq #?,뙛L/JԀ;uj<>x52Q6uIlKc631\+6[T(\WL/?RIX53 r=+']> O(Hڙ4¹g\F(F,f.3Nq(dYlc 55$@-:ј( hWj:6[XG,E,n~넻lF&’mY 'oɴs [l TO)CJK=EҒS$HޏcG+KOq86H@Ŝba!`2uUgP@%<'4Oq C\T!.B}xB%Β]8o "C(U4%. P ۷ 3"Qp@/k `pp5dqhq#axj[՝ɝD$$iq 01(4Oh!@8&sy<oX>Z4MdgZ1g=y1h ZRk3!)nՆJMoL5Gihw(wP)ndZTx~s\/0 ?K,1buB0K[AY ` )(4WFo('A\ !`ט>4Bbp5-2!hlE,0900$eqxp<-ݼ6J"~ Pg7fx.zBLPBIظ~BNPҒӿ"y]#i6ȒW4F͠!5|OvEg@a 8ŽkiPma?¬evYS1cG!sVIGL54&7Rm* F_֓q]F-#`{Ul? ^rsjhԡ)\n6|׸QT̝"kPNi(*cSH o݇LWMo8(y O#ЮqJEoHX3r=XcUI%WzA ~h0\Z3no@YDE2Nwle,&Od}IJ ?iO9tNj &2z0Wj2ޣ&ՄO @ 442l%E$@5 PqƲעl@Dz;17',WYÌ'f@nZ豎i: i|VUo|P3W7֫$GS 9[8^C mPwC@8v Ffܣ ㈄`w !gUiT tc\w)6_iT;ǽGfcHk3;JQU/|r"g6Xg NhUq0ԛ rjx8gj6/y$袆ڰJN D}5hA:mf? EqF(ò'Gsۜ#DSx!TV?Pd0X \>d_8hKƞCO@<3P0rE?R-f,,JZqX]c 9YKBSD"Jl( alȑ%Qپv BhȎ?$C:-P/[5G$_: TBX)L\E((uOExN?:btR7a.fG]HAJdiK|:(wb ඞa=rD/hk/#nyvVԸ 2]1h2t5R8-Vd} Gef_k=8|n>3|\*szLd}BjO]x Fz12m6GE奢I ֙)_ K2MEmHMrd\rV[ۃ!J8}!~\#tpY 09OvV"(BPUвd"}u}%ھHƲݭJ{b.|Aכ6Q!z RxO1|X ى-Z!l,ǂH5`(; *qrT4S0 Q(fh2-]R\hYZn<AIG; 4q$`!E$AF0(N @T!Mk *w|x/y20^P[O^ YFH~*cS:1OVO"P;cDGe:bD1hvGHNۘ+Y/a3hcdf`z=Ev}N_ap21RPqx5/lt:n.1v;Lf= :E'WC4ZjJе!4;g֘j^8@vm/aJ5Č'JR.rec2AP()h5;b-Q4 s!N`PF]gҋBen$S qx`~`s879=:(Q`E9MEqF9& Rj~qL.xVf7e< }AF:&fͺAMF!?<`iߥڙ;,Ô0t"'4\CNckdt `OfWV NKwe LR2~{H'F:3Vcԇ[_M]Fwu!3g;{:+ڈgqfob>JrQwiy}+؀F Щ9Z,(I4(;K+SЉr`G籱vPN7(՜є!p|%}pK=2ѳ͠b&qp+qV > rr#8?JLuQY&) OR:G{PC2F4gK,gUQU\I0IIQkHSä>wPq^Y;x42ЬY5c2P|6}h)P;2X,˴ (X"/B)4p0, LwGpm7=[_@HRij,u+5+@H,b5lbUj€{5n5,1= 1LZ;~.Ru ?4L@O^+qzid 1<r :[q-llrɆ< ;}RO䬬Wݘ Nrc>%x I" $6QSr,Phe~X :A҅ӳea[lʞ&x2⢲|eQ}n6k6i?e+5D Z(v' ,uv 7E + dZb39YõZ'V-N?Gݿ8`#4oYLbrA,3XFƩ)BT4Rް|1E͔B)BvZ /kΜ Vc;nZvwEAΐ~"G6_g{-`q'ʒ {Zb(C􂌯x~h(@j*}(v'@Y̙n$p )e3O|Q7۹V-*0(H=ZuٱQ$bܐ$pyebOg$~"LsTFW˜XQ0)#}= 8puMr wF.My%m!k#Im !':y5L 9n!=`ͣt+E* Ok~K٢%)Q(gɢfz|AV&VXf^j+4t d"2|RC:kd+f2%cfǶ9 ሜOnQӹ=۽[WǠ,r׫XN Kųl,V'SY@[ ͓5A?v1כ~1XGa1'e-wӹ믋c-߿syּgf1]KѲ#9^foAu\:iBgah{q8䫩p+e{he?+D_7lgDzE+YYY~.`ڛzxdfy{RLfl$U)c8`?6muK#\D 30wt|A#q~Yo;]kyQY#Ͽ?E>5$$BPG͸8z U?6,gvR+89C4s2J2u%_q3o3 ǚOv[:fk_.BDMlCfhrPdp#aT{3`-ce(=)|Zdjs#yg> Mڑə_78_&l40[o@?Wnuʱƨ^ ^X9~?EPyt3 }[ed /b[S%i$=_&Sb9@G$K2Ɔ6ˌBNs楸}ˢ{ ys[ }0).ZúO bK㰻<ؤb- r[tn(9*Pe'馴 wP\<k9U6qK0s2L;"tN/4E^Lۿdm^ w a~7x8* '6NC^MG?ړPJڂVZmsp;w_Cр\!f_%3<*1b;QsA_l偮0ojKgt* v cCs$B܋ U̎,HnyÈUX*+"ȈbUY-2oQcMtm>`iAt^c;6 RJ4>Ƒ,c E " מ$6T=)ZES0Xc|l1_vs_09*_ vn \Օq=P8]Td"Y񐁴Z4cטk;xb|ج{ٯ4]qJ&p?Wq!qg?~A*MOd]| wO1rs*0滙 0<ǻ qDjCB^SĻi=2˂>y^skip 7 ˷·3t @z47_{6I/+bbGCs9|H֑h =Qrz;)tUu2J$̂0 <gwxnX˘wu@`@H>wKңZMrSJR!GX-dp%w"ǿ~p^hTlc4! |*$$.lNN<2I䱔7sR(eCj5$f \T03 G8/RKp2E4?Gx F\W|lSr8DLN=^ECK+8۲1HJGm 3b9&} !1UDNN}&Oɶ澱ˇ`FRdS fҖ! t|8ZIE%-5BH r@c[6?2FRD:^yhi:Yt#!;H4W7(رLw \*! 7|e:7e0})3yQ_ xNPqi!nVq(>{a]Je qppie>YRO}':iK cg5L ȗ?uT,oTCPi8st!wrLR2@e `p{GAY6֬W@UDIһDÞw+W>O#:RUSSq sOQj"M#>:3^J|[(1I1s% g>wRm [}EY,SFnET3@`@>ae7l;ITj[ݥiL2Rzi 霻0\Í]_c@IDATkNjE;"aZܒ4PUhyOsl  ;tV':!B^}Sc`o„6JM3!1*'|s QŽUbVxGX4? pb?i 腠H>Z 暩Pqi1b(M!Iѥk՘osѸg}:x o ;ވ sR fYѥnRtyӃ_ w=r?Wu8==2rRI9 |:Wb[C0#ߖj /-pE*(6+4Gd1.dhojW\@uy!XL<;^Z]XTZ޽n!Qq aR1ƉҫX&Fw;95C :m Ʀh$ʯvv &DYh>WMZB-_yj=C6'/#Bq _pEIU.6h  $V!Y<)WV Ԃ8BX5tW^֒) Wr%Ld$Vd} ʥb0M#O,_iH:`,<^R3)FLdE:\}uqߧ`;hz;ӝ-{ "(Aә948+W kŞ!La Q*V-9XtM\U7cR2[dh*L 9") ) J;Ei#[$\<6*a24ALdڑ\4M&*#S.xRq+b&N!؍X(tܸ,:T)( mtck&F ƩElp!'v6ЁR(gS:lڣo b bVyd̠#iYֱ~V`s~*Ē߻<~\>ßX(i]YiYр~lBkDdg覷"Cf`Z& >X (&%Uɒ;O`X}pfLqIU%HsiKRKG}a`A$ `ILg~?Nqqgx) ,P`0OE^`͍_S(2zKBX/Q779[4Iqe'1 :]62B|[@V҉2iFY<% '@s\ڌEVge_iL|ʒ;UD4\WU9" }m1W}aVBgdCfX=, }e-42xfka2ލ[%4 5m}dMI6.@d*M4BvA G3(/諩N~ ,e&@66hS ]3t?{ Is˺j8sK}ct+&tpo5T / Z3NӰ4P$9 J☱<,%dO'ؐN5 >< I?{D^h=˰i}g={X \}| dLp@ t݉T|A!u@la>|hhAiwYK_%dw[pfϢس*;ы;Ma@R if#۫W{rj)Ehpsx`u'@489 QL"?]w_0eX5`=4Joצy[@jo biz E؝ 92Ùm8on4t70':%"lg;a#eh,ÓMFYŔZ׸ߐݱʘ=c_T-OcO c8 #Iri <>Ygg9S=OG>sy3cl,-;qZnץ7 39'⮅}pBiWnbnE2@tiu~3J W_^&:0v\.ܗ_S̓:)-$:\DC\1Βi2A p3* I AKxjCICafӱv(5YC"G 30N Q&S0yTQYHЂAlKÔ{#n._GJB#E`گS&`P4o07p'նg.ULH 58XL0ǀ88& `qO8+\w_L 3fqY&&ɝ p c;)ewdWJ;ׇbr֪@HH)6jxT ˱pMKPqIc%@pkI ՛MSc%׎ҡOglA⻘wE\{~֩PاSY?/JČ@1,`a1=D(Y|4`5 ],*0D%@܆?c?dm.Z&f9\48O@fd\<DZ!h'^Ƹ,\ן|Xʉ(k>F3ӥU:`=blnK[rWQ/9ZT<]!Zzrr_\nsx;7Z 2H/[SbSOEEW;wz?>)4]vg ̴GAtTJ27 Fxuyjdi.K 'AHϲ=z }Ub]­S s=t׍@U5 rU霅p=>LtaMM嘄.4tBK \I]=*B"~cʆ:¯M$8~,n18\4P>RǛSs?yUwFcnR ʶM,0 dHcVXQPj*5^^#Z]x#$3#ۼ\T{zi~rfН #A}.㧺mE,.qu [w|Tژ~R+vaL*3yd4R`KE.Uh%94W PNZLabrjIlPAmra渃yz=Zڬ=j7T"NɛRCE(M qZ|\ϲ6":=nҎD$,Fj$es)bd-3-%Pҭ-Þ2KXXI"DX[iIg8ݢ!TX E@Ð%,2hGh2]ZX*Ёfn-%Xw3a¶"0 |@ìmb(22-FF~s͎B, .mX=6*/,?)&Z*:mPNҥTj,NF|"4 UL@@arvy. 1Z=07#GզJ7z1K!zCi'mEjmo s\;^ʧܖ)~)wc9^`"TbyPu_3pvt+6~L\=T:Ƭ|XEDO|Bמ M_?o@r'&ybJpgBSmU3c!zEQl< QC_%1[ʔLqˏ|8tso<:Jqmzwbp}d%qz+G y{CX||\v֯+*sݏ1̞.;Yu"0!< qM"C|؛}FPЦ9yz"6O~7ig𻛏ʣ6@vC A$0J~S҅X^XyB~vO޶6tΙ:f )Ǟd s3~T'8y//!ٮ+>2$lg\.6hvpGT_!<Ȑڈe)3G.E 7V"<,ع敪%Ayr*"ǔ ؿA'#LJ~Oj]H٨Yvˆ`l*f@K Н@J= V)D19vG*o q})VXU6()(Jx+)q#ifʅf[ˮHh85AZF .0p#,,Z=LџB$hȥ?yH:SX*`(s>|SFRkGƪHo랱NP䯏2QʥaFޯ5ªkv/P%PBJV 1'Gmԃʫvy%Mn>nQB yš}5ؤU T!m|0JT(ߥQ- #*hgJy /CQe5d*,PR L &HYhP Bl vS\٨t9gTu}20SC l ;%, S##8bD7ԃm#0ZFNujOQW 00TIRpXl:XztH$Mɨ_kÀ4wŏ5Vhf"uGANŨRƄHXqtU*B&Ρ5iGZQh]1e֫4F`!+ֽAũPle=\\ępI" >5uTQq;!|Z{ibQRDYE\M#quH C׻;7.W{N"ڜz4]ǹKCdvmxXkd\NjE.gG]ek ߺ q)PVo3#-OC@`GÂI=0F}ј; ^8hB@Qz(!%nrƄ6o.؈,-J1(mX Mw"?G JX>cHsL@g"_- TV., q ѥR4f eoe3KYӠ)4 F!su/ gGL+^ܟ43 /߾OaudKjCr"ozLáHT\^Qkܷ!ߞ̞0) nzEMF_ 1R)ԲUi0h0,Qx dS4f͢L_pSd r葉[bRtoځ|bcM4P[9Oo 9^oDROPT(mQPGp b_hFY K\ܛoU Du /*tOF kl$㊅=5ٜ?|{[7S {H{a:94kq fb*"aG & ̀ܨzLx3-%ȴ Gw :ȍ߸3 C.x7mlͨK9#% AzQ !C^SVHBM,w{#,v E+ Xb+=uQ w99Ǯ蝟9“w fƞhM~l(i(aTk4cj`lbN{<߻Ȓm%)\x' ۩*Ф]?S'qV-V`!>L%a*T >34.Meoeft20aM#RDm7=fm6'c@~B(/6|O]U cml#cm^zXͦgACM&-Ci S? u;--[fp8vN*Ӂ^+cab*7l (u$d (HX OKǒ+~ӍQJu\J[U⋊yJQa ;|v1ȇP' 5 s>mUW8ҕt~ɌzU9aM4W&vi̧<#ƚScWIͫҴ`Q t:'$)SM~!)#[%8[u\?Rcpf!-9R*-C".b2#Ֆ }GaG<-=(*.)[23+g% Xv'}*:EdM/@yAۓ1EWI̾ؖ0C?<*Vp(s]8/_Vr3Sf IJ ʫLJ;/$rpmF\&u2ۚoaXV!s>aw[f( O'\:y+{4v,_Ɂ<0zu^q[J K{bE˼ppV ,孈 |p@nQn 'fA.64${'ٺCo_ֹsRmVv۷&m5 x l}6VgBb쒀p2 `a;F]dyRV*`I+Jmr\;$x"B(M9zW7aC%7K^Qx!dTeEpE/ad~ 96`(9[ZjiV_| fXj:tQ 75ऑF@~S߫F"[FS󂦌`V(acY҃9QhԤnPe0HA+xc ͼ#ӌZck{P2ZJlۥR4yR% BݤQRSA1@`I]mq ח0aI Y-CvCmw'Zp>1WQJBLБ"kC=A(k[Z4J]gnphmd 3gZozAC,<%VI0{]q|sӾ#ZQʼ)ɥ5#!9ڨ+Ԭ&$PjfP-?4I:QkWn$5M"x%`PZ3bdb1=K#LAZ'%REq@+wq"R75{Ί)N\^#ڟ2&tGӇV~@gJ#ר6登wHΓaý#zk >UǶLՖYQI3ݚU4C{EM5',bqWB!uEhiyoyJƷ}(r>?&49%13quNK$7T& >!D Mx0 [7!@eh [Bݏ6Eu~߅_~#^j#}rq=DbN#1Ү@/T&;;r7U&y`ڍa6Np2eyGyZ鯐(d\$MMME2…Ha){lF`pKnCj B谍āt){0[0*~[WKe"7]RZߓ&^/MO\CSQD!"ZLR@\(S#pY/_W TK9|xy׍Zˌj8d*2_(K 988s" n^B-xNdxNVIo|f!$Z@Zpua&ċzDOYyh3MP^Le06uų~fS4\4TAAn\"P2RJS*|/uQi:Py{ɯoϏWgk m8{w_= (Sʨ.]lpS=~V>9di- rQRPh2p"wŝF&Iս9µYVr+H`ͤ sx87r8cF lzŲ017GzAajsԡWRF7r`AL x@YNA 4Z.B糽 K|s:V03gSn.JdӖ|kja&NB0[(T26Ƞ#xvطFMނ  Eߏ_;e)w[NFhI+"[RXT@2p#b:;k5ţ}r+I]K2YԖZdחOsItV`zSG%^ )“ž`4:sioJx㿹d_NH ag <}VnEn'~șY|\AhyK vzֿ&A>qʓwrJ\L<4Qoژ0LVvJ -S᫴@BScҢxSN봺_-{NY1h&ST3-!$#MƦ!bHݘ[2}rj]<Y;[!y()hAM[M{)y@t6~ ?_ۑlU]3ڤTW.@Id  wqz w+&BYTvepp\D;K@ ~}7jdQĊD#.Z3`8#C@ O#7i}qT*ٻ*ljQ^[dVW֤NiZzxN#^<܅b4VJEx/s;1q S[ si5=6t4$҈T;D.kF;@% vnCn75Kތ gO(9^"dGF5JƩ{f3([Ug{0]u-ndnؠӃ৐Fޯ,e`ִSA]NlBpTe{C.(T" g۲ îw'q3 J8K/cp:B LC&2m<> I8 #P1Fp5x䦕WSɂbWmޱon*yvYhϽ|!R܊dD)K3TИ"tѬ.Y'a*gx BaJ&PDw) ,[ynaMD ^stQ[%Oj`L "Sٴ1ksZ*}x9Ρ H<ˮHx<))!k l'V~!@zX)fz`bhf;lM*vMr"YD(J2sҝ5kw bƊ@2_afWt5)q+:,v3ꜢW2׃U_#-16gly*@Nȋ`*fҙMlT闯Ժ(X*m8}p5+I0B6jiHOÔ_{\hϗ_&sj&έqؽ^Yd3pt6)1]1T7^2mVc;\Z։b7}*/SiE@ԞxT pn@loiy5=:[tІGdϯ;Ų7~/UIv7nڹ.njWٙ˚:s•pՐrfۓP2Ĝ' r)Ք_XͲKwԨ$.#7+ QdozE5ǻe5*Ɖw2(eiMepʁ1 ~DBXμGD% oZfInZ Oߚ0#FH1:f(2p&2UA]o6p"qym-5`|NtP ijO4y$b8KA*Qy%uft8ɠNRV߱eF^yKoE#αtc$mJNlj=@+W9+UjSۮ{0jxE#s:S㐪Z:{Aeޘ-L6i؆r.x}6E80B!I IPuz< &[-敝$5ށ*!:Im|LSo3Z%t(rCvy>wb'q?}JĜ~{4k^^i:=5D[F y6~kSS Mg-;djTS9q~j0C..+HmE`EN7%.`\gOǏй!u(8 ^E!š~Kʬ'XCJ**XzGd zsLB_r%"fsyp=`+Hӷ͋D{zhY0&`wgiO;V2ˤҍkd6n(l3•7gέpc׳[2wHE-H(1 dA<_]0䆚͟M+(;) b脢N2ڣ}QEdS_qiO*'GƜHxel6,A"Bf`sD9ZIoГ2smgk`"!V5'=kx6AS#tC^a,@aՁE?eF!L€0oUV$ʦ ck~"j"9o?(6  0a~ R&kj kNY,#.04b!"!Zp(_/&W7i @1>=1G>OR 0&MFؓpg4 o ~AWCk@IDAT Nn^͖b|4T-֋jTP23XIŀ(~-] oD&y]Cb=ڌz_ H"ñh8ύK@};hGoUoi35֍uUˍe[f/C}`0ʯ15<~i(jmbe7Z.Hw(NKz7;N|X(o@8cSجb 0cW 圚!_y+)%9A[ +SFlNP85\P6$iEh|%d+D`| FzsY>:9i(CɧM>򯋑bp>#v,Vyr2ګHnq%INHn T Xh%G \Z!S4ֻj XO,Y\mct덊+Mjʚ@&-h8ya3Y '{fz3T#U@86Ǩ?\rJ\H_Cȍ^NRy)ȌZQ'Φ:>O!cH"e##ka7{H bRro.(}`)` ?ʺCv2bՒLDۂz:)6 v7,$ tP[ȉemF38sG[6/a(s. ̳h jB8m*zר2r= t::+c!tHbj>`"2׌ ؕ sDΔ>{23(4x1ZH٪ 5HduF3Vc5gM2!*.q18x8%bw@m[h.E.3<h0VjZ IM>gg2\iᬸ fZJ80iBO?~e ez;FI$irz M<ۉI= O<^"k.> ^Ixcx_73 0Wb~2 \M".a*s>!i8d3xXuU(k!Gٯ; w^Z2 MXc:8b ng O{e|zF'j+Gl{r HZ6>ůySS(DEc!'&: y"qgҝ@qw~eմQ8qST;]ύ!ǻ+;cdM5\q&PRXmPОu)c҇0 nKY?$ ^o%7Y?fLqZ <1wj9EAJ^vbDvNf(<ĸ 洞qv0r-؍UU¡-5A(^`Sh`"U8 S+9Z#""~58Ĕ^-roO2t~N#(iTF\%g}5VnQ#ULcB ?(j%:7!ripj:J[3@ ix*A0n":`c 8OF܎b7~Bj10#גH}naƖ4Z~N˭q+GGmGn)f ctj/D`hi' }!7L>gAjTNi8ݝk V&8 LVOyp XϔEb'_͑~,AA. чG͐K,#-.YU{9|$mKЌjtP>y(Jt3S!TJUn$PQ;|;r z,4ʭ,i__E8_.R:TA",JmGo࿙Lt"m3jBOfefÌʶ7e-:oH75h^y|g0=4pN2ɘTIڰ PER=ֳ,Skyр!ƈx 5g ЯK1$s2)ɑ-0L8; b144|F;T@s-k1G0j~ 6lRA"28W<nK &3\ݼIXxsUnygRF=e@i4E6݌R/DQUgYƺXD^^UT!̾NKL+GSZ 窷u`-8JL,1zo#Hi(@;B":,5XČېw[UVV` __ySk*a{fI0_~AjG!g9!x}w o, R6Q:W95%Ett;+tDaDW2}`H )sJ )=x+HRFITz\tܗke*ѢT(D]q`|R#H}i8a(?r0pm&ٴ BB*i5C1$ =)9)٥7MVwLs9;.>8r=G69ʀ]IaSg*Q Sr_ Ur^Zѹ qнB!Zڟ_*y!S'qVnkw;[ßpu[FM!}FŊ|QznSp;AQ6& oVoT$"ғy,L4D\#yK A F6 ʐlUg'$ (nDzVZzB0;J=Q4 EWM~xÝmBu qbxֱಜ&N\NyGb n.Rؖ l?'?vWtCIBہl;Z6+hIφfsfX0 Gmn+Nt\I 7{ibNz>R(l9Eji7|,Tn~'_ tH";0Lޥ1u0A2jux=*~v6H[x;VULI裋)m6D ;KG1@3jJ-)O9@kv6f$bkb=cGx4?]aɂ*>τ@to=/1ZqFWVYS趤uH&r:Gʉ5Еڡ9Vz-eᶦ'LYwuLB|3%[{\hg.J'ϰEb2e&nJ>-R'_W;xMo=8ق"EI>lࣧ0ċ=7PsL6FW8Ȼ]αT*zZl:}^jղ\4O)WwIOsg$ƮyXT14jQbC.Ǣ/ُ|9F7j|3sG]LuWI.q׋=) F+#p)]㐠;s^)~YsnN^v2}qTz+Y7@ѮmHP37 a^1Ӆ Pd9"q ,5*μ'V7Mp]Emy]~N3XoV'lwH@97$=`}1>$3 f*FbC. 2>ac{JhӾ3X-AZC!Hs7pLn>vvifPso!3Pw}eyƒdA Yݽgllt/3=Qd$*֊{xD񻋬QgtMO94v " L< ,. $Sǻݭqe@ |~͓"xBOZk71^*vZg in ЉJ,Q\kF $}"]E<-Zô9f< Ppyn:Kjf5]c4/5d`k%CZx9#_KMˈhߺ#05^dfZdq);8Y8>s%}DA8k5z=6);)+7u6oM9L-*43ߋ40XD+?.q_8s,'C6J;nǔNN:~&w$Z3W55gOPz(xpUԔG6li$q4@& 0X* p|A+힐M3]8qvI1)W% حr>rHP @F4qb , qNx 4'\MʳSZX[&poԈ{ V#]򩰕-,U<)*5iըĄ"9dOdeCϨęqASF)Z"w)|8SJ_rDц88q~:S YH4x#w;ʖ>HN%Ox(a$k,!D$prIx*~C̥kns+}=W>5ØGu+`tAʜ>Ou0"u"7Ozh8%HPvS'K>*||mr K(zI.<҂%66Jo(@Ce.Px|T+1Txju@dF(vwrY7_fxM[Xf8)d/-qS/2(FW UD0)^*q4qPd"ŭW`=9ao<~L[ `ܮUB 2cgLJ :>dDR>H:Gt)Q8+2aƕx1y њ:WO:$iT$hiĵj -BHv*iM1đ-Y|'9^sxhȡs ̙a@M;Q:_:5'YFLFV1R7"'ť{ :-@4[{[wD`cu#Ε"ȼUPe&g-N%5PR #w.ݴGR; a 3<'!?2ݦj:rߏYk[  8d-U`8J$5?%Yam6:-S0S4-eL]$n JFICP=x @]V_c妆XL p&Q^dcD(@D +Hg+4ԂW=FNjN67B&z` bBiG`O0e;7e? f!mqYH1 Y7(McT_7&ӈ nJߵYLi 4 dd[p\[IHi@SimsFQZ\]PծA+A-)ʚ!ߨ-)ܟ(rR;B'HbyrQ)ZMB Ҳ.@ )xX 齜}Q > Êty=~a? &xW@\3xq:^| ؁8(r^{.񚱌J&zrR0m3:$(_eXóxQI5dtހč?h4D;fCKȡ#\˨aAk52cxmn0,w %o 8=aIQ/r f0] qe֏#uo ;F#iD ;l [`Z,&~ս%\tQ" ^#հO,Ok =1H]mz97/;4j?qٸ \ yÑ\Ct2߯ĔDCz,X胕?:!c=8B& 8M=-[rhءm7{s&c0V DeUʌrgň4ce/!lrV?Y,JbmDtaBZ9?rpC7Y>h'^g2\|kv6CXj*˨q`) SthBWÀ+ L`Z+UsP%Űå 9?N:qw^ZaTkI 옷Zn.mO"} A~Zw`+YJˡ=/阻Vca.E]昔kyhykYw<:6N@`i* SqD0xd IER`%% S4=4e#d9UwY5}>W:Kj{%nIZ^šrτX{BkD,dЌ8, 'eIL K[!w `UѢgPl+1x&|7]cΈI7$_wRrpz C_"( 6,)t3^Vc8 b`6f!UB9?jY2S 2~l !IW5I4E yl7η)Hn)2KY~g'!p!vr(4&\r%*)j‚ X;6]m RU77%<> O_ʢU60l|90QP|N' 7~(ZL2}$4MRNtkgQb魁p!r[Lr\{"6&qۿn~ҽrDP~?N QYy6r9s wbD!?Gٗ9޾<} ǃQsycQv`$$M13!enXW-AV^ -Ɏ\NjJ-(#z3 ǏeRL h"㞑IQ FT92Ky8KR:FoN5c IFT}>.\,NĂ']'ᬩcIHbO}'Yf1FR2ϳF )M Wm9: T3ԋH%$S@yo3+9#+2Dk(aXS|!-a0F_jV=8YpĬ9v5m4 ӱJWddƊ:'!'rY-􏕚%"L">v*(H~ x i8nEm\- H@HCJ29ᚓ,0 Q꽪0B ة;!: ,m҅@PA,eXDh}l1|VhsoG@,?⥉صu#>;/\,[zMI5)J!b;*-_#Q4uoc{{+IMN;+7z$C=>m:;5 xD>7`WeQ hx ;<z{^:Z uh/r=8Lӄ2,U aX\ǯYdB jT7M-jC- =)֞' B`Z7ѲKIHW3z.Ҧ^;&Xh`5t#j/3C6+;!4J^,3mǦH1mZOC; .4SLtY>sG noߌ,>њpzg3Fl*}FXPȡ;=Sxꅻ/ O8PgM9ڿuyިɌ h ϡ sR oCz @*(l2,%6 /@q,ea +]t 6Y-\r3j[֭lQnrepb!NAOrNse=#g~'[ EL ]M]ʣQ(8Xj4o/sBiO1 ;D ܭ]_Lr ʞ2Q"|Pʭ-3,ք?Z YU{mKXapȕ`1c×dBUf63~I=fsUSh\猟`fŰ4pG!zQr1zj@piABVԆ9i3& $(7 qBSD,lB!zT3^u`h2G΁M?>gנ&kx"T{G(7vc"cayIXξ6F[=RBb?af!.<41L?\Ġ[!TFBk8 t Ne2luEI-neP.(tmj ҪոF&fsIfuhtȼ7/!+" R~f}@J ?҄5i(J?yM~:Ӥ 6 X_B:w#\5ޖݞ@'#? cA;0;4 D-4Xȁpyf"5@#2R̉K< <ؚ'|TzzNQC}Aj{D@a0<,-{xavRX]ယxN |Ȯ=fv9/UT X.ɬF} ͔"b ^q1hwNi&͑O|}@j%E,^ԋm^AW*P_Ѯ?5/hhb|9k#%4o}˩cAqurHr3̺d^wMŠ˨hvJb\s,XMulN<%ƌLڹbE..ڭ6#mR~X?r$!kБL} N/l,RO mU60b)YdI?Z4;mv8D 8ho߾^2ԖsHdmp7p AD  A!5X@F|az\F[<<Z1;yƍqψRF6DjF$cM_bkL̩#q!;z(Rb dZ-w\@8{pƏvǛȜhۏ 0_\V#x%8r&zHW~ \:JF%FʷX\ .?H A(!#v (GcSM< Fɰp5Y&6ˣ4R+Hf/I9^AwW¢Go6Wh\,S9b#{qJHΝ!#l,UC=!fb M)PD<!&=\2fGFFAnaZu`dsmPG*51|}2*_#GJ1)oHi.P%a9ۑt#CW`O< f/osǫTZDQ-†-Z@4?}nޔNCv2*=mIYSkzOH"@֧QHdIʌQ1*yqvddE2%\F%' c D$WHSRIm[.rs=LCh[10(['ɧC|޿"%*kN5pSCupΌ6 V _'oNu6<>W.=úM" Si6)GQ~S7 hyV1(HM 1gk{ĪUIkG- N9r{jٞՏyϛg`LT荙t[8}i=%pގ]uc_dh)Ꟙ{A:Z>~?t4-z#+kd޶Vj*7x.]> qԬһ˹VEXu&1xcm[z;.9v~ 87qKcnw9G{u:Ή}sܷH!Ymy,aN)`jqywLşɎH3ʐ"KƱDyoTmVܩbq{o,ti.׆T񎁦)g'l o+`1ŕH۔,/}x<1?&VKE~hkw\Z]$Y_w/,ö2𑟡X@:všhxЇQW ?p^"`D춶:>l߀9Et;4j㓄wDgMW}J}ܾa6p?ΈH_rpnG?=dhӪ]+{6"{ݻvP@L"2äMf2x2H!li)EnKߍ/J ]r ^Lx5!*~쑱.{8u$Oʓxە9og3XV}(1zm$0J#p%T5=N6`㎧{MkЈĺizz]x=^%=<"By[N#h$ށ>8'8 yyL%5F(:p`#YmuS)T:D۝ ]#d1ˮ(fl's]y31LY9MMLx:ϔXscM;fpɴ9z6F_pAJe%T `Z-s"p6hcA9_A6#&L"{݊4P=Nr DH!!oۿ^5d#PSSudB Tf)~G< +1ݦ2Ä&fʵƀݕo3燖j &֏N ?CEOɚoEC XZ/b .wqb8g,JR+O=Pxi{c=v;D uJv9UA c oovG*:C x_֗m,/4YMRB$ߟHl'dXE!R%81NP #Ԥ-~ǣƢMGpE p(1˜_&_)RW !9OZZC+O:HY9݊gl`skzXT=A&7Fs,yK׏Ҹdv*7;<~ޫ/t&u>/L##*g.AaRc_H.@0 L h"<'ǵ1ʄZ< )zaT^SB dO=N0'IjLK{3/8 ,c+2נa Y 6d@{*a9\lHyW H$WcjTLc"pFߓZO;Uh" Wy_JJhrbwy1\g㑛@4=aJؚ>+'ޑGODB3v}˰ lݷp*C#'wVm(OF2Q/ί@IDAT@}xG` &^s'ځ0]Eb@;ڋ% $_>jy>Ʈ5Rx6@珏j)tCi.8jѵJFcO)Gz2'KNp'TƧ-&,eSΗb,u$JȔn$D0 OɓS)ϡ`*2ŀx]R}ҎQ6:[Kx8 }Y"I>dByRB|<Wnz$lҎ_)[[Rxy>l䬣fr)>r_FDCi㔕o~%dƮKTafExe6B?quxn$y"81I5P9:XGvz H?BO|$ƁDZ}\0(Ovqb 5f``m@ RN(H 090>f3cʋ(^qfsvA 1uYmNUUq9b(P(C=Fzνrպ .f [- ~=UM04cD!gY󓴼hVۇ$,1@6:rZ[<* >HrW?}1W!S4h Vϑ&( ]"Q<5dcGţO؆ SOR. DqI3]orI{DagIh'J0-.J2&"\0`sW5D:&V2X 4|\ a$a\nQ j V7ۦ N|/**zYrZZQgb l})+OڢoSB۹1A_@H%&(FbF%~_^pHTK-g#n/`+)tlTce"Mv(aW#3mݗ!"DJ" 9lS" >SX.l-:CTGca<,.AL ,`_5(5a9B~Y, y`}R@k0 V&Ҭy 1bQeJx .9ŗܔmMnν)V0 wer7kdse>;_Y?cE+EV4EgwI!YhZ,XxVmtBEYsX cܿ~~@(S/^T; av0wRZ9uu -ڵ`c^)}x1YuWw >!Nt.w\%So[:Zw;XRE*r4'f:)j(awi|5d 2Gl[|Ac} Yfᢂ'HN9}IwA~gb?#Xɽ]]HžMk BiO8WB#+-݀sj*ҠUfb di_U硹@OE7 }DwhA#6 sVeSQBj[;GDTxk Bj#jY#qx<1(pr|!wKVfN1j=nbj}ҌΝݨ;պ4H"Z^Bzp*&s)^)B[-*n-4 Wfl]ag\ -}83۩i 879DG('-O5,Jjd\(\i\&`D Qe`\>[]Jfdrsvw kT  ^(7rP񃆡ؠNR) `?j*J8)w(2&FzEZ'{B4PX?vKA820CY)F2A4gd E-QU?!o/7y'/p!qGgqdSet+!N;WqC}(=/T_x%Mtxz3)#=79ǯՍҔ_Sawkkc/jND:T~-WqR_(2S(.$W'ںm1+URT`.L^}6di؈b#`d {a8|۪_b}qg 鬦%hj{ݱ f#M;Q༴@`2ϦTx9jθ)j!و-l(G:.0FH7cg>Q :]ty@\&[ r0rrS V뜟,E{Tx xl4ҲpR(`*A[~nL+OXݤd8\rKLUo;t)`)WKEJ,VS{}#(cpq B6$bpT0RPΈ.PNy6 {ڇ!ǭBQ/6LxO@P{ֵRM=#a*4ugJ!<@׻sct劖' Rh[0JƿSMqA-/V 9$FyqǰQBa<~5kNzTe7=;JyqBv [ݲPuZ]~!c*M\ K#tD3sv rp2@m{\ !?З' 5{&}QErfT p$xD{efsA?[j B!53%?=SqaW oOWA3: 5Dx<&^|'f<2,o8^ZэˊW󥵷<V^cVpa Dum5%er vwe5a/GĊ(B=i 6H!-\,p]D*|k@GZ&ǒchOɿy=AiNDbsBPctq635^iN[qx!,Bi`i Y7["A[=JD"!T1*vcQE=.k9Ņ8BCBLO6b_Pm 3?,@7pcs!U\s{5\)ZxFcK 110|__B6/?ߝJD5+v3T(S?ܼakDz]ڱ Cok⢀SIISռt<[ LHAd!pYUa^X*e xqNq-JZ0$30%:vF]r[`?l}P_AƣoKԁ;'ŁN?G{ͯ[;7lz%GĜi4#߄;s-BIeYbisz6$^gKbg|Ud:wjoq" c߷E9O?^^t%q=~.e'V YذypZM\kI sdB2}&i")pox+4~ޯ-ڛ"R}~tB*&qHQNGb*x:`>}B|uG.>tH)B7Idg'1s{l*-ʻ /rrVBS|Zwm+3"2Nx$1-^2\6pҽ7;|Clȿy]|rwt{o[G.ECʡ|J8_˧܈1u~ 6Uw!Om-2ؐܐ@ H'-/Sf 6Tà1MpΫiHv%u!9rUZ|@JE9 S["Nzڭ4YܛQ9gF0w"Iȹ|%`$ _a7tK9kHxYy7tӿXpQpp.%A%'<V-/%6jBVwd).Ke>)g۱|)T貵`mw;3}-/`YZƸ;;$UiI“>c)Y5oJCndu VR"T|ڀ,p"7ȃ3ŏ[l.ׯ(uL$,[yzV|{KQے>\\~+J.* N=I< E<ߩeGɑuw~=iRfnhv$;歀;0nv>>/NJ4iViJqo {YSQlH}&dZuڨ1Y}OD)o%c>@@p[ljg("9ꀿiF(BRE<6HX&r6rј)Rx7491ҥ5_\p0pP؍EљcxsO5pe pbGbKWyӆ1N|#YU^3 zn`%+<5Tϟ?^uwR,EP3F+>ƺ*no&lbQ(7vB תT< sFV]d M}"&uYMp#A*x2u>J({qQe9 ̥VOï7d&_?ؘ*wcResNy7HyK,3DjpD2)!7k@L)N lUtbV 1v Aۏ&3XOw{Ld7j.% ިzODkptn )j^:~=D)Gd,revMFӝ`S6(NluA&(8dp(C80K9Ʀe=CYzv[w4&}C3"TR4O@7"m(I}{&C;7|Yv_*5 sa|/$\`S6k`ִƸf5WE|'W8cJFXPvV whLdO}䗡.%&YqAxX`Yxyap(\ɞk΄&>?W %&!ti.F6Gh_@S+^K,N? +R_a2nwg\jPp}w)=ޤHC*CŰsKiᑬ$ B$ =t8a=l$gԉ'9u-iW;h[RdeXh]FpK;XLT@EBRrEҿ>1i^;Hyp[\ϸƃ$FPhu*G=}|p\l_N|˞ *Tf]ih6@3X;k$JU6c8eoOgb~+yS8$mV6I~*;'NeޛTIbb( ֫d ꚧE1ťǫ184 wXlrD4mLPAz! V8І&9KT}αU3qX}윝f{*$l:$:ЛJ>] !~ԿaLVr5 c;;QJeIOܡhĬfhDM䒂h'5(W~9K7R:e\djcF~BwUjygLdlfo;:]7ű܀|yfi?<&"*~q?JRIa=Ij@٣@+8k649)ˆúOހZU7igjmGߵÚ7t>N370)$ӵGORVWɯ-%@g r0&)3C<(!F6tQv1O{c  0r[Fez0dPoT)!_BH(35,B1PEA?fJ'`ư ~0/YMMqO1=QV$2B͝nBeąCʽP{c?Ҋ@_ԇR#g(avt3)J!i6l9DyJJdX=؉Zw 4Q#(I YzORk_-fke=aS(i0d0& keHJ3݁hyJ8}k ?Sp|'-3.;c^ |XI-f 2C/9fG_܇[?JE=KΔ:,Mqǹ󮋕.% 0L=(4EWv"_o@qTMê%._ 1z*921w\~ը5AF Ħڍ!YCɯ`0 Wa !|S̕InBDr# {czҝ2mtx7Cxpđ66 m[(ۼaw[^zO7 c]6\|A-2) mF;P?-qj1eU5khD)їX8uo@6-CB=Gҿy]Zkh(`/A(|Mpz%R #F A[P+!=RxL@5wd씟?_so 5I=fJ*F~L()r;SyB\N?ЕMV>qmJg~:d͔17$~ h&D\'[0J1~'e@ mm؁Y>ddW¢K!ݘXhˬaGR  9q(xyks 3՝:6/'QAɰz o?&]KƊfBXIMJ)"߿yhkw|֜"紼p3N8WGbfǘb9$VԉHf}rdu(@6^ i m(2*@hQ藧u4k}[sr':,Kl̹?ën9IBqLW4E(O7@_@kUlrXR5 6"Ό szShžhôT$Hx7ԯ?rxǯB|(401m1 &AatU xz=ȒNc%6&^%6әabWƒXNJT|% X)o*Nϒbp"HQn$ q*@y/z8=;ȼ#JS{Kzfjn8"l[.u jPn3^E:=z1RiD[aH"5Pn -Gr@b,~PO ja}#QDGD~5Kj%I/ơhCPl?q&KDMjq0.gהvJ?Kѻ14u]׫+P[+fidDoנ+nmneƞRJ]S Y/i(ZdSs룩->̡)e(9̼D]`Kw6.)n^ﶛԎ,L\ՈD{Pߖɾ\q۸[ kSD+B%fE(A-uʧb!ܪ}]*ևSeQc5fޯhY?_ Rh}ߓ٩ұ` o嬚Ptǧl7GǔSH #lbn^6x~Xq88vʔ[*!~hhmG%)qu.35 DP}W P5aj{`|‚ᇩꌿbb[:2@^]Q U=|  $Ky)[&SF*;[ Ȏ84-vFGT{M:[%qFvXPYqDvGkR*l:4j5U0DpXiXR89"K[>S{3 Wp20S`TBSM21J/wq=<w pI&RW*), Yf[._7PEfy &[l|T҄F`m[j2hbA `2SI' +9F̚u|i5ytu/Po9$o"M[#^2('{;* 3U/PY=FKɤ. ?I)IZ)͕6dz~I$c1J!E@<1`[F2 6RFICyګRt&n<-5ԃ˷pmXryh̸5\nD&|u? Έ:֔b@,%MzoR_dȈT]e⺸} m+֒MhSŇ պ%uPQw,[_ 9zb&O&Jg5m\wtzo~(0%Q-WlɊ$!?E`X\2|x_ώRƘ.X·}5LB,2,lSP"N[\a!y=x~\&sTKSwuQ8V+VJCCO2 YYV׍m q$J7Ζu04pX/hc ߏ`#TK-1*A$;NJ0}Sj#+[`YUʣ OD n,?#"$TC3)=:Dc&CTdI?/psSj$!~|<7ۂ"h#hL4IBL zP1x՜vJ9RF] [ KDE]:\ HXօhNWmg*z0h)Id{iF1֑4N= 7SDQ74w;)h+d!}kn漴`FCOCZcŢO0C [6kBrxE˫zs # X0L7:c]RG1N7,QKs"F[ڍa J7xőP&Si4p<A==MZSf}Udv/Zgj [Ve OP 1ǻ §9np J. \W@+ X9RQ98zwn<|Q%cGRk#$ <^}L0DHp=H O**-2Kiℓb"Ԑ:i}}bՏcZI1vD"RsX[ЈM[cxs1_[' `CQ3 {G1< rPoLFg#u~9DFb˷E6F`qIIC/̐XS;!.uU?@&$kbt"I{a!@_`;_˴E\Uiktux['M32v'©&Fc0+h*$DY+-J'yr3p[;_ !Ed=2MQ R@{;'À|_;r^1(6-I6kk_L&R|Tg(ufj":;ha k4=ޯ6#_ΕJ9  `+l‘w7iv/Lj< X`Tno=Jc"Kp4笍vEdF#"; P{xHvejQl4Z0K"ǎ{>! 4ry Z+4i"IEX#I> bNlAh.OQ ,I1sSOsy˦2eg`vL@68u6Lr08G4{ aj I&ҷ,#$UXA:k%#؏P ~jJ8^FKYRIz(r}1 ʢ _HR`kbY8VKeK)|%MALp1u\.r*M=`nqJC5=^%lvy>|z^^_WSШ^HJSL[dz x%5 =^j-6u$/ĥn%?eH򠃎NQسe[)B[$T TK<:ip9 ЬJ_ p.([hron6j:D#ٙB؛C1mAK ՞[s$umh@)pj F4O-U(E胘n2KTUyc7"#%EHOds$()Kv86\b$&xAҢ[J)NHe>g i"*z36- }JΖÈ`%V(=!`FBi(8.Zg:EcwǃɎ >́BdMٹОM,8ΟVJ\줂zg]2`ɩ7OǍ6k!wriRGxh-n7(o:}<'Z}Vg⤥Xi4vlyV |v¸чM mlz&z(`m.?<=koGkBg֕@2VnOsŏć ,kC)ۅ^"d)7[~s<*E4^aLs*zow/ =Q8̇| SB۪ htgptp߬'W';Vˀi0dƫ/*>^=$s9/\W;8vaP dUd_(HUnm4_>`At~}Ȝ8"޽y-D DGSώϻӳ!FAǁ#B0c<*]@"/s6AKZc1|8M2UYmېpѵmM]F'nO[\gF4ghhinO94 6ϧԺ"(&Ҝ̔?=jJ˅҆vf(uNfN1״[}[jEu$-^W,J׏̔rK,lt}f̩4wz/͒cMT/$V={Q|z; d[-i+}e)OGB2x(ʏßB.Xa}:26ȴuD`12(P \J?@IDAT*1\XkO?ۮȲ7Ц7w~Kc|NψS)6Zernrx~2wYYl?KHEFP. |eItYg]6nH06ImmgAhZ鏱%?sWHTtAA04kB!vS&;b4b5~[vt<>i8@EZ{mȨc[Jiʑ:wⶃZnJ ѓM2!)[.bbrIo|R!4$! "r㶔*)_@acdM6{=)_h I6i8c@8fHf+S mnbdon?UxUA##dG;ԩ5r}ީ[W\58JXq l'g|T#T\o paEǑ@k~Z ICMu4*"dj m"̧ "6b{-3e(;.7Yc `z6&Z؈VW^)Q |F&sw`44/F{d/Di'zem숂3>%mXbP[PAmTl#f9OZ\򖎠~S ؃hբENL^=h&nеkj7vҚ)5% ]WuQ s+Iw|5LV )ּ鐻@|Z]ష+1TvΔܠ\Q0q3V[[Vr=[#m!UQgN"'심˼S9@9V0ؠ"}lΥmG!R B558BEqacmy P쁍oY$j°8G-bK$Xi x1C.P &b L  +%U<:MdyWS?OF$f8ov#|Ccg@~lj Uyά*.*X)gYC qn\5!e !SBl(Qs}mI^fB7|"k)ǂʚ ЬNhA@"hGxaXyo<AS87{ri7Z12]<)@9$6:91lZGʟ>P).ewMT9;AK3N#PpDJVN0V~!R_?t=`a!_<M>πiػ*|  _$Nb\E:yeZWb2ڎ$a'MI*"OeoYwhxa1)~Q5P, @B>yiyiXHŭ<8[[#c] 'F.VL3XQxyIfp@ BxmTG6δ,nAG2t(`Tc G;0#oRQ'ňW`eJr,VDTWrH.ri,PR<s+M<6!bT 4( DG5`~e~{ʸԨf5$C>$&7©ѯ_c斄(dd[f"ڽ .D EG}wS|knC$xj|d tQ?z=Eg]U s하b۞:[F~JۇE VA# '蝹& &ΨJS>o2w .b}G|[Se/ EJ2dSr~+T=5iSnxRړ-I) x8osxM\k2 R&1س2E#kO9 ,sR4\f59Oz7ۯ3L#O-o2У}Q*H,GFdp,6Tu !mfQ) d`!*5|+-ܓ-4FF\2f#F>&PG?,-"{髣 Dz)~HjV~ cRA?OQf6?RpL%KA +׎u'))`6 DUVUG+ѴH$OuM @*-(I|B6d@>a=bDz!y^gD*i:F|u-Gs&ڠ;X/|fʯ$\'"9&gd,*rШEbQ:u_HpR3z-ko!B;Euu-.C$K1ψX{OYU>8̓f5>:t n'VW`c:5D5iyxyQhd]f.c-8piX !TmwIo2EpS$g0^J8ds7CO09 ǵ^+MB ,9Kwq5RI #!*K2ep){3 K4,ɡ5sbD7,A_ĿR]s@ʚ(T Ч3#y6 k^H)c*d|FgXf _ ςG~ *ϮD6YG]m%l&\2;i%hCjZYDaP5)_*i~)R8mS9Mc 5;QH?9?48z4R#&Gqd}ni5|a6RPwwSJ+ʠ4W&Yx5%eI"4njB1xXq'r&ObGMt />5_P%i3+(Vs 'GdMU-=DJԒu$GFi{IKʠCnx":o`8CZ/Z{xxC\x'u )vQ2S3$^z7p3pjXQ/BRȦB}>X7) vAiF#kAە^Pc%ik"R`YKr]*FRoZɜaDhGbEH] ?Ih"UxfD> &d$u] s^"v Uz]R<Tq*H!Xm?&dAZQԨQiQ&SL5$<4VQ@uf p}`7thYa ZT2Ef4DKcLc(Ac,(<(|q]@pMMhָ:Dz^aM/āh&+vY~6i@*qf(gׂF:ѐoma{tk5W<~z:2YET@(ei}["9폖aR≑ |&gp^KKxF eIU  BiQRI#u_ ZA9b]&x+9&rN eAӳ/I! XQxKE(Uz[~21E32sqe\ qq| (xgI(hxn] s1"ȁbA$ `PA7,Cj my Hko^R*zf8]BQ0(DZ@5@B9q<,(G@b Tpc J1% @->;JِGAEr;yu þT%Z3J}P V' LI(]y}>TvT%~x(DWjaFZvrN{Z͡Hi&S Й2g273E# Pu8jKQMP jxnbXhS!R6qHkF*2%ik\D%T / j\zM 6 & .@r^b꧂9(As)ajv\u(çl/!;_gPe|Djd,oےEEP: UY L*"xAVC˺weMKMq8e#:ěhH7dr1E&vN8(ӑJ'DO?lHfA6wZS(D0!Q1Pj"X Ѯ4-j[M QHZc_Uyּ;$1ckq19'W?1"t*+Yb0#*8tnӽq1?tvM,I@_p j$?䉋C9V{uOMK[p_':d m#I0@ 3OiѓE-*Okog(Kn$)Lvc;X,7E "H­2|r{J3z%H ΛH\Dk  ݀ᰵ!*ҡVcٜ~5agĝ9@yC}E!eP28"c%W`meO|7ۘ#=yy2}xuXyENV2ނ?P2sP3 9JHjw 9v2(883|<(kDU<1] DE"Md/}dkF Lbogj,h;Gƹre`/d!54i髗Q}~Hk^=J% =f#6H"m8ٿFEWAЙ(_QU@:_[H@90!g{qL}1ʟڙ?pN={᰾[~f0]d v{1[WW{*z#fo%D[wb7%r؞ Oř]1:RLrpN20yҏn}:g/J=Bh#oDD2I.?YsARnu?Odubu?|Z\h r^/tV`.pCW/UzM,"r7C>D+0vFA ۋmV}^ef!b>4'Wьvls%~[) *Xn_N, ú@ɱOؓHq<~n3FH' sZIcM 6 Luܩj1"? ZAs7MHA¿^LZaSE?*:4釩BZ05q.Ԛs0.,3D-uנFJ!3 aM{;`.ր8d*k?"}[%?L3< i#hQp7/FO6ndp^\&!s?˷s۞.noӞgqFFpea2" QQŕ8۵q|R"3`'Jie)FOJF9JQ~w*+!B׆~26wl)POs!{cxH8ܒrcc'n@@E9j@S<78ȺY**r'oo\=Κ=T De^\sq=H3--?-o" N꺢Y`L# ]:yZ i&{llmD|)3 mcڔSb:5Hz>bIw.<.Tl&tUI[R <Jg{FJ_&&LE $w8-.-kS@UY#~E2Yܗ:z`c2̞1,.9BP4t4Wj nsv2|gƱ?p3L4}B',%%ZLa wDd的Ұ_g8 `%L(> ,"PX/4Ȟ&Wn,}26+6Ф' ):N` @LAʟ GB;V8p |ke:{D uЁ 2 e&8i/%P@YE8Z}7L]^%cI"@]Ec#OʫDrmc S^2˲.Gul.^UJ%gD$=́ pH^կdB⹍A53[I] hcnl"vznV͍+댣kyy "qUuLͲ0#B2bi6Ffe*ED7碏h`hC8tC1&`ޣRڤ[_mC[#KN+vb2NV ;= xg7/_ivȠ47?js./@ZihA8dSFoN\r(/`L^Hf`er(WMN4E#(;e!q[2:YlF`vNA߈/*IWQ3l~I);Kp_2,޵݉DdLdh".lHE$Яf$" T_jAl@y QK l & 7cKW=&oIvuI²?ͦd..+KQDjkJQ2ᗫ?67z:YyZ5Psg3!?"U;K0tWG@U,-K,H܉Ga*.DYvFe l.]zqx! ͏1jybT;BW`}Nuk1F0*6.[,#va`M *DoAf+r,v :WJ{?ם}2ţin]"e@05vd+$651nA 4õ薂1WFy7zIeUt\@]`W,53'p(~QC; xRnǠ'(*RANh$ʘv8h+g ho+@,F_e/j?nօ,`.e\Fp+{qP]ͥUzMjOttΌN窹2uQbIְi}L_Z'z EM; D@ɋen 7顲zi} *!Dv+-=|[$: mSM䞩,SS)c hac1@ n؆% mcz()!^l(4HcMc$3\kZlBy+ahG!-Œh5L) /} Tu&"pzoaEϷ" f6Jd]*[`bHv4 !M8GnΠa,Ͳ9oʟLNrFtX|R_̚A@FIH!TJrA{S}%pcsk8AͪtR8"FȄ6!Ŕ^ AE 5SDs}4 ͣO;S6oKA 9調wɡmغJ~BCf AS䅱ZjD+T22*$g2onbsH0hn?f{YfU&d1DJY,JMĜh\G(o|D~%$˺ A8{k\#e=Ϩ t0.¼-&Z D|+VL/XX\_B:<(L]÷  hz^#^`G78Bץ=%$JC(w~8iw2{P','%a3 }E{<%" rD[kz˸k>'+ʡЯ^fMp5ࣦEWO껸ӽ ^ _Xk4\C]~ #C&x-mՄ;ro"Iw y^7j0 I?A|S@l0#aWԑth^mEFqfIf"|sfC<+,$QQA(2A=*VvI-n7J Ϟ+;Otv$=G.O.7j"e[*Iwx3"ǰ*k$5{hS7Ty 8JT!V'e|%q9\F1$C戴kMYSrG$ufX+쇐-&bOQ" @1kx,LTDnG{RJUg vu_?`@I sEF!$ آ9%W#Ϝf*X-{D.T[>z<n][0r6g|I(qBEI tm-)5N+'zTDe<YbTK_F[^L-Pq@ F`i3 L %:;XNHcuooH9I xXv?eOg֜.I1_jrT1VrpF 1fd$@iz„{Ҡ:D-m[;I62ueg8hf172Yӷ z:WweN9`\WScYVG.׹`c@sLvl?wz={b 9.l2$?;ȷ&GIBsBu(x!E̊e ۫)X!m/[gdR_Nj+ChN43 \-_XP}!`(߅9ył b&V"IMadz#is/Cjv@ݘZb~0h0̱<}9xaYqeKh e\݌-RU8YmE1I꒨tG".e̺'ZRpt'GyEluѠΎN0HqFzH@7.a. ZCe_0~eG "l7ϋ`U͋peGҽ$^X94(m fbN8\RM{`8H.&sRVY)۽:ttaJ \(m*@Ŵo*=Fr#AٷlʼnY#bKLPGFĎV`o[9  VB|,󵇛->DЁ D?$ {R +xr^8T,Z UhLQR[jd\Z+p8$QORgaT"6nD+gAPrz󧇖he6lV5p`HrZ.9&FC%N;~AeE.hgf w<-BP RCmXBS wC,63Y@TDs ysaD݇\fH l.ZejX@z*<xMwED@73FM%AkFNhmρ-LU'̥MLՍVn?N2WC *l;g/(J*. 2ngVfLke)4 ̊ق;x[9q,"nmaS_㇪DϺxݯG~CGfxLuJZ&v)`J<P$nFGrM’u"͠59`I]"_7Уup:1 t:]d%gt۽|VWT00"U}.2‘39X8 M(!Xm3jhM;5A8^kU(w ^ۉP. ԍJhw1e{{0!e,J*ZAn$-F\{@$ջ/lbў 8DI“x/C8kY #vʢgTKo>[]۱ ZjV 7nc$n~H=uP İ"$88IBF]D`.R`/>n(f2v۠+Ӕ;(i+lP6S,c}!c0TwM@0?1#YcD[r=Y4Z.9^^-|eO,һfpNVVH7iyl@4{7.pVSv6LSNlly̫ZV$I1ojKQNE.M%i1u/flQ acĹ>.<3>ggpNAO9(@ 3 p3W9eG}L@}ՈMǸl̀dcOzT>8^X;w mC$_?]KSG8`'[܆QFu|DUmic z,?}֠,!ʘ9 Ri+~s|D&^K2(Og6 A=.WbƺB'Gۺa'suMē莇Moff"}3wv7x7m}ֽ[(@ ۢC#}1]% ,xnc+ 9bvsRLw(DZM3]V᳴T Q2FAZ{ Ⱗ+EM {a~OGr䎆v#ILd [!|~y>r"J &}y^]A.cJWO S G;WXnx (yO;RSm$|{_^>4]t2QQ2qs7#  {#\,'4# &ah,W 5xQO3퀕).A_[> qm@h82)'"35BkaM:ɲs[kqrQ#FNr^?+$6+/fHg@IDATNm85QO7%67 ͆:ZC˨ab[3*8a +&6(49VzDc+maĖvGq5hCe/Fݭyo:?噈U&4.lKv\[D@geiJ R𐷟wu)–EW@( |+Kp?I:' J@ls8HRιV/ka0g#r2Yן&I:B*F\\|Px VE/bF\ a]n_\U0` ="Ÿg l'MM$*4Kv"3 'N zAvۡU~ tK#k;Q+Iކ 6lMQgZFTv0 Bƭ# r|[TeLJERX rT%d 2zXV]Q+&~ $JF%yrf\M%F1KS<:9Խ[sU1 ^Hו=J=Jc~CQ߸㸻Wa2`E؍)ޙarTES pFݓQƬ!+B2!}uL~yʚ$}t;yLc*%mU6D݋zk=6,9Jdۦg&)x_,g1Y)Q3RvEXefٛma:?wG:㼽ޛ1nLJu9Ᏸ&|Xq(s jtލmqFaȡ*6|o8"vM b5Y1,yO.؁)f7 ɝ7IQ>BfOI\~qDNyduJ ς6؈M:%}إKΐAkD!?H^.+;&Bݶ᩶Tй+;=<^̔Fuּ9)裮V搛%." 7" 4VӜt<}8 Njȡb2>/24& }V{KGwB9(*ow3Β@ E(q"JXhjRM4?٦o%psGaF>^ E-l)VD xa4*,[3N|mmF䛈Lt:xQ; `e $hVh[w˼Ie[?DQ{pS9ku4>+Q.S\6B-|9,]>T) ty/[Ui2ۓL%w o%1sй-umI?&sߢQGKzfBtڽ]0)$=H2/^  orF#ca;T`lA5Ȅy'F÷EW$LCyÜ$CAybMSECT= $͐51\!f@/X: ,KD:CC.^<@%oV>,9N" ChECOm](GeqF&C@_XhK&Y^P&6;';` 0R?) 7[ls5 pOZ[bǟ]I[ĈF__gf&Tm>"ӌظWn\ ;HhP$ftljvyZC\cЄͷvV %~|>BL7Ӯ)iLBM!!s_myfQ\lӗx"DxQ(}+~?35rGO|lq@ fV\H[jϔLjdTm I!sV6EFO~L2S:w;Ǖž0{wL.CN+)Qa[k=:#󙂚8EMF5һFb q0RtDܜj>u Zis,|G Xsk/H"e0bZwxb a6T'|VklA{83iNsLF2GԲ K>U H" jnWKD\;d -PZh 8*Xza(Og=.2[ ]{ִ" m䌘KHf`H "" IC9LNߋ]ӋpmH`'Mkoq ZQ "'j"v$} aЖ{Y+t16q֬<ŦFϨl uΒRzՖ@F+TT~V'L;Cj4D*αΟW(6Lq3Ű͉=zO3ߤ>mRlhL2 ho*v|uJe'@WqƒTres,8Y )0Žs[gپ {>Jvoܡ)-OMt05HjQdj## IBlDFـϼTE0Y a$ж XBoA&)!2ͦ00- &' 1MC}.{M\Ug0#j@CS "3c@ +LUMb 'yy|ܴUGЍщQu)Z83~W+A&=n(32~WOØ9 Uif_j)7QJ2M`0he;I }l0AMq:z2{RO#ߙ[R* ZKc5_?ϧL`w?L:KV8A_8Z{}pSlGFHmjym%}ۢ/l s8`GfQ[@;w1][k⾪Z/9^> ~2A&==@&Rb&;qC`q}ܪ2J An$?fgA*/+\$GL܋"AMye`r>,/^%b#$A5Ʊ]ƻ; \xAm,>) \sTXxj興Ne!ť?&F32vvp+_)!eK!PovՀTVܣe}ْnY+EsqÊgCb>՟rhDU&!l.ֈ%uL<~']Q =d^nO2YjFJG0x żaS,FC@~D~x"\qD:elH:K5Wlj 2Դ <@qr*EvLzbt}:֩.W',f^;ɕJA7Zv qّ7rm*ɨJ tH,IkeQ008vqxϑ$'TXCm̒*`wh_77;1}&eY 5RZa?>ԧbOAjg-&]4Qq㘎AuPZO~;þ[uiDlcm**h\o7kd$PM|֍/I$@$|">æȑ51 "2R 3BgVɝuv3uKnB_ }Fx #aND7tڞ)_^6i R4jyuމ5/>_ ºVtYv 2_-%Y5Z$Du*ay yK|VEngx&F_d6J!5kV)O+ Uّ Fg;oF!Z`N2cOT0`Ie>t-ni_a4PU bDA <3< H |psFymە&̶ q)`yw~&M+;=k.MjpAथ(p>lq&׎Z<4$]P׮ZbZuUi`L8i$A{VUO(hdȡmw2t7],ᦕ y;8 m_܉v&C%#tt3 6A'~HWcYlvuZ=j9'g,/@~tGRE:Q%+/>FR{g(i; ; r1맚jй6-FwUa\[IsQĎmtq^jLXDfWPahv{c+6a@I,EQ蛢0V&scNGOG>#$- H4mO@ U{8° 'G V$et6*QSy1fcQ\ۿ?yzu-|t{3 {̀uܜ^{jE!vy(N9,4^͕u?cf3YOW.o<aaioEjwVD)ꪫ&'gOً#Engg_aJ8YywOϦOӒymoK;@MҹʘP/'{>Xݴ;5 %s?_'0'3\C &GJq/T?w-/~-;EÁTڎ=|xLRNcA/4Db sw\_,"M4~CfĴVn;҉[dg2!ǹu^z>>-)O&c'|!ۡ1=V;˰t`+y4a?Śt{<G=^OqQ8cA^bB9ȍUjކmąA,[<ςLMŇ? lA;4AŐݛ!FxL5%4sJ_tl옛{SM)>H Y0`7d+_]~+x:C) -13 HKl0{a‡cˡΰ>K:/rjhZHzGڳlOr|6xc^aysmRyv c)\5M_■qܧ[6ҫNF={jzAejYjɻ#d?#epy\W,MЛ.7 >rLWKiGc/h̵4{™*,n [`_K=-BŌ#8uĒ!†R ?y+XP` lў -f_˷;I** 9v?k)4!È $WKdsvUX&DT'*6Gw+4Sjș*N@; Y멗q+y3Kú3>4RHdd=g3} F~ê ϒZ α*@ub)?&x'fdd8/OUG{(s_ࡪi!DcmdwAv"Ö[VeTRL՘#*u9}=lE{ybj&~Q4L4ľ/n`kN8Y FY^'_o E)e)j)} ÐX89K@rOy7 Uw=c h{ 0*0+n`󗶃E +.-,CCRzz_$ aPɨ.1\Vd,y;i\ixr#_ETUKك54 SIm`F}%gEwXޜǖqU~ 5.M^%5@ȆZg/ uvk"/4iv'.}2Y2j F_B -d [԰,(0|p|hG`DAR-oȲz4>C-h=xR?_׆I+pHb!h4],O6uh%j@ToH>aes%y]2T:P P,B64 0FO݇4n ^(O;(KIl5\YVUcCFJiNJkyVՈl$D8]v53$4z)wQe#BoƟ&T椗aSxT@fc&n|7xMpd˶fȎQv!T=&-3K40[II;AX>mkUt%Std?DP,e'J02D&3 ŋnveGh(;+J8)@(# A|^V oa&w$ 1!"à2|n5JƎ_:3hfx:6{A2LZy\H90=3^ n7RَB6؛(C@7 h1粣 ,PdlmgL ]BgOvK>Qv{goǞB`n A(gN65NH(wX}^cMEȽ9TzM.&nH[=hPYB>HtёgԼ hl`r\q}-^T[Q>2Q@ -zrLc(N.ԻkQMB5"XyPs 'Ѡw$/Gކ*kנI =h~Z彙LJRAIPm"c0) )#N' dPKʕKڪ2ADc%ٗ.3|c͌"3L}gL8% PGzQs1QV9𨼨ZA%' T[>#kʂN'7=URã ,l?Kʄ Yrړls_|^or25Iٍ1eĠ5?§F]`г(ģ0&B!*>j:gFT*KĸO #k ,= 2ue6YTy)ۦ6:ABq\-H^jF d cj)Ij˶TtZW5QC|7Gф8Zu2.0u jv*D:Ssj+U4Ԛ>d7Cظ֎N0fb /d Ñ~MXu95hɫOѦ)g3ZrFy eDKU RVZX)+8#<!&omq[RE?B7sQvYX NMeO\6hfi9~KËhʰ16[6 4Xs!LǙ$ˋly*0-c2W-WKVFc|qVK!0MA]5$͔G#{W3w^4{٠Rt$s]1E>%yXzنXÁ!rhdȦIӚFfrH07u!#iTk!WĹJ(0.wi`D1>6ݥ(N&z&"54 MnK+Fk@{pMK x k /&;dr%CwQƆla Ԫ?i_{ }5. *E.̨<@ȚRpVk` /B2/057R'(dLQXRsݣʜ!Pq\=j$CA kMGb~S(.kJΘ^. wf&FU0 [I\˥.^_a|fRlw.&1Sv孧4V΋ jU |A'^CqrqI1 _ָڱ+K86d>+ștlT7 簴]%ln0cȎaI+91F.ڄ:S6G<[,u<XQ%OkЏ3[ McVks 󞎯O{PGvXOS! )fK :,fv"/txGY_7@1Rq*f.cxY-0Zb4Vzxؚ1sBF- &8$M ˖0MsF4+{II*T$dɥYRMԪ{e_Ӷ7DLα= ! &"We>QG&@ !$rf'y$*׉$ à 9" bS1)c9Ccw,p Pm9Y$({ 9^AH=!T"w*pg߸%Ӣa `0|d׵R@.5&6U @XGQ 6N`.kG +Sft0Mj)B:Vc@e*'*,̕;IЍJY'U7#TBz mT5k4=BAL1͗l"3PnD0zq]f+vN Gcg4].&vUU _!&0.t&K y=񁞜wpuwnm\iT5li#z)E’jXL;(:ޖ`EK.E|C?!ƊDbdX,bǷWDBmA@.22hTtM!@ߎiS c;4Dg}'v o_T$ĒlүZ[h]nKVilu)6 ]cPWw_7O8 Ա(ߗUl'^F`0hLkPmG Wo&㚡[_>t8@n-å~ȍ8u> Wd7=/e5V45hя^P&>؄!&3@VuFCBv9> & Ri_\ EM ;"he(/=S“dwM-jnPbV 3EDyL[g#Ŏ9'xDwhu5լFDyfW8ۿ)r4-aXD߽"n?chbxSkr#F D V Y}PE@㯓OYJO {tչa f66@DȠtIR%kJf?5L<,0U 'S0X.;cL%K`b^~`XTQc` MNzHqvVF[rolO͐O׎l"y*D*'8$Qc/zNPG0[B(U8u'Ep< EeV`Y'$Ўj*zo pQ1QL,NlpZ\nĈ/ʌM;B"v8)Z3#O]jlKnN4rXt}sATm#˙,n("eFe'Xh?`2NRZE_J"XCP,|!ZW#eH[}u'2!dOun˕_`O6-A7=@~xC%_$nsTwf[cj̰^!\SǪMnDѓϥ-)!4谤l0g l&;K }#zWXC@IDATf K]-i{ö"ͥMTjZE7@W-C0I7s6ڒFab9}ac'fI<FV^9v#l/\bDuz3] Z 2x`w0oPYe,&h=G{_ډ f\ Y`̾NQ")k3׭;`ג؆ٷɩldzʞX{V|B~s̀q6t}n==8> v=tiG54u[><9҇⫑ۜ]-kkѭwOۆ"*}s_ꔒevZovz YMPQX$TGq]͵P!j<3)TvUp\?ex K9];LF|'mUAp6.) ?6FG=aWn-dl:5"VXJ!aZѐv&uh%e{"@]Y~#䤋G`@2 k\-م*d'y)#7'~|4ͪҍC uf率Ύ&.!Ϣr ngg~5x¸i Nga(*/B++U)eը/]GWZ}!Ւݾ2a=x$-`LѦu:Xh"pV1 h mua1qYȐ=pHLDdDm|܀x)08,~n9Ǫ#N܅} @$F`6)Y,"\=كch%67/} b.fnv+22sc +!L{:dIPcW]yUz%CW[JsJUzӠ:=mQ[Nu Q(YO1CkYJ\ x Yx2 Z23~pqנr!F'b&@$@1Bȶ=/ڋ< ,݌jr MK.Bpz\E3wEe|8;!Za{S&]WƗv?e4'#K{.N͜,ijŢƴ!؁Mhc:HOcHefX[bRX{ͱkWӻ.L-.ZB;Z2oF-|=P y턹ˑ!b58];#M"b< O/BlwA7 Zĥ"ivЭvijX)G1-H }3$ۃ}wKw@[yB634^óS-%~Rmh?+B iSX Nڐ1L"ıyjVvFןŰYG\nKN"sS_91O/Q,T Ƶ>R}jްo҈Ͼ%3Z<[ ŝYM[_+fO@VNhkNj9W",[Sʼǔ?nM ݟEf% %I.nSҭ/”2Z!E@#$jH7i6 #|A47Q=RCQ݌q9LO"5*Yb1pj!~:}ꑊj73mA.h=:\ˌK'A 0[,عiyq&$ X,I*>.Xb+1-e>j1fȅ$qRc6bZOxW(*.8&K>l#*S C΋@tN"rzbI/3Quh,M9 4g"('N SqH_MRJpB sTb #%jdpvaȓQREsM㺴kVM>}@ۍ8&<(c}ŹeVbjʎi~h7pfMf;¦gy;u+LgՈNPYg7n`)N ő${GZ|k_%ۂSr7EN0fN*eXh-&@rÀT. fk|Zv$=jWj ў(nU- & !8RNST7"܌bYkTsmx{fV‰q`īZ@/;mȊ2 d\DEX?1' #3?WSvTx{6"3Us.ưK!hKLj4o(ccQ}Sوԡt[/sx7JKb..Rf Rsgy8yp0(k@$5f@@c<I)BMQ=列^"4!\$J ѕQ&4V&4ah oB ѱKjc[xD:3p5tU U~.R:"\˧J'{`$V*cXlbhA y7/$лh26B]aYpL6\6IMwo%HP b^0ؘ-o͈==(hݩ"|Ӽt޴ t] ĮT!A("jkӆ2Dh)f9*lmc syM&cau<`R6TdlєT~U7EP ooa})R¶&AVaze54鐆WZ(׈Jw&< 7p{$*@- QBkS!&W',mU9k w3%MFHcܙ a|D.5Qax05kLSJJaV\fPL@XKP=5C-f2ƉK%b";0W]G8jfPP L359o>:Zv0G[Rso>X{WrD9'{Id/>4*MԛlU;)dBXO8 H@tJ3@tj6 %u1ɳ䚉N`DD'#ZM/n"`N0b-@w)jL Rr)/gԦ=A}6Zo8&Ž$59U'b@%. Bx}%̍BcR/&3ҾP,ap*\"hT$⮦T"CK׾F?v $LL"p2{] ܢ5p4Dkt8|v mjEO} U;Ca15 Yke682\nK?c1) N5`|MXHt#' %aeU#@=lDX*CC%I^TbqzU7M^>Kk`:v?Z uoEH{YRez+z9S_"'FdMȍO,]+PqhDW^:iUf;D'h 5? W]9XͬۿlAOHaTkI X `葜hN0`a@t="HmC{(C*\(BCE{D4_5vۨZ)6q`nۓQ4cɤ3|FIi _KBWmx",wIȅ V ~tٽt +򣱄($]40dç rr&ͧ}hKeqG$&}{;tՐG)N='(E*tTF)`S#~]%)Bjb=C!+jOG&" Qc>{*Ӆ)Fyz@5nit߯El3J oja[\z75gx8 MLZRRE?v4MfH9+cYssBB.7?8dp|c Bv^oiscHJJ% -PR!HerfľjNZ̚2o:Cq Uxuߏ9K(Z1}yrmP` ,HqȨ%ě, ĊHw&!x>%J1xZ_(XNj$ͪ` ^/%`-B3( V"_'{ûV\ؤ̊Yiw_͹Mz6!Ks!dl4p!cxH/P |_ʙK`ct Ja8|'FM'ORKO\Jᝬ[aCE;x (t'K8h*s:9Y^cyُ*Q̤>Št2es^x8Ik=\4"k,ExYAgÂF+*@%2џjY]T><=\>H2:plT"qңeVeZ͆*MX[i,drAO2f$#.9Em'J IgV@W7/QZtQ2wee6Xsg<w΢0`-k?ZŊ:+A"XN?|Ϭ?k G]54sδJsLk+scS6 EK"yזlv}!a#g:7QAVs;@ه^nygb3eKW$YhM7ǜ2hdbٜ!:wɯS\''$ؒ?/'VIb1չ%ZteuZ)obr8- H`$!H9-[N\eKkGZM'p!~7[wbM@9KPhZL0NƘ 0_*3P/orH6]&%>?DfK~fkÚĴ t#f܆`~wG\=Zˀѫ0kN_nӄ4MF.hx`&JKkMEGQt,1]p ) x پ葙 DBw') [( @F[;NUNS\U7#ZBfLP(r {f6J Nl"GQ 2߯P{~勂 %jZ[,uX$Ì?m8h܆425O#3$$݀ip#KuwȓJLdKS~)6,jMقe1t/iY!VRT03dYWU~\yALb𴍀1u$ȵp{E5ආ!R~ PϓW۶ 쏯7!*ȀJ!2'.pk%,ad [v5o2$_¤l*0(z,i_ӱ>&p8!Ȩ 뎊49hNfX&PL'GTՐ9drl,-8ۗ5 "*{0w]Ώ ֊n8Y$zB> $Z`%[XQDSF!N-H`' Bst 1)n,L tA_E˻&r`BK7Gx_ݬ0"hjB'`ٖ"ֹ Q Γq27ga6d S3d-o42-td;𜩌)f:uCt$ly B/7ۛ#2PҤ_(E4M3 YjLIJ$PLe M64.4HжPZZgy]bojB5{k^#t=Zt׸V")XM-;6@ٲskSGĵ>LI4,rwSԞ!ðVdNye֊M4<42`j jN?q;BI":5|H55Ј-S yw@РfT +;vCF,*Fcj`j=oq Z n}H-QXQ5k*4)N홤eyqb44NK 96a.B߮Ge^N$5LpJ:ٕA~}.:5RQ+͙6%*|)3*_ 4+ֳfGK;p*zy< bu*,phK#i 0's܍*W&F س9Yābt\v8S\,__=Z;#)aj+HFGr9O$Œ~szZ&A4"E!q1 <Ԇ7ؠDOrsdS| L/ɯbABNvSC![qd:/Ty|awGL/ CFDLe/X]!S#% E4JD`Ȅ sdމCV:*gh ;(n6d,kI4+Iv7*<_ar %;?D+`ivc?\1k ICَF[86Te;`uhrn/3\j4rXa@MEyuyM~~\jaeQ:bfO>i @z"*Q#k N?m#[aٜv'ax"0^q;z҆ ` G E"!Juup|eR΁z?D8(g/N~.a)Ϙ@߯)EztD2~I赽,Be~#Y)ƶzۄjv )CK)AIg#f4ҩH.]]#1* Cyy96_m?v/ߞ0Z.k[j7_7v27c!̷SכuxGs?a~7hѾ9Ŧ0سz݊gKuv-U>Bh/$|^^v2yz֒)kQVarFDvvzMhq ;F_o]ۙ_0RWGU-DEYG|UsiTaYx{\Y:lMz6@;(Q4&qXfmyN?eC)1R K&,\>w*NI2b QL$OO<ZQli3qH=Bn6ass- )L0G9Q 'h3ĥVehc-S(,M4>qi Ew9wƓVE Gc'MektVl?^l@`eq ]ĸ9SR]a(ci\>|d(KjsGyUmUb& #TљVA⏒2S>"4uTC8Jyg&B}#4L>_'LW4@ '3~u0/B>cd"um:Z>&tB$i5Kq>#zw1x nHcV$ F=AE ,h=@rluCncۧ5Wn޷?k>h` 7w+fgd#[nY<ÈPHwjI(EB z\qL-*CV߱4{ᒮVoV8z`#_nzq Ī7<pdߣŇ%sz2l& flo?I}Ko=б^/M2Y7Gx{66j(R ǂp%Yó0\ FP(Dl ^4U1D<yl59Ε|@FW# Yh!m/>\o#?܉;l3ֽEae4Z %EYew>_LbX=S+]BlAӤOtN)hzxq˿ٳ?1h|(/t7냚*'~,]\ Ձǐ)|fn\3@Y[Rg!kWiHacg |{3[4%߭toٛ6aV0dOG@i9heMYRd:G-ʾdč͈ȪRz~`s\v6D2n}0JC^`r,SO\= Pb#F}*Zvpdp\xAKh[ƶ@eF~?& ?_:UMܢQL<mіgE(! V=:/?&mGͤo0k#7r@S ؙ5s)Dvy8~boWD 1-#hgPLzZI׫FUZ6e lBːɈOxkWQp4ʸ2b;"݌ %p ;ä1` Kr76Y9VƊ,a"N?"=Ћ $L6x! @ָA2BAɇl_:f*nY{Gd/ne&-sH>aL7&n3FΧ tׇ_! N +Sv?Ik Ge=( y=cM hi144{v Fh%C/@A*%G.ʝ#}[1A}x (#QDG|Z%ESƂ^u$A+v8.EF ]UL)"v8X^Q;8D!xנ8ln`Ås$`m][N1mrNȉ5 J<]M\N\VfUS /nD9DbwR5cH@  老7En̖JR<ͅ'K<bGyTA"3EGc)<8 I )HX!EP#]E0~e((<B \Rb(Z_lR8,/\ 0ikZB6SҪPbLN19ad9ҴB8.-ê(4$w6(W GɇAIN˪Lk⌚L)]y<5{7.LhD89)1hM]S k=^lٲF'z}baYDю4l32wq:&`i-N܇B'%. 9u7x㣪*\qA;ksMqSmY?8vK̻(eJbEiUK}²Sia׿vqm|Id,DFCD&:0C9V۳EjX\7Y]~8:!c&>nA'HVDa|P!=L|+ RF7V8Y$ Ȳ)7sw54͂hE)2$~Gf HRHYgbլ\7;bU`;#4nESBG"cM1tݠsH‹l }4 kfbsm3b [~&rI+tnI~ }O ƈnn# 924 HĮ7<~qڇ$:嫚?Im]f~Ѿ%J DbލH弥!3ΘR^Ah~SB{OXԱO O;\h p: פdِFL ӞAuuTWx 0MX}a\k| "TZ@v/,STR%JPq?Hȴnlj'n}8TJ ͖prۯ\0C ntw<6p$My!;8XD,vaHoRkIg5&HIrk80ŞS;XzW;<_T% :҄715IdxL#XeH$tB(*R4V*5K^M;S;b޴3u@ft)}M|)$ ( }cu4(ѓ1&cfӈ\ޙYk*ܤ뻘K3mj({M@͸nlt #`j(%}3Wa=[)h)S\i,ЭH,iv`MROX/{ i>#-1O"MtDgӽjVWCvԞ}wIF§15UTzp|טhk(Q`l Q( X~|^u3\L?„%iǢJЇYִ/:7eW`RRFXPrsrCmd/I-띪z ,z=rceDC_>]hؚu"'X vRDnMMĻR3Д"n W5PQE%1 EzSzئT@ktO:5 (?Q<`Re#5Gح]'hRݽfx5P_&ߞk8E =@ÆD-#;:ACtkq6wܖȔ@[eSe/Ы|^Gf{c 8[h"lO(N [(*ɟRdW_D$:[2J6VsQ ,ìn2,)m"U HhQl HH]S9g<kjŨ]IK.eLŚ%|E4rSz15%/yvXpo0Ƅȸ_('7vacsvh6.: $ 03-<᭕uN 2nC._sTN?*V{P?@mฑW_+OϟN *$D́QvxYہVB gxPNG=ɈSO^!ɋ#LE&7!zjƚǠq+SV)'}(9kr Cf©c4(G] Y,1PTor1woFt7S sSOqE25B P t% D4Ǽ.)<?ѭI'YhaV2a&^Su L`%10#98Y>-H%KHh@׶+ǀ;'H\38 䩹oLF ;Cd/ҨaOTچǀbԯU3&K`2J._LHT $\`s!&u~h4_eg})`wgꨑE#@j/YcÒ:N.6hS} *gf~k_-Xݐ1^(Q7d.C͆At rA]IoTR*\ cu'ㆮ3sԨ" &Ewԥ<]{5~OF:~W B ͓5BvH,iOE]1np"2v@a%3?: Z6IPQG#7mq"SMl)""Y:Lg+3ֵFƧz JofS]Ґȅ<Ѣ)e#W)b8*Hه=\fZfLIlLJiWH)l舗dFh6l1LU;݈: w0-dzF20s*'36hdm f̌h?֓"(a:mF2d̆:ќ ]眒n7NϨ֕ M!D%Roo#zE#)W_jnkӻ;L^:2$)m,yψ>?}--,a]хD ah@QRd5"h `SYfG-zR8W]On2)AV8xYzphNatxj9Wr kV<0Wim%F5}V^?ƨ]Q=̦h4Ith>mT1'!R.}؉ت节֬@fOz~BˎשVr53=r>P+1Nwi2=NT>mYJiIf(n[k:.8@IDAT UW%NQ 37]VLs'Tצg M#jh-A8YNh!O3-/EEͷ@&a=H>j9DD{orv 8 vh6"&:d߉?CaA%,FbnA!C/)İDVX4MqM3m5*Z1rd;#ѻZ<-}jY<(ܞ;Cɔי;ʚmDY"+kBHt­w#l2'ȂP@M="("aiJ!=<'8\?J*&{07k^U)%TaYUeÃS3;?:~UHk g[QcӲm5;STÊp5Rarðv,75Y|5)bxNJ4[Uj>ƞU*3A<[9:PDCX!$Gr jF|ѐr7 \1hlQ#\>c岽ۃϵQ8E{B">OЙի%9y HKUڶ)5={@&Ș1(U9ɑȡTgmd Gbz:{ÚLHa(  䈬w-{9`NV'čB@m. q|馘h Uj5M4'pq [^_b$pc%q pqQS-yz5ܧ)"ON "DSiWW|ܗ#x킑RH)IF@C~351WS'~{D+9l@9d)ֻ#+a#ȾH:fOc" AfX>l6`@J@* Pw9(>[gSqf28+T4 W\NfwL#vJ1<^vPc#iڧIqP`xXyctj9g:,Say"aHՑG2uTL of-"GUj5u26jv6`'9vZVHOܬ,.&q7n7WLO[fa=!<\y,c k$QmС!m*4I,?TKaމL!tn8oRH%kQZb-#Ïo=$/R֧X$#Jin` FⴷoX\S3^5ag뗧=19:Cb fa:ʴk@t|#dVcV]&jXJ1i1_ji=ƙ/`3ɂ͎4oX9fk[WMtxI*b #IJ0Aכ 3 bvROH7pb?h3relDnK~˔l7ETGiLb-1f|QBYHkYj6~$wW(굩,ik!P0ܮ,CެZyT(]aO2~\KvRPF 6s<ğAZ^o2Wҳ3N2 r@o,pI%Yla$fx)x +P#)h`mu9*;|9҅zh 0Cgm$orF+aN;"urń)f Q*P qLKx@+6TPKs3V˘h`*| 5,<AS r+FBU <#te/GKR <9 =M!L /1yEob~صXHBNۼ_).ӥGeDRPcpI3@o_+*%RJ;~Q68ޟZ fZoY'A|@ Ťq β_r|vrex|ʹ7h`:C`L`.yǶ9`*F),:rfLE)9v,)볲fP|®H0ٙF$^;ϗS3| SrxY>݌idţ7_+:œ,B??}{,W{4#RnfTIV@;1 vQ$)HpVbO w -촳,L1h;RU\*vOw/ዤ "J,Xv.C2r9-PuPK} β#"(0p&KR?enc#,9१"ݩaOL0>J 0E[yFуkǃ}x؀eo/ϭ+pn[Wm/5 *%z? #tKx/7422G5;֫k^~~Jzqo jvAPф,UٗPS?YT"tãmPi)KY#:#Q`[G2vj`HGyAHEh؉Ob#[[jםLe%\`)´N 3K.A⮆1b;z:?jW@Ё)y1X yFbZ}Ӟf2gdKr@8L@8 qKxxHe %K(f%*h-%NsRH_zVJd4H4` dZ34/pDRE_ѫ{6$HQwjbVTTGħxbqgy ` "ZaEH'}Rq"}~Ym6iyB..EA/4th נghTtf=d\Ӕ9N7|^o$ b,-`^kcjWcn/F  ܼ>?eX4pL}d~X,o#ypT:?QQÅj%Rލ-oh $M!?i@ QDmyoOKEl 4m:z3 OSH٤Q~R鮑Ex(HPq >tYqs>&'H0tN(EoB'ižDe!a\ Nɘ=9J>SI6%ezS(+Ig~UzpG~&f`Q_a|^"$#>>ew˥cs";@yywVC'5FDz\L8Ħ5֡7  M'yo DjԀec7Fip'pDC'YP[)DJUQ: )-lxɨ=(Net :ADj|T=ދr'^(:a1X^d*]A9OPXgFё-Hˇ,-T gGMei R(VGQLHgRwxWz΢6_V-=!ɒJ9]~8̀#__%0K*ǘflIkRo+]mD橝ZрHԌti!TPhRUem`aT`T-6Pan -W 04̯<[[mr~uX5X&oZ<E%5 TTpH<96a4^waﭫdzH";1?, Db!?$Nz}xn?QqٛaUm%s32(̌B܀g[aQ:!;>#>&^r{):9Yn~J?2o2v\%Hh,^IyMe'b| ev^2⹻$<\uģǬ ޺!Aa1A9Y e-2ZH/G]bceܠi ]3Mg_p;P#sEdPD)hUD+uP|~&p=ACF4Uv**UEsa5F9KvG3s h 70R"XNV,qmpg (|?Ҏ` "TV7ųՑ7T`>}.@4vs  "BXR0f3XC?TRz_4@@43zv3H2ds r'Ol8mf.de΢b(_ X*? `KE Fh|p+f&;£qGw]InKɍ0DZI5x;0ɼ!Z䁖i"19 X \# I<K; zޗ|["y DhQ=T }V65`SWf핥/-Nв) uC/忑;{"AU2P=Y0!%JzkZ<~1x)`3@x!//Is_upպ'ˠ[6^\526E4=@8&l%V0 eN4:ܔ5_Rg8tOdHR'ug 0}FRMmCm3dq rDQH.-'wcs$ F`wG$>3s C̆o8U{n[(ɑqGMEP  qº=Uf_A2 >GhWOE H6"~_f6vo[d8IP4cZ:R^ޔ1)4swI=3UbDX&<7" b^i! ր腜3UziGbJb!)KB @|^Bݜd4K>8[6\pHwL*~N `0)3Bfl#R'^&vodQfSj 0.U=:y1l$h(`?mKR68k;Ї%ngGĿ/+C?Z^N%͞EazN¶rfF'K XkX'# W@ R>k\QɁr;F3ڔʄ$]S"doV8 F4PC`=sLX2ɬN1P}˓dv*:-/U" yɆoDЊ,9{.g2ݤZd3^&afXEe\nP)DVsT6.T 9Dh31c`-iW:di"WCJ[GV (C Z`xLnsS{i[Lqa.RrLG?9$Sˣp2*{?NTd&mٲ8E]gD>3MKYFFf'`5"ZK%naD*)MWUc!n ,{,,?Pd%)tB՛AR8y,5i` &0:|adpUރ! !̎y\^z@'p瑡׼N#1LSs0fE52&&l尬s4s^Z +@kc=rh @i3`| mw*S*o P^C&(k1XpMT.&H5GdNVh+<չ x< X#漽|Sy`O6 47eZ^ԄSʦ8$79gv-)$F[f0Ɛ'2yz2!0F.sSgyKRc#-Pa:Q\ʆZ2j–(6l}‘ڤ㚵I : -IG#ϑ3Yc̑@RŢe5;Hc5#`M>j[ L=T!]۳#H:JoOss^7V"zS !+6,N[4tBqR!aon^?~TtCJʞuduʃd%^C7f[e:۠e)T<8/1G}xN} 3< Kih0%eQ@<]ؔVQNkgHrU[ٲ%x{:*n- # g'KB$]Mչ흙ًLiδך3fĈq#"FbifEP :Ϝ&Wd-C34 U #'l-=D- v- 7 -Xrb9x|  BFC*#~TXߊ뼆`m("~ R͐1 ɿE JedIp1ՓWjD#"CyXOY4 B0z\*sjc4^VYֶ? ^|ρƞpS#}JQ᫜-kUjk.g7JAkϫz=Aq0E&CVڐ$x>$HD!lJBMCofqP"` |Jըl 嫏p e] F?71+>yN Rǖ@l vE|0B<ɛٜu|bՑ*%X 4Z]M/̜!*O86(-u˚b ¥β@9g:Tfȏ Cӆ(;^'xeU &g!_Dcӑƛn5DqTfnXIdi8Αb~ٽmWoJutjC^ԚXry_IHf8ob 0U& ={DTQꪵ%R),hWo;,r,$a\%dzKL?mh*k-0TRXqoɬk@G]Iv=m%:Z]+hAfІl9Tvۃ<%ur53.f(s_^uT/jSJ54r`D8@R1::Wڨlݷ.N8g(Qht/--V[y߾nxѐ͏;euEue^O!>s_k&'"f|*bkbTqR]DgwOUj`c) dm}YjN[zæ@Ar HQ [MT}p_l1]$0OW ;W6nD fצA9n3m6"4]ğu[geC83-CTRˁX* NkKj &6J7KRm#oRK00<P!՛%$*GZʗհ t0Cei* -'{KM nny,!IԟVT?J$^XOrA94ӈv`Hm4ij3tvhK%E#vaS^eI}AȀ轖Rj׾&SA _CÕWa}K(ETxr|!9.jΦik=~PHdWwpÆiL! /9 4WVqZ~{jp!Ygg Y@E]HJgËim\o@ 3t) 7] lp"3%N&bH t|q2Rn}lÁޱ*;Xint:Qit4lHx4 ]q(&XK焟߯n{g럿o6qIJ3ȪR1w=zxv:e)u2 ß 7&[69TNFK ȿʍ(ScCXZ6Ǝ$!=]ͦ " r~iE׋VvlYJR5Nw_&JvM%Or ܷL'qJ2e.|w??rJPetpZ2 P% SPO},ZDXpN-0pA[[(@ %.X1dj]&ƌ(?~xBP<+e$kUEbn[ci1W{nɝ\<vW( XWӠr:]O%Cf--h,W =Oyw>jig8.}ZB[,vYKYPW DuegkM< ڂbH{juz~Yb`O{'Ʌ@xrZ;S!;SPD5P~5z:!nj/!?DkV82Q0q5znlf}aMbkFzGt !)U!dǸ+`x|E$>Oo~;1i;? oշr TlFK,E2{=10KCӔNQho&}-nWx|Èȁ ~tS)@iA:~^[۪A2ly t?wFo_#*qD!xor0% zA`#SSatM KI靎,cPt55vn0+Ϯ?'scJC2OPP屾 MAICb49`,~ߔ!Ff K+_Z76<݃VqR`u,Tt ~lXi58tW'-6jF䗮X#8 &ԨĄAcP?^C5x|خ0塃:X( ZMh#XLԲPE?X.k~|G((܊GAPMYn̫X׻^QzeW(f RCV9oi$;{F"UX EY|rd^#x}H8aȶ G1>zՠ|[zE܊wzf^ASP_[,48:V(<6ej?x#"M9|Eff@ՠ ,|(p£Ɓ=.v6vq/I{g2pj$06y |yW ݿ=xnLE=g- wU_ɳ+(Ek'њi${StHvJx.g YZ*%U-hua dgB xa]8-W\T v>SKʆZ3a@.Aag6Ȗ"F8~*PnL"!ί|kѤ6[貔3A (a z mh39E"z8̻Imq81%r=1tL qTy38P%OWW[IF뽅& } _"@'΅,ZP'~`b\M$ A `W ^  WG||"ѾiMY@yoZ*W/اAfxn-C8X{ciK60r԰ލ X(Ju43CgB? jYҞɻf&'v繇L"麲_+RX׳$1`^`i({dk55ʗߚ!NOߔv̲~$RUlRǔ<1[N۱]mZ'\Kűʮ_AFyE68 ߽Oaf)vS3jUW+lJm-ȡ+5/˒|q,u8p,ϰ*2y3R@bR݀n B,uhs̘rcmkdH[V{aMvsQH#Й"9YGE0JL1= +`"!!_S8 uv\]YA*+u[aKni s Ġ}9ߢoBԪ|0^k(5=|'&4 I.h BUф|`a$S}b )vxuѵna(*wa/ƓUblTޜDi̍U!k|5T x٪1L!CΚL|IL(a\L%]c8#T( =d8z8vb( Ee `rFA'7& b(ri hF P)hk'%FDWHy7#_"b&X+MմːkmII}%NՁTez5{Κ|xvZF׿}ڡh@z}ķigQcd% C Qt>F''q&Y8L ̎q4b5~A_qMvG4}^,xKa+hglKJGQ ]v" h4a+QNz$єO^ SȂ.fOj4"CYU;SSb\Ҍ ijG\ꇇG@oew9kB8D&5ZnQ5Լ{jٳHfILV2:+`yde.iPusvr@ #$tW y`baҒLasVPaow4N洴gQt]^w!% Bevdbt~"֑5`kTjlАN(#+m(TPQE@B kZ d}ŹVߋ͠%F>6.s{Z}IAZ۱#hΰ|T%6}Z{@mUծ!߀{9[4V?cs^O98i*ʖ?jb61!/ZCpS 1SZ%oԞz ;R}MA"Z I2r8N_T'PMaTnr8pi+^`xI! \Zlwk=4 峿B|t*.>Mi.cF07S$[c:j}< g7\y@rh惎ҹ[o%oly{\1ůfT~Z5u<\ɝIxPnslEw3ucdN-=Drl %r5+~(:x>vحv%I0 qj׊ ~ lUA-s  P_#TQ\ BOCX^!3ۤlocfB]dtzb:p-0weˎ1t ^})I,Aq/:3`tT W[a2fjeśf![-HPRÏ/~x,!LJ}flL.rf}, Sͣz ˤ w]Er?OHJFe_`: U\#M~q6ݦ cJCjh'R2z:ݖ"}̱vӚq,hWYygt;Uo!Čn;_y?p(=Js91f)Öͳն;gj8qBpoQmFIW7ZiRBT7|aZW$E9ҵ^/K-|@ tG$Y}gpl]1\]jH+ Ē2*-ڌX64]k{SτHLt1ԣo} OfTgOr(j Wt?p,.V;;*ÂG>j*5Թڟke;WhbXAC8:֮8[Iy樲 g7ܻ8{v#aN. .k{+[:=EȜ \ܕ0˩9Hjэ w ]<O d7^aS7bTc)d[ :tD."$|9::j~}3m9D"&\9g:orYvfk'aPv0} nCX M:?|w8 H#*Dx✂(p΅x>orԄFY3&AdEJe$4b5Z$\V4:9 x@HWq\NE ,UK~Mm%@LahzyD)j:Z/sάM)Nrٰ)>)`&/l%for_ 1a&# F@#Ai;gҒ`~[b7E\4 ~4ؗGhbZD@l%u$5M~&(d)@my qVkOAU#SנN-K꒕aARGbh SgCxMX-042kX 6::C1VYBG1XzU&]P_b3L{qxE?Ө7܊BE* +OPh<(d Vw(r'cyϺf)c j:1<uPCҒ L<u p̯{Ȁw >'wR8xPIq/1(Q ?: GRjğPH$Ey9^[oQG Ǔ>Dx3L!j(OT'^zP4^.W .svb4gtkՂn,O}TLw *?IJ50V!祥:I"m WzG23z6pFnN]m}qS'xjW_x`MaUϟ8٬jP=^[2' %0WwFC z[G&=.0oFg;EGiEpj{7)Ӻ/Ê `c!-]^6/6d >kӟX d8ː䄯>cϜ`]jay6X(HP\2t `sWNwjۼq@*]ԔVV02'Dx-7 G'b@.V]y(~ p9'+;zg@T|Q4&TTN;'(q<Ъݏs}κCmh e>%r :}1hc6Jc7縔G*=( 14V0khBoρ%F(`=k!!JcH5I}D2q6뵅-NOKi.ẅ́;$$2p9\8Fl,9"Tr"i-w%@v9:%)͘#42ϙaZJ1U}7Ib Y '9>"_k/z}26ԾXW픂6 ʐ+} `򹼿h",y˟dWP;ax*FymԴM<>yXC!{9񲓑].?6)7Tm&v',(t0i8? @J}7"u'#BJhBb\m/ -qTE&LUpZUYGm!5'?3+ՋʱZSVRD50\vxHέ2 H onw=AtjV6kNI]ٞTЫy[wIHw]2a @_l*Lw>CSg5@qmb=Scj2WTt ]44YI,!hxG&7,[CG.Q3B)E4Ԟ) ~xP"0RSstN828xZ?R3ɺ9s)7o[diaR+O)-2!2bӧ00C6ӡюvJGy8YM sjQ2?zl0j\1+D_ău81Kʍɑ2&&j>tfyz 7ֈ~TzX ژE>^8 @ #iᐩpCI8yg}N^ mPET F׎"Y0i^ĽazQvəJi,j FYo}4k{91I,4S2_#6P[MN+ vN4@YΔ/\nE ' Cq0y-Dl"lVv@,vG~/>/!Z[TM42l\+3QmdѰVuUO"K.9,}6 /ݫU-dšͨ4{fu5/utq OU^̽(g]UF mm/\74@\H0DZ={^1*ӘlPV"b[/--]z}ny^t6/+BqTh'%T#7;sǨˣvBZKoԂ3T7~aٜ' RLe?=} Y1 J &|qou%搇%%մ2ns011I9GNժYg~=[cr<+wp0V:;;q`nPYm 1$fiޣ@& JtazVv;}G z̩W(F{^VY0]Um1P2$ΰ5kF4/9p}56A7yT,Z<`v⺋1 QJox]<,qj8T~@cD~7##a84h #7Ev)>2TK<}#'%uu .X%" nVmҿ58MwԱE<_04)4A1/),݃V_,xCD$a(I >v2cY&JsumD صLÔ.jVoHV}^ K/o"HӇdXwfU<1 zX.Αߜ^K˕)osd0K bbVO,ΔspTdFWG)¬;)k_~__8j\N{?RdRЋ ;}4gk> iQ r`@9cVUowۛcv_"Hd\s *F59t1:m e@Ν! $x)zo.] 8Tmց T-gz|qxYMnz5Lj@٠Uc ƑJ e9)J^m^)4ˢL¼?E 4ځ2 о`JO:CC3L%БbPA/a B9E iOCjd&C1PINKFL` 2]FJUq$|l*V0E]*q@|"OcJ!c# *,q-{SYp E"f`TEPGӤ8i: `&uw=̖uEb\TKS$V5cmM|oxё*P 2S[{4};]8_Cjr 5+ـbd)%?;*,3=!R{tlI|x}1(SJ +dkϻw!͖`4\\ٰ.gf3o_ Vum'`na%2)dަ!EB8е0}3k j?ZruXm͢J='RA6C&Ĺ2xOp#܉WQ>ZXfnoFq4ɢcm;@Jcm]x r5JBQgo11vx {z:wHDžR7tbs eXH75X^&QaumǺ.AK`9X h#4d#2K"s( \ݨYܠI9EZj K';~E#}bgt;L&t@GW|]i3hL_?6=m7T/´n:F*0E\xĺ`( 9I^`NOj}n~M2cd((&!)5 W.S^g6%13j*T8Ws05AO.!}(ȦEFEOҪg 5$l!L/D"Oij}jK@ &l+Yw F_]mnOH&,@jSK>_++`Ip@r%H~ ijEH&isx'9bzfYwu:]V*bW/Gv2$捙M)KR?z]dj]w\O2<x{sH)-lJ:8uʣM&5 EJTCr^W%p֨+BJ)BSlmIQ4ֻ`2a 7k_A=C"fJ-#!E_w3a(^sګo2O1ՒK>:KA.e‚K z2M ٗc둒C`H!&[0UXu!U/Nj~q Ш #M+Rz:35T֔P[a蔥yL -N z("HQ e y n*QeXՂK N0DO`PP[ bɤaƟ>D-6FiCGo3RNU@-:v{"*SԤRٰը:|,2I(UEc"+_8}su_/w߾"*~P1u/yV8)Ń%.|ַc mu4fCU8J{x f8{[Qe::_I!7K}m{ͮ%H^QYs dUėh"{[|xB4\>+?f[^6O\UD2$D\ɾXua%FeC,;BjwmѾGKt Xo?:*yC1>IQ(\4w{,vׯz[_Em-eVɱ ?6IHο>0IS"Ycr %H⣈(64}Mk鄤,R[6DPH##IHIXAa֡:$W[KDNPWSMܢ}Sm;Q<%MOIĚ>C[SH{8o^n/" D<Joh7^Z9{l&3ڱDqlќgDrd 1w\lud[·Ўg8Eh9 M!{˷(֋^$m"3 Sdq֐'Z8Lj'd#c=~17T2E59/KNjT,RvvgYwfW;Z%(ra''4_vׂeS?@>pޭiy텯g Y b;,43pFh'y Xſ%Ml {P-R1t7ʤ}KQET \P:!B~6..Y,=I;'Κ͈S8!}Ru4[$Zypȁ8brO-,PD"[qzpXM°+;]Nn" yeR=7}n#caYkoɈGa쩹8S;rc!(N2hښwRM,o9zzK5 cɐ"Et7em=Vl &2\N^D3@,W㒤l`1!4ƣB4KOm$=oIlWkB >ps;F\ μݩ,Q=o*iシoܲSaRR?@YkYS g2f0i@oDja؄'S"Iu.wT1-Ɗ@9θ?EBmIvڮ/=OZ|M1]ʌ]D!D*0p8@ӈyX3 Rsi/1<C7ZxM{`<4o'e#PxcEl`B,iXiOFg'p𤌕əVu90jqBK ,ƱN!PPaWE3\[bhTDB=<(E: $HJDŽ z>twǫE]RjNtԜ`?LX@Ty5b+ LKA,U:xT|dC& "vwqD`Ќڴ~nnSyO=h:8نm+>}~]g|)F ~0gO=̖ݝI~z{ *NlLu8}R:D цU//!L1L~~?7l/|*}!A܌"}7yҹr DPbu~×l@an&n f2kci+tзK xKHH̘q%AꭄH :KD 9H ~{& /jck7ȹ1-ubdXOR|'rj <*TaP# ODX6K4!:wAFp#j+8O-blpIP6ҷ~EʋBjok.CA eSBPb3(C)+pE*]kaX` )YT!E4 - F\ďӕS {F?r0iT!Tw"; i @IYqDSK9^KAk@Ԗe`o[G"`gsqdSd jtaƘ ܵW).Z:"5D,v1C))HSoiQRݾT.^[ >WF5epƂ6=B "'6dVz  Iڢ6g ",g/@7OZ:5ӃA~P,UnЧ` CaUmLQܤL 1:oVP릖f3 %Փ2kyS.h :qfȂ[fI5u4ʛ UwT8ɗWXH ?6 *cၚRYLVſ6UvS$lX)0k,wt `)]3jv)8^Ĕ`&2?AP-';cOC|3JF1Zsu ާ0j,OhBmK-(;G:Ӵ^o0sZK6o"{ Gx_RM N;6a΅+jpzk9MąwPG 6J,v5+#pubbCY܌CyąPD bysAѼiE7lۭV8S)ͿUaφ=%e›WBdrWY(瑄\ :'djXR8ɟvh r3Uf4 |OU҉?EFWhXDllΐMe+ѴeD+s('*sᦱC\i_YJhSӌ=D^>':#衹۬tE t6)(PwdcP!"hj88.;j5^2x^\#r:8"1ch%0}JS1K {cIԈUUwJ Laz[Q3y\ЫM _T;*2g|bcp0JSOX_ݗI.I%y}SǃqVgVw_xݟ0p`A[%װ3ȅ)en5ɔ 7P 19UP j=I4cRW Fgc3Mro*n}kPiuR!paFpؽj C>:z 3#NxOyT5W@mwQi3]F/լʝU写J|A2 !˚hOѮY]oZ >3$xث$XL7} s^g$r9_7xsƢ|MW[hGi=2`YD*Hcc (G-,);Q_|98hvX#dVh!/wb.E@DmqaECt|IrCK0%_P$Qfܨˀvg x|cBn֯:$ }F^,2aAS&9afaGmy+]'8kjDmgdўb2| r(|nС~WJf!eXЦ  :K@?H41›ĮaV[! y2V[e@ ԭdU$[ ػmhc6 pPDSj  w$'@ThUu/iB|!ˤ*rL[K,_9?._Q|cub+{zls 4 wEՈ1P@~fB um:0g \MC.^T3Vh:{RprE@#yO ݞK*.-qu#2PEl"l5) l>Qqoskl2VjAs.܈mٺo[D)>!*)GϪdy K{#%BR}#M} $@eqn.{ J|J>ݯl[?%ֈwꨫ{#Kl ˱ԧc>?H4c-I3Ѱ DֲPV=鈦h?[6T 7)EV 5nMt:O NŸ_)H/~i5`CVcpd\Lo@H+}V_?C794#̒tOE4'H3h؏qM%3ZEQm/?? jgaI&:Z ήvS8<y~M# *U*Cjgʠ<9Cbʈ~EFZwTLbɼݿjnhj4EaM<Ћ%,*8Uh^/AFz4#38|'0FEaFHwKۖ'6CY]d3Pbvl&Yы)jz ^W12k>`G2?-%"žAaS{P\.uS %>9xȫ,Homk^qKA\e\i@Z&YJKK?(4pr`-iKs\DXУ}MR%x=w¢_"u+Q,'5IMUoK쬃pM J„'$Kh6nTGnOֆL(.G`A%lMIooe~ )PoY~UMh=?ic`֭ߝ@Bׅz:3jޕyP`+N *SH`\# 軫&ԞҜ~5/7m%Ȉ2v#RtBH߱ί滄qd7-m]#*Y>H%W"hȿpn&*xg/6ki܍C}L-MGdO=v<<ʿRO.nhP2܎CV-iANtu+y65NL#=گAJP4@x;L<['" )O}5ff@=uo8x~:~mg2}8_r rÏi2~?$; S,M\ hȗFoA.-2bşjh\V[j#{G6wBXR^[N#ZVV-|9-H@tŠlz(=/a_[ħ c|/inLd }׏6ca|].G2a*kَqduORpźdp z<i,bFK ǧq{.$CreK"j|aQ;#}t;igυ-'F4Tt$=KY)(=3H7*. @)>6"uCfeN0^C `:G:N59/U_J BZU3 kt?QifH~"x>)IS-昃k&k ;^N,@P`#±9^[ >#Ŧt,Wa.q'LB3J{PVx$H]ݩa*`0@ S6(Ng} tomñw׵#s0dmBjQ8|FGhU[$/D1KudŚ{I{gb8 SorLhY( zcZ̔Sx;s8؋1V`iqg'JX[1DsbSՔ"T'jcVs?x|fO1-_Q@+x6|Ctq#L;$:k Hys i81'r QOMăU!dg:ҍJV|F^in@^}o\ue`;fX{~xm2I"2'VI 8n226ѾƸn< sLS@*@-/B6_~~s3~)H̊QQ41j2(&Æ(3v>>'{PrR,Sg$ sg1yod6]PC12ی?-a Fld0!f&ňspO[B<36bsM1p|25\wҨ{yvQ=CWDMsnvCSj 5x^ T ؒNKNbVӵ(@i6 >,]`Jctlg f>{uӍv>;2wKZJo]CI,[I N}ЫWp= ̼d{5f?F5G0qAP 8efiCG UʫƄn/\SI\܅KEc9hx*\@j"ڦxuw|8ya~S|FW;bz}fsr@m/ɡsۤb8Za N>:pwK\Jx_ ;.kAK]{-1^ zU*ʀH|ܕA/PqKqg*ǥn1F*@W$ rG!*]A-_ݬMn&I~oMسWP|#ci*w荟rRhwTɻ2W9Dia6@ӱ7 Zh6wǖO$xKp;ۄ9$D?׌OmOaDWI1XZH71|cE|U\>rvӑ2M* \K$o0H3e/1,@AS gHuV!bQR,ɇe%m1`H˥&Dm-\ؖNy gKpl3ûZ h[GF'-3xD ZmdDAx,B9f&0ٜ̂im4zoȸƒHMo)ɝdKג;4FV6ʉt}Xc>bwBrhjhPF7ZW2Pru/ɑfg݁$"Y2M-@k4TM4QڬIJ*ߏL 89vn9EDNGAoCYG 0Z} IVwmX86b;wAV }n{uڦeYŎ _η z;97oIq{inK8|cq@ Ud F!7pT:*dV4oFugI¬A^58[m>{{po'[\s##:^ו$tgSS˗ab*ݞdU;"}s@3p[VD"F [{Q:N\@‹8֖{Wq2J t/({Ri]<#0k4`6lhFҴH$BA A(&GjOMD4d**} ,hZ=|cA(#K'#ŕB&s ӇSqM3\j D4շo9 O,_OUH2EZ5)nE4>A&^G_4`3)?ZA/6A&kyQnkcv6]}{;WB{[bD&|YTXsgk<4cn@Wf aF4; , YNXb*͎"RgFI^^H!Tgq1X9FY370D 1jeXJ_}XjRCeItX]W>H#5דgCNjpf 5m\W7~ J r7%=%r`zfE/ex`JϺ*aTn|3{xF0XȌZ2>4DB JV6.긿+Lk-F@sA=)øS+VاןT܋P0j;R~y¦nP_{R\e!' ?\=~HjQ"t⧸z)>ɖL̟];D#H)' $Z)7ЈkV! dJk?S@ot;L{~^+Qd M9 iκ/_IKc@yf'O^5e5DBf $VpΑ#>ߗ'HǗSPSS < @SDZ3*{$<B['ԋƫj%TU`C_)~MHKBPɋ[Eҹ5a+R~A(xEx7׳KK#ERbs _s n>ݮXPJOۉS*q " Yz.NSeQcBQ9 C֒L^Vw69-NӴf16/qL;&\KAo 8[CDj 6ZP18oC9#w`1w]w&t Yz3+h& b>a%{o+hZiP˅ϧ&$5ڀ{:gP,m5MIR?"ufR%xi|+0PE#Yx'cb}!W3B졶k9bxRhIlDHD57is+w ˤRf i ^;qF 9w M6 &3 @PO|&.c" 'z F_AVyzi'5ڽiYtkز\]X2V ] 4ɝ^W6=kHk)Lela38zf@bHspcXt׮\bD<,"M}cW;78Tte*"qh]_tY_?7j$!澽I2ߥ)o"_IͼE'wW L /JXO,sa*&Aەg]Zgko3)Ł'Q2 dL۱"r!t́7%QW\uuJ q K#bZ]S^gKSܚŲS NM6T=;2PWEdI[$+Y߽-re7ioxfbuP 9-<۱@`>fo=]EM'DG|h@zGad@(p -rPj 'Solڦ,~-#CSF5OE:0L6^Jۺ pk?ZR?^JFVӋ]TrO5Y9}-2H yRVdSUɘ-* JŮZjG:@ޟ/ұ./X2[ɘ f`>ׂ 7t~g dQ+ /ߪdY&M#@)0ܨl,W wd4=*fWSR"eǡY\i`xkzۣ2C떑+Uۿ??#?ጠD* b6`-cˆ;*! $ \l3U|uH֝ eծGCcC2rN!VtnUrԪ dpHBW dʍWfpH^/hg{EHC0Di!Κ⃄S 9"'->$5O]f9H'0F; Li~ J-Kdٍ 14*/!!7|2R,,12nȶıǂy;ĂSm.FԈVo:*_D ։CwǺqǘC*4hŌHTeL6KO.Jj4cJ! g1c<m9pX&zܧWزڢ6|1{:O;]&##Ve_]3ƹM0bt*Ѿ(tjU^ սO B&ৄ+J1bxNRWB3gCuEWkŽK"l rP+wTZCvp0sw8 1":'tPy hC+|{PM̩xiL3 <~Ou)4=+gH0;ߜZ~h Zb2Ƴ9 \4'B[\ xs#AoCu2^L}#RMn^Mu[M:vO lz>K[X}$^p4nf&g{cl6Vz3e;K"A2^p->cD`t6G!ccJ w:Ϩy H9ޕy1I18Fr.V;a(̞hRnC7IGʩ٩_/p{$K˿K x{>[K0EI<yᡔj?{iX{0߯}q^ 9(I[ix'15O$tEld(Xl.@[P=2Ȑ.Q 6GR#3 IJh"`]קHMU#i4DŽ2F=LqtQ1Un)^V49ͥHߘ,XAB!Z1 @1f%v<{ >IPA>ז$rƪ٩s!9&8N4&2C{@URL ikBa+zBB@J%8&AKI0X"$ׄǑ `GI>(=Y}:ԗd8,7)b 9!1!!}{z}]6iivrNVz6aΧzd}؅̽|*$^!*Ӷ)8zTs~3}O";cꑂa0c$sأ8qA5CB96N۳7g4"O] 5ͩJ!d]V[=FtG0ZVְ~('Mc hh<CK&tE|k]0*Fw2}挔dÌnw)mJ#yIoD6 NzǴO0"esU!a$%ͿܽT8.-r@-$+#΃7YhuUcC[l0pld΄W&tR;A$!#E9'y*kgԋ&CHKc%Im>6C֊G"CZ/ڕ6P l M,gڛݜ"̛FAATPzJOo 6J@0<ve ,A϶vs-2øO&3S=;\xP  4WBfi9yǗ?/?9cf2ҍl#>)ZXVtj !̝t4[*~eUIoc aϋe6{fꭟ2c#nݫXqX@(7cw v?1+i$Jq,~aDy_X ꡇ9 )dpLXrͳcYn3]('Wҫ{K*)qd+6'Ҙ~+t䁻gh\b#q8s=@٨5uHB)|o/`$"#n3W5.7 %Y%-3*ÔR+Z113&S 'B!wdщ\ʑxZ1W!a] =K@n xG 5X  6 ḓXՉ"+1Z:;/14`/ׇ; %frI1J&N˷0`Kj(KèSr.,p49P",WhZ*ѭ4R9t4,M|4N׾?T9d MZQ&'HVFx!€JYO[VProk1 .Drd "5Kɬ9 M%v.qO\SY5RKƁPA3&s:s 0HC1bY8I[ G ,d99EJ(^P; y3e[(I:xgk@QJ5"C,#]%oMts/ԩ7K^فXm$AȖTN@/yұ`fG/^nľ_3&l.e[[ql\9fol#EF%e䢽>1VwhJ@*6 >L1 U.)nWZ(6=19I"j3zJS'ˤpxI2MM>'?seMKp w,Q\oO/pg6U $:7BkJB.XsU@S{`)yQXN arCSl-^(ศ#I5m )ʙ9.yjЖ4Ountpc%2f9~]?pDI^V屃0FvFn],ALZf=r69sz 8s :1c ͟n~x<z# Đ4m(O:4ːROV_, :b&ޜl]mmL~}_|6 o_EiNTrf F" 7%\WPl@vZc7_;gO6[{Ex>Θ8{*w梂[Q&:e#׶|`4\-*;-.x9, 0 m}O΄rRVOEHު^IioN,#Ѡ3t,f6&hJ_5.{1Mf"^s=ONz 2 {1F}ij#JNnzHJNQa6ba~* OhfXFHBRhj:oecvC'OH3$)s5A!0#7&-52({,'_e}9PA0e/b$J bS_Ck|.T٨8kE/%FkLMDbsCϓ Y^Gddx~֑A,k[xLe3j0>I]wZjK 0cwTŌ hcO5^ŭ!#OGXވ#3D|]0e3VhVK"ebjdep ՊeR$bєdq:(J_Rr;TL.%ƨ4b2#:+XWcNtK<ƫՎ{)旰!7x]\2]T[eVtqwmxhys&ĕ_Ljߟ,6L*^|V}쯔1}̀jq8:C~~q;fHr (}f}oX&ȓ}nf/vX=O_Jd}s<=FajHZ @-WFv 8q&)lL=MxC̻zs k*[[1*mK_ A=8\eds5%P&JD_iuxUQ^Y9ń Ŭp8.a‹C<ݢI8 ! 12hinh3~o1VGJtG$&q*{Gİ'l۱)ś&-F_Pf!͉j\FtD=M̗%  l[ k(M(1sX/E-k׮7?/ka$2xЮ~kqF<@kyzUVLzaU2ΛEh%%S.twRh/ݗ-\BTi.* u 搅r23oQ⎖ѧd^`2p2ٵ˄)JCT~/gȌO{e1##XM Lpڵ*aYzꘇeܥ&@IE'oT76!5V+c2RS%A͸`{DX&8Sp |Yp&wŨpcE?IFa d^ Уѫ:d /3f%5^M5&䡳k)x)/'@^=o"@%RsP P~ 5=&~̍\$1i E&62M`_ ufWdо! liXh_%ll4eۚLVIt*5H,U-KbyۧKx c/c5 {X!=,K>sE4N'o9t.n =tZ'ZŽ)ȣOPFFIJs<_ҔPU|EBU`¾ F\g#d%iB'ՍfϫnqKalrlK鐼":kِ{Q(o*`>~ L涊g 5+6cH9=Sxkh'K[)q2OF|}̄0@Le{EWlS`-K yy` 礇,7=ɣ&E$z_ *| )OTi%%-Z ʎc j!. Ǚ4 ֤m}P*u`pQ9{"=#sH'C7=F?}.]%cȑX U?90h[BRj+wKX!͌"Q!+!~?sWaX_c7{Hd"I!‭YD0 feYR /_ٌKvAz%4xB&%:0I 1(KZ k-z> jLDedH V'03ۓȖѨKh/F (lQx7>۟Np"RJC!(Nt3*@!g} ư!ϮH ?5?s.IsLqqm !c;p?3/u〃6d> 9) ̍#0'(zQ0#5؝GVi@ \!Zaȿ'z|Z)˲߹Br$p=+#]RI@֌ {R=?_N;6wC&MK\yΔFTAd(Q3wP,O_-nbm<(qnݩ(XL-󪮢.xMΔvUoSo˅:}%dj4:ab4Q)&$yOZGK @LP4I5>J2W ]&wl&y$zEyA{ݻm]wٯ&='hât\z (SFryexn2W 4:kD(jc7toU^JL:K/t#q^d0Oh+lXzftF䑘/y;X^ ?wO_^b^1&a8^56"} 4xƋ2C]P %LL;sw7IucBfS;*2IO1ɁDUE6=juї;6$ZfttSrsۍ4S *X}w"aO5EյtɡaMG3m{nZjUL% u4v?~# ffEJ t~cPGf|!ɛ@BpHǤ-DP6nXt"(]3ٕ|d0wm~DWC '%)l㛠me\|[184fHPSíH'ۓ Y7WsnW71וQ܏[xbFjd9H Mz~5@ڠh"* m)ܟdRD##{{?ʀFVP ^H/ETɇ9C_(|v=z4E&vߒ&20<$¦&@g4-g1m PPVq6 -7J.>(p?Js>TnH=MVm1~ޜ`#/bG^Aa*Xi/ 7+̱|~yVBeHj|FG߬o~>9#-ްڦo#,zCfI{"Z'=g+8O bL̸q@$%<055s ?Jw)IA<T#ؒuߔ?3-K]&b&,% 3BLB[cNhʚs:-ZIX4@Di Hׅ}t*(.-$} ck3{ӻ8YD >O+ }j ayH9 l5Nte96';0#[)5Mz+d4,[_zx_ kx!aBgybkO<K4@RuFcғob9"Ǥ^:F׋Qj>NtM󈭢Q:T(F9JgxΔGY!8P#M/2~#5,@r2rPH /- [4gkce&xhjr[ Y9ugyfhLj1КFV=*PuCdxR"Є3z A8R;WGqc-u7?1B|OkS *؞M/%ebVSA\AJ%Nғ`ÄH6T!,hҠfɋ؜MpVOYbvvc`il"M/M˔))#@0MISXϏ.}ZL=Ȓ_)n>k殗*'-Q*IKY eH@=R},D3IGKt.?,&T-ҏLLOײX\M'!8 YՙXt3X)=Coq!p>gkg;hFx'h+LeFpv9$CTZjсrm/8z'jX*S%'؋DLJ!l|Eб{JbTQ,y/58'>#v]`t{:?əf(؄J=mI #g-b *u*1΂ycD6BoUz5|2wB{Lr? {yBOY Tzܯ`,'P i)>&nCYP)hD@ )Dgঢt؋t=Y)2*T֯ZqucB]8Oz| Ze .jDidKgAXeD9fԬȬ+),og_vDBj<#e;* Zt _bTe'j&+1;6Ɵ H%MYmEucjTDvc[3]KmV$XV@1  !nF,~#\/MmH/.1  iMI'z\(0qWtnwsk"&= [ |?2qmk=D(C&# 4"Srs"Hufw<}~]v0*0H}b%+@5ZKlYpqZ(l,Ec[k LتeҁmXaIInS===3aGw*T|,>&7"-p 2b1*CI[X74"(Ig\\ <%4mn J+3Znp#SBa {,IWQrOr]L ubS=ӋzCݡջML"ZYNi ׁ)m2%m{wzkMIp6™ iȪGrJ|1VK 3Hq4@ aC>6) j h-uj o.E rI ^_L6*]'R:~$^4$ivɻ#>/KԽ_ջ 8WgV2aLB7!fy$BCdɜ#zJ"vxwl1'1)@T t S7 'o6n`hͧO# GYJ=RAZJVHvņ=ON˗ξ=LJoOK'sAb"ןoV[=A,p0i%OH>~0svDr᫫#G2PZ/ 1<=2zLvR%,L V+ۧgs[._mV ;v5 a??ο=[؇E)^AW{hTa}9e v;BG9egFZi+URqu;G&RX*4&?t-VG{rX{loO9vHVlUiFډ1d(;;Z\ܟz kbB2jΊf01g^7S1V6U>08ȩ/87|Gټ<oP=2I5dMrN.:!-8[ʖ6r۸_#1rw_BPll8$_N@V1XT8'g^f2H.BgBFT='Pdc,zy?=_wo#u2}8 yݛߑ 4iݽƊ a򬪫Y=}lgZqJ^fϏ') mzk5uCFFF_5+ @(}v?~^j dlL'^| Cu6l9`Z˳ȑ?%ze5IY?)h\mkO7W;"U$mOb E{~G|{7"IM?@bwƟidZ96UѶLJ81p7_٩ն)߮?fw~O2Y^!q*IG$+MtAZ,nOOϷiq@MVp̆FT{wRWԂyX_m6^:j~ ?hy\ƞu2.еF kGPek *&>B#N*S1pI0CKc|nߞAy ['FT 8UI_& B#؞).heћČ} ;25`0m[uxSl L CϙJȗ̠k, m\X1cLR"9B8n!fב>$Xt!"AHkrV[Q[Pz= 7t*,hՇiA@lI }6 H+vmZ)>< x;RlT9p<( D*V/D)T'@IZa PhNSvuQ.deh6t3oHg|Tg,{W/(z\\XцJMt߅U~6|(f҈+0G";Zm Ī[4Hv3m\u2 |FxkT#+jm؈GS@ ",k?/"eYHow9`+WܵI7G8&sy1I(74[q i&eJ^CCH'"lqIٯ,pG;kfG1nE`܎=Sd .U}U3Fɘ2+R@ Umn{0yշحS@;Rтkןf6*Tgv%`Ȝ2$)MP'2||#-zVVԵ*ut@}/*L6Fk`DSq6)L2޶$TEZ蓔yXRڞ6k 46tI }1n"H3 3'̈́OWFGq^=߿BL1^+DN:;j_yL F\ V Q8'rT*ir)aݣM%}x0muOb/s/Sn7qj ̳ԤD^|j8ZPYݿ&l[eB3)!ʪGE%3,R6n5K6*1bDځ%0.O z#"6Qĉ.ȉ,R;sX2igNF,1d=F=Y-."E*}2qC"^gSnf`b7SzCJ ƘhUxm=V M*- 8ʜK 蕮b$El 7kN;وďw,n)rs\('XsCE=IZiP3H;dQ$&b{d- 㞯+myEb[|\& /*" ;<BRu΋悉:-AiA?#7kH4ۇ:Y⢀5RI`GB4f$<KFn8rV~_:1nsxFL)G Vτ>b PSV7sf yqLvb߆'gSq h8 3H=LG&$T|vwn +%%N͐{lntHAsylLM ~;ڄan}޵_ev4Cf=zRA̐KiȔD1)6Ơ `Psj  {W=UEW- ũ{.~RbpbMa-hr-Heq ƔFӎ'Z!/ENso1\)xcvl!P:h!C/E'Z?lX(7@Y uBzL" (MYO4$rigl@/aQOt_oE)@W=6bFɯsB8v A>z6|DŽ' DL8k3.uBOj)U-@Lo!IVQ 3b$,v)WryʁlvEyU9BH0@B^jvy*ALq3 VM$@U H֣e= R)ؙ֢1^XNߙDLP(øz0䴖PPCp;bXx/큂.$c{#gδFx/Nxl]AJxHA,Qqp<0188f˼~ $ѭ怠cb $%|&#Rze`"sb V{[?m8HO{qXSZrmM[,>d$?k|O(+eI a,%9MXۙY cÙtUg9 @.iyg?寯,:ioӿSr ~Zʒg0(4ǚreLO)SJb+qs4АOT$r5QdddNgU40%GN\btM7H"12FF7%R;.ܩKJ fCB6^Z>_kI Ĝ/O?RԴj"ϩdм<,퐯#c|Fc Wey53 %pv!`I3:FԄz"DOgq`e+zoxj/_BLDH*PCMgAU7JRI=FBBnd@#1ppP&)5 j`,\ϧM4F}mpUoPFDRuY( aXիD!,F@%Z.AMJ<`*~W7B\ PCy eL_X3vQm. JC'B $K,B@+b\=$T>LG8u-(h Mry_A[4%W;mik>O:FI_2Y\s򷱫Ѱx W,nD bH1vmUGf+mgB$bj nIp R6v"*lW6|D&Ϥ=ٟfQk_\`j}C4 Nv#7R \2)a]B,Kxgs=91%& CwY#}#qˬt RiKb? LkU̸2#7("ux%\*jMFEuĄjzDF k lKtS#TnUt]cث;&5Z'RId- >Lks5UCo[iCqi:Mƽ9%fK_KWni3b W|}oіcs/ grƐMh|rMWj<ƌpG^d1)Aahi$1S|2^@nMME f|[SDVBL6z>'zs8(&2RiM*l#J \*/j;6g&Zq46 {/}klZ)FT rxp˧@j|1 Ơo $bҽ;"8`tv%)#a-}A%$#x`D`Yif3"{Mwn$TOd3vܬ%̼jh%-*y61tM8 @=՘Ae3j4y@W-}k{_J?.׍MF&y"^hL=G*W0$P+ysqLɽ_Air 0KaEuő}&m~j\~x=Fz >%fb Pi$ybfJ,sRT\0IXI?łe=L)!a|Hoh"Tü4dT .acMdGzd]9wCȠOĴJ,n․! ~ăa"x.+i]H;Z\xxGuqz)ieldDgLc n9SFW2N5:m79$%@oyH(e~dZ(Wt\)#{-mהSo 8JɿD?2l*Wa6 j~rY/Yg^w̦S0A=lwv@nTWP,{bܩr4A8CHKŃDD84;+N:hbfw[aӭSUEUH me4T@Q@_, p)K|H.+:%g ?FLpa.>T'|ӳpK9b,!eq'4gKBdwݾ<|1ek=0?CmrM@CoYeފ;4Y%[6(~#3a4J؇Y j1c6~qmlV&DVVX\qp&^ԔovKC 8Qƿ((A*`nDO1)OZ Y2u7m07D_2YI ȃ ČPKq.G@]ߚ=S潂ЄOI5WǻyrJƃĥCAp EEȚ]l/bf,b$pd(G޲u(`L/*1L¶ЕGAD@>Mdj}DVs ].S]/c)H0# &?77_-,GôDI&Z]JY[UH+B1#*i4j}$~ߝ+ #g$SL(vQ8.( @p ?IOsӑqUD\(ӈE qpu:Q/LQG#ﲔd(>\n;3"UsV/n1KgC?kcF3bhP I-8$2pH<"&2E))o/̖2@QF%WSkFZgY4=`X6 =.ָNnnubtw=u}a6;p#K-r~n1K&-n,,{ɥ4friASMVYDԄtIQa4Dzk@pt#*D$\rGMzi\=gIkpՏ 5J&"e|=#nDʌmyVvhP<&D"xmQɼc2U X'f|ś%j[ P l{=O"%`?m9,A @Pk*'̖>xTa)`EsI>RssNbDE8ڤŎlo ~! 1IdSr# F E<ί{/Z4RD٬~pHHj^hYN f:&kvmLjQ0 dRzjl-m-ƲN'G*~o8=xv_{tޞ rCTmu]}^~pί'v ~K92̷h.b.r q8լ8QAg'ZD9%բ""/!h <//oO?/\Istt;KpTE(-24{4zAl@}Ub*L. zXL0Syҫ}_ 'nc,H;-,o"|:NmDMgk0%VfĤ~BYԓX7[ S"{谀| Vb̦~ƌl*l LCx8 V6?ڲ)HHPʔXGq cekeMD%n%PjΠiJJ,J8C#_ {~mN*[!RUuo#U-088Hz= 7:_jCVhݨdV_w 2#=4т~ nD)Άno7vwҿ^Ű=ccCO83#̀ʬr"eN-_ޤӀEoHkb 6xR׭CB_3F>+7 ~glVT- m#ov7OvǍk >l1Cv]Я}6$ޯ6vDKg#)_/ -ڋa?U 1?8pPE)yllFi~yz{3 {Tz9^a}UTSQi ER6zc ژ`N 'H.pQ{fe]̱v~}~4Lt~:YfS#t\]&!o7 ck0zqNU(k&tpO,\/ڣ+,kVL`ɹyFpQ.g`c˥\Zdf_.M=өt0{C+8mm(RI;E7~1"3ۻ jJߜؗ# c;^_^s(^.qI $7`$#[pAnT"eE?e!iw- SA:*Z*ѯ;텙׹6F,g7j}m@{IAbBKlIpKQLF 0"z7|]Ȉm ZdB$h2mZ);!ыi .|;"{Y%Y)h% Zd,ݽl\٪Dat!$OWafJYO^::0yL2+}ĽB!_Nh2wedH=E97L+'6@&e{:>*=mװZzG'ɚ0aB,*zmģR;^ɂ?>D;A?R`=tkT{}}?Ghݷfd"ɲef!o D݉rcIk̬Y4Hɮ5HL~?*{xxD,ډfxD1FӋԢ''<ٴ %O H'іg5RaoD@" E,r: ?. AQIJzҒd ѫ5SLIj3y0=5QoLkq@C,I:!+Qq,:(OX딑ѩ^rͪ :6D827Z^ESFM,4kHls]`xR j: M 2 YDJ4FPX 1baĔ9} P8@QZ,$PuM m;"XLs%+ck5r׏_/Ek|Pk| 6"oFeN6TZ2R״ψ0750.nk@RP"gT7Ix"S`x'@~:d Nޜ{ŚhJƗc7p'g1M0v?4vay$0 -@هek<1v}+. ~%>n/ÅyrVp 45mcdkpfb qnRTA #dCѦ8юQHpSULxTJ{Mc@:8vpސ2OP(t4ˮbDo1X'w-{TZ2bs8ӏRĝ*+T"a,Z4d{dX@!/I0l +Y[ϐ5QQ'er2=T9445հb?@CKҞY>Һ^H`Jc>26Hj5Em.fmCQn|~*(̜ͤS0 v>応sRDd-TDHT3zHO7Ku SF X1MOtIZ\7m^Pav~)  4˥̃Wt0QH+@zxeu*)h>w((cI豳pB]pHB!M MulM|*|k!d]= w~1aTWo_5-PujU ˺Pq*a{8k@na3 ֊u[R#qP#kIDwO|U33F1gc6;&J;Ɵm(5#jM# )P  7e6;aqԘRU'ߓʶϖr*z4ܥH+tN)m[>owϖNi]ZO`3OBy!n><͏A/\PpëD@4i"-Lցs {F5iU~J >+ hV9{6L:{(j$^8WU٢"ܽ|Ns"Ć&\@)ӎ"F1[HH+cU9,P@dP4s7`:K44V+*5ɚ9KՋɱ9u!Cg *- id0H |\#"<0?GFzb"E\"lT8y3oG/6LK/pEM%<1sf9p1S]>W1 %0'= u{<Ӝ! ௗ*\W(8Jn >NK4 tߪޓsiyѠ\h@IDATέUW2&/҅4K-ŘN:wa#t#Ŏr(.'3ҫY:S^p0%cqGc(0mͽQ$@˘lc%Jx)Q z nbtk+%K 7 l NHjCa9Cqrdh (43x²AE2dP%kˏ62=\9CEP ۩B+ŧi[BI}nN ZHݏvb;z]2_v-tO`ev O7WoêԿXVx֬A~qKG#&HA3+Й 2rʉ&;ch9\\Nob_S6aH#9<{^tB|܇ng,1jez(Y})W34&ʩDL|5kj(CGBy^`=R]M#Af3 eCVEt0eۦ-whQ1g3< ( \'rLv;1WD!ϡ"(qM ~ƾ$9danFKAE7#RQ,x2ĻG!M d=2#=>jkYߡ'*}_ۙ %-xܽ ڝl֭G?U4秒1v+Sԉ<%|BS ؈7:Z@T1rČA2'T[[*I!G-{@vt4oNel3Mv5h3Q-wԙޘ"404<%%o2# 9Mʌjޫi@iʏ}(Rck{40䎅 O" 0|=q1ܫ} 2$V@c^+#R_RM6-N8 1E >Flq'cME c_}-P%Ic{#gh0ق?BybɷBAIsY ~ yt =]lՠa&b=E,mp҄nQy(;/3w"\$#WT>s$ CB2B@NPeQNpz~B 4Bn+=d N1$+kZPPs|HUz|%(H*2bb0v13tUQqS9~|ա]% e-2[^uR 1#ll\ʠ6~@ at 8j+աn( bt50ף Y^qoO{ԃBjDx^7[){R`rA *^ YZX2F FMHP]Sd b|a^8s R0(`]x, 5KI#1>ž[xnB9g:PVR8+^eASqXdqXG"r{$5-)jCr-X9SyH7I^Sk-N D*3OQ@ P(=<luy=~Ƌx(1'sIY ޮ/D!Bs[G{|PsTb4R~6LY+&N+I-:zG6E9 Dî>AOP9 ,l_AiAGg*ee LH o榲+Ǝ^i( -Js 6EctDkہ-h |FHeowo RM7L׬"UQ1,܂ &T&yxy~mۡl^.q@fu "1-iB=XeO&*KǾ4u -oޮ˪RO\<`^P_ ă" eY:cz|m\ݲjzљ=kfԡ40lvXUQM jS RS7xN9A|ۜNQ8ԋ.`!+ 1q8fمB{ZG|HtΝr˫`o~veo\m(wlV:fxƳ`qDWq|n B4P;FP| Ȭ'Ҹ}de Lܰy'Ne"@Q[EWɧ'S4j{xFBފދڡ=P*oSGW;?M]eL('+b!c]PE$A~QcR5l?Ȇ Kd|aO_( J$Wm}KPϛ- hnLe2Dc]D,âK [KSboέ!𖞘dP`# L &$Zdw&+a "} D@2G#YyRG$$Rf9f8:ik*_iN;Ϗv :d)VAV3˄vj$WRW`Kwrٍr6nR37洰\Ь5[~ p @,luRzjc$_l7i7﷘&Ԑ{>dmW_|2E31,M9Q`CY1s;5n ,2 $G,ʋ }߸D)hXKR9!3pV V#N :IT'\}NF~$y3Dȟw' E(Ksc_DIշ9-eUIzZ^sggqB5jnjS0Dd=z}dZ[ hOF2frq՛Dաq\7­*+MRာ|C=Z|; < EO~i#u&jB_ß9v@2=fb l<4kk:\> U32/ 7x0,MNhlϧ9QʚdƊT,ah^!w?;Lw+dI{LoL GEpx'1XrΟD3Jeas{L@I9&QLKQ0Aa]:ZId0_Q2(5!ΠVCb41ha[ ŃMMf$k@4PsRaNLkxGw & cF_mBA,+O6+^ ySaV jNK=;RYp^A5 әjjFGl!&e%1a3B?yU E&6ªr (6hQLCeēRDZAcmmg 9u2Jk91{]6s] [8eN-TLSE"0ϫ{ i lZkPj{dvc̽,{eypj秵J@)R3;;VR ͯ&SEA4ۋI;F ͟-; hU8f6JMYH|@:xXv?Y I܍8y=uT=_zD_O֕ O, `\Xz3+U9-2]ߟ4񒞠UL3%!"yl} VŶqm=pBhKAN7;RN);Jeny$&#h_GFeȄAU}cU@ΆlMk*P1QGqQ}\Z}Țs9կO%H^/l|bnoimx_,(eGO;f@qīIY!~cGd78@WY6 Aݻj{0r8-xՏ3#@ wJsZ#O-qE> GHx?[y(^ۑ>O,l'?nPwD{ թn>5lN%eZO&`~WLOv4дC 91WR?jJJyd&61 1 5AIu÷jf5W});>J@|e޻&*T a]=1lTWe2` X\A&:+g@yڻ^~z{dO?RyJ)r*`egcHAVF ~k R5w։D TH o%9»V@ ?s1EQު-ܠ%0gn0,;L4EO!z0F97=$Б#bM4j C쥣u(;ᛙEjP!o(Љ'j V#U G "˱`XK,-MLf /DĻ 9 ?o`Vorzm(U t%%Z>'Z쌁iM"jQi(q"bt~;ZK4%Ɣ$RpW4'~XD -o6W7noE@`E$VheH5+0G>/M$%"hs@摻DNCښN:^T5-|-ǠPv0Ro&Jw׿ف=`P2fC*VVSzD+cv~FDBT (@BO8,E).ΪT1PPy ЖD`dbrfk[<3˜wpnWdl:6Pu}!3 lHW0k;fskn5!LJS ahJMmx뉐0| ,o|>#$ Wb?iQ1)p Tx+g/l!HED6v1xnjU(t? .*~ D=*3l)t^Q?>Ujႃ9R"T[ FY5v?#TqJG+;ٽElėye:qI<êT%ě̈ +;Z|ʣm>/?κt(mV/>PПH1ȸݔ4OP0Kl@gH F A%a&x5^y ~fH@t. 0B1Z)'=N6;Qy܌?z%YjuPO͈F {^#P 6@1ɤPQbTZ*k4ջ{٦\&*#(Bfm{xhDȶDAji`,YrWi*}ҿjzvp 7r/^a4j1;ZXx8 {(p|Bs. !sclhLTH.*\ f@Yn{)j?HyGf2B0~(Kw{x$'^ЌXŗb ߷jkE NJIM^:\@TQS17V%A67~;4-Տn[ zL9k )s5Ipqllߌsq2wx>eydta`kpO>_r!ľ4{߻<ӟHއ+.?rק]etwlv1Ȁe j=O?QĀB<!Ll~)zs$@p/KizT*[z7g(yPlҴPDFFYݘň5u41Wb$5`t FNV\+3vH-uOܠJ?f>'GaY3zث"d3;g诎裭Spа*P4EAp+q,5ԘkV/8;_e6x5S8vH)UB9OW  d  5QG@ bm.߻y ڡM Ht{@\bevT1qvjhbo{Hd<]]dgc|h/w[(3dP!/}{vvfL ;9W<?b=ggaEx 3|&R3bmCmcfw3@d_CtU9wA41LitSr\8 )uF*+,c{W`yŤ4`ɷ8D)Z!3=%@of=iL MrZ#^!OKRw\3 X:7ciЎ^mHK_J&9,EN#5r0^<0=at:D'@+xVPDG(K6FQpnKxn"/V[m/p8Wx[8WAZ;Ӟ-{U4 !Ah 1igF$*Ȋ+Ո UTeZe JiBalFzX+K1AQ%_HqĿL`ǵYO,p!!A!v0l`A ;Ltz_G('*7Y3QwY䗆zQw{$2' 2pbT8_yFS"ohW`+ <_f QVX&%&p: ab@ sk_1'޾o=f#XY'ag8Yh2Cp(vgvNM}i?b\&3/"dsyˑuQ+ :$Z,ľ@wr)? M@ cJxP䘣p1i7cD9Ncޗ\7fk{4j薚“{V96ʏK`Fstz[290FvfKzU~nwf@N{ 5d/H<2! y|"Sj9&3P.X|Nө9OXmyp<6!AˤD_+{g6dvK)f_ثm|B~ӇSx/v/FD<eAi.&Mkq@Qi@e"3ЏiфfArX;o_ãK_w if0q;Fؑ' e\PQ?X%5t/ &%1oUUnr23jLp~XLh&&TxmXG*QpKc P-/:k `f0Ҩ4! xt糫0:l-QcAB&|}1T2ldIUδMkx#E h9D.%֓UVI۩֥Y~#rڂUqVt?X# %k@}QaT ZK]!qX7c]ϊ5Ol^?>̮5&(la,:S=JQuKB7Ƒi@9 s"VF0 N2eRzsG 8s-ʩPAQ @gb7;]!'S~!q5>&$Ȗ6A#QB^)ҨH Il7iVXU|jE`=d)Oõn-Wļ_zơձR%rz:]FHBMxaDiƢ^U]?p G<'K0EX@rmoQ3vZ|}xQHAQ[A <"_tExqD#jA:yY:.ob9xkqVFs0k@spԂ!DIa s"^t= ^jn86M0c]5iUj'< J*9A0:#B@4'%b=U4DZQEF4ï!-Ì|6Rs(;I(}s55dj _cKGK o~yξlx#W>B&fO@͞i@`Y2^ֱ=C[xTtg{4eqD.:M7Ԗvuddal4~%tgDSEˇuysp#JP3ΩԫR1Ӆ_bsIZRDL O6Ґqr0O=&HhJম9hS%ͫQ^䃤A-&RXlԻ )\=I-&9WT 1@:vkOt6n.qjtז54v['4ެ(L^dmYf_?)NNz"+,بX7I{zeiAqϩݒ=gʚ:6`F!Uۭ,t9QgHJa YɟQmŰ0EM,*V`EheSMh뻜UAӂ?zzN6z~~_)iF tI pdD)`m#Qp"'l$3õU>"AR5M$L]ǢwDs^1~#R0ۍW#\)F~D8%b ]b9KC'zCm!j8 p}X!FtO8a+K|xϬlUh5n7ckHO뺃2C*\`:YZ>!.y4ΡZ]*^&P;]{\5Q3g7n1Y7 D9f5s Quŧyh/mɿ:+8 JhܜeϷ)ʡZd%w):+HiL!9:"}2mM}[/v+^9+`K 5X9-'Ж$LhCڇ,0hWYUc&G9@B',iv'9zo(9wŏ`$!T_jʩhL<2JCz%"Re:8;t5 7g1B6Lcu J'CC C0k;:Ws,j+/[q<iuZa{pofLgG?^O'gҽ%WgVoWBDrJI5"V ~.zlӞ:|kdr kJ -Ȕ~G$X_4R!XRDDףLcvD'`zimI*n@WE#]yV2qmP *RKfG`Za=rخ!N% eʀ I3U|?O}н~2}<\G( D^|Wf퓥 _\|;2o =9],nq9Qʩu2lIqF*>]Y&Yڎ>wN[O7e8ԮQ^ɗk b]L""x,I6<KT 8\[9q1Ԁ\,aȩcw[@A_n!M0/2kشfِď%CC A "uڼpx8PH\YqoS4DY,6zm'nxg?U)%Ai0ݸUcۙp|N>nm R+ns*2fƠPo-bҌ Lms[R W,vF#j!BV^#S vEd|n(dh`!]=>?X^1Z.=|箨Մ62noj_BsҼ*K8|8YX2 Px=6* W y| 4/sH5Ok~!µ6߽O0}ȶaX.NT6XdK"loCLтυ ≿e.xf쬔wnhnxL. }iKX֩g\MᤊjV&>MsFdU8\3[i Ö+}| }ޘ9z_o)vnWGaJ)@N@k c.l׺ bУ4e Dc r\}>h61^s|:ڞUF:Gׅ4go*:.IU#bMt #p_tu-XMT<ʬͺ "D& v jG[vb75y$T4ƎeL,gzYp?ߓh_CIiEgipbѰXc#0 8'2٨S" >:'B*AH:ԙH۶YY$w:^|dآv `+*# 5%>$Nf-a8 1`2r=2C#PENJ@]%1]%o-B86M^yF=eOüug驄 G6IiX̱ 5+^Sm,%:Z b{UYY*d,: POq߰p(C$a}ǫ8WS䅡 \/f[&>/fqHGdxWBizO HhhjH rE?:cu wIBTTPЄg$/wmX#;YɿWcS̑}j_ B r Sha;t/c!䘙]+0K`=W]"+Mi}nɪC[SlKy'bsQk6ċT>6%]P\-?E \7[LOI#Dfx,6føqHJ/ARX1¤lCI5NlNj1|#)~|>03j](Y3L'H'.iSP ~˛H)0nlFm_vӍ ԷjfUwaeIF& H`RYꝦofĬ=0B<8.e"hNhE I+k#22֡:QzhB(H,£963Y%iAK{!6 ڴ_N!kTw΢B nx<ŭ5DeH IX 6V f4v#p$7ƾ\,Jnz16h_3 Cn!oQ?~S_8N3ǒ_210`)"(( ~*b;/e͢Kא-OVoŚk~47񬍋$> @c8 $U~X}}?DaSqX,04d2m9Ӧ9ዹ&'!B1ĄNI$"Z5Uc#(*%@ NL`ɯ0աPA()Rfx,jUp4n)X첯2/CTuF $a9U0ސf_屼P a0q> wEf^+KX }$JH8ÂJ(>xAʈfuD'"S]CsPPO6sZJ- vLStX R_m!nA.x/5iҒY|RKlypk  *bsɏsuL1b@IDATbFQ 'jw .-"lJ4e3[CꀙtO+`#;Q0;@Hzi>KՁFn5FjxTG AS>RoObt-o#Hޒb2,=*yZ4ŀn/Zrj,5 F:"PgN GQ'!wxoa1hOrhI#,[eGlSX)Xy-!=8Mn>D23D.x?e+L;?:^Vi =0X !<)H֢a VQ?zd@ I :Ox#4ggX3X$g|%i{ FWC7!,?&_~V8 -`{5Zr44 MlPMթK ů`|0!p&3]oi5-;2hfJGXB0^lY1DI <0#ԾS؉PXBʫ6Ӏq.Hevt-hLlD@Bq VKe"ֈ_"Ġ/ؕI,Gg~>V@4ky+QCȰ 1@b#*oZH뮹fOhCe(<\ (^ IoMpl23S5A}g&g Ӷl2&U,7{~2My@ zxpm.&YX^΄FPօl x+*Syh_j~f-@!sFJz"6Y)B Z dǠtuy兾fP'-qԌpE H??"nzC'izp'bR2j<,޶Etlqt7"P,$$48|ˁ4a/@*j΀SJ1I@a&0c=p_#gD 7Էh)qCz/Jl7 ǘW)AA"' dʼnWtP@I:'6.'%\fz/ :b]Y5DDǨ0m q+Bј2pSy|w VCǴ-" "bFd:]҉bdoDgw?7sjaWL  90Lg(#0vPV !T, lORF)24]Tq%k n䮅\rstd'xj[pX(Fɜд {э a}%7ul??k~ H8=2S ⿛" &VFG$F_VQBtRz֒?wbz @ok6j.M --&\h&%7(^B 9TBVzݥp`%jK-q!07.۩& V:{ק ՃOgCX@C)(d .Q< e1৻Fη z) I[I Z 4 T#FIu 4;TS]Ey2ӆ~5 $'_-3S6ZL&UZWP䣈8>v;P,Yyp T.a}łDL_a-\ z#eI@Nz6,s68]vUf }A4IlW٪OuH*VH{4.3'-U7@JR{sCg2"uѻC:9JtF18!59x_|7 $2%2s9+ʙ8)RQ -Ui B5;Y w|PCk,XE0ֳ>q@Ŧc/P4vre.fupM"tw;!&o5&HT(B4)Hz Jt1o?B]^^ZøM5\+LCr;_櫌gCsCYa[G I>V %P&eF,pqB+G -*V8ɓ Uճ!rA"X0XfޘF ׿~V¸~xiR\@ 2r""KwjEpssd2\~GY1|-epmߺ?/+Iy1#lH Sg3gUl<*y'Bh AgP/ ÑH0g$n \\kRM SyY?8),τ%LN6LE5̞(I:ձPZ0 dƏpXT*nxsLKLJWb 'ȥ1j>/#rmr? bB̒`0ee +Ӌ|hz?堩馑{ dC$\w*97|z ok@Q.ËLY'؏585!H.#)S߈Oq 1Vxrxdg,Iu<[@" M&1%u$ > v p7Ipp4YV\j,qۛ54OqS&UQgB |0 Ƭa*[7.ZV'/HP=jyD[Fͅ)ifyw!`%J`ZgI! ' 5_JuiDHRKUawh4]ߴ-msy^WCH;hqj:,Nƺ#KlP,, AF=Kv% K,n,}(Dř!LVl<676Xf5,y:Q_f|zDs7N o\o~ #1$< P',G/)"BT+Ua+CJ#(/&:ե)~/;1yV>C)@0>P>ey5gM JGvdYCZK:1Ǜe!c!} ڲvHuP 8ؠ5#Ax:Y:FX+C|^ oy<^ 1xoe lr!n!+jE N#;d̵KgHXnM8 j/W z%@{"{X4D ^qm_ ꊂ}ŴkV/%eFHy{ o~#*1Ne"Rf(4Rq{o5{jk\RFK| ;Pw/& ۯD<8]Wn0*ٽB9EG'|3kvq7pȶ߸הP剹}  LQe7i"!Z(bp˸p]D N\* `O wTIfCqd9]5n:}`_78sDyh~ Cp(@6JWh%Ui^80zPỹPjGEk2w%J Z9P.%o ƌ&1Q MmU|54 ]%F4/iO#6>9Gy5/o~t-y֐ZE@(拙i)I2$W6+o0y} YU]Ç#%!Ϭ\kpx3msm.`PByhT0KW6ZlO-^z!H|CQVCY9~kY@IOW|% ^fYqOx`F~H%# GƋϥD)ƈzv^6' Whq) hm62I |u[/(3E& lk8ӣq^7ag$@"9.:w +)*%ACfb;xHc75Gˀ@׷ תtZ"D0 ǃm^ Ҥ%AaYRE4 }opfcGArc̰>MZGS6ݍT>%1P4i|?R9c.arT:noE GMNɍ;.XA50{-!&m!{KE."@dS˨$#!PJ9'=ܔ;8I׬MJ`řc @T1KkRp2%: ` %dTE0{ H# z~SMq,d6# P-m9Ռp A%!Ǽc%FyzD஽ (oUx̋vk!2,gjNS} F 8csSφ3m_P0EyF69u/^0 ~ 0Í0*oI<}XP"h#)rl{m3eoXiHϼQ,Pgdh6u͙RޤEӌZL4މr"ؘ#uTg$=D 00H9}j7C;<5"" `X,UdTFr/+bI^^,bGPiqU/t24a[@ڀ6 R6~uhy5"kE(DEG E/L]r%忣Mj0?One>^ dpcs[>l4G<@x &"fXC^#Fx4JFL\u{ɿZ O@K82:]Fj9V k9ݲzqgz:LC:JE>,iQjM46EB|-e Oʓrᆕ(*{cҿ D@W6I, b[$M\+3^F\&z ƝXWNz X`b!A{==@QuOfscqԊ1t{3R Z'̀!j@#M4Iu'A75Mm wn)mIUF\b9O^.cFN8I ߦs"av6b+vpA#V?٤p\}~p710eci!vx$," ( IGff~h oO5`JBX4ѐYz%SEt$[hX`$iJ6]yR!9Fp2їG1Lněp"` e~Hc#OX7(Dfgo2zS:SCTfHFd;]'?P=U%7x5lc~Y,{QГAr&U^͋^ӤH1.wvX;2suTV+O-TTsεgη oP 6kYɖgɍ<=\)oMI*"sn74Nm5eŻ/fGSS2o:%˧$q="*jt{w gE:WU/5x4A#d/]=M931_2dwt $}^IxLP!a.>ήMШF&q Τ5|7b1䵜 9^w#M= ƙ̬i Vt쏽 ݃釴ٙL`PkgEenng37w/bm A?,7j  Iurh:Ft2ӣDS~tL*\[ZP#'Yxk֗^0mE@(NVf3NLragIZCu3Y,I  .i'I&8tGGxPe?2$|H[k x0b]OKÝ6ij2A-Î: =Jvo,n qs^G 9vB^)h5@CfOre> g2{rtBN8ۡ;V-֯ s߽(el=Q,^ߌK1䥩\x#gc<4bQC_5RVqJUai ?Fg߃9|13>ȝkF&6=IxQ(1y;5Տ&<#0a}[HO{`g*fDG*υdB%b=oCm#ád}RŎ'f3 K 'ՍMxNU_]E =fR'sM-i(@C X`jT՘`Klt.qN;-OwNTX28B$ha Xp}2XsBc!24  da1U -?Xu`r7= ׇ-:! Q.ql EJ-(~ 7xx-i\vfhaZP؟a|!z g#,Z Fڕް߈rM--&v,|xQpxBҫ1N&׬pBG2g3m hCZm,TΧY >'MiRSxȊ5j3072 tpxY# !5r%@WTsbKk&L7 z&´ETuؙ3B8gY`3z1\% y~حi4o;C98lnŰZk!_!+^Dv L=z<Ps[ haBqLL8ЃFOyaIbzu2B;2.OOj'`Yr)8+1B fH5GAM˃/65&Z?ma<oH(0p|_-F*=!t9z$4s`iY\`5F,FC+&繏=:r2wmIcmE4%dGK (?8>4cvDRF೜mJE?zRV0R$iYƝ磍GoP&`TlBASM2&cZ|O0_*<;8!tVTVXbQBv7%]j5Z/Ԑ~S?em{ON#JɡY9IgÄ][Q?{PA"VstEҠ@S,WxBB]|I <WbNN6ag}J?B2h m g0DVķ<&-x˔OGkcޙ-_) !^dPF`zO-m(% 8l~Q 7ӎatH71eZ@21k']I2!j0:k!U0Js\9&3uႿi PJ)7hs8jX3aF̱IJ= M(P+g ^uEt'3k˻$%s&IGǯmcxrOixθfYUpM8ؚIR[HU`v-J 6b?,\; xP~|DC"%1d]uMi+q2F@|ru~2WXQy C"C}=cWO\* er<9`(JF_4.bH)Yt4ޜZo(le0 @L@K E0-jox2+2iM#975͹J҈uwT `K1)j -JClh$R xr> Ïg!  ŪE8e/"V d ,7! EL8)ENxWofDEgvD@. 񻍦7HPVS?ˑveha?#C pkOSIv Y+a0%ps@2HP@!SdRTņ@Xk287 l>('rP*dy4ղQQ*Z9-<-ˑ"@uEdd 0x ,L8մ=}{ *^/Ƞhp+DVZ/Ͻ^ @FDxa@&=f="R\pԛ-F`|r 0Q@Z-U*0UH S<O 07haSb^Bbb_aV/6ЩL)9\nf$mzm|)ZSf0A=a%貞k itMqcj^DzoH,F `6qf\JCu/QeU[+Jk4v{Y}b+L(ihgDUrst8vUvq:ϬOP%2Gg&N t˵w$i(UHׅW8c pF@^M(Inp6K=(I2^h.b+ii=Ji|xQ1~&}NI(4 ƨX,6`ԌDծ\2+sVB["`WH ɹLٜdbW%/BL 2JVٛS9]>qz Œe)!m(H(!2,\smh|c~(m\53Bs ZzSg_JhЬ [pSP&NJ+{M6?PзXz<*Bo4EӖ6?+||ƕ;91R*N۷:y$ڈ9tn#%h+?c)n Ɨ =%r=.dKBhs[Yfuh6ՏQa5v#C.-(%1<64ϐ'H|i+LON:*M d ߚTr"xb:X%{lBMqZthhzX0~CPs[r>qҳno Km_5YmFo$G:@b ѫ9wqIG`Xuts9jS$޼Tm#FB1x r=i#yډ]m98lfקEAF36+."+{RRp0?۷ [ !Q!aŠZwՌcj;"DO|]_o(+Rz^e=MqY)h=}>g);nAçHۃw8w$Fk~#J^IO/46q΀){$)|o+#jKQW&\:!)9ϷVI 2uooCSR^ F4Gݐm(E}U Yfmޑf~!&0=r~X{X78H9&ٙ6"kݑ<5Ǘ}ks힎\Kg_Wvq&ظ5W8CJ]'Ҧ>V[H[g8u:{{|U_V\9^`h>_=J B8FoN"d|bqx 3IU'[sMal;UW4̥1r |>^! ~|8 z-1aGW}{ oۧ"ŽⅣXc<hRJ :?ZJ>X3ޥ$b봚G5*xgV#Gݞ3_ڴԅM [!EJNf>daaT\ fmsr(cBS?ؑwCb]jԥD ּގ?MaZd r T,St VҔ!/DPN_vƣ 1]ʻrGFfW9f?-AsEI|n؃n6]^SMhJ5PȥW@Kf˓xl;j xAB/PCxUpsX(T'0T-#ox31 Q._',vb>Pαܮ +r ׵tV_!ՏD<=?{P]Sa =1|.l^vaX5D9!MM+zhL; J#4`lwG>qez .1`ǔ)?+L o(If`gGU1x+jRg p˱|׵ԋUO0g~~S1ӈu ;yO<SJ(TVvGo'|5cSZ)FxKD#dbj'6PtZ=>J</ Ą*Z ,@7Cg`yOȭnu܊L؈]&2x_2ك4e8tWGS*J&jd K3DR؉?6 FhǵIqǭe!Ӿ-`!*,[AD _JA"~LU/\F|ʒ9\#ZI)+2٘k4hIfE:MX _U4sj9{#Obr lr[%*lU"*25V`̟U$(|tuiQݹ!tTFReC?\7'nRm @2Kr7O#xw;2Vx77D-EGc{]F036 ݠ!}~61 S6ŧsqz{t7JȀ<0(& 8#5XeiHk!d-|\ԥ#|7)jjb,҆o1j&`Pd=+)^Hji(F 8帐0˽aֿ>e11j>d  w-˅ji@"_v?ڈRJ 7;SA)/`pl$T]y0..9F5N"";-{P*#DI~!`+.mɾ(\w~*775sn+kg)|^ʡHq` ^?e2F!)&LEPRy`U# rƟHK2@`hC>bH(ϩt=#`e?- L}8,ĆE"dpt &:ӅeXI+.Djߵ/Ay2ELEt[6}xEm5rs)/T dU/ YzuNJ. : ih 茿\ eYuuƅ ȺRjLL_7rD $|/HIn߁1,_ Uh%q6ɯFI8jwRTO6#c\Pawh|15W~|(nLJ#Fe!f"QGY9%[_LIlxHDgӴ/M-9DfD2ļ~N^P瘓Bm lOڰT5WE| iJOd3f#p'saURO TO"poRӲX(h?ߢBH^lf/QFFZ2zٹj0TC $7a?䘲w4Rn Ņ9P#3 'h(A|%9hm]<Ȩg*:OH0J7䵽,MơO|^.ԓ.l`F; &5⁴j1`2O)s;eq7 .AĤlon\'f' rшےJ\/C :)ř CS_-' Oe@9Bzw;輱k]-̛R oe@mS3Vf~#SP*h\H_M^@&uhg[[9R;8 Xn"~y8_6gqJLEn -XПP62wZ*+vFAY52쌱 fohB3, +E¨oc+ޥ8"P bd\GY͗ymę;M O1 Rf.kVG dKuɍRn. #ƙE? *_cKj11L P Ĉt:C[4)4`nQ`pXQ2)\`8jI<(/7P^@H^N @7G#r#w/8󀻊Ξ@ ~B $ApV:iV&U9rkK[fڶXc-@궺Nә~ضn!դ xZ8b~` cSƎh0 rSֿ氒#XV˺#rVg&i"btj5D h1Ǽ[lFzJ51=a*H_Ʈ2q~Ne@(TѴ\-E}I3f(=6*ǩLcctieZmƿ* DtY09JC [2r2'ASe7u'pR'==X `e/&m;%0]Vc\MGV Roue?;:jAT5C]#?ƎJQ~>xC0YD GgL8**?Esy]W[F1C5'MWk&d9.{/ĺ؍nI~PAef 6ޤaI& _gڻrJ݇'+o\EZ@W3̜Lu\cӇ_,=Eeu$pl6ҕ,Ym]WLv]oIqJg:{78Ce',D:^K1t M3:`d+0, L}]hYKVbOKu3"y̔B3n;U!Ms9N"׀<'`'E8 phNvU\Z\ΘqAѼ{tXN6h!|qwJUq؀l`@>jf-a?|,`_ ;w9.NGu|}uc(zł !xVpNwA{;E;e f`-e8tu;>8O>|~Q4-Z˂. __쩿=Xg:JvCl0Lr5թPSJ23,G{:85>?[0zɮO:h4Q3an)Ҥa92M,􊽐ei) P~{tv|'QX;OHn5{~ U u..%E/"TXY;mxk#?nE-["h,>OT|!GKio/NrxyW%M|neyq -%bVwEsk&>Λ'BT9ɵ_Y44"FvK!SȍJʙgNKm3Bi ZH[ 6,2 8Iꇍ %y<`DH84ق ~QuF:?*0̂|X5X2~^[JgڌO){C+ّA4Q)|qqY/Y efbV?*@?fWvUŧ>EڡIdc7[;jGftrػvJ%ǹ.6DIPq~W8o)J==S/!\YfL`O.xef R5 &E-7U0^@mlL'\S-.KV,D9_>?Eđqr]B8{55ngs)o Ú[/_6qgGV~XOЧIѩ8K/#˾RkKTf$:O`׎'نJ.o4 ?o?rNj8ojtaerP4ŀ}=,8J8, g{P+)Cץ3Z[D1D@zЌ6"ab< :mF/\혈2F)AY/ZX>*/Q홚YO 8XbQU#8V+!֧q\߰M}ĵi,FMՎKcTٟeǰTzw`s]SQ=אXd5g E>$b扂KLm2{fo(8A7!--&XsbH/|mdNH!1<KO^}RA<.("weF sKjb&S* 8\XDFBͥ͊\DNȶpow{?V(\ Cc?SM.눇hJ\;ew@kn=m#ڳ ^S?44PcC>6j.=O8K<|dIS&R[(OJZQlL9CE 'cy2'(%Fy3BڡCfdD$}.X0LGR zyj$]Y/yыəi8HoYWjՕ};!?^,bթV e9uv@M.MWJZSk IfC8KBFpjޛ 3?IT~mӔT(g͡$ҶYA p#88v$՝eD{ڌWr]Wm2(pNKRkp'9C@(Two)d}mE(38I 26IDЧz0U;vl1 uJuJ"n ZͯiNeyP*0PƹM_u{/EIO>2M' g00s|,]a<1~FւLe}c' ].w,F5J3ܚ ?3Cÿn ?V*d&@&}7Abjz @{e >1NK 8BWة!dX"]0W^I9FbEPM+TL#S.eq:1ʺUSAVzB0e 54?gLVaR|Gzܤ %U-,MN-*lr !펣5W#I[~*9|NJM0lYH/KSb/oOP^hGhES==EC[;VLRRGpf_u[>jȁ WHq9tAaaY3Ŝqc>s3hԷť]dbdz ZzAR栏N O*s8) Dgl_s( T3oPc A<%&+}CxlP*d`>>QՕllbT $L~А8W%{W9QܤijN]gLT~ W)-oUK78\Rv 3fh Cj0^$tI"H4z{ɉw>35xU|g<3&^zbrv*o/}Y5~)JIrJ LE@Lx"jhwpAsN׼LlS@iˑ%i8ӱPǓ2i xԨ,/,ꊋaD!YIcI(qs[+bۥ.Ke20 OTf|W] إ$ 9ktL I< DG-,J  ߻{8ߐOLx"Z~>J>;+I*)Ў\NnhI\.'Js gGh 5ne!Iֶ,HiD :LFu3Xd@Bc:SlnCֺ*(,Lk ; v_li 0uPlHMQY0q.9|jZwU t "YMM,kqWDoJlcH .KfHfBl{laHF  ~V؝RZ׆f{F4XH[|b{ 3BnAK;3NOeqG>,C1Βp|.>.Rv_Fl& s _TxE.\#N%1*`Ӄe,].Ơf^/bZД is-o⯩^8ԣ$I298֛7&T[{K F1׽ӝNvyA{at +p `mѪ|Yǁ:WV#]DK i)CVSkZ  )6 u B/a_J.+heA@pM-7UͅZɞ2XWQeR@&=bVLmwzo?n+U[_G:RdEn U2xQ$HN8aD:AZ۴KF px_IL&[߬*$ nPU^ [¬/v-,Q4hV k>g u<*8.Z޽㪘isr V4oQq~|Kw&dPvTBP c8;?:hT=1V-_,TģƝP\ŋ]6LL~AQ mTURmZķFB JL?pg8_mh8i%.&Ie$Y7|&[Qb0e hZʅ86Kjnc֔ 8pK-."űPG[⏡ClatRQ]tь:M=pM0ڨӳN!fRJFm^+IQM=.J,^2ɜ%+Z|P .iŶs[jB?HJ4jMtOT ]0<lH;waSmRZQ%_r i񝇦N%x&FEy@ i;Cb3csc'%*fEG`y$ 6 NjevXc!'pD eq ,_ɁM/'ƍm9[q-GJ2tj:Ue뀤zEv"ψ 'k 0*ԱSq$ˈ7׬sMi;x!,٤VLhC!܃UiU'D'!QspCᕆW4KFytrOЮ0'Ɩ)x?YlZO5ЙkSa9Iá2oS1k$' <-[Kȴ4,Bz6c7˺ata퓣 Tv5E{^QZ2Qx{>\t<{ܼybW~K=<<lnþZ!d !] )>&#)k>|TP oǶy I&짿h9-bϷvi!}^l5)ď*7g.,Y6aM<:kq Ŷr'tEh,5Bɋ6-10X!nY)2(h+~aS;%2-nS#$XΣ6/2%ko5 f&y_?x"l֪عB@B@6/ugKէ8-a<ۑ Ep/rHH* ȁVd`WW7Tp -LW(]O47Nw&iЇƫEaD_bDIt Zq`wCy09 PH@{%̠gW)(;xi.l<H⑺ֽfuFX01?|cpq0_+Ge敃l3]HClC8h;A XăJI !7M2VsCc-''Mf2J@,٘fX"$`RqlG;~l,RNsmT)%T&p&W!CZWZh6>Dt9L,8X˿PQ?e-OS5:z<80MsˍSTig_ۉD !`x6H@42X¥%TO\Z&=8̧[|oC)6V(sҎA?oѺ͸^;pK„$6X̟oyP;LJG$V$Vh}ox.DžQű}߷ H "5FvOh%pz>?!+Uuה-TۉBtW]"YT ]5J-,7zNtF1uSeK ydn6 6]O/\4 zQi=F﷖󩈔 K_7qsaVO4J6^쎧~}~mGy ujE`13SKb_ F_RI w8ғ!]SY‡?k$$RNꐖop3R2ݷBRyk"X[oj5e'h5/m-^$Xu^ QM\8\3|Ǵ,. *ɱ[痚QjRe4kX`<>L/R\"ґeEm 3f $o#Q@IDATX8 K8+SF}AAF[DqYe0*E} 'g|)I{Tdk}F /cPy w GrV$r,:8Q.XafRu='wqxy{( ֲ&c֞t 4ց>ZzeSF MFؿa#Wj$TZ v7uE+ȼ*$1} m6yNnӧvw}{]jYQf)64A4MdB&s[5FjT~@rw'PyϵZ;W%B_9^vߵ'!kq$;ܝǿӷѽKuú3|ٷ@pt15#) edq?&E=¬wo[|n\=R=# Hr/R܃pnXB٠3dUb!DBOq j }M/pz^0U,%g`~j*E~F0tiބ<M( 2WGj % zZrQe̴)V@ $ Hfx/kdF5F96| }~"gG5:\ONf*ϒzHdRQU>άjAkd mȈ ]Tr$M: 4O UO&: mt\ A]i5j$|I 4AbB3TyolfLvhOl.7;f}4100 hOzʘxLmYpn8Mpiةi&[S,F%*vhsS)qOt 7C& .)zuLrzQKvb7 VvڅW]MaM[J@ b{Z> ^5Sv#ËT 7rl)Gbe,D G?<SCZk`1uqf83U@U?v0,*j0ȱ)E5,='C t*A<+`ExY !ׇ}sf^h"u8ڠ8S@cCte0|WYfߏ=UwŇjy !upeЋ~u:\" uc^=>[5gIXt,7vIé`VEt5Cw\&cTu o׏ۼ o|tP#Ih.4S؏Qps̭I>!zHކ?H/L`/mR$ 6;;BSSi 3(1TqMda8?mg,쏤Rc29(6bgYEnq-ΜQ5RAt1@*I0i,6ק9qң5tPhS!3Ps:y!HIQdoz OHluaL.2"q'iG"zPopCJ95H '@>עctۤ;+P9 tЊboO>bXV?iYj hh\];,`8Hb Blh =xT(4+Sfd<01w(aEj5p+Pżу2} ϏbE}rc&qXJaxjY zQ.9PuNgRTbJ!<֐0(8~?[63#qH2A%iBI~e1L v;WD$rc$iflOff2|)Bu(;p! ӈiyՇc$8'wO7H:^+P* [y9p8lAIcDŽXKir(6N^³EI@<DjY 5tSJrP&s`qcQƓ Z> ljbr9p8-SFEkOҰQjC5Tib|8rI{%wЍHј5VTO-cX(.=si >u{V3<+Ӎ'@}7@vGzE.>G]1tסh 8ӝqxo߇W6FWkAylA,PW0hV0߸1bț)8k &~?i5fDϟg0Pg2#^ުx C|B4l jS;@ 66G'E4B.(%G28QOm;y+?=x;/?j^>>I1",G1| jk.C*7˽z+),7'-zs l|܊U6/H6ऄ)212O=0r LsrFz&ID<XVА3AѓҘu< {ͺ暪.B 34-/,2OPL4 fuC4Zc ~!m $85%C0K85%iw\pxWgti`A?( LIĹY(UvMc)R/P(B)\c=ͭQ *!Z5 57 X+VrCa^ !;I/bJZ#/L8N$ N75]dCu Ieu͈R"2.i#R,jƵ\Bfg2}r8~_ aPESf9xR[q26;)pMÈ"ɊΓj%ıC<r1[H6@ژL=HCU-DpO)m4+֗pj?UcT(4]E5`~p& fL-o]8ka;9 ut!y`7z\d: Ȋ YzQM{*ᨴH.;[SQ/Of{پ'&w=Oꔁov7J\R3A𰡦56.K jRa*UqCCt[ަ+Rnk{okC>Jup y~#==񴣬t(x*x%!`B@|i\ӅVhLs 0NL~DurE論>6&k2\*#39XMi06E~y|-(M>-Kv;ٓ͌iN@berx *O܇ƈ'*k-{zpKG$3,G,u{h`u}*'S5 舋 -NQ>:=פX"~:lAJMi%q4)F}V2wTiJ̡G(ٞ׿jy[Pqy[q|$qxJ5YIqΩ>})4y$y:)Bsr&6 L[},K;op!:?`}uj0v> {#>E(ZnKF(HB&2Ơs\r2iv+chX~)d?C2GM1 VPk$U4 +遈TBz<$F` JRma$;SNG?Cw\MXu-I?mM`D 5 l),Mbd{e?9,M>vL1<3; 0^MO8I@ 36hx:.c ȅ[Qdب,rk:NdR`c&UpM!7\fe&ȠYxDjJ8 %H\L:o@iʨ (E46dž8z<mN2ݚ`9EYBy`+UhT4Ii3B>c5=DÙ}s8^ԩuW<PM}!*\6#f˛pȴR% 5! , E>bPR﨔a7aJˬ9ΠQ d*gZrCgiao__@M^0=% 4HŢa'ܕNct/Dxb=\dK\D-eV8TP@)M6k4e6^H2"x~\m2Sa{k j r 'FN@W<:a1.3K"hsix)^v j*ϫVNTx2螣nPh4!ljp%g-܂`eL>=}ßAIM&j)Wg霗QgeQ$MZSclj}ŁJuӏ^;=~> Pч R,_|Tr!Ge`I|Xit3gA">%l(_`ݪz/BC^4,:UZ&˳WASD2WNݶijJs!qX$4 &$[|r$e}a ʲ9Eacn-93̯`t[-FpG9?Y |Hmy>A+P뽞 K>pH3X56K8LUcwWJD0tsXm'>D߫v1gIW٣\ϲ"RgOHFӐ9@oWt`ʘ?7TܼhX#=xQj)Ć5iOtgހ_`P/^Qnl5DmQ. 6S[M#|J .Q?( 76̞jD'%z2ZIc=-CBeZq@BG9)a›Av8rT ,Z^$7 (Rqؚ56^t.xA I(HS  L[&" {j[BI?E7[T'g9W7얷~y6JhBTL49kx[HsFҖPyX0€t؀Q;JH76="56 OSS5^dA!07.v o: :Rp{?"-ƀ4Z#=U!/(+xvߞ#%\6GR`U~SA1=%c 7~r&# -{x,NAɲ’+eD%jaX(yq 3J߮,mǜ A9BªQ[ v+?uɱ!Y y}]ΰ$'0co{}%@7x\j{XlY}V,JÎW2'<}[vTJ8rl/*MZUͶz=l:u= bzq?9 +$Ns|F&0vݟcB>% O}6p翷̘WBF2hs3Py1lZ\'$[v׿v%SLmD0$alMqrζٟϧDǓ(fY,iMZn&\HrXG}G=?#H!>$=crW Eڏ_ e,BLOµrrK\#K'҂>wۦtݍ˦ cUB8jb1 1l$7*Hc+j:/v M@{oÆo[g F/NKWDg 4WGunxJ"$`A1Eh#8ZuG|M_Mҡ(JV,e,(́1ًoY FFW~a?ݓ&{HomrZu~r7쟨`B fTx[K`6!:[K,l4JXTS2m\eVz`%kGV:̃SHz/ˮrzza@*k0jXx' #E'NFFݎ^jERTyцuWOS!?tHɕs6p:B͎`g~EѢ:i8i0>4egЃz$n=b8: NH w 0tS_DK#nH7\ʕ;18BCwEp9׆;VvD򴡋 b8J$ @|3;G^rgzl+L Nؒ?Q3v@ 9vi]C֯ahё^OQ^ZXC*W[76DCPOMxbJ{P/"U:3)SLP zJRETd>V Y@UQgHE%ĸtn`#M / FfzSEE@b DZ]2ZrM@Q6KD$-4 '.jC57̝!N Vz Yؖ:WO,9Qne!qf rtx1e4\گ)HR7v$ueHǗ"[rdex#2 pN іnmF _r d9E2΃jD F4 ° iT3Nu!$5yQ1zՐq A ei.Q_p*DZ\PF{-i/4mAC 5;V+ jV> n8{mg7.ٌη_x nU:$sh6n:2b`1KI(:j#Y&P-n+~P;"1$m<!YŸ#*φpR kXw봴`GQo,=J.)3sWhNOI,qMKVДв9lodzZs:l0}a =)}o­ár.EMc1)֡T,du!ndޏrRMWiJ3 3;r YNtLw՜cTgHˈGc@4]#QRQPl;CEaP9q|"TeVWgB~U6^|<\doA9> oCp3[+lLP ޜ[]7w.~ ܙ^r\3XOa" 4SYh~Op > OTq\{C{}I:snKO"@љ"T4R!r|}+h"lw"x=.>TB0ɐ}/4&:;`nols)*@WԂL; W@ -0 Wّ0Ltm;Cqw0 !0!G2C?-)>HՅG,x9}\?lA p;8= ԕ8TmDlKpht0N|p)k8J0BuJfag9k𽓘$Qh~-Qʼn |_00.&R#>ի"aaYg}GV&;(jD#h#VHuhF<*}6vV-ض,Ven> p){@<πgjC&,%M$LUeq¨IWP8bQzvΐ)-԰siKHIOdI 2@ZR֯oۋ jjJNRJҭ$G3S) $lt.oH zIDH\0 j/DƶC)&æ,m=9, '3M粩lR8]gR5K90̑ ` ib߸n,P*X KC_0#:1m8v\,.4U]41Z^wAbl?}ry4ښ1nDk -_esRkۿ[") Ç<(}Po32&M-7I aI4ږE5‡Nq2U*d"F[•cb{J6nC#XLfxk΅hd|hy;: rv$ hD-\IDesxS ;m0 (/z,VH!flfͱ=8)XOYln p'ƌ_ϥ5zq{8Ff apRcRMX!HE  숼mE[v72&Eo#pp@_/w!U8uvE2,*2 Us`;vڱv.mkG;Zmx0cבoO2_f%+!@G|*O(lqp13Jau]V-M>!jY6ilUMښhCCy34{퉸9r-y6Lix4v3)T5чd`K:V~#sB@IBշ宰t|?=agHsv4T j?~jCMN)ȗ5BK~3v=e*}^Y>uŐ38mEj'>%M"L5WY"];iIhbv}o@:ۛS5AsBiHJb5K'FRINb2#"`HO9! ^>LB@#0G S7geآZ ө6 $;lai.ͱ.׋+!Qd#P'鮈08̃IR8kDy7s>-TZ PxUBWм_!Kr6;Hpv-i|BNG\* 1ؙ,)T;S=ː:^8G`?Տh$$m?NN؅\n"V]S%iﷆ;@?T-wUUb~ Xܗf崽d{ 4(۰Hޢh;oVh B@^`$$c&@R΃egHZE:5ֳ-sM@Aq>qeč0WE0jTՔ% 6Bh%"*M)2ʝŝ\F`̎.Hf(NMÂڄKϺuDvdTP `'# hzt ms-<_lXI~CT4`BhG3T1{1%0j_pjJܵ~n晁ڔ{)K~rZm:X5Q`!CUq S}n,Q zu̲].,G_F\Wи%Р";c3 ,("09B\/:۸̉srv }JZW~Ge-m)"&P.z Pƛ*N1^"tA=L̞zeA:\ J9> ?R`@˶F (r܀`cth LøjKOYM?X4%NT's[-f1{g7S0R{>q,h[(8iD y*:4G:0VGu *0eCJDW@`3 F6&'!hqbK52+?ZV_)Ŏd! H nP/c#fܟee]bw c5*Tȟd&i4κtxIB 꾭qD ]Ut 4'ɓA^uHqL$ш$EiBGhηGs=- Kî ''y2Q!{vǬf0׍x÷ƒ.|:Pt-]+geiX厀U7 nC(~mm*h8xQ`zM˖U</ƒDfL4 LC:׬b. !Hր K^{:Wo8KDK^KZP5wiBߒmeR&_Qz/C.sqI**j-73\*ՎQ4*iU?f& m/k4׷6X X*d?yz6^Irm9bWcC{ ݍt(ʁtw 8ժ[!#F=AIDZZ$]H3|"yS;ƉY3dV-Z}[b~6/WV*p]3H@g`ڐ3 6QϞz,611ǒ4#;$Od P^ʐT׭K= R@dѐ0pANHF,vU|/LgR5/0q LX\M%rqO^߾=j5Cǝ6.G!X4xPI*\,Qb%E}uD0\'6JPw?~:}\'3Jߢ:)8:Æ&}L'C!p^VB [ Fvh I1Qɼ6xa~mTT{EJ@vf@9fC("k>nl_!ᗇ6m"\7X Esd*NKIHw>eyD}qMq 0T12P謗OiCRe.&LL@gY\7uƍ ONcT<ۏ# +RWN&?I77|s,rz#`F|)P6֍3cE !61yK"XÒ{~a$:.j dFxϯdb=mΈH$_0e eyr{mr{%W"g{AuV6:c< 쥎R(>qFI1 { rvlbȫ7!ɩg ;?=Q:?}|hu&}2|w" lJx)64pV E2HoKv^MB'=PYn&0ьAL1΢ī :.doO' 63GXW( @FZhW(kX͚&Љפm2.G j1X奾Y0 #G)23 O L  v|jw#´L+T{=391q6HaRW/}&9`)=O1“ƹ_,a1tj.T>C2} DK5hbsfVV0=$R+{(fl#kv}y6apSw77&ۏ~I|f4Ns@Hb&WөadqK7`t/Ǡ Gz0I>Vh.D/d{ۘ)A #e(:ff'f*4¿ [i癵,rZ7k@bY{sI1wo/zõݒ>Vf EF)=|> 1;)‹ 양$->@FԀZNo!Ed@f*,;Jrb:ĻMXA[nE6:KRZˣAN1$mʷё̋v\+cYglv5=ڬO?gr`Ke>1 Q̸yfw@OǭH\:^Sۼъ7QLjRzNmeݼm@oU\Au%sj&&"F-Rgx)擒$j}o%B*d{'Et&mo눂4bQ˜?9-?"Byڄ! +tXܠ\-^_+#Hn2 D?Mn7h1ժp^(;jhQ?v覃ƌ[ bA #vyw<q!i=SqWtgp %pcX;{DѦZm%BZ|o&b[>JH!}icճݕyiU;WpjV$/EhE-ϙ'z!m@o;(du^_Uc&:Kxڟh2۱>X=g5v_?3(Md _T%m .}ŖZi# 4N.ex,Cq.:Esy Mؐ tBIQëxe(q8FeiS~: o*ڛ$8O"_f8s Zh O8^xptY;Xubb=+)oFNaP9N4UDuH p%\"cXG ;'7fC41$LJ` -urAh2v4Zyg4r<3T0>Bsg[cytvaAy/G&%4(l,sSeWfTX\sS'y6 3@~[^Z05hKB\ dک(ov&8iOΖ"i#}^lBus^w~A:%>gj)jko72E00LT"篬6[!;HoRYQ\D- gQ}*(#S&v পDFhԞ1%nuR93mS5i,)Qft0??c3,PpBUk-0Hu?^~tɩ326/ ڰ+ n_H3?K9F&Q =Oр4r(A.nl%Z<s8Fr;$_M@3[Zhc$Y}BXf&: ͻhQxXȡOb7HFKlBunt8[G-o~:Vئ5 z9Zer> !rd7D.Y^_ dMB\Ji˘CΤnߓHJHS8jj9Cnm\.CQ*I<A#} Wφ-R D(!ظU1tD뿬,ņ9] 6.cU(=1 %u`{Yp+Kδ"c8H#>6{s'╘7JbvxbP`N~DdAȏ(F[CZcJ6BnȭL! sY7)fJBaBrj.F lӣ5QtW`& 5:bҸa0MV $A)5UVlܼ "dB3A5x*SC]4GJ:)wA>M i DDFm"ɮІ0#0|;z] ϱI~=Kj*%:d1LzLZBHY껲˻툅k>-rl%YFP3DV~_OoG5L "Í裞/$ˉ6 [:g U ulA[3Fx)@$KP;omiڢE Z9# IA\Ui=~pX'!ftU."[23&}!D$Ix  .uD,ֲoۼ S >kNe G)A` `QVC5"&}R8IԞiht>!Us+t"^&F^46E&o_ "h͗n >::nX+ozY.~ooK%.1VfWݍhLo㹙 K|AOS7zt/QRMKaPh*QCH3 ~'y}HTngQsF%)S$mAuAO(lb<^ՇC@Wߖь*J*6,Q/eZ\P׫8J@bo+!cgGġ < cBZgtU %ytc;N[Ss 3[raʰGfr yIZMN_pқ~EAPK&=%HHz0(+yH袵 ejxo@> xng Aq]lu;\i aakKr%:˼4$arj֨/ d|ku! :A\o`|Ǐo)Q4>B~&?OirQuaSr☞Ey/MuTɽF7=E.bBSUL`n}_#&xWA{ZG*#%EJtGԟ>. ا{Sz[iJp(^Ej'σrFO`#PCQ+~-mrܗ`Wnkؘ2(L$az)RJcP^Tb!Iʀ=M9Y'2"1|Љ2]7dAO>ZT|s8'PQs%qHg*@E֨Y2!wD7`sdf8孺AH )Q54uEM\>aM^4sSPJ lYB+IRci f4uG0":^>,8H59EETL\x֒ ZϤ#߈KGAxvQ,#e:, DS΁N$)H A:ɞMjbYO f?k<GJBHlKk##R:RRQsY s+\#I%*%X2S$f\%BTyf$ajZߗ/ZTۈ$xfʚ!is}?}H7`;V&rX XA7.V#}L섖Lk_͡\39%HFPk²d3q6J :&-2OG~xX8T~5&f]^h(  vMc8 yg+<4HChkK-W:/8un5P Z e&ǎ" l;"*UAvй0yd-z[h:mX* TO6_j8K=;@÷%KԱY_tDQ,F 9F"#F`bFf*Ջ)- O(_칍L6px}M=Nr>7I"# D!:[OR8y|$ IW*l+z#NX~a"{@L<뾕 GZK(B~Eru,fc f(!FU[*錄8Hy)N3/?:_vba"v/^6/Ę7tQ0.ř0PII0+x9 ~gNX1;(*r(SHLh39 ZhXF & (+* xK fruO@nv?l0T$iY5o  Ob@qZW@qWaם^DJ4 ,Qo^BǏsH OgHrvϳ*}F*A|t$زցIP!ŔC/*(j"`0p#b)Èhb1Rhyh!9PO,KWѾQ :/TW dKTՖ a9oҸӟ?CY$kOg%hr_I,eT/4F.G[˽@~NFIk^+6bBzLC i\$$& ^0c\"f Zy/ %LD5'h +\Ld]A7Ն_|$J XIi[8y9XI5Zk4`o~52W,Hlf-3/N\ŒL88Y3-rj8Ɠq M(N첝.? S RڇƗ qIdgV頵ଙrEzf2k 23qoB! Q=nj܎ D:޺7lpU{7Q%5);eOضӵ<:h2D6%5JiEHX> CK݅p>0PhCD/ 2=0@188g@-Ch-.zeHCa@n?ж׸lL , `3hdO#PU-l ;Q! /sr·*_PCXs0Pe j"CkĎ6`j녚$|LZçI KdbH%yA%Zi 9PC,~8WgXS#3# q=a]pK!ƿV{IT9W^a2בHxF4Nk2XE5-|"=4~ _f%cDju E;[-!Z d0*11%ǴޭN kJ?8 +W!MX!UWQ結1&H^NEl fvcB:1";yvn0ׂ}f҃9]*0Hl;xtnNM2jD3FFfӉ=`X%h.OJ \IA\:l9"K+t yn"&pTbMf@!JE K>5!Ȍq7l >b;96j8^)&Hf|3#F¥W tm=b {<)F9EHAOBV`-Cpu|IVRV~De#!Ļi%BĘXؿ~d+Pr2kwQLYUN(qF^ >ovo GN̯GF-CT6XA#eTWA~s "c7V"^-5JQk&E# GI\ÛQ26w89&yT t})bg8YKǻtl ~Tw7G+bo٫I9 T5y5G 11vrMR=_Rv3 <Ycp_F5V HHo(2i(SFoW6~ss0AFB2oB`w`g.ґٜEfA 7&TA?8H72/" l>)hInSkďW_+>+^/xB$/ aEtiHj; Ns4Үa{|R+J^-xz~o8FE*4ӰLz:啈h9a0/v*kh w~acDf;Dj!r8BJQ2}]@M*Mf#`BS}yF=B=-pN 3Cnʲژ9O\rH_2=l>@xkNAOtvzeWMuiǙSb\.LpKg&ʀ(&T\Zzf8x [IU 7\zaLh0T慗Ŭ7iMKFe1 MgV} z`{x"")t"bZN.|;}X=ش] YN#wyQlW/&s>ݴT9oI4 t aU8n+$0 8zeB&krݎ}(+JMǭQG5WsjYd Ur#Xx.mKȡ hB%4LlW_8/E|u̞obݧ }Ud`"e1STBlu6uj@O$|J4(XflD!@"s" kkgޟi(yF^U ֝᫔,HUQV(%&ϕp#K'%SY؈l  ò+,yQ!V`߫Z'O׻ ;T/,zL@ ۵"l?ҶK9fݸy+3)CkN8Qt7\JΌvb0 dzPz&.PI]+>ݞ觵.×jxL 2.lj)Ǜ2ęoRͶDeDO~tIыv\|>lj)>&}>7k Ɣp띖Mr21x?7hcmNhͯ4dԿx.PuBl+ I,? L;8G옅2.",`\Q-ķ$M[v:7~&EB>'.eIdLLofGd˷2~+a/aUBL7lոfX-:(/7 .VvK[;M#w[xfv 8O8own` [,Kmv}^|P!˜V`4n۲uy 17Zh0j4DTdš塅RO'BҾ#spۘ/en-vj#qE>- ǥ|KP̀^ $$%_2@H)[200}0MlU`d0;֏VK$gejHQ!=1x] t mq΃!6zΏιysu:Y&[,\ Vk[ɮ7Ei0Zjb0aXlc^p̴.ӴKd_# o*ś8/4Y-~~y=\kד9.HFjkb(r`0 =Oe_/W{o^+RXT*AQa/s=] }_S }I  P} QL fP*+ؾJ6 f.x)' PCX )X2ۜn!&ke^~D6,ro5l.ЫK-],ABsD(,[xr1^<AˢAÏFO~1K>xB1T4=|L.blj6u!h|aox#2%L RJdmP‡j^*Һ~T<H7/+ Dr`?/ ] ~irMRW0Y+럊*;+ol^ A5iAClᤄ *E^HuRd7$yؐ"# (J+ M*mn7A$VF-OeQAlKi&@y7U`,C)j HRɈmH,hi$(I'b*nGwm0;"&ѻfiL?sͶ/!)CAlϙZFyec{M4g1aX׫ÖQ L?0wZc$ EzQQ-IQ8SM_x&ƤlъqK/Ep H%X@)Lžn3tt[q̓HF"Lg)H M~عMTa{A(D +:& Uk2[eXN>u(ޙAYc2۲܎٦ePetq2{ls1aTeEs'R&udEYE:eh!^S;-Y+)5>Eܾ=Z (r!p^R@4!3`( hQ]σ.7?Q[F 8RFH]e1ʑP+X[DAs:WKބ[Tv$Y/<:E!5pjΠL(nT2@gx:e 9RrTXҬUQG,k`齑u!9)Pݎ1b) a4)-Z?bÂD6?lGXVFEvr~ $_0ǵ -Yµl"77%ȀIo;Om_% u̸y&ykLy21) MS0- s &c3=r{@K(EJ$_uad@#\D YVh՟`lJR!,n 9^T!Oy& e,!K&4(MH -kńGͱO1N(}W"l bA*DՑH:L#1C`c(yy˖@0'a.*ggAD{ lۓ$憁QbBC|L+=.!A>1*sRO~|+ql \v77ȉLFQj#;kTn0F!r$nCK.擮'AT,~b_2/$"SjbtX(]f'M@.A1<>x&P/ڮcciKs*']ݛ !{c1|e BK"Suv0n EFG?3Rd_荹+Nʽ᝛=(VFO]*d~z+>(Ȝ ] y6I\n'í4g!t?izWC% )~Sb |oDX@Y8X^ \!.0%PL'GuK3{>N?a 9V`#"8CiB{IlAf!3  hԏ?_ΕCFN MYpt<" M&QVokN)2Psj0[h*f5%6l94E(OSu$Z~Б!j P-Ķq0:J[:Ra(C3Z奈lI'l1-ҙ5fR]%bSYQ xpmo ɻTГ|`j<(?] k6^j@t Kߘt!vOjd葸c4d&m۫KWDޢ9rFWJ\>q,%p(9f`!ZoM5K3 R$(rΑ͜,0P۟#gxi>gJu J<@2\@0]%R0-uM@Ymf,C%u?+_#Ozny1: t2/L*U(h2{t"=m,'-oI^=޵K1\fsNaI*/JXN@8wB 3s0%9[؈;Mo@;A,F:+0iVFȱvRRդu-@jk^bJ <@9 T;xxa7qB`@Oz2iq%LJŤ?Z|"]hDN $w׵xE'F2qD1DϷYfTL^>2HQ䁑fj*Cu,%(D2Ô}{ޭI(i@%A$Hֿ*huE/)GSӓ3@jMEuB\IJoM+:3a@jGe<}Jl*EUjQUr`KE?gHN[56䌾-)&E[ޘQzz! G(4wn ߱ '(g ʈL.? {{ oMYlz l-ALmpQg xpUreW6\;{a{CzҌRGS(Vӳl?=y";H@s : bA̎}*o+Rf($蜵zģY5. ֜{PjJU QFF)oQ:F jv#ڥW Ao2~͘yW'\{}k! ~Zü? B;ٛ{Z[p @++umlABI8͕g*BWDϑ,~E@ @`Io|3jJ۝̌52ͅYzZrjҠL{PdnP"c(FmEQ 4<*\Z&^Mi@ H3yOwѺii'Yڪa$B pj:u ]cJIcuoͽA$ w`} }7dܲ)HGԽ7,yȪ^k$=/[O4#"g.7&Tm ?Χ waNcMnHuDˋbY$/FʬQװ.L&ۀO"3J1'uƓbE G;:8 H hjhRJ^/"g(ӟL3rmQ-Jaj#\D C˲|@L!.V8aa _!'qШId#n‡L˚t@IDATmOHw#Aw\BNqwD{Qo&Qm!N<#7s  FodАWq8 C=olP*`Ԝ[ּ݊[=, i L+E:Z~s = k*xCQ 4l*" ZW &w!{8ͱ9;Z:+򸂏E]@?7Up{m\nֹ;$f +")'4H@<ĘCyf1(i?yׇmoǎ0;eYj;b#=Ievɨ2P@pFڛbS5z ۚpX\6D^oq{zgCnc =&5NN(#)ֵ@" Fp`붥0̃v2|ˬ1v"gQ\!_Zp$FgprZc8OֽCъ'(2{SjyB&~D,Dfdv-Iî3zA2[9Һ[vLUS|T`q}{ ⥾Z*04t٬,YH j\ؤ7S3ns)(NkU"$z!Mp'˖ƒ}b` IЪ9Ӏlї.,!XCے8*cK{C0 wdm- cV`2e66}5h͔ q2jKO~Lu.=SMaYl1N8 X?.?Ut,M}S xnw6)Z26c!T街&ul}MٛͿV`H]mWsQys3O{|z+Ύ+I)AuBIdWR0^F!ADUEG) D⠹O 5/*VJ( "Ɂxh+ZԪiRSn)@rQ T1<\%>Xaצ_8q R敳+#/zY |E]~6YW,Qz~{=5\ULRКœQF tRUk!-y̪v߾7p#m];cĬ*\? G@bR<Ǖ~1߄.B˙|X-@Uf`Z6-W ?=, }'_f]KMe L7eӖ[ Zy4خV?Gb;kgSXsw,<'/S[ PƢnfy,xqIvu]@8٣ )p$AGvy89Tdpc#[e|׃E8EM-QG$<{ eaj9jgY =!q6O$̛NMM@U}[ ^ ̰9x0ޯ$v #X+7&v:`@jh?1 ]%"tbVAMpL`ٳV,bH ^ؖ))f?` eӥR49זكP͵F_<7yAf c ^-kS7׳~2 )$T|P#mov>sNsaOR+j`ʏӑTOCUQ?Kg;Ydg pD1ʌhإ`.B$&_t ">h/8csyZ|?΍jIg87O U&Bxƺ1ZZn%S,Y?ߕsn!g`p;>A @a4 yߵ.# FBab\WVqWt^IkR3V7LJQ) 'FӲ^H]"x-5ݴƨ@x%`8E35A* `f3i'C.O !ۧ2g龌 8}t|z/5^D͑O3pdH3S26teO&)v532y6aB"ʌDd|] RdKEgZ|UUdT.ʄ`C0㷐 30'oRݠppQjZӋQ7;8DwAU;Mi@md73tu>Ҩ#B^ OrJI]oejIZH̬7*_Q.5>Oٳ>^R\^r'EoA\0X{󗎌qC2.6)!VaW$HAk&G!)?&D8SKVwlϟtqiwbsSuc mVnVW nL,DWΓ{Y*!7Fmة#/͋HiiFXg!K# &ork W7ihاϨD{ QAo! 5F^`SZ@'mwE`׊ `` ܐϤ)< QwLwH)]?1,H}*BzAO&;oEi&47 ͗x"O:OJ$50oԊS\}W͟Q?dD;iS%+ am:?8 xՄ~Yhb&TR1 |Op~ .a3c&w%:I!\5VSE 4 :ou8NOwD'TC:ׇ?Q Qfw&Z,4NJTPJ R&u.5~`rdt,Z=T `Qδ(P2Et!A t&y(SbH )*$bf1e{WN{$-]ҏ)٤ U}cu6zBS-PI$3m46 fIdB C`P \q#TkܺYFAn&p\whqvrE3G?(Luz߸r#P%RI05FDDXڄʆţL>U$srV Իʷd~3w.+l^G5?d(ڶ@>7eC:;Fz#SB6JUѯm`m7A9@W4$:kX6HJ4;9fE8ig?IT 86͍5ZU9*jQR{ -cX:#e )CNC En93SK; 08\@ 3C,& w+({iFI{cETZ3S%7juGzhp]PqVX0)d (_*6(]L+Q(s22]zd}X"a "N”Tg"?6C$eh$gߏل{XD(fB ;FDSՍtQ0`ALi⮼<cUzZ5b"&n"h!M*2 zS&v ^HInVR@]Io*%=.*&E ;za>gg#:&qs8țZ@Җާ?;=ϑAOۚNhA؂ϓh=S僗'f<CPJE@э XT݃},*&@]J=PR-ܹ3 o$~Y=fAP%I5UVV133g27l 1Y+42^/h E  $M b1U z.VUX?9o21!"LL|ABq#y9s`4]J~R?^2LϢfOQ8˔EI\hP:`pC 6RLѮ:$\ k/ !k'SH@x !Zz>m8g\%A'$e(ע2#Q8&ѬQJYYH֏>Y㔭!H:)ES9eQ%ǍifK nP'3b9 #.{ޅ>oA!bt@ȵɺHBu|'q%Vl4+Ftm;D샷 2!G'mxD6`?טWAd)q@cl* QNq'r;9tm}3[Ú\Wd\v 3Fu\vqWeQ@qKnseLTt>=*b=~?XQқėk)b -GxpPAK.ڛp)," ٙl-FfmW&A$8>iRf#H.EHG 8`Q+hȉ!2่G֖@<+)xhY5onv o)A++CREfXc#/iFbvo؛$M`E@{,_EOæ2Sdn|/kԳ\s8FtV$; ZErF gJB\K%^nfx|CrSfNGtY(2> THTt_}bz++P%仍b^mXWp9AMR7?W҃m"nlz]Tv4>_)Bwd.봐4ed;>ktMǝbt#O|JlM>pH]M[;KflV`VeA:lDZHڴ~F4ep\ft]A6{lʁHs;"3 # Uf૕ES lOm-ư׶UzPCc"kQ'0Hl̐>+ F*VXoP2g 6Mii7sW%|xwR k'M &L0q@{h@߉A(YcSty@& .FlX6N!KA}Lefx Hx5U-4M5= mCE/m8Irj-U,gE$"y6 7_J N8qtJ_ 'fNkk8" 91K K3b%,y5EB m" P4rjDڵ"٤[N?_P·$!Q$9 OP](@fyCު'\.r ƸG2;#T`@4I<NBJ1.ȓ֜v+e`i>@xxx:~YJ'l]& "l: "˸WP!M lgX0hj ;8=qUq`+ IaRH"w8"鄡ɉþ AOTTR( Pӄ]h& 'dsAzB ,:;P1S(?^,y8 mAiBddH:\c`ˑP}\VrO;CX7ݬ, Tq2Y u,׵NT~%8S;FJ!2"G5KxdX({ 7M-thHџhjX5QxJqQR"&Vf'~S% L$>6X [X4V oYcFФ{4Ptp2HNQ3iG~h[*Ba  ld@==Z &0PoVg#Y|Q.FD)p2ʨ^B ۈExو"kfbNoD?_k?{"%"~s|oYQOVay"#*ɔnU 5x.dYā%*7ה ȱ1w|瀘mװGfcKWr>1-69&obY)hh/cx1 䅀i$-opw$msUj9gY([|(js|Q1zr^y}7PF^t~ѠXA<#<|cER /"yV4qLRŪ :xxM j Q#]Gɐ@y@Ąv7a, 8VAzYj<`N2@j91*Uzm X5#( <,I.P`^>\R됥JYOeOa ѵ'+./)ؤG ԙЮ@u]s h #V S" ; Gݪ,Dj'"3U.!V"%8m rFV 4BWJ&e+,4c^eG렂[u){B*!ɍ,uD8u!oe9W\J_DVQ1ĖܻZΎ xr\dLH8E Sam9q."s oJX|/}b?2LB6m9*XYx'@$~Pbj==O88:󤱓~`?f Q'd:yLKaBrlG_i,؇#5,U-pcfZ`6ri @ zO @ރұh1 7@wv/tloYЭ[ٲ%> 1r:ף㣣@u ,XǁgM%tpUyS)1'"Ė$E+&/btҧ*ΕŲGCo:^:Gg#ut5~$ڧ`xm}:iQ1b~{Ӄ*&+tS]Q_\\_Evх]MXcye|$ZXQ0b/uBB z;;IU-U+%?SzzũnMi茡'oi,A+=MKTePˇ%"k$ !O-%j7tMLS]ؚ6J7)ol⡉P'9їhĈI2QoDiORg#̋FE1J}E*#T/DYWp­{A$9WW.YWmL0âV?{K`MIP2$C˕EXY*@ٞf} =W;:ֺl˛ewڞ6l?q.nB8>h= E$ 8q`>*OɍƢ#zSRpQC RF>~Ǩ>̏+ A6m5p9ejuEiwwЗux_LiZcJhRVR$ %ur?+N 2G>1 IB$L#Z<,/2abbL_o3 #=%x'0B*IiHwY' b+&]x Vos$ yPHSb0C:t#v0 ?qAΈ#CIVp>E3Y@vw ,'F|ǛwWmdSYT}%C  W!@/D'5~ t::rBMV݌ۿ+eKM@;lq۱}HFfAQDAhxź'=J[;$WO3C CrJ}-4cA DZ 3Fa b%oXڜaLqKOĄYL۳`]>gO MQLN ī-d@O p8osX1|m0}a;e5E@9}pj>BmLpQ^ [0V L59&_lb IT!bpעSoFa5dEiCF vI\;ڞmGA|7ƀ`N.>Wu2QVent*jޞAh"jyj6 5)bnFg @s }6gQ>g1y%PV![lQ5;!&ߕw=Ԙfbvu{_ׯKy\>Eb{ ?БQdJm?ڈ=)VTWɑiC`rűYה5Yzܽ&g/JƩkO6 &1 F 01AsSRl}+ES=jxbw$F7&344 ԷR Z^:FW` KsKٶ#ӷ8 Ct$rVCGq޽اF q8 эMQ @g;7v'PFqKr`n1KDw/Q4?'Vb}1ZF*A")G.%y K;`Q@u1zD?}S@SSVCXgŨ(ЧHlw;FaŜy}scfq÷KBbxn$y|n$ZJcꔱ,}T,6[|_P1.y3X6"JP.]e?Ed ڰ/zv<ܫAnՆ21 \wfs^"BFToo?q\U*Li[!~>|{+U*DqJ+z暋" Lšfp,ǡ6Ar6FWM zY894Y0kêȋW"8tk"="Ԑuq۳DII5-9xq}nK;FM-1-la.|@{=Y]- "ڰ#_ݿI.<< d}|{~6jn[yx~nO橚S)@7+w>.s)h,[ Fh̬:XlW8d ~; B~򡚫{J'2Lya3ă,5qZ(v2aE,o P7;0(+#@2(a.@nFӅHHY֩Ww_%XHD-56: -RiqI Խdzڒxѱt DQ3nWv pssNf<~jPZ!LA jD/R{[ς39ߞ)%s o?0a~Q ]6Ĵ69)!oì&>&bQ _ S5"ULTZ.aY%u/S 6 5fd0 D15 &KPII):|WgNᥢ8 "% ,CPPVj5܈_(QWȒz Jl,0]hPF4w)Uhc%!ln9E,m´U4ޣS=BDEd!*3c8RU?Z672*ģ!mjQ4rluܤňF/lL; o5mwyF EkN W!a x 11ؠ[0tB hJZnFNY=\#F  "P+Ԭ;s?vF82xmlU"̶cR$& }5UpaB;>*e8CС@WlKTea?")ԶqmXFdA5\# ^]=ˀ.]:Sc"tA/qbS?+s2PLƕ4'zD,$|]`O`oiX{=6hQX)BᣖP0W+O&,J;GʢK)p锂ۜ;?l~Ř p4J i8&)Qi@Eԍ͌Z3Ho3r*ZRƫ#nͯMyҪJ hH<2 f"=żOc1 Ȱ*r-(:5Nr=ZF^ݾrgY/<~??0 jyVr1G۵Y'J$e01яH9ԋ{0 tZ!:$R>F- ыa'@>vpn$e?5!P ; ` '_:X4O ݿֹJ~ *C0w>*<;LxH+t)6lȘaF]ڊ߻Yjqns+Tf2J46Kv,ֳgdMYDrI-r\n1+^MmNWY\A曅9*/@>_Oܥڨ~̱yvRQh;Ӡ畃™ :)z^AE0Ĵ MY/HH|C/;*DtE#E@a9RUVYa0@48ތM 9'9d)`ZˣzRU-0=[L*KL[B.a.j&cf>a*z鐃f}Ms(jwQ t~Icu/)1zDJc 6#p' e˴=zIsӏ4x3ODc;6P=8)opd=0 \a[u6@%&`mc#H1xVh33q҅g d,(f(2x%4  X4 h?t 6~\~(7`tST]W;K[/)G}vZiZGiLY02I0ԥ~(4^hp?:k]\јyE3o8'H{DO?NnG |c^DFC>Do'̳riAdQ8@LD9YjZbGI)7}if ,j ]p/Eh[ Y<>oD#U!~IzE#jёW1kѼ4~MM[*H]}. ל,)>lCM65`A,j|8 1- A;0(=1~6Gդbez2R~ġ0CZ$ϖ-f >!m:&[c!iyУ-8rj` diDz$R{˔8:(dX8iK"\ޞߚzb0Ey/yD)l8'*QSNӫYuAZ>BÞ*cLi@j*kT_q!f̦س]>{e_nPm^` ~sICf3ُhi%cu\QS*=CEaM {Cý=nJ$֞cQ,YĭaeZm4O&iQz;ʊLtS{h_yD6{ NhpqsoKZ!P|mB9zT']^9gIg~tT: z6v죳Z4[,Fr5v6C^/)$p".`KYu>Cgr+?Ex^荹 ^L鮱p-ޠ rrâ`3XAV#C51WL7r>#2XYtBSXԍED-q 5ϵӣeV[׊q>C|HģHݗlln(L%lEi 錍4XDG ǒRwI.@Fu ǠUؚaae@y#I=GfiJIMogRn!`\=䞫boB+{ؼ :(|ʢx,dkj Fa}8hBLɜ\My (gq$Pu+t]R!6[DJ!Lr[uBi So?k'^-LB^t)PπMU5T0pÚj(WQ"ao,'TU,5;9vS Ɉ孱/,7 (VwW=/K[zi8z6͖i诸3$~b)v%R1IpekrJ YeHkG%.SU >k{>4d*'SӴ-QMXiFM ~ &CL # EՎ.`03%" (뤸M펥b7!5eFvcЉt*:zz4`8C;SWK!/QkIհܒ]md$tF$gzj~Zp;P=d] . ϔ\F 6Dv2N<]gn繺dC$$u=-x1AlOX@<),L8ff!IwDH2ӯݲLP?!,00ڟ. Mpy  1Y 'ЈlRb÷ م S k-뗋KbVmZ]THīrE']O9:``e،9N!XrQ<ׂmLBF0=ϧ&L8^۽i2:p~l{ph֬&Pb40ɎA+gǿę M]Yl֪p`,v ,晠){8=hawE/XGHb%!fel#C"FF<-#g1[[CXFs4.BFF>2EE\9> 3HW!'1ɺXAl6nWv"^6IGr=UkRXA*|~ʝf`dvRWBԅ0cTX0\w'޶Ne_1)8ߢE`w!^6> XHgϼ<{侦  `.%N2Kͳe-Z/'iwcՉ5G).&3X(p^MonlU|Hs&q*[_^_\'BUA 3iv 1TQ. Y oJ a"ݜ1Q0)kB kՅ~uw[8_r5Dzk7IoN>/㳈QooE[5G^HL9NB uŭb8:{YWX-+0T=x7o nWQ 3ŷQ'Rg$F|AF*|ơ^= he!Vup8 + Ӵ 9FNq6W;mԈ ln +P/h^m#Yy&xGė7! um&cNY%o4 t~|z:qjL PbʄRD㚚R}$p<_zҀU+ Z~||0`D $;sY A$'QpNQ\e>ʱ1 X}3 ng5ߛ_]o~;o/N_'u7cL0IY-G9/?v/[I@_" h ?a֯ R ؛գ)5w^b{@D޾& f,;lC-1l&=ZTȣJ鐟޻2fyX4tgN Fc 0J/i/v_-qx7^p|o ud7 VX"#'߳n~4 4VmBnMv=7߽2`Ĩ\p'̗oO4o8Zn||8 ҏ(SpQ:@\yyX@zEhWh'aҕu4Hb`ȣi\u|$=kimN͹O57 {NY&B,&{ ̒@h.?I&DṴp_ UK1pɞT 8BIblxQ,ߌ\C>tY(cu7^w.EȆ.jҥ%894P5'wA/DZjI# &6[' nG &]5}B!^BM)vA7W6l˥}"hvS x Էb zUjR8hJ%mpe&IDdh>Ōn5 D'JJЪ+YhQTg kn&]0` 1-ZGإ Z9$ʪ\ H*AdI=ˆ>sEYt\"g/!\Vi0%M!y^u+i>ͷ QVi]-n\# 5k2Sh6Z#'z '= hadgQC* a3#P0$1f)f޵iItL:HY2d_>5UYٽuTF0%4[3"~f&rjtI$Ɨ)xc$63N<3gHA!.Jh^>ŅO f? <1zĄ>ɈxU Jjk_FD)Gh$R>UtVMIvA뛍ejRf^BF_~<4 h tB+bP!S:uYXe lDBb-7U,i!9܍|m`3K>, !nÿ#y\'@gcO1ja!VWHs0.ݓVv\4 \c?{#%Y5=vsC}m9 x%i|Hԕvqv)bM{^P kAvtߎ@u۸MF yd*B>5S5U%RG o]xsiO7q\e%Ӊw}j)(EO'#a}y݄̚WZ +?^&5QuCCP!Ϊ0}xzF)GLAѽtܵ5.;T/Ljb=0rYpL䰃A34˝zNDGhb ': 3fjb6N@Tj;Ti >OTHgJp$ vIq,=9GD"V.2j=.j Аlɻg JCkprRW~Pi/Ё@U/Ur'OdV$3Mc/T} Ա|}.I$U1C#E::5KV0?\w~vxd@1@ѦH\蘅`ɞ`?ofCvq= T5k<ڢu)((SL~Cks],[Sws}nb$. ]@Zؕd~E2 K%KЧsU@_.ʊ~ִ0;0Pɸ)ⰴ!fqp_ٓ9暤gNl ԦviSe 9r؃H#K9d ኍw@SO P(]^^.ӈEDO3`_4di]qPVXӝd?FBm,zkYbX-! mdפf; d2m'LVՠZΑ,`f׫ $Jm(c1d(u!n-aH |1 b!#ۯԏt D"Fշȩ]]XH-9:RSg0:x2|<8.f0ZcRȗԩM *S>Nlozrȕě OqWsR~f4/'z@ryތR+W=m@ 􉫒U@K$BJN7y$o?[5Έ CYiTEAV0zk8^ T~pSnGh5冪(0`ˣQ$jr/bXCV7#fTe{&uj(L~b ?x"|hN`+B})3:A*-Stң)'|vq@ E唚}=vaRtf_KC"mO.bF> G+}|1R,e腴*H,$) ":_d 3ǡ}s#4rhIY L.~xt#z kL <ÚlU4"vlNO?2F*Ҕ%ac[B=ellB$C8{32NӉ^Q´A_HŢ>u umDO3sX, /a^Φ~xi}G-\$6]%*ł(Y#DNz>8N$T6feJtj!!;t Q(Ǝ4{\W16n!%ЪsTC5{tJXA6'ŹJ m'W}*:"_[3|JT\SOHTkT% 5l5R8\t~"^J Q5 gW-qftjaDa"N6d}fdAS۵J=w fs?qmW^Z5<֠, &4!QCt[ӉFSKi~Ռ-`Tx-wUKb&$,YK )\W9_#]K_m. 4"Ղ&l$ZSnVںT>Eq1g.65UmbwS&,51.Q@Ǜhe$ EP8:5e] ,p"|yIs4~h~ϧEְAc. i3kiPo5YL:[L)ow$0t]%?@,#EB;Ӳj[1$4 +0aXm^aۛ $  ٲС2uZKaX]5*HEt'c"66 f^"g*57x;actO mHA,{s>XL(l*֦MG&k6dAk.fgOLFXgڬ.+x[?aImWFk^* NdNGX9顿9@ȝrl F!_%ꃻ806|A*m zl1S{TZBTōR-ӓ9|)zJKn Ď\ylY$w֔%q,"\=FP_62x S0#l\ )x07N*Pb[f81'n@ W`l|BQϘ&SvZp/Z)g-O M ֕m;]luY j:'kUQ}wJ.M5DD2_2fy`V6}~ˍ27uw/x4,8[v:=1n:>:F!sGA pGq-\?Ӄ?YؔQghFu 9OXpBB8�Gz*\ MQQ=$NIYi~@0 ~ HgW@SO"33p!>{cLhuG]Gf9x܉:i*[&oٺ)}u2k3eց gЍUifG{" [klV}Ya@ǟ" c[1ŭ̼)Vh*4PD LA6&huiW| }Is~><43!L-&$@޺ˏ.%7i&K_Lq83W;y U>7 13?0u"RHЭz(&jy&B~{.t<o?(zߟ=ݺ.,qeaR+H=Mi]D G-Jm.-Wt~uEH!#דPl0VYJa8ɚ CqWm xysEm)jLohjT$@?9 gu8!N7:HEkEN&(VVc7y[jD%Gtc/vfp$̤3Tsm ';ز!4DwxtLE;O\IғtdQJ|./ 6'0$tb/Pڙ7"A)nJMJ;6dC3*F,=oi$Siڦ 2o_K鲩e3 T)4cM~:ָӅVOF3z(7$۴MvNPvx$@MTg", j+ne}DU=m>6}>SҋQǵr)cGVqeq6A sIU6#܌m¢m;1^4&/iGT4%HEeʼn)(z;\U߭a/*aAPORVe",Z $& /㝲|fՐ)j>qdk$'HHӶ_"[X$L.pBeOjO[pl.*U=e")YxV h;An,y YY6@NfmA&3uVe;I$F=t'=pûxvcX},BEZ ^MZ\ )/j%qge鏙 \Ÿ?V&#MHq?gHs2)j8pflWEU#eR޲V;cM`:,gHfCLhJh36lYaߜ)qEY EQiSv*4: b d3z bHa?,\wޒVR-5j2sΝΓzNɮY @ (YFjBla]>nW/ 2sYŕ)N 0̭3cTT'FDaO{L~1iq#I|jէUxV At8Tij<2kynedܥ͈LMV% Cr6  6&;Ld `a{sP329&mnhqN7GA#\%6~Qho3LM*ީIҐ*$m"W_I &3 i/ZOk7cqm#F)]@ w"dcseqf!Y6ۘVS.0FnoI-)s9PȻR8Ʊtœa90'<]x(\KcVFg 2Uݩt/ DXQeyH"kUvY9ԃ3Km&o7'C'TDX%jR;Nb_՜ txЋ &4'>Fwcq&6w,6!zyR*5]o[q9.#~2UAiLvHv^!a)Z-0!j#Y\)hhd"ƨ0 XԴG$q[IL' '<dX}* 4=I,GZd ̽  s3͑U-`2@PJv49|ɱωi߮T{!_7kfʎ!/s\L8̯Z:Zc4!N6G0eV!8o G'q@<+L6RrJns3Is_S$Hdv.#7тzeW f*ʫX$ Rɯ7YEC^qVEYY6G?S_BA= 7ׇzvV]`x&Ŕ'+paQ`6B6_b F#hgW;(J csbZ Ey;^T#2%/ 5+|1xB= GܜU?^g!aak6&]%#_KiDȡL1, iF -:QcĽ)~ h`q޷gh\JÈe1i(zyB ?%*`KuOO+FDKZ&O{\A uY=JH|W !x&$ׅ,dz`@FsK<)9-9%'4 ?2\K?!,*/em>Nso7oca#B-Mai4>5=x6є6댹G9CdQ mNШo W V!eaQn\"@31AtPA_Wd؅yF̝v7yd@\ K4|o?A̯FcR@d]=Z$ߴ d°_A̠S#LfƧ@||.iNҴ< )q$q< &q4vj(Kh̡(`k)m$U,Fg{ADk(!'e6G/x=[WZX¸!RB26!6BfRD(R 5(qTYzѲP[!r%Da祔:70טOhwwd,mAE{c|7!8ui'{#ݪTiF~?4g٭S{@ wLlB2E'mHQ4|R# 3-pYLٿg1,`xd($(5p򚯼LT<])ƍYM4mv<J$Z.ALl|\P$JBWn=ǐB .-2(A8xLz 4fSb̀th]FKGE/AA`V2=gx5,WF8_'gTzl#.n | kr/F 1d zw!!o; SxRuwj<~`n.U6hG8 g;SGB3htE-%юee\ΠtԶPv7Qe9ϥ}*-3r􋔆48?1Ebu>D8<H7aGn.‘YKiMO=Pr<&7Hc}Տ1@2^/Lʈȟ4+u>d.[5S2Lؼ֫]lf+?xiI>CGTa_.Td$1__:s:,|w lQ~L%1C#l,l|.2,*30HtLY bA~VN$d?3',} 3lB*ݨ~쎣!ĸROWt1"bJr:] ⭰&E񳐠GHezа$|џXV_fLLATX5n*㰜\e mk$2Sw4λCBf&y)pfpP RÌfXjrCϛa4@ ^@LBXH=v1xN"\V 4%et+UQaUzyObb~BM=y>-tkʟ@`s:3>߿nEi؄)̃}6a&ѵ .yLjk?|NE'=g w o%AI'Բ}hU"!6p}`h>iV60=,# 'H*H$#ϺpRr۵][5je?,`%o3]9YjR&kk”f>&TY7^D!3қ`ħ_):G"^oUXJwG .V#۰^"camW|« ~AO&:VT#%H܄:(=@UVv\|G[ "+Tҧ@U`?)}W<~~["awItiSI8twRFb]P?t:Sm `5.2!cy\8TMՈƲ!;CTN41[^T:vdI' *R*qybW!vz3EhCG|LpLM(~3 " 'dї.w-}SD-TYNϢlrcd!nJTjF\ dOِLК$O IU~9wze@C#gFt8h8Wt/adxF, ]״q>Һ=xG XQF{3b SڤMd⠆P7(:_?]>\v"i *4Ij9ݹfB]KHz7FǐiRg3%Tؓ5O,4>MÓf/zJ1D(;bz+D]Lv-L)jDQGCJ'$Xjޅ7:q"/[-"LG8%0eVwA1X8 oWC-Z~<>-]ؕldhN<-#@7.gJE_Fwr _lk3}oy1l@8Kdd`EeKƢ" -r~܉8 L7,ESBX<AOfuZ\7tj/M̓jl x?X;c2'-cdYP-$mA̱Ib07$c}79XEEz3;IqʐÔ܎ <]D%,8jUۂsIXϽ2~ _z2v[o&ĦVOBGMY!FyhгeO_Z+F[>._mkZY$BBwZ!)^,gC+ĆQ-on֏wscD5ܓcc42sL6kI0"koSZ! @{ۿQL.̟vW% :AYYlpXl4wv?F|eS%;2Xiu '=?ƛ།~8zPb%'q=bn R4OF}1ѽ8@ ;gs' _m14C<LbCZ?hfkzDV TF#|摜 UZ%y(q gHh}P̍BPr6}qer="91E/E n<O*NC}P*U-Mlco@Bz)106w ;g#Y"*5di[$У~al<^+Yh]8({#zWOMj"?6B́0p;y;ں:[SYn6̿˯ϖR>-?rQ Z}MeD茻#IJBodܮ@[#CsYӴ5}10LJ˻2Vu.[. P\<ۿi6pinu$Gc gi?MYϺ̔İ $ cNaI* &qVB П3@P*o֡yj FfD?ֱD9! bY[y&TH9ce ,ANul[mqsZ$B̭ )7 Spt,VɬrkN'dVFȟt42gC``b{R{J tיf+oc;ıT=sI{6gM}P 4AbGq8al>T'QPSkXraRіxY ?a$- bo6!n{"ɛ^׋+gD؃L$ڢlXZmȍ1&Cs4dNM~8f~BIXhU|+n+JWΪ@͆yV>1Бv0H⸔7ޮ?0ʖyejOϫ 5BɵYV3qi ~5 xk R^|( 1 nߟȅ1Pqs>nG~p X[DT;ZK-µhX =ޝoy<Iٰq%×[G.3)+D9bAe;[-M)\F'ahD8N,)}AqMˤF0<9Dl y }mn*faByǖ9IzP=^3 m'3XNk‰;u_9* ?Pq}0Biq`TQ(D%*$rD_ @V[ ?Q<!]!+&)!g۴H> w2ҷO᫱0TL73_#rZsA$TfN(̋p֩NJH-zJ! zd) MOf;pUqJ`g j+,Ҹ)FSص[jgBq iYH%m̙ld|*$%SY͑Y VMpG[M6*le!nge6WfAPJQA53! Pu{ȃ M'n:v{J Q7<ߏzi%:2j)"kb;ͳ_Kљ+A^26% !^Luffx)1&i-R̭2RV!.jvjds۝ szl-]mÓ1U b}{ _l6")d&/?ގ{حFy3W;,+gb?c^Ţ+u%YYS,T'A|lJ~* &AH M"Rf7Mȷݾ yW΂AM +*X>I^*(?4Ƚg,W6) E2ΉZ!Jz >:$JWN"腁83kYk)x%E^*uMyݠ`<$ </8#i=/ċNh1"\:RФN1gCR]!Д ufb=8|(J \yDܜWa6{O+?T^V<97Cf9$kt]D`j9Q I!}o/' mʟU RDr`l')􉘄XgFq|>sV[ ;~!ZR(kJg/ffL#9Hkczr)Rq$M4B耯W]3Sw%Ө snkuR *ڲ^k]7ȅk O] !jF/IM*9 *+lYyvSGp&UY^[LxRķ6)FuG郂3/A5zLʁ!M24KZWj{t+P_3Ӌe|LmYkiX83%s,|S*KY\KbPLpUI<`mw;~Yg,d~7Б`5.OJ 8RNRryJ9?WJk4{3֏}U<M@UxG䥇#n$5]2ȕ$lsS&4₨y~G(~kny-{@A#}eͣJd.8 iwpJގ8tk=HuFcyԹmugq֧9 ?5= @$ahd:p"/3#^žB̋bnURC(@)~-JBԩ͆JxRXAq]&$ϫ7^o%#rLZy-̦ES`=hjD=𢡊yg6eHTHɃgT2 ? 5ZLZחU01Zp4 cNC$]Sn}6B=e濼2 Y%Pj1zjUv̮tB~5LD`v|~~Wbkm1SޮӺYiOXz[Zch4:6%Gɀ?L^jD9bБP%_?$k;6TWUnvYr+tKBjaEel ]dֹ&<3qZM|)wȸىYqۙfN. NR,'M*cM7O]fAo$ &/>C yHt$Ky&rD)X ªfMan~72ZQ}[Ez^zDgC:<inj_є D©Vn'zF$~IC}e^7J>4 jY Ґ^Ru!ghoܞ_7ןݐ)R,6,̔pYS-MhAam,=lA0us. ?#H#O! 3YTt/L?ӊN&IEF A}sBnm 6$j?[@U|]njFyOV.lh?`\ɉK(Y'> +c`oL]8x16$[+KӢn̞+$2uQ^a ܚ&w2"ΐ %GD213}ؒN5ibAu0f@)|ȫD֕tP =$!,6UXǥrHv*4Px"SxRC e`kt`7ю mPWߞ|~B\jôa 1~qOo]Ѭg=ki) 'P(32߫1a 4/`wW~z!D@EnR 4_>-=1صK͘a{Vl&smƚ+r@ ryu'd26n,VOUX+SA ! |O s̏]-RbQJQx0gQx `)q3&uƴK!z3h EU͋CaZ,Lw*Xu4Pa9Dݦ~1Hhe$)▷'F baI6E9m"!L#Mld*ZA '~qGQ ڝ(s0MRv &0s 3F(yS0 } 7 #J$Mzb xk@q@'tJIKR*>vl ~dQ0аdM|mdcIWl鬑 Zz |7S #a k[jjeV'~i_?`eItCbwf4>9#jkc{U$v/v+4H$MeHe5ODR =:s/9eo8"<=3u ^< <'7(f҂1aф;sBkk%Cvfǘ Z(KkQσXИ؅L,o57Ϳ?ԏYR5&ET::cUV}( 'Lr'N]l~d+ū3#%دX!I`zRn?R?[@ UsGI6b漦;SG`Pt"!Zԁ"9>_fyO+7LjS,. 8f6#P:+"k8 ͐pXvxx'5fYQL񠙼#|x#; yjZ @hSzApbU'XLjt::Xx5ڰ(xJNIӯWUq\ky/.Ko2mC:[2ߤ9^G{Rwmk1Sfiަ}PMD}ϖ?޹NyѪsC\7lQ*_>l@Q|j#s딁'( HOnӎ˘[2,;*ŸXQ-䏢(% Sb@3cMƙeEgOf])T=h,xgaUb+hGIjkɄgL6Zp?xR订np<1/?TIVGCtte$8|Ӳ{s<_Mϛ=7~$J[= ,Dy4'<(m@۞$gypc#+깂X1P*fM =dkK-zG2V(WubELiu,I R^ȾOBƀk~G T*em!4?m:DDSRƖrS1[Z铔k/d3'`c+4hlwXn'U>9@8KӅitHZnfEggX]S&O&O;D8XDh~R`S$B]XU(S qY?bM T"0F)DK?>meWQ՗0o89LS~,jhV\lAGAo V@нjFA$Krc%҄tU5t5WXI{~( 4Qԗ;r |'sX3XvnOV528:LCYLfSM2vZh6.Z,G3Q^Hk -{v2ve-F5/署I ?5;}KHA#B ^W:Q@'ި/1]?80Ã!XU L+f8EtY?õl dB46$,Dvg?lLH,- O6(1#.l!bTr&,W3Yd_>( yZaױ¿Ona2,D*|fL'k;j4390c3"DpZ(AQB#i8ex]y-bxT3N.cH(rSh*α!%64 ' #DF%aNQQ^!C\pdĥ=(1 \ˏ;!fֲ4la8I+\=  (8\>E*sA#z!v>3U¸[eifXRf(CPI1cbl2}90t9n4_mN%RFa2PM1` FXLX2c9BA+MBFoL◢zFؒz``@'NWikrm7CRQDNȕ+xDeufoŝ)&~ -`X6a$[ؽ~7ra`C1|ጕ6$9:"t$*>Y 04M&J~jZ@I{@Kus#sVDp}*X"( tjjk`1O0@bb\!f. MOXDd &v<[oM$SeV>HCTuPM$Xyʙ$NJzhQB)#MnvJ-E{ ^rZm5QOG헡5 90 qH&O/8+PKw%pn]hq^:9YHoe@LQ"Kc?2hɯGbW/ff| Wzrv$[)y?Ax%/H;K19kF xДE<! 3sx\ B`f==͆!LdLEQin1*3ͭ=^KY-,m(t76QGs^CS +:/+*Qw' KHʏO.Z?O4ʋɕI=ϙ"D}h?}1” k>|p6{1X=ҮjKuPQ\ `Hw#~o9f&*&Az4bW<'. Z09 70Y>tNeq?!<,On[ !geHH,i EnXc P-'ey~뛽a&J0v)3κLݣw0gf4%S#'mst&KYD#YZpJ@bl?&Pf 8x:YO sBJ7@m^z uhhdg _os^ 6`Ma~1pqb HQjs+Р_\ւ\j,PeGe7>n#˜0-br7K !P6uwZ~#z|xau` i#7h?&"LҖS2H)v[=C3&POmقNWTaˡ\P-(M]>-i㿱) {Ľڣ"! p,#}˖\K E- C$%nQ)cQve5̊cLMWÀ_͂Am+@!ej-&`9oĻ*_F(RfeEmRjo4G0ą %4d+ENnފqnx%F(D/TF|جrH0F9HN6UQ}.[{%kE0ơ|`w a, X.OlbgWG { hTinf1V 74y~~jSΡǂYrgtV 3uj]<3c)Qw0u12{2URM*3Z40DYɻ\I '7/ *>2ElkScڰ #\ ͏^F-{GL5Qv:PE lѕunv_o7!0|FgD:Ymɽ:IFHd[bQ"MVBGCR+*'j(~XR4ZEvˆ` rʇa^St͈?jEzm]1pzh/2xuDž(xkvh 0X˩P@5 )J$w0v# wAsQ_I\sG UE qֺ⑋Z0||NUɳT3A0{@*>(^,aK|O˚۾Ѵ\hX3kEu?m6o/4IcOFjp3/pxڂ}<Ԧ2ZeNԫwF8Mk#ܱ/:c}"z$Au|kqEbtpVned,嚴U0!*/˧eыi@HrLJbz>Ԍ&oR*WL{^aYm R*+Xv)$OYa6ӄ1E,z=ͯWĂ1Ux^{*E=qpqoWןBy ![rLUa ڪXԊl)])o"J?%5 ߍ$őfw% 2F;̬a#08\0)^瀅$~>4 ar8lqQkQOCƐ^?Q P*Qe >[|=+ l-!d! B(Hx.'?WL;W>4N!Z pmf572(t+x)qaΗf-!A6($ɎI ( W"ScuxؗSj ¨Ã{!fj%˃&\nC"|_2 `wwL=b!M{)-J>2Z? (L#:B1G$ܫ0cқs 32ؤrpM3ͺ MTpB+ Y<aF>V\Ҕ~3ΈFz88Ul'-^ tEZq&Kb z-'Q dB^KLrf2NSLG6zH>XuşVkP&c4{]lۜPNk"m2\3>LeOÓ (or͔#"yh(I9Yى1-tPr!T]T .!L MlI:i2: \,wFoÖ41kc@eךNd# ͈/Per)zvS B gLyDC)ވr6aq ɵ@>ԮI'@uZ'@{7 < hyHZi {?yTk`fכu@I!KW&$ߪļ&.4[D6Dr>~v1;V͋~b1$岽A@|k~Y~_OHnThX+ԘX很D\7K~& cBoJ.A?q-1UDE `~ "6 +c8TǪ v],Uړdz-RZP)_VYQ J5G@ OGAHz&4}AXᄽFa+2ֶ_H_!:=b0木 ad\eSX^ĈPD3/9˲ j, 7Fl$B˯72e&QCA=Ɇ|d,%- QӣM'\x8r4^P肼?>7ŲvD a,74XV˶8#x!cG61b+c#3AŃ'J+qH4{:! p 2u^ѐ zT* ]dM7[hBTD^3M~aFr!#t`z$E"xL&jQӻVxaO{{]k\d}\ՉVwEB@*Ě =eѻq E ҍIں,T*Y f$( T7-^BZ{F7^DskE sK6'bIm \Q]s&rrc>PhiYoȣL?*Zcq򄛍 X'pGp⍯C%WG2(сjSa"ȔdMeE7-uE6!RBp'>p?,wWع5'P'$(Shum?^ c:NR]jǢ8JmQy0 #L(: .CKFms桋*@(!Y֊ӳwRTH֥NjB0ftR@5|$3݂W`.xua{^ÖmJ}gb.["";KC5&n8F&ž|3$^oL%x%ǬZEð) К!,2Wa?5_샅FH6v1){@ƀ9n V0 CRuWf}5 %0S@Q%J x16uRcUwl ߽MdVY\鼘>}+Ck!QE2aĵz (_$l2| "$qc(KyC~%K%j3DZLT;te=G1u캢Zvvq}}o} RC.AR/MNPrٲir–ֹ7CP@TsF) 0(׻;մ`$SV9R&֤/ZZܔDos1q]@q==(x'y2rFb+WBV妙_}jsu,%A2!LH?)Y3`{_OQN1@IDAT+ӏA;Q):#Ru8oLR5 VhQ=6@tP&YV6Ο@ط'`% M|3I&ې *ETR<$1r@FX́ȭ}sXr+vUJm41Z0LOeO#1%Eq&t{n>ؐa4z#[Q'yT6 <4( \Y0OpK[~R#}.|0 DM>NF|0P NCrUv&fd, <SƆZX Nc! =p&` f#0HFխx8[ n=,=M}f-yҸE$h`ߋȐ b>"SE !UnгN>( WVQ,oSGjtϸ[S=͐ KuK)wl[>(|cw~ y #p3I$1rwδe¯F C!~,4u Ek ?6#u ?[+Z.{{ 9L1VVDz4/ൕ6񍕠wׅ (Չ6T02p B]*e5XWKqI3 [|R8Ͱq"| l"'~B/ <)W֯99 Zu]PaUH7iE)Tgݓw>j5ZXϊZѪ2tuj2GsLG,8P4)qj<~ϬƵ2d/meB{uQ@׿2eUlѫ|av5*VMU~#DۍwΘ3 ;`DxJLc38%Xcvr(K(rN+c("fh!pDb̚K'VhTlys=֮~i؎3%3C<뗣EE*[ꮌ &c -+:\H-0Bak?E4 ymh@BFC8zPL$"rjFű^HQ[RAd t^?GF _@@@`liYKȩY&8%NėI.5+_V"o$jiu6CWWH<~P4p4no0|@M2,MҬt7aNaOqwb4IPF@>2̤-u}w%S F({L+^#1E vR${t ,xkJZl8)=&Tƕ"AyMGA Z`ÖzdT1c&JbSLgGP5#*7HS(İ H yĖ>a %b }Ԭ,5Kٹf`J "r (ЖR~3q1D| ~]ZB3!q=Ѿ[.`E*hGzB|^W΂٬ERr\NW؆BR]e#8 `0*AsF!+nR?1lbN_ɓ]XQ<]'59QP0sCZa.SZXt$=g $#n2S染 ܆'4JTv3CTh(N?huxEXxv8B?h%jEB U^ rC@9JWK}lY훜g<$gZ$ s!r6 5c.ӄq=~|%}aQLV?'= :ޚ;7-E2jl?pf$O4AknU(H9@J2ϗM70 D٪Nv(ik71<?;.B!/K Ov5:\+a.^Zt5i?d}? v:xJHzeB4bW1P4Yd lk5AMKk#j@NL>a7fV!6iEVrT#slD"YQ+-*9%;vszY֏tvMKz!¢JMBDD[J +A"VfIS}Z\_ E.S^vPD2O>8l⅘'O;#ZTE?Ia O P/yl7'<`HPVPXRE. ̒$[}HnNk#1VxYmzl 專IkW wP] KRou&U,:~5t RkJKMLJ1b:J -<7~74g'!$UcLΦ짢Œ|4iTakF T/& D՜P)A QKm[/߈{>`fÞgg.-njE 6Kdqlq6(R !}HKqu}S,*hϙxsHEk}^mQ9_Lnز rEһjw\3Apyx&iV[ mè)<څ<>,f9?0BKdmrC_Hj-(Iגsv2wl^8/<@CI;v&cSerHc9KhzEB4JB\Wآt;ޟqÞ3Q-CWCXf1&ed<'$^\g|rbQQE$-M LPNJMP !~!F- o CX-*0V 'QE51X`4C'.fqJzqv9_)l{Ȃv%ˢ {fw?NO6 8{:|~[[ `=ǧQ.3Yv87.^KWoWg wfu|b?݄'U ۏKZQ^q`r8>4&ժy8m[߮lb9JK(zGD&ye2=ڟߐ`TT 83GŜ1ԕ vw+U[%㟫eΎsVFLas""mwk XW@MT5qQ62܏V@grZ"m'Φ^C[+ﳞbwhmy÷WKm'aRI,j\ek9SӦO"σ0zX;gu/L!QdgȘx}Ld &=x8=M+Y;@;懸qG6J`t `~[|਍=S׻!dg<P{w31 Znۗ+ñ^ʎ5/&Ћ5v`2.)md2wBb*)}&"gg^EoKA,F}?}[\Z vR"[kz]J;E?ZX)#R>ZU҃H ѝ|$Yeq#j*7=INOߖz76#ŲmF&wk|9U~YpZ#Q5B $>PB.SFӉ*@̼AJT d۞; o]GnvːGW'72t4t5kՌjexM~V"J{25 ,6&k`{ٷț ml'X3@+\YOJ`@9 DvI*dh`j߰tOv0HąosyDrüA6Qx]L TvG/{n?=o*wǣfY9p֭ &s#A(LQ㱽*QhITlGy,([I NS{ ZX滍fxyzkq&O$g,6gc1` ̑`M]gՕ/v2؅lrW^To|p;JBVsYE$w@*Yh"nԝ.r2Wj8?mDzt/9+|r2$3hP; ` !py ҈`t99DWA ; [ն 3dn>/t״-gh >N > ,u%ir5T*S~_1F2; Cxꞔ^$|t}!pkW8w/(,8Vh `]k[.G 'Gň>𫗼2.@m!1.3< -Ga}b5`x:3v}=qc}1}d gI/G|$2V~Dϐw jZCN/Odt:Dxx4BjmЂ~ Fݖ*E# d7ʓٱS|Bg9&NU f4?٢9Q애Ɣh@ S1{$OU(L=mB;bBd Ir<${3EQ S8ZP><fo?Х{xb_QUaX{šҁh#A''tw;7}^ n@jq!W909;1Rm8q Gl%7Yǫa y*2\FxlVl`-cl]\hwE#9f ÍA u )tBSJF:Rf)Ziڊv]V-?o'0SLQ`cD$H yL *t h@m]>%E.Y.sQٷ1sP04`*w=n.b@Tժt|x7i'{pucLAplRd>E(h0 #aTb'[84|o~ie#P c]+s}g=rT?OTvA;F\eZ{ 䩨 ?lAƔp~Jm..ax p}njI'&X U}F1hnVw'do6%确%ֻ֙G'i$Bt-X|~yM$H_ jaCD/;ٓ kٽuDL8nv}4DSe[ɆB ҭE VS T2hHnFP 1% _?Hu8=BbNJjk9lHU$Zs[DFi=%Ϳ.v}ۈD;X>Pʊ:mW|e:Thxe[/NU3KqcGпxV[Q_ZZ9$Vr=Wp^ @+9rР1=̙9,#\s+n1e "!Ճs$VR^NN3TO 宠렶r F:t24eH4|bm=1גabp݈,QUɸEQI/☉ߙKnFC)d@<Ge#}D(!'Xxan@8ΘfX50:tMwSu%bc# [Ԅ҇M;KϐK]dL0V昉J _5aU3T?V\r]'pGkvjs.R𻟜D9*EyMבcEHERt4 Z Շ59KY} ~'ـF^}|U V_hϡ-^S3oQI`!%˛[S'9ި"iy ɉJA*LJxj)qu[Ē*WT1ѻK<L>j-V-q&TdHOF"мf BÌ*~%0U;~$?BىoZ !:| d9c9 4:BQ'( P WڶR̹1oM~w!a9Nㅘd~*k`|<_AApɵD?klLSSA\Q Eq*K#2YJgY"7R̠@UBs{NiIqrxV0iz-%x-89Q,:U`>Z8ڱg`(9QvQ!&=cN͊c|+I)-Q›C ~D"%ZF 󚖐kxnN/)s8#A5>s܀NkJvBateTBs ݨS=b9¾tTcl|2%&u4'1\xT$;eގgK|nrvI%gj+f9FF8!d:ȩEK2Sg}xϬLVpd|aPɈx*y_ Xh&7~*aGe6KqHCs|cc)x"q`]'#&avZ%8iJF^=RvcM֪v:aW']ѿr8g 8m•;8@\ bڂJMT B;R$25M;6ՍF?5OTaIĔgB >\+FϻAPaT^DGpSF%vΑv Yo/%=DlVot}AϏO:R̦;a ^j#a(#)};?,ɍ0 zŧtplm`K~ B$: euѭ\3Gԓ[)sc$^*iFzH`Ƞ! x&fNa)TrhǗ>PRF]!yŠr= d3R%71VX<`UA4*D Ӆp?% `lؼh6ފZMZ2v=joO^nIPBt(Z¾:)iqY9o6;,fNeRkhW2`Q;_6'#xok}3XI2_^sH&YZFg d$NzAH$e/~N=瞤GTHwۺ5Ct7^Lkؗs_C 4i!U"1Qk:) щux|#c4-x)_s3xbEuMO:˥$b8XYj01&[`\ǴA-j @6I@2>B 0Y+o~*jaDA'w_b# F5b0wN8^Bh?fQ C =oEXʯmbixxytM9&ͼx̰tuE({xp\yG">ࢣLSXQ8o4bu(}?[E]P>ƺ\M!'r_:h`Q?|שmsh?)T[w-̉ؼGIZoc` oyCwr5K!;oX! 0p tue4 1q(l ka5\ݚÙThl5iJQӾL%%C Jtb)v# P.S1BxK;)L9BVr Z+EM]kVs@7bZŐq%9(Ѯq>xr<у}(h2) 1rQ/[8r2)  A@z$U#ʠ9 šTSXIH,(ǵZcUIhP=dE6R%\tH܉gx{͊xR)wAy)F7!hp?QbP,`N%2>5ǏGv#TVV*UhcܟV7kW:+ .7iÂ^6iTfk+҈lUc!vK|ҲÂÖDq -mqi~FGsmüZ$$5=:Apn-xvjLܞsfjo"zCU[~Mk Pޑ痿T"o5< [y$7and7Ӗdga_:~Λ)Г=:2pJwb?psn:MMdT ~BR !`.Zo+nmp7e˄m1aY4bᴌ|v|7һ=_1U{x|Y>.FI 2<ԑp dDJz BqB= Ys]TWt*Z7,eNo/*_V'~Zm+Sr @us:jT.^ݟQb3uq[J[\_,;CA.G,ړnG__ "Ȇs#2-]dB1"G'Fm URa1a#@ys Pv-M%KD<bP`#@5t̻t܅"U5T3!.Ѕ!L\R=MmQ"'`tUNDW/x'\YRy H/%|}tHvbm:8QaF0!0o,Kdɚ;%f RH7pqp"Oco&W #h9ÖR*P rat!r$`[FF.IX:k<JPP<ЕrxĎeg$#Ciw O}DB֝YIΊ$9\Ls2ߺ G&bn9B.;t4ؒ(rJ{FN)29jN0 ]؂>a$,[ YJ#>H8l~AudǬl ~윈:r}d6b1;tm?zä.69ᳬz]ܳUsDžfu^FG1")FW I~FNl;m=K@,DgJ^E. [ V6PNln"6׽3L)[ߏa>7zakbzxbsJ`/ R Q|tRDEhXazj2F&p4'||Iӝf F"IҗpB5 @Oq%yb1i x`"p qu[XtP] 5`bIq#筢ɲKKh"W)IΌDRq By \Y~&QX\m8ښJrӓz9m!D;AkccH@>-%%|..R.eh~^)ιR#1e|Y{"@v\DB`I<: aï=Y˙x;$PUXp11iV ҕ +/?V~ dN g?ر[ʡ qLbEH6nHujaF9WТU`+O ֈNClKj!YLJ*P-6d"XH+ተT,zMX?s%!BesD4YLI?/$E7ZbT]6PL\ \>N 0D G- @֤U_rvL% "h}jexf :"qI `9,glRDςBaf$tq4oC/y2niH\JoS :MV`(JF՘f-+="JqAzRm%b5+4 'Lr:^զ3,w*m:鄔hT|iR ∸Ypmi 2b'E5,4J%m<"LTWi&(+~_=/rrxfBva"@!sƹ-xDqٝsgF"M4 zKϺWR -"FN`76xD }o*& T0bqAs"JtdE?\y YQ]z#ʳ 4K{ +O22bM]z/q[/vd\=P%'^D}Z_19.Vu;I"&g9I_}hB8D`dЊ"4yz<&r9˙I 95Txk߿`KY#AXE$)cŌ0ص1j(KNM=c9S]*FblFJyePkBBH9sG`1TL홢-*ϐ7){2]ᅦCUSbHQxƄCV;ڴaP•P7;Dz‹+$4br6M #Wz+1 T4#` rHe73EӖVOxjM/M2rL1s lPFP.H 3. l th iQYaUO7FAqyH)(gI7^f_$/cq@.UM,aX5?lW@=,r%yeo~sdû'1'^*9C1UWOS|:,Do@<;T*ZmbzD<8[pkڶ6F*=6R-6Au37E Nerxbͼd]IlFZy~ .NݸL,JՉ˩AYFR {sA h:dhont#w^zJ]rh,| (}#BOpw b^JN" .w[?lQo;ʷ`t#G|UáY<\L`GP>-!0uG$KyWpHk#U *ۺV?_,߫%sM5z0(,~rD+xڪژA<-:;mr7- YƗ֐IN `@z$| bB %gj7ԙJrR:_d੺Ns4R@ȫ}>~7aɦf91z.@ Ѕ^̱Kd R C3ubiU ,v AN K]˟1Xh ZY<aoza 47`˜"&۩v.f6ʾ9 YNTc4Ax?B%V0H<虤/$- Fa=v+X Q#|t8Vp?o>R3!zħ2xN ׼źߵ: >qk^+zޫ,G{~mxo7mDBVݝm9"PaټZ ׹霃]5fyݸuT}N.P)i]Jm#ɃjT3O]b$IL8y\)xQlŇ!&6_C iqUu^d%YZ7¥0BpƶO-PtZn9j#8&)07ˍ?XqTI!ecΞ|'^葓SMѠ [hc{@ c^&,y>^*JUx'0ј8=.co$K 5h9rrfyQX i׼LMz#,5 vɎ% .}j<_tK Odꡈk:$"/N+87+P(0췦z8Řr Av-S|Ej}H-#ߩq'U;c0am,~f;3ۊX/Ղ;Z3_G @y}~.7FoFYMM @Y׏J;98";! =kn~ƽ:L|(H9Qsi'?Q7$A=9SpU7]X5@qUQ`C p\3$2c!8jB $-YaOuP2n1ލKK)R4@IDAT:T)γ8>TSmtQ.}(qsSUPM?Pŭ)ӢPW%XRn ExOc6?keNnֿ}5knf ! Dhkş3N*wbMX}lϕ1{QVUwP)l6\KH& \Q`pMj>'cBࢨqZhe.`n:(- e*.曋ʢ$t'> \jQ Fߪ$*ʅq:5']$T@%}}vzUûubhʨف,KiqEM qجf04k> [ amtyYb@U+]vuU[~sIg#au [M'U>5*@3rfB,kC9 ]~MAh&`sry Lј3:tu xX顴:1XfD84L-Z[a@ˡbX`*t=gX0Y*>Sߋ&#A+9ɝo m8#%~gio]YOԹkN_a_L7~m .1,uS;Og6*dd'n>x;bj  <^4\lfbqao:DP*(|/&<;%M~E/U)W(>91 $ >.lC=f.xy5{^mdT {fY;8u󍳢yKHJyn.1q!]8o%ȇIA*t ) JHÌLZO ѡǦͥ.JEQXA-,h18L$~^.?[i0BlXGtsCN9MwBM=0h#]krf$IVZBFn_O5Y6]Ǹ^{ۤrvۋ.dP&V"X;rOR7z͎0 KM|K#EwVdNxF t-M>5@mïoa;$,raW 3hݱ[Zg!b9A\V Իݖ1zFFR%CC >^@Fɓ!"VRyZ<Wk.>5’[ T%ޘː'<7.@R c?x eQ RGԤ-a4Cw=hm3|b(FѠnJRS|h 3 F] ֶFvF¨̭Vͫ`(<#c:,9Vv }iԜ`Ib:J~݇HljD<'fdpxؙ @t;CS(}MrMUوv<_swpKMHLhYH~pZÆ8t2+hK: N'`r69QѦh _zլ6{=RS6ѩha\;IQ:V{e1 m hNCs.$pŜu2ѱdSx3`78D Vmu&З}| 9#G3I4樓#MV$@AC 6 i6 *ڀ=|}'hi6hSwX(F{1*1P4*۔~X9rDr#zǕVjxa!8Xܡ!27/F+?=' QG5> _LE`g k<ʢ=؜>T1sބn?,Hf65Ug٣'&W/&e"#B: x-""s$bVJo/;?^wn2`ʀ{𒇕mvG'ߏ%eZe}t۪;om",}ia`+0/KO!uR4Hbb\+/jjԽT/Cx4쥥.CwC8|OwӜVJsx3Oָ.&ڣ#WY2+0 k 9vY'uQ)M",\ aq']<|7mƐ_ 2ty;Dys"I7] ) 8YxC}7J Ht۠ i4X6 n]Z4=SA\( 1Ϳv*q0daA\SnC7Vۍ%XPxD9PLX"[.$/m@q?WHVd<E=ʪ2+P0n{g2 (#@c'DO{X[zﻏRNF$@r Zo{q|%)`v9LW6#4,d tcx%*|@S h&9&!M@{D9gM&TU\0|!Mv3iXb0.t2zL]j~ԎA \ygUX!wzPAE;0@Y ojo 1u'%wՋk@?ɐ5qdi秎VxXs$٠cr| \/q1R)j`* 9Პ=5 1@C`qK ?Ioz՗YrJs(|sB{t^bqh#X#F>zĎC}ƈ3bH)~ey di0@H2,-w-vK r>;mdĦ XvkUeO6ˁ O'7B۽t|8׋h^n`>e))ƜfwŌ8~a2/ ~{R}4,o'_uk\`z 20(b8p:pr3BcL3&D/ѥ:jtϔn(m-2]Ye%Jo,Cl^FUWj9dvFTAk~7l-7 Ki Fez.vL)AvZnà`~ ooy[Yu'}Xb$ǙjaIE n%(jrV!mN{" su6 t!RH |dRT[g1:k>ZNSTS i 2ohKVjU%x-+;sDubmöYkFh*,B9yuaU_%[9f67fniJ,aLbl`i? TsMzgV^/ӳ×MQ[}M#T ` I8uG9!{Uݎ#N}H[pɥkSQN-(/ YTMQjoODuՎSߣ3T "z+{EOD^n oR^C";i8*R)T5 8C%I"l!Rب)Me=a/ԱԼlןV[Z!Pɲ'^*[ W&󠏍Dwf42`CM>5 ݂wEn qmr[m/nA3E=0ލL 0_)ןf 3N%6ݫ߼}O_%KAQe.4[ۉ5 &~ caFx5)ZCJ'p(}|jNþϽeM츞>w;Zn=?[w IϽ GR(QDAsfkXBw6[jC*ty>"᪾9 h? Cm[V(^{C-=V_[,q<٠ed-Cb2L=Niw@)X=b œ,K?-g;! ||\ HZ fyF_YjjGB4Q5#fO܆'׬Ost\٘O,5y+ 7[2r|=!rq6Y]YoRd\jqlV!^O.~&ͤrRݶ=Ϩ}q8{F~ sHO=ǟWec#$񧹰Bq87264<qt!O.|vHqmѝZPYl ߝgLH:OC&1S~ZX蝑!@"Rӷ6^ۧF2F$vg~)߯}tM30,EĊ6tlѱRϹߎo'Ϫۣ I1 3v!a!v `g: 8"} 7!W9$Bn(W{@=>eы 2?@BR\K$Z=.PC\E's< l"k qG!0xO[ Qz>c 1 E/ (ݟ7Pqlr,Pa0 ts75gɞ4 ^ͺ`$8н|-OaBʺr`]bp Rz=-E(jk?z-I<ˡ# G 07 zXֆX&# JPލvn4es:vDof$:mm0T*a Lpb  eLmm6~`С'Ă(&ts˶6V8*BW /7ztaWo88n+`bai9:q>w/VbjK^[-_D#1 y8&L( rzS<؃.̒c[+[$먾ӯ਑:N{ [ ɀepc#ؗ]I^ՎofȆvHTT=kP{(H[gLW#`tce.m-2#AW7X5u;OUQ6Vv~UY ^A*=ϛV2Tkֵ#'nB5-YLY69/I/h`>XF5*cH& d[KSj!-P; %mIXxYxO,Ň C#O)2.}\~J%(ӣ0OZtCJek+A4E@ӹ O _B%È:8GI]v&+3 -I i'h2=4nZ>:j q2G=< Vֽ0IU:fʄӗئgsbctnbdqMb1 d h5h+IRYve,x@ǑYjcK"P2;)VSeu}}jG,[eZ"⧼25`+m8Jl,"wz b(}"'qQK\,fƪTWCTĹyOtm p@aեF3z ;%Iwq/c lz1n>ZŠ;)7]MpjY KꏂmZoȫxa[8r yYbHڧW 'X1nF^dSa@w_/v6 ͷ㕨=WcHn8cOD}(;-pkA) pE[-@F^k8QtH_~5V乂TeT'_[PPǤW\bDM/ɶ7Y8*2l`+dWDH 46~cPJ2xSo ֳ<$E!&?y uxE=)@sUٕP,֪^fU3-śxTC 2Sؐcޛ%c 3pӫ\*Iv*1{"3#.-$:`n<^ LaNn)_^\YF߁"Yb;hF(FC8)ٹ<h C@@{Ыys;UBFtH1r;R$`P ̝2Ag MW` )&^EYjNQ,_URmQnYrҗG0,}|b]6Bj!k {(WɔH g*5c0k|g1bVPoz$|PyRb{ڸv6/N)q.Luh^O|RG#w(|x#A=h[D}vAPmd@N@ FA7(ROQCe$q؂Vg>7vV/CGg Y \gjw1{*ǣp)!uiИƨoC!x9MqUV^" )2pj XMQ'=c;5%A;V\Ӆ޲5! E_pk!Td]ƙxZZ65dʹ0P) UTy{4iSݘ RW Maiu% @z9 ْݒZU/Bv@S#ܱPZmkom5%_s"P.ڱ.&'~;vq303OaiUk"y#t;9iISҰ3 AA=fU RA2Pϓ@!tQap-O jj׾Rϛqr,VoUze;# u|(Lt$ V)Jg!:>oȵF`~g yMPOLE<LcVgœ(G#Wto)NomP!2xTcQ6õ,}`͌ 5IRJn®O5'S4ܮ =h?s1#HO%"+sl*e !,jO7跫NbQ%#Kʭ6RfddDp1s^%X#Hb#3M@O6R)%vdچ"N_769Bbj %dr "@xs- ՛$DK<|# Fhnq޾)KVt o5Nk] Eul b;\pEvb\ԼT}dZKovh2GfﵙW~#gꏯ [H8(X]Fd˔/ݚq\ DJܟD`%3`jpIª&?`=#f:'ԊUI5ԈnqdxtTW eC;fX6 ™"_"8v?ݙbXgk9+W<@@)5#i~Z h>b_o:uT3݀.GBUE|kJ54-"91ޣ!jn^Ji#Σ-{dB$nHͩUIR}:1 5z7P<=*m2"BFcBsj ÚKvGcPF#w_7Dj(fbHCzB_4T waWPJGj/I[I9SZAq5륰ACڸ8QӘA7Lhr_iR"g@ݨBv?|6gi/QM;85ǣ.ArAKԥ߬: -.^ ǡjY/VJhwz#A6Po\sia7! ϘT(6 + z(L{Mk27={]0=mjEB5["]#r1:8:BrF#nup=76Lpb<(f&і D,n"DjSbkܑB>^QnuɫAhkg~ޡ5pZRI9-T1qmf;raj PT+"RhD{/F"j2/jHTr0p)=i_J;CZVgB}_MYsٱJt.AQtvdspOe8Wb!|⥵3\e+i\sh)%h"ӓ~Ik$4^h ˪9!M\ɫ. #bP2/Z]>=3N!h1kDQL)r=fӒ0{q?+cM3@pK1R`q1NBuQ9a<+6]~vQ_t;<]TZOz9>yɎ򮜲xd@sad%U@4WJqԭHI/ JQu&?ZKZ50ApSUR jz(LTnN;Z-u"u3m9O"f+<)tI]P#B~[R) ~=quIzp''Ԡƹw⺎CL [>!T-#ղq1mA"PU"& eF٬"9C7cw)݄ zқBHX\mlegM4a7>@j`M4u@X(FAۋ98ϋ~P7- ~uÈW,G8owV?g¨0ŚvÞrH(l=F0CCU.|>5! p6VvĹFWnf^w*੎/IhdI-]5 xqMFξ2B=bRW^9LH ]-(`4iV'3',=<{8bPZ1CQGZ\ls`M~`QZnx[+z=GDÄpBo6+*4n @X.ԜtIk8#o;􌍌r9'8^y޹ԍeqyYꜭň֖;I;g=AV|Ns"6.GWir6Ө,[KpE;  E3Vt: ehcHoTrkK8w~y>`dt-.&ӱz 3hܵ!Jc/$LD3<X NxSɪӡ[gnȦRu{2^$=ϞX R^B(X5/Xt<FX O`,դo#~S>6t{" ݮ]B,m`I|ڬ2TPH&rZ=Őj5JPu?p.`R-) }7Dyeo>[}V% gPU#(m)ڈ@2%׼ A\yؕs6ʯ[^q[Q.<7RP"9d[SNx o\qЊX~v 䄫6b# jʕYoM6ۿvQޑ=WN3da㉅BaJ؀=g ͩC=mH?au D3UjXX̖tVKj%ʫ|*m5x6B(k+_. >voʌCmm!\t;;Ϧ…XAk9jJJmU|g̵}W),V7mtV􀃖ۅ)ahǭՋ4:}6ׇ|1l*ǧ})ϝcіuOW6z[ ւ~==j|<:H:B8D㬨11~Q2*|? zx(x!D6d/$dYkLwXTrtϕGuNah\?~x ^p=\If= /vOcpLVCbkl**Ly8`;ko4ãw l g؍;pQ+{"OT 4M8iciC/Vk'lqbpMR"{ST6GIy+}v' lrJ-[y9#c/ۊ(A9H vߣ5dtEUtfEGXL9IP+.iGN;*gR,٢d"ɗe\!jƴ;9yt!ƀ Oj6ATԶ|"+ 8.҃T`>Şil@]WXp_Y"aaSYgY_|l @E'+1Ź6ȀЦp#߹ψEa z1<AѦy'HB#;!~2FjaKL=Z7F$TM̬{^>NC5Ȩ'\pt~Q5ҋUI7:%+UGUS.u;f}A`\sSc8^07׾Ȅngr0^~pp|}RV67.ŞG qF#_-J|(ύژWk FBN#dbLJ$.A%"aҏUk4A( 5q *Ohp7G7#h2J!6ђ9}=,/?SYWho)A9H' XԦęCmİ+ކ &̞oS>['~5(4A'Qz1GU=.<O).v[_ ?1K8r>sHw[_q4Q@_OeUT 3hJ/6:|͈"ᐸXK+ ux)W0d ;}^6]e M|č`ЩkΡSl\1`"2ܣv~n܌iņr&YWTUQB8i9']]F n7V!`٬UݚJ ɚp5/FSBU Ө},IY&ƺOm{e̍"ƟZEh/ߜj٢ls|fI L׉D61f+׃) 6v? h9Tʈ6*lg *C$*Gy?[(ek"rsڳ uU 4)*-+V;-|463#d Kvk"a*-zCK_oἯޠF r`@%Ν%|E% ( ʪ{hNEuS&Hw i FP'IK(J]{]C ς Pai5hRŝU .6JdЍT(eb,YH!p tS-]fTI& t2`z$_Ϭ;dV.fU ujѡZ]ROZNsi4l=G :kHe,^q\SH[LjRv" .  8`ORaӼJc$L@IDAT[s ]eO!2-ѐe 0\51l`VN`0a1QF<Ӆuvmn ɨ7IƄG TU9B2rݷEbC8jDƏfOm͐v<ãO[^8P{&9P"|mx/mB>f`T4ʬBނ"ij |Q16K?W4H<؋DVl1P!@*T:[ENPq\T?# dY 2 OziX_'^)Re)Դ G^<'hOKU,줾LFxP8XUzi [4 xLUbKFR􋸽d|Z/Mm 6S^ۊG"M+DJ=l=aUW"`0_'99J*&!_ +z@q)ϊ#&"9勶gJ$Tb@ pK ؆ 5 Ȝ,Ϸ\`3~ P,ԙw"uP|AHAAQ`|~t.R;D33s:QK/UwR Z,s)iB l&m(щi6UFkE[-Z&]^2:s}S#FC!9uÙi:R7- ň% ^|sX#i.UIaIVᄩꈇu{T8H[RxV3[;~{ ;֍jZs8o "AGUs4tLƝ]XT'/JW0vs܁ F I-0`l),nhXn2fgsB$O,#݉әMw|* >CYt8͘OY0)ӄ`t1,U\F fѫ!p }S~_1pCE}Q`pa%w uҴ|"9` Z 'R,ۛbZ$Š%V #vکk&IA=Ϯ.xU;Q ǜ$kRȐ)T-fiR$i}bD'"D98}}Ei$?u< 9]t}gʟGF=Z4[=Y =rS2׸rN]bf:íV/PPI-@I>7Byzџ}-HG4:1q-5UwU냾Z$10]φ.R0g'V#9kld.R+Z `O[5>,֥K#9uJI3^j-7uuVv' ) fͶUJW ,p7>IŝL o a MR/` Fma.~΍N8mTM[ìz #F̒&th|FpDwECSݔ> ܌{xg_q-])ȵ^fZ(z塦[_1PQ>뛄A=jJ>V# m9(}?nۨlaMj5y F1 I xEa`{|Z iZ zi@=lD>e}m@%Tn K+JL>5P GaNauO_zhz(}N yrv٨SdW[96.qSFӴy%05R\+SV`e9&|d7m)bŶE6@JJT+iXqʻaptR+E:h.ߦ=bX$?i o3nKy/ rnLf ns<̺'B+7T +ܩK|k|bh|wVx]LHz s nLdo;@и(ׄM&|Iƶjh-vr'$>k?ŇeR ܴ7Yh\t 3iH\"}u zM/g'QL@{o%k$/ M݄R9Dql,[$/pr͹L8xUƒ0'h(hM/P{eBgmKd"&VC At$&л"I#d'86Zn=k֩"0l܂d;͐h|K؈"`vџ;0ߐ\Ӥ#JTfL\ֵV{BRD2V3|/ ;Uh] M?a\VC;YH I6Loq E.z,) b-VgE 2=n]4!u- HD@W g73B#ALnf{&5KojIׯSke#"jS| wb]@ό_Z3Kz,==wX[) B tԸygylj՜0x̦(Cf0}g*N Z&K1PHhLrf7쭻"/i`ޔ@4zD_0 M锟ٱ84\CknI*K3C>h*G4tI{#j%3 COZ%P]6=Cs-,{ Z$#m`O;m-o6=N(iK CT,gF(K:h[i­NOvm2̅# mTAY=3su\(dAzNq?+ڐP]=- A*!* VD(&^k] pP5vG LB.mN 9sRzaXXdMʪf<OC7~TUyLA1:ⓞ3 Ft\S[oN2ՆR!䬳/&¶EC44[4c?ـ^t" \"iq+z69̒Cʓ:]U83 e*lo.b+B32-.&Ph'_4 yVQ.@ONxC62?O{a|AW {3PuSlVv4x[1߱E21n xrR]l s܁v*ZQ{dsP-afgXnhN[oqgQ3r,YQm}4m51NpreAvx;܎f/ k cǁ*p^IUraxvCc!ǭ!SAiv5HCY8=&/uXĽs>qi!sZh*Hb_=dU ) F34"'~$vr ~k6<SB`scVg}=v ~f yq7f"ÀBEQ|5SNQ BCR;dɪ(PeDž H5E^T?X)$9OBةDn-GݣuO~e jjrbSr˯lsh..pߪMIl ON6"x4+mu1H'A_ 萎b zy*dD0NP2^YpX,w%Brsj0c\ȉaݠ(KMU~\<*E0D8n%UQp M?Iia 5!jwx8v몞,CJ^(_1[wOp07bG=q]Hm4^.A<@2a<=uV~kWMaS2m &bHrR&0xR쌸eMÇ=o_hƓD@y8xA9yy'hP,v5!*EdJ?2kO^ۧ;SU x5 W - !rixn4:Y41h "i*pkBHej̈ 4sD>r+kD٩ۃ8$]{4Tۚܭ +̍41F%hy/B:rK M`Ic6jփ`̘ :t=jq:H["k9g,B!d[I7lʃsNuRi}ju.a&"o |@rpPzբ?Z#fvfLq$Ũ4[.06RYf^Ӿw4~Ewfᆮ~O*2̯ D'FUMR8J֤l  v ,?E17ѦϵAA \3ga@0#A]WlO%2QZ.>,/M4r'x@)̋ >,M݈ MHJb/.+gV%4ShXd_͐{3dORq*#IJXꨌ ,@2dbc7,|}:*H!{ BŬ!(|_R@'b s\xs}bؐ,ty2f)4A `R~u UT|ZCKXT@ =5r@y~IP#U_/@F Y OI Ss&sKr+35I="rj,zɌy Yh#hQNfG`I+g4N#'6y/ hgp{VU' XhaOYO ,x+] Æe. K]~e78صRF0UԪR#89Sb`ş^]ŝCzגߩtS:Eϻs8HX ))B2`EZ=)o~S4c?ztiO(Bl(H8_ml4%GU!.AD }6(_Ҷc 5L| SyTj1(QV!aGgH X6 ݕX-p.Xi-az,(Gȴǡ RĔ6s]@jr eApâ7`/:wn+7H&}C:yͨo DGaq P=l=^7(24 $9bp&p{lG_,:j7Io]ò@ QD9Aa|1[kr衷\K1@Am>8.D GR$F+L4˝d!N}&d8Jqk Ja鿗@:iܨWMD,#h.Řg5hTی';[E$ũ#ۓɺ!X%0+:iA#d}̋: H2MKe}Hb%$3yz0DHCun_]^Tb+oe%mz?4"}jbWD01# Q $F4x pkչn"1V'8l<F'&&bY7ue%D?lY#\t5Y ^k< yk^oM{M\bKˮ+2Y|)$PECb͌Ml (칷jeT K܇aYd#]R+?9"S_LR(N,l\9 eSޑr&mTmERy mV]C&td*B~ s3`ML-EpGg 5ctȧ_M 9`^j=CIs)jr?`Q-A)#”xfo),+3Z4/^*"MY1wb=XPoR7;7Y}&P>V?2tZ@4? սS Cz9F|bN,=E+#xoM}(PV18Y-*͐]62>`4'0~y{C9U^րy×R՜l,OF Y@`l}3jcIsRn)rb_z_ω/du#tDmD<Ԃv+o+.47k7F,ǻ\aхi&WZ1j$Lz>د[sw$Bno37D{Uʮm-je4uEFcn儚-fĥp8͋>HʈND9GCFNg7ݜ,+Qa_R^,XKSϨ#=*$o w"w]CP8!`M܎A 5Q`-&_F8‚lxꀠȚA%վ ^5ŝp9,IPs>mI?OG%4/z<{.ҵ@ER |AT[EH(WEUiG2|@14Q"^$ОG1sI2Θ$2Qcԃ0eM\hiz DHb W$aE폋 !Kqy,xLFڈ2Rx3☆ҽA?,bOױsQru|1m1Y- 2&1' uDy Ӑ pxS^uVtrƨ@AmHEg T`Mc!Բ>B>nNa@hV!:՝ě)w;ʮˀn)aX;7‚V(1AWW"md u+7ɋE $̘sP qP.yEc\e!oXaOYݚy9ITԁ/ֳ,s0 %-FQz8EZC<󿻽 t) لG*N||;HFW8`l˲q/UW[L>JnlO<,q4͚)ָĂyp ,h:`6]_ lƕ2] ^{Br]>۞QjF,Y)B(C6%T$ h7[;pid4. "F頢7 ^E,6+! ;s9o>bj膜S{l 2p@,^RY)bu:=lATN&ܻUUuIk1P_8<#7Pe2! UIC[=,toojZs2>XMn3b E TlC~ﺍ|NuBu~A3hxH׼׫__ǝfys;lY1Wo:U 4~F"JVs;K?~FbW;)^]^$Bo?^ہQ o-)\rLLc ZǗ>ҙÀ+ҜP# _S(}cy|bMgH 8&@ky?%FB5.A# kH穼,MiȘ߈Wʾ!cŒ lT ^V56X[7Oc=% tLb۞I4(ÞoO;r@'e*L."fw{)Okw~9֬ZyRt:#{4ૣo[ ;H^?$ :#d(;nz2iFjrAC6Dq*O|ةR`C1e&wD pL)7ԜR0 al|7Ŏer4gAV@*Њc .+e#U&ALE+ò+F#Y)&%%Zhk.ldb vP |5/Z_p#e1Hvv[hGNBOCgQL 92J 9,BH5d@&e[&ƒ3#O2Q߈IO:/OŐڳpؙ#Uk}b!ao73JP'ժB{M\* ~N"h{3܅ k.icd_,qFO@H(M ϲt= yтG[im=zi^Oi̟:#KsF0~49hjh3K_C B0v++ `'QX<֯ D0oMØۘ{Hr6=Tv$^h. 7H !&|Ux9茭j$ucwL,u µI1=GP쀗hvB:`=-SU0sK.b% 2otX9Md%= ~kmqAͭ;L}؝RFS8X AJ'IPYOAžƐ} bbAkJ b!0kJ:ǜ{,G7`&X(w2-Ǥd@cC!)7o>훺[F $4z|9͇0,6d+jmUFA`JTtjr3 33Tda ˺>Mo`l)Q7!ZG]Q|EOkaNR~yau~D"H Oʂt: e)kvh+͵<<UzHn"x 7=Xڡ㜨^%#:$!iI!p<[V<=mЏ'ؐzAnCHJ.4R9@h٪c<2|2=/Y V*u l$* RCzW-xv4hqCrF/%.P <J/ 5j+}dڃFrSU>gt3v)p6+P f) v1lXF'ݟ'e"oyCҧNe=i8<-i'#Qxp'U>? 264/wS" Qzkj3$a&7h4X tH+Tz“(I!2X~V "G2GoMJb*CS6h"_ 6xhn@^6t̯Te_g^)~DZ@IDAT $-ʚ/JEƛ ̶]S-'hR^8Qk|zw'dNXN[M"Ztr_CARkA pd91mA(5ٝJ%d?a@Xj3T)GA[>Otb3 "ӎdMo2蛭6uTS@42gk45{HZRMLeuejV.7{FHhě<~KXHM+U{ݟp(Wc0CG }iGTv!ᙂQ1{ B{ٰHCJ4d9 V S}`5u#B6 eAN%Ed'9z\ ḠsGZ黻3nj:ZTqhRjN\J<nq\mV> +re3Ǣ>.3 Je0Afh'f0]CA9XK;<P:,xϻdֺ=fAc6A1UUA=ksG~}Qw:ˀ 赿Ygi8A \>v-anQ00"- ڄ:I>5h⩮쬉 Ta+hFY@$wbOZu{)\OQ*qQ 񞚄r;ѯ^F@tc|׳0HvZԥG Fi}nV"]ꄿԮGf[^?DMJcVQTZ9!VdAd+aePugtf ѩNp}4rd/=h9C42%OY+: nd`HȦ`%2p~RO{:Tv[gb}bx,z(H ֩NA>$06<޿l_lJ2ܤܪ|y|T?}sg 'Ij@}`T5J&c7~3c+X~?T08x@<ųP;v \smzBrfȢ-5MSIBPV 7 (ZS;L+Ed,YCqdi Fhԇ .FMyt<ϛk O l;!3\"XؽKxD_ Z!$K iOb]*N//Ϡ!˽eQυf.@"+#Btcu lX.D'Mַ1P\i型 CYN̜*Beqȑu_wƎEl^s6ܧa~F6'w'=o4O{ jt(6a;12l<X@:8O\ =I&ڮgw4-eq_sY;=Ӌ>=YgΐjoPX8Rre Xd v0'#]w{]N[d\8e]1MDžN~Gu\ ?j^a15ٯ|d(3rNn 7p JklH^ao%Ngr:6 㾖 zvs_ת$̲A5-)J'i!n/tŴA?']lebl2"m^kX-e#h2}ihxҺC,3,'0/UHuil8`MV pBP$,p@Ϫn}[GsA^}?>e&tvuD!lU@/(ɐ0懪18Z ]<,r9, >1MI)'TS_Nz^8ȝQ%rǚatUp\>`7t0#KG(}FH坜դ" Fetr^wձC@C4C;% {!pJY :jD,}ޔjJ@; Ndɰ +dv`0i$t WGX,aUD%WHF%2px$̜aт$#ca@&%6H) }ϬR'eVkZm#&Z\ʽ4ۅ14=_h5i;;DV<v\@I{ݞǪIOiFR:DnvuA6v7^71pvIX gxsvrZke;q(H,햻on.f6@/ſ}y٨散4ݤ^ B8PwUA? qy'ܛti1Uw j* ."kɳ@$}O"7eMtBS {62=h%A]h|DLESP.%MUgm YCzR?ʍ5H Is(e2s4Zl0PfD{_(L6}L-(Q?p36XY/ȩ8v$yn *K*IRW$Ϝĩ *1e4 ˚Gpf'W}w}4B8ݪs&7K;ۡ:k@紹ħȼ.7%2"쁚('}EV%XZx~:]IY Nʸ7G- c9@zYM.$2)2G-Vxb<`BFv+)fw%_P ȒHJjV`?]W'^U4X$0Lf?r/+˶m^4r,eZBe~MHP*% -ތNτ"@fąEt''C bs1 RBc-h\Pij38HEhDtg qZCj@QE=a0TjLSURRr/ʾK !yA.݅Cn9T`j9HzΈBCSN7 [jsnyY@%d%Xb]_P`ڹ1ك Q&2T͉h!0~g5*7\(cEp5uI " 1/IbcT&z:׌FRWWѴA= 0eb.ZW3 TT-VC~A>H&IB(}/atɡgtC+gmsS`hutҌ Qiv*"{(~Y )+!:sMYWtll]!I-r'8! p1t ִC *67ɰoD<+"rIr/ӥ8idsɍJQ/$ʨW!$k 'Qsw!aG6mVvfM55x"ٝtؿe-›K3zONv S#Y^ zXO^nwGk0j35B@5QFy .m!)@3C{Bc:!9OjBh!/C^EDWGc FкqmTXQj4$Xi@L13gð& mf+Rt s}A˜ezen!bƜ쳬kabbKA4$Zܨ&Э_е6MC[#%T=dSõSIo6 ѰcȌR,fmi. 6ZQV!K%4 sV0 56~e!rG@?,Ғ`U]RO'%xHWwY&5rvzc0_evQY6&*2.f5RA<@T&Y4H[ǥ(5Ϋ'BwX{v/b<,#bS=z5l̯QHnl)0EX#Y ԫ5LdڱB827 BMtG]p? Խ\=֛UPqIY[0 a g2Qpu.MU @RHYF?*sq̬| 9姟d@vKEqY\NG}ԛcYVw%hwB3B3%lRv9,c׺M^\b=:9#q@qQ5凯D;lDl~T==,_Iގ,s?B/Ps$7SړwksY8σK+m/ϕǥ*'4Ya!_݇˒ &LA^U?i<ب4:K> H(Gf;A&ɀtܮ$m1[3]=Gr)ĮTt|-.q< fAݦPԁ}@iq6mPN Bz͇۬*D#pv$nTteH1KD)=<0`N,e4ZBŴc]R~1Iqӂp*?~? 9:.keGGW?cB>,c)a|>!_fމCgA H(H0\9)9GCu.fYKEYG|zr K*Sp [ɡEÅ~Ij")B;*"E{7R#UqF6Y pl3vőЖ$3 .nnt?b)8nxmq:bQHƁ`յߒXzB:[22B4q* 9u ( {=kӞ0uR#EkRpg`sE ϶~UO"Dq*C}ƞ1en@82 #rB`ctjr{&;`z5zoьwIE CA"\M) wF`i{>5jgFV+op4mQN= =Z'aRƗ@s3~ss @EDE:y-.*b53}|O[ /|eDžh?ڹ<]SÍ{J;.jb{( bg1[7 Rƛvy*"tf!;/"_:B\rZQ.mTNdgX`e2v8,hW }qgpKZBXzf'",/4%vHKGh_wXHi{CFI}])R=}|_օdH(HoSЄzev(q䦺u e^ɨ75(`؞b՝dqyVb_VɾFƌ9538bvr cGga@]u \"ў'HKhkऺ^;UbW' !Aq*+@Z] 9EzN C,$%!e5T4W=׹Ӓ}ByULkݚ"1"L~lk{vtk@49P͂!qI͕;#NmFˊVdg$çI=1*u컦"fy3WhK}TIp/1"wGqpqca-0wA"Eb(OQ82P/z!@'2Kߥ@KE4<>`%w7)4JgKdW72XU{T0H`Hr*f~mʂҏ -W;@Aah+T淴 U,#UyUZ\K5jC\PfJt3a̫mmRU, HZW) `i* ^hVbOt9EuzDX$HJF*rCHW Hb |:8&Lv4S2/yQ R P#` kh3~BR;iI89m&gU4>zqS@kf1r&+ˈ4BpVOeνU4U.2hzj@*N*9ziO74xP~UO~cbH(aהJ!ےojF/ti57ZUbms*>&2)z z ,L =Cxˬ4TJ-<<-EHLhIҍќ\@XȓϫNiW*nXA" ExW !t/],k@U1$+ m+I0ycRd.ߋ z5NYeJ-Nj Y(k7OHѮ=Tn䕺ˎdzLB E#nwgz1q.DH;9jKҤHmUo9*%|Ej B j*k}aIπFa4όg (Њ8t@r-'Q1lETрä Ws `(m b&1'+,HD"1 OMŀxIQ\s5ƒQl@3MS@ iȑBFCmؙ'|'X#QrWTX]{&qq@_4@|~c%R[o49iԈ~u#u>jFv{ 7"{F@ p/19l Ú'.Sc=n櫄ҧ$RUieQ]<ɘQ,# 7 VF'G3%MUasoƎ~X| 6Z0Mh.QBI$:ʄ})j{l*S5c#9r!"rX(G$r^ S#4,OCj?6t c u?ɳ7 p4MjU+j_nEP+ߐ"^ҶQ8kOâ 0 "TNyL*,=蹣eOJ0! @wd|'ۻR3ݕ1kD=jK(`[{U(xTkk@X (,B;c 11y1WA+CE?-Eq: .FM෼N7hB0LxKSp̀z` _#(u(zLk '͊bD@(ٮcXP$h9Jw9ڥCImA"ʚo"vwGGJmS\dQ6Uw R|CY%F8Bch}1X]%yyv& 3RX8TǡMf+@ڄTdu͋ ?*x2CϺTAL^v*ia#UͰk4e`%[sK#hG?X^.#b!sg#_I<4!!JuVl{n} 8{X%6iUM3> . 8f\3LpEd2bJgEd}!#2e+| s6Dyd3#&f`v(qzԆ5 2kT3WMT:F%q>r)ѨH08$Fp#{ҁmorEDN{6l#ojE2Fcj0h2qTQULF>=Y' j4D:8֔rf%#>u@:h2trUH(&8pt7^~0["Cu~;n_,84$xۊ{}[ط?u2pyeR0(,f,+W[R.:"("^HLc_Mʂnl߂/@".̵hX7b!Ag`IH=o!S, (P91Ձ<Ҳ[,IɳdI#ol2UQC/M8;Ʒ!Fi$blJ࿔́^7B4~Af"YSkA@ c)j/,ˌ-<2 m D-[%,p}Vx^NJiI=YgrEk$Xk7! ɩ-NmB |PG `_}vQoLo.F*!:&FKm,o(\9G)1u1F!~FXc=hbպD5)J(MO)${L#^2J@լfnτqYW7*t`Lu|lL֓M[C$" QVh5@~QP-#VOExKe ̅"V\*lza:A7sZ{yc6yT9hrKl4P!5B4eҟDh2hp K징),E 1"\Bq{;Ž#R-*!$ѯ戆cף`|4R=8JwH{-~NzD ̈bqR0R-sP6,79Yjكvio^G39J+c_'Ztnza=!`eǣsZqp;ƌ)Mg-H %Ӳ;m7b\]o~PqfA^٫\,,ay(h@v2D^hx_;aB0bEXH(U) 1]AFC(q7J=HTPQ'rٍ)ij  56M@b=U)#QXWVDCW%tRň{"3!閆bo[k&(!)h&C#i @ٿ4+jH0Jk®` }HL3E$_^2ZXc<PY% ?HnЩysz֠TyYM'  )_ ?[IƥX(30 mtb H_3"Bm#QID 91 Kc!k·DsSÌؙMj6X噸 xYW ߗ 9[Xn0/a}jr;>Ms[S0񠇔DI(\ p`egk\H\"hy2zK^026`/li~4z̉A;P:bóZ [:N 6`(e#'\Xl<)>a)F|dG46Dt'#Zʖ$U|-J)zWXˬ)a2 *d<}D̘4Ĺ.؊BOwZىX)[Z6&yJ,yղDs=hTE V7IΈZ. ‹6Ÿ\00$wnI9N& (ަ@m))4 *`M0B$*Pio,8=UP^@>  :ۇB%SOKR+~Ubc6#GEKӭ K: g|qx4 H/>5Xя퉆m;(A@w ^4bE3[!Q7MF݂maEIj\0tK"F@"ȆD~ah܅Nqn1OvЩ7ԈP_N&Feg`+E=v,Wj[,PGf?;8]I 0UtQaB"21א&R27YCi%aYsKa\7s-6Iď #zFbRd$-2܃X51T4: 1!+S>QDj$)F^g6nWBeQC4(/p)q铆)p FvȤ`Sxz'HPBX4ݙb?IJXYʽsy6P_^Ȑ.mQ4. ,=MR|F93J t>Fx̃e"3U$i| $3qp D@;]?D o"@7,o:2$sTo,[XK`x+FIs\*p(i؉J%Ѭq|Tp),nƲ%Ϸ 39S N<2 tG##} `{/]|c_mU4.VdenJ8pdZp2 M3BUM g,!@)>f4A'jf1FY,L.4ix~J)ʣFAv DL7C[s@{3' D -eE[pCj(\RQ8#jf{ob|kN(p'όd-Ja6Y HZ$=AlI&B퓞,!2/#h$tFM 7'MKR]5ڮT7]QhRkdƘU#i|hƕJbU&s(d/i!͔8aкe~J.@DJڃ͸ݞrgcLSIa)b5lI2y ƽ'v&#ʔ`shݛ,; "~AHұ*67:jF {;÷IвqC'#(&Lk1߿[WOmyH;bc\9P"I#6M%j"\xG@CL.||>JD3⩳ZKK=e w1+In_"ގĮL!5/NmyDVD.&8EQbl܍bX#C&7ppYDX ]c3 2JBMOvj1g9F)< Vڂ&h=҄X ƺI)dXvuX"uk|IZ-h`:Y芋%#F8!e &8>iLoĞ4'Q}!GbSJ)Yu8֯W9k!AL|[P]f; Ieo1T{5RPIS?W *)B"6bwR-2E1lAjGE/@5êKR1@=HKx=V1P({ZnsGrf T>Z e#D Nɟ\An)0+fvS@(j1B4T s`\]$,|TjDP즙#&22ŋLb1$}B6m<툣ZLJta ֺpк!9ۄMouYHi59\d /ې)R{ZA i=clPf! Ӹi$zZՈSiX3 _@̽U%KvN9l>>S#i8$P\U d5zrV% } i is[=lu햺Vsgt:mᬕƒۤDlm FB'8@ąPhj; 2&onR<//KPױGH'Ҁk=([U?ql_2KBC2xHӸ5ΰrgcaz:[0OºĿI;DovxDd=Fsm#3,.Ft$)Κt aFY陃pʒ|f#Ҫb+LbQG Ӱ*MWKI*Ėr z xX@bq^ qJ +xD[bc7 vT'Gm5gQ}ۖT*, K?{*?!b ϙHKe*1/- 0JQ[a)OCZC"73jn!Uj=1SU"NÐ(44XCC0? >4%Eg>o,a H qCFmX[(@Q so {ChP4]pn (v&dDDfqS3ZɆ8EړH_hM_WeP˄%wߍۚN*=훜iqx~>M`&b%!;݇__9Xkrh0JN1HgD$|ps3ցv#ꕪ*`nܮ>-M-ނ,a8vP.[n^-v P2q@250#aէ31DWjN]X،ܬ8kղDϧS Oۋ{0ݟ>c؟2`n D&8UE#:sDE ObQD@ /C=愌"NC֌3(*ɶծ5 ӥcY^^=vP>i !?mo+MEz#OxbJd=jyR+XF6ʀYF.6c5\^09of0?0 YP&jU@ I @Khz> ʻ)φq@"Z!*_"xYDghYl 0UĠ<8 @Y$۠Vk`p!zϖY]dߦ0G_J'`#7pA=2cA" ?hڸ*hr[kk@Bxɤh1O[, /_wiD#;FrX: 16-a0.أ/c42'A Ş:mu^euqW3lo1} &-^@[˯&V 3%o')UqCP#rA9*Aۍ+,+e0ZKd6i.Z?6FMJ .c[f:oC}5VJ_xYkL[L8}Len(ekw%0Ibr[ z# E+I?#HJ+V"viR&ḧ́@Xѓ[v jZ1 U>68ߤ$7$%|{۵*|4S6au9;V1foɃו% $VS@%|2_*~šjwmїڿΗ7{؏bLe^y<j㠣\ЗЙf:!oR*cE?+ULd `ws׹t2",Ph\!=GB9Q.۠| 6lck#m}lNd- ,"M~^sFP;97a4G+N'U:Rn,:>F7ZJ)p;+QƱoS3ƦG;HoG\DRN)̺֯ MȚ3ndՏ[]*AnWcQv˴y+oܙ  G8;~كVzH{g D_?wM&K!V:}P 8xHo$d E0ۼ \+#6C-IL-78=Rlri++/ mE*̯9Lkc~֘ZOw45j hS D}5%|N`|]޾hQ|ȪAFp}Ï5rRkJत,>>zέŞHh *R63\Øf%?;)ӕ H嶈tNmuydV9v8lr1Q zt60Od<2SB@3'>/0VzWg@rf[MkC%b/#@_krY`4t$yNw%H ,EbI# qEF6g8+riσ9ށTv+k-kv.F"6RÌoD{i4f!IiIgQg<* ۫PL]N Ee$X|WfYs7ç RدI(qeC:zhO{SOkM+YY F%#oaA '1CxkAbɤ5[6}ȼEt 2FidC H>ik'<#Ť+M70ǿZ&Z1ߓlo<о M9AG_~5!uNzeY/&\k"ᆳ`%|%T{|g"ѕ}~Xrbʭs֢ޥHINؚn)rrȕ=[?/@UB:/F jhCյ;4 bEv^ jT!apP,dw@ .AӬx^$P8L8MsB[ s-Y dZQOc`&; f}Xϳzt /T [_4MYz ; FpJ!A8TZ$L[[5i3րʠKo˝2wiuv}Xه~V/G vʴiVٯ.mg#z^ thhctKȔ(cGU$`gA5~Wn3"`cuf& ˧$vk D:a}4Dᙹ`NHŧx&O0N>Ws%x,gSIlZo/ x j$(v&Cbi1K@?p131\-JC.D?$W%7 걇= 5H6T >>~6牟9͔YKdʸ(` z9_5"uԋ9[yJ^`K-#hUX]Yvjef 0"s/RiSf8B16ET;f*t.twz=ĆӍ`}ZTjiJBd`X򊤅WOc$'}祏|HM5g/}D&BKV&ϊz]3j@0 Arۯ}sv  Ɂ$:2J G9'6hl#{E?$a3 i\iʣ1 9 a~% MQL6Hy%xY[GmY.֑JOQ!|dy{aP|Pmxj b (4$[~kBB9Čbn*/q%N}{] k8-ne) )nL<8~?% n1>1cCp*K,O '++p f>`~"L a~ = 0g6R0)aoxpk *NdH ARi>W]` Ǭ»X-1#L^qq*M2 `^84# lIɋ>Ms!![ #bb H2<$f@1"=q4|q)vDO 0d:KF)r Gr_îCCaP۔u7%ǒ\d㐨A2?< oYӐ vdJҵHe7ꈧmdanR'ЊC2aٯIeejꡝ퐯nJf(&7R'w{zy1SRlsM\n0 m1i&A̙ Q5x>!9f~5Z NGXk{AS%JԼRV+GiPBzv$w-KcHF \o$UH!X%QG஬\bUfYEMNDz5\?omPȑ:HGJt-3Znbv&QԸ&bG=D3<τXz $8"8dE3=ᱞ(~,ʌА#2p~ #`Q}'`VY[bY "Su?$d?R QbIT&[RD!ˮqK+F~ez#7:, 2)GmIy =MdE~s"$NIRs}8vlEGD^us}nN|v bd O) p2㾾\iCE#řD/dsĥSz,>v[NcQ8,0j̀aǀ0p=Qq/0agª>y!:c4Nv2:`ߜ)PR%6Zf/̭g>;3%#ьh|:Y\b(2z(}֬3VDmH ZxY6i4Ed# ?FIi'X -^&?  ` zTS!v:{tpE[{Fz`1f L3׋)R_pd/M7]+(lNk Wk2, M܍%DDCh!/m>71HT4;)AԦ9"#7А1LB6‡C(aZ E_妐$1ڀ!PVÌMm>W̆:-G|j!2fwlj/~b@'(SQhIyG`Kt祊J ฉy!4"^wipƝMTC3@^SƉ-̄SqkϳФA^;)BhيEȉG@PIU΀%IjO7?~Q2FA*8^nl'h% E#V#/*yVMɐџ""!s<$ٹʪ6?| <{' çS .OåIm0i jaX|PrDBGε-T"Q ""/Z{i}lG,N6#~ `ܟY>7椊ԤDvK}O z(*G;J.?@S'#E Ȭ_:h\2Uz.}}0ы Xѡr(,Lu18@XDF:FB-2i8Z&=GP\5㓛JS4'DD0yMTB'~eբE،BY- *A5,~Tُ>9 FZijʗu"mwvCun,wO+듰gPڠ˨iJJyckx&R d\1ӧFa)/^3,B0~ȏG1sJGn͍b4Ci WVqI:@LF\q!&^iBcPrxI7Pu<zro^OɎ]f$5}p(*" aWjaWi%)~k,^g4+Z!!; G(*jc¡ \yA \l)Vɡ ,/N3F3ZԭI*zUPM#:EeB QFHY,g.qc8w(NwdL 8T;Z GepRfj6p0.ۚ^Gt,0!뒂h 5^ UO`ڶ:?-=Е+AT]GiDjh|')D -soWHZДEB+K, !(ڤ侒 @Us<l\&ه93nD w贓0BOÞ//`kXw &)\P(Loɷ4Η7`5Js߰Pc^ *Mfs_@vS4~@нF3@a Q+k`iOzje~4"-QW ):,ݒm<`tO'\Ld%biQ\'n=ib7306'6vZ=\b CWv8aw$U1Tevu( òC(|؛cr|]Ba̗akM#q悸 E2 R%͊#tFN>Pt)p}4R*XP[=\^lL8H=y/6>gH<68-m:|]6!gtQ`$4@'ȭE!Nc WbQ1;n!%"O`FcyI3VL G!R5y)CEy|b[*s-5w:B^u>D?TXΔ56 6 GO:uDBl·Ip~{@۳\k@-uh5 (LT90#kz/㞟4`? dpPLumvO [gLсU>zl {n󴻟ǧ@# `="~$_ē"Ji;BRhFdt DLS2Ce,P9x٪eyO_d|?"ꏃQj=tnw[[ -[AE:OuW_:H;Bo @hX#٤wSfml~cS!V0J_z=#m-V_,5aU4jT iR{[ng-ho젫$ji~#gs1`C:7eJ3lk$Gt\Ul`Wm1#B 8@'ىxvF5 Xcrk<OLWf>CD1rHdDjuRy-`NHV5Dd [W&WmJ؇҄P@-[@G`;7uĠA693O58n>nP{{Ɨ@ a;U؉qdMN<B3b &G2 4XpDU#2GapQꬖG. wȩ' %IƎM=tUZp;,<̑RŐF DFtqz:}ֈaׇ~hp`?V)PfN\9Dl~ąbl9/aqIC+qLmst#o*窢QNthZS E FJ2PIK yFQN%Eb Bom;tQjz6=&: 2p9nm jBu?Wt{ќ=Ƅ)JWTL~m:WZI~Q5D'*6 ;?oNܝ=n*_ye'U'%nֆx |3wfع <]B+Xtatʾxg~P5o%)vttAƖʸY l*Tꛣ4jd+NX/yBUd= էuzT5F)H:~ޮjppF:HcnfIwvo w@ff2:2C#2O/GxwwqM%K =,zh ؂t*Ųڞ4y^){q]!>=8dgɀ{#.~(wԈ|fEnl)9_b+>g%_A aJSz4'0f\iuY *M0CIٺxؘۚK45VH#bF6A|hEU!"_>8{sJgxyԓU퇽]VnilP]{Z/o|9,ABװ})p4̦INyҙG3qg;2ʻtfKޣ({Hl/Fx& ¸3[rhĬZ߄m jl rxCH#KhSNm&Z]or+0dqqY p 2 3[4kC7zWIs;RaNQ}tE5]V ')8#gKoƮ͇35_v^WLx}mHD8- BͣŐ ,?@WhC>< ڭ`xAr(d9˩y HnZ}%!e[EzdrOq1ڽ932AuU'ϊuV##ʓe|vp%nzW2"5>j6xѴ%1`. Tw鹱'T~mG" l|"``z̴0j#x9ШK;u]A*Į"ⴟf흱ې雇8O{pkU|Z||^(c)f`O{Y C >)@IDAT6{%+:BQ#N='4hͷ D ph JRu_b4E!P1 Â:箣KZZc6JRJtZ[ "%dgdR~E1HCRO3z6kNFPia݀ɆzM+c {]MĨSO 67%rQJX,6@!E5"GC7&+%Ž (FA<$"DǗu4l6IUnCJXfxa XxҎ1ɵ%Ү'- t)alNqf'-xͤsE! = -z tr n#2huu<%@_ 7cIlLv&$$px6Pݘ.Q/W5ō6, ' ϿSɄq%1A7F E.Ķqx ?Fz n q*[B W&|Q[VC/we@8tG֒[qD[Lc2/Z=e%@6o^` ŤtNsT89S %ipVr9@WiRپЪgʵsr8t1^?C4JrfltJYvuumzdo$<&LPkY0"c;)@9Fl4P. Q^ sa(ҞjEJ ؖL;`x2/F@ OW*CS *15ha*_+sȣDD}|$;铓ml]:4M}AlRޔ,0nl6m @o.̹fvYֳ$lkW^o/$M @& a#)J7Xghē;hҝI$! 3}/Gр#!'y$"Y3F%Jnk"(\. ! BQ.4 6r%XU1?{DQĆCb}Kd; }|?'`LP-"ل3L?tyX}㫲?IiY8$gV4EIC`uTbhSHxCڎ9S$ܥ%nqB0-yEՌ$-L(>%V)6!lnzJ_# ]%0E{W<_f3'#zGl6ZlT}̜GE! pP쓢zgGܘ j]%z؇]uh.sEoaLF LAdA+"5<M؞A H CHVĔ9.N%bbFfDǓ `EJZz8RI%FP;#*+ a,`ŭ}Y@D=0~{’HƮ@CE.eѮ!x\NkL8o+z o4Dt ̍=xFǷg{ 1!=%O6,Op7dS O@H#cNͺ碫@ڦsA7V7C /d,#}=q"gb0^g鲛)΍TĂ&-G.hEPm{kثz .ȁ % 3YRV#K(iض&#a|r$tkKY"Ck.2C,%Te'"ނx lhv07uc </ap01尭uon \G$ w!ObF_#&|_D_&bDJ{~t[rŽ:R9X?c]`"tCգ {rbra:k: =&ȭ0GjIzjPIIJBJ,Ia zv}32P )k 믰YepHI=!S?Dmp(>IZm`b8X~hLQ fY#?cqmQ; Ѝc=Ɛ=doqLNpo ÍƕIn$NeQ4[tCK n^ϤXq3`atZGOM&Ro;+jK@C6)n]Uh:=?ieԻ,*ZB[.M4;]\zZ [P[ {^ !K-h,D0c"@fVFF!gk4rؙER4#t,3D4M@抅lx|w;۝(VLH8n @&gQlnF1n(O<mFvnyy;{nmPϰb{xȠ#T-#: wCn+G:*ѐK}џBEh >I^#}Ƈ#S:l7$]g!S-pԼKw#]oB˸2',o_M)%kxjG ӁɴC]y/@LhW7Ob=eU8 (0m߀m+bC^ǡ%LdLP{q.0t(ɣģZ{xJ1*>Q,,3S/fAM_'I7Pv3uk͇je_5xRl+i$\OPp'-UJEbhlu$i!(6Wn?s)dvhL{/X/'IoVDY9xPj<j-lT,Gw)5Z"g,j_ϒL5 mTߧ5R4 B磊o1M wY:}=".%zF޺_hiE78L"A娫T9; p&i1:sjldsFIcįA ^QD'+)w2Ik6!, eir#9 x G) k#(@5nK9* AcRRu%`:jA)o^aVov?fd4U9.[:j\j"t$F/x@;Ggl ;V,, 3ovИ%;K!`"i˭vW|˒4$R*Ѽ%SXd".9Ҙm/׻_B"]&,$c6̃>f":9(doHtnfkFߪa?2>Do%4(^FRˀ~1O! &=n:%Xd"Ƭŝ7BĂ6ېS70{X:&9kăXUoǹ e^ImB }|G 8(FXOZϝex?dw1օZ!99_-V 7@^rJ\T3sp/^]ԩK S D( 'pݔB&i!bqB@R^҉ƈ Yr5["NST!:ެ{ڳ:%3qf[Ѷܐ&Mk8TiuTdҏɄgQoGsJ+]j9 AD( `4ZJ-w `BuǛ.5MnءAW|駗Aox6,}r&'O֠Y&1=j۱٩B*i2|IhP0 <5 1dp/:T$$U]S '+,DJn,!LGp-GYP/(Cm.tsfuƺiϾ &±\q?{ጛbWT07CEDJ"AD7*NƲ)Elͅmc[#9(A$(4 \9P=D0ȫ VJ0LXDm'-6scq,k帲~Yl1kIXyY y86"zȩmUxa<$s>;[^DT;JM<< hVqDAN%yҹ@qVA=H&CD#m(31EBQhVU9AHIU80WҋZVW-eIglo[4V=P~TcHnHx$x=7Ig.W;۪-G@Br\V3n`'~tܬӏS"%s)0 7L#<5ꖵV/̡ma"0Sdl씆 b@E K$M<mɌH8 g>~r& &#җDMmS_. -٫}8o1goz * EaD!omz]/U*ׂ O6P.L !#/6,;AKzJF>esw$71)r4ᝌ)NZy_].[[4&<;bztάۖ{[:}\s@eeh %/ǎELA <|);JjQJ?K{ye%lŦ9;w#HŬ} ]ȷdHJ؊O :9NB8Rr Dq LD1l?vG;gln=_Hr!r`rحM60Ij=8 ǔ]̈́M);x_D^oG˥cDY l+?Yzl>2z tq'9bi8MQdz&r-„S(=LHv^/^X>4{Ӟ+Cc}O1.n? Z*%XGnvvQS.lđB+m[' E!ϕND| 6?-$Y3AAfUs? AЛLֻ$nŖ̄dZ~w7{_XFH} }imnsj'郤o,Tˆ/;F H~}ߏc/%T΅Qgv[QbM+ lg4<~^s%^>p@L c}% ] yӯY)Ky[P~'p(d4%4L~_;LžWǎo;z>3y2C`ѻx>=ܙ耨57 L?1Ý)X9sntGr JJ<e{0jT ې]p5b>}ݭ \Lկ$__ ]=Ҝ^ !E=AbY)@Wh[ׅ;; ˄ \$2{uGzZLhVau48 %jgzL%z\%7X]x:Lo+ tymy`Jrf.[NaX@ީբT+Yx~$ hÙ+tpL >?u?>7__=0i&S[l=p=gZbvG$6؃OX뎵r PAevZZz jP6&⌧_.SUgil(6Ds|ĹrJmxJ-O^CWAd#LS'@)s2X #,/A1j< Iӻ*6Q@R #q|u4IuFzr^awە2}?d2 9ˣE>S Gi"&4*,p-AˢR])qddSGV` ΢ff+;^518˜ϳꞣC0Dx@I~4]ܘ q Pu9lw`mi-p B9hm\y6&cw9zёvD\ā0Ն= 7xRʆSUnuFnNїlUDNxu x;cQd.: `pFO"Li0zNemu c*PPo1xż o.ofݵ. 5:Lf,*9bƭwΥVn;b>w(;NeZziDT؎IG8Ëjo)0 V ?Lz7+x~{ DBA!C$_Pz% z`'jb&PÖ$ZOƊ}# jG4Q q}%}hܲ9|aaI9 ]lƲxzm`9˖PtR>l `s!BJM .a.LS(q"@xVy8^1A8 XScX %ϛ>ػN5W~Z̵=d)޴TO4br0< M9,pIkA] A%D߮̌B_'n~Iz)osAoLޫ:q>h[ _NEm"=n-JIBa.v-a|r@E&t!&v#:鉡AgmMt1#h.TEJ1ZĠewrgEPl})q׽#jZZC |7v=&[C/GNueuu|5.QR?:>1[9 Ka@ (V֊p4 V/hvrz+nU;'SX{E{(W=ѵ(mi=Yp؅'&0I"e,,P.Ҳ x`%LGz\}+%-CC)P`"J~+LriFV螶bj'P}('L…$@t|:Sw8 "/!';w؊1H} k`AYyȞVwKNz@@boΰZHh-aI*uܳ湬0`[bkap-Vj;8HOjlM J| ɫ񧗄}rt&<2 {hFaԐ~ ZP*+[3-^DC㫖IZItٝF$#;qOJ+g4w>d~bKU>y#v%%@k gG vB~b))Y+2J>jFWE |OTdݟ ۑ2E/a}7g-/u0a]?Y==^s\V9nm"tFwO#1|v0.aSrrнb3T?4dmE`lj=V6i> ZJpQ"^H2.C$ ^dRc&6f?ѢC)9bv29.a`1.It@36$$oY7QEQyW5 tI!@= j(Ӎ(vG%V| 9DhZ >O}XBq+*O+ 8갊-=cu"(;b{%M3@ɑ02p!ҭ6z QphRcq:ٱ>KmڗMaE`av}wi]zz.a"dKJ&% [L@+4]'xuQ ,tpY)Ȣ$FzLe6Hp?UVֿIAx%=C9)qYFЂ<2 "G9]Y)  Y.s%K^}L!iP̕}Mq, hX{^G0Mvf_rm rHȇF50:h ]y@yy6 Z짣!JqV$r5C}LU;<%#94i9Z^6E x7D=*S-&~vgwѠnIWPZ@ZU1&72!E"j̼I7༴ T0x%'8:4Zq2GkI 6rm2Ϋ~j~`ꖱNQnElN;Y̳ 1P%)8ƀ6ƨDfy`VLm)Td}N~Qơ7+h̾*2eCυ_Kf* H\8[^<޸t{> 648j/hKa\61s"5/&o- s}h8oZXyr[5R5. a;8#^(a||!+^^F"~bxqO?WhC7z13iQ'P8+ Y)]18⪅%W%4HY16CǮS#"lnҟqqNt]KF(%[/3%ѐkEH#{`.@ j,¥ĤȆݞ 3`8e]PBNUD M!I&o`L{2tଡdg=rǭd0'pE8R+zďvi0 VB+"/Z=zpsaG\dXbf(-Q A]f::BaL-zH% 9g5^#0bۤ}OcF/YZfc9ڝN)5-+= n9|0g81Q5rOd}Ɨ,e>bs p  6<=EiB#@ Cgp|6{R;')!d)+d,u%F&Pv嫘Ԩ{3"m_ly0r}Ԃf -PZ.]G*.AhAk]0AO  |6{si f 'mXF g))p/] <cc?7Z(Q›"BT(=B Fe2jMnsV1U!4^SK!T@-QjJhXҀHVeGu9 (nIҽe8ET$ MSNNͻ"׀' > zbڎ1aQٷqP)BBé" 7ڊ+"*=ӯU ]R1 DT8vi"-zPG=MѶOY;N ڒHHf9k.#.)$$/n!:MzْjZ~q|mpҟjKuzQ+9Y_& E]jGώ&m=gdVSH Uˆp Pov:6<(\usqӯf=<zQڙm[)iXdgJ!A!xJƘ`)Ae1ciؐ)enj6p_竞\@'Ͼkթ ,3Bq ?Z^*U" NS鏯7sS,v6g!r>Ԙ=9P*M(-G# f5gχS"lʆYK(B WS9&0 g5յ`[}Gs()L1 LPu]bX! x.:A]J8|fpQH6'~4dÍ6O @KgV1kA?;4O1a Do}|JVg{˴c,gd&3e@x} 9BSeb~n7uxD/Hq"܁'2ð4lh5\ YO@{CoP;.h zIsVucty^f-%^F] I[pPA`}rlG? *>\.yU#:CETJ&JkEss)?rA|iMFJxTz\V AlF-w ;g8dMt[6Qؼ!B"4UBR $>[\Rqمo P:u0_M@؏&"16& d̓ʄkV)MHt1FWĂY`&\Q)fm>,ϚEvCBu]uHd$gnONkB|0I K8hu105Bh,|'"akVvMLaUl46#jewJ %a(1V2(+y~wa-!YrЇȅNKhĀezTQu}?f2&D#yE?P)'yg?D2 8TM{u-$6M-6}=p1Q1 `B] 0)ql=V7%`42WpwH)㒷kטZ2ЈQKЌ [$X epTbdm_%{. @(dvC<_6~y M[pjm}[Rs?$r$!i42 JwR(,`?cŧV)>?h-OٯKsa|[!I&ΗRG`qnD!5 (1a, 1/&@f WUJPp#~Mt:"Pz۪ aTN///P xaMd/hhEkvsf)#Lv؆yc> koP{BC ADr'mpaoӮ?apP]'"~B|?:g>͑_AsIft~-~Eg*fU@lG&niQ|;\-=mGۯyzQ$˩rwXضDuY$.949lKm!]C''!Q&vZGөѤj}[r2J}Uߖcƌٜ*&$ B6'-7'=r;hi\]c %_S%sr)b嶺XaoM50)Գ/&ڵCan,DBQ~w?CL3+T━\*/kSE'nqY-G5,`ϧe] 6i/Y:46 e@aCz! "*p<[7zgn:cW{B](雖noϖ=.g}*I;>sRœx)co)lZZ&2GEn4G'JMFN2I`NnO'Tfݔ< *&j.-%-Tpx+UMN55;/ 2~SDvi EeʰJgo28٪wtP/by0*bg:ԄZ^,"l)jYpi]9Zz9ÍJs.9ǔMBm1y8ܱ4Ia e P[ڸZ"G@W B.lӃ;se$:\6oK@n.8_߇Yv|3^$*-RzIs}? E ON n? K[>O_>w7̶mImDs<xCI|%vG/9*˳e]4CChCK--|Y;FO;a/ 9N\~"f<)%0ïmX`i6] #OW+a=YFRqkew燄]S y>'{d'א=!Qζw>rQ4?@8=]]Ud} H/s-1 KƃM32ܒ:ہjs)y<{SnT5?7ڎ5ϯ=Y(GD=]p x#ߌJβ7$N*{,emOR۽=m^nt`*ñnFnjԦpL>?_I1~ E3eO2@$b/t}ȯf5x\WmHC'ue֜ˡd5/1o iENl/0w[m&;e_cb" * oȍ/52ԃ5ݏ11hqW7%sɹ%FhP-NC(KqǸCf?D,"]}ڷxut3M])ĵXkGp(,u2L]02"L^e[sf(:AIMx,O9q_)}&"VA,kp g{;y&>c(S(VٯAG\eE><)Ves\!-ZES/K<(C\Ks9kwFą(~? }'%Va%U/7wP $5+_^qA33?qOlfDJa(i]\)+DPE_qQWa"јHBsb v*<90G^&}Q՗ч=[| )57΋z>h V}J!r'*#v@}h]—qo(nt8i?ae[1?|T5GQY85Ӓ~XBWTp+ NtCtv! /W͡躢:;mh(8$m IGҸŗ"]@0[*>XPIܐYhHǔO\XD-X!y["ܴ` F=hޫNWbަ=fiͫ*{P\Vo-y龣, XE`4ʛggE.wUvx ??0c|SR=)PR ʥHh*G_j3/dd[5LQD[:K԰EHN#ܰEb4Qjs S \QTH&I{*#"Q.bRѠ$ ԁذAIɔԮ7?e3fI7u+ExSVJ?$bF nS18YАW2ϏYErcs9 !A_CB$62MZv-& *ײw#5Ak;>bh<_؊PE>Py,ڂ!eT0T2t4,0PEO~2lM;0y\:PDŽDn )KgVR.Pq".$ЅʌS[& hj %:\Гyᘆ@sSdT =t,PLp2T$Yvz^/ǚkJ ז!R> czoQq?qOq\B#+73hl}k2ff5ݕr4YxRnw(B?OsSX z/e&CxQ 'zo[ZZ& ^D4Z M_:bJr őT0Iȭ=zD>ĚU9U@v$]jl:-f=Vޢ2-)UH$C:ΨS51m>cy<^-~qSso!7s0Hg<ܩ meNSUOQU}vXy@!7,7-]AζӴkkwP6PPzC9)}_ pa3&": d3OQ(hQ~!vcD(nn3T5Ȗa[:ZSYs0D0x9,kRFHվ@%z<?Fa:w JU{tnF 0H@0Sd[rTyqe }>!z5;pDeS܏Esuی~4 a m٨^EcGRSzﯗo޺lCəs @о\f#\X%!5I7'^Kw &8G V#^ȀUa1g8C\e(cWc:T,sĦ#CۇW`6ƹaV(#U;: cZ[ GʖCm5.j}e#?8 7#0d<]di j0Ƈ(;̡O۳JMCnӑKy++X#\kznb?aFoڇa+h3DKA_mm^Ѽš$/D 4ΦӖ(XpZVWⱲBl;跒N64=gxQD^XI%HCt#>DMYX`2N\r40덷ڛSiFSTm(1tC(ursz .GX2{.ǒk0uw#Ë !UEtE° Z" qh!5eϿHvIL?`I朚eG{Ua@ATw'ZmUFt[׋$=rCs KuȉUH zO<=s|a|S ̧@!a諨O FjKQ1j\ȌWST ^K:H佋.h3R·஑aLC/jBtw$% J3T'Ӏ.Jtp5qۥ*к)&*nUx 5@t@]茝mWMiG(x1ވ!NudLEi9'ˡfBA^Q)HJ`ʫ'P3g=A!㠀Hp]RTTNKx}u n+&wRzuu<Vna(d lPRbo Kq[kщo9QfG JRdFP?}Et1r$ϨS1%FftOf /8fWGşӶkNx0&39 |{~`NwNSr i'v=CE/"l4P &inhJ2u,Rս+NcK|=;}_#FK̨Q|]5PL'{RoZ5$X 4 T!nXDy* ,O NE?!D)it=kI9F07o^~b07*6!HsDZlkStу䲴t UnTf.$+:)Ja!AD Ӂg83> S =rdyFWK=55#eHgåtn!{+ 1Ca,LaCL1Ex\µA4EHǝ)ԝefMKӌNUoN9\IעD#r]I!dX*It:ݷm5i~{ME劘1gel`fX,)̋ML*edwFb'`z1[F W`ę>]*y[9#lqos J5??&88c4$/8;ŸbȉDM40ֈ;ASE46ut 'S9>,'s`䁠o \0"-b9u]\:Z{Y)"V";kkvYvVT*_XoF)X$鲜1۴mh3}:֒HЋb(11[MxQZ\/v|z&#@ `xK!!/{U` uEP+spK2Y$7Ai?qV& uQ$d>*^*E#Lh늹USdE&o q8IVD!bO-eT:<-h]"3z=ާ=;ZDdq+w}%黐P0^Lmh%l2H7% Q`qTY rt(jzdkgxVDEǹ]qYC43G h K. ADocY] ,vf 2;{)`z5*K`>Ce H%ߠ=;֭<|HfrZXknvN$#{ZRbV1?5> usa:!AqO\d*E Z_@2@FRc! feEC}ۉ+V4LiMάޤۼAqi8J@~̭ #x nNf/vf)9DDl8:j)o,}_@*t=CW*' mW)O p߾05cjΚ!h/z{|vXYB5YIkUҷwYʔ7[KNgK[#Q2F6eJIrW7iTlʸeF1EGdJX@y"7K۳{I w5N|uJ:rX'˕K/#eÂF|ƄBgK&FCm V{+} {>_-i1L+-RZ/דV?YnN?@V&aBhҐ"veS/O ]{lA,NI"x|Y2 +o@Oa{a17"w֕V_i'm:@؋[X')\&i]a]-Ұ_q%2Y9fs̡GY]F[|(e" Fhm0>nޛh֑ <[ϽdA2Iiwx>q|],$R^v/r:lxs#:=#i XXA1^A֖|ALm^SBG>@j!o#-&2Cb t~i7LcWQcZpZYq6 =H䎂R+q ,A>[_DΨ\$P5q#!E_8R_:-E%Cȳx8b<=>!@JP?{ h}B9HO=^LE۟jG\?0apZWQ\Gz.}xU.?o鴵}RdDH]8 stxuuU} EabvK,Ǟa2BqQ 67'Quuu6iuzS^68"qa{w&?NӾ~[l;v3Th 3oX"%Iq^mxC݄s⥒piU JFy8ĉܸ)5Ąvr<>b1,GMH iJ($oE׶ML^SN+(>de]܅pT&.&<^ =KuσFD6/8z!Re>7 xx &ä Ar"PL~B7>RȆL̀SƠj6U2}~fY7kƎ(yО"n%Aͼ1l\(Ƀ; Clypy*19lt`b>&0k8$mA"|zP9n@[TTX@E-'ZGx_RD%J'=Gěh37tC+lj?%=Uѷ^>8jۇM"d_%j6;[}@tEor"%*# h΂HL^HW"LJ&* 8|L$/Dd,ʪyiO- J-3-9ߤJ͊Rm7GY59b0 z w9nG*S`!DdشPO"9r:2c+zU%;ofN97rxBؔ۟f0aR1haw Ӭ+Zop!j@_xe6݃2K33!^{  26یXވ;p=iX+zk8eaqke>_awL%޾kecq~@޲ c~k~<}ي/&SF/{<#-hʌ\tcTʔjV=Ă {Ql*%N1C 7i}2Uim Y55v߷LdT|PU~~qRI\3}t~7@O[9hpl[MX-?b3"d&yrg5" ^oB:4[ %䔖_2jg~XZ<{˩aee4;F2gPYUBR"FOxC8@b@f䞫L6 mbV$IQFyӱ‹#FY$yFϹj*$Zt5%-&T d\ևF وfx|m3ZStf~Շne?J[q}|Q Wn4* 0̩e4;1TXj2.>_S hO!zW _" EaZ&eHbWtgU9OQrD04yFf1͞s`6WlMǁ/2g)e26hQN~k?0PdAX&)j%Ʉ~T@+g"xmXnOوl۪uK@*FU %VImnS1ERJWOq"W)J`z"cWfΧH;Rh` |u?4G")Wߤ 1P̙;Ҹ,j !np}RYYx$~AC㉌ 6Y(jGI_+ }!\* eEHh*-%|NR90[rM?GF3ll2'y}=`I|-"dkrJ DÇ ;$yfD=B-xPjmܭozu_=)O:W*:Vفf7dK%*m!1|y9V+5Xf4G`69 `k2#"G!s&@*Hp/p`>0XywhŏVt6!v΢ֿx+>{`_CM{!K IR}M4O=gٻrDbmjAO9b]b<$${f 6vcN5m liYc, 6a&FBi{3e Cn6J"Q*]'` !%3|k'~( rg^S/ZHFq6bvS] ealJ'YmG}*Ix0ҫ a !)W ~W0GDu^0Xۓ[ ;΢XZ"!NG1㴄$,;H=9<Aq!ȭД9=_Y"zp#Fi?E @ZD(OUXBtˮ7"hl0G+gBM$fXKehPp} 󑴸BOQ 7k> bfBnϑ~Սd$q4 A*E20rƍJ˃Bt3P@?Y7˨pj Di@Z\B͋%lA 'mۈ#),?l 0ٽQk&}YKA̞J g$2{%Ն߭EEYRv[>-VvgWxL}jAKǐa;t*W&#  n,#@R8,p FhxG+ht2ϴM韴:Npj4h"U({~sUU*z4t&y^ue#{Uܙxs+*Џoƃ˜/v[AԊ,qInx0 KDk 3 U㨛xwCp|9| j3 *H¹&Ʀ `JwH) \+RD>_B/km] tZ?)In@_HlWE RL&L}ϧOL%ې#2L?tl Zg `Y^)~MUx+97=0&QOƱ,A舵XWNIOhZR"_5STE.7Is Hb&cCUKyA`\ &U"2@ᷞ|f5WZH4(GN0$и=NA2T3H?@Svz=E{c/ u(-GJˆqC0d~F6T!LU(PV$l8U p7_[T!#C"b'5z!UغpU0RLocQ- QQO?Bk|O㣓N,uz}Q S A{'1l%QE~xzlgG7aIQ7-2bMtѐ-Z#U˨c!PF{mn"}>tZw򴡿m:A5J]6%mTDa=ab(ԽI'R8#=AM ٗz64 DF#Y"JdB܅%aP y4~%O>Sj]dτf_.=Xsns3"Hxc! fr}_) d(*;Hme"?*ehsDahBMWOEy@A2Hf>FJ|HOJP((t.hRw'MTĞ_bAai@./>:\Vq9*r;uE@IDATY uو=ܗ$ԬԲvy_q~{%ŚX8[d My0\zAj?>?<2hd|?>FaknGWP4566񲄑VZÊ 0zOeX|PhZ*q7 y]4.?~l%ŧթ"pcDa0T Q(MNw0n}'(4u3Yij<$tKE!pn( %͓Ӟf+G+/'Us+T4_n y͚m9C*fqN(Gv*XA.5KaRnXG;b" 8u!R, z*o .T+Qǔ^X8 fug?'Zä$L`HV>mU7Nah/盙"8dxrȌ fx,C,;) r,aZr.f^7'rDH7aS79!3Eأ9\]"P;jߪdMlJI8Re쉹x2.L9-x5nPX7(1g!npR_BGUMR$Zu(Kw!4n{%I'")k_Uӫ0_2gowe"Q0(m]9j&dZΒHi?}Ϟ$ӓFqD=J_ѵJLMc8ޟM|mWů& o25guʅK B)xDq!R8dvnxTtj+K1lmAo;Oqr`$YJ?(|fpR _8Wn*#~t"uA"hE+B LtQ;6(4E[q ɇNY\Uc2F4|>d:$'|~ 82ٱIo @)涅k|fFZv ֌ΐ UX`ds"[Ʉ¨"6v>D}A*~JZBeL-w[=֙^w[`:P`tϾ1N0+aS_y4ζvEʭ r I8 x!KĠlUD9<|*[#dOtRG;WI.RݰNѬ>{FE.=9بj,3M6.PM99UR}bRCcC|Sy -?Șx 9&.p``6;tXD>Gj89a$`EvzJg3!{^B^D rΫ0q40n&ׂȞ$ .H Hh&lx<p"N#iy(X;ByC*XR0jc8(B m"W{.,>;Aݙ) qj-%('A$м+x[qQ՜cW[@+edހ6Q `)M;lV*pˮ6df\a*aGyr) `{3)z\ @W=pFJQr&=@y?l?*hQxbso%v4f閗:ỳgD/HCbB^:ǧLVB4$3`:!dWgm!:$!LL[b4T Aʰ@RY+>$1> ZM@,@IG>j#" RS`։+[R *(IiDfTf^7#k!~ )3lXI^ \xcx]z]=pI,,l $lbqb [ KU swL$oU[`THoے%۴}vRܦ8VL^;TJ!ln}){sJb4!FDndՍ0/ā8gBˉf! 2C~Z0M9I5 Z7-)߸zBVF`iþ!̷Hp34l9 $n.YnL-J5nycJSbU血a@7g'@%o\V#^).&~"𴑑TI@=z/3y;-wxgO|^dfʐ7!C#~2b|j)p'o- k]XߏtMXq|@CPe%Aq7Y _"R:/k?-X !ܰ18!]id%7_mnE aRR,U'ƟiM 2a$)WO-a؀ }OkjH]CvC#'Lt, i]rkg" ob0sE:A$5$2mIYjz8g4ހ'XyΚeq&b VEwzס"6) HT0J0GXJ ;W%bQz|7=EiS0QG.hAWgē7#s[AvQґ=Ӗ( B61^d]:%EJ %ndqDڻV,ijCi37E*oAΊ[ `5f;5>YPq>x4`ȳ7SYlǟ2;gN~sk Fb Ŵt m\<ʀjŽ@K_.p+)+r|HeuA>%N}(nVf#ѥNlҢ䒼dW%Qo19Q?"M魗~ *8A0| njJ܆P=)fye2T(T4@O6fN%1 ℰ r#jpj6-:xuiyې--+Gf'>{?D{;,L"FgAxoEjkm=y13077s f ;եuP >b@oztIքO& O6p@) 8k{нr4`{R.d0\h0DBRZ.sjF# V>s 遰b^P@מ L2;S4̉m:3(RX a=2FrN9 ~:Δ)S*KzSeʻGF_b{tեW})cOFP)'YcgUKMX/<5 :5 ?5Fm!Xlh*(^4n#%Ad^q`uh&G8WZ^ݛAxt1/$Y^t4DG711/{LCaK൛\g.\U\oDۀ Aw6L.x<OVk^ K0ĹGlխ&w6ތtlg[g#,x:ޯq3!V_obIibah EҳY`j\lWkގ8gT(zTӠ\/ ^~{Wg8hC\I (zsZVf*'$%K+ qhh=?577= 6!n&D*(h,>a ů~EAsCj/:S<Cd( ~*M<$ѝtkyHuc`2(ڪd-ͪ}:Z3mFEXw(2u36 ۓu74%R:.݉G jpE7"Z-j $2ZEMK420SKҴ G?؅ Z*_T5%ka3RY3P~sl\ iE]ָ]VRoXm=$ ~Fk"D@PGpRΎ-/an2 D'1F-6@X }v xK=^>#^ R!@y>%,zrDQx\R!77eV6ҮЇh~ o OlHhC1K;"?S`" 4в|Dfz#oiov7 8u~={Ÿs &#i[+!ѢrII|#==nfp@ a5˖=LC1G~"ʵ)pwq8 僼LCoMAw[Y~ee)M;D*ެN sO8h'˳|f#Gp@|/['PHS8 jLl#HM&k xaDHbʒ6rv;/ȃ18M"t 5Hc6G'&},f٨ej@z$)ǧ5߸q~LB.S)_cU)ӡPy2zPqa!B؛U%={pW yj,7m:;bm IwFx0TzC0d"#icyXدά$dĩ%uQ ?h4B0cˢ $Q>"-#9螩9P 9 "<7٨/mijoN<*)e~kYҧ@gg~ԀЏ/{2G` f!{57?Mt)1= Z*j?MfwAWaA/s˜2a3k9O#eF%3xǸEk!`|R~K1s%o)&/]~ qiGhSa^hůn1#Z4qjqUHتvhņuN9v&rTIK.A WQmSXԐVccV C5-N6nXga @Ҍ4SB&ŧ`ΊNRr:fK[' Aȣus9 lA?,|g}ddv% ݩ&/'d+R*c Fz}uCo4ءNYq*f͐h'ȉr͍<,/> DbsoyD)Op"$,(Y\%p jS`y!YСWgi.\]:Ill'&lez<p  9FB״{x*7u'f{wNBv&h3k׀Os G`sdK5xYgw?36np0Ye^-DzM:qZ&}qcGKf4"HCFq[AjN`[PNѵm8sSt |ҖmQI}Y: 5CF7M-Vs4ܹG7 ry>R{hs"hCV[V%;*REV#T "hSS5m QSIIT/!\U@9PKpRa5DqQbi#8^Ғ^~mOCPtyhlvjTmw.ZI0F<yK4t^1ǣ̥Cܮh}orTnj;Bg.CmQاIHİ>Qd O;{8֌d=TdF(y=Wmٞ 3:%]i:Jiy1%0ͨ[D`㔼5X'gSg[zKK`Jv+]6DZ9Pkozix&U, h*I!a,V+y%xM=me4)M&LN3"4ݏI\#>k@B:a7 m*=*xIRk9e6X,ȋGQgx V;Q\؁Ӣ6(`&t#jsGGS#v*镮7B7oM?2CɇulgjܛPFk#T\nx7ۭ>0}NM!\!fj7N?өug2^"l][ϊ7k>F!ArIl`dl1D)@G3bA^$\ϒGP{qʧHɶ5f&utSX{m~e$m6رc{g[ܝMɢKrN~"-zCA m@ϱCFTWIaE K1D"S,N_*I:ǔ: U!,^M*U#xWA)vc)Q^+T怢%Q_c_@6zWcN\r-h}B~,*tvFzFw6^^u|ɣ%$6҅NJ.>x$eӈ)6;@"gJZTӀR,rcY%۔x[m|dNR\ NW8ȊFn.$A]V0no7AX6z/r+B,j*,\x6`ޞ&ȮK8/:[9bi5P졡Q8yegc v}UW r,*%IDK6up,az '9&#TkjA\n)m֣o!n%Uڊlrkdst4Y 41MpnZ'1&5ӅC0̌Qa5h XOvGj/|m 0A]63tTPݶMRx4F$nnS *Wa-z.4F.Kԙ:<їxAiR&؛畹6vRV_`*jr>0S:|V*e5>ݟ=\.?L~ iy3GjIj4" Y`‘q[.r:7HLqLh ;cQ-yNIl2嘚j H)Cz3ɺ^d!!M˭8: id4-xr1VAʝE2YÌ; =l?Ծ8'q_'a]ǐ8D8" ,)69DǬm{-hi:sP "C-@d\ʍU/D775sn%|CJL~ODP>Ǒ0Зv87%l/Sh`rߜW7Ňzʰ1wA◀OD8,  /Ŏ 3铝9 p7"[͂dHMID8J=RQ!ZL29E-y!F " )"I*rEpʐE[hŽ\ fφ=o1C^FOgb){9#(ǏfNiJ FjrZdDBĎ=)$xcLI6= a'gʶ8Q p7:HSpќ# VLb:\NwYtWH1S:B0OS1u?83ڦ"S?*-ї@ @;p=i$TňDw=0C͚9Av@"TBH!1iImvKYӥkUCw/Z]/)Stio@&3%x5܍FSn[4AkYz#*YPa3hiu*3dUW̥vpxu sz<Cj?YWcX1FcZ' q3>&"cųْy$! P.nƕ_xGcZp\yI2 vr=h(RyO{W,glmrmvLyIV͈$TP'Dt옺cګI]aUNBI5M[ƊQs#J8 `9N?t4X "l3#<+()(cKY)Ӱ4mDxgZc0@jSYZ*\, x[ QlRDJ ) Vv(W۪&حB3"JXjMAeDK0LV zt )GIR/xwO#6.ƲIh6LÜg!怽L` MR U TlC?ɢS'tʔ@LP*$Cr|/Ǻlwb s8"v$!Iv=7D66"1ɧ1((4xw /zC O4{S׻\lQa^!aF&#7oi9ABX&0N.dͳ%oQ)evʹ'>ۯvKsk]u#aҧaD*]XFna'$&;m[w݇3+ tpij+@r|^#,0aGN],ښQˬ'+>P -HPݗQ^b6 'q@ Ѝ ]H^D~f; xITEVޯ|]M! 3݈xbqBf=eLك,P z]@K#02!HT4%G>0&#fپ,M[Ȃ[dB!:*rgM#7`"7};ej sZ<ԫ=8tD>"NI_םBj $Kq8˜]tJapac3|H7tZQ}CW;[^IF\vX[%G{cG2zeX;MJ,zahZ2/IVЖuE;OR OSe ƽX** RܪzkƂH1D9^@Kߒy2f<͘1'N3 p3*Ğ"4B>{+}|&Ki^ L"00 r Dzx#46 =<.̲8~P,7I%j9ۂ@B[pYDe~Lr~ I+VL ڊ=# %1 0צc ~Φ L!ŭbL#)0a !IᜡKX1-wvMK1ޔNًX^fTƣwF!=]QDh坤2%_IfDh-0!ӒbxlI4)8bvJȗ@>!%yn,X 56 ,󴬎HW>YDXf+8r'>TbKԜzGCD.*K:|ŕT?οd9RDehx?ԘS4Osémjs SA{=8ot꒾G#iPQ0 ė9( ..ؘNCkp#A? 6!Gq ]]'x:z`*Qc\93nx'\K2̘ yF$' 5%4yc>jeI C^DD+)kN  f=j6l2ᤜҐ#ε7 :-xb1OIG6F. v< =? MLv1|r3[j1hn@&ٓ5q~. &e@IDAT!}*~׳!1:`.Z@x8lMB`5t$`2d E?v$4| +"؏c5SFdng. ,# ӝ~!O,kcZhāȊFM 2>"R#V{\c>WT+rY|AZܰ󟻫qk<Fifb #loKGSἺz ʚA8!]W>٠+4lmj۲zujd" #O/J4"($t#5?vG5 L P ӟ>j4aH\&SiN۳BO!po tC(1nlw<VYcjo!$7dÉ3|jzbvJZ$4Ζi=QyaZxRCvCD$LǨļB+8iՎUfQ&{q؏I'o݊$y hkl⌮go2=A)f~ b!ks(O!`m!HUܫ@2F$J+TK:.V,.F`M;qvI?M;  $Y όͻQR~:_WR/6 g"]Y+bwr@V:rtc0\((ejdD+>3y-ZglaQcjn3\9Gu)Ո>?Mf}1٨P65.*@d&ˈ&.-iR#$1Sw}"c9X E4L ]eF әd. lkҫd4H}@AXY$@ o+ޤMŋitʱҞ4CG:ALyiro~oshI²Y-0Q3igP|u=fL%k9BTcւ at>k*gJM(`L"2$}%$QiP{MN~86fe514pZfbdV'sr}[}wYsel];W%p-"V" ~]Ƥ5.3.=<<"?&% 9' 9t"v!hnHܭئ59)}cб7脞*0B$еf qn9]x/KTħOS}bAjc_\j[g1S׿6)鰅vW*e9a<,CIG,ֵ]B9;(&-5i9s.7bm+LHEԤ0RD5$`(K ϖVq)y"o7J&"$DGsC$w EuJI3av63{0Weu:pj@2,Lz'*4LF,dgl^`Fr/UKtޑNLVɜ wYsiqL!5俗T;hui'< 3 &y~VzH-Ӧc3K! J,<k呶kkVv!:^?"wV+:sh~VjM s"5-5a[T"u(ȿV8]ɩ<{+bdƷMg02mbj4P/CuiRtWL/""YIpߗZ9d03v8*/aSNuga-ڋI?OfOT.5lI'e<{ m"D*0,/\YÞQGo}?.62OY݇ Fkn?3ܰ=YS{7ؾa S?Ԫl~?hR:x(gpUĝRq趧 ݡU>5R"8is˅u^u饖YSZ;gzm:hB# % 8aؠ,OBJRnu*u$} 12@ [G]5N C`<,%!տO&'<|=JH9gSfH%owl/eM)J@t8}?d 1 SОVf٣ e>*$g^,$0W;t"4BagC"ԾfCWe\T4YFeY /ї36֖\h5aAВV@[:2Z[eEY R^@Wz>RnF!]S7׏FpZӳ4Me)`BB+nXE,-鴯xzM4B?ͯ¶8m pG+0d8$aBE1Ζ*  \r )OͱjϞb XI q8 ??PJ}K +c$o:E !L $4^sY@aR:qJ}.X bP&M4dUf@1M ٜ3S+ TxE ⴱ= TNWozS{BN/Tԅ4MF`5rժ쿜n Tt`>W!jF֝r>,xa dK3 O")+Q=~<*o(3sZq)rapZ&ރKQ|:EnO1XENRYVF zD]Cp@U -aI/ kGNni:5RMY=Зpi{CӝH TޠqD gRH"41^X3<&s@Xlp'?4'qlmV*opg4!I{zښǿzjDBbHOd<upQ:/ #':QV-&$FN e3S8(,E&ep AC3X~E-Ty$obKrܫ>( WtZw=,4um H$-I ~#lpjy\aRc7CgA3,K=Ԏ0I(5`b)ۗ#I)ܖFbLF! .% GL`v6UvRGXO6B)5$3Qg YۣW.YwIgBϱ ŦDPډ=h@ Y gI (˫fsȂiN!-%_6Wӑd4/Y#JZ\Z)QphcT4U%=ed(*Fhh,u]3 e'2rW͂x)lK3BŸL߶xDòPV\چޒ 1ZS`b&:*>|JS^ {cuI<*R)2G/F܈-0r!Ermk#46?A 3'RE *+5l~ETYmC‰e4I^exp|jalB Rp&r0"\iQ$Y/RQ>e֛rTTqL,}X~j 3 OAs&Fw&bk땸uTs*&PY48Q6"56Bsj YE[ClRCCD)2+*y@,w3923p+sƌ0ȆqQ5K,N`ULG 'h,@[ʼnB$Bm7`zh)M[ *W[>)4fPO0vWgrNÇOH;`y9nPQxEk8H{B>^Nqqi NNqw54 9PɰTi ʏ ^8@̃z#(':&HG|> ̐eHx+@ g֩Ѻ"-Rv/iN]w*Wh;>x5R#` *B3-T?D6fLbᗽC@n^0M]A530=2w!&%ׅ ambCES<ƜlGԳ[UJkhm`looM&5bđ?[&643D͜ܥXAd&i JHP*vn"rC[ Ks&zdl(\q4#+w D.y"ձ3?L@ȶM J2R~1:E#䤔uM~K1p"DQ#vgj_yUu?[D4+H N^Ziˬ?IH}\b >.+(6z64Y$!4\] 5lg* ˖$`9 MX/3Of~ +X'eŴ iUFjz -=W2OY6޷lXB'R >Q:Fs?6{ף̘li(W 0΀$"Y!V_&m%>y wGeZIcŰ;L^0?kØk`9BLk(nJ|YC|oMrL*TlOr{^~q BD j.̆s!,YK+rХ#x8\HބK\M'.)qx޷FX}h ClR)1fD) 6FisI2پCİ7L9bֺ#'6 Ir^(f˾9|0x!dΐ0n^Su!^퐼88/J3*o3fKy'3PAob60'Ðx)s "k%_u6g8+nk Ę-ZX;fU"kFoZ]0לzeA]Q89k&IalF p87+@l9fXhQH/B ,vVVwtcQT֯r1ZWPCc\tAJrT?P%ُwr>@(T5q e*ZLk ztƦHE|kqS+{ܗӎJG8@"rR2[xDKs(nO DLGF[ۄ;}55z)dt9]KҠvYp-ߧf,sX(8ȨExd2HEǀcPT(l K 1 YixNJ^`|N q8`)b1@kXhv%ŞH4QHz[\Ş!*c lL.D'DCp|PFO*d# |rJDs^.lz0JvdH =DhR|uc!A 2W)&-IgvFZ =LBR⧜ȃP%%uOqk"Ɏ*d.>i!SoGVU4raeB&`B_i@gv%4$Aq ex1OB 6UuT4mRԐ !DL(x H"E@ yzQAXΉ(r/ Q0~b$őu]PhEi12Z} 밪w%ZsN󵋑 n?oR%NuZj81F4v@DQPLu9NmQ|+) [KA g#VE?i Qf,Zs#m Bw&Qmq;naLsP+z~1 ME0C<1Edbju  P|ϠK+[4Iϻ>]%.ԉ"2ԥ_+T?R rqhGFœ[rIvO:2mkJڕbBQMrQgH4ÒrrYesC/ɜMEPe:1}__kpyU"!{$4..G(4B-Ley:F8nRPؾIg@c<Dj?XzFH"C_9#T*H Idaꗖ4+=ЦC:_'[C[t{ElE؍(x|6mX=&Od& b19P]ˏZۙ`޴tMKR3OJ[ѮkQl\jO婞 ]d ,ƄvdIKu߅c+؈#q)_1ook[␪vPiF !}`ֈ>_él ͺʐ蒘k-3:Q]8i4U0#Jz J/s Hs Ii8/E D/o9O@:CQ'Jf@nԄפ{׍˅^ʅhDpLi : I 8{\fqbe<8Noog8G*<14?HhnݛGbTq5A9BXV{?QI}8$05T.[c3^dפD%HŎD{0٭E{!7Tq XY,;?03codpeB]6DPy_i4E u\!7?`cć `D;_/#l4n'•Տ,,/#vMxIKB^hLs oUATd0ҔA'y|4o vr*D @ X .'t)3GQXS\>] &P׶o;Ox dž 8_YCgJC$5=z{')l֝{uUW$9r=D--֣g򕵔 uI euBYe/xo ̥w Hzߨ$ۑ@g"]SQ=i! `0{A=2)kơJ {ヽ A0K|9x*%q~If cLꗼ>ng 5< L91 mԘQQyݩBtRe _xDJ?9%щ65 Q+5Qz$6l:n: %lMh hq7@Vdg(^>aϭI(k,߁.=#5>ZrL7OqRY?}s%B̄5.F JzG.FUxR(9NKM&`~q\<у6^TN*QYSk0G+#3دFI,3t.r$hۆ<}T1sI[kJX.OXJLS݃)Ku5Ak⒁-Oƽ}T6TZKU'W;=_q9gG(?Gv>%h/a1T N"ElFyt)ѩ\58ra j!6~Xm6N'-3n)\ g7 -Aa"H,'b M s,r|X(<Po P>]։nI}>)<2%0.Y̎|8xN|Q,egiE&$vaS-.Ž\i$K(s8}EsAA5f4'$iTE"PiT~ҟۡPJB9ZQ >C>-aM!@!.b@*(8i2js,eaBuFWz@+آFTj惕:YOϤI"+~3Nj+Y7!v8L/fVsYN|S.sZqI( W ZTLĤ/KuV1C8\C8?OI֧7ɶq{Y& zc@_\ם7iD94ʊja87둦 \9T@r,M35F"ی.|TNOYbZrYnT®]Պ5pB50a'ՅڜKּr,8&oͱ118%{̿_m0(by\uQf9G ƿ}. =B2&Zea>FiXykАבt${W\)4;ޜ\EG/$vaQVw7K5--Őbv>1*nwtkaI\oLbU}6Qa]KA {<M?Z"DsSԭ5E*zjV!ePs9](R3 gāx5 7Dg5Xl!^Yva EavGv0>_7X%P H5JN0Bx˰I"sJe˻ɱL2]\;쒼a qBuݖp1;E B>Ek@IDAT@A)L6MsuYQ۞N'$'MRʺ:6 ĩhy5Lz(J:m+dNr7F#fe3e`8ўE#j\nΉ7 sG,QC?\C$̛p] 巠żPִ rсKz9Wذ%QoM'X/JK<:g,6Uӗ;U% F ;Xw<.E@fvS-* B̝Ο9T(UpEXpALcs+!]Iwѡ JWkŬ8m3IynjU"Ʋl~ѷYF,#cͅEeW%H| qVS#+9a) H* ǹ}lH񷁥Z4|N"vGaI;2 gRJ؞vo]F:M!l)A})t50mrфij_M.t i2jV#7"IY$&̌qHzɬH}c=dz)ճ Ԛc< Fxv9C{FСwk(X2],xHoב/a쐞} D/nk^MUVb0H|EHRt0~'BCM] 7%Qb}m\jPFF=FFXrokBٿ$MmYnq Heiew-q#Rv|;?D&)n};KN dmTc$S|8<kVưjaD$m?Q6nUW;o_#gXY P/ 0OT fIJ.r nw)6j=3c;ҳhܦKojJFۉTmi'aLEiJHUKi1|ëA2@Ҷch<+lAҌ4d*נUUI֚jJNIFm 1D]d5K:thr rrG@Y?E.#< ULAU@WodNGwXSE+MT25DZJ嫹VZΤH;]NP$f[3!q:͌̇%VYQI5[ÐÁ ms$y21 Bִ;#O pM0lby#W 8]#l7h\>G"Tj4@Q-HꣵIZ +Ndrj Ӗ[/8ђC*xp5lݎQ s N<!ż4ِQcDyDYgu#3bȑCۙn{G4:Qu:EOW{R.$4)}7h 1)EaFd4.m|xD;baWKigG[b pUu4}iWc'CU%7h(пX}l3ɔ^H'8i:<%n:dm[a푔M:4NS )FM:᠎J 6wHTI,9_ƼKmtO߬Bh8i#W-6_Pl=-緡20AXYۖKk=d_vK(.h*sh RjArKU}ulQgqd&lE@x'ze13>{ ^hf$ic2*/*|%#OqJ-IhmsvP"NݙRo͖@BN,K1e_ rmibtw2}œ3n=5x,CZ$,;uYA`6x%0HdMTGV J3ڑoPPSDRà z*܊XƠsC{g8MH7V92M̋z &!!i|Gd'C%PGOKiien'JMA b]\r<[Vxww/,tD\0b Hnfx~f^oL7Ŵ9zń'qKGNbv L%7_/TӦ$kO mHe[. Tޜvuar.y31j嬃|n[C` `oƚr.eCx=[Idez.d3 G:ZB(w`Oވ!IECGѨW~ҧ37`g4q+R?W~q?$ x9_ψk{i.2wzL}Jfa1;%6p?7~x4.&*0TOΕɟhf=l#\Us .ECT2gX-;Di.Ţ7qJ?p{z8{KCtqCܱ~)}oˈk,E4C駒<{Y\>=3GVm& kmZ1` V9K)xX?>>w{Õ);ݥ̘rh`"[TVꘌ47gAtDֵ㼺UW/RMTѻZrpHG^pi O*3qz䁱n=jpV\'F6trK15!׷s'LjhٽO}d*XB|X[#۸5<I~ŞՊdEQ9~A G-` =\ۀ^LQmkiTFq<ܥa !Ӵ]wlE-EήCWb+ <$&kde7l w~8‰n7]ivt2 CG6>XHR4Zqmf 6k$eda`ji>Ȅp XNjXگ|(Ral C >Zx`<);^Z}3 ~J n7Jkup >FN`(RrY)ص@Ʈ'2(H\89 X %AL,ĥ4= g}(g;sW1S!Fg؏:JSĥ#6t@ v9 $!㔀Fotbad>UkrɶMgBՇR6@FdH(8>~+(AX3ÙTC$ JeRLϕ[:ŋr@F˝Ѩ8=;gUf ^ :̻.1 aW?3Nr OS>:;: |T,ܺm>ز9Z`lCCzpȁvS_ۧh7TZXb/d)RwՌ/ RzysgCߠA=9^501; ?yqGb[4 /M_7 B*խ8$hw?R}ZfĀЋ!=5jY{ w} ~(lоr2VQ(hʑ̒"g' nd)I.K㑚϶v=:].dWI2d īt1|YNhF&*̕F6|uz/ ؞L,&p v8ޟ >8lX}qo$!&'10|u+N'.Ji/V0SO/O39&-bmB[\?q'23ָȥJo 'N+JgN7f[e&RW[ҩ-y <@;7üu}.`]4*A9&RZR*zDQf2צz$#.1LH:ŷI2Q 0[9yf/dP)cǑxSQ8E:G,$$( Ab 'FxcJ UhPoD1zkp Հ vlYgSޞ֎~{5`2@!x~9Oyό$+Iٲ #1>fݖIcT A^4++?g,w706!PFLqS*`5c/:M D aGczy6jE"NMڻYߏTsz0vR-^jxվlAӑB79ϗh8e1ml!L]Zвt3I qu/RH3ѯ9}G kird{g@\.b}ISF+)R EB ^o5D{@R8[6*V\1uΩ%@9&QGWAp"$N.巴 f ܴ NƞoߟJb߻?, Yc8@3Ake@?ٷlvv+L =ƂpjXA*50<!uJ’ĨFF<,q%,>\D:G"u.A{UvPdUdPzJpA섧f08tzs ^)hz3%1ο̗]k{qUd5ͩǣa8?WTk13 y$`)W 3ޑXpzp~'Sf]+Ê&L2qhm 0!x MAl%u7EqdX 4\E*I,<{B-ո%N LZhh3C) ^_;dw˧#KuvjO@?'ֶW5Zx׀m|SHCr-;F %g*Th8¢%GTa h mk^T%w5&AYC}s’S5W+,oI̕*,9GګN"QՋTo*$@ Ś jhTmմLq= ?Qr%.\Z -ДqHdCtͯk6o;=F,ނZjVEEv^pXPNim[2,6#JE~~A BECvx3{jay0 0B(<ΤCHgtl}CW Y*ƳFT;=7nU ` i"㠏.E OpOgH-5Bj7PEzZ2&F7Nr~g2jQK{Ρ5CfBQ3,݌.+ގ RH|unQ 巘^ӥx<C2@2̜b (uua5G^gڀcᅣ6=dyLCi P(>dƓ g s`$E|]+ESTMa>0h0\€, P..Q "PȮ{tBDh<1 O3&=OeXw&ɻWiojӽ&sCG0Q&*xw⳪dGz ^@(Wǐ=6J/okeazAV k/cIxNx3KUo[Zl {&:40 @R"m%8g0H9(+.MtЄ>j7Z?L%=F))^+"=lShjF^VhsUd`;B=Jزt{ 5y;w^ &S0U$A4 {hzq*в!M'.C߿ҡN$D? rj#`\6<9J%-:v' I )?\pNJGRQ!^<@]D2;s}D×NP7B(K*͋t~_ht.Jkyk̎4PV#g\osn@S: =-|!FCIy;pa4Q,p+$r<f&3,Ї< sf`L U{7=V,JĄ}}DmlijnT 6c0[(QFJ يT`jZ/jaXXNfSXVD*WrZ+m"h!]L"PpO[}-KwXEϝXlp\b\RQ[!JQ+|"0OH>$Yf-:gBw@ŕ]FgE1ؐ8٘K~ܚYU-̚<5H9 0di\RV)ù4Eh :r|"1a1=TB2΄~>pz/ vnFeuP7,lv!&(Hbcqb50SOM?1ffXdCJܔx^NHI|WL@gP.pl5_1 BB`8Td=uS &*jVcSltX^m ~(Z A ]P,m+{ 9{уhq<0KuCJ:!3Yݫ/@"S9#vuvOo&J#.YK{:%AH~ec~̴|3TxwD>$_B`s$@v/ XҭZs!Uv A;߂#&«.; FAl]q?tTDsa=&]8ã4\uTnsk|HeW8ƭ>21i n}s-nz(=]ŠlϪKm#4<Ùxߊ> 嚹x*rS@s" 6G@lQ1%&zf"W>-W'MEKvګⷼp?=i pi҉#a@)eӖjF(15I1X[xfofy -ym6}ZdvΙMo󨛎3R@2PحTn]YȒ]a" p|a-$p7I@4ۚH z3 hEr[-;OpB*[S ,×lY^ S8mV0bsD2O?wi~EYYS $+^\s"mbHe!'eHRPxy~7DYKڬۡc*BlZ Ỡ~cZ9 KYW|;hÃ()@6z{ql*r|CH5POHFXGHpI2nHa\DNٰy)E)j700Ӹ,&;՘8L)Y 9•S#@ab s{U8j--0Ӂ7j/7G(I4U1jN5rєukeQ).)( \2z( dƺAN2jsIcIJƠHvtgZ `N 8\%P Ğ2x/P֟X%d{,(Cŏ8)ʠU,j64$& fHu @/E|!X9#cJf; 2i ܴDQNiD]WKbz ۟d*}ٟag.=1Sͫr0^3-*nGHkؘ'cNUTUXo|'qti5sy%l8IvJ^Wo(v A0N[5sx3ss:pD<fOU{ *$ÄWaQL 3~sx-jNߍ{ P9*(|t,q( _?.>>/ٝ\} ptnBI9H3ȕ<F[]֝|Gxr<;o2N 4[)2;GXE"ON$c'!Nzt/O_gHt.?:{x*tNyJ*j%ܫoK+Bܷ~)=^^ER [e&;! n^hZxes?*S>t*KgZ;*]@*.g#¶6~k|XS~>0-+0qD훠.m_cEŕ$ʜF,퓬wL 8+@trq=PZst`.laC@onhQ}k^F"OI?7R{P^RUٶ{הϖaˁ_&Maֹ&W '_Sh HV&4v?";DM(y;vxمϗwW:CJ4Q:Ec:.ME"^;X̷ضKRqhb2"v~G2l|eGju "??/ct haZv|_7gu/$Ph<k|3X*=qJgс4suk sͳBʶc0XI} *ySuu1´ w]iƎ|l po ΁/gӳ5&όd }r vc矙MY5ǰkms6va)2;xpLƣ,ټO79QB9T3kzUNn| V: $Cs;?]!:RPAP3Fo]goZYglNr0&Igyo4%B}d%V:OMDCPF|>8H D 9UObfZkxC|]f⵵2]@t;Yrw9>WȕZwKѿ3lTM'%ڰRT/ȿAtJ l@"rT׌]= JM/Boy1kca fVSc=A{8-mDUcgr:m#@l@REt#cEYAZ1KQ,wZ:g"-\l$4䧶X R|#eXDy@uplD `-= m_ [ $#0IEIJ9ekZRu24hjY|WS  J>jK3LX.6h$= ̂Mý/LId%3 aї{ mr;BxG e<%.0m`d!'u w(Eſk|IZXJ ˻LLS|wyHvqZ]%.w)j=0f#u/TPz!5j<^f&ahS}?~LLR4+XXf ^RRaCеȍk)a<{1PGOf*fjNV$z,Hg0uD"̷s ZY6Jn2J1lo8,o @?R`c n~\ SH9y[l'F!+|I?y'4Z1P Q:B3&'q$;9N>fPYWpGu !%E1A⩊WBV? ivj./Rne`|Eә4x4m3+T6Zѱ^Hf^@__neP`>~JNk<Qg%!vdH@u"R)N^r= H` @/eZrF:@33}d|&eEmf65!.@15id0َjVG5"՗6`k-sc)-|Qu/KW^ AʑCdh02?;I⸶8T&15o<[(G|`4|KI~G6,iy5dHֶ8\ \Ŵ| 4Q ($23Iѭno4e?EiB?$>L?D$<,cuxKʇdA5G.= 'x.bp,MD*a7Js/zBWnInu`>2CNA !>j RC nx2L(ILw8!ԋ80!â *5A~p[ "NҲ3[ h59c9᧮#y RivHf @cWLA/=2m A E a߮vڼ?ғD:lUe láqY}Z&}j=İ|o,>(oƁA"ԞJȱv&62'/i#;ՙ,0:<1N6+Ft|RĄ6OPnh#r:W p1ed<a լ0LHI TAL,/YpPҕM1j;AQIVE~~B?~].m{uW+ij|ڤ4iӮ+s7,$%󂬩J8Xc#:"?ApyM#_fZ.d^VB6`rDD`z4eV+0A!)C%헏n)j,{˘BHӠ0a[%aTUڵwFfH"V196BV2_$p)~AO0A`$ LL%/S?sidӒCXrxTv=. XAGa]dl&x5c"R. מa|T;@Y1U0"*-wg>UQ;Y2U޶qh@|Y[܂Rm.L T 9,Ny Emi>. T]znݽZ[Ցt\5u]Lqo+qZI4 K ( ]Ƀ x`]t9R5U 0t.3DH=8vDK4m7 Z @ +@B91+d@X 4X*Xv-(&KAD)2'.ɹBڛ3gs|U*[٩3z]LnLtxПNCI!gۡK6Ff@>o׋ox)ϋj_|xROXXH*!:@uEP49Ct^,I&Rj`"@_6^?x2l>AW>Dx4m1: 2S7\)AG Bnڑ*zC-Q-J돀42 7߆^2jp4W;2pxPd@w%sޢTB(Q aP73X*1!g=>/>pVrf}2X!C\Ћ ŕj~@$ v6]ͅ&F1Cpm*c3d'a-|K-/9n Lzz5D:TkR2EpI e@<8@5\!*6JZdU !S8΢??a- p: b%C{>~D7(Ub :M᧤(cXy<~1+G)n"خs 5 fH;:b7<[J*0ai&p!y-͞4`ϱVg{aJp/Zp:X&a*!@Cܧ S]s8NQ~bQ F"OZ>m>CRJRógS墔N(Ԧu!7x[VxoeguIoiG6v= Fa/0&Hei?s;Uo 924uj6Kտz$;a8S|X$m5Ru@[J<0J $A q" (s=_oWLcAÜlYTQ1h/:`.tEJʁݺ<)?zd(!MA}J{EDFxL2qGiA;tԞڄ_Hxp|> vyܟaZTja)iw CqUG !YdփR4 fʼnxfɦ۴mLAH螝=*J('{Eca#Ah[q!i$( C Py[>ZK=؁<hKf5-PVNzƙ hd4R XM5!1H+gg *K~P9(ow05}77aA:h~Ox{yxVRј\$A];sL}?gT3\< X ?e 7Nk5l9qLa/vѧ{\`KO^B'^wyja 3*}M8^czJG +V0GD1 W;0B)oe֐"_uɓ%q8H9[(st~62.a)@C iFR.8?M,d4T,e`REΘIT$hphlmf3޹_'HʯD]Y/!+A PWVz遼v盙_0MyW o~0'ONEOŒΤÇ"aiV Z!h8s:G߯ u`ꚩѓr>rGX 0;ipX--kgw#v=^0e+:?Gg߱ ]S0mMhiv ޵|sȊOnbM؂d'y E|wa٩k4x/WƶL0yaP-uo-fwtle ?7ks+JP%;MnnG+͒qaUm}u+Į/)/ޅC;WFTY`_m0;+WQkZ]rpSDG'Txy^[Mo s۾>ϭd9uZj.fu"Hj}\,Ǎ_5z0baN Z"z9}f?bK+iGN6ty9*yNxھoƼ uscwԍxYuAxfLHy}:Qw5{w);iS^r _/gv?| FYPUzr+QڹyZp̹ڦqݢCU(c>/Q:l>m?gctJC/ʶ;~VC^Vv2h٭2ɗ5fɛwݡj̖v~<S@=A8b5$<)97K/4R,wz28b;ȵt& LoZEKn$ӑomv#C]WQ2B !vVr$ʪZmhh2 A1wt[wVaQU 8ĒA{vl$#cDfb¤yn$.6 {ENkw蹓]$s<&7jA YZ#T2 Bove m͛z/`QYN >6csڻ[@` r@ VA¤?b)Aϴ8;W :=kޯ7Lz{r!ڳI]J~8%@U? -62(96 >_vo^[g.аWMd*t cGb;$9l,KzO#.ysJ8ǟ]B)M`2oT0:_ IM457E"R+ES0=# O1n>fVy=Vo9`=W V"aMEo&Rf(|M"Vj9:㢕HM^ѵd}(ѱ,!s =:$/C;ͩ[k.3,uy6!/tj,8+-&̎\B<)9M<1#ӥ.^ϗ? 麧S!;]<3T3t~/A ʠ@9X\ZLJ  fe zhx,V19aӍW#.2 /Ƅ,-G;y)n; (<-3Q_Y}BAD3bHp7EO"T;ya -nuyKV'4hp`T;;T*ٕCH?q*>iTNDDq=] r3VtB֊-!"mUr3˝HHQ޿l$9 ђ]\ΆӄxBQ04`CyoYdHoN9ؽ8G1JbIdZ%$8L!=N\^  3DJiCy"ZdP{1&?;{4=c~ yФ0όe6B*jDzSO)Sw ,Şȴocm9 &VsD;v*uݽ &DƚY.9_Y9zF(b&j;"6&<\ѱI 'ZQQ%3 ?'3BJxl0ۛeqA`j,nHi r2,BiKvG{m{?>{u "GtYȳ9MQ_iU=FsQ!!S9ᗲk,i_ᚢHO1"9@s# >Eg!_APl3)WZ];xu{52z 5],q06g6dh|Đ@$T~}0gKW6=5p?Sq)_.[/Ό\WH\v%te>gͥ+- 3O j<#`ND#턼2$ƐJbr1H(Ĭ'#Ɠ޿XЉyZ>OsJ%f$+v(-GK\`u$4EB,A_==T|5"jv (6wV@/,H anxfE!Ӥߝk>քX)ڢ]ˤ+[jR4%`?gBx8QNƉ̶|%tp7<)f2ɑ'8Gip9<缥AO؋n@NJ$]AőVvz[I@@s,+ -D Aᣳw|rhq&p# uFezH8tl\Ṗ_@Gpxmg:N)KGK=P@ϰѪ9?#Iar4T tYI4r{O-~PK,XǛqk6}.,b/*K Y0њscH緧!XeM48J~I=|tJ7 B'!Ėqh$ -Oz3YԎ<:j p}C5N3k0$BD~"j|"ٗ`;`˲Ѝ@bpu.%+cۛSҨ~TqA%ע?\y~STn׭D+JD3:mΈ_|9*bP>wP~w[y` ",pcPg|Y ߷q`Sy^IM]dS1Ջہߟ)YD[vmQsMGLEE8-cZvRcC \7iOY k@]os!'RH/9 9yKG\ia+D4j 9f]TCP%~M43 <ә>Sc>;D ʞDsxQ`o%‰e爙+(&PrGSlІLB<s .%lKn17{nZDYaÿ{ZDSR"Fʾ㦕+d<ώҧ*N~Tf5)`-}ڞ k :e:h1|8S4@΄ԣ;xb|Z\ &|N tL֐mE@*ojn3k8 O x "\vNӷOX^bq@:,ű'Ƀ@pABFcqE->u|R_.7G,2I1jgJ_U2KG0{u|X/W^{-G#Pr) LDEy}8P۳VYy, AE^>y~mDfZGr}Œ פ!hmU΂+>A 3>8GvpFlj G%/5ݐ76@Nٮ(*%~ߺ >^:1|q(r?\&3rbWL(Rum(o ssijmf8knv}+i&mN | l1){FXrù3DiKk,&/GC/z,|ԊIAmpD'p̫lzj~B/WKƂ֭X$p#YhD 6XKqCOA a\׉!3LǒOYk&1GeR H$`qs}7u3cK5'WjJ@ryPS^ iA mc.\D=EdQ~<C~ DοuD|mQA_>23zĴx0 Po?72\bʅ$,2+2zmDQNQY{TiCT(X(3`\LȶC 0署2IpC=P(5ЋN8w 0-EhqrIwδ\ᵱ|u$t1Q<ڑʸD6M6h3/X <tTs@Zfc%w ӈHBA_& 8Lʵ3K}U`N?:, -I(_'WO2rğ83Od a0's"&0 bPcZ~ W=`/5>c;"vY$Ñ%-;b& QWGDe0G$B-اP]tedLݸP&!Оߟ(YHځ`JFJtNԆ12xcCfM !pJd_TFӷlL˜>$̌(c[ MDFlx aŀdWŅ[9p\7 6R-s2+脛$XU'!?bFgсB≦pOԝ-6$ zdf֩nt=驓\ Y#0;:3q0QFÄ;-I仦rldSX @ev:e"zm3r{# [dm AT\)6F5*oȁxw ruwܑ*A ]u{]g,OqחmsfM5lEXBDd_2(,"KR gM)ʝikʬyG1ۅH DsQAuĮ<Ț8frO sA;*ތ1 l q6oCE(9=G+5#2l5;̉;"mJWhțثc. xcV[p.Ϣ[c6kN֥B6o/Hb-'ލ|+j~,NhuFmܤM [O tG,ɫ叻FF<̜} (x3ܘQ_""߾8RG^ӡx6yՌ/u%\y,42ĭ$]LvU v5(VF+*E_jytAUp@'øUx<6Mh o  },/„̅JvvNAx\Xr퐏RThQ-h!#!Q?_,l ̋5;HN/J5[݈,s\DOb#hI~ڻUM1A$]z~8PMe1T} ϲ 4NfHۑ8Y`@'a]TJCL#_Q+:]F|+r3[CXt,9tR+ݸ'X &NSB?q_j!,^ *1h<~z~[Q2,&"ѵx `AEκ*;:P8;mժS.,h s"ڍkK _O+w;3vlT$H;F̕Vhp!|{$у-9-S=Fh RPd2Je |T傈hCSo9W2] 3^z:C5"YZjY+CkVjggNkE14w\/i3ͨf P^<);1IqAΈs6,ASmhĎ1\|02^x Q xy1wȔŝw#Wz@Сl#l}FC!$Q))0sc >gg.HW&&TSgCɖ1Wf*b Y?ʕ\qPmoT&9Oؔ˒drСH EC qU&xlyv4cG1Fܢ77UKɹ)2`wV:+9:{LIFn =Nd3Gm+;Ȇ[5/#yLwkA$UTF&gqY ȳXh^( ~02e).˺8"2\ NKKviDQC鰭l}Y!D,9\i!}o,ʸ4:V896@WOo #e[&4Ǧ g P43i~7&-7:]z'ͨۈOx$ZYv9)?3!t<#W]W g܃tOGZ$.٤agM597tul;1Y"=`.:5ڣ0#uXҿ!eBR MF(?9R&sVU A@" LP;BTn1sRH芐 4HَZaI]r.hséGQ_\"V6ԵN"O:(!=n|thy;rv>u*w:^?Rݲx2%ľ<ډvkaC#=UJ@h5H͹aVV~&4ڨn)  zKϛLTo9}lGNN~Og`u= EkcNy7A5ZTh`u8cՇ 24'`#zj[1yFgPm$p對^ITebx\z%<3HLSk[ᄛxFc+Y-}V4ۋ ={nAh:|2e2D'2%!N2 s8hf5uO:hꚕ!Gehv*5@]PSE1z /G,/o!'c3r#]S\SBZ(М@-q^@}ǁ4sY&k2uVi]=$#c4f$IQþ *aV!(2%i,TOV(V@g90k6 {iw.p:d;wdCKWPЗ!!]ܾrqOgc_ҍ4sZ.sx0 #[CܾJ'Y":lAd.ƠD@P7Coϻm8$E>x򐼺TJ(+v6wIBM= ל'ih/ƥMHϓ(LyGΏ" #|G`dY2 >w |KIbRI/,]VVƉ8ʍ8щ)6bII9!`FiS.Ey ZbA } kc`}["|~W]*u.!`Ap6 j's @[6oS`KHzy\xmo NnLX ,W~oeV<Ζ',}S+W#'K~*A>bɱ{ȆLcԗB+͠!.zlJ C'Ŵ3 D kUeg@1&ȭHs#(ȕpa^#sD$,%Lܠ-J_Xİ&CPnSmԆD7XL1`e-x}ĝ-0_[igG~F9e '(Ðks@T9C(/4KR !ۋ/_C Rr5PMS&A\c&.ۉj HEGY~N-YDwԏ FqPbm%^ŷؖf8.\n ['>P)نLwp|}k"fwIh^["Pv|{Z P t!k^la!ZI@#Ooי3" v5׎ % Ϥbkg+Hqv+v<%]E;u}#m^ުd)Uf/31^f(i([0='!R\䕔?E7Iydz/¹[Kh5bXC }7>hAN0;mX-rEwΆ=ٻBvA_pz$V^4j@`RU'ӨH-%Ip=tõH@A V@jE1 l eFJf Gp2뫕A5q#k+-go'Na%+`q:sEvDDHb 7ff*Mꝵ&քLPќZ52΍`T8:FMf &BJ#O9X);GFcH.Gq`\.ZNBI7ՃTTtanIC "+`=tP4pl{FT8g6NYHUkܠOp%J.Mnw'I/N̥Q-"=#f=*Ҩ[ 4) xr^2ȬffOC^mڍ2ѩe`F=VU,PDuLWCݩ|Iw O,5"]Z{#B;f6߶cAb/-p#|mB W"E87\c1=Awd!FRCDgT P+s\FG-86vHKJޏV0x-oDcWDy %B10i0Q$]SOb UܴSCoc&nX ԕlf憎G2*u3C*V4E#dҚ5B*>τw/9dc}kYNdk>6ȳ%RI^:ċ,kgR'*(6GPTo\I3 F&`<}^wu=,`{Ba.dST} ha\eK6$ 41 ]pC5 ndV19n<r"84%Wşf Iݪuh.ZhT WJcH>⤗.!N,8CEi Y E8H \v 0##SwW~0e~*Yb, YY)u7X%Rh!(3P{<<Z4 Eݜ^5eJBwnry%9>y$ S0sl (],o m# φ  vݘzS ),H O/S%1 YDDiE#T=­ech0q^Rxz&-`5D82kzO0jXRsQhrK}4DbvQQ(#kŞĕpZve!=YUJZsl^VoE[.ZW0蓀IiVnpW B~Obke3#HJ+({UHwk#rYeRQU|2p3C no,-Ev&n,a1sH8Vg߰'exp ".htbk GGb#Fn?A> <"+a:Ao )FtV* hw}*IځMhI'Q|ċR]%wghxut(aogtys<ٚǨ8'GZV&34-4cGq/5["؉"A't s&++"'ʼyx B`C#sM@S MgRa:yN#(qs1,.x@IDATDsCb:qUj<ʛu[8:~WD(bټ>O4f ^yDKЃX| ؁ovXIRTIlPE~/T5PKȔߢ fT@ Pv揮[i!]x 6'5U8jF'Gky1!hRNJP2Nz+.}֖b O?<=Sdv"YX|.8i]8L1"M( $V˩K:if_GF=0E $[c#p VK?Nb$"8aLS L}i1$ M@q }b&M*`N2&u(UKU+x.r̃'Q\MbIQڷx1QŎ v Y0Y Ɂ`0Hh淅iޜL_> 4aw|*[6Sq ,EO›.L"ueG">b ڏ%&Oư'K9˥gjHХ0gR̗}OhT̀S eE ThK2[PJ36ć!A{S঍x3Px/@t+d}d| s6 6D3GqsIB$UtɁuOj5.i*#HU@$O?Q"CIN1m< ]ahb"}IMΤԵ3E'"a'(͇[Zd'0ӬG3S5Or2Igbܰ"  кɦuCxSHTR@FL9?RHY$=rsȃGQXCpS%(51٪$4}`oEv+MձHq+֏ZwA%HRLҟ7fRYQ +B;0-f9h#:q$) e$0 ֶ͞9B[}!/ ͛*h. fFzVzUF%_#R44O ! άYR,LG[IC\Ne)'281J|F PǡC{,gjlТ9\Lk434wdQqnv  MqswnS?ge`kH$'l1(N KEc=& cIM>;szkbP-lR 1@ Q6bEhR0hFؖ1g116Z˶!_*tfOC|f6E'46 X~siR(s^50FPq=k} LJg&8")n4eEFq3$pH4ih]Յ؋r.[]fwC1%WN?˔nL)Kn7~zaoFg&4B$"q~r1kU ls"FDǤ%WqI،Ԝ6Sc@EB(# 4iر}}aWw )^0_7Hwcv;!- ZXCR?!T-$0WdGV`^_f Yj]KرڑNHV(΄쒯"1qɒ`u8>[*}#5ɐЬ CkO?_$'῍C1rp0'ZR4TR$zQ?rnu9kgq2Mثny1 a"n|?K x,nrNp\;Y1aPQF$r%rMBe3)/>;D VQصq SDXx Cr Cʨ۝NUswUA`,á1C^n12[Ռg m> $jV*"ys. 8X̌Id 6_3DT)jYZon3-'X񔸙cyK Ӡ3y+$ Lae˟~Ȥs ['eXaD[3:"PRpv$ JZc;D)RY"8NxQ6tw6B G%uJ\=H ~ddבq2J$jRLo XXUEi{#58r(1{2?8rQHY4 }pm2NwHhl_?ʹDD0aSy;FtLi28*()ļ$>1Y5~,Ӑ)-@E+;ĭ.J*fY8/e d+jL$ܫ4)Es9Y6ljuP^¡FYWB)Jֆl@8$nSQzy66軑psʖ i 00*PZjSL>Q062=2x_y,Y;,>=Rmlaž ˆ5@ΐ^`'=NOI8S# 2@wH߄{Ryra~ @pՅ7Ph#:%d7jɿM[n =Y)Y+Í/FWa98}z )>쐮^)Z=j&"sd[9KRRXXlC&o&>@l];KKpW]!Ma%@ejM}P& s.#vzb],TWy#@7F~0=~]2a s1+:zkOqb\G̋Y@ kC(MHMm#?=AIERdGQ*a F1휹eR;0a R Vwv/~34)Y`"PRp7opt񃘆armXay|{$ΧUj_GPL~ge?qH83mh$~96)}mxĻ2@.qxpC8~u  n &;GlȺIpXe(.uPFswzb% EFDBUcׇ"4^LH>,0"%l'ʰ}]NV̭e{xTRTСQK=J`XҚ:RV8?sv1VMF$(-ۉ1X$kK;mHCzB!H(oֹF&MeXez)"Zƭ#Jrq5SkQtu֩J@FBM(0(aBVtaet6".+ Ԑٌ$ Ex89V& ?F+r+amCA\**,2H]`dL$*laRѳ t"’Jw2FE'q 3ۭF*\9 Z?nS=CWPG("E<2ov5scd}D)K6cFJ}l#nm @E #^UokqLFLQ25 /$*r3oU0IfO,bBjsz$d(DV%<~_X@7?5t#:1ц b+%+bErY5rSw߃C E (@Og,%OtY}P8] ً1'} 흱H,n$_T3ʵ:)PLC?~Ԩ"~=2_q6# u- l}OKIv.zP%^+Yqlɍ+EsChw+Ð7} $Y,Z6҆Bg>jRbCT6iO "z=Բ=j ܈zZ׶kcb[GD?>MRm[| YD3Lr&H)=\ȍ ! %D^ݖC%/ pZ}kq=GJo'S$]u4dueN)0jT맵"Ӿ+HO3$fhZBTlTVɏnw)|V44AHk Sq23PKL=K`9U=~=k A.( \/R"T- r-}W|QTDoΟ6G]=nUp-ɝ .aP|E+(/YX&UY'2Yƾ `A݅T&F&Hy2qJ% x'$ YjLD$WVר~Qq >W$䢍ƽb%DYP%U ˞Up ^26nXE[ +: ڙVV!WeDZr|> #Q VMY^jxTۙ4!Ax|)[(叢Ni*!0*—vq(]E4z\ZaqELC|oLGmҚ86O(SyX`oϚ|Uyoۗ}#R65kd-vReqS ^C(Sl%}gmN/d(VVk+pڥ>I\xV2乷g\)  y,aG@5oaЪFS?pHqAf%3;Avuݱ6ēTha$ @WiӸԍ&%;^@uAײZ2ģ`VBOc67%B4;Udv7 43q,2ʟ ;_>shP@їԶd(\\PDaߑ&v4Q_V2KLI05(d~tBcZcо 7O' F_ޮD-?]6:%ۈE9yd@$xޞC猉nZdoUuF76e3 /,Ґ4}.(=/cĖKl ۷dCexl:85^U=J2X\fQL28r'mk| 8Gb ϖ+zp/Px^~3EH!f)Ḳ՚ZIe6fln;zˇBۛ+|iBDmSȅm*Jdև|-uO!0?)@Tcۑ$+(IGN=S M܋n sW;NF$3EO 1:_7\JH1J ) {k Tx|6bMKn2cvys"dqQLkHF>" ZG~dQa_ΜҲIɾqzZEL.MӲv ~6#>p o$Z#W48'R)@|eC\ڀ`gKgC Yd¼uFR7ג>&,^E$Ogjx|Cm'@,޶!% tސ8fь\+ 6'uxiO-)2>G!~I uRdO"Va@Nč0眗1ulR(Խ?vɪT&YOMu^倌qPw m|(/+gލT]me[B>g`LfP#dQ#_',CJxETM-F\=802 a Ҋ5Khd) <šlo#7/lhfçj9"1Ә5[( ^V6 jOz! FU2џ4:622و\bi` 8 {7h<~>j !zfȿfWú5xݴQKþ|?΅\.e'PF ZĚ9K13ly7ߢ^MeD.Y/xr("0ZBbMb4֊ dXf^x$I42Ds8>sHއ"݌~ [ϟY~/BZE* ۤ|]bD(֪9~ndz>q"d/VD=OV}cRvKR=<ݡ,G6.yKihWnQ *U$ē}tb,(gD"+m[@W_s;{Emh%^9E*?VFOSob9SP3R+[q׽~)ai/UnJ$k V ئim+ct=51WіP]&ʰ%z dz]b#J(yMQ|#gqTI/h}iꦟ zxo@4W^9(Y+![LfO_^drU;f{R3q m/F6`2]D,g\Lk+t?'b)Ĝ!FdҎ!4>CaF Zp?&eQTa$ˤ}t*ɀbLtFdx"϶[tdKssB[㇕No/݋`H ' (&"1͸qy@`Ӑo$TCh{ikcfZ^o8m@bV{IS q)hG?Ix&UDաqX`*nȀ͙U8džPf*~VqNO䣓a.EDU۹[,a1#o.⌇]ËI6! ,wA[ 9JqlHK:R*D`K'.1q=. /~Q 1wZ'5a Gg+ۃ6~D/pU͉R!hϜM6U0Һ(7rm.1vg pr L,M`cZ1/A~'gǘtvj \L"n*)‡\`RGt|x!*"R0Ȧ"9 :rGgxtg}ܫŢ$h%ki`8ɎjP?)onK&!3^q &ڥuPanK|yn]TPteC4ߔ N^AD`&1+W$cܹy:ׯ}<2a $# ,aFjnj` Fեv}(vnZd?&O);- }e,xE|Wo'n8f!bL2͐) <\2-# хcF|rC$Ǒ~(Kp4CE[BHY-d]m$%4^F,(10NKܨm@etD*t ήnN.fX-aUSg zd W4&[T^PN]3 m b0"Ж)1xD蓽c#Dr #$Eao5f.dA)Y3<;IFޱ3hK'Jp` h 6j`[:#dٕ$?8\vh?~6Кl>>/ͩ)KlihhKI(yM [ bKc[ )[a oxyEN,~ KZ'BuMn.29$-D >[l"5f~qMTh˦l(pfD0mB $<qFՏϫI% j.9m 5[NmLvHvfP K1yJ'X屈u[d?8^J&6qM%BcTɼ?1\O]oa:6Q9%n!'a^^JA2ptuOK\Eaim7TP,,|2^̂PԤYEh<6aNf1Q‡TxX [qe\Քu{ (R&bmY *8Z@فcэĄr"6*'X&Ƒ,hNrO` ݖoͣ㩛Y[?u2ƔZuNcq IꝒd9XHqh) Fj<4檸)1D¡#6ƅ=HDޚ_hQ˯*Zx8\Oo//[9tj=W,jk6$̉jĻY$ KX0"% r}RpT1nC %̟pjp2ɘ*亲$9cU ukJ6ěX3{N+l0G{[_ +sc!ڍN{i%D9c="XI\YP''3Rv`! Z"T Wi@̚U3,JQ$Tla !%^;(l8./R Ǽ)u70Q:A'{>FT x&֞uѴ7(^ha_"|xl_zSiE<+ŦV3k5.\N`&|w,6I.gQ;[eH'Vw=:HxJVS M<`b"7ͣÅVS c3'B[ vY`gT_Mh\rdnZYv-*U)L@Ia`tw}Ⱥ1E5_'=aOq4ce:f *7Ͷg3J?x.ԐN"j9,*6S!7& d3~2lA/쀢B:L/>Fkk-~֚6i bD>ڭNlLb!U%A"B~ SSCQa2"\--*C5:>=L J[bA<͌ rg ;vnBR@꿟e6z|;g۟,4b;HCAX!LOD)w3\KŒ]P,N'ͿW %|S"d A3R\@Ba_Z@O ƛQa5`z0\cI>y,"3I uD1q80ZGq?9޻4 cK^ϛ+ya`Fd:(i`QChI/?O,1΂HZ[fLԆ*[w>U Ҷve-*l5IE0˷t X\w:B+SÒy2kk;'0\]$tF¾4cj h_ ]^Jrv18]~ 5_ⴈ̌Kv$7F+n+`_ w)RF=!XɴCI W'e)کgRQ>ǽ;+^7wSyjovҒ觏Ǎߖ'YO/ITH5>FF,+#O6avV|?Tt~X./~9_R8Zk\`d_c-l,6w*6̠n犖I^qy8L- [߯ }-* k[N,wI{F1-pV͒r]0m/N =9W5R`(’D ?SIݤVbD=4tɠ]n9ՈB[,#=Oݱ [phCM$TRrf3)xaJ~)֯n>߈(|hxj/.tW45ڒO;݌$RWk>_6q_nNaʔe (Fr&>c7w>oTg7}T֮v FC^r8M-!_(y + tK`$C0 S, wZE%DVH,"nc9flpfK:,BA-]-Wx9$dC0TϤRv-O'qL:qHG6@͚K$ ˳Eqf7҄V$UEqKqeǟǁJl؀*[3Le&&8# SF!ZRĆAW~dUNѥԓv޳]ȤPcr?@Üf*jqgII* NzoYb&jaG_ْ`p\vvK`,ў: ظ DtL!uN:?]?V6#)ߟ*x{)K@ qwau:XVPlM91~'H- 3j&9 7'w +b+HD3dC<|4a7ʇ4*e}5B%vyڡwG>x a<2bi1v'"Zp"΅h*~#U HG*w?{YӖ@K7FzCN;KӪDזvɨ8RD`^r+𜖂hԨ 5WX&5'GC ا5!قXL9xd7`ߵlh P[mkR28ΝׄVKXE H}^;N@v$`iQEf"Σ/ te )IB Z+a&d =% `%(ÝM~@IDATd]UZvРmlyTJjUiGcSj$"D˾ ɽG앏TUc0 ñ߯|O_0ne.vܑRWj`" oJ݁,Ѫ p, YDmBҰ)kne5zhRN&"΋e)31C oj41p"DD=)b@w<=KH"BU@'#=1,?H4F]cddSsQ]UݡGc1};d*֧KfN"5"6)%qTa0d^L-GY=yS79P7+[= XlWV PCX{u%^#MNkxL5"\慙rD3O~$1XhB:+Kӹ(@ uэ$&$м5*QTf8. ,'C>*nij-bF91h 7?~y^RRae-KOW,@xη IHB?DJ@>5h$Q Wa&S| jzkA*E4tU&L J.ST-]7~F@jR~!#=[o_hۗMnXo7H`F0ajϔ['+\yeOw#RbFCJL\GzV-^u{x*H Ms,Q YHk3r4=<.b! OD津ݕL*ZB{:(j7yHp1Ίk/RƍN 5tiMW83ܟvQ(0Ku Ee'^pzȆ`y͒F']\jÛ<04AyF~)/ &yd`} 6+?MJN]OtΕ9[իl ٷ ~N2^}I5fjɆ;v4R"Nl( J/0 pEX%VEln.tJ3V%YÖxNt?4Q8З}[ْ ŵ^eĉ G|H Cm d %jg݆ϖ':Y {1;V a_l44ǧ&5OwFkaU2<<8$XU銸8"rȣZQH(xǂǫ2M?ӽҕVKx* uMgLlrBy.6Gbu/bS),V"#$n3PV:xUHxQkYywE}%Y_ݤSf3b3 8܇ QP@cr=ZEf3+awG#pwQbs_lnu1i:m >W޸i!vX pſtzcZO5(u`BjrꋈKqY]`F56j("[~ˤμNbTӭ ;->`0` u?iڼ|JIH.ldrXV?9.F3Y UweX*U SY׭h q上*Gm #7E ;,B"!91J.P: #2=|$CxTfʩ$EUꙨl~wXNRG:mcCgKACN{R"[sB 3 B_:&" pR l}`*j&nEWR?ɭS D$E/7KwQ7jDT b]\'Mw'Ax9驫:4u+q^}}"v.|1~[q+hB@\)ǵcqƘB~M`rlLr'v*0DAʕ @!ߎ]!NVN Hwvi~H!ր`~dpxIKW4##}]wk g{)5\xYPHv*j-)MZt. 8Cg,6RF: ݙVd5jLL]kewMQ>q`cD5CG&٭} p @:pm2!`L~u'TQTIX.>AnÜ/ah/ UAzfhKR/4\.j6 O^ZIh SI, oğXiIG+⮗}^&cte*3>ͬPuW2DNʚI-.#>xm l_Fu 0V3m |6#J&5ՔqtVmMtC<%4h= pFo\-UUitDA-KFEp"phmEx=&w SyVzMP%v`+ʍ:2`&hI@^~QRm'DǷ-βwX-L&_ogA# |j`~\kFm0}z+2jB#mB3RBf;Gǚ9WfR[ʉT&@Уe.Z9Zo #_S I*2^}#OusqkI`X88{Aplǘl AQ*7y & )V?]֎yqbd# lq¼D I{5mPטρ?#HMu9^u}>^HuăD`ƫ>Z-|va>keV^`Ke9Nši26Nuh')'y=4Q ~[OC!ekֲ f*P7Z &-f崦0Wԇ'a*-čO;4G-fI`rst&VnGLhXti5s2E O(L*b?Bz fa!=4e 0j9G@*oXEPkd]G_FwU@!?IM!5/rom=8a%^GCQ3ir I/C"nlbTHb3C4қ:/670jyXL~ZT!CGeEI8Bz ^5 7%$0e)B5|qb i}?t>S,maO6 8OR`S󪸑d c]KV{0 xNpyXMu'CCpxs_h?`e\=C(>a`"9r;pD V3wq}u"0‹BRXx{*@ %xu/u+]`|#mΰ%6*x(1ޘ_S\ &$ f%2lA#9u_(3(C9 M#nɸNS hH%]pl4;po_/$MKdoea. U6 eq\.YiRjvnq(q4FG4ƒBXyfq 'v94NlL X2IsA% g2c&n"~&c`/RpVL2*H(|+#69 &P[ |#K\7ʸZጋ%“ f@Pltiu$tI?LGc\|?Vcn |6MeMGdIH@}#?V$mg'4Ƀ-@lȴ֋8`%Dc0fhyo|+~![!T#.3)e#-8H`hi1jlˆ2WIWг$uO"NA̲)UQw^⨂?hЕlk[_5rN23Xv@^ᎀ#}L2 TF102}v88^\J:mjDd1HI%k퐤۪ ;D54!<_ߋ=m+ș\S- n<JƳ΋cV+!q;CwImV%#mZ^Rd஭֚<&Av.!7wKXgO203]R { PXG*;A RWEA6>&69ۨodA0N o,5TltgqJfILJo^.*DH$}vmGt  wl}7#K?x"':a3G@^6tQd#/5+L%f}2{S? Ё>4Nԗ) HF Gum&&RdSR2ȸYH+$? Lm5zFX8VOx<рa _O|1o ~ "`,Yd$j)gwК~K"+Ȍ gծcmf2JDZRȽemsjvTsp-@*(BpGF{]h_ t̸٘`ؓx(ldZ̭<L˓`ayhYYY:!U@C>7w]'vO?}?7+B)z/`@tHbRL$Q)CKsȧRйS"%D[U3ΡnG3C6ڱu^ЙMkU[$]34-'\PD.s Cˤ~%5SdL)$b `׷([9/\ M_F&%Ѩe('Qci+zFmPI"BtHY];=[`ּE%3H= ԝA/֔Oކ,w2|WјNW26y2/nvcXP8>ː5i SGO~`뙋 l\`ݵ ;?+Ri˘{Ϝ{jo1YbRN('q%3.X,"yxdC:>YBP({#bZt=3ll7y[ ȑדC()ZVoP`n>G*NDct^ 9tΣ3miSA&J%k+Li9}\^:MIek&A/#Hale:N(()ziD ϛ(~N^#Q 41@h4SO 1D܀~M_o2Xǟ_yv>jpOnQT)?QR^vۊS=N+F2J+ hv0 |Ŋ72Lə 6/D#±R T4TZ)Vۏa0\? [jK .sfq0Z)ΌN%HNu9:?:O+E _}^ w7|y$ZoVV uC|ۑcJ nZ}<a:TA`w3b3 e 'tmNfru,c@J,O"v;u[gmpd^éY٘Dv{aީ3es{V:}t^dH)YryiO1)ڽa/ &8fa<ͯɃr|l`+'<K枇$POh8b(I R <4o\Yu&UGҕkC?_|_~. g ^ʨj`^"C(hc(f!(6MgmϯׯgAox);d88Znk)/@^C.%ZTY_\v?bWKNUܚ&g t"tC:ewnʣ& 9 +'=5KƛA*N: ڕU탙* =AIJ0MBD# if{>F`C24=ɩ|ɽ 8Ve#A24P9ݢ}gvʎ)aD<t@IjΎzyhʺwW$2O<: UETO3p<D_bQ^\1H])5HmtlַL[G~zd#vY9e3`Z[k1SvwKM`Xw-Q*S/Wo[̍mrdTeY@s-d#E38ƏL$ J۰#43Ֆ^1>ћ~Q{ՅSd[b|ƔFV6v" n)}$ R4rmfa?Wu-DH!`2ycj{LHnq%6x\r5B1XOG\vismv/vыcNJo*Nv?'vݏhő Ybγ?h`O:sgnKG>^}kAl*a1׹h,z#FEzþ#-63k5Z.1dߎz~9>WZ+ySmB;TcF\)z}ۆ@dDjPI "t$j|Ξ8[ + ؗ2u9Ȣd1׳#nQ5xyV;Oc W:x(J,ONRd7 @!*Ң"ݑ0ԖM'YxvU"Ob"&, T&NŅܾZH,#<ָd [6Jbʨ7cLiheԁ@v>GhK> V$S,QbYqq671Z>d1e#ynzb>ʨ׻0 p#? kɳ$ǐB4-ȗC`MT\ʺeZQoVbګv wГ,z84PDZ̽!AeWe&DQ6f#e u ,uRL`I+(n!A5_T.~  0jO;=I{7PcHV&Ǔyhؓ$;Y6[yg٠7h& \X*ϿeeP`DzwpZۣk>,"LDl9F #Q_qm'P.\T1?'.<:+l \_JŽ66mk9ђ*h3XYn{۟o6M+0F~LP;V".z 1J"`-T[c7jގk"w3o"mgm|oR xydQ:R"pJjkQ1DFiA &@HGl)/-=KT}"'H@Wv3w@߹ JWcD=EXw:Dz9Zђe.ЅHx[CԈAC5?rB-#M9&yGRş_;ͧiMr'Dɝ>Ja׎^YBݍ@@1v1f'X 6/3khD|_ORΕPX;YlIh(x&hXRxa41ݱ }.~&\iUp&fUAHfU\ȫ)R^жga Nw#e(S/ .C96b֙Vu[%v'((2.60nצR[&*x#lpє}mxfdqߧJqii5ϊ1:*$bC??EYH7q~]`'Ԯ̃L!AJP!P2k٪*# 8+TM!q* ܐJ i*ȝE)m\?Q߯lo Q BME nxf^FM4{[Ձq):w"LAUEy!H+7;kJ\ )3NJ5вF #·vC%HƵdgS҃,J X@=LltK - q7j%=s6&+w`zsElGC}LTm(Yk=Ǟ [~$!m'bzA [Q+nTv.高(4=qkbl]0\D[>IV|@K0K@)cC"U aU5"(Cڊ(YCʾ ғ@UJBǛq*l-'p^.W苉'sMEH'#!]yy &_312H r좔r`%D 21c ObnGµd/A O8dGX>hAO&`jCh6lx 5 $)`M9Te&pcynFICÈ&@ݔM'REhyus:0zzee;5q ߖ r88D%>ީ*Ce.œTl.\﹘ETBjSZOF8$M\#$%K hj$/oW\+HNg$M\J1"qN\&3Ah@h h]un$K='dz$j޲p5^ʷxs ΰA'SJ8g Ptݼȫ/ ;y$a3Le={ld~R@i$5Ԕ24"22X4T 쮂6TE|T!![7е1?[K zD.ysx!|k@" Ϭf$~7ܙ剬LQ&U, {jJ3̢fZ"DD~%mӂvLm0 <`fjh >@n\P4I,< EmZ&wsjő}B?'GPȆcD%ATH2z^'$R<\?aI >`~XuTYzg{¿ymݨH";6@?R 2 kg SFgb6urYMZ#p+Yt8 RCp6"4FR1Q`E4pj]ATIAy7%P,:TDWK ' ekέ,u8o̟gtknobKK@,AsCٚm76ckL I@`  BOrKctMETZg@$/NDz@/2\=sy ѲS364:,F2Ofţ vQ y7:vkVZNl%ax<%"O?KA!#r܊}e~Ae% sy 7^g,cey\ qM8H\:&DC5s\[%ʎpjиQ>"^0 8 c{ eRx`+/-o_2ȜĠZرdRG7łTz!]Y{{.0hēċύ5WfeH|$ʈX0,NOz ;5V_֦Xud)k# 8#Ήla"c* 1 I! # HjL:N4z=Z&GEekQz *Z/&L'N8O\4 Hz:Awz@:HE+O~G#42 P]d\!䜱}R$]XEe'ŪygSj}DOR6I7jz%0a4~MiWN2g̫K=?˴$6}TNM7:@sK28Q7ILO;s5RqA7z %r]0"}!%!) S/Ei"Ɩes6U*>FGe\fԉz8deFv&⊪8g1T$(*epHq*[\dB8TeyNY&>(YgzsS6 \ mMb?)R \)ծwmM@EKX?g[JARlĤAw,.d7Erf!\T"2A&EgA<#FP hcrUȉhZY"I8?@G ħm%Ô9MELnRrCHau__+ډ?`o;ں. 3}B}$)?눫;lD`(r/6TFDf\hŃA[ǶD_׍*>a3'wߓ&=LRd$ّ#cz>O#jf?r$Vd p\MצmL^65YlC 䬼!ժè2r dxTJ1G3bR$w7~VTtz2<-$גlQ7#?qF${Ju(5 tN^ju㍈ XsRIM&kY48'9Kޠ!-`-7[&7#"?AX bf5$r}r`|4e @)D1wRթ8 VſU*D "k.)ro! xc,y,8z͖m|*WG Wǻ352|͞`*[&RN(ظ*?d|Њ^1KdR݃LT`M` {e[1à +D i6Z.2=J/ǷEc8Rɩ"J+v՟A+#ͬ/P l͑ dTIk$0gMDkq aڴD&y 1:+t2W9};pBzt\s~Q (p4C&i_[Y}ln+3I?WQ`N\$EIy?J@yM oE~',]Xz%cZV*a\聬Cv^(ṈZ?)nED^& ؁hYy>s*,1-?3A%9Ad}A)O%RG5 A2_lH1N2{Hw5z Cu$%, PZ^ LP\̺P+sV( EY* 1-4zؾmC~0h3.1ڦFeﻮ;~.lDܞ7>`Zղ.Woo쭳W׭v߳E𫧫2;Sw^[ǼmőU'97(1T@?myEޤewcX\`ɶz+L߆+3F&3 ONhOs+ ,EB(@G{"aRiX\@^6VͲxŧ 3+mo^ \ԥpAlcʳگ瑩Zcc2b-ph(??Bx| 糖C{7$sQLλ4@#zzJ8Ik]/K#9I"ptola-n0q:P#!p F ӃOy8J]yF8}&_]j\a/BAB12l㠔J0k3/3C$20-Ӄ&Vź]V`!Jq(Q .'.]zu { !T.ґ\U$E$$rvR}G߈X:7Iῷ* y!\5C8uDbg+JL5D~E ~' BM߬7ju ~MU lPy+sr(fwB:^0V1&HlŃ>0aH!5j_'2":ɼVn_o" ȵ尳ɽEyYѱ*! RI}n֒?އ<"7˂c%jA2 `9ǧ.mQpo}Sokm/m5!hU,|c.Y59X!vde23`(`3Ne  hj2RN0ۈ:9bOLI0$W; W>Zt6?Lf[xn7j&8PNj97{$PW+^od Ok+9:T+8G& rV6:ӏPBQj_"2e۴HfnFLSϪ XlLy_/ CY!UZ\!B蜅jIe/UdKn.qvb(FP]`G?key߭/V~[+WY0KFygs ͝=}^?%|8R)Q"MA{,`21Ee ] #EMjwb׶|[UB2,Ԣ58rJӴA$į H˾6 vgz/Ln_Xͷ- `N[@IDATHNA{߮be_')xߚ)g 5.DJsj p   hʺ( j1!0 [71j%Tr(.Ĭmf&)BtnژF><WcBcg`tj1DO_GzaA (D:8tIw-IJ'8ub"3 hݸ~2nᮚݒ/ !v-rL ~`n/'^u=YLj+Qbf4'{8b^)]jO_GI‡xiXa \N.SU+SA$h&Í5=豑C7.>xIt3:5cՀ=Vo%ͽ[zǟ4>pǞymKz\* f˞<"+㲐R9XoY,|F`Ja)e0wQa=k+MOL9Pv(n1tA}L/jBƑ&q3ƌ!TT$&C, Om4'Ow)0#;*)pQ&& daI*eZnP x:|ILr,!Rć [WoU@)WhIrO_!='dy>By_^fdR#7xPHS.FR*zz=iG1 I@ ڗ!r0aģ8F>)-hg\72xd6NVS1('m8r9#o(јo"tWxI!ݽi$Jc98Ѭ7 B}#T# dq: Kڽ MR")IF-{Хzo<|LK$-?$Oݩ)}DAJ N8sk@D]).NWy"C K "Mꃅ)8 ,tũ1ʼngguu۬45)ZPe6&jp=z"uVVQ}aHnAE 4)eϭ$hRcmdeG8W+3bNaQ/v!nAeJh0 lzK:Ѹ+C9s趈VO6$AYz8[ׂ+S~J؃6\ո8]$]1щIZNlH*3M(T&#FF?oD=’tej/ʗHQeҩP ՜~Q:5 "D@KNlƑ:5 Fx7P'A շJ:0E Eƙ4rO%^;p8$ gG8+#2`W3Ʒ=ueFJy< A3W P!*#+K d6 {M2ȗG& ȇz ͨ Q @ObVki/(OO: (G^2'ޢ}E9 Sds\ayr SZi OhTZ M'ᒗJ'Y"KʽBۗS NQe]`f n "Vhmcf9'T!i ݄V5j婮&"&e]CaIgqggNm3xȩf~pQ@⸖zy ڿX4ft'l={M%5PTѻ~,wz ,\-Zo ; wb{s EA33rm'8b h| w҇90 o^H9,~s 5GNU%GeN0Gi01)$KݜY@ 0:Un TφgrqA.&DHp TxN^U!Jsq<%=O#yU]QB)R/C1R&H1X4KQJÁ85wH)U@SR3@XU A+fؠ~^"v- `Vd,.S8drdoo"$˖Li 2ƪ84hL΅%~D+BfnxeO~oD>G̑g .r_Q2ʗI˳P"^~/.4n&@l;qhOPjϋ\ʯŖ- n4N|㴃~&1ޞ'=3^:ϫ; 8'P߅d3Z{Q/_%ǝ\ϡDٯEAJ?ӖFٿɠڸ/E m 1fJ5%`EqcS*ZxiB So4ϛ>VZkb5+roy, ,pԻ ]*ce-m;&' ;2jXX6*d2J d܊硒;#KF,JJv3fVWBt۟~zg2$c=/RNF#nS];Fz07 R&P+iЙ`{0EYN~4DٜUlv i%%nWNym#P \!)2,՜fUP%>}EMCAb,5_V uԝh*=f0C9+z&,osh%d"1]z-L)ŅY88F|z5@q-%Dk@{(11cGI$#\b=+xNmCeTd ̚ˁ34t[] p1 ?g/S4J! acb\4ڍn#>(g ;. zAVbzE S->1Bn:+J&{̈l ΠgP>>TJGd`Q<cXOLxkao, 4E(鼫yGO\}vt#+../ cD A@e_nb E(^C?#R@\H'f,]8 ;SP.{:{[6K! H= Hë I^AhŴX7&8rdo0AOl)dv2OSnXq*NA+b]0_k". N1t}p9g١5k Z(>{}a'~+g쏍Yr֙J@I qqiX {4<TeLd V8ClaZRI4qۥ&InFQߋu='CS6^R pؕf:r%x;@@ߍe O `A8@\t> ?Vd!¤ײa@4b;dev;Nzy V-GnytELuKOw;1|1A?!P2ł Yta"YB1 K"a)\*3E/ ٷ0bs#T**5%jWu5%kЈI f3 :̌Ĩ]@hZ 2ǫys7ذ9RJzv#),kXíc0Ĩ* GFwD4G@XO HgUQ"X9*+ۏ#P/緼.5-\^f^"V5,loA~LT ݆ːdͦ#M`"Z=86Y5p LoE ˳̆%xI]0ɳEKs C! j$N*KK- ڀHbޤG`{fAXq)jY|LNa": ixfჟ#$yoB("+eаp@AUN0٬P:3&JǓ$t6~gMHg>/2(\[sgR%TMFNyb{ʮ&2eGQv8;E?mf$<s+9 QqK[≵~h-a/WA08S@Ҥ?ofKޭ|>*k tC~6%hŲ3n*a0tJZ1sV?3xrT/ګ64!3]) 6b٧%VwFS\2[sn]aJ.b;~#Ң㶢{rڞTB0f"%}Fس侷|\XJʹ54;/Um;Ev32tdAثz/gi!s  M@މ3Qk4*9$e57ά sdt:tT?ŝjG0aoa[zG2 &I*ԤHGSeze:0 wؒcOx & _m)Nd.D\`2E?/p8 xM?ħ z7?l ٩hR8H캉 5"۾^vAoDOc$(_Pd)c2kxnAK"mX13mQz$&Է[ڡ0tXY-6|/J˨oC '&%u FeP,̵dMnVD'Y^Eo5 -*&XZhaGժؘ%qHb}thfdu=WքjxUqGh )$rkq)|W e˾r-Um3W|~ANoOУ:gM!Qh,;P$ЏTu!N#Q,=jDJD;M/<|}ןY Hb1B QT*GX|Ҧ`_esM|y9">hYVSCQEc[IvNc)蝖9 r8ϳHr#H&־k,`=,=퐐G |I46;L&cP"Cԫ{`^x(ϥjմV }*eV31+U$+ܦJog? _z袪\C ery T*+vrpLmzH䖆5G*̭1E)2rG%.Sa'|š'gb|пjIYRآVoMe N<5lG7\ʑM!sT"g'VݑTBjg,EU$HGk%f0~ёYגp)DM*,=`  Pe#bF-NFR#qd{[H%&!2o"N!,>{:ц (Ey(" 7&HP蟷X;8:J{3¡1\s?hW>{Ckč~"~> 3JCxٜ~ $yϤUXyOo_F9'snמϓ {\?V{/of-k^E\&4ryh*<|(QI,&B_^mt>r_ cӝ7% FZ a fhXW΃K7ǽi8]leJm1Tg=U뻽i-w֑]x`Ll+>NS޺WY_0qv Ɵ^ac׫pwiFDŽ{ z8ϟmC@$McW[ f6?-+݁ fH9˦M%+^N@>{2;=39˧j [*$&flU˯Dkƿx^}QǦ4Ys9 dD:{{9mJY'i연ys0~=R€~7BHPe*2z,٪믊2u~s8kG<MLǻsH[J8q|ț"v8'my>|}DIPWmFXݾ&<vYA2"[a_բ'yTU'ashI2VR0S~ We{Jm,@*`iǫ*\_ɻWoJKN?bq‡+Y4;J، DG d<ؐ+ԒI&tX~^.J1婇0).L ȬQO,DPuJ 4KC =4 J&F$yekHxЊZA1fc@1OaF,l 4,Q#Ԧ'Fz來n02(u U"Me}) n#GmEَ#Et0%m?>v|v{6fUW T ۴~@^{F%>ItkE /L .ѨzQ,0yЉf5RvoNn+oE-u .o W4>uafGqu^ktc8?MOsWX4K!3 (5FF/(`Xp 6.Wh4pV7O nHXS 6 ^Y^ 8˿--4OU )ay$.u,wT##™vH4LZ"+ZW  yל"K: h*EؼAWG/E׸oAD+.6EZQFzҿLύ#e[[KCM%,#Q<^%Um7e&5p¦xS.OЏ;L)^?C ha%$ PAd6][(e[Xq7mPUdv k̑^ #p~$k%Vm/ĸ?=jXL :%)Zrҫ8]zys~^<5ÛC9Y.NGIE3V\Za}QG*4CfඕDOa1i>$ +ʃzcƧq!h9`(* 2Cdhci8߳]9s5C]hڃtWja34oͻHj"!qڝb FQ5W 4ٸ똚)x[A$4ג7V3 42'6F?S485$ :y. "WD9BSȩ?ӸF>s4ӯs ddb1E):Fƴkj2QM-vCJ0Xs<]1ÓEEӯ+ꯨNEC>߳}&KQ ~AM13 jb< ?ѪQ0bGv/Re8/  jؙⷉƑV68Z֎%)@``pκC!湑!&:ELXC+ [z}"9UzԴ*1Ci+J/sfeҬ\i/cMsePGԢBV.6c8}(oJxKj#^HzW鐺q#:B(lvr)U3<8y3=nF _lvpgD<1'9c\2DONki->EiLJ]a"A_dLSS)ژpSDmhLg(SGɁo^i^88m"U78BԇM4 '#7"a<>ڜBb,m>QCȄwi!@r!CJSIT`־h?: l'J]"4./E86(5CŒ9s\MD4X' tlx5 ,:3_Жkz)>331cq%}̴e,hVc- 8\66m^-mY;pfeHhy؂ww?0̸񯩛=^C7uqt=66j+ڠ˜U5]>Ѯ 2| +S(m..xK~07YԦySG$G ʞ7ڈ*a]?B{b^NL5fl㍉Vf 0_aY!Jy EH%?A4-1K5:D-3ɥLP[:xLF .*({2S3ӵ)= $@fy+PL6OBk7MӓJAVE>Fc-{sp8_l8ڶY*0o 2;4#F D|?(}̠?l؃]d(< UT=xL8:K(5'cԠ%∧0Yg[F`pM_ [?! :9ܨ| ;* {dZ)Q¢A BDȑǘ:HH#u&.!ta"_ۅiOUvhKj1X(׾5xԮC=ۿD 8/EnHp\z##6 $}h \AGqF zJe{[+%74iCR\'9 6Rai*0 `@,3],'0i@s)Dʓ(.e;Fp%I JǘC;m:]Ud`V/<h-ctАӫ'cu^|W !ob& (9./ٓ50o3s-0)s0PDZdjjc 75(GɒjBU){F='wŭ֜+j|Y25ޮUh`z\~16]EBG {zUv (`c/n Y!X\كismTL^2W!3#!7 g 281A,%)'3#..J7\xqM]`95{`7ÐN>=d SuxJG[]jӚUGma,WFT6pgf&5ẙ, SPi=y[c쵱׍?0p`H{oZ);jC ֢w!Os]˧+81I%aqi^$gELАsvџ2( )r2d<= ỞҨVMj gJ/dZ&sOG.j#BaSJSآ67;ite\!Tʪ+DITF Ur xu8H70LP݁KѰnz"\醡 A\AmrY L A;Ԟmź=G((a;| xD =RLΧPb}|sUcRr`>MA]?  bٟ)+\`S^xj CC6*f^T* i.Hiu12Ac…. ) ]𽆀Ojל.񏭄F2;nٱyGCx' [01bDL8g%3cI G``wUM{A%=DRdńYyN׽Z0'a#r_X3צ3y!9$Ds HXd3!' @@G[`Onm~z8xkY792"fcTI B26F3A1J:Y*E(S~ld;i=I4Q&HG,^G+ '%& C\F(ʹv՘4r2G`TeRdD؟>GyϦe+ `dh|P847b7埐n/tkؽ *1PsT⒇@,P ִK`!B_3x ${}F䵭.JV8aj\'v-%lGq)=uMrž'v |W`Li{]cj 6eꁠh'(|~~bMY[IJXٯ7 }NaWzI4%Wv!(%/0&mKeڽ={e)w(%,j5&;y j1/-̈5( Ʃgy N~X*3DEbp4PhŕLbH!VW$ެT`!e{1BN?_o-p6?6O To?SwȒ$fdҘPOoɤ[EbyV"dfѹ!ђҢBstyk^>U9ܮw<5ˬ_>KZ`]'s >ة-eR&prwḂFr`\#5pD^׷5S'$҇?|Pk"5DȥEf&@IDATUd6ZQw|OoQqfHn:& V]v#ZJ<>߼x`#~Z;f7y\*9[ecAB۩}I"mY%1#ůF]ۭxǴi''Xt2xݬPU;釿TՑs҆ HO~̀d$ʣ3}٩\C #LÇU% }D϶dJJRmEKuG Ǐvu>dXnc}ʴ;#EkvͭYm/JO=L_i<H7X_Kh܆N6ۺsNIk{[:P\TҟRR\?Xmo;_Ov8P~p$ć쯭j/o[4,#vgw:7Z"Ɍ_fl!Il#)7ItaPTM[jJ/+7w\#~=ϩZ/bOLBc&جו,d~S9m~nŹ:k4jk_o:Ν6tzv|jEc F1N?Xt;ԍ+b>kĒ 66ApX~{9V[h/+l)pC8tlA'OzI `15Y n0G߿~IS7q8?tv|&&Ze7_jV'Ӌ-OF6m)}u}y[X{+>- Hiyz\ޯxyH&:d18yZ˖Q(El5ܯrGdWupCzs킠*n‚Fn_dmjsp$IŵqW09_i2uU ( r}<6̑X xG[\ R NJvZ&[->yhMbSg5nᥑIWB]gp$P~+c ʀvCÀvg$m؞cj6^_,-U80Mn*gaspwQqPzqW겇W.(b,agv/[7-abߎ*:\ Sa rr-PeΞ?ۀSfՑEGx4c;ɞ{+b(i]bt;v4pa,rQ)hT=\TGY|I0b@F3 l'Iw89U>4 M%h-_M yb06$?*f}o][.5xCѸ1bͦ e&`΀crcpjs<A7_$*i+SA3UK8jPD(& й<ѥ? 3`Qd7?dH`*Ok̀??R8MRYAsLLÅ]%(Dvc$k`[ 0mQrqEG7 Za,<>0Q$X{o@$Uga2 ;&0[d# i xsmj `=F:CBHjUzmܞ}2s=|G3XGuqC$O?JQFQx7":z\)#"Ym.ͶoU6hV#w6 &zI@rh3}`f-.VO2Lvpcd D{MHtX,$5Am%e*C5 6g* }[Τ"z _ww@hmrGTyԂɜs+?TTg4fd߭61@jlػidbR!2j|d'x!(#Ij`Ұ C`R*#H/<{ίRZX =^ @`=Et>XEo{˃.-`pg¡h W<[hRM1}ΪsOZ:z_+Ąٚ ]o )T9 [Le jkizGf&e@z%bbu^u[]%_DH9͗ Rx]S:5x=!ih@ qIy0yfF 7gh;D2oA\yHARҼj rZXȾ(&s'80F7 ](2"a~Q: F2jqεL1M1xb4!M9%6#sJ4I%kha&%}ؿrc$djǔrXM!8;82uaod>P=8DHz^Pn4~Jf`/ sh2r qG^w"K='0Ҝdo&yeI77߁m0RAzl<@a@fLr7 ,q* n•ng' .cX1B/$X'&-$HC+DB+ab}{x'i֙͐iQx!3)l[߂;x>Il^X*i2`#`zy;YH~BEY~6`qc{vYdD>FI0zSᶶu u A Ta=`t˷ ]lBT^ŠThZ[5`ZgG7ᇝKe ѝmژ; |K8Tc̖Y|_P[YULړ9Q}m4\hs] sMLL}Afv'rxw{/2 vUųW'' q9j*p (ЉCfh{h\䟴6_\H¿ s,~Kj I=4L%D%YBl<՚ ?@Lq{G⺇՟ *#c‘ =em mni?1P0@eqJF՗A)UحbIq 0JP'hFn+2pTwlP@mDBߤBAM\qhQ!hSs˲h0fhLYͨ@бb@i, \v+$:P,e`d_T)yvZ;Y +,D_MF;Dv!阁CO^i<>uLIl#42u9.CվDrSLlZ˩yXjyBXX=荳e 'kʖ .H6Tk,;r"|Ò,Cm[ԇ,R1 +#Өy+do8NRr4L xԠܪx{@*FInU mِJP@Yˎpl9{Ts4 җ8,cjɬB9DϜv*\Uwant4,(׮?yNy޼mGW Ǥ)mJN;+?q\' f] ܆։`rYm;y%uj+PĽ?̀~7>+LHE7Cˏ*+XZa^E6+iۢԧZ#nL@(nTOqA c#,b̞G^T#C;|aR)TS/\]=Pئ/Z+g<_(藕g(s遧"÷}:1Kr$KH qTÐ?~IT=>#V.QH^Lj8:UA22.肰+yQoApil`['H䪻Z*-R=3U]4#H8'rj$ơƒC{$4UBfaglqw 3u7%"([O\Rwt>ʟV4V"_\2<}_S6i"qrx `$@߂1[b[{b-%_ ^9PəRffe6$S`"Ii=ȊRwWE鍘3 KHx$:23F޵&p[8͐"]Լ]R56,%1roe = l5Y}4 b}ȗj$>pZ"g%N4f_*[fz% l+vǿ71 PBۖXc%,76!TdO2cavps I0n2hi'@d0mȏn O pTܸmDpAR%ᰉc{Hh60Û6]c{y~` /~zDv]棕fVCЭFPvmi58+u3~8g֬ =|-}2,(%h Ɲl5cNQ,zKyts@Dm6ʕeIΊTWvs>{OJx3*K;l3s3K?=~p$9Ja<|#]o׮۷V&$DTLM -' 1m;X#.wQ4̀8a4A$j<5QV ]̷gaE7k0i ZS]SBr;IrzN#4UWa&zY꿁T?0L |_5N5O'+6v8W3꒵vq%_$h`BVu9:`?XK}lrpID+2]N߫,6av׬35LZ&ZݘG@xDk;-wArXeF J ־3`XXTbย$ҟm'\+(7n짖M$Tu:|q%Iqb x>d< GY:힂%d/3d3 2iTkȳ_ReudI=!l8THy2b Qp"E/Epz?Y{[e17EQwϊG~X7ҮΰMG:^rG&1Yd1khw4uP)'HX(*@N{*= zm5J;4*W7z*Vb!%h.Y&[]‡uދeDzMP,'CҀsH~3qy<<]$1_Is}'ۥp)\]̛:m#Ofg>}Wd|rS<0bkY/ k!ԋ1u|te[z\j۪{_޶tոl_eweM&OwoK=9X[ @a~sSPy7ZI"6f>2%Bl,څxUB [25L"`6S]sn *#3U,*k}4D<L2鶿(#8ɯ! F=䳇<% 1>K!|N7E$mԒ48~3O[vZUB d4TDCftXb$RUX)eοeA*ZbٚB Zny.i[o[L`RekLe̙#Z'-hߔ|}OjfkzgOD?qk+.~!DZa7EgTB.䕒E|?[R;T`' b+zBkZM+4-/Y*('+!ۃRm]_ !#&tp4x6-OC̻:mଈ?YIFQpJ1 PUuH}ޗ k O*N=Ia=ӔY $|&0c/SBe(rp cQ4= `N{` >K~Gp -!m ؁0"a(:CR0;b^s-얜(.2S@e,= }M1w |2R]ρ00t;=4R[8&Hs<7=/GʁE;V&<iE%ڠ2z"|qAeUŻ*Z5m֢z:!c ;隹:@Eo'E= LSjJg˕.$GLo)Я7ʾf h_8 bVz]\yOu Qb2R-'_4 VVo>q9gLf2r5iB3cK3H#ל@*嵭v͙ P"ĹIS7;?Ac9ӝQ [Ǎg1Mv(LEu ye17|ٵjsi c$70P{j."9Мym*oRh*&i #eĸtD; "]Ĩ(<&X7M (l)͆Ky MYlSv#njmPjT,iA@V=N0gS$ k'p2:7tѽ9Pq&3 LdhJ.Ɔa ~n\Ì"-N~S岂ͲҞgZQT}4ݍ1J"x.'֍0θո*<`I4#ǰ@Bq@܍+҈Kyz2dJ"vxFV+B%BNjG_;-2dVB/*2suh2$0;HRy`x!66 B MR7{Kk8<ӕ͋#mSP|+Z s27ֺ2Nm 2e^ȭxZG}?Z9 OSW=ƨԘQ*w6N[pϯjiIB5kșIP}˼!f, ݂4C!.f6qâ?=pWў?tGd$96 F#?i8#2 0|՝Չr~@[ Iɮؼ[ۏ&凴T){(A;`>#pAΙ6ЧBPN a+~ o՜%c4ƣDr 3$pnTe ~eZpIæ\!*$=KhK|2L̔d-aOo_< ߂&Y<AM2 +ic#δLzmc1ݱ]4j,GQyڽ;PU#-;@XG@EW^Y/> Ag-ޚɝȣtL@($14noےI٨|σ_sB$A\yRYrA>5H0! 04Wq7,ESPU'nHdxM 0RfJ&mgC4vLm(A|8c %\Cx4)Ԣ3Jsԋ*Bˇ}@L 6E8x0#ؖb)n;vdס[b4s Ɠ A@G~< Fr 'E3/iG,\Xp6bB⿮c`M:ﲯju拢.>i;0O23%!K}pY0&'͟īӞxsf,=|SR~rָ/ BTSslvex ›>tj皾2gkseRUP fjX 2-UQ1N!NH`:k^{&~jy\@$c&6 T8“2}C1P1| 8H4ǟh$ ~B '*qл *Id/aj^hɍzoTv&LP(u޶yK]<JULD >Z{"̜tSoh3{zZ9-_||/v5hF` S~A,}c$*U4"`q^6o5kt Kz]N[9n0ElʉK4S);IZ#a1/ k+$y*4}lj&˩[rUD.+ 1Lhd]sD01B%SvL 1?" H\U`R ?&EtqAc24=sWl;ֆ +D*R3tBA?1W)ݭө7/TO=Ⲁ`dղtIj ALA6i Q˝0roYW찛tQLS(E*gfFA$(ÅRt$d>!@RH=$Pz&i-U9LO8g{U]J}rrF]sw(3%2Ft0[YP8O5O5 lPۍ#xZJez}UH>2|͡) \4X 42_>% =nUhxLcEKJ0#J0 V9談8O1!AܥVl6."ɋ۩wSS%Y[Auj?yFeB@N/꘳‰#4eV74[,gxH j"jO'1cǕ/lbzBtHP5G ? r $Tgk .1C*\8^anCRM 3ϋhgh(4%!lj 6^22:-,rk|߄|q[Z@;}R+J}Izvbh.=s -B.NH6Л?aQ!IƦ⹆,$#\)X_jMlVܕZ0ݮ@  S@ (^aAhfP "ʿ =Var|?~r!G6^1I` ѣ|6n40E%0z+Y.M2=܌*Gy9#1aӸԓTÃD2O}JDcno3%_6d='qVu35%y=&#X^#^Ѐu @%'GIk}Oj2Piq[wt\ Ai^NRDP0ȓbNrrysZ_KxoM;V0tZ(G$YqFuhatȤ='`&ذyD$ۯG')cʜY Q<,M9P@|"aIǢ7 r]I2u!B ߤcx"9& o]ʅ>^+K@+AU'(a!꟧-~+1#*g2ɺ4ob*h{ ^l^l "k}6(ꂱy pDHf+ouYUQJ2JsqxġCH"MB`I|oEX|)h!9HX@rRJTeށD=/$$P:ďgޕGrje%rχ sN9nn2E-)$Sz&ό![P%Nu6a%:eb\|\ߴzDylax.:qH4q]\J7jd& x{8; mIB:a gn!]Zd]j BۤYD; <8nTmZ3Wf 0XԐF^,18P i BB.N 6$ nqd#lFlDHc.ӒI NIpa4Dzva 3[M3ٻRRx$dYXKbd +>K ^9:p^Lt|hOLQd%u]MpJR- SWQKw}M\ԫQ7*(A9~kQF'Ȁ+Juؔd:!46rk()?@H!3NX=j"#9*d$uFB)><4ZDӍ21'#>׈՛W`?*H5{֡Og K A1BžoG\-FM Sbrq8=ѰI;VO^PMSvXGQnhNs$VE%mL%8MJ z R3 ACc5Dsl+n*4pְ8ʠZaD^%,3qi󈂣mָy2)6@h| [ܐHĐx|eJHCj6=߂%zv륽ϲ!rvI5Ҋة\czxCpYa1"S]A;fNc,_27f*e+CoFm 8>9iV _o3yqIz"I527\=K^{A6})*&Dg)'`㜩qpVg`=KXhAW`dN[oJVGoRu땷|Ŷd̄@RD[k86%ѠcGAkk#淋6ϻ:Vw\~!ݘZj ֥y64I4KTD=s9+H-T(X+dVHT?RCH0vH\_n~R@IDATל1 -~Wpy>-͍UYrTPƀHkFk}@LbJH\?m~bPM #TrB]i}\|FK7T ;|~5 L^t0l06B$" MyiAzdxIg m,qk;9y 7* U'lt,<0,)ڼ۶1NW&e+\M˰؆n;謸:Sh)Νc|7휂v'8!Vɿj?CL?­6`!]ϔHjդZB>Sq&TĥI Z;ԤޖO9@:!8jq:Qpp:N2K~,ŖFH+-.&Ǵ5TD#i>OdnfM.%؆9Kѝp=" 'y#S"&[#d$3-i#!##4XH)nYoeoS s [@2#")b+$4T&SFx!%$l?wYrB]K:LK[B/9SQhM˰|ϖ؛m21wmO9X"e6o HNӨ!q41'Hu@3BOS f}K"+*5g}ɢ|5J8p8Y\hak kjmh{6Mg^$w%Nb4YMVnf]%y7Gt&K0I[,TdJ('(_NwX}$bԃ%-ϟa{ݍT^?[ڙN,m%Y tl;*(R*>l_fm-k,xpO|9Ynj9piR;h4+BbBS04 .t |%kab_?_EXO:F(TAi8TA% A>ݭ*ĒC{foݕ)*-4:ז䕸"勢$wפ#"k/  @d DdU1Cua{";]˽2УxMkXI֜~'E*Aw_%D*ϡ@pfLƲmv,n98ܔ#&1ZjPpgǣl=pBԚ9TPdb}x4kMLX&oUK|C` I"_ep5**O| %FDZ#xfqNqp]?Xx"m[\d]#dt 1y m<@2 =h #Rcj~ipO͸i{È -m#犈$'+87N[!aD* ƥ!d8c_77ѺYք$s yxh8?ukz~٠.k\#u\(OAN5=GfLJMnE<ف)zY=]Ԫ m((@0#`K0ˀQWM? SH Li^y&-X}ϯXLӳ: ;WŶ]s(e8rRZ'0fURChsΝdAN4# %Z Ntm` 1JF4 f!ӖÑ" 8{^J|l4Qefk reAv Ő2htJ|%ʯBf_{g:\j`2Bs31<|_ByYRlll6iUaZd`FQ] qA:dp/D\9-#fWn"20{Z9&gzb@{imșbnцH'{Ke4Ҡ/6i`4:Cx_«R` n`Dw Ծ$P rz]%Hy,_rjmcB}r(8M\Ԏ/ Ԁdp{\aDDkbC1^jDSb ƙQ0 @5{ {`!ޔ*k9IQŰH[3ݦX" )6Z1>HQOb%Xua K%wsK2` QcNX4#x|[ȯ^?رb[\wg0Ў..I!Wf㾫$NC:\`b8 ҔW2FD?1jR[2uY`Ztpm&)j 28.;VИQ'4DžeU;VV-3NsU)GĎa.DM{$ 792 P1;pYx prچF#Cyc}cjH4ZyeMd!ջ'B?!<{u%ZkRɃ~5p@LbCr%dz$ 0YGU 2yإ&p'ƨ`G;y&:6éEJri&Z<83;E$+O&eq"#c~ "x.tӑx(ڒ+i?arjBvΑ8\[F$ߓdT<6yw<>19I'm-#(`ƽlFl4>r$~apP Xe44ر S@9jMmMZ$(]⃽*ș72"/V],l!Fˎ.Q8@i( Aag, =&{7G@ن"i4KxK/A ?'WvMbIT [HSAj %( t*b,"<<8WbX4* )TR(l<܀C~8,U(*GpCAS0Q\(ύ7RhdF:9KMM8j 6E)X1NLwGo̙3tI9QwfdRƠ8}t4{L:DuDc~GNy.һS)ݸI TI5ιL|1R$2PӬ 90#1P]Z I aH**1Ȓs`832i7Pq&F̍K3iErַZ=y|ªGOF5 74+k>B 7[5a߆q#H6hk.ב 6֘n[?`W<'j!Fܚ5Rp+l}ЌY[gn&S坝DBDyP{ m^t تYѲzLJ3S joDޭ}2Ƈ%Rc@ f>[ 1W<EL|I}?3̬lq3`X )cVFl9_9IH,ZB=z c,(O1 9 y ^ 6jƛn Xmhtr` qqP8yǝ0#bDC 6|һ!U= 8-ta7Frw|n1slvy؛0):eP̄HtAڵi1r͢k4RLޯZ)IYf@1͐+哦2k'#)PgcaY@[Ԋr()קmRP I _U]Y6u*4a568SAJp2 &c7yD* _B~$͘y"Qϩnzѥm#F]\NsV9: aKd -:yW5()YA\_ fyo=0xE%lP'c*hT v;Oj>L=]6-e zΊb,k=66CH(I u0JWDzaVL(|PExTq㻰kS$ υ]L}b֏,3R=ހH]RNO7S۰t 6)Q]/u/3嶙=# N>I9&Žs'߇$J"(&t]o-2>F@%PFQ_?.CAr7( ng,I9]>|;+žs JtG) !-)GyO#9%9Mhzs u'6Ac7?J*"#jD ҙ# T\a-.87Rׄl?ΎR.'2 ^hu\Aq?mC|k; +_qNů}hY" \\zC_a`K~]$9s;|acMRX/{Uo\A9`&tSJInc^G>}uM[GHy[HCEI 3+N=6, .(yNF0L~~©*a ,+y)z*Jfm_t!z&3T|#Ϫ1g\PL>EWƬrҊ4xxh(4B 5 H7xmY9Ĝ}m.ԅG>t,DR:N9s$&3h 9r]z gK/sOD^xnTȭ̍䗭eNg3j֪=+U?}/U n%46\+Viszp|И=v ս8K!;wPE3N+\aR,!G'CMi礒X;N]=~|rƬ7 #D  N _ M뎩2iMW`4J=A'\"ED Q/L r)=Xhp5e4%MiƔl gh=4Yלi_2?ED+K?gvXؓSɮR l5"8$6N^KC7-JAU ٬(ѳcY%QNwPfL*A2 ~;F40QBLȚ7l KE ll,A=nr (3c;kC]jfpkWDTjIJS6C~`uT8Qmװ@ e;tF͏([:+=bNЩ\){~f:X6ezK ōHIMq&X` Ji'!)ҷvvfE|@ue TçCz %RVUsċux/r|8;z=kf8ryFqf35Gm蝖'>]}TvXt *[`ҌgLh=e4To6BQ1!BYylޖhzz.HbÀOU4G+Zh8™̋"L (MD~T6Goc1Qhr3&}\B.Dh"&Q ;ޡBe΀I9O;J2$^2=84zoC:v,&x!6VA ;ZlƋT BGS\D*1IxXMAoIZ:Pf?S\4T@ z$a]A NqrKt| ~Mnu&ORH,{!9ҌƬWȠƂq 2nǦSd47ramzv7Hqxǹ:Uv1]a4D.qMBO|plk`R1)gX1~VXsZQfy+=x>"H%>TAˣP>B[wk(#vJĵ+sHjӶ+b^:})M%Йf*vMW G0.Fg/Fև7?%Z\zvv*76dj/$C6PyMɟT-O?]ʷe)RrJgQ<_|3bW'菔%~7pP6`¸uyi,Du;?8da$l|mςxD!($RVaUm`X2w9VNSQ((# .g*5;x$]@36 9>OgX٨7Tl9;S3$}At(\Sӣ@)5 kj:]!O[|QͲ6Hz-q0z ^=M2$ΒvX&h?H`Z%+28S.Fk7:XDZpT9 vP;hE^ D9D" $^%$!2uBWuIdi_:bN;Y +!} -͛?=>_>`{4?/樛_wwo$(SnF>˪nP32>|g|ѱHַCNCiP‚emyC%HZf_7C3IFb2 H mm'd[lg1-Rdb"y|J ϭ6 l8C.:`d7|m1EL{;b9EeYP;U!8H>+_F9-,X6xYTHc YZ "߬(TMV:J׼##!V\v5O>~HmӃ`: veZ$v^N DCsE[x:"ATlLi(XopN ipxC!} ,"iQL4uh닕'gk(<]v+ZP(w`xTRJ+)CJ!Hjd3WYSRhMo{c&y1^r+k-Ś˲x|(؄I \d/9胜Hnns^F~2NS,Ӓ4"[5,~5!$yŁ՞=.✭XŮ7| TE6Q3z\G?.pչLQ&@r`;["ZhUhڈx^ B]WFix{L5 59Ú:O Y×4xJuoՂ[U2\ 1!V'e̶Cd/}ưܗ3ήM t 8|s]?&(^)SR GwJBnh0B:{f5p=.yHUpHBJ=lSG1&.:%ހs%:2$$ƠG-s%'A'Id0bVnunS=`[Kf2 @LoP(mH\?o 33BVStbȱe|ۨl |=iˏQ,S1G˕TC`YY(B%$)RETJƐtt`QWv1^^d3珝oM\p# _&2,wKPcz"H|f㏲KN'grK+~^ϟY:a.6sxx~:+#^)ٞ< ^[N܇Cg$ԄȠ.q]Uؕt*ϕ8FIeYQtͩĆ*宷B`*~QSe 0WJN/s&^ c|YfА;v obu<dىkEH(dIy@3!4Ê'<7X 72՗`Dk5 z H6W SEyCP]!oy^rY68 +Db&C9u6$yΆ@yvQ4:UCmP+^%_pP"-4<nh<$сI6Fl2Lm/=Jd.-2MUم͍< aysOOC(=j\OOh! x ʴK0^=)3ȷeN:r|Jq$F}I{S2 HcdGSʹ٢ ;Fi$ pZF "LJèҔo\z 9L0z b_"0){&kq\X2Ѧ2v)zP!/~K:nF;9A ig8/q*%lD9ɢuhf9` zx/h>T[)^Jr)BCO'$7IY&N2ѻESiIΣT!ĥ@`\ёu D d'ٻQS p9d$MQ =raD퇟9bf0H?wצHPvr?i#,zSJՁ?R34)v%IJD/ 0DlHv ^JE|R=<~eo_vE S~NPv^ N XPd0Jy`Yxdv-mQr o -# wSQ0qZ+X 7 <M(HGz&Tk@:i1b6CͤHQ2p~ZTbyLެuV4T8T Tc<6&&TlI QCcPS 'X"0`@&0#GSxK 6a"H4@2%?KJ{e[FGH%UC;)[zPjKZ9_CZ)r0lN{wݠejV0%~_⁉Fw\X|@Y˩(xHyD_@ q(]։G,ٍ# G|$RP~kXi[*M%5ty`߯;lBq[e:FfzMN NGy(m^h3Uą&1a= !W9jނM$3qF1(qo}e ]ϺM[iv4oP:hVjWqp8|Gf( ocAbXu (ezI֩~r=`nG3#Q>;lFeKXB"Uzp2F,3MCSn*/jGBDXx:VS;^gZ <!ז|kp8?>ZE[WzrdCJFDP0T ]% sv_+wZÃ'MAܰ x4"##T`CŴ< ϓ #a0"ŕ*wrM}9 "B):߭l-Qi17Uwͥ +V3X;s~0ZBOj<Z3O;;K9We M9M2Ϟr+J/S\v謃}dXXOzWB%(aq/P|Aiַvez.f{.1^K!}WN㑟?1nTJAFx$g|Ty?r0t`<,;~uj~Z?E`64) l rDF]ƂOIdO,k$>4[̽3&0#~h: Dk۞ m^ 06r8%2kÉ92y*omCps_28҇ tNqY ch/bt@;R0kJ>W(F_{Y9=+2uMnKсV$~X4A` fՊY5 <^h26.?w*Z%Mc5e1d1t_+&={uT0WoqƎhl#ҷ<h#Phe<4HіL$zZ\CGK}k7LIRVѐVN}9NdTƣ˷- 9/x5)^"@cn v)yJL U_t{T<zV(-0C@pIsRs)S$Yp+=\K{[*FY .Ħŗ^c).DfB,GyāaU+~4&"#6{sɍZ,*3&t0D6rW<^0|`e`=#O WTuOlȎ2TO AQ麔nsL_GiU/P'ă/AhOQQ()g[B҆Fy鮜X6¥`J1$`Tv5G35pJw/ƟaK)珫SGMG}xIdf( 4bWgڶGa>ytf<*xR#ɔƲjo 311$~d{\%\<Q0=TIXe{)A[Ps^_>t{SF(y2,@Y1h*Mۑ;~]Z\dsK))U,C}ۨ?X=isl 䶀#q=clSڠ<2 ?8Ɵ Hr&Q^BvhmKҚpq1C1sih ,_|GdxAH?Q'__b$P I|(hYw}AGz4X1ry'Rĝ7o,wGJ9 E)Z oKrЏ22'F+DIܱ/N HO!5G^:t|/^9 1Aƴ `}1ؠcy}/^XsPW jn ^x$LoMAT(CgNK,%S,e~10{FGEk=aƖ_:Tdɳypi6HX')mZbJuxn:}&j8u,8N[%g2*^)%oZl2"q /^Lm}:u^̒]q܀'Dj?+rB!4RHPeR 4wmiFy8T<ɼt61Oh7HHMi/S\SҨEauíy}vRrjȇ3"Fl ,As97 ~Y#A>tԁh_nN.7iȇz{>^_u}:Hb%M򧷡?E5 6>Zh(-``-Tpi;*[9cTVp ,ÍOl8"C[%qlQd~U-̫XaNzYfb !#6TӨl^"ʅx\9y(D&D-k 8 '-Ikg;`}yS`=R:z'lJk&wWY+<"MWꚹ9А?hKnF-JgL\*є盯p(KvlAΫ|5{Γ$.lylfW˔6'*z a4ED A&QVVnTd$ mkǘސK̻fF q4 y[zl;b ;HyqC`ʻY  MYW9˶ j}8wefqk*+Vjb{}ojCDnJgs{v߾i\-C76DfUOa"'2 R/B4Qq I˚ !Fn>]PaYlBmc|Zyj,ֵfȶKrS{էKb(pXJ`Hb"67EwIbGKaAE3PM$ *GDIhRY}ёQ*5u[mE 4bdSH/kcR䞵e=u4]Gc- \̋Xru/zQCltQeCtKFU4Nԉ!S/u>$[dL]}v(0@^, nctflK??/$Be^Z|9(61B̵݇!pE:*cΔl䨷p4ha5;aB&d/~lnx {\ ^098fd㾡b8zo D# bSD Uڒråm_\ED) hŷԲ AT]EiWѳԓȔͭ=U(w&*f +->Jj Q8(aHWHQS4H/9'Dg EJ~=jyp uqk cU 2ogv|׍wx8e ꕘ*)!s.&gW h-l682uyzՄ\C)JgOe>(KF<'_`6=٫>bhyq lGAq6yz:m,<8_VjGnJ:bb{ݽ|Z),ɢK+Qn |$|lSt&dw !s`ͨkp`[2}v`5w + AjޘVel<X|5[Kk+B ?X_Nhn_M <3өiߏĈzS{s@>-:)9t6>)ͤ`,M9oK63Z眈|߲: $II1+v9fuƙ#J^jSBg)N̤^6[6c L|>v: ?d믗 lzyRowVXK3-"o "*xQaTl[BSo%Hބ+f-t$r-0N\:A YNM;b j?Rn xWkYz^!P$ t^O|ݫ?ibeAT!a,ʍY`Z9 DO٨&Tt.nxL \ ܚo;=7߶5ۡ!:H籡¶_#M{ 5ml:9!,|ͪH4fm;5;ZN? &joJej"rae_G1E6>++̲6/"s%*#m+cay;; zѴ֗ǡ44V߲ 鱍Oz؁fUМ sHl+|:hʣ6L(=z̥83Gq7Bn }Da;F~ l ңQi?&֫i5s\,xΪAK 2/|_V:YˡI6Eis(W쓑3kߦ!D 1VVk;Wp$nuKk*m4Ti$s{.5l`y?k?h3W[ QOU]*bD|C0a<]#Aᶢ#RFfFRH kԔ JN|S:EE/c9 O,46ҾӴ쑋9Tqr?On>_Ǿ"gH™::ȵ]M~qu}#HxZa>4OR* 3=Zh$3ӞyfSfRT9ipEr$L}a nk#fۭcxm@"e/ By] 5FXſ\oo\v^;?'Ҟ6_~hsW t(! /0af Db 牐 WSm;45,MτKl&jJ F{jΒVMqbJQy-6ּ ĸ[3u`71_3{hD)!*Ei(;Xڧf֘sCGG !v.f"zMҮZRp +ծ07~eZ.4rj {Q ߠr`y<>U˄W؂BY9od/)*pip2|a(IsZF6>%DeYC~.QzƱU*k3x ( ~%fIApS[QZ}$T@k:ou l*v}C"Ua/f s5 -hAwI|(?`yrcxU"I^ ̠$~e$D/,XG + A*G_2(0w> VdPuG hglV=gD]I}r$r (7L`&qc3@\—ʘjhm@j 0O}!mm.8uiKޝi`@,RhwF$w1l*@N\bG[Džkq/ 70YYxD5a{WLď s.SQ{qCcc -pX =0<܀'3lRS\!c4w>[>MVp&w#& k޾-l]Fg:HDR qZ\HFRt-~dΦ؜cbҽ?lO? srY̔BB Ї6Ht|//X 痣0 +Q1CDFB8r>O>?;ro,(L50nsKIji_,>r J%+پ_̆6 %~zaO6RrLTTbW1NI@7z.vRM*b20o8A͠x?T ]b9ԹAe␨yEE^.5JKO{'i{9m0kgpox0#U|f_dd0~Yl䇶q] U>VaY+oPkw3a/11ZYEc:8\FmuI7NEKSzCx71"'eP|%8-z9F=ਝ+jAEB/i<3Y?υs<iA72!O IlX9kאMcu/ńeV-=TS}=}ڬ|SAY"Hu|'1&E)Zˀq7׊"uHsi;3QS OIԸgl8w1%F0}` (?eǵK 7r2ZTdΧ<W񦄛OZj aiI޶8n: tO`i@ҖRVeE6 GNv|v+s@&חǭe3 Nl/KYѓqSq)'8衴،qiLUe2R!O@y @BqڰVը=uiPgc?d8;xQuN$hCyn__qPD%L4ɖ#rF=܅eiQƺYf^ʄ. )I*d ^ ,̱3E$WlM[E5@h2AGFq :8 ̙eG-bB K#VQQfty(Gls 30/mpZ}]*?BiI4n򿛢Mԥcx"1cW̛yd-.c8L8%oM*̹@{1P+: Zrdea #H[O 喣M7ߞݜS4&1=P*HwJӊ0FF{=gC'i ̩k5U\'AdRlYĈjַXψ.DC!T6I׻4ćrfA'щ"ѡq =bEr#S}&9 e/f} 6ڃ/n6$@&0 j@WAьB \7q:&2mmՆ٣suYm6.3TkH[cg#6N6czє{/9$NxwA-N){~GhOA[z=uN{6sW[Kz+Z!<*̘/^b/AϚ1˯ 94:@J1|ԓ" Ir:23dIAjaj2i (YI )|<ޣo%%̡q|=m֐Ƹ?>K1`= M'PA{W-"9C|kڡQߧ?WENOOM|ox\4L}Nx?!w.h'1o2~%Z!uiaM, rl:WO?r8G 'S80QXq깩i^/LF~o#DŴ^FS #טPLqqo̬wSF9wԯ-HSeSKƒnǡMű;Rx7:$ά Q=6ȜH2agb# 3P UB4o#0U5mD9"9kFL , Kg3$$xe v4ژq"ڶ|+968@Oj7L@Hق>QGT":_0'2}Z?YrB9}K z߻Ll\$EI~ OsFbNOM\=Q:>I9ITs_4J 1E7{%| 5v 3alvL1 y0dS|qE Q$Hr5uQ<; cO3@XVyqZ8ܥƷӟ4j\q i!M]4nt@@-ة{mD>F茊;UkMAk=n-x"Ej,$ `5 g@# FIkr茊`a);RrCϚHb$%@ m4i&Y=O_-?mγ}+SL9x`}33fDI8WW;# N@'xԈJ8{lm\1^˲h?٤ÍF>*W|H)撝%nT@_8~)Gs':9z*u]9͵]y 0V1Arr+GH0RmW(s7sAs0hyMlز A e b .bj_ʀC[F܈\[F()kjt a}M- Z˥(Ơd_|D80Zʥß1Gzwtt5q iCaPn,pڴq GE@'5Lkذx@llAJâE4'4L j}DBYbns2F}wU>-~c#|$#c6쯹ue g?% REv:H#QXmz͌1V{pvq`B>օɩp(eFi2bƠ8_UC' >ލ+ &D:!"ԉYUlc C[p1qeX|)ܠsp#*U*n3G&`mJc85LBFFj]hCz\Rs%)Ȩk^"([Hс"߇y=W8 ?rC38©ZĽ;nZ0 fbLj7ւ飼:nETdyΧN#@U^$ë$C)mpLhHxԎt`eI6bQ̱Ë>m!{ ]};Y٥L@jiwByBMUk% φkн bc&R |gɎ؂92+hF4J.o*{Z C>4~RLހGsAgM_9 <̰^5k 2kҖ JzVӪRf~k;,Dv:NV9jKY{/6eɪDPo~O|^+٤gڇVԮǁU~t0P7)|f*gXk>WK7-'Y]>LXJ#k `zl8>14&Kn:&e0T#I\l-D*-KCࡃOv2y&F5&Tؿq`bC4/vy GɥSw_VI*lF[|}(IDBc@V p 41rr1u}An&\Ŵ73Yn'@H_LOcG£=}%ViU_;^Rئ)/o`Ҙ߇ =I1HDZdM#{a﹌yCv5ڣ=m\ث(G+dFW#AT? Hs/X9ծCԉ,[VY{T(ϧ`kJ]W1BHӻf#mz!BLc>xtHZ'eFW5.Mt,A)"P `Q'b UAHGq'TS pAI #I9~rz]%2<o.Lop2 Z ıqToCcI *ԯ܌ZS|1 GG\c)DZE 42-;L8St&OX]t / 8%MYI5U=WT rr^H@ %֠FKZüt 9TyC_o <ǜ$0 z)T3X F5˲2J;zO j_Ěpu9㒸JH';4D?+V(b0~OddUbdh>MyO;POF˧&N֪T9x VQj\ üK]/71EIR=!SӍf`rnÙvڨj/n#TT2) 2A9f)8Y@.Bz>B3׻d:nO@KD'"=ct q~}.j=b;]LR 箔@@l*4c ܔF˱G3#?XIhm_mK_,Pu(Ge |,gbHcp/ 6xd<2]L7WE2g]g\<ٟCM~Q(zfJf| UPd=jk>!ujNy,q3ge(jh\XӌCaVZz8ϝ>jMwݫzꃴЩJ\k?5BI3s2ԏ >p\&kXކ!e&]-BjFY]P./r#JPYqgYifK}Z Qy5ptr< .moq]!m }?&:.GOt35_|MawEݵl:X tg?E9MΩi{euaxaxlyϻ_ސR7nٕYWtSͬ %/4 $,`= H>OB LAZ_YN[ECdl9loyhvo$IHcg Kޱ;u9>oܕvj7Ų%q2 bV˪щsL@|Ȏ=AFSn{mr[-=.[!PSPD$eW9D#%"ƿ/R!mt;[~D{nQ:Ov:ytG@ A`/EO& 8zv Pk1& bu- c &;m!Os~r;0Xjf,R ]P"FAY.H7v{r5 ilINNQSI,.V]F5M` ;Pʄ9Xo%h۟݅.fv}Np <-N=3eRbk0q~'AK0ޠ1rX?o4|9swoj'[Εnkh\~ xhڟwdDzM| %]=DEsč0hk dxgɯoT\ۿϧ9t$}#5yb Z 6[fEe.߀ۖ22tManNנil4d7rGn(q޷~JA#>c%%C\(3 2'Zr!W ao6xIzcg)[~~˝Ǜm&TlEks32(ٙe *qx[!fPMsG^U~W ,pjhLTm S32N5r mF&:" Y`G)e9vrH_cRL]"&i <񨇩}3Ds%Zfhp5>-.C۱Uɻ,S40E42]d˅KRT"byޔjy 3s1<^Og?0tvgz܊ڶ<_/<=)3Pd Ӏj9lW2D~&'i?~^6ݵKfL`5ڰ'}[h{ ꪦ&vC#EFƣ&x".{՝aUK: dpr#F7LO =ƛa:lKSclS ~pO9Z/7˽}~:r>L9J^!~k q_q]z'%ÚxeQmc.^RR#A$R-\(f !OXmfxլ2LB_@%̈́>gvVh/4$(z+r¢BsN+!2i>h0Ym}E D9&FN2V(p<ҎeXpiG..La?z`+|[׈ԾO;L}fcqM$5U0X?¶j*үOOi$\ l 'z9Bd3#PzZ KME h$.2u7jv6Wifͤf M[OP$j8 1|o eko hT)QZZ(J[ɱ?tb,cX$ k : l(8chFX.$i!{:"QcK*ϗfHCو=Lb?/(x^' L,^ 7^b:aEM/ .#I#M~ƔmUB` `hMWZQ7ŨAAr%J[B vy.Ul(*r P%Y>?(Tr=a6JQk_tY>1wd+^oeRҋOn.p8C(z<~R󕍭aGNzs+amSO_ȗF='Mr6&6郳. hyJuy}0!\(DR8 ͚CX ~@ޗ߂ `PpθzMN,nw/ &|?.HK%M)U#+f$l7f |1E3x8nmb`a b=98 -_iD Xs|7Ē],xUA&e^]KY0O#2J`c,8ij:on@ G Wee #fE{F"OXC#";@L@ۑl2*`OVCX"l|3>;w=E!ž,ul#q( äيO%.I 9[/`pi.\=.Hf7W~ȥmeGO%T{4b|*Hu57̄c(ej{ @ygilǴP7.-6Y P!3#3;]/Pk4]n͌N{Zb{ ۷o8Zzx+;t=9iqJB\>4: P<iaȀy]dJ *(>9LZ4>6|p.L "t;i>/ i*@SG~O7` JiC 6lX>՛ЫuΆQz=C}-Bpx:heQb=7Iȼ]&n?xYv;70&v4{c(;!ּG,#4uJAe'fq]_ Х% l-R]L\6IA=r9,ḣ; S8zߘn1])xEiՔeѺ- ]ME͓Ѹ-B\h*Y:}#zniF3Er!ԁ3He)c J)cڄQr1_6!:{c8 jfvy +) (,'CW}*P_Bve<$x9~%%pX"-'c|cG2 d L0Gd69)%] AE@QV9@M񺬯”~Dt;Km|v 9rP G`k+zzdxO@$)])Vtsa{lh3U4(n v?B%bfAnC裙o8Z\59!#';yI>O v\ HWS::-AZ?ތܹ \v,G\1f.gzF7ulULt^Jl%aŽ2` ˌhXGƓ}hS;:4jݒ 8͂oF1-uQEz]7X8[1. $>3khf,vψ;F/g_>MsM:ަoD|Y?sY޸USM6ad? Fa]v2p jdQ^C3MF**| /fpsiJαɱ!d#aZnD͆ uu#dI5Vːbc0А 4l:_ԠyN7|f#"#7k "ُ%? u᫷|QikCzmP7FosPms蒤ܦ_ۣ0)2NlYH|(($4Syj7mMe온D~Z2;?nGN}t@؇&wʑNT 4>s{R(6Ѓ7zAIs[=IͺeAj': fϽQRՕÒ@Gb=a}^yx^*u:AֵP4PXI5Et ^Sh\Ye"tiug!v ǙTJu(jbK- qj;1m8j tY1eza3q"_]㶓gak YgYʵ s^^b(0DYjZ4 5X;FѦI|>4 "uT{#|Ҹ{ǡp4!tkUfY S-(pg<_EXBRx 槠x "!'vFEVX0O9M=9Ϧ áZLmp`1VE?T L74=j2Rˆ1x%ØD#fZGM|8ƒ:7Nχ@}oirӻ2CzsKjh7Č})NF(xvs#3M&$da) X;4|ԁLFF ۂ!H6qTER{%{=6Z /.yjܵ%y% ݖKuZe*@U2(U'OOEldnq-?uI̎?4bO}AY@qATfcQTjV C%xV^lRHXXH'T&WSdQxȏ85܅YDCb{7QHd %6)4E2"4xU F±uЖ%pTIHGp9.OR.K,00 IDpRe ݝ$ L7$2:#6oQBV@3)Ik1<&(zZ9U9 ii@Bb7 _T5:\!t߬폇vs lR$.몕Mf8X9K`UvzÙċ/})(Eбm {x[P{2GXgbMr4I/hZ9_$1N>"e.01Kf'j!Joz +3) *9 sR ?D >ބ#+lKC?[4TL3:nxR#y5v=kټPG!B)APQ0+EqDA&GaNg)UI]$U ?m`C]MOAsxZ!@kԱ/{qfRRhD6o3%HǠ$Mqzkr,S٨fH:}0SϊŊ=b"_.$5GZ-e$%*`ai4PS)"ɨM{"^Dt/" ^ q@ϔBǺ*,kI @$1VvE4M5Oa*İkfv,_9;? Z E;B>M,*c:Mw~efі,ZERD`V-YY]SIHCڭdu[(8FPBPy!SE"J 0f=)G0'H`E̳}dXRvg9v FoHՏ6jH #Ԫٚ,m@("$~S5-RԨگÌ$6hBR<з*)(\,hpda䋌bpVr"KM>qȹ;Y5 !t8ňbG pܔx} &&d9*%E pSXmӶmhbXZL[1~M[}9iӡ QRz[566-l<'FA}5ˡ7GqVe)F!H*Ѻa-A[ǣeߠqsN"U\~ "H} i0"elp'):|+*E2uL! &6uxpf)ZF'Ă,`_T2G|][MKO;1;i)LSA#)Ԗ 6<="N -"e)V+fYh,etnj Mݳz35ZHk<9Œ`=- _q5Oؑ# 8ekn_?NȕNkG"+8!6Ti!H(4˻ᡍ}*!o { I #TsQj2`woBAU}fdu}cXȊv%IHL5Zp-mKxu@o/N df_|a|̫CW4Y-MNq5[\ ձ6A[Owzm>IMEO*71>@ypeJ$ ;ǰe)&?֎9&JRs[~Jf+4 Ќ˷5's!_|.{tEJKjċD9^R&WYBzNW /=>!fy+ܣ/Ll^9:+AܙVa jAs)y=.93"?:*phMk fmxVZ5vI@2U5tv+J>{ծqBPᔒQ4.: |HDq[6B</0l2?~: hބSE4*hWV@?ZJlUmO` Ye$[9$A)`ڥb)rzo./j5;_;3۩͂Tq:/_'{ OW}*o$?W`dl8Z*n^B6R? Uny8rxlpv9?m{Xc}?SD4GeL֜x"Sʻ 9lLx ,;(bu 6^k:QNflyvpsc=h ҡ:=UH B)msk㚷KS*8E22t? Eؔ*~fOȤx4JSFQ AN]y]\ ϯ)l$uؿX tVDv5*AhX꒵ύ](!u?ܶ҄߿>Ԭ%9j2#ޝIaAJÃ^9DeFKAl|ole]S݁.]ۛKA܋\2Mj#A΋iVvP~H'nw_ÅҐףyou]-ƿn! X-b2SmWKeXG/9tG'g$)1s#8"n+]q<8{%yfa,FoEGɏݽbhPFS˳1I.1X.6xBl\{!/BQB>RNH" UQ};6$+h7K8|H>?Iе0 zy/*${f6ӐޭmW$HLMjZ,\ԶHZVy﯋3_][ߜj/ Q!9W bYF>8MTFU_D>*Vg{^MT)|2{W[6cr{@vpdɢ saY|Ճ4*+[O("L<{VFkaho[KDl_"k 緺4VR16#Q146=So>a d!xmehNj$3M3h_viFN74xtפ/elL.ɎmGUzZq*KɊC=+H%v $7|P ϧsx@]Bٔ0 RCغ LKHj@^bY2q[9um6{8gc6AήeIPRdFB)~j^SP8Xt2-Q0c{!hqWo jIC6 mk)Ug].dԂF B%m@5D8KTA{F+umjlr162Xz&iYԸӹp8ȋaF)\yG״k4ea H&9ݻR)(+`< :1.4a52/:Sɑleڹ演l&ձMOD{Jͣ%~s\$x9t!kܾHgK\kSA:(3vnРwYQ+Ipi]7Nl2lO=X-4ՁSRl^Ԙ6[[? kN8 y*/϶ҾUJ~p)u^lOV.s;z~xjTd„l3 | " 7[-?O_W?84\mtňjt|bja7{Xhot/R$ )>$m+$?Ͱ /%qֶ11`@ȦQ$ckVt"FU( k:`Aff Ҽ^ PϦ 67+W>^m|?Lt2UPQhu N3% "8qg}'aӃf@i[sJOv2 wDK ^أ҄ư# 2LEe^ p':/==,OeKa/C!~of}E5վ7Z!\gLaX+t |,?nͫ%nI#n,n6jNm8@@V*"H["nžH*誕4` WRK= DWRW-B8j ]mvR<"Bb pbqHj 0$ڳ7wSWC hH~NwI-~q]w՚6.f{Z9\>7B9{Fr$1)TcޅSIFjEL Is <.tM+2ሀs^@d72`U;&nwr_28(mPdHi0R@IJD;P׽u0֎4 GS.*JQmSQv|]8.@c7z/QsLM72)b ==eZn:(;zj ᰴS" 2=# [QV= 4y4 %_BN{ ZFOP꜅ ]%ڷ2JRiTp= jF*aXA*eCz<2ܫW ?gTR qed)8xEml}3e,VWZ&D`QgZ=<'A tK&X c|mL5GF$S5Tc{dTՅbrqZEdȅ3A*1ϥؽ…s;+b>mKHRSɉf*+s4X!wЙ J$@6jt#A64UCx.\ۇġϊ rƜ^!&M dSU)EQIGgRHK[tqF ]i.# ֱs1f^FXƝDke+qm$5/Xa<3cmBL684^آ tlL z(=܃7^N쪁dey![BV{%Ge&8F26_ !Z({(VI2&:R2c\#Hc7uQސN\hѰLxk41v}xR`ԁ876tDFejO)vNGC9roKux6GvNŤ/ pvu5$oks+rۘn$^Hgt8d%Eaȸj?kX|h>2O7DF[rW^bJ*"PlMuz'C؁~N ׃wi3SerP>t|:E{%jL#W |N/Yi)؃}˃us.$FETڷsT0V΅I#YI[ "*WC @ gڵVm'ĭfl^J$SIW3Ê}>aHYev;BˀW].V'j秋Ȳ]6'<۪y*6kU#F-]$B 􅕹 =AgX_keձ5V 85.!DE xԶCQJZV ʏȣs%;!cjfK([!]Z?SkfA*[^i2Z`D=9@yVw:I8F9F V aneA G֊g뷣[r :nlQ Z]a"iG% 2`'_=ǰM᝺<)9{B")Ϟ|KcM{)?]zt.^B4iܚ$N#x~iQs6]`tpQq|8(!G60Vc* Ȑ`292]J'`խV5n@o﮺{l%+łRŠԄQ?WF`'9f3QuN"B"g약q#˔eMq}{r~)WBLO#H>Ijgt"iT lfu36!x=]M?Dsee}S,bhnTw&3@hyb% ZeAr]($ E <M2,e#$_B opj&v3Vɤh sN^ChYsҾMgLX1ˬCyfX6[TbծGZ ?w{u{J[#oIGϤwGlV~|f`< 2yobfG ]g揧| K:LJZljL1XudY"[: H_y]>#b855~RtRq$7.dIY& HbVYXD)u@9FI1#:QFCL{sH|k>+ /5q;T`$!=%\qqdu>7cS2j+ҧCB:GPzsYU-?;nkUac5~$ܣӕ$APy7ĒRsY2҆?`{RDPEzcЌ5 35lYym 7$"Ӹ=ނeNqTBݞ,~{ %E\TJ^)MZ4߼S0.U>hpb93;@\ X9`mrdLiCpŵFu!2pOIvW,F}-fNmA ǎ6?X8BOOc2uyg'%ZJc _tl|wEa@JE7 aq jv_&\)ŻZ$uTqԟ!4D +'V7|0lVͷX]Ce.e&rqm 23No0yo~F(~5ڑl__?'q=íaNœ15;`>]0J4bg](tab&HŇP0n~[wqY2'|^ z"κ೜< {qkyCa,K$SZ Qrڼ#wHJ^P,K-_"Ü`I~[`dNHh-jc Gv2, G Ђ!zzrCsY0EZSF8g^Gj(EK؂/>Y,&r=c *ԍD@Ŵ6h 8ݕnEYxKBb; }} I ; Ҵy [6:/daJt)<96TS hjPt-չ1i5t(YfGޕ{TAi2Z> BUqFڸV!z;mb1Tr<TKAp1E~vk`5)zKi5|ˇm*+*w{$5䉋+eb"K~k*"PҺ~ؠ-t,s R)Bat䥳iJgV^"&.v-Ȇ0drf#SBvzlJtƇ67i7,:>rU!fLbz T5,!wUƐa<870#Ib| 2 _&<#>LT b.SI_t'*,xHs\,7}L*HH $woY%e[u1W?:S_;hj7]c9"t\Q leyUAsMtD;xG~FE5uP j&~bped4fbϻ~\ĥ)<[I\Qm8E #GSxd[C.z-7د׃QhCadR>UT7{=5\Q Rw7I ;#o(4B&@AG: ,ᙔDhlbӾM}E ny<5X.=J,r"v5<kFDP\CrD2IڧPLSRS޼QFP\Цv W,|H+6 t{C4fH)EY-OHowdgRLJ;[ތYc3T,1A6'kS/iҖhugsW|vx(@HʩPRTˇQU=? 7齵ؓsi-oD%cj FS4{DX6EvCL!^8ZYNdai^.R{P4.^?ZW^Y oGk7M\%s)^تP&v5)F<ûZxd fY: nI?f>࣮`9VN((b}$潿i1 $H(L8ѫU n# 9%( qFR=M&("H5!X  2jpaR a^W^5s[S_74b.\f )TXm[.t% m~uz.`JGqv u>u |ݸ4`mpǯ՗uv!^_+DAtC9T4nrm ]_ ]*opä:ې 16ݠk8zc~|q@4W ;27 uJvau Ii'z^.n O GtH[4n?Uc&3)E!PVb4Uć-côѳ_I V&M'$En4Ά5@9M9 |l̓5qF~R|UYs<^v,b>knU.{{f`rX,c?9K({舉 Y?sWN~ T !_V*8s|<{P $SG4(-m4[:g޶Ԫ?g6 TkjǫN,q k;:ѳRRB?2Iɴ^MTnkm6{9SkmNFt9cg *©-=uyޟw?_M81mW@Lj~`x4DƢDmC l> Jf)0`9S; !:ks?+S 7wF^bFJz`mRh:vٴCLP-OEXQ+%H0]΅KlD(= (KUkƆB5Qʈz7H<;,"U2QV+ &j\j?Ȟ929 @Kєf97gm0m OM5czYz|]i%Eg *BqIOlKCagP]2 BMggO^L+-.M0]AENfKz'͋;p{Zido9DT#Cs&ԴHrp.mJC+xH9#rvQ(]@7m˵ +#y-FE79)-?Q̘?'3^8W{wϋ1"ӄ&˅aWDRņnם_8 fx5'dA+VTPR} vfqӇtA8'v ptBc3| AP'>xc2EQbHS \ g&%*/8aFStEIV[k12;S !:4TsFdFShĂM(vk=v w>ߌZ&x*䜝b֖R- If"\'VR[#7 S.k8‚^ALEN Axn'I9Rװ>Kam28lZf;c':EAÞqs&K됊E Qi5 !DEM{i_ú0N]00n-X wUW=yPd#b+"Q6~:j Ⱥ ٨7Sk|"䫌'-12$C77hE gGW'e[ E_moEFSHbPC"`J`U{4Vu稗br/;!~@~!7JF .G~[ziq\.^s\t{?oրfZ2UΑ/㗅h 9Jtq2Wyxt5|2v^ *SaPbΔ=K} \ +TVx!%}>_?Zx<#kuc>%0@d\shlx/ƨh q,e@8c ܆U~ Wd/2DH#,>G 07w!i`קL}5QO JhiW#? &d #!R;7ԻQI#Ʉ*M ](C PA >Uyά6V x9UaAAk",dh?"83 ٓx? MGBz[Z.`$i6 uI58u*S,NY䂛e'5Ic&/ 6ب2V%F-RXtzA+?y` T6@e&Q!/I'6/R#A6s8]Jj vEUxD!PXA1l <Ş/`tGHqҠkxQmD }ژ>=Y@߀|Fg;&/5 1~@Tw/ j;hNQciΛ?p]-pM-Bɒ`jXj Tl.>ڐAؠVڥpjE$0kk2p5+WOdz NLMۮ ◶IA`MOq*EfIdЌ@nI,OR)AYBT]~f&$_ywSg^_U3o\2ae@')5Azy\k\kEZOd/DlVv4GTŀ_joɄcp`XJb/D1<ArT,_ym'J3/tA]Ml93c*@O -Mb!ݏ1Wl2ÊAIV~֤r밳/|z ϒh_{%'| ZAכhjz+,#ƣthtMI ]gU윩f?^S2kG#ԪT3,ve:y*TlE!Y ltX D!=G4Ңn-.ƞz붇,g59XK fuܹdtB3|v*|Szq8+hZp*A|+w*e6 CԸ Fbq`/zq&XSC<[PK߆Q |'lUҐ+SMRPHE8liM-e  ڍ>FaȟM,!ST }4~14Aw$[QEҏq6J>֭u~-uxE C|N<8mzWFpr\2"2ű*F&־֐gʺ?qN3n*phܦ07 k €-xmp20qZeUR|OkVGXaG+<m1#s)tEkaijQrpwW5[_7TCq Bu|B(ͼ2M `=E,QMooɠs8*s '}5tb 1 @Ҩ+ (7$Z_hHu`t $^Lƣ+Ȼ4-nri}&2goB7M?IDAT@sidcSM a.o>M*Z~"*ْ@^ݮqYbȽim?}8El(l!v Uw#hioEH#ZȰ;+GUX?9$}B df !% 1YPbnCm1Fk&1Ն8dG_IL=|I 3ؘ<;F*֙=sF! $~mO437prj*e0pmc7B{N{/"bHIUҗYZ7 o!tiHjl{p\@X`Ɓ,_e:0bahSrᗖ&IX_YUm6.k+HUvc䅿1짍{ Tiqi3´xi WH<0o&0MfZ TòdT%_t@00l˜R)!*ȁ49b_4ʻ/`-x_9w:B9{mnN7Z硘\H] "-'pS!(->2 ky3ן;H@ cLG~]9d[3v׉PA &Vdt8t#%gY#gAh`Jj@ÚWQtŵF>b8y"L? qcO^FAe3,?uy;]W",?j1抸N6j6]A(Qgߴa;6h'6dFXEwO ]~`Rky*ˑi0=_uL40vNQML]p4(hL anДbPUr .T`x'QYqْ{ZSЪ{ %>VT4 ܑssYE hbsπTޕ~I XKexYACP,kll/pW%s\jj٤f'Rz !iHe Sx9$_=/C/ GzD<@OҽB R<ءGn27 p&NKfS8B%pX'>M冓Jg8BmiA:R(L0sL$n3ZHJ h#n@Oz!];s RYRέ i/NiblL{pCY(5j0t &@z z!kӳ*1pMI= 2bQJIekXj^/rvb- aB"F)p [[jQ\Tj$@M L[[-d)]dd#qS*E5 {5BIҎivoiRXzVkD8pF`úFWQb )LZvnWZUV)m !Pt;+D>)U8\C%2+wz5sx~ޓrZd6IjM1jtv][)zb(_pB AǞteSK<^DآQEϯ[MkfPb\ RT z%0ZGN[b{ۥ K6aZO%6|d bVߩ Q=o \Юu!2I)uJ=CVMCS)ƆнYQZ2֞q{稒( F;oNӍؐ]o DVfTr ^֧^V^ b!"8]f k.ut0Xxw2 c%eWwũ(O\lvH]w_/ٴ!=j $xDqyc^E,Z JH lZ]Σ,~unMah7ǝ5tGeiD&|c'*/+*?qd}rH]ra?HCEZ.F!X3 \J]5kg q^O-PZ*uAUC7dq>{zTv`'zj`M}HNĢE>Taώ {рZlîV LnNJb ?_:mN{RoOV|#X>rT(x6dxBYX/PSX}NfŬ)'GV/[]W=SiB Qn8'P`ԵKkVÓk0J,9hkiV#!so/B42TĈÛ5ܥPƤtEFLk*90Y 7l +4[<ϰ":$n)N zr"ދE?=ϧz\aKIrG1c\]?>awDdI+f\m]*_9m+5aT]ssI/?N}KʩawlH ֒:J#}8023vX"ga` dnƆM5'ME\F94tM U&VJɈ.TLa[7u #e!=Jb溢A2'w>;$ >֎_Zw dìHTwa'ciH@rY=8,A_M$Z8Y=rdd^?AgjjV VĎ: H= Z>Ha3+iџ]/B7Owg>^^$<X\q2OM_vA;)e{Sg5ˆ2%OA-hcЭ#ΈMڕ3.$^.H$ )}p2lF90¡BP hM.y2Ѣ&vb!5)Uk`0mل4<=Rt:hdžcձŶQf#Lm)ש=Ax}:feIvz{ۿNqMŞJOglh?s< (l T4>nHB ·q!-ㄉٵv— Ғ|X=.hRۃx>$Fcm^݌Q^) Ч̄>̢&yg󨔰fln4Lc]L6Dj>~c9|ueeirɑl\,\f۽ZF?'PPeZ mٿ*MDXs">յYr.(l*oR=µ`]uIt߀d jp з4ˢ7>N"٧@4m"=0.TE]E%+<_ F%٦&@gS+NF?y}фRgV$ ΀Lq´MkkO feIQvV x yg[{) LJ`bԝuqoJwɴST< 2)*#bh2/s[ezj<vI_/XClgxt=ͯ?{ټ0E 0uRV_%gW(>9R4V@7,nd?%DxuFXq1-L ((x}p{S2EyDtC:B C;26q81̤wxh Gaз"Zwj]ujL{9R=~KW-,mq/˶6vL}+@t7!Icv$]5;Ł}9iAPM-:Tx|lyD[ hAZsp%Ea@F,k>`Z$aoFAj'ez#epA«1Pnl)1t=WI@B]rCTVU!T=ydE^@N wɁ'tj}hVX}%T-o~i{locV_AI$8}86FB!1TmЭ!J`A FšAFkI˰r9Bs atyXuWw}.1w7s(Lwꇻ婮{YhIr I!-bq8rSDLYy38o:[, 52b|!N@NiHVzl!E 2sL&ޑ!Jc{e$#PeD=0'Ůg1ln\>&(!)ɈCl qM0 b/or$AR<L+!aCa|!fHc1C}3aV|b pO `AQvy߰A]x{:38b _yQ煅E(edwB#͙#D0&j6bL*7q9aPԠģ`LAIl~tMi],` cEjqA , D e( 0A&Th-r@CFRdTɃróTkd!}-c 鳇p;7tDAl&ڗ pVii2(!u=CZd0G> |gDÞ8 {4r;DܰϞK}: : (%"h{(1$+$VAH+\֥}o}u!o"\%\&'\TF.nTFbGH rdZsjVR3xD#@,TW ZoK~/=~PkT~v^tM%?BO ^?|J^* zih59h7hh[ );FP[#vk C}¥h)UCx+ %YpoHpWi/wN$-?Ӊ~ b|:HI i1rTeoKu9M4)"R-h$9\z#=tj Ok;x3w u:情`-(6P j~p4{\Aϓ.W`ABF]1GlGBP$ I@4H|dRBʑ-H5i@N +-AFޡj:uEhNCYhZ.CJCO6}cSĴ0cs|p,Kń<+*ZZkX֋ʼn:N`XKr|'^¯x@&la !0PD(%TNExE$`~\`9ĥč=+ć~K!yILTDZO!#]%u)9% Jv*Xn@^E\]>\>E>W~6FK] 1 jN+UxhU\XWb[%5%k%_$%2JǕn) dr"YL^F&$'S) J e>RGJy,lLW\|@r SeJJ ~UuUpLեTϩv,R նT{oS?ޥA԰`hkhqQOSMsfff-LBZ_]띶6]DVk1:>:lb=:m:t+u"fm;;Fc֘1Goo704478ikecnah1'TM*ʣQOQ%[/XĚ1g`jjƴٴlYnu--,--[ԱdXYkEeUiu},q،^F9֗lPgF+[7[m ;%;]nN{-PƙKr\˸4'nw vvd9V8^O0~'L`O4ᦓdNN]ε=.f..\njF.u=Fp6߭}_v<'ZNdO6񡧉'sg+gocowS*tz $$C^=]W/`;/)pN BPHʠ Q v |*D)$:CGGWw;v7\~2ISӁޢ?U|j\K_r2_ .~f[׷-=C>-] iTXtXML:com.adobe.xmp 2 1 1 1 "3hN@IDATxD݉r#Igvvg^P&3B3;Օ$CwĪ$po?rm7pXe}^Z6\Zo֫vVղ;.j޺s^Vv|_r|[_m<n}SZn>\/f-p~f01~/eqzܮe~@]me9-\.sܯv_/i=;=}{nSG|;>/}ٮx0k7R=7氹osY|!~Ch\NӛA܋أNg٬ /d6<8Y|4l}48vvp}=ڻhh#aoݿZϻfu~Ьرں_fYoWR9EMC۵xhx,j{vvOhߍv{70ǰq}?'y6ObPbwY]/0y?}?wy~9=A!50—H}}d總SsYﶛ߸jwo2-y<>n5x4\Oޝnu{n,!Lev]Ox}[?5Fz: v잗sy\vuyyNCc?h#ūr߽$Vݯ`JۗEkp]z-(Tl7Wb|nOܹ_Wt2%$|2D&_Q᠇~PtcY]f]N{ZnKs7^n̿g:C#$mX%vEo]~fSna{iM@zB1&{@E6lmo>T9ŏs! (# Fm=AI3a[l0­Mp r%?oz{3G!G߰Y"> 1~uf%o1]oү;;Aݐ!/ؼogj}Zޑ%Qb[!)#eP##4 ^D~3*t7C%ȏ vy/UȆ<67f9j Psu+~1{8`!r¾1#@w}~/xq$OOs׍0;|msߞ[LKf a,g&&g׶R Ҳv58'~r^HC'˱ JFP[̓ e{ceY$5u󾡔<]y1GBNZq%!I \[>'YxvX hvbsk>h{1]ea.Iq1)a/m4/5٣tgA0)2-lLy]LMW48˚@+1 Rz+U\Χ<{Ĉq/%2?/b:F ?'7:$/oƠӗxBAקH35}O\|+y[nkXOѡ"4 k3"p@執94( y!ꕬ wXlp̀%[NeCaWEb+F7C5E=Ϩ=B~u'a@v읮p\ h#41>-)pjaf|gyo"XY,̃jrȼ~~,.Eu?).s\g@Vr^od ^ tb#}cr,p:=M2H^ɍt$]oN.aeQbYin9"t}]o$9HV\>RW=L^F/>{ǥd SO"lV68UFxD  v'O>őe#Ȅ;Jf|5 ٱ%3fDK,`t0 L[8@/B*CrF&; g[ˎ$pR{4«5CH%H]) GC6̳zre ƧK3h2m"!*poG.Mm}.5ՇlAGA5* ii>b] j}*ԥn%^עm*h\X2셼HUlZ|7f]bDR'٢}[8 w> 4u7סDžG"ҍ(\@ B?l4"۹$){ _ s B>}v׉K'}Ԇ>e.Tc@#Jn8*e-EHN캈Ƴv!(ؐsv#ILz$"{"Q{>)e)\Z62AHo6n`fElCaxJ>:Vb2@8fq@pc('\4%dI$בPia(.?.S%RX2_"VCťD$: ?l.TR(_r[$ vA GtU@¼~cxAQ +'uM@@4$!g-_uzAJu= <6[,RPA_4:mZ h~2p:G  _Y}Qr:|^<1\% GU}3t5>I!SʔaKzpXbVJ$f]l0m_9 *FkŠ1#v~xI.Oz)6-Mr!(抱e]a`;`DR 4(I3B O271c' դ=PHM_W5('A+x tJAP r5d6O/6CT |Y͍ qn|m~ARXSU0D~O:pg7XR\_ji]#fj˕_=<`.磡W-N8a $7 >"| &a/!$8 㘃M}=gf6Æ&iG{&r<K ig ")GW۳vt1.Jh c|*cK˄.٣ZFhd>ڔ%!. 1&FuH0 f^s`bm FEۇ9QK](nB.l{6 V}Y` 6_2?XZ 0Eo/^H v5ٛbHjjxӴxywI7 ?iԼz!J^,zYmp5iaJb &\AqL(HYoE}'ŠqvlMpUODll۟UdYQŒj(`(Uiʁ֐b,!rUZށDeaz39tߡKu$;rD8 ܋ApRj.LF ;?QXm3 UAuG F[*4D Kc {&Yx=ɰ\#;%N8KU&͕1SMsQt diA@_T~ti+~Gn'ffi^SAz"XΔ^ H$%,ąu]UC_B7-=*4 DgV:a3!579C9El(1߲LJg08 ։GDV <"ݎy\0.gv(.J@Zkg#D"6Ec&ncQb+s=k" j @Xu}%MR.EJ CR`pzT04, =Qݩ߮p\.g^S(Ib":`cd2G!ShsÐ* VU 2 cq|]ʭ-byf +4,|; UE58),<f% =3G,{Ѻ(#q:Ӎ*UZS֤&l)^dBTLND"PڅC k[?< dAF4e3RO)Tw=Z颻f׀H݁$SNj0hN(uƀG5;Ą x2cRÏ29Y`òEқbwz7@vXƗ.mISF5nagVMDl[Mnc AУJg'=>WR˹8+wi¯AlB}`Z[kBȆA$0XjLsS3}`&nmg3t JѯgK{lm#< {67m1 neug/g~!$#`Z[p_r@ NIGI  IL&O u7R2X,cS%~"͂T^~]^"Ό O_[E@]0z&N1!ک  5aB-Hv KAR#ըJ0=_2Q'D%J2:߬ y$`C,4nthd(fuCb鏳t;,+A'ye0ʞĬ"m(z_ٷcmBhYL5̤&7`=$S#Btv'S2!ɕl˜`X]I%lVBSM'nPHl(DE)1j' BY73R'A@'~z"z&|*c[qUPX@@2LY+!r&/HX-Z՗gwrAR3Y{b Xn a^EoVF!k:-;fG,d'k__Ͽ?eB(NzrDhL@r̂Y^Rz!U?zI:2R镥,j9 BA! C*7qswŠQu 6xJ-n,XIqC8c‚ *WQ/[@hGnJgHNjp,rqɬ/|=Z#u?Q}+=Wtm9ݷVBa.w4rsîV0l9<] &)8EZ͙ܰBqǙ3LKtxG}}ܵ끿Ǚ=:9E⾯3;,P=?>8m,f?Ly+n_#'!>=[ߦf#A˒< 4,e= k7_,W~e;Nqfl Ę^gN G `Ì*1G p7E&+Ԁ)< L#0}`k_ڑo S[*ZKU~ z]$DU2~c"5[{"2afMrV[$}_4nqxauHƞ$YCb)2tOAE^u|/j'OLeQEIqUʼw3w ʦdo(,% 6{amy;}/&:^ԔiX\ ehvod$Bb5ȜLȝg'*o+>E۶38ۖ؆4;$hITu8sQȫCc3%TAIkS>mhM >(0@}X>_>+3|0Sݸʼnl U wIMBEy&#֬NھV3ą J 2uaV',Ё`JLY޾/~ηn!r}7a3!|1LlC* iBg~5j8uh23lEhE {~Ѡ&OF竂L=ͯi"/PsXi!N#%.pyR`HT *,JG΁HT$vB@[T:fd{񟀞I(0 ZY@E`fʘ FР%>by ܝ9TsU#cL՘+Y+Q[eBh&Ҿb\t6#!cPyh'[`";K\`zJ]Ayl~[6K JPH(:3mZxp 9XX|hf}g{XÖl, hy%1Diֳ;!^$N ZVU/(%qM$po(zDYX革bgge{&GC% WY7ܪ`RhTĆ>Â\j}؉+/h/u{3PWD#K/YQ))fJ4˹^"\J6P 7CΕ#po1lC:Xİ =Ɇ 5!=Ϻ2<R1'u' OI!g7jH(A#JcT\ļ-?aآp\R &!5-=1 [>nG̊UAֵKv[B`St! wW]`Au/AhM@ nV-t4<7 ldL8P~[5 ocSS!2Fr17H.\-r4 )+ڱե1yPJ3Abq0`O7JOh͈,Zw;|& QYSgzYրė(W櫷IG/:]O2?cQٜĒb&}hMF;G63ɗZEC%y,QehedLD6Mui0&H|LYRo|]aZ]O2+}^Q$`w&2 *Q ֕zڏEo1m\G%:\fSg`(&>be6ER'مm&׹-ЈMCԩwSy vc Vst3O: <r^9uL\yj/HfeCLZujo@2%C%4(  ~bٱan=ԫ ?7k[o*~;ŁxT+3 cY攭GXR1 tWst'k'|ZH/.qa?~Z }Ϻ0QMgrJ 0F:l_$N$s*ձsfLa`1J*3\1`~|hwI ,i:u̿qԆSXzbX Xۥ+ 63k$_OFևy\kAdLdS אc? S()##LF@a1+[^E(P4Ch!*\mf@C;djӧZDa8!9!4&`)[i cIb:(*(=ܺ= Ί%}\"g\p#$<2z 2"Z(e2U` eIWҵ@,Az (1RDo3yTvr,xazC,*hVF&avo IrP&(hg 0(T%"B͑DnvH S*@GYl)Sf!7J(.>-h^"sv'RCA X*GZkDrvtc>5fP&>KQ@hj CK7c1T#3cNmCJAQQa,C]# 5Ac0TUXTm c{ F>oi͈.hkgB ݈5*y1MN@rY3+7@l%3׭ic SĖ $lzc~'|L cm\Lf:J0Qϡ#Ylmr+ɮkG :ۨd` n SQ19K?.uy̚xn ַ Zt~[rW'5W}!D]˒C$߃ˮ\/)+T9~#R7B,2raKCczEI"W &RT1;Y/6Mil ÑK^ ^ _‚_u4jL'&D W 䢒ڗJŷ>Ɔ)r\cZ>d@Q:AC;1W[DC.8gf:IJz!&)u@)hjN@,Ei"4J aLL!"t|#D%ኢ)LA~Aimmg[ŏ*iԫ@"6Ķ?4O霃Vޠj^ɗČdƨ$>2R<4z;/ҮTVlXΣECdȂqFzu80>nP(՞ 4@Ž&0OkZN^X R~W[X5Oh|=GbnG6EhQR3{mYm ]<"Hg|Xµd&b/m71n}@24ȓp8 T>=P3ʁ-f`E2Ut 9Y8ڕ\Sz-߮l2 >?pP']r$yG:ȑ- )12@8%*YFYc\0 8GA@@ef&F ,yPq5c,a:73>87L#ts<:,m';ђ*K` Ojm~ "‘mY IW`5!P.BJj\2={s|MTlL3T'J8+B`1Q&ߙ9b%&&VEjB+P"W505Fq'h'gfg`щVolIg[t[0v3KȊ`&U%J5/%: -}PhlhoUEQ%c`";?a) žF) UԖQ;¡џ*\06n,6TIw^&{G FgFƔ)>ւSN@璏 t[K667jjΏX;BuD5 /#iCӏ55Z뢵`>O0E&BRGVgo$h̭:+m m䱁}(2g%A)1 TG]$MZ.11' z%J'iM,b4$<@4S%;pOjf:1vǐvs 'w$LNgմ衾Hq` dXM&bWN0T0mrRv“3yc43$# :OV6/, @b:lD9t76D |JNT@ ubnVCcS`RQI7(PP#k֘Юl5 wyBxA8OKt+ ΊF)ަs>ԃHr )t6C XzҤ AwDl-LȩN J3P 3(,$0V-N+vFKeJnF)GMƂoYD7Ib_借qS`mMX!p` RKnvKʹ mGZPzjI-v*}3N]MIIMMfR,7A{X^0v pf+N t#pzTu! gl0 Pe<*łPrbXBp0@**:23Q)s"JTo(:21r J>]a uLpQd10aO9cÏVjOA~&L4Pp}nNb&zvz_V%nKլ2Jm/zҗ#75grF  ɈJl+̼.ʙLA6|B!hwR:BO0Htt,UZ^8̅tO)OE%HJDgQUf~P3Dc#^ύ  5Q=r/$H?:m4DͦkR$xEXIˮrHÂ&ޘ%h\YƔl bAzywHDS\ǪȔZ|] ܶ:]<(Aew}$O\T n{%Lę-gYӫ?~;G,@G=|H?D c|$hsRW"@=4Y߳?ECa,G xۿ]תԜ¢OrfMN'ͳ 8QIf2LQ&uw} 9N&c$FXd7512?RbA P<A%ӹ#?A:"l'z*l{9 6ڤxiAׁIā}:b\tL2RS ?D jO;el'QM][BEJI!Pzǥj5On_(Y\7 Vh!Z%j dSGxJh/tSQecg/ؘbkLL]2 [Ԏ[a*dJyt[:K ,b9]Q Q÷"?j\X!u"/dd®¨{>0Ob\u(`<`KTՑ@T';C6+SQ!(=.%͢%J&!#42x C"Vy(PhNNB]rV%?zOIc4/™>S3YN8ŕT>qx)a"q4ZzBKOk"D9<q/=λsMss[Dw ۆ'D @-BB1]l+,,8>Ѭse 'G$'FZ0m{,roPhʒ7i&NH~ i9vP|Vt$6lj upIn͢i+,b!c ڰF .PF%ޠ!i}7}Ȼdqg?p4݅Ifcuݞ!G90 ⵆ][ɫ^Aє*iy %c3fuHYYHu?&-M)<7W*YY~R[aζ6oSP5gLWKP';?+/X2aߐcʾ϶~ﭹ\v)MS?V`ϞnPoB~tg\0@1qeX_[KopF7Ԓqx(NlT`)"a[TޟIY\ :*JWY p R*xA !lP}oAJ+/X'pVs%vښ-1GٓuiT{m x"/|1wV8)حfF(R%<^>96>?Vle s@|H:Lj#xW`&)[o`t>dPX"ܒNyU o^ۛv53 xmߵykwFS2-{,w?+CY@yU<oɛ,ϛ.:1Ϟwz1M7+G$2G(9y*Fe{\6 ^n^{xa9jDXu`Fi ?w:kn X~{^Nj+BҭIZ^FVƔD+Poƍ\3ހFy jkx6Q}5ӷc}٘H hڶl_۟3+4sYojʔeAANu;HI ډby0xt>wjv s/B01#w#Y{HIY"BDki1[~?aH|v Au;I=2^^٧דن+HAr Ƚ?|ڑsSsׄ^b }[Z.ë^ f'\;+A)[V|WqtV^dP?]-%uhPs783NUTdvc˚XquyT CGJg!.`0inRx~YYjo pֆ9gtDZ >n80rde|$Vm~wn`[SRG8JcPS Ⱥh08Ae7J_T]#Wcrk5&᪄ ;peuЏ"O)] `osb)dDM#:`A4j_0frޘS<$0@IDATgYܰ VSL\@e WщoޢAiMPvaQ>lz[jwp3@ WDN d R7' t;}>`_/q-T$S+֏ql8;D|?oE=Q&mbQLr0@xHL%aؐ%Ό7Pd>VAcxa< M3~; 5sq_pΈVxt(66}FRslc\yOEb@n#exVrv3,hjFU!ϠTX/Si@-g,H9[~m+%B$2GE!2` "'D4po,$t REU<#!GYCe:,Zxs|5 &zIʘq~4 4POڋ&a+NtlrܝIzwe,}b,9<-M)yE"";l5Bs 鍯 2m$ n(=UXQ0uQrp<`@u~{}蕴i)<Ήoބ=:imNTD^K i#;p-EKAo31]FĻ"K 2_,d1aQ嬁[uSz1wl\!&Ff+|YJfjPjvγQqX܏B$0Q$0Qh?zxfAKiZ "?, 4#1O~d0 CBOU"rQ,BO[}4Pe@ o~`ۃZwEk;[ULߞW3-KbB쏢vPzmc7C9 DzpG_果$l dzE SLh'zQWQ00RG6!`4|AtBff׽[춞g`ES ׃7dsPzA^o3I oS\P4n<щ/`fʦ+*ƕW8ҁ\0 P>P=+v֣j}A=Зٹ759+21R2iUa[s *' KPek*'{ZzG">%_qAs.HZfUj֥I+5fA~p;^cw3#\ZU0ҕ8 X:٪\Za6"$}\NsdiCI2ڇ:gQMmjMM_E$oxS'!pEf7GJv}vTsG[2)gΑa N3kPj98'cVw8ўL#!B DVeU ӖܬHsPddv鵯_@~d4t@#I‚5-CDtn% P 1 ^ޡkU!^QNXD5tnyWЊtY!7(k̃nLbV 1#|1ۿ-}쬽22>qߘ%ŕQrj.v1ziB@N9:)3sA%4kbWY.ƽZK]T2Mu`g*[@2F/P^8wWPBW"0N`cRKqf7RdSѷ=JdHb'|#9oW_#1""=3A.CHFɫ!XbJE'Q U_LO Tz-3V9WgZ=K2z>T* b&DF%7s;/Gcݩ̜>4:mU1z,qh䱋+[?0QhC ʵa!jq !PJ0'#wkIM )m>dn* Ǣj4 F ]5n;JQ tէd-#ZmO5vUp<5'2&Wԟ|!]΅S”Qr<;=:V`Mfy 2cڼP<6԰|$.8>]בU"aH gع>`` s84҅F`cT9mI^ֺSQyG (9D|'c ICD! %Z${1| /jU$gD ܱ~4򺋮b\O20jޖ$`"$Ds&g7pK*C:qY;BCHKLNI1jͮ$"?nja @pD*i~ȣA8_W|@BdLdC8Q[0<&33Oi_q'`0*F/tGx L* G*Uv'ẘT '9Hӄ:F1J; M@_r!Ƽ檐Ӏ/3=`U\co31䰯ohճ MN[@KS1v _ODGxe216 c?ZݕҤ_bY^tn{ޅ8o55 Qߴ xQx1x: ˡۜJMZ\&CТ ̝Lz NVߌf7S=)\(\dFciߊ26AD"b_?>6`>4ְ#/Ri]m\k*>I) 2.VWwx E ZY6`$3B7l </_GHì+buӆC"$'"%f}b.=r_xyXY NKJhE;^Xr(qf\ w$eء%'IvS2<9D- @O2,c{#t?<@#Bs8ǖ3 h%*,e(;wD\X)bQ$Xl!N56Ic >S3bpPWy* ӲK\]g* L3P(b*98 7 l1 «@xNj3ΰE2GK#hls 2!#J-p?O\OlW^#}Pp*1| b@ GE AK@UHw+K7yv% H̋#%XNcp@IgJnK~P?MQ5A)zK^)eeV91Ձt׌g\V f7vIM#}OJ(R-^6Z)k\7ωtViUBbܒٳd(g#I o Gqtɛ)xwBri h (.bNdzki޺:1@$) .aA oQ_;!_d#ʩ ȆX+onm^LjkJiq[Ə6 ]jAj&o1MTk.hef?BpG 4,[ D̐dXR"s4 PGb_H_}) bTEe,I?2,xlH( -]d-UooK~}zM9k h,hbeE[ҏ∍=6%wj%<`#VjGGIr=\M ЯBB[(y 4-w^~騭Þ*LNd+uJ٪U1ҁ7}\t@l9? smĠ<* ̟@EMN%Π ƿd->p}ڰȂ 3efmicl .8<Fv28lz^=I,;@J292j̙IT4TwPXDɹb#Evvz}qpLSM[ sL@\bo=rMgjԡ N:>E,)R!iquG!Q'Vow~Q6D/́هfZM#&Y8jDg\=+"rE ["P[HqgkA`2}=.[pTW)>@"oL,EODݣE-#9%4ظHG*_h8#3NUn:ֺFeTpk`%$eT&-hC!fɷ2$a؅5&+bt` eѨ?/= m z'[ԃ 0bFI+:D"m9 KZ2/UͳV;ٓZr*B@<;w )BHsL$Y?:9! Kf~Dc7Vu7a! ϐ( Z $C.gCӐ*$g`Z=<6QSk̴sG~y6:mƓibGQF;ؔ*-"\{V8&߫ڄ,C\K2# 3iZ lpòQ}a0Z`ثJ{(ԘkI6Rb2#γLM(C#W6`KLvCe^_'k;{8M+ӾqlM%w%H^ }p{oqa\VW$VvX#I$tV z4f4JEB$ qEEQ {)Hc$-lj%AfAu[mVN{v F}?^ FlJ#tvP#tVޘ3/>^ yzs6j!٪؎3"ixqQW +bHgٙdYr0 Oe"Tn^ )SD.WmTl#"6#{ <8cW%hOp &|]N,K <@^L %@lV)G9"G*m7m鸅{[G? `ҢTvdJv1M]kfv~YNݧ [>#V7Jsltt}=-$ 9/ؑMN_IadIP'@(S^unG+ 82w#Aku;i9-Z!0\r6=I]hJo 8g3p{O{[eFY6JԷ GiDZ׵,$\$-߽~*^_5DP߾m|U(i[9IfNgc<_)y+&֊uZxwz7s|!w\ж}+&Ǒ\#LLѦN}[(Ls5&(øR(:z1 X|˿ooga&ԄD@0|ˣ9JM 15 69$+n/Fw)xfs3\F|}8?K&cBhw`i;rPr߼OMwޞsz|8W)eIHo+ =܂fk󷢲|WDŽΚz bw۳ZyT8HuZ|bOwbWeWqlSƓx㪠! ]Ag$ոw>|HJ&̤ttg|>$8By{r&bk\ =!@9 ͵)d˹~ R̉ RPh J0<[ʯ3b6[/aɻ^E|,t@p`ؚ1%hbݼ<>rY+9q"<22P͒31y]&PЙ;bB jE:@2qʉP{2DLG!\閌tB(O_ړ5ZxC~P"mVy*>v=NYb"!lev18' %T W/ wsaGA M`qnU9gn qބDb|t 8M Ц~LIi(byȣs:)rug(8HSapK!̗2$D]'hXA*d;ݼ8_fV3.d9S7B(>t̛/SSԺHQgJV))AV$i5U,LtAo4p nCtr$,fFphg,>.1$AI 6qC q+^WoAŘQvϱXH׬r㱚d&PrV(86;+L:9qR%Gҿ+d3C;"dlM$syP;aJxGt^=],0@Sё@PgkFt9 ĺqxc|a8J%$~$;F%ׁ 0yԕ (Ce\1 ƵW` 6ouFQd5aZjIy Ot^U]\hC2Msʀa<'NcL& fC@?Aq\VA= 7A6C9jHL KN**&ArEsFm$8iAܘ΁IT}}%N&7Y `ٶU Z@Tz[kIX"fôw2 ?a ec7wjz k|dJ@]0!N Ȳh2hsa|Ѱ2q:KmaFak{CT$;6k[AfP=,WPXjKPQ`>`ph|6ЙlW ò^3em$6/'X1lP>+;n,I3 DFDeiƴZ-D;>b&ً#D& f37wkA:λ؏:c} /}%r{׎KUzL>j+L5*bK1SK0K^{;3eǓWÍ7ա98fku߼ຈ\ aCcc5URhäRlZ&uJWթUB#K2;z6#o[qG 8y2Dbό!8qUWyi|sy"{wF5H$s,LY*(V o9,L&іB~vd<#yi|ܞP =az4cv::.Q n I$F6SÁ-sBSI8&?~f0K6"K-cu*P 8N;<' uh  吗N{-&pIZĪWSTJ_(:PNlUa!z+OpyH1Q^q:>_U{*oq 0X\WOQA$rUD 7Sa6 2L{p~DT䏦ek 05x?l/[2/m ޮ…!؈HVAZO賩Z2.A.KG Aڑ#ZdēFl'E A[2* ;暻9Vsx? Y%2;/ f,5@lU_D4Up"!)9R? 3 6T_`"|;" n% z7<` Q|^ ˕,zmTh<8&k 98%&Xf6yn'rmF輢t`llQRJդ*~8ZjȾzF6F / ڴ:; m*(59i-,(8s-|GILذL)-%ÿI(1$H,qce%0"WœΙco mtJծNKg9~B3G$vra:Z bEu)$I)ġ\ NAP׵<8#FoNtLN:+lK{ ;Ex'x' 7\fHYmFT>8(B$#$9T{Bj^ŖEAY΅}w{rb? P}WheFWW~_b~!#,VO5~9hjKuw-ƃ$ _~Ruc[luC*8 1 16%U"gdmݶCLD r 'qgZP*XXi<V~&𛁴& Ծ Z8x8WJwUnwd[99p7Ն1;W=W__ۉpf($"AhpUDQa} 5eZ:Ȁ܉e`UR^ Fg&faf L =VI (8#6 yD2"AꏎmNߖ01"F [+qK׎ΰֻǧװGxB$M%kmE4&$ߊ+x;h$53mLr44Mm17 P|jzx‹nVnJ..>CqsiHFT-O:6 uf\S nAo)?X:> \suRĪ f}M͇8%Ei5=' At$Bg&l/BO(+k*# >^>;m죎9]N2.{/dhdp…B]I9rH2 ޟ1oJd7JHɅ蠔#9.HSs tsq`k*?0-_&kTz:^S[fY./Q3R*V ʰQo}FuenfrnR@ &:8~ƈ˂KD2DŽ\؈, 0#U͹sSjÓm)P/7x<{%ZS *>Ÿt8|V FG4 YAϲޒ1C@p'DA|BBc1Mz|S|T'6:+W | 6~@ MҳaHqhָ daU릠#okx'HTkJ "ǑjB=RPZϧaF3C%s^ Lk+9px.Rll~쒻p؈RG~l~2vfdbulIqkc+.TͭW`͞mp:E}0 0!I1}k \u9F*1G<Z[0,t/`4"H时(XW: `[myNPYk0qO}Lӿ5 h yW3Q [CPZT,dtfdq$ScӶpl(5PՅӯB 54Ɨ[=ŨߩK:1 (e\//ԡhdrAڍ^jn0o?ߓߊ1<(((ب% 0N≏֍G`soOos H5 #g_z/HK5ySGf$27phI<\-խ3<0fR~. ZqDN[k?#P^ı%^Hw#Zԛ%iDwpmWvQ4{@Mq%ﱁ[XK/<ͲY#BCc]0FSBR2Bv_B&2B@C>nqV-X 0KwI"xҔ= ˛  :Ѧ_Zuon@܍jWJ^/ 0-gQ v37+R)# VFe<"a-Ǚ5ZMެQe,1$A!U/c!/M#a`tO;<>kt O3Vf/1iҸjp&PB/+SX>AlbkC_ qcU] "!9ƟNG D,Uy{JŭWn\_s@}|H'**m8tR0!nM\q1~9/O1הE-K!Bc{8?;/o{ZB9EXQ#qf0¶u_qh'U:[3SYYsFz9ou]qv_ю~;X<^lPm"Uc{vXp2i=ت(('JbX~ŦRjg` s9\ѴMj=>$Zh8Sv?qt]hO^9d\-Z)TlViRM18Όd Q?,G؜p.^m| x I Cja2164-i*zADt3XZ1ll9KN̊#"βSI¨Isx̠Ĕd g#͢hs { ):o>OC;+(" ˵[D²29R憳mۻ`Pu͗.V,V6q CtFS,rOG30,]5jbË4[KE||jXe>Rn\1k!nђL) 5@ی(N * rR&@\,XHMZ.Vs$AF1/XeCZ>L!m[uPsb2HˁN!5!,=\J=>n)~d[KO#^TՌBRZ -4Y %~A0pq >`pD@ޘpj& L {QDQ;=u᱿tL]Sm/^om ]B'JG4T?e[AgEX>+Ph ;Lʝ9|/ k!%!dT^4-3 wȁ%suqX$Zy|-:!y[P"A}vT7xJNB%᣸q2[ڋYc̲bIښ(6ݼ9wPs;n`namjwC@{>ں#nbvqh@)?Faw]B1VeiH|P i|狄2987Ze8!kG`^1T ,4ȓ$HcÙ G)SKcq>̣D2F[R&ilpqsE$GV]*qA|9C3fXkYYFPNwJmn\^:cÂnmNb$yhg"-_ Ry/lx,ܸ \4%djČrO־TЅB=+șwNK`f5a2di:el9:R,8# :d#y( N4xtYwSdf.3LEDx{ U8@>6,nBT%EMh0q:`a/&paΧfGnmq>s yWֺ){mxΖLo)ӂDYXh|1*p(WĶC$/:>v4BB CQBf nWpC spC0l՜˰yB6J.%/o1Ibja@X hz\3LK_(A8yT=,_0eaΑgg(pA [\)-k@EֽǍ/zP81j%Ht#)t}䣽L1IVV̧&_Y폺*Ё#?HJn &'cCNtِO&744Id(w;:G N\loLڡw(QR~ z/DCBDf'O .Q/d)[sMXo4LdzhmUORF5M h;;ZW>1PQ;y1RX;"^rF)F&g(˜60TٞGt#Д $5#gPqDX[cJ8_H]{+TIgkS<&j^C,b" 3=t/UZsM%KvZ2m E.v49xrz6!gQ4Y/-=48] } GTZh5pm_tCZ^=fFdIj@Ԫ:OlwP"Q*,֙>׵Wov+wF=$S#Asa 瑛lne{>(imP&zژtK3njzFllAGQk&RxXv_o`OP %rMn RFљ{mz~_؇ʰ )Ĭu_u~`^0mq# ?2ɨ6ag/= mn<7@n?1áS!MIWFD>WS6(C^yQʊTqlWA8 p tX$$1@ XBv`%,5#Nu^ot[z8(gDѦ4aSTPwY((yPat|(:z[3SRJ ˜_BРȃ/l)X4Ra&I""5󻥘KQ{U hh%=CzJҰEkal+ʊ-KdOo+l yk('±:˨+5'5G7@e m<`WWFIʶ9Cn|wfMwiYz Zd&S>0IQ`tV]D4v#uTbwJCl)^hFB/4B\q=-moٷ&&Z :9` ,6ÑD-%Qxėo4:'&s/ky2$z_}D 6ֻ8f5- :φ= {P7\{UdJszIaI$1+Ԙ[/>(o~dc 3$Ѧ H s>R9 Ntէ&\5-+/mD?:(ͤ%Fp` ,nt/g3z](_y{3y{`Ip4f! \(Tts 9v \rhD.=Wڭ8w>^I! fӽҡdIZM/ōSwjd$t5yvƦ(DG;e8XУIR {%o×k*9 7]<۪фvWmN1i&&Ž'yeMh9G3\͸"J!LwE~e>KXNFBС1/9c= 7av欢VYOH8 k60ѧʒzqg܁ uTBzhqQ~u||O|$ң"'bIm IS'  (J^eO L8d$13z4 !"$:i,,-Bp!$ڃ'M`hGL0脆s&*0M8yUP,arG9kFQL꣖FiVYML mOZ#`n/+%g$VŽl̫7z|#T8E @ (Ў_ݏa% '~1!#l3 p,T: <*8I[ 0t}|thE8cFнbD9C_wdI i{|+!J#-jG?r;D|xqܝ퐜 a t!~ iǁHW8 `ջ;UC0*$mi7 | @tkI/+!!U+)^>5ZK*L|PCp5)̚hoU*baE}yٞMfpdO޿w]{ud4kPCLk\n.r|QӟKGEv\)Լ7j!c 1"6kt."yi,Rf9|°@<%l|\\7[?VVëU.WfCGR`/iXs8+y}=Y)&-4qˎlFs鑝ugH~׷H.ND~wQr:B%K!Qg 57SƹOF$H*2^P"E#T#ԜC77ۭ->S}A(;׊/Z!f?ߎG'R2vҭb AuDo?yVTflNUݷ>gɭȳDc^-:2s60ZK%޿Yoy: JGPSKoNML1 Ismŕy\F֞: (p "9y_UCZn{.6ɚZ˯~{??3/p3̏_%,a)0x 䭥hGοEd,seyCZd{VBV UXc{dX-ŕJ̹Ie*P%*֋iua\9%9}7omoawƹyd8 Smk[L^PKZR:d?L} 30#a"C2:[e>}9<[R <6| lE{b&>Ǜ86dɂEJ鯦=V_ b7[ϖaV2Y PG-bU-ALتϨa7CAj!V$L0&fe-i<7_:#V!qgՁ!JCcD';IiX~Y `ɖh8ܜcthOphL9jّd?R0)3(Ců9if~m2c."bZ< K)(Z~4A*(HEOT÷AuO8h@d~uZ4e9O$$ƨr=q+FM sd7(:9eݏjb:[\^ҳz⢇8!UGĿ/:@asI[W*s( "ӬQH Nt\5 =y:bHB`syTE{ r2$Fa.1 |G|tV!e#Dk!x2J'Ӻhi/8M"|j%aKA`J\(wBڭX (fnH1/;Y;ulEHf!.X eNGyהȜ&d|ik hӲu? bP'klzsͷMp vՏĿ+vř,@~tD*aba-Lo'Jd/C~j冭l |"T ji)!{Jϸ L33 eLݷGh{, ,.Iwgf0L ZbE.׭<aWDXppJNBcLj}OϺFq#8Od# 7%ka,}25/y}t \{ 8iIĐ\-AVDcPrTQq3*GhFf) R=Mn׫Ъ%(>8WP3aN~C3/Hc.pA(1/)͗dv lQlY"sH*B,#kv 1x _?Kd ΄dž>踱pp^ _@ xhUx1^Œޫ|,rńUT\n\NgO8PVʑ [ GCJFb?O8]N/!NBK<5ڿgkn" a7~TևMNVa2}xGt?QO X@TiиRnА7дK#,wȶc9Cf*S$,oKl׸Gb?ƅJ]tGj<. !JX[2&3/vVȺډlMfN4h<>tA<F-IFh& _ 0k*y A3}~p{0HgKH7eFVT*4qbiX㯋8_C޸Tbԑs?E-| Dlئl͋N|Z1`z2e)ȊPC4 :&#*ɡEm<2v`HYV5tmR u'B v-*qfi#Q//97Of`Fo~"rI2\ʰ_'DÈk|8[RaݜD1\aCj]$mQnLxKUR:B=h \TB$0kiWv8~SsRhD|[bjk"ЄO :{e b%#^CsdrWΙNK6m6v1^qN@FDVfRwHlJ?߮4{\`irO:bVx[ׇ<5,D=\f.loeR8uƷ"֘T異pAS vyj'm]%9R 2ZDJosTB֓5%( ǒ{T}K<0FoǡsBأUJ@Ȕ1jR "NTM {pMD cJI4aDkM Oڮ]^>j] 7q.PR߰q=((]Ѷ"8^h{V8 Q{wJIqM \,DFXə\cVLQNapIBz/aC,8u~O!ED{/iߪ%J:3tMⵠ_sam/)^+ ,_HuJ=O {>wMJ]|ʂ6oL;(fr KL M*>s]X&)ͽJ344)3JjauMׇU"%ZK,EΕ˽Zp@>C8Xfሂ >OY)kɖ,a.` Xz~]+ۏSd@#DmS1wg!=Gsp8YIE hL)Id"Fj?QJx 8:0>!ۉJ>yz&f=^,!5ک H"4[/r3NBGPS 6.t.Tఌewr*cJr@ p8ɳWr\tNpDvQoxwENVIǂEM㦀 $h׻0BnRSj[7d\3z5y5ϖM,\~_J6S@P@hD\ ƛ.WHk%}R %WTQγo`kX"5YQ@0`\QH߼y35@9ӓ" 9 9-I0'v(K}. Ȥ{SL^cm0=NN3ϳo3U*~ ecP3VR%3?cP #[HjPiRd4Eu_ Ωn9CW|pʥ<{D_bf[ Q ˑ/ RlzҦ\:7ˍZ980#❄#a,?A0 Ks 8"hC!+;ja}T/;rȃGW`@DJc"~n3KbzmCL|tI6!ɥj rh $| JbyŮ@ ?`rk1>a$p=x6˚A,Q0[;v#;)~vծ\*]HPZ/Ex #u5TʔI,j?|Hu LHɉ!Ԟ mTp:+2}& 0忋E#46IYisKtN.^Ҏu!ͧ(X߽]O^QoJ,"D4#]F@bX9 g!8S*\ "ّ *J9jb>S/FMQ둂>2dςW Pݒm#h.L:TJVTL04:EGkRTk>4B'D<8χ(=z#re]s _\H ֲ%rZ(30Ckx0 +aLg~民l}kYh*8B~-54&~5ky ,`{q5vRIč5 kswk2 WױECrBN4#s9x:5tpަ죡O菮N϶ t4p/  J2>J8ˮZ1'o(8ծDO, wܻ.&=ԩKDtycQjdc y]ycd@8 \T ! y8w}@@sd2Fi1t@r\OVr:Ue6SRQ- 6֚/E/qp&PR︘TU{( bB rU=Qq{1 ހ6WDB.݋cZP!a񑣘`Cbd>2 #myCJj5a${сnDAϛ4+J:~ܫ "qsxb'jz;Z)pM;12 3\ q'wE;q?aw%s`IQDd嶟|ˋ;x8 Z o L/b`0ހ\,=ެV_:Npch)u۽xd:+D-C+aT=t Ke6UopIiԏE|XzMV={!?yk2KbBACEcS Oۑ^ъwDjz?󐴈ãOX0E7.LmT10xq}NWT~aFj@/8yW8U&92^H%`D4iR6迦{Eaaۗdtr tG p29{j\Ə:oUVLJ&kނ1,obyl䩌/8ky%C'ˣ0gJ Zd|w66gd j "`UL =ő"GQܑ)xt'ybݩ{ws=fI[IRyaɘ4E8~ i 6lރT2wNdsݰJo(3fNvvHyI?RG6B|?)NVwXgF:ȷ%Sȝ'D tADXbTSϻC`C2(lk_We-\)9LaW5{ 'Z\$՟M1cxqnO͒7APW@IDAT2W׿d[W`aR I=<;ԝ`lyz#e\" h˧1։LȐH.'J0=fa=7O 1l[?ZP=\<;>3( 7584Y0JE&¨ s1X !屜RV.\B̭1܌~¥͞Auz!iB,`r)cx7eF΅.y4S/Tޜ5$`+=Μ ̑yW($XDbxQhgUG8_za_i*5*;?N"SK,> F=xa2iRؠY/ZsrR2,qFҲUnqYvXJZ'8NJTbi!d xĥV|1IQJ )ro T7 O{`)ͳ69HTj1g */19g<38Q<vp{b8@m:-pu護ԋS d.C +xw+/gpz-! Hrd+ro7ANB GQ7PO]1D0_ЇMJ5#)'4OC X5 AT|q^HbW7DX?e"o9d奷N}6co0SoN/[z?ގ㾗_ڲ*t%dGCUoBur[ݾ[}M;M DlfD""{QeCUޫMpi#P5=a)ڷ70fpz?NV#GĆSfJm|NtnDDD}jT]/TbF3V.SOaVyE9j{U/ hزfn'e5Ra^sПdžmɢ<[ibcAOBJ|j2-3Ux۷2)Z g̢R۳:ݓxT/NW(LRDL!,"}:r<}k) ʽzqa=uR\47r 3p~9ί(R\ē4:TFRo'J+&gNwzS1gŲABh9[KS!Z67>'Ƴ@$` TE7ܺUqS{A%(՗xŗXJ:9dǎړl@SN [R]i>VTa$}K(h70W wU;lBfg&[^Nj͔˷i4J}h=5Gz`߈uU{合^yK 0y|#PZѸ^R0.:KgL} @6ÈYO?y4%>#Q b %BJ4&4qɆ?ȷ?v&^sQC5N-x+(Ke(i]cqM>dwG =".+o,OqH>-9`痵:{Jͨ8ubʉ XHN.L $S'F$>G}g yĠatBw V$4)Ԅ#ҭpۼ#/i7&m &QP:щ&g@ #ZgGƾ߇荽T0y`~ɑa^=qt\0x@68xOuap8U<U +FikdA7Q ˔QV6?bh,5*ෑFf`&r;fr7V1sN 8r5oFDn*"A!+` FOߴTV9|W[A!?f<ɳ ~OJ:}$ДE:e7,M|d4Kפft7;KhVADl^yF BV? EE3^Y-'AVCv Wqdc 5u9&oi0& &NM CPEDl-O(n2a^v[`Ha @Q9Qh|sXbcdQ+ژ*FGGҾ&+YB:a/Ug3yx46 4`/uJ hU%[M,k(kpm{h @V~* ov :a\.;V+9U3 Dֱ |y?3CIrc҄`tyAqai'#= p㳰p"B|QAI)lφM?Dmo0\G} fwe}pHq 4Y{S ?uj!4z3"-~oT7@07:@P8#VA (J4}|9#D-j[~ÒtY(/V Ңv"wXAԑI_|W ub u{v}r^ k%kآ2暓VĚ8AW3 = t3 d3P򥥫3N9Ri̧62@cu>6^5Ll]8z{y+91%7!a Q=.NQ oNH@Ӻ+A2;+x"!ل/DBz 1~m?EMoCI~A)N{@HT88E_N SqBl_n\=N, Y$ڠfҀ748տe`3!>V+\yI YG jmcb!(o#u?Z2+A1d6wOs% U.44RRʹ7f'E R o{mQ #=bu=PR4}iy _Elv* ]k\y}?{Oa:Z]X5!jX->ãV 5c*qKvaU,9t%J#("݇Xf(*n[EVu￙0ÞGF ~ÑQBZIpv<0RN؅3%<'?у5Z#F-ݧkuaΡT[|>>e {ڿ)78k!EO."b#}ȏ(`(Gq OSw&%VX`@FsΡ72bi46%c-,PZ  X)wx>W1J%l ǀ)QKײaL)hzx*CCA!:yW) F M(XIwql9diŧ b1\L%?NOA-<ćz.Gfudx^<$(=FֳkEj,jKM"j"b8qbDsBhJ5eM\n j۳Ig(LQ k<^2DfNĔl!^,K "d]!Ë:2&io`3 Rc9b"s3H^CW6 {7nٿ\`_yQx#h !^Fzi cV -s[y> Ï-VA`_ДX3]X;JbV [݀8DUYL98 GᖳƢ5u95ȱc /'FUpoBB~:Pd'JYUlFтy^=gBymI.٠aUZvB|gz74O2!ha5b6?1TQok:0BޅAvL^ <_?]7p_fwc+ v}mz#b$kULgjDeEhd@ +),@ FCCYJ20_:!,&ᴖ?Qf'AFlvB,0]qYI{J,h7Ye3HH'YTfeEİ/>z?>1 ҅o@p=B v`R,̒V_*cCz5 %s3a _uӓtc)7h|`|tJY0p6 'XRRэT%,X Yuq3ډ>-Қ%>&K!M'ZM7mtϵag; H{1k")N y]MT,`|1Z5J+c U3۵?z&>t)밾_"ֿR<EÞ֣jC0-6Cr*׿V?(ʈ0,I55 ̷ai0]Fsnc&t7){7H"Q  i0-͊aHj}aK2}78!Z &oiD=-c4&?g 87O ɏASC-*(2"-#r WKٽVylT~^1hD~I&Eҁ4)<,ؖ(O)sn!/Rd}s.gƑ/s?捹>C&Egg-*:Ddpў&aj"h@jt)g[^n5)4ZlFo 6{ ^OXxf%Ѐix[ e0cs&[ ~)zJz z hm}X L 6]7Qo L/L5AET^>y~W8=(*V[n.[څdmm\`rg~D`/wYV.axZ^.DɀyT[sܿ̂Δ/Yat2t?ȌhaՀJT6& Y~DMϦI 3(:F.uOP \TĘ>1vzF7s?zۂi1 <[8QJM 7)nq6' ;zA2(XBEzwwc| $Y@Q86YZo+dK@sDx2ԙJgg:NKGvCbƵpro& ՒyY>Ti9QI!zhoy4 ;˕?3S^-.ZZ=4 ƈMiR 0$ah.A"fZ޴.v2N`%#͎ [/~l#֧S Wc.z&Tæ;l(<ކDkOK>\G/_*)) +Klr)[ӆ*I4+l ڲMj:@MjÜǡS-Og(cy(׉e&q%-s4d> z3u/ڤ4hNv۞A4w /)N9HF#HLzC^dFsQY [=x"f7_Q~< {>Xl:\ގϋE6 ꇵݶ82ߏZ)`&T Nӓ/d}״M NJg$)L52ޞjN $ɏf)b$Y)\FZ+m.Ne:3+<䦝6=J5tlHvќY}E{.V+B#1dV`4Cѿ9\>otpXE+!=oZYK 4-p` z4&\XJ~oW P_ų5^SΪ|U 9|19bpJxi- hMq"¨PW̬cT7̎A>(mUG_dSZ)s{Tm߀4TD*6$4*0PdbX oksJ7׫S׻G'rMt<֯( Ҥ#vQeͯQŔ uKXSJ0mfz" rfG?fzۗÚ _ p+t[`=.KN9OҌuOX=x2f;w2^W]ch~zNSWfG;رKɝ =UD`_ nݮ0@ >XI0j $u |H<Ѓ6RDQ??.2_ng0=_^^#>,E§}gKoǣa:c&ȸ$ 4L E1l`pl׿AgYВ12N.Se\7z\=lx_va>B7Ǽ~;=G_V6Kҵ} GVs{剮_f94~_yq?7©S `Շ MYKe*3 鐮!P /5.40lK<W[1͡3#{8 d= Q$nX\wb_ŸN9UI?]?9[$@x QzkBopLi,ْ_zS+NW} J!W}l)P ^h//$tM{`{+sš+cOpΞkBjsDġZLT[rI @H9m*#:4J6,iA/q^jB5=x;iY`9[-0+Ң4䚓Ox\ȊhlȻxN~Se 9O^`]t~;q ` , :uKwu/O14c@ ַBjOzRoy, jOg b{+F~Ʃညcl~)bj j-k:^y3c5e!OLDz>03gsQH:i:WsMw0E`d8 d\bWYF%|t `)1 =gmV;VO/h$7gIZ4Q~+о y*ǀ[UD;+*ֽ8H5<-fFk.zϚ=7v W 95 esi6'4SB!?>M1s3Gg^pʘbσÇ:QfjU'CYy#EDZX}.mHf9))=MƮ3jqFe3dema fdCܬ݈)]1 AΡ7:cɾ%t(\1fC/ e02B+rQ1n熼V6e0NhoE 4…;tb)]4Ɣ Ms)^Xm ueq n)靴C7(`lc9RaDt:+3Źyhnb ҆k57}J 1%cË !P+2!}Tac0@9[)IxfJ3׍T[FM߰t 3H;cqRqS #(}j'S.}.fV#^6 /qd`bp ]ǛH?%ZRKÒƤL6E!TO/e#U225Q59D]miJJJFcƟpk^1==w _$}{v ѩ)?΢D/1n)r޵6JfNn!Cp?#w=SG`v6Oe?Ceْ#-n*PcԀGiA'41'i_$*2ÿGe0cLz(2 HCx&5'/-)240ބfDP^Lo)Xe)s?Wp3Sݑ7@0cd O+p1#7xh~zEχP@Q] `-+YVGo@Ilؕ+vYII6$w^0hqm}x~\(X; S,D!i8 I9; F{7E=;0).#I`TF3o^s'I r壋U2 \3+sfjz{،ie#Hk\% x'\m4 ēSOY#-R8PጧʣiL!2kJ[$19 #-{cvt)5/ӛÚ0x!&%-A4]38۸nʡ qj]fƔTnlG\JgD.@~_sʧwK bƧ,%cTʲewxPMnE\tg p5ɾ ʢ(bUM(t.=l F`,/*&=>Aeu&7A <|K6$5Ws}V4vXGS1B|[M7p y\e *ߥ+mè!P& 0!4"X;9RF a8iPPX]1 s[&'==BFCf̠Y#җf2y "H`ho bg.l̥C@ilY*KݛVPĮvj4\`I1ƭc͆*s+t 9Z Ϊzw.95MWd@W;,vmpbARUH^},pLJ5I:Vl\Uq)m0cnHuks]c^&aLxV(6Ѳhz;C GϫYmt<(z}'b64!‸JGΖkD4Sy(=ImY1u GHh-a1'Xk` pfmwTDGRVL2Gi) #ǵ5Kw|=U8TamzQBL9 %Y8FgMl `SoTwb(|ACK?G. zc"$}$Hzx YIM֌_"BXL@ A`{ʛ^ NosYÂ"\nS|Dǽ>2*\^ /a@zFjQKr}0UHsk homlrsS{$A>ZCF% Yep-4!r`9ԋԌa?j< )koir,e+}1"p % _o&=PfzӀ,9Tt-4I" p-NyF֗ oGU]Q[1Gjѩ\4]鎻 %I`V/ upGpai {<&qfQ^8=1j90PK4i<U2e$=Sg ֊+y\) `ʼG+EsqzeS=ВJYR>M$?P?1_!a^Mċ"R G֏UAe)asr!Tu% qP9}=&mEwPOAc5p=Y^f{kц2Ƙy"HYKzoa/4=@VK&w+>p}=8spOh%oYu.?>#\əj&2BBg2YlZZ⽆S eVP>_mQeL&3.)|uFcLhfRq@!l g/aXI[)"{P,g-ḀpUʏtV }-}  7PB7r@CСp9`#F=RcGϓ@IR˅;rv2.p4kp jE3 VC]mpD s B:eO>yZ˅VM)2E^,h\ȰЮ[13|T1GzOzؠ`-/DZLH": ˱wBk)Nk46R׊Yp$HG&V;w>wXcHQ4pog+U=6喍%Wи<o'!i>4_E\)2v2T[됃ZNQQoE6fGǫmFu!)\ :cd|ܫVBBoAlYcTZ1Qx9g,ߨ{QHδ,ڬڲSpR !ñfnzJs M~03bdġvE-,Ӓn}6N.ZeI=J&fpø,o72X7 "oRĐC8#9^}y:!8(N8aQ*Tj](0a||njV d^B*VOHelIij.v c?z[G_,NMmq8㶍< '^f B>pR+qƐJV-G[܄Æ¿DIC!v5:w 4ܺI. _S/|#\8(wd1Dǣയ꾇ÒRV4n^ztrCE\؋fUҖ2,KEj5U~5nu_bj= ;〸CEi:xegy,FӬJw\]|]Q9'3wHwfN^jp/2+17TQuT)Gϊ&UU`4iw̳Grd.rx|S *E->w'Q"}Ԣ58<)u2&mFs׊< T^E;n }pD* l{CDBM/}$ρT9GO7z.׋T݌{d>5>-#abW["/@Ϛ:DCj66pV \QW&{+ Jݙ9s.nm5N6mʠ"f'gX'X,=@9z(c DPК*%-%4E?eHh JFU@ 6l_za4=Ab/iKdF w栆 aDXEP_|4Dh%5kߖeLpTtg5Ѝ@GCUaG]&`J͈Wqoq0D!ְ.50"Z'-(WCD=]Lc<"vyl ZBk@7~<1Pv;oUjyʯE7\Ys%q};k䱺5ipH' 4u*-?RfꊎS=afTQ"|P(!gUeo /XȌ*V0xU*3qùjgJVUؐ)j8*xl 1H~|' :(܊1GQ WHhMqzF5yX.e1J^w7 6p(Xȁ2>v4"HiXd=ynQNߌ;($Z<ڥ9q]XJ=SJ.{O'N+FKzQ;2>=%QoC^_!(OQlN9F]"x$ QמAFY"4,4 ex?>~35Lߚ=7<";ZM 6,xk:}(Ъ y04])7 Lɑoq>.aE0T&$zTx[k+ Ug%@9ca17tTb-3ǍIoovqR%&9kK)2m{g A^#5بsgF ӅF YTxTiDhFvɈE {% 4>`:}4h9ӆA}zYH`ahYի9{ s~}\2 \k)0}fVJrQC?rb$7%qc>|8&Ki daYr| ^\5ap^7=B@Ob#|M3D\{R<>?my%kn49rU樣6J"12١r&hAVzw+; r8!\Bju{/tn+ il%krR< J.ޮ$! mE*(&6V+5r{%;5YT5ob0pW^|Dm$9^igIzUeL!FylwyQc&-XsvLJdϖ/)fy6p*|^$nIxuon4Ԫv.!\訷* ö ϗ1}Uѣ.Ga`0m_t(%S Zt렅 ~yKg0̛Q DtRlZmwL9j `3Wܮ!a,\QY&^,)c`*L#Ծ!3}tr/ϗڽ-]];Qo5s=ă%Rm0H({]23|Qr@j^|`=-:їAsv28\WN vrP?eݲ4:bߙ{`)R#LxQ#=zZDiT/i|5 Pajٔ ,xL+[keÝcj$ J4B3Z_3ܻ7r1ǏOڹI/p𸩉0lINNË42=cw)Eg83HjAKʸa0DtK.]\EXI gUqo%T'p 4գLC^X07n(ܹn &(uNq$;{S5E^# 1/ M55+]ו]+|@ܤƤ$_&~0W@%)2`g*q%Zctf#8w۷ aj HgIO%P^]2թm};B^9^b@1ĺȆ1Fq:˨$r -e#vEDԏC`x>ɿ q5q +^K&m{+pLVC @S2/& |١jZcp%L)Q*ǨWP. E16rg98KvJZ!LE)h" V[S6vp))(ģpeS}h\܍%UG2 LĢeMͅs_(&J IG*b6-ژ:ky&`qfH&jc ΟT*iw&h١$i^jYP#r%f+*zO&h6+B>Q\0ȈKߘ tE8WрRl#hDdK_Evz]863uaV)9fcX]Rzp8Uv"ɲih@xʠT@$3X3Y;;We" dX[-Jϸ}) >Հ(ufkue#X|&(f޴`%A<8cu-~OfSYܵЏ0pˏ$Rv^skvNոFij8ލx 5o ETElqBJ {Z>\ά%랃 "ZײtL Xr0X(گrv1!2tJ$\&@N/t"l̙ݡ=',M PzzJH"F5䶯v̉Ἰ 3U4p̏@5pH_e@]8BupRqCGP7>& !1/j1Rmߞ ŶƜ feDB߈"dЅlwJ:+1Oj~:G,f桕C:zT=^Sica:Ty TYB h{#@k)_7]&1@atkEe C2azOC #aUΌ? {X\qz~z hM#=XO2O7_rgx/5i֔ei7*xc f?lnć?jr]uk[ Sv"xQ)8~KH$1ˈMZL8z49ᘐo%RcxuX@R&O|gBNJ8PaP${|F KZ MHK1(U<@A }` t'F Q@ ]#e N\aDC2/Vs:C&$ʢnШBty=HI= p^#uF')k|\s%8F3=c-Z!. DeH9O| QP7A4^r'{;pRs Cޖӫ~`_SU͞Qۦiŕ,#;%huv;uoxJx(E;X+aP#^c4j1ڌ0ChpF8dR*b[&7:XEקu!8{Zak3#I'xg)*2nY~5X2]SVs7FZsJfͦutl\F3{f7L19tH 4Mc&&pWiC#1jL*Kj k2mZƒAaZ|73qTM[hPkjq C FoRp9de<.E o|ێlDbbmås Pgt'l*:SJ7l?Z`$'&SuA,V#w zDϢxV-urvPLR3S@a2y=%DGBVӒ̏Ir :Ҷ8E. ڱwZ20G?$'K"ErI,z0v,pG7ɺ,bH9`d\R[e: r7F 6O |u &#-Z]Cp{#2 }Yg͌-|f|>F{DI%Bm[2uPkI f(ٸ؎{idF0tO] 6GKE]y"SfkoWT-/ǽr+ܼԗD:sR)1»SNnE9Q(Ls֢ͱ0*GK=nC8غ5foGu !J)& lMQF9sB0;m<l`z'CPIÍjEa7g+C OvѬRX3` 6SWdn;#S=%%pƒvB2c!.$厁DHKR"#Y@01)|'SJۘ3\R.(C8,?Mr0p*WXzkPc9>iB?1QxLD\Ӿ<$H:q5 .R-YpTHHoMy4` F[I˷RWNݍ vqލ"3kX]] )Y45=&-kOc2LJ]QN9 ͩMqHP=̑)`̂"۩Xn[sFL=tTd=\UD$A5!_n E&78ʞRvc $,sdTy^#W+B!/JU7H)`3w;]}M :9V.Dn/aZH=|Ex5~$PV 'K7Ȩ3"o huxP¢V<8Y0<6[zE.eh&7( Q=cD2!sĠaL5XzXVFrB8@Ix4Vl v݇'*c`g D¦G}(1о]/ѕ ̃iX8Y|f==HV>O.q͟ĤioC.Ϲ05-p\U lԽStf{e6QlNBJ'790N"YΙ:H>eHjƣ9IO 5Tt }Zű֋R}|S+% !Zzk#OShVp8`cs,;N_eՏILzUȿgn%xR Cm?RWm!nSvO/^3xCH#|R%91؎sTt};B*h8% $H.)mR$"F\9( D8  NQEġXm!2c Q%\1"b7|(5nv<*a*R&l UDvTSع”Ԉ:x q ~T |vͨmoEKiSx߬sw#oy9hn42 8'yrPX:9Li2$4G^Ȧ"*-%6d 5eAU+JzO7s8tozٝ:BvbU3# FԖ{+[ә{6RaGZ"up~mJq!qK; n96aiՌ w~AJhE@!J뜫clɉ)a P1]e8r{kG66 о-Ʈ6oK K 1{5lEfgQ0D)$[Ι}\BJ1ޘ=T EGYr<f/EyWM#Y2- M>XIؾPC9WD J9L3z&sȐ[/E 5 +I><ίF pcPM6yhq6U&YAF% YUJvj_${DPF&7!4go4ظ2KsI'_F - SI#=JZeְ!k?8)Qpofsae5e?mner<|g_j@yugѩm ttK!D=B KVD!%HgNV0ܞ>pv)9("Wyxϓpbi,D,}X)y+I/iü.",L#$|?N#Ɔ؆m2my?Ծ-rh2;94}mlcݰ}++FMNj)!{N0i{U@1 K̃yF&xҶBQe3<^wNi/?eͺ4Em9D?~}EShBVGȨ;M5sѱ;SW,,-og|_/E4qe>'ތz+Smլ/WUm[`Mje132&k>Eljgu+Z>qh }wػ<8lt6Ɍx|:mstB&R≫iWn Om' T#D'6¤;<@UUhDY BmHAs<Զ+5 ȳ@%MOdv ^Hϙ"!^1ivnPKݾ`?^-YYHNڿ+O0KKLk.ǯEf v3 <Μ" `_T'2jڡXMyI.X06vk3-)Mj#Mp7Ȅ7N[J/XckQ R tmq%!-3ZZ ܗ_"s7u{lf)@Pn@ct'/YwjrIFm+`#jʜU Z4 Dfp"x. xŖX=kg7$ۛ EQP'U&xJTB@.M/|[#`K'V^Mo<>6Duo lzX048#b;/gTodsyaX94XQY:]G1(B'EQ3 OW< %{vPȅa٤"p<*f/xۀ!f6X?[ <ŘeFDڻ#[Δ+t>Ug Mc+lJP,maPrPƱDRQc<ͥk5Y{?nFJZHc>\J3#h?T0~SʛOS  O2@+x>qe@fRf8pjBj TBGZɎ laJ!S5zl^61wÊ1f_\9й:}xXpmq*m!=,d#qzbBn4,[i4G!r \b5 .P-h MX ]F4=r~t#>Z!pbQ×u= &F \D" Kow j@GKWd0WGT8 P8`/uzu.],`?FM ${u>+7CRM5R=W&ʞ}煤 l{@ ` _c5RM4h + 5k*H{*HakkWahÌгk@:BKos {r=o=o!<{Y: GcD=[1/M঍tE_BYS9m[U24|Us|u8~lXv87gYY|s|mpCyb&F0\۳~.#7޾C6Ձz?oX2oR;ӥ1rr`P@!/O`(LC >uz-[v5fkgUa:=EF` 酃A9A"B1y0+@cdQ m vM =75<@09o Ê#6d$N!0,5"uMkLUW4ɝ7Q9\& ƠҀ z}p .1$xV"!ƙl"mQ>Je`8-FihnLM]iJI5,Y4G(r@o"W=6E8i([`T z3'FpQr斏iL2QPLJ;-, X悏Wơ{ޙFCQK/{&Ӿ!֢=yW3 ]i+oR fi?@| P#12hInbHSJi9n8(]n`aߍ$z(qɍ0%#U,MjEDK 3U7e>`<Ql! <0n(YRI ֍fN #AiVfcX*86o(V6h a s7% j,✑/#0*8M W[ՓFC`EKqO_ \P mr:( CH.ɽA׉:¨<Dp[Ի x8p*n=7 ΨSswQCo[DRBCt[ # rn'L='ݭؕ/-Ԝ uH; ?-gދ%%ntDQt A1QLPD!i4F0JX,-zu^H)31jgg ϨcPUr$Kg#݀BX42:75 wU"9f'A,IK7aA3BB[w5YEdчԍ:Y+=0,)f)<~{#ϰA,9^\ F@@WI4/zxAWXxa3X)=k,a~Yk姅=s,B#΃f=?l$I0dfUh{N 3i*I,} {xxDM B+?!!lזi4S0x\cy~Ma ?1;QΑD a[&IJ(C|ID–=^Na$M$kW9{|mw^hI2)$/iԛe*IjӐ yR19, Y)*w 'JT6#&!ByA}dKTG=*X~^/d-ΝY@Wmxdӧ 0Q)tsEy {84( ~-A4V#{[@#0^xqn mB Es%?8_ wCd^N>"J0DA C^ҳwMFvL$ R ]|}m;N:*}oU8j%sS1;B-jZO0ZeūUQ`Ru~umٴvFQZ(|#k#ؒjt>#@h잚-Ξ5Ji 9c䀅`ZQΞN[?XX.:%<{Z, 9+WUacً$.Eh̡H@DI*dW<KV6ہND(##ӊUffN[ Ay\#E +#4 #|quq"V/W#xsE=nh:+ YjT0>S1>:wHr%5y(91@)kid,o,zaiΐ% 9,F D lbq ^$1eE9tfGVXhPR^12^EaHaO\P]79I{ al')h?GPlܵ]ؠ¿e@!%9ȫ2h6Tw+HFR[VVg16RÈ!;:\0[S>駗uk5!>mn5u8Xfp-uAaI%kh0&=dqǞ rQMܨ ɤ| w]c?#dG!rt#;~2i_BNhjrUSBVMa4u+QeP~9F#𖚒޷@a*fy:d]UD^zc`T|􄛢%ck tDdc#h8S;ԔJ9'}!/z4w'@@ #4dZV1|U V/Ydt 3ܦ:-!V GO #`;&e OspEJvaIϢԛp 7mf.,G*@̒ઑ#9x37.w*tӅ>r P s&n4"@-j"&{[Vo+ pL@՛=@EJWQ;|2$YѽsvKXn_~*QZ{6r"}-omgN//BĂ`Ίf94֭9j6U"/op9 ȼ4(_חO?q;úML[0} ^XF\ߜq]e`]aN1.:6[p-Xu8 Ioc_'+"NhSDt&7_pEFFsP%+sJHm.!ardY$2EΝ\j0[>O?8rED$W+Nc%(I+щlH+}I`k v^+sj3e£X%\% |wv-xRY#g [g)Ɨ=Ec' cF#X3]t5|U0´;gpW,'Aa_푕qPSb"0"(<X<9mJnZZInal-^qV _ nr) Z@H6zQVn 5axD2,s:ZٕA0LV2Pmɂ|.:5Ig۩mm)'*i%` f8"xȬ8~mKSqV'F73C [4hd}+:YXk3)i[E]P P!^fCͺshsRg~PԼ4OEit2e`aeUW5EtnL-Hra~3MaہowDi0Ygb]W­Mȿ=NJ,Qez2ͺA.5AM[v.̮ D m@ V$\Ze7p( Grp'AKF1ns`)o7?'KS\+. f?w~xv̵rúm7.e6+N7 8DPCHDPQ[} L!OFAC_gE#=PIǐi)2ؠs4fg<Ǭu_Ce$4Ifa~QS)D ЁH@9 HUC_%i~ oi"lj֦,h)+➞(r0IO*ʌv+TW'7hryR!F|ȣzqxbCA^H| {ݜe Dn*j1{y6r;qyhFع!hSFa>oVƹXR# 7 YX.Q})v#-֟_?QoDHdjp+:R4R*YКbm:aIMi4 @65(߿m»˪#jWo8Eb>~f0A5"~5ob,i^Qn+ei)t$;V Dw􎌈B#H6 D!VdlFz# չYԍDL Ɛh)LIx~2M ?(jd{VC$)*C;=)>-`A_σeξ(F$$P/O {ՠ1Pd޹Fb%Hh fhW`~jEpxk25-9SQAp($^0|-g/\H-c1A:)[JT蒵tHr9oR2<7k<>AH E6Mg"IGČ@ Ôny7 F>C&WJ$T4Q.%r@i; uأbP /=| CR_oc5k.lI>伨7T]ɟ= 挀 cnedf\lXx6FJ}].10|B]D7DI$yy"VJ1u 關Tp^4 B  eFJNepKd+xpgZ MٴGp|9qUpzDHފ7{c Dv&0j Ӛ%:ڒ_8i?j cQgDU n W3PFy : `cİz}.j$1qJU|-7cd-D͜@b 46&VQȆYkķ +͎Oȸ12̥{wC_"]rqn7K2O%yAQށ$a5RQAw޺U V4 O@w$)XWv1*um(&"X\h^WڳgWESm7-[$8$w+m:_!qUhE(!gj~e AXU' LkpZ!I6A ՗H5t B"lrZX= y{:ƞ4ä 7habnHY#\p!+"7v:X3"KIB/jcV :4693*tX $N RHB9˴QlcE)rP,G~Q3Pj'C-fd$`; fwCNtƹ5&Ox.ho6CBW-!uQ;ZC*m'TfZ!׻Ċg_/ADƞm%GA-D/P$| axm(c'v#HEкi횡pdrfЮ(&_,}4TnаȨѦ+OOJ'3lJ*'AXBkۖ ',A :x+euT*#>iOCz ƑnOI۴\r8g/1d@[MH2~u7 }OSetL"n9i.)KLZo%gZOe`MYuټF^/Ď#۪k@. SvߢL80*>"WGIxe**2`ԓO>z#" 8ث)hKI.7VNlkeh[IQ´ݟ9Blc9)* }'?AVBMq{yFXVx\|N󴐚XLr!^RN?f&hZLCB*l6|6HĮl,[c&@jWxۜ];!PT̈]џc"+YOVpԱ#խ d2BϓX8kj+)K֪df0NdkcMel"RP/b¾%@{]MRD,-cr`eس\Ȱ'%JBGѓ:,N1a QqA&C!c* @6, T6kX58ҮZ_xُ uV!U(hs^aR2]$z/rD=B$ ~B'3F>#P( ]>`qyˡ# h'T~R%DĬOSdW/UQS饝 ;33|f|igfZEqx"v~Rch*`Sω\,T½xْ:%Ea#뱨{VnMF|k6#&=faOl.\Z8JblI-Tc0`f?uNƀo<2-t^3 ByE#o&Ƈ6=A'mɡ'9@7$ȵXF/ 2& FxIn<3T/՜U/Up.Q<f @':'˽MDz,Yip(7HP*ԝQO$c-{BE2$*Ue0` U @GA1R3`I.0z̄|ɞ34c2K3DKTSߖF4eOl I/>[QEF?[]vCqCX_vP>8P<6'߼cjALjbkjkĉDԋH!2FM|ҦJQG{e[NMh4R8)F}zJm ^0L8 4gsta`iz7 Tnn"oKFB?IQ?K,Nv$xUvMC7!V<+MB=O$ILE̟i .PF@- I0->ʅt> Wb࢈@Kw6<(G4]$EL ,X"CEI0xR!˪% STVtvHNiP,XA bNc"I3Kb3[aԍ*S,L0Lhn*cjYbeB*6pb pIy?3OgUI oh؈ND #]WC(ʎQ)d&rHT8O IT<A!m\Y[;%Df u%&B1;1`Q rlf(TV[/d'YP%9tl^cpd48`KI*LRy VȷB߇ӦЋ@"'юpHd+FLL`q@֫nֳ@DRgRWIA=lإCLg>7O]|:lu^Pi5ʒ<2 V2 0$'HzZ` JB$[_# ,yhV49Ag\Lkb:(=r?`aYu~O E>MѤU0\QlIP_}ĺ) f$#@m])PP X0 +,ɞ&ҢzfGt`GngA5p[2=2&].3~BW 9QhlcE苨d&.YY`$eK,lGfZ:@d3ie@ ˁkD暤tRN* BE'Y",V~*~ҒY֒2_~$M%3X1 IHI$cMA,hO[,ql\(jp'i*xl"hX+҆=X6`s]ZУ4rڥb$hLjPY +; 7gQrkf}iX!w`Ҝ)Q{:?zllkbweT5/CO11]_>#OUfӺܟݟ?e 4VQ!zjVۯ~aiu&NXScf!1ovn d:F%ehU#$_)7Wl" fC"zo냝>ՙJ&ڍF 'gz7[ub3=#},׭Ę1 $HlJx1Y(oD ACܵF>?B{[?Ou$[l\49 Z f&$V#|Yb rQViw_4ZZ?emL8@RfA a3n`41n5akh4$J?IzJXX I;L#G"Rb ɿím 7 ^O9H [ef,u3Ι/ w'<'Vx*Iy!VW'U >~AwoB1f4UZV&LDOɵ~%|1rYkbEQꘈAeQ;]1HjBW3 %OjT ZΏ]@ w  љ({XwU88p2, @ڰ|α Gd#83OaUv&t6M5=ʹeׇ,M;Z nנh 1Mk PFxbVM I`jaa?ϛ֐''I<> /dmmyG{]|]._?!R(WnJ񾺒&H16c ૙ida;Y j2CEIcp\x:X;Wc am9&WK.Ù<7  M/U@v6*X~TIuo 9I"G -bLn>B?GWc](:QM&>W((/Z~}s{LV|^x!R3dH>ALx, 4R|Ft0b 0e>-6xnGClQ( 鱓@XomYhȝ@+1AK%u{:lϿE h"mG*QA騛] G -f"eq \Bs4qokfՓձmgUt|l_q~ -}d3?y!;.}YȗRyh(uBLY 2kb~؂7w q4k xY}Kl )~DEFȉ#-*b,T1Wj‘i4YJYeq),Z&0ξe &m<a{hw("KPaBo Ji+S.)j$ikgl@Y1˫<`Ż,Da3-]YKvBBvmLƟ{B4Qm7T&VN8(k<:c:tY,>- ^b{^E,O r4 s*kw)lCL>9j/6۠!4Q Œ/'VBB=PT<$o*5‚䜌M*wHU+yy᲏9lGL9V\) UBSn$s_~(ꠅ"6=wFQJD~B oP)<mPuv7fWb].][ЉfUERqbqtY}f$B#IF2V3"/b%*6 M_Z!k]5{in9j5n4;Ɵozin29`LH GT㺌F:BL‹pht{hB&l&4LgƸ])Y 3l&+?Zݥށ{a &sL"{ Eޟ6x-$;}DI-W$? bEvI*O7h8l X{Ik W݅e\zeӇ$0_nqM%ni30G% kZaVY_P1/R: C@(u Zٍoκ(+f C^|^DK j^xU4@  Bӆ A?ĺfɌ 9 [*g{krޜ# ܓ+~7>, 7i`*.t5 jƮx!W@0i*`F'ڝLlR[ԠE9 ysRΐtG Ba׬gCNIqd5;-TCDh,g&m)9 1)VZ_vD2M9\!QMW%SJ>iɥ_vdaNaTŭ}ݏ>F719pgpr/-4gnφ`+Kj♊9$.D6!c4fyq]G1߹})P ٞƀs~aFPm$`:kl4fOac2l. 2rzkS2:i1`<\LjA@_a"( fyFҜ{;>gKҠfЭ'$+d u֡rc-֘$"jVoCLG;*@):*;MTray7㪂iZAR{ƫXP`&:1&љkޭb 8%WH:':C8u9Ft`[R_@G4p<^"O⍤p{}M9w(^eZnkvH1 /6 Ê .m5`8R|D<'3lJS!%\W)R!=K2 3FZ"oS%3dbi`$7Esyã@deu,E"/`3J 2qNqڄ by]DlL 279' A"0F :`񹆇;2GCWSCnH(i$C+ "-l)v7y Ȣ3=Xu1@`i6YT!:+޾U8l(?sVRCp.j۲hxaE̸F05=U; oCD8&~02<ՠ^2衆ÜkSI=S.cw-9 hČኂvɘa3g$obL7v !Պ7xJȀ;@A]p⑶&{Q%9oGML֩5g$K_ #Vʶrf&滉$w$2)ZzVq-Z58rNphn<Ɓ'g:7\kdGq=؀APTp(eF)5'`z3EtƜ(T/]O^ݒ!j̄zObB|:?AՎ "q+siT{:r&;H 誔 }&dj (t͡(|h Ox;ģ8;G7FTۼ^BylU>-&C*zHHZ5򗎽\0gW &f#2Z:!VrPGs|*hc3nombKe7"v֡ą=MʿLC62F떷bj^#2)YbdBU:p_ 4(UK')Xk9b_n9Fѡ@oV'A/WV WWkEs;"72%Ph"M͐ߞUsynK,UR?eQQ`ֺ>p#Q!8Ok@wV>c*򺔸83ҩmVnPQ 5S`a/sIOf\㤿.Ld߮IAg?ncYfPIU6P#SZ!-'3J]+o4SٱBz 1Δ  F[5KXlPmg]OΤJt?j|}.KIzWO,[Fk 66F".j@`*t #}lHtFWL.%[R?v",v[+~9=-zwgE>c_.LZsT$^HiږQ'%%b)ۓ Ip㣣mdCjLVb^K*> AEݡ)6Z/>jj/)C.0(DJa$(pl&)QI*жlaeh@*:RƤ:qU4m_B'^*j1^@l =$jVh^%ceQaS#HZS/߲CLrj5`͔ xLq^Z@IDAT';@&]EZ݀&bFȢ2 0s-h󊐶u8_;@柟If @)#>˲ă8;/&͉c/3ɛf6fZ)LZrCt1IhA cG`_N?FD-`ę`eRI߹SW n/G1z(~:k?& a=l c&ԋ8 rvN5D\~~^\MoR9ӃÿߍMtjmAy4N2g0 FB "_ PUMrb%up|ȫCf^[@"qL'4txDZ,eSoPqR"rR!bN0K@Zm6nfx qpЖ?0?Z0ai&z2҈=ܜn80;3޳c#aj*\f 'U21ףҲbs\(>$ lQS&f‘jv蠈R*21fuzl{Vv]eKdI *0xeT2 F72G'꒤IQB c 1]o`\+4[◠D;d09 _1#~rh!DĒug>Qw&DǒӮܪ*9 ִ=;ȹY\pipu,S<./0q`O\R;hZ E*:[&9_;Q׼Qph6:{qr$J詓I$+#\:dEꨕiVa|A3UPT|{`Rسm Îڲb҄I]0> |G ,H+φ MD/#MQ,P_4RQxV\}UfzȖ 7I& -cTgw1*>>Z9Op^93$$ ͋1X>?2xi^ l7%PWK{9J1zj L71#w&4]B͊K2h wvzؖn*h.e&^JGV &եiQE6?6-P+ Kl=g@=RS 8,~ BqCqIDeJkSG\'7#)w)ZOJ$ 3>qBXZ^؈f԰58ЀH3hJϥX E=G/<ޤ`0d`ۘbLdV>$JZMو7LRhA2Bwp!v"Oޚ"FbV3mpلyF>Р 4ˀHe]P6@@IxcHkq:VG;K6apZtmʊeأ-h2gKܽe3ңL %Fb\%!e\:̺.(8Fl `*xSH4FQT`^~"Ue.CPLxESΒbI ^{b^"CsUF`MʪsoouD- "2~G e:"A.^"5#A#4y5MTBS@$Wً=1rg=E֭[bwqV#Xt  Y>vPѻxSޙh&I{Bd2ng R KK1J߄Rrj&=jN ]0>.Ԇ*=x2V!#Uc/g8TwyHK {eg~Sr;V ;jxۅ(H#}TݟjAIƔaK-R[_%X!u Joa:"̥/)A|ϓTipn~BXyVSAL><&u,{[e6b30K?.,! cu,whYYZ ŭ][(Ռ#$`ug Ѝ}o`ު*,bvՍh"NCI@!ףfoLϟtd׌tH\bWJR rYPCPAxvbEmM3l4]2E(3K$ʖ7iݻ"1fAefo\4$ݯkh̴~72ШTFNDDe?[c(͹h;  6S!%w),ی<0DJ"I\@{ۘk?=z3dPBD,ƣ/Qwp2>Oz pv..;ގbO@h}$aLrl&lNHt݄N-{oXv#\ jC%kTB#fna: 1U^:*5ݕxV,@?ϖ^%EmKŸU+Ddo)M R!0iHͧ{ր(Sl+D@qF(ǴvNꂙCn[cYd &؏#:M$ҹdDϝ5Fώ$]wN2\c_ "/9pff?L)t=lGVFnғDS۬Z6Y!B!.1r\]X9*Q Q-MPh:ey'ygJU #ITӜl\)%6Ѫ 0l$O6k\d1mahfYV3}XQ,}\(d؇J?9 {>!˾۴xm}/>/Z~S)c/USK||JpH"$_u,_4fM f{sMn{/_/',H#Nvg{:Ғv/V98q=`#̟̑VR;1/wڟ.wcB Yi? uJd:edadD 2 w)D˼ œTk8ik[f\VYCѭ5r[c`_ LcgA(Aӿ_ Q5Bc@g|R+׽6ݜy= ԠĿ1&nl1XCPZeVI'(gs))#VY05?j!M̕r^poAph\u;ֲv$»mOjzQeCv<2qe*hJ!cmZO%ಜ^(h}-mCZ8)(jC*|ZANfE)}~\6-xy;@je =3QԖX&T_@G@fO_?3^ٴF@M@d`Cdql!tUL: m-bu1]AD5M%:N)wF*yD`dY3m`㈋GbSW!0Fd^? y5! 磠(YbvN 2D,L .W>VyvlwW+a^VI r_ [(`z Ffj^N*G3 YJI4ZR@ eM58 뙶iV9!燃ad3ڶ\N`pā.chz,VV8uP)CBtOjC@jqރHf\xMX>՚[OqgD "j|K4ͳ c7BEMͽFNYnf;+HDϖksp4eamV)43)]عO2<ߪzqT ubLeCHo@^S$#gLRA;1.(@zěﯞ"mЦh8Qiϑ*˭Ac#Ӌf&Mo0Y:הh)c+{ *v p3Cx:I :C"hZ*' kY|^⎦:k~?F3c{; A"Ho >QA,቟Kt7lbk Aζ9"CG_w6K~$XZ2qvR y+;_e#BF4zIG`={e!CȄtM$}1`|M9*n#G O5JC*m:]QڑYhFd#t7hV{FRz`sOxwANX*ܼ]-YXz'ZƻΝvb;K򘣢i?Xq C (+FTfmaεJj`Έ'~؋7 ܭ"*\P BU^%@X]|/kqQ8)4o==4C5Y<̝Yٙ/ L&ID)1# (clBQ*nL(AD!T7K6޵?IN˸<$}/\FǓ9R&D>p+˼P)BF*{]uR{d5#7ގe_ټTv :@o0JeJ!:!}kPЃԟ" ] &dh}"c8D?w/h.륢xxƈhao^ ȼ19i!k_=1_ UP`SOn8 cBk޳9}cc8ILf񋶲 zP 1<|pN< |M",(N3v-i[rO}6xEcgcNsұgO`ZZ.!6E'E)1%eZK@cҨƥvEvgލQ4eF͌@#ƴKCSwb`g@D0Jy(Rb_I叞^0Rm(z(Rj y*ȦҤڳ@ݽ3f5)uyʼE족=5zkR[F ޔsghK:SU>DÉ1E8M s^p;3bc/椠-"`C#ӡ貋1`4Im]+WFҊ!meZk)Y;oM{j1&4dNL5Е{" ȐYR?q1VͅŒ潳O۔UҲ*8bXt)! 18i}&T(S:yk"YEqvDL/ }CWtS}U)@Hof:VDVlBF)a%d5cې`{_N>2P D@ `8v&|>?\Sf 86$O3<@ 'L )Yoweۀ bE+Y$8S8baQus0!1RرĂŸG0h@Z<_2(<\=ERqNI;B0Ve&lȔ ]64XM@Qn %݌IDcP^E303;'-vDR,Uzqu}h[x1`Q?\$X5זf>k/6 ɌKVG7Qy@ձ,^(a f:@FȩbyЈOwav䂊y!Rtl3lL`zZ+ P֚%mԗgj{e?Ya\(,TǂsVq3`\>lrίafjh9!ou}DZT_c+9mfGY~&Q(I>37pBA,$a^  hy#FB( qJѭwb,tQ[|{de ':{FhOسG#Rc N?()_ ټdXN|19H9=% *zD#7bƑDWy3;(4 h| =ocM |(V{E[CEj QY$<0q\gQ;*HuVQ7;V.,D} z^Zl逕BON<h wSgBy Ƃ\i!y~h]c^gL Pִͨom譻ɳu|xƎS4 ٫9%(X/z4_Q0)/)`rVYږ@QCgK@m^㰔+ Bb6M1MsD; R kڸ=,}Õn'4:F:{b%}%6ܧz|y"r6x$M.=;ԫVMe9x4%B TM\6PPeE+?+65\#l$F ]עB)T duWQNٲ%Nb<[lT\6$+'^)J" eúpJ+Stvc(J@@*zC2XzIXNKqh0,R(:s4V!*1!Q<JxG[*0>N^i>:e{%pI~z8m>·Yt+meqcw@d w$y/6 <6)ѫ2kD 3UN2LƂu2K#V$N=`$}e^Z"3sՕkI9^WdƸR % 3lu5><|Z2,jOjZ/_gq6q[=ÌulJFK(4܋q"q럴 7]z)"/S9)pcS!%|٫Xzc3=]f]O{Y'a*7Mh_oRϣp0dG!fk3-+kf8K7аM`P b "^ݡdH|Y&]< "ǣŸe@Ҩl>%|>U%\5洤LnEnqx#-2]à sWRwP*a5Pjoݯ(G~6 ;1D&zP cXjXzq{v2ڶ7@/zSO)7bd7NK9^ʻ| }&lzy:k@rN؈ Gr0 e}Rv:~_̱nOYj& um߯&@FRȖ}T+<=ԴƊ!dܣ8iE,2= K-o^.NNtQ+>EK~_?5Cc'Z^T/spw^qɞs\ `G $/i8\6囶o>ICkmvCʭd qҷ"Ua6ιA8eu%D&q,ZLǒEE~y r¨ UM{3կeͱE)b1 ylOd(/X ]ْe,U^$F۶ 6Os簼bHэJ'rC49T~h/Ls,iOV#:VAz/[ D@5n07_{J߯MQ\i'\>H-dlGg.?Lְ/ m)1._'fsc^})sTtɋnߞ=9*e/*G~ p{.ѥ/<>ȢjU,\!8 ' KY`)B9_ݛGFX]ʬEՎe9b,aI9,Sr1Ϸ.=Ĵ'_݇7v!ns8+8i3peXKiY`8DNJKX0w.݉ITpdP)mnZXiMZ$:J+RY6x{~>Si6ֱZen7͉5lZxK]pLD?]p;;'GǺ[| $=8J[ 7mIKۂ v`sNڵF?_Z$ &,s/e/_!0-D/X&mznJڰu[k??m-Al)^~l^/7|~~ ;c5'~Tl*NnV\8JƀCa9R5V`#kBB8B9oT&~\Ÿu!̈(`=!x\4[B=ვqTecReXnL챺~۾"a$Yxm;5YGl [Z!a0m%$Iϸb/&wM뙆g"s.?㖈96K>v`q5z*&/'\?F@c+.iAwL[^} oBoz2yrD#ݳc Y#%_>H8aY(O^-=jCpfO"0K;iKvI՗#ABl3uVAo(}cy?`[o>23S3g6o6{|-4% `(%'ڍ,aZ ,e! 948W?$H 1nĔg&1ǒ17|:˝E+o-ϙQcY^&z݌Z2JrGN^E2zMCM>4"pA(އ1w9GJ|O/P%ZT8&v`L+3-@pݼmv(U6j#]yݜJEͫvR 8`iY?˖@Fn~7J.>0o.<uhuRkSC}RjY`*s$2nM&x(8!pQ5^Ot zXOZ4x2(bHV'UIR=lh^0 Y~؏ P˰">8zMFRBI:șU:oKbcPj:2`Ix4 |nǁGg~MRU A#SV_2Ra=/g01+g+jy溲t~I@{ ?)rs@@p~MjS^M b_G]9r06:YL\IFR98y,f98;Yd:Gfҹ^nIdCx"AgtMt[{FkDFūrѨd-Sj?1@f<)$L=U rb 'h9wP% ku!%jwkt!-Mf#c?hi-B4YH"9NZ­>UR¾aG)zw!>dqQRÎh[#Fg7jjLu4~pE~ts>zh8H 2Sxja1Cömbg4H;)nݚOP IoH=4Tp`d /RV!̆Ql+Mi4" W_9NykdiQٗGk8xImTH  %2ڱ>˄ lU)1#d18+H8R4*!dϪ\6JC6Q~qFӱ]-*a䈑#%Vml__6A1CҶWR?9q]6Z)lݜS7dROrJ'8-H:*з2ѦocZxZU/>V`:r=V5 8=H,\WqWeO (N x?AȵHwC8h{F^ɠ0xee#j r@D~E{g:(a~Kd FH"h@ytt*z14ư(Ma|jܾ:_r#t5=ʆF&tK K7<1E-ȸ&_k m*A)5tD  (8qԄ&DݖTEhTx΍0?iZ ˝U !]%|lawԅ&Wn-/moG\^ [<._V?;6E7&''hC{)iBXŚZVN}07qH-B Soų1FrqK45%{c?*YjroNuXԘk1o Qaȍ^O Ykn9<9$ ֘Y2!6@IDAT$- xn.ذzlxŏ>/6 -W' ;yW|Þx 3v:`Ou6(AwSt|tJݛ3c,E"k_UOfLFlIJyY1w|p@x>kz k`?ȚF_2ntK>4t`DfaE2{Ŀ 2Oā2"x8dC !gH~ӗv@Q.!RH9h ,Mc@C4j'q{ qgx/e3![ulxVYlL,RCGM Em0,Qւ; P樠:hˁ^ɝ3~4y>5jc V. Fs_tahMSBV_\b5jw$4oËXT[uTczcZ|tOBSfAD MDYICugsAY}MHM!5Fbzk=JN保LshE7OLzXBs4,^ s!YnX}Xպ0cXTgM`N0؂X[eHG XpO gplx%v`֦צ3$Rҗj0wK'tHR+f$ImKM.S1yzAoe=;'1 WQ\uBn f4Y}Hsyf_ uҿ8Z@T:f&$/(E D@E!?C* $T`R8qSۆg+]w">#;O6fseb%HAءPQ)87HI1{Q XgH,!e~9йà<Ⱦè#AAR\FUԌ)8(?Ci`RpP'4$\J\NEO89/j5lk)jE0+KM <72 w Fd/{)6]'b8f]Ru908>EIjPCTC t:ޑjPbb|6 96 [u2s@D! "G^{wPs0SF)cL;ƺ!_ȞfH?Wp -2i*tތ"~\ҭ/s"%`A995ЋeP4qGI})\r i7l\O9 %4 \@ciy'ϋPk*-w`cq $/?HF (d75|ﻇ͑/ >*Uj5jB#jzC6% g^6I4:=Ѕ^fG"ZUnh{j́O}eoE!G//uuPEr+:^1@mBl-2/?m˻2?[[,SfG Q|*÷rtg,GhA1&lvvw|}_?51pWyd81Lg+̄ A=+Ϯʥ2kԿRlf}Hf ɒZiHxʀh H.~-*Mmαj>uxJf`d_ܛz,Mԟas`H+/]iR"\u58:vƐcWczMM^5وyi-o# t!JwQ#M˾Nf-#4=, qO5h)9+U۽n@w"Mef3}2sʭ)ڱ5À*c9 o/yV#{ξc錷v)}&^$VɆ$dpO}Rα$gMgg3#\ hNX,%OP$=qFGl/" A=>$EZO(LVk3vl3jf{"[A+]uWWnc,4ǭ$ f0]$R+Aal pk*5ŷ}Abakx~2D |+O<Ȥ]!<wu)6Y%Y!T0 e6k,XrtC$3#QF \t/lDt# oJx5?_YW{7l^6:W*f3V|j:Vba*04BI/PS]rm!!4.XH%mK;:8 ;3[iQ`%RÊ4wh i Quoo'KvIsxԶ!_K\J\а5j{+T&:Г*!| Kqqx+7bc B2M"sz* wʍU&/Q ( .$'^V%F|A n'.SyJ[d׫sz)cWF<_)}dRqW9rfP3P-Ar,fA"9m M5FU9HBZ$&D;X̽>lܔ1Y"^K?,~ c8V ) b~̯D]/}:Pz:̆ԤwZe@gv@=8ܒ(Z6=Wh'Mid;a\OtvTZД5! Ξ=;3E-3NL7!Zao ,NߗYpY'/Lh]18>0 ɆpOѶsB6oَ\iۿ91֏)W 9Qkrc; "kmNjOwninT}=&Ic5O[wn;%&5Pg$1QUDQzAl`+RӬ|12+jڸ)(DݢeҚ ajݛeG}XSdy:ǏҰMvla3C>7Ȳf!L=aLqP"On9[uf@@}PV)~P큵?DQE`[SI…4AvZ -.*Q[iHׂ"v 6Ʈ7w Ƀ~Vgu) !ls fZ]p~ (S-GOEg9}b;;UpDY@۳S:޽xF@I/SGK7Kg;ƨ1K QJL=w[_nd~L9#*|֝ v}.a^,[mBՆNJe!N }Jc0H195}0-;0*'Û3#9a}4v+Ɋj񗣔$=ֳ+K&TaZZd^E𭗷:xfWū>-I 8jBx>vƊVm P32RN%l N&S ;1N 8oy˻H l'N7WB{4Hs4 O{$;j H:S_,@ss3'ETd> kκfDR$Jrd^ցڟ0Yʘg ͙c&aͅnBbc `0L6їI.^}y:(328~X'EO|tD@e%,^A_y 9~v1 `.4f㴟z~̧ P9ؐ̇+ " dJҝ9SIq.P UtX273f7C B5;8 )hQ r %-biZ^@ӎșZKPeA'sDiY`} Pmv{C[--2~dVg ?:+scvov1E8*}[ܹV1l 8h)۪6|mnVڐFoY%g:he䉭(|CEX` .u=+vs|5{F 6p/Ȭ,Bb#x k^RM۴%<禝B_"u)aX5NNM'i{OznviTj)X%a3UjRoV!Dc_4`}0]cx>Οw~Fa4C8|8d>n^#bO%_e&sKgbPpDp7Za2^L'S8$kXcK Km(=ե ==>sȞ%y&/#( 'G(qu =A{ȝDXLo|"5Fڱ% B#?bJk<~ hNyEwW+F; FieLϞe(&#'}F(AF:W 3YSj4 1RK)i0Th ?| p cM^1 ?PhVq9 msB Q EHCyvyy%:C \)/ )rOO,J;4:Hi @7O2{mz=P5ܦK7Y.2 쐒 /dl<;sE|-Mg_j/لD9ʧՃL40b A$&(Y!#T/E%ДG~#nX$6pBuNR-?pM[މe7K1.nځb lJo'P !,Mhu(r6xFw> h:ɥ!3N|X)'QֳD!I0)7Vp~||zz[,L;b.%jrH "je扯F's+Mܗ:3`8qc*:mqS?4qI ;%8oYgՅa<9L1BifR$\{`0EFS|@/sD~,҆Ӷ+911+@>#@Necv6wjH ^OWstfE^o֭[6;'&T!<깓@ `&㴘;'֊׋ƕ4--_G2r'Pb ,i{/8H MIvM/zFq/)ޕoSD(FYXm}WkLe&ʩ!oOAV s Iru.ҲV?̆pi mq!Bd0zΤ<`HyB9W,F2Ҡ t4jcb[j@pw՞-A݅$`\akLW ]̟O +@ĮFҐ@R߰Q.#H,=^ec2:CS$@ާ٨ErvH=C^2¼G@y U=h қd =ΆLVf?UFИՀ]l`$|{#L0giy;yZ+炆 6q*}n!t8Z0~J.:(rd6|pc+$뵓-} G0G y( cyYb"4&zc+Od h]l•7EZ,*ŋ[u!M(Rc3v*!{rXUhk9H7Xw8Ac,w`4T d8>@14osJ3dMMr8d ڠ9G,&DTQm dK^l7Ɛ)޳~B:SHrt 7A󊐗F?DNzS:Et"Ga;͎l8(zBe!d61>L 7TLbX@A X! J{ҠMéث*LU z5R[R(>9^\O I&$JCyUcG"23}5R̈́X3L7DD)>hQ+XC @}퐗aTHlfXVj`pzyMޓO7%$@ӗ/jwf%wTZ V*ht9,$ZFSf` 4xO| s*e$3LD'a _چM괾;ktjqlPhW4ؔ9xG+َ\W\[$!A- B(/z`j&Y‹? Z3T0_S߼ow|/3vԣ'x/[Am}9zU54A F¹/s)y4:B'Gb9|?z&ϋA: 7Xq}8^ˇEi%3q4K +op-ǾML`;gÂ&UqH~ K&鄶TQ88K10ĖFeٯO%q^R4еהi\{77e v.w&G0,lpGL~8# y=kkaHCL,Ư$zH}YY^ iIza9xR<3W^1qRdA&귡QzgRF5tOE1pz#>d[mnMȩC"vI+; '!L\oqeuԈYˊ (p 0Q'aX?w{J@HzP{;rD7۝> ][ܹrq`bHOz@uQ+-'9-2\!h`ޚq[D WR͎@>]GA#;pas; Spw%@,{iF^Iٌ= PL6XD+Y*95\2D~>9?44W zև)P͛ҁ״C[b`rvlab$9YER .Spk">9#sf07ՐT9:%U7$h5>}_ ء"g^Z30ayHNct,cX5ߎl3[ZQ!lsv&% Rg6D벽V⃷|2߾U`ѿ%!"&ݨ_ԬȒ:a0[8]ٷw ơ/9=!&VԨN A$ztHCǙ ,F=qc #!IiZS+<<>X2mgd=b;`e!{"5HN{@oe`{U C ApwzCJ/r΍`zEBTEl=v.@8mP|E'h``>V` qaSrd\#|4>Sh>f24nHߤ[ h1Hz$^wf謥 ңemYL!cN3K'MoTS P h1Zah.ӝ.( ^W:8;bEf K Ut,s90vGGV$3"@B4x"_2q$rŽ94S<f]7ϬaFmQ^#hFb(HBV|g)BGZN P Cԛ0-P vK'(N)8tR>TvXJ~j1'0JD*vRעTѰ9`V̹#؍S åss!([X(?];|>[ ĮXxgoɪ(*AN܋U\eT .% ƈHwXmtd0 < *Jdʍ(F%^-%&/vB9\"qIˣFXPT*e0| c4FniUĖ O@6_-boVՔ:>b #y38q:mz5YJ3>DB4wU_WEl} e_ޢYp"r (m|>p2mnG JT $p=4鞱)a3p +:34h\d\z/L.yĨ7>d*H""N`}>3,cz5Fo(X1øAp%DeR:.Ȼ= #8M]3̕I0PE&Jq c SGW "˅aqD޿qcM@uEzT屼p&`p0i:A w6@4o+J=Qlޫb*=JGr(Ebq` ?-fDX60SsG(lnsqz~;,+1ҖSKi2E*FQϳݽm#\`[P`F+Ni"OR釰T:"|UṖsJ76 / 5f,icHOǚ[84Żz$ f3aHP l`?6GPoiAq6 k2˧ Z XXyg--!qH 2D8Rذheix,@tvTIդ֑h٠ݲhM{5Dy5[^ßҘg3S/Xəup5Smgn> [_ZB,pbj`T|fظV?MG~*X@5KBdz>r˷F:,x)bjfs7+?h;axa/VSy`鞣?bS\ f ,I'f-ܼa{4ˬ.fe* {JfΆVWH nRf(2uH`ZwlmJdo mp'Tⴅpu16iZ:09j4kY=9UGOf ̈+Àql:#N75t6欨9" xHMhwt2@&ME`z~Y (s%X;5 +/4#ؿIdl>Ook>ZJ%'SQLVQ3Ϡ&ʠPƽ"F'QE@mL ѐzMՄ"%>;s$Vn4:xр;\(o#bɔs3,ֵc=d!v"#23ڲx?=J0=!W&$o1A'Pܣ?ΐχqsqIi8̏iI#Uab-5ȪX#o  98`ѦSZE0C`47zj ݹȖmsW7'+S2ߟ~j6zΨ[xp+ҵha` -&͝KXp!@hPgf~^E/\W6a1_C[q: L.q[lPdQ۸XU܉osH?lo7@>R u )H$".צͪ_*;6\}cA8 (A$<|v!a`zG;O;s|.0^{w_gu t^2#Jrcb,+˓(Ƕ?H|575e5H8N*F(1d3{1gΤ1H=f,KK7|U8GjHg1zv?G83mUM *↉,g_4@r `B=n%}C1u 䓶dz\yͧdx_;eS0zLw^LqL?^/|:w[ah4aJZo&\yƼ;B$+z3RdT_7 3"c'r,Z,1asc ]*~Bfs1Rь-/[|˶#&y7>RS!-Ǫԃ: Ŕ(ხdj&[.[`#Á~ΡP1юu] :!oґ9^MyrBjH]FAbAZ,>) D»NEi^` _-Z+3Le6)-JYjJfBUϣ lcl[sW^ρ#KxӔ*(pץQܩ]hbj,yzgh =U aA3DVA2S6 +9%H8Djnʼn6@G3vT'Y@iur>R7xX @ nHx=hj2.lLP'CpBI I 4:Ē ƀ ~%]Cnʣi嗱8te paԯe;c/ZR"mLY 5]a>kq5~g+#4]>84_eByўP\}5GE~9Pu=Bc%c!fF] yx2eU!dOrru2fe4 lɝMcbg{#J/J ߢcX*=T$?6nOugl4m= Q~QA ĩnyx+'-oJD;|9Sìo\f Ɇ@;xlYoT#(SV rS5,U`L)RnjCpfJT u/J/C(E&*ӀK¯2a]4Iּ*y <.mAHU@ j*ޑ4ZNsv(Ի i 5tgH w:amD&6xfNs2L(p|_2b2BRa LvoH9 Dq^ĵ [`nh甶j) Kb‚B-AFܤRLyH9H<L3\\AT ԚqM$ZQ?s.iRS15 Xc$,'jIJ39- }Q(5,d$5"R"`WDP'I6V>mN:cCY^5ymCT%pf89 v_?}$XtNDvv9.8{'Q###5,s9Pdh  if ,0倇&]Uz_OkU#kaeq QNٕH&)iL^t\W&lJQzuhdTPL~ W8\ B&\舗LU!Z-RevTp][\iYeVMgދ &}Wir8aL^J%_"B 9+q N;B.3*=4b>x PN^; 8pmX슀~Y0_3(I[̣qm9Vozʱϙ>ӱ7&5xqETo.3]U-)a0dz@ XТ&6RbLIm},/C}i5p6ljJKqB҂lb/lCZz7dH]dL6|(bIfJ%.ώ_[W'0AH9Ts$τμ<ψw|6 U~q&5p>!6y 91 DXJI@(VGďd&#B-CfOVD7zGp7紎 Obd!d۔3ȓ$uQbam5_&F%d3>9# d"G= :~$bdTpx]"TրeHjЬpu1)1R3 !dHV9qTo!ȿ% ssښnv81L}\GFNf2oXdeaCSriO)=_N ڔpZPr6Jdau_WSGuɑ3+G'#}W|Hh>_KGwj[B|]CoAF & Pƒb9gY *0df 'j!Sx# (;hW0!>nAZE5Qh)Wzg;xS۾ cP% eɏ3 ̮%ZL$[~V-8>cMZj'a^2hn:h[jgtb3Ȋq+2i;Br ~x*}Ǎh2}݊Y=/]ǣ, 1XGxg\\-Y Ba ?x!KZwgjX qiPm8I׌bTyg9U R>\MI't(zU _vmR 7-7 /p׿ F'pHgTI)J36 ɯ;ooqol\&@%}厞UV6#>"aѬ[F &[]u-{i<#P M(p@%=S91b AjrIš3*k* (B}&61{`%M僼kN>-AdKK怐 $9 h* 5+0tSmߓiIt>?R߸MJS"; xNlYuAddujBLp@R+<]=>5 BbR8˼o/A]"aeoTe B"{BZXlT>B"kN7'i5EVƌAt9,j4"-#d9eKVi^PCeQ.0풃Y]f__n+ia8OάlM,"Xh@b@ ?6! bܽn.Ĵw:S.jn ʪxDWEʂZBp~o8Xfm9.8`lE۷ć&W #y{\*CJCP%gnY4\S4x~l_lܮ?7 0uśjCΊ#0bF'Q}>?{껟-?^@j)HElK G+0!Uf[WN"TA'j}n?f'{`8D}Y°Ǜ>'(±  *ý0 GIH[}9h|q 쏴)1UC럐ofqȵJmz''"DO?/9-]9FW#!mUk (RMA,ra<x\:4KJ]A *q >+A+ƿ S*dpXZGEen/GEhz%eu@="݌@Fr){y=1/>d)bP'aKh~g:&uSy6[d\'.B0%"ryˍj@G੤@ݎcD+(h=02ߎ'oR_8q P8"I`!щm) Q|#hSal: !1Yavv&"|Hu-Nj 51y3u.EΡ^0" oDq:x,<:$ &MP.yKv?ͩ@@G9v yFl1 f%>&؏oTEb"Iʐ$̈3Oq"ko#/ӓ iN 37\j`s`-\aauIgM nACBշ9B2&`c dTrWLt 'J @.Y`ptmXrL?W_2[1c:+1Ak~Z 챣— |XSgW)'ǩu )ZM/:!鼂bv#VMeR#'Aw_+7hT@huV#~IBI&^;7-q2)JΗu*tdK?,d,X*KwC!kNZۂ(j5!QfH%#I!N"qAt8ҷB{]cq$VUE\,B`6z@D7vCf|YaG OBHG/Gwռ[ y7mF âΞ-VF Oy[)hք=kcEg:6 }~y4>.BS1rτ#'v% ](ѹô0)$BP;eݶ W02<ɻ5䰢@I*s@PuS_6>pm2#E;mu6* eT>8,Fk FCYC(̵t5Rn)K/a^$RR<6&dTgWUSGd*B&C(D(U؂"`b2}huNWi3$C6̨J=oʽB 4$v$9b<uSɽ" xܸuLZbI-FL~Z|y)iNT ,C= (cc,M(NД0eаDCZf))].uZ yR# \0 XN4 =D!0DTvTT'LH;IUQz[]Teq=GbjtBh MJ,IKM>DNB 0IJSzÊ1&^*!-ոƹHqB^ P][rr 5S$ M:#sfY|ݿe<H%f!MAwZ`R[&hv,J؜ 0NUIA$?vkF7%% WrΘKۆ5Q8:".kY&jLA`m>G۾% @55 649$0վccu*Be]t7ڮ̼1|D,C$Vs!zguBj7 0&&̠``ȈHJ%!1s } 20a_l&Z>DcCRR圐q͊4R,0XaKXIy҃bΡW̩բ 2n+]dXaNtbi;`15<,˄VΔ x'+Poj y& e3Ԃ Ϧdm܆'и>0D2F  T=gos|IᎻD 5)}i,1CX>G4Yb`JQ

    *m~.G<"ԷB7ϢD_ ]ʄ2Kb(i|Yyh>lMh:۷]R4&0 |\ {C3#PI33*/xL7rτ4bd"eHb3bZ.YvQү2R&d. dXqАQ9Cϋc~QU$)!I_gش24JPGXy[+$r J:P  Tv NJ˹H%۬r0ULY !z /662652/ɚPZZ# +)?_OruqPI@w%ic W~ a*VvޚV"9S']/@]k$@A>y gYEH8J$:ӏO'2stRM09xԝЄzWG75*|a#FԁXE +ܸvDi>^D%bX8uʆFXNrv"Ӎk*tXx/TDw4>W6١Nɢn]B &mɣm~1u:TK;TbŠ` y<%jxwd)u\&8nRE(L9.rQ,V*% U S"KƖVRᙛG_cC\)#?c#lk]O0@EGMu~%`nd +BHry%Fֈxlm\Rr~#Q8i-JtemPbE . # mz^3 4>0y SpYO(a/vce]EpЧl&U|gOhv96n ԧntU[tlGsra,R܌:L,%'bͣs+E>̘5?2wqp.۶?W\H{UKqbi2ӂW;ơ8zCwǘpG2/E5,kb-)1(H`i'D=jh0t.ԏVNQIVk̅+kXMPi33nKU䷧Ź zl@GI,} tH؉z>'IX tfNU'ͼp,$g!Jx\ek {0Ȏ.KNԬ(rP糨rTv 4~ISX +$fWm["/;>dȑ1ΒBn"yf;Y$)Y7r`}F,Xa1TH¤1EMMd$C$ߑrPУc[Uje\tȌ)Z#L9Q\H(fÂd>+yeWf/&-e5Dbbe#%L Uz1YB<5}дj}oe]o iF6SaH-7hiC.T2f!F|[1{ U#6+΁d = E[`r¥uyBPɺs v؁t ߦ?۷ĭJ3JⵆAz\sA@/gH̿A wѩGU5:iʊ(''P/+ab<-M0}Ĥ*لimNao*h@Vh,s'WR`#IY[ OjG;T>z,0D@)&M+$@TP$ڷ[H7J@I(Nv\CwZ@{85%MNzfɖ]~ c&Ln%(S2 ,LZdEJiP[J?l vı޳FòeDgfU VH!8bb@q' 3RUO<6z6ZI`AR/.yfrʚ1ي^~O0䖛*2 ;<#מL.917~!-=PӠ)ӴnHh` ц HxD!+T(۷XTs~j u Ic@r`F꼙FMY̸Y;ChV FUXөBM)2Tm0fI-!N״="~1%vQSeHǪ!XFn#V۟mA*+;pH6{?D;h~Z&e5[A u0| lM]XĴ.V9ևUCݜoQ5F*^fY47 ցt&-A/.)lבeDy I%` r'7 COB$2 fÄ@feo%[7SPw& OŒYYv=:5RjsI~Sa{s5< _K%2+P n[[mNۉb0? G!2 <n3 U$hR"djiTů A0!6Qj/}2Rpt_u9 L>#wQؔHp{0D!C]x![&wO91}Cj;]U$oLC ,UҘk eC0uj<rsX*Ml Ǐskoh"0"BD |> x2EpXHe*R0bz(!srO$Fkq10 gIoLۄOoxǯi9ЅD(k@6F[ശ>_{2=?7Zy1a,OrYR,;[n;bc~PRX8fE025U$uYU,W& >JlBJ%D2L=_-s;w/+U"I K7|WP\ 8B}[Z%9?Qn+5l2wR!Nz$(7٩Gk޳QN@:ӫL!H91#ogCM|4yj5g@m(Cl=(Imw -V ٽXlhLм )-Fz-X[=B9+oeO@M˫&FBGCiLy$4wئ'Pɍbk6q|U>!a,ܩXgVoaKB6Z,MٱOq+Pdq$[ߎXMXڝ}BǮ"xNxO i#(n-P{ɸ+ Sp$4N8I"N;'Ѯy\@D(n>ļ#$VK'WczN=%yЫ; {Fm[㱔e~IɇӫJE*˻u|ÝgG= ;T' @_xhC`!W >qR%*'0ǦiNu0ԾːqUaUfE )}6qhnJ u?[+O~8A]RvYÿ<:H驊z?l]| yHp"+#=Lb5Զ/#jPʟP~I.v?'zL8@ 5v?3lq{prA@<0cKYS)ϣ$+k6֎MYsβ <g`GІs-v.llxZcꦤ`,a !8A_g3fJƅSbORlxz=55mD[74m %h̵ͷLާh׳MXQ:@ gNP{;6f|l%eST^͠1T/< t2lsz;BZ!t3B@5-;ʍ~)rN/)b\4=JXY?g֘'(\t|;Q2L 1@6E ILÙ;kB%z~&.lX:y^ksOEg<3K@ wa:,̞.j6lL6b!ٕo#mTQ,4mRnbc ٚ!DgL;jٔ7+_C ȵ녕EjW[`0a&n BrѦZq%d +D02~Tg;LUi־|[fP[cقA9P7DԞ E*C^ػ"ެwUCwYBV?^T>/CStt_0~(6(w@3(aQ1sy  yBZ_@16:_kڝH.ч\+1dڕ<6cL뻈n|EtT@NJm&>c/#1tU4YEvc4a hH!<.| \٢^"]8Nuz%wv:֋wR v~ kHR MepY7*AaV$wSE}".. Kԗ39Z+<a#Yz\6)f߬:X;OL&,(EЋ 0:8?2k#gk\hj۞ L?=&[V7TiwbZk@SL ւM͕a*kpC./FSYԪgJ^NDa\%:=YrJswCBuqC>2Kúv1͘ꝓ*P L^ >E&=FrsF 0Tf&D>=V#\\M1HTaQ4 )jKߣu 'j@b>MWQvptn3h~[#72 UdAD|co5]ԬէA8e{vmOۄD/Hlf6$2]3/Cl坈i_·nQ3LU'u,z5A^Yv?Yp ;:ZA£%1xK4lJ#uN}@IDATk2"`qw%N~9jz3yi K/8Sفd1Xy;։,rPSG,2k۸kcQCa.U8w}_^#>*'NoY2G0h'ïmEк ܚ 9༳d[XxaovIڄI R Vxm[XBc4q`Dj=\)Q{HUvMFԌ!-C=%5Gf IvsdZ\,m-8;x:AAh@o$4Fk΄wSgױY9v>()#ZkEġ.Z슯ՉĉoJ&-s"GyU-Jo]HXTt[Y7ܶt P]=s0&ymmX$̈\ eQBX ƚ54Mp"]-8(#Ny%0× aҒ2j'-5$'> c&vZb-Y|ÓzZWQCG _&paG8 *]mq/1DF<:PX7=ۆsS@OI,UH1K$ )0": AMO{,qʦ-Wz#[M}/D,*BT6ŮϷ!3+!ŹZ9dZBL=CVҊ2e$OeűĪʍ;_;mi8)AKєLGAHN&;ԡ5Zx-sm/6S/yXyHFw9)?H!qCM\r y6ܰIF7dp=< ,!<?C#(G9$M%yܲbƗ %8ELȨal#5@7&qktKDh /*i -t J TWW.zMYC9LhKTp4n>1aCU14x"g+O!6?"'AЌfMQՄAA'B"ƒd+U,XGEo[OĬt|p+ʫ́ā3P @ 0c \9Ք2!J!*"n+|ZK޵l-$ R^3 EA QlWdvTyR._↨dMY .@"-z,a{ Pc_:+d&q?DtoIP!h3]sn d!d8ݯW)Į7w9tڇ=jPI=E<SaeX :qJ=P8qs?Rs$wbݳ. e 21hP CR8A8#´ <+ۄh@[8KeAֆU  ,v8F*XwvB'@ȅWyDs^x9&UR?(&1/BWpG%01w=!<%߇l4P&cKΌcl-uɩs8U)|i\02 RK;Y4ԔH0r > is ~bc\LT-6&2+nB& #Hj}+-]J cm:$Hh"-Iw p坑@Ҙq6z˝1[ڗɇ)!T6;@^.dfF4i` DP5%UG3lY]+Bo6^fG L4KC Y&ِLCa@H>uQ+H|]:Iy  (if]NN sWk U 98}̪u!!0(Ggr';g2'QJibiOݢ8z.R`lW%zYIF'e^r1r}9i접w7rt4̾@v\P *GJ07 (cFD^ODNS+I%3#u #TsQUp#4؅e*SILlJ)FMǾ JGB_=!;}Ni@,{lj̴an&Dcb"S#ދ5Ӥg}h, M4eiN<ăDLMTXdE+!$n-t8.@ xK=АYMtJKfZ j@s~p][*^zxvQtgL(}Y.0.'?>ɟ ,U% +ypAℯHu(&[|$7EA-R/+6V pxyX% E8xO jf@̼R2J]2r mlR+rWIseP U2\o؁CmÉt%d5q)\ۋ!j6S{0b e_J}'L!c~֙?A"sQwYL˹,#$=k, "A% F1v:Av_?ry߉(>9LyR4iXav>/ܟQMZJ4-j*Z#k:2ƌȌ'g21!paCߎ&tPԩcScA%012X Ř5VgrУB ="v(q•' X7{sewB'K˒!e  67nܷQ+ZoJLd;p}H@(jIs(#'D([:69E4fLיj}Ds" b&bCyE5ċt/.=>9cT[=ͨZm2dk{953Wy%(`OS."aXRSyGY MNd1 &@FMF[#s;Ae,4$St W1G#*z%vC~ݴSq*p5FPwL)J'ɡ fB$.ˈBzTMq52(7'+te Q`#+X >Ll;Ռ0" *fƈLwtl=#7V"ӁE Zrz0lf1UL'щ$߮"d;PAqvwN@͛hc!Lڄyi] V Wq@x tv<[ۗB8y8Y67ꘁ9h?Z\6n[?!s}0I#Ԣ̜e>CJahJ*y+ˣ< ?gJŅ)O-W-^%u%~xVP,D`gDnޢtB?)#[Vhg6@$8TL LHvv6;?dG+l!cFIL耽9Y6خ`pX\Ef7V߂$Dk!3Iz|: L@/ D SY^H Rueڬm/ҦPt(&V3Zhe^օOSb ݘɎt-e N*qg1Ψ`M7$5Yd9yQʻQ3TV^ A'5Օ*[}DDaO]m.a{VAe@zk1r(vBGFzLN*,a2nrc$! (UͣU`H )f멪앀sn3;U.쳴] s0cgp*C4 Vp`Z#u^7߁@p "^ɗ*]d%0ȉ1$r$ye,y;iIDŽ %%o8=CTuՒh4e#1&J2,|tHqZdQCŃ2&C6c#]OlU֑QN|%M4&*%1KN/VV"FP4 c*~`$.)k#~5ryb/:&H+x(Q0H͢4k)hưk͐qqKBV,g4'eLδ6vXe&l^ɢc[m J-ZGrGIWj`D%*K]$p 4:54&޲R*G%tS zTN)x!rO8(^w 5TlqsUB-s@lE$s.8B1=4.d:N)!eh=DT~&0^ #y;UĿ~}O_ߝ;n0A5ENlriP ӌFo9V-,Ś3QЂ;42~XfmԹ'>ȾL 9=@MQKqdnufm |ޣ;(١d)bϦ$QB_CLz72x[_?ڒe1xV %7rV~>Zh=π-\H'D]x|yJګq|CJ 6m!E.xWE IJscK$eGAn4>_Ѵ('AXd<D$#y؀T 7itkLꭈ8ibw Joֻ7qH(@P_%?B:2(yLsΠ5Y2ٖ '*C ?O^2&%8L-2A/{("S$W (/E؛ i+Աܑv qE>[ @)##"c ]Q"Ȓ C R?ZPkb6G^Yv@f/Ta?][}JQX \]L(WQ(A`/?|v~fblbx]M9M0[`#>5荐t.\F[,Jֿc<)@Yo!UZ6z5R6%^oMb=;Şi9Nt,̍/Zw4T[϶ "lzB׳REALn߯#e ȽXky먒W'6w-g8 m׍X]bvn>.+BL(cSk-ԣHO*u<%[ &9bE1 gTD emn'InlGlm-~Ri*#)"U*3[-{T3n(@unMk%ؼC髸8iST? H#0+gg88 ipG![o]qEI AMG=m)mBLt*/rm,vau4DYn{u_۴UxYR~ɞS#,Qޓ3lum p.9X5BR~={]9wW _/'B6KvX^ bLJ S£sYWhܿV8PR HY gc! A^г GN0O7olYl_nv/. /IZ x̔INGǁ1*&*fpO;b T *:{z;u ҄٪ 9O< ?D01nhfB8uQHokz]?o?XQ 5&q}p,DCQN/ojM'1CZ;TY/̤e0+Yf$K6rh6ۮwe%7>R q'Ҭ/!xDe,ZӏS㤭֘/1d9YyhzS-7:qr E/<:oިԹ e]y6%,!][#7_7?@}7=ΦvkpoتȜ3pSH)Ƨ/]zyay;Gz0+ts%d,sbA"ŒlO&i$Uc0 󆴏pXL )ؼ1.(%"GxM mޠF&~@M0>_~O_k͡Z/*措J;.ß>Qnj~s9f!fR4ï"ǒ:=г/,\5?ndqX+lj^[ezBNTa8Pƾ!Q.y{@%6WW*輺N^SN;΅YᏩh%] 4ZS *r~W}:w/ܠdq6܋1BU03'd]Bbyc(wJC4N~پU2;{]sȕ 盧ȁQ&;ek"qrT`p>)Op eQۡUCf 6ťKE7ԕ(Lw| F8 x(.YԐFYt[HԤ%tdQӱ֙qcT98M)jؗ U:Q֞ iiT>${oxd]hʾXGHKRUNђDáW$l"WF)S%4f{|):tgwu=,&-fCؠh/]+,8'JIXHQG ΂!K=Ja@aj.-1|ЁÅKF $6&sp`_Bi/t/.¹SA+;ņ1UͧOrwg 9T_mhb^j2az8,J1cyL'= xݧ3&~k2D@Hdzf߷u .r9Ʃ ]Q)T>ήRo"ӆ2RFe='&\QMfv-?n(?ǼU S$4:+ioU5o"P)T)sW]~xvWD 5nΘdvA[Z )fʒqla:r/<$# P@'hy\ #>$5*w(o£Ũ | a ^VBޜ.xd[Ӎܣ oթj@s䘩J  `WA yĦ7noej>D]F&':{V0W7(2WbbHx|vw{J7@B,t] a VEnEZys*xF-@d~,7D'TdgpN_Fm\ }*8˔NsqBQynzBh}.GG`y /dtyxaJ?NDlVŎ@q p|t1 Q~1, -zaDsB)D7:'Á=Xz']PoJaa';avGLTRr#f#I)1NDOHA$8)iRpӖSe;RG14?v y Z F?>$XozW{ܞP{KH,jOꎍɚLG9T!>(@~]~:Z&.QPQF,S`pJcf_ox[m Su RRgr,rEtjEinQ2Q]0_M79)ߘ4UUKzJ ! OG+@caI*V#9{ei}Ot[-ChP(11B(^!]+'(_rV}~ia@' [Ff#G&)!SvtRaC0yJ`@F3sd(?[UJ`i ԸLFׅ&kDd> F"خH-rQCeM=Rz(`ޥwS(1T׵iJ*-?,ڰJĆ/0gndr~\:%ovm6\5_t&ف30r7z=V^(*dAy;3A 4ziBz rNS%8xBUVYh,`0gO7 Hp&8]?4]*uA;F[`)n`H^Vβ7@[XԗSƝAD y"fHЛl+tvŔc ꛟl Jo ԺQFf} |?5DgWXSib9f-.T:HЄ aI'31{{+}]IrK/+uELmiY?DFPutb)Ժ;7w.=sLC)FF}v}4K<gK/GL{ s= ܩ7 rg%רW9q>X;nJİĖe6/9-mv=\ˎܛ9ӤS^ 挢 -Ny{U@~ Kws՜UB?S@)uA@FQD6h(f51&̉FP#S'H OĈl+i¨IhY6N\ <5 Cnª#+t(ȅ= G ۠/J5Eב b F(8ݑ1ࢯ#p{kaQ/'V!θ{-Qd̰jj56R X%g lc-Spt@WvV~#pgeu67=[LsȎ%2`նErfKGjeڊCoqm~踉7VԶ3\+0"v'JmU+:H`yqVUlC|4^^J[(d7ZyWR2qI6ߝpFr\ N/kjL'<ͤfV`&.{RmAx(`ahO-t1[b^-t֔]])"̲NN<^ (m;6mOI/,$>{c=mRnhZbў a:{ ms ǍuV#qO |&/$5'-?fR'c{_0}_D/tF`- S=wļv ' K9@ϒ~ 7q[aHYU%@[u춀nf:BQW"=qC"i qr!EA3zFK 1&$.U2Ab DބLz^ɂ)3n 4}PM&d #~_* h^ʧNŒ3 C*$ͣ2s0 Rn$$:\9*Ǽ!asƿ'`حʀla;@ B LK$yQUwz)%,xD?f_m5w6yBWvOSS4"ݔ&P/X3kVbv~0yk{(n'HDFiĄv>26^cU%V_G&$ JLfB4*6fȭ4%_ZĆtenFfRAҒž7Ƹ:}CL%|7 u^( x dڼ C X I18 C`iM  gwR-,2k:[ 1#D)+`{yJ}HwM@cP[.~`fW?[t}hN *`EHgL{2Ѷ, `@MB<0`% {xSL@Ӊ@qe!53'`(A!LNIj "f+\T4V= ngIQƦx=c[ ʼ8;mu65}1xdD̬~x{l6%5)@. m70 -Ғowh_(_q~@yFŁJwa0:i¸Ƣ2(ݨ>D!M@rl9a-0B8ӕ"&9#,e;ޛڢE ŵ %T9Y,XcfRDlx9̃nTIWtkTfq@&=N5yFR$|_e6(P:+UjDU'&xS̟&D8֘Mq·"`±*dyF˨'ryl'L2 %Z VƐZp]+(1*.NlpTf1cyeit$r]< hc1;Ix}8xQ t@f[#7U[G.\#eqgI.JP]<810#Ofⲯ|̸ZM: " jMRbr̆a+gMO5\r-u.uBBU, ̦kA֭[1Ӷ'o\Atizxw?+ fA+¾˥0>zJmg]N0< ` _^#BlޢHZXpJn |_j +Q9v\8c;Ik$bnq?ޏ5mY4y@2>`NY8DgvnkG./4%ZY, cݾnI~]!"aQ #glv'-Qs8<.(_؛(׵PI?6rn` =5O(vp~.KM( uczY=L$UdmQT3'}?,qrY"|qzq Ƕ2'|*Kr,[ J6W(~[v(̝bL3Ӭ3=| G pݿ ŽbEą9Tg8CeaVWGmADzu߀?ؗ!JQ_a/6t~w$ RxOp?QNUvKC dSQ@ΧOS':@,ͩ~\El$sy8#Y;йUص`U"+eG$\YG0#H_,''cEKB]LշQtP}a x eWs8ؙ,U{й8QU/v#B⿴w`8$n-5 /Yol*ꑹl[W1=)NpȦP;y6}Dq2e3$P@IDAT&?bj偏?(jr˰D:Kl9braM\ɽh=8+>][:Hc>ѴO}T gmJ)9ݩ5:q̆qPDζDu١UbQ!K&A$ D)vb >ul%%۹P䍱Xpy`{]7S J쉙/&Eb^$]~.*@9Z G5Hg94 šɏ[H'9F JҬ݋Xy!y+_G8eB`LX\bh38H;'OQ_( 㬝 p5WFObHX(nxÛ|lpoA6j%PPM6CTM6}ntg>^'&kL`[&gW *V?b\!M9螎#9RQ "(6!UYĒx8ʒa7Cdi֗Χ1V*4UQ I: 斅N˓k]1CFl3y&fPrf6+ߟ6 `"TVz)XK@]wR=DXOoؤ S eb,]۽}BcFݻ](B-EqO L`xjP8p„ɣn)B4EQLg5ɏTTa%m*'ԵPUab)0LY IRq5t\g{0!-*E}jE <>;_$A%Q<]Zῥ!7^W{ .Ԅ)ڸ wqMgW| 2erzYT)K%pP}|4DL#6#=Zb7NDpH =E3HQL' q'dۤ $6)xBpCd2S˽bDWEOyw ,m̿:.hSDT`GX,Qdk^aRI.4M!!eT8ڑ\c39XLMQQ*(*pm*h$? NsjQJO lE K.Թ [qԝ2?`/HП7Mk M0M I!S4S̈́8WLRޚ/1`eXO+ܢri#A[c8$!#?Q ,zvLA֐'y.[?>4VX#rp`l"HZg[;.%lje)IMܟl $r4=8Y ;! HT/1j#)*[D<&@r-Q ٻ;QpnUSb.+KN).f}k>p(P9ykj0|9V\oӦ!7k֒R|G"I'PQb=@H@R7z R6BtւB\vsAUۡ0\zea|­l2ScC[N J FK¡~ jZ!-E\A-kUgA|okbAzS%X.n1–%zl2l WKC_'TKky`2sW#P\s~W@5)b pF53@ `P$ZZLH.nj < AG)wô#H,PiRHa3yRQ*fZ|=nP%E \S6iF"0_j^J;+2b#7~?4$K({Uځ#Z̤Ve&I̠w&~ɯ{.k,f 5#h@˺M5Z %$dxѭD,}!_'׈ bF=/C &{֬TYl*b&))io^ Ƣ w 0a]?<5+ّ> rYF vG`m,0T!*8ONj  }.vwvur JmC侠Gzhޤl\MruuSP<[V:ǹ &3]Ln |\~H? r DZ/ŚFbDu7p(fV&EqYtM2=*5e8Ηz[ @h JS`fU-aACsxэm=EnS T<@wMH) pfAyJX@3*mY$Ԧz99CRGYNLJG\R۸i F^Qzs̴6:ٮ&BM(jz& ԋֲD-^(6 4i V PbV^aܥ#HQ.l3IhpQ8}\yUvgH=N5H|| K' j`*n ya^82漎NRvGU}S Si%z8j)}&+U񶡁v&ҹ@+bBu2UApKMcTI|o7Q&8퇄O9џQ waȩmh %*uy#0>Rfԣ2R /ہSĸlL>`WkNu.= D%~! (tfeZO)P/NmRpÑ'{v̟ȁm2MDzH6}%#C~ Q`FjeYG * 2|GȽ|Up@a@>[㳇/Łě|Ƕ|s7dfR!G̙P[ cIiҩԇCRA]T RT2 WE%ZZ0DQߗ+f9PrE Xg.g 1 i^QA'+P 7/m F*@}srz>/n$"L%*9 ~koUYTly/%?hO1 >{ONKxפL;gт(1S @"6 ,. 4R#E7QX2I}3ܒ*~~厑}2P\Ot9 TIbtB%uؽgQ"ZƯԏ$(+ߣiT7LkltEFADWOQr&M+T!&>KA)&&CP&1՟ 03&` >I[MZ~X|@ >IZ@!zU/uYq!$1Рej ;[,̡ɕq+9)Q҃٣@ fFJYoyy+ dOr% QL@47foOt HPL)թVx ,LTk <r#t@uGk#YҶӑw0zƫDer/-; adCB#/[sTG`$H9ys6k_Цi<Tg/ .u 3xegA)p=xxbG=NzF郖o;LJFKU{.k,.Mh*ToF2Fd} ),y 2L.#c;XE)`@T  ֋Q. gFZ`Ƃx0qs}db^N5OjR&iɾxy0m"*duBđ[5C J͟-ډl#v%,)#8z=vG DwJ7P.S<|B;" ̴ۓGe`nr" LgR٘j= TOamLď{\&q+Wdgzxi@ڻra~bQBl07%3ZPĖ3[3jbFT14'=44$=ƇEV2P=Y-Sh4x+&)R?^EH̓H8ڑK$ {P,p!U3k~ev&:wIbV m941Q'S|Q& ,!~&s@<0I+v.:OP22:v>!HĦbc캃H%g, ܉ . McY$\@$Xߨ#%Nk}ѐ+XF-jin]wP.&x`i;9?>cMX~ Cr14~GIavmL F^JXE3C-itFXUrg7}Vah{tL. >pluH=ab=%(p xP_zLX+s4)Zv..U`6p(h}I]z׆m$FB7A9<+W&ym?q1. SEO$P5|%3Ho0K9 kc%Z/ѷ0;LhPgetʱܠI̓eCL;gU_ AIjJy}v^bPy0gT|\f}_C BEYHo!ZcO%OnMD76 2ĠHӴ1R@%}@T34 9j=ڶ)7*÷UFk! :.'fG.˘G°ƌ$A@AeÆI8r e! 0=Xk0aNAzh XW`a~P&~ݭE$lV菽Xے@ [ ~IC#@FFs,zkCJ&dWͤ"#cWa.|) "sUД/C U P2Qy e`]\и<;bhFvBZwEYmzvn(Uf-/u)!?.rɗg@3|l!Ş{3*˟ӏ9wUvVؤ䘇d@,h.Wvn]0!{2p rW\ϏMwg`тĩ.,sEA܃XAnFh,f]=s9p|JIp|?YJ:[R y{(MFOQ3Hbb \3f)nLlI?@Eb)x= D9}AdY8 1˔M* h9³#$ܡC',0˩GZFvMQ͹\=*uPyE;;SmV=6ؕ*1ĄNtux3#K]Q@7wJTBgDDbDt{r+8W%nڥY'UZ(yGH(}IT %0e\,vl7}ę-@*  `OewbgB$c \K tCt creluLpJ!!k#`ƣXY'O(i<+sfw㞰X_>%n!v T ĮK* >xqM w=[) ZVOYng$D|8aw4Q-'Af\ . =,QοH_*B _Y9Xkbڡt_ (r8wԐCXUB8kCv)hIڪӹP Q '$C:EP|PϯW Hܹv@طҎɝ!^ 9^Z6ZR OԺ*us߷_!Ly;2B ՛9`3Wdu·=${ ~c0 <b_f+C}Z\˚ UT0* QyXTk.]֖XXӇeսwHN--3^yD' lK+tUtz6z)yd8e| 'Q枷\9\fN\kkG3*+Ț[Tk7&Upq'[7Zy^th li1P"m^D/ )s_(OqH x }Dbܽ.nE qrOW9q{/qBfs26%G4xy|.r nBRqhZ 恡ǭgRy"./k3f`8 άpV5&ó.$i'igD` prS@ !'hr"ĸRt+m\GChIh HܔF\OqtCMHО2K(wׅB-Q=tv8r񁑳\1{Y-BS7 J*>P[n 52dp'쌅Y[cg4Rێ $(a1Fo^LA9~4|(3;!> Vܔ,t!fpgN{ü@{@ 68?Ru5/dA|Wy*s(l`@T-^tD aۡ 8nBVd٧% 97 BcX 8xV_)peRb"\4ݝ",ɠSNvb%4x'b7I9M4Q x]nđ)e^`!b>Im1 ʶ-&q'. &iX]{<]_ݔ> !K6xØ& 둸B"*-`TIa WBiMOUD:R6 +8KWIɌs隡!7.gjZ vDP *cƯٲ;zXˌpߖԠuoH5Қ8I3Iko2 ̐p? f> t+Y넵iuPK)vatG6X*L%l ܚJ #/a(?sD]c|$7"`OL/J k@,zq]h[% L}9Ԍ±c"Q_ n(jSdvҭIMقQ)hcB_ T9 ^I'\O H ^CeX% [#|ËbLRƂsiY5$* RFJ ˡLW* ΞwI!jj@KCHcd p2~8Ch Yj(["o0M `E6?(/"Բ4?(#J8 ktK ՁsU_ ,)MVIBw-;,eZ%/?n) D} Rv,Ʊ.@^ed"T딌*(eD6JA)PHiSGF"SQ ŵVRt\ģ$ߕO!V0[qD8C$ց DʩIqn*)n,RUW5EhzWX)5U1Y|)9HYXUPAAxD^|n{MwMɀ31/ HПė~U'IjQ$u?,RGS 7gԖKJM77TCtHf\ݰSVJȳSvk˺=>H\ tekFOonvD/zTR44\]=rpbh k w?A&0"Zs >$/w+&jIn4r x8!(_ CC|2-Oh+g‰5/gRʨɃq/4_58ƃR7ƻ-k^#27j³1Y#Emu22HTqI6-1!0ۜ괯v{GC zYLv%oCS#D ###to:@(*x'/FX~E_m~[E Z=.'ɭLR=4" X-,Ѥ.hB`I_egKd%*b15=Oθ9^ 1mK1p؂D}V7Sc#!ÁFU5͠:j:v#`ܛ- hPN%0֤Y> r1e3xF\S 2]hؖs>ls;q'#$XpDz"HD΁4AM‡i L*_,k6Y>'X]=䦸N=:mdF3?!ê un_BY$|ks{Ѱ0Ƣ %j6ߔ›Yh?(ly..,e*~m&~Ƙ9 &1M\ 9 DE鷛H^ yt0[fJ]Z:$)y ߁=Uueg{rۊ(IHTikD˚H(^2? ciwT>n?~vÇ@.*G-}{ Cc΅TZ,Oa m*+24 F/ɑmHAoT}ӈ@dAfX ϐV2Pvè5 D# E5Wܟtmj`Tl"oߥd$1ު/ʴ]? ܁zG>i1G{h r6E3 t5)oO,b!@Zw;E(l1%o5~Ԓunpw)g]vFZdt4{pX0&mM!bM:z;$NCƍ[3̓O j+t|{,R.GTvAcB&"CB.oE.#:4/uC2O~_:[tPh\((y1rS#Lxp˱d9~v!ugq?xyꭊP&)h~6n,֗lE5 \oXmpE Q|VKL0G$!hBRx0h&̈Ό wn""0Zxn!2#~huzz>ŷITՕo3s6_a4YYv==DzIÖ' 3I\AoRcOٵL_w&`EۤrSa홱\QV’k+{MY$ZBȯt-qV H98*9ЂhmQKL#XPҦ|q\hPC)6c&ȡu2~נIJ*z` ڔr:Kl`(us8Zm=3ylET4D"\Sx}'DJ"%EFp[iEL]6$9VqV߬]<5τ.s gLr 3wxeq[M=稀g^wGAb&`fOK^KR z %ha#s\%Omqxo?s\̀~aABZwet}#Xbcyz= ql[ ϱ%P"c&v2fAىb0G fXږx]PvLDԨ(Ι=G&dN|9Y؏oE@%^3ʗ q ~oɐȦ!mܕrG~As4Sr8Oތ3PYfEȁWA.[!`/#2FR\sF,0.iqۼܪK*U:U WVB?tNޱ*x0gŘҨr 4*xk5EܚQZrN3Jc.,}Rcb3S\GS^]"_`\ި#_Ѫ$VekۏIUF9:֣",1qPKfz xFp7%$JD_Yt`&7}Kf"j`4 D(*D(43Y'E4=Ph 8Sʳ 6o%zw5eH-m'1d˾gA`*Nܔ\ą-J֙7TE`ߙHXd/x!|4]n2M״O4/Tv@ pР?> XȎI G"!d3AC?h8?"k5b/VNN&O`*2B'ce/;W",g@ 1*0 D<5HX}xlp;ۆ5F.uVgե&Yrdn7ڗw4C8JHňU T Iu :\,2>@/+кXsw BDWg:X7C1 F۸' ^n7YuA 4>Xh{C =#_ԤE>l\n}䭞jUotlD} ox/Os#J-u nE"ǕI? M8'7+ŒHո*tĈ9g!AmMM "}$;ɘ˓FcCX:*9f-R]U<::&bbh}#q,-qk48AT-WׅnbW O#"bk~4Aq`]xj`GTZTz/zaJ8t @VDDe kcec6`;2QWN^{ 3Pwѫ}HNĕZmߧ.R)f>bbr."+a\s_t])PXd1=9~!H"8:@H(dzpiNw1 V3tW>lP 9؊ާFF|vStmJ=tr"w.=PᯀcYJ =0z,Rl8pQQkž,O2eb X>^P@q}Ofj e(2dxv,a䬎Z8tc}l& Uڕ ;PJso)8HPT¯lj&%>?LyfD-29"Q$,X4@gQ`?IE|* O:H0h{ q>VF~I%f vYz :*C$LӜlHfOE1 (xY" aU@_+GKЧ⃖9Sλp؇M*.g2ʘ۾;Ee rvO:,E6g"|joyf l`iqIkm}f-4 *pN7wK˖4YIưm^r֔RnquNOh_i 4QQp0Y@8" UA3ʸj3mm91`&>Gc KVy[[DY6&ks/}N} 62D,YזCɂaaY\"#(+d}|׆%,?k>s[ ^45f G 1Ooҕn>:cZo)~`upXıC0P`:O=+^s\EԦ?g: yJPBʜ%gC℁ftD05Ҏ|[G-iXJwلpW^S DnS@ z:I$+TFvwA6<~ 4Z8qeBL5KJ~[g%&iu,/l&1C$;oVs4)YNJ!GG4vW/6dRSZnNW8RnBď;[؆ZEo2X=iǚ[ٛ<Bgc^ƢNW+) !"9XhLB @gPp25%{ 3ą$8HzTk2 |uH.c2x/_NE߶կ owXBx6<0/ѐ]Z6QߙĢkF Gx#sByn%89NǢg=+pdHQ$4=n'9G= H@H9VydLHCO*&t_cϟϐN . 0JQno3zsp=KU˝ۣS.0>Xs$ekM)`$q7(p:-ddj|nKb=y9 Sa<S[uFRFէ,k8kV5+Qែ%i ҁl0?Qoݝ+N(6 4'b!3ap{/2-@G:P6 |Fhweޒ;:bd[BI,jFvl}KHi bN[+meDª yAG3MgH%&zyҀÌpjh}O;ҒßBy(Xm+MO}J'rcdaײ܈!5R^[|t|&HGrZ0J:-%s%~`4~0tT0r\ql/wBLNTIB==FB&hJȋ}Vl{qhO\fӥ`/ uGOE.Ӈ"ot,@@ Nخp5ۥ䱮Qk1c~dy"ƿd7X6l ?T괈=iʉ@y^B;MMS@F ۣ>0QRKB+VAX6҇k'}<kM`܌=+w-FN ys'LF_\P9!KOuZ:?Y&!a&=`mmIcBUwHg⹊pu3 ۟Q"o704RLpRB"xGWf̸#H;`3 LÅVKVfP'J>#L21 Zdz,EvmEbpn Q؎2 S9K)6P*>D:,#j]Y4;JJߝbda5'|yM*x-|Cż1—Je(475F#-(%՗$1/YStrnj+7OqaUq 85dЊm Ebڶщ!" 9plK )1"j w5r).!ucC ʳHw lq ` 0a.xD^7#(ђI`2eߜo=" WOޡ_GS>v0)3}rot'O,wgR /<]hvh&R6'/vBy0Ŭ|w1Ccevϔ#8єv+JRK5%J|*kp'8fDb nQ ]VB+}Zc^ndD66*)FKE% y R&da`@*!4߁*,LB4ϨTV}=$qB$u/A2YuR(DŽCр($%fpu$}X~s F s`M]^؇y㩇x'tNME׺#BBp!1H (f@'xLACeh/L 'm.R, ty 0%#ֲ"ҁ:do50Uy|,)M^Z+Fbuh=&ώ%n#Oᜠӝ(Cd50 Qm"P+7Y2YZ 7+yƺ _e"xQ9;GR6_,xycxacTNa.Eg&bYD"8U%.νMLEOi?2yERB`1U[lũ/hz]/&v8F%UI4􌨁5Cl!JDNjHBjĦb'n䫢(fɎJO 3@'It0yX zQNa!79{.ZgpYL__c < ~ȄcYCޘO;'-c`5 ͔ t=D"׈H3jVmk7Sa['΁Y~:ǁp/)Kpe2j?##aZ9t=[SՔFi { J[9QyZx>R-\I)pY 8.d_MevII`nXHR3}33R\`"_K(5M.75ؓJ-J#_?56C!Y辚R]ܡ ~3W0PH*htvaD>Ýړ;i#R~pו$|D//ze}"c^tڈEii2vHJo =P`Z3e"0_"<1Qu^-kUBT z' ,0\6@h#`!5lbY2q *tIk&8tFTYPpfzijeV)b,N@ (x[5+P%g 7911%0hL*dw dLD/3R$t%hWߠW"DRK,S-p"rq2肤:@¶uBqRkjĦC*vG6X|0IɆf@W2)f vz2T"?%*N755_elnޕ~QOp}݄AEPS|,:j tpU޴6o3ᵅI2W`o;' h͇m $ nOHDep@ג O6ZVP[z@e=Hnruc2,dASOaV$ņhCW{|! 1cpS{8ú[ P" "AZ1xy)Qn#L,,X+ ?m x>lOgFv qm|㐜FSvL؁ TFh ^^BO4J$lϋKlAMNs ,? ͎ tMlyEu%+KY>$$$䶄bCIu^`Y+u{&.5 h[b3.z~0  R?7; o"1Hxx%,*[ EOb,9JZ(_rYJo""ߗud6zMO>= `mj}\<:[VܳAwTraNaIyL- ~[a! "RV9+aH*f$^KcЍ8=+c L>GsRq/Jb>i^,i6hOR,wǶ %ak#uJ+jJ2ݪYI`>A8Je% SuQNVo׊o.ە#`) ʱ Mm.}R'1BP#N7fSjCD (.91c,=ez@H'pK'eH%,QKɇHzB ѽ'DHE3OF(4qy88P{_ѳ{}Mcr@BBBSzV<=& C&nɰ6cQs4bp\HcFƯT!`OZHtI\NIpS˵eybߘpZ"J[f⋘!|eXgt 7ۓпGpFQsDcN+0/NζT/Nٱ0])pKwfIGuv$߿~GĥRuc;"pDC4FUnbTĸ>?xZp^=x+gp W)^6,y:^NUb;Α''lV3Tn~L預)ʟsPWk!2xm}YPP/*ھxq ٽIq;-X(:K-U&~(T}Vz!S N |!9eodKA`ka?PѸ|1Y6׆k3c@}:imzTB͑xHl^72Tx7^SH/s'Pq&*Gw?|4n|u>҄_)tc-4~-V`ù-ic~8mL\ }z9C6n E !w{&FӒy!I(s1เ{>FP;.ma+-2AJ0#F/C v;RiV:DJ^?:q^mugj'D-Wl'O'`wPZ͢@M|<4gR, wٍF1T;yR}_^`i^Xܕg^侘f 0#7`&:ص@k)Qw#S\(dn`S~_%}+;Z Ar,]S*dO6JKv5IZ$ XIE }mJ~*0oZy*XUH 4oҕ%.6kHC x0wpn}xMS d#5e] J97$&UڔiLy85s_Zh655e41&^tzʛ  3 _j~B.6qL/L(6'>CPo .X%vڽnW#v"&!XoZY"JJfۈ5TN!BHCձj*wF#& !ziJplD6r1H탙OZj)a6]S?PАm6m7v |Am@Z( o ?9wJnSB^>s>&M10N_8)Eg^hꒆI-d ajǧe3ȺIK8EiL5{KK4ϙek4ed}cc4eĖ<;WM7RtqY?*% X'EtxP B LĦ_#B%r.rVFDDr@< ҖjOvI/4jw"d;k.IE47)K"ވ%rc2Ec' ow7wA kT@4>!1/1n8R 4Yښx, )O%AˆQ3w) x,GM whJmK}ib!ڈv$푄'%fWxouxr亓P*;-gڬ8!7Osz2-5fD0c[}ΖI܅:2[ zWarb-ĩE+ty=xV)_W ӽˉ`uW,Sɹ@TcC GzOi9r0Iƻ9 ,SGq  pJfj?zG;QLㇼxjJ탄,a q:S/ I^}!["_B5gZxGE?KYU8011"7K<2 Q\Į"X"K[]tr1DMeD +e3đw'zST 2xVGHr?t IH/5SM1$5il`L.Q%,aP͂@6h@;r~.LhнUIfNŭS3kt# *LT4I5Q]@1X?Q6ODbiQIN2zWv~y\`T H9o&h}Vݚp;ϔRfYYb,HA,`$+24,Mav[)y(T P`ZC[K.aDX5ϵZހ:YY&  ͫmk;;R>V_Ȟ8cс4r-6Kz.q+jFt 8wi 0ZM;ˮJjeR?! o6%aL=y'~NJ B ,)` ID2;{A#"UkiuB=-bNSqN4%i c$*/@rn|l@_ū(.³@in>FLyQDGʜt$Қ&uӓWLgc8Ҋ< ])cJ$L0-hj ` ;=$嵘CWsʈpa^H-*Y=B#ST-Ix%HT6qi=}`C<s j24!,K٠Iݨj*t(gKC!5cz}"֜Q^ƈ9G^Vwu$gؼeF0APD'DOk ۙ]Ch:}6GJzw2BKxybs1 VF"ɰf f5,!EK */͹ٔ ĩRwjc&/SIe,зJ~!SZȄ<¤@LM p`mNJt{*O(" !vgWz #kݗfP82o.bܮ\*Φ:E|=댦%52O´\ Q!2'!Z oK@%+k!ȉҔ&&̑ Fy8P jrKjq@ ?|c -k-~^Ki^ CTAkE i8xP̀o!lVƱT9^*6c5o)?X5ustj6NwWs@;V nSi|Ԍ^&cǧXՔ-AI}'YwMؐ80hzCd'xz%B?(tų̚1f4=1$K=tǀv6%0jXƚRO|X侼$P۳7m^HA 5lL狆~eiO*9g<;jojaXݙ ^~gZ2~D;4%b"ӦDw]_AHKQӆui]+1_y <=K ~$Й!o¢1)X[o2cMWŒ^7YHKEߩH%ܐg зыK)M-r.C}Y \xD^xt\>!{7!O2܅d\-?3P5Aʔ jNX"8r Ctw"q=N1XL.uV5 Dj#%2(K>5[ңP$JeHIIr[HJTy=YQ*R`m)o/?JT} ,VxvZaAEyBezԺMhɸ^;rX-*4 I@[M^{ JfƭHx rzй(NNg*Zgw2I 8W9RTvlcT]// 4PJ2YƼOTE˭^ze_woݲPnK6 1 D| ʦ՝(Ǖ+."s=~ܶwH"kcvjdfjǒ-qAgsWcp+\c}L @J(bWwAL V3㷢ՁgY?q?ET1Hv J΋ fW1ty?\ZO?^'IJBnی} N\Ig"Nݜ~Eլb$d{˗^]EF,muodiUTt$7YFIdLf ٬<|j'3Y+7ڧ9"2}Hw+@S,c$+l> /]i1؁ <\ @XӵCHSQ"& $QN H$;\CoJE;(O/Oj3o:1sXRƭ"M.0Ok=w2-xSnzf1os&^2!fp3 .i2ay>d1#yDCdx|3N]H$łt\ʼl" QNN:#˸"[<r]e>+#Ѱhz = Rk \g2%S8<ǹNN DM!!+%;x`9h\'U-IpGCzce3s , =&usbbؙ~(,D Bzl H :E:.a-3d: \K?X\b/iEA1[$k ><sӬDk82O) c@_#bt~ 6sb P@_`ҿqXR #&be|7<8.B,z `:5PrY$SQ ϳP!Pdڳ k9R-DvDAFM`A~ida"IB0iԠ`}6'S'HOT6Y+DP6Xy3Vs\LKM( ]õUaZCYP"bEѥ?,vAIG-)FU 0}.J![X nQțW=D۝>$L;:JX~祽"ɝESv^:"Yi7t<=߆ 8U+2=#A@:YN̲#^5Wҳ!MM8cg9j@1NYE5GN"%_ ; 1/PCv"ivhZkYKV54j!MR[[lc7_ i,*xK&x1,V9Xj$| )I#aΛ`ΣSU}H~1RR"u}ZW$̫uQۨyd& 5ͬO~ ap"Sb# [w8Ƥ+29u9/A)n6w-;V_c+jlB>X"OAhg<*46;zH ( \ n#|j{|{u>|0ۢ0o]H&s?,bU<ِG7|>oWi@ZuV]`!W_+p/b5U镳''식 XT'YT#ӪDUY8c33COcNZi 6j8GۉRH鵉.0j  ]-7B@LhqJ\wgZf (kx4cnmbJS#%G}nG$tpYܬ%dYbkG[k: yx'\WI уy vqڅ寀t;61Ѐ\2823|9|/ޒDxy|Xid_ ȴl07Cd@|]?`w'~X^8HnWzo-W`sT$%thx}:{PNmjy߾|}(  |w9vā%5[z8_|;FS{6]cABe4evqӿK{?9N dR< *VA8x̖pPYfH q{:BJ֝[N#Tf) r>o3`b[g@Cv~Zd]c-|z!%c`?f.]827{Z˚e%%D 4'%+1\"6ky¸R:j6"} $nf!1& ~K_iO h͸P#2CZ$W!E4)3˚[mT!_|v4cF(l@3J"K=o|h8gk i|I͋9@H}X"[B9^F{$C'E'5$S_<;/?M9*[D9`wYܶ }]/AmK3ܭ BgTA9Y3^*ʩANŘՏŊnƚA1? W`AX"X&2\ .5#[Xʋuq@?t+Azz'e<"57l3s dQ18b8ŒTMδȺ&Ndh"#<|nۥ$gb߱\WO8޸ c oYHߙot 8oi U !9e"tDIe6),K恪Tc:u!lv]'-[D=+EncӐYR497d- +hWdzoq TH3eP? ~Y#P|牖UF\ T/tkҗ]8(3n\͏̨h2ְZ&mLK* >7E~uWZW\EݕC(;1T~Xl'fPdErY)QN'':ݮϖŮdmB !0FK+,Ƹ ؅?'\,B@L4Y41UT P ɀP23=dǚT-|b>-F* IK|?A)t'7!7WBV^jHn٠Ԭ"(0q~bizlPC ̏B\xQڀj4yj*" 6/q%#* m"4kd@y.TYIq IﰩOUy(*s$FͶ8@x(ˢϴRzB1/ i>Cd(Bt-">/t e+sruSf ezQn}j dVnEI3f߇nhɡT 𝲇DH_~p"g#iIT L1biMzhI6,ЋRA9 ҼBXNZN j%OYW%z)1bTPd:櫳8)#//.-QT栙AW?VfKJRw5h3U8"x~f;W)o '_Ym{ibL̾;t% m;>^&5o-Ϲ+L&FF%Tr5jeh=]4ƒa lp }zVA]Ȍ&*!H{X \-}xb~o8AC`-9[H}X7ɑJ_`Д'`Q&wڕ<26Z pc ;)dyza*qB14k QV&/8#&섻7~01| @i4{(fjT^-qJH[tx81e6=,T(_CzfFٌ)PзOњyI~cp mm[/в(8H_Ll%TBgE#sTR :L#~?-OPdHmVJ6`8 czh޷'3kڝʒŠ ^Բ^|DSJq؈2Ӗ @SRquDW57"%'*64lrbp2|5̯ .;F|Hc%_z\"iy, ~ab'@7׏IW`m֣WS7Z@kHeϳ/@|7!'j1A4+l@Q&t9u\wBhx5 <ŬŦD: vzOc*;J1LbBDp,#/ځ#4I i}0V|QKNv6tJTyM& 0^PKIlX"~%c JƷ@  OP(yk6 k57^<o5es|/X3+ϠJѷ7"i$( PEm@*SjUV/pquА&54t'4uǮB*p,M q8һBi=~%! 2_9Ks"gV?wq8QV"-.֗%GVvդM5 y:"IFBD&O!f!x.x/mq_?iVTԲÕcy~Il5ɰVBOGM +cx 9ܫ[覠e1ת\F"1$5X "{RFUg q1F<(Ǡc 4.hPD0XYz `@+]k}M @.78dZ8UY[r /(FNquM82ۆ-?+Jegd3?͏0N<3Yp'nhq 6-&066i؉2SdgF(DOO)aNT s,C`,kD+!ÀfZN&@] NWŊИtT !y.OdN%U9V!p7aA+x\sZ$ec5C$aNa%C!H2 08 ~J.e翗DйyE{ѪYH}G`{Qe)mî0@M&&罃> &5b<h/bPk$1 vs0Y/(Hbv%kcT+Bv.(2z:[>!+{RG (2:7g)EAޟ?ÑMZʵj"2/\2Q䦙l0m[`60 )a 5qItIS!eA*E!# 9v„ژrTꃆ7A~NNb|~n^U^G/4&ȟ =iTHa I;@R ք _t, ϰ}R 4`KaH3o>#CMp,;$t'nCM(a}Gx-R `Z #kGR`׿K}eU,DRb͆\x}pǍB1_U%=tyj$,{z 𴹦td UdؗK6 1>?48CAU8dW4\Q#0iex>$ƛ$sPhN'!>; sǨ5nU}V2FFVn5ۓ\.l&UANC80Z98z- t[ 6J-uF!pXEhTԦ87/:ڎ<"GmC2?0 W6e* ejK:`E&+RGzWV?L '>> ?A knDM la E G yWk8еȱ/H0&zC镵 4jOhxZPNl~mA`hi&NpEU[Hs_WjslR{k¬HQ|;. TErU0t;sq}K?s5 \I; J3[*C[#ҨC>[1m8 рuNǡH#QE72UR\L7d`Fف8¹-D}c V  f-n ,G'ld|2xfn<OI>8mq :V7vޙAJǠKuϜ@9`"LI\؜G$<9g0X'X>Sb &̸P'-$dۏϯ}`?~w!pXgU QKq9߯a3W%koO:w_N~lsQ[BWN0XE]>׮ݹRvܐ5Fj{SE~܀7{ \!ޘ# ِoVK3.c=%ԡ7_\-:^_tyJj`g 5s$?>xH~lnwo7 |r!Sԝyrf- ΐGef8؍&Ho?^^~_8p{yek¡)6dLjz5I?@rx۞,>x̓z;~*1quuQ4G/=w5v0wV*`p1h2ܩΧ2!" |R`)"qv$^˺rd4>72ޓ$@e KmNzqvq95S(`9lÇf 0p򞶿mL!4;y`a#ZQ`5ؤgDO :&mVԑi3'Rba98*IU7ld! jJGV7,s^<|JK ϝQԚʀIݞ,Eo"i5 ]e'uk+r EM%fܤTI χۊ~m\9qMz%U@.zpun_ft5Û5o)ݷ^r EVpBCM.9!p0r5\'ʬga~ycϗ6c7Ro+}w}Oc[q?YNXx])*3(PX1kHQN׿Joh4%#`}yb+ g1@fuqnͼwYYQ n?=>h_A]6s- J9ZWf9[Ӧ X9d `QFCLНFVZ,,|4byK볳&@P B0a!Y45zKa:' Hz89ڏϿmϣYO.rɃ!̫5ʁ0kY l!)? ɤ| M[\27t<ڧvlz:P]B1?9R/"0Xg,yB4Wq=JGzKS d#Q#=.n9t7NÞRߕ`Cmbw7&;f. 3zCz6ss H2%Ē^CNd\aGwy=2+߰IbaD .DQC)L|YCR n B۾[{ԓlH{G4J%D}& \ͪKRĸc !}i6h瑰'K^ʗDPsv\Rzkn2wpn.#=g^MEC`ֱ!T唍&n=pu[07OFA- lW+Jȇ6:) B#5,%79<&\E_-,I5SJq-K|Gs(kMbXUdX-G)|H{ X#t+d"ЯQip!*$\$-s V\^OkI6M$TwS=,ffΛˇ`.|DSf~R>,K@L PBd_}:)eȃgjyo%Sh84Kn}8. J7^S,"u5aQk;N> i'$880 TW]]%Y)%keH2-Pc /6ڜAMBd)3<(F'D5ҙb{3EB )?! ΢Hd(@?gSsHυɗ9!"B B7th\ă~d`{}R친EK⹾!m;k_7Hz\T 0~.>$dڴd *(t)Uxt>hxl܍&4*?Fx >Ь< IJr8@v$6pigrBUASz{60c.c =/Ch^ $).z!}#H ͉w5nt<*D3gȳQmD>+i1ߦlT_I9+*ua6:J nW]t]R=T{|cZ7B#`p4Ɠ!D+򧽧*j%\[Ot>MudQD-PCbhZ `?"Puҏ7\"뱂@n6!0p؛R,Sw8*P0qP}:yɜC]2#<oQn?dɋk"<[643ö,Z4~"!cD|`&?j3$nv*B"UP|qn{/ھOj6䴆MY\&_#+.z;))m@Or0IBT0&kEwdE~ :3kA405@4.K޻Uy%"W>~[QI Ȑh&h彍;|j's -NI-(ICﯮM\3\N|d/4+`(`,#*8Ʉ•oζES4bKa8Y 1-rB;q%2DӞcY0,E]WGP{Ќ,bÓ!ڏ#:U1 |)mAhԓƳ2)rXF>} P^w VdA(^f1@~lPǹ_jBKF"DfZ4cDs6.2P P B)1f!@:*4:4+ yƮ>8R{2$=0 Z8M(<.}>pWCө:2,ND:Q!Yu]I^@ ,k,+qbiPǼ<9s96\8`#!}ĨϣTZ'0]cd/|5:~ܞ†2ivEgKڏ~'{[&21+`sdPiq"BbRΚMv8B䀅H; 5qF?p򳦭HV;K7Dc(ۘ4ӌ i4jef6Rq~,WfG=5@a0n^W'JBS~>1k(%l"\wHCuԘIJԐ+3mE>hHsT_ZGԜ8Y)M2m(uZXx 㡈f% upeu:MG}XBZN8Al6e{THӉx;PV6)G΁M;[U۬(.~xϫc,Z X6v,GhĩN<?͘A3,EBZ7'rY]Z>d:ufmv)h r)z c+oG i#JЄ"LȵF4M҇ZTI 0P7k{LM-#~]jxexO@n)H+42T3u_&)n~KD f!~n@||z%}DfHk7+%{}8(}K]Q X 24omWxxN719T\>Apʚ |VڶC Ѻ1OȂ>*RJሳL/C( =?% V{zNiP?'cEt%J]Nu2G/cA9Z.w38oJS@l?Ke-@ c< C ~Fxt)a g7R Ɨy-xʑ~xLON|r_mu$^e߷&Ĉ@-,9R]JLg4%0z{uk_Y0 %Sk{E㌐W&-~A/3ٮe>_ 2Ѭ>iȨթ.F - Fk˘tтyPoE7W`nVә=w1wc7Bm+Kha[`x9Hf2,KGwQJyUpC5Tdx\i0A19 Aa l0ó˩-8BAeWS-mg~a?&Tff.vJϷ?sNY)&D$RҭH|v~2PʘGB'F6@ ?fdv֒v&Ja4Qr)}avbn!PE]:o]D:ilZk|}DQ ji3 v$)fK:*|G(/v[E~+@g&+ Ț<¬_Q 6=`hJ1D9ꦥHIC[B8/|/d[BDN]{4U+[Py6cܠ)ps]hмtD`.R62XEQ)xh[!bZ- lH + h)Ĭ-T躎ٕ\K|`Y͘\=M|Vp >39|H }ҘC9\.ųcXS@kȕ=~ o"|rNDZ&ߪʳ\>ihsb@Ԉb.w˚t $HS0wP"몜q .׬:jgBh>c^?"n/>-`HNyc8A Aw8I! DvD+sțyWmRD"(Knu;`&ݸλoi<ل m(;d$Vj•^H壞̺8  tɣW\;3 B&MTyr@ߢé_6U;@ Be2?011ٿBrAOH尀?rM3zɨ[+Lkz Eus _ݮ`I/Ӭ`:jkK;_ՠhOBF=z`$lPY!*/*ʳKQ$Cz7b X12ij))o u}V-!w(R V'e 0XlP`l+q (`(?7BO/ n*1Of|g!LJu{YrnҜٌ$?j?ys+r@ +Q)mD2ES#mfy,^S"*/ƂkcZqGzE#T}!>V[z ad {D ;~hN2b}: dXi@AdXf'9*=RrͩVBvc3ic}I-4L]BOz l77ʭ@@&7ȦRL8S<#Ʌ6N,+P30E託h{8|~8@Q yk0ϗ.%8پ,o/c[M߽ە?y"e;v.ee%+ԩT;nZy#x_tΑ֠*|kR}vs؞րU%e5!<Ӌ,Uv8<ީLZ"Ҟ\m㊯$c}i9hQnaɹs\9v4#`0JbFx&;! q`ļ(,$( VaāЙ][u+2ˆ/AV2+`HZ4i*ۼ{W0m=$X۟,=0p<9\\D/8YbC_7#kqcq>/R)vGf.%dPoBO3J $3 f  ɺXv -.j_e =ߞʋ9%^5C~}'-"Wq0OӃpr fŁNOQaJ p̀F y~|છs kD7)@5'%oS fIC9c|O$ p9+rMS:/u[!gYIu }#lbPi1 b3*S+*>XvxxbH^02H1y F* 1jd~I j8x$||U~yXk4Fḱ43d<gq엧#f 7T4ll@j1uĨӿa 2wfָ{knfcc9i멞7~4J4?=&@{sD*~ut|3JQ?zKnɪmXA)*A.Y 1xS$$ؗq~s>&5atkr;b[:lcw9E}z~oE6?0fdc|p⭵9%L<lC&&???ƣ'WFhur7=:#+kPV2?j.35g'^!v,c/lUT'F)DCZtR*Lu.Η嚓%;om"ewNB|:B@@cE޸/ܽ9tma`3 l#rQ61}A0ѡjP.KDTht}=qs)bq a"`@Vid#}͎4/ez <"0˩*yr)%l@ejr f9QX"(nhA'lmE?3$ y2 t@*yfs64 E [pQB]L_!™`A3]1es8mO( `wӉGҰ?q?S$Ll||[ھuL:{p'5/k hq:4ʠbѼ>J\C/WKt>i>_D)=x s{hjq^,ؐR0HxO'|HF^4>`/_1h_&qu[އW?RP~pPun2󱚕8=#Sh;)\s{t r̗l F< [ lf VK8 R/gZSSjA:<zA`c,G ϭ [~0 F {t!)՜!w2۔\3g!Mm}4/dČ9k2TՏ,l}m9(;GY(VKQGw'ӷ[,0EfȈCxۿ⽽O׏Au %U q;⧒\Sg }I$1zOKګŊT)L$Uj|6O c,Ndć iP"c@̔cMƒoTEA庁9Wf?fp^pwN%Zț5G:-ZWr;"\%[g^o6MWHpm*d]UB<^;}ET<-W?qKW#3*Rכ=b&9)KqM)Bf]/'~q:᰺WvAES] MEZ,kF)~G!Q;t̊vL@MQKCELsu_VmIIwXYϞK/.PIqZ C:, )hZ$K (&=aNVZ7#Vlؐ!mY~:D tct=VOUuCfU#rЖG$9 pJ++R&aM0ڐYdEiF~!ASoG$G1_ V46Pzu r!ZXƽvJ@zL`=6%?ɫK&ksrOOW|"\`PF"P(ur4@/>lnWYT}ԹG/P:.a<: 99[m?0@5_4ːp)Qr1oo2A|!t#\rz RoچbvlEN:XXNS̠9%sDZ#V$>׸ 2Gr AĕYX )Z#zͦiAPSQc'Z$g\Iaʈfl?ıȐIɲJSalؒ(R?29#Fe)AhhD9Za ĊORD^"XEh5:aݷ8'U6^X zK^ڿ#ql!$&8)FkK_TNC<.u$>j[M^g f$RP\RNv{pR[2 !Q$ m&N ܧrrZ)QY\;8xp0݄^DN7xvK-Nr1}**d(vcCr}[򻕅蛮{/fE{񬑆@ߛ~cOE2z h%ZLj!`^M[g,푂]#=:JH 4CGaba<&u>x9vՕ I$~\~#$Cr`%)`fLRPԥ8HlZF),I4eSꭍ 53FU,(+3N֣9` Zy0jhP_ IXna@P_gP ݢbj&Gx3 CaXxB"ʱ0Sn's n;0}P[ܞS-ʎ8L츖zӉ7 b+%=%1U$i 3 K+q)O10- x^i?CI 6˒Q(?f-(cT)ov!Cfs=lIm@ I萟&pdAbS8k 7$6WҜݟSu`!XK Z\YAkf!'0c5%.ǼTU+wc":4Ac95(߹T )5"Ruyc1ExL (i2>̄5M1n $氎N~MπS7n[N_ە8$h CKmR,GX&kG${xfw,$^t??~{r__OgJHj~cqܯ]IwOr*uDS4Ĩ-]p,SGgWZ4`* }YۊH:aX͠b?)SI!yJ7@$rR>E:1ʆ ɀKRr֭)œU1*.3b>woT7ad>| T1T+I ,TAԺ* _FļԿQ(Z32Ahy|tķk5h'6^#3B "&롻R'`JC6hAsC64 l>qEA&gŠ.p4}ʚWgPF1 Q-*OvN\\:sб=zė7)„]!< epsw(6iBY~?)1%q#7녚ֺE:Աsr6 Cø;ӫigxƅRuL\b.vuu ؏IMS 1?ے;Ks6:DQG_nVd7G&|,nG<&|S f<#%׼uhuG)n aa]zKM>00B 9厉{Nգ6%̄E |g1_voiH45ZW;-Z:Q> 5#BNڦE0!N&gjy Kl+:drZqu+y b7+'N#LV^$qp-; (%T^KQ`ä(.[B ܱrϪxƙP=B| mzb0)]Jn Y pQ#M u ǰ XHn:W旣]#g }~Xzȕ[Kv Y 'OX=ޒ(혇0txg=)I_q*yW8Yq?wPbakĉeRX3}Ҩ=۟P >Ϯl[Go17J2uh[FjNlG.NQObL{`#]"16E@ GpG),/ Bts{_zaߧPfI X_:kOvBb8Xy,ܟa<0@Z@yq#'%aLe |hg!#>l" 8zam ;V=fB#nL@t8H t!Ż#mbN>yǯJx 9 IDlX~ݛ٧8~ә%mj$_Bsw8=bؙsKbGKl8R1H<: Li4@5`S Kڪ.|ב O3FQ}5;q+2KI )o$[I\*3~=mx2!&| Tu MJu^JNun|`v} 1އ텣T)T^ItKbF0CȍҐ^&NWTMmǡ}ŮW5E*FXErشVҾp_ >~<(pJ2_)&bC='-.`X1ߔtɫx :R6)^?];Fi A8wABRLPsi<,0_b=m$\-nUTncBtDr/3?ngX>lW4(_} % j1mJ6?ksφ-`E,Qšfl@,JA j\v/rEU > }%xc\3bO f":6/g@]׭4zwkEϭo")蹷'CDÖ1I5(Bb;;a` y;oDj"Ys/r#.S&BQ͹cF.Dӭ{ЏQ}S##]p?O(ÐaC`کfzйS$j&[v`8&pI@OB+~|y(e #>0ݏ İdT=ŋ 0ӎ_`?syWF<0BG )@RPrYd׎ X{H?;n0̴?\9gaM'䛐x&i!(Gt%G J&l7 7@ ݌yjg[O$5NLQE#;k`.t8zN 9%#uʎpX]^Ay(/ȲSbc zg(+~do1-`%;5Nn-Z Ƞg\v k*v+$8 \ .;,#v< IM,VեYq\s[ΏF"C gENZ"DEFN:o|5Qu|m튢Wy#G{CZŠ^08'8,N<Ųq0)6uH8୤ P9Pc^ A!Q)B`كJc^.4\D9@MuYHlpukdvyމ/Jys;^ZWʝܸų5#72.enhXNT5=ZA=V{^|CqT!E+a*D 7x)FRaq#,cڬʷr_p w(ˇ#L`F*a9VirL񵛀6 Ңqg0kU<9ԟa4ϥ䢬+c%'MgUlڈflf1qjxؗеÒzx.g6FׅO[Y@9~B/g^lrzQ3Lxqy~9`kj*`VvjN+71=JXʝWYAO4l*;808[3_ [忐AvXC ZY<ir #'ǥG,XRGA HY|4CLJ~Ţ*C*rj\;0Cȼ1]2hՑwE/Ɗϲ$\!) $Hh1}BoR-H5LVoqO0oUh4;% Ǧ0LAk%rn6y"68L(5;+UBy<}E+oBLJeWl4!shqDm&[Q,[}J`@Q2b1TR[8`oJ볕7#)9N-l굽rחi\ONUA'- sN nVb9͑1-UR\ŵjbt8f1wcKRaykxJjS6/_Q)}Fճ-Peya:niePigue7Ovڠ)|8 0q[Rg_ 2knE`&m3 ~.Zx)RFNiفRK8Cewa{HTñ.ͫD=Vr?ϛĽw)[®/ȥHuzzs2bzɞڳ뱩<3Cē`E "f'Բ_Ř(qޱj#FR-YߎP&n06:,̒,{X6[H۴-/_0ρ^;GDw\Γͥm-pQ3 ☾swUr eU2"x;?ͱp ʱ f;oO.ܩf`Njs7{Fi:wH3r9A Rɟ;GsJzd%C^ߙJh_y?} 6I7t^ۜф+5Vʚ)2L=;s^?rnG2 gmu<de0. LO;i@#OFB#76\j!Oy01ggP3qdrZ R("Xd9Li# kt2c};N "r4vCp֝1J1/{{Jdy%oַc(x.ìl9ۀSE Mga&"x +\vGcp\(vE6ITEwaA[OC]a;~.78m߷]ɪݷ?* P|{&O#e ؼ5TOv#PbuA H^H(lInL Ǭu'4{ik U(4~Cn 9Ss%0·vL'WpdC z-QtE7P!IQY 9vbf I{BR%Uʒ!&A6"!͉XO i\hC{2L 'vΦD|Fx0`34)G[;7'1p =[аH-S‚?IT_` 5x6ԧfV EqARj!/-qVջbIӵzŻ|^MDE, !Wj3nΙxAN5eRУ+`*ac-y=W0٧C~\r/kCY@/bw]gÃ7 hiƪVW9z61MSn4qr9:4t!:gUIχm y}p"G~XjpF?3dVΠB\(3hOKK)v@A8.ip^0C=RA[8_c%854,|Jiƌq=z"fvX3ɓ*apw}#/]Ӣ4, Vfȩܛ.8 ܪi #(iرSY"gz*0Cq,=҇x` ~A+z9qXj@q>aԟHp_Mi{O?B\ b$GUE!)~XԌq*MvGmS1Crn;gҤfRCWlhdYjB?yeIÖx!C:LHxp̂k 3RF"N G z6d '_Gm`B[;c<+4phXl&-| [YpWUX{R ̲U NQ饹Qn0R1Uã"i}3 6@ap IthȈfL ;'#W_/+KS!`ns\?9([ɺ7Mh2>/7:.#ՠ`9X;9{lt"_;kHBe2ô7 2H88Xs1MIv7<"$V5g .xy \C42׎SΣ{ +ơ !5!MvG* \p _M5.h+0z?(ZY2r@;F͆鱬yȗֽ8"fQm@s|S\.@aQδ:Cy+_&[jy1s,m46*xE-dr,@1JBj ;֔G4`.qryv}~fUPmiI nіZ*_t1jj>DRͱaC VM9S A5Pь򄓠ub3_ xI:2\c8@L&)Ie5JH{ڱ5bA893ܱ"YDRؑ zL9k*~;E\.)~h: PJ)g?% xJ"A-D*7°+$bK3pȢmxD$xh[;xsREŔdcMU? -;z~T$ΆʷU'`2AXwzS40RncȢ &c]!ktHܴdJD=/R/MZlMV{b~I2@?~l r[Wv'4G +frbN)0%1᭘ >(VS = U0EEt]sۻ$];^D٩\J9 Cmϛ4̭Hh^jH}n`Lr(IRg wrV_F&^:<S€ 8=7 kY$=lkߔWwtIAx~RaƙHL*EV`ŽZS;-mLQBf)'O?l05$"`@ @"cxҬkws-4 e0lS=Whc+!b)`JF,3AA2؜˔b MB0$rZ_ Va ;C Bh0>‰:5KNxP,Ų2Sբ0DP ͰW):SR@k;FoUMʯ~vPIuvNQH56b\hAg>rQҁӒ;@s2% ?S7] -9I~J$q:c Yoqplɝͧ2`Ί~@+/:by#3ҭ$( |gY⬸ {󍃍hh2VU=YSVRc^*Pa^[j~;Pc< ,E*`0uuln* qMGNx9ώPbuU~2}1jM'39RF^4-#B,$oD{\МCWpGxe)oݲju6/pa`6wLqk7 sO4_ʓ}s'iK|E8D>mllZ/x8୾e×'q @]7rq>-dP8/<0/Wt_ kǥQ`J;pJ❙7n>N 9Xi h2H3 nu2U"hoC&HX3b,|}?A 1twēnS'9k;r>D͉/% `XŴ9~3hEKFT,K[GBt78p6 &cM{6IMQ~\)` -k˴C vDN F)΅rՈ ko},-+dg:r e*|IQqMstX0% 1IҘl T<9?L$\aԅ(2Ob6w(ɬx`UaE(u3g՘9n*-H3c5ˍ :-}`!jas"Wf񁀄Z\ ?F`P)*zއvM!_nuFQI>!3, -et~^qV^!Qt?1eat$cOɶP$7PD #q^QbnJ7ټ8)-/NP-qHBmo6[v;D#X6@qXD?FBqGݤCOѥxn1:\#5jTP/dY 2)Ƒ =;[#k߲PeMϙ `g,2aF@b =m*B6Tf*!r yG"%Bn+2HI,`֑qCCCAIa=Y'9O8ݓJe^;s騑RaZ@7&VmIb͐I>(946QT }Mp`zU,ٗW!rcR5Nim)s+Ab^+!|󛕄&I mI̳ڔeHgI}ϙ뿯^dO-.:s3j,:EcX̶Y{7ĭ(ׯcG7䡵]lߟ\).%(4=j=dznڣ-!+QoU q?ocy "F{~efyajY:<}e{lqƺq3_HJu=x3Jn~Bpc% 82 ,i|S6N Tk:眄m=1ay Gn)Aÿ~cb:ՃJ3^@iL_Uf,p0 %=(GsTdjw&Q Դku@F 6 ɷ:‹@6lבW!%o) !h,e}??iǗW~n0Fx 9|L+Dk(2<,_tn[Co^J U r1 ҰB^:]EZۯ_o\m?,C?e A1HL,J@^.[K"Ndk/orB^f \So΢@k+Fy^*9l'bԘ^2EOrzT5>lTQD1"bYzsֆA#CgkjIp+dCO8!Od}8x0;ή" YvO:N3fAZS~[7ëHV܂! [AXXMY.I{k|O@:>=4Vz\{<L5zS/NYe5x{JR}qqe#I2kJVJΆ#R;WwɆ`So&N#q _##Dz(wLN ͆:n|oZ[u-ONTf]U6VfWJԱ ,gi:80'` 2}H//)|,fU @%BekT^nm%G2Yqtip3:ܱ?+K72B|;<vԝ{dJY^*\C'0/k㱬<Ǩ(8`;k$JEEm68m(kLsDW1}/b QŻmZc}{ɛ XB+#t~ϯv˻|_v&#v'= %`(ݦ>` _&NEmGyz!+m$_&+c@ߟ$8XAAA5|p 1fd~͆:沵艃=Lr"%p@1P\PY|QWlǺs1>,H^go[ }>ǏOV9,wAX{ظafG#y|䬵 N+9ûr򄙆;!<>`q;Q4OIx=ӵ^p&W o/1ܵE=*H<Y!+DͰY7<_MA#lP3K& #dΘ@8Т,b\^ڦ_u> 3WW*,W_fvFڔ*W/'*bôiR(ñJ""-P Ђq+lT[gLTsLoF(x׈Wt Y n'mPaTZzt24'lUnrbI%VвX9v^nSor}ښiSf[T@D}QՊZuNv#x>f-q削 kf%)@XqB 0/ KsВ qI̓׉z ~dO҈תL 8F2(S`e<ۍ>xy82`hWjD#}+eP!zoO")iuCRVb1KF}zuWldjZcB#lT|S} +b!Xh!L_|Cʥ(82mu"zM%#X'*nN T#YF;D a!Bx%`}Sʢ,a.yj="+e ӊ;H}lw+#kj2ۖ29apjVۉt>`A/, jd0` ڑCЉ==o9{^϶ze"RƳq*^q"?Q ̲Ѓ;$ԁg /l&` ^I%w,c(97PETx+laڷ5JS Y@Xq";zCjžuG5JA\+K^Ɋ>w/a޳FLlMڶw>:y5VysKbTjsN ,RxB|K~<޼ J|БmWCb0g``2hgMUB;mVܿQ|a wTN"UƜ¼ff0ZA|a )!Uw 3qȒ9f >>9w8 KЫm˷%M:]OSƓrJQ.,"〉3 b!?ff▖^f_;$_c.OIyrb Ӕ0P qMU"LG#$5;"P=HqLb;5? OFاޗrTf FGL{dyaFj_u̬uq;V (ɁYH׆2>=jK˻!ۂW#p2%DVJ::uFQ/ F)hFeDN] ya槟ԀcEm˛3kW;&(͋Wa9D\VǨ*8w]EoRa(  'ע|%GAT; jor&kE$F\UY̜T3Xc4Uc"w&g;ٲ1kܡb) )/,Ci;'iY](I-"Oc (K942NL }]L] Χ^Q5 jtU5uVxeaXWl0rnc4O m1hF]yuL0%x\В})=7 ak|ECTe_B#֡[z/!suK 4㑥)%n\܈xAO5v|54hSU> 3ܣlSHP(a<^Q(Ti.nfKW˞z?1_9#'VzM4ܧw؋ ;`F)>UӰ . ~*p?'!0) yf:aYҹx}@Aqc:X{mXҘ;2u~n5QLv- L]lYoA a< :&̆ +KFA](;>p:UП<_Gp췺we ..jHi_RۙȊ 6ADrЏB]Th# cbKdaurrsl|Lՠ|&Z9LQ+a3xZM/SGYcu$,t\) ?9.i/q.?Nb^g H吙"ƺ$9R8q}4$h0]%i|׮Tarp5q#֪$mlJzɡ|s/4Hi K~f<eR*nSD/ #h0 29O35~, 05Ǔ+`#J wE !G >2h \f)NQvQJ;ٖUC0\V D[C`X(CMi2.m\! Z@)7:nE oA7~Ҳ~rjX E%ed}|Sb-ŃjP̜"Kc=O&e6&0.9b+`>(lS"a/[GY :L8 tr 57h-Q`mBĶTN p70nl:k8HFY E>񄑉#0mX^}Mҥ?'O+C[/^qBxQqO?r(a)3 𘜯S 5ЈFR?잴>ȋ(7>pׁtiXUfRX ^Иy<܅hϔ^TP1hTrx%QB>` VSJvmvdР(_&ۥs Se%T0" j8D4 E< -H^[nQjw#+1= H 1XʢN͘$Z-˓sAK{9DJGSnS82 ISKEs e` I@1z0A)$ ʶq󿘟,gaDԈAWvxq5zw=1e6l [vإ~Wb>0QPiRC㗽2T8j}-) 4>V>yn|])mWўx﷣?D[IF@Q!r$In$_C@G$􍴪9$߾K"إ#!YHQ?#tw-*i낡 ͌5ԵVͩbAzܠ(V}g˃Ce =aDHڄK`AQvw7$:mF1,u5}2;A_ p<g 26+:;( > ~zrpq)mF&pyq)'=kQǸMuD?M)Zѿj-Ug6xjcR2 1|OEgCN@0eHw{)/G>ɠ" e1f,KT&Q o-A(/xU%h3ABZ٘5v/: U!p{ 7,]_? EB"űw)a^?XKHp$msɑ4mw`ed趈P> Δ̉a0{\`1P!bc%M}Q@<(2ہ&AS!2H9q Bц#/ 0a@hEԁXA"-sj8`*cDZ6n/JhsC 7I3as<7޵ XacR.uZ;ގ l%3䌌4h{sM G+@'s|/ ZB*_A#KŜ LC$õrchpܝ#Blح|uh-Et@[E*:HxJqz@ `g÷Q/Y~*˼f<9Uxڞ^yVr؏ `V<Yp4 vEl=uP;>|3E1cztމs39p\P4l@d!}{v ;+h7㽥8̉a[|uŏ[c֥UNX݅8|0h~!oK_qF6eP}Ը4{3IÏ N8wІ Un F&=Jv*uځP$~g^)yGAU fx^S0? OFA(X"IrU GGPy{+'I8l3A8#p}bV(qS*D1gGރWv#G$H%Fk$E!0]=D':WlHv3pߨwʁ@*u۔p׏7ME#Hl#%M_ɢF9 g+(yMl\(7nv~;gF}ɴ0V ڹI;_hAk Kfc(|@u"1=2,*)r 1nE@ّ3&~-թ 眥E C2"ptS)[ NhLdHnrҮrlC0|9QW,{#sL?EƵ.Z_rxΕWL?[HX@&l5#Mub76˶uـGp;세"&YB- 08ƹ~i'6UѴLvj=gذB! ԇ1nq:}m6D4*nPپ[H-h NQ`*›N2Tz(nqhsnLrۙ <}9&١JqHI Z)L+X'"ɃYW 1M/=gb; p:EE"@",Ӓ!L "ƨjgNz69,@ 7XUtޛD;/:DšmhDfJZƏ:ߞ\Y}&u [}d}}|,]4-)jVL~A<;GXm )4Dhq{K23qfZ6ZD9hO#% 9c{؀K^S]%^)>~];s8kkwUxo[":d=Zq}mdm͍@dr>GG#(?2nWSL) -wPde٬2# ͬaf"2E'j=QrТ,.qN@]ʋSC;_;ѬȮˏx?? Uɨc!["v??cF^mQQ>a?m/jcM?#JKHYT_N׋@v~efOLl[`4)L+ob#aJv.Wӏ?z&qM9KRm} ɩ@RR9D|~7v{ Z='F@ |C.\WjZJ PԺRY92 H}kBR+9c9K2lՊ=Ȑ!p)Z⎖ܱ $ M~9Ù /2m$Y~%Μp)vye/RE\` Q04௎y@2?7;p{R*$P#M[ iёfP6oddB<,DeBdLeet;/pbXU0ɍhd{37v>0<BO6zLx&4/2߲"ػX&ry'vl%4_DںY+Q<rj>U;ỦlPl$R%m;e=b:09.}VnyĤ -BViH9<`0nm`IËcTԉL8et\D0"~)`pRi2kA&lX&k/ ]+uj!zz! s ٟc O YT޳'kTR!VްFUcBAZm*8Ӫeb~2nWތ4 Sdlo"|HCaXk!pF@X0By2$p=ȇSҡ"$e^'<"1I ҤC8G_O?MC2*ǟ}pE*tSvЛᖱ%E6={v* -MzIcmjܴv2&O-~e86ɚvގm^!04[ē7HcYg/J/{lan 78DJ~s)ǢҍL9ͦ&JYYU;MlmtȺp1$yQrFP yc"'*Awc2xfp}}j~;")iLDl6.Zex>೭W 0!#r;[h|v8HSAxŠ7VGo \w]4,HLHD]Ѣ2$.ÀI0X}ʐy\|!y {Rb%t B`.dIdk  ~Ë_O_ߒE ۩2:0*LIfiK)o HauEX^a3J#t)S- 9?kWU1S ɆM9P3n; h_cXh”tHbk0oLpiHwLlNPr9+CL[r׹Q /-*>TϽMNMמ uZ2$7}}X 9S?ڊp$@p #tEQ&Q*U)Vo)3Pdt0͙lE#)N}E`Xb4}C,N^Љ V- V-MiC\v3,#nmT(%')hW8zWHP T젨x#M bb19qz/}M;B/URM<$ٞVG!fP -s+RF g IJC(#!p6mM`͓5 ]?>#fIИ(G8qEyeoeh]aO6Кoه&d[\I5 0U/=o:[.Yk^kVRזģب_q =ǂܥt 1d1(%tVd4q:b &M@$XalЕ s Y<_VY$г991KJLjAK?,m0(^&VĈ٥A03C`װ3JOx_ld:qDg'ڤ"d$\W%_Mγ~|p7Żxo@geh7~Ѥ%ג(4J(W:UNH3=HE֑ǔ ȧQqQK_Ǜv)Z y;mh" Ctt;NүE644q21ͨ ({l ȸVj~ACrpԄ$Gy7Xw.[|(y@ғw K0{`ئ{i4qԏ߽(Fe4.mIp@jbӟwB)|qR%bd@i^i!/~(}*N'J39W* ~iش/2rT`azvViwe+m 4]SEP#ei]o2UY5o4QگH,X e{q#[ꯧ Lp]^1nE (Ub,rcA4Zإ@J ;Uv%qΨ>DedŨqRbCs]#iTpma<r8#FgzSE;XPa 0Aes梖b p0{vK1Hs៳#*Ug]QTH}R Ȑ Qr`J^Wop`'渡Ja4Ӈu`?iYqⵖݥ[PTGQe2֤Q!oXlL"8+À<ޅ lxB%":7ZNZ-+byo:7]-h8]/Ug{:W xП-/%L5,đu[jV ٯ}Pl~*oqUPzxAHg)Șn{4!>nח#}o9$H=`*0˷NSNX"LC agJ?1tLƔ Ⱦ)$DJX)d7+XxGJ{#Y{Mw>5a^ug=oʤ/VwwϘStxc EebU.t>R8ŶUrEF<2MuUasICw^dG8DE2*I$) gv;rK lxa֥Sַ +s۟mceⶽNe@x[zg[^U|ʛz e(D"'P͎p\Dmi-2fJl%R޹2$ٛp3|磹ljɶ/G O  ɕǕoISۀ)q1YJg8vrAGo?Yt|`8NXoR!Lu>yV2mC`2ѢA7;h(j.k+La<|1mMo,TJً1nkh,HBM%AFpk ZBӑ?_[_* -Z몛;pIGI%SðOvU1VDnϪ q+eft~=ZJVvs:[䲅񱙍QZ0F J}JS*ׇe-uZ̵ }xZ4)7‡k˧ԁTL=E b_&تjjyv!hEF"RaMEtXfXe~u:{͍V8)F~/Ad_*粡G$|˿5pA @ui;"z|@Y;Ko#I5M $Jp譜-z?}U%D,?$@ f377w >mހ;hǿb)~28롮_8޾mzu̬Cy̝G _ERTw/1juZA'3)a2g;䊘b9ٿI*ty ˻. 5疚JcODJ'p!Ӈ\@1˺߫r9K/_Rh-}KBšr)t"wes6݁&ˆM_iv^mtq޵Kdg4m&'(L,RcEߨY=a/?"#2`1d$ x3L~70|dSL @T32vo*BUlCۭ^1T_^L5+޼ ?$M!`4,U0u8K÷˛-)DϢ$.Ofښ} >}9]]8:ɾf,E7)GDz;3A9*?9Ѥ<bd]+'79M(k{YihHH tsoq60 -t$n0YG=!:f琫A&6d `Plq* t3&8w@ڌ bTJ\m/eE5+J񠹺pwrFZ6FS $9| i==Q)#xXgu rA$7wOvf\<3 <-2*e.fJaY  ͉Nf J f48d~6L x\s)y/C$9=IMnw;d-`K=:\. L_;H/rR\wP4[f붤JTfsH/rI.#P"8'򞀳 YnMv_,v6-c`Qs[M,Q j#[-8v^PrD5 h&N"@N%ļܛJX@9.BLxSsqàmFP|[d"^]MG>vj.gP,no[qMы*=_wV|Dpc ! lz$T|L E2p iheW ẐTP'khք"nѬ|Q 6•, o?՗qCa|d;e\F3JH<s}^{Gފbo~lr6Wt8EOI3fr0'f` ejLWODFEgt,}jIVuƶQ>yd_bD&'Oa:;~fF3O?V: )(Ƹ$BbNSoiۺG gz fF8d zqv)]  lEɁ.b=F]$L>Ӝ&|& LЧ :xBfwh1@XpvksN@O=]:RN&eة=ʖa !{:yrNc!<Ǭ"$2uHVLN#qư3Ś|?Iψ`4,7%B}}+ޔ*1?9ϣnbMQCDiPcԌe0 jy) %F4vrxo*:-NT5[ -[]K˱=p W拇V ]2XPҎ8fY,Li5@کkoAҦC ̀3j8O^{`@]=jRc_N5&w@4~%*x .,ih$DO~4NXڥEt.7;Gx\3{#ƚlajZ)YsoLHCQS6ϒo ^AE,ܤ?{vpyoR|t_q fBLl,7%W-huCk+xHM;wj J^g"ΈXKAu"|7BCdl.)p8 6l&#IL_% I (r@3x)mf^נI%\wѝ5`ECc(0DVf`1&eM@ 5W/[I.~]]E(Xc2!8n%Y]j &?i';I-Y#))&sT0WWtJ9 8`ڤă7 ̇S,}KV%L:ZoX( x,b4mdeF4vðVF1^ѽ-\u|*v*75)cJ_ 6;:hYė  t⺕Iݘ-^ȑ uD'c-5 jIQ7j`HzN97(inTRпVI!gS&GpZ,m 4#yFjϔ-F+ tPmTr֤2 mHCCH$qI?Ic´R hjȞ[_͙w+QDWD/3uh&h۬fˈdzCFc[;gAa<8Ob5&.0ݯ$L gQOmYVybMz3Dy8k1E';F6X$d; +8o*pP1tQJgG5Cj.4@H\-e#gN{)9@0qw/0WXIp[Nk&Дl rؾiy+9eh1*ǠB5ё>=W] iE@Q%4 f\ܒnq,8h [TON#R(lH2DTMV6j۴=Fr \h)&m"X9 S`R zH~; G̨WCݼI8nIz*:$mRbQ_پH=6njE(T PΜv10юU`JC,QA7 P[P|#-$_hQwzj.Bj Hr^A=KL4 1h <цnH >i S!)8dj+3@{UUQ ;$t1b/Z3V ?HE0_lNLx-z)Jז_f(iPS $uI%ZYPؖ*D56Rl(ΎԎ:AT7$Ii=<ʚ1A $B9[ʷ!FL5 c':n㊕ Ya :* -XS|KkH4g X̡?K=P;z~@j m7h@;P $Z#jJ F9&s<ڃ*idT!BW0$ptA)G'DBo<4КS'm61 ˿y XO<`kyhjT^eC=p~f*I(N(<##Έ<0.r.TCm^ЏSS4L|~{c_ѯ cfz.GlJ]!L4S9T^?Lm=S|zk M+bL&I .PEes=o—P\A"@iT;@ÛE DjLJџj"6L\uL5qث1@>P(WJgeNuۜ/ne‡F9eJ%2zy"ÔU4ݳ,'u,2b|MsLHr؛rߋQ5E֦ƀ!yUkǁ-+@Mu mNf^i x( KӂoؔyRYɮ ֐4hBY;X ZJۃHk~yvJ86Zj,_ 6PPБ0ق{,OTԲ)@ZQ+Z߯t4fHQ,iO"1JAuOfj i8-KEt!(c"T.ɋb[M\BqΘvBNih7X@uT2"  ΈӍN QڂEy-ߜp#`U֣FO40J<@@Nd"Q'8ۥ×>4ަDA;>gl5ØntXgI/RAaǚZ8'rN&S}i)#nz7r#)cy"00ǥ5%M l,q&&oۉ_W3T%|c68ƍ˶5PRm*l]/g5Yaz}"ܰžhx7u6Rwɥ{%Iu):Ww;ޭKY)pB&~N~ 2#xƿYmtڞ>}U3g}f:nRbHM!CE8Y\W^IKlp+8k(9VQs*tH2D]_Ra.NbSjaRw?`C WթAf&͈wnr d8UgpIDD7 q7x$94xvE=11E.o 툫 .w y"Ns'¸2}eReɾF/4bD`.㪔fwDI_2o 4]DX2p.[M!cTm-&r|aeYNpWLF7Cyu!nʝIlUg~LN{"ʬ\eb͂4}j i{F&ef%_by׷')h,a}~sT×cfVb˝mn.4 &?[;e!s;Xv| Q BHQ_g /ׇeO{EybHJxHHv#z;rum^j+EƹL%Lq:;Yg^u|KH 63G/.WJz^H5Q*a<5HN:񬶁=߲^,Av27aLѢ`m)!OzCń[il93}>Cٺw6KLC!;{X ӑDǓ-֡jXNT 3-G>G^b*KT{^]>2 0 FXuyckGgW1 mܛu??5w8Z+#AG^ ר}[Ozf+5VTo5 %,!$+SxS,!;#j昵x@IGDـ11_=x,.L=ƹESL)vA #/)0޿n`oޭ#$LLSz}Q  znAvxnOGX7_1k (Ѓ$(q6,8I6 ɸ,x6p&,ua 5g`{`P btr s:O='re.@Ts6Ҫ+o}>^'Phq1|:jՎ ֋+`EK'`O_uS3M.DAsq?8QHdlxm!-_+kT +!|Qˀ. ޶`/ҐQL\4- gPT ޫr8n+ȘΠĝ(%~Μ63.[~|)Tfmpk(|{.hWU(q: %lۙ%WoFƖ {t6ڱMQJ:[mlF`r`tA˧u z1j n<`f o}r$W8!,j4Z%sOeho֩^ jZҝe;vMN7!θCRmsER?[Aﴓܤ7a,hGPɼ OEԐ"Qz-.ap"#g ?FGB|ceyP0tqȨ='qaq>XXֽI,Am̰ 5\:y͚f{IG6 &34@I]pq=j:k~';'Pj\ő)Z2̑!AvMa2P1D;%^u'%W4<ۄ }8GF-luцSz]2,;;\' D-*B9Fw#R62@ &ѬЌ 9 ׿(tF.'^݂5R2!χ 7[J+j]F`ƛf2LcW؅޾hcSeqM&+e{fop&t^[j.RmØ%!*FҘU=3eOrZ@@B[mӑ8;Ұ,-P]X4G=ؠYg sޣl$GƦKd2` Yt >!"~fhY1QIzåY3ΘYABdJ;XI.W%ha8M:>QhTQ#E30A$z i N!}_eؗ@Щ+(39(Ooζ_eѕN;]g)D9qTUԲnmhtf c &UnXuddCIX̪^&j?|u1W:z͜)6$eu//=W !ס EO@4vm MGj2Tg=a-:l ,@[5dHӫ:fF ! E1H>ɘ~7{‹KQm1i[I%UԽr^s|} ܟDnϒDGݔI?襍0Z޲Pr-е֫! (r4t26dxI̮_;T/*bԌ;5Q޽IxtIx)ȫwL1ՀvOSO_6BLyëo49t9suh-kعhFUL>F:҄km^;0;t)FEb<%z8?gIB> \\LqỈ[,%hMU;J0A6Dyݭqz\o? /^38mmfԼg"Ɋi{+3 B4FhIȓ,|40-/PL}nk.GҘ~#}XKϗlQ A嬝b ,#NT[-]V 4G{׈u0fQp? v'JB1p(&_ٵp&llHؼ,86#g \0jɾCtYE } BTpLc. C@CP!pb[cEд ܲh"eXYMƒF My*q6^1ZRK^1^M'NYiw@X@IDATֈ5R ϥ}PU4V8]P AN͓aU)e ܷ:$_2@uP"Ge/ fKsGj4&MR(1?֞NHw826dk&ec厞 G`}M)Z@ KŠK`I10o%V@e lkHTu$+ĠTO(Nm<XI6N`d |kRiJIMQUYc,vȼ-Exs {uQtC*|I{Ϛ?>sHu'=<O+A8gu3$v.L[59&)nӐ(>t/x\k{`y1V6H_ztz~QK9[LM^\ں \gGei),ꈁiU^)"Pa(T{ qMĽݶ+bMUs%<[ |志ꋛԜƀD/Jgof1ő%7_ ])V$"ȼ+P&0kwmOϩ7i%%膸 |sOx9 2(bU*> &‡}?,'!7Gϲ:wҍuߺedǭ>Q́ȘUR U MyӜ?6QfdTUWoG@힪}QK'=oV*]&Iћ'5tҀG gUD)Zm܄ QeV;H8|7`抐L&ISZ`t,j``>4rvQ޺SyW| eTUZܿ 5ש0[3C& ~m„cɆucIP7#FjwE61) P`Pa@jnG˕}пdZX d)jF>#L(q ii/f?ѥEdd+z1pe*$u6f ϒ h?λ}RQ{ӡJRaDhYߡ{q2A7@X*)Tc*aȜ-y=Ϻ<Ђ& + \Fb)(ca2]RinnZN҈FzI;;U/ PwE|72jOgx?חo8`Tcv|Sk3u3!Q{AP4MyB{*q}jB\B EȫV($HḞD}Y"B;nΥ:4U,Ƚۦ<8̀©C4zDqd^2c/n.7| 'tV^ySziz׊c j^2VWAPS‡Q|}Rxh /4B D ?UO2>ؠS`W~r,J$7mkKw%-lZxӇ/xh<#kxM@+=PD6AE(P$A!H!DqQ6Zߪ#/Ziwr[;ZWY.EVY]"'cVuXVD1Xhs\.jl;4v%:44cp`b#mq'GJpoOAbCLߔk=~`u%V|t*CṠ:.mjyq'<]'bXttZJo'Gd8^A ~tУ 1U㪠m +KtXHN`d|#^AރdT, >*uSfYmZw(Vs(#]h*VJR g.OO8QZ_[4s4u`./ݓGqAH+5lE)Yl@ݴL%0N_?dZ]lm$R=5 =q/="is.kcF2 ,PPk%c/X7Z!ݙD5K7R+i! H2GD!(b␠EN V65}FT]hm$YĦa2(4Iwm֍ټ7Y训h)­~/PBy["~@fk6 ycDbbځ}}~5aCcK>UGLCe)Q?/Cyuk3$͑cg)l\oysɳ;ʫi#:TAǶG ׂ!~bui(hm!$ I*M! u<]*^XC ToC&`Q$0"mW!ë Yd`"jKJ1IQ/& E}M @ҝ$nz:` 6W!oݓ U5ks?)QUmbH^ IwL׾b'0vt .ъJoqhNoHƂՏAGHҧO@Ox#4`IA:2Z\a%J@ s2}e|0̸#(N,fK$c}T?{Ҽ{'ndˍ?OJY'KMPƳRFRڐK.OD5{$Q8̓Sø Yl@IA\l<\oܪ ^(n @,NL}P.Ʋ|D"Z3L$0Jq< *03i 276k;Ox˙S B=qO)٘aZE$^I Ve8dwD^J`*FNY7 Q1T)x)c2[p)Y i8`(RgːԒ OZguH8lgJSGŽ79dƋؚ-W4jj4QF}3zSo> ?|5D2HMmtvu+Э Z*5n8*$,k\j-Kزlپ%l/MƠ*nG6-49;@B+bT.(9#ku{BJ4F9P:qwH,yIoc|!<é!9 ]"aIg1g׳C׮}u u2dã砐Ҁ j6dB6J;aT[ЌLnrȤ+fTM+:aVBϦ'٦OV0GZ! M|I.xnq7Y2Dn- HHAOJCMPJ|*?f*t-Xhہ}[SRA l_WQĞ~CdcC(ӿ qd2ܣZpL΢453W>)jk1"7O畘jaLf~ 옋'nSH#"hT"}BFxf|BOD`z ԘFQ V} ?LGyM~+yRdZwnpZT :QJH,Ac*QsىiX?՞4]Gsbگc`h|@uo8ct]w! X` ,}!~O0Q;ϭ$ꆬF%d%;:)w3oʫ lhl&P ̦S@UlsvI 20qG)ѥKrV(E38,F' 1>fCD(j vOOaK3GY"QwBbkYcwbzk+OjV;OTJDe($h&J|ݟCF-b S@<YT>1Qs6^6|B(%kA?Bޡ:Tv[x]%;AjkCsO5Oqu&|ɝw 'Z _sUxij@$lZ[-/sy?~˼QaȗYouqv/v MG+η CfwD7kdQƶ/!@SnXՅ07@+[v?Ǖg(b&\CG.EN~3c?7o lG-bz vI]߽>vbG?!\R>BJVGgr Dj'6^,;˙.1b/SCZ8kܥWCD" _VS>>>h=EWk D._״T'S)␪Tvđ,1ACKXmtb1/g x`74{D2_'xbr\(!kׯ'k,"v$h@ F/Xl`y_g,KECl<@]~rm)XD3t&g2FI|Nj2L qm\AOAo&&FwJ̳8տpI$}pZ|]Oe1*Jf:l>{̊[|Ԃ_yXQ@5:,w1.QMml|Ē<IQ\$Ik;S$+h ]"wոH8o"@2)6Yi x8F"fZfl'*`ZO<5P4W PE(UI[ÜN4I}ϕXwFLdq:I/+u3y8@C4JD6@֞]9 skkǎ$JJ $R6x,@oX6-裷PYRgܣ*ݙ]2KK @bOSjf>mn^.+&<ǀ%kVqA$;8չF-T/HS-; \P 6m> ߈֟*=YoVM !n2bW~V.!9M;RrÚѕ\NΈ%Az3C Cof%&1fb!kzIctqya'}#@4z| l=eEp,zYA$E@sE|t\V;m$ ( s麮졔. gHPO &Ra:1/F"il**i#2{$`0998Cl%kp?n<}I {t]li5l?[ͧ()C .x8Vd~ЀS)KX"H 쯣dcB2# BhS^{ *eR`o^ ML#zEd$g@ S _I1:SZ`#C0j2^45K`.AuAP{ 1[j 03<`8&& f$drPGSoa'c/c0@%ۯ(ʩm .وH+HeЫi>7O6!;~uKCԄXMP;5< ,mTDZM|@yU&e䰭=GC$b'H&eFFAiw5²x1i& |$u] 3ݔT.6/q[O0Av* hn>Xh,Nbs$X 1}TxUf`C2 ebzJ5Fk,ǕTrCY4r&b_%]将Bu%jHcEˋޕۖl>jF .K"|_P5y=eHN(@Y.B}]Մks-BFڬp0]`BĚT M>iHl$VxAnZ.Ť=D2`;2j$qsZm8kZ %ʠ7V1*"j`Rja`v|/A#\$umCRzeI>?kXTl6Ao2ߖ8ΠZOːPa0y/m$jD&`$63Ӕ<|i 3C"b4%N/,Lgèf7(=_ CkgoBQc0.'3,qKU'GWU{ ƼFP|rcE+l:/DK32lSu)hҰJ :HءghmyefJbR?rzRV IЭbr6^,e1MM|%(_4J@IϚ hLʳnQk-DO&)UCtDf [f}U+"A eҗsI&thףN3 V.7W'{,d72`e&]C*. 3K+#څOh*'#<%kN̳0>.g%۰(BhtDQ4d7]b.`?kQr&4|~ʸ!K4{6< \c4pՎsh~7$J|+߂ĖjKF@B3zzKkSsʩ"!9~Uh7RNY}ke*̘d"OYK|Ș1+ܤdoc+ |i(8w mܙst- * zD1['[(k.K線3H/Z o`aa,[6 Eقa-(%_Ra?6n,,} R~R 2ACr[4z<YBi3@cqz Չ]G6&-#AJL{vhh4hzvwQeHѻChhK@e=Cd!PvA< `PE(.h@gH ͽ3rYDAn=yg,X~}2X<;1F[ %ۋzQٝJ gVFD:_R@כ*inP^«c,cbȓ.0rρn6cokdT fRhKIm}yٜz/HI-uEVedV/3#D]3v>;weE}t@F>ea|"6t8҅:x9I%2CʞD륁,N]9?)B*묋D%{f_s? &X~!B0y2XEe[S$0wamȍXHRmba0`&j8 "Č/B𢣙WeKf 9[@+f%S Jk؀ @H[$Y@PeN&D^-odj[NHCu,`Kzlcs̕Z ?:MqxdCDfi+P(s0i4fq^tGhh̊S ] ݩ:IYEwVV" M%ybljb@#3K@P)MDAnI00 8xXh'~:VB7W[S6,Suɜ߭9 $I&|ӡO MVf wDluCwC~v$#'#":5&#TtW_!=LH2{Mt2lKuxu݉1`\™t}rWˎj!m̲x`}%FPX2*YpxE2yS3FȑV50g*x3B#+/.ōP&3a~"ԔN&şvrʐNfzJ2z,+D9s9H$WcRGO F0iCM`a>6'į֖@`^F-H t(";f__?賐/5j=ІSf!Rn `pghjR#3+E`Ps ,+br]83f@DW&:K|z @{L)qT=wh3[[aެӒ=;ܱE%mCIN#^ Xbվ/M nen<7(Zeæ%a&!Y\TB[lX)7?lbk]@dGӵT>mX ` r$񦩇ƊVB&@^II!։kq~?)Ͳ5~Wk`)6fA0LtʓqPJ9 ^l?P)tCbY+JV!قa/jb #IS`'J{_Rv|[u۾4'qLE~'Bc]j$U"L8٩E"#ҀGɔPya81T o`AiuffyPw ^(aZaIʷPz;Q d9x]dɊPy H&/O9($it|?Kȭ@wZ`#>־E(Ixmrm@ 27M6֝GN{D@]%ECTpbTbinCBcl~$јp3âF"GbY,Qg.LgfVz(2sU^nѴn颥#QrEa0mqs\jl>v]'V/p`]inDM>Z-njCnaa㋳4xDK0G]td֔604uY܃v8>XV(6e7ەZ{T O_'RoP:S ,~ l~5d gc) -!GtVt;v̯f"=E$da~5K"/Yo' z$媔;;%WUƲ upFVߥ*=Lk0V MhJH,fHg1JNz:-fEFn{-DC Mƈ7`ue1i-A5Qp:Īl5>??tU}.)ގOTi9@"QyBQۅ P(z*"mmy jǫ}~;[ʲ]9LwB/; {b*}B+ejhVɭٍLE_ `'c HKXTZ" ((L ߐ I)9㸂ݲ3K%8t{e3\45y$߃G1XӕWv$xSR +-cΆ'Ʀ<\$or I+Elx_m@=& H.}".-8D|U $nHs|YtP(ci?qZЀlNGG)PS@"W5phЖ\;6gl_䇁VNsSiR{Y{ ʙx>'~nos^{n$Y3MdVV]ك69I b߂w$06sse !L~"]gmN1%.W^ RJ >3R.n^:5qENl di'C."68  P@IDAT) "69C6ЭpX dĨ qϔ4z. ɀ*!S^6 05p| 9!O.p4P.FSDѩ f9R"`ղ?Q725Hby\؂J3}=N)y_⾆ H=fpNvsh׿Y(HA 4TȬ B-/#g=:C2AE5N¾JĿ԰FQ6X3l])F!#ijixNj IJKyCĩ͕!LbO4=XT$CQo 7a@7%lLqOv15CЖ>}5$[>M&!]8N4Ŧm4v8 bJ1ڳ rn %W?=z0Ph *ByoZ O8L0)Aޘ|IVc;x#no1RI)JeRRrQۄ,`47ZNi;> dGouX%"};I ^8+:+"wȟa!kfQ6^@ Ҭ3O٬l V{ r2d,&FyDm1ݘChyjw* yk<:`ٿdܟGEoEq_9CN"m+mbMJvF$[(ÅxVS*Į1T#kP(rUCfȿHX˘HM=†IrK dո4bዡR/Q̚ΆiBX1jax[bk֡JqQh}df˝ yR.6j(POۍbo'i_î©%ao]F쨇'0ah0 4+GrvZdrs$ Ct8 1 @xrL Q0ZSRI"l9- {#S?Xk2H!bVv#e`XЀB*)(7Z%, ~8iq`*)+z}1n@5 ܎jVNA{pMqgMMFL(R=!K ܁AÈрzyyKE(-$Y;Sc"ʐP>eSOLe\vsW|ό>ý+>QbG]y ~q/ԍ1`n4C/6dǔJ, ?hqyoEDh LVx~`RD{!͎}P l~ms.uChÈY.!+tɆLJbsV17p)"ӖlyR2u6>7DŽNp,5znlbSrh3i#'r9]1щĊS0{p0w-©O.1q jVsқ!'I^%*U-KYa3n n^5brf+Xw6I?q8ʥ9CPp,=L$pT $Cm)lmdeF20{t_5q SߝS-ӹ>nt8j UCH[6AAmdøHp.J#LæܛA܏p||*)-" 5cW9󅎷ָ5s.#wG6ΆVsO )$/n'x`Sq̌)|}FRF H ʵ6Vu[]tL)09j:Z V ":'b.\IT4I h)e(';U )fm֋ P{Dhhk`>3݇ռ?!쓍A yq`~%cqV8cb .u PZt^_f  q[ܳo#)4F .Or,JYm+n@Oc[,i gpU~ `j3ԣ?ada X{y'o*hiҡg!m8,q}3^zְ8 F,!~Z2>ty6F)qΧʷ끞4GPRO`mІXi)>9RH&A%|(МCP|Al A׼vdpIIIFG#:Ykpmj!i"DKQ5?b'䂈نa|ʃ}#Ofs<;o{8=-nF( ra~ 5~.d(KzC*Iξ)F<4 &jj--ئUH5#>dI.w5RmM龢Lnui̍Հ{)Za#rz GUăL/RF.fMed!Z\DqX@ke VEe9FpZ<>+aÌNkrR٥X[?I(Nmz}e 4?d=`/Oͪu Ʉ*S72 14s']uK̛My\U*̾O_lQi8,"6$S FcvD:dNEn^CӝjhH3`|©Ά-^pIaT)ޢb!=GEqf&3') Zƌ sk\d ^݇ s6CqRtdZPD,XQЂ܊k*IA5wF* `%ް쐬~ Xx6őZ Z[Zo3TQ #.R2pQ'WLh \d4~ptYe>tJ"\n ߍXJѲK_;4\!/}9o׋Ԟ7D FU .@uȍy&u`5 =zؼMZxL&CȄVq٩*Pg&18ghLhg"sRz/pl O%Zo?bjyVGc)[ g8!9 EY{&hMp?ǵPa9^S!=hĞR$uxq{8/G~V Zzm%wrwej~P?Q c-Q 4x3;_O@ TX)Ŕ;.Q4mO@d-E z1Us}J܏, w? 0C'Aް=Ol1K< d􎕟kksp .L௣y X}Kn#Ahaum^ sUSeD`¨td۹ct2+unO,R$yNssc?S¾: vo+(qx~Z;u("[pu_5_WW 6g>g|Ү?_7/?^oZ}/"ޟ=՝=9-bc7i!"Ppm}D8GlDŽJtXInZ42ݩ'} nu!v;wuyG5Dtx x]ugf+P9/'xHA9dPD=VΊ"%jPm0ssmڜoF$>^q)6,UL7pQSdם-͵AڿL&tnxVxNx`ן?+O+τlx[mQ@xO`nmTf' ›"`{?/aӒɖX 7GU;&uHG®nA.BlTK`]" ;o p̗.qzP PpS7SKo6b~|=EޓyZ=6߭ `":j6d&I[Zs[sۅ@: >1-rr8:zQ8C)Og^r#6Vn@Κu;:1@*;G Y&JY[x ?ř8$ڮW0jFH۫R%frt8_cCQ$#|+ň>TIo,XSIN-P2B"R<`Ld>$ 0!wxс`gx0G,)1,j N6yyܪ%GUM0 *fKiT=f";  @s!wfWQ5{03[6 S3v^wPVm>pʣf}^=MgG8PF j(D:7Q Epk,1 p4Ӫ/oL9_ׅÈFK]?OԇI7pMcBQ`$|ip)xɢYQ!r x{xzkcWsbtjpQ6eEh7lS3C pi5dV-Ԛ!C@|o`|?( {UCv> >>XfS48pPM{="M:h3i5zv1Mw%5~ZdP;@ӑN}_P &D WCr+FN ]x+|qc('N`)R9 gn/ZuI{`(+}ȇȴNH9V(*thgȳ>$%Uu70$6654 esưLRSMriIߥ%ϯϑHxR ` F +L(nPG#(_)0q)^z F]k1ut^#RwPIE8?&JWp#L0 -8 SnuOR @{@$]4s]+aǻݒm^qwè!EO6p OXio")@CnZM`%DxoQҩK{,gs#*"CRD Jju623KŃP?2?+!&(˅옖9"> Ёr񲻒CIROXxT eCS8mN\C1M|{{]y9nڼfw8@ Y5WՆi*k+R6' a*6ThUxMI1rS6:iT;Y`l|ۋIC*GH}q(^3|boUIǙuKH?lv;Ʒ|Zd֔eZn56WN3Ϫ 7C.pm9@x LLk@HWq$ /Kŷf‹ 9JMCCzt ^.|-FJIco';<֗"Γ+rjT.;3%bؐnpHyXaZ?ql_닾>h1 %cׅNO!jk׆1nl@ͯEd8&-Vr>|ԇ|}cȴWt!tBGڗoQ:~w9UslO#RZ ϐ1Ebx%/x⻙ DRU_O/0)K+g,I4%eq_*\Sl;,s=;1V2 Ԕ-xBJ9QEVx5ѩ2,l#=:jH Kv8 x]c&fVlĄ$ЬCd2SRax-ǘ̏/w7:jۿB4监C#UzF4mi&!> ܊4P9wCVNi= Δ[J#r,/vO` O9QRQhaN1wu!ܞ)r*2oJp/qaK COd$684L*z@Qj)!S~t3)O?0Pov& >H,/645e`ńT%MN;_fAtE:s~Y9xTb{_oҸ:*@,ڒbr'a.)E)z*;>5 4!Rsb0dգ C(1_RӯN* J&oLؠRjkP%D.pxS`pd6 ^m)%Y "W !72:k޵F)'"W8G;"fm۠OAlx9D^Ô8 i<4D (<ܗHkIGU%Hr\Ws8t0;^ #Er8ՔV WE>?(^J/V }T)U ѕ 50e(w_޻;Cs R2Ml1QZ D\}DbIg=ʅTo`4R]aI|^Q qghз5`uD*G&cZbtR^ϗk_&w 3Gӎa**5GJ55lshcd.3$:# f4@vd!/`h1OGw0]PY5קuj㝱*JϹP b}ARï{$c!|1f]{ap<n䤾oQmt׷ACpLkuΟr'S9|HTQ11U ^/M58mwjhbPAvn?Tq<֙!yՉjkἲ̑얩|+G-?լf$HI~ϑ @˕5P5Au_A-&0*hqo͚%ǣoiuE!߂"5f9.Bezb2cDz`JLYL!p1͙7P2fv-FhE g۵mwPQTd+e\z\qBX4bO.r]a0Û0=-LH..kqAݡ +M,$Ne$[&")L olbZ򖺹^Y`C"D3 $W)h {fhA.쵌d4PX1$ RxGSZdi4XJӶk& FHjr_2c _bw}o0FJ k.E$liS+1}BwS< /꟢/u^U{лOvG?@/׍ax!K?ژnV UgHWQ>s_>h n``)?>r2\F*^@É$^€WYE 4O m+Ke0p!Dܬd`)/`ohJYNbn PT si9OMhL8'?LTgo [m<^0<Y~ޱ;Np۪͊k&c Ĥ^ MH:|oOAYm7.2tw`k'6q,#8fvLN@j*HX/=đLJ*#Ъ"0r4B"a DmSMlcY!84t@p[g'D($Yڧ8R=MfiE`ϸ?2Ia@>äEǤOj4K){x.GJI7Nb/ M׭,#ٳcnUAHt3s$!ZeJ[B0E # SHV1 Ce88TBeUE&ͬyQ:6kogB5Jk"KUr{xQp_ _ C'2O"G]HRb]HA bIP Y ?JE&0xm0Xڒ$dFT(X Il3f{Uӊ H!öDSA@]ԡd lYG@L3A"Tg/dy{lmK))IgL)F5p8p"3ero0,C@Grd œn}Ll,Ze3jxTCi5A텅!,OS^-\:4T{5W+Q{s{$N>U͗=9U4(dHtP8 _2̺0)"&:l!D+sR@V5{Wy #OCB"q[J{! `uzt7ԮTkȀR005ޫ=y YnT9$+0hg3r3m$~\s~xj *Oksk!1]Ÿ-RcWK䤆֗n;((mTz|Y<jىAyZЂl'~rEX&kW88ʺBSc?)Jxby&y4FJna9@՚IHV%UbVx~Fp]PRI29AzxGJ)&\ٟ,r:}u}MeP~ kYY,ˏI^@?ƛR4)ӎng0&c&%B3/xaI}d\JS^9?r>l%|5 >laFpLl~3p ]&O9t$Dxrz"ʿ&1Z]5w2unʕm,c8K"j;ˇ(΃_81U`( . NāCe: &Z<kzAmFypsɕhE=*K!Kr/S`y (v\Lqzb^ !❍8`DŲ Au`u|Nf$٭%R(0u|Ub;>MmL`kq1 R0s6p{Jq~ wa1ZԇJd}DS,qQ 6ѣ` ;<ɞTh\s8Ҭ%=g0,{n[h Ѿ):CH+}I+HwU ~-:$դ {DV8FSRN,X@ IU `4JJecG11`n1gl8b0Y(oK>cWQaiJֽKsyWYL[9͂dV|*uJ:*o26rHc!4ZY,5 <7hjR$rGJJAL|[:E؝.筥R Pø1יR:e,я/͜)+-M;b\8ƒ^V*Ц!!8iۃQ8) s9%?Is\u(yBlRayo Dl:lGb0 0˴nNώ.p,SKt1>&6opTJK#'8|EՏBGGY.x3KhXGMzTSaS˲ ~gDSe{7gAVI"сP&plZ]HR""ejS3^iH\sB ݰ~<b?ieoP )Tv w>Rns}f]SŒCi ;ԂTOzn'Mn-|Y-1wAҷB)zS`,=GjjyģUmz?9H<)F=&mo% +a b`z#y1D/fׇxVDyM1 ȐFVޤ]02vYzoF*ᰗJ,HDogt'g*|xIb+ SBr &-w3PFoG9޻oNjb b#;%Gҟ4"l/znZ6.޿9{g4SyW# &*Vom_@ywaJ?SPFrk7L£R[ 5qiiQ"U9`;DiS9B́r#:B+HwP'YոU aMK4<Ő1XVİ|B͂qwGٟxyX^w+(cj*I,㖑x \[K|^,w!Q`BT'flz: YfHKRzFR$cwVqm7F8I,Txo|HlcNp+1w0 E|\桒2}~* JsTaR\YdSUC:l?Ic8mpU sqHLcs,ә#j:l$@Y)D"K?[p'5'rlsЮ1̲>ȥx܄PnNR҆pP *WH\re3S&S91UΰyBA_p$TWTT v.l,5 ]Ȗ6yZ0lnFL nGzZL{1k9rԶ* GeBVG59p7[.NpYT]N}`.;Fe"\,R|SL0WG3*!͸S# \ )4?g+t*e}/\WζkM]`?s͓կ퟊=5eU'u8f2z>y~T^KED b+2h^*b\1MnЌ)H@G[0ԟsJ(i7^ʺsE9ku=%ԖAj=}VGe|z&^8[yab9G\OHHVl`]i^,ݭ16gH<yiL5dLΓ@CT(H&)x&jV"d{ !&~ޟ.̠%5vbh.P1 bKůO t4hzM$ %Q-2_@IDATg"NCHfbiu̷JTy8F 1L=EKF@)9> \" %{ծ &Pnݶi. 6"aZB-oc 5O7s:u:)s>UC}L;w۝7g"۟8M},Z/aUoVVT@\3&K)v6[ @v)SZo**mƓڔ)j̜4Ll3x'Mi7K&1R̈w˕1%WU;Յ.uJ9.ГT}"^"  LNaq-eiY5=;Eq\զ]% d4~L(zMd Ԝdb-3M@+GN)ɈE}vfM;'٩eŁ2>vjF`Q`vԄv6Eͮc+[([M>G\J;@@AӰ26C@ 3T#L}v9puDEU8ZBȟ5N<[@ZӶwZ%h9,x_1z4nY#p4h59L e(L/"+hh"M w*clĖGEqReAw~h 1)pIcEin DF8GHfϦbx +`JFCTYQ;3}Z_/R {@5NBI8prSh-K$Κu-^K֩4:c(>u qIJ5Oɣf4/u?| q-ڋѴPF#?8ȦBBPŸ}vC$2PU(EqXǒ:`5v;;C9L,8pXÈ_#/}>'m4kfOLuZվ'z_j% iuY&\v2I{hO$K;?+.!OOӃa)*tcn[)vx*Gѫ80"%Cxmaʓ 9,A癏0mg59e`=i; hx"C+X[è>β {qRM}Bdtӏ fTN`S3RƉp >/-r}3q)هSau` Nuw_>wc/_υ0v["Y_m/d]FgGӟf+oAn?&`<8g2E=(!Zv6mT [`t,_~dsA#a# Y̗]Bpx=P3,=S91*g:ȍ=De  @FtSS4sL[P?QfOivH^7644š 8'߸|uAA}ȳC&vjT|nVi>L z]b8U]M(Bf(,AeRRdGj9OeMx'YB{\] ḍ IQlbpuyxl>"|?M )Q(.i_[SЯ%_J x)/hɞ?GJtPx+w ϻɠ@ML7]qINq`C!BnX#zuF oejs%^ՀgGcˣ5nda^ `sӟͷn4cɐx2 -`!`n~( E#\Y̳=-0ҭ^gUxmgբ2b=PG Z3x՟çW,^ld[`L ^݉/#vq B/ƴWA5LE2d*#j؄|6H Vţ2&2pB1 ,Л,/2~}ג|ՌdBRw8`4Awe|̔fn~qO&,\m:,ltGMQ/5n$aALL&qRD΢)15 Rٞ_-?0aF h (=J F'zk.+*៽ܑVXG9ijb~ &צ;oT2'Ն2yRy !0;e$JrZ. o]un(2SY[Uh.Yiav$W_V x*UKe;{9]*pI`;1+OPX ~ OG\3#kղBm7}T`[g0pk\xOZ5;4NKӼ3d}вb<i+j7vBA(a=תC7"ad~7?5h H)M˨75HZ}ےm!ׁ1cTXD 19552ٽ >q. % _ȵtD"X( q@ r9y~f- q|Xcx։=H=6z@~0f -7/B1XL)6c=}7dKYw%SgSm$0e|<-} IPN6o4@bWts_ʘ2}ʄ= @k@AxZ\3߳PǍ66m<Ii婭n2Cs76n^Û͖胨 pnT "v f-$+q0!kPɐ YQFߐ0Q Rc*͖"</(Iίzt 00NG%sgb9j</%b5) a4a`Ǽ;-0ރFf^P,7zy\OǢD;tb*U3[njp^6o:^PXtO~j 8hA/Qtksxr5cX(_#<V&tͻ)%aFJ&9܅Gؑ<Kʣ3'gWTaN0p}bwirfk #mJ:Qҟş929PbOrp(j:ہ7B~1nkXe۝BZ$%YerǑрhs2kobn0>>GBc*?b"mϹ'j (b&)-)OFarDV㐻[EC 7Oߔ9(Ak.pceMyQ3a<]G^v{# hOs9Qԇ+zIp,JJtnՏg#Ey`Cg}(eW*O&% '+JC zS:xf FYh慽/髿Gy7@xfbHU7d/8k;0iGBSo04.  ḭY-W ނt6|C4ZDYH4y61$!0:BH&ܡ^(1"U;O@ތ(6voHxdm%i5 MbޞA2!^%2q@wvw|^ZV6x˻Ÿ4x>% 1'WkJ f,5 SV=a3p2\U.jǒ)Wo ^?&0a\Jxr)cp(JA`{AyOBru* Az%&SyITp xxPs[&;ְن)\]f= 7?(F94 F5eQ@u,-/mp7$;⸅y X]Q 6|\%F M> qm ΆFg )c yoE˫9RS@ 榲6J_441AHpv+LaNf##,dhcI|ѤJyRdpOC3D e7I1+&c`lqkBc?IcmSӌ=#7EF/JaB`1 9 MIc"T3HrH.W!U||r#180\6t޴bOsބVf#ff=M6~C܁$5vH'LWS4&8S?EYX7shKkezOvSv*i)^UC' -B@ZAft0cE/ Y}Y q3is|٢#/Fݧ bz& ( c- a$N\ bН~8|}BgMPXqL:a`"8* }i 54\iʭ eh4ud"%ӛi h_Je2msi660Hks|B2+FghAgLGE _oZ1n:*WٖA+[F7į#I\S]Մ&e7X[:t=-OBy.f:-1Bu=S) a4O:T_=ǘ6I#t1DDӺ$2i *NA/r" ;z_j*SUf3عbR.q :L |7SrhQձ}ؑq:*a&sbDɻ-n"RNiNc_jY:ZXny)5RyǗIz6sVhycBCRymh(Fs=-a!4SU. ^v.i 6E ~eRoKY&p[:P˵b:{K|++b"z 43ѥD>mY^9tͱ<^(6)Z[2!}֊%M dž{L"tXb (kN5n6qsPyk+t_IC6M X*$'% &ҧӻLߜ^ о}5a$k'kwga%3X],"+S97bZس9#YQЈP +>}цe+$h^! C2H9J@YsLpӡ2szg b7~!8JG wGLNNҁv,=ϡQED# yYUGK-t{*ϱgo-TvŸ@vmU}oaYޫQh bt>/$C~2zr"):tZļJCqg/?\m'uly`J*~#zo"^ZfvXtK2F>Ǜ[ۃ9ѭ/):ay jԲ oo;*:W$)LIL+*/[r{%EBS.ʼo|edC)-sH:'#O)eŚwބ <`hf[ krOkdr^ăK MHJ;vHTe%!ը ?|:~KRua75V@я/J6WgН=޳%ݛ ?,l[Gcf#)D<T!PjG 2J,hM!Å3ʪGLr5}z+Ear!@|x|k$QѐEٔ\j^ȉHu_(1 RuOhyyM1i@ViԠDr1ScqXc7q׵/e0Ǘ` ohqxA7fQ66JlQi?N2w -e/aIh3p؇4VўծcN߃Z =+P}؞V9V ƘC39M#o^.fX$mb^w}~v8^?!:Ǘ\5jII6"8*|ʜÍG3 `8ܝ?@?iޠ8-i,xMv?Z~:+@_l1NAmj?,pi=k~ Y nCSDj6[ޖU!.\/A@+ֽy*Mץ:Z! S6pNsqIlbm|6 D&|hԴa c36PÕ>gns<,}r/#6ٹ6]p{E^F0&J"|,C||Jlsga1xSL\)<$(E$1[JéJT*=.3YE]qj+`{漸y.9h7-3DƣK9}fp>̔PxhP5Ќ Eg *gQFatlanD+H(vMw6K)Ywk;AbR_[=5 `(-֙QU;YJu$/Q"FiuIBwfrS\I / :]BB<^xg Vj"KQtjZwc*¢1FH%pY0I1Ȇ o6t6k3얶k Җch8~k1g6O)cz|Mr/10Yyz=UzH`^rPʽM㬽EFF-8]S<պgYjO@3 'ywD䎄(=QY0S~y)?TNÉ'X S2dckH8_y7w9[>tZ9]m];?L!CrWxqx7\7W~<!O-}6!\uLr &8~ (AcŁ-i~eX]ߑqG?pt<ΚuZmXt(iR @E@a=;#|ִLFl%yqQu`}O G6"Ućӿ/?Oqd')k}{QV6Jf왹/ j}bhAf9X;Ռi@ HW i֘̈́`G*&ŃF<&G1J3w& c'aXYGx: 1-ˑ>/bt-P.wgMOEe"VD* CX(/蜦 o0j)v;{:j j~شchm;~aDn;tא:q84,,p p2zX %_mb jCtd=8w Eښ+-5SZT{V_ҼEwFJdΆ>4 ~H {dr "糃ԧB) hwXMñ֍ 9@x1sCW@L,0_dؿ(>o!6JQWTE[m3 rɞ,BR(u9b3dFI4'  RE7Rp:ߦэWQ!x4ō5Rh[yә$ wDV{Z0MMA A}Cw\\wDac{M (nif3fez)Ml d[yȣ)(uZV^^qtyS0SKqLJ--TQspL3օ4b h1gȰ%)v(I{J?Ç2EɳoN݄ɟ{]QШbq7x{>رsL~'YIeef:)<G՝47$Ad:Ho2I󍺫H$l-` $2#|wVXL6bzVTQE?/{ۺ$u Gh 3V#xV9gݪtjP(cIJ̗i {sg[__D-.;^ʪ S] I:tdG/e h7 (0<=swXOq&_$Z/^Z`}vvD˗ D؃'nrpnmc{շ^lڐ $\3c? J!CqN:%y%$K\㘉dlz1,5 KEzA,NKci< |q3| ˩dW^0S'"$\$&ҥ6^>p~ޙ6&"DxѭZXK(GȈhK)pߔRNf,xV]@2;v>-$R֬Zj` 1W7| to3j2PçE6sN5T"X͑-c*! An*ڑAoi|A[kLj5C-gv:&†EMs_%s >vپO$(IKḰ̗?Fqln`ǹ ܚ `E)7/d l)b#ZY]>Wf=QKaQvTvz_GC 0zsciȻ`@,AL0TY֬|z?&8Sf^G$44@h4"|%e/`ECzJu)`~hv^W| c;g:N͏^ Z[D5.f"ㅈv'Om&t۶zLΑGa }-np%U_/LtJ,S#2҅Q:0r~1ی;*?l?߳|rI1x8]㙿4;FW䶖 ~0{] <{Ύqap/7< 8EcB:R:ҰYvM#m`RA ),6}x 1W<L'I9nx޴y/ Y0RȦEۈ^P-G1r^#mz!'xNʅ-s[.mf.C m&Z K=+)|\+l‚Bw T pppO[t-˹0DR Z!0BQsc[˸tgH`6Pk)3& ?kk-]o j:5(\kŻTOJqM!1z mY&n&.JtjXlN?, +0 S|2_F`Xd2 gL2uQؐ, 5AYJ)|swђgC̗M jg{{cv)dpvET[jdbm>]?q1 "֩LsB/sj$C~uBOQPLk#Mtbw[f+(X`CZP+Eq=Ы"tl~ddOFGh  e}`}knᙫedyv易#L:ky4yen$lP[fmx{]UP̡?afQ! |%YzET\䪳nRaGt4RQDY_`; :#ChX4\4OSR;Zlp =Zf]H!|JHGئ/oV˨*&v'%4k€z-c1a]Ϡ1FD^v~{W]+5 d[𑪖E;XЍ-'F8d̀ฮoD)E]^lz`x؃lrak'H}_>&O`ji`7Ub+ CN, d*[ DبU?#d\_@jƷMRn>IZ?,&V:D. )ɯ0D`V.vsa[ 6>!ҡacRI[ 0q =a%)9ǂ2:Ӑu*l̙k)ڣkE J>\+%h4n)uN͢l>H.8iq'S9HbɁ+>ߪ.p>9d[i-cϩ{U LhD)>zeX^viCh$HH'C[{bpJϬZWRlUQ=Zl:o`:Vs؃*NTZҝ.QR )SqqnlBJ!Le%qVep׿? z6n)!E./T8mG@G_(0~4:3v|'-QW> I9;不Ck!R1UgEL(^I`RY۝UJ`YU @PXD+=Yh6_ÎO~-5"Ds9mR.AB3Z%ܘ6'_{ ȝy1=4Eh V4h${:zm իU @lF5*W1t@0|% RRluiyf@th&|~o (5|w_0aXGD;@2 \p[eH{LP fUyw`MdH0KF0s׳V6譒0dv:NTcQ$ 扔rQe&lhmsrn%q:v z7MWM1a 6u.3:' Q;=ٱ2:.rjr?qa.Ó3W3#z\@ WӮ)kr #I]f`J*zAY5WZ21v=?c+Xahv(}~vB/ܤ{i[ Уib cZ!{l+&XV& DuE1?Q7B&@LÚgk.r|G;Ս!j$u3DV9y璜C7jcC'_x}RW`)/u޾I}0ZV}İ2~'Lb8c9\z)_6L0x:8 ] }]V=/1cN4u'NY~xIe$ܷ][l[0ɳ{[&C8˄p"wwRw{9.*^hbm48{g]Ѣ WܲT;$prBdc'2x4gVz}Hhl^a6&2!5(?htsyIf~504oqMOoy9 {4Ӓ۟‽PޤhP(CшD„ͻBRg,[n$v<Á N=Zd%}.(^]&t;sІ]zGT @)=^_6--`=nZ8ɖгzxeEj9;*gAĕ@ʱSۛ Q*?ڍhy^7 zJqdzLNҭ $ZNN4AxE.cB+VbF3!ֳ1-q:^IہǮ>mUXy 9v㍦.eL$ϵZ@G89L."H y8W$Lm"رHk> ڡ;)glsؿޯ)xƝrM@G`v5oe![ʠ6MMc^YhvSTX|>ޜn ,K @IDAT iUh0'}٪EwkZ2Z$9N{GZ@qha9G%/-PLzv 8{S dUˌ]X\=F ePYϔ9❡T/(8n\ތVޭޔN@< :JD>6i_ ͎ %2 ['տﯘھVK2v61={g4=<^ lVYQT>bu0h|?)0On%_B& ZVJέ:ȭ=%EBE 5NKW2$oG{' WnYhdS-6|.%ZU|E $K>l{=a5 еs^)mn^ŭEU&Atl! ;Cv\FEg0 49ܱo|*yy[-q٣X#y[Po"L9vqFsO7r vB9٫<$4fh3Ոc/g2x F>Ɏƺ[{uX(@V2o~sw^gV) ~KktIѺX~aO:;b~__7ߓ|PIäD(bbHp?ơg2-&?ctpu FrkS?^oA\0cXAZHB=fHJ6T|1")"fJJ2j+ fmcFG"\[E#7KceeK8$A P%&O[8'Nw-yۋL!w5,_`ۆ,YZO:ſ prk,TLLy^ 5F{@GK 訋0WBpܨ5,QvX^],"nU̕+va d ƅpcC5#`s:5ǻ 3(=60\:A1 댬{^>Ez@\fn kc@y{d tժ(̮)ǐ:^hjRGih٠ DTCPF' (܍&E3a빖_8HI#gƔG<{Ss8S}`|pH?}B&bceB,9D;JCU8TIM*`vdZ E4Ņ/44b':m0B8z1G>W̻b1^uGǞ8"j^.4ץx2]S4:]xiY`JR`( 4SĬN0y95+:ֵ "a۸UV+.’G.QY[oQZЖ!4V![Ɖo<ߔI2dY֒-"i*0Rg%fn "qI@S5oNzKs f7;e^ uujï+uAd&R˅MP3GͽE|TA!6A7D㌋^iSZo[qMĂ#P_OWC9cq+af92']cAy\)A27 j̘T/T,CG@f5@.3iᰚcm3ޕCȡChd[#*|=>BشK€I9nj`wY#m6E&s!Zj/kNseNY}6b8SzS.?Y@y{q=0EOSkA5D<̠a(l+Ɲu2&+}6 {7ڪV? IOpIO355K Lfa҄xEl}1N@aYPh~T炊8R  ŋ {@kpWCj 1!V6)A_͆R D5#dVퟣAyeHw(䕽MRŸ ͈4;a}`fv@TAzVp*/q1ħ7&i=ճf&f3{8BYX ՏΊ{09HA:2b[4quqXN%x.,/j_/K#jՁ\#)Gke)ujD6ũ>ē<uB9 ΋q0(d_zHS ; *%SԖķzo Cw60љX~$)N1D#|00gu [%=8R[2nɿ_1h')}KdMHÈ$"4-YUѸc7\jCP$v؈S,oN(+ؒyԾF+b q` Teh_UKq$ r*ꤔ3"M& X 58?a)lwi:xrgnHD:*vłx#C` {?Bշ窚 X1⾢pƴe\*,GZKPF;<9d)tb0L{jFh3/z5}l =YMaYw󲾘{Yfqs(]l#7gŞ@_dm:QurK۪'%7PhFBŴ|n (bU+GϲhF!ϯ/kaJ}Z YhGvh&f2\E yHkfP3N=32L&a@W͝J1ZKH}NӴ^;fXdOANxB sI2VW̆MkШ9^OÌ&*nqej8agS]f?&[G6DT8ў}$X{)8^K'XT&)4b#_?6(Orp>feŜS)h/M. =DV`@lC’ZfWX1 F4ɪ`.i@)I=\ä 4UCɦ=l,cTYn}~ -˨Eh[& ߴ4Jz} G]']## Y2ɕ.j+>=wEIzͲ}3z6}O=L D6Bf3< *$ ff-Wj[7Xix#s15Rg(ZtL%,'u?^UH7uNW.5c:T!4R)+3P!OKv]EFۛWŹ^#.H<<ɦA;@L79bMN1 G Qm|).H! AAn_3T=dk4Ei"%/VA&. Ʉ5 4PnU@}qn,P'7/LŇ}Ik B \;;-~ Kh%Xec6Seܝ&כe(xU4SC-4*ՋP!9,yaďsɦ8ZS?j f~x *RlTG:>N,Y ۪rҸ%F }q7h:iw 3S$0%)3% Wહ('Ǻm|XO[fD *_kf~ 񐑝9R1Kچ"B־C:]DʺqMY,K<"D)a$o3wzm7WeaEO{ ٌTԗ2G^!j#Պ96n[zf`u1؉ik IU {5CEX44["OzYd/&OלLYEaD̨;&8Ogce }:Q<|S]B)ιYLD)IrU2F MFƬpǿ#;J^~+C'|qZzGԊ~ty Q5Y:L!:-E$3-\ d_cYC<>anŗv\܁L3yhJ:`Tr՚F $K԰#_)Ce CK󂛶K-ju#s 7;IC>2Ü'/޹O{%Dhe£RyP- FfLި;39 *2x#',ʔm%@ht.x6ZC9aK ?=.xH2d}<Hے򍹺7bG5JٸŊQ%=fZļyCY#z#Pc!;Hܧ bv4-٩-pgqyM ׷;SDW44lĝbT Yfqh=PKu ~RsܽJ UՓA+c6C^@2]lr}.G#ͥxz{bk&UЂj/QyP_u9ߩl{99㶵5ZUn '֎{WXʹ.:l׃8:qHQ"GLAjf(&GgAXboap] %k)aN4o^!sn-hf7 ȎkD^`=9LHShԍ-X[n1G(.G_0NZ1CNjrSjZ"6ibֳ 1V<8g*5>6Lc&hOI(Ro`fQEVWFC&m8$Ύ{mL~r W0{Wxا޳"H-Vh1"%Ct.覧QAMÁҲiS@AHSVDݷށ݄ ^1!Gb=ٴ[PCl5{CiZDY/U !>Pb(3I`r)Q@- \Bcִ@}"P P, =nUIl._y:8JS9/7\1Ýi Hm]SeY |[ΜIȟ u  }@8иk)#ErQUsckR\8@u]9ss]#ɡB n9q(r'0O sa܍12eSR(\ABSI/srl v~LVPs)Dܬ4Ldf2>L;"C7fgZll SRJ4ͤC#ht!NGDT#QLͻfNX>=ّ EEvhtjC52v0_L[Sqw (ٙ$|%TAv]w1ԌPyw[{~C%fq>:إС H 29!mUşI ~MIt}=a Rs rD2 X*j{p:Is5/Rm/ZPaƍt7}S $HMPrm/^ta`219$%#b&:5hAƀ= clu:>YgPpj[OG%%1|M KB8B;2}xq#4+Ekse8 }ʆLdUE8"?Mta HbؑtHdp o۟X}S!;xHiXc."i0|z{:Sp̨mOH?$Q+s-ڛ^0x@o(U ZFXe0CK+5j sF`^mP*>rWkEJG!>='>8Iq, NPh8?lc)<D( m&YÑzf,r6G5&2:1'%FV5Ll2bAKxiȀ65H##/ z'Plp|Po6_U\-0;Sµ3sl"8! | P FKXmY$SAq7{4-)7CH0eI>3Џ"ffPLC]0}Ӳbh׳/cB%W6(=^jThkOc8@,|E#Ggpęl]Rg>CssFe1RU+EgSpBXX&[+g<Ken+˖'ǀxX0򯯺 O/E]gfXQV+TMe6~C '  >u"7ilsgh"My΀#W v -v;r`2eG+"~&Y3\FB1I=̋EJey)D$l=FCa~2<\ <- SL ,sg~N yM Jܟ`>8Ѿ͇hXD )r5FCx$^eb>sbtM^!d*F6CA,sP$fU֤P 31oEã׎a-*Q!h)_Mdѝ)Ia S =7F Th!*v3=sO yj&kϨCwHej((KFOEƠЄ{r!HHcEdI'97mh.o%]׺AݔDj.Ȯ=[Dis Z9 %7l5ԒM5!1hzU1iKl ([K p$| 8@B +y3eV4%u9qU|& IDj);u(B7U%:ldF<EDJvϠ| ۔.z;I쟸$h=~QV؏0"̅ ꈶDmo' A ML1w j \\Lg((>Q4iWE)j=}Gh}N&ɶ(_[?fAWH}&&Q\Z}+h榑/S SHۗXxD|dY13:'I+SSp Cqe|`K3p4][8ZCQf wutUT)uCZC ooZ&L5" 1^h_5!I fXOo%P#[ L)j[_iB` 5&}Af7$T;MSTW\J,4L4ۆЀ-( kuC'%\5 8'jZp! )s% 1z9~ҠQ kM ''ȍ!j+F +Ugt7u69uCpe'dY:-A@G)5lG) ZoBAxabGW,׻hݽ sϧxB =H6{4ďz#@ RƖL׶la_g>Dss3_oߙ$ , kazfi3c?y#Q!a]Ց#x$NuQ"Q1e'o(r(]Xzpkn)mSܐ~1w{&I8yK#ϫ%RtƘ(|C Soc wljktt됹9!vf4ybC7VYQr (I#<\eSlTٛ13M l1}NƊO$,A9 3,Xv)*gk(j<5Q)sX"o:pBc6z)FFS~Oˮ23(EHZi$+3t  =d+GfI?rd{<+V]ԵeuD =?(q?{\/}H24z5Y YZVrt'(elbӵ'OpX&8e[?c {ZבVf3Q%Qg:,Kk>wo/l:ƷƳ0Jrr^9=&Npp3 @v2w_u*(A(rQ2A8y{o y|{k#P7^o@<$#0x]YܞlIhNT^ W,Lo;rW\1ȃ}nVb`(2]\@τ z= h]Ӝ>c$Z{veuysL\"y=.c~Qz"ưܩBB!\9QI+Qd̠ڷ;3W8y5D4K1w2Q5d *4tHsjҴ 2>-c$h8֍A^dHC+2&ҧlXD#&fLFĘ#7cFLH9!'/ui5C\de&(, g*.S 2jlGak30"  rSAɢs0_Xar+Bh*Ad%ucqlX5B802 e!} H0z?vf#WxڂLV|^M<#j$GT~J@t% PL2mmؗjG5mlCAD fz48FM }3Vԡ2MxNJxSzT5ti-hFN|' (ƀxu=ۏanLgt[ s Ogr26Q>tBe89y_qFBgѯYpj6;TF!IFqs)b&MmĄE"nVE{j Ջ97Uuo^t0_b|Y.[EK /ʅIsOx1xx ټ=΃4si \NDIOX$ՈV%HKW@!C0c%$Λ'H] ><$p&}|C?tT'#B;֞, DzdPEg&2. ~yDSdrH NPW_^1$"D0,*S& $yfN_\{'Eerzup:ΆdL4 rA'^n$]j q$J&@þ+(5v>Au[^ji>N@| &%s,;,CT!%i:S\ʤ˸ybA&xcI0UNi[Ms^TzWf )^1ÆaB; i {)IW!3D:[fB!-QԇWo}@TKm6LND¤;uug:Ξ{"+D):.vܪIl1 y;̥X^bE7h讓MhPa/lu 9K/F>h9d%/,g*Dͱ\4KsrOlKyŘtXPyJ#[F=('^@dS4аS3fȈ1%S [=(SS. 6Hrlj]h6EǤ1MH #gsqzy9XQ*EXNO)Ghѿɰ@4`M&7( fuuq(X&3BM Q$-PG3%t"i) zǑFݨsI8gIi1[m>i8)TYTTigEgc6|[-alI-WiT.uW@EAtǯќu=d0.r#)e.A#m.ss)(>I9C7օ $#|,tGkK~Ֆ%- &1p2l"Ƹ(8gG yWd&V" v*_2PnmU'%e\H@vxi|.r4 @^yw 'xjj0l)ySh>xdNʘ=NBÍ*2ɢ^!H/ ^ި;{"ݭjZ"@'T@ARd#3Z^ oGdm"f)xl0,> ƌ=JW1E_@L5sI ok~ ;`r4ozVJs>0N}ѓ~o-g\(v5e{qBwr*,S?w bBl4RM+MUe|S2\%MjRv<QYsg;N @.d>6JpɎC)q(svU{j.2@QnA#}SIG{SL%/k b-DfIz~̄[ D[".Il~.k5{#.5:Πs^ 1@7y"S5-($6bCV!GUskT m*F@IDAT @!#, 8ZSBƠ/@jicΈIA4t틆2o**[L\=6ruLT9, V^?vZm L3f3ZCc8F=[TU>UMe36ӈJq:e8ًol\.mEWMeEÑR`qM$=-S X;(EϿCgS~:=IHՑvj*hu%ӸfAu{|e"EƦX]m/Pv_njlЃV=a8KE+62Y^&a.5] K#coYQnؘ5OˁߑaR\=g{.Sܢˮs;'Dq B)L}~9 GQ&ӭx|U_Nf^D?.2fz'a+I9T_mv*a `S%qNuVՍhHkNFn'Ap<a^4\#b( ǧIé$GGƐʑ_*=SwTݚf(ue89˜Șk&~r@j3 BcCJ\ K0dFhqqńpݼm xckztz&br94T1 Q8S2]# B5_R @d5UyjCGZ/ḻ6jYl9lW#{mN䀘3?)(Ň2I4>jaGoFEK#4]I36.*Vi7CWAih|re {+@+2mg3VC+/\07UYuCIы3rc]U?Fj̘m`]EЁeg͞UckbY ]|r,7+Owܡc/_.[X߯n?׎^0D3_ј_G~Z/8#o7}wA'(=ejoAEr#,@jl tX&?KW;IlPk(^U|Q1.J|JGoNMߥ۷e0frh~ٌ)%OLvlT?]Zxd" Vs";~0{Ӧ?˿^Ec U#)n{2VqX_΅%7iac/ͰV͠ R(SbT=l"%(蓢_b6p% EQ m1n4SN͵lr1S+|c솂da{y#FE_%Vƒ)4~iW71AmX˅] LPyF&vʢk˭UVK"v$i~E1t(Ǔ7yLR\}`=6N!2}IƘ*CRmY q֙!NwFڴq0dYs,se\9TbRfzq 6O/Y0B9xhHPa JJ&"eRdx5!&{eW,p4|6  (ivjwv~CFlш#1@P*̫ $6!K#ܜ>g6b̅-, K"v' @Q;݊#j>B!3{yTA@H" I@W9)AwiQcȧ^ v@ӚCVM4O*^Nq==C!# Zt4Ǯ'ShȚ_$K0HЃ9jO4kNRVl7$і㻇ot?tU:_Hl6pM-{ؘc@xPLn̲/49muРڷd4N@)s b@m >W|![%,B ,("78ʲJ6/w;ΩX!t&yʦ_0m֜VD{T eCye> RX,h,dڼ'6NL& uB^w k&=$AQ9O'M2l" נ Aj޶)fw^T~{I^jrk,)P{\Δ"ЈKyz 6[r>76^_ e)E6|bبhE1V$:t L]b&9-4P2t5XNZ3>>d_{YMR%u,H{8A4t#A)EH'Nj)W{%-;Cf3/I]TАR9SSU7m#NAAG>2Y$.uNs=%Ҁ`T8H=ER(vd>QV_N~:o36 H&LxA= zrT29ǁ'cc,!B_;"E9L̡bHFϊD |FzJr0p,E/y.ס“WzU*_PTQ@qEXz# }YD2G0?zYUvU!?Cf]JEIFcйuҜ=ۀLOV* KIx M-Nj7\;b6@_̌Ea)zzּm8;["XàFbtÅf>} + z(T  d<؊$ Rs"ĭG/inPyhSZ$Cuqge}P7}Kℌc )H9!9gi Vi9N%'3馩[[*/BJ~PӇ [}yqYpG"ʂ ?y*?Ӵ[2f@{@φ`!{T6BF͌+=+ՙER{Zt *t}K%*}:Tj[5pk{HB;Lj6aHQ1nwX2}9^IΥI%Pߖb|q`ˠ.(PEֺ"}i;"kK`@"Aq i#H0\M^ J9\\ы8FoADյd9k2HAൄ?ɨ,(j!H lݓ=() q6 ^'{x0I`` fBxO#2:ƩN0z S MՖ3:1xDe4I667/yIt᫅ꝍt=*rownR kzJ1lZQ)\MwQA"ҩS˴32B"n.B1QhXtfYa>ݐx%]et~$kkYj@bd&`6>"ڈ$ 2yw0\'W3P `0 Yʆ1zM)^[>l8`ʍi<%%wpЫ1gduR] yfu1 IwL|o37s7-Pe,q{\eRҹHkcW֧iP7 'IJD*r${6 ӾnmS˱I C Age=kٳC.~GJN'Us^mDLt[ Yhb(#?%ϤKuzT%41ԠRgE|dE܁y.]I4BvL2)H'p~+)³e#P%aѶ;Ax8NKTB8*ˌȞ4r˺iJfx1|G=sy:Xj9fSi>J͋g/vY63!j'H(by|öhjH".2Q1bS"ԜElOj\{A(s #Qm!?'X̯gq+g d [k4=t?lHq,_BdXp%Ѽp} 5[]VYApm9z+ͮ#_Z[(*5&V-lƌf*ƁfBZbTnc mX]RAnȹVnq[N)'GeMC#;K 9 $&%6Qb覴H1c.4 TkZ F N^z6xF,(8уǽlnU Z&ʩFN#3)EW*sIߏb*9*VB"hJ&ï; X\Y [2WI\c^^10(K0.)Io$"F֢AHL?E8ylZ28,y"e~ʖ4)*qZvE$w3 &\ uHIrl猒4-PrW_\6<# ⧑czHu7n:Ow7q&[ڷpum|]Pe'|6VT/jx]8s0g2 ay,ѭ;݈ɿ2؊!\vK 6[W>^dzVhys=\A7 -ٳ)CSe"p/jV# 1a 2EL 2`*H$?[_QC`RA42ban1 n i 5|$}pWͮf0L:ZF8$1;I$O"|O'4Zb̜7 QiI)_~W$SnB{:$7j`ڠ]roD\9쟔 ˓<Ӛl4E\9%բ<~$|4l|9Qr⡫o~ z^u57" >xڊ1d SWXĢhӫw_k*3ivH#:R/7Ow$fXI>'JrW1")RRޯ~nIP{ @4)C5c<ʢNj!hP}LƢq0s@=I\95}pBzA/"W~x 4yA(fȯBbB:`$,|g9ͥ2괞v!ygDv};iS)S#~}@D "EjfNMCXB%Ne)- F' ]ܔlFC8G'>롑ZivO}Fiɔ9֦׍+J = -QtZC8MC-eL>yIL3nv:R9PR7|3pt8;s jy{~}wk&,MN+V`p-Uh9LHT Ǫ <[j"e YXypQ{(LWcȥ\k$԰ӈrc/t*]ѓ&ړڷə"Q VՓݢ"Rg4ʹYz2X8{VK- }F֖n:-3H'Eu! X2F0G=x'՝uch;? Fs&4BtEq`/&/&UGxOE1^`=r*MY궉S$1O5ũJ$Ӥt"lYu{U]\6ܖD(s3 Mmz*8 x0*Y&@_&SN qa 7"Q'D◙saay\-FiTp@u[RCac֫YzՙV`\k]H5R~؃x8)m T-xQ䓨٭3q vs3ܤ=3,N{w R)?*ֳ8@}+ M1ɖg(ʹ^$1)We}{#2%} 3R{k<)xNSp_<U@:ꦑXQJrsbo o:C*eN ]9韉4ZOsjNҥ`l #׏~":V<_!UյKm:&9iF_dW4QSjb.Ev _󶵐mu ?ۡ:xyy] Ȼ~xp+z:^UP;a1͛CrV\IYZt ,~SH4?nV˨ΰ$:3Snm<Κ]wCBŊobԶ)@g+[A~9nό_}UIUaٺr*Hd~gLƝ2oˌ-h=4_HZ\XL_ƃ P g1ׯcsaI5!\iJ]wnC?idg+ٟ }y`' ǰy֕Xey=vlxf`V~u ^l t`̯6?tcQjE%щQ;\%̭؜.vx_w(/y:[Wgr/TryyD.E!R2[H=o됽tJ2#Zܶ#/RηS&!$<6Jh&h{n-sX,JU6k_Np)HmB!'*ѠG蛱npߜlxaϧ'bǑ+ʦdLA$F(* CvLdT쨻Hw|1ru*Q n4UAę6Q0pg4aBnZ221a~WET͚j< K8K4 N7D36R<2(vJmTmAM$0_i]ni|zvկbe6(L}ud c) }Rva?7\g41]ADm >8܋I<~L%2/gr9ð<+ϚvH"VZ㡵 mR!<}>:V-@w fгtI*pŇ:s%$O%i0SX-#KZDX^͢?ΓA"Q5TXnWRt%6CCӏsxI@^;5 GZ?e&H@ZZ\J*i`bt-˫>>Ď="eؕUto{ Wj T.& ~ 1|?^?ǜCg47gkl#7cy7~-Kk&8]&׏aU -4/'A YuFpE}5SvoMcʸgݛ`;'X[i9Xݞ#Tn;kKӮ6$a@V /_Qaj&Ɔzʂ6'uB3 =Uhξ /`[tӞa³;㻝g[3#isl"rxOm|K~vmG7ShLR2۞Bh0 V_` 3_N{{9c !'B]H6X\MI1seNFct |lnb =~OWr2Y3҇m/z8C:hEy96"?_zNRcl+;-33yBDrS5)wJõKz) )ߖ> -tÑ̸Lkm U3' =!У+lbTgrtٷ t|"EDl,l݌Gi~-ʘw6D?'>οF9ֲ "k@ajZcjC>r&K HбBh-TO :N]jDCsPe|X0'V7먖ѵ@||OFjUS19ɅZmˌ{ ĠO7c .J "2爕lTYgZӄ_j>@h)JF&PO8Lu8-?v0:tЀB:JcPIfGX٪e+¤i#QAzbx\7Q`*/RH?b jCak$hh+ahQVcB#^l81dM^c|Sz mwo6b9,47{#7V4|)$;,{?Ŏ .rXhBAp˂=X+  wp&aIgR>H![q |HpoK؉y=yl0aH&hiH#г֑L/w(_CT\ #F#X'Ol>1`\g8O^x$y/tʬ*$ y)@OVi&%X&$ ͊Y;ƒ }ȳ'r£r-Pïea>drj`Gدy"kHFiM#0!^l h<ӎarr^aGd9 =lw:l{IE xͳ@7 bH(_%KRC ً5xp-`9'l2RơV "g&ݰyO&ݩ%(<=+/hDfࠜH“z'@ycQ4'j[sP,"9d0ud2X7Vr_ShG /qRﲒ4Ѹ9 1h,k.;X?9ײLMxÍ;ñ\fܞ {=BG5}Li-2OwӏY08Us"44Y>P17O Dw/UOd{ ᫈1$x .@hf]᠍Gi;9T3KȠjqQ!-)IsSRbj!<ñ1L뻪8"G5τ#8ums N!ܫ@V8&_3}2r>7hgHwِ(h_ ă'97X̴5H- Y3s%X>-Q*^KbzI$ fX!jS${ġn``g^gՍՔ\ ﳨGԄuu2v5ZVX%0AcRvF+Z/8W89D'X`t#6e"|nʣ0І~nP|Rh):)Ap{sC LB$g20^L kl&hL #ib tW#6Ga6bx)u&rm-7W'>=R58E)oi!W݁mGMm{Fo5ghʫlUz]a{+s 1=k0V W1 bWڙ#rXFI9%-MPA Ol;vn)F8/6lEaP#,,GbN4+ӨE 2\jnh fժt*כ쁉w<љGhp΢H;jTL0A5) ]r(~E<4jԽn@|@@syM>P N :vԶ*BZTD4zОG&݆M @9R!JEji#]`V @dK.n;p̄p9D>4]Aht V@P";LL_CƐS69ʑGbn5}DPmTJB@? *R8D5KtϠHM?IP!0?UcC' & ̭?g9H?^A6.>/QϘ74}t"4Cl sīMN$q$V<єo@4>P%vDZ_ MUif 'NnNM.hQ\w`9ENJBҎ豪`F(-TF#l=}a x? Dh~2b܄hng}~Jk&QQЂ SNq8yjDvVpfU _Xi4Pаc){06 Ԥy~ tT⪚n{ AU3R]>VM5~mXy{Tg7ihsž sAN:p>?agʼ2j [A\^Zx?$IL-Ϙfؑdx`Fp$lӋJKWD߬,;u(& fmW+:+o#ws' Jn8dIz!YX5˰yM q fD`|Yް/&xo}V ,PXt X0w '=|˿e;4M3߼5EW7۝n8걨/oc$V<ٹ;4Ϻ}Y|U@0ØeINȉ$ivgNjGCt4p%Q ~ uA0ӆŴ4F/o .\5^W)GG&~JC|hd6 xL 7ag=PhhpTCdRg(P^qa2X Iyh2A9,e[6qo.2I.{~#̪K(ss| rSRg#E CF-~sg6T63]Fyf֖q?Þn$  #l[,{5cIN Z4e=B92ӎ\+EVVrі%=`JhR+@e+00( Jss%m8|<͋=;CuoU%lB~ۣy=bزe[< s3^HUznhNF)0|Ħ [OHI^N :즰/ʧC a5ՈP$Jo'10r1Dq6(KG|W1\?>u΢:s؇& ~0p[$Ѡc= 7LPRZ8GBC*Q1hYKJsuiǸ9[Kx86Ne TT5;=/59x$RS|hJN4 #|!=ueE} ?@IDATEB6>IևSgd,mtkIF wv؁X:9ӝd4C'AWs遭MOEYᬗlG\5-Uz\C`lk_D6$rHN!?B#QAxEaګI]<7 "!*4TN¿ZLDe d,΍#IT'# $QQ/RqVLT/+8RʘO ؝ݚCR&BUؐ%)hԗeC|jջ ͂1BH ~|l3c/Wswc"_Gv`5,Zzl}F39_-嬀4x2h 2z&Ft#CBPAZI("1Gl8КiIˌ#э% vHajtV|FqL> 8M P o`jK+QtrĪ .qׅn*7WQN*l7([~*+VT~: cܳfMԎ1 |_OJC}Gw<|?wwJtrr.m0yySw 3hX+ccf%'!J)f TݝsܰbB _ۓ оBDLrM_ e X6F9ss PÒUh8VQCE~ZG >8Mq(2JbEBWv]:?穭~۶m˝Tm`Z 0QaRך A{,H*X0D TKR0+T(wV\v[Z"*E~#TIth8f6ϟ.qy;̃N/9$g {R;+|A֦ FԻ3,c|Fod52j*' /;37qb U ^\ZLuuELY-'})@M9첺i#y/fAQF&?VS_B֒g(xwdF|X(b7=4Yzc)SZe;MBZEJԜ*ۏ*v],' =a 2NU39lkLМl\ަS$vAG$Lߒwǵ }ULS҄TK0K;"&%??<tvTh7U +Ȱҭ Ӿc$dX-zh䠮+1s"pBiLO*{#^KaQ`\jD05T}-CXf89j>ssS)R^.M56zC"vN90o@i)q3R jBNY5ixka=w6jB,o>ƽ haJfq-"qAE}iLweM0:+7OI̷E. 91otKt9(.*\ vx v[4+qXSXgqM4oD80|ЪܶZS1 Bdm&F{xVZƄ& ^Acuk\!/H֖qz`2I R.傊0b>ʤmPB4g=OV{3p+b{hkavO拮wV;\r8* O:\#Ƅ%qm@h'6tjz\p <̓ 4NuRE4`h[=EMqOQg[E׷Ee<\* ̡w:ZBhrlhmR/')p  =@.a:uΘ'%!37 Q|":ۂooiy%q80Yf?\.8*\ag9?N= %)tZnv)X%HKo7 }9w? J}cɶ:W"7(:PB1| 0fM(.HWW-@,]0{[_\mdxY/#ZSsڬZPLf1ͻu!Ԣ$%УzekP`,(c ;L ft#vwy W_\_p-jhUgqBy(Ro蠑>\v2R-v01r7Z+b ;qd~%e3=C6f[,}e`tJ/Uk`Pd<_I $*'CN @XȔsd 0rcb<к$*EK0MOF~0'j Ph4P,y6"2^},C7.A<̋䠵FI5hЄ!*eO`9xg$QZK4L CP2!Ҿ {u'QAz86ZJ ,|N;o3plpteϯ /Ƴћ B zڞTuFTѺ?ӯG&6҅gLTx̤4|oDFn/Oԋgm'І@ gMD‰휫D@l8vx#쮨O}f)^C2,U5V i0p9g1_STKl+kxQf7͚1ep#C) CGLrߐi޳ n1yJP"x84  L{{%r(۳#; O.s}-(83<t%w˥1XKh}B?!㑸ہS7#nI"E*b8Aor' UZp>aRtبѺX=ߚL 2YtW(}y4Z`QU,7-:dK?ZcЌԿP5aM)*0+ CrwJV!V>{j_vZ9 iZ6)2"^E=j0F GM guJĆM ֩n6XC*g+ySSOQ`tyrgNVk1p |ই!H:b3/%3 `5$?1MX5.? rpɭ @l3z ժ %` bP-R *L^$#b#P,;(1&IS~zYsɌ(./5T=+YV3_7MxEyhB½|"j*Cw4 Og@cg $rd(ƽ"1\Al[MЂ .jv)c8+{juhAqq#i0*j 1igب;we0MɔMaQT`ToN8!H^}7De QMPu%"=g9JM}2BoU]O疂%=B_M(JlM㷑 o`1A7ߊm{{9\ : sTIYʾ1`yR]`ŽS=]hW ?~gi9j6Rc'470tHQO`gp/Sd_T<769U)X: B~Rg^ChS;ˌҙ8%rKƐx@64> xTbh 4ۏ1wp% 4 ?0 Ff@$0\<ߴpgӰ^kjvmmzW{-78kO7_:JDpyN h$~ sRl:f6XMh cq͈prm'|(,; eAuRs4P -_s j`cd4|4j -=n l>G iR;{1Zg:a10Frb2p ^57QlrJ\Ui"LD8 FȫN/vѳQV&4񅵞F\'A\DS"iFr4 `(J>nnEvqc߈\vc[HoF9Р{nL[CGP/a! V=mxiۤ~LO :-R[3aC*Øՙڋf a{ 6d[^BpWS+3 K;&QDR |sEPii™鯥^ 4:-)ZU0ZϰQXs?bvFt6AX4}LS'!%{>S#T>lPK+SVH=i_ R< /- w$X[QjPvAF[M}00&*sC _105 IrIvLpp|̎]nmc9*P͞aܹa@N|$9T߆Fè+䁙bjm#54 .WWgЩnV|hj Y"JLj4ȭXd3Ve0c}?`dtZ\eQ ɴSEL2 XAYm\KD}@&l5eC)St^^P12430É3E.H1S=GQ06ٜd k2O4V8+2D/u hM 𥜑.d $$NJ8LeѬl}ԴO"+RǁRQ33]WAbhx&f700d ?2+ CFv}o"t0/ +} Dh;!w&ij!*ZےC6;H#$a)X L'n[}GL1@BP쏾onlyMB;`B3G`#=Pm}^Gj rVlPk4 `OqPZOtᛠͭ k&"G n"'E0T;-@8:hH}2׀FX;K\[RUzs#X@j8 rSS*Q0߷`:ciRjeyLV끹U`+͗7y :tQ]Xܥʺ&Pdn,#s65/^j2聲+OtF?4\ʭQmQlD%X=2 qUK6r^Ƥ|bMA ` >,O;mK[HFT jQJFRLƠ6v,|MOP)Onh7E~F@,~ O&4% "x" $bWLvs6?,kҧv:X~[`{25js"7+4gm?jcz- ƎE裸l4 uxN*R_ FeSL=$MK%*zgf@yT@(O@/MeqzZ9hJ V k )e5Iw.⪅ZAihIEk!FWL}뉤=52"U!*cm]vUn@7{$鄓i3 dwCeYVe"WWCm4q ?Iādnڗ.QY5qgQؗOol+w!}X]|`hkZAtNWIo`OAtrJ$úI`U5w0,3^G1)Vh8e`ۋV -&qֽlg8qfkT 9HWg( XaH84TfsG:E19&g9¶V46gX_s(P8ʞj6󷰿}hTS5r9D &w6۱L@ӉnRp,{{zUÉu j;)x)O[;I 3N#΂>14`3L GÙMZ)XPV'Fx dMPHn[ %Sm״ CݕYtZ⬢`fr1$.XMΖ?I[ ZZ)%f!p(G k bD4wX?6 ;~IS,c:\ ђDF<|ؖ_M1 KA|"Kc†FߗɼxQaZWZ5A} kG(Jb[VzAY" Jr  @a2@~aM50q<ѫ8s݅1ɣGU;:՛cyrmZep@=fDBڪ6 +~JrVG&QsQRKȣ)ct$[ui9זQB*-&ю-jEYj*>3UdU?La5MKhSx8Hվ6|7.v2ej`,ϔ5 1M`:%K7{ck_wl+9n=feѥEtjT%0ĤW!3{ln!45S\ 5vс:lC-X(">-LۥY߭ g\r]*Pzv Hsڻ9b/ˆ>rYXx\ݮ)qm9I!)6_4bvoVˏXd#gV[q8 O.$kcxjΫr.KqFDHR\[A JSl-ݜG_l  xn?] 1 ڞ-ʛ<8u'-؝0G22,#x<o^'=$Rl &qEGLJǒ ު\ޭ졟"w HרqR,ѷ3L}{ -Ageޕ 'tii Ч# ^3)DII,xY5̠qqmPTRS-ssVC~cZ-e9rz9\ʬ?/ɴr"LwgB;*4aΤj C ӱة( : K61V;:=;o>X@E) Єˬdʰ OKMn7~T(fҌYJy16IԫZьZ1@jNqJOxчTdLƣg;*#0Ha8O?:Ib,.%;Vѻt8Fqp R).eQMkͰp,Gbv  ޔp+7+}o%NzCb9ACȠ^abe 9m?N6<:+7r[xbv/*o#qaZM:+c.KjRoKS4}CW3o `Y7iGӖ϶_n{uq,fFI4ĈqoK;alj32Ta?B1BT&ѭ= lmֹ*?m5dQ[>3̵7J%KQ]}]Hٝm{pĈEɋʾZ{_mEr @g/,x8"&Ƶ01Wdyf)E+3y)/LɲHa5)O U9RИSbSv˜fk>;y(͈ ѿΤfIBX$'E ZaKy+ ^yfG>.Z":AUiuz݌ʨeB7j&&|1ÂUL Z x0S Ze"]áEj ^dHS># " 5$ʅubk[n,,v]:ԗg({=Gc񼝵ug.YeO~qRFŃ%jȵc:C#^,iZaaa lG~| >v`w' -Wz)}a5 tFw ѧ^2A[ #FZ)"g85?PƎdĺ@K覊i7lY)Z9>*lg1K fqge;1dk'<1Ze^ g+ #tRp ~ke {0eLޛj PRCFỦ3gZ/)s[3I]SHA7A"tb&T^f}I1cS@ 61ZSpcb?Ǻnoe,P2=4&J#zhƜo&*qI##kP©8r!וp3#ǟ?w?_q>+,T yߺ]a߆ۆ^*yH,Zn0IpM4kw{*4ŵM1[[ 7)tWe71вP)I $F,8uZ7\VΑkk4 O 2%uuӜg 0qjiwps'ড়ˉ"z"^3Ԧ擧2\,GGz'J140H#,i!F{D2}kbrsxKؔO.k3a4}c A nhERZ{< ?Jq8h(ƄX?v^SQm2.U8+5XиΪC mv۟o9MS##M Ul8Z^'Y~u8Z+ْs55TtRhPS5GXIg"OlƲϷ>`j^˝-2=R"_yvBAn`], rG3zh (KO{[ZbK^50rFpD!@!R[.T.0N%zˠHe (;ExjBܠxٛ LYlrzӼyOs80`;X[XOoAPxk.Ę?ʑ>myih,]{7Ҁ&ٶ\:l|#:8\>aF @g{c ;znJqO{. "#FȪS2/DҀUUi`ywPEch&@KJ2HTP a4:!y^xϟ $hs2)Z87{$#Vk &6*K3!*<.}Omi*HS 㱱H&@V+V d.2&.Dl(=YܭXegW@$x h oeKBbs<`Rj!A2z6.*oQCM^1@&77?,32 qݳDJȩ+dH"w*”G1.yǞ}dl۔dLadsBAF f\h3j$i`IƩ 4=EES1ϐZSiS8'M*w c|D֗jX 7"wHqࡁRXvSC6dN8FNJ[8cOze!'x)ÉNg=&,$0 OGhŔGd-g!p~FǿfCF:ϡ @2Qr#j,i"4U739 Mǫ}dlL`%2LM$0jl d 7%8ԺUIo$sEZ>( p0/Ƀx \Ũv7"VRu؃ 퓁@?,g*iđ =ƞ" dlPE) pͿM?6#yQ i3Qi(4`'UY)3؇DνoMը1hIQ$e+P#Hs gcwlORY">VOfj7' x{6gfqE]u^A1F&0*)VN<牮'&wH&8CN*6@u6,ġ2u'QY5",REg \$ (Vg0CnbC@d2$YpASEtc9jȜZf5~7D Y@= T1r~{uciO\t 4dx% MFM:GO 7$-.k;]j53Aga#tιy: ` 4z>Y *(%P=%-dXEE4%/2#/bS~a< 7五0j,GPW V!Ddsde:Kp|Zodž/3R1Mqs X5oG-| ;ěAJ@-Y *a $MAA^9 \eBo ;;iYW2ּG0k}[.G<65C#MQAßkKڵqB2ç2TxaI1\ hUo'Oq:{d*KPl)2h6(;}i;-3/]Z; /ɯ kP*QH3 n|vz3R .]e܆\H^E5z=U}>H5+M#~:, HD!^xH|F85.6COQ yO1ˍň& 26) LdqHGuI>ͮ烫 NM-VEBitz-O/PwX7?EXUuJ_UQ8Gw /e3E5/#*RG|mɠ>4/ǬtMiVGf^<}Hլ [aa*gB@ f.4H P@IDATE?(WqKNG8OL0\l(`G1ٸnޜ^bqcD /o?5!pz>yp&ɢ,8<&DqfU Gp܂mנ@a6Rp1V-Pfrk3f0@X͂|r|FJBU#a(pl`L oJCi18 7Nk9f Npn>3*PG¦D&T?R$Hf7Sh 2ZAK4x‚&!dS!$x,e!] /X g3ahCMD0Gy8c8K|wR ㍫G0c'O3@!hMwBc,V~bT{d3}.KR@c%+u2XoI|,IJ36·tn@0ddVya0nt?k-PbVr9㇧yh8U;̞4=z<dVdI24ô-7ݦ "+1m9]yx5D w_,_몚/DLq'>~ RK#Na3,sD:V7)j{3@qlLshaKq7{Rw5TYt2ZV~KAKiL 7w Ű2UΉE(Zu/F8E*sPN.dE#)&߿-][Ek о pƶ t"P'FX5M& o2o7a)txu°En{C̾ڀm 2jC#'uܜ ɵOQ-iE9fϹ&8 a-.m kS2vgϔ3E!?W?"~J])lX\0<)EppOQt#`;r}MR`T^+9nLm%:룟V4eJٟxdQm `DILxFs%AYյzl?se>]̷c{zWeJ܉/~-3$>t"3}d * 6o)э gr Dv65 &$&y+,Snq2&ZxUoHMBE(ߛWsgjX,BP("ߪ$:خ'UQE倊-ّPhEן|7Efox|F/JR, *V$f]ZlxUSnF/=6AqpAUG vmrKd"70'cG`}k"p^:K@15x?Y U)UtiI.q"۱)5 DbtlviD[FF=EV׋T֧B_WBVa9G|T sM@a% Ց>a8Fn'I7*rP8mL@Oa7k(P)@E3U*߿3ץ'ٿ9u7*t"KrZϧ$E8L.gu7W_oY[|{oRx O,JtiD Ȟ"}J|@ :O2pI]>-.i:7ߠ@u'3U*^Lm;< q)Oy {WT9h[}=g .Go@%F'q|;!h_8RH-ZԘ7oO[j_TKnLX5d n09uaNt{v};q/Y}ZBg-J$Jp0n;e:wL9Dw_"S&%@qtVsV +=8Ӯ64}8;V4[7bBS44VH Vwh& NR]W4ϛ~x4\EIZ";wBgӨEVqNbcdѫ>֗ż{`}FŢ8v'5("T` (&91*Et2f4nՐ ΊxW̠ZKᔿwATp^=\R:F| 4-K "Ϭ> t /_g5Vǃ/H r" }ȧ3og{Uy1P{1VU$ski^ D>g]g18c9Vo|e&T /1;4;K޶S̈́B U( ") Qn}/[Be#vHb|\沿[I8,!=yySwAi_@Zù~흇#qToh/p=d6/"H<:pXB#m |gHlbLafT\4d.b1>[vڀ*rn@>.!8&׼eIOY ͱKox vܐ;.5:C{rO~+ L"r\,teZYoёNsYΚ gTYDpgZ@PjdjShT)~8\@nMܤkOkK~GS!~ Vکvl0#pH_Ktxkͤ{Q C3JH1z=B*+S0%z&/9n%6s*,| 0)RpW\aֳNgZ64S"lֽM djG n7o)d] f%WIPTº(:{5" ? bdEdY>lͯ+:c5<: >0%Wƨ0ӍX.eY3#(&{Efa?MÇɕDzXaQI|]x DĪUAGT9f==&}טևP/4 _3ZLJ#W,g&P<`WXtdpXI>?l"4&r$ƶյ,?lgL'qyӖs ~\cꏝ~ZPS9%O`Պ>Bd(C _ p. ö>Bw,_6"BHy(L1;ȺXt_>C]Sh5"p iF2!ouQPØ4g4_#?hFz6|w @V9 |=wD c e) YGW@!(LH>M0w2J(рL2ƌ4 X 4m,މAyC>.5skя{s::a5,Lt_&r̸<;R1|)s"I [cJx}H)gvđDN"P!dDG4<lĒm.tknf a|[V+ZA#7ªƬ#?WvQ.aE)Fv] ac?,ߠW\R6f5!aXE0V%"޽(xYkF) D;.8%?:'&'NM]3$U'=dF[Qo"a,$M%l:L}8x*K8J6YdU5='dA"^xWH33Nq`,6h?YL"2 /]-=-q35q5,#id/2/H?71F@IS(o~Uߦ!\v>c,?ͨ.aFE%3`|9#pO Hͩ}..=?GTmnA75 T˵PD ? EVfnap1736-%OkDfLD3SQ``Ȁjħv_jg%{jf$r&}dID<bƕ0hp' #Yp߰{9v x _,PFۨ>JHBshQp Nz5B1ߝK2 ҃,LDAkU Q!+fu853"@]6Ѩt)aHy|Y:2`%!wĔ(;iH9%" &*MT3Bkdw,,3D 7?Myh`.p}Κ]}ᛂ0T*pRYGDW9&Ȏ0BeL3=J#V,4aۘrTeԭz.֭? -&pX28d<5Ib}~tCmh:ꠕjJ~W-X]3>h "[gb{>bbDS:>F2U7haDY 5MU+#|ȇET} TwO8kָ?"?}ۉ(du-]f Ŷ̀*P%nbo!LO&sP".2c3gыr1ڐwHq27/$ >p'W)do9Klmzkr"jI c?"p~&wZe0A*T "Q䨹5I Þ,qWvpd.uuP.8_AY xVp__iVJW VYJL"7/9p,f̂:MwGz`?"2 3>GZfsGǑ¦ޕ0@H*GoFAtXvU T8@ *&1J̏R5A*b3MM6FA tztb'Qq44}ڪ;gt\>>HЖ\Rp,"yR 猫(" ICI"B"+,xM$iʏ<6S q=E jpLߐrPM61x/8)x $EІjj hfT3IEOk,rKQQIE (DŽL)DCAkԢy,^i F7OowJXG Qh SC7aA'A~`b,ToN(% .Q3ú/\^a:5(8 5ԧϗ?cLs`HSe"uȭ C݀oX\Ieۼ`p/YBkqYyid"F\0!!.LQ퓥;Z1XoBdC0,; @|þq8$yA!ҘY" IJ6FT*)RbsƏ 4jPSeA4 Fkc_,-d"ȠK`ԝzq#y# 7PP4R!P "B0r:]')kLLǢ4 ~N^}鸖Z}dPWE Y|B+gُtWuRcc=0iAMls&1 -8R ?VvίzzjX`DQDbGd\rXe Ċ0rF$-=\jE`8 0t&قiW;=bYNwY|/_휨"`7nݏ gpf`r )|3sGq|j&ȭ؎HTjiXԩ44&<2p97qe)"\lןY4v({4@ؘy}(9|-{$ީ"1j@IN&e޴ҶXq+\c B R4Q˦_iAc563ÜM-rMΑe̢N!Ǣܒ*!__eq}A7CIO7%]4˰1zl3 Ge?m8C]k f-C"LZx[AЕ}XPR¶Mc%_hSR!i֖tkaA)W 6M 5:2քJOo׺B19.Ck.@}P\I (- <(AK%". y/U3uɿk9] Q 2^Y^7ϬFx=6iw:~C^_^nrj.had%1FY7'4` ]cƧmd@XďAϲK)xþ%;xq4 Mg&*FM2%= o&{#464&F-$ \:OD$3H<_0G=i)P؉0m~wX)PFiejx,hN0^U.1 w 3S.w\{z5Ɓ=p'\Zv*`VÜma>Q|9T`(|ܻ. ೺2SYrb` vu[ͬ1"8t"9C$6>B⟎#F$Hh:p̾7R]k ǫz B "?+00wWž23AfIRzhQ~p2j@o hS qpf"nIe;˸_b ;̘\.nrv$ 9qf ;I &E2Z & Ix_λtt?Ki(ϛ[[m|5M񚥋FbZ54EM=j@ "aY5Ȭ46L((,I/Ysܵ%,U[ ޼U_~<Ũ@X* wvx_ ;uc 0q&cV[TN2@k."!fuxԼmަIƲsuu[ #I1h pW:+>r_Rh=q,OL[Wwe ]K+(F8$fPFiig cllan@>z6cCQ[Ee^{Gήu~ti-z of S&aRJ3*9f(o`=7K`U@?qusOH/̞lAM,,D]%g"oS)7oULtm,#cն1+7=-r's3w.p1jy d޼EyOW/ oQ.ۀItwyONcLJHHք lxv6'ݷ\qX4-rEf"gEA(yw1.} |;Q*Q!k,؃>U&2E`dkKwZ@ ʖ鋥sA5iijOW𐼮+'.퀕\|?,˺;)P|n#/!96eFIQb\ ^8|HN[@lE̿ήmLɚ6+X~Qn'l9'Irf+՟O(y W2 ASVUCT~^{BJp]ݎ #y%.7|P~%dl_ha^5&msWgEVm㯿^׿?ndhiI S7 >2ԅwxmeC胬Ķ% m2ifUUi܁8Kq5 ~K&LJ}Oޭ; D-0\Rxrwc se7H5L t&y97gۦš1^' )(iݱJLYi] U턵RjXQ҅|=sL!]@íϞ۹%3E(u7*Hqs?FjY_mdq `}T-5RnSҖ(*8{{Qs&)l=Dt;&Bsl6t1?ؖ~)s*?믷ߎz4kRX޲0;aym$8 YSv=ˍNBA}Y  2(Df~A}2`%7 gyOf 0Zu2fPO&݄4_YNLA/x:U¦#U&҇s@=~Qӊ?VUr_ g(S6?=gDWh/ K'4L|vl J"h J1}fCxZC\HVQ~ ~W:% Wc\lF:H faJ$lYljԣH~c_PսN1 @OƬMM|uB}r͑pA4je&CbHO5`˨pqÌY O8h lX:];i,Zn9ikxIA%н2wܑ0mjΎ.VUHA$Y#Q($eK|깖~4s'7ӻ̢Seb+w$bE_# pjۈ iuo+aW6!?\c%9QG2ig&G:k.aBM!!4yTk{6rWtX-J.%ho0=|kJ 1:}zޘ Bc x#&4R4s, C&o oi1|J^"aoS.,/C k5Obb5ϗT 0Vor6-AUݹYR62 $l3e8^ҋ6&birjZjɇ\Bk3ˆ4Z H*D Ezjʑ fm"ֶ#2<',źiw*m (e̎Ȓ/=TBn*̦:$saV`R}F`7_@mbX=Msba/85U-?*]΢Փ=E"5/bgiGڀ =Q+w,U ޗ=c$ xlB^@_Ӿb&1<: qK>skՏy(}L^ypj9}p6L% fRg_C;P$324)ې-8!F -pXEvf+kФ9ND8'(i2FPKwC1@anUIõ3M}ziOy|J3!4@h|q}#CJQt* P:}};K]paO29/)'SKA2*I3ЃZF@ױ\rQ5` v+ёP}8| `+7(se &b\\u=bhP&!Mo ,@ECP4˘ VA`RpM `QZS [S/!tUk -4O\=)0(G!HӹX36ę|IyTn"[榴;@h2z3(hșBuAN}rp%Uq*a$r䲳 rl6H+ip/P)Ҁ-3TJFOϢ4өg`ZH8~1JitkLqJ݂9ms087aFF>3 hD'4Z-dU_FHH"tiiDReryQ2M:ĸ':Hbl!U|*= 2W9v`fB}nlKDԒpJ='G\=309vuӢD|3z>h$l&1÷ZF)A d@U(jLUą# y9w.!XÜQ)L40$0N'`CTIcesMZ>JEPx>2~a8;;? Xu5?;+ ɂ쵱kWGGOBoy"M~ 咁`ܲ\( ňz&maeM9<ؽ4T,IH L e` >҅#[Zo=A 9?06aG7- $_GhbV%3ֲo^ ?X(ƐRӯ/)tK`,ST '] ?nRdĥ'oc?"u2%%ǰ_(> uqq.zvG/EV t9gFCP=KaXa5=}&@H|\  Ӈ!Xdt(&|Ibɐ؊>*:adF4#>9'ʚX/њK5LςĔDG:>IIpsnY?:Fh 7ʊG"_M ؈ C: RذxT|;$)SƬ8iLZ$Fw_Ѫ)LQ7"I@\vDg2- bLSS7uJ1}Ww p1- ;xxsW7"L1Xr"LͲUA.}F$<#"3n5J>3|ҕRQ`[MU|9FrmOa }=Un1ԣ|h ;Xf)h~osıq WeGv&Plp!P,9NT>fj` BI fuWR qGf@9ʹYM&q N{`TlțA חd:j2r;G弐8~&Lh  LFtF3%SB.ww?=2e={R{DQO'H <񌺏|? fM\gpn&#tcJ *|z~'.Zz#Vz(dhfe?}c& E-A} }&K @i^8`j@*R((yڬ d?֥3ӅR g?c^qIY#v "A`Y/K=f*4Eiԧ:FZAjsyN۫-WJ'iĹ?C#,c@W臊%AINU *C5D<:xCqC46eLuAգ4wA\+y|otZ'o.;P7A6N M35P)rnEZ TXpF>Ln}R$WƻTuOF<X5: `JѕBԚ7\׫ٶ9)6$/AM\+CʋwЁ/7P.A05pY9r J aN?~8J%&ƣʅ-F5/l5t2@v& ᯏA \9ዹHpKe@@ĜjppU(idшb)H,*!'>H*dgaZ T}vrDw8_2Tj@w)v5#Q3ڗ þd }t ,ݫ7N=XŌu#bNGhpqJI|5h䄘9`[ZMM ?~oT:GmiDv}MY)7&o/fΏ5׹D">JEug+?Tus gشR-έ',Iǰuvri:*0 O?2Y ^Кԡo՝FW[y$06ѣ](Ƌx;t %G/Af5V+T F(Ne \2SFHz$X#-щJ51ۥtZ-kҦYVj$ T@dN䞘~\iiB~e63=7IJ1x %xx7:GrH(yaWvj|DE'y]͜@[HSd:n-5 C$ XGɆ/1psYaH%mm_eOQhvOW,B,N)5 mUyVp::KkE*?CvFjv[$2:wD%B%seVbWjpq;GtK_ +T $'MUA'f'1*y2fTƮw F^Vv<d>G~Ju#5 Qz/Fmr)2$P?:QN$&8&|]ЊԔS܏P*HTjnif ?LL7˰ a2|EU?BaLHeN>}]??~:~\C/r@#b}j߸ øh/`w&2}1Θ N?Ys^3c扖0 fv5>/K|ٸL̇] +k!@Iaxӓ237=LSboXf˕/* xZz!TxtKl8`C[84ZOEc|"9{ $鿀=gäI$` ^zDM-Ki뀖p3(ƞ1I_ecB lM+LhM"$[*{^s/jfuRf2qYZL:2];bZ4Lij#L2ӈz|fvymҫJ ^7f's zm8TI}pNaCFݢЧq ƭsQd$67A[?o[>7Sm>1HYÀ%d AYj+Q\IeF̱sϖ# 3jM-Vi!Vym٪&5* dlCE|MNt +KVi/6.g4,ﯱQֿM!XBE<L>Ɵ[?]vh0Z9 %tSp*l`Wh$OU7gxخ#/#z̃die:7= OELOzryg$dʧxlrvẽ9rMs & krl_IVf$61۾K@lo$[ۋ:S F/QG_=;=tŻ|tcf~7gzzH(Ԏ(ܭ b jGHP1ҏXy61nMb(ϔ#ϓhcim]-.Ԩ(ե\wTP`dC8rqk4?d1*'} UxC{ߕ~=5nv_y95S8-;] v#>djX{h_+֩5]6y>w/۶80Ũf2u$_Iws۝%G}Q9WB35em" 8WCWv  hUaGX^#U7cϞeqwx% 9dnpB= o=Ƚu^ k| ɮ}9"Hf 'r+bݽuK>lٱC:}n/gqfp|?v9JesfwC3Vֆ^I2swDrv?aɾQ?]zCu(#f96풺Mqȣ)i}pQN0'UBۚ $:u!G988I|}lO w3׻^_;rö|X6>UP?_-,5eͱ(~6u|lk'r~>3 ;™i/Ϡ:XNd6GKpt=$.s1 :S(57n~b TZYh̭{LASb-{q3),t gKfdޜM(0hZ;xe_]oGtQ^9o gŗh|^}LlNwWٞ*`˴egLZה#2Ke+6қrjVqZG)0#}}~]6ŒsyZi_\b,;nwui"\ (iu/$xvRRLgU` rM,@Lڞ;Dڸvk2wQWeA+,rt.d|@y*,W Oq&cD7ܟU_'GgN7Szd|^"X9K rKo#v?fWx+iO#)V1ZGKF=ǂVg7 70@U- YcL1&vNG( @[iL~8X#l8hwTt).k5@R1Ѩȵ;`U"TfxfZi#$Ǒ1.rYn!X$@P;mHb^[FeK[ Xtbh7?x|\ 4bᤎc(RS2cwj̡|-{HJ٥[m}~2 d2 V.8) {J EX MQ`݈GP+U66(c} iwTuô#ImGE8Dj)}eIE ޠd  G)qˀ~h %`Tl3{Uby0C4f,Ltd".^Hr@J/m]zf>I`T N۸ipS90o1*#6TJ*B4i.:ݲI1%t^7?p.N|\5Ry{'릗n)dm,o;)QLNcGwߺ_L¹_{é rfo}Lm Aơ-/z3GFn2Az4 WFhݶ`b*<ܝ1:.% agdm1>D8xevH@4# _iG%ވ:MF{%Mi00@3ܙR,4"sx*1TeǀZº*$.@G] ( &ozxj"1Q?j'qd"V?JٷIɈRX)yvYbLӤΊE)w"6UJ7G/!&1 *؟Iƾ(ay\Zk%ҳmd 4g)a/[ <&[lt[t1T8eȋxH`gQSg,| 9C7z%M0 ִwAƞIT|@S2''9IaOyv$u>c^K+u!"cOF-&yb P(絸"FjFQSq4hhH31KOtNĹX@%LEhc5*Vީ(7^uN4!F‰`%M,$+c`zd>p<# hB+@O÷I C1h0IGP *ٍ0`K$ yQrO%nCC p9YabsDqJi'CzjE<_˸:?3yUےL^ vr Zs$W*uˇ,JP@X'NriT}_Y )-HGCC! M»&C}>/o4N_\&MB}"na @f$"NAn2%`E) q;X F6 jDH\yZs ~if ?K@8K F_w.+-p󬈲d`cYF@Jrf|Em!a3ӗt_'ߞBX@ҹ/ 7볹u;q* 1#p6Ϸ7ªGu #jؓg1nv+VZ;/Z^~sj0yҊ?K ?3&2L5&&&Ĺ;u@SfթgNC-ep綋FP eo"5HѝI5H^_Y<4 ݓ"gRnqi^D*H,pbnҒ24D.cl-db1.x. ,TU6N-8&j`\G I_N]3d=6p?XTS )Ou0 (9TE< Uf2D.8 &Re53XΗT' Fr$2[j(8u*d&^͝Gf7hR9°TQZ0,W}s_ҭ2ac[*݅ș@!XV7R}iTyF FLP7Ւr`y*=CK࢕a`SP1TƟtTBMjFF0_VK,xG)Tdl Vu\)D$3E{!JΤϳ͘ϩ;s"((q@Cd,Z6p,.0 CmjAz}?\M#z!m_Rг ~Ƒu2/q BEzb:Z~&S FE74WELc <9O1@ t){.3OzU +j|=lg56N0LSrJ<tnnxĠ9/r Ot8C1€+}TăVW/yg6K="j\t'm-i@>+zC=՘ Q6{LCCpH П.|iN!@fkEժvZy5v#bBu9']U[H-G5 y"A[fL`ۏ}^;dICC*͛(j=5J"~jX}+z/M֓>:f%.kF􁊦MXUd#,bfB{?Z2JmYݰA&Vx"?Gq{ƣf3OCA\F`phAls`iZ l 4ZݔPm^W* t6V KTi,(GK~pv׶ 9fJlB>yJ5*6yY{&JB)`́h zAnn=M&=8Z4Yxi 82EFV2!3OPN.D 'U _M ľN`y( KeZ`_E%TAM[baf*SL^&9mr Ռ53 pF x6GUk^Pb-DY7(|a` 3#S3(.TtֺpP$;b' 4C>G8]]@*-Efyx&Ix﨟."w!Ðr>H!f/83嚥YLC#􁉤xX;z$;SC糩A.FWv.oEHBT{)y jO=c~j_O)%AYĨW4,YhH\"ڷ{i~=/$"Igۃ ?ȋjR3H*Fpb>$jGH?U _'8O I\YK4L3~]"XS@pOSь+%g H9YٙXэaZ\鵮B0[yZīzY©O9 pu5$sK1,j#W;Wdd2[eU<[׭3{IO5,NwHvvI]fFE; V^K!1.E!d6i±CH^(Aq!)f 偤JRFgՕWO#% ˸$#FH)3,`10=͢)<r02.'ѸKʭOJxPɀ\9Y2`.\s],cXd%Z&+z5} bfR 7k|aZ`u64Y[8Pz+0NDMhCb)(>@8ADat*=:g|y O)*lj؆H^"\;涳BRdAblWkyYD{P`Ykb,x)C:_vI!i28h:X ;0P~A_{z yV507h@@*#%J2zӴ)@`W·E+8t&aBzT-CЂh>ˎ4a}vŖA;=I{T4/oXə@YypSr@+U4EsMqf/xZxyD \t']J3E4q@5[4P&0n1^_!Бψ"WvPUQ4<<t.CDփ 9 . 0&"u%sV @AF+ӆ8&(pTZHOcoLUz<|=%1.2 Zu)if9~% $7!˪."k;(+~T:AdU !P' i4Va%Fv<}`F Y; pi.@L;┾|b@&F^)DR囌lb^`2Px}pIw!Y@TU:]|yv7ouТ900VPSY`MiB@\f(n?dVMQwMb8GXbos%$"&5iɪ'r|䢿{)WaJOy)`k0%f[BޚHxHjP حF L-1,LzŽeg:u3iTo_zfKGDET'.I Kk𻪇mQ/.2 /ذ6tlNmQ:NaHzKv *-KL[5ـ:%):*b,NX<Sr`Fn'MC[Q g;~+t9L.ڒ`jRlIIs'D6ʎ2#6ga ÑP P k`Z  N3n8!ʴjgg\-bC+ta7*zo># 㯳eaޕ|O''"/-[f6z\0PL5 c"+ιD ۓHdzKuOSI zjx hŅOrGLуN<4x?-#g0']0$_% v4*kjL b{.e5Ѳ- Om)V_R:>ۅy/Exu{7 +`׭7Tl_ءqHǢ&j1%˒`wzwfX(q_w0=Ҏ4EzH\BC:V\@!!56ŀbc9^-SB~p=9xXq.η6պ]WӾ~vs-P6jX:BW5tnʬUi#}Q/ }rQ0SMXD .Yտz%.0ڜ.@@ =bJQ ڶRQtGbUH$Tor0J@pa:KxVl2=FPY:JUXsSb3-11,Q]r2s€ NN' iEUM11FV>W̮ -ʈ Bdz*/`C."o3}2k2y虝w] ɉaSħC{F&1k%1O>T5օf3E 0 +!:8*E'Xǁ|$0$y?R^ETRwTr6sB?vYGph>@ꞅܶ?: eԱ~Ej]?gıs"C-1 " Y&Cwi0ՙ+ztM$ k  PV"mH%)1[ݒ \LoڧLB$[)9AmZa~0x:.210"krGo풨f VFZjBcL_hx*U2 … Ju L$ OSj7S[ P˴CH$Q%NjҺf|8ASF#b8RDݧ3%p>~{g˗AF5ºmvHVotPӉpYĒQ);)Ng|ZQꠙWJ- *`/}d9sZmbGB9pjDQ0u?6l%jtXZۙI0y ֳo>h9768l,Vaߔ/G@BygiS/:Lƾ_Q٘":]co6$w#TM֤R}DvG GE'\Jc앁ٝN+<h)ÃSm/1w9J۶[5}&DT_,xߺv2apYw"71sQPW^)P$ q"Z..c[eLʕ6Sm <:]iarǵhtβ#IyR!E˨nYxw͉ ,ȿ|!10 y:gɒ0 VD `sv6Om[w8a.7_mr1X3ŁϜB~v䤂9V|߾ωt%j2<+$@y@<&'E&wʟJAUw$Aݖ.^5**I$ؾAOVҩnAURD0 ?R9-yKkL4OyǸ>ULZ숛X;sEn\_MEDH6,<{\ӛ{Jg{qL!| ެf2t"u ^/v`ŤaJGr2e ;ej!1)}pf,9JX*&5 ]PvipeA?^팧gɏ4[ge?M*G=֝I LɡlTN9 ӳt'R\LA|v'qW#gј&':s}vq3?va}]/tc7R33Bg8;Z3J45bPR~'=ߴhvUfQ^| - L0bo+aڞwl|&'_w N=<;];wG TtH*bey'.Z-& N*(>>/`v} |OwJ3ow$8/Uպϩ(L:V3T\,v|-8_JiuTk6ON$m#:RNB>ֺHL&  msF66T\~v\q$߉i^`mRL|ű4^CO;\b@S5DP< xu1n5L",K$2hLчl1o>e1e!U4_E! vm{KM| 10n(A_v3:ϜjgrFH`,}MTM ̦5|+2ޚqt EFl <\3 {K$F #m`&g> 2E-J9D7]#$9 p*쑵m>ÓP?v%Y3A|d{U壽I yzn@*3#2223Gt? fl;F(nl@@l@ss iQMr6(Q[)^SvMB(1FS:GCRKѮA`X%x~w҂YWQBX,/j4"b< Oou5"#LՄmq%wFE#r&*{|:[7Be8`tjhb'FiE¢x}h ˆ~<7XzB3#p4%ш>b}O/`[@R@w qB0R5;4y(& ඍ.ey42,$AI !yOGCuΐmjr 4iE]72ZH}am/g&,T~BʛH$ ȨA= ?< XGC [)Cہқ )+ iozV8#l?в Qʘom|ENsEs4H<7rn.CB\i3+b^Y'F11v[IJ&F,U5C6OB֜ۆ@xiU]sM0ϸFdOi)C 4!EB qCh#*n(z6ZM%URը?lg pڔ]6V_yLon:2"ul}0 1{({u-Ў'@>&hؒK>i`n(B4<'I(eI91e"Xp-ۦ5Gh ꣗N8($SxElL P`&evmb}hTzB j53S<' Ĩ%X3T_F'5SKdycOMΰ$lk9c 08;]c%^fs{؞ys̍ܟ^cFdr4O0|87ɩV(˛u0_{]QV 'le Mi[>[T^isrHJl <)aLJ!˔Lvf%`-O(LDX<L/L\!|HH5GAJ&:gՐFsڐ)Q.4m]섛*f 0D)Ɛ6J)tJ1XlC\ѱEBC0H${b|FB-Bx5U׾t7; db] [#HZ6"65w 1B8ȵKn=Թa ,ͪc%MzD)>YAq|ǝacX, ‡YlnH>inl%{/vѰrU=2O.K!x34 TIj B I{ Sb2{څ0 c7&RBi|&ߖSK7^J"z|wF**^xEP됧{(/GU2 E?hy@!ۡX\cyQHwi)A+B0(i4>8!Xu (uY{ "3/}фHYGn<\OBKJ[kw"x8G.:^`\h2oV%7aWg в|ޠ)Ҹ@{# u yU}2c_C7dPjefT3/\EM1bDpqFTzA'T'sZix"])AꌇیdӑBTh7F\A&5u}u1He&XO$1rX(?mu1Ҙe'VPu%& YaqLo$ sE zAԗ|`d]EfMQ,[P@AɃv)kmPM xpQ~>#"\9jSQXMc=x<d`xic^j5"}n8hre#m)3G`Ƕ LĨDxqvX^/?XLXAC:McɌSV^3zܩ$ÁgjEw{Ӭ5lMꢃgFj4̣>GvG?y[Z6\="G|TeNEpwLF@IDATuO;&J$vƴqR(m-YޏՐGe 5rLf YOb PH? R Ac2w(F6gSD0?L;r9d'#~ 3ӊ 6( fU-+\OM]Fq ըX%E?q:ٴo;`Gqxa-7b@,`m mςFɄQз!:ƭQ-ɧ)f~ݣ+%ҋ 8``JkI~6O-cpdYK?_0jY՜{ 3Tm!ſXX/ //Ƣ I&mkii ȴ1xAK񍌫Se0Jll c Ɛ+^qqID%~]# TݫZ%i#)%bqB.$IK$ SȦ`/G&2sȖaVAqFNѦ}.7 "ء'0xƪr!;,G^S1o{g։;,#y ]=Jj -PLq CqX ߙ^6vQBO $|N3}e)DXU9\P2m࡚IJ;TF#O9{|d.h=ّgשB-bj76%C>O(8LK K>fF!aVQ?uh̜lr gC#/" u:}CADCqd7ˆ!xdcLŒGʹ B5!CeS0RAq==,Zny|}9*kRQ70 q{T(]@Eut|f٤5ˑ0A3p^gNoݺBsk؁˕,GQFYnPpH>@Zֿ9}Gzz2`x@EāI7Fu_HAzd}iXx{'(21%-}hM;^bq")l'ŀ =4WQBY9SA6zLgb!!j'm̳pIF5o<6j8RL3Dk/6D1OeݕF2Sa]@bMbDNZ' h"ƤmAOJ,J+dУt.l g~7kuHpƇ؝ʕO_UWUw唴<23.hV=>a&HB)S5+MɃFf:bOӅ2ůMrnVm ߓ8'bZEb8@-Ca$C.nO4=OKT0V,fc/>I bQ\ʢY9NX@M:KDޤj_&ʫhVF+H"N#9K2իݽd7c5,<4sa>JQP]DJ#.M+[eHiP?$MZϤM\'pqn/"C9R`m ^aψK!"݉Wbq̛" <ӥ4AԾ|fIWTI^YYk Y^窳y^vDJiu9V]z5#jBVЧlg=4gPFLXj(&%L~'fQonM[{Ex1=%k ,p/a6 M9z/JL`UiG:Ǡd/PL=Qi>Zi%Ce^@S9|yo# ^yS@$WF$їUQ 3Hsn5{6*v9`J Ѵc^x#_gáD$'`,.Nxч$?UeOtS?kYe U&CnX1W!EqwAMeS/n huLf5%T à칸 8Y&!@Ep`iKOUjP+ $˱3Hb+O$X'By}@qQmaGȱ@}F**Q`Ra3xhXC(SO5`y8{YN%,i{W=PX+BjY4,;t嫇F2JI076QSD6,)&>Dq+Žj1dUn>,! ȞjL`!/f Ymy"wG²GHGVNfn=Ŋ݈#)27[~ AFIdf%/jhjOGDL8Q_5wvi%:[KDG"9~Rct݀ ds$Ȱ)V \&'M\+#73xx#e~IGcfe Kɦ"x!Cc1:t%S3^@ ,Ӳ48K5,҅Cʀ7gړiOw&=_|3cS:jߊ%~}Xs`'pA]ͯ A+!yƤLriƗIE8L[ڝ8 A :ãg,qz8WD;+X},r`GPgӄ*<@&cZzº[瓶+T4_GW)R5RCU MBSAðZ: Pm4K6_RҖ 41+W$jl4 tbi_Y{gj YQ(`lLwq gL֛{ yfyCz=i8@"skgT6.+ɳFd=a\~#%|rj fB͐)^gu[e^ª\G)%jd=W`dēi2ȧnOg\b@ %߹hY0* YEˬsmN۪9!$Nqh+g=QR@*.m:2BF$tQ(u!pdNqF5d}/_鈴nV auY8BZM:RxW k jJ sf")4[=E;Y4_u d\ ~ "[g7 +"3x#_  ș36@y|/+ g+xqFdl UeekQDUl6cMv[\L8ݜ_p%*fłkغzzv6:H[vPȖ.ZGo"go쪟ʹR4獥t1p*>ws@_/1m1SpzA5Hm8CޓD!Ez1O.ʜ4G\a ѓ/S.YqjJm:sG" ߬L6nN113 TV4;,pǮAZGXo\.NW^~3`e, I-ͪ= 3FȢn;g}ZCYk>v☈}r\o^_?^QB&SKqaBL$ ^D N20z%^^HDȌI$"0)H!YP1ٻXصc{`N QSڄc@56g2Z əl<8s$B )Mzƒ/Cg lQk#;8:2VRI1M|5*P^Z6O*?H{}=<](}A99!5Pyޟ O:%~eKlyqI}Jr& A$@1mETmnl>ed6x+;em]|/7DBrO8]+NVqB A߷ ɣQŧ#~9a]fr+f y <PܧtXf#ĺ=^'Cj<$c٩ `gk1@i!jKtsC=);5|V)nXXhvMGmC#hc#=0a^Di{+[C{سj**3-6r ?W6~}zeR,Ӱ΂G|Q%lo2BO2^,މH^tJ[(O%IKsk\i+(|?KҴ`Dhͭy6{dc$1ȢA_.ЈG)$l1ön0x ׊R`M^٥ (<@b({i *v.,PY@ѫ a2GDr&[RH@vQ ;sۚ&)<ᙱbZ׊jěN΀^`N8Zz>Yo"@r82y΍)2W{īV^{z{8m'oLd+NtsX#ct~uhK%E5 ײ=0MXޜ4Lb\'mY~Ol xۖw̠fBT̫4lL)Kn=EcEP[ zї'6F 2`\pE j106>r7#r[^%+}0rԲ?AmW=EL\V>d\[2|qzǛ^& YȆ/YnۥGug-|zeZ;|%R F 6B&Mb֠șU[d&'dxL& hٍ> &h2WFH!DJd cOi8^-٫I[Y1Fb̊]ٺU"hc<[Uˇ m1Ƙں5yI*7L0ÇW;02h -g1*7s O+F9k̒z ,MXN0#Cku*Ʃ-3&v,r3v&LLq۠,@Od(1 k텑EJ-k5wL`ߍId][eS0?Y$|IFlQus}nefvi #u\xG(O&&z gt|ɗn?!4"ٰl,UPYq{ZGS|Uir9Mp#CJ)ygc{ed K%EY !+87!g,NSu+S,O߿4aXP52KK1֮yxHx4x4h4`n;0^ {I><[UaIbwlQAfkan1!(2@n\˜d'e˄4N[N8=3iBC)}lpf B U Cy<: C9!nWF֞ȷcD$cc;@6Q3UZ7w$laUa[ UgęC]Er ,0v+1ShL%«kv37` c(2U;W|GD8ō6Kq=԰qt00J^wתtP@po<4==R2b4P @{cíQS.)=7C9*@B3/~Ӆȅ=xe|PȀ+3LJkWзb*&Zw,H]d+>"{p\t:+l͆2PfyD"tP!t -=A筩7uJqxe}I}A)KuGTS7G#L8-o! 93@6-3US?XuKx< ђ9I% r3 ΖuF 84]&IUUXţy}USEJROREão1 dxP#Y3`_5ݓEs!,R#<ͧ t!Bk&(Di@+"ؠ{5+=6oH2@rDojUGP="0A>oT+(za ogE?$T D>!}~PЯO` @~LxNaQݔp2xJ;L=P8(MQW!Y'lpc&e"0inmf+m47|zE#q4?>oҲ-D0Ʊ@d,F0PFT\?[ĈB@$[AF=cݧ2FmDng#|HXtrԮX!Hv\Qj) `E;[ "@uc5߆R| *H1FkÞd!5d ]0$#!*:/MHZRhR(}BJJk,bc?vR\H8MN/31`ɦԷGQ+$*h=hHAMFf=,9ZG` nZ]d26kz)Hp mḩMbT /Ѩf,r6 Kx`Mfcάl (J .T,WݠH, *.kqJe ^\ L(?[ՙG{(˔w 1΅0E,.J ?QjT.UI¡4tp;x0*I?PGczy'*fݯqK*j|/8beI>Xr|.)L ANXTP#K[vO曩,yy >'p4c1JKɰeb583 IBTC vMW8IviUJӧ}艔xi,@P\EV;.Y5nbV )͗%{$[vZٴ)$xZ-{h6 $vUp@6Djpx엳ywF,_}D `0eyVGnio>ap;t#Մ@HHF@Jx{f>(s}i?v!{Џ=(غ /=<e !4@GMl̙h 9j4" дEoˣsжSRZ2gu4mYv\-o bhfJ sL" ُ{do ;@g5{.ȕl==h]@ ]}?C::rcdtf#n,MpoÕ@47"!N . P )Ɖpg!F~1S$衆bNq0I Ƶ(s=?9E==V$nh?蟷m۫ɢRyHiAxiXv{`ZKF bj2x vD4נR4^7z3O(xh…FHXnGC3~u+J9 p_/$:=-s\y! 9(|M-5/wKJ{+ , g wΕpccI/iήߵvis1% = ګ(v}:?d|v*A#ƻe}H_;g.z$Ŕ5ǜy JM?ck7i_D޺!`ޭє$RN J$V%>1QS mՍ1^٘%DtżE#@AÓ|1렝-B#Zц,F`>sAmC/.nLg) I>a&}dǀiDRwت{~zaYmqR*wBFBcTd:c,0}aJ?;tԕ,`팈F 7v50tc) U 0%˨t0(YAVfiqc=S3n3v2(9dNwRL $}8MO列Mj2!]z]:t[g'Hz7Qf۸!,C18&C tL-ЏIwy83ZBځ*pQ#a @8둌uT,ډ*K W$ѰŮDü >x],+k2RP`BՌ42K bj8(y6wҾG݌|Z%SGX}Ԅ br,gȩDF`"튡瓚](R3&r >wz Xላ4<:(p'd@AB.h ?=؟BS p|UP͑q87((?^^ѣ$epx-7#Xr-S2yZ;/ ̻?-!$زs~Ee֫sH%Q&h|%ɎM RLMvQp0'smraLרI!ZC߫R<*8/Ӄ@й}'|ĒvZĶ8Hd2M;#J%)#85rɘM&-*%, `J&8+;S/c~Y8ol-ָ1.-]-JOz5'd T:.>"'Y!k*kȠ~vc@1F@^mM=6dVeHdžB{dv{FT,*Joa/Xfޞ9Bfh%DnkF慎N?~O\QZD2FaM Z` r1d}܇ x^_rL?cdƐ0^035!\@^9͢ Rhgp!l+όchfo̯./sӍ_!)"Sm fAI\ӘI_HSpILP  pOqW/3MMN\a YThZS*`36i2bk#l4:vSX,!宴 bbvq*KtĆD|!"َu-`hURK9 @0_ǻ?Y$?,O%v;Bz(z[{6?/Tz_F2anfr>#]car Pҵ vҡg @AӇr?Riw| z0K0"ږ !`p#[(w8lJk @H"h/ 5Akؤ,0u bz)|M)J IHUREufjq% T ڜzRE9o2}i:>&Pg5T, 3%Z]~_7R@3uPzbBsqۯrq3y%v|MCx/$ 8F0qan8nbO`(&qDQ#))ed%~;Ub9V;{D¡o`ya܀J.#ufQwk m!u`x߲K;C(m l_ijynÄ́0-D0^-j2DbnoH_#y-[DQ˰+#SXx-@NYg9^hAv?#Tx2eJAAf'#@,m@o4F_֗]fT4JT'5w&]SKH&Yƿ76(, 0yiQbXS&g~6, N?]{%#l;bO .e/o%SoGIvQ']w&溵坞&笊T@6-ȷbT\ڒ̵y[y>χԼ AybpvF߷Ja跗|Oٟ{VS[7<=m>.Lo=}˴ }]:לo8>7H"䱕 >ir<UگC$4<*4ȉVdU`9qs&M(õ(H#4*u!a8A$._5 ܰ 8-{:yNdH\4dTp`,Dq`֒u8T`}<D% YXqB!gX9·;ǡtỴ>xjsg}buC!vaSLSTHdo}JcA9.|}}tB{(QK!ǶRL"Re)Lj|'SqV։ ~c?O={;uin23VWM1|:PCZ}ɋJC`qs}"ə-`Jm+6"iI iJݽSjLVиpv;K@~eEcNnGEMrIrimRPZqE>=r;T@ܮ.|T0HmfTGQ`J^$V?MPlaV%RCݫ< "G֜h~1_.(󯺪B|4̿ArZ} @L 'ivGuEYƔa@>V P>/>S#\ވz4%31+dĆeF͚ Hqx:@/BFtWDLV7$NcU)lOFǧP|؜/mڒ)]0eߔ~ڼ<~{\*~/ TU89ey(n/ `i:R-Rb1M>'ª:y}W OgC}pEY_z^8!~}6[6-x8Zji^8a,wHaI-rtU5C.D_i{0le,Ν&6:|i 0<hP.;\ NW;# 2fZf(j OP(TFM";ҘA0g[Q-a],HǚpIdWnEM! Pe?ę7-'A\ G蓼ed φ-kP6 n Y.#P! >|NhL3{ؐjlxvw0n+žadx6U J s3XND 68+P&g=ȞQ̰gC85 $V5fb3!qk^g@?|%EOE&QH,Q!B !)w}B;i@>%ԶAB=Um+fR?y~xd3A: %iFܲP.ܼ|2_~cOvM 9"Js@0_!Iju" ! M=ȼ7Zv.jod?zjBټW3W>SMN DcXFs<]4)4M.5UՕR,0ZRvJc>LHc0O15Ex7LVx6ҥV;2KaQl}Xa~@b)mH(;S+"_PQ mF睩Al. 8F~+pQ  O=ۿf"@ݐKHdl5x' #*tV6zTwIGv, Œh{R}֯*K%hLw*Q"R|`6, og7V={H2L2D[b K7<Bj\Dd1xJvVE$E`KABE|W|i*%6AY/5orq^9,7r_EcEOur䭦HfU5֐0OPt@q Mg]U лCqߙ輼 s&zi9<*F/Vj,d5 %uN5~I+ZNE߶AUE ?L9R5xgh.:aMYѦ ', p O;ibI 1de\#,u0֦6$I,D:YE:YBRXx2LKy~$B,f[iW%dp9h}>Ě;sv7SdP磉W*cyϷUῑ^*x%3e]:{z4պ9m1y)bXߓo}Cp.Ċ3{&8D#' b' OEFj_ƚNa*6sE-j%R15=x@BcCmM{`:;M,5Qۈ\$N/43r07n=zu<}"K@HM,0N O^,뛑s!/7:XLjE5nD^`}l*H%I Htlo X\ϟ$'mς@IDAT5۫9,)&1˿_9/1hs߷}Ļnt1S۔$7Q޴(CG!{s[&D t(Ynb#e⩣DJǕ"0M7N Q׍EfoI\9Xh!y4dr^VmW=Vx*z=QZP//0c5 \."-ܯrٺzQ rc D/=/9I/G >p%)KD65ÀKAL#ԜS7├aC5;ˡ WlΑb) "bgbv T^Z Rĭy#(+! KȇG|W5PPI$ViMW)*hDF5 V.QK }Ft='UAt#oP<Ҙ,ZrZd4^̖öBz_~(1$ej~Drou: Bg.(wVlWznB?lQЋܩ88o3m&CaQAf!f_vʈtFVp1 >? )/<"!Mm{:#O)|bTZ8ɈdgI B%Yy$QK?3Cuga&ijJ%JF^J*Ӵ}Š!8\(|dj4 5G›ljpojme>B:]6뽺"?Xpc~]6~B,! vI1˞IoLT~]{p&q޼-j]kKi6kElvE^lx:mSqllrY>4YdK{#1+欱Z2PtT-MQch`1:òˏ*e"c an%g|U $:E@Wr<3E'JH5rhsyK;Kr5\m⤢XYXt*`B* N3GT\Ԙ9wj ܉~%)zLp@uwt2?{ P@FT) W]&g@0P\Z:o?0R8EP6tд% $nhsI>$=aHiYW @j.TXjew7wk6A <.D{B]Eġ SmL^J@M#H5ĩ IAmP 0[ÓeQlr`^nB!R hĄN+H|VLnF 5?Ķ}(84LGt iX4 K'}_VN/$ZuS VvP) $ <"4/D0S]Zz/`3B~;J|g/520V@aN Q)ma>.Y j>peUHU'g(kElS2 (q9Мd|d$<dH&FK{7HڦUTŨ |B‚ OtT=dTLI&go~8Rn8w |~WW ޢm2hF1Ѽ- d-t&8fz"N?:D ;n:~ק;4-ʠ_)(^g~cL l/m1^»X:/t@x̤[ZxDLh,n*3T`E%3kRcdsϪ΍OL&MveQM;b;dCP$z{J]vr!lVȅ8VO$еb`CRuqfu aUu=a~ ceN#2[JYޠ#-*bg PLdⱱ3 ANA\"sz*l, RG^5J_c` *K;`zZ}ueȚf0.)H,&D*i+#R0Vr 7!(;,lҦz)!ybH-iGsnۉW8S䗝 }eN80^~I2[$> ch%?͋Vݩv1@Jዢ;c1G&mX$+K5fU/d8GM Ac=D!}$I9Y߉'0AdEUNq%rnd LI!Us@mHCJs?=k;Bg%&r 1zb`}VqRو;F]%bNyCg=Mp UkDx3QWfȵ}̔ }3}?^"yw| YMI!hւmw;Uu'W神- ذW솟7t.,Ï?ގ?K.*)2)hP.CEQb(9}\,M'{:?[s2Nj BR~D@O/Ke845TZa ы2z O" 3…̒I[|n\7±L&| $ -W;ez=|܋E4맲(dj;l 2fxІ4qV5_0ވH]v`{N&(wSB߳h%jƒV.O"8|uR-I;(;3'Lx~&vt){Ş-ԛuG-oE;l1C救4b3Ӊ!}]OVx%2RPΉWԄ5 |[{Ԙ,χdx gAdN'E>f=tbq^܌ft% eOShvF'ۋaDUtAZ_m 9g4"/f{Ej)KS%˹$tTј 4q}{7_!B];Z||"uZn#' fnܮ _ݎ'׽ O?N67ov:Rd TR>/#p͘g0 %-,ORvv2k4-S?|~ju쏥׎mU>_6Q+`h=J6QFj p[7e;+|>ϳޚvmHζ'cPvgJW~_1ZSbĒ,qHQ6E^,Y2Iǟ;KmLd7v1D Nyd#ڋU D+"_"ŲwBSde>h5olvT([k^v1h?$kB ͠P|"MirEyb KJ3Waz+\%ZZŔߜ!/(dY@-Z3vCYCIx˂rI@R[}?dGăā">΢\ @fg)b BU^ tzArq[&ڧdˈXm]<+E!APq9*b9EM>rO#n8ZhpRb$ÍRY=yFgAu)&!WȻ/ )B}FW, K7k:}*mD+*rbUX2=|boiva"N~9e\H/L&r)qnߢ y%|]GNNՐNj'd't!~ؐjDbcFH I$E{ <7nyI12T"R ̀sg%-*@L[-7ZgIT" >WC NZ$dO/-둃N{Yz#ц,Yn6*x#N 0Jv\0N) 5f@`*ZEꔲᐪƑVVCwk.ha3s?|#k˰i5-lJ`g8>udD 3mxO.xTeD,P5D`z 1C"O6](Dzf=k /:4h&^b\ \\ 6_$qLSHp0y)^fNz 6/{q!χc`XH9 hl2X|Q$!ynd#SM\IOcFXɰ OxOH1T"0(Џ aғ٫xENPNfblot]@mZ3BrcHPFȳДkFB*J Ui=6ԏNS>HP+RsE% [0|9(F9*Yx-sߛ] ^x0Po,C-BR3 ,K9ZB"B\;@.ۛ +u,vZ(c8= n0 X3ŧByS vuf  \#_?d8bK҄UWnlFGc ƶZDD ?J#[\Gkca-,*W# l֧3 ;?3患!jr)îa 󈗰H+_wIL8sdÖ+ `ty.5dW矦 W7OS_qJ&#u.pr^ "bԅ-^uX O %@!Yg/ĺDl.N6ðJBH .Ҫ!t)QX[ p${XPs ȧVuvB'6\)F0EF᠋w=k&j&́U0wÆ儓'kEI׮~gH`2LA]O6*UcaNCG!rN{|qf`iä) > w֔gbghrvkM|<9(F5$D73'MR#)fK*z#l"),G-ʸmBt9r ~.7ؒ$d^'N.Ĩ>hK8 z]E$0oFh eKȪPyI ?2jMc :mƎ7S*$v|TΰOFR꽲8>U᠀@tZa"LNj#Q|cR|!(Kɿ3gX9%ݎEWd9M:ày/x]h+YX'M1wy5keXT"U*y6ZK#qob^ 8Ҳ.%/ha@&G;nwPiw2=#> vH`>K MIz0ERLW C?=ǻtn3sLNfHH TiԻ.PFf A}CЩ2Fe3_W%T[ 虒tlp7C@J@Z]Q>aT>X+Q([G{Fhed!AƇig'8|0_-#W` -Cg'Bav$]S;yA' ^dwOoGP{Qg8cz{@ ¨fE%ܩ%]HfAacbO,T-:N\2.~=[ޖz!Kq+ -ݟS+7MdGIZ1)-6hbnAJ"Nv#%\"}4?hEteTc6ǏʧߨSYmfaAv8PO$'c5 }LyxT+IC<5e:M&|=c}(?RIh<8sBR@(h}yp`U Q5_dzFP*g8\Fn+6Zu|r8ܵ!f:dМt!:Gv-R2AM[ZjMQuT7j2k,h3f!#]/Meq+fǛh9NBM=jJU9%/^dosfVO}qf5NEFNWf#:`8' ZN^ ü(+zߜlr btYa\(/?sn9^tA%->6d~O N.gC#tĸSdTգM$*@Jg˙%QZzX2/rs8h98dW8}gGT|Lc1lӦwTR)n:V+wC6=BTDnQ #%%}6#-C*~tLmVAKh 1YHWuzGEV̵P %ϔS  j_-!Z V,h]NݚhI$:'Afk?Ο#2K33{4\{t~B$̀/Tkdg-ȳga%ƄZ=x]hQCcF"Ra ViQbRNb4g-C%'s)WJ9a]= ~ط9%Tp&5 ߿[gPxkOFZS]"χkoDa[B.i@@nWG.6^ D[G$YI>R;/|UƸ*d -['wP %"@cPdMZOVmEkca[OZw'=Zg猇T^²$D,cIK PR)A)8H% jHK4\7KUt¹UC2B$$0'(N-w T~\8 F SE-ŵ~$x.R1Hƶ fn\&FӏN62ǚw% 4qTncDWT68gEeNi捫2|kTՌo|E0_y)'VM(C ~DX|dۥeI f5GgM$#Kj%vdzw5sJws "-YYC.ZgZ^}%lfX£) F=D,!, q2F#Y z;{:bhYL Hst쏟5,j3٠Y`I6}|0Bzƺ2D+N)݊6nW\?N)U)JN©tCR)/tP+!tAOjhEـj^u(s5G7؂ZD;P 9rz| jjm###ۉCcn3U=!;eH9&Hf2RيJ5PSEv~ &;DwKX DӞI]]{!.Ia>2,~Z"F1gXhݿztIfb=<;Хǎ/7Y[qa5yO hM@VD5=ejՎSËhH4KlHVR3g {·VFh=,x@s#u++Nd@=c^aEB$\,kԕ#؄}ڂm\.ũ>ޫav:%aήG.j\.p[si_&"ڔbwFV <{߃>UI| '=VW>5&`@>頝07P~;uuŦRx(1)C&`Xa"rS`{Zi!4d'M>FVQIfqѧ$2)!nd6eY%Ewt,LrEXXL4 ho~ץNr| -,]5>+}Jxs4{ߖ/C9r\&7 @i8Y!6R+~'CV[>Mh-NRETn"zU{0K?h Y2ȴ@X g3- N?`ȅM񹺿g] V)[ESh!=N׉ i{G3)Y@DDWy/t$_ ]tDIv W';4M,=WlIC<$?%gBYAMF7\[Y~~'+M* J aZޝ:{ D}O^=$n[)l껸.pBfTR U^EsLe.S^"$j~cSʥi,= x"FSwޱ(x2Nar6X}9"ךitɓ3YnbhNl<W0JZOL=W.Q~}uĉePV#rE*|2 =#5eh6tɥ8>]t^2yK(?SsEY 7 ٫)Dss^_PM9ggv=lec~~B-4kFi"7G:d+]y=PPѓET;123p+䧩x,WocAQܐg sݙ%ePDBfw% BF>‹F<8E JsNTr/oqyzm$|7Q!EJЙ[Q ]kkȀډ5r!lGFwd=["ISq~s:Z N*ż$Ũt8t ܩēgga@֮ΈJɥ{ EޙNݪo[jb-e%"AmtQH;RM4?29$Ghq85c.F wo 8/G#*VŎѲLEB5@wx?_O7{q &kq*uLqe͠c[U1"ԎK[MX&؜yA1·+kHU], 3>o?^OxgʏgԴmd@C+$d:FAAb֨J,[IV%: OzjMJ_TMi CxRp&M26ZQx#|Kjrېs7DRTUW4 XwLj{YM2/_{>Q8vr-j*EARֿD%j7G՚\{H5Q{ޅr㺘=f])OM=sqKu}6{Țd 2|՚Er)t|h"dsJg1,w֌So[!}lӚfC@bmthPXz@sH3 fT3J_dq*q߱baopD L#f4Ly\ E>Ӻ +CCXc^au(,l8CTTjIm^IXArg[5Ct(2vkjC2+[XeUXP 4 B@P$mIli= 9S.,ׅ2a{kw ̽>] `"J*Z̾yezlE'S7lk% 20lt NjKԛ% n?9+7m,IǫaںX qCT qڹ3'Y!&(FnJtfrm$p%DKP5w^ BtTk԰y.zR[ފ۴.C*,>3;->I! (̫i\ZT;ktma<[˻?9E q+!5d6b"6e@څnEŮ2J*sH IJW$ҠYS߀;'zs-fsJ%д*ϗwbř>ׁ?䱣g) D( U?_*{C12G\jP eP4ӞT6Id3~$5ilv}4=t"#E;5.EbqVmgu}&f3"Y=! woW6AjUHǙnKD#dqȦL,G(38_ 0g $rS%';kaM>Y{Q9WOGpfW|!\6ڼO (u<ԙ[n\ƍQPFh/PLutVp> .-p)N{_[̅| 8 E1,\2HtHk+Q=bڐ?ZR@3  ?8j?;7vĮJfYqYYب^5Kbzz(0q-ݮ[о*AtceY0/G߲;J)Rʩ@!7$ӛ!{Su2BMrϖ*RW+c)(4IgjF Q'ّ%sR"URU1G(G 'yk !u*8-6sn£XEt`Gk%3E `GO4 $<K_0 b%RE.SYГ& zCkrӑ ^ݤ2%m܊ύ"PD)O' I@IDAT[>=Ru`S.BXC岤'.U@`.rU <;z=P svf,!NO"Nk: o)aKqd><.oI c#7p!J1Q*&6VOСC #:-Ao`3utà6+SFp =Y;rL0R)x\Ghko'RE2E>L"b .<no?!NK@Ϗy izhvQGQ27~g8CI{Ƞdx_}P䦽`ʡ.ãi2:i],Q#ln& {koozZ &U`AJ$t¡VL0|< ʬxjir|q】Mt` YF;:hzn;$.)>NO=$:)kcaIPakE @Q;u3Kiwzyܝp}wc<]:D?#[7D@gcEoax}XIZzjGm,HuVahsq e*0qƪ&W΋&an@ls_jښů%a x'oli#>t^.<צ3wF~lIx,)ƮkH Q uaiΉgԸ?m '݁Zdu[FGBSڡNNRtKQ}yCWEC^/TBFnwGLd"B1 ܗ~r`0Qʼn"ʹ-^E234Ȳ1:x S4nJ{`LLVwT#ј0ɯQr2(f4_ t~"[prcX%OzEFԤK$:=r@;Fuq!Q=:_99`Gq@$K@9 qZS*7G3Ī0܌Zlb!GW iGs[8eZhc#cݪns1ݢSQVDPx?A, Eԑzdm"-72gTCn PXt"wtJA_"" fA$. h uAB#zQQ̈5_dژ 3*%^6Qo:hBo&*$|gKw q3'()3QaGj:Ė*3H2Rl`8룿@h詚 Mcn^*B|"_ #_?c =@M=0.~uy- -+k F})ڂo(*,]`R9vK!8 ׿Rcn^ ¸9% `L!d|?pC=rW]cf#l,Y3(c'"mР )r76@ `C7i,!1׃;t="g2Qi0]-^jJ(˾.Bzܢ7+dVoiδ$nNSW>=>}zׅHde JDȦEzF~<$h8њ w`g{u"ɟTê,E7$1dPOl|tI:a<Ñ&sf`% I * B9= 3q3D2 $ io7A0dDpd5~Egqɡ68 Sbt3`eZQ*eі3HP Tްh&5A(]Jukpr6V`طh !&O1` EֺDDğ1B=Hq/C.%hR|r|n= _#5q:d5]0jxZ/x˻ЋWv\$GWWԐ432'c)H2ҳ赭(IzOE}4ʮ, t{!]aX|Q=C/@zב6jZVnD#;kҋHذMK/0 +)7qL߆&L$¨*DYcxEQe U3&~Zݴ[6GO+Xc Gڼ͈gᕠMF\pNқEA2n8PQYޒɤJ)B:]Kx=A_pݳiT2(ԔDR+mJp3u !(EO0ʜmfvir dٴ_Vb KKVeWm{,hĐifϋ=qx 3ML5^hc43fPxըGTluoY$A,nn<9V1,EV/P Iп~g*($,_?+]rsFs֧HŘ׹/hEmRH=ѓ\[)m8 Q +ig.# ))ڗPԗ: Ѥ &x6$f=Ot9vPLTij G>d.P*澕@N&mlޓ, bil(!g? U|8>. YD0f0I^-/C;<:E/1TFhf3&^:EU{=砼)l R2aůQGN gfvgfS}TL/1-f9A\`DTO ̔7W~I濬ggWE=oYPAVc \܈b,6ƒP,w%T0?xyi wU^Z. рFeᬯd dm0ЭKA{1uRӟ=FPZXE/un`P+da/ OSU(VJfS*2/mAVL.(4(HRL(}Ҏ ~s(W[&X4気M\Wθ=U9=fM/ UD+Dqdp1DV!3ȭ# ֝EYp5 x8L]3`9 y`4wMJB_.U/ '\CG$CGƳ\q #q08 't~䞻ٍWtP-\Йr0EBS*ᚩHr:Iه7'J5C"F!0$'FcSÝ._Y:1W٬DQ.{?=cZ9Jxhf(:ιOb2_hj!T#eRiEOk(p8alIu,@| unN'ZUU:qϤ^(^똩\]R$%(ָc#Y6]|)]_h|~HJzU̖#[f5$im1* S\Z ,]9adx#e ,9~okne_B}ظ' H}&, T˿580lns]))%18qra@b5pP[;w===XwNX }1Irյ*0dۏcQXO8tyEEhkB,ko^y30ZzG ۫س3-SmeLvf Y!Idi|^|W !kbW's36Cn[NGcJ b8ϰxdI&0w7;!3p4zk>9iǎhh=ҏ8!O&EVO3T8?eSa[\Vt~zJ*%`\e,ANr#HIGQwhy1NZ1#}GVݣ0B'$VxNJU!czy@l)8mi*Iy%wJ,a;ޯROv'iT+\ș@Jjx>OZX"VE$ s}}Ϟ)ѡDSRśCdM/_k{XwL:v* X$I`{Ľn] DPqYdVcd &M,>7lT4wn`v}yÖ_ujߢ='s, WPy#L_׽S<3|a6@'ɶ^x];cM8]BxI6`Hu ȇ W27GA4[pr獍Ta^ 0H@ҙyKˤd7 )jDVfцlbI˼u_0I..bq[C~؟ظS/:g@b# DhLjoBJܘ*?U-甾秧?o/?yp]~T AL'}e̥C6e ǫ!z)yMΩ6"ZVkF䉐T!)C/g4vMUԋ3~66J`D$NEߦɠ Mt2pZdBFϖ``1^8p9\LHZd)$C$g ͢Eoo_;UQT$yʪp|o_%s8Txk/&HQ`~U&s6OyɪshJ$|#u|1B&0c9i GL׃.ؿTGdB?}2Ř}̎:ՕعLƛ3cpKqQp[3x(0^9)uMxcJ1V PdĨۈk< ׷̋|xK>ŷ)w椛<Ҍvs:&훳<;Bߧz$dzo8~cs5OXzsE\MKis"vty_L D*v]왘*J &Cr8䁏Q kX-q 3p+v?C}cw(wIkيѓ@st#%}BLl7][QlwR x!@`v:qdzoG0:%Nw#{ǂm}DRv0ճw“H#&EOߝӀ["@Ϲ˺ "*7+p'P[s׵$0(/Xs=EֶV Vc2hyRU2~zi`1Y|]r ie=h̠f?ħ x^y2lPu>2C(b=ey,3.}VQ'\nӿ8A0 oŏbIP̭cz|Ѝ53̱TH@mRE}߄WTA9S5J)$DQ` =kYrZÃSȈN͹bí:M[w`q/F7ϔh#YRaH(RBՁ O=K痧|:ϊ2Ru,C+h?W4F0I}^t6hN+X*PAV6!vDimL[ ]mB sz^s(bO`$H"_T@Rr@jQMbs6Sp#R"h:'{B'ˋ4 x},&I%2 wZ9n 2>p YDI;JFy=. 9U#:4J :)30楰"oKh>Y103-! #T*;húUFu[Ԏmw@Io=ѢQ sa<$nJHz9DY{p d萨qǸ.AIl'g@A;(.m`eB#.RK6'ZEoa4B~mOiX>B)E_~ 8zZsn`ж9xoCԡH1Z^dqyU`> - WļXR>@sTm(>{+H2eQe| `tp ++|S+L qx$AQ%=O a::9 <+n|u: }X3,eK>)ۗ>k^N,U5k⦵JNz5f,'8 "9_ZO5 C\6&Go ~{,i;xSG8q{Na1 bXrkvzzjt\!,|-IKmY= EaKn<2V b2u:={ޖG"s|쉏L@#ZUrdothMwFnʿ1opg\-#P eLӦ%a?|ϰ~ivW9TgeZŰdԷ[6v]¢ ڌkFyQ ~%蒐LP dS`*9|-p:bcqrXbC,%Lyyh8&eJN#@iTr[+Pށܔ,Gff5BggăfWY@тm^|lW U'wR3&Bjx*e[~t;|E Q/z$'Jy͞Tz@YDdO5qƠT{&@إ W!xzsBc IBdqS^6CѓJ$LCnD-KfF7yLnxXSH7#@һNqNQ}P|ˢ0;)0nV: ||MDhZVZܖ mz5dTjA }AcBipre0@oVz1e Ћ 'CnOU8kE) )N@'F0mf~AZV4Xk'X!V@&Z0~*3yf]IRI͎~7J>/OX:Fcy+jA=o1DK*ǻdx,`ǽ >7WCt˲5 8GPyL/QDR@U*6NM3q򁌆]hM+Q *[xAd}@|${(&Q9L?4:]CHÉ/|#d4A E\ `mG=qjK:Gw8'+ AJ#ZÒktק3 Y4yuar=-{, Gsz ƘXx)0G"U|)Bc! E%:tYUi压0ǰlJHKbJ70t.PDK KuM6vs#M?i)ƬuF%Y9 śT$^ tӼ;`-*mc*+fBO\薛(%JbWmӂ6D.!3P폵w' A _tcT-3ǥaW(,ub$tWP K  iejD%ƥKJ[ݧA#<8⵪xN_Q[}%$i 63kըNRdHYAdSv >L]_'$y^v?b훴-[f d`[v8T brgӯo-3X]@Lm~Gk>@v0!pHW@hy'S2їLQ]X?J5ѧޤYՋ M'\D5a̽N'Z{wv!jZ9?ZB_9p=J3Ə q1"@_ePTI $YPEPr\cI!fr-ӏlҐڦL/0!y |a k8pD]@6Sn,+LG k`Xw8 yhR4b<]0nxnr0޷T,T4Tn{!>(߷ Ie\:=F\`s_ߊ/;L\Hm RHof)D0G//'Ƒ9$ON0fZPuqHp?W d*M/W3hWKkT.vEHIVq?J!Ȓ@EH(G0Q e5 YLЁ.2`JԼ<)B bhR޳ֈn"0sΌ(#kGP.yBt/+>5— |hdwN #Z@w/wef4a2:2N?hkt9 }O-B_ula:04'5Ggw"K3#%X"L,1[oPREZh0"W:s9|K9?P:iʮUy)K+I? &DNJFohLgb8ThŊ$XN3KZV(E-1J0IK_qm)~dѦa +@^i+6riѥ"ne")8Ken  #0;{JedJC8œ+ 9+Z @,X.9)̸ha4Dv_۟Y״y6 n)K0$ LHŰkĨ%dw$9w- ÅHG7A^@d(ՏXȬ`۷K<5jicV'Ux\pLBb}!Ɉ2GmlSU17{˶Ebc)b#nO[U Fve>h葙h5x!A"&"ۺAU`-.4Jv74|z୩ŀQ 㵤M& u!tŗ;6!wVpQra{"|"T/>!,4'7p4XI}e,|4/v~4  :9I#k0 M NZw tSXqPIIP_. 9(yu&´(Q *<ݬӷ1/.&?V9sé+3>ڔ`3 xơ4eJVhmZ^"@z>Rh}n؜ ?E7lHcUͦUQ+h`MRU{-`;mI RsáEgx|(1/nje}Lޒ܉otfQ( oYegu)s- B p@ lN02ģӴ*QeZAiivo9a4T4/#Nc92c@i%Q9Cy}UZɴjTCdz^ 3/{H x'f2 Irqi~Q &m@/nENxt.2%bOhƲmăgmVSN$iX1J U`ED9殳EiƧI $rn'Cv>-@69C pG/GFĞ͌ z"^!莓 ejw` KTja p3[lD'`ĴѮfG<( #`ouMytz_xޜ udۖtYpe G&:@xy;;HT2K%cJbzY+ibDڙп #wp'̎ j9kKX%;Jx9jk DmAJZ%55"] L_y3^~xLD&:28?}Y[aqr1FA#>cM5d꒜ =[kbm'>;ib=A"S cZ"Z)PּU% p;+נpxH,5Fmi=lI%Bmx|՛CPPY41Gl%%Nن( u4Vtpc_r]ΘBг"[ViKȌb'1%=y@rڹ6I#2/a~zBJUM_W6re*Nbo~ux?{Gid|n?e"b*J?#HYIFHVҕ[7t>e]lr$96ng.k+St,NYo=ҳBko//OOzҔ4z9,<圚0X\܉ѳeŀRl{j!5YP%t&QYF}{.ڔA6<=$Y9#j.ZHbtY^"ٝF[`,Yee51GB/AׁM]bt! ,]6oZ( ;?bX 7ztz9Ɠ;d3#X-rh)r+khWFZp d% ?'u![]Pfɏ*&PJtm{Vk#rbɊ=#d;*Qe_ ʆ{d%C҉s2Rs;gǎP̼Cr,u%S<ΤΈnEW#qоu{퐢sPDԳ 2wq`|䡢~ŁP4dBogh,G ᛙgu9oPo]XK$mt#}= ˼nݽ ]'l;*#}N4J;C.e{;>/v| &Ʃb*FYf+u/yo\NM7r6 !֏p?|p uՄȘnW}&ޒ(P)Wt|j9;HQ VY $Z7vSԗZ(N+۰f9Z_dc_5- ((أrN1 L tPa Бjo;A| Qi=ˮ3+rh_oB6_?NAV }nf G0x+q;FK̟;-8l+Qf|VgC_77}tb`ο]#0aO*HmJ!u[!ʘ8;l0ܐPm:g7ҝL;+`pI=y^p)TF՜Ğ؋Zd7KT8WFXM?ޒ߇EY?{!PmsL"3C4GZ:C+NNCb&dd[H`˼.H6 3z*u]W^@ yrPˠh _v Ǚ| IV"5XEeMg52 H!3t B=Y\1nFBa_Uscñ#[mb}Pk[PRUe=Nο^bW:WwlAx D4%I+w  '0iG؁I8GcN 'c"Oh(c7o+%0CF'0fMoB$'^<jõ Exp>ͫ"|(̒Ó;lZt 8[gAHj5 R6Dk?0E~ fQZ.u\]v c-dWjtșw^4r2ACEԔaX~w Rcq.;B.9r#v'DIDa5u}(bl:PdUd۳@u94aTYlZփ1i*EeƈJ|!F2}N=oc31{22_,,qn3 ߣ1'.-(9|dΏ"ȌQ7GhE$#}, 5x$D̗(աU4M;$1*.Ef2Hx9w+ÊS`b.NZL:.0F3t=qL!j:ӱkKEC9ƤpQKÓC,* 3DIj@4;QVB1_DbC}U7G i"Ykm^@ubR{NRM03KN2㟫 0_^Ϫ(Yc`h_;elSk?yZY*wH]8#E T(XPFL0|#|wzt s79דnG o}?!S~PX3lC ѱ X/9O@֘ j潃b "J+AdYm/ݬ̋*dyS5dI9}KN]ǟV6ްUT%;>!,ۄMQDT-7?<MuTyjz҇/u+( JKl0ݮkc1Lն# ^Sd-Q[0l%j1BdJ2(.XFQM3"q}!$)1(b#pK' BBJE8>A$DEu0`-Us֐vQ=y ظJQzsbt=4¥̦W \qX"oߧY^DJ`Z>!_4ʨdhHp@r 1!wz"L-P桀*a1U T> g"8{HSߩs 2|5$ +W8"n r3 iW8^Լ[xiڧ/ 8GNG{Z]JȒ_ܸ1n#."gHI 9$x{ ՠVQ* ܭ/N]!=*)DDL׃xi g:gZ=wI^̓CN| `f@kηY}L51282M##zލћ3 ppK3QjQ(/U|E^%i," ]mB@4E6dXjIYO.ٷGUEEٚHJ>"'& rc03 #{, l%v%jY8IEGi{UzY0/.9^shH"kFnǍ;`(iJulRR X[U%uƆso0M};Ն(2zH2g Xn꫌O[PI|ވ:2:;.I.s2Z jA:(Eb0@)8o5\p]%?hM}y(kPQݼ +9%E\C KCc#0,NIs1`:v|||q22O~.!ai0*;P 9'#)5kW:Z$$>4_%mΰ#n?B8{b{ny4FGaX ݙZ05h l5t; .\Pci !"]:T19aC =Y@&r7ūG~:( ` m&J`ܺO'\B(C@^+?xto PU;[-p`̴) HE5)v@6钨V. :@uJtΥN :>0 t_YeŚ%f- kaweT2/p03Th/>`!_::: |V%(ve&DH!lc5PWӭJ\m|֨)F ,LLs |қu}W9Q?U%OaPz!ZIJa.0^ P_H4\M.(!~NbYvIgVp#E-IB nʽHRq>~W^M=F 1"Η#׻k$2hrBb颜Fk7S"umk ^1s; "z)@xop#]?SXGkO%_jZE2d T65 $X_yTͷcT EJXb$nd$dje7 nhvv9n3&M| aU&I1mRDp4h!TNL=p,`Zu>ulh>͉ͅ&0mJn\u魐v$fqc g/IY1ة@v[#pz:*}aKtAJiMCSDF$1$73ft:KȤYwWx{rV@"3aq4g̱ *TZ+5/AU ,(2m[C]qo[ŶzTY3N#xtǡGfVǣ?UqBY%R Rifmr SҵH`дspG&p 6u PѨGrVQj GeK_QizihJ}Yq2yYdZ=G'Ǵm"p|\Q&~V34-˫W.6yZxR`h@c-Y1|:&1&)^gsAr*`C1#/4YAh_(e-qivwpT U&渧D lySgKnp_PNՔbNH|ZD.]f[Ǚ se ¡o }#0>Gs$oTSv"7 :tc3>ym'5RgB1q |sSgrHa~yo)!'P:OHR*KXŒ9TQ#8mȤ'zƮ!'[/#ք*?jڒF41455G7l& L>; 94( )(ҔCM@T>ݝjێqF@D3_a݅S r $qj1;J*ֶ֐XQFD laA0+U?/'B̅9-:׃X٧x҈'K!z*#vI 1'bp‰ɯ%God"rć/q7$=qTXǿߪE]$6a(PcbPl"Le(g)!q %Q\LĈ#pP cu?r= ?GDed@A_=ZR2Fj"#Otu..H$7oOD3Wԗ'\Xbry8j?F>.&0_KRH 54:/x:3rER|>f iWK>Z kH9i< ÌGPQė kDMu 2c$1k$<`ȇ䕈hxy?nf4F3B[w{˪_ klYjB4i5Еd (Êd%M/C&kLMZyuUO_l2t;[Ue*$bV|pkRԀN-nȵjvؠy¶ !U\|UmƱ1-sΰW>Q:tjx Ȣ; W$JD![^ReAn$*8QH"{dd!f>+2Bt#v>/sNyZvz4ōv8iŖ,ȧ?p8MX>Nl3t@ z,^eQýNʼn"2@a슡KNj+-PdGOv=xJVrMe)8^xU K{?gP~&mK/%P],Sd+}U3 HV~,+>kϊQ #_lE)2pj"AV[zv"Li\ЊV#e>?k'O*eZ^GBYO"1 g JR_3].2[JhɼAh%z+hO 9e@~FlY]֏_OΦR 4%` t(?t/$@<;ᚍ)sWT8Gu!sbB2N}?_+$޾7U,f话JL`]ѽ[lbELeu[|e @|e}y)̍p+ًEe}?ӯ/>W mPvd!.?X6)yZlmUf bw1VXaWǿy쭍VAeg 2jE bZf28Mu[[Ӄ|)/Z9ZY.{&_~ﬗ6_j2jv.->;/bxEJx@Hh:뀋QO hh8f\ۥeDeUc!o cGw(+ۜ)+2 ding~ |yaEIJ%&޻N HdZ`C/Y%S[7a߸dNC07 ;XH`KO1V4)n|0=䓳U[0Eafĸ8e~O\ɶCvG2**EEϹt:*aE!s5ApҜ$ )y( 1¬Ǝo1EV d k/@1*4 A/{)UmӨ-3 a; u_HӤ"GLX'2~t N wPAk_fmlp)qU3DkHz!q_BLq%A%2H#R6*2XSFE t,X ~ktxw߆OF^6Zo=>z _UC1*gaR&VK{ׯ<>kD䭭yHBg8r:ŕ=:Ez5)?$DEs ~Y}b^t|'?, k2~z>ݧDdUHhPŝ5JS藨J(p6X+Ib*v0W}bA'16 ٛf"6&Jl5x˭D؋J1;e9S{20.~ b'򅁟ոxozZ%|( [I>j;_"ˈSuGvIZ1XT9ė3a=MnQNbL3,:|yYWGP8X,20O&D:HJssӵ qMܥtBoḰYXJd+IF,ZwUctX?N3 ]fu#Ǟ"y"vy3r`6^,awtn.hPD8( )Ѳ8]̌^0N! xM'UI{"Ue{{}4hO_Z"Cp Vi7 ~\TVq\bAB6^tT!x)(˨D娖-i$NZ/ 7b K-'(J `Ook;w_AMp jRYn oRS;IXL7w7uli<2l`u-qΚ~ UXTY o-ޘΑq}W9k TvlCPS]w|.n qhs S& 4B. ``lK3q,"g׼VpY)?m$o~i$YZk>԰/v߀14KDچYFc:mWA{"d\\_Is$h$: 5W9ka@-`jB%"н@GgWeNa!w$m_2a}G=W"c 2!zLDH.7rm8'=/F=+0h_iXm`ԇZs}+/xRVjـ}Lv.W_[#[wfqygh5Od&2JCy(P iI[CTz"jDvYMfX?/IϬ9sǒRڒ]tE_&dt$'fIwEeJ1CwE={qa[I/%pw̽!5{-"d^CQDvlK6U|XR;s-M.JcU`3տ:NVayujsPpaS X9Y*f@28Ak9vjPp{etH e(W c-phSCL% %7-CH^3I#HI %mu!O%;/rΞɼ,x \#lѼ^]n#ʩ,kRmfr6QvV$RIQ z=NHt4,hK|"L/o&IYv'u V853&rĔ# @ ]슩Q߃iii1@ F%y|+؊C) E[cdN'DIYCgdML&Ԁ-‰ KNσ0*bg^!4-e4V/e>G6b[FR؛p ?rhRȭIFҴg&@Lؾiq4wR~CR4qd"/[LyE\[Q/DRTɰQjLT<͠ ͰWhE7QV jcQS#טePc:/#[CnBoZ<4=砀 }MS/XsɄu(^$zB7!A0ѯmbFެ9324ϟU0wI=q$bMj'/%lFJ=>22,ר_ov}Hg @4t/mj}BH65zJDV G~ՂZd,2"%J-H6ȱL\ſXIQOaT$Zpdv0HM68oE}alܗXa"h5MX3XLtȬ>R([$)ZwŠGX#I<U 0sMLL*R3~+@1Op61bҐgV5Krek}D{5FRoPCIr#̼0 TwY/Um[Fz"5> Е.$Eʵ@L YKHKu[ɴ;!#@EnFgI qZon/^ Xc"\WXJ5g 6A5IKjMo3 ߲G&[e8Lhq"ߌ5!M.lf_R ̗zq!.T w~m I;56R=NxC7u°5glP99:Λ G,bBNȡ z 4<7%FƓ@Dc@)KgԴX*5BCe _*~ FMrr-Oj X:MUsb P: ̝cm_نvlAuf"g$ѠsHxE. H:2D zDZy:6݈4%/wU'0X?jHfTft@7iW+U-饫vkszY /[( L8oUg`a+c >t7'{J3b^¿} hus܂QW7#_,3 %N4`0xwZ&,-ylpI|l;ː*  @]+0D$]^V,`Ll~5PQ]s)~ϗ Y=u)JNTdEL ឤ5&.WQDG^+NӵUd8ɑrRjWDqpSA!x$P ,?kb@!aLÑI Bh@>!*Gm7]SQҝA\VYpaP-|~^Sƣj*= BK CZxZc^PM1kx [4͎#1ꌥ.&Jkfi2Pmq"ԇ}e? H25@tM#cQ54_8P@̣ADbBF+5HSq/o_&4@n].j1F ͬYsyٸ$=`ԹUPl><U{ FnliDGEi G5Z#vTYMmY^D^#1U( "Sd gZ^>>5/'4Of} YF&hcXy79_as5Pg"GD\檶t+F5;<x%ĞdkoaXlڒi"GUbeްWi^/3uLLc!&@LՒ#;C  (l$pqjn;{ݯ~\d4`-Z[/rైJ̡)&u ZZ҈Wۑ;8S GT-L6UQP/'Vdb %q 7n:KWlte!^P SYϫgZ2rඥ"S_hZ4 \oW "5^$NEL2T.i s|Ыa* [C(w ZBm{m(ՂeRr!n=렫zA? s#!-^$b@Ϫu,#w$&nfdl=:YS6 >y~M3Uwq!?M)U*jPY)kQ62+Re]rXBzy1HB.`h%:SB.s"`,X;@tO"28W v2Y㐙b?&7ЫD>(7JAȽOoSW> 3"$noeR |VX{oR$RZd}S@8h}88$ uxiþ=KV<^ыbۇ?͠R$ ѲFB"%0#ݺsf 7c x*^8Y͍<׋&x w2CŤzJ%j%7!cnGAz᫵IFe+U=./P(Kua+xy~Z֊Sz+Jy;> m;ldvҊ1R &Z:F~\wkPҥlcWxJ:lWD^`RTT!eᵍ]$#Ձ]H=/FA;+C:)s1:μ־ZK@x#f8DVi'"HhdVvnX#E?5Ћl:IGv-:lD_ɟaҨR(.DP{̦91%DϨWh/gj#p`< ^lM8ܶ7ޝEh)r]2JߚD9BYJ)E3k=Ȳ.Dm +s U5'M>.rpE2쭓!ۅR+%a'\ ҙ3[e"m)bhSJ/ =Ґ_'+DS3-]]8@[VӪ̒`Ed輷ib2 4|ڡƑ[Tk8hlsqb__׷NfQ;՜iQ[e8h +eP*"ŌtgQDqlm1xk*Y^Zܼ*nL gyR2:m}8ሮ# s$0SڪE oBfnDb葁Y2N~F!ÃsrKKw  D)sD }S 'j>Rg׊zN/v^٨=WjSD >ؼf }QM*1.CSl,AX+Fe2p(u=G n~iVFχ}'#R3ߞTmSq yapXv 0;A\({#ɠ 1&3O`8 Uyu%G[ ,RLE#cl |;$_ .xw\ zLSKbDNM%^V@$] 3P-LcΧS`s}vBHn d9YF0DXʰ.vJ30ڟ 2a>7l@^QqsGRBM|DGlnBiG<_yVU|CbwBw4_H/n2`f.te44`> x0ej0"p|䂉ĽCpr+'TuppJy>%xfQm u_׋7167W8ly\^*3,s7dඬEDĉ QJy,}!1º,jGBdMckBmfL* 2*wy/^{[|}Di{@ $3 )B7ڈ&i|Vt!0&UW]4`a*½!տwFjap5ՈT+jW\ĚOh\eosi_U4[3RG|orfM!!S:PhF`Z4 I5*R}x¢lc~"'5<nғԛ 톏0Pi _Kօh"C FF &T|ͽ$ 'HIXR +4'>H1ZLudJ5**|btM&E~\ofxiɰ7o)sUSRc% jh3#ԀS|<*=dCFPR%Cڝ.7GQfݔwj>CR0nQd!oLq1񜈱aLd-7&C­M -v!$5ͳN4(fIϪVXY x4Ӧs=n}uYg2`WwF.fU—z&^LJJK f\67ms&OFQT>8ָG?E8BZS6h,Î,[߷e(~"58ߙ݆-ؔLzsb?Vf34| Rq(1\)Zmi6Tsc+0:64!گ^ *4فI05L7JJD2 D7kA*Ϸ;v.yC5RҐF"GQt۠"CqgRofn6~H:w1u`u;2 E0>&[,=FP9/hq ]H4dx~_Ȫe3)XX5Dͪ\ w4 8?ʷzϒVfdFf9 gkeTHK⣫ނ9Դ/@AgH!jI7)05Dcg@Y00Hªz 4t{f{M\ˌ*dfY]3%'2Emq$萚hoD5jva7'-֤D\ 2u ғY ھс]RTy*G p];!P;ȴl;I]>$1"UU@ l)Q*`#ldFPSJǨXw`ā/cg'A${lY\/wvv,m _G#.{wK1el4h7vt)Mst<pƚU$ ď wuFHV1a|Mp* ' Y<=9@ލ䂠ie<.=+):+X FJIfkEh9p%)LM[V<`̎a".o߀-Jw[rmwݭ;X 묨E )MgW=+A(n(I[.W}#L!ZjHIvA8#=6/z}e $aA7O,D%{Ȃ&dRJl4EԎ vmMժ$ (ӂ9su h)CtcO-Pdl(mCcfs[ Xjr+~NNpXHC7"֛:@ V>a=Z &K|@1TCJF%ϖLlMM3 2u]'Œ,I.IV&[!w]Wm( T':\LT A@ #ax(#ֳܬo3#4QƽZr&O( '_nZ69@r&t3pϲ XpyChb4R]oBf+T=9rUzHd#$s֍H!Ų"V ~ҤCmͧBgКPL0zM >.K_w*S'(eTOsIVeq)uS˒qWŨ2Qo߁u`r+<򄥤u TTes>]Zd|VUB5$ۆ"Iaa4[*/URp0Mb&T$n?KI W5!+nDk(YeR6Y1%Ϋ>J`̏qT :3S͎dfEA#SF BS3.YG(Y"CSq!<xO܇Ի4/lt$8*.CfLg?\%Qc?ŁF s-U=F 6h~qlJ;n|e7ȷ YtL7s,^ӊ 7kU(!Qڐ`gDlpIa 垟ǝ5[Gr.2? A˜,vM@ʁ3/@vsbBwC[y~"co-Ų(2-fk⾴' 5Z:`PnX6ћ=K@s%q l0{ߑJaoҥ>  !}]S@?إ$nZ, }cZ[Wz6#ur|GRZ(.w{ G0t +gp (H@i 6 M !S PӑHqiDLjJPiYTDlܳLO'aCe>ʭ-~RW dM-v6"FpԺMIX 73臹U|j~:ͭ򤺉xdnHMbH7T7&SiqI)l&3j럄T2颫?_ N,7TǷ',lZ)slp cGBb ,!.vTldl9~r\nZ":@uɹ'"Љ),xXd =gL~ȱ8'Sg9lbz! "6߱\ &e3ky%pOep.˽pPЩw1_{w1Mޖb:U^&AnPEx7Kk%X֫PCNI f&0v]ƹzQ]^6ؐxܗp9i|S mY+0 D+fA,DghzYBǏ=tի\V1 ԺJB?KISoO'EϏվ!)`|x шjv9_d~vӦ >DA®D 3O;|!7Ѳu5K"( )%D-?JQ6~GmF`&'6ai; j:BkQh67߉bG"k IG5Qn*x&Y(V x`=lF6:q9xؾ-)+x(.e#pGG՛C]n$]b]IcQىv,辄_%#C'HaRN`6OT+4EqmEG;M1IPj";|0Dz&DmJܣPHŇlCӓ!o 4͜s4i N!8c>ꅎ s{2pDߡHhVaQ;hpSKV O[ѐhmL)+9^8c}3D1;[p6 eؙxE* ~װ\}<@4 YDlerɊ{U׵Aq|hUdns:N"6Y"LY6mJ]LT[_)J7Ln.; џM'1s azS mP>;3 |.T0"(PI˟1b<(89IbV# MA2>:OUvpZ[سp*zuc/-ԓ&KY%_^~~- 1QN -ǥ2T;܌Au)-LՎֳN=N 6҈h䩚ȒaD>^ S3"JY(#y=6'K}i標m}ALF.3~.'%sb?_ +Ù_T?jfԼyfחOu$6L,VRLXcs\8ފRj4<>iLJť=gy:C.2$FhdۏLJ8DZ|>;d y<׏)*C'ҫu}F,8`ۇ;@eECb8TRE9%i$M%}xMz3f!^jI7CM_E fH60w|&F:7#R/Dv]PX믷o[W_9hKٖB.="><8Noz cs6ƴW[\*J(Y: Tr)M0bӽLv}~{~ Y0j#0\zcxNb ȽFlvwuq>Y;x?1宄7kI! ^|Љ4N --#IKNS>kqq.# Pg?/_NWpOSqA/|_CSW"@2uH(.g>Rūᨆ}UHx$ڡei)-jRihu|>}T2} 6)X#z;̝w 8us?nEɔ;pl~]dK3hZuKAYgA_ٟLGF򼳉[|Mx'~3;zmlgwkTɺ53ŝ-Tc H#zȢ*\΍;.c{Z%A(w|IG;k ďPNxܪO Cӡ3^̄js¸=#n7nf \C6j/WnEXDϋH X$]KzHX÷¡L\\kI-~yVGZ@(er:$Ψ·:b,z$PG_T9FE_*=Fh|]ü@O`~ų8O 4U{ŨK.siaeԑO)y֕8-)YjHqkB@QڇܫNHtyѸ gB#f;BزtGXęgܦQ Sٿl,Ǣ Xn8~Ә";0hKNI(vDN TPd+mL yl"tecV5dNMd97<=V%D3Oo4 L@aV_ F]WtO )/E6$,7#(@8&qĔ' o΂|]0&ZtKP*WX1%k}պfN5bXMCpX{+y*^Xznxɟa` # 22\>:m{>j#lHCO b35o hzrkѲ"}Dxo P5*{lC-?!y0ՙќ܏b"Lb~2*Џ@myԲaqn%pLV#_Z% ي,kY6.!B#H=2LU1IѰԿFԌ!D+eZz-U8i4;sN-Q]-{v25X K'-XdfK\УYQfx)h;\B羷 PБ@L쇸|lF)Erh| ,gֈ) nդR7MX5efUB`±tErq9|I~,˜ɞu+_)ݞ i)2h#kPrD2p hiO`a3 B[n3n,@"D_(oy}wB!ĄWûFL(2BBH!$B]X:EBWߴ9Dy٬Ơ+ϧ5p!S wh6vJDj,h5D d\Y 1lkpF*]ИYq{ĈWt$jE&@~n]%hkZnÊ ȑF2l'ic qrWπ gWs+>s[e|1W%Êtk ^qD =B3V(F(%*ؙtZ̞duYfBC!DtЃ9縌28C؅] B€Ňb Ojh!gkZKzVk5A-] KK*b)Yߐ5\ vW0XF[L#~j@ }v[6%3KjUI~%c'#:fd(v*΅_$< dH.{L[z `+wiH3d׏3v&3u?"c Z!*5郕VcPubD%A\cUwET[2c&O[ rkcQZo\uB S9v=| DLe:%I\LG884UD Ȁ)iv"57?QYۣD&ҷ1ҽ3%T̯̾dj#d"=r`GW }eD%_q\e*VQš Ul MVz }kCf\d/0(FrQg43^x925`1G]jRq{=DC&m[PqS:k@UzxmSnǮW;f "χ)QRȻ! x>2H+vr hjd6 /tFk M [`Ҙ\ubڎ?W[d6Aj' rĚ%*a8T=#P ڔ)z8h:A6n!2 c".pjtZc1x ay=(\F?);c(N쵉gg[X8fz4w¡ V|!W~Ո;[ӝit?^fTm&fܖQPa2o$,(&Bt`~1A^ф3"W1g|OoF,0 ŌR4D ETq&]YZL\R"✜TϢ҈B'\nfBk& h?7 4Qz jlC9fǾ&Dw_ݍ{sHQIRnR(EYJRt4;2+$ yvLSNU}gŅTk R ^3[ D#n_)0wa0*%ԣ32}Bё W}:70 9s] cZ>tGpzGp[v=d.k0K yR]hHtj1Ʉ,EdzD{SDk/42P-3|hj2=VIR!@AڜߓRݒ_H@dK̺*a zxtzJV@߯/Bip q"ڨ@d0_@zHE7!_6O@ƍSi&oތD_ix}24QRQc?> D&f#͋ IFgEVDNV.#4GtF+| 8|+:&@L[% w/!V_j* 2jAmR"FL ac(4jP Gd)0a̝ej+Z~N_G j#-tE5S49ixK X#=2B3f7NȓaZ:P'[czIr)'ב+oFswV8r-3g}߿-p^Iݭ1rW*mTC20SR8Q&QEvFlc7p%\/|F*8bH_X`caĘ_ݝt>E-=ƒJ8-9a>OZ1z6 6VoQaDXkk /JtZOG$DVO)c%ͭǚ:s@;ԠSK$7 pfb4.X"hUh#ܒدs*SSi ኩ9/[݊&5,>t@AbaIr9n=@*B)/_&Agd*,;&e%jn P@(ыp%=5d?d634Bd7X (3o.{çf`5*/z.NCr/D^AΆ{4Pr5"!~IfO#>)/A [ OF2*))At?H"kF Fݨ83+(H7+B{ 9"aoY}C >?viy)ԵҨn(=* s0y˔"9{6L2ĕArlw5J۞Ġ3ݘ 3ΏDpG1TFf{2>q-(<; ``8K Y ^ib8  !ЙzVHŇ$F6ECҽ-@V="в PsDO\=ÛR1PD !]AX 6t`x^D*ͳ6kSw~y!Vqԁt[[V29[ޝC`Q̚+)oHҳ ;@sM-2t 3@pYt&í# sL,="?nV8sޤ|IԐAsM`YZNQ7-]0de"-p 솬r| Xrjg_[1 jķe95fُ9Q*%2 7lx ~f ?&P,)]Z'MfySUZ~~ɾMG__W.ryN AL؇}BK54*VdKW7aHzO+9w/4 3d+kB ϙ"g{Wr r5 :%BReA'T*Gܾ!OgX EU\7m5%iO?NSx\ ƴ8΋0"8; h'ghP&|i$k-?F28V0EG,F*nP$,J<m徃 7SIS1zFbMn}ߝIgi;dEˊ_ ^;ێ,G+MdDf溕~Ue}oa֒<#I`0_؆P׀~ξ ytUoNSG{SH9hE=ٟ `]O`>#|)1{v{7RKܯ >EdHz R ;T%l0Dm?E7Rb%@ahc9_RHa`dh*dYGwO%yGtVj ReKC20 \88hV?|eKcso.LO )sQ;Œ> PANqjb3s#fK2FΧKتaTբ< C1:N 3^LԌJoXVڢ1n!GV[h:U*! ـ{ҋ&(:yn详0ZVc&E" f_˃pZ x;-̘6_ĝѾ8 ?'`…;iSfu}@1WdjmQE?A;%e Nb0}e$GmenMeX\pk}p~G&Ph:=0\ܵQaJ6S8r&""L0 &1.dkA62iVh*XY}^>N6w?]w#$=? ꛘ,S S;Y\&|t(M- T3٩'P#Acq̻"Œvfct ,cBCel hjet!^}j]tK3-$7tܔy]+6[yӯMe)ɨ͠='_-,;Xu Zlu05ĢL5s/>,y~o(#}>¾+ndյؔ oa8qy۫vfM+f@Tt<5_qr:' I^[ |}O׽!@5m{11|qF1R6Ӡko Ѹ!|dK"[e" 3fa'>6w[<F|Q#&$ǟV+x4+͵{St,)rb s<>r@d?;b1*bsy.{R;Gv&rY5oP9o~%)tu@XU,+R5-g[j ~!B6l.L/t3z=Ѭb [>")/o;! ;E4YhM-؋-:sP=Qz\[H =+4ZTвj…m(EUX.yK yYEE_ڷ,.i ȟyfR/ELX>48tuX3FrUٳwZ  Z3(rP+O形 hz VKu-SKu@216Fy5ȊklL=7 $f b3q#ġ:rX}~; w 'yBj6&-kdFuڿ@= w_W6cˋ7fU,yFPH׉Dzt719Pg/R_:AgNLm>Y{YYV YZeX8{~?8L!Ů AN*0b#`  #ڨa S1[!0U$^!3Q6Ge\^]@IDATYmm6Z( `q|yˡgzm410ghw ʝ47C42Q,9FZc,ߨUgbs9}k5d@dcMU]i7ؐ43II:ۿtHIn]W T;dQ Dzw뿎frۻY(VqD_8H>&BU}rIejER䙷B@FԮU җSlau_JA"3>\$k&x:9:izOUxB_ZD Eׯ]H6jI:ÇDN׃%Z 5xNd9`4]AO]$'0\o!ߊߠhAoɫ<),յVu€$H"JX/HMhu1 fxnϹ.d;U]0qS7 :(PqhʹK6 M3Ҵ0|ET?f=_B(dX^#hI8 k i"^\1in*E>ft%ڱ!Io^`,. kSP pDRB|lOPD4-}(4鿞eS.nOGɖ"tj.ۨF\xЧj `M:#._81(PT1 2Oh,dt2!J^h>E l%F*1}Е0 #b" L][.$GeDRj 3@{#/(tcQ- Q$=I2B{ {OZy}|ɞp]HA tz \1 UjH)bP#SNnE_Z׀-쏋)YIGu$$&4 'Ih=23D9L|T`2#k՛ߩѳqS.FwmB ~:z#IW.gFk(-+| / &#! mc'ٖ8fW$E,I'Bsmz8D %nE R$l]jR~QO]øoXvN y[ XY˷9hpƜA?D)09Ҟ1p-zCxn:x8N9%Ӛ*(i;HQ @]tLhSi&ɌK{~ӓ:CgЄ6S?g BM:F[/Xċ;n`YsGMcٯԉEvz׶Psp49P^ 2;;7?YݜMiLf݃_?/!l/).MH);ڲ023($ۗML)hTNIRl;/hvP8a-Þ> #{@ ;Tp7}%ym^Rs,>`{ Ů2rK0H-@/AD/)!*:#!Tfy&ts0~4!A;'3Zh, .'`#@i1r3ʇQ@c2lC"##w(J)U򴚽`Ұ: 9@)4Tmk.Hk92O|b{eB绩erLsUIcY@ݪu icX.)R 8c~ 3L8ZRF< ٹ˳elEhw\r׊0g"XMieYr43O>9q( xlN?9ܟ`Lv8}$R$\)ҫ`;-?ZM6ÈH:[PnP5ųL @0c1N? d)ACYF="~q4#6ʩoB#Ib hr~UM, q\0a/x %Jx$G2'N1(^Zq/dWԎ$<0VK @= u2G7J9gS]~TUl.NIW1YK'.n785d+C@n'("LّbGֽb (eU#dؽ#a,$H&XՎ&WbIy4VY[F9!ShSuc ~jy1qYk[1N%7=Uj+4\O΍1àȸ;xJ?:K]:p6|zudʸ4V04c w d`1H8ne/?}i'MP KHA3 W{N靐ԧrh') i.X&GQ~_}%gs[19E(%4I}r)x;xԖ#N<%iiy٣+g f KQtw\RW:졛gS6aPHm,Cxň9K # 'L;##ZSuYa|:b 4$"ވNIrPRɣE]X68.m87U/}T=2~{3JԳ$K]Of DPaf!=q]0,%䀜 -1>p:^С%YSr{f)&E#d3:O2?۱L)b&I< Ķ ~ppͩDY-l CiP oV]Z߅\ƜtMaG. F2g ʦI`Ӥ< '), -&$*Bkn(OnӀ䅨v1:횺ia_n0|>h8pAMu5EEF0"`_bb!_M^~Ai(N#Rݵ|0]<6K+vbGhJs2%Ch C͠o#7A'*`-)|^Б#%rá68WvH&F43"{"L8lD+)˓R7i'&}jF0HJ y NpͰ5=kNDHR mx(Z3(.?wӲj1bFqF= moߎp7*PUTE gIKr,NAR|(*3ۧ(.' 5,VIX@V{Gdw (׵WBK4_OCpg-+k#ӾjJxGOkѢ 84*G4 gWK*9JH?9 =-[uׁm2:$k&6z dL2w; Qkc>0Ġq ``dУ><I& @ئ ڤ$/7|*jeF}%.,=Tsp`Fи*"10HΖRiI*1H1Š=~źbD+U5V5璲vҽ+&'XfZqR+0ݤ֚ 6Os &8zuܸ}~iY^"Qouz7E,ZuKD;@C;‚ _$6UBN̗l,BϘ͙$9kGc^DjIlmpuy^++š8X3% trwl2:1p7aIVENOB5eB%jey\LiǴ 8&&|=4I˩l<O28l|Q es `&]#9 [4^9RzckkD&”NEnCRY%y_d2B )6p)(!x*BkVG% qS3"1 (fX2oĕ\OQ2mZBR)v|g ;MG۽D2^yJI:՜`aL$pj[Iq]BZS2'H7.¼A(´ ѐ.XJXX΀X #군ID5SQY]j;`Ͱ{?Y9s.Whތi4I1w5ia<[DI'02P\ Z6WgUDFH#1WS\2}2:re f|AxI  (h_n( L;gP/0lTcB| &o: $fC[0/GUqIte(h0vٷ@퇮0񢜾=.0akHlN/1 4{^.z&DU,TYo CXЩL!dDW pbd$q~UՔߟH#s zZ~G^W>(J#磳ȈmĹ0tG~ y#G{[\n8AqADLQ(gԙdJ <:!/VXOI7pd[Jd@ajz8ڦҐ:3j"BǸ`h(.,rͰR6ݞfsȅiUB.5i0R/N?b#u6."bcN%1FhG,'zQVEOSႮM~˜f9-̉^hcG(Rxg!>\~S"i&Bg ]t|BMl:nREUG>1 C2F^H G#qH?N%qozua^R]=͛%(h)rF ,W}Ur|Xaa-^0AUVVL@F48t8DZ>m>Q'ih52ivgH]Sf ԑq^(p<*؛3{/gEad D} A=Qxl$ 4 Obl`B${Yb"T@ >@#9aFrCY-J`?RT:;2v1 zMD:B(b36}ƒ'hH~Le246wjF)1pubsQ+Qy^ɷDE \~QoqMʕTc:(kMt=[2q9@`@]L*~a r͏zUZ Qd} WyoU7&)faҟL ĎJQd1o*zO)Oy(=`9u%W=6?E 51v2qf(K4VŹ ,{qpHfc(MK#>m(*B5A`°IwC }ͷٷEA+YmeX/`V 2SlZ-SXrHVݱ8ؐ6}$LdЕQCxlY( 9 T݋ XDje;:UL`(^?#~1WT,OS\zy;Q6S cA4j%ngB&i2*iR$Mށ6ZaN+H7rq $B6P\nʔ!)7&!7ٵ 8^ښz7 *< uTdW@e)l4xGDP^%*5/5pwVq2ؓ""8Őͽ!^F_"d;уr-)t*+ax뛙*%GLbϧIi/"ixLMeŽ$$nb[sG-iЂă%x5y}3F?5wbrNHY;-=` G1{PZq IT-*k= ے7:'+*@ ELdP ⴤQDr@)f%V1J&)Ç "lڒt:s&f))(Ԩ.cX :%^U481qi嗈ŜkHd#d ]?u(QALJ;)& ڌ\>)ȼ.VwhhkG  SYGqelC_4))~̑K5C5 Z=jpF1u )4t"f:PܐCj–>öLS`WϜq׬p LTEX?m&:94kYm5u(Vi"',`I=XTW&^u>5&?˸ί^eGq}'.lJfbB(`^" EW)F70$ 0Eݑˁm.%F8 6Su@g; k#ªWΏNMpsknI<YpTv4TzJ{ ݳc6Jr eX\VH-l?1=2 qϓu4ܟ׊Q^[63YDgHmmˬI[g#ڝKШV?1@: Heé/qC0I f"J$ <װă=Br4tu&r3OA=ۃ?60vAE4K#p}j/m?r56zDP!\3L(6H\Bړ"aeH.p3yqVs44(goG -*/GcH@oHAaD{ϫ$Či4|կP6W=]\{חDMb48 x\ھP ݋^\r2Orvu@XMH| KK5ϞXK ,;eFΓ?8cp*k'!Z\mR ! C8NK Uݕmj^yWx(~ #ABE#B^g<{b8^@5f{Ś)7 ~=1\>ą" !qJO{,E!G3e5$/F8Y؃|[>!Փ[rs1e9و1\5 v 1"܂f`ݨ9a/f-$F >)ydO6AϢ~I blDصфG):=+H7UчϪkYe S$=h8|^*א!=6d,HW~Sym aބ\se?*XД #F$l*$K  B,5v32ÞF{HB=A KK9v8}eVѠ4Yanἶk]I ps3`J&@" 6eJOAXGr21)8ˋRM( @?f))mwe^i͌aug9˨%/2ϟUߌreY&ĺ Ghג^3 t ΍~JFҩ Π-qRKɡ,qQ,OSn;L ­9] .B5Y2 BzhE$A7$c{` gFͤ; ckф.*8<= jZ B.*PmNdܢZyQ$vmM}a]g*#aa ӂN$dQC1wC5HwU7pxh -)!4F.@g$̟ij V͞c5PQm=ɔjȡ/-$|<8ImKv}=Y>HHIIS 5c^dO -EJ]0Z*~yO";LLE=T "_[SƄ񡐏,y(ጌDE5}\|>yѢVӡ 0_5!2ԠWXis b <_&w&hVk:YA.)"n%I湅=#Z4bQA J۞ .{,S|#-$khj0$1 F\^n.TڥE($@YNi02C4EkQ!3{ Xk tؘTWԀd/l_'tQ.=;HGy[xOKjɹJE6%&{ЧT._ 2o2$@J9=^rZzXj03uAZ\U[JjP .T5PI5(nB%Fm!Znڰ.m %#+΢EA1 I ЄøIFd0&1\j'J9.Y#FeW#Bԟys%_Mt^25#%/Z-RINTli#!YAS$`hLAh}?=*#1@%ݵr1D Y+[6kLi7W&t zMyLnDlje G|WI!ntD/kB XCvGMvE'ၹNS3 :4dQp#; LTfލXAnKa3VCya3lY1?NũWѼH²Edy.2 H*\fm@fGchi*Ή2]͍,F蹩Zdvs.aƶbC5`2`&11 hW#mfN oB/$< DX W-cd4q\ _rQ+:ic|^z"Y+KBV9>4rvC1^]3޻zgsU AbT3)MR$ +Y + #E6̞ոܟ*z;]Fw&|ʸ Z <^F^1xL i909qyU5`L3[X +8D@ uP  yD@"+SoV`$BWOaT@YdsakrC}oQ8?1+gv'wAf7Y- LQhymjL7io!cH#OPQPD :%{#P` 6 qi9Zd d=?3g,~G +]nn]vo)Laګ`PzY%w0g$cDHD˅RmоQ(Jo l dg!dhI$q <{#Ol _FF5#_0ގ4 tU)H|<+NH%@.@blsU*tfe|&B|FnݲD[G&.E6_^@`oXiP^PCKjDv20% R{),u{himMy{+Hj9]g.6?dZB Ơel6+6O4f-#vڴ_]aacf/~DO!ݼcG晘#q÷ʄ (kD<=9L/q*^L\Pށ>&AT4J'o ^#? ʫej Di5 X`IJ<;F?#Kx99{*xIwEa`4 &10MP6D#*r]@3D- 88%3tAMt5jdϽֳs4Ќ@ʌ-Do' %+Oi5' ()W $>P8moo,tE"kIȣKy6|j~c?h٣)j"G$s$#o+˭P ,S>(@P2Ex7vOX+(8då-K&Fyަ`G; B1OD3O1m={Z+Ͼc[j3N,IE|`Ѳ^PCmoe#Q5'고cJ1 KaB zvډYȂv҂)CqEN)t6>6Î䒈5[ k@X XjG^lc9ҧrȄyQ9@E(~!@FPd]a ~yoPvᜱR5a޹ 4q8GKO!XX$+p^4~@xGЛtтdڍZKá%+ypg.W3F"e~-[*ϢZL\7hm~BЛ Go6&h<@yvJ8ZL/LKU3z钠8ln!]'b$fψ(J6P{4f. z"MUd$9 k{8eܐKbHs\A7".HHwKJ"xdZa E޳C!$xNaWzSw5^rw W/<$U2e8cɡ6lxw"cp7=CD؛+䓈 V=p 7c,@EЂ (.e|Z>2-}%:oUtpk 0C):v ׇ0ab^O^9qLg.,@./Ѵj./*TcdI4`: 4Edc"AzP%6֬V1ڒHAJi o5נ?L#/g_@D1o0g9O0R')B,}Pq]-n:~](,f 9F2R}.tq'6a ּ IV>/R;r(rT 'r6A1=_4XL~E&oEpC |ނ-8  ABJqFe)EBϖkP6~Nqv8}&yp{k`ژ$`4]эP~%r )d,P ſG[=0;Vxlc]]L&@BŵaC^)hc E;j/-S"[mr|AGcD!LV]/#irƸ9g,}XLXxN)5d܅:XO/&EDHxfؐE5Ω>$))%TlYjt`9?.6TPJ"KVY${E4q@ۮ[g 9 񍟐Nqcz4K.vx!'ȹY87:dB#>}F(Ec!ʲ/^pOWemO,&~[ %gfXMgwdGFoN1%+HҒQ淦-Ӄ@9erV5HΚ[5|0>FLQ\#[@o olݔ(  IkЯ%=rY9 x<;"m|tM(iTgl/VQ='dFzT<'yX{'L 8H؈)l@/;_EU E2ŋJq[wCm ONlz7uJbh ]Sh)'޳u7xa _l#;s^ DQ k\0d#B Dn̛ y_t\⎭ECJm͵l#Y$îOv 3G#  @lmeF< 5`۷۶k[ &&! 1bgy% #~$ "ۗꁈ7Bn+Dh7H3^9زSECM#=FvTɆdt}-XYM,X_dlNwUq:6`^aV4O߾ȩ>=]!sQ`؉^\4R۹DPC?ڵR8:)3RP<}jpNI5'obo"U5]ꝰr?lE(G :!!ذR'{Iv"/xGiroZe-^S{F3>QSk%ZM@IDAT6}bhiwk{gG{K+ؠxCcТ6RJ%G}ZV hS9E_پk$$u| <;'oVa&F'-ySNN 5[3FPVE]}5,#2bØtrcb:XYaq FVj)5T{ɌT@:,۵6 ݂?#kw`4L}jղONhQ9>-{:;P-Pm3gQUb$#s"# Ok FxJ}CêVD7fijԒ#Nb U$Y(Έig['YDK)P$0цYht HH^ ct<wZoL%ƶ4>p0n&L菻3B:2a%X2P`dnHCt ]ӱlޓ"r1A eE~efN$&Ngmw69|*Z۪rԯLAf8o#9M`}V"e`ptsy=ok3'"Cր30u٩Em]cΎ[9K鱓{0n/ZX;Tdɑ3jPYWvtO1~oV9qHQoؕ܅ެj}`W>;Sr7@_!c*8KWw?[,{3UPx;5)!``WltKKQV?̄2'/wVIڥ}!ly'V#=/T6 tדڮM^"oL0Jʕ^Xc’!lN.KN]Ai{/WĀ uhmFۂ R Md(5@Q="%B erYDWLJ癍1'(w$8dCMrkASet#2抆_9\@+dk u( />X "B&,7rK1OF"EϷE#DaO8Lr6+E2d;)`s83R7Ӑ>]6ўրAEUKg Byp0y7PoGJl%Ӟϋk&nXllS:1"jvcb(GB "6fGS9?\.(Ҥ^ֆG:lFROst <-ki 67ykx7 oc.5=@ă:GCK80D8$(օzlt 쪾=y^o#ߞ( \B΍zB+m ˆIA59R.Μj\:=hy&ԌHTtOXչX#L9>t `ɠf4,6LS29ᝥIr5D;%'  JwpGGB>W)~cH w- nwVOma"[(W\r>"$,0 hjҙPI!j8 )n_b졏au~:. "J;'c~)`2)!Xي-Ip~'I\ ̀rQϝfQ|q0m}}wqI2u5 AU Lqt)~V:`xhhěuvbPg2f H q$jeVbcd{o5&I}^Fp,#IyWł{暑GaXaI0qvIY1 v =(Kh1I"b#50:jd ]Siγ5$nSKc\ZGJrE]?W!fЉ>+Avh;O,Zr|qew^ŋCSI &t6PӃxe߉@,63ibd=7–o 'a(aX-!vxtV75C0,tO/]p6uT"qikYݲDȈ1*,;4L;ª4?а$a`*YX'WMaP0N :wA?;l,{#m'Cf@&9Q Я;%̚{Yk BrT8% .x_C 2ϯV~U1)C^\~{ j\Z_^ƛbI}z&3U(ȓ)#\6gmG*ݓ/Gq 8\ :-.bw CP[~g"ځ0tl%-)|^H0e=un4}2OfˤY]n9 )1d&ӵ3e5'տ!rM>H|RoV%l m; OcO`R3`׿9y!ȡVXz :<$kODNU2 XZ#qoRj1Bdӳ}1G֕28a㟙q(])`Np=ӭP2agFG \'HhyoaD8FE`hUtym'A-7j@QmfC֣fmJ\݈1K!A/Q Fvs(TRn/MسLe 7ˆCZ>FPY^vr,0NiQ))g992^(pM07@rSaWZM2ZPՈ~78r* *`q)Vf_z>@lP.;OB3$3BV?0axҳKeL"W^RfѹǶ0E DF0un(+jd K)uҚ۲:)R,YZM-19̄Swb@v_;DjDߦ<[V I;xNL~EQOon#^:AʍHWؔ;(rRk#ڙxؗoJI" Y&̽7ܐѭ jҶ6Rը2 J7E K]`' )QRF 6SR܂.8~=R)>84ƀ1Gm%F^n7c53ΐO5 ㍰Ymf"P+&8Z hź!H" J3YZv49dx&@CкRŜXWs3q F X"g)JZ\T$y%AvUdpCNi6=p /2q|0O#`_bnjKiāv %T4cZ5'fkRr必:ˎ{T[V (uCuuT&Ls}:А%>}-??yJ{­ɍ̾jUV^$1bORtxXR}Gѩ'mb|@'r@`Xu5)WyCܮvkl!ۼ:א68ΛmXov-r2DBXOC:an[ @ gz_z9ED..Ok5u ?dO';IpgٲDbtqrTA x*ʲZFІ`+:yF vYuHw +xGOb\(#N0B$G r MQ,y>^/\1.2@9kKi-" -2[O3QNfD/1\hMNmHB:0/-o'"3,sd“!B0U|۳5{i ]kfpD,72ň'3 C4E oo"zRH:lO5H#oL݃i]5Pnt8`伷&̡d- Ad,#T4s=~iJToqfIJCQ,&\MW4xqЄj$sPJ]Oqڶpѝ(\8ƜW HRzL1\5h׭U{a%-)?وDϬlM7Vnz&Oa@F >ir;vAp}yAR`L_' GpBBs4{$L:f3׈-jd>gt2]v5NA=&]tw: m_ZB\ !EΙ.{+6ۡ@QVXL&!4L΃27, zsP)V0&>Ep `{3`dџV&DN%cjLhA' ǛacxY-Xe-&Q<04.HXRJ5!!>W=U11Րg@`;$hZaQӛ2zL1d$*lĒ@&؜-z*>e/Jx !Fd`4lzn=8!D(£:\e~)#;3Hm ph}M%nơHBi3r{^${FU$62\͐ૹHgaqd3/^li[gXzCSt.:o4I .u"[ŵ,Rx,B) rMG4YVoO6wFaC_w'ʘaHg{sIsvp)>ɡdv8Gu [ڬ1O8)LKiF'x&rd-Ƶ ?;Zw}^ܞ'{/0!x#v=a`2_{^7ڗ7DDν|:B5Ȱ\~1)1a7"9cRUC'L]OOʹ!^h6#mj2W>/14SVr&*[< I 2,?rHI)6"#<`i7vd V0 -M ټc!)OA0B0hSS1 Ro t'6Ӈ|&1X( #?lubBV4ZYM%"&SKJךT~5ފgFl#.pP_{L}HĘ vI#f<\[uCW8yטű˄:+b"r"NmKәW yȢ{,Ӕ.fkA{Np)FC+2}LP-])oÚh2`fSFon4'Ҫmϥ[pd+ Ί9DF`Bl,FO@gm9 AHX E#Q$#\Jr䘴'\.GS_bvOewhqjEi('[k@sl9XhvAOηFB'H.yl.`,S29r Om돈+(FщaVKJv\\OCd,Pݎ4R7Hw$6es8@J%IC.oEP#LWdjvR]8 Ϛ Co4DrZH1o`yٶCw頫TXQP?c~҇JonBQ+D D`{"~W]nb3{<û(,r_z)xky9ȈvOfh8ctN HjݒGi %`o}1w6?*'U3VC1]5WKᚭP{a)ya ^탧.-@N"kձ>T㩷#p'xa#6HQ7t(cUQ6uI?kdjY3FR4wk"A3Dcxa\&M" )+$FH[a002Yɖl t=M !YӥllejJ={65[~\:q lEZos5F9c!3K.` E|{-xe|Z+fl ٥cjtB*) zk>} 7x_%#f^LW)2#gHMi?Q9"I8PcȻV^YՑ8wy^hi]'+cgz h=M)ي|Vo[5ZuH9<],-H*E_C'_L8!Qr4IHƯ' Ew5??C^Zu\D? Q/93mFI*ợ6+5א&_M luujoˁhDğZʧ=q9NU/=q<AG޴/drvE\:#ůi:m$5c @C5JN7XX9"H4A ?˖V "e>gd/E[;ya)`u \dr!UJ&IXsJnN\n34hDrqpc [neWF!ۣv+6?K~ $Wx1z֞rZfq5Ku ޞJ/3"67I/[\4bi*¥Qb,yԼ%nחghNolLCBjř^Qt?(f~0AuEVҧ p$$ۥlTAJDmS0?-6 yXxfƢ!r&`KQ9tƓbx9u %q'^R?-mX9㶗덩JԐ_mmgG!m­W=FN䋧=i(l+϶Itbb:ZizT2*wbp'ti{ upH] Ky;ʲDuoL;b4{+a7wŰh 2E>-I|(,#AO1e.1`'!wrYEPinoy`Xӡߐt` >G/朆GЇO/I,_<͂܋~ ]_a=gmOk[ lĉϥm 8&廫vukx;& Wp$ s^bV[Z`^o ખ*f4*m(*l>mRVub },+[+ k!x'Xi ~xC@(,/U,3R>vTOF*FzGaz i#}cl#"geΩk%]4h0:7([T0OՅi#8iƔ'KSso*>Ɏϋ($'9>K1`Ę'|w] v"؁cDU^@-6,A)NX䥋0.ŧD,³Ȼ;]>y>~no`~I3xX֞vBCg !m[FzЬhΆSe;-Pf IVCO1د:ƷJĀe+2i_=Fdؒ3ooldA刕FdWP^w_օ45#z՜5`ڜT2ҝ!g:VO䫜L'ϕQp9H{Æ xج I,B< $KT, Ž jr AQroyGW^@Jr7H lKDx0!ӱV^?=!E ~3o1A@/1KXKcn[VbWb.r!Hs+aCө/{n^j`;r  V#cV dqZ.T`*6T=mNm~$U,U;EhPTSv[]!v#q~pcjDZ O=҂#8Cmb^P5&ol^Qg+ftu5%@S+4. 8z*^\AE:MV,7RG}ox4$84b${FV $eqkAe!Љex=zp~ְf1%&A#i?@+vf*?̑I4Xv$a1XizВ$^@ /lL}mhE.'M;D].!xh4W:>(=%nAW<<4kgv7)rTk_68=i=|BFUl =zW𽇳qqcoF x7~xu7 a WZCS]AI0 P0~Jj49Ն$l_B;Rۘ5PٸeY[٩߄;OaG,Bʚ5;.O V$ܜMppnV\SaG(lhɭh4jR|p/=姭a3ȧ A0^x2ږĀ"e7EuqPbz>]VZhi~ 27t)UN5 NeS*llo}ؐ\㽮DDvĈ=%z{ bh}=T* !04^d( NB(T/G oʭ-2Yi3CkFm_Qto-g2r0tpٺ:m9f@:2VCΈS~ L+ xyK(Ux<+;epg n&@~y㡲2mc&f?bfM's.S"'b5$bCƘP.T8$#ii!CD^j.Y}ϿTn麟 f"Ň@**B$1:㘆 +.g^2E VF'%>+bN+2~Iu\|ܟ\ծ%,U=?MtRWt]{SK=U4ͅR' 9x6J a F:{;[SDdugj5$4f7v, ajIdCǨ/dUi(=nu8H/;3_;q,n_>Xnr|f7򙥊"OM# @U4C5(ei7;0b,A\]T:G;W5po&d}d C&xQh )Ҋ+,1y%qFnF亸(G7T _F?It slg'JDBe {3N/pS.E3Tv.z(7ޗ?1 [`B91bU|\ɍk/1[YQ@m7'P(IZ̞J,~ C:)}Wk@=Gd|I珷㯟Fk. &)kiiI`-Y#z`a]e|zyyFmԾ9MW&,(0TDc~Ki\g 80U6(C뛬( >2FKQ@Uk1g@+ ]ʋšiMhB fKe@m T09]bXesIP-(3_ZUo^ۧn[ bT/KSf?OkR@O>" l4/3mq|9ϝe # X;XBZ )v„/0Д4hcsGXmotC`,q(+W\d$ [ʉb}@HY&ܴ>;43#{9Qy4mNZd@W8Uj)D  0ӵ#3] Xܐ@:eS(#G`<)I&:=,[",l?YƔɍ u)&ҩƍ: Yvߊb`j,W8vΤIH&zU) 9"gٞ%I X/NF4O&+RkRP|hП&PJW0,'⻂o&Q#2Wb1!cӲY!ವU=U)x3 3Uy1N*Y~-_g1H5e]#=${oR,~-+G]` J)%2Ȕ/^y)Uܡ _r VIt-jM`uah(<[nIA=' R>ˀ2[;odMT$v EHb[V@ݏ  4IH츐5X/D/azqD`V;gy l_lsoF͞ J;3+Jm Bדio~EՇQS?ݔkiW4/v6Ӡ{Pq8_"B !՗"XF]\Y-xA’X;i[%P:0W/"I'֓[BuxCb1"5쉠dA}Uɏ+вYX9V wX}kԏ|BTA5&%!5\qa}0qV*l뙧؊T-0!y 浲SO)#.rXG:o ,qMF.6QUţ`32z)z ;C,GXEj1#c@L#t6C0܎ku։ Yuh%oDe/Bz=Zs>5'S(njruT7wB䋽͆SBЯФ(VeUA(lrfy^ŕedzOf4 \iAaf1&`a^bj iXI4Oeyfvh4/^MXblV=--lSM'qТy' .@In-2?A؊ksIUKvثq0 mzN=x|uK|q` .: Tou&CAP3n: ʠlbH\ 3I'(/FYC}.^)M1"T;u<3] h s,`AnנS y-biD2iP]hA`Ҡۤz 2,ER s;L ^]6K dB& ױ w7X9$B`G!k1 +lo @Q+-[NXlݧM8I9qtݚYlSoaQ_%tz$r{v 큣Wdps07U3ǰ *ʡ@$L{ZH\։"#UkyJ/1bk'L_dNd7P̌Ɔ*nJV{anaQM+ fxy"hZ#3&9ёY"I9@IDATΆ}_s_1g`% NBy5˘ʬi̮'ۮS1ZN#@\FzkɄ?>5@H ,9Z^:w ʴg^#sYoR:{Xn=CVrƱ c!Q7% P{T6_.gzRj)Nu@_I 5S'yN1d9b*3$I_'ZPRJš l4س_+`r&ڦ-P+]U714ECѲ\-Z4:-ag"13w[ېc\F,3"Vk'SϏqm*l_ $MYU7KKbOlx`<>c[P:;E:Y&e5G0`#MNU;ې-&S@E?YT7#?Oi.' Y:l:96ϙdEνAGv}?̮1Ӭwaa۴oʲ R$g}TE7X!N%.%%$ My?xeD 3)*kzr,d_+ċJ6D6PUg pt#/@Ed=텆sW(maB~GĽc,{I J?ևC{-RO|wM#rTL%>ܥBJ4 R- U!4hW'`,_+Q$=[\qxb6wqs54;pȔPm,QI*]k컐ߝdW?8} po/r.(L'X\&e;FRY'2aTlGeJ6(d@7AfV?}eMט?з6HdG'H?O&B% -B7dyEҘ7 (wP!mbi۹_ K!߈5A^" \J:NIC{X`IU,*amY^ɂ6bQ^ټ>3֝h QS3bwp/sWʥ )ʘZ>O*S` pgƻq^LІ vN%f9wQO: dP?D%*׏/A _^_`Ѿ8&@/mnȵ>x/6= h>=9&=2e1O%.K [ac[{vj.ӗpߟ59Ys.1Eqc≫H!Uq_#J"+x(X'g>,ȔX?s6qŮ{6PX3:Cf[0wWNXӐR[6/<5qIuK`ClkLsY1 Ӳ8Ͼ~N4y?i𲴳`uA`$6$!3^!HT&I5.@)B ^m'rkgXCIxc(w܀xTlV?GO/TLR:VBSb>űܮ-:4+eI{x5hVZ͎u?6||KUX켚$j?> Oڀ?j)4I72L*7אLv*U,mq=+Y%HQXc`RqxYr4jE_kH `SI2Rh6ycEu!Aw[L`zźh_'z'*?vջEXP!!' !4')5xt{FxL(O@% /Wr\>)x3(NS΀gV-CVq8&h dU ˒(Z1I먆#eeQ^@wqpX _a-z6ؒn4*"^ctQ2|/йLGa ;]•11"Pm ,R/4U a)UɶUD:WPb[%vmS!+h$:IZhK*:U(^Nɾk3{<|J4Ƈ"Vh;-(*ZTYf [׎`ǟ6io 3CxIAҨm'LWRCN PzU*ͥo)$BƄzH a3Xٿ Trb aM`Օ pn^Ȩ0Aco, Mu+ú(e&_&aâ(g ÑيV(b]M,{FIՍV۴fsHTt0g,C * x &6˶\̮3URxȼq V{5/>!{2#D`4o`t!Lm9jJ+Ϙ{mG=~QFvQDratPh|9vGٞ)N)͙KR&i@ ye"bqC˥שBҘmNCWW4s WNe<v1 dT{w Aɵ=5 N鷗]HDy(j"YS%h=`ՠp'N+1"ag?'EQuLm/$+VD$ ]%Old-9BzZձ>*ˌ))^HaH.֣=Y@zm%A,Yc:5Y>=ga*S\ʵYPj}t h/ W@^ E[Wd)"{>36"~4"Hab6b u4eQmD:^X΅ikdIh~z,E46!s"DmA@ZF`"'Me#Q@'LIWv6Deڹ_D,D diР^X]·c(i-Az'zc8 SDSTN~2 LB⎴HntM[ c~@,͐'*wXHMיE32i!gTHvQv=CG?"PwסN'(Y4G5P0=@ا :uxOP6VR5=vjZ;ITw6􂛡ț MYo׌Rge}nV$l\1(!@%愈LlŸš-W۔m;f[xzz1&ct|RjDʷDCOKˤ6"C/ѿrQ#T!װLOA.la zjopt]"&=f"f;6R3t6h:5@H|Hu:.ɦo??<꣱`J' e.ZI7+ύʅlAKg(U܇eç’$Čg #Y)ִS٢yѲrkM\"9i2|my=[i^h@(nO0g_69Dum.oTE10P"٘$&Db5 "bNK2TuB(X3^-.w fn!A>SSeb]OEAC[\rغeL3a/I8(gJ4P-i™ 'ՐpA؅8f4ޑ(+=+YHdxʢ4͋V3mU T!:K[#SH(x@=-Wp{ )(t{j'sI,˽!M2YC~p,$^W; L;EIEM>D׫_1"& ڢ!K„ϣ'aON\K)ɓ8n<=")ϔAJWhJ-/L--3׵8[DTS6a`y~\^dw^AX^!]k,3F02 (,vöeC{S)$"eڊ7Os $ EB)4 qoŻ l;{U` K^`Xu1bP=pG*2y Lke.opse5m6]+a1vEz[c,j>wGApݔ[6e'U_Nu ,po&'n{ Ei /c@wbDYP*m{Q fj'6( 2pnҘ$a*<ñOw 'Qϵ<|.,S &m#=:w&*o L "1ዔGO{m'[oDOdc&9D=Gľ-@,^/&p4@'ޘU4&#_,YB}Eif1doQ\VՍ[34@uF`@ M$ɻ9X4ᙿIa3Z1 Lbj ]jF.렌bGZ/| ,B2Ho:-yإ ^֍ W-:~~*h^*YcC0blčC ϓY84Ã#Juj%57&V$yEb#sŅꋿyM"mM"Bwrx`$O䓂f8X}cN'NR(? 45Ë:m=N!1+l3=0Sq7ɓv~!V*Z1FZZ@oY*vX^XT`yd]M"KOJذrL\J Rt6#68Χh1vT]*֕`{~ Hr\P"gP "r=){r//$x8ULY}1=R+>11ޣvi]^ _*Z5:cM: 4䵅 e(ՔLG>й ̍*'F@% ߒfG&]Ygԋ,dTk nɅ'3s OFQ"zW~;дM1uI"xuG!˃d֬.zHpkE7kaZk4mR*[%{p&OrdPI<b+͎4E%Ujo8SM3@EdR&Ej*% `6^C1"U& *2<]~ @.LxVxF$ ZqjV~ގop :¨?7K6FABG6?R/:hb1$%@j~ד}=yvgxI't piX׋uII}NGKfx Vb+ckI@14mn&u/'f- m V6'Ԁˤ ]J7\.<ؤX!(-''WFqIV:ɫͪOϡ|v8kB'= L1$&5{J&x9jkԻ&L9dOj $PV.rT΁kSv*JE1XY#[̢9Ύd2"Z0\!fȵA# 5e6@0ҏdF 6֑["*oef VquiQ^aիJwHE,h1$+RH TU Ϭ)o؁Fau) )5p[FQ } -dNceAX[LIsH=ﭵut5q]4)EB*[`点/|2Ch&g*;8CRM!%ph&3 KXnjܣ=4!7mDeu\9A{1"6$_̂h0f:Nduj!5, )"3W L 0][zE2BzZy?[(kI:0zѭD bD tvX_k62uQ,FrDpY8wG Kls{)6q!n$9_Tbى/kd4_W,#D>=fb{kq1v&H14^tИ-%@tԅlP)]bzu$K2XD~ ~{mK\ d.Fz/ctPOc:9բKt!ڮ\c1D|`NPo;3nc=E8bY=-bts4A`nF"S2anHY+\F棔$z Ngb$l'I?} pZˤ䵚a4x_}xlՂ?PL+gnk4^ӅVMMOeO0$ CXqd6ABzMKU QQ7vXy`yX84/o2="6%X~- ǧXf7L"X%LjR|o*v\9 a#PxI19aXͨGO**Ƞ US- <0A{̼ y 9%H9ˉ"r?  -^`GϹ62=nlC?X`,])g{)4dQ>&笰r ^N[npU2Z ; nrc)nt9"wDqiQw(?tZÁ&lڅ.<p~njE4[*oDY˱Ъp)I! d2ުcߓ%Sc&8i]ل!4PnX#6OK)9;Ҏcw|ÀF#Mު;SZ.7?gh"kѓfg+`IU`'?Es9ޫ=Ȑ<7Hs-W(k@ bjhY ϝj3+a{Y?$;!Nˠ=lF~oȜ@Vtg{ dȺCņ'mcPaW;MME z/p|KF'yc_P2kC"E%6o(j۪=Ry=}|oڔ'HQ:.ꋑ: +lE.8{(P$tr eQE*-xĸ!-fފ91mZx x s8F-dEgZwFDj'@,R2CssQwi 2`;6n"aoc.|vCuD>O8:7+L \>RQ4kȢ 9*1K0@e}b#Ɲߗ{X͕%Byڀ2ӏ|ܵjnh3Ilk7G΁Gc_kv.,˫|bh8n|o-PD^ӇҨ=G;8IF(͍}\#;>MڧE[CeՎLRZi.넵>Y!e(zD> A\H,]9A\hV `C+)bM֍Y/^idJ3tDids)x=YOǨ L5Y׾zj0O¨T/uRH"^W:fMb#@DF ~41q Hk3V"ZM -rqs9dv  De(S$jZ7WK]m%ң( qt\o}ΠG?ᝄ0X!1w$\]Ut{qM%`#Pi/a`QyA6k 6$kz1Y7ٕtZ@ ) dH݌S~_,)xX⣌+F:+>1S5*9lC_8B zzRG ՌǬCwVV%:p#>*]"$D4G]eVb[np*{ZY95hX'hVzl⓳ 0yhylil'B8),ňp0ъgǁ.ño>)s_l&m{wbmLCdURLڳ#=s'zMcllZ ҡ^u= -`]qgj|e7hݰ v8Zod? Q%N~u8.7Ku1t f?#1:ٷ}&Ms}0/đݶ'4>K˫xqt}odx#3ݯFlh~fzpƤ"58Kf4ue=Ok0妤(o c'G`{emctJb'yNzg4FH`'r4) 9̇ٸK0^s$Bgi?Dz5Efn5We$tAuz&U 5?jgd8Gu(*iO*§q\36jb2D C3y JR.v%wu__=!#RߑLWǖ[]c+5#fDH+ 8e¤sTϪ}fޑ"զV%:ᦇ*5MitL}G':z2j4 ucn tP*XQ$ "H%r(ݪ@e.&)XF>{P 0rE%FRܦD:WfS&-SJrR~9;<[T?S ki7#̳+H]ňߦSSD^O湀O9L42 >sn# üa]}#hcvz7 #k(u\\0(sQT8{L1u2cYO&lMt",jʡE6>t2zĞR4(ql t)\ gh*uoP .DD~W]nx75U fg˷зm]rW$T_onn‡S..чNՂCG[e({y.K6H(-7)@+#8Me+kgIҒdD\{1X[UX6e-&daaEJPcG9$ ꅩF$* ng"\Ν1B.7)֑¾!+3nЈfpZf 1kއKRjY,x]{UEI[XD&ckRU#6@gPH]AʦGXqj21^W(c[vbnf 7j93tLk=ՆNC$};2uFNһWMkJ/14NA*]Ml|b1.|R1\RE牢,m[#HכW 5Ac N?3R*qt%ET&V2[ ]Vmn,·w"O#~ C"I L ". c~p0Ū^*'{`Z8xJKAu lzjو7&h6ǃtE#u஽xf1IŚf9':% @>T"0 \g٣R[c#HgLIlm}wƱU{Ao"wݺ֙Tn+V/$lҚQgQT5 #3:G!Wnf7+wh,6k.⾏+ꠣ u{ȧ>+46|a!0B j+%hĉ=-_ ( Zeo'Wx{( ?x JQWEC$8R }#[mܰ9.qVdmKO'v{s^as ;u -,u~Pv lzp(EGUelƾ@2cm^*D^#j94`ȴ C)dI,w d޵D?c894/@D1GAQWQt"&4S4螺,ri^[EMqW3P"kY/`Ě;8p#@?Rkշ!.'ml-MiwalElZ9kL+, 'I8᧗H=2SStMZ(M͗X= GքJ)h\t C5do HN Thir52?7QJKE@ķv1bҹtBv1%(Rjn=l@ֽ죯WosC*!P#c=57ɧF4L# MBM$@!.*8|br5 gw _kx@ot&-[L*V=3EeR>t#;K hQ4X׵\}ȟY^2?#y$B۲Օq~=4IcO}DHu+YQ r3c"K.fg5S@?.wj0 +GS$| v6svdl?bTBh=z6NVӞLgj$ܿ9FkW+nH_L[2hl7 D^ȶDMf1vhTSL[}p7# Y/qF~L"lfV 6a/6T.+߲Roq~ d'hGscx>Md2b=?;o{p)QQfXzDX ik\]im+%-㸳L%V R"&px2kL>-jLX`U>Lj'@ d~t[)&x#1-۠<#7Bl!WQCx8;>#E{/k05C9j$!v)‰d "7 **ҤT}҆:fmk&g l p$ %hdBb0iJ`v7cH¥ZIc`t(괴cʁ7YaM5hUv|I+D]C3 XxhmmTA%~<Ƀ&?8WG qsNDCvX3҉` : Z*MLֶ 0AWCzO06z !D[XpMQTUtX~>#rYUI (h.+8UjP;k13gtKC=5(j)LE}cVmKsgT(KUI%~Q?/n%]͑z9G(xE k{i:}$ s.3Fʯy\)~t~Ea ;#/j 4ZRoF*I܀a6p+9zV 6c=і[bD{u; ]06J(q¼& 2)6C-Itؙ'Ml@^ ׄ0㙯Q#ZXU Dc<|Gǃ؍ޚgz* ӚK x!srjb`I9b]H "R>d}*$[$oMhu'0,?r8)j-s琪TmDRRLbveq3)BiQLq `m9UVS3 Ew2՚} W='AR x>)kvbaI륺c6J>0rd2!Ɗ2|S::clDM"z,,!xʟw.$Fx$C՜Ό_`x~|y hh$J0e uLD!DDRabI]gxR{_!Eh ⼖HQOo,(T"h>EK  &OB [vN09 alcE,"hkgS/30l|UTXM&P_H[.^!&\qEOf4ثv:2͆oS$%棍0Q+ یB!tmm3'pDX DRW2SvW-bӄIY|h+d0!H^IxX * UD2NE8-g[̀ɠd5*%Am#3 G@ze&d 7}Bv`'v?Dh+R#E?Ve u4M\?] $w|p#KCyDuqDmk9l|L%2 &SaYKjAr/Jh:BZ?;,+4м2tP~(v+28J%7zsH*gk efͼQB5@j%i-t1=jMzrw4JNȦd v6ծ:"Q־]~M8ɴgD_8F': m2U_5teFG\fPY&ˆN# /pq4/"=YH[PyANby)H4EQ]d  S xL#iu*76eLx]0\|"y_^kGјɛE$F"7cx J2A{#-F9O X״.0xU hIj!4aZ:{v}(먶fjM;aX_/&@ь5K؎nbY8#ϒlZ,jbGA*p74'3Oqj2aemc޺~؍Mffbpz;e[r"ccXS>Z""Bh6YDApo3-;== [FW?,vzF港_oWO5e!ڙs(N*jUk0WZ@'lDT2QE3vsb 3:i̷^[Q$)ҟ-$&3!Adh JCɅ;~0W'*?FI E:5DBD |2 W_IPތ$E=6sڊO=o14mްLi!~ā[YiDž Ǵx {PKEVi*.cri7} "Qdqɇˇm/GdC㻣d?R?ߐ,!v|~W}nD-\u&SkzeNܗpyy{GIr8vubZ)lxb(KL9J^J-.@)0&ů:݈Mz䀺csf:V)mCT)2<3GTNYEN,8cӑqA?jgƋ5Tޟ)'^,?m}Nqdͼ`.Pv = _iKd@$fhe¡@IDATS S)gb}lMW7]Wš)!m2jN Ɗ!p,S9/ssۜͲ+f92(^Y\3.Ic|z_v&%+8)@m.Yj-1XWٴ%oҘ$8php8Wq.`cϙv mRP,\S:tH`m g;Y|Bd*lN;ӌ.lK=g"Mn h(9;;ђ~Vjp&s۴l >A] YM z{!ecy8 4k`85 7q&PjbNC29Ym>*9F+ wShkQEs< @ߪhL3!]+a}c1^pa(IJДyzALB|5&J,U-+D*Ҷ|E!)ϵ?cvo㡪y<"lIYi,F,v [i+Z1#BI9lI& S6 (\(msWhp3Du1Ӫ!hkHYI 7$×d$ !K&qq'Ũ&aIm+JUgL Q#j-M[XT@N8r}Kp VWW8r#x했]z\xen%T=̷U5. Sӵݎ:;m23 3hI4^CF!tQGנD"$MmRiC~m/8q$4\Z\D:Q_cg5ڂ)FDk:I',e/w=<:;D0!jg$~m,bN3"_83O!CV3$D7\)Plw0ɏMb.DnG Y -' rrĀ:O 0og9Ɠ wV'#4En&`Biu3-GO#jyگ9ИSd]Z2@,3L=y=Rvh"3iP eC~Ekij^gdpڰb&l҂)>gI_'r@kA~t%U  bc=e"%:CbF}ioɑٕcS4 #1 e:D_itT U 0-F0e>osE~g# ˀ6y4 *֡s[=**&o'Y_^)14UȞzZ~ :$"J>=`Zjp{Tu'uK|L6IeFi],3k}_{sH2-N@Z8N1J6ۊ0RHפ"cDVzH d@Gv:[d))x>k ZE1H8q"̱U<M=$'˩V_{7d5ǚ+_zdsz|oLfw,z} |wD<s8r{'2dɗC8TyRp\YL?1/:_׻V$WnHəWF).ta[#ӡyj_ c4W>}IG{aJr _Ѓʜv{\YC/YpKKKC5a`oi֡橸--R;IY`fLcS) 2\{ w ,Œp}>bLCsRϵٝm*ޙSSP jkRl%=f=úq >~avcӚ5.DB h U!8$4ބoAxйL}}xf}Rō>I|9MEXeCHH臏pT%: `>S3x||~9s^k2(ȈL =D8j4)GN Iclz)|s6NuພbFdHf|'Q 氀X L0s/bksdwd-M"!kـHTY9M{="CX Z )JR<% %jPN3j ]/e9M#Z\=nPMXO-U2840:ۂ 5'+A~ `)0@<=˄Ix p" &A #3hFX] =`T[}f3MRgRӎ]VjU)E$w-Ck`yQ?J=0% L)UX^vJY(&ĵj=@Xl,g2)üd&%Dvs^dz.v!G=<6|,J $e0޺?կ"eRuo٪>X`× PKcj?+!gLY$L2vH˺PP'lv`G+7&*Z#p6$ awQm )fggĢRUR`z4kȉ"6l%.*DXj2NXE\O1iR b(g>jΝY1٫CLxJIN1݆J)* Ҕ" Ј^t-~0= hH7"1̟DYOIH$h] D]gc/le54`۽@hr| fգĪ$u],C_d[ _@Rz1l4cCn?nEs4P)>jO! y6ao胖1eKTGWI|tsȅn5ø)Bm(FhSKc=u[Ч L$=d#D^Wj((W: )E$ж'=sf:T_ZLpp؜ %qimz񪿼d<:iܠxfٓCԝmGv#IVI|Y>nIy~rgIdr@WọVfRD3_Ç6*G0 .dzH\a?_B^Mi(1)JVSm7O&%l[& g!pjߌFe`ˮf.5Kb=ӃLC f&`Hԯ7-F/6-7#z I6)#K؁toF%~l8c'b m!=M(0plw3QctV6_Zd6b3j#{ڰJVAЛW%*w4ɐ7bQV X(<55.vn_tݱG@kȆ4m\$åDMOMf(V+ jIs1щRFа5(Y>osb 0K!ם>B-|s,A|z"Du=|Za9I&S@oju ɮXg:Ѫ*BN%70"%9{g ֯&ګkMtVij\p MEӺS#ʛJJCq+KFM.r-4"՟)jť绗2<iӤ0!$u3i8KoF𸗬Ki,ׇ[lc 1/q%Sΰw%&yyix["E ԐDjȁ]y0_b\ՕParFh%ɜe\8c϶9kvû L#!lTηȞ :+j`BoP/;񴓔E12eNuRL S7RY,V485PAATe1nDD X9>ɀtEe!#WGh0 VbQ%r`_I7"wT*4.y9͆҄Uocx8rs$6PҜcDdP H䐵եԷa 9v3`>RY)r]sW3 cH<= AMhtt}y٪FfYVrk橡GVa *8 I]h8BOb6Ģ<϶3 ={) R:|LEnKavkV62[H.$%ȟ3kzisg@jβ^::׍PHQ>3Y cH עąSt$x8`hJV늧#;r'% @i[h_JK ?k+`1.Ռ"LC $RB ۓx~ۍSlfI?#dqE6nqPe* $PY6EB&Ma~^(Pwlipܧqv'aK WN0%*ƆMbm<\_::jvQ"ÂB7ǀYUw`B=TydT!LlD ES(@ղ`U,b5M Q:Nu]wY[ (&~;T*$s$Hmġ#lP md';qqC]+!֜eLW!x49IY:a] OqX^|Rk@j5ze]U BC94T0' U-gJcyQqi ]씹($n_R(9Ðg%p!/gr"ж/GUOX;2! ^@T)7}e@P\R_P[KPndqafݪiN`pΈ&兒2&\܍HhXԃQǣ{3-(&1IDI9C3(w3%~qCfϹ2;fHc.sI]aLxkg~fJ< rz1Ȓo&C1mɪ`[gۂEJK_]/~KNTo- y(uwE6ӳLU5F7񄥌 L])>1NwtDV)IO0GUGʯyZ4\)ub٩F/-%= deQnF53|Eˆ+ƎT SQpKr)6i9 }MKY+w*[гG QM꥕D:J B p]nZeDN4 {Z㭳##CF &)a6EZ.idWeˆ+CFuhZ FOEfz c!P&ч[f Hb}0^# %'PJ=iU{540sj:N7h!fF!q0DrCAS|ƧEL2//EHX&"àjRsQ0E7s+`VDB߱g1bx蓐`:!U.%=B _!39w,\MLٿJ&v C5UbUoofʌ$v[ju'-VjE&<ɞ,Xi= ݾZ|㤉H337O*?DӶP<r4NFgfm#_b\d+*(Gkc/=z{dU Ai=ϫ-ogpT0+#3(H 1"=9Jvh\:tyep(J n'ѱ!]s*+יdTٗƓ"vsN1/OW"2NA֬˴X@WNt!ƻ[K{?T3P/[h0FIO;N} #mn~jbj p"H.Sh@Vˬ ő4b:e1 #-B"E6u ZgΊlruSU7}IjO2*B}n<{~Of/ZrS۵ "~ 1r Az!iin= ӺY!QЌ3Y%4QArꥯR7M*X~ uM.%ޣc"Sy󙑱QfSԹm% d !X؇{yyu6 d뉊;kP:iHQ9L~?wV+ltam\Oi@Q)Ize)5mf˰u_%$GqB=5w$rfE{6K♌A#k$J4}ڳsq<_Y;*6 tW2`T:gAFn$3&ui@p{6t`] lGW @YoU-Ƶl %XQr&B qnd` @+SLXZM*5Jb&eNFq@z٫?=IbrNʴхdY8 "x:N'DC.-qy!+[=XL5ćƝִ\-!O-LuYY<S~C$|N `\`"vC g^ m9w<6{~?ݾ?n 勞 Xuni'ZXc99gQnvz~(Rd#n)V2ד#?_OH8j"Wd>Hb="KC -qAɂ FB&)UƮeR9:b>p: 8fo4" N)89_Z?\Bl(kGD;wh_:3&1 ٪ie<Z d $6T$w|>=\Ю__W#MËdH Xh%+@|m`Uw`G+v!GG?Y;65 }gnvPG:Ϳb.3ayH{]ƒp!hlSgR]ͼ4n-Cy!a+lcW?*^!NNs]*p 4 JN2e49n|"1y{н-6,kH;7bjυ󶲞:>:=[ϠFv$*Sd |8` ߢhMlqݪI] ۑ.xӾ?A!F%fqd,Q`J6*~Olrk}7,'v~ r϶) Oz)aBsy#'tI:.,`@Em&R k0M%z "bLm˲G翟-jGfQJ~*gSt/\3[􊝰߃s?tE@26_G`" _!X_7BXob&|AUc>WVS|Q}z$&'r э;>Sƴ<1/[ù_ٽtivP~]OQ'ض! o?ڣu$iMNx+KJKcqY˕ꊛ2G{OӸě#KMXq8e%{^>_trcSVҮT^> ek{:.[%z$[ͻGJ {6:4)^(K.~NaVsHOm*F;6ՐЊD1Z~13NSI"4N0(c= ԑfD|5NŐFK/k"E)FnWGJd\s=Zw5q3sϑг ;v C"A f2PV|A#ya=5@ @=3r"p<6b4<0z"%֏t#|G%X!bGYM >醿cX}˅ŃOr9$@ڬO kˆZ_an3ݩ" }VT(Yx⏦Һ8Sh9 ؾ,7DKM$Lc:!$6R'5~^Bܗ\;sRQyktkUv\tYnq3SU9_ԏ+G;Q/IV1_F/JHRzB>@NkON~Fy1 }@+{ZDŽRVhP2l|Ϊ|]Ax"D7lCZD\pOl]̩A&;0g-'²$ZCt݇DT8gtXb J6eQ,@\t&] ^P:OBf d1I75>fGm$`aLMDbu\{cZԘ/ s|;kXfCPֆ=sӾ%E'}2@ 9gT8b1xiSJچǐ{Sꉠ?5MUЊe^lL<0 ^Igkcd~D?_ Mƛ^8 V__c lPSΎlh"PGCJ]@xӔ>Bf$?AH>l}VEBb(2o^4YM {>'P َ4#&zKm ,0)F^Xω !q.)mA}ٺr|ngU+$!P'm.ā] sVޗhJDs) IFMq_b&QA7e_>H4&LhBEi0 S&`__7>tGbϏ Nk$YTSADQg(A8G@?hZ4, ZE~ 1V08} H, Hx!{x5 s@5pPdSړlV#oڢhp$Z%"bt#x06@]/m % a}2 $FLXP(^ջ]3Y5RK׽䆕I3Hɣシ~U1G#]#d_ΖPvlmΛx5qRF1J[Lkb4.͋ ,޳9XI}a26ϯ4݁n+Fٰ62Po:U,ŝ!f Xr#p 3am~҃QѷI'D@clz|&^n% Ln辏9v'Tшt$ӎ4ѾG@@ ߋZ_Ȏ`j7~S]gKga uqj~^,8!AS[#HN3eJ ӦJO.e()L1QvS>`W'NpJdbn,xBx;M̫f,mFJFoU6$!PM=I2-J BgK)Uhwi+cMغ.C}"s ZaEBŁzsBc~_ &,MfjF4E:𫄂Z1qP#{ʨ | 쥟\=;XXu'+j &v=SԀm1qXWM=pBZJ!&4P/ơM}fd;bĜ=`Ҟ9(4k*C4*^t|Eq*%oV1'#!QMyYKCǏ4L^^زiBWSmRޮL,M>jH(ݡ4p>uSPA" {5hz {}~)eRTۆ.|:Ӧ?PF ^ d 85L)zrŀ5˱"){gelL*Djܒ\,kdE|3O$gb6P4^z"K"tJ42/C8S(+YHzëRBDnCkkq!v Iv9Muf(c0:R1x&tAFîC^t/9':n[>F Yig>o-|{/WsVk,lUl $A .}d}" IBΜ,)nP0ǛZo3(*?5oՔ٨]b_!V!M셎1U¨e|E#h`X; uMR2[n&k96H6f4K%X"&0C%mQN nAΤ>HZVtG5I.~=') Ԇ V$9|[wN/8r/]?$kҘNao*&t&5oH jX(+0r:6 0a?pEyȀ"J-mStB6ϒ);w |B`,s=.&l9@WA3~7W^hą#ASsJv#Ӛ'!%^iKS+}p|‹oo%ەj4rorCnr~ da3O}Tq8>VzHCUE\ 1fzZkZr}I:4ǥѰ C߮Qu2 -/Y,SEjqdK.btlG8FX \:,#Fr!EfU텪遅Hմn`GEc5yi/"SBv3R15V&;`#>daeޱg 2mtmc0Iԋ OIsq7u2^9\]Qir=^\UIINvr m ;HJ` *@ -CܑX* Z=ݫ4DIgTrZ`_(V@\ݵBY^CZs]R[pt[KXؼ(ӫBX>eЖ㯵L0,J nŪdO@\Kf<E faX) DI@k[AB_?mQ*ͫCa0ף^w5M[}>8fl^7{A ae"Flh k#r$d u o"wJt  l6]j.<8놊:m,_tp.{Gг4rK17%_4wAW5N&G~4RLI\vCU0'7 ♞I=~ 6Qn)h!"+ z9(-P䟉@u26B)cģ}"' 21//کGy+v(hR؃6Jrx3A( s_S uwi ` =+H\ 1j{Ľ: eٻ"b{!FK(tr?\]ԥ6KțHpGS%~E LWB ޟe%P9lr|+8D&!)66S鏥LjdY3o՞%@_?oz5m Б{ (cK|o;Rɶ#/-`ev[Z04<\ǐ< 6*mC .Ҙꩬ\}gĎ I;ubaQpfK3K8\j8<? kuft_UYV.@IDATaۧj`j XiҌf--!$=vi#z -P>Z՝! :PDκY+iN#Nݒdm ZjhhA b V E(i1p"HzՖ7߆Rj4"~a u`ą&hEƒ"phcH#h%[$ݿ+rbcs5T&"gm* N ]ɚe@OGȰMVJ@0ӄTw~ Ă#:9Xt#:!LE3AXRk7䟩49HrViw-e-p@N[fӫ8`sV?Xt^ Qm;1hdSB0GAas_)h~%H ĕӢ$,Gv][m3X-.cw|'x*+Z,pMEBřoiJ-6;`>%7P.'&Q+wwԩwc{[]i(wFUy1GE]mk-S:'-j|#o/dc= IJ" Ҕe*5ZNIBMbayG(X9a:*RTW<7_~1](Bxy:y9<(S{$Go"\Y G2]Ъv!9IËMi}8ݽ2So?U<ח3m^¯WGGwD)VȐxZv'i?;ἠ(J,MFL@%KH?`NaW!Dc|ȴ1\4-v|/Pq*h@\ F y&H`&5ThNCbmj1Gu^a R~E>CJ2M hY pɩH5#wiqITO.C3H,MFQWC1YM,17 To4U9FQp;W^/µ`&Edth3 ,_U) ye,> ;,o٦;d~ [m,`*qF" y?{YegډB2ϊ&o* w3zR`Qbl0wЋ|kom0(r%@AHFY4ݨ$ ?ϷZ * O?TJ4Dgv-&HW#g32/yTMF6Q4JIZU=viO|bnڋKI]O~Nѩ ALYNY_ߝ]0M?gᛅӔ\s*,!`T#nY1܉slgx$ G16eK% *ԲBm !" 0UVT}cYd6Wv󥜯ܧ,k\Åor:o|yj 4V:>\L`A| 'QN@A↓{#-Lԙ˳E┞ 6C_l%קz`Ylya[~hInBl(-luqT01A8Qy[ؕL;( G.\O0nE[j}szppyT '>!/>RD^0`;=r_$Mn\맚3}d ˅Mk"|5qqkz"oٍ%LZO͌8]]Z8. XndjtR cK&u~]?w8ɫ$%(FY)!3 X!X$/,d \jSb9A7D ,5<ˉ-|h;&jP)Ry`3c~}cSwH24`˞d l 3jHR%kAoYW _8$>- (D$xRSn Y7mZBa5 VgR@GCmC=?8B[)9~. y)&wY:7DQp4!SBCF%3_(H-̋=?7VR ,#$M1nNjxq?TWҫ4>-LM5'rbC߾yBAm1AQvIKZ3:)#-*9='㟘T8UR; e*AC0EW7ptRWU^RÖ%3DG8 |yO$=܈_M :pгeɆѲȧoKl^~Q$\ jV:^)w wr뢁-ķ{@p" CKXYIuaMd$J`j7 NX.i[IQ %h|i*(O7$ @NjQ40Dž/ٚHċݟ JW@x~xt>]0laCApFOh(sם $ {elZ>qMlaqLCB.'eN1J7(ȧDGx/6P5u+Rڡx: 8%d`?D<0L*2j:qZj+n"ZDu _'Ru#ySԕH5=IOjgu m/{7BlιxŐ& H4Z KVWcw߅yvɠţOSxg`^ZیLZْK(f{DFѳ`|ʜvyfd ºidF4Xck"N*@RR'C` a͉ZkBwT6,8nO0! ԘM%KUye_F:%C|0d"[fk\LGz{'Lpn`b{: “p _mߣ_<" T“_v'!Y T0gA*(]uG薠ۦtK'B@_v VN(Us8C hzu"hT\yO{mѾgWK4RCej**6p#P\%9?(?THV+cb_1MW (ƑӣlVGz6.Ӻ3[|"<հۤH H`,a _s~DYDXm fv唬Ӊ0DMJz"t?1ړu< Bc͹H<Ъ閝tQnU%qTQ^7mc(0W21#ܡF1kBHFdYMuO :mг\+a@[#'':R-5E@ZPp;VFbxAw@My2"d[,.y_:۵HTYHfߧ~:FZO:2:.kk~+9D/nȵL݌sʔ„.KFKQ1˭̪֪ c8֕`HIr$^Г 5+8em݀ kb`'{%J7ɋeC9-Hэt,8s1hChQzz365 ^W7#Z4%h'D ʣaE}& l2܄I0w&7;L d#fHqP!;6s%1$97=!cFB,H$%P!VJn7Et^(4T`ŵD:yl=m7#/f!- N+|5'' KP F˵B{R+' m*Ki#|JD'G"$5aR- #9K^em싿C r?-fZa%0.iz]L5Z; #M\ h'p+y@'}.5%lYRd(*A}&L2vϘ{?bDn%wEbUKxEHrE7f k጖"f` Ҁ@b Ȯ + g ;(a/]"mn+-^zNq|ZۛOiM2,'.]#)I#-U!2#HmN[J |@s@o[j|9 x+4P+Ph|"$:# 0Нhfgz-IK&%>ıJGG@Hu@YXOwl#ss-2(RpC7F DϐI,3,懐N:iVJrjo3ԫtW4iۇ8#Y/<@2F֍6Z3Ej~$#srơ] O0 #bhcjբ!1&mCଏ1TNS3~eUs^ E"ؕ^IJ9 &M7z'ѣ_ukQmD6_HŅQ>.%>Y?]ڭM$t`D0o >eZw>*3R@[hD~OSYApan] lZB|" @oi/ y@; >ɵ8}}ꑞQ)&DCψ$|սq v2rY\є벁1JG3Pe9d30XKg<3D`BKS)%9Ō\9d~SZfm$D@bA )lF^qu4# Ȋ;;_Vd̢ K`,:.JP(jpo~?a*Tb#hwsAU>Fad p ky3\0]clؼQJzjwn"vjT3kF6=>3R,!7 NfWJ]ZolXo L>쭑TjAe//~&cOsxM&Q6WcNf FF3qEUΏ'"'N /qҋa #(ަF]q?``Ol}8ZGDZJ‰;5e_R39H : 08:>A1ǘM4,2icrI1K)ܷjTI_Ӳ#K^yVԕKHwY"rʎ|w7*8*RL*Or:ЈsΞ=kcOW_]^?=;.;i[=aaU ־pݿ= |##uLD :5/WG V%0l|JgcT3аwm$!im-]5iT=Ŏ-Rd:4Z7eb!WO}7hCwx3OgD"vYXJTN l* R`M if fYGovėnlC~x|=u[ 1i?ZV{e) oNLBS=xH.͉|)껻ND"9pH3i[I@\bگ(BQGW;h@\S wVG6imʁsf LBC6t3V_[%8[-A ߯Z?s[2 )Lg?_WB1.5oHtT&R=cub#[Siʨ+i_-OBO38_O0_2=%`*[amR01AfGd<`=CL|td0v,[HJ.ٹΕzyT Ty~G^eqG+j_Vd`r[5 Z@ f }Ӈ2!kqJs"OCfo;W^P,ə$|#lj1vxRE[i]ZWSќDvum.B6b&j4&f=TK IċG=bM|,XH(xHY ~4!k\ 8FDE~Fӎx,y{LghwlgmPݎl'gKVҔ$i[eBH+C\35R=B~(|zUV#0*ް7ӎu%b])AfR&NAY0~l@w"1F(bbf0|pu5)Pp?0XǎDh32$ f@7nL ˻* _Y~W$_$#Ad(9qe܀ L=Ѹj:ĹrjtiR/ْq1^%z$DC:4fCzѧH~4 hxЧ/}6Qlw5A[Fl@9uViT=tPk_%H)͝/5xӘfrRճجIT!E 55 rOޛsl[} eҙ-0m51$n)LTqWEB_܀| jUZN' ,"  uQOOckGFNQ,MGvCܛߨRnFOtdlGca:k2K_(¼bc SžIoK_QF=$k^f% TmKnRm= h>;[j1tx"&SM|Վ$@[2@Ua`~g ϵ"rOrH &")u"4K&#ʎաSmI^rR&QEH{ bOEzn=@!#C" @HVڞEٽ$ݻ񦋈gY3mGo @:@?_t!Zڷ̺'e (ӤpaLkPU Eۮx2YQ)&i2^9yK%VThal|2 QHP)ל^ e"(p@ʎ”\Օ1 'AY1,Y;`!((•aP@t=@T[EzF&uJ(pr8|7([~B=BTb[ODб >}פL%T&z+( T9w@!:0!f)Pŧ٩M쩫=temdX'\?-;y$h i'8pv-KNU5#NLYnfZSgCdžfZmOƢp#u9Q |m#gj]RK+(l =aB/:sBzzƉ@`Kz2ݮmqu_qd*ʍ؈w;ψ_̂hDc?<uWKI)Io(T$Tɰ48]؋雦ܢOe# b D]uT٥5-ӉiUd͞$p$JWE7!Ǵ7OiԐx'@wȡHqYEB@RC3tfh-H4Â3Fnu2<졐EDhC$?bÀ ţ7+ϫCmh4@WzU;BBU02v"B,&Obtt3"@ OrFq"1?GL(]K@;y%¡2+zufn^t +E'i߂c9[0JCz{>Go#O5zFeԀO+0+׻G ؇[.="=茒Yu8qgLI ɹ. m#)EʠXfAضs):6 8 IEXH@t0!*d@L2HX}C{FSwzT2hğu8[:Ta0).KEFN;6_UW E-\W$4#c涩f^mFR @jL&ѽ*D) k-sGf&9mOiĝ"cD1Fw HeHN2ItLjbJkov^[肴BP ޣ.-F+x]i c;hQo# a4IqLS f؇j9Anj@M>gObprf넕d:ړ 93eRrK88Ձ!U.џK:<1^ 5*4rܸ7T:*[:-̿c. MLJЪ]Gw2Kl8R o2ݐ@MY+E1Y@\.@TicGxx24fL$@IDATAZB )&i"MrT^(H)#H^4mg,LoP7QJYt0K]i1Uj9];1,ѭ4D NĎQ^1mdpr9Vp?4cK0f`tm$&,cD@fę8iZK`hO1nBy#iwtO^tk'Keį96,D & vcIt)kvg2+ĝy*Y,\Z2 BHtY?A47}(OB^3aN3q8-X.yԱŶLiBr$L /k"h"CsR*W{9^w@mg &Q_* @,pnLY` ѓeͩ &6K B5%\؄ZRp2ğE.࿈YJGHꛙ5FT {K_&#a"9%x۞?,QqC!UMbWSgS{WEVQ犰yqqk@!;T.l$ WJ] sH y̑*L%g"r|Ye8/6 ؔ"Nb{@09ETLJ˂"3(E$/J-x~j7A9C Q,С$8bq㛢,Ad,GGncWgR/}IԀnsJIFY ERԕa L:Oe+ Ą>3B/` YiyTk\B $Y AGK!/QҴuLD=79Ɣq$DgpER/Xf*Fy  @o:K=#{j&HM0᧽d\dMRY!εWqk]6R,@0/Z`X 8Nbnd(,)eyQSc>V!N41pBE"GHC4ʣ2T[FF"E94aja(Q}j8K5ءUՆEPꇶH" ϫa$QU=k}?:HVdNF"Qg \7חYj3ar>kLYeH^ZjHshetpm[0PӊB NNi0Ol*< Dys ]=5VPٻb3 u֌ۃd ka".8-dz{Z6M]A׍`!V2NO|) 1nPO?| )=kǘ:T{/*R]*\':(!) n<58t6Oi`?;7=7O8F37iMH*S_=p͉?S.A֝_rR[N ml-@} ],Qζi , GjSo07wStYxqHn#"-bt{54TIu1:B5뤀] !@8G;!_6#VmX(Y>w} cgl%g=[L:q)tWPם~MðB׶](]UJ-O\v; sTl['$5$6 ڡ[%J 2Se#iKlo Z;1#FT T(=Ȝj߄^ϘIaui.|sqsKt;` gy3& 3F庎~C;z}<-nôpD ,Vxr1R#}^) %|A;:eiy*\#4ۮ>xpgvKȱyߟ"}“l:?_G1iuKl08ų/84$:˅0<ഹ|h^*hcυSゾ]8  dPz#.Ў<lc^BvN  jVV]`YܝlC>#gGl^\ת#IM~΃(P\sA q4+g>8)VQ!u!],2c[kuu#EL YdCN,Xs (>\0P7xT&lC?:b+ڪ*[/x޺9;}c%JȀYTl:ß_ldNtӎ^yhOE=%=47ky_bӝ<%`# % zd2 di*ֽj@ܑ%qWzuQ$^ 2@T޹Ez7&@2|p;+-#N0J 6 [,3Ůh8L=%G5ce_zJBf@u_GP4u/!5P:Yr@ 0 [j51ɰ[BSrEB?eT"մ9yVJtBΰGdUkih1qE6% ( $yK2 if ow8{K&j Ȩ!êshe4 eM[3+!gU-Q3Oˆpr9* Tzݧ$[e=wt@ !a2jqaNYfjZ'51 mzOI5#4U[8MOsjX6gԁ|쒜Ouf-ihw?˄&oࠄ#y ? =!@Rd[7o94BEГp"?r6&h/0kާc-)8@uE#*-|YÀ%˓Tt˶rV$T3ABۊZ`Q)iץl"SE̘f+4@(jao>fl n,E| ߺ@.Qng\)] K)Z$1g210"jtP:!Y2S2 `G0vؽ3G,u.( ,?ź5[~3:BCgFK}c$p5diiژ$Fm;Gx0Kݍzl~":F UgD{4x}Rބ5I5yVFǴ 6 <#cAsYWeYe|M~yhdlD'&N} H( ^1O$Azgay(Y-2EK:ëpÑj^mZ;fk>^ٶgA=q()kqk!cwE[!q>cf" ,&YJ(H:ڗ.l,H.(ˣi5B*UT#? ` `Bqd%f64E͕jV|H}Ү/BlxE7;2&rD%Zw Z0[C.9Й _h_YcR2H$?<.-"QjT0)ecj#.FMsGhEFv[d!Qe9G:;ed7c[{U4D8,'Xl(npeݭ.As@@] Y̩?)<`*K ?m&';[Zc.@T0U(G9!P!֜xmi1W\=|O *'. s5^u%ɧUGeH^JY1qf/턩 _O "yvæ\s_;R%Sk׻rj.6g8#TH ET KD*qќ l' ""3:7 {+416MԞTŪTu5 BY;MVlQ?>GSěnQcmo*2Yw>ab?k¦wzG,]N|WutpmLBCE*ա@D o#@?-x ޤcA>qvZ[lbntuᘗ3ɮ>$|{ 6{M0jw2ڮO$\F`D|Rn,\1p]sf(agn G5!8ʐ_ nzu74:*Ns<mNwlUJ8F/o@a .㔐bs$V0e\e;IBhp:97_ CF4 s&X4`f2j2h&6G<&=7!(L";X)AJ.)fo b2e3oND) @V٤c9WQSrVPʰĴ*q4=W^lxڡ Jx&vg-܁dfl&H0ZǕƮHt$2] ăǪJǙE"ze4N6/<4EABVsqb;ۻu|  <8\*1`3L:j-}D9D=m@E@@ 2(x4*;Y_eiHJ4Nȏ.Iw^YsV/!TZfqUZUa%6Z ,Yydں*% ;w2L>mMsHTU?G ؞E<"QpOs0kY`* !j Dfcl1;Io>* f9}nJ5Pk}"L)ըE'U] G;)yP XhV$Ո=hssq4w!dhF3ƊS4cKS8Z#~)lwS%ؗ*a{uhB$hu dmNl(:_sQeH 9"\,J( p(0~+j)Y%rG>˼|޳O V[E<iy4aiLfQRxݼ *Io :ޢ@58B'dRd,H[,u`$ ~0^ʢ btaI(1#\ #Lh~GI֓ &REH[N2y3`X^-/"V CǺXʛec ~f6lKϹT9fxΙWHg%Cq>^km#$*J Oin!`z@úqC|$ ﻽ʊ0&VBAm~Q,B"qb𭹃Ցܜ8o`,?c/LGȂ}ߟ=kn!a*tt^1-Gu"wAuQW%uZibV6u~\aUMEfN6^OkX2(3cT g<;;TyD2HAC btH41o1'y#boZN6ؠB}49 !“1o6Td٬,@/52zt}ڙ^/;j'/C!2Gߥ=) xT%P8it83YUWcd:]I@Ԩ$3cd\ ~?,_BbΎue,eU v2]aވ UkGiڷ g:k%&*p)3[bkÝUDF% a%_f<~,ځo)$B#>?ΖbYob R kl;_grdE=lހ9!b QvJM(YCB8Ǚ LgxD0i ͇S}·F8&+.zB6]A[f]0Jy?]k(j*EO 's;czTo).֌]H}2 "uL eR;m(WC̪8C㆕}bMg) bk^ӣ52ym)B+HX h0z\{j]]d5ˋXD`XXi\8Bo| LAX`JI H#2Acb hpa0ৱ ‡-$.6K 4Р e |4%d-{ PϪJHHVAL&ɝ2zb9rcBQ f^ ]o7GC &z3Ps; j,[q*VqXX'!0}ˆ4[jL̸A9fӉ#D[]?$?ddB>;êEr b`kݖp5q4ނ3p=YTc|>T*hiԒX<v!Ebt'rlwjj{z̆p Q#u._:˨2 a&hr|d|").6Z*g3KUlK`!&jIwIhb_vzb[g7ƨ-j7Mwl1[%Hb",],C{AHWG>]v0 K|÷mQFC& `GO&[ݭ܉H.1u9#/+]˾>j$@m dz;M(%Hp>zJ{SuenBĺ*ɋEX_rWu aFȡ:3KdxӒ+O*~;gF.͏=U-(ae061h^I&M`x*ݓ! ;St{噌b`p]| s᩻\ƭϚU :-Du1OwSEeΏ JH@:Ҕ*9җ`ߊi^:rfܟ>G`U?T-d=}M:Vcxr!qsrocT+>?#.ah=$0CڟB#.M(R Z׶ZԱ&*NSspB-v]w٧bXgpv6oL R:8SGpĮ#7%L͸ uҤZq Tb;|S~m[tb)PȓRݑ]vOltQ&2(۽ 2]I| gi KGE&[FTkz3{=:}i Jڢ8: SF~>>"EbY@"K"f\,Y~q5E՛,pnOk?Ϋ!ã vڦbPe&3lu, L!gB\PKWgEDC[ALaۤb '{+ՇNp5{;"ejBɋ 9BШl-G"H+P|pH:y';9UDDz9K<әpg}P'"4>B9[֐;DBv f^-RBh={9DŽ.\tލ=Z*RNd՟(;},c n<(]"9*:c.(inϭ'J8)έ!_]FPAtVbсg,v-)3B@&ן_LnXdY_y[;hS9 DP1~ŶTfzzwX@]>b0iނ%V/adahGaЄ/Jyޙɺ)>S9F|DSB-Ps7l. SZ',1>"~S֍-QZp] &\rҀ3YmFmB#Fl" $֞4SmNtK"u8$X|IEL4rBZ]p$X u-0}ne 0ӄ"'0-Hq=eϥQ1Z".z) pV܆\{HN;74t$B:hm41Fٯz.87Z-D+T-8v|?ڸP*I@7&AaK$3Aa"9n6@\]->2 %0P;N0+"7z%&O'6'v>ζ]' /f|._2$xC Be8iz%w#,ΆDei,JCFe~{2L"XTm- 'M (X"ڃ1'adfoѓ9=LRI4'A8>ЧO9B%^~aYP9W'!FW{ ?Ĩ"$BϚUG\:V[bb,iH7%:M0YlNJEh]ش&-tY d L Ba%0AcjH|lFȵTLIB+0m7jJ2=lHƂS%8B%[AF/G2lTL j>b#mHF6|[r$)<.XM}柌-B[mh~ V|ZTHlpbOCC&YHpcũdsUKa`<YoD3I*=+DnMHIt]it)|Ls+!M2|eccol$.r2gRiIj;>|#U e/k2Z(#Umh,:J;r+֎Q)%F1 •2?5AF:#sL6Uİ҄XAk av1>HW$ӳ91*hoDNGly:jIf055.@ 8DЂ1vY>4!B+3r!~yNS#&xe!Ԛj,? a84eus#y#&!z^8:I|'}jȞLTj1mNDB,IY1ĺ(bg"L/[Z10Ǹ<z ٲla0T)ѳD/Mʴ<׺X[РVGt$3 ࿞~DWOcv$eO7un/C$G'dB@8#uàQ]" NѵUZn f%r8*եғx /q&CEYj mEWF3cZnRI'bb2 uOi)N67Z!8ez -G&/śUg'm=|P__0JdjhUiOO0*5AF+ m`^/յ(X|yⴘfFYbx{AaJ2~&ɭ/[#ksT=$6'8W+Us"#r.DWo}n+*I Ɉ7l%˰eZxcEzsN&#W4&Ϯc;#@{ fAe0*GM{0{c^A9^C+ ]ߔ^60!IW 4ζfk2cmT;="R[/[azd{zMbz0$ L4(n'C"wUI%l'8JDSGzq<.~7+mG{"+RoBjCN'$T>c*~b(snpz};|Hy&TوX磈oPؽ$ЙZ* I}yph|< D44q@OB+챌Wu mN> #x5QQJx/Qk!f$ ec}`ٰ-E AXF*t2JH ֮+EbU(Jد+זjФ*rKߊr#m3i@$xVRGNs :z1b=JB<YF'÷ ϖVjhp$*x21ɑHfGPq~*4C!4-O AuG\ 6@lht6+)Z{e? 7<׋glt>3 z/!"zvXC^TF*ѪKK)]upL*(*"a;#+<n1+.qD^%5&ЭGevOPCƏ]a9b i]$ide kFu%!EDx1 . ڢ;zR)b&^tT GupHr[xS~6`}+?ըN:,pk+^va;VY 4 F>|?)z*ݢhQOh}O B $(Bxys&*)yvR[d.셶CέPq?ݍDIvZi)x^$Vh?0 S5xavVȒ$ƴ8˴J~@`w<94amPFnF ni*5M@֔wD4pbR̴# IL"Ѭ2ƈ*m1"9Ւ'x٥i}aEsjCmɴI=HDLg*޼b {wԃ='*YMCMMh53_ÖBamp`z裎RMنϭd)׸Rߤ~n6=T(N$kO`]\%;Yņ h[/?ADh h~}<;w{iAk\zlbV` )?~.̺P()HUyZKۑ,҄JpC$:fRdM&U+VCㅼSㅛf`3(包]҇QbveU%iL_EAB~DCᵿv틤i+b%[2`%CU%LEV LZ#@0Z.F=l2|i*,,YO+q!/FF\ ō>1">AldX:bg H&GdrC M|\03P-,t$54N(. F(h߈R$\@ٍnӪH{p+>H 'B7J}n4|PD49>XD5,tE=l"ݩԌ yMSd/S 622H*x~FBMj@(֢bKSEo`a#j_/u"UUwV5}I݋ƞN5/Z'wL$=4gĭZJ3Aq8v;qsl+ԯ$.if9-vɳC-DqxtefO$D` nX"bH6~*bda9{s4uxLo@VivG;kd,؁@[M ԙ)v$RTWm`kœvfRO)Y[u6DC8!*aR 8~}I晇b @mǗ (1ج;:IWXs!΀ {3k=1w!T; ю\ OДEP@|Un8/4SPpa$ҽj~>) JKD}x$.Wۮ[|&C4GVS"Py: @˼fqDf@0rC'c^! BB##AN W?fY᳕4*`Rq9A)(Q42j^QmIgDVMj9oգElYwpf_t3[jX9h(FyZX"nNCc{Y+CdD>؂t+:9Y ޱɼA\קG]^ޥ"[V}+O ԁH"y8ijr!%nY+b8:i}h&#}DOi^ crU7~Dלșe&rVKdaQ`Ix) dq*(HL#;A ` D3l)Dԝ=\.wwuP'{^ׯoNK}O`W0%J;vufpU7 &$|WvÐ,Ĉ$r~_Z(w-_F.-b] &Ng}ICwNZiRǐ~U%h B@9/QDY kVsc轾ח` jaD? V `o[64k풥˗ jbMx7*>1TK@@EX%S;1j:CcCuq_Oz?-J=|}ۧis75Sh,tvOZxKT#8J2+,2Cs.wfp07RvԢ`: /dМ DZAj\HyM67^vPJ`!lN4oLK+`Gӊ55!W>v/ɟ11͜)|)x7cgTtW|,$ [ƌ)mӉZKyңTR:;Lcl|ǝvnL8$#Ǟ.ol/NJ_+4[FA@󁟷::67=  ]'ĂjŔʈzvVsӉ̿ݔ2 Qg)-dQL) s7y;wq GTYSYy!\[m_Dw$Z ă2O(BM|"D  `X!ro_`ؘc$/.y>tq dʒKP .0rCsBEw jǑm]Y 2m#<9:R(us$yȠ+A"a^иOQs4 ukgI)}gdBϼty ' _M-;d( "lc\A을 $[AM|:v3r-yg.-Q.HˎH%Reξ2i5zVSƇZ0"Up!!z}~d<E["|̚@0(FL{r_R~'!C3 %B-x(&ow`Kǝ%쵐@xae>\tc^mފ.gY e? αqJ\pW&',\ '*7waO&aK!L}LjؑCI_r[cǬ>_u %c{}kΐڒ#5ćJ#33 j-tY;opCZjrg#skmMJq*X*M4owFe~E~#@_`(Җ)g\.Td=)T+aagc1+ÐsljP0)S'mq&Y $LMoΤ/JQ xNxуܜh蚼h&zlƊ"Wǡda{Zc{C ga1)B,B`wou^NG<2 >t _An$€e5XwJ30&YcY@K*4g=rNG=ιKTN5UAhL%4 Oc րrs"sӰ/c]]#]\]q |Wv$RNPln"5!>d@s{ܪkYt02qP& n4zvV,j4QUjzNzꥵ% 8*!t{ _c&6˃ 2z!;7v @(Yh5M!fz5GOnxDeWkCi1W&_fTP`Մ hѱYh_=AއaҊhR3~HȬ+\E4DXN}L1FM̱s}1a=CNЮ8yEk۽%\4nֶũs樸"V(aq6>7@)7n sCzQ&·.31 2qZWJ}_uJdyĨS%Ikz d}דaxO,( xK{H5. CPO ks)t]ң`s*7_Ըv"sIDǧ5Xi/94dDGIA]|H)&hl\ҁh[Pݷ'uht|% >&yu @ޚD[F!9<; /H)*HWaH $J\*WlmzIQ*ɚlISl!61k Ƒͅ+F( @]ƋHVGcJ zz;t9y 㡒uY9 lJ@Y3feVTxLѻ)Fއx-5?}6D%#F9P,õ-½ڎe*}*'Do#l,.@KIixby!ۻ&~7NTb f*qLn\Oq(}Gdϰ$e"00>rn['R)H1]p5<.Tϑn5mJZ$|A&sB+u7ʟO DF] KzANwo .Y"Y? ?#̲ vy &  \SKۧǝc [ING']d_`J= L:vi`OoEA`c(#ϨY0)3T yN #Ľ^_K^¡u-uiٟN'ga(v wU3*cR,m/T01HPȧ:W1WQhQ)Y&āxIrVHRQ6/aώDc8duN,H2n'ba\WnlwKd^՜qwv^yXN6OwdB(ǜ3j:Ay}J 3 Co 5^h@e>8p̣%&o(MLG+&+2#BWCF; :0E)m"Ui{~-_H }'Vˢ^ҮpMF_0ib:oPwiH)0bEMqufvެb 1rH.QYjԶ6xɴe_FJB}J,RĶfVT@?g!Ze)C\5=3h;@OK}R U?+X FfLl<_f~yƭ4hCW# ~|0DxNz\ ~#wl}Of EߺaX%jCA Ϋ]UBXfSN3Cq܋`Ҙ0{ o0FvF;hGxUf-3J"N$ u๩o ?hl$N^ގ -AhLkMѧ`8$ Ѹ: EG]f,6LDXh&1S_OVҫј!f`8K펱P>Y^-?'W-R(' ;g 9 =!]^ Hta~kr D~,L$ }Ѷ uqbe 1!+7`PXMk1׃;#W$Fݼ(ha/ i!,LTHaM#ŕ,rԘ⛆"t?j@em_?۬LpK':;C˻%AOF{XM㙞MTuxXV4,΋\$t(PgKo+- p<,mtLVH ?)*B|!(.QIx*S`F1,0']ZUqkZPfѱ]qԷ]c9P(TpU CiSk1)Jl:mD cfhJ}euQCv: ̆5V5rU~BZY@NԨw)gʶX2ӣy_p5TPYi gʶ46AJr\z<鷀p׻̈%,Q,CFd=zӫCUBoh> ΗQ]6FVt xcT4(!wc Ti;]k(IJENZA{]`~y[۷ ro @qk*yPux~ցi 5ueᇉa9Gb'T\\Hj @ zzp'2Șbjt;ug x*lFg="xπMeƒ[N6߈&ƨXYG.:XQoF\CKjWcU]H"{D1@Ύ,\b,*c駂$O7=h vW=L`Ű" *(AfPijBADL!7Y'V~͒z=!ۈ c|2|c4}0 +Xxp};|W׉i7 w{l=_: wdn xӹ+Ss9<4إ^:`5^lmqfS%h&,'BhVz'OqlNsEn[H'ቾжk0^DdP'5ͳU )Ga*i/O`|ae&깍uW3D4}݀s[w꾳0CfӯPlH&aj2> K=tZPp!8EK R-Z =!b9d[6(^K<.4 _LC(}eE2®( {N8, wfa^jbeG *MR4`3Z :8q+񖢄9F9d7k2~ʾ촤] 18h-CDG.8a@@ )V Oq} 2T$j gY2C|Adz!<2֞Po;* EI\Z]4$x}MroBrE@EG}ph 2Q>ka%ezw;'x){߂u,R/nE!YMb ̴>(L 2S^CŌ #d"˥v:з&2(wTvٴn <`YI'2@+08 2 E#*hH5-FœH*Ƣs/ki%r-(Pʹ T6c'JHȰ5 ,j!uV)@jÛo(0ȠH}:YrkKvT\90+E@=ђzrYlLnqD&d/Jc3K'O,"(fǐsO?Z l0u-\2"c``?èn|80tu./(xĖb;\\l7̜SyȚu]I&p !{F12vn2)n1xiA*[Fr4, "K59==obvtU.R (^̮)SlG<D[BII sd=:ڕ| c! zc/\1p蒀ٞ>YTڮYESG\x^ :ݑ2WBPhI&!U *H2rE.H9C]`9yRM KO*()@.7¸;s$zWwE` ag\z#*l]R9,U,{8\?Y܏qsv(RSEG Sy2pz-"^&O 2d=$uj@ڤߤ`ɨI{AR$.\.ae7qJ@2iWOr$񑈆@l1tEN2Knj15!Vݵ]N3;S {\~(m&b&HB3p/j->w'.dZ 5];MmZ>Uc1ht|!5b&FZ۪p3\n'8FzNl yb !1XHlM E4!6G\L6&Dv\|$+L$jDPa1%_Ks^ϋnSw] EБКD`Bx_l /^Eg  !p&WP,@ʝ7.RE04.c_4K*Hf4{bk$AOrp+Ùo1c]Hd@Ҋv+&b7]FDF63^5e!<ȉ/9U34֚, v3z#n%4ʗ!Q.(CK>MFLϲz-wDF¬HWY#xဗ K4 N^ȞbDF6K#,"z^NfJaa>;~o3QDT&88Mrp1jvezҡ7J"*3~3mgɃfBјW1BJ@J~@豳{+x5/\-0`N9-=COnC66qSX$hZTdFߴ!%ߗpv%{VzMN^hMh cZ]ș`\ň{AWHLߜ8xzHAn/N6T6YKqNTYuڏBZKKfTmUs×ܰsv<8x,u?lSКfPd>(qV:r?m<zeҔb\\[琑B|؎Och2/wf7vw^ni!K+Uh&N݁JvN/?is NEMTcBiJ at[[:4 +L3kJ~h$.G@ /};2x~><lۄxm uR'T7+bH}R8(gĄKFblg;<-V̜j(`T|sZQ?` X2 c&3KR^l1-fY+wK>8*ae`/Łs3=UqudMyNB׳uX@1,_@x#[#;I畱6'HEy=m s C]&@-J[ﵤ惘?SP=stj1ZX}^Fբ8,TG@IөǨ9U[;b,Sg|\ROk(j۾ueOBdnl[g l+o/䭊pb_9i[@N샚ם'_ގjA/~a䰑U3bjа٢|ry|R jQhķ6WP>8nIJY(\T"ْG\-c3C:;Q}g'`~u̘1zr9u@f\KRNo΂ɔxiRɗK?ۿv?_9 <eYc22aܞ4Ң4ʹJEr|o +I\Dl76D.+o`$XZm^bAܠ@yԆ+cf! siBFŬKuLedw 3>&w]~u uQh0 Q$- *qG(7{Q)IgLs@V\{1/>_h\#jX4fܧKßP(Ec'qV܆;8]{sHX&5 ZĢ@$øQkQʰJCŐ#|6H9;x6׊AfmOC2<[|4rz1lMkk^7aքD|4蕊Sgpˇ0"ךx!k7W|d4w-AC#U9Zrb1'bױ *b~*@&F>4SQb.[!q N %>D<Ҏ~HSnD:SrQiJeppjBd `֖W B)p!dg!G m>+ytK^^LX؁TPfge;f't [)7/B@6YJaSi%x0F &·P 8,/*"(ju}EOt~ Zj x@ Ş[KU56>I4@.͂&yM,\DuֵBXM?ta1S`W#DJN[@a#M ۟ 8(n[X_+̛jXmL:>/-iY\ 4衸i=Xpg H_4ȷw,p1L"`]W7y.~,H*S/P0${' LrsB(9DajeQ?!Nɠ xbd&f؊g$b AN 1Emt DZwk*^m09'iG 9 A(k5+қX"6|wj9$s<#F&L^&*% /#dmvܧXà#8C=q;x!@Lk ~i"!ʊ3цI #@u\Ѓg1I@*ٳ=WԎ9pO9ToIVI=GT xF9ϋ&0!hآ_5կu[<(M`!W1 jL5@-a d?H9EiP9^w+Jg ?f}N ] x?C-CClϾyOJ%]`F!:vV=P(?^BStx=!Գgz>Q{q⋢AT@s6En%ׄŘTQ7t MsÏ5 dO7݋Qiۘ~:e`:yn}1~/WcJ r_6hB멸Uve^G>d01N gN`85r/kR]ԖNJ5:ZT .xqC6{N4AVӋkJߢNӜIvVDO[@Xb[8Q7zlXeCg(x\Śѿ "s4j%}p~yQD׫i AkSHWGa!4ߌ,GE1!KI x 5z7\:^J(JBE\*/v. 4XT2ۢoS@aB,[YU<Ŝ.q`Rl^HJKĪvA7ivfX ~ QS SY"{ʻ"Hdh}yΡq^xQAjWS܀7Ŋy^rj; 3rM  ؇0ÍJ]K&p.dVۯ*mYh=a)@ؘ -9jHŢya5- &n7s0jR ` l`G3Ug>q9.O'>ý1dT1pygTU 7;5]@[@=J|>s:2``q.Qբ78#4ӗO7l| M%P`XkY7DN7GÍ؊'%;-HV@"d<,mx21Iڏy zp{c4ׁq,3vcG'Ks.=,iZ4Mtom:Ox鈟ii3R 8 &%AA8wɯz^ޯ*ПŤn LAUIl+&˔<2b4DF:H|Axj#vu^(\~؇#F7mT+2tnbI1 MdE@vR(. pz3w;kj\i P{D=)fN(aN؏5W~A 3%X\ԩS d@]u5W}h^RhLruNXx/w`y@IDAT Up(5{y4H N ^c }@7 eT! Vꔛ%Bi{b ؏^T2job1.Uv3Ū$N>אՎ(M1OhHHa.5-KjJ$!aAcz`TJ:aB7zx{}!M5$ip/-dI|@QJ7Itl23mgd`$ f% z;o+*D(cF H*:ُț j$acW٘pV[䓳 .CXdT~1*vd"Z8%ˆ1{r%jyS -QĈ7rnEU-GmzA'y!3Qh^FxX;bp#̰Q0[&P4PV!}ʰ6ԪƙYTop^ >i{_pۼiq%k`Cv𧅤n\4d pP&".":`A;yvkC05ܻE Uay}KUqיfK)q *sr*bQ =RDrvHݪMi0ы1DM-=~<3d:>:&D>BWeNB\]LLȒiql'CL9\1Bgm+',54Gl?n[(IK[S;T J Ljx4NUyN%bzHXM=Vi9U@) =4.\_bf#%Td"U8ƏΘKG+5Z.+&Rm$X%)63IצEL 6cY >RMciqB:JҬ0Hxoԍ6uErd[D 7rB54y}Q ٩|1v=SzA\v Jݽ^͓HL[&3g(Dsre{&gpq& "vL_>%#$qxVb)& lk2ߖCu^h1%-N-wcKSyku iahA4]X4oIvTÂ#4M7i*'OUbAsD@$VjcjM?!ץnq|AL`h,X"٣8IgmΨ7]2Eą7!zEDNJ>G#@5mx//\:K Ƴ{kLliIGEPc }uOhlcsB|OD%atDtU4JJduTt(<|MVN bTe3Q@/ΏmmSQI |x$7ANւ09 Q=!D0Űk嶵pmlgSA5qMїQʫ۔@AGS&n ejDf\dGC&99l8&=KᵧDlDLXtg hN CG-Rn8zptfx|3U#cAح>p1ZFxÔd Mm@4,*~7k.187ȽVbr'QxGQ .-fMIΒ`TP+ }>(U@ /3# <¡)v uo&C,7W^K9q"$EgjvLh"2Xˀ\ϥ@;RqtK+J.½A(~buc&.EeP5seCO~<2qt[X+sdp`}&)!ƆA݌{b155JTޤrbٞӗQT! 9_ۛ3|5s,d\eoo)V ZQ&V$"FAG ]l<Ɓ /oaU3.=%g##M?Xnmcnm*B#^V7<#C{t?fCz닧H̏!$K BtVW."/ҳf{VOKM\蕪1UPj#NrfҘ_.˽o?m^NMP؇V@Ȱ]*lg1k1 f T5/P4aS5;,D]oѬO( o/WЂYOTGSVj]aWjH'-xW{ GD <Ǣyv7#$ZHu7ҁE2}CEH_^Po# Et`?*x0 =q-7,'+64L٭F7ɡ?bΪ8N,K}Qh9C:weF ߍ,3'E4 X\> e+F$a N\kf!OV+/9V)? Y֖q_ >]?)<,Fi(5G%>aj}ώv;![+tG1"]6 Jd ;׃i+4PSK N2Vk=qWOC*ȕݡm/2FG+~]ܶLJ3N 97?Np0R|)'+Q6 oy2\bJ J |[NUv7UW`2`\l °<R~W;@\g_+lP.sr:%,:f 3hʤggHlf&bfN}b ^c"$[5ҙz_~&޳(,T#ɢ5!\[ :+%mIB? Hk4dXқg'B gƏGeX]Amj_<%X09ptU?%V04{"3bAC60F-p3!bMg.&ݷ4w5V?c:xĐ4e-uDqx]0uTLq7Ǖ-$㝇Ժ**'ԠNA7GZ.,EBV2_68rpSKuzlmZ퐅KI\JfXΏZE0Q[ҾotsaXsmJOAcx%=?f#ֳDVUgCXhhf)3UZhaN"|>6lx W&{e!lQ$%QwC ifh\>{sFdeg>)N0-<ֱ# 8gakķ,HT7n/l/Xh(ǫHbnCtɡQH$Dj6v8;ڗ5F جѥd{_/"dKU, +OP` 2XU$ ãd?#\˦v)r޸.>2iXP7/kcSF9ʂrx|0on3tyo\m@1f Nfc'X`j)niEa@<CDI㣙<JoNQoR@o&X%qeV˶;zDx ɇAÞSS}{Ft/aĤ3*9=o.3Ki\|4IGC-;ݸdX\1bn!<fq%'E':,lDUcN0GtHgR8F.1Kc Ό-3O(^KC#<&6Bn*gD8/G(ǁ-~=mcLM4*9^A`0eȁMgC"P7ЂϨ_ڣT:3 l9Pg)YuoAA'>Ӓ-c(򛖇+CvY$"QnL>.An`)c4EgX߈˄#=m5q-2-, --;}e .'}4o ²J*LTdyz. GIsiX9VEH1r)0L Hq1'\ْ+ϥ ,pФ:Ę Mubi8'V0 H(9/;vIД[bnf"?0c,bZA V i+yj % #A8HUӎ4~] q"ͦFB!7RFbF R Вlja;3"mKd">S2㌹uXfXFt7KRKLs# oN`@/e|R Kݜ R፥9` 62\8Y K)zRZsX_E$i5N.]6Wz7 pk'ڰnH*>ak-N_#;ɜdVg'( _j>;>b9$ɠKg8ڲ7,awAVr\^ +NƷ%qQ|/@"Mx+W2$QC=)98 :??X+#_^4&OiI|{b(ae-b)X/Z/jœ"!j`(\F΀!O=OVSř?GLRLr޳Ije;l5՞@󠵅Ά8Dq|\3jVA8;'3XH} |O?$b4I3kۊXwc N"Y"WYxH?p5[vKc*hRQͼ[M٨SAJZ65I&Qh  ]ҏBOFf@ 0ƁƸHQ|= L7tcyX +DiCoprYDAt.< 1u]t3h䝃ku—uD0 6!V*HѨI>Kemv"׷l=815i\%w2Vә+9r>dtEuVaïj-19VB^/af?M ){K1D4h%`ֺԘpnuͥp[Ρ$G$kU+ތ'XpH{ʋ*:,9D@GdzG(\ݠRqڕVH>YV$:,s!V)֨ Bs8Gq/f9LyIP;Qg*1Ûab4skOPxS`{0#!o r}97W TQ`YFeDj|Bqȓ!=lmOi[ mLYÓ1|6+R@ ʑŨ%BL 'fbLA&KfɋLI".̱9;i2-0lvZSF(pr`KѦ0 N45YoԦn`-]86ß6"|f%[!7 LIr)fE4f\ٹ-`8"\nX=JXĖ>/eD_?ȚFiUKe[mBxF;z C·dn83CMu53f9#M}! B)q?OA͗M5 : s,-4嘬jUmb6aVOVufz tְQA,57k ev/:VSX5bNE.W+>, OQ4v  PHGbuQ/RJw&HS ynmc9_0DfXӋca1&!k>!6Ɛ̔oǓhFxZ^9La/TRMBM:v|86V 쪀n䙂!Wp^!y&"yh.; +"^>0F2d*##ov3Tk9A+d ! Պ+g#fYG,\rs{7d(v2Iuc \  @|=-3\CHsn<c2"!\鯘 3 $ػVJH/ďm}o'n6*!EBF ./4j0愬ǔ]*@-3C|I=\Zށ@[8hF'3 %ІzHqrZ2e(acC9h34$_ܘll.^pCd츖/Z_ĆoFV\qU ]R鿦R!7ŒڪqįtiMǕE 6VV6MRqF> p&0FwR_6 Ie~3JaxXE@U&$\POW7"&ۼ܃ &?@ݧHگ$_eiD^3ɩќ2yy= |qz5Dnb"O"\klҎZ8px[3j]v:Rh >ur~ʄ )J43b2}TXE}\c[_Iʌul34N)IٚአڅijeoKuT^5hcu`dEdH/m+-?.@ZB4F[m'vC+OA JNCʃhd$$ gq-an u7U橮Q *\KAȴm?3`&h^!0Ś?Stެ[] B)U?g0Jv`d(CF(l ى=C+ ^;xe$HA"(҉ɜt޵6D,+0bE ^H}3@"l9rYTNWV1ACwP۴T/bTH^xv" Wɒ%$(1:KTP8-Xfi^}Cf ^M.7?81K9$eb0/f,)bk t ĨgʝNԆ'zy(UR+W>G]^k> !_'$'4캑hHPx$~Ht+MjbH3H7x $'o DgS+<"`Qޮ,;-;Bh![{tlVʷ(\ުwӊKĎs{Ai2j7"zP@ӯǜ%j1(4^R݊yzC 9$T: f\UPw)\jݿ:.bgW{l0}\',H'hPmrbH&BR3!uH;PLM|ף ,ۂ|МA#hf@%d OaWd)웶4טDtBզʨMS|Z7g{4%iI˹юԂT}q''gM@Է#2*mIŸ0VB`^* ̃p Now 3#w//7ك?!dbh>nWF6 8fdiJTC0)ҤވCP'g.C 3آ^.f ӻmSm wxG)O? \UVm !o54ΡNbLXu%4ЋMF!0?p*8b"%f D{.|.[1yZ4%PhpΖ-XV|>יb"A.1Ty 1}X: ^| i&`g:N[SWqk/䅔-}c1{rN:r D GW HT"F =2Fw;y+DScS,i NU+m6J34C]@OOl-\{ &bG\Tu ?F9BJ\E({sz僺z\zasNySMi '^:Fs]vPE]a@EThFڴ% {E>4%kI+Z<ob #kF&<^Wa";a.BzWk@ 'QEV\ZDCsņtiL'tuO,L˟^1գѭ܈j} oqw˼b\lC*qx,)o~sUbJ`L~1 Rk:- * &A<Fŷ:.@+VÚF2-RMh`=**}ln0R<2."&Gb[ְ6 fd0(jYӹ@SlD4 l7&OuAQbH8*2&M8 |ntvj#j ?q] 6S팖+Vi 90,DG3Ԁ(:^O.kw{yX8Yʚ5X=\;ȂY/Dl7c >IקMKi(B^ bT `nx[|+kۇ\@R¢wק'GSOUs*c,ġӲE1%=B SIGǴ=|T+j2c䦀"i&zɲ %L qagڎz0ӺU)rq=E2KqXdx 0*)js0)z3tcʗvM2#*&ŀHHx:n5''pg,DeI 7,VF;<^Aco ~')Ԋ0$"W:BV p)1f;ܾA/S ;[(y3gXw8K.n(x>[n/PR^6 ,b# n"ZNi /M\*\%^8)Bb&U R u$h/>h5艥 t}+g&&4G?Ǚ1. hl$zܸe7 ρں v/|+3Zm,*ᛓKשZ2PǜEv^sBOKx*@?Nm%*|.mxq^i>*Պk<k{;h.Ĵ%?EU0xEqVcv;1 'CP#UHQm0Zk:C$Dxqj/TJ[s=;v?>l?UfbΦx{)8f۪Sacnqt/q"Q*b0ECFP;v5Hom`9̗j̿KPor-xۮ~x ^}߇~m>>۫kP*Wl߭ ֊ [˟G<:Ћmq*rl᫽S,-` J!(U%#c^#GUޥu(8lf)j_86 7f3QIB_1:(lW!-ݶVRE&WHqmkUʉ8X 1G*K ~*). 5+BSA8 ~|:dtKG7#?9%N`/l5zE…`N MSpfe/:y^P1&ز(/xTU!Oti 7^nȌ_@ܔǠN3N*ujNxh nzNJf(yjTtcPBa$wmeP Xgx>.IC#r<;`KCnZ7<,)`'M^ZN} YPipO{aCe_g6nՀpAW73aPέ-~_ y[f R?fk6*`lRw7XmsVLUlK_OA2/Mee<)aD`-y5<[A'tzgFƠ>ӺIë&ڤ T0T:vW b/$@C:h3+M!s ǽe%oz\ћ).]~??*la;9 x;Y' I3Wr Bwn*wW=2yق@$&vLKShÄ/Ka6$ՋK&qP? uIi4+ZڬÌjK1Mt$N)єE0 rf>GYl2`Gv܈ÉQ$hhp2 .ٮ wÇPF 6"&jT5w0$) Ja*C&k#fc\@.b2|!: qLjcZr(R{Wdށ #ŇRՏqϖ{ՑK&Ú6Sfh'ǼHTf qLg4qub6w&J Rޡo&@''8L`&l8*<`87{ry in2Z,pCV:TT2Q&|I<-wh1s{)Lj? }ɳF-5cnoۘt3-8%mdFzf*M)Ÿg%l=8 Ň/XxgO{L${}A8)gp0 <"Eof#+ĥ gR"!.^}@rC5ݛGXD=K+ jvFjV a)cʌZPt9 TwM5Z+j|7ƗtHALB`2Y#Q<ūD+H'ղ^]Ku[LoKTr|@1~go¬W3C ½n@V5([]:"C`U9 2jƅ?4CcK~gq )wE} ZհP[qi0I֌39#!ա>¼mJݰ|h:7#_g\:" ek1A忉ZxTƞ`OjD@CyDB A4j(034zkW>E/t'xI{mRMez*l DÀfe-) :ő4:""fJrg@,LbʣY\bgu-%dYI {\sb<1I[Y1YF|$C6p؂M{!a)Re/flA%p(kn56}~cy"6"j2x. kj8@IDATi[ M96NBaIګ3#!ȔEaXِo\Q{[\H˕1~!t{T`y<)H5+1QiWKY&@)X I4G{췺9K˵!VfCP_ %?sX}DLwPlw F΀+c?!>bv2嗴͑QK!B]<~LSKwF7'Kg@FR#.r=}>:[:<毼&6<'>!}7Tvȍ-h吠MVe9J/LQH6ӛ9s#U ]M MXH:)/TUT հ<67T#Xș~ۚ,OSވ7hSL!Ǹ'UFdh#(\Q JG `NJ>,y9XS@y|\F1B0T;3kҊ"91c-M[ UewQZb"fd" L;s}K؝-6'x*r/YC,Yrt!LσRYDʁښv:#^X4N >LY"rD&$b ]UpjT$B!&)$E7, i `5Yſ$шLS^o  SE9`BOm 6fd|B6N'~'O=;DvzkR4V\f)GMz0d14=с@'bӰ)~a뜶^P!yF`3kۼM ܮ,pJۈ`US ~c"T O<8g8'/uM. oG^Һ X"I )G}BD~`}))v.eǹĪPȖC&'忑RrTq}}qL=n;L2oQt6rC>yԔ4ŗ"-2cL9f(BLsEZFe  pz>c$FBvXZtI[Mj ;A:ө TpUy7h#ް?vHF9Aci!G>KmOWFh8mxO ֞SscF9 P'>Sf6۵9}DX 0x%?y)iтZ$ iC&}V,{_>6;uqdp(j‰"hl| lM%0i]wXQM;r\',{8 EMyrn=94Xx5SA*7^^7ǝ-VfbAA)LD%vSfMJZ _D\XȚw@Ue C6 9Jnš2a Qepc b ))8-͐sDN `%_,snV4v37Ǻ L>J:{Oxp:iroxa<<W֢5(+MY՗bTY?l"B3:܄M78҃EL{Uq`+vTY $͇ @ %9#k :sFJ)-TJ%^"gJ #MpcPҬ{>g;dJ!MZlI1 *da nNЛ9f:u2q~<Va');ǽľs-saEпP,kDǀ_K-DJmC>U!(aڏ-,;us{e#,8ͦ\cVatZm-@dvta^A=bߍEk)p?*fq>RJ'*+jj0{^}@9vG -O)9/N,x>߯VN/i|.2# qGYYN/ oSZn6cjDs3=iw;ؠE_75Zܼ6cl3iu]9(G hOPfn,M끤3얯_=EBNQx@& T\xa΁0@s`3==δKVA>ʬ2CK AAZ9] j)os6;)i< Р 7WafXy4ntqg_vQe, wUիB,19j4H> p|j+OSkSŪCayUL?Z0Tnv7'e[4O8S0#%f#m.(K_L!R> ԌѶM|X|O3S+F'"9l *`!ޠ]GCˎ5nOOm 1nDu56 &ܪzK#E^lUL:6X@ U =:`b$Z!ug#0`=hxSґHPj2~dw.GHB0k|E ` :fE)Yd@}HHR@ 9>1#S1gV3wx,V`-6N+faxu@noypơ&l-Q1Y%1OٓYBX05CGL+ڔ@f=<3φ9p ^,2TM4fB-l=9܂jtJqrs2c8oW30Tм8 !)l*c /)xJhGV%ӂ0QcnU}3M:H ,x*z@IcCs|T=` R+2 #\^p2}zU1[ #ft[6Ƀ%3rȕуOY&ӽs q( =*04FpJۦQO@`=ʢrιmNZܶ%f"6v`7Wʒ }DŽ`YNp3;f +մVy Mmi'Xg"RQdtC~`2ez7 ]n.RH/J0Z{q>f~wmhsaQ;I^*>0̰ 8wQZ Dmظ1(bp^698. ^jGaW==ToKxE$@Nפ)i,t@/V:JyI׹dlQ%)JXffgw>;S0q疪;`r]:pH04i%1YsԖSt+^I?Zg^$9( XĀ.?z٘R8{I1aRl!G ؆eU!;Z3j-UDa(9eL*ywjLǻ ,Lrte&:(m% p\-BU T2o4I6w۰о/k+[GIyb>HgTVHV- gV+J$N4&mH>^[ Bx]bf̵:;j&޶h2-ZY/`PݖL7NrQPܢH0$_n|$ H9'DsMJB?W/=z?'CWMGz\|`'Qn8D2)ȌSkO?ơp4lK#)4 4J}J"g5/9&*P6H:vf:Eb>q`]=(X>{nю.8cHPhgZm߯" X#blU]mkDz(E3XV>90y,`GSɏxKᐽ~Pko)KNi+N,Dޢx,ïh@78Nw (zT:ɂH'})Vf^Ostj+ڻׂj+~˲r_ڸ/Ӣrk5?1_*Nl/?x:|"ʘDn\Gp8E<״"'GM+l /Js0*wgZ4h?b~!Т ^#!U߾ՋTAE8_5ENw&6A_"YWsBP5=>ܬ0dlaK RhjeSnLko*]fCgXQ|6 eDh.+4*d#57@EhBR]!GA{wr9C4^B͑ `Ç\n43Ldw#*߈\~q$1=$WN; $]ZHJl* E4W)[^ځ*O7LC3e_@eo]iP_;iĔ EؗMQX_S+W)pM"e>ѝ 6E 2Sq,}_RHEOR|)١:oX kF:/6rd."]@0@:_ۖ h7.JMw;yy+B#ZU> L@Q/;K#WvHUF.8b5-<1_![ήs{@P9O @Q~Z[׃;K+ TQ@KF[]ДKq/+c+lЕt7miIZ ~dXI!0SU $Lj 1p(RM͗pTz 2rGM# )lT(s[1OxgYP+7eJM6N,<]VkQYOމgDYK^٦,:D,3t#此^EX@as5T1%GٱePč1Y ~b6*V! FH:!QoH aNؑl$RtY x,S<6z$٘WsF qͮ"=_Y5'J/hlDO1_"Sq] 6k&9 "CgV4@.FRwK7)=$(&}rC[a)o{Ҏ$z`4v[=ODӮR* 3d', z?fEH J3KzĉCH+`%@خ$0saV`Sc #QF=aQ:"q9:C*jrakQ,Ք j5 ƶ *\I5[^6\Rj~+`ʀ<~}a,~4 ?ˇK@O`[%ˁ;ِx&3\쉎|ڊ#^l*#4 ֛X9_hC.3 h*p*OC`DfKdYm˸б~a{>PEю%1m)1P>zLRݻ!zɹ ׻N?_3(x87b;V[L塘ɑZw+ڥ/l'Xfl\X{ӕio'KA<erYQsV!~w݀ 6x&Aw\}%b[# eÿg f@1,}$#րO9{3cRT~XkI}ijWgPOqUpW$?-9a5r$>%6xňĤձDL fۢa B_ae xs_%O ;#7 6lF0v[#[gPbKPR*d%(q@HrQ,qCX&I0 p`eJ hay/fFT>; fI&Ci_äOv2B!ɈGK?ІY*ONHj^ћ-zþ!o`ѯb5MQQ鼀E(4ItK\SZkwLP{ !Mff&xoe (LMMq\_P1I&ļ"gE?kN,f3c"Oj87,WgBN)BRH"JTg:Ah:js>u&83̦fMCkۑTKΫNRP+r԰/LC;/@әlyIq5ϸ,OrX$)Io(4qe@2[?fLI|wz^qWzP*ijvLw%$W̯FAoM84E!B`:- m.G-D&ԣBuܸe@5O (DfXH4B;17(o(2n! -G"d9]X4(<+~c՚X ]Y!./;;**#s4=hyzT8zkh#(ioy"1,w7S~˒ɣU>i(C(Jy'֣>P\xEv ȊsWn_3Y(2?ZϬn9!0ZAmB(=; =g.$,MJ&!L#\ףY\w&ԻWoz[WjŃfT&mMD.H!mhI;g]&PŎjx:vU/ :Y\۩V󿆠FB*\4 A 芬f7~啨*fa7 . ?> V X!Qz7o}_BA JYtA)2A d-&k>*&&;T?|~!2􇊆\z\&]6r8SvЯ{$cb `w7+jXKuLCފ{!J74AM457xasHk!HX[vmH*6S-*m5öDm׀<vP(6Ǝ'.{JJHJEf<1g q_j]xdH:)ocͫ79%TGDMÅ [EoLYSѺE0+ؐV^%1?S,|b:JHCD'ŝN=:G#4#QˉPlȈN"HS:>Jom4AZ'NHL!+=@R cf.$( h z"uc} U&jlk^rEZ ۾&b6DVWWFE KKG8 uv?]j~0V+G)QQR&'8˓=iYU5=pSǺ>) D] `[x#$l kloC v ikPYVڰxZUrMc|^X߂~Y2%&O8f,OcYLDt.o,eg"Y%8RYKo13IR-Mys˜ >oo^-B.@s0v׭iŧ i aBt.D'sxs閏 ZhMfK<7#PRe˼dst13 m` !Υ&,ⵓp- X`W?H0Zke2K4\m)z2)EHM>#Q^w7N"j@b0Lof}Du%a˜Ƥ:vXsP,I'H"aȀȼZTXPKleS4'M|7h-IL}#6)0pNBlG*C?IGW]ȁ \OSI!;ZϘch~(ԯ`^'//FI4Fxv-T ) /BϏc'2L"yVӾ4|N b5UMx"┛K[C3rͧ /ެ/!'CIO=(usd*̆\s)ä3j&]ժ;9B>~ ["-r~xu1s޽3<|4%'[c_,fW6Ї(h) P=6,bup0Y |c> ![YjEMϖs{r+v:۟'ZQU)dBv4n))i䵝^](N<ۢ]3Lb(ƒ[poyd- l8l FAT2* N"آx&n5?!Tq##;$0ȴE>.o %8=0Öp%|yMα=ݦ;W^ԍg|RݤJv@.Ue\0& ]wu8AO<SiSC Tg:)ӌKƝ!kZmF5u'yRjyoj3kBo"bpaʻvzr;&GC^DKti |x;iv_4@>1YUtpk6 ( j4_ aysZ!Y(ppE~ZZŘ@ mjO"n򨇨J=-q6Kږx2|%eҕZKk:[MHfAeAB&ʞKR [FL0Av?]l][.2=n /U3|ȗ$40Gp$憣0%n2!?XSe^ch$,bVz)OE^,n $ (MpJQkeXU9̫򰚫R'd?aݏ1Uw1c~(k ؚNQ[s4 R .n۲tRԱ1[@}\@8  ~W uP^mcxp/bgeeUXZ9贓D~: 4[11vLͰkF /7_Yʶޑb&JhQ4bv~OXOF'36Xy13J?s; WnGCyRu@JUGo>2-;qpMFV' 1a+Y焰-c[hz8ly Yi FqyuX}g@[_vov`"w0Bë-o/($gD~߽:x>7 /m".,nB?9n;:qO* *+fyv^O؅ތ.lI@,E.1K: .fiahl GlsӮVCSV:V?p'Љߤ%ŶBM!*3[ϸ|ev PN@߿՝ 3D ]a&m RG˧fkvqnZ"Z"dUK{J#:% 65{M7gMj#S,(Ν.ϯBj$M^o}=>UvgоÅΪ﨏c*+m[r6e/1 oS9`}MX 6n V^ X[ 08__;2xs.cɟ>7s|3ބgc@땎 "0 ^đ&LXQX]hd=6 E]% 7 }T8/$=Xpwd OI %D?%L`(\&=8%_m)MzFf>~|wN.#.]9cR$]!V~`gcĝ 8yt.:`ZGkHOdB\PKLA яtj a-?\ i,^a F^pxco RF0e4pɍJ u[EX.8AkM6/!3 q4R?G-N3KLMXW33xQ̈R0wwefsq2aqQR/IfzL*;^3h(JUirNёaoħAf#<W\x}3FmjUG~@IDATSCMKQ -n}e(x@_nDZuf31NVo."1eNL*Bn2TK}b11. Qܘox0W{׆!*?˖t0qhۡCdWgM #wTj}YX6Ld6! VWXr1 Q"_6": 4 vy,vb-fPۿUiCBo(i.<h)aB<h8P]*#O[|+c*핺⦜L#HşV% (7k;Q\26+9HϩBT4*UfnʷN|3hn++DoH A5]eXaJX$s}ٚ>nj542'6kNxgHDP4RSG#a㿕9)#prɷ*3_]٩$I)GY 6yuz 8ob#H#AeάoƱyW6Ԟ_[ڄeP=\9cW6 JA$D0'̉!p8>]g RCIJ<v>춮2C VJfI4YؖcIk/|Sfy5z3PT `eVޡJXV^QTRHu4$'u7> )ۛuA+' ǂ2DNx@ɺ|C` \n[P↢*yOQχ+h0wV֟<,̠a(9-vpPREu%ZWP"_XT%IQo%jDzds/kYOl>4ζf!-!ڢ!Md`(6m^^ڗ5uFq2S*yȖUo^k#&oJs,m4,!TIV-"weL2*[J/娚kaqt6 /, xp tj$]Ě/ˡV"+A옍 #HʣM-6-N4dQeY3U U<* UxmӜ!E$+g"d1"k=h+N2:pg\&YϖaB']Ql翁hC;a an14͒a'dhd#TE @0B3bsE#Dž/E@gOtbݱDB >A /$T0B@$*YЌeXCƊK+s%xUϣc g$L7}?ȸ黂(,PO |O;ոiexjJw Ӷ?ײ;a,bjR3ML3T"J@TSD~\y~LӘ4U5UI9=1y #뵮>n* F2bH:eʼ_àvf2#Uc^dA,#Ն+lP͋X蟑.pktRey* Y 1|굸sMvqr*,|Rfe >Z/wți=y%C`1`m#/?$Ͳtem:6$ӳM"B;KLp4L 4i ~m'EiHgtJ{bc).7~1.5.̈́ (hqj} PJ4OrKc/IWN*nw p2}hlf4O&Be }]xU @Fz9% ~ʏ& ˋ}x7ު),"9xjXhVdSࠉc\74R-|-o "wL1>_7pv̅}IJA=g*P8 l ˄3.+-T?6=EB;!X`GNU[~EfR(Ea;|![_#ʫb++>!MI`V,:SX9=}I| :n,ny U8ʵ |2hAz7os((2 +JiRR!=jo(jSA0?Hz|k]mǠf{ãt],*`k lD\t`#8%D(U𛎴 &xICh\ 547C!X~cjIUW<47&j3MSЀ E,A)q˘RƒT0ϳ}V1z~rDT??܍C2 á= CLGZ!uCt@›R \ ǡ4Kf|k-ciZ˧~c2dLtM#HV?8ux$V&vYXfJ&qap*0r ɨP-5:H *?GF.2U'Y/uK6ٷٿЀ*һ񔌒&FIշZƤ5ڎ,!wɕ0:v"%hpҘ9GbYЮeGߝyq$ %vZ^h6Rh;}޽~m厇QQ*GDɁ)PwH>Ba֑7o <<}hA4kq֫3͵SX)"hmDדi*OHyS+Er*z\52BI%ab2?#5mwC:FD,@Fzf-"h. UzEH$E&#R~(xiMV[6=gpF /&+h%,Brr֪cv@%l]WӜTѹ!mC >TMZ`\v)ϾnlZM?jA-?f*qUjIM4)D@X oE^=",԰[ 5cx}w+bN_ͻITAv>W8|LJRzkGlcTrqU-DPj +ņW§Y-d\]2w෪rƺ\LbdCpŎw0yfۓl}/d;#>p 4)R6"M`-0NbiPգu߈·^LEeq1(lߗ~t> ?.CA gBAxRְ k\#R(IK32LMKGOh>x6CjG1U!бF/T a{ r愕X߸@`.2d o]l&&Q뚬W`4Sm#WAg4k;]$q$#LG3Qf璁2$ȞkdDX)I&2K'kxs2,5ϛ -TQ ZOzҩ߆VPldq2_c!U`g30y-J^ݽYa?B>ZSHd饯yt_'`7=u&64Ii6( L( U8QL j:>+ɶj1e-m.O,.]4~^j%o YR+,7|QY92*#_U"}VnSx-5˩Au$M"TY;Zavk؟xO~o_.DjuU?6(euDӶo-7S?d~BFj!nÉt Xe3Ƙй{Vs Dy ^="sCg}(P홦z:f{G+B F&Zi]ĮDFMGSwDbޠJn>8aJʏa%L`jsKpuZAG;8zj]',rz?q)f 78TП1[ 2=䇑|3|cc}3:2 J0†V[X=q36<(q8t8:xNw<^)3 B?q #eh$ReԔ 8/L=Ӿ!̃ 3pD&$ʆJY"^oSAE3-"b//b7G.0urɸ3 `N, 4p3KOYI`沝mڀ~班[7而2qGg^i90$|vʀݲ?d9oc4'i0ygwomOsE`-<]Լ8aMS4}Z_lFE:sFi&34-#TJ2 gdYYJ*˚YCA /0`Nǵb),6ryZf~pK;.-n80gAZ-!ۘԃ\I&|fRaNANދki=k'hu2S=/7Wp;wsz/’ e.餕F,ӉQi2L9u+mN]k̏I*䅠|yԜ9sH3aRXVsh{E/?8?e1kiSb/F[g?%I62=\FJCr6W:p:8#WR̸JeZ۟V`6`SPBQ@ޮ ̧U"pgswVDI0]r;Љp<>r2cPLA+Cl; -⤭qqGLVS)@69")EP03?pfR,lY ez~v,i6so8J2d0aD8DƢ8^Y{(|5K^uIm4}QCwT0 XGb:bsN w#a)%WTܣk3ľHġS\ %%Hx)+ҫ/F7_VlO#[ 7tG29;\O6=xfŅnuίzArJ&$ߟ_c[z ޶`4gLq+h F;`OHyJ쭾GZGhX[[bj:|PMG67B w߂E]0CtrCWvқJnϯ˕F\G6%I胱Lnzu70 ~3W+cڂWq2Io -fK5~0 IYa [ДF ߒ'ɻ&{~l׶ա~s,A}y) ,ŊSUf' &[%6-9!Vfd[x%/#;pt^OWgܲ,u}gh_zo*!hu%9ۜ8[D1XTZqscss2ЖvU7 $ [Epx50;_6I8[ηqfO?޿?_k\ [C_KM{y3UE$r2Ɲ(Ab'[~τ8&I?A[d:`B?PN.'W`1=cȭ-2)hhx_7h0>AX@uɤ4Vc33׭;O@%ҍ}N@m|&1(;^i*GAo\0,3ݡg%DX+0Ej슭F"ǗR7:01_|0#IB#2TRU@LBX%.J2AEq6'C*P1!/)Ǿ8 !Vߟg. PWiO I#[kjfZMY>_W#󚖦_$Mj]%SeK= p~ X3mE^LȂ31ǯd)[i E3Dɯv.T7g Aà#a⋍:`+%y|R20fC xT|wСzDH0@)a!RE@rUHli-ip@AwYwωSX G9=&\vNSUBPXv[+#ן+h)g0̤{P(03;tѩ"PNOFr4=yP*y4r,|%Q>=I  c7)hDϪ1f*cٲLHSMۥD'uAl'' ^?8>Ck9]3} $Gab͙ W|M\'H-*M̕CiF"#;&#/"CoH?l7tbǓr Ir˲櫈:ayۤjTO5_%ԆA e YJF*swC4 Ĉ&/ Wgh.ay]ﺈ#bpcڬT[u,E3#E0c;hb&|6sW Ey[)G^J5X耂$dt9vc )Q"@E,s B :flB[0ɘ7~y,09`ǀ&+Ȇ# R_St1HHqsڢ!nE)M^azvP<j_dKe|~t_]^8;"Am.l TH`%o}!T%5W;_-iHzp~Q宲9q#%|矣cO_ˡ*&V3;&]UU(A'g K2Ľetat{b"g"D,:Hi0#f7YP3)a=Ny%&yNE\3ُN}]a8%uBOMEơRŞ ͨg*qPWmLJZS) TzX6aitrҒG>rOբjQRVz.(gL*Dnp ^LHca8zl#2Ϋd Ꙑ'~!&a! .EX`">%t$lѢB#jgE^LA%V!&6pͦ&bfˬq|n6ީvGև&v$8Qƌ?1CK@dL7@ VuF lEl) m3o`VgƘh"YN[ Clzgmv֎7+KI-T.W8荱C(=%xLA=,1 .Ei "uj@t)=ziRGnc= 1= ҆})~磢Ж2n@h ӸT8\ɝPDߵ?oN qn|ʮY37ƈG1ƤF.r2Z3 61=?틹 T "%o9j,"b _ېWrv7gm0@e2@$UlN\xhd;w])mB!v=OQq ۀ"XLx1r uw)>DF"xJp a$;+cI[Xǡ(:3T| 'y;1>9>PGe2F=Nt"7)ΌaCYw*Ac[Pqe}6уȩ S8BD!k3K.QI-bh{@V`| N1럯uk?j{OH!&"{O`KZne8O˷lNH*?Wa A]i!l|1Ɔݨ {2y 'WIuex Nǚ0 k L"3@,țJIl.s"ACK /(24 Z'ZbR 5ؘ>+:!) p<8ͫ$m "5kL4q9}4H9iHj@v$T -]iw v1 YxӀޚ F" ,̥ 92.rrT H~mjMQX㫰|@W|P"MO4֭4" Ok9U;^]{ff;,Qp,LrGR,h R,nCWAS  ^UzxИ|U(ZDq;0s} Hp8BZ@q)^ i=6<:}t7ŌZZ j]* -x@6ɥk噋(3bZK;pl&\2A/r=k8C{NJxgz=`:k˜^y-8e,YI lGMI`{ߙRiV' H FPU:| qc;2 KJIUr@ǯ3lRZ|mlfA6Th53Jˮ:#Z F@B]jBua噊MXP>7sGO3*Ⱥ5mD@zt(x=c,,ql15âLAFa) U\/zd^1{o-9A PҘFGQFƯ#=آT*+_AGHhJQecqMxu h4*hέF9\ZCGUR0o%!b 6.&E 3JEl`z hǟZaXB \3KA?*żVAdAS5{Y;fr@@Qr}Ef%+ UHo,fZ2hbxKˆͿٰj›HG: -|:4V7 -_h)bz( ǎMct[(ӗ;^_O,'IAIZ9t=`ɚfTvLn%E O xz v8Ul\aog"Y,2Wi}xisĭG4M \BQ4FR0Shp~djL݋;#njRdbR系$i~lʠzl:|XReP%(#675 XVo^mY&Cdiw#ꐽ> H ]bWCbWQV?**ыh_d}O敁V]4/ J?,<Ժ 6W3%V0r{>kb?eXkWz|*k}[X,4jOSaiY/X ħg5b@ml98:TdvX7^K`~!c|TȘ|;1(3PR`aw ՉFd$Gt45:C5?oFN/ƽ!cHHk%3>Ih|;#}5nZZzr;ctd $Jk`{y~>vq17(r}zV!,DXJGɄn pCed^?㶞,ecoL̹wALfy@f)@Ȉ_ !}*0!p|i\6hB`e|{<5 9O;Q (Нkby"SrL䖈A[4ol^Uɧ*L0sJ!D1S!t#-޻uRT^2"aiTjTm$y!8} z{gB4(WM݅nU)x#߬A'hucY /)s/@hpj^n)H(Iu+dYNfv/pTY{<ѥ]9Mr[Alr/+AY ԕjBHbm=~29],P,ʦrR͛XU^2iJvyYߧݯLо|"!9>]@,՞!tkB[IO>8U!!CI"&/PP;KPP`{䲱5o f.9OEb{Ku6M-`{0 eӵ<"hɂ!?+3PKJ>+$>LK-g5}K]7F8tKmhcm:_4AiAB[N5w[MisyB*I[mC,>Lȃ D+e[_3)&Pgټ1w-M{_5Qr{qt,'(C.{g;ie/3o(\1,AV<=KoMԕ9< hd-5"K}Q;`^ں,+[=Q!R0g#1SsTP,?jƧp%D(f|-)ˢmˁAObd qK)CzO`|De956Q Ma4u\-o"]J(S&ƺ e/|2D7F 1#QV[KG@oMZEpLɃDF\O dƄ""Ӳ嗨R7'MjBJ?AE@5I "DQ*<0 -6)öxece}oǚw6, 4ϧ1>NjB Ibb @IDATCdw-g%wlԠx\|RW V&l 7*R'Wrz*!un(f1}ol3#-܉ z-fO=Ik)"+X5ErciWF;Vuv/" `âT`S^Їt`f_ݘbD)Sg)Q`'@5Pv}Iri4[1~*S4z<^w&`]Ƶd8;*&^*ئz,=:,b# VÌUW萂JӢV%;I2~ Y1M?x ϫt|[I ųCT5@0}e؅|- ~hyvq Z(3n6v౟P!u^E&IM-e{ζ3w'&`t0Dyklf+ׅoDWq:` ZTē\%]Gxt" "h`Eh1y˺iI`l7ex#髶,?6^ej=组n/v4枌=Fe#WzP`{ҋEd08^XVRPȝ뻈BhV07ʚO.BѩcCjѭN%ې#!?[0"PUrʋ>c/h/|c$~GnhfM4IM]l0& -aheACO= (6jZ:!, ǥ e]r*4y?BĞ:('P7W:s(@ڋ<͗ wY-Zm*`| qMl&.F~俼O{@^0ɟGX)PnMz܄4͈GԴّe"z3EUvIlcl^yɽ!MtK ? ̷^,h?s4@ƚn N3K,273[A=@U*z١D>kGtG~=ֺ@&ψ!tmiHTQ~X|Ӿn+!R֓0+&UVZׅbv wz e+R+`лyI1w}|$@d6 h"-;j6sn,$M3b|b/G*x"Eͻ*E&$䥟'LM0?%{yClevgP| CG&@< ҁ GjWIJ c+f[ >XVZPWŃX l i)P=#ITL%؂(=3 ȝa4ғVWI*-ܯYފrYO>fpZhc7D9@&F'z+/hg t8 "FPc/D *;AրД31ێ?NvC=k$qHºF=jZso"i@'p:z?4ɩMQY"~ĔYGՄFWrmPLҞƠa6 j>q_v:BI`RcX@Sz@jqcQ{S0F_&K&N >4PN`L\:dWnB"=}KhSeY6>E'Mof9QBm!&Ra.Ukz,(, bXYb& [ʫ;!w*Xg+Ū+M&#WnxD6KH.PFZ`&,N'tjFưJ@|؂3ץA{>@pkr:m,qLƗv*.dїQh1  > Cz)於ի!GԽn7 x&mwf%_ԬmJQV`wɤ!+Q |cod>ޛ0:D˩g [h+77֕~M,MLml`d [Fvz]dJBS0[D0gDN\l!o)6xo`6 ӓ[2&!#^8%#ĚH خthr L$oA0M\ZNץP$w(VtPZJD H}UGT9tTt7Tf?f *Wp0B Q$$#xp~˔ )ڗqi|qz2Y[GUѾ}Ls1Nb|&#"3P# (JÙybM~h*Q]:bLK2" :mH|.YM*͵hHef[' do8s1rNYXU+6)?vS 94hie~\-ؓ鮝r T D[G/ؠ3迼9\'k '4_Bp cOVASPxSz@kR/c"0˞Hbxмݴ~%+nt*CB"HOX,Dj.&/>_CeI~U5so!&F:>egM++1$hUNV_/xxy*cZ2 s\HGȴ9t:Z٫vD!XUgi<҂fDik/ VT˻SI)|@W.9YI$ɻquA¶VllD 8Qn,t 8֞;AxOljg-%:9fhK2D9r'Ҁ,w0\2h{AXg'>v@1# ,^N jf0,k6yk)Riw8Y_oR(8X$+jUSi*0؊Y ;qu"36GЭ2vXWxՓx6/ 6 (mQ5x i)!}TLN0_|Ҥ hi?< `{G:qh]@njFIU>u3F4X ܎kn+w[t?P~/Э(_9۔"abMwf2eƗAF\8n̼р=˟6tw)B4osf013_〆> #Xz5TPJLڊ/4˔ 3l ѱ>h& v*33әFjtK+e6"0(PhPjE¼Ӕ@x>akr?\k8'?p~H9k8F,C"8-AHc̆V!.2ܦߦ&QdB0۲3CM Dp1C Z#GXV ^ܙMvDs+/Zevup`ܘ6s K:jGUU~+YPD< &_/ ? %P-)hULGM7̄D(C9d  ʓNG $_+5!4QҀ ;P+{7qjIsI<V7QCKμh)}H%'ڎjZUkm!G(:@y!n3p (]ݮ%maE3 !ӬY׺!&PV(6<7q—$%Ht# ' rq7uP-UL9{k9@H:7@igiM"2%ZZ\Wa :gMTĝ⬦*RuJity q&|殩g$)=X-LnBY}ZR9M 9cQP3 'Ptƛm#Nۆ`tKL;|0 3 3 -*+ԤQ9xu,jL] {Ӿ P%ڛtşDdR_5]ҀIuųyF,He,O `ò4;oY h!t Je5[G8e8zb dD9 Q.MOD"L( 8L& ZHI)PHu'ЖSt&[+fO`&ݰSk o{L3T*fw^^c/3^ zw]fZH=mŘݕz x4ƨo>u=7hAN>#sIŚ=q[+ bχ9G( %84Cp9cʔ0? Tqn@ ?š^Ɂsֆb77Tf 8m/:jey;3PCA_iǣ"_jF r@RF=`A+Gy8gK |iLw8R 8.4SLӛsFRf%ö1^j736DL?%;Q3m2Iԡ?*}aԭvq XR{[7TsY !LE߅vgK]rnV#xgtbm]ߔY+?JE\] Yجw/E1bƀsݚ2X4OPQMZfFxKM62 %Ȫzf*x?qgY{ar0RX "ҙ*ƶgbUJšw%A|! x*7B'$<;J䁌 |>݅]8 "T U$+Jդ\!e5yo k&=hS>-ʻתTw9\Za7c|k|e1! 1=fdP9jRY6}շ5v9e("(!zR7DvPep}*KvDǥ(4eJ8{TOdj+|݊U wer0ܸC},a'C`B8:hN**#[棭JbТ)j ͤӮT[/˂UE!m _:+zlmՎlúݶ6u^^S:uz~tPum8Жӱz:`c7 ba`E5˓5)NXE$)>DO/JjɧUM sI=zIc-*(k(ʄב;rRT#-cXؔiҦ-u-8Xz4U$9n Csx Lˤqn}c~  o*.ӮW># 7i$V!l@/ |[*<dM}ltX@겍S!_sG #G ҘU=Zp;1ci`sch}Xlo0e|Zt\K2dk;Qlx&VSo]זL"Fc`ӕjhN h`sc<Y0y%SRg'ҟ6ni32dr0F"jUT0U k/c}9zUwZe. ;H^UD=΍nc̃8@څ~uCzev$W# 19֝XfL屛ifhJPen j 'ۛd VS$Pht \"C=ȄG ƭhfbZE˩lNJ"y%Gwuz$V)yT` '+K:Є|E3dR \kvPMrG/.nDxʝ>T)Ckٿ„r ʡSCj3iM} \eF$<;mB&rs)F`wߋ}P.sU p8_=5y{m˄{RAlxz(bFywPI $TC`XE\=J* ߁6 SgQeD&4ҫdž 0 #ƥb&@ ݌9%)P{2-iz0.#HLɼ (ΉuqMq_͌h)e~)ɬU mBG1 B-#ˌ9, mu#-_bws6~/9䥦-xp/S^;+La!lb0d5O[B`TQٝώ/YIpaISb廉$_fS Zly"º.E?R<3/6 &[ ac\46ѽSȈTN>Dق@xP+?p>Y^s~߯y8]Qvx( 8W厶q9j+ʁo}oY)DPBÅi 2 VI]fLZB,=h2R<* $m ::$röʍB$Z>|ߜ ty3bve!`֜iv=~6L*BA@ ':HP6ba}b"*HS#E7$ kI?(9,/V%J(:gKGgx+JO f_gLr0$X ±vZYh0'k Zͺ*?qx}&\$7N{aJFSљv{f4W stƚ2 =ѨMGp<-:O z׬X#?w_CԠe_FU#"԰xʆh`"J'mucL{4P6Q|ȣLEib> ~/Z#h p aV(q_P(JE_One`],1+m|[YI-=/9d|Ia'Kڔqxտ )]د"-ns~ځxA ˊp ݀ixz4N8 3ؿZ$Nib8%8#?~Q Wy:\]F}CD?GPbTLH4~8vw]i完5GeZw{g/xpٹ21VE2/j#nĂ/e3J{D陏ۍMɝƅrjMgHXpSYDm*2BɶpwkV5 B-gp}8{Na@풃AmmR򻣾A3aQV?KBDʊM?g ],Qm/6 `v_r5CwbTFtn5L1pd0˼r JFB85B+ 0FkپH 8t+/܉H=eWDž@r_`4(`" 1rџaĿ^# ToG?nS,dw*~ȦUxXPr.͑Đ!;ʄj3:Ӄ@ 3nmd"h rWڭWIp7 REMEc00xr޸鷽;@a$:^!b51졟R75um[Ryfeּ@6#NҪ4X<54D*}Րh͋S&jSL213b>su 2t|͞3~a.)`( \d ~ГԄ8Q5: T{W9`OQ]ֻۥKy5:sՏ&+"Ls#&TBjoEiI<=0KUٕ/B6b[CZbZc<3B(LA%WD r ƔcX,ԀB\܊r?'y9ᱼ44ly[N/?9ab EtǛBF/|$o!'Z>?0>-hlƟ9(zP׽۱᾿ۡ~>@@sLh\nf@מ:~SX<>- #xQg~鈄j$E87Pj(]hjۿ=%,, 농h&H{RP> 7̡σ ɛ^iᛒAR^qp&Gi2m#x5SRVҶv}ґo<ػ] 7=}8ن߲G|[Yπ`**!qJw;pb32bȏ÷"8xYB@} gC0`4#99#ARh /f#3JqEn| j*xocΖvHO/w"3h& ~IYP,ADea[KY) 7jn\o++ge>)Hتݴ }bʚIHfwS>O_Yu^TfBR14-oj"A˔(9e]Alߘ,V^]ΟmX #K܁E;>sV-bN6)!(d"sn d⥗qjXzL6ZL+땔]mzG^nxUi1. QywO^d(٢ʸE吐/iyt]?H9Jx2R=kfkj}c6M;PN&b3  J?A|6%g}7Ȝ e-܁ڴ?f&#`:e?)8sC ha O=w?Ssa:7Q b#aue@4e<YypeHLB;7gbv/Gx56K'z:Sn0QӲV'CY jcO}7I k5lho5Z~!wq Aw+;PI ۥ+y<@8syLL$ӳa&sae JS%4|zW Fe .E- Nf%ħ &w"7k&:-lu-vPX( N}1"y޼k[{OB *GjhtRYӉªaVDi9xKZf:L.ߎƐ7{%/mDs2w:`j6CxSǭ1 }HP>/@5t T5욻 ꦞP E&20l#ņ)p}Y&;AOQ=VsftHa~ܾ62rd'G &~Mʂ nBx^nJ+cE־llU&M׾3Xj u(1$;űuOfA0y))oH$ӱ^dr #;PʹT=OVƝu'GUKqGUٳ'f&HEs)# =M8%`sSL4q!_2Y.E,gD))E1mLHŧhp\ X^Rryfؐ ۘ$LC$e ҳ nOICbf\ua)Zi[+5wFŐ zjbr3u]I=j$ufP t2bSXrMD9 / B"e#W8֬ݍ.:3 b,e)?:2Թ Nn4qd9*(:Zۑ Qx1xLI/VM8އ |y|ؙj;ρێV芐ZfE&~Mpv &Ŗ`Llzuɴ#)iju>jqֽuZ_ >q zX_}R9, my)|ơuT{/$$cڵm?&A:.Rqr.UaWJd%cݪ6qCdQQ$~X-$Ԃ|%/QC`&h/|$`\l|R7C?DZ6ax:wxMZڏ+p(:z=g&Rȥ 6ae, S$:5|37עlk^7ab@p09TY[=~.q19]v^ٱ"C30O*Bѧwt `+ЪrVQH^N?X Hf"s?0:gR?RVȷJ,c eu|/!}NP{ѻ#Xѩ^ Ys宙̹{yy]c3@9c|0Ύ!#$-^%1F@ِМGWPD=V1fgx^daO ð-4þ?*RT~W>;Q"(甑޶?ԥQW"Lx$ښw.ь:sNEޛ3OL&}D:bV[$r @U)|o;S.›!ʨ%R\ ~>/$"fHl^4`!_uYU4;Xҙ8ߍ: hƘc%.sQX9'{>nYy}v½"W0w@/!h %OmM:CI6ko=1Dٸ 衹?garY4c~_7.̞X14HgDŽi(QWDBF# JET`qQYFHۤCNkFV5K{[L\ HaΌdhF| -e2O5J%ɟ|9 2lq!FP*hۻTg|<,F[B79hz_Kh>6B{Eh6Y˶aH8 '-xIBᰨՋ-o! =όP@6 .4A9%J"%ouoα_MPdQl4+~h p, #౟JrMxjzN0bsH(?~dZni߱i>0-Dmm.wѡn*9Zz`/ÎKZ _da|~ٓK4`l( ]i(O4J FT^hjlhwriy GoCg0dc dq33|+dPP#_vntFD  #ceʰT%496x7ڒƦDD152?x'^^$y |Nꊍ`֡4Y& &) k8aCj;&~ğF6[r\sCԸ5s *GKϙ1f]N#+4 $IzǤ [LA b kJz= &pE7~\[0 /-2 ,UQ :͋YI@*l; /2e%{ r.up4)*$ <]ưFr_T1x#j_nxMev)/0IZ\YǦuyAe<ȰTovB _"([zq@C$b-=]Eڐ ?Bu* BI&_~YY߾%s3Fފ_ QѾ:,(heZ *[;¼ui%#mwN#S0n2?ՖÌ*֮<5TَyZZ?:51Ok"viuL^| (e -́ңaxgDtd#gQHzKD>=Z[=w^xaW`T}{O7M l:N26$@6UO+Ei1˔)dA) ,r7W?ˏחMs?ՠh4ZCGS 5Əty*7?OGmS0>k4,Kك)d`B3D81CiFj(o^"3C4iphLa1d>s|u Ytɦ,74,jmofW~V #"MMnGM6.k\.FDrk}1lh9y9Y3Ȉ9R D[GΝ 2m+nJ<R?zâAtUVNrg["㰃$;EJbfnGwP!9b&^p;6&?Lն"Ql $2Ow<ڦ0HvvS-cueKCH' HCY-N4=X Ut P5u8!v P"~%SR@@0׉~#VIRl NKS8ft7IXN'ZXTƾJ6h0$BȪC/ZNb_2N&jTk8t΢(e O j:Tq8u XIRzFጘ}Ӫؤ88sGC'ՉÂߥ"͔J)\_*.B$ܟH1_ܪf^和hLE|sPŶ05J)Nȉ1Rc/f#FNY|RK *;\;"o'Bk$L go;<م j;d?y(^'vMl~|<&;>>g.gij@+D~[]:6:Yw$(YM]dO*Mw N>~=mONCoPPfKӟu5mdv>."hPhA':~Ժ2j ,ʐQMƱD#s D'6xXǰL?g0S>!LO9>VmAgӕ$~om)oX lcLDꗻ6ra,'kWjknGv{W_D!*F_頣ԲY?ĻxnqͿ9vO“jK`G?oCI k7g&e)׮YQ_pzu2U(}ޟ dI'H$Bc_Xr~Ήϭ"K)2+dMCgϨ\3~]aX؋ó B7@tFKqKTF#޳߉-h4'c#(()%8%Ύ\Ќh߬1,8xELt!0m@ 8^cc" tzOSԤ怋ȥRc#BJHP{]Hǔ}ˢxlFc@|k4۰'I] h7kZo3I)hkކ#`uv~[-0F$صJtmAlzHڪ&o4 \%ADz kTs ݻhJ֝,6"ם5I)ᐥB8??2તB _I+VW4+BW&Wr^a~&S[r[Q|F&c3R|]gnDS4 eNˌ-GIMzT0 f%6 ?g!EQFOk$lGCo y}O{g?A2oy ‡ֈI}$MϘ2kW{Ν =Z3Z7Ьus6`_5S,|ǭHj 4fjIv$Hf!-o@x8cpLpس&luE;*u˨p E,FZ8*+ WNVYvm*6mfAW $ViBA;3rz+,a2O)~6 9&2Ezw9u7HJhc1%A}uk2!8K7a(z=mܽ@RA:kӻwNŪYCj;@i% V&RpL#ic5| 1"HOM2gݎTFBv3ʊ2-MdqI*ZB'4(JES>Tslll,K#4nsB>'(U5>,3C!s:nJLbDxF.R3e .M jl^[[Fπ+KՏf=3Y&dȯ6SZ Z&&{FL) dfF"N| -դRt΀ȪQӮ}<\À0u[簚K {"Ͼ U6i%Ԁe&v5DǏݥ1SG_w>cٲ`6;0"qlI fI uyתs'x{XFق' Y&F` F?o/l7cO2ɣ/L&%ƤuYaUWjҘ:opBCM*DoqwGhRst543U[g -I-/,U8n^OImY5 9q=^|Ka84r(oT;pMm51KKbNc< ˬM#43)mKGdB'/q9. Ga[3gіQ,xF,@HX,|;PZ) Bn0LMCCW(~ MuA.ԅIK <6* Ӵ&r _,YO3`%1~}~iRu ݄vt+;Qx׻H]M!) o ;I?ϣx q]c#cliT!Y=j|02AU8};qH? 6-Fa Oe~KfU<QzG JJMGfhqLDc3f  * %WgV8a * i7eA(4Uʷ B|Z͹\ c^ _#DVPgv~\ 0p[<&i)#.P9H'n/0}^ۙ0i* n`leطdKCv3KP6o*!^.}`_q׶un~KNCxT_#+]XbSbph팾N P2+r|{;ȶPN44V-CiY>11o픆 T'&I%5nU7PӛtUuݗf+"}&MWJ߻O[( eYl=2Mw@HEȖURϓ逑DDY͈mlmgzX),,_O"w> A"ze3/P$ȱy5h5ioʜpVB˚!Vy#Zgh*a~),_%!]+^SFٛk\59˓\J 4a&_h3e-RR &<ǾyaFDLŴ]ݞ7 _*cK/[59Ȟ~ x'䬜ڐہka:op@X.+l$TrKZ" 4n80 RK.Ag}F8, 4ƈѥFZ&hncpHU-}Y]|HZ,N9pƱ|#S.z=Bfu*!.&IE`ZBR+" äĄʙz/46!8©4K~N:hx`ňӕ6ͷ;&^ \go>]E'/ص*diqz7wN7@ȘɂP7A+{SHY kH[I1ۥ'Dy|]COz)#} q&@wUN~v-F(#57w\ )#v]+vj)o0MŶRW 5ܳPmѲL =07M;6y8*4uDI!Ϫ~yڰ}xQ11t}{cOq- fp-_5YӎR=1!5:Anaи21(D:}[qy*5ropSb[O3]Nr$^T*=4C,< = addl f>0UV>ԠRO*jiRi&o:UFeN9qÎVVU(KwBzv<ѵ|zQUp6옼f_T\Gj7i=Yi mͮ"ɦ;Q(4p'ʅvf~pfiPBPWh8H#pK 1ק=_G*=0.{"*C ²J~1YC \@oC!R*=eLJ@{EAHh {UӸڶ?Lג'OƎosoR>,Ro##L7#զB2Ayjg ppj.u*v' ('rB@戺O3vIL `n eP;,? @x ~J+Zi^- 2ڇ? W6MtID]ݏYE.9ᬭ[ cN!sqNd "9-5bH+\z6ɀFFp 7J%͡a~nm[QLu j/K-د۶6o,Μ[iLR1pWk#eүleFUvws9;=l%1mlpYhւ>Dsg1o%LНEy3;1M{@yi&HQom L̷V'h ٢L@!kp 7kdž2kEKLH.LUś" Wf#,H|kvp>wEN P㰅v׮2pb8^„K[N|j?` vOE8'㺟*빻QMOmx DА!qU})$u1b~Q5hS`n:ASϟ>3w4UI ԥO\!OdUPwI@XqRm"6F_)(%tapؗ.-\-@i|LCLy̅q:X0ʷ5$P1 ۧؔg:YA_xZ -$a8 q6 ,9`n-bn'u4as  Q"UW.AM@WRFP%9CyO< ғ}2SB.Q`8GCE2)%Pb? [ TI4'B.s݅5Hj9GQ^p xLr?p&{/@rYp|TАa\29It />seNև밵qz2L(! Ѓ4鏗ϣ-3UbSE^F8xh$C@}uD(ĦzS~Q;&X6--]\*fBo-ii1t66&&o|@uxj't_",'tPȨA.3fINjjIo; w*): " AD#]1iR=HcIRgx\8!)R/l{fpa6*0˘@KGZy'"V3M)ʾמsBmw1rc1lHDw:*Z!f*H!e3?pCjLkh16uHŋCwDi~d#3*#II hT`k@fQ-9ɔ[gw&h4v#bX)$=ttA)d5-kDI)Jv3e|>lTfZgxԽDp}S\N C6=\`C}"H|)j$fe@b4Qd#n0F6|a|Ib`c3C-5UN(spVbs^y.gZ6עY~2)Y3걯atT7GO_Ib[0Mk{hi{A7Q`:7"JU.7%S"*j|n@0RQv+dmX M SQȻl0G'E1i3*"q ==<ܭϪcW H4aHN}gт)fAC9W~$`MEZ|Zg)XIH?%⑗C \튺eCTBЄq&?`'-zc>a/jCB¢7--͢|?\bn |oD[6?m~GN$ƞ>&V̥iC(54_w{SF.GGZuڼܸI1ZVHˇ"̃iGE>:~mrs tOV a0nW~{ō8Jk靆aٖ3`UP a)j+E(no!-E:SƋ g2+$= 5*`,/%mm;Kk26kМELE88ebG>1pؾ(pn1]9AW/[ZB|3dMHLC00dFb_oPv6>5vH \œuY f70+3EҴނ~wLdez0ď?-޶7[}\xfg&C|vWLԮoם;{m씎Mz'KqIc/USU&Zf9=/ٿ6dbf KZ227);>$/Rgm?vׇmzy=Ң{{S󆺫"!l̼̿F,9&r-Iw"/*`|Ƀ VmĄ5/Nae[pN^@z=Wκut|EtBz_=-:xH ~0 E. 5)%Qq].2;(RuP;#bHX);ZK= b/8Ech77[kݲ-!៟A[:؞;L"FqU\ %[Pv8>:Wo|]C]/ ?Vo\ ꓍%R^Ϊ|lu(RdL!t?D_Wͩi7 %_}&lq}u*XQΘJ MuF%:@Oi+_2ye;Y,]cTE"ږ 5n;>̺P"x "|Y5 ZN_,宦&_PCvʣ\NKE7Ma>sU$7g`[F> ux W*5 21phlXT3c6َdS {I/JQbW&Dof U p@&+Q\Tj|Mfٗűٖ9MxJh($``S1V(W4X`TN$n&>/7w=@-5U"HF&aYTr<i5HУT!5PBP>SWG WZ֭ Zݳ>ځFP=M|C[/(O9*8-?Tm wL;D<zvz&Qj49;&  9<讉.x!6 " x}c`5Jķ0LEq0?px(M4Hhҫ4X~U}̽ {SŲXI(VHWb`C<.GX @r!+;ȐiܒSa+m@2akJکMp)gv}24oo T*Hlۨ_Jع5q D`Sx۹{R` Gs/beiźb8.?#QBzv Lg&j!=/$7'Vt JvC]  sV %kQJ_ݢ-o,"/&5%ah-Jx1)3B3bȔſFqc, "r]A ]ְIFV&8&~El!.xa)¨nFnf'I ^ 6]8Zʷ0nBl!܇4V#\fc˒eʪ{kÀ mFofnt)c"Cmbѱ!ֶL\o߾_LTIqkn7?/gai2ُ%hij~C#V/rr[9!G*;FC_5 1 & *q(d\$9j-m/m 榀leny9VZ /:b x [DyY&0AD<ґ ;yW*ĎL x(n,AaYb1-f &o;lhzԧILx4^{]Ekph[kSlǘ25o$=d+GaSY(CGetKLdz_2[瑎>cFR2VI^H]<%Tid c.[$`e|L5b/i?z).2D$FQl:q0&vt/{!(T>B"+w}ĉp?.d ϲet/ |{(^N} ~O ̀ h_qv=P8tf.a5WR+"e c^|GwԂ`_4є&,z㈘%%66״@MPY_D0JN:%ęm1 --Jz P&6 xp$^J&[;֑Hb[#5j3*0iG\x(P$.FF 1%ڠx0s̳(Bh;&b/1"fg@2%4 S9N4Њء xLêDuO+.lgɓ !\X{d!(&1 &5G}% _AUA'uNDŊQYCZ~t3 s?֣8@=H@Gd]a"?cgOBE MR 9#LLM >(ܮz{h~rUrMr|!@RY_O,FESjMs›t.7rL\Hoqc;/4"Rb1瀀(ݳJNHHXVXKt~5R]̹DpBBs#1$S-ݓxQƔ̀f6F1X O_ueas_X>L$>(,l˺1İO:D_E~0g 2Vd <|84 qg\`} HX}w&G /z_2U RYDVϱPڅ_)=d|.ƛk;+c SP,G&&Mf+0~:FC sV*NK)Y'n n<5*3~Mr`j* &l.'eT9>`A}E\^{ ` I 0g 㒪'䉣g"Bw2uPxpM,~kEU9#K+QJE(IԴBO Xf@Fm\9bgLcWENn/0"a'0VܟD`+[E D!0$B[?n\(@# d3F&ȇ'Z%nF,hN߿d I(Tc9:q$֕fAw9&V̗)2XZq dҎ}*/RmnH 0RKu&nF E+P z"ɉ="gp1FF`EAM~Yackiri>9B4k:9cVeWbrdM('΍hTg^]f& xc&cH¯&L{2Ԛ(̛?V*Mh 0[Ytso*/%pk5DɋL"ItŽ>ENh#\~Oq|dj^M/$ڻxVS]e|뭯^%@F&hF^77q(`z Mn[QW*_Ӏi^i(45S;BQ>41YyZpFj9 jb0僉d sϬBEXV@bSKy,mw䕌~k-WYj(CďcE?3Z0.$$/Z.^ܡBժZd2o(ͨy "~$`X5!c0p7)L&30oLЩ.H,κjk TU8DŽc\>P?qvDDڌ\\(N ?y(!j,⭹=$e Bfim\?bf2}N@SqKB__>K{#vDwB}٭6b@(^7Ud52.7/v;2S㜨k (; "f#ۨZYX2ee#ArEErn3}qhšYX!1Ch"=Tcg^x,N\֩s:;j߹l 'l|m^>|ʹ@IDAT]+Ri0Dסp)XfԭGbPV\X_lXǘ_,iM6`QҐ|֥373ZO}TkZ$Bba;/FD" B `!>xU[v|̉.%͇5^ӽxΪ:ƹK:0zu?Txշ+ jR;F3mB@Ş'܆AeVBͺd4Yz6.m]RFG7[1P]2Č;YWJ݇M?g{|STȞ*mv?8;[6_׷#b퇯yTI&B\ҹ_^&Z14f@B33{AM`]#{_[Bu~+$;mq{Κ%>~X`QWx{:B;YyߚNjm{t 3.\9VKDzʲ\ԝZH#b2MK)fPrE\4P.2Rٹ鱘Su"GU'_WOiQ,=J nf>Ҋ=xAmB6R"wԋ|?zg򽓤:85۸{z@Te{yVzhJ^[+`s'gϖ^NaV U<(²SN AvnR?U4Nl1J*P',2J{%B?X- 4 62YnH|=8eLfQ#q}̀C6 d5p}DJ(Qa%&S rl]we;fV% ROsYDUSlF) zuY/fb#sl8q7leM ^:w*&Npd!uMosR,ڃ#_H6_~H_Mek߾>^ lglw(1㓴^l?^MMYs0 IpMuvSJB8_a #cH6~Apx+?}{~{7SNBC۩5,wG(j끾@HǛpL9UѶh߹"NƌI!udy#x>:Ȋ2SV˜D?ux\RUMP e ҰERfc!Se96KƸgP0@dƋ^Y $6&-ݩ4]0i&V,xl6;)a+ٛY*g/mQ+6˺HY:zSCUU`ׇK D ч lBr5 bsj7WP֖=ߥ_c`mcPp蓭AHIBH偗KɃn01qW "dyx3Μ#Yw LkAu˔/2\,%ϟC㚳HĢюh`.lCp]}* <^Z1 z6W).u1y!lYNW Ĺ,PlVQn+%52Y8͚h",})QBr,ڙUTyn3t(U©\=CDZcA)1!!l'Ex*iZһ!XԵS4O+59!-^NlXR_c&Tq%7R94 j<}VSLo }`ñI#` ]IED-COLуg~{ue>AxHHyԃMT,!gAA~P|dB#LAAAp-#*_ŢDG0eG|\,uq;kө~ؖ_.Z۝_T'rj`нFE@ STObc|s+QqٓT*"&Wc+HTRO'\>:!UTMȘ T=TcOs8}umc3?x$A8ۄ3a0pPQRUu)W=-"i蜾5xGo*ٰCkKٕ&cCٴY"I}=\E(ƒ>؏O/cظָt_7CHa!er;rJ͛Mb23ZR\ QWuׯ!`S> 鄬g85짴gG%(7Ϳ4+r5۹Frh Y!|4k'Ȋƀ^4z1ܜ{Gdw 5*W>5ib^qAC ,}`0ds5TPyO75C P)KnGV<4I*EI4aTwsq枢0M`8|qj ~yu$*iJI#FS`Q9 sf:y|GNZM@Kd{.ԃ$aopakMWbڛe"r5;4ےf~121[^zŖI$?.ĊSÈ!t:F## 7)c+zŸAS&'Nᵋ4dGµ$ՀQg?Ea t-TbV?SW t>j'p"=V-T=b/w|z Ꮨx^~8ZX˯5 r3(-k=- 'O//%drB:4f6-_q4̺# {O؝\6ORަ*efVt!ۣHȃ'ޟ.Z6ks7Ӡ!.4ժsk4vPOk_]8/|&p)a™'R'$1 3$}sUS>QAٻPɉ/1P-\eSd6O[o/{9$[:/ w9 缽8&[9}f2}ƞˬYW!弙**i+ykE+%a|||Z$y2hޱS@/q+]99 n*S1 @m? ЫwJ\9bJb`n%i$Typ*k&UdI^Β(.rlmCs٨YS"΍<.#FJ^U~ZZ- X5'%.B'#$Eu;w53rtW/J() < L{s|t\nnBD9+NHvK 6M۸S5h 1 n9.jHb1JLEE**띪=ASq8}@U_NA%Pu5*xX-\e/W@)*J\ nr]b^LφERyv)a(RFΛFsH_10A ?I`1ẓv]oƾf.ֻvNl1caOy%H(yxwQ0?Rhdؘ S އq/59:6\G]4ި‹1YhB.7.n5,ZmFɅ9u/6nI1moPľe0K!W0MvW NU즓\ R2ǣϖNWk`jaFr#~u@ʌ,jQ.̌BۅFO(`pHa"tA ?e#D'fso˯۲-#KviuS=SP0EƒkٍM'ԉ>30 GR!WKO5EqXQzrlT[v[ؒ╪T+ͮQ &M)_-gmKӑ{DeK o iLE KƗd% QBˍTڥd>$*!sUYlBh(fzYfWpu'"u{e->Œ[ƇxǫmV'޶fʼn ~08X[6] !;{~ m'ʼC*찰_OMT7kִl-dI!w{uU@u9qͺBR)rL;aD-Si!u TpgxFWq^TS|8-nJ E^!*p˜}v$}$,U4X$U|*DEw'CPTR &*SO{<i#N1۽9+ailM otBF̳}߇dRz$ aξ t/#ٴĀۯR։\A}<9}5ϯOϻ_*^_g)-&кGxÄcTj3:Hu+ D0dhҞ?[ZamhY9 !v̏'u5~9 9Gϙ} )06Z{BaR!>pgQAO{mM1V;Iv(֊?:τ[Zz NjAyFe W*Jm\v:%Csv6Vp"Nzkiuzq.Y޽Qĭ ژ"? 9q]mg9LG59i[8\)q`PXE/% fm?[™)8\P`Zn]d:׏CJo84%N œj؛  V<WDV@9_Av e4G 4'ЖciӠb!*M_'x0)$@ewR&RedY9 Ԭ;)Z[`εjVj Hr*рbulZxMAшY(þ4;V9-Etp" x+y =`3%bk`͛[PԖD ^¤vGIf+*836~8GtȽ(_$ؠJO=b bs ? gqLCfSАYcΐ>[.N7B7(Bb;q+o$ep&OC;2u3wԌtw1d%=kY^/Wfה>BC->CU.CgcuOEB:Oz;r6X跺)^XA\o. z%:JkDKHKM,L͆jgMuK([rzFlfMKNg S9=~QFV)I#==ک'+$no㒕=Ci?πrĨƩ7[JV,gq:}A~g F-Q@ހkW CێwRo r% C؎T.hHw$䌱_I<9xD k9:qeSwhrr>d!ixF):Ԫq::ɪѤ?>8`y#2 "G% C-KUaYP|hFpU@ -aDЗJ`ґf$Ktqa])*{@!' ρmFB/& p-֦8gU[ Ϳl0*8QdP"ƛ㳩z o7kH}<HvUJwFQM^N?+dxK#eװEH{Wl2/yTS+L\VU^<*BJ b,Z_VVR[j7qhyjnK]ȒJ!z\u-vSg _.4&A<ͺYɰObڟv{I<\a6H&/ D/İez * 8qWl?۫ Y.0c 쟥v:.)lƀxT8q2 x[S 984~cﻪU*\O?bKr8 U<9s-_[ wW[hO>2l8A{w(}J0dGXYc$@c1(y_ϕGnǟH3)nGcҸ^$H=[yo-rVoǧۯ畳*?gK+bLbEEXkg|V Bdy 1[tGUNk!i^?^Z@~vLL|1bR-RQA ucAJI#3Uy%~0x1q04!Rt"9O4oG/ >y͟~)"ah ;~)# ~FhFݤP٤~[0U ;kOD  ;7)=Q\,4ރTV+P̀:IhR/%d9"yR 0k&fx pD.! PD 1l  (aǑ3"qx'jyɄ~gpdR*;©emN{R৕0Dɉ)ˆ)*TXnw ?K7>I+0zn۝A1dW@yQG!l!ʙT\hu﻾„6C9>45 /69hwL+d>dP(O4KL!)\a %Z\V7c QFr'YlJb-23  NH}I1`f'M36j٥E{z 7GO+K MZћ!VNUr [#nW%mZkk7pЈe^^mWx1&W7xƒɘ?(^E wȮ]boDQc<8Ql-NM5nՁmDԧrQZuJnE#ԴEh0@YF3hֶ8@Gbwؐӧ|<~(Ȉ[Z䬰g Yux8:llc?:I98}qD=7i 75 ̡"eقvnU/7cއ-ßI7n/Vz Zu΁@Gh?#jBڢ{ O?$@9{ 5uFgҾKrޟyHIDߐ|rD7`v-?ӚeQ&g;irFFlu|~JĩO{TNo `&!$ q-_SA64Q@U6z<<ٻBDM%ghv om0HuK9@G2j?֒;$FK-~rw{Wf@IPncJOrllpOFx/XPs C4Q˔1ܣjXrD7GRa*,y~!\bk/|n ?(%\(k5w RAVk?1\/ > Pi5BxHY{yÆ,Ҕ Piھ<6F)EؕbrQ%9lԷ#tEÉr9pG\c<6[c<Ł #xsa^]w:ސO52Y_٘ym̀&]ꅱJdcXOB ‡i_GRJp0m\m#\2Zr 2!O2GIQG<l# Vxӏ‡QLT; >COD}>LQA3C`2w$'*Ƹ&mm5mXIrwm==Ė`ɜzKm(BfyÀpŠw&#=a1;@I72F[x]H&f*J88bn?+se 7Y ʻ6px>s(xGIX}@9lIdl K) /ĤUj 8u1@7"WR e Nm{ny#},9 )܂9 0EC_>6aJ'8Ja 'u"ncL,V! K[-;94#A&D0@Dp=H<>/cYtC۱* P#,ޮf CY_݌듐 BN7:7DgIt'*L~`b2njVSnx_?~hc"1<ߌ/t~+K*VMj ɵ!0ZgA|><. ,XK J ¼A A#O/OVtWx [leF e9>*?YiIJ+]p9umLiF',aO#\:h(Ry0]9 Z:.jjьJx45]R`5"p11cPIV'o8 B mCʨ9M! C_8 zSs'.Eb#:=`g8Cf'//xuA" ,mF' juAE(`.i:98NjUosr B Xhdsx=i,H(L55]&uF9pf nBŌ8Qڏmky!D} U@I8Q|S?(X&}˝}¡6&j.t-%~gH?` GBG< 4ZW]R|.ٗA[(I^%p#dO hug s?:E,})DEJ~sSh3)PF妯%ٞJf/KYabP[ш 0|\6<^DK$KF"v?aD(I(q}" KB-C6 vj|t`A2(Oc__/ {s$ *h9{n%^UH?$H38@˛,c+iR.nੰ:N-}7iB`njՔ4SrOA=^`CU&^OgyWӡhe2pg.B;F5;pAֺO#D=$)#ot;vixQ:yPᣊ3jTH0%mb&i#Wc ΀ \13f+8G_(#NSAY6;-<5#M C-+~v/> Qô.E15OrJ nH"iKD=eV#rq6AB}SvבO$JjYP|a}u ó!@㱥W^6c?M~&19 ygDt- QX58"ѧ/Z[3L<$Ț*siG- L}r_JMH7Ib)3M#af q8{]o-6WפRW;TvMWO; 0g5gd}Ŋ7 -} 3(x┆W^Y;#:5djS>Ԯj ERYN:dꓵ/$ :vKOCӹ@<<](My*A 4 w)E&C"2$_kɆGp|,$(@ƪ1M"GFrn8@fsd,;2z6(K 8@a;ݷi cɰ,*kA0f Ξ*(욢џ1IڛgRz+0S0 ؋ qrzRW?'s|<Nxg_tIH\n$%Exi?JyZ4ʃN/CDB7>W`OcSZM}¤ * 戓@hnZt?W$nZ3š6_R؆CYq  >?T,sR8eV;dHTjYḁ%Bͬ; ϙz: '"^1!G*ub1yюLy4"Iԣ rqy7We@\fOppԔ4LY'9HeC{!(d؇V_s"@cKz˞4GkNfD7x/qǖF+!F i`8Xt-爴~8}͵ARu\+y/y2]ڗUĢ0Tfl y ;"(G\G]L&&W~b/*2flj<W4Ys̑ඤaTI9zqPC(XS=Psr,'b4}P}ay}YM}t8{!FXd M/Qv4М0ІKˣw0S \rM2bL`3%NHor cmz ej?U^6<Gc>qyېEB> lljJ}UP-HZ@ fQÏ2_&$;a~M-dj6+55č@bv\f.Bf 4R}[urٕxXi!0`Šx\!L0+u\Tas{ugHc= &y(ݟ=@a<{x& ϋ jJ7䙢idfzO(g0?ZsXO6݁AV1Z!,RۚRi_9~e~4aʵx E^ !7JaM«oS|f[lpx~O~P;&x" ]R7I:(S'ڙUWWfURd'x~A3(4ԳZ۪U;-8ˌ;X|db!뵜@a؄o>q< y( >֘e˙vB{Zm߲q>$ ' 'k鹤- X)VZ! k5I)d`3OXpx:@Y@<8]Z+H#$.UjsxV k`rKnmgL5h>CSh*{rWvba,$" ی2"-[T;`ܽ\n52OA =̊0i,_NBp*ɮKK- JPQ;/MJ#!id?X0RM䩩闠4r^GGH@:@?UT$cM%\a֑1gxԲԑR02(HQ) p$IHG6b@IDATVI?=*E@ݴi "MIc>8Cq巯NiQUO[Ȱ D ⅮG_^C Sd )2aaĢ4ِb1fR@cB0tκ.*m ̸ܧQ3rȰ u/ؒEmlþިӭ T.Lա'76n3ֆ^S=.?jRy04ZY9blumnF‚`u}ZA.GMJWX7PC7"ot·fG[^=A`G \ 8M8ᜤ $TG`GvtRw g-a䒦 h 5Cܷ[~;_~v2;|U:@q/>in.pH7L v\gYd;EDih nVxq2d{!j< ú[9Ѝo]8A*>i~MMnT:>i|s.z%38Qq2S;55RixԖg!\/`hktC Io9(=T^22NY@b9wڳQhBˌdGBSF5;?y4Kkۅ6F򝲛A`%buR;M#-ݪ) d<+ JŤ2,>]% N]B {4Y7Vv!e/4e?hs`2*`tٸ( 8=mdc[kb*/@'x@Fͱ>\< = E)Sϩ Eգ&,sΆ'JK"ۀxMH%EGp ۳}27&dl%dʖ236g{S] 6cUXݫ`@,o(knK6)rað/{˫CE ~ycoЂKo@+MUAiDZK5jZ\͑ BC__(qm9欐hBu/0-X ZΓg^2]x $! w4/xz:u!N +$yI)Z%h^D"!W t %RxWSl1ljxٚG'ȟLJO'7Ŝ>[*|eKaTmVY?=}Q҇e ]Ejp(X..\&_w٥{qq +}e>r|G1zU{z/,T2 luFǮ圇+?KW?܏|{DćcÈѭlȣc1jՋb(X 3Fk M[0Vąj1숷~;`>|(MR>1xtt cj; QL[A39opeHO"f. {YLћ=ECCA7V>ElR1䂀Dfjaqs,aшFPebb<&\`1 Yc)&(zٚ6k Ew)Y&X']8ٕTRi[ j&ƕ7FAbAm_$7tĚB;6e3:n4JEJJ n?S?ETTkP\ Ls+tԕt%݅1PUit4? m\i `C m?zզ#Pnܙ1MkXU[=ڣdpdz71 HOyԓ `9S%Yb-TМċTA`- =ҹ 8C8USPgPϓvw-@T4!39HYѩUصtt[{Z:ݚ+Hd#g> F!wX5$[9Yx8NVy?SY'2y9(0yEߚ/UHNq0#ow2y;6l#`Ď!jSJ:<$f)t<e4!v93BDAƍƉ|(@ZGp$?+nN-4Đㄵl.﫢`I jyx1)S.!$̅L YDz"tugLMj/ifWxn^G39"6.;2ζACw='h#*4K:s6=$rґK7j2wiqEWwXM;aKimT=mvvٟ+J\r(kdx  *$A|4wQ-\~|iͪI4@ kIzV i]P멮zdc]^taEl CW( cFMeMSV9 fi\yT`@ Per=AS?i2\Agך߶6 jpX"Iډxwfpc8KsuVjo` MQf/wg9 4o x]Y{AP?Ywz = W/լ>-'!ye ߘQ^Eru'My!Y&pF/&賈(_5sCVjrWFT)܋D&m 1|qffm: "w/B9ۅ6"!D!?qjU &lBPq9B!TA4ہEO |N27F*tO z؄6.OcKȲ{7sI쨘X 6J.ߠ " YN@[%5i~tk+xp(ÐfZFG(zo%ܮAdKi' H 8Φ0( 96ֹQ,,TI}hdTRPp8BCLQ):C<}L00bӆ@5 t$ 3mYߛ5qt+fB9E6v [(9IsD`1*X1,@VPYj]]lj@^[-ۦQONi>쐢 *I_%r* KS|8֖ѕ6KMc:1Ù+ݎ$&3(e*]Kù﨤BZ[<-9^I3A]mFPSHi#W4""֩b"RS bRlBywf.'CszXb >Ѡu h38{4gճyMu֧ :E%"-]pV*sD daVgҁQSrTf"[;Q2CzcvKsRͲrEf8jzp8#7c7|;/ף(@ULRZZpwiOp^Z# T㐆- hV'b8$_` =t;\;hýsiA?~,2\'&~A&H GavHY"kV΀t"AwRυZ:mc_0r^[5w)>C Sb4~!Ĕ1h,F}lcwYޕ[ ,΋>d?Cizqи6rT#`x%eb<^K-[Zc5т"X*_; b[q9;F)r҆"RY,,ĢI fI>Tȸ79l!`y7E P+;|2uscqmum|!UuR*^|f4MU a.jfR!7vAũC O nq+pϵkJrWu9{T-m +m6E0V-A.ijpp]1F,˄[!BE9|r{z!DdNCϦqJ5bN+FVǨot`Po/˪mdV)6]@> CU ZܓA?s]sws=ID5ggR03$L~{7qM R"ua@SOh܀фڍ*ZSeЫ`u+ڣT$hE)/:<?LrMi &l~ǚ'3y=Y $̌{xD *f!F`@y*-iM!LA)<}s$0KF:j/N|^ CH߳)>n1:80ϥ bl 5eTs[֤~t~6dd9=M$Q L9NK$˜ RqQBpa'\pM͑A.Qzbv}sNaqIaKYm=~˛  xƳy6v+ڦCt7O fxnwν W4nGRZ>Ԁ*˧!\ЧG.qwWsPCc#+u.@8o)@L iF2 5?iNUDT =1^Ɏ!-ro3vF^zC@ggE'-7@sс@$2k(eC&oLgؑP""wm\Q{Ad[6=;sնogV̚N蛚Ҫ4_2RTb}zY]m)_! ,4d,~lHd6@Rr}G3k`ZkyHR\n&=x(-M9_Y=9`N`$3.[9Gnh=ui?JKv)o%F6( UKP;(fn7LN;<2~v!L)XY*rnp uZNx*pLƨ \HHl+L䎕 Xw0YD.utIEva`=P փGN;Oh8IFQH'&N1-Uɗؖvq3 *^B%y+-+'4"[J/E>'J)Z3!TO C0A:R^_b2ret4"#,aA};Pd`e dghRqtL(aP=)$҂-\FƷڿkxs.IV";)u (:G]esyLG+O6_ S[Dd둧 >z4}NJft~PӐf~:(,TEM|8FG<0q^udh88 wH'je *B䨡'c2)_feW^w8+oo b0~rjlmykl+`gA'Yn<$`(F:1L]Ȕ[ß/|~2<=-OFK|˔<o)ۚ?p7 x{O<F0JUZ3'~8zu  4E-Dv-[6=V]h|;bbe >Ko+4f'9- I^94:n$ ֐ z0@:PD{ ǰF"oI:ڼ8ԁ}\oVǭ rTR p[ 㢀Û^I?2>ڏvV'wps~OmC  V+3Z,?4RFH5$GzN!H LP3P ܮob-)mqGQ0nЕmEM!`s;kc`S_q&C[ &]?O.s*2c+l^_l<>g q?ܰ[?QgdN Ơ`0>&(>}҄>@o6QN.[RzSKm=m}Wr,aͤ -Tןo/oXէu 10ljn_YޜNW.ffLh'1ѕ8sYNX'D AK2T 7ĩ[(c4-NM(i(TgF7yFBĩB 5eX\SGY2}Q/~',4t +}"G{] &k؍m'&|+w|s46--#OaL|5Q2ƫ%r-h,<)vCe0I2иᠮxia:ji T- k{C;bbOC,"A'w2+WTJ# wޫRWC7ʬ bvVϧ&rMr6Ѯh߆r^&1g@PhIrޏ_ʹ?8hAwTߛl}AL+B(t/?l`~dxdW+S D]H!uSy]zy>H!>nDE X)J(oAeF5/>~|tgn/"POC 'kCa1WԳ~۪oJ!|_w<)]Is#ozcqDYADSSuW?βJ!24z!/Q XL(@g loh1 q< n',GrvUclOX3]Al۹,[Nq ۞',qD?h:P{h͚¹ w^%Hn￯T_+م%Hi)[WGmDp(,gpD)~oNxjd ܶ 0Ҥj ~W-MCgTG ]P"ۧF _a9z]BEN/r" H ݭ=FqC" Mbvsh^P-~uUt 2y19)@ҏnT{-UHQvUh9 ֎jqmq gfn\0bu\()~R9?5ORpj_*d7f]+&q}_j~⭚Țh Zo0õi!8O9,EV~Aw.?[bx0/ۼ5U V "x! 8J[ c)^ /B#+Єf`ϸzZvYtJM֋L61gL2xohtu<\Rm }xes"lD ܀E7|cp mjIVP[D|dӄޙ Wi p4A|0&Z w#[gpR2wqŲs҇I&ƴo (9CF$Q.;n@~m1QRzi!(1 S~l*h͚4v*1u#t}<Q\PJ_L/c!ʻ1\ FPM:^/wW+4Ȟ<a{EQVyAuPJC'G(B}#[OGyތn:d *D6PyyȪ5ˈԶSXbʡ0XbLKP@>I DfgQ\U;ؒ1_ g1\Ĭ}Eis}~7~N8&;MGS"o"At"wn7dSۙahpn ozLxmU)"Z.bywI= !_Ƭ^djܒ#P)c6jx'IzgRUi1_(nL[Z%l#]xYjdBVQIKT!Yp%@0IIrm 6㕆ګ.D ͦ -4y ؕaAFm6< Rq3[6#;˼P+br+iuej+˛f"_.NY`.=e"$l ?0퍱ețFEobAYBbpN%p?ofnt|([] “ϋm);RV6hWXG%`p`ure>%[ j'[ i[oebiጳxjq'>971f?1NHYC;[bR|%!*sZ-Ǎ13v`Pөh a*cDw 4M$:cGu6c-`C~ups0`)LG 8jb )[4V. WAЧ˶ P~-уs6M oFXYNPXψRu)?{aùnPY:0)3D>e67'F%BmB;6S_ʵj_{?e>>!y/@Mk+ִ(A|3'-ۜܿ3*DOܟU90~7vb Ul@AtG .M+?FE:qbPbRL^E/Pfΐٱ qOͣz_Ԟ[D "XLɢ"҈q5LGHsgP WnR.Ix쓺IIK6M$< $O85.̄ hJ ͣIǛ~Ёv קx9~mh d ܴ@i#sNڴ';^wS VWMzHAp&o4,%^ 9>f5&/`*49@ 72(JLYِP K"LhE_؉yScf0a3f:'C~GyH _ц{?5jKvubGt Ilt>L̑kAC% L@vv/ȟt\!5Wp["M3gHEa486^|X2+ 1HD.bd|RE.d'E)UR)NFMyN Ai[ܽ:Ua@3<̜@|dzQ^G;g-5&!ugB )H\JrF}b`|(pe,6< yMrr}+^h2+ιjKUǠb{XQ[)Iĕ_gB9aMZU;b,vPt+Ŝݲx2\t=nǐɋl .Ud PH)r殆P'7P2gCpUEJg$D5;]_BxR&,:좭݂ l!k@iب'P)OjfF-b: 9n ʓ *I!g YHnz~T~B 3-1@cAVbd}z1Gx 5u̚~s?qН'bkZkk lp18W{7BVUG"'dW(RC Enx -Ls20xY3$dynn5)A?JjV43FIMRg01xa>:$,ʩR,u4hc 7 #/%=;3l^Ao8'iדyzhnɯN 5Ӯ1:wMXnjGqi`6!h`ڎEV\G$\Fy&wp]LTiU햱SIrajl̹/LW "R#$. 0)2l)Q{(LfeKFo[BŵiN(Dٞn@&6ϪR))@R1\&Kc잠% ݓ(N mpSyEtX "#/:#$/n1!|#7(jQ4\CZTd\''W]M* @>o_VWs=\fӷm:Ԇ<=xCK/R*u3cRՆ݆k}rfH*wc:D'$ܒ'M$A|dVK¨;uG-;0BNB,ni0Vb0_C ң@xHf=qR wMܟ_4Wxh Jxvi"L2FFvjyΓDkBE4a'X/@>2w5H0Ï.<(YQ(h3zؠ)!1/M|z"\anLyn_`p挷 /pTgKVy'< mtl<2/d b%qjn4ي U(PYHr~-Q'sFz+2BQ:GaȎ &Q.yde=I#r-HhM0sl`iLM|g18WDE B YF P"OQVFq;ū}k>:Or EIF,q.0lfҲ@,'9 7xأMoRuk`-ٲM-ix>ne D ^u2^^exAjr$c/}I ptc~EEP)`Έ$fR"JA(w{4=>얝SYf>7GwZ 2ǒ% uqOu;0~9ALٔuj5IG,P6|:L攐P"<(ŸY)y/ᵼ[(/sN]!7jR,N P؋iTTFe^)^̧;'h $Փ`2?bWgIV:Lr+磥dPdqTH]ȣEWg>'_IMPhCR#[nef֗݁CF+"oAv\@4 Z4oEYT=_};[s  Mήi&~P +شHF2 4&QD/C6bh8ŐNO.I%M ҫWPMLߗfhjRbrZBQƖ**S^:G'cȔ._.̃u&arP76ݮw%EHnc>S ğ8kJ攐Z))e}0O –XjZŅS,O![6G\=u)i2Mڐ6jVȩt`ˌc0ߌyu }?!T§՘IjIOzV,cv5̈́AIQRJ i/ۖ`I;Rqmg8y/+,8LkU3JQq/NBs^hvSXjvjC_O0l׀Lb)ISc#}DFl]7c&YS "#Nn8:C{ @cCt )hNm<~Y]fM­Ud5(V L-=MJ0r ǟ#&9 !<LNAY9OU[U|s4(n*܅m든.; 8$}6AW~^*Y_x&0,]z6* vC+/p2=!v{y\6h. t(峓2M` !V"Y\c%?fM-qC /%T]51l_)0jbjFzQgyc {^iA?6.RpykvUߴ֨H u[Y1@Oڤ^%OGk~)bpa0=޷tzl%Zca>Ю>j!AI$L,f/+jϚ rИהHYh(&/h>Q7B,l%d<$n)|vTlzF&.W?ro;l!MԑyI>QX1K4f0Q9'tUܘr绖`)CǤ(=P"+^gl]٦HF\nfl?&̯ES'r)$|Fn$ v.7`), ) |gK@Y4ts`Z\ Z(8GOUDӳ9n="eY҉&,mxȜn4f_&[b;iQr=-ao݃"ܩ>8p,?<<~ Uwb+u813!RA+NÌ2CYͮWUqѶ7O|> 9SN"K&RF P)%T%q>U1?vX3'їK1\ hĄT,]etjjuEgwG~S:{"hм ?&ſ!ȿb.\$4&HT "z⋐Fkiԕ% lymGS14⒣JHZ`t#ۘj&XNq(mWhFݏ>mPpMAsItmp旺0afč g:q~3+AP6'/]'P7$JUׁEvQ4hymA %mhgQ}D$,]Z?t8JZĜo2r% FHpk҄Z;0Kp&top\1x&|jÃz7f?Ѳe==lZwkuI"}9 ~iZBy뛸Бv>T¦qQY)sBg9ˆ.KT)+QnH&&U.?3/ϰ$0+yԘ'ozܾeiՖ?q\\gUЉעZ1*_wY7*% 3T a;=v. cGR@75/A` Wx]w{T}">`R>z]?1!PFAzTAƴOOgI@D"I;3]֒J-8f';>InKY6(h&E N v:+.v^0gE92Z EkhZ#D,UP!ghio38gsA`s0Bjk*CGy` '&xh4.7%0Vڬ[T&&Q+adSVrKٞ7Jy`ҳ4=I?*r,iF(vATn[}3*Mf3oM]={j@>CNZ:xp. vLo=HL5813)=Zf3U[xht9-n- SEi<2m=c/ hWRj@1z_05OBLl9dYߏe(}Ad=!ku؋oQo_R /^O픦+}5#3H䲇]IdNGm924i0d C-Yo:LlT?>-jf靹H 1,2\6E){^tfR`lcӊHr01U4|<+EP"@! c@3V-^QoEP*l;X|jc^KeSYe{ Gޅӏ r9ZX8@K-1PzS*0oOiq԰VhnX#4,1AMj|ԇn3 PʭS[ұȌ-[BbyfsY\Tv` G6!< ĎD]&%xaeJ4Igq* ES9敕 62hR6%GRNm, }}&f|=t ܤl$D V,N+\j#FꋲHٹ4_y`_G0SV3̒f0S>Xw~T\zإEH+Tp(zass֠;K3˫2Mq%q @0bj""o2e90KrbdL T^H59%i,V~wpR6Fq+Rd'9omd]/67i7O<(qHiG71a8UaZIbeFj*sqFtl`' o///I#WD0)p[PeK>'ʕ:дv{Wu脅_*pU3K &Bʌ,U-ɜ ϗR"V`Ӂnca2&׵)^=@“hgB8NquFr %P-dȪ1:#Mh~2 *Ցtäs:(Q p`c4GBєHv1:RQyԏ >MDԵŷ;.~q;9M.0!T!Lb]1k' #-<[_dcNd ZVJE!PQ9GY_cZw^ uISl"}U&hIOk[BVU$xY(QW8VoXہ\t,s>t j6^.&'O3S7蔝98ꌀG8#xې8FPݨX<ӏ#A‘pмO˳@!,U<~R״zNIc,hX0C@^CqHe.Z#8Cko0eAZsGtds9wj@oos1yweLvӼ RiA2j5)\\Gu)GwP o^?>a5gas7FPZ"q\ 4OLd4w@ЏoBj E%{p hg>5(^z1kdIu$z}R[;͊?d Ve0nM~&^o?~5Z ,zmC p!dT(   qN' θ$8:܈k1:n:2~}K7Ps-7]7R}vJXXPkcݠSxf #eW6PO ^Scc0|aGP hEDG(GfύRi)R%ORKضx:%oL^.%vr*+ W#𾵅4D)Pvp8wfn$_9&bfr(܇_Tu65!Wԫ;{:Zs'ΦMhTw9:]NiGtYIP恺==*NBH !emx(dzQr$7*]Hb)m֞ &Ct θd00"ⅎ"o:h% T, av^!,CB Îհ2)X1.7M$ZE5Hv >Mf*eD,|0d,ldm&mLs5Xʡ\s2c=:WoFb\3u'yY3-^0 5/@TפORs:Q1;ڳYlw0eQ"*d"𤐚b/4T5mÑ`ƶf&׍ T0K5gZƠB<[@WO/g+rLZ ԁP|Cں3t,QfbxcWyNܖը)Á4D:A4 0Ayi Fj;.wTJj*7lF^[nH##2X% -o'M-XhX!B9wPå`Så<+V! &Uɻ Rx-0gHG9dP zxmՒ2w̩RZF%A P.B水L~):ظϦ{1T +vfƑ>fbgKb,(dc3c jU,-Fp;;NZ5j J[ 0V w\u?" Ba!&';\rQVD/~kڱ(Qm!Z@YJd-1 Ԥ+ů]%G^K`Q'cOrjs -sHisjˀ4IȾu)` Vt$/j+YIѠM",IjV7(/tuu_ -f}9Jf6Ń0,ѦH<GJ}F9?鶛qlKd52߯e e7BJ̎T\WɃB;@!mpC|7"(8`mP!]ʠtdF[? F2@ͨA 99Sôaض!-,0m5Ԩ,֣ 6 %+s}cL፭~TuۏĦPQ$g.ӼS"f0ռ)yK{@aι1{0ŚQ2AQ*:Pz~ѵ.!;%2U]e)n@Љ3mg62&HGބ/z̛e5QO^ZRT<:kT7 t><'$;(Xr5tOIE3E=Tm+\va|ۑՒzpoH _ox4~-]47,P)hAP}y4=Is@~D%ZVð(9+i:m^׷7g6 ހ9bT|9 肿jnvwrxgC|;,~K,5V}>}0C9zq3U7l3sk|jEF'uXo`y5&euhC`_(`})xIkБ '1V&K~ Eiⳳl2 pWJ!'֓BFep"iȸgrAHJ G)LQ:(f@ :K=r,'R}ݪFP{fld.zǤI& Ҡx֌0f ?|xw$Wފt:Z+8n's/D6h!LwF``*'F_xv'ٵ]C@R 富( )R\}M=Y繵/߰aвXXH@l<ՌbsK flLTt\v _"`;lbPIff1 Ic/$.>hu~~LNUD2Ĵ9`60`!Gk*rsO6 mw:읲leJ]*!շ> A5Wv*:ˉ'nF$r1txb^ S AK/`tl>4%Jlz\ّD@"U XM*WXcQV7Vq>X-J|%Jgu*O>ݬWi)`_2a֯r?^gy)~_/w C}Q__ʋ>~m^hǧ?z47<ȩb96(7\\F2dn'LLzH!y?54T>a6R"\۶u%?도 O &d ҿ)\8Q$'^Ս$!U!`ɧM! )|g,|)%"C[` A0 jzuTrN#}/I_6]}D;Y-{kMI+0!|tOfDYk,.j%?/ۉۜ$Ug| jw Oy&Yf.[$Ca[fXŇGD$#*}i0@mnąozP-aCh 훟joјˎ/tC Z[$3HYY mOlUGmexYiR̅{:n~Nsl*mc#{;)a?wXhfQ" /-yOg34H.67-zKQp .en%R,6Q;؋wߓwnRm&ы>d;.we@zlq]|4U#x1;6Hi)zqxC֟#e͆) c 22l_,+?MjRZpxxP-V/]q&b+{|OxID E0N}*6R΍HY?ڿ/Y@G@(C0h|'~ݽЍ ,1Sϋ_39vך8sK)T $YJ ,?LKTl\tpáq5ӹ5aBzd!w4[S/ga/Zc^HW 8mf4z3Vn-⮕A4}11z3<2E<'-Z[CrsbR4-j(ܜdxh$R2>շHB e *[Rd|\-萟T@'#h(/F7X3RzrOآ2Ls;N7))qܣPZdx* ,X (sa]d+cDT8¯:l\ѱdMlsSt-To.SQ Cģ,[kճ h܆8) ^9bLX;Xm 17ϯ?lg F5g25B47rh%G$2Cz9^nbΛ\{tTNu IYk{«D <-H@Eڟ7*_ir /έn /E?b SA)>\ͻt Zd~1߁` AH"#tZfFnitsG AIFGVQ3 GKߥ[qu;Zƫ6}vU:HG]K_m*'Uj!d?3iMCɳMIfǀœQb m+"ZG5GyלJQH%cZ}1EU(Y'k ZҲV-v-E:]M^.ON)J^Oav%W"Z(ry~2@-loj@62* =ZC');%=!by2:J;e7ThfAE%!iopT$\* XC+:'ɑ~)8A'L]!4.N$WnQ o7+YgʂlC19~x_? G>:$-1Ph^z%dL8VBXj 0fgxã ?Mc _V8*l*HlƮplS!(32'ͪ;dT $֌e=Ah5D\ͱ楙_I@*ɘ 7$_y7 pŕK,1{bؐ&'@v-$s$SueGYnk$[sOzx|4qdPӫ磷5\/X\zpyoqr9~ K _ 5؍o,kZϪN,߲|Pւl (2$a$zP7hNsE FN۝,??c>v|inDIlTxd~PaB,ޘsն/j Ժt.S$#9R-0Jf?. 󐥹PӚfu.m|+KR6艏Qj7BWvӚ>Q}4D8+4pУI@IDATl:=sof '30 7)nm]? Dl9oʐyh]weBQH$'AfZ$ g&!e gb' 3G@_vexgSRo=,'t#G a%@áJ^hl5m̪Abg!1\BֵYyu Y&YD&C[ -ΎÕ- t 5hI?ss%5kճB1W$ 1xNH > MWEPӫez PaHI6|~CA\ĔXb)Y~xdLzβ$J'HڸFc׃O )x(_M t@8p9 ud։PnGk}W]kdt7H h="{,!/ <!ϡVC6piPU~2ub(  IS硥ԕ>?cxnx&xX# ˇ~bc swAȡgT 0pƻBo2լDiu.o/8,-F4/;k;3+5 +d15 \7|KjT8dkCaR(`s>xק˧ǩУ<7|X963)oDk6~R'OJc1 6ǽh /BE=VBЏ&ĺgVv3"qUD}#>.Q >%sC,n}rfRWbch:7Φ_z7ax?e- vV<[zFM). eFqu)g Nz2>` ^Z\ dD c\!P}Zw!^6ʎ3R@n^< Ѐ<]!w$s8D+e|'i2O{8m!?}Gz#a-gq3"8pKj{T%`/aJ{{}BE<{uo`]\Ce*pwiM[ڛ A4qbh|TʆA  \l;z+ T HM6 bddr-xiaM@ɘX* ve394*s% V;\vjx%EbjaW xa..'f\3s|ǫ5]СBu*gS [(lRцvȇWD[‚A&)BR}<2/j0V "FZ@@.QLD}U2/CL_HyP@y5dM7ݟvjilLW5R(ظRHؚ@JE{f-$ cN6OG'IQ}=/5/o`yYn?N:Q’Hlfe2'AD FQn(vžn󏗧_?keGa9 /M6kg!MvB 7 AyB W#:î`:Mgi>‹T&(@Gn@Yg^1cܨGg`=Nq;g B33a;WآtcajJHa2KU)TE$:)b7HSj)O8UMASsf.pPÜfG3|ULir±[PVHyz zձprUrG9Kod ÌГsY5{# iFH#nM>֬j /{WdW5eFYkEFL-ҙz77bE8qGظ2u\Q5't*ً ?2QB?xN&d\oݫ[<٭@ `_zy<ufi?i̵o^7enp>җ>t{I6B?GS aua@M{IE | >;*W.&iv(,B}4j! ;UweL"T7Gs4{Nh[5%qάn?&)r8.F PA6 Gb?,GD, xP{0]G"4G)pڅ*9 1&b;O<&U=Yv8RgVE,=G3~mx0落dMYSƒd9&b0^Y!ZY\"%'\l~kzLb]k-ã8g\_m$h8r־–a9nÖ 9ڙfj/'?&WVj` ɱPZ ka!U୒?#8؝:0CB\_mnOQ,}x1բ~C CnCdߎH5Mu-eZA^ 2?ǒ`bYdcG.^)'9AgZdLOufK}pٺb^==9=3àZp?e]94EERqQ?ޙJ*R9@#>F냨5UjFs D3 puL/ק.#G"[ u]fȧPAFVN)%GP2׫:VE2h/e aߵ&cvBQ&3Fu1d߳.~dQR6ZI6Ҵ 37j64h>1#ߊퟐ#G9ۧcqn)bΰ]$4/XpzLA2\:-/}vEmZZ8- zus͋ |Wicj?Û gaMz ujY/` RoA_jy˺ExѴ4:'tgIY^H!(4j1tMI9ޒ1Ԙxǀ }Y= TnW|X=X>ь EC#B/Z{p $oMphg-X2 -:fU{ I1Qh^vYax~ۿ)+pGa4ңL NvjJcƳt^$F8Z cxۅ6Ɗx9"EB"ިu9Of~vFO=@r#ƕ}@zBoI*k3raȨqc€ ϫ.œ$vj@7)hWv=EM)qgp)r&nːz:I Q,R,["K`a G25L_a(<`ŕVW73;|CCk-f;3@4AVO#?1u6WbnU".>- 1qə]Uޛv%8f|]J mv4`;}d -C5$>ʟvDAvY&db$ &*6i¿?e^_ɖ>.,LU\6 N,Be8Jc5R9icLZACbIn?a{"C/^~)w޳}2J9.~V|SVHb?ʦsHP rR*<t<>:i1g.~v1RѩZ__BgRڞ/ʼ6KR-v:V4p)הr[.;ӹR/ݟwL;,joXX'Q~ՖZHgJOA~Z@,}qq]?[tx|XVIQ|[2ie *|ɤGlӶV.XŧerqϑwGbĵ^B+x):=tۚeq8KۊoJF )1lϮD߾X6s{ lQE']nNbc:@~Ŷ>W]r,kTqlGAL`Xboy;әhMY~_wg.(䃪 a4v2ɸ( < +zz:ُtqhB8$mWѲgT/^LY* &2{CH6®b]웫 ki FlӜ-/UzՎ;;b];iA(J.^ ACS+WbpjW);8y"G[@ULP|Xo2T٩!4Y}"pp2dv{ۮnˆ)JxO:VnZ(]t8@j,RhF\P%PtԜG4:i-aceU$b wo.=OPоvmx-N,eFDlG$k@f:u .ǃ4O{AF4F{iQo3bќMXso<.iz{H={Zd%96h>!By,p ?6b-yS21ۿ.lJ[F^564x) Bу zq5 \},v@WUEsh ׀y:z\!>5=9 7 lg\9 0` @^M/Mdԃ} fPa:|x3nVA[S|++H;sȡ0`kZ_8|h Bd472l qx88Is<][l1E΋oQ5bq{e+Y,~~EJ询Lt;~+k'אtF¼D(|g2gtG6B~:\E_鰗 W𓅵|6._EQ{N2#yySd=yj P GIUr %#K|'H^mC} m^[oRt6aZ;?#V*'^"e`?c'~ѵ.M85KۄG7V 69Օr@*0rt9*herT-3z3 )qrDRe+; ߮OӉ[.v$ 2e:9 KhMˑI a(#n#\ ;)#5eج۵}ZN#m凘TJTZ ''tK,jx2>*q*09>duTzND6mM$1_~tNO-ᥩ>a\XܖM b[FN/ "ظ*K |-! & |H9(:<S_K@FdY2ϼXvnvtU c9-xFm*\"u HI56 \˔;]LWB2p3$3EyiMutXF7ҸFea,THrʩ 8 Q[b< :쮩CҮ4|4:= ke.>4F:n!ǬhzB>3M4G"!5kq2ZΙ>\W5Jh|)T%2I?cmDu/먛NM_[z@Jmy@#Ĭ 'q,g@AR%nhO%i HTnre;h)hW2&U}8 yͭ]$`W@E?\1 `1/tۖ fߕssZ*+oA4)U32~U--+>xpX~p`Ȥ/a|b,MGk ؂J M2;Ϙޱ1sRW7D:+PS|[]NIvOebQ !eMf4<4^݀h01̦k&̎LM+~L,70t3m7sʤDBl_") ͑a.z"@ un6N0|`MP NLku\; H9CrӜQ~~{nYX5%O9ndzBko6fU( ZcvX8u2$Z FDzV6`q }lxm:b_9?: 0dMo,Ztio"0hL[ ;xs LIF 8ck9dDa>Y3%@IP D>bmƖJE~NNXD5 1qhpqOCaphj*Kk*ȶ;$ +Bfd"g )A=0Y!sքz>ke)57Riht@nNGzlBsؽo<1 ȁ#]٦?B'DyEbu"= Q syyFٷm=\sgׂFoV)ۚ'4Ua}!(Ȥ*R,QP1G~=ky,|_ȟ~Q&x \2 l_QUu=a[t{15hs$I /!;EA d+wWL_kKlKF9z+Fwg8C̈́rpȶ| H|<;2B_l(_z#5&yH`*ᰵ>g%+~Gpl/P_ځRM}Ԁdހ'VǪN9G+n+88HIXp7氒(V#tf+ݚO]ޝ'Ej%QU}j†L }@ KP~eeQZ5cL0Gd64GSz]e~Yb,q#&@pS0Л8vqA#2/f ]!Dlh/S&qlp$ . a}eN3C9T{'$EK%572t`mcNHJiZQOOP+v*0nZjd$)j>2َ ZJ}1dHNǚEnH f:'Y((7 %hjK?-0z0EIM7ETtw-4&BN(J Gɵ1@^7^z߾ 0D5„/ V2jAb0-4Nf2XpjG:#`4de?a"?S(!MߋT'fݔ8lD$(PV.躐Tr_5W簖y׊;ge TϦdiyP!8PGʰ,\RR2$e 0A@Ep=t[(z$a89&ɪ2_%R-ud{{9y) )X>`yk4P}~g|\mfj t) `NĄA_޻:!xS\uDy}b)#d%1Pa?D^ ]_^NfvX"8 {,.@(^W:tu}A"͐TW! %! UlHXa3({A BStvċg2{Cy%h18h4ĹMqA`z*9&/!wit+UJBt#+)us.B-XROޤ'Ab77]|Q#nJ4A) /=I%4Avnl$c`.<P.%/7ez6!F>ORU8ArLr=݆DFynoŵn{{GM.+JgiF $U䝦YԪOv.'Y<2t쾨n%弔y(͞eڞ`FjtKL:}Rq,q(-gd,YDek; fvu{kcVX"c84)^=7 ~&v0oy;[zu@l zLݟJ`B:6FÏ2>僰?@V Pp[k,$t8>oUibkY6j,HȨ Ό -hAkk_,bp8'U_ nN Ŀ^m^B3%LF"x׆&9)(xiXTHm;$MSJ%v?YoJR̀.RW L.-4KǁmxKqnQ,P0U2,L:6_fR,fK@s+3_J͜VU&WAds."FL!{n; 54,gs8^ޔ&MآUIȥ#mg*s'2rM(ؾn# Wjb|NFInCŞ`Cp봁_v}IJ&[Qc0Ԝ2wPK08KN)槯6J{)|HNOр Q泘hg0ؔ$o*RK[oyX#B??q##@%-\}ax *._W8{6s7KVk'6c7Ti9mT$&3n}K9W< 6M֫™YISi- ]Ꮈd/k: 4W 2u1[9 <|նXhx8|õ+#|k,m-vfIZ~4lj72;cҹ&+Mċ)yyY8΁2$HҖL, i^ IR\bomd`qlY Fs~*k꿞_,~5HaVZLmܘ,؄cVx B~D67;v|$"%%CRf&nCvXu%jWmYɪfc>""-l_Np1H%EXqQМcH XzN/l;3R?Θ"ͣY]xH>(tH1l)  QTf<3ŀq$@3 P:4cy dQ:C#w7G^;bN M ZƘd'&  96oe^0A61FH-U渼`W֚pC6hsKy-Ͽn4 mgr,\fXP /)lxgz!`_0և,-6}8Mwr q ٫iwS MTxwzη$׃9] wXH;pWiy&c3f]  8G a#e+E@wԗoL4MST-C`1dv@ՄuaX%F*3`G,--9:)56G{:8B<S'rlyT "9]ƃ/x6 0!bUa嚊ȋ0wAZ^M YCa/z6/*һp9Z tAR)#*DS~pL4?54S2:}o kBeHHEDƐR!&`,y9r]OGTAyJsSr!nVV46/9BH"dlMA A :=!X3kPJ6Q/jrrL[rQ)Cjd^`Sk!35_:or*U2,t\m 4 4!=Ju_vԄ e PؠLm6ޞ-Rʿcmsz>fPFl%N2/ m%tCʧ9M6Z1I9 4'RYk օ$.D"->Q pAuGE-ONZ*ڵtgQI0,w-}Y~؞N>Ye|oOkF<+  |7Afz-UVsaav\GDa5C6YZ<Դc+H{腌ƤZ*z-}`ɰZ)s7!xPQzzI-.>au!UcD8/A Zj"21˟ e*ZRӨD/V,L%YG*xSV&I% )dXc"_Пv> ;3 u^e$|\I,GE9o( jU\x+v}Z]swB~ss!ZF.e9 ,|8ыG<kvFth&,OB6y,%"M%rA29$-!:Ѱsܜ ;79?B^$:ٴSԂo,'77a+WB$xNP̉B×bT n]2'QA۷Åb>]4(n.2;Qy5aL`3 Yv{ܡT^'R)"2= -I*6nOt̵CC''Xؠ`mkȂe(sY3χ͉LK~CptJ:̃Kur"tMH!foڒaNׇ& 71poҧY)BH`4R,v7 cOe肻ѝtS"jƗj.*sF٦GcSj/qLAu9v/Fo{y1_`vGy&= \ S)Ǻ|8hEʀQ]NBwHX2SCho}mk0z~"9l]jD(aX7* (B߶w y{\ѭ䓻$c^(PU_:X;eQߏP4⥱nQT%9-IBGx$x|xOPq2T_I}bGM}Ț.T Ix!,, 8[b@ ;_v|X4zt@t.""0d(Bl6 @BaO=T1#찦)#~.R-\@B zG򍎖L]4 =IT ӗX^Adv6$:?:fHb20ϋ-2 >vr6]on^8p:xÅ֍tf6rDͤ^'Oyt<u+6xjlv@۝3!/Ň1"NZlSP{dD*Pg쥈рV5BN*9;34u|PSAt"|} WIL3 ֤(0Eaƞk/B˳=aZBZRy2^ubt 5?ze\= GrYC߄ L>2G}۳Xc x?xc6]hT|c=4@r?<GK\-V?zH85`d.X6mXdM݅Zt;,2?̸{EbN%ͦFcT9G.BCl>ILSn"(g̠KaᦀpCMk0;Cє% 7yB}}[tX'f1*U cìi)bgn9J4tfjϦޞwH͇МPnӲ$^V>:ߦ.rlS(Ng%(CJXMՎ MO3$j2lr FjM˿z{d`d@0'_ݺVbۍ؃F|}n/ #WIyY 6;0f Ch:nUCw3b`dsDJ΅|6RȏP50eI GZ fO&eM0qRvOέKX)fv Fpu$C*.鈐  x4y-?dFh>(9ds`m7Gvax*0 AZl(K|Ț^p2UvTPM/D^ԄR $Vԫq7E18!1A8 @Ah&A𸆭GiF>=+ !c(!¸65:.:.@4r'nN -JݑHuU3f\ĕ oF5ણ\U, &pAXU/ q=@9}2D]k-fvU+ {۫8BDMHmXΚIQLyWT!wMBFPI<(=\Se^Ԕwr(.YJMhumN{Dҙ7QT٪|&':0-=l`%8t#–톖)ǦfHYC os=W4zb}͓Kunr\{,6~A(^wߌopUj6ærj*FPD]hC!=CGU\0n\xuu^EU EO/-[6Z ج {:ڴ+ *:qЙ09Kd h31<)L8ȳ?:&T_'[I)YKÒE;qh1 T cƜWspYV0ĠCoN(+>X)ev`AAWf~Z7"{zo~[Ӭ cҚ&КyT9<8It[Y(< Ӧe Y86@1LʓJs Rdb|;a@9*,@E#P1 Zvg•ſI{Y8_ד[?kR"uJb?ȎYG"issj9u7c7;GȔI0{8k!'Q@LQ0BQ ?`d:jSV1]0@iqzO20rag]?;m1-{5R02jd9u<s$dȓ/ة( ѴdhEb6WfF;V>&1c. >#gNw)2|:DeއnpjaYT͂y5;=HNVLݏΈDl|c>Ǒ0aŪ%"$SPww#RVGq_.E ZJ7qExc+Ëy(a̦1~s0`nu]1 k0)k@˰W#2ӵ!|q(q0ҕ/')l|/e*YE5dbn~pl0Ax>Hd<9DQT+', BO{gaNo5I}H3:S蓠V9XD2ocUʹ#T_:"]ўr׆6IroXUy{?T ۲mXp&g,lr-@ [׏7krloKa|ƗYu4 0ݒ[؅ַ6Ƿ԰jP6zkA %/[t\Hcdgc'qv0zBpsXW/ۥd ?Xso4R;15}Wδssfp>Fz gk)~a-J!1R @BFe +2DƹOIrH:F] A1`1]C\plȬu?6=LHzEСCd"\vE}a^JbbCW6I4[GXF3ﴴ< $KpDg?7"[4>tN5Jj'Rޤ:~{R1nJ`m@ƦH^H 6Ј_?28V70FXӮ $NPyf ٪@WF?&v7;zN]ANQPr9754.Pff8JsLt{f_W#շ"F6˸[dٞϭ:Ko|y,f~S;/D d&yQGm!խZ̈́&aټ,YEd|ءdwBeMMji[*MIt ËMc`:B,OsԈV “UCWNPQ*$*eFvDSQG[$ ==b\3Jd]$P5cׇ+b艹 з80iM9 &lo2$cL4"oǘ` >[ԫF*Pk'$+ P ]q0E3!,y\uMyPsihH⵮|j~RcdmVV;޳}[HNN#3skDu1NE04`<vFPݬP=hEby6ǃbۯ8XȠ]&!Ӳ7 0! zi=_fFqJ.|HFzQiV^!؁_6P~LbSY d*5kN)m`#`&1+ZX")9JD&yʜ 3E^n#)JC,W!|1_E6j&ꦙۜ@havq]/iM :\m<^B}iq:6G/k ЫHƢ<*==XSlneκFh_~+0BK/cU V1+ r<@@A nF5 ty\P{QS" UL9pl.\ha+*eArx ]\Iv e~_CۿZ1SE =jh׭!%V,9n}rE0#o!ʖyUT \R#9m8a(O"Az]jɠ'- :-V!󊇵Fјkjb3VONeƯɂ QitydqFyx5?AoZ/K~䧄 LXt|knzQ|= [+KvUU ґF*O3`3R5 l(=$+GM[&nAJ,\8KŌɢ"18BG cpQB:y5֔IP r\2mx.*ygԕIMToR? `%+\xec",YM(ǿ_~~g|i חہ!E` I wx&+CCm8w>7o (`3[_q[힯x>.ߒGrJa4,e:eX/Xu(%;@ly%"KQ4Ae)j0K5;PF. `oi*B N~ 2IN9a2mᏬEv+k%J"4\InA/߷ke&1$P^r PDH-P". CҪz TN*\F1m|2S50裏Z$RY4{؋B5wwY2Q`&Ч]7p1@MU-3˜!*ݩ3k 6>n| AFvp 5}3Hg5Ҷᒗ̧X7Y 0!ylZɑkƽ \I?o eŐ4kZ̟gL iHthǥ|!4jڄ\j" It9rM9.7"?/mi6Z{D~kL,pr/,Cna-XW/:TTZ1[#K "GJ&Kǰ.M9ZpM"dWx^-#&OacjY<~^ z'Iơ/KrjmZ:1~|k*$TNTT|v*_f$eeyBJR=t_1XSZńFKS Eq6w]u`EKM*oiS:lR_i"KI0A~`D!h/dy_BAi f2ÌL [> $tco\'zLg Ud2Y-7mjNd4~K>0 HQpgx׸ fb?ГWW1{Pdj:y_G1`jM 4@hg؝,j[\j~N)pO;ӯj'nȻ5-r+Oʡ<ï .l)xb`Ywk $1Oa)O, Adҍ%jv2g OZb0n64*q<?W5"hscUƤـ@^Fg\&iӴkHҐgЩ 8t(K`Cq|8|:k:I[dY_tOɌݝ)RNLM *\f)S:xX8ŪټZJ&_O eD1W֙Uov8rY/UsQcICBk3؀KMPL'Mn.|aM1g H, SA⣨8q )Ec 'Uhn/e_P Ӯ"E!3&$I-嬔=Aej&1FI`jm̭W%xrv/jd9g0t5-K tcXATΪx^k kL|EvC8m@DU]oYQI:2S)pX"k?oNr]odY)"|\$.:47Y<@fT:e YqCt^kO{ey$َΝ-s- _Mia|q.duv-=ԜL8 $'tJX?8ؔW❮Ech#ѬbLm<0@ ð$1b7``1]dK`f,u g(0Qs"O~L?5/?9Af.;}v/r@pG2lB:ȖԑNih)` 66n6".A nR[M?UUhح 9}e ']7cpVG2 ER/xNQͤ)a_:Ũ Fa Vfh @[ OL<-"E5#?ŐM( ȏEPx$*Ɓ*c! eOn4^kSɸm/Nd1$$Pf4Cz`Xw-\Tܘ!_GH2k5gM:71۟,z3+5s/MzO5=w T+R 6p廒bqs!A*%# | ϧ(~{;uKr/rҙet@`B:IK2A2;{&m?u\]+lvW(yjoJrҰQJ)0aDzCrGU__޽'"P;"̴muye.v0>X jH3 ih9o<3U!ƻMcv0I1+ׄZ,˷D j'@r )q< 9b^sr" fLb2 .!O؇̥BO㠤R˖ {!UQƟnT#?8ћ% Kqy[l.7ШpC5LU~LN*8'gk67o AAт99$@f dtNtaZZTa &ŜɦֳLe$C |g@T:x#Nq]4?:Pdʛ}jwdd)<0s3] S.u!rf.i#Yc8sF]'%stBQ yci$*6o5ZHi%'8vaDu[_S(iΡ&?{9IMG$٨jِxOG2og6ɾ&MS%r)W&!>`s;_,sɅ^7* 0 )rxjF¿)=Mk.x"';Zܑt~;mnq.UO8BP=zE$]y i]hl#b8K4Hٷ9E)jnÀ]^[p!#TrJPSckz@$A7H?RN9 wi( !#2!o&U |#jfhN!\ /ߋmLay'E%x8܋t\mq)3|CUwd/:BET—Q Q-5T Lnl֞c:;pA?.$\],bj1 H@bIM,n z6hщR}j %2#y@z7=!tٞٺYcTOc9LK)zejcQVlH4$N"`-ŵubuH33mn$СMC %j:' q ^(1mW-&z[UoKKYEAf$ .#.#Ȥ!o4?u.y$=:g|oڒ)IvD݄%X?JMHW 9Xn˗Bm.5GQNlj1+ojD ^3_Rr~(\sauzw:{TԷUhy9J+o/p Af`4qrΕWȾCw2I9#\i&<(g~.DElsc^|d?Żk9(x# |j-BPq1>0(11/%Q5zOqtjL"=rjGu 3ےahe"+# ȩtIU~dXʐ%|WP}#s?/} AxNtqؤGB65%;Mϲ{L g? ,Ui !ܠ l M_wVkcsC= hcȫ04ǞS0fcSKogcYsΈ4 &WC¼)F5xggh2+7>=Pf2$1y^Cu4oc_X1⨼qN1*#OlgP ^)4P -Ko!!@lPQ!:6T eeS]ے'hPk1YҢX($$4ZOceQp AæoVCBdG{@pq"<5 k滶`Cf2 Mr̀D*qï~3/jWJ*YKQidlAf7ejDr<̕`pSոgآ;b6)!%r *T5auyʳtBK24$|0zIobRNW _QFIaSIln35[lì>î`ixYu/7~,P:B %N3yJ"|Sܫk(BX@4>*Xׯ_'ΞuC{Be&!+1,z>Z1; ,#Is"d<2X{kwUUXg4p,!D!3 _,2XK1 fcA4n.Xs xN1L?_v8^(hGDaQ|,p1A?}P 4 ߴ qNjxMNxɼOO [o590!iN(YhspNMkzƿ >(6jkOHva.seK/t,ftXN[@qCȦF,&_"9[ٰASS@<5xrtsK\ީrCVҠ\71A~[@(4k P (OrgY*:U= A?+*u }*hTEaHx.adui8Ж:~Q #(e1r[{T_.Ӥ_]rXN/ʔ\GOG+9{wJLيnqFR ZN o96]^^fUr(Z׭=~Rjos=e"iYxhC-qxl덱x>_J)r>9 6r2AWJzدDRSF(S`o^ E/`Y_j`8əvLP/e<*cVY7~xDzOV4OImʟF=5Jcy8tMh08č#fi4t@gJ^~]+98fv:>n_; 4[$ͦ:fbS?CQ ԘrZ6{R>h y~'t/Tqr%+}PV+nL*L#򊠃fᣄdk$ꑅmV+ Dܣ qO.3E[V#Q#!ҡXlsg:D'G?,+  ^%݃B3I~?&*rqs7rsqp^fZa\kؒ3J'\/> 9t0;@OmZh\ۇEnawMH+?΋Lw,՝Бjy,XTx2sklJro^f3`r nI {21/!y7dQn`iQa{W 5^&4N~S-y/2}n1ǚz{|.V?:Ǎ5`kd"$:tJ+]ihi[zY sxsʚP77|b@ } >ytŊ^@IDAT0R5꯹}~{8,qrT+K2S-cD4em2*t}(P"d"<mǤ`,RFƕCb-m0ߊ ^>F r# :]0˙X_:?xU 8!? "p{+tA[#̕虛3yVA7{)KZJ޺ n>ԵeIYdܷٚMUk(#6VQoP BY,Ҹ8"lk9ﴦPG4a?2ANI S޺6mKGն$14\ʎdKZS^ٱPAbJ()5&"uFlv\4\}3CGiM 8DȝHq/1|>iK7zMIYdb\$ŭaPiRl `8![ݚPnR q-OR2Dp7V̢j7,Ihզwgi8-,PcOEB\.^lkpj>O;H΋V8t=35a=ALl{{.SdGK؁>>Q:;sFF\<M)XCgGk@ޥ ?[ڄӯMY<.UO')J^US0h9l jmDTRbk\K@8ͤ"ŞdĩA %rO޷M Ni0@,7`n 0ȧFZS(%0RM&q~(*aq6h> `?3A_8ΓA&-fX03&SU 97-rp#<^'w?J%m3fR #K͖Eq<7Ř> Pg˶>u'Еp+MJ72έ<^㘵r֥Y^iQE;@Wbp)ߒtxow~KpcV W\-bx-?4~}0PguZ)uv]/~q>2dO/&Rf)QPih ~,7$]%T&nȪ}M/ר}P }R:vԯ>Aش.)쟼T)1f tn _حāk;7]ɂ*伂.l1͡F֋b=Á- R<,ZK˨q&$yaUIڦmރ5[Q4>@F7e. {ȫρù_ȕЕga^hf,HǔNrvTWNbQim\4Y7iOuⰭ/!&6Ř尉 .) ێtԘ KԝN` ^9sf: z֧L7.0.3{Js}z E:bQ1tGDkTgDyp۲h;9E BNV'n0HO@,GFAT/8(*E^׿+窬Ț%f'g!;PC(lˍ-#&hwޱ)q6BE];V { XCE ,㌭i4ÍގTE>ʍяx3|XBclR`#Yϡ ,M4~X8Ä&sQ䦛x"\UGQe 1&)潴d\>/w^?A,+ `̌GRһlT?FDFֵTFnG_m'!if(Ke| ms>\#HK/%3GJ-}/P&B,K)UbGJJm Aʝso3ȖvrDyMˑ;edkgF.c@k:*Md-$>JgG6\Js8ʰ5r8/yR^@3(hDyX~ff*bЅl17H?e1)LJ{&Y"^!vb?IW(低}B\h*FK8>^7t*v_a( KǧET )`g2E!xrk11vիQU>؞L,Qb@U–Ư@ 5u[c3!8: &y<هB'qZ|=Bæ؟*QCdD-_N) b, = }9c Gsoچ,F )~Y=.tSӉcUrs#dc,U !Á"HA3 :෠0Tdb qL"B((?>ZބT2U$Iթh:>IzH*)'m(-0[õ2Hl |VYxD@g1.ۏb#~يǿMey]-"lz` Xh8 =S)VɨCf0p(XzEgh*,o7<@IZn qUK|%Z0&xyW4NNJߊt"t$s2Չ)l$"c~cw #@vr y0z*,(^N_AY [FvMqhiZDbϸtj,|IQTA+/t`6(̿q qRP7v6J=*1y7~XJ֞ }3AU޸deZxkwa RuOgi%(Z۹_:ht ףL℻#?1`qz_z.ьb1Ô}@h @W7\l.Qt9w6V9 ڜfhQ={#/h+APe@B {Z8Vx  Xԉ|ۻGZk!Gw58S26,K|,f!K_ve鱏Xϐ{D@fab1˳lŰ씅ZY2L'+dСu?wN9/xvaG)݅C4ΕH% vVqD5L@~0jMHw ,|EI!ob6J!',Pvvx)|TECk/k+r~xܢʳ|GXF3!*;LA7seG]"_?bmBIJWcT&+d6e\;. E$Ne+^$ro 7y+wi;1ԑHÉ[KpOn_1923*X5Lf?JNǥxpO&#BoF)IϢ+sAhNvVTֆȓƪhc jJPO8l+ՂD 8x@#Kϧ Ry~`n&9jԵ4]^}ջ“ǔnJDi]*:fһ],g|BrѓMr]`X{H^Q%]xT$26&I# jCx1mEpa~m0iLjC0Ycr<1nb{¬Jt|Aaqŝ1BfRZ¥Ҫw6LӥbsI k`#%XIq ?IBQʸZU&:{nsVX07ԯT3 qX\YmV™nPQ夫56@MV Sn__!U3 tRC!._I)u"հ46$]ھ9#Mقr'>ܺ*qtgEaW93KIWv-۞+5UD&{gUS߄{W!0O>V8OLɨlu#!G*o>L9"/ۃF1vX [(u~xwsh8kɒsep* !F؁y @[w{rGeRe3B6UB~7v6 QΥi1٪|;8+H=&j>ER܁tQkrF'"8$j%!U1_IeȘ_ZswAOږoMLBB"$"ף^Rw33'5[=|ui2 9AQ y%j+dϐ03- nMj{btqP>nj)r6rDg<|3`{#>#eŽ#B@/3xoM~`Rޠ.C:pr@5ڏ|jF3cš%|i хWgxۧ0Jm Cջ:..=(P^o]:.FV8HJ 䪑dzT!Y&k{/TKGFG?hAn@~" JzP)+BDO76I3@4n7xHu[2IX@R`F@ 7: (9QW؈ot{LfLMVBDNw%b s<jV rc0\,= a>~mqؔ/_/MQ*\دDJEU2,A3ʖ8̿m0@jg4"0x쾤9VIO%람IpKu}G;Yg B@hh#-Jݠ,_fA۲;R3yduv 87TH߀w[+>0bnvWÙ \?8MDUX ZOY^?,+ʬ"8:皉P[զ>h?wڋÐtcڲTH*O H:p {<lz.5od-ZTe?I _?Oǽcˮ}MXt#-LG>!a0CzٮgW vKW!Apoq$u[ ڳ:;U p8bK,)s7[ҍ. ^O5OcCKjsED1'@eCp;Y˾P|1fu;ϒ;y*Midt'/6OEw"qb]rKjC3?N}8Jм<8GP´`a+t ,xڟ B5:R~Y)d0.a ;|fBb3]/G 1qd×_1cJyY ;e0[=F-3SI##&Xlq1=wr/v5VWw~bB#*vf\.OnA%Uҫl'ic:Sk  ]AKPd^36jm3Vv[}h_eh("YB r"R6zNV^l/[LfX* T*9c :s{hA֟_5Rko/e<{cpb$,j4QuBDR OG \,ŘV&nxk8o.wP|q}~ۯ?Jr),xrp`[1U|O}TB|^wN'i#y*5-θj{SAUks?(|S`]?K3$132ey瓃*Ci7m% O"+ c_/aUJ>$OtxںWq>om/l;=z߬q̑ϝREy}RNưJ.Bd[@WXS|Й*dl@sȴ;O^PooZ#^#q0lWיoy2Cyjۊ+8hZ*VHfs=?#® >YH!/6mvDվi[)ŕ퟿ޗoCuf=z9)Rh/dƄo]Tz}j~|K-oa|9n@u W /f̸9Fn. mf 1"D`]/g!>Qeb?ݶd#TJ&54ŽޘIYp}&($RSA >$%w]>,roˢvw`=h7:#̃N[*[ف#q:wr/3Iܐ,aɣK8W-0:zp߽> \Wq] vD6/_"MCP:M_g~e7l^ҔQZ,-.GֆaS/zݡ"p#RR6z7ow6EnDgj{'#Ӆsi/E&2IN&[WOb^o2D2%+≪-?R~Q(?2u"ֈh̢XH"yePOT~?hO`,oyL-R R$ ]4T:_`L·jA->O((Naݽ)0S(xV#`@ȤWi#:6f6#.{&Ei0>XJDRx :{KXs$^Vtx H n;IwgHf4 HudIqAXa-So' !y*Q5}p,`8uN=?(p 2*mZ3GLw/|pV]M tKw+QAD$0`^}0Sh l,؅޲Wc FX28!eX"P*΃OkcBR!I~z}dŐ962)~0!LŠ;櫥SDi+vJ0*2q ~% vAx^ei<"0 %tx,@#+Hb,be5c\؋C2PpEy; L߈gel<إ bn01kSզA; )gc0>fpM!҅yC$O*ۄDŽYA-l` ؓe3HYC(0ې,wDgS?T6?`lWs Q:zdz~SM}阾 >XB 8DNʫ8rȌU6ϋTI1uzŴU{x()L_9AȾxs[CSfoVA6vYהY=aO fKx!w\;ϓCc: Z2ƭ&..Pqqz+ªbxo@HMue)ai)%5lJk"}5FKJ0)M6At$>F3\EI be1@N"|qgf7d&˛P:8x8JX!.K' :2_KaksTd&0,T_aTp `"'ǍS'c> 3[CPi1!,EE^\)Zy ٳmsE9d@1Vyyu^{̽OF\wDM!)&I|yi#oE0 US[ }`E~c8)3sy.S1Fl>}(Q)T'5rvYp ~;be\>8 i0ot'4;_0nrR7[%J`3Hjs$q'iH@>nx/O<"\H}p3x`mg #9*hmN_*=8+AC9ʅJo?<kjɳh`Ё]cKixH$M[%T!t7"6MHiL0/' A2 c&Z`LA܋_73MڃlE5{ھ YӅ=sELH[og?2( 7#z\ q0.UCVA.$j7%q.p_G[RLޗ*׿W-.lS #E^ɞE~W^vmx`|B]=3w|`|=/vp`MnK2ЧCuW{o~-dN{=+6VTҤ${O ijjhlJ8,q%ċqsQYnHfsDggOjAwڠLp?(uY4gj>4$=|rzeWs2M(ƸjBL߫kseW9 L8HNs"đxa Ws߃lI6a,p1GX) 2ػ@*U%7͟㒬\Ƭdƒ$;=ݠP:bq;J)I%Ɏh)˰W;Jzr) }얭N|43AdNK^񩏨 1_w6Y'Gt!0e<`P/x1tt2ϋΏ0Y!<{@SjAϬ .TJ3Fcӛ oq@BһZ֨ K9t׍A;? k002ǧw //HkT=Ǻz%q06|28A!Y3x~a)"9yD2\>l R$4?ZHcc  k@fr6*-=B:p]?*C0&%yF"U7="DEX.vn'PUZb3v@;d7ILd ZD[s+YňBG,q#DiՓR˕LD}s#1* Q@îc%=^41өM+!ðu豷M6)jUZƊ?[cY[,Iv X'r.R=R|XbL ~j?MxWu(@݂ s"ev1dƴ)瘬=U`Ya_ɐR~hRع"5ٮˮLG=1e'Yh]An"HM'h˛vfDOd,ֹ^MJyZO+{NQ%\*Q(ǶE'5%OCa FܱDputM1=,b0y;6L&Us5XQGզ6iio.k $X siK%\ cwH2ܚ80^.DQ(VLKLn7[g.`ˡZo-?Z'B,fv$T(aF0YFذm0H)hbV)\hnUisӶ=V P1NKٖ'Un%'x,l2ɒnVE6򏺩0H=ƶa3;u i.B?uC/_mN0` Æe?}-CB/V~RWh~ J06 r֓ILy|$'uۏ3/1K5&,`S(,Ŋ,P;T+^x]e+Usf-v:W * N_md:]\iha(Z+P{kW$cu+J7 > !VhZ(_pPnzopxmڏQrG}D(E!QuRk^ͥ&+^OWrv@mj.p؁)VBv":T=f]r[% .vHLths ]#IF~:V @Q!AHoxŒ_9:Z)C%3ؘg&:4`">oVzC/aN' @S,ȤdZD^Βz1r] x% X[t2yv\rɊ頸m׆2./L7Hah;>e^R⇒D }@W*4|Wؐ뽦,PyvsvɓiS$]6TYZiOE%AJVmBG+mGF%VexOV0V-_=^4Uu |VgmdbVg Ƹ+;Cu,: *^'VNp+qL X]F=YrwdxR 9Ǐ4V5=7Uv!hGԣ Cu8&Bi 3-jJMijsD5* ,)B| xpAjhL>uTD! ^Atx< /:X`Qx wcmu8 +RD^oϨIZl*XIK"ɭ4̬" X} u05G,]NPFGǛ^7~wM}XrKEw_*ukC'"۸6V+8z䑆qi1cæEUCN -)\%49.5婄CX}/¦M Ef>ZX0E @?}DEPڍ>ѣkGeXqNγJSO*Cpx?J9U370Wj3(HԈ׷ϗuEB%BW1 ?-֠Ø&jk6L]AL>qj(B^pv>=qO$?VIF}Ҙ 'ӆsK0p)"=UJdrXףzG˃& O{ H-lG!J+ɳEseB8//׿ j̑ q812]ɵ!&*Bl,SbƊXb¤4 Z^K8mdzzfTWb;SuN1Ii`'3ڈ|'COro,@"H/"ib܄?RVU$ ҽ5`Fz/t80AIE0:?b6D~3{$>'z΄fQT- Ed 2LT |BӊmYp^8 v 500|h2&̸xֿG?ZPFg+"fWh?n7`o_6#F8³ SmI¿W\jP8DZOzs,}stݭ}gѠ?f]։(KvAx# )>)81Hg-)Ӓ,35yƾ.񴈗v6j$b`d +\&|ִT@e2sG=Sݙ9є>A%b u8om@`~b½:ț;E|+%Y NֺKqZc{>1yA߷K-D=z W 1@IDATww)9OtqJ׶7#)zE?ç>u z)l ,6\I0/zZU\>d6 JJJtxAU؞jz_PbEWxz5nUGBka^&l| )*bn c>,N K4 *`TL)V:^'bhґ-~6)8 5Fc5 uv=Qq7tt]zF k(J2Xey]W$ :s11b6CŰG8cqYUXB)}Pr֩ǟ7sL7 s#ߎt ӯG)HȧBLQ%2i6=z Dˏre9kN0"M՗YCdĎ=/d[s!Eʅ ºy\{:;C䕺AU{EelKJ#. N_uX_A= Jto?0(?W9;}wf?CY?1\ݭ&^r=W!霌DR YOA%GB3" U;(Q(]/@dI1HEĞ5{IK]Ui(ATDt%BQ1ONv=[=h2{[;YĊ[ -w>/ ̪fC <{~;j*L㟎畛Gmv嬽ӎiRWJpZ|[JBޕ xn ;AR-+A/  pNrovwxsڎsPBnrd"%I OSH;[?z j׶7Xc?.)(,As/!F`$WTΥu`J;4@2 A6Q,mli \l/Ǚ%wj섐oiCNc=[?=}|o_^yU䣭}i}lIQ;ɣRiP7Tۗ7,H%}&C}5,=DLX%g7:i>}}=|FZݺ(QĀPﬔO| ^u{8| +4큖Q]5qV3y>M/|lNRҺ(Ver|ݞwٰV*q ^* #ԖEkݷD삌5a9cVepݩ4F|U*15[%v\?oԚF"MU/~H2[~_[r}h|U~Byo5GыAvBx;F<;99zucLsep,D[&G·2'Ҫ/$kM 2QeE)xp/ &]}bv]ȹZmN[^@ķqSjp}-Y{ۗb'{h3 ᓯ]"T gh^uP=Sz@9Vϑr~:>NR4ȼeVVJоrxI%)@_'V_4‘Lɿ͖gljUM/N+p<7!qC]~/ݖWB'O38oڸ2 X2%o] F.F_CeF EgCJ^GR9uEWq mOeh0O03OT`$&ԊBN '둕"5}kAGU(ɏK?_N%ZY E61 hP3ଔ.Naf|uqIj5ӁSDoZAV5}"^S#z7Jd_&+e\_ypbt/ށmL׿wI)\ō˫ԉ6S89M' I5?`c8~΄:gW&AYVN @.bQ5!6Ajtږ?$lE6T|I|V̔僲:se'j[K:6R!c+_W3̴ iaaDuK ?>&-s(CRfoy!%~EAѾ_CyGh)S%aᑩd*?!<⪤6_PNbr3?$ētFɘI]H B,:% iV"yS`]8-/Le؃u%>ɓˁO}sjPr: p|P9$Gⳑ(sy#pe(Ls%ENjXsp2J9?/ `cr"t! §p&-!׀t-x{f>\Wp5z:>EԣOmo򢕰}Mn$MGE@ sxdgrR[CjkJL$cL€h@kqP|<3g" $0\k(FXo5D{q{ 9)}s~ڕc)*#!_7Qu4> g1ɌfV74@CIeGˮv Q, BD2dnv$~HTX0P君[ r2"mKRL6 @  IkņzFw_X)<NJ"gtiD٢c2D $ʟ_xD(xGVN88P/s%-0;xa8JX9K gA쏻δi]2gKosTVX5!ނ< Y eSBXlOߢ`͏6 Ř}d(#٠߇ ōSjHs$E0"fm^ H6Ғ"HoyANPPĕOGTR.\wt@lRDyqWDEQJWJ%ipF'e>ʱCIQp)d,l5vJ*|.|zWaj9,=V0+EbGb:S zE9 ca8T[>E}}UJhͦKQ{6 "b-2K/B Lk#DYhG^Z;qpQF̲}8(}KdQdr@V: xxw2bTŅS'xqb8ha*)IQ4s$$k,-V˗v4#zz`2%$哀%Or ȰHREIKv9@:iz{A7aDHtgu0mPd$,NUv(4eRX1kcXB7zJNtCZu { kLK)29Vf|X1΃6 ck&6m7[`)R w*]n1 YNȣxZOTHІ1,܂3G瀣x2bţKUm^ƈy~EKO?ya_ $jg'?|bE!r+1ߦu7[5I_Pb^3JVF[p[;9Ze1KmZC bkK.$(I#*1 DAĝݟvL{:x` T@рHU0In^@iJExӺdؚs^-Bj#M( XHY'vЅ]fHզ %5W:v" V AnLG8 P5Ӯxp=f* 9FU@WpҬ8C\ݟ(M*vJQt hqd3 pZ 5=kvqt*sc+6S쎛kOrG<.m.u*Y+[M}Ǚ!n!Dz\1"tJ4"vu޴LbyڮUkq+e(ɇZ\,}D9ڿ,.Iйnk혢8 rE&Wń6uOɵ?uLS@3m=`gvGHd9lT 0ljjC9c'z 瘘ІlT,h.y8ŌTV[z@)ʼGr̥Nt`Fvxk $s? 5증.G|/ T6[J*éyy]CI|@}8pVD &QV 9Y M{k{>Q 3.爥}9ʟu" Un=w΢Ʀ,5SoQ9΢!zƇDoxB.գ@sYp)m53PD{a+/qrΓ\pYa.Q483XNUƔ pPEլ]_Jg )ÔRK׬gxjQJrCoN+Ş"-IFn2˲A=ޏ %U:P NvJL?JPgc$Ag(y1 F^|Q!Q#C -sދ]owuۚGXM݂x>WЧlp?ՙ PfyI ?u[X! 4#g@ocZt -8BG(;qoixFMJ>hlqSL֢MCm߱Rp;'0N 9:/?qjVdMq -ů{#DQl:nچFC hڂm9F!i ^X(x~[ꇞoD&^3؈` ,w r! V6$ 2M6|Γv:9?:+!3DޯwucrhJt[j1tԺwi-y%HLP{m#y,}+;=*o(G#η,.$Kфֆ"D=GTzT ||gqbTĊlGcZ YyxahT[-E/ybC| Z R\M0sJ~bx&.V[=D BbN/Dx+yP IըțR cY.U}yX6vbRā݊f)09.J$_5I 6{H1]Qz5 LcM/*60 QbUѠZQYNTr-U+M<*g-tPz b/W6@$VYyk i|hr10e9; JQ@_U5**DV A0'c}z _P:zrF X O%;m@YV.?@eX&o.wUh U3# c%s?.3R3ΨP2i /A,s~g+:y!x8|x$I)m5֝qѨ@ZtCxC!YvL ;8{M8g0ab5br#]LjpGj3Ċr1^%\Xh҈qgkl!ETyz5qVHw֤-.N\5nnys3Ik/dPnv5fIO%$]r' /_q~T}'FFfٚutJ7 JszYy )䄃(*H*Za )A/ $F]ы<}P2C']A=+ $,N/;̹*1OeB1~a=ZD|N ]P`(~(~\XڱlnCXT$RrFXCx豐1_ I'$T8 Ȉ=Z&|խFu'#M8~UC3@0F,%od'Y(9@ T5ɑ%? g:jNuxYS>F(POX<rm oU [4R@ω꬗!`1Kg}o~/.Aܓ>u/|IYZ2JzZxr2\-*;=ڒ*i]HMNtG Q}aS0{zڑˀ,ߒLc7\Ԝ̓{G"}.¿دXf:pᲺ e*;VRjL^h*ꝳz7r4ۑARv)7}?Pl!arm.;􋈝miЉ ~ +PbyݱTixFӰRYAųRԹ8_x킰CH[p+m^/ꨏpQ_F?i5U˚KAX3\0YjU[7 ,Fg떹1+QR>ӗr˹%?(H0+ gUa4pCa4*H3UłӹS\q V %xd]v_9x]G+`o _!Ioz؛"e/t,dv޿9t`V9[$pTq/.CPbxks[1ug1 \!NiTȇ";zĭ'e4?fLe 9ýǍ&B`6Z2ޞAD6h9(p;KCWT)܋Ȏ^ .UE^ 1ܔC7/rB,QE b]xz8G"<}md (^D.mWNBQ̀Qkfk+MlPeRG{Sa"l[&}|jrog0{RTsF\ђ?'@Lߔt}}SX-e> "NSo5L"mIO璟jy9eE f[0j1@ْ~tLo *-KçdDZFaz[*CN JJ2G禎iyY,O\7/㏍tB{Mwfߋ @٭՛")Wooχ}}2l>>O愼/TNm{&"~y_׹(U ͛WAgNbKB5 pw݃6'hV?YJαzl߼\OSbJ=8;`X`=zHY8 /ZY蠸7wGI{+GLKNe#wCvp5po:OyH`~=u+cae$!.?5t& M*::xKRb3r/Sw$$ Y}}mwK*b j%?sDFF]{[o ̴S'@}\B,VT&;rPE%o5 ; :GC$r((LkQ)cCТ$ lzA3"` Okv7 av[IN*7&ːR=ZNS-WrTTH׺c{Ch-vf,-,+TE35xDB9_KȭhgT 1;n%fGY3O5&tZFA&͒HUJK1C4ӸHTGp}r+{G l5G%h[[jdNiX(ތ0^C5NVeGvQ`𔡠xˇrDM$VBe)A =WI"2Oi&I^v$@8P:lAF\TZ4̞0P@'mD'І"ELn]Gq@c> z0}tJ,lm9JƁe'ծ! t-eCR9ێHzQ 'iLP7pC 񨨲K 6=9=<C8@b,ACғ$VeI烈Ւ}d]24uVP3keO*R[jEEAJl:@]ӆ5l%Lŵ1iYaHOOb9x2saYʈ hfdB޿6꿩uݔwi7#~ ܧXČ9cBC?A(ӣXH:DPB]*KT =1~_ڤhr6C<$;N/Vm3֬Fj\׎/$)u=j)HFǮGl\G/>d?I6q#I]Sgxwm@9UPe@&LZyԱz:BZ%.Y7*9iq$Ay{뉹TZ 3x/Fw+s~&\I(M//U^O١"ƭlwWqf~2NYWS/o#rMOL_sZ $RM. ` 紶W&&J{&UC]c <@ɫ[z 7kAy A7F 1+pw|Xz:r!ixUVMehe$HpT"Jߠ XBwGlRӸYeVں]cx$ 9N \N[9:#) yS{fM9㝁>* } jidٺjL3s|#n\OC(`원7O`Xɱځh5BAAtd@8[瑃, 2}p_$OgDm9[ڮ|25 LrU<9躓IWz'b0hdE6r4 `L蝞'm>WalxL/䧊*މd00#߉zlBD12%,SV˿[q,&~'Eא֠ TwQwUloߎ;FY)R0J<!Wo0wZ:ףJ7[xo=I:(dDvv qaD=sl$ٳ*;Rf0m{ ]Ťկ32JjJ Bc@W=EP\N:&vRo-Ē׵әҌm wE2Ё ' Uq".{D_r}.40o^^٠F!@|7,iJӐM2z5(gNJx)4Ez X!dΈWCaE`^ҞU1r b43!3[.T7Icc @O\½b|!! Ol -IjэSq,%lZMsY9ik,UπXl~]+`\tY -O?ŷC !%j- =:# 1oۯ'ea72V`x85>L @oa wI5:~fT)>qG'ia9B"bCە ִHMeILYCN .HILSGmtBI֫C=瘱's_8ɞZ[Ĵ m^)"QT V7×<@b{+\|2 !K3T&c"<=SCBrHbɐr &O$tp'_ $Z ڢ Ye&x4=QSCH kw`"X, K큒&M7z8F9& ;D0tp7pm㚑` .&%Z6%] oƿuC&YoO{7Q!򐔉RjΝvXQa9|[2Zߖv`y :eP4`uoDX(%jwa ZqLV9w"-J§$g L ێ,{opxXZA8FG]BCMb4aHP&k(1U-˄Xȕ NDrs?yҐ28[N@0@6Yu2%np 3bsy_ M<[PhĘ=D 53Z֋_5r،pg L%9I:(U0j'rL[1j'*yOPwN{6vK@J$lx1P\ <l-@ˤ,0`<`Xmp" w#%}B-mz^i;ZY+㬎؎Aջ~%KUy8֗ys%ӜY^t j/ӯP"#p7#>*[bqģzQumdSi,4,짿B[ ܀@ _*qMpjKI9Ś'άx0pJLAbD}"P cgI!|9=ĈF.UJy*௠VΈLt#fw߮f2E;܃` ,z4$* TV31 D? BW۱fP;mS_]֘GhGy<{RCPc b4hcc94Gbj;!MΓpx>/-oH-OF*{HfRU  vXLw$$QH-')F%:KIe9TkCSV/|e;PJDh4mnz`paܜ6oh[l*I e1*l _0K@!(2JzbkxaD|5)D`tAz'=tCZ'+)-ኗx`i-v Ne,L9|_އyF%=!xbtp$At< c#+n 5ܑ*1S0rIwC8Y.=dd:u6(wdL pB!R_rL10pTkc+G}lq)bqu- ]A%b/@Vd]#|4x~>-N48kAf9 DuҐK嵀#e%1 h3)Ŷσ+h ["ؒSRTW0g޸cD|@IDATQ"?X)yO[S Bۓ+E!e5/mhE8MFt/ Qb&ny$.0t{T^a Rxڍb2Xmܚb20 L$.Y^n<!UUA{3zHVgRpV3#cGCI7*pY2A 62;/~Ғ2'ʉ ]Y@4<Q 5ft*io%{Bt2dpKnC}:J`E!q8)'@ "bb^?ϧvG\ἲǂaZsaz[@@`Ĵrݞ~iq -ّ9R~ݕ׍n|~tσGXziSU:PRY<@2;هrΓ6 ٧3OoRE+ѓ*u)YqD_Ŏ{CBL n;!P̸N&dF h}df!2+k6%Dųrv[ C?Tl\ 6 i7 ̉e7p^Qܶ^& pym&,rW OMZ7PѱL3 MSZá"4&ڰs5RBEHEL7jZA颋DFOdԝTHҗD==19Pnˌc>H[ܖؾ xs 3:a:w}i0rckEP6<`_@5NHN΅T؁A2\CbZE@LޯW 6Wn"әz5dpF)}DL n$h ,'D´]R0plhRZ vS־z??`2H$1zڐY2:F^ 4ͧbS@zbap |V':[f\NgM $ʝj-Y]#  W-galTjA+`1@fH׃=C5+8{EPd sɮO,w1{k);64RkY3Yq]l&(aYcj ~V/DZHC߶_b24 1o_!c1癠g<*gBfx떭_:|j4ak_֡XN'ҾƧA7Wlu<4f1d'V殏߷'!uIVm"˭a nDD"5V?P>R~coC{a%i3m7oi/ `j&NLA>"7=kdeۻ &prI]hI>SA• $E4aˌ1Ƹ|c֠Xt$OJ @kU ~yy]8r)8hkG,Á ͒ i ,)=hX)C<*w?ξdkU߾[U g-rbbog"-{ӭΈHoEh<1LD YcKg"e|gEŘK풎;3%Zd{⤄b~mas|.  |RbۙZKn fO)@-3f0#r?lkMlsWlЊ& yé?GK2 uRG )l0ێcZ#j`D`:^_> @fM8Y qDT󌕮(sF<{:Bxsg=*Цnrԓ4N;f=HH~cc'[|\Sx@i5=4Yǘu*xm_7ǔ>;Z5 ت؈Dg"vSjL+JV 'w `dŞ;>Ũm}=XL6= 60V.H`CL_ `|34z)3M vp(|@(I hIlO n .$Wq t)lKӢ !**HsnL/ xtG}C?Fw?6x-.eϟSlٮ6|luz# Z&{h,ƞ.FqrB[Dp287~~aE℥vu{UzIbaFK勁(VÛazg;d3B_[nfrr̚DD^X)!2j鍣$gMV(Ò@J[:Bx~#\.IN t{CF@*D>R[E #O`rr^i{SnԆ ǕރkhۉO8gk:iFKɳf>oΉ.#/X5yɠ+ _oVD/~s"ݖ%yIo)D2vy`$ QsU6{n*@FKO bf ,$ȗdS(_4̶[g|˻qAdcs~yS8m}y}# D{_ltzſ\xZ˺}.J;lMOgK?pZY;r3 ]MpCNJh,sG)Ao"BOv1!S),H"eT6_ǒzՕ1DD;YagjCX^GLxL!ӎn> bVcC@N ˆEE),Rฺ5%؝,_oo׽c-$^_V"b˞:+h^:%RlUQ0gCa, ` ǗTcmv,tr9 nsPbI͞Hj47K$)eH!7J2(6~wYeFYH/ų<?'YٰCg`imukQ3>S\$~Ÿ$x[Ÿ5xEnxo 27Lƀ*e&@Y9>j [01 QP'7y%G'}(b[Bt. wݖuZ zxfěr2JpYPYbE\tVh)V0_ު'u 1NK|nj')Da:ޝ2TP V5[sDđǠnEyMP֚HF~:Cb]Tdzk-{Jk]Q6b `5 "I-F^Vr״G g Т0!Z%i6b=1@# 3X8upPqwPFӀ|e~fRo/",eƕ{hu> .yRw'#D|p#e-_/k>7y2xE|pj+ӋT`ӫLm͚0i xubMyuWQaVhwtX$!h%Ox hלaZ6AGO#=@Aj͠?@+ObL Ob Rx aÉ'FS.P%~n Rs,c"cSՍ@'*zrg ʃL)CeĂnsot0t1;$1!2V<&`I*܊9/[xwPj(tm;Hk,)@9# #Rxp2M0 f@7\9Ɛ}*!9d o0syk*~&ƽ3z쁸D[[gV}:8@ЖNwV)} PX=irpвN l('D^0a#.9XCS Hh ,_#]L)3Lj |>ʙE$Rv &U'8:l6Q|\xwA%c-M1q B9@|vdE+0PB+WI0 xL⣗bg{|4i|~L ?|I vÁ*Elȳȳ%ws(U0 _HU$ ю7wA-cM7A TK݃ɗn9 h41!5t:rȪAqQhP| 54Z:/i XD!"!gvvhAcegΰQ{{pSyfk`7,K . Ek)d /gT>mK*Klt 䬳]-ĻB=Z"tW^4=.FF'7Z|g6P|fDn|ͱ pni2gL^չ] ƚ(}N`}8O4՘#RL7`5yE7Z#D@Lp4 $Ɩ%|g8S@?ԛ/S$=~.9]lDOEgYʔ0<6 ũKXA=j8AXoGDs>/²83D]r:( *IN:/#¢S,sZ7rY -;b`jzu@b1>|:tk<zj!A>coh]/fEfSc[%#NN&i V3W!/w7VX@Uo>'e Fph.0ᣞAr6?Ӈplj@u Y. EmDB6X@[oP菭x%hp XZC4#bcaphAg__ͭV5|NUu!h ٲYy`\lPo\{ _]@b!+=2BQ.czJ`|e@HiWKR,R(|*F&]L:þs1ԘpjiPe7_??2.,F~c2kI-J"$Bx1|D[$_sE[U#IX)ƒ%e%tTNw AO.T4[~{\E֌Bk1e~cgI ĵVW٘vWy;n?3nj?;QgAbTS o[{|8Y +P0!k2Π*ŕ+%G":%w๸*!ȶMyqcp#&^7*QK/5)P@[$SaTB\d1Evg/ ziJLa nb%2LSx"CE@-xG DBz kJ.V4RWkHPf4c85=,+tiyުA5U͛F=FWy&ٜ)@GT@*PUĞla5gX֐GXY (*IlEzx^|:.B!g@#Ekq/=$v\Ƚr雊6߭ oѾl?9V8x:K!" qv_.>LjAiaYf2d53m6%ߤ$e\ QŔ,iQ4UEV>gؼLoKiZ61Z8Uoz?6toct?.0f$.~ZMO>fw(\D8qx#(3, LjАI1[RETWRKIcƃ+)䦰E,r `ΐ 3N%gޮj|sH B4_7$<o@W/^h:EV YuXkz߼lN; 9.@E핉E6t8窠#4@ ]LZ$$ϟd)ggwpbM^ &LB 2]{3م n޲ wdWwwN]VEe՘Qgp$:1e6ֺA6"CTeÙ=[*1jP9>dmpN)֢$,̥B}DqiUdF QGF;|e1vMyD">lR-^0N[ƧV9`.D6;pYk 0V }KV%ua%iCEJ 'u@'Pch{Qz6ǕbB#਩5D= tƮ\.4̚ܗV p"PLV(EG=QRN6gBJ eídbpzeDNG@jP5- #b*>- 9F4Sf݃Gxf0&, r?ysuAi"V] @uGa(4 q•C^'RAO.=d 1ӳTG4{Tj!ה\9g!`m{HcTf<2 a=m f11q?8ɻREHv\>AQNi[ i,qls`̶" #,7̣D?}{X8%yESlXLqC^ m(AZhZM$HQN@@\83iڳyH$kAn >Hs%VsAҝ=O3A@BT|H Iހΰ>EtsmҤJFZbζ'l!|q0:GxAw݈f͐O,'iGdD$de")3@ ֒#F@YevBGq]? @qR(wևUZ} d",nej. (j ǀp;ӕޕ@%:*@%fNm*/Ք6>[L]NX" !XAA]`T2ϟ`_s ~2h93"֯B,AXSŶOxCDi'SV֠w`8l}71e&#g[A:JrȬ?|sς e̳20u [a cNyֈ끯6fW=bO0ޛG*j: ΅jT( [ d!)+aqPz‡R RfGppp1xYĹg2k)JoTf2w8zC,{fO_Y k^"R4Ț4JP:E`N0WĀ@ZkL^+$La>&6(dxiOL%ZFITT5FX*>5BoØcj L=i-j y^}[hc(F'css,YAG)pQR9zfLy^XsMM/0OBփ{ O^5;@Aah?aGg$FE:tABZ,Il3G)bt̜bdyJٍ_c1mS/QF-d2?! (Lfxdmdm -,)#R ۀ!$3jf ǝtS̟ȫcTgEXs9JA(CZ&;pmL0j#GY/E?cbeڗ|q70^N#^7q V4ݖ6X",)6[N]5:W]t)[]R~4=PQ0f$Ա(;({/UFb߭:Y"%o%FNNص~HHFx/Yt=;A,m)iK9#iaoA mZCW/r$J'%CJ”J>a63\~--ג@|s/BoA,o7q|=s54LA;p' "Ar:授)h75@59-P?w{Sg(<~8|Pui3DQ9Ci"6BH,'!XUQ(H:O+ʷQNk˾֝1^@WDd βlkUHRPY1\ Z3 ,1s@|T@ njS# Kю*W!!0*ч' .4Mn)w` ,eɼ;܆rV߭D rwe>sFΕZhe2d=,!oŏ+g&at-V!THq=,}Մ.S[c<]+Y=["Yi$ʎaVP}K<\e uL6.eD-x` :#[&$l ]0\A{WXȣF8kTSAkxEu< Bے#w eopSW&c`ʘdDurf\#b!rU4%7I&֩Sr( D?8ܸ:H xKztb$G183ZmdjltBsM5llY7քQ~%5>*fa[ў{ 1@eIFX[d{UVUZ?ʽcqF̈́^ _oF!X=U}BljQHaytWH'6:<5ZTFviguZhLqFdW}5ZAl Y z=h_Gi( WZi)5/wqxk>Hd`p䭐kEŢͦEQ4b+)/ 8t_qJUQ.7Omqz #Yvǥ-*ۼ/X/̣]bIܴ8ϬZoXqA+hmoKkbvq=Xv+D'˿\1ʉɔo3ѓӻx̕[aۦR}:dpvyF=j 6)I>o8.ez{J%HloFfwm|pڏi3:TVP8$}zD~yzʯDYu3ŷ&98ۗӏIDߎaߝتsrvV~\W-ETR;s~ݚ/K虡9ʬ*:ZҐwIƳozg9_{^Sfޫߋ;1dzxqz\SjH,GEHvfBؾe~?/_$1?Eeڧ ̬1  .}- };/hT1 Wg9)>zuqxSFP:r$웷0|ZiT-űظ=|{޾l~CXEfGXXύ'|GT +M N +YT eat}?1*F+A_gM"%L8^=:#[ cNσB_4f/@))7L_"~ >2|;ݹndN:,keˬŷ9=Wz?b!KT?#|$cLyqE50V}]4"!#8Ux BEҨq/̬s h\وiLw ̧(W(d _5A A ¯_S<1KOda+)2kZc fʜF0)^#4^8Ѧ~kW2Yzuʳ~%bT+!q6ey?ݰNo}tcawe-7^Mq2'D¬C'M4&Qyfg Ke4>)cd`p'RlA/3bNH*bS)CJ@$bj4= TԀI]t=u xYcp:/L ެ؇߸nR:z%[B%U(Hѷ1mZ39gPyhl~ %- p#(q7rXlb~!{a%8m%za CA (%u ЙQeإ@,>?{#]<-aJֵ(-GlyЊ},ۗlȖO{If3I!.eWbʁĸH3p}~_:_vЕT%l1`$)@&q䘧Q}Ш%*RcwxB ܌ND6]QLX :xSAހF!L ^ֈڙ<7l<d&[)E5S_~zP`,p!bl⏸1%Ef(J3i[܍4J*I2.Ĵĭ)ΊZ™.Y5)_N>4X.#ni/G@^.*}Z?`3*^Z1aGnJ܂JzUis,ſymAPp;60/<8n1;C3&i0g)嚻xҫݞP6vǷqf԰wMkzD$ƽK2έ;3BbW,j<UTl^j4.9(F b^YzTfE<_x5zeŶ: (pha{IU/">8p;EB2$Kp"NA#lme'P~,MxL6'=u] W"iaAfZoc WIE*,Ү*e\kΚ ![uҠ2%aD-U@ƬWڔĘn:$ӄXuF4UKzCOo䁑B[٦ YhXP^=JRp? s􌙷?c1zKƵIw{zpW &mb'ɓSo7?j0c=N؂ hׂW#>L7f]2yE='lr'q 3Cpϖ[RShW?_rd]#T'*K&t5+Z^|S;OrYPli_k7+i[:`fqRV0p3d3<roENd@C?:Х-;w;CD#xؒ&bJ+}$)h$Lqc\v]EՄ s~g=\Z☚Vq+Ѓlh9P OٻIĵw)ӭĻ:j\8+z\b!oY<Ķ H, _)$3@n{(\ i,B?@ba@IIF 2Z7&, xd@qتCM|_YSsEY.,[+⧆ oBܪ*kd]D RuϐMȻ&";9ea^AlU8$d9SL!H%;~bz|cwj "l+>DŚ"pTS]]Ў:bψ('@2z'ZU6+˳xv/P/ƅiX 8Gn/ESQw c,mUҖ TKb"F=َ]"E c>)@4`\._;v4A"hG:x*$n[ hK>\`C0QkwpٮR-q|I[? (˯ʌCLИdʔ@ӱ&:$mg!i#O1 xdκdfK#UBp kabCǤNBHǴЈ}1pJ!.z`ۄ'Y/҂)$ř9=R.x1^20]YV6P*O|5ֺ?wߚSbZ6Ǹ~I<8P @C=̬n<~?YUA2PI5(,f}B23R{\t1o)%N9Pj;*,AAbFry8S17 lL3 >l2HF ƀ@Y~_cIPtc%Z xR|?^v*d{+T*๲)! !siyq'XKJщB]#rc/9RbHNf4 Cav$ ;Kyx'w}-BTg;n$2Ls٬_EaFEE" /#a"Pp:/'3Da7 bD }ܨb{<w@M *U>.IXdq1iP%İ*MƑHAQd;6K3EXΤah}.z>l։X ҲW<F2KJљ_hf%iTj)-iOfcYHpxw5׳LhrM/>/"N9v(9A ;1%9*l i ``廹dY@ fȃUMӢ.FYÏaF{kIY`Ǽ7V|3dz -Rf>X|fՓzjZ?c5䤲 ĝnBdhזuyiC]Lgb xaMZ20-k;^VRI+1K<%#TBiLܤQ6¸ )ASۜ\#xaHVHk&Lc1[Z>XLv5"&4 `ڰgd Dtz' vgZ2J"'nvg,d4ᰐdE.^nqN6C%KJLjo Ek\raA$[ vOo0<ӻDvYok/a?6>P;ܼzeoJXIATCKɢM+p0%C[Yd pwzU"N]̰'N o[G!ʹ b,]2 -4x̭5#֛6Y~+42#H?Jtɠ7@IDAT"kl2aaMS`T)_BN\vf3-4% ֙Q$aX~wǿO\À%"40[K1s1]c2RXVH1)P%ȩ থ찑"Д`|5oіf'R~SWს3.z䄙` a4ܹ &qYGb\= A8D%{Yl/e8. QbؒKzlj#BQ-J%&`,"8@:P Dp6e|ŇgdL6󦀀4'(xt#W"*329@y#*<;Вa!|ψ NO7,:BNZdϠ:YqN2dm& g"Ƨz6D?5Kj>GLJaK0 Cw[Qh"f^0h<Gl#p&M?FY0Xq,Ooy2Ke ͻ'cHtk\ΰ(>l`>R@ZIX(sqz*f 4!^/g9̕aHtM3Kʢވ)ZsSQQ\6>G nE+4m9,dp!X M91~kl H\7!*g3F@{V?G“osfɱoqz]VrkDu͒}@(%}/~}*C3ImZx|L%jAu[GǚK4x#rkR5)k+sDG70"DY }B])v B&2Կ[]Z0:"920}dLDQi5&G{& (w%)yI̲ mfHM̠]uE!|^_oҮ;高|Ū5vxtܟi {OoǛjUz$ əo۷\U9sL39e({GNz}Y)Lg1t1rT_,z^U*QM@Pc0^=bCfmԛʹQT0("dZi\6xJe[li6PcFUBra!d #7zùӳFH)؂æ]#t zeࣧJ`3]@/!ۼ;G{d..hk.\D80q~_]&J`_O6 X\!=1`_5e;" a-Vm՞h3|&V2#IS- PhZ:.bu=v§Bl2֙`6FwctþC(%"P:ʔU63ٲl (aHtאUd& hUth'[G2JJAtT b U: lR]q?>Vw}jd (?H["h!ӘaT^IR+n EI’J0H  1+NK#@KrY$?U!@tODčCy\ ќQ =D! 8E$pExj-41ܣ1v3 :[O 1HD>„LCtXbM%Q gz>[M@J'+,$H 9-(qQ3A bNAf l|@ ^[/v8#o sԸ֠m%?j(6!Ks`XL t]t4s܀0E~<??baPh3by">,CV,% "0Ǥi6~q3*v_Jh&l%:ܠZJT5t|1zTvh8 ^,,`NTڶ!zx<~S#nu^R>WQg1D]%5%d!%U& &pƍ@lelƂ@B=$:DAnS5kZ\ctcja{u*X]?`Yv Gn(2r,t9lKe9- \R%niqyjT~mׯZq3?Y??,FLGP +ˀ*ˑuҝ3x9nMfiܦ{pTI_n,^GsR%**V/e6/oo;..DxBk$ߩDoi) +?wƐMJ=ý.!8}}Yپ6^_?~1Α`T.]TE.\,W7wQJSdlJ#`rJ:Z̎b]7=~F3<o[d"XX„ĽZJH^m@b +?>E$pn̚8,jLTY \ N5WbŨ1jo}M\ ~P pa;*;&,.;u9Audd:I޾MDmT>nt#5rdU: $oSÛ`-6 cײ1q,fM ߮g@%u M,\ްh:LPc j]IɅ0qVzHmOZg/%^ˡ9y:)˩tA8ET-qj\(H]ѓab@Ä{Ɩer5ثUmi9OS*yxDgwc|$(harRw8ZHS*n#\38,B7u^? rd]j#jPܥsӆ|%ʟN=%QKԮD$(3֩)C|ׂ}w@?rOaKX+ݧy_}}ԖqOΪJ 'MZȂc碢80I"1OV5*((A 8$ocs=fV 8Q;ȿ>Y W+ TOf":PUFmi= I*SD8 "2k4BTmIa<3t9@_Ws,WW^vgT^}ڥX-<2~>Į\ iBklM W%l$kEJÐ$<,^i3.[3:We'p)&0еHW'7;4$9 )@I#i ڈ &#n+ٳF)g>^/6X/n?w(!ocro\.`pM g;'?*`1d T`Sdx(s,L6o PP"KIJL^@jcj8M?OeΒ(%i AT5K%*Hg2^etcW8~+b:0nc+= R-Q |&4!ey]5U~&P3wS@1R%JG߱T N۷DH^P=G,;B4 a?"BMeVPt tb2XuA8ې )#p@ Kͤђ`3\#d,1=(%b=3ף0o #`2dHލKwc*ZT Xe}(3Cp`aHh|x`F؊ B~)Fp ˆȌ'HRxd}"{Y{ZKj.@??x쐂T–+ByRT!0wb(c0pdU0.w e B`K&_5ئY fdʃZWu!ejpƿ;>qA0,*j~\55d|?E_~!%&rmy9DX.ɦK6S%!9 ,bn5( nG '7ZK<[ zvg)s3% H_ ]&Mfmq&Õ5*67e ~\V5Zj64v!AOqKrji^TYư;u`憲xfJ4V+>v^ԧfplʻ~~ ${(a!ts&#چUI8`S`E*/%W&bv):di<\a1s;ۃ_/?9SD$K!@i%ZYn̨}J/'DV8%#P;Lgo'J.qVrmb(]WC䓭Fѕ.W/|Q̕r4D0Pw*0ݖJ̐5Cȭ5{Ms[iQoSOL(sZ13Zo#Gk]8L&  CM+/gum (q]Gǘ!A?f@f{@;>ɠ,ǧq'G1dP] 9u<=ZO&mw:HٴKyո%9SBm`-}zx$d6Ƙum+kwɋя9p uc_fI\JBbqAHD3Ey4X^D x^gdJROv o+)G[M K{]ާ+1,TP"H?tZ  E`NlB1nj e dLz[""T,oD۪S$maԞ諾J-lÔ-c&U#CiO]_;~(POkqb'yrcٍC$ #YۊΘsH`)+ԫG&nh5C2ח8F=3&ZmTJҝPgpeQb8]2Xӹm"M'Eo WPq8# &V'oSYU;S.*WnEi|XiM U%O_!'&R0bNX!pZbr:&7Öh⸚ @qGhz<(5쵔@N-\vۈY ǣ#é4 <߇X@˲xS![i(Gz4$~HbmD6c_ mymPs߫d= k#M(b~y7֊MOy*gzBsxTcđ6X6,&ma/D.U5U1\C|fʝEI\ )ٗ2ccy'V'!bXfq9yц9WfFA3?}[>9:񸛿BO,oޜQb YIdȝ\ʰ^qznjqښ8ڣ3ǚǫj8g;JUEjni|Oqm)!MiglD̟rj1ԅN2iAxB<boРf8K֐%E&[)uBbĄYC!TVI"uNjI{֞>Hj?ɉ4 (U8|໋t&F5m4\uCRhRPk3Y5'+$XM 4**'eXN#FֲV }킓88@cZb)Gt0<d8,pjx$|2 Yܫz_ine+pƅ(XH4L%e%\t-N͘4i`N;я?J`XA^ 'n K U)^ 2,M]}R+z w#0 D&bleԭܖ9T$vYf- l8ZeQba$'$a;7$|z-}&ؽP  FoQl 8CǸ8 b`Ա˃Z8|S S<sip[Yh꼇`Šsԙ|:1@':ne j~1Ip L [w|S[F1U$}*hϼ쳇=+? o+܆]w (AJ}ȍ,0elq~\6:2Rguz'Nqibfvj|csƨ{^eToPN-z5/Y󓋻1-aDSD)͋(ؘcIMX!ARnn~Q' MĘyPqo PZmc_jYn3˻_"뽘Q,E#&=/8(XL׍ uE4&Fd*.&DϼfR`MÓSgTMc%2cc9FF><<zP7!G0oU>Nm0c'c9!Mc& SpDw yoo4Q C3tf!s'Zcue=1IM'BA9mHOBP C 眞_ӐUϒ Hl3_~n{UxkRzGP]OIP_bލfΟ/VMq8 Њ]5Pr (gĶ}4hor2x t0 "&C٘NNQR|vb#"%HLBHe,؈~v)Ԟ~qQnS h sQZkϾ`^mW?Ȯ}x%F(z39= 6^(P-ޏV4>ןTHO^𖴺㑉v8f݃^xq!&)ZU9<.#Bdv.eRfq?jn9̒2)fǻ9ۜgrCx[-kfI4|e\66}f e~ `" ĭǹ^džLrb$\bcr,3 ::!gi } Sc4s֨Kİ^Hۀ`VԃUTt6m_Iґ;J_t-_+p6`)oGzUmE],fx ނ0\gGJO3|5YGks jO1T7A|ϡƸL<ʂ ASM)g[WQ? #h)$TQ^JqQ`jDsܸG95hCjoEMZrwůNsA XY\p_l6¼c-hX͂<OWⰧ-}/b}'K]}&(-m@V&$i!J?U ә>է`'zSrf 4)]f.xP/*Mydт*pV;yY}x{0 zxfxJK7 In FgӝoxBDVgHȞny@]Pe5srϔ%3}mS~zX651RvYڔP0z}x>*cEɥ6%(K.JMʦJCa+oO+⛛9C/iqIG=iE+d09iI>>\O9E;yEʹC%["hE@tX!FHF&#n#)fZG.ptއSЯ3+݅0ӿb!"qqϑIBd[n m'??\Ȫ Az߯Cy^ 2XKZ,Fx>h|||xӇ^w]o;' _)wU ?2n;m~YPӁ}v?[藮7;-/𢡊YVzۺ itO QG-4^?^2{:ڰ]:#ҀhJ2uȻ,\-?:`/* NlR坘ɽvCg k)ޔS5@䴬`*'MdHBM {Fij_3+E:5ӧ B1{N/I#'ዼ.ꖸCaWVCCPЃ"< P]C7"z%^H߯*jU#|o2Rf㈜9joj~pvytq['MN9dマQvx%u&Q4'n PnH;'x6zTsjIAB y)"r)yGgb>xȚ0 w,G@h&rUx^-w^S9<_ V0̪܎i4CiK*bu(7XmR n_x2Mv%!V9A?*UK~-؋6 Y1'~Zgu*ݬ{c7jPˆG; ||G q @;PZZzkAY|vt:L&<w3?X4@#O ?O6XV%IG_.&qf?"ۓ]ְ5/2xVGRt Oml`U"N{7JǽTD~{"{I4w^ 뽳+4ԯ'mdPX_^я:eEݡV,=n5Bcfݯ&<S,+# 6xڽ5gM2r*ebb .Þ5:T)ZYYKtj >n`:O"-'?Ӄ0bDQb t]ÀW&= ZkjR)< Tae < kHfcRv*^ogڗei AU 6RF&1w%e|.^֯]~0d cqDz.XIR$ao;_TPўDD]G{QnFFCVɇ;@ >bN*2j,nT-7 n*`qn7pc^Na!衼EU+ [GL?MI  e~BƵА,PVWǼqPR2YdTX=x@3r+x{ _-:;1ơX`O-pL ~ir"nki/@00Zػ3<cPxب2&qxa=o㫏=6˧ذus>nBX Щ>Y'jCI?-֏>ʇ1oF,VĺӦI=ĿXt%&W:Mmf MsgvRj|nZ*piL5+FC?d>.Q:/̱H?q<kag:b*}q"hIOi.3Y#t'$ t \!Ũ"2޳~x R8|\Ej{P [FqG %P?I#=7מJ7 Ԥnv( ]4AnSaQ ;"lX)PDž>>m UFMK _3맹o+%p@ aPdQ? o LM+i/?-z/4:c ~D"{ ~,x}8(ߔh|M@?b~$bP"S<%Ǒق+t^5d؁p@58/O+FbgynbPܤWA?!e!aQVmQT81'0TNBIܰ#+bך<+DGS̄r'*sMRNǗZm9tt s|Uߜ~-H.b%+(S$(Uq3 /3[s3/\lФ1C1=\ n'yg|6pqrVqgy{ڎC)1d鏿- +@|a%9D7ӆJl?6/lg7;DyZW8όkL1TVP qD,mUzfxR7Uz '@Ty8kj([`Yn%f~)v 7qi`O6{^I!0+x Rѫ6F)bDh bxFs~=6bfWItݦ%o(4n  `L1Kظ;@8)|F~VNu_!/nXI][JM_PI 7&=J 1 :| &Be?{=ЩuSP4''g0jVFB7ҭ |xˉi1\;@H+ņ&0&% \5,Ṽ=2,] >mڲ]9Ҙnsp  =f=,|/ W$!"Gɫ=24` i>Á}o%<=!TMYs0KuU@ %}>meΡD9M]x8Pz!? GU A6-Dt]ZmԨ Z3Qk ʏA~]­_ZHd>CAQ4SMnk{>GMyn kaKt:T1(_@BԾܾc42Z%Y&uڬ^;П01dW,xtR1^ 5ZjCy|)-Kqհ8|["2W},XXgE⯏nOAh tZ1*ntGRJU_$J{TWc~hHjTr /f~882([d"\suNKJVZ3mk)ojZ?50&rۢ}i4Ty}5>J6FtKlárSا(sp39wÇmp XdOAk!lV$!G}32z)L\ ` _/F/A"f{Q>|3@!(1oJ堾 ihDo@bI YLȻ3}H?Ce7/'>bgGAVqo'Wd<iվfE@cRD,DQT vQylxVP?qetP2q}ښsa%Ë޼4g ^ j(` )-IDFQ;$8R yA)%-frkl`ђx2fCr_<] b/)Hm6~*teE,idg55;x4cBU&2;Vzb(mDƣr3̽W`twHR@@]goZy BzHOi֐)g0<;ɖ' ܤ;ɂ4>~p;_ sыTYv[2Ê~7% m" |5=9v9OvBM ;Y%qA{ըMGV 2u>C|B39mZMN&8;DH舁rpP /y8}zs_~,7 '(b;rUqpu>|惽ΰ9ǓEo26֭~>uzj"g*;Zr8@n=m`H`D@ߌ*ňKnZ}ۯ*?oV]гOU S_wǖ mWx< AT[Z~=D蔧F\@bmiF3OɎCȴEW[zRx:@Zڐ.ܟ^^^[ WiM/-N2uθ_1UQkVK|ChE~D`tC*ݢoCQ_LLPd+Sȃξ"$ D.U,1-o#.apD8nW(k4I 6*?a墡+I]JImQf3Я{ȁ_ ׈{&<)Qmh`D?S=ȸ5_)1qH]z:NR4H( t,7r>oL#T zEsj>Š0>9 2Dx ɓ5̆$w\6 p =m0lZ,tiH~7&S<]'67PcFw~c/~`Orc2=i&ColeJCyRA  h2&b0$֣Z\Iɞf<:@pC̊@!00`*Nb-oE6&>zZU(BTQ)on!cr<^-Ҹuuhe0h$Ba0 .#~iyH甏# q1p8gm5'db}M't6eCSFSLnWM烬?LYwXJąLU2 Tҿ~{R/CI9wmϛKI; hD5?j[z Ժ;boFr8ȷo0q7R0)oPKuwdzqE ݱ͒H$/BX&/$xb]+SJiWQ¶`$6GVX]ai>5.C+B1'U;"3'`ÃgOt[T ͠zʗSPL]۞!c?IO&x{Zbٚd7 *ݥkv-e{d0%Y'p*]" =cIRXXTih(`)σFFyՐ0SHB,}1u\ !_ +D)upWmwA>~L7794Bb $ ']NEL\J*nq.Bi5g5& h<'&$՘N ĺI3]׭㞶Pχ\-Ž9X)Y>xk^ĕIR,ASMIt5ƉᦛG wŅ8{<nҜL9o`۱~H v"tQ >;: WSC:3a.H] &k)isut-Am%&;<4lNugZԧbʱ\ dtx-+Meq㞴+KGCr$nkE4hqVW׵)TpлHZFR3Rjӡ%vR'2'=fwMHKh*c.105y <ق5䬼ZB>'Yi٭-UۿǹD A[Uވ}>V/l Coc]N\Ź#6Di)>vD"Z1s^&XbC/ @ei(cFOGJn s|<ȃk Dl2:;䛞G,GWZݜD)/Ml8~}T-Ͽp#H6W@\2ZGKr#j& K=tUq Ki+;юmbp'I_ zq\+Mo뗇gbm-NswT6COu5$A,TEm~v?pbA$uNe4k͊?9.ӝFlRqJ}ʪfa$JXI|C1Nt |/FjmbD!Eh.9O |&0N31^iLkPVpj{< raW&A;< /^*A y\2;؛)et}=Baؔ /E]uj,-%bPGrpf&XN*NrSd{\qֶ8JtxnaL&$b )-/౻a'1zd#ѓB]zIs P ,_:K*MN^%},&{RTۺ>mb9I0h IQ'x40gau ^\YZg'V„bQer[.AovνRG-SAA{7I&-LΣEexQ7&rKә `+CƿEF]l¤4pq+jʹ(p^}tڗ=g])q#G7X@)f =>Oc&wh`Y=DIxlFٶޙ= XZP{8w64=p)['qi, BxI42! 8OA: ABg}uaZ0ΔB}H}8ӗ_Px,GAʟJwy8.\6]82\Qpp~;jNk]@ko>ՠpYXܨN:ʩHҠX>w;^9,˨ۻВJ_%MhuinA⑁,XIׅ8|$Ԧ &QJr:쟿l)\ʩUtԕNQ笈i>Op=rUk_)#1G?G@0+ow[1T-jx]Jx .4xMe8+Z-7/|g͟Z.*(X _ԧD0GF .j/Ϳ/ U"%D2Sʡ6ceq7ChVdeiQyPJY_GS4l{Q/ ڂC]ׂyq93zE%M"F7e9v]#dJpe-APt`b 0W3YnښiSCn=#x8>~ϥ្s+Q̺QR4#KWG5 Y1}0-qK>S\( "Яv'xZZj6gbU ܕޒL'k aldM ɼ==kw&x<>>A{/IMR|dV_R\~KOOvy|Hiy3 FWUDE+d)ZO>g&TKGZ/I '6-DJ߸06t a|4b.pcPGVX%<&D^ēu{de a"Pb^hEb99,Dl4LT Pq Ɨ <6}`9eM 䱯NC ğu2Q+Hz1lI"y`|.D*$H>OKo@'q{J۹XkO0?-ˇtr?«X:i}wjq+/LnTeP sg8!1tyɇa)$uwEfpC ̄~V{wMQ+ h|@$zO"dHEÛq6t 719ɝ y}>x]!r_33OM"e~4 0gp}r|}_4nj%xG8U?BY&I_8MIxݮR3[&*NO%( \œq~tzw۞!BτtLkfh+to4fu vGJ$D?x@ PG 9`qEbt ?`njd~fD |q 1| '8z ro@4kD;݋f,|@i)B霖Xؒv&gԎWzŭԈ˜4*4)>lߞJeRCN֭:Ft6^XP.0a'u0Hu RWеǵX$\]R [χn ?4{jpv?ZXNIMP"c:  # JЖϨNlpE t >=mF^W/pX@.899n^u,kL(jdNfaSR~R8g'ߍMfªY`]w+)zBYT8a8o,n1~,2k01\J{Û]t 8UxQ\uM¾7$SaV'1 tްV(2r{P!kYM$`p' hgIwƋV" \ z[<Մ0!j.)QHgeeT*ȶzZW,6o)҈6·?rKJG@4eHPz۽6ԼT˞+Z+[XzyO.6 LֲJ)mMl%y̙ }GQ"6¥ #6PhlW-0 dbQYѬeT}2Ool/ $0",#YbxyQ?O^'DaF31$\4\}(K7 HT 0gR` ~A{X@h3UB35_sT.3 oZ*t\:Bxt6^NL!VX݊w)yW]zr#3mVԚp:^Sr&Ո7ځ{ZJESL=PWK!i "TpדҘ+ \T,xKCw[ 5Dc)@ظㄨmgB+HLRM+ W/4J_&KV>4d^K\k٠)U8]G?ĵ=fX 5b@5Y?Ҭ:"jnSei3P99 #D=R[R}+I>ǥ}&%S?t`"ܗ^-YJq?C RobUmϿ.f4ZO^@qU˿ɶxE`IC ).3XzW={! GJFM,fb~tW\/Ǖcw |.o)Qbml9K=OƦsa0hu/m *Tt˧TQP&yqqǚ@8@\c1lsn90+YUwn/T7CMpГ 5?%j;cDN--oIX}j 7Ar\Ӫe0kD>']*6tlwytoR@>ȅ1F'0N?ɂjLr<ܦIVRg̽o-Fod}<4pқٱ-M׃ڝ`Ƕ.^1T.:','uJoxr4VS4da|l8r.NOlhp_*t3^*z6R#-qW AD҉A[ rliVf}?3[L|G B͊z&ciPhWofD2B2fқYnܬZaC/$^k6Հg"gl03 &&nkRGL;%deĘ<G~ "r Ƚdjk!_X0 F&¹xecPhBF~;>Iqmf5  bQKLR%=|Z D{wiA %g# ^ŸlwXY&۾4{78& t,KsD,BJ`ۆ zuT Z 7)(_ј| 5QuQ!)P{X~MC.Y(~A%ҬO_R,0,KKגEt:܅=@1ooDFK cmX#}N>*{AYtHTd]:53 [gι`l8us8@lv'l| [?O)K1y'򳶸p2#|mFEelECPCSݎB$pcdv%h0cVN&Mk*E#=v7-tuwD )#YJsxT%+ YM-qCceIRN(}1Ҋ28&jg5X[%arƸINRv#>i_iM9bJr|<b uk qZn?:yʔGMIt 0Vė˷~.>7:c^TՀtQ6':=alV+Gm-;raL_l8dvlK0'#]6_XHo4-[FZ|˙7TЧ<]w Nvݓ#+j(*܉|)|b,K=&D }^KZ9ҭa\h rڿ\+3s(OoJ ,4m$WwySëbT m9MovW0 M zD8 .ѷ1ݱ*}(e7q Bwe<(ppYԟ=.}mk&p9ԑ8jrOqCK-:ھ}lXؚ8ps$*ς^T*6_P|^[X&Ǖ6rmNHPJSf޴[Uqn=YՂ) `:e;i3'@k!3hX˖sqοo^`8̑Qad2f5W|%y.V ů~vwFxGzJxyu{9 ȶe<E8Ip2F'ǿg$ni2Hh2jU9MiS >XJAD s{:y* ]@28F TEo vrS<_!`P5]T)EN扃8oPh n zKӡ\OLcGdcⴧaO^ i1ƮPYWD+ҽX3Uаwm@+-A[OxK"A^%jqӫ+G~_r@_G{.\mwǠ.%r=ٝWx6~`4(Ma ㏞QZ5.ȼ&~RF$O2W LR*E%XSiPd8 lI˰9^ȅ,SaOSҦ#'7vμ Ǜmn_ba}}F=g7VYIc關t(vƉțˡ(o\nZKg-!*(kc0\[-GpL3o`R'G*~96b+s@~q|^ֱ6'd^9Լ^~5ԑ׷U<]jp^J(4c@ŧg^ [hA\NL)K}mڛ\!5D=7ilo?_O ~ NnVWjME0TR9K,eeIy(tN=b ?f{7WXDUYUq=$~UR%ku51@_cQr Gv=C~^]\:NExc9..C:^@jJ?On/{X9Y)IvnWn=; b?5s{lO˯ch u,(lirWZ{ xUǹq92u)XO": ,".LJ"F68a^(GuenS;k"]7M҄\3Wtt~JA)3 zZO0P%ʐdɣS_؂ }(OYe;j0Լ" O m~bLpZw'MغjFo%Gܭz5Q(0߬/Xnq{ǰk_A P zmBBJ wJ!49]䃆M#Ќ oS܋ g4$t_5ec: lyX S77Q wv !&?ji4zu`QqeNaz+k'>Ar `*k\ oYb*^5T@2gkc%F'ʉE"Z8.2QjMjQ,a&_œ5֊ ό끧`j)z~U9f\)?0l2 aT'aޣw ²F7ɬB/wYEKb .4z;۷A~OVH7p ȑ(;y{?Uo+>Za&nGZ-w1trt*gYY4o%lBH㒎x鲀Ӂ%(y+8Vru]pz27_yGx}8Pl= EV;T4BviwND r<2")O7|T{.=6@IDAT~! l;x Kz F\K9 bvkM@Y*gl|>?jSt|ymX6JST\]ީt5|"s%܀>=s6|꟪1}mrbGmʠaY,dps`˧J`B75*+_!fF\'^gDy̻v|aMAͯmCA.^WLJs:M&<164g2E[7;}Ϋք $BMI#asUmGK tf/dDORAM݈2y2bugf7&~,MH^ [?EJ}7O١bd|TX⺻_O%[-#)Snl+BkǕFIMnmUQa+iLhɩlAx)?31JCguXꬻSxHx?ere*To.7l 2LHi;!lqn c> "ޥGz3k;b:~ 6'kԧWx]Esp)v,3Qo\Uj|US xR«HC'C(UR٫W,)i©=5ê8ߗ:h"o}| :%w4r9}G(~чa=$^/5SԄO ;L-|Z頪8΁#;۹UCXyTY5~Fws/l;dI3 NKt UW&I1![`&޾mܗjŝ3L/̐ie>L,@ܟ6Y/|?~BX{eeh\L[/z"ƻn`@Eydz[,/1p Ѝd\*Jb)VnuPRZ?I<Q9W]5H쿺mC7nJ_ OǕ7f:)yyPPN+[.&.uOjkЫtaMKgwԗ(M; 봅*b0IHbw8M?08ܤ0c* H=({7ڄ 38z"+hhz:B>S&SP.3|`+?!cdHFOst,DyAtMљFw+1YdWWIY?>l{E߿#D(1MA!=z+2P;!>h=Ņ3/$aӿ}خ2w")3ܭI$$ڙn+j!As5./}pY 'j}ߖhjWEZ"&_a/ @o0,_ CyrC’9\ TO 2d\1sM4^z̚g -kBY}*EF/w?˸ KNӴT彧SM9>p7oa53B@]qxq̡;-9)vԜX˭㤳rE)p޻6dğV'dB}ZZE1C||J2+Ĕ q+;NMZG-pQRd=EOxf] zlc$g^@yfPjV~O㻄Qn),Feh#ZKH-BsuN̩fNi"Rj;8X†s> e`:U婒drC\ȵĐtم.z֣ xŽ{&4GL{ #~2HYuN$v0&&iYR pXQ% S""(t1K]8A[Xo<-,zb)&oh5ܦQ19-W{n!D7-Fj3Y|΋Bn j!9Z4]q(mcTJGK_wC_;cewzxDr'-QpT0jۆܬɋF /r`Y mh 1 I$A1'bh13MD_?QҊC H E8z7b62jD%0Ms,9hVc%&aQwRUU(Y&Ё=VFFAo t*=Fd 8N'D!  Ef$Q +GI{*< p|-:*J@"C|/lAȪ/࿢^UYbdOQ?N\Ɖg,X)9\1q}PX ޫX!mX5s&:WH'KFҗ_FW'Pi;kVb H&*_Ӝ{;41QKt"˰w;5QeZg% 'D&2oBRd')$F~$aogeرȞjqyB(fv >{DDމdsOdmʣSUk 5Sw).fĔ8p7|$KoE n3-HAeyp[35|,jي! nAtsw*AI5$˘ q X 'Hy(@.m!-ndL38D L.G6. 0؅ߕܢGd-*=@?˭r$.Zs~B?dln$Opn8`^:̨X@Szjta߷t9$q1=!MG%̃U6A|{6C#?lE=&pɻX8cW' y|n@h0h98nEfu5¨:ÚP I[X}ZiV5S!P&"2+3IL墦0@vBtV`LBhgNC93L[5h=* %b^c)D]eQu7XKWT*c52¤MV*.&k!E ;`.nb?Pnz,$S]|t$@On hF}7<1 &lyddt W$NC%f5_F F\PUl¬@rF3 +]2.C'CbƀX(CL߸7CsA3F< lg@oajhM, x, 0+ ,n(zW+,Wf#ȶΓS_6Q }N]?<)/BG/@~%;I Ÿ&W(Pl'#S"p3aU -ĥ/_NI~TQzLZ)&8f;"1ߢHRHԫJsmdLj+qKt>bKHA!uwNԋ>X>P0n>[`axh&Hʕ\@m}@_HU"#$c{k+n{PR,@IOaĿ;r1b{v.Ld?,%Bp)s4*:My}WC%(NctG^ 翗1o*:+VM?U:9iuJޅ0)ʄbTxlL1`)EFtb5~(H%J7!UߑFSL7t Y)d1U;|͇$BoN8ZGD˙H$ƕ$,Ye;\B*0w[ͱlCWٟVӈ."vQ3A"ZE"PYP*d mX".eE&R586KyuF%Zd3ƒ βJndP 9٧.R޷5)$?= *2nOfY e9m!f,'VR2fN+J!X)->$[dzcFe3@]Xu!`Lذm5X&#=v.TFDlr@;uH?fi;3, z<ϧ[xd(%7qSf_/3s5a3ng`@9);܅2+ŲJq-=l#su䰏Yng bnߨnຽyo޳Ͽ{Sp⹰qPY; 55M&;DBfIf\yQi1(̓ H4xb63ȳ$q]=md%-lײyͣZr!S|@xLb8"evηXx險a$KP6b.U7U Fl:P=jF] L(mqۮ <9yeP  <\q eW R̈v T-Pyϩx9OJXH]96AHuda!'WTUHFsOC[j4-O,M314+ qCk*r=- (XEjдd ݎaO.Kଞ/OA%l<#kDvɦb9I%[]Z6 l;Y-1sܱԶ:4MɌ aUl3' "Ke9%y]gmdz}FFDHtERrlR#K{r=RO hz0FYjb 04w_.+ϊuĞ8 r\0r_K{~`yE$+U;ڋ3?wNn Ii/WF5d8[ ]=l`uKĉL3ʺRrtPz i1vIw \)>FS.Hrb(sSgGE2 U\84ˮsѝr*MEDɴZ--iU#OI8rNXQH&kAa& gƃL^߼ᣕt$C&s*r6sjj[q$#umjdMEn;v,qɔlwi%drS7CAyˈ:e,xʴqc_bM  6jOWKY.;.ڮvG.vaO˿_o˗I0A]wsʻQj]n-/%םV:?Y{^E9-+f%tܳnβ?/[ v qTr}vjjʫcRv*xt`\=\$]̮|ҢMk#HS^JeQgSElsRl(Lܚgfʱ(}=dn 7T)@'w{8H ,x [[*A:g;xz&3nD r}P1B =")i:gfExBx% @OCH&nŮk l8𖔹2xBF014\=˘rSM]bȏ}A3?_mȎP^4h~8Uqm!HPh'4o:Of?$$*Xʤ^jd|ݞT {1*j{'\rHͧVyw,^6hn%w"= ;v -!D>:Saѓ&mш NMƚPKV'GrX}M:*ND A_Y8 mcKʛhKb=fa~e63tKYvMbzd@fKF2(F]4}2-ݥCB[X7ܧ~1B!h rmx~͙4SL%͑%Ψq,sAݏ%I$%eq7c:z VQlPBj|MJF 0X2YldcH,A$Ƨ|ʝA̪Q?&R4E0zb>UDM It V*lx- <:2$7iBXb8g|CLQCqGiL@ڌA1)d{4lwoX"z g`SD (( fY#]N {:JiC/c”ɸ;!J9_1l@0HV/nͬѨr(:RIs4ہ7f1ÝwL{| l%Ks]jĞ ,#<ЩFWUB7rf'(,PV!_Ûb$_w=jOЕ趩g PC7q(J@OKN(LKuWQ;`E?}1ZQ WϞx-Ƨ)\ =/_%]42 "viz@h__g0wp/p` \xDJ?M](˨_~H]p ZWJ+~"@Ə?"Cj@Aoa4z,ڴ$f{`2C r 1G 65|<M!N)%b9,û8]@Xǩ+۾Eʑ"Dᅨ1ՍiwAQڡ"hydz؋'z3eg3DrM~ESdGxqz-)h|$(>=2B^MpFk붍Ga&D`j!g$!>ۅB; d] pDp֯$ED*wt +RPhYEB2V &Ӣ1V~3Z_(}OktG޾sGT'd%3"!8l440HѧdGM?Y'$CE+b66-ߋ|ɱ e@~:+AQ.~ٮ!1|IRJ2[YO3'rcOvayVZ\'%\QR#ϙ5/! R0pBԚ} 3bEIQçwc-) TKD3zb'~R/nRrrK0p/cZ @5GOA타h _"D1 ?;+Oe ۦz>4vGz#z~Se x;{ 5>*87chGQˬת A?*tpiFd=CUhEL&gk1/b Bkyh 7xկ6욶0b,('>>m݌lm=zs1եFh"곜;؛#A<̖e. GChCINc E*(IH0lZHg/ DNF$a@Ln>hw{[VQ_qIe,EeĊ=?(a5ݝ^ث̇:xYBۮAt 5m0  BW|OoB]!$;}WB߲PI@kKM$طMzVjWߩEd=bUĀ|' +eL8Ђ$(tbw( ě~w [c1h*I0 ^6؞ Xr3FɴW6 4f2RAldĶ%zWqee6$M:3c~HBm$e<<W,xP ur|,Lj:kj)լ_$)3@%GFv+$PK]oWدgŖQ 9bNl >c-jn}l4GiL3 ^F)138 1deG'M)X(?ϫ*J,Um -j/ުDtu&-:Pf_'Z7`uCU 2_eY$g  FY1|r^Qu:Aqth>k}Ẍ́ 6X zLٵM(]Y7n{u ;OK8J:82LƲS×1=|ʱqZɈiqtXO"`u2$ei& yAd%/xf'`)K(v V4fZ#o;<&"5mRI^kXErF՗VAK߃`k#EȽ3SR/Vә Yx©1Ĥd.G⦬P"=TugaDfOu҇pFc@d7܂ۢkpd\>t+u21 6hBQ;*InNLYiѯG;R uѭ@tl93?ݼ|Z,xs?2U @sی+wMlNIҡyꫪ}@,$Jg[y#006X< hE2f%ǃp4co Jktkj5_rbXc9`@W0o[F}/Y oU2ҵp,KZ5!N o[AƯ|ifٽ>x'h%\IWʯM!L!,׏U~T Ԛb)'&i߫P2S9ϘiԞB`1NK%9C,y_c6H 2C|EtDZrz(XRY7ȏ~]M[g'$'$jzq~  >gV We-bNBgW.Ŧq>FbvV#M1CA97zW"pN=!$ms2<Ϻ!ʈΌrgz`JO&U\=|wQ1]YR9# b-[ؒL0+>Ϙgz~²ϫ=x0ISE eB q 7?/XnH蝏oߌl_JJH0\n}J$P?I5YD?jSei/Ni tj>oaO(`Wrd" )Hb8@+3qCLz;zaAħN J¸CQqP/T& 38na(9b27;GdIWq'l! X)r!2KfD52S0X3k1:=e ؎/ͭȪbW23G+C|nV?$\!ArF]\Tz=УuJέiaPӥ(դ85&B ~e1Stl?#GlocnrPZE͗ѷ.%J0h:e%5 Q!A &D4b&$Wod=9 t[LMilelz2%:fTY8^&\q_Gw~A3Bd!I/`xh4}$Zj @5j4kI_sݼV@5б?a]=IP ttփx,-xɁ_~|#FEiVجvCl2pQi5ȹscXrr++cݞ!fVO{L ?XtĉR 1?/Qg>~j8ϗ&1ᥴ<~6J2hOHQ}ޛׯq~ ΢s(ͺV0j_1A ڡ~,)DVԢ>2;k3ff )D$c^`.8XfӴƏeaHm&aC;_ A[ K\Q!KeQhRF<2N'K#Sv6qOѲn:]*Rܡ>>)=$}ιFr5(oxu]bv0Ayi |(#^Lkd9ǍdI1AFF h'H'j>o;&D%@|'bey2S{s>"%-Y)Da s:vQuHx^BC;[v]@*_9d #rso|9<_X`2ԇ:)Ge L$ELVpW4AWy^(~@R g`i!voq7: 8bvF&|Ԁ,@dbݪě>fz (7Y2œ!)Y @-K.*a; BTCfx:lZrǕM4JWuA\TG |ɰ 3n5\!IaMa/SoB;ȜG\^=베oR}S{_G`Qc߉wĸ~ zȵ-xl-b./ő!⼳]l[)Lݑ.rᮍh 8AIb9+d >s킴 T amED"`9f'Dz^/6с } 09”SDtl#=b% I>YT+C`D!I qfކiG;+,Y9FGi4 ֊;Yڃ 4*H?J`\Yr^ &ƽ-WVQ 9tu{& P% V!ő| +܄p[S&ܛ$dxW4Z!  h >MͭUgu,fe0oZ [Cuvuȶd(b?dM'VL0-it#K EfPS,G\,ֿ̉󚗛NRK?+q` H c%}I]c8҂+m`[*`cˤ#Y3&REmbD< el ហ9"fkUr]㋉Za@IDAT+QDw9"X~Z?F .TK֪Y6%Q'dd$$MwpWG~ם#Bݗ#8fKQԜ7m]h3[g:eD7xҹuQHJϓ@/ _M="%BKFlŬ#(ؾŝϯoGƗi`Gw`$5%W}B6ZvFL H܊ "?f@]W:`b\y4Q㩨m.\tj ֩avmL" 1rr9_\qd67:]rf_2WbP q̷+6/_ӓ' LBZҩvJ# 7w8٢l&L뛝O/[;հ}9&u0?'DLדsnf}'w6_=JKY U8+]OO'y8y8lNX|-s| !! :3r2`m_oXwBwZj9hgF0V6M@=:`腢A:}y]9Pg'VFLCe_״5BZ<>ض_YrRշ_5R}#L/KD:VĨWZ_ηޕq};/W 1"RN8H`=VbOu;taoP'y~pD{D@ANZA\7r҉#G*j~=>_NZ 495lɓ?P>G65SyawN7,Bf~>keYt38#|~V~L޲脼sqHx89oA'%b(Irb4! 5K{|uq٧sA^_ԁPXaUgHUcQq<QlWaZ=+iBOTQ1m7ϔRa!ݫ_󍕥$ )LȲ$p~)`4NC 9Hg,  {?H4R8 D_>nX \7{rUu݂fQ5D jߟAAo(۬JIfw|t)D;5icBRVR#1HOqcʰ|8DiN51 RaV!S'j,=k{T=*5arOtt6k_&k@?o5yW͢8ʈqһP3WSrЂ`_vTHSIkOj qEe@tHr;5h{ ,yO]",c23HAH(e6[2C xՂ[!J1v瓄v3El6 M$F$ 2Zi[_ț$0yoGT]Mt]t 8[B'GzZ o9[Hm74st՞dBAf曜Iej6 ֊y$ْ{.=G7^^›NAEP3%ANJ, W$0)ӦC[< Y?t,[y[f[ |W1?{Sm 嘣t}Z;ͮ `A ?DOfw;r]3]DelA,*sƠv:EKa8㳳߈EkE5>_ \G5X)7_(%*ö;(A#Q v 8mIwJVrh8fEn4)f:'3{iw އ/W1Dze Gׁ&Я#N2"]3LS(V8e%]OK\s]["R3$ DW0PR;ED`BŷmBEFwu;=b֐B75mC*r]q:U!ceETQI7_LLayC86K+ql8nWxpM/IB9LdLVO-BP=ׯ8 ) P DG/+%+Ƅc&dmx4pFj0tfL>ܞmAkCxc-P-ưp ?O+]O- & M.BBmM\AaXl2.#?\?>V62AvLlX=k; I2Rf(BMTڧoPOqxEFt|NG4>)e.ȾQ1n6œ,+@V8r[ͱu`6)uMz9 42CU A]M}i1e/WTkHB Hp1I17 ib HMȷG^B?#g)BLNy]P4V^ &|YiJ+*۝R5@] @л(+vxoC:\^^5!@pie(fM\Gθ#--U9,=W[DnwFvՈtoyx^Z=Pk<<EVpI) J4m J&06jLBOt ./b>\]`_F>P$jBx>! jt13aQ.ITJ4]"-q$T0v^N{m:b948dӅ+9HsB#@ &xhQX/׈e,vU 2Y@fJ@>;Jlyqw#o9u J izfwF?W荜ni倀zs,{=TZ_)A$x!(cn2s,GXip!=̝ P&Pčf=9+d?ȧrߴ]mvdk;TK[ИjFoKot눢V<,+ĵ)"-,~!9{߅5o_1i-L{׊t?yIV7"UKR!z*q Lj<@Rлeg\MtgC_fxRLApcS!j< ̪3$إ9i`,}9} Rx'6VK wnpzk!QΠ/ҐXmp!h)P(al$')a/Oe]/80jqH$5+\n~^Tw[^<& (^p;<)wmR?~&x#2&[(奘f8:MB}ٻs"+I$KTO}L{f4S! yzQ0w](N26c@ɮ:So@U#sH/4<0RΒAk$19"_!f{@MC_H3`)gOA i[y(l2>DSi+r$=!(D0TE6CDn5/TK­PT "4QG3ߴhllFVZ\#J09CS3&uS@4Le\d3v^hd'ڟ(~4o5B(8N ^2l锷,A?jɮ3Jto@f_KOf)Ɓ̤檱P]InOcc.&brfeMzĦ 9*&JU#^ ˠN+)0GaŔ[mEKlʳ@(8ecu.CrZ )>#D!@1!!bR# o?"oeW$J3ĈP|8 @1dşxrՍI>eba)3Xad4_|T)pTlշ*@ةBȰYH'~=вᅶMF&dgCz$˜0>>ֽ7ĺy962f1w>pGۘ9nP4 M<lD`5دع*Z6TaSi``5r .pa6:CF ܘ° 8X& 2"1؜zMk0ʄAʓw24zF$KZC0P/b*Qo 'πʌ\m#bQ͚co}!Œ-ilW BlDɹzݿHJӀ"zgRHećB0D_rUd;P1xW ?OWa(邦AHPV&,CQ[M!lZT<:ytDCATGB 74MuOj XKk׿rRM$s!O!#F)'+xDwV@C+Byxi<_Α mO]>KVa]q}+H2.,F*A#wIT"]҄=N10QY(.Bd$oXsj .hoʂc =e; T# NPT8磨7@(1a3a%ӄ hxA#)zmt t:l ˺PYPxF=Qf=֐F~24A.暈u) 0ء-| 6;hj rT,9H]!A{Y)oP&L08Q"c&F~y[\)J9B4TS٣j':`u:r?Wtя2`Zl =m@{KLWuܞ4'm>9؉CfHub|fS# <$4!PI&Wj3kmie4[' ͡1B z5=CBTIL?)P%|]OS:O (p2f<LJ U6g'F)C$SpXDB1 ,_i\3w#⣍{,7R/ z~ ы4SY 7iN f0>?DvZף8%C"pHv]s^jzJ^DS)MՂӖ |$]3ll -6ŞKr|7Ɍ F\a URrg.PfC$"N(s 7fڭr4!1-c!@5 ߧ]Ee SK"f'A}Bۘ67hЮ@!$"_<Ąhh ܓ}GqD(5c+fTkfJpGaB7ZA5Aώ6|1h]pWFU."Ii$$w`z45cK =d9;n9PRujJYdVO-b@NΆhR @{w:W A.ͻ9x.n%CzUJ:uģ8HI1"*2(,!w6r2Kb4`eCdY>+-$3f*JAMq3(h 7t5XPP4;q d7N<]VGSB &"3=R,di"sӮB_B .> ^I `N,.;3Ɩ"8wnmQ?$;(Q{ڋTf\JC}mLb.@U$q M]<5"3t%҇P]Ohe[03p_PU'@10T )vrBNәh /I8]2ˤ;k{ss9M"M*gv?\o_VtcPfI,} r$JaQ%S 0BTچ?4>BC r`j4&0#)mÏ"N-*{=#kWupB4sM$DGvԥpP&gYoՕCwȲwa cA“w#x !crWq V[a$$݉@H;3Am-+pi"g2h%KR?AH:ϼ𠵦ȝ|ACx\Bg5I-p nb6;߈B޲ж!AI F~%YU(r^ ;ƙb$BC^\ޅ E\l%jƱ=~)66ɣ 2\ΗG6w|0Dӑ=,Q.\ 0y:w'BtKQ S 퐩/~Aqsԍ5}8t;ʑ}K7>˔PyFۗe4blF2E#"[8OLF>$p3$C]D e}V'a˖}>3aX.X*"ҿy3f *󣷺7R"$"ʼn 3ߊ( a.\s+Ffq-գRBg%6(.%Sh%B܇8|mHBC'KT]s ˃^``>|*) 9A$GbRHbXdxljrXPP=%lKEpY_4xE@X+É^{9"~:e3jSI.b1-ܯc)4{0 JcTM v[Sώ&~!gk֫]BӃ _-5NmTaX@L@ %S9kfpdK$?ό_caD(O-OJT#(xTmיޓev"P$6f$*8U[CAǷod)HmM}|"nKY MalXHW:BfآŹÃ$ K7(I iq8ӊS9V}eʩRd!4?sM1(eLyѓQ?/%6!sKPzQ`-J hrij. Sc85 ;X*˖X,tWGi@|ƌc)Bq,׫#d[UgH$)Ӕ ŀIY^DLJ~9 ulcb~Vg6 7) #xD&c.0%A[䥏bTf`nZii )kq2PCrc$"{Y<D0"?uޅoa~ D"F#zS4p.#VJ θlrr.J1SL4&7rs?lP${ ĕݏ4mϧ @'{'/ ĻU\J|е!^F6/b殉TDj2U%f2 kד }@ w0^[$Y6‚$TSQXRqu0"[ v7:|nZꫜ`+"1W^B]@L9*\*Nju=^B_us/6JlK̞ wۼϋ e9,*d^يCn)aCc(yD"RUr%gûPyy֦0$[^>>gɺVIϿW@y[Ýt]<bƔ$AJ%Ap# 5Ymb!j5PC8׷{0)h_}~?DSicCRD-?tѢ0 Nd!؂z4NIc Yd//o(Y/6_?n_4;Q&%g*~봦7jYfK:y٦T??O{CkG{مDn+.Z'z& _Πb oXiT 2"TI~)}~ 䅔ܖ!d%Ciճ=9PH $[PƎeg&g ,@4[Ik"E\ ]>IM)O}sf.*NMD4Vw%?i"}ۥzDjBdm]ӎ׵"Jzr#,\!CLrWZ f0% @.R-$N7>ҵkȳPpQ FJϵ#o)݇jRnhug{^މr)*A눕gqF9ael앶G`GwF"F7)<0fa&$* "jf@4(B*$hqI3@4JkhɋUlͬ!µ/h"3"E3ʹ/BWUwK3Q=&.®lBI@_:QnZ@#LIc$Ek`No')J+#t)>l"'Yw!# tq0ښI.Rf/4>H=+b|-/5F,RseF]S4 ,@pNPlvX toԟe Ƕ1"OTc>ץ =)GeOO=;`AJ ={ ]~;,~3mJYՊyIja~Z V΂ F;$^A:ˇ[ 9GB-Ty :-UÞDmXB \KUb*yXVϱaEܡ:֞ȘY- 36#:ԗf>4]2|#%"跳)#jhF Y}Czv=P68K؎Nmv rt[^gwN0'XnmqbOcyu)RmPvX)i¾Gq$Z*:~=min(ps;%& U9"ʞ?lLD{Z;W"aR._!!ꝣ(/Q#H-C3YBQ$#Wd9H)K( 1& /9rVz27=2F:d2@$`gK`xz6*-:#&ᝧ![ pu Uͭ[sS 5rTJ˿[gK[01y5G)k#-Sl9n /o62FhAT(0.=;f `i8DFߨ钐_}L֘ZE""N0u<ւMA8p"nQ?H8`HIR'EDxWg ȸ84bdhn]gu`3Hˑ2ve|.8B +Gn]4`FA/f ]D C-j,,= S d.IJ l5G2ٲ "ͮ3]j/`$֬$Z<ȉ?44l=Ea ci%Ia(=:glwF m_)p"8Xe '+ xAtй+gU}#ΌGOUԊ惮s\~6X]@,1S`gPAQ`cW{5P7,W .p7(#I`:Tv(4si<>x1DՐ%_Mm[l ?ey'2/_ ppDɁ!E!6\||<#D/Rnn_Dǐx`#7vzHA qvQHsxS. w摩">ic'ňMS"ez^}}{~4Aܪ|m}P'.WL'uYړG pymxoʋ/&]0#c>*YboNAH%*tᖥf襌UV5R@ &qO'$e 5,Tql S=f 4@ ?;N+Aܛ[rL@bqxC H*eb&xy4nH|eS2,(%F ۣ+.€X Ȧ|M#1_1rgӦ P!:3 lސd$܄3 L ppQugۍ$IbI%s5҅t.i2IdIonnAAK"L=gfAUi|F,@ti@$jY,|(cfcc:p00ף#/9 ̡]-]AڥSe81H{Qǟ{.|Gc#V#-YqWr6Rq`%bGBG7.[:͛0K, d杲j PBBގR &Μɇ2@з'$⟙|ܹk&bsRWìR0pMY.[Orڶ$ h@o.0sxa-' c mGHXB`pncZ m+ BR:bN -z橙gq>RRW]ׄ>2h/׸\~"dZ+H+[$.J7\>7!$vZfF_{oTpPC|lA` 2]uLz"2' 3`Z.q5dH4SS9*1k5OcB? X`l~q5dkz@E5_QZ+XjZ2\nSOHnNvUӔKsg3ꨂ2m7M,A{61YD1ɐU9W[VaXPL.MOѴ^̉]9C9z*Fd昴dfb(A6! x \[H|ӈHb}~s߬+CKa%M@?i|KϢ8f#c$jĬUYKL ;i xRR=sN or#ڦ2Bʴo*%L=JZw0IdzDWY;?9 M fjiq>K!3p7#- BHR' pCxHћm+9IĪJZyx@X\֥|?6M("b,-zyٯP,SHci]Nd9U0YEj)]?X2n)לD. m:iE_N#GjKM4{y ؙNP].uQ@-څ$tb{~ZW+ij03OIHĔ. HPG@#k]Isc|) 1YqC)2;M3Rxh^X|Yy6kύbi%ANEJ8&F#W*&e{ۙN \c2ΗPeYDPj,ez$i풛+OZzS8 'HGrۖ L*5Ls-BTL>_O{} WӶ"w'1\ɳc@b S$܉ԡۢxL9B'XWOFg9)Vvu 2ĉTT43fs܌tكhl6+:9=4?,cx0㶣p-ˌG^W%{ǵ.'+źh )x1K`STeyѰնU=7-90z\L5GOv1S &xRߚ 1l żdM0Gܒ~|Y*W!\r0ft)o7I`dwlgb1IV%:9!E{EϦ- l׃޹PԌ]<20RT5JTIrM m*٨l=E8 b&C ̘S#H=0ETduj3%`ϬnrETT(<4'Ocl?:}c@Ma(~tThLHHI ,<dHVi mP þ^ 5b,kMxAh;Cڅf_9aq@c|9 :@>p}֝9l#  zH/lo/ "D9##ڏ1Ѱ,./S'D١rthHv?53pW㔃FzvD)( Ľ,2҇X `j [i@jMj_u:G4Z${*Dg䞅_\Wm++뉜fx"9>A&6wխ,Nwo`+bi$ kaNER.55XnA%12Q ɊzqKVdС N-] \ن*x7u >>pa(5_[E͚+cTܛ]/u ʡ 7lz4ӊfhb;wW;te"&a{]Ǡ^n]QF"L&x0n1op-m݀%^A] xLμ:6_E,#&V_*YyJT`"0 ڼ@IDATB[w@^Q#ZUCeSFEm:\9I\Q= C!0@~=UG %Y)`gb7\Q*w q*硊>>2ɡ%9h= 1::*W͎#ZP֖HSIv#Bl323_z";yy7!U 6tod$8""? !8P7q_-5ȇS_6bj=q)> *5{(ltH Ր$ō#^x%Y}FMP#YhQ8)tqȈGIGċZobh՚$DlD2+(\"]Y]xC6d}zI\O0`bg;t xBPMtSwnKPP`˕`Ca i2 e(6&㝔,M'1sXBkp6ۑ8prZ~-$ C^{G1Gu8aK{cP$lv'ξGH[ e5));ٿLߪV 0L)o f,횈({zŨjb-Y}URd bE ˽Auo]:DN]l մ u'Z^< g}Ýxi&rE|La1 +jߋ/c ʅHdNfO\ jq 'nokșT3Qn oPA;ɭErnr,kSSgK lV^ei,ċ䷲dtQm4o(-b!~5ZZ];mn4#nyJ17.~22 3*jk9miEi0{{/9{{_G1Y@MFz7*TEtԖ'gH D<*-_,5$XJBhHVadbJgOl:@b %Rp'',FeV.t?wAB5ZI%4 ^$*L;$6pɪ= 0*= $LKsX!!$)TJi3'`f#,[au ҀUb- &.)' Bf8}xxeXՙ,|3fF_|j8=aׄĘY\2(%6uXlVΑ^?UbT"Tw7)vl5@0v49C=dvkP B_FC- "BpB!/%?O^4 9 (r;)!*!yW>9&gc p CJlEEQ)JBvbn,Z&2-ZՓ##Kƌex:1{x$Z6s0c !cw4n a!_f)6wwj6x.xgȾ/RL=7_1F ;զ6\Иfeq%/q[ddK#Bē2yYpX wq)!pbJrq>Q2Hc"pO^Dt@3 uY&9ˏA}mxG3QɻyJruk08^e@웏?V7 4<0@&<#9&,b%LrW΋6[!wh\>h͆RtJ<܆ccפ]P\x͖HΘ?X?wќHW舛PYE8leb4.S(W*?xT#I..waK`x{n>aE"REǁ.9؄y9#1ytWřfΊu[gH`\_1ȲE cTLPf͗j(NpĒ*q"0FEII[9sЀ`C,Gׁ0U(:G`qG6ީn k5` h[*jegɤm$Q'(3԰ WZ/\&(%Nf>sQ)V RZh _m$1U64T(f!֝*1Ξ6=aVAUuT,l`U)h^9 5å21i-712){Bx&' ,*mlme$4d@r^4g]օm:/x 򢖬;1]=݃:.$9L.LȘ5a2O,=c̔]HZ ` Enw8 h""K;9L 긄*BTI(F,H:B!F4-d{AQ*@0Y!Jjh4WmzxB) W3b DŽYj MLh%rN#3mF8[/rj|NdkE>Y1N\^ 5vyr+tO,LHa}8c v-W1ogWq8EniێJGM$=۾u} J Vŀ2`PC "aZ X#1W0` qZ^H2P1ɔNU /rKl D` 167N]`!g!{eEiIC1YYj |/Su%j"4ܓ@Td:7EbDݺzxhO`Ⳍ{<`wxSg=)3 bËԣLb,YnCm-$H QV0LՊDCKţkLBtd &F ,1C?yR;;$DKPTE0 ,Sj1CV2y,E TaUl:(1Myi&ScS܊̊Zpt9 F+4ra^ɣ"VTj$k2l~s?JIhpn?Cv臯n,qr秣>2ޭÚV`n888Ъ2F:j1 E&AZ`pus-'QX  b<}e[p. q++$Ǩ)왘'ޟTHTI?};H]|[H|D[eױoqSLDPQV|FS QV,BCgaDly- y˽Nwx+5j)vb0jU21WEU3RT9}huGB~MH0l3 S5"3wՒn**jSz,Kn 4hi۾ҠpeLh)lx:N3JIF!\船[X+=#d=v,XW@`uEHb ~ZCJw @@ 7.]5eh>ܩc#;u&,qjڡKWXN'0daޢTf~VsLl%-1I!VnĢC{*. Yf&Gr!da-f@c@v[bPS^^Oi yp7Zx(ܦrxeأx#QWДU64,=!E IPJUa* _#+1>|eL(?/M%tri4} Ĩr0I2YM1,prCո @[##2ek93烔Z"7&}WI!= *b9Aj9]8܈@2lcFݡ(E 3zX#-V/4/EPQ>tYWcEuWyM9P|SO٫6BW: 9l?C;$GbbųO[K-=đFELqrc)b_`DsKIއJڤ;׻}Q:Z48gtMR\ _.ЂzZ*KSUGAW M*4Z\螙GuTi͓(5?#ˆГ{ š'b !]I=ԨքD1=َ˞@ 1ώdI](&kx@ggZ6rغI܌Z(z)H<)h V $SqNOKi{YHg<tۂCؤ((\yy&H'ESJ |*f]* 標]й0*z8<l䯍h<<rhB0t6U|gV( ;7"=.Ŏy\@Qbez|Cp-gN+1C#iB85Rf*|>)ΌGAlͭYY`wdPĭHirL T0+3GCeT]²M{/ǣr1*^(@X:XE#($"ql󐄲UT %B7ϩ&Dp1k!~PRVZ>x%[ZJy)&iyc|\~td*}V܊2LXϠ!4FrJƒ6:0vUU/a&8 TRR5uqBlYfDB1>G3TjnD}zQ:9 - jOdQT!JWI9r4 GdYҍExņ~pƼYyRЧ 1+dU*`$"(L*72N;qFn=} Qx$?/73 33ty+` # tS]A!a ̊_RBA1{BoN€& ް&[^b+]uXBrS)+M3)SfH  q yE񟘊vd|~&`w-A !"(,'tWz-|tW90+= $ V$4>ĖƷ荌䀍dC[V `y\p@qdwbϚU)C~ }?[|LHq%F |{; -_ !g&F6Z[񆙻 n 8䟇,p aЛ bѡ>o*yu0^V?.IsefFs\1 ,#;jYvd%Ce:91mC$&3ih Vrh o@;.0'ov =w({l+溱DDd?DdTJRBepeq ky,ށ8V]'\Z e%շЂRq#LCNU` %s2 ̇_"h>M,T^Bh?΍i{#O0 5 .u/~x5?E5鸜̶y E6TȥQDiw.{gv˘%T]Pe,rxgC(T)qfv* @l=NYV=̹*w=ϯrLdZB=&-Nf)=g@׆LL[8+8 6T`TL; rB2Iep\:TXZz8Da&yz{Jr Ay4Ή|@$d0Q9[7<:i1ʕ.gbGХ391B$zK#hJ,bH'K;;8;|@߂&rvy](Hi6fYGIQkE" ݲ%-kLdȮcwWI )<+ɪ0FtNrBмcpj>=ە̒Mt?j8CÏgbI a#- [%KP6%_.XT+uDi$pEGs'GB+; vS8,>JKNY'[xI`#0rh(tʋ&e4W#n'U(L<$ʙk_uBSqA.^Rw|:5_Nmu(91zױ.@+'0$PS>9HA6}7BQP$`*.mh\$cP{qv)WG qJ̠&GVR!70G! 8ݶMO54dAd$"[߀x,1sgZypY9)~c!#>)!]Nk֮օO qo Ls6*Ғ6^u7Y :JQL":ձ:"[P۔4{f{A>Yp7y_v\2'ǵNU4T2he!+LP"@'rV߭^4 ,jQA; c:t?H ٸ[+[{ϫںuϴ#S/7lqa@BG[&<ٞ4q0 Pa1:I[=nߝ:PѾRg zQ0t|CXgœ(<U#Z˶(zevIh iJ=:CiQZy2pNigA Ml݃|9+eEja)NW-߯6oS􄘻mg>>v;pCRvެ]@o;=kG}^ p e+:TU_&"eH`$%EV|'V'~~y|҈ ߄A;R8;SKV(V|qPbՍ6)1qB͆nǽ#q;Ԕe]p,&AKFRP,&VCS.m.qI&s٨=%yf'IjV]++GD&H'!o %QR2i*:b ıYyʦ#L 2Gø '6b(5*K, '`qY6! Ifܞ $TqOB(0J<_Blۗe>ru wi{.ϛ|$m0L4n}оa2 ه*QW>K&kb/iU&7 r9\Z1v"E @$"0y7C(0tӋd x:u >9uI >rN͖my5U2G.b^=~tABmBXu\ {6o)te@:{.@}g>ep,„A5BWMvY,dA!)YD I{ø/~,Qfv8E.Ckwd "U->"MOΑL& }96dBAJ80P>.qo߼Tř|A6&Mt|Mr;49 Ą3IQkP>X %wd3_<#޶߫-l:&^Q#/8UsPk =e%J SY+BO #;s@T9wCuqZhhҐ-Œ$ֲ#aNtcB%9@\JDI N 2 -TNPJH4kDDLbpIË5]5)[{w`77?"2"gkG'~6# K)D3?J N1WMPmfߜyS!TV 5Y|֮L6:}ѠW>:ޒjib^39 H@Z@W&ٴt.8b' wD U3EXa0FkCO9IB{)?l"A?Ěk w}: 40L@`{ aWX2:z D0`d2OgVyEu B*cuI5\Dq5Ƞt3~*H$,`,Vk(k(tL5Pf"j,_z?Mg"& T(ݔN6b :|x+Wk!= xds I$[XKpZ\-fyV'[2`B3;{=Ȭj!>EI57&<ŪfLk6@q |9wk~EE>uj["-= `r=TX؋"\"^ i@mV?BlZ&:$8Hf>Ȕ)Fգ@; LVS-r ry;(M;CKa~+ʺ|uI,R{j,^̄n$2ȓ3௢OOkngq|·Nl :!qxG3ד0jnd:Lx *,gJ=Ah4h c*\-̓1@W"!=&d ="PaE` gwB kiao߽w=|E2ύ{[9@]C=H#\[v`™u&9ߜ9ΑJzpt6$*bQw\g ߿ڏNfPO0גC$ˉCźaE"\nuHVĔ 3 ?7)#S!GLGʃmYťs#G.MJk|bJ0ΚUM86VuAƈBtX?zq{"{^?f 2@Yv9`W^ha0|ID8x$~B$LPB ɒ~Ck@C Z2:X)R"* {~kEdS 0, foG+i9GY xzBOmr&:=zdN{`rC@6"ݖ؅S2Bk#7ދ gԙvYnz12P$wb𑩈yXjXDD *) QE%@d\z.qq2`9GCH46͔=(1BfV2./ er{FbbnT)RIo-c$IC h悙So-޼vjXP,([b/ku\]JM &O0<s|䛡\ٲa94 JqJFNj̲C1"c-'wϗi~$&-s^ApqeaϘX0M~?}ʦY$Vlg#?KEMRg1{"Ѻ1HU`7+n, K'n#BLMg͏i–JyUS20 !b| A}1!YZLE6%`tiD! slk%ϐIzMF v ^h&; ܇#TK# (Myo#-7|9{| JYo;Ks`͟&9ľ,5'zz'9;W<~6߭eȺݔ$9#vВCsq fy  H:U]c!jx(؈U P0FA% dT-「μn۶SY%TBC 1h5oCAқK8A+eK^e8#^v&ET~[/W2Ax!hȩi&X1#^V1!M@J=J8 j+֪@%iRh%8[40!Nפ<@s(:ڼ)|0رK7&`a;PP6kG1N/o9Zt Y/Q'Ak=4LR $dcQꙅt0:AS 9wޯ- \4 QӦ4m'LIYn -tӽZL/vOyQUQt4Sp˪@E$%Z2N,U}C`V#?+{$#!7 E5,iꧪ03_65m'Xb{:۪42:IYGn2@+yj&t9?2$BxPye"65x=V| p"縤AI4GsWjn==ɻ-Kh]23` c'l:HyžF\ JERkՑP0C \K\^pI A|RP>Rgռpw] jmǿa$]۴Z &ԍ֐ @IDATE?rH;ejNi$@8s(J.?(Ei>L%@K0/p".~Gk6/Ե.wD*X?h5H9]Q,&Mx{o*Ly P|1OM>U׺hL>o`ά*mad`Є12ɉDM:l>ਰ=rȑ~1c"]i#z@O-_\h #w\ZmXimp_qQmY'%~Wܠ<VlD3Pӻfdh K|֕YLpHl͛4WH(;"qpVg9Anv1(sspK(it^]{A~M;TH&;ߞD{qsTU*_.y9m-0c+5lb: (Đx69˥3 ?9O{Yޓs^e BW#b=R<͟jBT GjvЁjaɩQbƯ(A c*:[WBLk  , 3j93`0 #O2JTOjB0NgGCtbmQճ-ꜝ5BhAo+2> -&n|-g-Hdn_YcQ#ei,i-UĔ$LC|K R9&?D+cC]*XYYNi~Rm ^A&+ 4kTRymχsK&5_d@"[3LM&̸,֌c$(YĤG*֤^5(~ *?Ni{ 蠎DQ|n#f bz<PD 8W"Ź3' 2FP! [#=ElʐJI%S`I!<#4TNip+6/ntc$ 4@+s|;L;;s-8r[Ҁɘ;%12{maAWCO֏hmJf(om@2yWF3G$lᡨ9p@3^q\VaC"flR?~=]Z0KtI'2 /4R35)󄡾p9> jX{mB)fo~{y `|`H wq3p αұICܔ\EV6$2-M*!Y>Vtc$ Y2V3ۋ$ry =X86GSa&T<(ɄVxlo68cZE Q8b/AFdǐd B%6%؃#ip-jZ*Ih0CxUAZғCf>HcH(v,F)" PC<]߅z xNc83,$z]O$oڬ쫶NOk먬\7dű6F4lȯk^݌G֥',i'72*+ar])I[=|IgߔxfIV6>p%S~=DXUXQ~@ f?(S~JM(Xg&@L3.*.l?qVcPZun>ߊZW^`M2mPMCN7@& bE_~dbฝ`w[l~hn.GoR.=YFˈVU'Sv[>UڦV}RfX`[da6F"VȻzD àNP\0w유3j%"{f'`H?LhQQ=l᫦dj =ef<9!u:O8mFYs콅bzW{y~}걭Rfx~(/"^fo&9Q=>U%!9R-!љaSnnep,k~@ ‘|/<$nҹP #Уbg0fcK+|;Hwy?5~_/<8ŷܔpSLgZ]Oy3etbCIňeB#hw!mWB\"g͉Ţ>ѕRCRI<;My,Fh#8ayoX2zO‹3ۉZ"*l5 Iۼ_L0* YEJ U~719V1CTƿpTY|١Tl0H=qFIu-CX=wօ8A3HCA![[9ӤhCYdܭEצ2?|Y HǮWѫ(fcI26/+-;5Tױ'?FAs(uHmvegqj! R<؁qo-ZjlE% MU!M-@%ID n.sto[d#G6;`g7~}mrU+# $L~oWTy{yY)o'~y7V]U?M{۾ooPAdf:·ڗt<s0>X[|_4~j 2H}jNP1ujuw( .M,~=>>坤ZoUWďrS=\} CfNGZ MT<2(6y>q$և f $y40>hg'n&S5ZHǃ+y o-|_o+nh+9_3Npq }A*.;q x߿?Wݳ& ;;gaOHy^@g%oi%y ۖ/c'@؀xnMdv9? sLpRȾ~q t- ) /|>y.PQ&C6%ҥV,>Z^iIL~ )jKcFP) CŜX"ȰIpv ,Y[%"VZ*Z}Z܊[*}qN*ź}g@!%}|O}'Q I_/3jH %Rqud~YnSAzV1 ~4u@ge3 "aK-+O'L9\zU2p0JeLXCo](y&m6>iTnPr>#;n]"s6 ٺ!y#:8Xګu?Qp$΍/2YvR@d@g5R~֏g…t#~$wEwQG/ K8#hFhЕqyi\!#sKyh$Y^; =70H޸(0B.{7lw|ԧ0τ:&fz:t=+CL;!Y$R  B/wY8"{ڕUNsE1Nz&#4 <6F.auJ B ﯅V6CEQHmwBr!ʢZNX)HR3WÐيn) #I~bD|Ay^;/iRbmh'ѲS]G@ @AF nB]'- )vBd *VWpn 3$|ߕv-8ϡ;iNR/G«Tafؓ2 sȪP-Ge! ]r3ܡ#3ɣR 9[ i} A;6I|5hkul!Kz+otdϒ0&Ҵm@ߝ!L@Pz4ȕ:7`qVu%Qp[}MANaA7-#W\Qd9T,l>^7ryB5C>AdX@:uT32{VArl#\+V?`K0QE+Wbaղ̄_&D/.EY.(;5m xIf]|_`X:ʛk+.@/Q68Od]!s"vvU_m/~|Dam։n(^uhtu Ȃz$1^vi#( !?uK8!?BN+` |ψĿ?5xbKVr`2dn-IR zPm`4|ODxn*~"d<-(I,Uo|2PGlJ4dZ{5H" +!*g:dmH )s*:$_tosbPǛ*HGz#R&ԈZH%WX1FbYWOTgw p\}(£>pRV*1NU.Oe԰@JtpYR4!ɛ@KTBoHC)ף7Vya^\;bbsiO$¶@'[")q1B_[Z]y(ja *̘$jm 2:"<mt**p߲'%G_eGٳqR1ێ6 ̷9+k =eG*Aop;22L80E#s36B*.wpDOtG w_ʷe-r>f2rb,'VUt[kt^Wt+9?EM؛15gwp& PmoRȗA@WhV4OC3L.52G.`!`#QBMƮ#m R5 'O1FKxIm#HTeIP]I]TlQ6OEFO0VT\W`|)A 4VT4u5/s-L\?GI6I\0)Έ\Ek."Kn=4Ja7d~<JU)4Q7ۊ3PceFL8Ta fo$ܙdM9 #:5;gʿň̩!?iD%(༁RakFsdA_ɬ5!ffMwefag`[{B`^_f81C =6oh!c"p4HC2R UX[]u:F Lg:TH`c,XSr *a\:T T5Ǣz*,HJb2 AJhKtӅbNl~n@&H𪀀!g?ga^Xǫ65`|O BPq ~~iGHTJAgYX~!V/ e`hLUA切BzLdո+^_AJtӨ(?luEP-Tr|sg- -kKwuWƭi(TN~f]V==㓞N,,tMVF{@uVMGDeP:!~fegwU7_)!UpP=ΎCJۭ"44j4IoOZ_n.AS*xK$/{; 8$wU&o J_dJq2Uj=(`z9*u# :[U{!bl>7i3-~Pwt<)CyLMɵ@ GVwNcۇ:Iǭ€C'C*lljV*"fo1;=ZFuSh`(+PxQ)c͖&YYڂ-FΪ龗Fǵ.X Ktw; N ˪>,o<B+5#O6v'τ ^"*@zf5b\.pE>[ $QE,,|D(֩_HM V5AK#s; $(3s$Տ`L܃82c9#:ɱ  (WYg)̋\$q=pJ@'<2ANam^e*<4ϒ[n@!ބ" >YAD_' $xOkNy \LYɗz Y|֙y?Fh"a>l&.GQ._֪+ L(b΂F̦:].x`x*әjOFu|ۧ*l ۠?MT'ݬ2a٢02/s|ū|9_d6"6Q>/.J)v6!:ߌx)PmcȇjDCS;%d8 ,5JNH#]yE(N`` m @;1nxGX $ߔ)^ u5:uhJ37B *Zt8R֋ѭ%>}YGm\]0(DC$U^ " `u=QmTx0ⲫpju#b?TY2{7Sء=Yg,ϟf{UuV&D)^/ *HA9Jr -DZa~oRDV;m,EA cOW#*^{{(+QcZ u~0/IA;u4,-2^Je`8ĚWB6SDAN1wE* fz?9'",-=mNy`ap.-QДA4uCgXL e&c7aiĿ?=)\;!(R}|v@CQ-lx]4ňظ{Lb4JhKM1 |._)Pt;#yխ/]Me}''u"w#_:Th!H&bt ̰CNRo>)vyk/ϮBnV '0I9r7N~}!'q}擖xɤ]R}5#.QpNqt醧</nCn 4cD&hx" a'>…r!O[N:TF3!R$%o9{S֯GrUOǫU> 5pC83)2V\JH0kn<Gϓy4 qo_d (6!5g=q0~F]]jFAH8xyŏ(Phc4 z^6[bFGG<-[ -g;Kewn8/ʼVVӋ 5Ӡ+C ^.d[1Chlv̋r(S-&_k6ͱsEMP3AX/\5fZͽ/0U0v6M} hХql@;qɂYPdMO)*QϪ|xҳ,,1Ȍ =Kܤ}`>}<Ћɂ#>0!9{ZGہBb[f ]grp3na'2Dc30vň[qt?A;0"(%je Hܝ?x?l_}[D"w?VݎuCqW=&8~VJSL9Q4g'p`t 8Q,=dϪJ29yߠj@dZٻ*Ջo[T9h_M?$:LJ#ekQTsW3]w)/vKSrw/_)7B@zɝ?(ѱ~r9 \#,bi!I*O1= bH(HxYkU@M꾔"%[hd Ҧ`ܤzfĶLW՟Zab0cp`|Kݹx45Lۛl'rkZD ~|p!]њhj0^:O3oƙ(w>q3嗴xk3#q`<&AS@sp.h`iuY9HYUu15I{ *7<!bzŽ{?d( T(I9CʾLee)r7 ~g'ToNg"eL?Ft@@ M%TCb +\A%_QIxPpk6Aˍ*XU24ɘ0שԺ C!L\R991?QUl_vrfuOz7:bt%ݪH}A4q2ʙwjf{X;ePp'~1T)\_ʖ3tUXjbFdX+ d%u{!HcH`fabr\"dNǧ90 2EDS ]\Yntd8SnT KK ; Vc׊ 8ZSAP5ĕ+g8q-?]_ VjWLu鞇 w=>Et)3o=f>=~7u_l$/'GE h lHZ6?C͛yOKՔ"2ݑ%g+q aJz zyF5<S=;:}z$ʠa1 )(~q?߮Us}Ԑ59T4f|]T_NdRy=U̳s.! D?_ N%|,o['kE^8,@JvBaD2w8SFpNjj@9rJ0{N_=o;k H$v }s w!-N4KzQPJ)ԁ%5ᜀ}^~Ob91 6fIwĹHNk[y\s˓["/b8G|Z"P6d:p gOMKZnge\%S,]^ubB bn-H'M>M'qJ1y=@ *LC/x14+cPGD24+H(/'`XxǼB q>P)ȇ x4ޚ~Y3ڈ P_nnY_I֖] 9z[wIHzI@Nov.Zk`#9m.>DW˦X"\BGABI`Ygs?^n0.CM)2n¦~'~Tn3?@{OHju4Ň\R$d%#(%IN>6|HV–Fo߅.kkj=oߎmU Gu- )ѨkU;s?814b,%h{n"Maz9En,w"< % c ֐Ԝ|1014Vϝ\o'mh J9?6;KUA׷Rm<xbfBWMܰ'&rAL"G7Q>8Wyd VPy-PUR/H?ͪ8#O][8btzv3OR`! I"8 -h`*34'KD!:h'TIX(TWLp#OSR-ys; 8_U8j^x nQN\1ӵm΁P`,aXT{ Z\nְCd814?%@@f]~JA腲M>/b!T|0+3e!>/ P*ouI7P"{;/0(jN{0q+mřf/3u9XlG-QBF>qyX3U'CeM-;9J,*E1!7T!h+WȦQ!1s^ N+p%(.៯ {J" {7ɦd\k^_,#DK%Z,]6ȓHJͿs8IH/i+<Ȝ AS)_jŠB T ,2 Zٮg=A]$"֣‡?:f\ɮvf0~!!7gL8O[^`f)p[}J(?A[m"/Fƕhqh4HO^TfƗu%#DSD\N<$@(o Pd߷FȚq9:0UsD1;gwd 8_k"qKlҬ N 4S@h;mLf?&8D=蹰 MaM'·>dF)EY:hj~xsR hXT?3TRJ-L`Ưe!{z ^L4Ьl4G8B#+'2O؁Pt<i}_ ][wâ^]wNSe9C![1RjQt 6%iPᦖnv{޾s+NK=0md;wlj?G񚲇(PlW0gF*6Y!)Y[vfݪ,зO_NkSF繪5M*2qqYQe Uqn͓p6hҝ\(Xj=(4c;ȫblvCa.])Ⱓ=J h{66J݄EyiePkL+*%f,5JYÀ݅\ 0zSz`6D844)*6# r|r^@[;1w 㷡kPcLِ}n7  isxE or hK;tF(]<ȍqt9"F$$# a" d0ɜe( bFFxG1lCN `}@Bce10$j|DL[qE9]zR#E fbD] 1J' i y4X\.—;bg΍ 18[sSV!!Icb} E27&Rܒg(t_\p6 Ue@/7a*7Dg0C"$'{2L;B)]P h%ntd쒧0S5bōɨ!h(e} p:LJi!~Lӆ6qzQp|(igLt7ӇjO9: `yHF.f壘Q^4L\ eG s}NY| "%wNT#dTf9vkqREb'(D;頉y4A7bT;+_3 iSP(|uFfra@SjO/:s$- ܚv| w,5 .&[ˏ|5@~'>R3j;>8 =L>Gm3z& zֈN JKX7x36S[ Q&Mh#h<8Qŝ gL&2~ %2GՌoV~T .۠fW;A%Pc氂)K-U+P^$*u2,yQU]R<8Zp/ )R%n,@q͵q)TLxlD!I[f@>d+L%\qB!1.δЍ> #7A|d%mRzsi~2em(ܒe} sX}>^;ECDNU|`&ުh{ct%]@IDATZyjQy4ijї!l\<i6@uHQd,ѱXW7#;I\J<a Z3VKRx0#FcTfʽ؋ER$YrL?)|R՘ XeBY뉼B,-#䧉$iEn[ ʣb1~\JQrZBlGTAhr}v?/Oo%}hvjhR.:}$uԘ&F{7yD8BFdבX2qRcB-p z]SS1?CƤ4K8e&D2_48 )aHdB F]6P*#kz3C>LJKExmpR7xiP0 0!31*fDR)^* %]T>"'dmiߠ#F4GUPu;>^Pnq"TM4.xCظF:DK)x ga:5;6B`;4Ay " [Y.m;t!X⑌?4khľ@*XW_%3oܜa()CbܶL =cBK6?:`> 4sÃE5Դag>H8s-O6f2~ym9t,[(8葫]_.6}aEѐo.nQP mSꇴ \HtW;K"=#0 \zg<rP4lJM rF'jf[VYtWK{ f͉:iNJw_B#@:MN\&'Dby.c:J%LpZ^߁la9xqAlrP=5Y`xk`"Q NTϦ" 6--; ՊbF`9`@!+i0S[tF2cLFŪMejK#kmV~xoHPuG`ZK:;ZD*cZ!S*Tc()F(t?ͷ!3ŠoaKVt ̓/,5qW狸$<BDt$K 7`W*߲z([5Zb̍o"ȕwD1{[ޢʪYܤ/7>Kj3L֕b>לufTQFZ$ܣ<1Y`8$Mj&%Saĭ-N6ہ=!o_2ٖ 7I9BWׂ ޵]qtHz}G`Ғ+]a!49<LY@XDjcmDO5m|9R98 qā'7rsYDXX7;# -#>A`Ɠ \Jo @F~0QkbiC$r7碐#0Q2̮tiiH."nqJP zlcfjJ ~3zā^[>tTNyhB3(R 26D3O sFdMEMºw<::[{b7I([,l.i7594S?8/a^ 4+؏>  }|;4<3}2d̍Q~q(ZTDL/s`A@xL Ӄ, *X,lJCDM5LOGi;0MbId:?XRtaȐyMebvϛ| |,w|ܼ(b|Fr*Ii3 &uTYȘtjge ZOi6"Tn/_i@NE>ypU Ѽ:aE>&shޙP4(W [8vgJ_eM; `%]x>:23 S!=N,@ynr').Z?rȆOu>f$޸oJ9u_n% 7}!.sU37ItMY*(I QnT,Ic%].Q3[7pF*HIkxup&ew`om|詃 jTsQʧM& m#Y)Q/ڜ$jXq}Pa06x?j*gr7|9x 2D2\Eшv(ѭ0(-ڣ*l8 ٓj2oC|@3Ζ#H(b73h\pM4deuqK-tN qG|^gHJ4st^v{H.CJ^. Ʃq@ IFg.W1Br y.)>soEfьBCםJyQ C3'cmv! ג0.Eџ5A+1{lN7p]!^p 3PQRq=qH2'@>=ȝ`ll!qmq3(r/Ygw ˲f;A]j,&g0!lzNi}J"zZgVLGlѹ" 0L4ɍDxg n+. DNaiD #AS|OJxY  D5'B奻 bك|T㸱63 1VX PCD[`rtfmcmU@i-ɕ&SaT+ le . D)G^Nٗ)Hd״'˽ngDڭ}eR'a ߅M>/w#=!~'~:%?kKFlz|^.wxӁ@qsf ?"NœdY "g1_T<83U`u&◜^M^w,s<=<՜{|gVa6;a$C5+8@M=L-+b}5̌K%Ytٶ]1L nLiuCzjB(f{=ϐ,f[gL|&/n7@+g빝7'4x7AegxZQ2L Eg5:H4T6qDl:t0dzzjB-ȢQp#GClDP}wϥ I?U)q*U(&jkS#@5"$}X椃rBfA^'HW>~KR-,3pIDzX 9hfLIJ֛2A@d,c2O_d4ŠV'uMܬk_?pZ]!b2.;#puɦzav6L65nj~ hz// ^6k\nw{CN5RE?^u3ļ#G SmcKϕarM 9!R}rhnhE2.l9IةLVQΓʸ>51fq.l?v˄k~uqmGeJ "sRtы;7}ڼzm Ay~㐖x>s: C*+OeDo,zi\ zph(%0Z7pPuKӀIe6sHyV2h+2js*zl͉yg)݊lPDTO@m8`ad0OsyY] Zq팢bcyd۩ũ4_Δ]؉Ctk|=;5ɕ!QSw;-\_oPֻFrzl 3˪szRniWr[9ZiK]ܧ~z{nf]_\(6 RƉbB˿Q۫jJ/1Gy72)) x9}h)~Zur_ Ї`ǿOGQX\Ujk]aSVHz6Q#ߖ=}ٍC%X[920zhO P]; !'},^miBHGvA(0IJVw>vt6Q -tTz{H'w }!lS꠬->mLfL T xWNFs KetEA?wg5blYT0?qUM`Nu(Dm1٢Y)j#23\=<;O2rqWeCDѣ;_&祍_O"e6ͫ@yX5um7gh8 ,HQt)-耝^vo)rV5 ENՅs^_m\L\QL!1_z/rիt*XMͧlgP8ǔ)^!PB8hahX۠={05µߥSQA1竜 HQ0yv(iȿ^;ʯ6 | oAX ' $C/)QQG/c?I#)@׾VI6ϹI؄6c-vNB Wi2@`Vei PdK_sג" u^-*|Yp ۡ]o .J"h5a_x|°i-[?ǏPüafjO o˝k?2L\ׁOb"*`j6G}f@(t+:Ȏd#_l4^9_ZWސ_6"M `&cHA\7y~ӑ]JܫA(R0ʜ?JiV\d@zM1Ʈ;˷zz%DOS~KP/k^=;Z v8ޏf94 cjٮX!8^`GiNh٬vڢS&v;E-s5jzpzN8K@0T=s4ĦJǔzH,%c*ka;X&֐+F3|[3Ch_|-dtfR OIqxX8Z#B7f؎ۥFU·`D x}/S #m=yI#p&6x%-t8COO{r$.*F/2K/$6SaGEZR`2+N ; :0&g9vO1_ٗİ2h8k{McX"YPhf0A|>"fdb;{(#ىDʽ~lDp^9H,'-åR&ȦW_CMA@ZAjZr}ѬU:ti㳻lIs:̒YuT`KHB[*Q- ;^O0WHl\jUӦO?aa[ĆB44_СOpz0+J˺t$ڤvy#@]ۂI6DFҳ$ӧjL$BE§ؓ'0` v7xM<8{O]\G}ָMf3aHO@u>"=/FF'l1ni i)Q7sp+;v~qm+wGR ;(nom \X e_5ڢ4c.7缄正Mlҥb%ب)jI//?'ʨ,Զ0D];X\5hӳ\2׀"E_PfCkijVHdX"ʉ8ВItȁ#=n橀B6l VR6N2TdԔ0ly.{ql e=6I-lG~qpj -TYS~) tVl19ezQ`tB»P_lcemlZc Qok!l6ٯ* {`C59N$s?8H]iҾغ Ld% )d*hP&KxT.47q= E >2~ Pc{ֵ$CCґ홊à:\Qm3=?7N 6H LKbJ%bFGYOғXNC9Ji ǔ$)0'#A0ժ| eK?hHsDkd+'I9`9<p k ԃ4Ta8֫ q0%ӵ)S/j<&Z"GZA9rQ<7ء}:> 1k:KÌCWP5wF_'wy̕ C5/X5Δ '<~<;+F=, 0d^ri cqVe>}ڑx(T+hpISJŨb :̹MD^I9:DG&_y4LWp7|djmٚқhM -jVAE3^H;x: b"$̲4RD-d@ Dx`iF7v90I~{a> Q:JTRWvgjdzSvz_wM hcEW9\qg,!> ?fPOiߜ<'΍ h)[͇?I]\οhYqulb _2_ڳ=Q:Tg,Vd5cθ'$řqeo ls~C/fn눯,#*\gc~$8'xaE)Q9F柢B⍗mz05H`̀s *c\jD|vl6NO\s"'yrE,[@dxɲRt[z8PѰ 妥p Ap^ke,vsPY&\Dݿ^Nkp$+m n0]#qXr@ML3U" ,9(d}Szuyy=hN_> sfśvNhx!T%w&ĪNq!Ca."ǀqS9vJ7rFy FiՇV{!Ͼj+5](!0 ֨#BGPRe`ݜi_@uFS0120rIG89 f̊+?~yٹ37&H-)ZLu|:I%h+`v8~:ΗMb k:J@atrNp)Os)<gZb-ʎoR`ǐgͼNsq-הG2PrZ {%]\J|'\ י띁Oh>zV:#WYe)f}d3lji c9iP^EhtďamqM *ӂZQCzmr=utd\zI}*=; e#d0te|uXAְiV71SD%('p!Ѝ6<ƟO;%/~3yjq_@Is%&Vޕ:z%\}Q9q$gmVM1RJC=T콙k\ cRU,Z9Ȏ8TQJ;: 4P\ %94g \_EP,9"]S{W!⃫maZv3 @J'wcRkƅ^:_>Br'dNb @/=3oZ<"(iE`YT.}%tC$"p!_h,k*{\+s3Q9 z^jZȥ˦6ʁөK!OL / wLAަ̨1$@~ʬ;Q ƔI-C6pl  uK`:`/dMwO {މ̜-4/\aXmhS(6 Rgǽty9.K8 @83mqi'<*Fӄ:T!nA\qr{&l2t{_S٥N|VuIrc,!WҴ({-#f+Gg!HK8 Җ'λ4D<6^$DDÀa(zѼJkgou{u`\0cZ5p_#E!ȧw|ov 8mpf^ PRBw `|Q8#$[#)9 l,Vk?y7[,Z*Gm($GmlC hH3|JF&^:֫T5~ !+h_g@_y.ma {#>Ďd:!}MtLvǂJC"suƈsS/ D>!j<=4<=TM𷩍-QFC`o@!cb >XåC m`(Eתܵeŭ`tX01o!JO~>՚ 1+(xM~ D^pYZIq #JPJH9R \i24XDykc{;lcܪ{5?6Q`P2_mXr^{hB'InU)[ZV _ 9펯)Q=}cԿjIRu9)ubd38IЦȱ*C:Y b8YY9~Uw|msn-.XWaGiwHzKىSD;J )n ̆# 1} J+qU!IA$E'أ9 XgvQ$h g&q,Q$!{b (-Q8br\f.~Fi2U/wfJ:ڻsbw&T,fr:rq Z8᫏qZz [#=d4 h?Gic$R'W8ic6sc:Z9IRdϛK 2}Qe_>tRzXW|3TϲrDqe̷Dߙ%Ѕ~fܜinA JUS"Mm()C%mT&Џ%pv%wQ:TQZyv fҙK±`T(8;"Ng ž+p*JНTUS9d.5 sJ/:ާ^a_`FiߘZFqU͌@وϫ>S1Lw՗88ŰUrV'gD# < yR2%@8|6 urkQnf ,."- ÚyYg%i1 ese1LQPhSsg[|,oS {5I5ѓ} #= tC\/y|?sK &C8nJԘ.ˤݣe)4j;dG, GdM#:2;|a4"ޑz8V%+q'xw?[[ ⒟hY"?333AК&ZJeTOO?]ZTr% r1ԱG#7?e*9b ^>`y14͍PXMՔp5K vzJx]}K14[7I8WƝ1hܯ^`&;>E@ۀR8+@% PU]V,BWᴱ hDK-nſ?alV=B;Zu~5/3iFpn=4Aaژgq챖:Jt߰:7k2#Q+P#:1!ha-q'#Q *25æۊx솱.ϓ~@z,~Mvo75E! 7Ji~cA63߫âgu? 9F`E 6:K}T@AضZӆ2Z28òrkNnU1y GʯPt| -ƀb$J!s 7z|;J,+e9&>go(vBgT750n_m^j'kJ?RqdOF;ī}MG3g${Rci 3bnu)]#/zBL\{cy`_%4Jk`V}:;yPaRƬbq eR\&nh#f@1*29taOK@/Z.X$ڼC#[ L\>I:Ce kr&9xq-؞6:´Ju:|&h"؋OvgN+09ޓpC:1g{~Q*܁\* Ǖ*pVBx3K?/9IF}MaLbݎGdg*?WK `@JGdZ F8$jE#AXU yF =RX <>ۑ ì& Rpb#&/B(DžvѶe?zx@ZKаHfz#Rbbvi ňBWL=U@&Qm|m'H~$ER"ٰFO c*v! ZZ%-3yA=9rFG1ձn?P;3؏&w։{$gBL/b-y9vyI0Ir=ݎ~cY$qh5bhx>/bx:zݟG.Zoo-)t0X|^r `Et"9$ǂ+Y٠G -1_Ց2-,׀8b# m_m#=,>lCAPغrpP W \Oh\&H9֨j\A ݊~] Rlwf30Wup b;)HEVyR<;Zd6g ;=MtI.hr~W(Mʐ1^mkFQLΉl& TUS,濶-,|wnjB#PARl8ĭ$Q[A$-YQߩC'5KL\}A2h|lim=C ?\,Iߝ|cyK@Bk [HG'AKU1+n.~sy#O,Ҁ׭4Bw^/gK6=/svt]9ѝn7Tfcҍz!cqv^4y/*ZܱR@p˟_,o/te$_9rvm4gtm hdZ#>oF O\n&v|E ZoN&h-[4wźƉYyzM 5RGm}6Ⱥs~tIbp`T,%%jf+ثEX/L2ОCo p2 CP184(7PaP}V{J1l]:P=5/-A$=F~ӁJD]H2DQz򜛃gΓ*)glPr|ޮ RN\"*ΙVfY>m%؜aѹܜrNKG\TZ!B[b7y,?Mvw3gAˡo`֎A.0}\kP>廂{ݤl+{^￉ >xA{ݏUr:@]p民TebmS*bGN1fc`JKn|i]Zxe@u;es͚=DįXNbK1rƓ_]|r1hS7 bX;hhO[&i| b&]2MF;0J]s/S-2/wl, bqHD*hCr٨plzsbT"&Qa+ʮr9As),Q6ss5eU0nvu=^? A5 QGOD  7SXi3㞍f '0H|4ᛀc齪.'riS?\ -DhS&L碉lГX (xեw.D4.uբvˎqҢxX٨%#PY'tI05|ρ"ọyG ?+ Cxe'Z7Q՞#ʰ|`O{籬o;Ѽ*M孤OSPasz.~H;:J"ր:[? g;ƇeRDh[/mQ X6`/;_{«Afy(IZ4nU50Sy'+_uU|tGe9rx0|q` LJI%p):օ`Sz$GEw~z7hL!sX2 !P{|zS^4[b߲I?wCn*p(2FkI6-H1a',ϸEɱē$4dR-RƳI U=Nltg\ƖՎ+!1r_)62v&D4(y e|CŒZXj=5×ʠG?:`'T8 5G _uD!n>aV $nDVY&9&P^ALƬ^T y"yR֭ Ns,9dlURhn8 4WZ9rEϬ f}T-lv/T<4Gx#Us u#.Y[JRk BIg&h42ǔK(| ERH;ZI Bl=jPM7+Dr 2v]~=wOoj<>7CsCs+cÅq`"z-|m` &=?[[Gm*t g (8ȼ{Q7L9]CrCm՚^O;Lf$47KXv9D?xU'E!9X19l\6\&]yRuG^(kxX4*~Pz fBIjaVª:S]$tPxL|t98i"oKfW] , M2 axfsȡU&C=Ci72Q뻝vsz:LAK3;w=ZȫiB Y<9G+LwS4rv> f};cûM`D|g5(MĶJЁxtKYyG 03C*`~,+='@dG، ??K-` Wɵ eX/k|\, (|nSnZ/&]S[jPI_>j^xbZ"la]By!Xm󆆐֨Baa v 6"2+xT(F[{+[2cnx<7(%r^7<Tץ @/0&<_\#R,Z8+Ӗq@V_Q|Q#Ӎ㛀cm#+$h|d^@ $h;pP629%Jy` RTR;23].I6JjiBI@S9}OMftKhL!c^e.:h@~ 02~Cp6y3_ }m[**Xon,͗g@q"luyx&jS1cHN&01h-l-١Tϡ<-<@0`%iPHr@ŽӦfI܅}|7аGQ:Q'V#qYG,!BΥXC]NcȖ^1\t : _Ѯü_"N=28^wOyۻ[x>ϱ-eQ&0^dX8I7 rIR{FtϱymunNQ({(+-}ZLG B->ݎdչߏG՚y]d 1(!HC@\^>R(QUis*,(GZTkmLFJTSxmm !7#IK`nӊxĶT>VC  o3%ҥ-:N:J,8&619B˪;vъYG3'.>G ;2L«A E3iʨe>0co3 D'p+V]TtNd?dnwy?W2{}I8P]猁E=1a+c'hf*dF6Wڵ]=;>}gf=ok3bMy8h Jws>M4i xvry=Su6j Ps2s KY`q6(Hz(ZdO\![s _p!y+֢T▶6pG)HDv&3oJX \fJ6g/h5\hF s3!d$r8sT4- }9Cω $Rz>C~k0iv"j#I TCGy eۈlJmV"Uǁ^gtárbQ}`%XR,}Xc2Gjb{ U_RfGsQXbيH~7\ t\) a灦LRxP:=YLAA*OB4lrpB"N/2_J]4s1,r-ѡǧA2;<UL/&}L_3#ڒ@6آ0~.`N&^oR  ^vjhFG{8 u& 毡)΍$ex(B)ZnYv˶7vۯ(1+yW"BU",ʤd}=E2QP?Ȇ7-y Z ;G ae(m_ݴb^u#N1#9-=LǥTXiwiEalrW".H&xc<.܎ԲaJd!iɋ3MpHbj@nK;͙b0fGßc hLϝIc!OpRy ;=An $h" q%Mz/fzJ|k1T_mbtFV LD|ٚ!pJ=v?82L 5q(3℮YJt]w?̍bQ's{ h %=mD3)3]IRiC!θU %wW @Mv1_IS~^\g\^֊%vۇ[k)d&HC#;J|L~T7 1[vnԉ2 |˟8qOIآG[j!ǦR/jji^JKHPZJR\1sahBi"3d"gN\+ױwS =FCv)yH`kNV]fEx>Lgz&F%+Dž<N%T1NM̈́HW{R>Kco=ɂL(L hא@w429/~ Fpu4#nv 8(-] YXd} pndkBpkPSCecC6J X݂GoSbV  4/¨v PH55Х%et j>6Ws*$e#mc Qii״q zz#o`/ Z7q6ӫ2ȅXGŭ5qqXEi+ЗY,Ʒ,Ѿ~UZE'\J1>*n5B ˨ DLsK.ث1zPD+ v$4 !ަԭńȯ`~CL ύ>9"f`q2%Š%jr*iG隬4Blf=V>iMDsI䄦FOONPG%] Lw:l]F[PًD^!1HXì"lAi>kag 4Ô=ȥN*0dAɡS.uf afAjV\ΨSw׷FOdFIsڝ-}7㖸%3e~ZGsBkSf;;N{<VWb̈M('u27wb%}~rs4A_?o{dǔr.?p?q:+]^!8lU#-2 )$Ǎwґ iGJApҡ·d6(CJ z2 "钀a]+TpID[ pv\:╶0qnd~2Q-%5Oa P> Ft=fX%LMPR&ѐ ڼP,N /c#+86U (ė$H3g$Ĭy[ĵ ![jdZi}zȦTns`ꠍNsa qz1Jv!>c7Y?+ة>J@бUT)ˉWm/CK03u|MI[1jwAU*,rF6@[r?!!-Eu#~OHm"2n@T[ġs? $8o9p M%p7mn^k:q͢~ݔnmCq3'eE$cw<)GW+D7g5D9a F {T6/Gzy'zΰ:̦{Q2hGI9Zf$ :rPe‰ zjTaKk'B |Z?7ğ{;Ջ'+a,ǭ}mKEЊ Ȍ{2-xyR2-p8JDKxla˟!<5 .@3 K %kk"XG4`ZⱜCH1kR!ʻIӓYbCTڟbXPą#iů.K{ Ϫ],ڵ+tp 8S~6YeM3탵ge:ӺX@ZMyѺa(Ju0.2[k~Uy3*kX^QibܰXia{Τ iV;UK׷_;@j>lG޹;Ic # 5CCVjW`ERy;߄GԸkzCZJ"jT^[4![ m_[&tQHw?|8WD$g@e?c}y~=YJ}I{Y׽ٳg_Xb\-؊Gl/wpgLᾼ3ݽ£NIż9tٱ#*۶\ͣ}.R䟖tNY|) ̩3X0d!Ii:a~ob{j`u>%-ޟbF0az* E%YSi0Dgyb͔KxX/=/?ZX/&\|oN7;>6dˈ߸|4r<`٪<\+,ؒ_@?9gEE\9Rj\pLFVu%T+vpw>Γ{ yﻍyxJpF^e_9iIR:a~rF_J A[LĄC4AuPO|HӮm ykY- [۫c/X4s0Č=LФ/ŀߗ=yew)2:ʸ ҬD螮b7߇ WV0m"fxz5O+G@T2ͥZ^8h.^/xoREIc0kGm& x-AXNb;6:[FS|ݡK˨&Ǻ3Q!z2N/jEIK:_7Lu˴8f}dߛOu"I ݗ& KA*я_Dnlu| *4a))F(F_ M)7KcULN)"LsGVTbHяݮi}@j&#=F0Zi :"w`TZ`r CXlL_:,<VMn74~50,y%QNvX_3.%Q2 Dns6 A^P =_yoy?|8 ze y"]ld޵\GYM=FPͯƀwxIK}"l'bv5a8*8r+ ~7A 5r .VwS*bXXNbtQiV؎0{o^PJ0Jwѓպ1Mz 7Sk,T&=2T4)!H*Ra#SѶ~y|?,15\x<k>h\f,0l7@^`E]E9<),3c]RIi[м"UtL9>wV. `ri*\ʠXRC'䗏7!L4腳sSqBRE]6_gM –!hzHs$|>M|z =m$+XpbA&-G*%LtT'46&lhBbIsOIgS,1vH{ZQ57B'®AJ{C.ߺhSy3h#+՛uB{|hfJ˫1Mhp, ;e֤[F($g) *GSnמFK~SÛ٢[^#2@U"JѨj ERMIr.'2bUErTS 7|h >@LonD)ayy oTO7SE8o{]RRm{,2%K1RE)_p Jqߠ@nc#08(a1{ 5MM6k~#R7i,ȰX5uY)B.o& +CfZ d~$'4p1qٍ # Lm(uQox.7}ze*\2I%VӘ!ϰCU`l:m4^ݣ {^](='f>#*ǀkCb4[L֒IȊ֘OEFc0gzݩ5C)Ɯ68`MJTl7xgOe,ZNh/o*v vW샹8~_vsrvmpfӖVG6 7\bykC&oH5nmSǧ:5 }͹ŲAaߊm8=f ;k ܐKgfh=c # `K^~3A9cT0a0V\U<OlW &w)ULѾEV8&;%8򕉛iXVaK3"\sр\"/<~+RTMS&~j M[wAcAڣ#u:%/@P -u+LM_KKm!dv']GJi)P_ǽ3TZݯy8ցBNf=UUNu/z vv8#! 8X'@hQ;g7=LPBfRx# %qNu-k4G߁8{<+-ͅ0ݦ=}ʆTCAoGRh#૷qX6[Nbt:? ގ^Ng;$ꉗ*].W% Y˽27^hy2ALZ̹3]4#jOe͊WA 56Uh)dе= d2""Z.?_I\4fN(ғ fF=."w= fj Tc(~^hKE{q)LWKVr*\Mn&D 9y/<&a >G%T {IC=㮢GbBګ@^PƉsnZBBcB3!mX!뾆 Qh<Q> Z}?=9Ce/ukGƧebjب*i/Dr^ O-F y"E.HwZ}3potRJsHs01?+_Pt͈{Ж2Y;d9ԲA@QSpD~lA󅳙1KħZz@*R?7 5CMf'bUɸKG H`6pmlEkJh=̖A21dQN$~X9?si GL+RzZ <4)_߉ dX1f(,fK tOխfpdXE)ٵ* K4G&vR /qcm!$ BdYb]l/,']+&TFqVNjʵ=O(Ra#~ Xmz@n׉t;.Ԇ}G/!4*h>c#OLS%n xtL=9 .QҺ"~vMyX+\J;r1T*8=KQ[uIepS,q?tflsTP7QDYBRTox()L5iՄF]/Ӑ` $ 4kowp0Հ} %!T=Vb:[cfprWM:kPuP-Og*^ZYlŕL~UkS$%+B=vo,j(2dK15~LSi܇6sT9H  BoaNi/V,aXiTk =p>v=JՀcXD+I@cTKdod"/\NPJ0T~D 3i>a_F#p9y>eIhYbu=A|]n`)'T)a}S ޟT1_H-Ovi;Aմ^Zf VcPfDR`BhT67Vj;*0yw mpҤ E ǎO AwɪڶtVOYTFȥg _L=?,3ύ{{{wq =i=zQ#6F+2.-v|Vl -T?ٹm 5@r!§,]1Zٖ4sY6.(om42`X.P TtPV4c>90 m) jȋ9ڢ UxI]O y$C٠ErK/Μ做MMs43Tq_ 6ZNX eouv_Ii_b ߟS*?i2AѩJs0fP?`3Nؑ:y̛' =b)Ť8Y.&:=0j>&;ͺS!kxcj.0"qvI&MEPm1Sri+絺 л 6E ʀ7Eغ.d5j Ŋ>" dMί?6ȼJ{Zy,vL&R3.2.v^.Ln–/cvUTRi;<4Ya6lr1nJnP4OnKߥR|p2Y@C>SFb{ )|#FWl%m\ N+[.LቻK4E˧%%L mB.:b "O51mok3ygF#jF{޸g2@t@V"axkA q7Km V+N탳B\OA3.j!мH G4 hxma_ʍ JvD dN滇G%У4&l7޴ A8yнYpv(2a;>TH'=1qg ;n9|"xHDTh#y8a1yAk WH͔ [-]^,{HDZCh 3^zY-.z;V7!tYDTc1 5= /!;3#~2 CX\UvYKz pEQD%8"Pz"]i]pw}}<&B h,}6"zmJIi!t)U΅ sc5Z~Fc7V:0hP #FmZhQ FW :$C_1.0}QwrȘuj #(.!aBzЯdD4&ZYV@f$~ԉj#G7ŁR n#EG :&w(|.-D}o f]zf\Zp 1haY+L)!T)..%+,ӂB*?C4uf7\_缝o0]GZU,/Є LekHxψLW[PYX ]Z pCrFNAD>_;4q|rU w ,liZBR ߟ-"U,4y|@wbkzZ"͙3&_1\ے[l#xvH,Eohw\-kHMH+TDa@ʓoG.Oːۏ! rU`e|][Zxϑ AH!`* #a32@55%iCUjكme?XIs5g$7jW9"x{@J%5Q| kmU,/f ^[6A<+& n"2mVjI[E$T+/0Q[Аa\ttY}RSa6?.jC栽O#V;1Zb[:(ԄI&C<捇}C,w?$# UPsIw;2EFJID MQS0nyY{Scm:@%|z?+N3 tw{jhDiV~$*Xl#t'0pSyWk/n9#8r7PIt'֛BNӄ*-Ch&]Tӣ&-hAYy\UFZHs(hA.(uG-rF1mѻƗNLʲ\4yH"jR*wxw=+*Ь8ϳ d˿W`+z{3l8#^4I"tCp#?V:J]aԛ{{L5fhm{J"d5'C6xp]T *q+.3-,Y}n/rp)+WVIAyC )8-}dYjB!vMƪΦmapJ:%z9tH@ 11QQO]QK-q6>9md` ~hI1yu|l!J2mY/pJ=ui9}Gvj|QTo@0#UlqO,9`cQ`r?E`3;bC;rXYհ7M8rV+#ʙ%D2Y~9o]7`,Oo/kϧ_ܞΓ2.o;3 ?ɂ:DHP^D\ls;^;j)O1$ta޽[6D׍}_Q|Dfg߷Ϗٱ\J/_x-e,! `] FEl[i|n_޿qфVHab?SQH\ %ߊpW}9Z؄}Ujҋ~.a^*(KF ,(ǽc2S\ȓB8s̈́!zWdkŅS?M9#*DI(b_t^!|||ClĐ@rPRx.SVjimCc\ +\lKCM#I*€R8>$4Fu]5j'gdVB8H5)FQ%XiYhƒ^-CuOjY3|3|t a}{l'5}b:$~? K\?=M-aP6@ metsTrJ}=ٵA"Wu[=3QJSFF &dY.&*Ti:>V?9cUl{ Y)l@h ª6V]] e_ `(E2|mD-QZ0O؍e$~?KvyͲ<DƃwW ٞBs|cPxp-BT-E%LH +Ȓdx9j>d@IDATE73^rB.FDT2hl2slN:4bJ[p9S{vC1aRPV)"P?ǑZ][w HFR#`iH[0 H:H RiMr~+t~T4 ieqQәͧ4  ӁT| w * $kXm-R@B^He-8RuT߰ŏ2_>4Q m. _x]\l,U&8 {Y#S&@шoQ#^e7` , Ͽ29mwM|Fe{r$MwN d| &T"%kvyȉ2fx|TRwtuE+6|gw9WO#. Cþq[eG2&d.,ݡl!ЏdlflZ"_:?l l AKS-mb 1Kƌ֍)]P.T=@x.LB|b#9Ԭ(r2H6unو[fFVizY4c7@Һ"c3Z&lċ(+JLڦ:]~\ rDԕx l#Gj!R齚zne)Zh52q${.\F c$?T|֠hKƏ7p.vG^ LOx@ b2!Ÿ$lN "6uC6/1 ֓b@HlƕgF<PkhkF:;S  'b`SKم@B0n/YÏ_e.!իjofg;Y:UH{5&#,^jsGw~ˤN >ץi ;7O_ 0a { di]c~%pQB mWb *84Q t[_ {#j@.Bn.wb5/YM7$u܍4i{ }hLj1,41 ) h .zaZY[K[M벪80?\ƘhMrpOE)Kg h=qJI"26씄4⳥f(5E`ZwFʫC=('g 5(8eHrW=(IcMM~͉|̯bvbvfM } !Ihm"Ɂyln3^ۛz)Ni3$NNW?xci\sBrmP)U|7WHnI4z_DQr~C9x@An{ΐTYNćT{y)ws1u4V vz̽XZ$ukTU}:}^i P&mqV^ ^ln"DDٿt &2Afe?:(;g.%P*3b0RUaBOX;$ФW<"-6!g |~*Ty%he:`GiA(b,*ħ荐;oc?"zF$9i Ib~=J+ $V. ֦ $ (]cɲ0E-E`7@*C@%A P< 7ڄ%E  Xy4kTl26zLjjґ'E !n*ʘYkuk]=j #*6C^YLv,JI91{OLnc^]B1>ӅNRSqrovǪ ۓZnx CIrpF ;_'ZjL `IɬvrL=FpPQLhQ<7K`_/V"= A d Itw]LT! s>kaM[j@d}QI> ] .u Jw| mt:J1J4Prhă85%3@Ekjx\AMѡ8 :\ ?5H:R_+J^%L;@Z>d"0^IX՝wZFn`YH ~l@W6u{G[+' nHܚ<{sVeGx6ndAZE0/\Is!w`sa_> ݌C Xd8MM. 񣱐+ WF]~Ҧ5QZ\]yDΞ?2\p~J;3 qEۿ; "rP<2vB9'[h(bNlcܛ!\1R(m~bZ3o@gytFKbr3Qu=j2#Ƙ蜑h3TaC!Mx*\tQqUY, 1f-AQbh,mlIh@+a i7D71?y`?d=Rs&܆*wwvBH1#n ɼq3TC~~NH}Aذn̡޳TVV;ogbU?<7c><} c8MH&p)t+rZPaFr̜eƒZK^-psih(cF~u뚡Q䛚 ZƮShIAƭmJ41H j~)xAM:Y/fE"kGEQ&zѾV{&;5Pye".J1Tߵ}/qja!\q]miX-KIPpa&ӘQ"all, Md4&[҆ĤA|w:AeWGS01 Xgoav;>RWtM$tQF6@9ӗ|p7s)R s+6R %^x]cݝ6]g0S{^aS7lDTCؒ( W &e<m7&p7 #m_(V‹[hTp m0`R:'gU"ƃ/PGt (4!*lg˗ilbVd۸#j{ ڶ3We4'EECԠ%vxU#bhZzQ5(:)L U4y5A05Ca'ۢ)W;a>sײ111q*],2O-m**Ҡ"DTTVQz.ˠtb,0i!0Oe 6`@:!Y0Y6|[7ul`*,ډo^YCg"5JӅ3rLȓT4 Uf/=,6C?ПlO,8s!TKPŢ+#O^λ7SKE ԏ!D]uп%ƒk -VwFֱdap5;nINB)&?Ǐãï/iŸC\G?-0UŁKd/БƸ<@IT9SjER.vFplC 5fNˀܜ9C}=C.'Vp ݷ~˾\?hw`h+^ӄF:r\=yzQ:DD1mK=PZE2-kM-ey"5 I0EmGH+vtsꉑRwy)jR噌ԞHVa>\7x" ^f~r] e9b̼Xlj!ptgx\Ab^ȅi 2f T#[>j$BxѓB v 8HϞ,{wcy) p r\nؙUS'A@LG(r;%6Wk -Yl.A?.֦[D10/`W Bq |*F֠:XiaG _\jKXt#0|jtqcyI#W ?+Dq9/wӡM} 00yT2Y9ުpӚH؄ݔ@.2Y F@Iayq\O'"2+C G0wMO8c$X1.F dQEhM'b$F( B}~޲lJ-Kt1f |'xQpORuL؂JHL%Sѱ5vcPK1cϐ{6F胎yI<ñX]#]* ^VR⢋x*0Oe~:w{J^:xL}7u_5jjX;ʏ[wBip3(ՠ)%e4:?+FKϨoؿD8ւ\z]n, ՏIGbŮYz(v&M%iZ-;v2\ (ZfySԫ!w}(uؾ)q_ Fs=T7uH=dWŦ1I^V=2!DDs)=ffnfb@Oj/ǽ ~l )A@=ݵFY$.,KZˁ ofcI*E'9qa:Q$\R!Ut":( , )gq:^?,N#S+%t'!8m8rpC JMPS=z}U[ag;b C!siY^Y !/u8z:8W<۰,;0ܝL+Y0%p S{0VJ)4~8Ԉ ŭ^FϤ?]PƞS1[E1{f,ʥcD#A^HǴF-e_$s6ʌ-k'ښm.WB'?i융1LM=M\n4E{K8tQ-4ˑ^L6>9g_ɺ? MjyJ'N?i_D.Sd}52qso OUI9y\c @${dcw{c{,`8+lYl8b,*ZpgOSr{S͇+TL6Vj?Wۢ{>7Ckz{| I ]5'_30[ßXЧ^jSY{Yu<=q{ڼ)ڍʶš>)ʈ0"Yv>Ü_c@VvcIj[&'>Ԥ&""\so,kRR9Z&omlmӎg- >l穅yNew?,6؄| V+hnnxz3%;Q9.MJM.ֈ6x-_LPfnf<\?s ń(םi M0f "-vѨ҇#Ӈ~2T\ ;:Ed<@z^)c}@f|^hl@pPgHKQuX"bl0z|b"[/oرz̓ՂvB 3F77Zi6cR:9x̨ 5a1K*F0S6>"UZ~b9!6ؑCȯẐ! iZfA,뎪q[BT&2zW]*cT m͠vbolXiWmjS}N&uPXhg;uuj4tQ-"7|cNةP?s߿[H}MdٿGK^ZT`׷oa=Q,`cefhЊjcխW"7Az&[8ҝZ&)~w8xѦG`ҳ ^Rf;?l3SrHyM2!D'6Pq4ŧ9-rډ^Gq?#c4Y{W')Z[r,cYw/dC$!W|wVEC3 tPI. * %"yߊ\Q …cAmd:Ԍxfc^ BP#IoLÔB={m lT9M5vno/?((7g EZ~ۓ;]/q:'S/@HDA=LT߸}MZL!<^vxƒx(mnlhCcYos,PhF3 ||۰ b+Rq;%܅7d:0ZLa֟4=]k/EܗfX;g*Ɖ| 쨁yqL{)D2jg\I N6{ƚ61/%=I2OGmNVkRXWbRV# G6ˇkSjoLR$7,-6)gʣuH20r&ot‰BkUïd ǎ^3Y"E37ٹ@P C\cEt ~Ø4>ya`˅:-na{~a#O5pw[<1 9Eq":~ZقT?ؽTu,ug\]*N3W;K*~L\<9Ճ+ 4+!cD ˷ó'tP'4\5WIm :XtN[{xXĭ?9\SO=a)S{7f}Dv4\HBw-ώHRp#A$齊*dʆBS,iAȲ 0` a+'@/5'z)J$@WRh^,ˁ0NP+7+gǷR*k#{ fpYv?GC\ZkHX/fJ6l^If,X"|9('aGE+1v / |ژ>k{cޡ6)2yqۦ$ ;H7o0 B%[y/ )yxwb.E t-P\շ.@SL9$ 6Q{N4a ;dP`ݷwzE]IZ5m]=?MɅsxtI&W~ b>=8G*5֩^:CBI-AQ!9ωI^h&Klbs+ry7x*<$mŨɚBX.5j.Okm8\ g-&K2^10J"hP#G|3ഄ5RFF}~pj<1x#"Q+3XZK $&=Szz =TSVKp"]lѷ|lwݏRHVpcD֩šw7|Gi5mYѥgPk!DwTπч4qQ+<NQsMkНA7vw8dM{>0-6jo.|=i\ -2:NrHR)?,%6cR}xۭ*o~UHq;& r pgT܉#h} ln~ح?m,؜&:pmښ6y s#NV# R,x4JIykW׿?ULH^3mR ɋx'NE'ހaj0; ġuτ YXkIyV"Ԝ#ڌj"}!H U` wsN"B+*NDWjo MMAeXK0TA;)'; ֒?Uk˃Ao1`[`q]7앪uW^~rMgumfaqJ(m!pRߥy?'JoRB۟oB'@j 5I!qb?י!fFNAg ew{FJϤYa@PxD{5/d3u"Z,P1MRpb`K f8X/$KV1~͔?w;#myeSHڡi}#$G\ϧ`ٜvwCej AbGhC2 W'4/@Ny16-w}Kʨ˙yt*A ۬Ht%!ުW<\}EIaNN烆`=jN?c0`~&%_h,E ؐIFB7(ܟ˽姑jP,v5#ꅺo$Yb9 p|zv wtiN~6ra<,e*ɅI=:2b%,+J@"y\݂h߻灩"Qr+ VHOI4Oݭm{6z"OG)C"~MPAEљ³E9|3vWQwSB^Դ¡{iQH@%=4n*3 DA G~~N;"i /V_;WC}7& >AgO`jcuB֕h06_~bR#Iu р'i"F7w=&»]aۙ?@oJ@J)K]R I7三OMbŘB0&@dug9K0C;nPa~#%Xy_ b9)0 r@-u'i䔑e`h շHS <֐pInYYzc" v3͸3z4; '(痌Si/7ڰƉg'EGG }01Zh֡C9-6 V@І-nR>I{Jvv\Qn1GAqxFp|pIV<6LFeUrfVa $A1Eh֚1iaל Y<>5M00p|'A_z㨢ee_X [i2F"U5Έ9vޚSm'`w&')S6CYH}zS:M/F$ch*ԿA<띇;`voe*KG*R\n3_Y.ҤZb&k!{~AYz 3%2T~hj,2c+2\M&֫%.5CYKTQ YcEx%8nؐ>ƘFX3!TW!B0]'$DpcODB-H zݯ?JCN6\y2o&-C*'F.@Vps J@})sm?4,շ3Ir&(w-EX@Zbiq8(R[zeN̵şqʨ?599_eh&gs$}_o~65@q҉۹p jAvvn[eIµIRQ_&v)$SZCǓ -T cC5:u ˀeTdדjID[`AX./"jE.\qaoNP*P%eI34L yʊZ%Lv) Md^Yh: KNW[뫝1Mn;͖)WS 3AS$k)e0ʪĜ䋡᭸!bgeZNag0scM / @z!IBL {p4G5lL34xӻM%*LCAgS!>S8]3Ur7|q>j:cԱ< UozZMC'yV/Y#V @'@cAs"AwB%Ska 0}(kLmp $ 0P){O _|2TnSP=QP1, oJNt4r6D{ w:!+yD9%G!{NW\C[ּ"6 4~XRi'Z3 jBG˞徵vG FּS]۔V4|\ P>ʌ ayq<դGqZu0 ̠GQUV%Hİ7F??1Mw1_(rs=,&X+ x_gjT\k"ԗ  c؎t0{{m-;XEذkvFeXג:`j)HS"jt..3Po[> 49V?;A!QsŔ8%?9qL\oHɷdsտk3%^~Ei{DD0( M7g L`D Y*¥%Ljel>{B٭t8(}Px~dlja @{Pdz&8*~ݮmI^!1eѶ}{8yEk36%W^g7gX[>:_>6Q'~.Zaw{N?fatm,?xH~lƖZ]W@k>~r+>49GE(9)lZcهwtb&/cN̑ XHI=KL/̴DVϛ5--@H$p&}`J(D%ˡH"HnpDIPЈ.b}GJk삭/;E^UjfFK)ܛXi~,(ToJ!og$H"Wi?5paWTPmAgmkPUx~+wHY>2I7|C+ MG(>0ל3?{6IH>R̰ (XXAO$k|Q׳Ex* GT*_'r㫉AnnzT oRZ$9HzƺƷKf:{ܹ:LyLn|;8@cR0.ڵyz(fBqΙ0pp(m^<:  &WAEtXb5'Ƭuc/8k+ 4}9bfF.xR \2(n`f97c"+fH>X:6˵|o6ir-gWµJO+#A )lC!i^)s!J|͜0Q~aơ H4:~Y*˽ ǖU>&* GP'TFkR9) 4!}Ņb$[{~L} 2t'=&:RԿE1-)U.A0^IJ@@ |~RM?7Vkjޓ"$Eb -$&&HĿ# ̯=Aox1`EczCd)ӆB" AB}H8&d"EIrdfpZqIwh ߞ&3LPn˨x^z ʈNy\PT]SlaS,ζ!?bnS5# EV/?쭜(؃w&\ц|͢8M`V]{~wKX |>C*'pzkvmnD5!E,3Q0!AR uzy)!@w٦JAI0H͌CQĮ\{Err+[Nxҫsd)w?`,3Ƿ'#ܮ­b(D9,Fӳ~oa:!6I/cW{3 nƉ.Q's!^ [J/Րk1B,p77WyA },JTV]*t>-׊MոUl\[Fv}lC/n@IDATx[So$V ?P6%oqF6ذRj0]=m42X$j~^o~*85%!;yr0Uam{DžiPl4gD蔽^姠&2%S+GS򷌛E^QU (!H Y0ɰQIDܳٗ9>'[1TO zEC.$)N*p/0Єtx E},U2`EGe1 :'kvSs3m=*Hvl{W!.`:d;|;OHb/h8'0" 7o;&VilǖP*~rkV)/jmџ MB#ϛfBu0UvoԁS.⧍Ժv#&|JGÇp88#.җf-&"$S6E'|mvNϪ }]9ik:t5,mJWM{⚛ysۛ2vS?>o4qr6bT'gr2F x v8xV(Ik,Va٭a.hݚoJ8tH*~T?m /i?*(O\lȪLz~'\ɴ68!"l=nҿ݆ yʭ3TNM|C~o,6u$="ܝ|&qRw߽j, [#Ԑ$ h;mYKS|Z _*˃g1U6Ͼj b 6APM{vuXpK4뿠JJj}?m̦r=ؗjl!yDC#e?m;(Քcph:/"b~ǩumIJ?Fl,d:zv&6O(aG3:ـ)QTTƖ[#k2nkJ0:0Mȵo? ;^kŹϷ4WS,g;10V&NNю9N,HM̐Hl "E>[s,٫K]OMȪ\ѵxNk%V,)B綹U^,{Z`|%\&c5zmL{G+1%6#N*mK5 XM[db@3/#-sDmf jF|f1ۗx)W `L+,1d%'n_XϳW'R4Ԙ2_? ̆,bC+M`n߽1* Iۑa.^Q'3K@֡2q8H(բh.•e5g<DUt?t(O-tg\s:b/5f/HQH(1FiKZMZ!lb5%މhɕ(ZQlA2l ThFs,WWc$Bh0K%_ֶyY$2ҙvӥ\h 0V+ },#-s_< z,]!6 % xׁixV:M}AoFH;i4 ga2`vmBJPHrY-ϬGrS0IP3Gnznd_CeܖK\k8IKݙ~\$Js_!8}NcxxI@_)й_Cfwd&B'Yr.8?^q2уZȳö}yթXT(W2"G;61@-jNYŷi He6THĆAdD?шh,2.%N֕ v.j`?().+|-ۧ!RX9VOmR<3lOgtU[riM_ BV 5}e!@,ޮjܿ].e6 cE EUݤ{j;1җ8|~{}<.jpy( sߟ2m0CVJf 0ˏ<% 3#:^odPmj@a Hy yӔ##ǥju`O1$ ǛL#͵"/5`=z~7|.V>w,w <$ ' Y^jMeJ ]8u 9[&"x 8%ȡS"@5o!r >uj5:V !B% ȓh[T寺.Xf Q@(`DLw*u^tZo0b,AK2 SZ*.%H UW[Kyzؔ'1Q֯!fD5pB+>i$U7ƙR(E6ixY_ |6%)h }QSRu= OmqϠϪ nHOLC vB!]هb,WMe-ُY(֧Qc"o4#\Z5IDKp< <#"xBPbҴE|\Ooy)A+֛XERi"1g$~{<+3IN=5ݐè/JOIzVsIĬ> 08M+( e3 6E[ӓ[;* p2l$5h~"JdyH' A. A X "~` LJDUX>vg°!G(9>e8 G l3X,s~a/cV{Ujs#]]2&+$"iQPMOHsHcFꛈZ }ؕ{qѯXeOK2E*~NxrO4[wv\o0RO%"3&oL./n)h %N1\,nLFR|45 E)$:}O,Jb;3aͺPZ{źּ=1* 5>\2Fb2d{ҠZW 1Y+-H}V4w0]L=\F}-/S2^238"SuP0&%:߼̈́6nt>E%ܜ@Af H/Dh[O]&: 8Hi)MfdX#'clbѕd+8"!h.|t:53S*J]F`o.oat v/od owUM;z||8۫19䕰)Vs<8M!tY!7WqDTpe]we$t&Wu4uWN8¹2!DF"q=[-EoqYjasemys`%"q5Aߩ:o'3+@QjA3)t75ywQ2#+0rsĄA,XRVIȁu$`oa[u)xJ~GH"hW4ȇy\ f"uWv'yԖٜ].ΫҳksRɥ%LBUMiTֽѤtyXbT8h4|C 0 P;J#l 䱉^mlpb忬3ƱdD+}뻿!49O<;̻; PK&b\!we/ KW^fnMFi0S M\K1m' S5jEԨp}>@UogML93lWίt 5meT3Z֑f<=oëlC (9R0y2>Xȗ@pzK(&9b;X1|>e5l9O*~ ;*۹VHĕR B):‡6B dOUĬhvTEaBaMc/M〲{ZxB)L8 ol=]Z 3)zGOlF% &:dDxJ\$I6W+N(3PXlZD!\h_e~RbN9ţY $x@WS<_2Vr+x5I'fEF`Y҅vybM Uq zDDJyMeë*6e3ݶ(N }ǯl `(bEeAвݎ2> /ͮ1^m<͹%2WӎTRS6F@G\e-/80UCf(ݝK1'1ȍdP, ,E0|HiAN h A'u;`*G6H5蒂8s|ig Jv?Wve9 O!]z4Ge$R_@A߭wέMh-{S /vFK' ޔlzhxAF[?C•LH$7< ~ƪژv Kr1;>IV:MkqdZ_r xwGr2B+b eW jK+ߒ!`{X.QVj^]W% TN*rI$x0)3wٺtK70BD:o"BHmwJ k4mu3ik*H4oCQB8##=,qOR,A>-#xDHx3OVù]j>8YMmM-[,P (5 ]{ZP`C$BCm/(Z*}Oy''Ioqd~*CkWVSbߖıׅ ts+)C>@AbKq^S1+Tko%/0o/ <>`!#jXƈi2&dRa<&X=inO@ |{,`Ɔs*#r7*h0v6:Rlo _;:'`lboN:MQa?Va?8H7 {crR,gx~|<αY ;&8ڀpio,F\$,b*ٔ4}7ę Q}6(́ =m~H킨ED (X~_]0`& xB!?~Iڹ*h/洿)0Ҳ"(~LC ^iE姌)W̲Gd6f?J ;Ȍ^dG9T1t)b OgS{kX38[|;ӗ%.'6:: U}[Z- \rp>s@Otare(Uȼ~>+ʓ=yT0L(a}sHs2 XZ|{a{~fq>_]*6iS#hA|zߜPly$s W'6+?~ZMb Q`"+B DD+IkkGH8dmmSi'۶(F%-6ߍs 5>rL3ij!R0"(s3Q-?=sk-۶V(n@<4!!T"CUd0Alkife@ THLc1K1ŧ5įZz0}M.mĶ61¢s<: 3 [e*.Ů%/7o[>?,&EJDN2Xh#j!?;WsR:Df[W/TM lphi Ąb@y&Fʢ/XjBJ}Dz :uϓJyk>2ka'.N'(VMlÃF$[.f_ve Hq=ADZ$> ևv *ٓF/RR܎-]\ Uzq *c!9ah2K75^ZYY" Mg]Z2n$N4\'ǀ7cf}%cʌ 1'37ٟ;yiЪQѢP`U$.m1}tZeH1cY֑A!52ALc^B\pt0nUGE56TAqJ@qk&PՋ|s &,nQ꒚@7,s̑.wAp.7d/{nyWiv^/7o']]?W,PLeL4e1w ,'_0Kg @y*,oHDRR1LW(#jɜC#JE8X*j9lFhPFѺ=P.F(JJH EOF%Ô -V: ^ʨNc?S !d#A4R=Q)=iS]9VA [FÆU퍦( le!Px<߫@f'fZ&xUЈXzu-<;%h>װ`n$t/EaADfh^F|h:>kd8ll>.#C@iO3OXŕW[`p9"G\}.*TԤyCO$W@?-DӓVo8;YW -ey8Bf|_bل"GlzG0A; ~ޞ)=mJ9bG? n ">ZD2L0.4ԢZTO3|iR5ie WJ]aLTgYKOKk(sUY{v_ _܅@P&-fM&Cۧ ^e3aI$A/0H255DD aԳ M~QCb&,S ;L؈x$ =wHOݲٴX`52GbO dȗE~Tβ=ZP}  ks/&w`: b)*?x@+Ty6kY$.}i=\;*)xJ7@YFFw@YtH5FM}F^5쿰 a5Jv1@(ݏY 7F2gP|퓞s@@EcێxxUKUifslԍϤG~sT dA/E*`0#XkShf;DPfJ;Hacb#v)V0PhT4X hkČ8H{"-lK[mf1_"*sްQ0 O ͣ&dmLQh@L+2a:Vt*i$Y2z\}la8VcK4̊\X::;Vbó9Y H悩!Ҙ,tRGh׆8 P1)ñAGn$90jXeu"!+)5&G pQ%K\yvVYvi(A9Wdp4?#@B-Fz|gXzd,l<i4 ? tpcD|rKz2 N$M (I^o!}#_eB .oOEHjm#f @Cu.f^2aa/]xI܆bN ;Ph _I2Y9J i:7*t&Z'u"KZ)Sc&ʲפt=R)*b6ipThTL˂.۸GD )]'O¬{[rՊ <lCΘ+].{-noW9/ДȜAqai#?"'2@S#Ssu95 'O @  ߨ m#K56,ĥ,fǕEhFT mixd:YT@T*<.>Q%XBHha$PKsi~ .?04WB5x+k ,.v DC4՘C*Kԃ /lo`>KLٯFcV˼Ȳ*ұ - qLl-/$#=҅A紐 WT,|-N@1zS\gq"gǰIt>U5Y€*& { ,ܐtfpß (WAT2VqiO)%3QS)2'63Ov9\-z0j6'on#)-*~7Ci$v']g!oi\lWyc !#(0khlHXFSD&.@ID{a$%/"'x?=D3L8*xs%dC>B{a0"C\ڙu7R% A MWA!jÈ*j%:A`YgV/; zk`@e%崼Mo@k( 6Hh۟]/mo$̣u?( oJv AEƦ~4vmYli ǓaNW2:`Kp^{" y?]%,&=?0p/"N`~w]@̉$XxܘYDxF@ Jx@DD9BTĝn~Lqɑ@uYgϑ!ոX ٬Ua +g(ܪƹijSAn=2by  !3dłR&tUDQ-yw_ҝ3#@HL{@gT^n xͲG9e?PbRPSPu=gn%sab"R (Rrk}U7P~%W}h us~YH5k)bvl"6O:i*@BBLF R8$R|X wGѪlV_aug7`qź`DO!g )0g)1ZMT6kt%% T "o,g8풧|/z@WcV" puq.c"۽̯ԕ@ ~%Kk5MK}LmP"K$iR.#ؿ|R`slUWG%@ŰU"DzCJAeĴ|.MZ0Rl'jӁյcĦJ?c w\![䭠LXA0[KvuP :NK|eTԊT188yZB5n?M:dمߖӇo;7q+x Mv|ظXs,qy1FbR]Qdp}0E,ʎ1ޠ`oƕB=vx bᷚum>@&"|FP‡fJ zx~D>~B|ll);@ MVGE/D1y/Ja,-P,@IDATӧ3ƛp e,4%4EYyݖk*1/u[l ۃgdvXOka™ hE)JJHҟI[ukc' !TY@k=7oaWtQ/,q'd&.NcI i i)b}yf~`#]%_}E ؼ?b}zʹ:b{ST"#7djV*diUt0f14, )4"E/F63m 1¥"kF6T*j|Tخ-==;xC!WOom\&1tx {LwLo4Ow'B:q0`<bY'jTM0AlD7",mQsIcen7h&gPqTo`yLtVM$~R2ُe>Vy=84Wpf/6+2UP!+_r׫Ӓ%b.lk@~f~9$׸zC׳o@Rf>V1 CV4Ti$E؈ hUb}+'1-V(Oak##V5+/".q]UeyZūÛ:2CQzDolm@4Zy? E8ʤBFk.6|f@[?Rf-ԀcJi4h_:/4Ʋ8!`3jjxCԳFtFR*b 4#"D wò@ [|<(YXnΛ ?F#]d|ݲ~9%S]va{ȯ; ;qM&PLLIC嫶hx>7~OssfNB@G3#!e2?$y.uInΔKF?! $F_h,FL7>pO}>SfWG"dĭvRPkrlxŧ")mm H2U~wic䢝q+?.۲d?^T_DYM+I 6w'Zj LVMv<(X'b)B}2<'3I6v 1՜c{HO&#{CV(a>O414Z`:~m fm6Qx%af>Ƈ{"a{ p@*d$޹z3\xWhȂoA12bgabDk4!=B5s%b1wib7^F&=0c$a\O:-& :  zl. .r4. Q 9]( sE S֌fnFm$zskerѳ&ST-p}a28&OLAÉ0zPrIQWOKhs(EZiTDGO>v\)Wz5تH!*^4H0O{;4p:+NVVlb]S|^QšХp*tMh*SbYF"l$O&bS4v~ %FR]|rI@jH,Ď;0qAcEJO"bs()j qaZ>u6zyH ܡ|/6f &+"s6n0 N$Ԧd&`֣9vO ԑǓ>^`G`db'i`޴.a0~Gy/vyS2J'Q~Q:LJd87ãdݰ!PO8H0.^7& h,{I1 " ]:JuT .ijr@i"g!0?Hc"=֤p:5SADAG٨TR )SsLi+A 7[EZ1h;vЍ^Se`&^pfy>$c >mߐȇb#'pp2. H wMj r?^&Yõ'0.G34yȾ{.0^88YShYp1_Ah}-d,{ȅIȄ"HB#xN:317UŦjG 4 -ҰsG=¯ | ZCVUfd*H-)\V<:lnm7'yra.roǽŤ֌v"tXK|XV pbjhe]GC8 aH /;ɪi 'Hnoj@-p+%{aRm5SgczpMQ\OLY GCuuއyoy&CjIgz7kLxIj,D|gsCFAnT&Zh0Z+A?=ƉykU޴J@3ʴ*P+PpM_?`wuD&)C6CdcHѕ$>꒼b]Yצ* ?l"-8s)/jxE:5er?Քr8?+raLXdUQvIę"giD[Ae.{<& \Ф:ų4um|mU3*>jd":2;O `&0>␀ހܧ`ZV fT_'lq|iD4 $u[9ƤupğAjzTl0٣ O}&i`jىN#] .ׯ `eR틽[ 8zOUQ*)*3߈[Ęwah@'#._ElB3?57fˎ:nh TXMTDۥؓ]w.g$-i 26v+Icƅh ,D"nj(( ژ(7[M^Ų1fa7PjQ^iN\޶Y T C{ch(Q*H54!+4XfcX:9ȺJm{hk~;/GfNl/NG[=r&PxR/\'蜌G.ToNڹ@aRޟr06_a!@űk(d|~J{sۉPr펜DBi>'OHB4vACV)ME̓Eznט \c-Jy`Ƌ2r(QZ#c l`O_fEu1zF]9.CM T6b5G:'ۭ'wV'3dY< ?Qw5I|֪ fó[Ï^[57$m6>%tU{\1(c3t̴:8ޭm/IsXhTJ|@ܦ r0^\A8́N*d@! rSguhۣKLrR-WfD n&|SS2!H-b$&}PUqHY>a1C]Njfx3#x0\ⳒHB "B:ZKQ6djdb!N4lmȈ=eB8F/aG,SީFW*4~gt,➸^bے nd##6"p%ØjH%4@ c((@&:h!AdnzS,L;#tk~z\cY{~9}Ws`Q!gp Dʾ|#zoJ`&IPpci#V5z ƂNZ4dBYLA$]i8dczK/XDn@IxMkŰAل)Ha ̂$e/ ;Y;-dXmD]Ͼh+2hme djMGcXyU6ARp832t@ {~4Z K:ThNg#2[PJ%T9zJ]v1娆z)0Jk0NRfqr`Yzm~y`9t:e$M <&GU؋Ty&''zbMw#śy@  g~# cd{c=X Fm`#8aC5Cs и& He4j>kpt0$O '=Ϧ|7j4`Xǣ1*P`;׶ jɭM4H`e;MtP10Uc6 !` L ~(7oYЁZU$BDSb9X(70l"QD:u@{kwqˁ=~W3`P"y#{Ch'l8cK#bQ 2Ƅ[>d%[/VGt+@fˆ.5R)ItnxK+A'JySs䞯NB Ҩhrz<0H)YA>*pKJr*S!yz=-ҏjSv4rzf3ZIb_ϰXDQ^fH/Far䖢FNws2Y]dumSq"d4H !?neMøh'+ӂ2.ṳ̄%^LDtJ"0oDyETi8N/!6!!l(J|I9LHNZT[؞S:<&zЎSAeчE H7?aHs^_-w7MHcJVn]̪f`omBCW&̺Pl@Oh^όȃ?"!+Z-E9_-3Uؔ<ISC4DܚnK0x$ʜcimsqO&TsH gC?[+*kwϫ j值9yZm9Hu8˗QJ¡!ZȻ6ge D7w?>=(;ƕcO]+Gܔ\JJIB9I(p>Gě>%L݋Nzi,Phi5 U.:$+ZCҦjKbb{ @MN`NwzGu6%j9{=P(C0b6d>q뵌!Í۩E#h14UJ=k,3Q '\,@vHSB1;9=lC{ 4TLSGfsc&v Xvpp5jljQ/-U\.ۉ|OGFW5"}fSR֝X*y,ڂVYECSV$EZhu^as!)AdmI+O@$hZѨtտ{-G Ox@79S5_$#N/c,$ư &&P̂ϛڎ{hģh~'1 u͌=hf}jB,GTз23 ,c̆A/al]QjͮHy"lc m='sѱ s4׉Zg!A֙fhL-"o7dy 7ي*),`i^f&zZd2 j.j{D{@&P/1~FmVZ\4h2 a֧ J\d mNjn`_Jě&2IÑ3zrdo29ڙKF}D~a?~AA ?#yЯG'7;D.AB]EK]c/E I )'l f'٨A$9$Īs*l{ʅ,Ynϐ;/G9o 'Ƶ)5Iip⁗Am\{toOIkH7>(tF1 b#{f~I&}&iHlI5Z@ 32w,{~'|zVD :PelIIf ,-XYՑ7fsqp@v >fgr0W; ؍mw_w |zwhM;vݯX_]vmt~*?̕}}N χ=C`>wp=Vak$>؁xʩ TkaÖ#M +Ũu-PrcJ6܈%0\xspP!y=ev3+QlH|fyrE$Q!xm]2[{xԌu:(7P8f~*b&& 5$BΦŌ!`d2*sq*^Gہ: ,[m g^q\j7a A.-1[r<.ktihB+*,>B\Hٟi>N֤*BC9/ PxIx ttd:Q:3P`VՀ\6Cf,!pxlxg|k[uFA$\> RHԱN[uDGTU_̤H&Sy's2+#W 2Sz۽l?T&yS<0Mpv'</q%vV5W"Ć""@r嚔̄H'%D!=:~m\P5vBo?eaMsKT̅NI ϼV#SE~ue&vǹ:crryڷV6WG#>ٜ͖x_ j8I/с{V vBҔeO'wIVg#jj}?rڈ˟49wȟCb&'yADA:QUT$'Yز\U8lyn iAB7PŊ3p.[/7e>k7%V y웕Y"ڒFN%!:7hA3 `}1{rLx+GiefwJG!(ԏEhJ_XefM gJ%tQQ%,LtjaocrC)K*C_u^Fbv&P\C1_bS\ɾ4Zg:bvlczN H%[+{xX LmyX@zaDwv-Ů mNR87&7QSyDX0Ӓ1wCA/C{04h4/g$|6Rw䕿S, B!Uz>Kز:FhRQU1rU&6H BmsUXidSk{}Yff7FOƑk9I|u懶`SR֣%=SrDc[?kjbɲ39{ciIMuuOt.{++87D2 ZIw-r/ll Szǁ@D0 g!\I8jw`Խ Hp4Uʳyƕ?f5|f,fZ^sɴ"Ī\4=/ 56sI8xj,EZ͵KT>gZuʖbi(RGKrB$th) p'=),-7EPҘyjSQ(Ru#YgW4Bĥ,Wc;1:n/r.,ej"i3MsANVwakL{[jXcY3e^-f5:p޴BEbVº# O C6&&PUsS+MvDnt{םK{#NŪh3j/<9ȠrazI39s۬eDQLBZG.)yXY@%$s:*H/!o۷쿘|Dy9UdGȐ 6I8W[FF{:@-fdQ%P̣KEÎWwI$cH=Qc?5Fs#X "fXdt#MT-(qri@WjCsPF ikb@m׬(V~~^" Q+:mdX2TV4M "b-4#E"{cpa$Bhv % 2M$ 2`h;yeMCBJTK /܎v%J\N# .BX[5<51lv˰Sz#eB tzŪZ&#wSg3H: BPYV@:zW+tTx[ҮamX-@mEA0 p }S`$Q틍Y²Re jށP5=uA- <ˬ6-|9@w86WGg?,ZDdVũQCs-\ 4 cYŷAK,y0SM9& ֤uGZAUX~Ux^Mvtl)I__jt(jV7d-8`hzobnLz$~MaA9mpC)\:H_spc=nVy? Nf RO//FZƫaiQg܋ɷ_d~٠#JM6l?XP`uC5?Z}УO+Hڹ@F[&%4ï{Ok^Mu43 :ٰ.9?ڡ[`t|Ҹq<8>y쌇ZT3fSBxŏP$̺ߗyg+4D^QV>8y2Qp:yF"D^!ydܳ,zO$abPL& - "G Tf Jtqz5FZBRzMˆi@=KywWFYr% dkXCV-+k|ķؗEΗ:# FnfI!/ sy?o瞻nv`U:AGBuZ賌DoI=k70niWZ 5d2 *iP' e@N`REW5SD4@?M X/<ʞJjGҎ.,+i[P("C*;Q/0Bo(32_CU4y^iA?eP4PAAMQu U+UǘІi@vbw HT\B\[3f &fשe]2)œ) .nrQkt|Wj@&2}Xo:[r`cS(/ϊ%$K =`fOQx: &m\uYrx/Ae{yE75/KLf[AL.R&,S`-Sw@bk==^&X|1=uմ[`eA0-EC%+|@I:rj8Hy NWQ^ݾhZzPB*!76~D[G܄xIq<+_L*;* pKڂOFޥ@do]b {KP_AGXZ(J Gm^-\DfDqř#1W%4lC-jT2 .<LXbŝő"5"R Ϸ&jh|'y)gr@+`K6WD. }#(*SP|4r} 2$>/aԱz ҀHUƽVіUZ^whH= J6.0pw輹ڴ&` INɷy|>} ϳM>8xU(nUQO!>62@[Un*ú4cRc&8W5%gšԡNHOb[}<>7wx&kti7[v:-TK<^`j>wfK>MuYAoܣfW6ߎҜigTrQw!OTz&53$wh@w{f+KYH,{27Po(BR5aeB!N!&Ϛ;2gL&-L(\DMd/QN'|J7t"$>H 6H+Ko(C)rb[iu ⥏cpf$=&Vn|[d7P}X]q; 7t,r"!"HJ ZV}'Ne31 >?Q=2SxzAJc NSz)fe%sD\goH>[i')ZT'@cE4wq+~ e"ƁT!!^2 xlH=0GH}=cVj!T8HC|A + ^=1|eY)$y[`K7+(~ / !%m#(">}S!ru.7VC1{H\x&/V۱a)e+̺͵(f5+;bywHԙUƀNbN\Si ;0Z4DP"~tlOHr<h仵c2E05{IwU-'kP2]~FW*hlHG5GЇΦ,dLF)*#T*xLpԬ^#EJ*iZ.h}/4tS &ƔGAf'bNqTʭbe-4QM9" a`E%j߱Q9rlgª{z@>F`.*j~M  1I.QCQy_ٽ>uEhr.ܴR7Avn]ǀ"WZ[w0懹Kb!ƷPHԭ!ZJ@ c]٘oD.m{x&zhwbqCA'Ԓ676+S؈aO-<;kO3+d 5[OYB28Q{MyM\ ._lY n=B@иX%#:# N Gٛp#,2SUFT`S*xr8UGwU0dFJd5{˝jI".TgH-x/̴:,A XcN(.Q&;s4i&GQTAGyEJc3YW'?|tTE~e2LUi*r+Ah*.i[>ҘkR,XQ2Qujum(X-o}Ld8RrmPֱt. pZWa*"ެP4ZKմȪV*󯯆y`C~QX"K^3.X$~Ͻeu`}̷˄Tԕ6+DY=jSUOBڪD0#;+0jODU! Pt:f$}^[e";@JBIAϟ;[0t<-m dXmS~$?JEԼć,-d%83971P}|lKWWt9Ď"M[`׾DSngS0Kmbm!j<=!ZE=t3YǏ2!i?v<);_LJWb=NsT50Tʞ2~c5d3sI`#b zFH6ІMIv#zMia-j'75P¿9$Q?2ƁdA$I=od,t(7y>-=6\ٙa}zabΐuV*k؆Y4㿬~5 4PAV[PIwՄ`NT A/T*h2dH\-DK&Eg;eq'uʨنV(6mP:^q_8>#ۘ2/jC*;+ByUϰ&z.LOq._+vl3)ܮ A9|P,`I`+ok 1YU{* ~jS,LDB6ʑ%v.6/1W"7I}~7:'u'7Jot DD'v P}֜dIh kM3YTÀ_řza9 'Cd%EZ?ѣ44 4ZAۣЁ+`} &-wjaˆR! ΰS~z2E@7* /Vhfڎp P6Ouf`ˣ-L qZ yGI6Ens2a.%qfg~b̍f0;_sU4Z>9ZHEjiٲ\vO'XK/Xe-АulNsߥZT22  Ab2 0͈mAUHuL©_v`$ƆzyB݀=Ѓih;5Z{'kԳhO,c,Ԭڙ`pOMQKژ )&.RÐYs%9,{c=tt@HH+O8r+Psv>!`AqMޯZ?ŕl3{4ST M' C6Ǫ\uWMɌh'32lTj/Qya1wױm@j Ч^СK^jHEF )V7ZhEܬn3 RE+@P (@usQ{R"]*D'CE佅 ^'O3Ei.¤Rud.V_jP0U[|Gsؾ:@X[ftrUtNEوJh#sFeXTmY4ſ-.q]f}#R „Y /5@_F?Ê ?9BN FɱQw{!M7$oOꊅulvOO|zdW[5<Z1](P '.&  FdL2wFv{کk5NBUU cQJNpN{rAo 'W͡j]uF)z+B3fGQb}Dq GaC>o kxyga\SsaO+" f;&9D vO"T&}NM}%`u< ?(Ce01ILGh^rN[./^Njo)[ca-_}V|$sy7v Y\'=^ ($^\DFV߭e"hVaKIvA[ꨓZUdT:" F%j).tB2F\*\ 0pz;t"ś@S/y]C;9; yD&A=sGEz;anK6A+C:BoqĴ3X;GZ`"5:W_:vScGfM$gc_=?*  RR \ӋKM`9=cofd* S|qؑ9 ̵(EJǬd,~\T4 pXnҡro/ve'j|Egf^O&i69]zɼ?:py".ԯIPBDe Ey-wc6119l1Lwoǒl#ʘӦוWjE-'#ͭ3N&RH:V] "&+}'z!L1%5@٠FLd-#a^hlJ7n=[I\FGf;2&OJ6,`uq\>h(2#)EuxÏ ۜE:e*_/S ޫ pÓ!l!om^u5TS/SQRa63.CufJC-hjBhLj GJr͖$WѬ `#ykG;Z"Y$jQ$/bScCxo \y luEO M>/Aj3[RGpJ>M >8-B cxÚ>nsBps8'wpctXepuMhp9x 8XI೘z2ͬKbӷBFpģߝnir&t%}Os><$˛FL$*xfl^MV9:D~ n>ﻷ 65rP/WF(+˩xN#W'j(ހjYLN\S91{a,}R*ylyjTļ&4 _osF;P*eNES(R2ӂepJh`!$e<6%>?:g'<| h(䌼uo"@BY*lxltB sc/čև 5$| =/iC+y\QsDF<'ƒPCLm!YYUZi6 S60">,bI5hXIL%kgf*4TR olա`zd,$ހ> #3X#4@pg(SNpQOx?$5LA2ҝGM3̭Q T-B4s8P1(e 5. >ď )҂뵔:F/oNC$*j"\t[9k7B$P@Ca^x_V գed(0 4FY5Wk띇աizJZ~ј+]?E Tzj;j[5靂P:[-/(0R <4#luV//?w0ᚤ m9 Aۙc7-zlxiD1h?Zl'Ei EVBn4NUJ+kxɜv LE*fL I1]$SlkJ/swG]*a|YkReZFtJHezpM)343Kp[m_ U 8=N< 06R`&%㱗Xøz̶lw@S0 *z_wG1?C_eT+EjҊp9-p6 .`L˓o#K "VðN N)ܲ_6 GLYH-$F罬ЏC3P>ʲ2LLAkYd>/f6HGxFlҸM'R!{,4CDPW~mDk""$46:Y+C&\TXə' e1 Ӡ2n_SaP=dMB< +kq{ 39A T^F%PepT.g9 Pb#venYfӞD워 uJ40|V@is.)XypxԌdh.ߓZe[E3 &$Wc|xKՔњT„f]~>2*J|ɰ'S6 P,RI/-TI*u}ţtBOF{"CC$"{=ŘǾѭM<dCi2V!2M6&AzHXj,>U`|8DnSZ0-c` zfk pUuDiA}L[@"{M.ŦZ!=2_ϟrLgr=L$;SukfFAk6N*&e>=fH̕\G)""aXmS˵u$D(r)ƕOa޿ڌF)S&6aG0fC_)w&()z7_f[-}fLA_Bb>$~"[] bsŀ[RzG)z4jsPN;i&F4/r eB f0AQ Kozd5r2ᮢzQJz>^g&g|DJ` <^5?Uzi '@w#i|MQуM^shˢJ_Gʫ8)E<%ٱƛ9ACKƹ&= 1/r!]IU@^jI} d\l20k3Sjþ?P$F5opᶆh!^hԉbAD*LYlie2v։fJj%``2:@Ta=˟k$ ww>^K,a}Y?ڒ5nO+s@^of+/BZ:%2vFMky(#k=/ ٢؂7y7Ɖ,~_Zz4f'#-dk&_q,_Q)Sx8"p5 O<^U'kXDRa͏cG4#qth}1/,W'c}לQus|DS $,aV`ą,>,tk0Y-A=Մi95Ⱦb{NnRLU@b'1G7ӼUg\Hߖw5)bAh2 aA"3h k}e<~-ϔ:1t"_Lk=Kmϝ32Ӌݢ+4Zކ"LS Uܡ.NZSAیbB3D6_oG=>>7+ >7w[/V^WV|Tv$kG]rwUOnF{fAJmPzaChvcD ;T)FC6b >L=ͪTX'Af ͊emA' m)\b afU !#'mʢs:cje@BKKq>_hZ"A< vtS_"]mKq'+ U8X>cΝPg(s ^8Y븶2Q`hGcżm7L*p !@kE6͹A&)/#:)/XМ'LJ1<|ބLm!j)ES38<'NB,=e^j&/pԷmHՈu9DDܟ^OHT`6RgڬCCL)2M096Q*$a*]BЁ1oNMxsX 9Kș؃84){w>є`~ .(u p-~"BT5 O7i'0s/R~*A\g8gVOʅdZE{R%QGMi@%SԾj KK*0Ud i޷78kZv'H'^c-lR*y}! iHi,1(^U ζ~0Tk s:4kv @tdH.!닞yP&׎j7}}4s 'IJ}=+:ԌNUlMIEn-*hB]d}N/f+p&y/k_Mū@6X2<=A:$c_XI\E>)s85oPZK/gj>F̞vwX "4ғ* B'O>.g.]WT@Q\\(#C!RLCzTȣ# "|]BFa3w?zSV:bt{K`;deHoFhگuqDۓ;_!2h-B@ȄG :TWyG1\f'ۭ׷ #`|xC43f3 HЍ!JT_<} `) " KzU*Fj |5vP?ǞJ/E,*b XtP碠"iOq;EPHG3ϤJOձQ ^(`&՜AP3yCXx8:{jY.iL = {SԪ" Q220,Ityc@fSjUGQ9iQ|H\ ^fJ;`l|;R 1бd3$]rXB??#ƟOF,N47E0g%A-t XMm;r?GF4vQ1p+Q참aVZ24G#cOiI{JrՓk;ҧzV^ ɋ}8i 2=؜w;KWE,g._(ym>R:1)tV?|3oTj^IV߄S .rQqk4{X]`i*5&.e1Ÿ%mPpra}LK'3.7?26nJ鰖] M'F܀A8%? ִbuΓkhh$Cr) W㟝 STH! 7L:w` wg9:CK{Z+/-?WsF7wd_ulR*ARH8\ci uѡ_4Ď/d d䱡1atuWKw$v{*dիW2HG uCFNᜳn5U{.] 3$8 m:;UhM٘#$,̟I5=OT,@(Mj XQejO31|iOY\`#DPycTj+Rj;dd„{ET+1h)zVE|8" B v91}(; 6~&H01*_A`$w(:P7i!O.] ÂwD?ZZ|dz ezzlPr4E 8AQ DXl|QQ\I9t 3,櫓a[2JT\D!=k;6f+R;i2*p'{oJ'FDbfgɹ &"4vh6":'#@'$*>L%3l! '0_n,#Rwew r!ЇyՖ-5THJ@ eiÎfqHr66j?^s3kͮI as%AgzC6y[81cR.$u$FZ^ɤmbYʎLKynen7ZЂ@:eUGhh4afz=R@fg:JR8C|q♳c Kxzh +k-uB/mJ4Vfqt6fl<}QTdl$\ ($# Tk6^a5wr;;[deFR*Ƀ,dVE0񇶪c>2Jd$h9`u. &L.Y=V=Rn2@ cXMSZa22EqlKrm)< @5e6.jj/㰫'nNU$^A|f.&AoX~P.O"dRwQADȪXN~v_jCg pHMY:[FZ(W1 aU[sq5R6S' }`q^AL`0{&{wMph43ϋ*zP.5l`$d2>75*XVԋ|U]QX&QR"nwnyR52җ"19HIvJ-6C*ӆJ9^"WAR)BR"*j2+cRmp%trYAmy* 3f/穃@U'RrMSsr$jAnMV"g; d MP9=poSA3#\F14K[2 X;h"2܊^ r:Ï*$>5K8Uge?HƤꐂCL*;ZAђ- 2h{ 8[y Gʔa1c I6QSo" -hأeݠZ Z3aTH?'p XWԓaK`4܉xFpތ+4N2):T`LnbӋ<)4QH ڲQjfځ+ԪK\KbG>EyUJx3 [zP 6fkyUӋЌ?DU^lTȡul&v$KTjX.X*e~!.P]`g4\PjPwP䴧IiɕjäP}ۙQ#3&XyE;H7*jyC*?i/!|%CL:@Y@ө"#SE=Ti໫g$ 9M5GxTԽEWDNnj|xk KrQ2#%!I}qY}`/m&EH A}&0xv2)f P@jiW|~:~,n4' Z@+ʌF-?戨%l@d{9k(¬&PeM,uTؗ BmYܚA hœpGl+BvFR˄_g8jZМ}-{7N%z&Cn V`Pǧ>D2oeҍEx/& d0!GzE],p7wik7d%tEU5TQ琊Py˓(eC†Wf_-cuԉDeB?iь(Wtq<6J(Qm8Y"oMjJcӴ 'hsԃ׬br]ІZ7jP1)Sw2`^\_ Ei]}h !][ ̾.+*z7 b(˳4d{τ|흚+]`"O׏8a v Q: 9>>/q$-{^wb9=ZfxcYyh8"NN1N (6c,|ړƪ{+E2Lع>T?\5'?b71(C S Qk?apjJ/L+4!xzes}nnݬ@U/]O'V/xٟlVGkH /%^."{2ӧNy+7 =0f€(g:g缛0 +賝^^~{< K{q>x/R2Or)FbU "Cw~S*`_ AJg\:۫+ w}XMuJlO͠'C0472}{&SQ=oZ3dwg=pS"vL)ԸT-qTq9OzlӅHkA?xXwN7_&2p ~BK #/Xc _]њD~ԥ3NL&x>N!#E݉6^fFy$vF2%W_ pァ|6gxE #TM9* $D^7:lN~MDRdI)u,){nΒ7g9wLݪ/'%/6}`jGmf y`C$2_p{':۰ 12ٿXh=(KnVmCNy$>I6V_.xa{?I;U yqLG涖k<p2r_JE~E KƩ#4`r<' ,2p~jg u+j)(n4jCswsFLIm!yG!wf[zIlA5gob򉊽)s IpY ^W?†JLjvF篭~P|F%[)-=Q&oӪѼ !h f NO[FymRaVB#c&颺8[XG0WnvDWIT05⩑JG8ٕZ싐1B˭*z7*"δ=+,ZH83 hth ɱ\)/P7!@B\.Xm׽3~ڿ@-4k|zl(Sfm߻#[ORyً6BZrgwhϽ٫MWv'JMvP}ZڿҺb@Uk'687 8]pNj%`!ahXQ/ٶjH5'óMoB~=WƺUWA^QT r\cN>^T,w9#qQ ZK{i4Գ>J.CR5z0x=pwJQFk^dwQE?QRA5+ G5Z t& f'9Qyp;3ņ'q?RS#ydhbA8 o{ₛ~)s81M[*la$ETFeA3 "xTY ͚"Vat ZNT 89@*؎vWz5a%=N;EsMre"dB~>f wf_{6TRra-n;/^X:F=)4)f~{S58-z6#OY'fK8Y!wbkqD&Jv^3x[)#(\ՐԢ'wt1)G ǒln_\(kxej4]Xej9f D1uYvdzCKY$8p-*-y?y8} f۶p|<(CR)%*N/K ;PldS2Ʒt.RY,2v s弳 v1 _Cx 1^ obaөe(\2YG2xMLC_朅l홆KjJ.sRM}*akV~u) wDK1":S(n*\k[@ƾ;nB1SoBG;{Z(23M"f}kʫ!Bt|T N,#fi~J!՚D35 D@B/Su9)@'TtZB:{EYEV~d$KmKGDE,(>q % |P;s60;*TbnG ,U3 L@̏F&^q_ Ѥ-N.✺l(ȵ:NEgdiRw9˭<~҄!>4GxjM^ьAH+VQض-g\>Տ (?|ú!|8pٽz ˾Mᚹ,}L0W`8+:#y(fkʆ*8RlZ2:GԬSݬA,eb[H RF] )pJ*#V/'z5rͧç9He^tM_)hA2Yy .ӯGmh\ōǑz` ;ǎ)$a}4eX<^Rg4uT}( O)rՑm :w VQ/u~3IId =~ [/ EQ;HB^b/Jӝ_?_zt$A䨲ECw)KP7H | mH,&'ɐ+a&֩Nt%ڈK&g?_jZP`Qh@! cFYFgn= H%e\Y#]IYRj= sɜ@x/"a77'CXc97$X|`XT a<|F(x#AAU<ј{aSREMho&;˝;,hsR[XE#}SQ-?iY$=c@UPt&Zme$=^P!aT@:&imAX ɌLך.xƷlM!4!G*58OwBSCAyXQpXD QPkJH4!A.hFOBV'v=ࡑ+K"m :8 ́Wy792j*D[dbƲ¢_b8W̺&qK ҐQ 42j / nۇ!e:5N, LAXANC4.zT[*F`Pw4^fH`\VWsK@`.ߨYfM@bf4)ȡނxqYJeT ɦN'3IV|2=>Ee V`cQ7D ី} h` 6;gkdU:6Pʿ*$g2k³kD #)[ժ0uqm8Q"XhNPo~Aµa$8/&A7nWS)ӋFVd0kdc[S ztHؚLtծT*fGITxfF|_z+G k\1Єϑ #]aA )tc ScB,N=[<1xnъC6$:g`(,Q1BzQ죇0 gõQI9B30 lxDPxDzRķ"|Zv[cd;8L/ @Zho*vkN`_ӡƠ6莎-maH9*ZboepN&x2ѷ܍9M0}z;4db݈ -=E )"."?6t)%)D:T_"u3q&c,v8.J]%m!>5״BuXlN~fBMj]e *WFUM>XcMoʫrĂtH9z!ٵЌ?/:-SE[mqnE@Wx!da @y PYPedt9+H5 ٜ ȫ{[ *80QZn8ҚzD'E_V!WDoǦQA:5=K:uwsM^R+Qd ݄WE_+%iS"c={/kyviY@Q?tD616=`+x#'Q{% \8{hnXE R\PCb"X ы+X9z\釵90 ,S} c!M @Drw\T9XWa#YL^DX24oKj $I?x)Zn7YpFzjO]HᴫQP5 6_&]Va <Bff"x^D䐺vZq7L#D$pJܲ+ UPhmnD^%˦`b tap"0>5aWAE-*D[:֎Ζ 삘\eL4MIWj\(ox4MƐ Ӝ?X'{F`@\8Wwӑj(.tu1A?Rhaev& Q2:[dMͯ\Xgy>p>Cnڹ;&3Hܜz!96~H^eSv]eFC!H;=0$*FAutKY+1RLZWJb 6 Y.s5GGFi`d"?1IA8f:#XpcyX8^{uj[-56 |MxAF篟vm'͕A*U\_=&zY;p~oz/|F>E+__]1T:ucW\y8Љz$\V#/G :^B^%A۝\ X!H7cя2z^}zٍjg?MJ;b+ђdkQX%Z 0nkT;q*R9?|QAgI^}# ܙ*_JF7#Z^S `0m. R1OK!ھfq""ڰ0zm"r5\'XqK6dyӳP^ѥ%Ht% +q43Vm_Dk [''JD?N{5X аOz#]P+]@/`#kct`Cr8NAcSH,6pRLt,uϊ47eɓ6'^Ad5I >36ס8V!i!>FUӖPhP=wY''~^/ eR}@c[C 1cZmTz<fT&ֹ\@Ϣ:*'?\^7$$*:N4uzig;[\]_٨~í{"[h_(*Yݴ?PY@CU᠉\dL)/On,ԣT+E'd˶)ѳ'"52Am]%;<ˀ9$;y>tcϻnOn+LcߟЉm&ޜ2^u97?@zVg[x0 q6i-֖ N: /#@JMF|uuS,~щtfzE#P)"ȋm0\ [H؏Fj8Lr'EV%4)a,`7L$.*Q`pe;8[`z&v+ƷUMzC̦Z c<<\fer|L2?4%~x_wZ,bfN=`I./N "YѾ뫳&>?h ʘvgm!vQ 5J5>u{oU;L/@n}\}x@8yyyjt>.\}њORɘ5wWmT= qgjd.2 .sU&e{g py2G'$KׯK<|鯖ܮ>&ilѻUF: m'teiq;ڒy~1/?=ق'>t;<>r@G1_?||9?{W~1 ~Lo `@3Kn!]5fNh)~%<ӾR;GNx|v vܑM0M{\ۀf?~ElW:b% J=ըRB§3 ʺe? 6g.42 'Fs,7hx[; 3r*x2gLl¢aM@ʟ>k61LNs/}k2* |McM\rE=x;zbI r#VޑÞ^|ws|mDy!"PZN,?S"g-gW[ ,y^r9KAuJ!^DH# vXRm :ӠY@[AO1U=;ān,wwgC-: :נ72N E-_5j[N`#b+rװy 㥵f(ϲRQy r V@I=Ǩ]v%gXkj=Tj1BP< kjQs+>1[Dt1x_ͦpJС1>3JL]AbOjkt.u^l/(Ѡ 5.(Vٯbz].h5|z6@#5k 9\K-4 +G:EUs(Fi%F `pyiVF@ǚ>~.98|U'DC2Zau֢jJh,輫g >*s}U폆IË8gϡ_ĀM=$ŌWMȐ/r铦&#~zK! h8(`_# 9&Q}!O2OTً$L]0w'6m}cqoT@H^_e3 Qt=8 ص뀟΋dDP&ֶp82Y|EFnM ?p-Db ,/Xe]@#"Vd:k$Z#AwKjla.θ]sQ7T[u(9`sHq yUk~:Ǯ ʊZ!1H+"<3GFi[ X0d[uҽOCm.krIPٕ5q&ꩊٻ&9ZIoNlokLEEim Vk3w3t.u+zFEb!ʬw1۶Pti :@3ZTWЇ4Nh. 3jn kA;Ih, 66y088Zi2&:&1:a=h}uζNxήMt`j~R<Į40j c{n?VFHrgDg}ʌLvntFFlKVOjmL=npױ8MlsేBȿUe.N(__ 1Mww,z q5U1B}I;EN\v1͕@ MCj=TRY'*/EGID4 V"niˋHԧ\7`1W374THeF;i"0@Df&r h5if ںm)HFܯT;|^9 >(Ba!Zoo'2C yxQN+}RIiP{4`EIh"&532qc4@j-3HvEWvgϷ (7Dg/h|D^W#v|s#%;޺&QMR#"+\^ =;9͘?jG#JX߄/?Øh&X`0!OO z* Cį$h3'잼7jE+#9O-Y܏y&(l*рd˓c~>M]6`t;Yrkn=J">QԦ #$k ]B"=LA4%Obuq$_qV6b7$Їbk}ђ qtùzsnH_ AA Y!2a̷ $⼑5R>bh]K (`Ǟ`a>K@ꪟAFagL`NB2GDͥ/{3`/#O5+/a'u4MɤRXl1e"pP $¤g$ćyltk16&*mq^_$'Wp&~2RZ0 rHtqV/S0B!g])>7^LYa ~QGy%/:3Z+ќM OߟL0RA e 45fxm)c45R2XE(w1Yo &\G#a/MIJnnPrdgGYQ!7/Recrruưx]P@"@?* uZcD 1 Jƚ 4CȢTɎ)v+%Y_(Df, uCPzH[3„t#4_5&^j4Cv3*ZN^c rtU&tֵ0мqڟ#w?j&Keh7fڦ@z >oKPEkC`VD}7lԄ-jsy$3NU!ͬ:R}}PIsk=ZMr @f}lY@Vwh~{TN|)Q SrT|@۴b8.Ȓ1$=c]0eI19Ĕd{ؓAvTaŃQwD? >׎&hR_9Pɘ[ѼuNRn[Fd=Ij꯸)e 9/y*@΍lƃAI]xUno>k Q uY:m\&X aO+BMunRWGH@S8:XT{%  BT2AS1 a29+_СOيt'\0 ܄"&9(F 2h\J.WM( v iqQp_Rz~^<4!iv=:WA`Y5ݭhUj:i-"B a:%r3w/y\kDJ$]SIMS2UR WW\ܶ÷:ATB@(Lq>K X'ZOz iFUjEzelsު絛\T줯KaJ`c9FnC5aUeT3Gm]cL:#EtgkYSk6uZW{;Ƨ(Wcpt*I ¾yiVcj`v,71钤Ә('[H7;ji77t$Ry9pwNlVBE,}yly#{Q"ysBG5ec'{o#H&pGX&аR,Nv?O%DC-8VEXh~*_"YހCA>nL#Ōp_bJXm'`2)ā!9.?I.܉8)ƺ:P]>r!ŪY{8=x P^@۬?t#H7$SFw'f* taHf~0 Q`yz}Cf]Bid5Fɿ{/|3(^%VjB3]Q E0ԑE_ЯX_\=At*;1ʹVʺk1g<* |nSTG(יRF'F~m|@"X*[62#H-TFyyح|t@ 8| orڪ0agE6D_cF 롾2X*5~YɎ!\AQ='Ee}2ADad݄'83kA. .w;>D?\jAzB%u까RQ3D> 4!+dPvza!̻9@ H6S HG bFcK|K%c;c_h|^~.zFt\BXG @\5K5ēڳF*nшErFݧO$+SЂ32yvW+X+99 E>"8VB=s.4ƾt7eh~KAsJ6s5B@ִLh Au@J %xT [~X\35J3I\45#uVEpl0r FMY$W<Z]-wSUp,_x@KZd 氨uoE>2@p):$%:GpZԋ=OLvvKsgY.%,&m@IDATbj^G]k ]Iѯu| k^G̨Yx%b սȲy CQᄷ RRω)-M}ق_csɧecmi$dh0DbWЉwE{# heD^Pnѵ!e-Tb:Y!AMq1KPPÔ__f)Q9l,, :C_'Ncx Kڰ%bXIET 6]U\ 9I5-r8"p]E;K~/K c-84"^c7AOڮ zkPUG~,L>E81J b+./ny,l)Jbk $]MB떀o;y~-aiIᰒe#EH/@brYa9X ĀD7'Pidnx5Lە%#a Vo$$')ӿ_{Wd/· $ɳ"D|g#:Ѭe3%m*[|yi>9:1ĮK $8?8sXS_ɒ1дJ`{= OGf$,½IV֫ 9R+yttmbJ/p,'\K<{ΌY_c=bf/B9 < F_{J*poߓ$,'|JN©t-Q, >=[4!MF2v^f%\嘒h9)b3살 _'V,Db5,xj9yWkR4^PMBmJBt`v`[Z 4n'Sl3c7 75(&7?tAƪxZrSPݓ{S))\`zF !"[~f[m,Wm  |6EF܊.Μ''.BvXlD"Q g7?*+k̝9#UWxc+%Pj[ 2 CPGj]ۆFO"Ϧ\S-ѾeM|K `!n@'=ipcme:C_IuwvRAJ.i{qac [NGõm"KxMLyr #&ڥM~SesyHKW^mjݟO7B[>輣yk+ )jKljt8CbG xlP@8yd 2Nepz`mD?<} EORkH :d sD>hϢZu}zx&OA'5_ůڹ1g"WS5?!Ia*BJ%J/!jE?D6Dw/8J2uطW!ɷ`Ͽ"$V4I >< 31KϤRjӀH8L?\_1 !;yp>HOj_ѢC.y)542ъk{þ,z~(R}(;ή_ۏ7ro8h1?QȂP4bH,K\ioPVۋ]5R IiTr1Oq'ʰ8 kZ;uwĶ3Tϩ^r`Q9 ?MP\s$NY$n G1-Y̘p6>v)qhзoTeSLPIqZnLVsb35Ex1oFcƌ;D5,T)8d8lo{& NNW,鞕g m+!"'7?s?gk+8W:HȌ Lx(^ǝ4]G +CgzqG{vb'82BeL,ϻodQ7d8WfwO,P@GӊL?t]'@)X}<ہd}'zHoMd;zeB;hZ1uwGBu؝0:pO`3[ ;aͪyrC\Ho\ >q/|"Gmիv-r L-Nb u">b"2a V*!5qX8{JS.Pc827-)CH(e .o%_/>ђk,b@[YSem:MBMиG)2B+QY" Y^ a">)*2JE6n,C;s#dGDأ?е qJJث@FMM3T߯#znˤpKu4/-OW/nER8G^,D@RB3 rΘoy_ұuj_& \ꮥp&= Ng" p4FKã {.&I?1Uqk6xPsl\䥋3ţbw^#-6"J?BzNJ7mFlBjV,k1Cz<h4&/ܕHHNr8eLSG bG.l&vQK=g'[EQnCڳ)̱QrXC&Q<> r@ [h߁Lb_?zGPtZ1w^n}Mj 6#EOjW"^-΀Fm 5KL,IB(&1AU@ ɳ6`#?mGS"WcGk1} A:Bu+pDm?kizF70z422@HA#>s#ӣ)цlp(ȰZ?݋Md.QKA ϜN f!TQšDR=-C =TrkCTU vQeP9s%j0632h*'ږ-BXVgJIy"t8aF2c.2`BୋJ&*̦/ j>,Zq=*%C3GrI ًOU}!*;αzO Ak:@:"3qVyLXwH=[gp02"l3Yv&Μͫ/aDÛ` KrSkrF6:5# -| qbqvqQoVH v"u|$1]bpYPub!""ftxvȉ1><!z5~P™.5&pCMLdldhP,enN2FOX7hͦE8a,㣹B[#+=e:V n%OhLD 9nLO+al`@Iȵpun ,'Un+yFc,x ՖV1կOEp;RMP1el9J^I6]9 :%La%r4†zuXV{ '׋w_;ퟞ>GsLs#|RQ!PDg}Io54aM9ޣ0)y@Wj;6@VL7gƨc1'ٻ(D&6mh*/ދ LLxD3q2F$n6pӏ]o[Po(1ͽ]00loXJE:U.ꑧm5׍wAkzת)tYYθENk9!k#E\=J1iL$T+GcNݥ{׿Ǐ}*OCÆx@̚ׯq`;u%R>pkAȲ2j./@/C&ȏC :MCt3WlXmE\%Amo#Khx,B4yUyxklpq7gYwQ%"u7HO]<5TBŀ(%Bmhjo"!tIy45dTVJYVޛn "x;\A`KG֮=dꗆd2.@f;k RL} (eATQ"(@䦰[߈g솱 r1Gp4{öP|%0\KD#/|bOzO4Qx w33Ƣ֓&Ž0OrWW$#]Z&x&y ێٙI`*VR,dRFQwT6f@crω#xAod@ |'/I7b G^C1!VLE Omg cHiH"!*1K[^Z"wURL, j2%m70y/fQGn>z) g;^}i" ?(s+?54ۚlqt^Hӳǎ)>'93ls$=t'Dzv^zjzu( athu&ixrZ09םLvxR`RH K<Ծ8#q\x2 xw#LKi 1r8Yсj:"GpX9Lք}U%*e׆UMWw.e=6r'L &[oR I ߍ ^79=vQСBq†3Y~dĢw?7{Jxox1򊧝{Q3 r䰑aLDd8*:cn{!*/TFF:쇷>Hq7j UWZ6mpP:~+wej!U!*yPAf>:yGs tx㻦 CEz հee︭p]IWIrt(9dS&j!_mwl; ̀mcE3W=/u7]@.UXϘM!t}bw5[-VVF&F.Pr4j詄YvutES۩T@xiL sO>pHseӱcֳ.~`Y33*c!L8^ޘ%uxF޼i7jbiW*jLw랦rOXK}y恨clG~/q'MpG[GS'G2jjLX.-樸=h㽲Jw/q5p+/ 7#מq;qp0>VW|CCYIXX6@!kQ64(z9Aq-15s"'Y *ճɈNCjҕc5lO}m5W2=Qȳ6cC#tRY=:mLg86ZL2~oA 2A%p7ģr~ew!g]kUU{?uTUַ0ژĚ#~j A2]a쩧Jcq@0Џc2[RL-^oĩ\*\ ̘sw͢fk\6$ƉHraV~&CO5 yw\)Lb/z. +o!lnp#859/C$A OZ^gPB\w.ehj8Q_`wEu6-~Rل*nNp੡{Q!^%F9BG>RDn*]A;s,cA .o|RX݈HHEKT¿H3wVt(ucW:%tD=τ#jW@^ƂФJ%tN;9Jڸ!O^@4v-Ճ5]bۻڽhFV&^`E\_KWPޏW&zWUmJh9-%9/8mRŁa"b0[Sd\t@%}6 My:dܺI[da[ T BT23$2tDO %9,30EYwV$[jFdK<9Gk s+>v/3&q2[9Y1 3-N#aQv8Cp9X$1̩X'4 ӎbuݪQ2n \vOTlEuFmCIi\V!qڗۏKt&N*&ָ]nY|8r4_Op&˫Tl[:dg;g Bt=|JϓFߪBXl/9+0{BIfm&ykpܥ""zVFag֩Y/a?$0sbCS PgҌ0 6 Z D8P8רUX0 @H!C4Aύ2B׾T4IY}9 ^c2KijIwr6 H+.aƱ!Q5FiN2QE p% x2Im)k`Onj0գD!Ob3E1Cm'iN!(;,6'vu5¨k6/"~Se}q#SH*,?S0).J:*J %I" jqR?)Z.p#l%᜝W@YՕu[s5VJ_8Tcm\ƀ\3=ȕarrt%-CD'G{x7gIN/v4;.;25A" ΤZ6\glNaetyUU2į&JpL &)tP[SrZӑ#ه(?_,.l-:p]vSW'Ӧ@{yئmhtIn6,[ZK&*yjIfL/HX$brfS4J 3Jh^rJ%^ x%whƒkxse(C$#OP,^RH>% 6!%Z Sa{gA9xQ h~":b+ 5ʌ]rQa-*_ @$\FkP&G/Yb:~"d2T2/ltؚ |jrʀ&y|$ ͒5]$haibGqP >~Q=Mf5)H'2,4VU2FŘF:i Q#s0xJڅ&lMQC}y'%>rɲ[ϔ؊)G5L: n >s22>@< b=~4 ܃I):a(rɚ03t11,UYX9ANfԭ$Ǣ r% )p5\bGPve0C/R~Ph~0Ӟo1Ѫg4ސB̨7f{D(YQ(Ov:eqI҈/1Ie9YUŵ2.n"@@zh6J7T !mQMVBtR}Z~O fA^ɐI/i2TQh#@&׮dKDܞ>nΔ(2 JTJLjfd7b]:1 (9F03qζm1#)\KŽ@%j17eAx2ȶ?eRd#"dSVMn'G&"fbk>tbN< /-t>$r?䔎1=.>5Y@Qu+CGEq횢 K.nR/v=iEJE\QduNТD3'*7'9o7!_L{aI$~6T#(.Ә]d2 +S˝짵Τ>=mX,չm~[6t {Ov̾!kt|_vaw4g'UČ;eѢOm=&ByzEpmdR\̌01Z1B6>tGOavU G/n︖-;6('jPPSN/*%ng0=F"5򑤓qu\# Bb4c~{(M[~<@IF*4l/qc^VF*4k Fc9(XLWM-sK3ŃI6oV]7 HP$yo}^4#RK 3G) xHBg+)_M-J7ghU,a$AF vES^zq+tۋ6\vќUG^I+h6N) @ |BGЉ'ď5ux71YۏVJ ^ٷ[udȸO>W,tU˗zJANq U%nT$#݋)b*TڨSVP D5?iĝHB@lcWpf^DZ"gOC3; Wt#L)`([<`iQhu8% upHP+QOE]wԣM'n$?c@cb^Nj-B@@b~\C\D3_&F:r?I&JD&)7m<8:iHOJ>O94@Y24ha[hPd>\ܨmSit(ϓXl9Nd¡caTm)L Y-O<ܨj{+:UVZyH.mb4_@qbFf6 Q]j[#a8X}I qWnD`cy vBlLzH8(7Y>I0@F1P"'e2RU"nJ%yvUcz vWKٺMM&JԹ/A|rwU]YIGM1ړ!UrV=A= КZ .ERsTbX) v>ԔJV?cP5NBTUz#[JG +SgįT4znۑ[.F5Tս57o/R.ڌ6֡0YQŞLR[M!VѡoXߺ؝RF7InbԊkM1GV'a1t@+5˳%vH<9,@cU@r>\t4IooLKFQSdM BHc$@f^E#(@4 \$ =R77QTHdHGQ8x#8R@SskOOn4?48Ƣ[URJWJ[\,CbN!*T`6W܂(fVTp!U 6es 4!n+CR2*S:`uS;x~Yw#E_/vMkx_7mۯ|ԜDeB/yBS);B[;u_n]v K0hg/\;"͘1y$(@5ݨZ)f20*ir[T He;KWHQ>3euNgGRO&$z Z/Y&jBmu$/0+^ӱ8*B޷WuCA Nt{![%q0cѡ  FGTd>=A-2UŬh3 2S痪t=0ѵڿ7\b^GգD:Xu9!3{IRY#\W3N:WY%~!{v O2C6$0낳YGT!Y\&[k^d-Z0`,rfA=#R\]mtoѤ[Y}+\@jM>Is {H&r=%+Zcfa':9^Ahz dS ?G\m<Ћ)Դ~@iqX^` Ϲq)g3#͉|3Llo*F0}@``/{-*SĶE4cid *ROcy=Ol\ݎ&Z7YWn JDN$fe؃+g  /ҰKiW[ض2br_-$Y"ìC{Tt $#tҶC@)u𙼳䩑*qŖ >ؕ2DN&%bVo.o.KBeaELlTSY<#O#o乲;.r6H/+cAu)n)j/`.Lo*PWǙB5/w%ʋ'ih N@,Ngɐvٲ$ݤ:gZ"5-v ̀NݶsuTq%u$ְk݈+>jWBӫDf(jDI@FTS͜igu"B5rEUQ}jٜiw]{ςjtG&@ߪNݮ!l& XTPN'2:0_I3"aKG4an$N&}|cf/2k`ځʋ'( eSJϏ=3YRN;|#AY#( <@.)S9=;|c1E¬V1B I%]*v[ zUig-Fp+>{y\|~ksÂ0D62Irby}sca`a4gŰEj2X}/9تH%7ZTҝ4SwɟC M0j>7Q}l] 䠃,&j ֨e\ڗ^羈klfVoO 7`M_-7Y$7p0B )s_:E&^?:{< B1`,Byǥ̸\8F!߶fٿm\Y>჌ARK{*[I4adUM)Vt- گ5O~+Z!~q'z[^VJ{ 4 kET.(6EBXYX7!\, (Ks3sJᢋǓO0DnarzDY5;PAgvU"\ ;y( qK:G#JʤCٕ(Cg(XCPM3&]E _9@RgX Bp~3X-vR6DjU ş.wirqؽʊ.T7S#9L2]=,ZAuYպo.;4D]=Ʒ|-f %؋Gbc"َWSQwJ lskmZ.M (Cm<@b CCS Ո_oTvKz D4[cS,kHv"`xupHk#a *N+ڬ`ghXIoT\ }kX9[$;&>D긍7ru׈W#({kt h hDx陹2h5}^p( e1Yj0yėN8̐F}h vs^a(Ê&@WŶ`#>4 5m `]' t2$|c +kC0tDD2:cIp]b <[o}~DxX)1.0˛+POG/5f>nB9*ްO0ggdRGGd܄I)Q"F5e :秩//@IDAT;]$KձEfV4E8"./3]]>gȪEp7;Gbtzgf(| j IDAuu d7YDs+cW)B(79Keo  &IG|3䳛ق(T3КS9D=Td5%`ܿdb]F1ν܈NH>?e1y@.Ce% O}W 䓠)[Q;h31 #kYļajI)^lsG|XTO 4T* ђ/9xBg,M:0(GCJ4IDya\K BN-ꔯ@^7lڜ{p~N߯MI5(gZ[j`UsMgS7$mkd >9B:i-2AܮBO*PAd&)6g Ԛ0錃{5$2A.mAvoT=Pj{慉EoaץAkP6^~KkCOyᲣFɾ4&FDbPcj^~4`Lб볟 )ڱ!Z֕*˝-$nI#-@,e]6`|0F>E۾x)I>12) /5Mew+[#̠sfy (uFR^3@G5~{C>n% J,Il-@QxNi $2pxrw堬 6 ㈅KMu:v> $MJ9%~" _UK/& Yyf0^\@w2@|kZ̡>\ߓL }ƹBNuPRg2Ciţɕ-!27/j(`B# vo(4@ aQ@$8r8~/qE(_TŔEx\~Z?5EmP.TD۹t^LDPT6n'f꒙0Ai(%~ $8h^$P6ԬzQ΢0jt|09@0(,& NI9k(8ga@ge *Uou]&q@ 6p "{rZ@G@:ߧ莐|GV=85Ǵ&4ӑ&[F@~c:Gۄg7‰tJ!dF#O+G+ˌϰ}\ @l:7p[;0 TD~n]΂[Ӯ)_"9 & QZHjcHpi(-zv[&Y=$q=BN%7Sq iY.ݔāBlAvr0dt?%k B]FDt|@W}CM^%@Tesp!a8|-zu ԓ6!5*xz([oGC'\ umG'HٳRtw*)W(s"{,l<3ĸ41 sa!XڞV1B#~됝[R(,\n 4ԟd1,ϺGRfr BRfhA]"Bx [!T^!fdN3h{M PJg!h+g mmndp-[t@#⿈txC,fm/1tá|ܞ_o߽Z6]3. U qq !P)bf8lf  h4[:A@8S{C 2cBggOH-HRyٌ6F5>>{sI=+ 3($6fޚMY+/2yIKg^{-sK)0pR@QZ8 +3$cp[I: )>3H>>돟/ѨI3J?cw1{%k:- R pBzڴe2Fen'` 3}w^ 0c'F?!bb] @\)ao.-Q (aDz޶RLlcLՔFLF^BRQmƸ3li%YoezvTs-<l*X`#,G/ FTɎM5Gu[7)WxL(̍c=_/.b)㕘cզAkX{}HmdCPFcbJ(_zOAWM0&!Tϴ;E;d(QifpiL&ݯSU@q =be%RՎ9)mLqVDo|ReC0zJǭtVp&x j$ K~/{) `^vS%K/(zn1yW1rnhY~wR;Aʧ1hUм/sY^jܔ/*,pd=TO8,S@ܽ~}Tn~ڐ(1;1x G5|gP?F_WX%mA@r`!*2],^n;>E)밗;hx?\rPڛժADX焈j֥E Ȕ+c! 슸o狠VIs¢G\xG)bF9Oobm$1ʔAqEK@H/ D_Egy 8J,8v-u=1xiCeu}`zo{0M1d:*- ya1oJ6U2. M7d4`uZ8I TӣY,i26 8$ПpL3Ev͎>xB߄l\O.L>ښaD`>3o(8p {2*0}Z7. nz]/}g= A#z$f87ۆ@]s'媷lHG:I@aU7l NT|)9:s_ݿo#Œ Z 8bTzg^2zE\J:[Ul;}?1RFLQGViC DF?y Զ+jm. o=: 3to-jGU3pt}K܈'sNqsTw/xbK4~%xa. $4pТ%@_&n2 m+c(&BDvW<[$ƍC9i̅k݀Ȫψٜ']7tyȞ,ĺ`8z-Ⱦ]'+]6: m| f[L/"IU2 x'R~_{?3 n`bwexߐ虊w\R,~Ql&!"{ƃo@oLJ Cid+h8Ab AnӳQ'ѡ R4((X\e*nЉ Y3Lhdw䃐cNabR҉gfD@-ާ?KT]{j^3~ EKxhU(H\ H$jZhFDPJ&C ξ* #Љ;58 5w._zi%qt6Qbo325.AS?Ƞ,5Xek7cBz cc*SE?` 2(}G/u{H[61D[`s+8n$ Μ8\Fek$Q8?J&Q[R_I'shva*0EzeMF*2qJM,(z.H(in$A}G4#^HqR謢H_q}.tx.i]ؘ #'VѠVҢP.-eIbw /zD + ''6ayz^%fd qGmnd~>=c`jFNt G?zZepABG}Cd/QF9x !pLƒxǾ 2 3C'aPEjA,1qyi5P'@Z:3!Q4Z',x]/ s HQCk\S,R,#>#"NgT0#w_`+P  \R Owb/T^p2$(&K, (TF) UǬ[S,p2h]ä77weGϒ.Ό`@GA B vdu8̩{U!x/RnT_wQu3j$P܄Pg6%+n:/| k8FcЌ2 1)4DJ1"76.l{7<[j5C#57 Ǜ^[B) PN"h A)fAE8(_pa  <4((TKUH.FqE*ƋɁ+J!ܾC#)r=&CF̚K_{V׳j.鑿75B"8TV.ly -!0Bɶw:N=6Z߷:ǡJ_[ @XIoK`{cwC 1G@xx ](.P2>>ȴ@ Xmw #)ZGAs#XO*uhTr su+8TSțBvV~&O3og6|550㯫撯6G+QGm@vFH,s(d?R( do$Q :C9I6d.aG/aUE^dEt&q! (p=3s .@I*zL/Tox8yI*o欃v nYz6 Ww*(BhfܣWw\9\?1a;KFȠE?J Rߓ 8/XP.6iUD,‹4 zn 1,ǚTn.vky_61@qs"э:iP{tA6P CmQ+Վ5?0Q}+úqU%t@#jOTRDK/۸M; u#KpNL̴Yg c#hR'Ey-@B+w< 䪬;tHH1gݰ1$ZTk YR;ϒtP%ݐҤ@s,(niљ\K۶HJIL;(=>aE? QeSDM!`j#=AAm( ܅r#lJ#@&?B(f5gUV2e7v^~kP |42djQr2G*ajY7_cJLZN +s|6=,@71!!˪釪e 7/N@A!PF2I{Fc1<\eũM:rZr7U+; qqOCr۶"(=W| +Kb")I:c>ζhD09)9F $3–t)h\{( V= &Ɂn] ez\p"bfX,Ii#P1(q*p !bc+sZ$6Y wDѫjkFwc U/0GGQqhlʖGy6{}pi4/mT!Ӟ8R QY0|iI5gA]Rc7ӎHӂRMw.n!FJ$$j0uS]'Ma%S0d}1<^DӔH0j+%nXN2rH QfSrӽ)`RR"8_()q&:o8Ŷe@iN'V0bu  >4kF+5&7z^xƉT`SWЯ{BΌ`hJ·%Kdl,N" Ytybs@^f#1tGeT   <8EA& Q_/Q]}aQYQ"ylT1<4+a`关vIl+SR*B^GL}g+DS$rWqzk>3TJuU)KVF`!`F9*EeרEjh _u4ꍘ7#{~" OWSZuˀF?ҮcI2,/3Wgo;\"BiFfon ],P"m?!"qwPpD֫AlG5i%z0A!,UxU?G+7l ̭&]H]\pR-zk>iGXN tC)x "tӷݳnmSSiqpߗ SW+:d`61 5I8Yɾ&7~7V1RY0pG$PGڌfu%u Fw?=ʨB1]_D8"V0:lBX@ [Y$[gAEgd Y9xdѤm4zC Z0f(u!zBtipzcq_΁?>KKa7T#@ʁql-shissoSIFDD4Ka6|[Ho7mI'`{&ى"Ȉ>v/r!BYG79gk?, `N'*I`oQ@A p֮B}Ш1K} 4P|""-_gD$ahȲv`Md׎54J Li znC' c.&ͰDhȣ2_/{lBP~JPH4c%7ZfD5oзptbie<bJ^Sfo 6NR6!B'<dlB V(qjX^P.9U-'DY "I\R2tU\W$Hǵo (IU_Ogע9]K tVRVY L} |yN|aSUvj2 (񑫣7Q(^|%W1Pt^lRhܚ a/}1PO*CPfn-+~I2Fe9/2;?YџlmX0֥$Z  XQhޟ<==cKmGoT֣Q>a  ^ix\W ]0&"K3Zk5߭m"P:Uq=5!.)xzB5\z|@lƘM"THx2Y©TR.Ft;P舓y,t`"0_EvOT0K>}tKtch&&#@ U3G ?{Y'H%GVr`Тc!hq^VzцM:n7bWDŠD31d1Z['Ǯ; |nP^j%UAƋ8E&>Fw4Bx b.> z:?V}|>e ):X,. bA/D$#{ЊMMKx\Vm? 1xܤ5E3jtJkx5a?Q;:c*Cw%5QΎ>h_ yT W ᥃"eט >咰phHN!0<[a%+ňyVG-Z F*r׉tvg_:A)㰒?.-a}𾂶"0 쫨["}Y"YH7jcA $ 4ߋӮ(YQ[Lv5Z'f`cJsc!.odA$.iB9;J#82; 6- ƭcF1MQNjfQGa uAz&0%v< ›4;+f&|ĤC&6&JA#v< R7=Z'85R/QZ@ #jTȖHPczTUS ]+^\Ač',XK h&h1^^'w1}ph+{ໜds, 4we^av {:ڇ0! Y,i&U'0ǨdrdSH6I }^DG|Vh%鰙dtsEXw8,11pJ QoNc))@ *ker`f}i4µȕG8YbDQE'Dk=tg8c]aZ= J aYa_\]!Bߦ߈9{҂iOkԎi zELPHIZb42PVW!ꄿoX$;Q"Y%WxJbo+ sȵUt6:q*$AVLJbmF/F 06>QyL!b7qD`^ zi:.i&;4}[SVx{9H]*QPUZZ@׋TqRUOx{9yZ\4[ c鄵UR6TFv% k?d*r 1(DC{b\4pM>o k"H@w'5H)1ewu4O~p[-n"5YCuI3S_!F\4[u4VVC(H4 Įű8}OZRF,$s'HZ ~p 0a1/ZO\q"QlXجεaJ2* #ehusQrЉz8vߖW/#!ά0Z6( Ph|u!7wo+cߕލX8rZ7 0rk&%#;8 ɏqet$po AlREITB%"rڧUE.p)z-B;:1S4>ԧ` J!dm "l(_f~9MhE+&jH0Q/muzFtdb_],H%94t,MVZǜ4&$ʕV{$%(x]rI0Ŝm Fu䭏DT>#Re ީq?gF2DВgh[~sˈbm֪(y4슴x@(c,\l뫷oV%Ah`!q(I̶9}LĴ[zI-|wB@=yw [1)c3U3I#:8FC[2Ϯj^ G.]GIO]!JvrH&Dӥ) ܕԌ /ۥ b^-Bơ?;~#ͫ}x][0%c6_?mh+ yp6);ݣ?ٻ QKkĸ܏mr*;'@)Mȷ-WoϾ(!k/;NgɠJ?~Q3REm:ŶY ZXAAAZ9N-cxq>"oḁ񙶙YNަ.zO,A$ȟ4~@濒FnUnhϼl˫C1BqG3lxo]_$*D sԢ/rd 'f:BIjQT:ϧi&Rb Aޘ?y*f96`יAqf,9D86x[eh |+n%Lx/С.3#* 5x#>41X< :B(U]IuMr__G\zdJ`98ů/zh['m*:/wT(xH+6_:~Rz})yiC9A`PctXUꙧ$D(\>N9VfVt+=)mM -vl Q r;| N54PhmxcսA6avR$0Dt<K@@ #^͌sA 43&_+zze "qj!H\a9Kcqp[bU.E$'A*U _$AKа}݀a-F1r/ AO(]Ȝ$BA7Ł)crt•ݚe'",VRu#n'cZf@gzs3 bқj㶱۫K)Vy4 +[\ M'*pb) Xƌ@Z b S}!!زL%",bϏ9i3;P2KK15H])F"@BNZn<=^gqy#Bi\[=^[PWzէΚc.1%46;O%k;yRH~kINht/;:S5S4]فh֮dz?f<" ԄC9 {K٥C}H( XlW<kT{KAƷ # ,/G'!7>zZ<eDC"Kح:T"&|31-@^(a55AOPIM4#׷ 64]K PhmM*]ˍWlmoNvw:D?lqp۠ɤF#.f$ftfwIr,MCօ,qӈϰd H#a߸t Jk "VVvWbyAL(ZMyC)6 ; Q)r)#y9cTKJ&鱑vfAXȼ ~v\)2cALJĂ);C]F>x p]PCc6,d;u8MI1W,Yq7sn}er&ܑZ4s[j $rD},gFsL^HfsW1j/ S].'%F.@oa\0?2k=Q$0(ukLL#czv[gkX]kv)0@P2/3Ik36 Stэ(:YzrZN(?a`hFIVc_rм%mJs"ɝm.L3Q΍npFzUѰEĠit%RT+(Ð Oo@(9[!g[~އGl\FN8,@q>Īar5Aٖ- ."Q,KwbSCtܨG.}teե ';@[jQ "0e,ZCQ6 ե՜DE``^G];a8 &O23H &7;I_(o꾷x6D輭VP"9r@7kн2ZZMG I4@IDATh|3/"*IDt?~ͺ!C}I1EX38b0P(sݵ] wD=v!i|B5XiD"ئ`ҿ^>Qs{B?Qv$ v2ܙz,`+@|0,U!#e;5!@8-auXզx#%-K_jIՅ' tTU+u,z& ndI]%z:!E\}|"0.0$>uGSJЂpu /E"FG2h'V[td*:JOh4pOX&1ǯKU5, égb"e*'V6F05_>QY^1Ӊg_ ݔuTqUH?4ހfSj_ afrQ:هx?WM`Y2Vn]`Q24CBzZf| W F`HB>IF(B }(kCLmD?{aY':-933\"@/lɱ./qj3)RݚR5aw ֫|zf]B!jҺGkǞ{p?~\}ܿ<ZX #$~H_iZshϾˤ~ٖ%zUw _@rIPI c2h^C' (˪tcb?+Y'B_~7x$qTl"^320½/&#|@Bɳ*#j.ܻI\?> R"' 1H_jF] IA{E,^+BLhrE& \eE_ Tpw "\ZDFQRh,\#,`Qm'ut$_3֫,]PMV]yl E(b$K(1\V?qoA8lQ7-FIIbRhI{v- @W8uq57-{41 /%WRL1Ϛ02m)4ƕIP)f] *pk~!- sAxJa6X;uCq|+GɵV>FgO_^ kt}}x_DUm޵tE@ukqůOwz}oѝ`.>[nfN26(ϖ`tTޯ<o>TQ+Cŝ)jT.IH/JPd,O쇇0}wK"X;hI+Zt FZ$Ӂk^vA_<P&:hK߂N~ *@yCşX=->\&fBܷPFE;o<଑h(2)ԡL!\C?IPc# J|SxGv?^̨O R>dP2%E"`QH"ɁF#_VK;5NTM_6eqWabEzLt5WgC92*b8FXDY/}MQʉ?;(_xKoG;c}r` *h{x4~u"Z0#И'zO;;@wwgSwx]D6FM&Ȝ2Hq# EͨTu`!#\` NY_O_NWIpuJ/rޫ5/-&/w_1{t|!*px, p?w/{w ,bm qk!^[|wƴ[@w O6Xexzi廗U}]> Jb{PŢ3]|8=#)d#ZFz`Y04bB2GȤ q S=?IY.ڕ(qL))R☧/>+o0 is6k 4Wu$e2:wo?ߟCe&YwM <4ҁT,1 9PBuڍD3;Es^#hb]ld^$},G6`s (#"B֓b~^?9O{zM8‰wnbW;MՎ-J_ĘY?7;\ ?u \: L4 FkK:g0%sjgm :]kgXg:t껿;gu5<<#>re (bm{'y2nv9;Ƀ)/}-/ @nƋD_N]'E`;H `|5շL4=K88@1pf$JEgf|T˱MWeX^+SiL6A5^ /L-4|˟\m? "UUIB!5?CE[CA5D4rdqIKp*T $=3Wbpex-: _u^EUE7QޔQ.v^Cq^d7] L;E(|s2x}յ`4+|~$suWT~Xkr˟Hq3qٮ )Bu̝I E߰xE3)fꐠ%)0Kˏ@IRF<6щ| i6F6H!\Go8IX CSV{ ,]Y3%G( h 2#&oF.d'Y`W73mlNWwO?+xa>QLh#xFK* $ȕ|UMе~ */^̥Op0ZiA/%Cz?yWr2Gq1FRx[۲_0'󋳤wFn`B|^`@&nRhtM^aD89"wSX_9feKL&C`IH&\X+ol:EU!}F=|Znn_jm8&c-lCBRc]V\ra OJ(45ڎr^$6:gN%QHޜ8Do?~aG).ʚ&hRQO?ĵnn8Fh{.Es hGJEfm[Eɿ?ҭfKÌLk'T.5D oZSVZej[OZQI-Q/3 fW tLB'6Ċ^>\JEY3|dUR_?XaC/I d$mPТJJ HmFa3/YQn#n%># )u(27\Rb6<[*1 eb6x.՞w2έXW"S6B7N<*ϙD$:}D}6^{E/[OR.F 5kIyk ^֡V2V3yK8,D_[ V:`T 8R' {2q9n+y$&*_K9&32Pqɏ|Xɿ4RY-J7}aq|"?AEQN! CwnL b'ri)+3zt#8C#[#K\z2\K=&pJ g؄t/5(W #٫BB`<`\X5=Gzߣ΅H@ #Z 0vKꔌ1p-Bap bjo z Agi7 g"n24kj|oь^n/ebl:,-@!Nrepq6w!R+PFKo@&CL3WS\b(SZr=2 Uܟ\&& ӳF>M`cu(RM0>LV U3М`Mp"{MyxE`E`4jm㩠9 jA'!}]bIZCXHi-gcWJW_]5QCkH3H,ٙ9p#u 0 x)q1 Ea Bc"΋:&^;`M,h~7^*6=)} $[C1>-NvGKtm3R"L!XA3;3Mc.lz{.1bZ뾩"\'TF*F-Κ<סւ|CfthjMYpp=E;9KPj雿{h LsTVPE$:!c"JDn"sӄ "4/04hIpHTňl;K0Q 1;C{Fߊ6KLkIy,G>D^zD}KvQĠ/N{9EȊ9Z;+%J 2B5!M| ^P]tGH Eՙ}mM2!cF(Z[Gœ>1c1Fbu*P8AA9 1ָtlcN#Y לbJ6y2UOjIC3+f >w80"T-_e)Auۂ,{C`bU pKow?~7r?_?nL\;:>Z!ZjW0u1'Ƈw\7MkWKx1cT]AF  įdIGGP)K02q=!wq/"Mp탏uJV7ahO׷ZzIW] )1^u'V M1Nf>G"r#'i?lr/i1*%lϮ?5U]l7̰~ Ȣ4tQ@?[qQqO7&ثاǭUW@^n*B+4۪@)²4QPVGt޾_>X|%cl AʏaiҠvd'2~lpMEl]$!%KH%e}PIet^پ0(ST E=s2W^ztq00RYkUya}Ы+qaDwk20Ƒ4ot`/7 $trVi%Łs Ǡ7s{ *[C4hPѲ(Z7>Cq:#槉(F #kT-%74 GYe P-;iΌXEVǭ/U F!|>;.ʫaor`Zl aMp g'wTkY KgB2"|78";!hRq"y/6g$.$Og^<Qg8*FR 2\|/?˖-ʐ icܡbחܓ3#D@fbix@tIOΚF% +'o"[ onI.K=2:xkk[y엾}03ګ]Q)`99zĚb w}eVY\rF"ǡPY RK јZ{I#Fԭs\*pS]DMpDy37֭Q@DOU aO.H)̨[a+ABxFBHPM!QɁU֨PX="M? c`Nvm8CƻB^n0+ @ "!`Ï?k:~Jc 쾓8OfM1Y 0yNDRq*zc)c^thQc"]#2qⴙVjԆ < ruvTY4vp=˴l6d #h'7_ kv0rq~ h4!sf;D 9dn` [M.Ia7 LlWI^ko$6'p-ԝf2FDɯǹSxQCtڐO1ER.姄|#^\Gv! tAv/ G5e{5:/39TzraBIc?1I8E Tee$ T-SSHJY_܃`tpS{d Ux:h9N-옶uvH?heLum'/ɰM땛$Fl%# j/;ж"Gc`|{ >Lp{I: C88cs+Et0R "\@8``_w!Lvt,&Eܱ.PȂY?#g^4S1뛷^=ҭM \>nd5B{)x{nLez0Jl';*X3LpAyCSG~k"vz 2;˛_8ao7?G1f?>~>x?uAt~k_Rۣ=zw/au#[8>z=pnʹK sؘ;l{Y $R8yk#|k !t[Zc>Z35P@ZC99a㱓-_xɶ @Øgt;#37􈜁/߲dU;tHq4.. E +X?4$p(ujQՓ90?E3>K͝Ȭ Jΰ^poܲ s_'A^0A$ӻk˪͏gє3(,t%T[䅁?A_ə2Lijk,eK,G"k&:Fk2N[+ K_ZlԾηȅ8 B5ٟ,_}\O-租)^?ҁˏ?'&|nOc]D,7^ds)+SzGL+qYG^toȚctajeSś7Wv WxzX*E'C~?o"5dH? wHVv0{ؑ׵ 㕱<vŗO*t\j9*k!ъ:D⶷D sJ(o3_GCGx1LF/_A};ЌRʯCҞ1-_f*NV]? 3_8̖X˸Dt`NT<`6ש=m"F$ƒ 't~>e2tz4邂!؆ZybsN0 ]pnrH%,{Vw$<=d m?&}Y'o Yr%YM 8r,m3^6cb,J׾.He,kr!WkDHƖ{-Cm]/\< % '3EԶ,2S NT+Wfxx`FN:z,MoEDMh̙\XRp͂oLEm}esB 㓕X ,83hiA,aW2"$mIL-#Ҙ)4HꞠ.Rŭ׹d+Zd.觇!٘t*+ZL6HԲ1 yp YЂ5<,j&Mܬ^@ZyDxB8ƈ ^"dWޜcYG)+*+)7.Dhę_/d0$^6waEr>4U#*ʦx!'ab*7?KK8N fÌ|kᕸF%o ]0$hK$IaVN4R*ȇh k6@D\y  dgE[kN-HOm*iT}cu燌#~&{Rz'&_o-+P|PӆlI/p8}tܯ|bI`43ǛrnffED2 NHJ[uXr- 6GҰeQʹp3(bg0ʖ3@;ϥEb!7"Gtɍ!-YB|YMGi#)糔dyR] +2cUb*xg/KtOǵ5.DZ5hߜL嘔C3Iز=*.O8RfFz~DAe07-ΰM7o. :{$q{D8:^WMȘqKE- nTqm&8c2sy}5|hK j+a^ DqݼR>g')s{|+~ {!sGJJ} Vˢ8fBp^)4T:0rk;QZjAD(P ry6@@Sev bt% Jבєù NaB?`k`sUHIAQFKU(x'Dc镞 !!)3uEHe Dr ˙rcr @E׺o ^{1,qȺjzT>C5GXAyz͵Y^D <ѣ"i*h m>" LrG'q -C(g]bG`ـ̎`eaHE4hpb.-#J &R͢.#FIYfmBm>saWR6A%c6WJ۞AKE!b{jӤ'LҪ|k}Xv |5mѪH2akuS&8#>0>sOզ !Y;2$fx!Нזމ`89T-+y+cXivʧym'=7=AZPS4*2}E 8Ԋ ]:2\O3U"2QzW Sɮpe+RXL*|b/dܟ^t~W6O=%׈NLLv_$`#ݧ)|\if}4tON@C-hMD1.T(D'ZqF W<y4jsN G !Ii&*CmP:CPౕrzQgZ DžSa%cF 2%ŋ-3xeC0=\D'r5mdrL J̆Ѣp5P-s5A)Hz.3t![G^ _m_7k&n`)38WPbY(Z5y$=' Ϸ mˬOH`D06%T?E3*fQ#n%*|H-%vz$v~,MCo<#x?;wzJe(R18@Uip)3Ba%KJbOW]SA+O3SVҋk?`,gAToJZ= /©2VLRSGF ,ӣ QgΪ ZB hUцcR2۸R 4EGAK2} [zir(kL2^TN6TKEZ^6GOj+SP,'Ыy|1$ye7a,007T w)K'@l(<3H./M€iШbpJU6f(:b=mF+J9#l>'B,[y5SHu&K9eewNh[͐^Rn`*^VsJ&7"^ 9 jgđ~c#f,.${ QcLN⨹¦x-cn&T~,Kѷ76W[0XH2cQ mה)YoR K &|Trm9i&D /dP(.'|*yaFN,wɋH%L`l9R<iM~ۗj1[4!;  4EduE FPX}n$Z6J#Ki*br!%mu {hҎ_VFOpzq>&[ªfAP) Dog^HA !iٟOHݎ]'Fbj*e[V 5(j+Ck ͆P*M$mT>#܎ZP &!>Vr/1QAq|Qkǭ,U:@&L:K&"RBŗ2t.LMhu v6%2 Fb[YsI| PgV$>=Hiydᠥځ;Ӣg\,(tcGҼ)i4|wz$vmqf<ɥ1&\M"C)Y.T`#]C,<>6J㺪tz9AQLݾ}àΚy)or/S,>Ł"X6b;1;C2›il&`As@/6x[Y6oWG*x}FCaF.#^e+4ٌ2s# whߛA͆Ԭ!B Z F*$Vw`朒=Y3 v.A[LjuL 8s9,b|g ٱ$9)Yf#3~^%q)(MT wRES: (*\Cw_دڞY;.V6î,J,Tk:[ǚFXDqk< 2bzU<nR9*pRv[h=0aW\w֣om`avWV5UЇjd0 3a\N@~ xs $c,j2_*E fR- ߡ+l`9`%B)kdExJw~;|J/ H2h/#ןX/s 63ǀl9 *ĻHT%D #UQrE)6^&rU3ATmM2293@/k[ u6B2WKɇ0#zh| 6>'XTE}|fEfb>$hS;9(4@CG(s3Z+uMn q?֧ʬJ^G,%*P0hCnFp~S 8IT&1S8㚂#_ -H̻37Ԑ]c O%>%~t sNpyJ9 frbDnn:7} ?{SȷxLK!b:Z6~)w+Qvt L.4}]]3u"J<sA޹l 5A%eeP~"l ggc6@nE!FAF_y.a:×"8C(i0`#oh"Dj):j]j&bGZ+ϕ-/}"A ŸE#t(")&􆑭]` Oh B;!V/sc yߞȋ&VlghGd莊ɩR54ꐿV&e] E2DMTa%M0/\}Say6;6Ҭ^Rrܺm^ "G4g"A%͌rI]fBPK{[S 8#bx%لG̥áaOTRTX  o5E ڧv*f80P|@Hz c[6(wjm& Ԑ}TQvDbX2i4'A:';}4~C4;Q8/"qN\ nQĢe;ؖwТ)y Z2vsul2 밻OQr ?-/2-q i7+t?O GƼOp h*#r>Q.1hCuk&Ɍ$$ ?;ON?% o<že+ڲ ۥO?!h24Lh=n=<+|p_@()ez-X#a %x9r2Kx_7gkt*F#!@A92]C nFHU§=$*G#`[-2=uqIQF#Q6NIu%Jӧ±ɒ8+2g8bِXK%לJw6znSB[W /'v7YDwJBHl92PFL&:xe$S$0QSCY)++EёhN㇭ /fC4:;\{[" 6M9T#ީLd\Z*4Y.p/k M÷f_QS^[9bQTG !aRoEgK4?ƈ oJVjDJCYԲGDCH|(ms4@}Ob y'j)BMx/C\_)HT]KY81ۮTB@CDdr74wBlF"GbjCD";+A(Dؔ榛 H6&+=qX-0RTi{0_fAKīnF 6i8mTƴ bh݋R }l:oy_DSPS1l-oany%d#%<Ҋ< \J-%\ kHh(.2[}T+~7,PF/ɤ~8Y"2@Łijh$q)IT"+1~6EC#*nԻ2*QV$Bj]]HP"~O3 zM{f7J $(1ϯtyi}Jw7 mOA@,qNoo뷇 -\4_Wa&NIAլ`s}呯?OsplL(?ZШC\Pv!s_(rxWJ38:6b+vTC{tԼx5o5Mg[e&jPݪ;2Jcܶ'4Uzs:ž_jrX;Ui q3gr׫6J0&JP䧀nFmsT! ࡳ=) w^oL34 ېķ2vuyBE M)^8Eg$p İ}"QQׂRogʳCcbqsF Vxص#]tD]~Fg,[]mr@o9]dž?3ԞI,#?ϳ92VCÔK6SUb=[4uq>+UΫَ8Z "g$-Fٟ| yKfX9LEx >u}A7 c@6|9ꣃY&}J|e$iLQ2ѿ,5u8MyI &H$?(WnQ6D+Q@y9)mk6gޮJƫ P{/wtlٟi}ST*vp}Xf)ODbzTrȖbw?.|棵!e]4:5 )V"L 2B IRmlsiGCVoIfc xX ˅ KRG^v2<"vO[dk- ED愺9Hs7Jb s`my7-LR Y)5. tg㉦q4ԻQ SHKaWd ^\1JHATF{T?,-*ˀ<Zy@&7<ʪ3ODDžBobh̎i-Z I *R P=eV\>u!)Je/ <捜x/btD @+O'D*ӘB 5sz'[A;_X&FK(]&a2YhŶrrW"S#j<>0Tu~f jo$wS 7*+\"ibnY;.GM^o$4-]cp'J6iILC+ >/% 2gs!52[6,o,_! CxgIlDž>em& f4y,a*=:&L;Z* T "tS%bn3 igB$A*KF>̾F`$Zd -"+lQ^W^q%XU"^NMJ07Q*Bw 8eUh&]* +ߛz[ Y>mG +m(nGq :YI;)8(Fh_WjZuCoxvmk&$3l|L Q: `P.&c * mS|xH|jT.o▄6mF8FI&dB4BT8xOON+߭vF$"2L`gp%#oJi8 fIJel $7LL0**KV8`iNPWŚDSHS<ЃͿRBޚ:&"2}U*kwvH#fTy\NV:0+>vRT!0:dH٢(Ŝ!&N7j$@[q@`bY9h,EJ$8EzHPJR:^rgvjeγh?TVñ7L~L>? 51Bb8IÇJԬGʐ~J:o8drLai7C$__vͫ}դ,*c4&hơy[45"__Wj|sG&hE3h'+Dl̨tff.HL<+ň$@o)Yzj[ A v$QnE1>S̿,1om5 g>?mbA-2rX)nN)MrM]dw~0l(@Z!= V]>Ľ>sN×k/>v@\MY9XD=R ȿK!P~VlZ)b<`p0OJZ@T*H6- */ Afkާr,ٚCZZֱ*ze]lHHC`bnj/$6:χ_+hurSBxyߕJwڢqc(²+ж"t\ XɎui=4ȬƐ ;̋.!g6k E/VԓtAYhh~p $$SWeq&ќt }C:AP (Y)̄QDKdm3;BUOmflkj)YH$2߮U A*!\di^fuDti{]p MT!$W]ٴvr܏2 *pNͽ~>sqi~B~cDw=nFe\2f}ƱT]@AD;G)@ U Yb _KwLy+lxNw>9;A,$\ׯQǐo9mPo0Vbq|B?R# Ԇ =}!G}ꆕ`a$h jEφhl~}[U:Voݕ/bFTDs&%.zFm#6YO.D ~^U{W< - jYU*.n" (<\}fhD<2=T#Nare|B̆ tll_e?Π7 x ~[J?{R,P8 +|: pu?v(Gd(:M `4\O|k](0oP#ہ>u2<(f}m5}$%<גbTO3 J^ [’2WhI Gh${`Hf]ljmm}Q@mpY=bj.Q0}0-<#Pu7 giMt+1f j5 q(l Dȸa.:*1e;$&pP:5/B']Vce|:GCzeRa4 Ƅ,i*]ɀXOaqNpL|QƏ zZqe|ڼ7OT$UP=_kԤyjPnz MEc}. yX9/zM4;UCHug9mLVSrIi3dٖVLn1k%)Hhğ9RCHsV9]S kAOkXHGȵC$ӺGw'$PIMޖvv U1'uf[[792C<]֩ ɱE=a4b!Cf`(-ͳ@1{K]|x$I$ ' ׍\|_gzGPSkx`I~_yρ:5:⹺*!"rӮ7zkw*QŅ pQ+8Zi=JLKEY!ՈdY#v 7vy@ 5V XT?G eNYN ;r$hfurW-a㾷u$3fuQ8Z@DFq>&-GG;&r/NQSm0@_иQX2M]5% #_+ }*RK4P? 7\8G"Q)FO; ,<x%@Ao1JEN`R}Q{>?Pd"xPϝ(.?qY]z^(?3ӏl7,jILioP@5mD2 )vw4bĦ0:m/4B2x:0qf;V3Iz0dlL+QLTQt)k@9z2D2zM!%m+|d,/v'-m?~z+71?R3-d}S_cPدǡ֗&(YbF-[ܷLTNpݞz'Qz"1#fW)D~dZe,x0 M T1DЎ E8@1Zg nv2~/U@qxV[l@O^kXT2Ͼ(A%Fqxy j4.TrY2AH9<_,ULhU8:~<_Ɛ$yj|2|I}~#Bkt]EVk7|?0dfc,4[8om1Y7Bğ<Zgǧ7XԲ]z|aT$o,r LEQgozN[:l$IJe@ >`%cno d{rrx-19k%a$PO-xtiI25^o߃2yj Ez 0BF=^ - BwYM[B*'*3-dKLKp t$ԣPè*{5C>\ǃdDBIU҅AC׹?z{nZDR VׇԘ8 4$YMb~?RJ߻1rkt!P29iiv}$Yf"g|-H[=GuoC^U a:":ZTmbE;Kz]=sVpxB Gj5!/81a#UT7 /Fu4\Gz$ IO hB~t!#f2_bU.V"5u!'R8CKt1N(d_ o2u3xejXF!3!w;=bx7yD&6Kנnm(U5jkhj\d- 3|kjd8/l FBʭ_it4C-c&C /&axŪI cp!榇i'Fcv1qN_.+Azmݲܬ?y9B2œ9q>^6&*Tn[5574[vAJ/ɵUI+m1-/3k>#v1*i>SdArZbζ(I>)`E.~k4> #YW:.oRZxDfQfG*FpaIQPx5я3{ $]ݸXu-5{\=۷`!0Ȍd#1l"7 G3 04e"3Pp04VflArjn(KANݗ8SX! 1|6WA!v_hVvXm.%agk?~h__6buO^懳5LM4F(sy:lm竃y!ÉreBvc7syeʚ~n _3-mkiRM n$nupF3f P#bp7t'LkԈDw7FؽM3ydP\ ̙ƹGGG˜$#>g(Wl[&hn#zj4A)Z>%o#I0 d('j'B(a& \0-%@Rbr[;뮳"~Ǒbz}4=)ᳱԋڴ5DžXq4BE.N_ۿ̄^zu6T3_$E**&($l!hBbye+_! j9,N8lTB>衲F :Va7vD9\ S &-\'zǾb|pb=1r0 J+sh7k `i2dVϞr 64 Z QKn[[l+[L.!_25c]uvM:?=K>dg/ԵgZ;3.Ȫ~6ڡأK߾r{kk(|'4pu!7mH7=>XQ{K VL!!n?NSQp۠3FلjST֗{J Eeu.B6C+M%r.x2Y+f/@ %'8-+p +ݹig24Gx=>:Kb)sj^LzVޒnSbI;zhOB3`&5ËHpwx:]Rz˄.jdȷA 096I~Vw -'#""ɘ_kBJW=;K39ިgÂN5Y>xɻy3vF1)/IXi?P }n'Y/v=ڀ\0Ўx7Wr#P@dm@ hλNu G͉ HYy)#2DmwJS^(q~ݼZH-˩kcHlk҂\t}q9\Gԋlv mäk݌U'*ư5T 5HOR 5Z'9,A+[*8f]h'wD1f9~Z8,hďd hwdυOc~S^0 vPZiZDY7Y9 g4qsM3#)tGx<都\H!΄nwpM50'>#313'k_ Q IGPsh(a6,x]W#h tl.hlw/ @O gBWej8uWm`F&BjF`AyCs V(5PCf„./n(0aJ{dh7, P8?Vj<̦pJ/mKm\Wcp+5")P-ibj ? `M{Q{!|Ul-kͣ.ͱ  W%ŞOi7)#u7cB^jd`о w%cV96.BWitȫ{ɡ [9;F^jVJe#8.g`vm!R^>s*-cQ5^ȧŹ iѷ#G7~"F͛`+RbB( &C6"lȈ E_BOAm1|Rx v@E4(*Ŝ>?Mg<6VΪltMtE$arg:Pt$Œ-^Ddc>KnmD@azw2U8(HI\Cn`c$ɵ1X3Xm0bIx$ZpgL%윅s0 cmw^|ƄBKZ &o@ Sf͘ b<< Sc T"`As3 =Qlj Jtq+ޔ&%_W2XM6vZ/&%Nb;/J46Q+ %fRsRuU.yS"4cHT](!ĖVx* Im2d@PÕ@\auju@qЧש*4}A"`ߞ̩ү lT0DvA;P5G; eNE7:`D7v98S!5B9G'2I֗]0fѳDd@&Ͼ.ƈX3sTdV3dhBNz O2"hȇ+կ(H-&bL+2z* EH xu*cHXf7[h LGsΉxňÚNX!ī_u~ W,*DAmރ^ c^*K$ߕrf@U̩3=F s0q[_: =k9 %1 +fE=UCaxztC9_3x@abGQ- '?nVuJeF~%6fʡ*d{nKrf86)u&Xbjf]B~=4wDe"vT3ûEUql[!qO|ϬWA'SOc~A Mvip|N:HO"z@]Q y2 c*|#>xoK]ϖ܇?G>Wu "§_mK3F[VVw{rEwL&pd.B]9_WP #C*~/ ŰR0"CYLIJƐXf ҟ&{##B&&^ħjTe2{RL{Ir5 6u >@>pt-w~Ok'8ɬCaG(Հ fteNGESܫdTB#S<ϕ|C sŧz0{KO!Bjn+DrVm1}hu9 >=֓_DJV;h6ARKlԩgNл{8;F`cFcY5diyL;Rȝ 'nXF[O5[dMs{٫rlXy+fJ=G:jL)Ee4@a@e#ԣڨXv7?ُQYBphw&!y 6e=cy MQ.[V2vzIOd$:G7퐽PhۧIO& /̒pn,26jM$If =Xg`od󄽲d\F }ׁ0p3T{wJ vtAL{D܀0ư`/@Å)yɻT\ƷC  RyEq`ERD( abYK2PYemD‚@TKQLV·Ʈ 2*#v)w$P<:,NǾ@c22i{4!oc IiHbqrަ.On,n/_ϝzFg䧑t1I>WC Tt\b$ x6'p& },W2QcEsERT60|wS$ zf60MbGĒa$Np!ؖY;n#)HˏW-e0| 11hlG)}湏Ьtn53{zUnP!V uq毠oRR<;'"go~'8ߡ9;썴:lPPTV})#Gxp֘vg槊&qB:6i oyv8+ 3`m =Y,l~gL< !=U&p 2<*5~33PKpV/G/f]|ČìZ<ܣbD,t7õ!Uz xzT$% "zͽemY峝; ܷ/%Ԅ3& [(!t XK^n _{`or\̿q4xejd D*bQK}M4SF$FGTowrq"+ul츐ýdIy KE ljdY`I1]of{1 EB{șyaxyMɫ*u*X/܄?xud4,jd^BM,1qyh^,۳HD^QI'H쬵h^0EJ%oȇ2%@Qn٨1QTԹ8 ߳S\9~iꖩ &zL2)D-F7{;3`(?k)1iy:n[<]+EO (EXeF3nMo_RK#i:>|6ؑ5CaXU 12]<F*&ns~WF?O ҠprxZ0tRtgDWFuen2mLL!5d}}u&X!Wl5/#_PFkNC|Di'} *0K{o䅇G|ވqG}CDy B%)]RF 6 |1'bds [ƨw)WDLX(ӯtFIP~@OEA\N`"fc9 R)3˽©N5>$ZGe .גRn HH'0Ɍ<*`y<]G/އYKkXuFBj+U᧪~1f0IyH*06#  yx`)~$ dB )=](eiJx \SޏzX~]D @"huVY ! VAʑ+).zz/9Wc>[4[`Z hGڟ'ۋ"kݡٶjGt]$TabTǾ66j+Đzܻ [MQҗlt_m%\AN41] ̓ ȺQVV0Lmek׀y҈[KݞO_:8O"*^O4 fAsfƾ"ܔ_`N: @W/K{ ;'Ic=͙~%N'Bn~r6( lMw^TJ"C jT ':T& L":U v"7ܣc\s}I7:aVIm%LXlxLfѻJas%BʴIJ '0C?0]Izg+hCMBD4Y A<ҩ`U ğΊV7$KKuW1lyϜb>4U؉+ؾLP #Wt>:)5 Al~4a5(|k|V?PM"ǗI#E=AD'`|1sJ͓.u(}:Pݦti=HBȗNEƂE̷n4GJjky MԐ`nm]̈æ-֮!"4QzfGopD_|?;I"C݊w<) Vcs@ +H҂ Xy缰3HB]|rs𜜉>4Z>t]UVG3:oxnZe}ɄQ`:%)TY˨她 ьW /')}B_~Wh|OTi(S6srTb$f!ʠ@7ʫ]ɽ%@3"_ȪUbt;TG@>vkKH w1x$E>ꘇ@TS!>;)Q uN=ksx([v[[aU^SQa"Ʊ $Cx5y,rHSbb$QhYW:Oˊ;K8"z )XY@J+! -Y~=eF-m#K4B-hmX¾-ݯU%ǭi殑 ^Kd|EzO.{=9ʾ|Kr3͢ɰh{蓳SWVn.Vߚڢ<@hA'jkvIuSYiJUZ{xZOGk4T^/7_u}m!hs ޅJj*-EER;_*{AF=Z853pykDs(+Ӳ{[m$y6CY8o cfJ kƀp'ErafcYSD[I1e.) HDO,CZq'*&O-Uc5pz\ x5L+?fdc!c&gZUkE'E:73U7*oꁜ'<}^ph1LRa4\F3#gMi?W0ҺY+ _>Z|ߪmG0wTXW& Ȥ^$U&PshH0[\{fo2OXT6h>x.(lCDN5 X6-re9'""$%}R` /gBPYO&Ԯ:Ď|~ \dXυiZQrÁK2>"Fk\'ՐLa EZl[\t]FZꔻR'g[l:D`%X(Rn)R$Ļǡ :A8J8)p`lSs@7αYTeDbzrh?>rqBm`*&f9#H|g7\g9b[_)-G3\hU 6 'jx)8Ο ˇiŝZ'X]|2r;[6<=F`ӓ@p̕w?!28 zW<ܞ<ЫRvU fOXB_ (A{fZCzEp]yv9T>stYpPo\,CHe3M\sqұ劉]xųOAd 'U0EEꍨc|b 8Dmat;Xѧʖ_3אM1ҍ&U?v-)I'?:eFrªĒ5,;3%+j:V Z'/⠝G htsYP G"%e4",M'j`6G59:댆coy/ll½F`B[lQ g܁6\zS d 0Ҫ`:0 a]Qq }X"99LW*1T;ƩvQ3:3ۤEpS]7BaZvZD JA \D ZQ7S&ۘ]1ּ^s 0D`B]W$ϭד=$I +ppHը̅ꎡ@ A3? 0 ٘K8If];`Aao>04[\V&EƼd<̵dfĤZRM=| }ڐKn8mL--?HPiQIiwBsj0]$boaMz: k"UJ"hd*KI#39Z_,q(#K[KS1 v`zRyqm .HG-ZD2圧WXkSrP|/l:oc጖?x8FjvlgJCloѼ|#GPMgABeoxj$؉ lЈ<{\J^ձd0lR"xiMŊr$6wf\syO#]*`*gw;p +r8,=UI$Mݸ_ O6aO7I 9c`PefE&(uW "9D E7D<*^^M뉳h mHvR)&W]?ͦ{_V`e=Qjp3>ǻ.Xџb;7}u }`doaZ)X,I0Rˈ|襑5I{+\ bxޗ9/_8^/`LI d9 c˓ į2XYLORk+2QشQHN7Aa|X5:LV2R({3g _.o^ ]zR@nʖNC6WL,FcoR+C4ėXdnT_`sp Ky@as+)܊4"pc-Ԇ{I]nk!)wE*uOKezD&"oXWs"V환q$qYu7{q+;O.#DF"PDw-RxaUO0}qRhH9 /ĘGC¦EUmgԢzt<f/ ⡉'#өSQU]kcJy"dƔ,\9.nU)գT  |]G8/}b!NYN ,m 2^FE8)БR)22iCÄz=RO&AҡRo|F'J H3.R'OoRW#sh1Ym8it P=#tqԟzdRF*x Bih s2[ު"OM6Bd/)D**BfMWzß|ۅc̃/ P@-ohޔ9VEcS5 Nc4?uLx0.~OvFG;1Vn\((Xj`@p“EpYJΚ7m .S,AtI`>MDk\ >d9lŪ֠nMy4I:تiyOfdŸOCΛDXu bt[1yˊXin)}NX @o2?QBAu5tV :cו#xJr$++P տ c@8boG-j7 W |)^V"HZ a) BKjh#҉GP,fAԺm,2X2=GBG )UC8kŻU !vt1Oot wVԻ E-xA TUWv&$s$fVDmܥZexրx_>dn6X vN tI1%A9hĵAX̛Wݭ6eU 7zD;̻FnMZneaSOtj_C()"&UN)5d- `"r9Lx|Rh7N1`3+̸ 6L"vm0!47ҬhfY=Ӫ LKMNg]c[3k_PN#ov\jhLh/A`$@$"ӎ6H(@&C<ؙ%lR:7۽5 Iq +Jg^$zn xK-)kfK8P}r>pJv!EHØ~LP|j"yPO>B"9^&P z^![?)MhG̳ SN)Kin4aک!+[Rl*Z%{D xmc corDI?ȁCʳ F@X:ģl}O!:z3%_O:=ď. .Lx 7gCtl9'-)kA,L.'g$RS#uQ8%,KMMu1} BOJǪfc^>R&dF͠]8]10x_w}@rS y;a@AHP:ҽiI¯>1,a8j?cnC|v = ? q;P=,RUҳ m;Rrt3r'< WG؜PVG([2b&fkHKT%5{<~ 0N:6_a1w-m! ʎTa?C>W뭦1wоaBj: `>f4|J5#52  &82]9hݞ T3+lBOMT撨5ɁP2SR|>q|^ -WT)C3G)ҒH !)Da8>2'& Wøy&'t wJU\ok4 4^@H*A-˘% ]DiىYfKɯT1Y~O|eAUc 4U<׸ bz;Fh;yՃE=jL7mV7oAaE݂e4NnөCG(-įz7KVMήCJ=%`h wg]]xs _IxIc*eAVu<+ =nKPA-x^OjUŢ@>AZ؜nW5 Wy?- *YjT֗ M:ܣ -9eEj8$OfiivFM!VN,QA.#qy[M"mnu cK2+Q)TBCiI3j$,؅*-շt2hOg>"QpO[+mg:[3Ѐ+3- ~dO{` V*4W=\.O̱$HAPVĘN B 5ZEׅVAOǗPnRHfs^ʚMq^Y߁OG0TDQHI =/37gvEs_KJQ~^TG6F?S8 rXga½i4kF2#yZvEACE"P{,q{ vAWG/mDKIUpLcv#L ŕ ZuXӂl.Ѽ3|XD":eVT,`fh#~ ʘk,Rբː*Mf1zVcpr!RE<_} Uw"+GmӉmg53lAQI3&VW1"{!QǑ?ծ:RԴ'Ռ0Ƀ^h[3Ѓ+RQB:+ ŬPq.de@:3 ՚z# bPggHXpm\GY}*eS;}b:rSc-ܺΈ秃~̵)"G4`{3ʈ\^;OqVL9e6gQP˭ž,'K& f3U%WP~Nry=V8P28KVS[ɥ]G;#i]2I(lmvxsO.ϢRC1Y & _. T:Q4t 鎯>≇dW˂KE--V tJbcӲDNj+!QrKUni1*u.zء.Kֺ@wZ?=s7˷~؈C=eU0 Tuhm8~lT ^')+&71 `c{<'~W`${zuP_Zԡ%m}e`&_aЅ4!oU;" 5"sېM;e5Md-Ffln̩6IP 8wexq(ȹ8\ܹ2,plR ͻD_|eֻ9{0abܥzSU&չ&Cd'aMu$ޥ*^ف.-9qK@6o93iBXP/bm"(Y14O$y9pn[~L楎^.;) rG%%z] 1 r}njG0Ng\Ϙq"к>*ǟwKXY3-ac73ō.Ɵ?mo- ) !>CcB3R`HOc )$/Vΰ] ,"X2')n8M :n s"6֞),򒊇[2]d 8 <39{PNEM)b8QԛQ~V?23:2 Fh=j̳*gBp8XTKwɱi\T12sXf bT5VdL9XA;I O ~dEv3o Gs^Ol DwĒ+JWv|3ΓbcP(_D'sDPp1R६FZRw ~İC 3Q~w_ .%:PDz5;k5ށPDak3#M4#;9B|f-]گt ̣d-@dAEOn6wU3+3zM;؏olQ&(֍'Phҟ}ή-"f@y|zH"(2Tu5&sd{ 0W<8!@Žd0UOw4ɎV ܙ$/xŦQfqr8<\E>vE0@cz@oGx|sj$b˜Dcޯ'YZ= VHxA=MXS2hw_,X.@e@=1JbȒԘ6sªLEtMvɀL:\6h˲[8+Lf4{lNO&y| q?4BD u XTtLHBؒ~F]AKPBPӬ6hV O^??̈7hĺmF&%5"d"T%Ck@7Gi M5XZZF>m#uJ?|t@#O-5~v WN61.ڳBlVcP)Mڸݻ|S&oKadQ0 o HmKΑGR5 q.tPcԩ-v&}\L^ogXF(e%fqI`-g6r5;/<*ݟ4r뉋q8v>>& C>}7.r_unݭ'lEx uCyo$uj&_ɨ'<Jy)GGGr@X3H_j`-YHC9CcRODno-b*ɼ{A#$ =90d0VHȆMM3i6NB\+wZLH DIL6)RNT[N.FO,+T 0= JfvcŒ I2mZ=& dD쟒(d?xP4#*H7_&, "K+zp\ ~=K @T4 5~$8LF"SG"vKqu[\TgxzKs@?UP##׋DME8cNlqhޤ>cS6Zũ³𚎩cKV"%ެ>\NcP$q& X ^a@ Y| >[D"ӷKgDlm)!!`h"bdrEB?O~܇)!`nٝ$DM%ޯej9M$!g\sS/Zp O/%^۪h77QSb@Eĵ-1( i}Ų(S0sf3HM>*t"8'(046XP O. ܡa^3Gn3p>AB@IDATc]rt=?{; '~:P+l|[xgBtKNZj@f F YPd#RaȞIXX-{oح7>AL<גVB7UO- e@VA*!i[`x[d:6ry:>I 0>li.oq?A,%2#jAej}i_TV&L+=$YR&#/00ߵ[ ӘA>h#uɩ&Z؇R SPXsVгA@8Dl+ŊOMr@?ZOŴ ­aUD8S5VOWL^U=$HG&c<1p}AG%b=2p-ʲ?d=}M zvZpe˒0uӡFPdҗ|d8Hs6# 3fFg5t"CB`p!9p콇#5dvDQEje}ԍk̔pmf`mO -R)&^C\7rG]t@JW/,#s8[ ˄^&0xg ʉݑa“4[aU6aE x+& @<^Edӊ6Bir?|F(?E%j*k}>SX*kCj:{]c E|5{`e]` <+5/;G PG'e zCMST 'b-Smk8#|$xn he=nEsuJjrޚx⬱2{}wIl!@v"qdu$י(=dK"o㞉 cK&13X T@D*iY<6NiϜ+riL 驋n?;3O! qG@Xj'%TmU׫)x)A=^ddwY?ԎkۺNne@kzmVs7V SBb\C z}Q AS*SMK;{R_Ukj9Q Ӵ"d8]D3fSLw'bs<˧`OMF5&WvUt-߰NP[V% oCb#8j `:/dˣXdH&aub0"0gM~/+{ s%&8lKe4Q3 Q 4y2jU@TNlg@FHwFifܟ:b*zUM5"aZPjՕQX iВ Qbg@n@M~jcHSTON6jZ!7 LU9K17A#E)ÅGuQyXIʜYHk&F5cur{**z,y:r=q RxI+U4gIIKzF|wmZʀKR'Y3 +l= H;:rzlF=nwWG_lKHumz)T'X޴!V_Mʺ_1'jLO`YOc̾:"1lrEGu;_vrխXkۍ^l.uM(+i>Bvf@9m}SP-Y Ygzu2y.7 g)XD3\JlZ~}*zt\xmhy-. TYw{Y/}-^hsNNrYY{3_|jXD("2Theq$FKKݮ? A89p8:]#ve61Q@J [R-]צ=V?c y9d$5&=Iw/`}pUSm 8Vj})"PoVEB&sT$wq`dxFaNX f6jQ̗&J$j7t 5} G&Jq!(xe-P1Lvޱ6-ͬOė1mӋiH\6ZɨEFt~5U, Lc%\7d&~i$mj+Qo%2 XЙWCjtdc?"\X3݌KB"[#V-2VPܪٗL4R512́eCBŒAivL ^XcH ~MM̥|n;I'DB H=foaf4m&Rdޱ B>H *~KY/r}ڽ>6}/JӏApr(Tq"(LCI}HqVFRiG EɝDiADD3$V|b!W'g}lxSv&hX@K)행р[]Z2}=)SF ,2C-m+dq;<[#Pr|1(]CAK"5+R-Kk+-!DU,L."y؀ %oNh^cbI3{9 'xdh9[$&" U8rdH6wVȬhWXܞB3&i8:DӎLoƣ^lËհѩgr;u2eXk^J6X< K>|c8Y2HLC4$HWzvpn҃FNa1}L$|*V&ڼ&_Kv}<l[+?c?R`KL؉/)#hOn"Iw6S0X-?cӡIMӥ۷eId\x5a޶,DQ4a'gfKViXA-qJc=6:tZ|[d L.9ҙEG7c|nBXDU`}9~(80n@H/>'h v Y {R. hT,"9+dQ(Ϫ.k}|D&@4L_;[[JāۭYԀOld̍ij0{ F 6lNgD'h0}h6oYI8lN,jI:$6A@{%M5^5]`s/u`; F̆%Qg9=0!.~D~khUST F Xr9YCBÒ)JhԎ;7Dx2Y{GCj( tޢ6vU1G;`?Xb +Ŀm_۷$ :M c 9UU$u!as,c_҆w*{U2v%9Nz:fGQ%c34o֦:rOcC?pknJڱgCj,apP~6 ZD]DO{Z1J#_O$C 7GđgNLǝlLSf&a6Et5IZXuk86St vC+q5oKY`t#W=ˆ?6H-& )k+ laȧiBA=uX{BŰUK (^o|{ CWDAMlRXH-3ѺdFQOEKd,2p\EHerHd ʄ_n` fXxGe ?AoTQU0T)`` :\6^ǧ0,K;Bx-(J , yxPu!?l<{82#I7:Tp o͸OcR`6uGDb_t|&,r[\Dئ)8WueO4U^Q%xmn$ZsBy% pu}S TlmTa[_;ȷ td?ZΑo20ټ@#ƆBSE/YXY#yV>ؗF|t cs$B ɣ5Ƈm|Y;YPh,vJ F8WF(H'@-&3_U63βVp>wecDAn?~E=RSm˽`_w*UJQ(/֥N!7R%{i̪(̱&;8sU5* -2-1C ''K1ɱ):.׶.R!Kp%}D'ٲ" fٓ `G 5؈0[$~;RjAu+[JkBUO6|u'_Nh͟zb@t{40` CVW+ġg69`SȔ^D;]n0mo>|VodyCJgNmj}( :™NB<_OJIE$^Ƽ|=U^3!E3 P"` *w)f Mn5W+KPO҂Dznz ZN̥7X}=2aw7(8^W/dWn*4H8/rXkM*}_D8)wc}-zI; h dZ Nm,\@8KӞw@t&pQE ɜ?$ml=A%嘥NZLoeR K[L}5D E+WLJԬE!s_J(YJס2REnF(&&uJ( fa(<)R{KW7|&S|?VVd hHwk$୵1X&N9(p|V0Phj3D|^Pu]Ѽ4&@D/O,d ^[wa9ZDW} QDi ͆ǣˊ}}I$z()DF#}ӹ-[3KZT*EC)])챞- MMK1 _3P>ZY'"'p<ՕQ0ROXm\ { J^ ㆾiR _MDC(V* ɖ":F[K}P($4lFЪ&S: L%JS c0bJ <)d-Vi0jEki T:'Htm3z&Wy&[So f@cAQ*C `j]G:TD=j^7R;m/ 6K02FSdup>,bn|>z4oė"bo5R\GZO"*`@*KǕ. ]]>`9Ѝ.AlPóymXdYr;Xk>Ad ([ 1{s6O5Τ"#{3iMUfw^ -,/ħdH L}rggBY͎:L b 3tyfIHieY'ߔ~rCɦ篲&;UtY V~,m_ j6-2V#e49oc1= P_Z{ {QК|GӐM}ߺ1"SoЅ-GSx 3sx+;fwL\)&mV ,`vOZ+9F[CRJ n K3\Hw`QNs6Y50I+P-L^cbZىH n)OVKKƣ|fBEAd E-b`6,? jL ăs*}j7w߷"GuąK~9Ą׍9#rabYqk\7Ľ`6 -Fdȥ5H(;`&?,sG%#F NCVbh&5acuĴqRI\ M;=l{bWNǩ3 E=VR,UPt_ZeaaZ+!U+Sm8\ l#Cv<v3ObaD6|[n ]a jdIAb\>χx""ڀbnWS\5rffL~-ܘ&JPDyyX*LUe2Zsani7FŞ57 òK 2-ybܞl^Ժȟ[2fR 4`4{9CݞѦ4^,lN|h󓷇͘HZr߾W\cRZ:.Y+I֬j$A%Hر4 龯)D5L`6BOʊsz/^WV6ڈ`D@AKtQf؅ ǧZJzQ1 7TS@s"mKD܁ṕj>1dZU׭cc̿K45"M/ޏK2x%tURMI/ %AetU7T}`G4Dx舖fs;n(\mkz#V7Bc0 //JFeU(59I+y3oQځB/4G좵T,.j|gRRC~iN#-#h!L⌏2Bd.X= K'ij[?`Fpb H06:۟H-32ܔis{0H;dXF|)a `Rw4Q|ԸP"a1B dVkU]>j_cҢBYys@y hdbx'I2xR$*TR \:FA݉L!IZ fGV@:5z?{?~~0?DӜ邢PHt CH ͒4'e|p1:HP(D)4FAH Щ[#ͧA1HjmjʄL c@Suhn%-d`ZcرZæP˷ӳzh_ttݬ n=h'KA?ébSG5Vt80Bn*S3n4P\!Z-UQ?|ݤތk{5go&iuA@G 6t 2!WgHˊW#hAN7 [Aj=R3BknEb<;kgZĤE\_YOG# Ԟ:JaT39 bjȔLYL$sDgbAZߑ, #ԾNH$ DQ !:C$G?ct !7tAؠw :o\$ruq&>a)*.֖*ԖJLPUxX*õ-Zcj:$E'3Р [ڬ!;sƔqc-k/ֈ^X8teirVٛr# p{ҿ7tm 4cmsdXA5=Rp(^OS t gY2zURwz<>Y~{ (6̲ƓLv[9 ݈\ːYI5ĊN`% 싡2MJ]W׻47ŀ$o !7B` ~Y9gV`Q| K}s{WIxz>ߠܐق@ms*g)%5yKW$VYNU8$!D Wj-޿Z˘dtXP'=jCua[WS7ˊۉw -/XÉп< &ݔiz 2")X@@ ,k@$+/YMpYA2v63}9ݲ϶I7LYN1pqhGN4 E͡ rgO>y]_υ YՑl.Nrc}gKէ:ZXh]HF-YDRp;VZ2&S]J ܄gW﫝(lbٲNZ34l`YHRfL @9ܭUImwzF554a\E;_ߍ[\sʛt6L^MYfsP{_ޏ}q@< ~!B_d߃ooCcߵǖwUN3)9 [P -nub ,a7VDLSx8 'y03Z#iXRhBLj,`-zׇ?З4zh݋v` 15͒锡\yn1ڤ:|-,8KHl 4Mox/ cK2羖Aۃ~#YNYnS>YeV[d(ǫErn9W x3\"D"mi-YB>ZFt[}J <!N(_q>7ɽ"ө`a"%.cu iشz3n+4\d|fެp8/hx+oNG{=aL4ex\lhF;DX0v۠leR.A,rZ.H+;s V@yh?)W:+F8Tr>.ʁf. #$ӝaKLk&ML/2* ;A|X*ZBg%$z8IЌk99!_.ufE'tfՊ mR֓uDϟ &h/N׏#" 9)+#bA(ކ*+Hmtʊ1N6^2fZҢiRt-{ķ[d Mr^<gpLR,H殾-3tp`đ(H@stY'Oaai^[>M1z a#BS#mMQcMHj5M?ԠlK<8x 49aHwfm¼vTGA3uu$FM`4ܦ9opv ( eTN !B tṁ^zD~Vs!8TI&W^l=0)J: H;A Ua;'akEG>@E ( 2Vإv6|-pQ݌pl|Զa4r&V0,2f ?+eYտI8A=쑺9) 36 J얷5R/CbL]͈֕FkߊpZx,8A*Wo]֦{!yS_U)I?(b 0ԅ%I}ǂjƆOr +![-8s,qLx[JHp^?߬,na)P|Fl6 8i&jy{`n (JՐ>j_hLUE#S쌽 -MLP-&ORԛ)dGtIJ@oj("sBuP=H`c`6hW! B? ^uOO5BYJYHhZ @pTi 'ëƇr``8 =DM^$dlgj^FPP$;AVHـGf:2&0v̀wfOwZLV itdEs%])Tn'PK1ŝ&|V<0y7uҥ]q꬀DFK+J,F ]o&9- ]UA"gEXQY-lIYs{E\Jbi(n5)wPOZ1ѡ!*a=@)Te\tTl5"֠ЈVV֡@9Mg8Pz0ЂQ)\z$Sj,4b QP>ch۫ɯF5P2zo' }F!D9̀\=Dt7 ʥ!yAr?lh7m)-J-֡fJE,:0D(Vu=8 a~Onz륚,'oN ,.~j a8XMz-AD KWK9kGFփq*agp9.NR\+J.71OxzP(!qm+;יɓf]gHկWč"zRm8!_ڠ;cy Pq=iC`ڼ @$opw{BܜZcID4rʛbQ5,_)HCJ>z&fdkxrxdBRVAl8qU IC:/.oۀ+pRhsq@IDATʇ,T.û C^s[d@"W q4N=EIeTIpBz =Ш2(k UI*c`;4>y +,TS`F>`1-*MObo_2kC7mrTH{ً%:@E#}]6-vCߴl]hyϨR, UMdliB6Xfe(l Sj;V3&XɴN~d;'FbCӍ1LcbX L@]7'ke[̱Gz]G>ac=Ցho%(A(L@C͛L`Ŷ-EqY\Q)bq@&6:0Te*dhGz+"$}3LB?۫@" Ʉ^# QelF]zN*qY=: .~c߯7}"Rq gK)Y<a$I yx#b#7XB*Qx"PGK]Dl̩dx?Fp*3@:vd pttfXzFdQ#RQ]tu%ܑ4}> Pbn)_:fliE674PrX ޽ddJ ZJzcn喿cNЩnU?BGyŜ d*H[!AYXstYsGW!fxM{§I0.ghOZv$6N5]]?-=?iVVsyz0r:(Z<`fs#؎*a YV/wI = dU,[LӆZ 3LhπBfP+'w RDw-ϗ~vS, ^T%K \(@ [r_"QM+44&*;bu`0k(xnw+֜,Xf|n9.?w5ǃru'ȍ$ɂAB2"޻^--ә$6WGTM3tW5 73@&a5=*@2UW/[5{ ӳ >,Kcȿ@YRVǯ94QDR5n?FGlAJMhZ"UԛRR_a yZ_JE&GLMVفRY)Natu-Ahf+Ff5>~!aXoD!BÉH;, [<"?23҇c!O[%_&(+V!)уr!zsfmB0О{9&#GuBqH#&c H+:I֕'}\>P\]@g.D0 *MmGV$$OLMdθqBt83K 7H4|Fؓ~Ġc&L3oH.S.#%K9y6sҁ1:IЪ&B1Wz%ϵp)|嘷GH66U#LdO/H/pFXǯܦ lC!21큇^X7lꁁ=jJ߬Eݣe\s UM Bb)%AnaGZ dO%5( ! $iGg /STK@?r=b2,XO Hɗ_c Y &`'iW+~N`&i/QBH :ڌw1*<':pXXgxP` hRlt"ryXKӻ pب%QzڡnNMz\2 {MOu L T0i\Q+hC4Ht ) I6,p[^p&k^B[yaߌd' Yİ|NZ>XԕF3aX*0+ o#Jy ؍N <`#CK%6q&DFM@ذ[yDm8򅜡JXd>Q4155UP-Ùɦּ=6Op'j .F4MɀΦ۞XLjH'Bo*NןɯQ] )hmB]zf:B_XL#V?q ȶX5U}4 e;n`O{º߂ X[bkƓi"hxg_hԎ!Cdx1=`P+pIVj`a&9,)F?bQUFʇ,@I`kKStfAHgn1#S¸:%䲤 Z,ۗcr ߗ*$H2H,)=gu*jz8{9bXo_^p$bj$׳iwk8v$m] YQCc A+ VٽW494]&U>` }]i>ew#!vRV&?EbCݴL'a]1ӄ:K]̿JMnVs;T $1Ȓkh>'ML.lH_=vV㨸h&;N(; 2xHgdh^kPYC2v̄W3b+a+vMHua Zi *xCb|$>y9y-:PN ,&z\1 u3=0S\k83eg<0}@y\UhgkDDh,!86b#X;}&x sf3">Pf裯T)_ !MdrX,l۾f4 "G:{ng8vG P)~ܓ [QIFzI;8'zE_m VL'K_rf)҅g- w ;'3`$q^57--CnL?- ^N_zT((;0ONRO*UO8\_أDt*1aPt']#.-f,IU/gz]dj”ӯV Aajr4'(=p@ٳFiYph,_G(ቪ-=_,aVB$ S>~?o?>DZ7Vlյwj:l{p6<8?!CݺM p`K  |M {H}8d/?CQ#;D2>&'ijJw}pEJ`:+M<+вM[%Hڹ@tleй3/ f4C if3sԟ_[h,sGv8;DuX٤lBaWg3E|>+,a!!w 5TFdH|`j!?e|;!4gOΘt%D:ԯ?9_ov)y_ĭ;g¿^6=Z<L{Ym– \8*(t)MmW 4J/+E B;U1R|}Py' d&C>BSJT "2&|^m`$ފi7G|=4{>?BX:P'6u ;$[B+~3/ 1jiNJ^c {vv`Rg}vnw+? 7q_A2l߆26f o[],qY(ԁ~-o6m1Z6Uv\6@3b4zX3ߴ ^ď|.j> `VK9g[ Ag8Ɔ9/"ќ"nº[ҀqEd3O f^ 6 jN nSH{y#lpþ1q6`XMrD*㘛JN 㰏|;%=:C]R N[ 7DlI#BĢ{\~R?/g';:T̳S{UkaM_0ב'uo:Y >}@h,mF:@Yi$>[_:0E@U.a,"-: ûmVX^+CŌ;Ir|w1**lR4ޠM?d~;p)S HdIjs$HqDIΑ>+[M4k@Z jZT ~QEcJͯP9x&zjT#×DK*|ݍ>yI3qJ2VP-[^ BjA3Df1 |Ƣegf@bo$ZK"B̈9#–%qg׻ ~5U|OQ)[3Ŕo'!?y2^ ɜ-ҺquɆ+ژTau)lVٶ48n*VS#Ч.rY}]cs7vft3a$6:0^8ݝ+L,m[~VU{Π` [BK䨟n!P&O_r[n$u$Tk< -IrD3LNBDvVˤW~e:P BM<4T6 C*5~/Iclt:HFεv xOoQe$4eq Ȃ~}~#Tqrկ:a'af >:a=sp:3f%Rm R#'cMV QXtG R FF/;4,oH!BDF>h k;/Z"=T7FU өZk,1AOqD9J([Ov Ն ƋE箐^yJEPJo2WD@a4L1* QܙI7M'j\K{a/&>}?*r57;/E*,N0aK;S!ƃrI1ǤG?٥?R 4lR|# &v21aab\Vč &vo`mAxhl72.TF֓ۓ*-Rdvh}^ޙvlkKQd_)D絚^pG;Ȋyȋn\5ۈ@JU&mU[>6"P(D|dxAմ&L-Ԣf@U{ bp*IpWcd1= s)uL#"=:ڐCaEsz:շ>5Tk(=m̿0A2x5@qbfܩ%]m3&(+ޯix {rk袌*#Q] Tt#XnG` OOt-W_0jPAKٿ}.9ћz}Q8,s"3 $rXq2X}*sR.׼w@}`Tb%QbtVri_sPCE gGt/@x*SEH$bv +c6~gp=2Wc0,^_M(y/ مΑ vFk`QcWMǣ?2is+#-qLq V f%`&%bFZc6찚<>6h`&)uс :ŀ'pZrd̔PTp#Y" h`@ =>NF*u(C.I7󖻕,hFv-|. H=C;~"0cMFi`3=ewTU1?Ɖ?!n:>TU}xf[ ;5@{*y,jB4[@ `'Lhwu js9 "|<|<#0T5$‹[ t4.TfS~3|捠7AҬ77xd gʢcRɶX7$hWIP RH Zlή^LM1*1߅" gl̍)!4&(~BFMX>h&> ghY ԦGj8B&*](Cwd72TZE13% c'.b%_N+z>2i'zK93fŤ,~AYs_1xI) ) 뿬RMll.Q&2Q'>ߌ\r Z !9a?S R`E@5XǐJUh=Tc7n$适DV;eDY@82 ērkG V6U a @UEn/) K G&g.tgv@5i+3rMW̠BkqLI.\[;h5D–%ӜIm l+kr^]>zcq)Z7]0ir&4O'e^>s[=2b(+j0W-HcR$EZR鰵rdJĜ5\;k3FYы1r>VFy[ИC\b侻f˹=%dZ)>fL_6 uLjmLfDYxVTE@cJ/8/-7tJlM3lL:#I| NNPFaʎ$CE@8. [Ss0<{/Fft')2+&gOF8<\ƅaS@K0v Ǚf e7 )RO=,܋  Z;^l8B\P%~XR: եVX9uӴZ|eGj&%<lnf SЎIُM>0 ߮ǼGiqLhP2~d~{2\[`-{XIh&NЋ$_Yo3#Ga;+iGX(S{EGT觠A+4bDmgzl֡*qz8huT9v~"ϻ?Ǝ4('C3* >:T2:#UCT?=_(ꆯ>&MJw%Zn2`%ȞTb~S*ޚwo{:L"}aSUNIoˢB:d$TΈ#-UF)z D$Ġ-.@T ! HhyP:;O 507FjCںµwC *kJDfE%LXLsȒ@hR?{#}h{d[ ^.sY[煤MI^Q%hԸ_짜Z 09 foc=m8dp!i|hX7oZ~\cb x([P'^lDuѮc/̷}dE !)Zwgh\ή僉హ|A(-nQRQ1$;CӳV]r+>̌C/EދHT]6w6"􅌨%>*Ia 8ZX-Iaa+\TxT(,O?(I~ߩX(RjԲRY"AaVZ@ terd))@|[5R^.wpZF{\XSY{3Y zx q"i4*GqbڍH&o]Fi\lik*B[ pcF"d×D*^^SZ*A^9Tc* PiOM/F_X\hKo4$Ց ( -oʟaZye'Q )58!6Ivf {̐@Wb71X.bbpʧ/LQ^AP]<KhQYݭfr"KH/cƐ =hrhNcO%d?$~)[5XfV=EKuu ^ ?}λ I,h,,OCB~%X b0V>ܙ B9W3G^>zIp#L" Ueџօp)JŒhu kA PB!]0JCt)N$QN%wJhXJ5^IƖD{= nx?.w(ڴX!=h,C')YG8 &h &AGm5_Ÿc!%oG,MyY,f{fIkI:'[]¤(:j3R&5fMhf#<"noH ,n:>eLsv`5ZXqlw*GJİ@)Ykx2fY)nє357SU=$*yps֖mnwnzG]ob–̟o[OR[Fah.7~gD5EDFH?Ra˴Գ'i{z{"#56k[( f5`i~oj b 1g܌@2h'n؆N%d ɕ/yB2PX.+"U]$ 㦫o&pyK;WOKN$.gg頿/ڋtkNEvT`.~(E,O/RZ1o{#O~<َ :pֈY& u@pB lCUP! t[ɗ+?OnZZNVfG/4~p[rOk%E' 9yokKɰPLF曫i cd:f!*2ncfK.)H. )SױC8Sie% #Ͻz LpJTw2yQM(mfQr%ŭN)XQWh~tj,磴Ӣz+^.VoN@BUd:slle6[-5Gy.D4Yv\1LuQ)k1Z, /ңjmb nA?Ow۩ %%=Eq!e\dXپr'nEoKBej Xj̦ ',^)OҨඊ E6*j閎1?v.싯ۿBEٗB,k+4jlht*PQ5{EPXuz/љlbk] D$Z*Ҍiޔ_utYf- 3.y|/" 3r$eamɎu?Ϣ*Б 0Sr%{1dfDa;fÓFD7=qmsBFMNJpٮ;Gh<'o,5H&vU_?,0|=l(/44UVփ?%BhgyncRx[t̍xK@y1X;&K+Q%Z;|^}lLlgsOnm2םtARӭ6|hۿj8̥ h WJ(ز%Ȏ'ˍVڗF</:`/, zc|u%; #"R1N3Rq0弜Us +l+-8kI_߷_&Iپit޺M^c}HѝL~v̄.>=^}nv:;0^on%;OUBOQÍfrx:1>~_Q/; TezRIl[j<6R2 JxEcc_d4Ro(r^)KGN$e; 5IMi?EtDhq8GKFRv|賗̕85PɄb]f s$9wCUdHK`ӡ5#xNgx,4VfT袅 [~ ɠ惺Qsq7wtEQ= .o,x ,w>3\t W8ՓZ!@Np /Oo=eTpO4:8"C: ㈟4Z%*\1qWEg9r1nLPAJ. n5J7[K.IĶ8[`+?@ sĘ&4ɦ~&lI1P( MUޖIC_mZu|Vvz4ѾŢ ~d((Djp I, vjKY{G DʪfXJ=SO]IzT^pܭ$#!'~!o„ K"q@ђR`kڴwJ4ql hHMuw MLddxf!nXғbnb4(drl*!XvR+/"`ňw/v;y NT"C-5eRq`qU$;8!,qX0/pgMeaJvݼLP VGmAK [dj#<:Ԓ1C5f:$8$ڕB:o'COj{edʳL@h8PHɷP74.FB% !+#үԿ 2A@ȫg%qz"@IDAT/X# 褐ymjͰ0VڌR^#gYh-Jh< Yx Y;VѨ8^IO`ԀHj ꔪ}d `z3}Dި ~93$5'g(nfX1y)8ű~^t \Bm2FT+JKLؐ0`:%z~^+1i#%!PoZ8D1 v5 "Df2V-IE $"1RN6]X5a@6ݤbM7`G 8{raJiIVDFMؠ0W֦c5HS9JHpǶa\]c3*&KY'7Z_~q[JMTʈӕ,ء؅ "|jJ[A)"V8Dp}a^՚ #֜niFCNnVUЀ\]_~_G&Ĭ)Z\^ma02HPlٛ8'{hx}iYO+=H=F5 Po/1xXaHP8![J*H&{W}ij%y?\7S,dT/~l6&Bm(agNDcN %/oo6%=?ʹ^=XN3QDK xB0,,YT ?C|4A[z6(MGzJS"foz 6D#*9~W;÷dRśHn7td=ZH`{ఀHu2jq'ްyN5aȁ, B4itBepMfj! cjc3UwL wU; 8jf ^ ľDHMAD?.G#̕u4^ q4d (-"6T^] Ɏh*!?%KshYqv:( 2eP=r ^5DE^@*#!a#ZKL'/CKiy8pks6<>D;?E;%k{iHBb+x!9~rؖ2 m4Zm4GMrOI9[⧈Qq\1)} )fCJN ER9KDH3RXϟ{I*̐&ja"3' Qty?z1lW._}낏QW-cOo(G03(G0-E! &ZOJ&9M!F|35j u2`=?.oE"2zukLׄh1754ϓM+ШTY$AL>2Tp:-ict#$^ wM L" ՕZ}δ1e߇NҎ&m=-M|2O9 []bo$f=DDϓ {\Ѵ p0s7r:e5XS&Pb&Pj%J~ jU_GȃGNڀGNUݬN,.壑boTGgXWԓ#t+_VuKmձ>paG(BDt-;ΥI)e#vD3V} fJzIuAqaZD}FgfL^M[2GC2j ŠryF !kKq#4|Y E;q)O y/N"t+"SMj85+ >|YOFx{(5SзBBRq]'sR e##&}@z(תA}Miu_7ܟv~dWcUf9DO 3}T~[Rui!GX)^p/^ъ ؎TN&=ms,)%eurb P&jShmMj$4[aIpI/74B+aNMb=8mzLpiY  9իs9wBJjg *3FWd.@rL_# F`vOCh. (r# }MҨ3EjQG2x)q h B0E_a9DPTk+yUC1żJC~46|maz ce}uQ/zDo  IJS*1KAm7=J3s2I-LIO^~RU(uI9[F'[YSYm SL4BU9Y u\4MM&b2 _."9tgJ=.[%Ļ$x"0BIIޠ?|HIBG~,63g7O<Ҳ@v:po^.׌OF#8Э7U<; `XY+w;f1nƀmlLO P,ܼHҊ7Ig H|<$"\ GW W0 wu#@#"DS TZkI~ۯ!̇Zڝ3%y(j=OAmrXzHCw"`3u,uԺ햹GfZD2^ xj4ɓTk~S@rSa%@M%DeZY&d̘q=-Ćr|<)-O *E;]H"Љ|fSyڴN*jd0{Ǜw ]~mS3z١Ix8MfߌhvJI%<73ev<"jP N5[(`Cjĵ1zlIo~4-d'1zid^ɱG@ .bh>@oڭ7Y6kd@ 7kbDqF(L:uN0!~l(hl/TṲ@7yiKsJu lUlk DsXAk[eW(GH\zS~}b<x!`*[YQh[i4)[4HܪmtdZKh('O&ہ}ٟ6`VWcZK7˓.^$!g,BвN<ԨX-`EfH--^4; !6_f^ bԦBd3ǃ:w{<_v 6b~ (k us`9(v|ӽ&8b,i+5Wf#| nq`@Y&u50^92տnL7AEh1Ea Eԣ-}m[||,OT&}]"[/-Ndj@x ?\;sp$:BmCWHҫxNMC{m&eRq)f2; ~Ub![.ʢI hSU~گS〲ypf6Z ! #[`٤Ro*-F@3'(Û7O#L&Cв\ t@ʧ UL[,-TWO?r爴Lj# Hu<^*X1w|(;=קpZG& ~#aJjhl5BSe0.Q. 喢7L_sgHF1N{ [zceU7Y58$ZkHh m}nLL2[jDAz',,5MV5 `zZ2J걏$ȋz\ήofԴX~> \Q5"XC$I1Tc(uI!mpdqAE$e/fyecrchYSrQΐF A>_-dꭳmVF $I 0Z٧22r#S myw絻H2;[Y>Ȓ@kRSK|5<>}|>m$7GnpnjF>=_$ 7lSݙ$3g$sq k`DOln ]`=\/(b09 V| r9Zvv= m5aWǶxtg~eZ߾U\Ph x}\z,䀦pm/^t.6fU6l 7m3W͑af(3k2(FiFm 1ߺ"Dcݝ͋0 &a&CܶfK}&|M6D D$Qwq,m.H' ij=uP6=\`ivd{*MĜ,cRQ"l LAĭ7siae x1أ?r.LyV e=;0Ω8'$.Hpѳ {̜cyo]C6;0pI$>jX"y,YLnl+˵3FLGJ咧g4qf``b4)[D:&+;BaKlx1pcmzTEԲuQ\XLgKx/LMk&xŴcU[C@݃< {ȼnz)4"OgL4X5q/2Q&4%5T0&_٨MJH68m(4Bʹ2Cy;iv *tՂG?nPٜJ J͆pX7Ŭ?i X78 ڞԭQ)Aw3'ix*˂4Gu,5OlW#1C"T7"Hw6?߬K}hk[Zwr;OmUkb&=W-c˴/m'~-'%VFCN s:%RME)AiLwɥ^|4$gB2 -oRgן$ve|8^saȐ"!/hHaBQEPpmGIJ^A0LJ} TCU8N.>Gx@h+:Obdg݇ìSIv3 '+Bnfp P3B/kE(XDC4ȰB5fTžq'te,(% 0Cf91|4\ fT 5V'v+è $B6!ҳ0*SEnGrb$VwӒu=lCLEPe'J(V+e/VUSJf p#+ £$͸0/l&x) Tہ"(AmΡ 1ud!nsX1O!uT%4r-([o^xg$P] Y@L ҕT6 WkY.Hu+BO^xnD\*5UW>T#dP?ZEG'Qڸ+|h](Et IB3݄Pm[l'PRx<59yuY44u?Cw3# n"u) 4DeŎeZ)`/{(bPց[gIQB+C m JL`"d"jLB0ˎM5Q&G'F~7l\<ﻷ|L I+A"*M/Ip J K_IC"@Ip\2Y`=27 ?)O MrWa)Kr'YvrX鑫ap6SژR7$o#$pȚ䀡}x;~oPsR*ObThģ`5GO_B Wx 5߫ %Lz/-WJWOh_=2 GT#:Gt(of46I5 nxoq2_;d)/> 210MV. jQ9C?1!By }ܔaNHL"#g yxY%?:.k:6nM]k92xY!G  AjǍ@F4$> 5]MIsulHWp)ċwI }~9FojjL $RM$aj^QRcуTc7PXM"j~m-E>[ چoD&z=1cw[K^YY!Dg"r%/-O=#"#$֥w{NFJʧKɂ CRiɣT߫HCS 0CP4RV2-7n|dҊf{|\:6m2]ݧY |pl<TFG *g9I< 多2J:nźm/$W__.t@+ۈ) sTJd٦'d8,P{0̡CSU.);ጀ7.KɖT(ܸzS/#O-x(F,E7 +Yy`Z[0 N cDffO@BdkcuSDX ։JWD$JL]$ vYKE8YA$gah/X*D'vIT;0ӗq-(Nh <3px8 (OÉ Ƚ0iMv5>[$XtSHJ"'#Ȱpy>+iUi :{nQk̐yY3$6D:&ergy(M@&@.K v{.@nnMDDž?HE,ML56'tx(7cKsPR_AK{zm]Sl\eJj%P&hxGX6`G}qܕY}f/u$z.nT, *z35@0zrͬ .m%M,S%/Ɍձc7v{'$U/ԣ: Ӕj{P r*`]b+:va5z?I94 (/%(!#(^DŭaeaWd\btQ UN/$ՕyGnb$Em<+y01e١#ñ6p! : dFkJ$x>}JBʋHj>+(SM݂ ;uw5oEM ЮkZBu5,3WW|a?**J%KdX`!f) qne"ƝCjH6 WwĨc(Zsv<ه paX07;Yـkӟ?3`٘tgHr 5 $aP޹he"ɛ?]5l˞:.FEe׷TuME㒗zϤϒxf!>g 0m5MmMlDo>tM8g$sIu)0KdU*B3XR(j=1ϼhihe!#bm?- HҨ"-)eNliNj/\%AXGAStw+pBIKZFjia$$@&/Уw[-RRnvH/K`%]*N;Vyxx1o@)Ii69M ZA`s:gDzȽȸYߺڣm%ȴڏϊB͕fX0F*\\ qyfBYH]bŇDQESX5 9ƾin rZ>5{\8rs\"H8tYwm[?0tU~Yޚ2aI-j `ܥ ,rzz1"wp4z`pfp(I.tl`3C,m- ٜ0*-/u>>dLjӜ_M"@gy0Oa# qXFnej"mH ~C:|:`ˢT4"EM(__/O C?+D̆z f!ҙeL]Oeh$,8d>cq(d+ٻz !MfsAPw{xj~HJ'7Ԕ&%hfkY1_YֈS Т%ܓy9gmei5W%̠?E:x`# ~?H'CXK Y>^'#1\0FTLKm+m%n#$Yb4$$3O~5ޘ~ 5-m[--mjl\[_5G#Qugۍ,I DΪҕtuӵ3IL@H& D`n{ &Pzf$i^nlwi.t3"D9Yn5^<%ÐaeAiII2տRދhybWz c0rAN^0.jVO0Wݭ^0.ŎFg ?ĪCo3_c8,W 5|PGݏ1g W' 4rC.r3N/ߚ_ZRCZ4)2%xIYsIP˦='ε?mi01vLCה2ft1`C_Ԧ7?rv hÔ^ Q^j$xZYP)+i3bJJQ SkBj_يj~!prr;AE6c S҂I..c ;)]>6:ȊH׵l-yw1Cjͳ]{^<솄t&lm6uPh[=Ȍ!aLn!x[$gcbd ":T<(uL-{]^3Sy] 40/rB%2d%`JZ,Jۦ]p?v$DBtiR,T9#~ep>ziل&ovu&Ų%h'p=lΉ9ymAJ,[G)TeI֚l")޾$We7F׏C[>X(H a1cmQy׋S|Ǟ R/1%0Mi+ⲒL>O_a^eCZngx:"+ %a1V de,#U36ꔈ!#p֊fS-` -><^_/^?Yh;Sh50tL3 ronT|K! ^k~yofm[bk0;ͧ<co>e^ [C6O%HG;X<ۧ'\RHpF $@qV A*gkEE>gcϣst\.-1/ZW94[ _|G{b: v53 fJ@srC܋h ~ <2^=:b}rȖ?d.5qxn楦mGBѣPkԎ}J'3R2rb(X7j1YJ'('T$7qV]N?U'rg.7^w.f~0y<2̆D ޟ0OF,ي3-[=rvm#^,eQ@jTq!Q85xyAe@͖|[DKׯϧ;c?'8@SmCTW/l L9;%vrs. MDHt [smЪN4wݣ Oa4ښ{&ʿ3p"$"bu]"Bt-fcpnX)sc湙p2-#paHն/ڠ5o$y:O{_ Ov w7oJ;H*s<0$g]\KI 11*Ӭ]Pi sOSM9aęk VHpXIdSñSY< ty( '$⾣ٴdvɧ:Ey=)+T/ڂkIU2jTDYDR4#C82i-/B=39>oxzݲ «)LjabJbSH"`ɄA r@IDAT4y;|3/ ASf@qd`׾̶ՁA\s ?j~.wl,ǒ:ϽU^+: i~<,z b}}ZL _6(ۭ.34neԋ'|4e1IL >T3䱺:Ԙ =*p3~yf7GD:8C˿>;gm+|Yn3[r ;EDO'VfqPO3^5=gKͣ<,oӗ (IFtCB!P"U*:CA0B#uUR&8y,t #23V7)җ¢Z =nD3لpδE:|R)P<.3F9x[(lJ 'xrOzQٺI< P5[{&1 ;e/@6G[z)bIj:FX)isP9,,2~Lz`NPr91$=CEELM_MtË4Up1< 9fLxyV4 PbAl% N~ g PQD.(ʎS}tʊeH!<\giJv:Qq3BA ;е =Z13{"bx< jC@`.;SHf`qؘZ-J~<:p/?Mg۾C8 &*Ƨ*Z9صJ ŕ }WN :n˕d( wiSmZ\J׉/+I!kP 3446Gm0NWi^Nxxb)P?}nx]Ă%ޒ GWm2IL} U}KE(jCK7=},}fk6v rM Hݢ'3rtfxN|Z Ÿ[56Lk hgUcV߿ DLU 141}AY j.wSA}%t?XA0C 8/z=5ft5Bk )("͙bv9h&E}Ey")g,>mlf[;М+N[jj6 ]Rh}t]ˎeޚ&wl7P< [V_U"jy(LPrVل̈́r |Me#y4Ҕ241mЈC8*/3t(\*1Xn`>"BQ?6#d/鹖LE e"D1uWds;XmCDc hTZgR3n;DZO&eL18ttHDYL>JJ(.L/jo k4L4P*QcũPqHj%+I-۠ XޡΧ4uM;(07">Q KC'kOpzL.V 7lŪu/SSXk ):C_8nS2nnXwҭWJFL!)eOuY3!uFP%v8;̷MxAA9qn-r%mQh<^Sva> sc+iF$@S;0Qk!f©(Z$6 @h8 AE xhP&f+ Ŋ쩎s"zlfM핣᦭=kV-At/ DaEJLbNU!  `G4Zpt}\BHstR^*Ԡ q@L9.U^I/h i,=#wܜߛ&"P5C ҾNWcʣբ5w/G;@^`n!rUH&U1g>6DGl9TG%sͦcjt<[LBAř(+ 27}@)'֌H!&Z6oTVTHbȌJdd'c}6TZ utK$fjUYhB* ѿƈD 18R7uiC\ NDFYwHQ6qx [CƯ٧ܞK0VŠXSnϫ}3Bad|:z̑1g_#a5!!j:\1m'O³BjeBӸ!w{:| 4+A(kޮa#q;"^$Д){Ku=e|Ip{r54!jk9yU6heUոkQqp;d4k"HyaOa. L7na[{j ~@>l|RbVTNG6ГG[֑Z]N2Tˉ6 4ltV)8rV(Dboˡ(QKMʸ*_3y0k"o&`쵾d|rXn(Cz7I,6Iz:XY`4֋l[R M㋙ΕAK?vf2߃[&eG`H3|nP! yhC~"gOP~~k*h>= }FFD4{V %l`ǩp8.j7r$A AGAܠt|ʤ>.RO葪93K@R%$Sîґx<&4p%s%QKR^zu꭭ lE"Ҫ ~4|GDХH6)s04QӢ_\?ULYؠDN?K pӏQ" (_fY]$p:夠/Օ7lƞ 6qs>3|;}Iѕ4C:_Alj()J;Fv@Kփ>ˑ)(MF&_(#`.0]Ph 3bqoAImQhi8+RTH^Rzfϳ(<(6qjyrU[90' >dJQ;/:_"QD*ˏE*ZC3k&d#;ʑ;3HY`0>bBi!C LS]c%5N1^ C;X&`Q"=B<P78vܶzg{png[[]2=?OgNx4|ʜ T>n:w{X/I`/HsLy,qÍ?>A\]Bm3= 8/Έ{;^NރD)GVkVLvuC,v,)CUg emƎ&gIVemN4P " L}$+1/0*l*j$?نx"6L$%kwGr"~C!ښFLTeFKhanUX Z~ic90dv MQ,&NMޝ;љ3(KH:zXH=P9V(Y[k>im~c|)Q'F0va4QkB~;ܦO E xĉ{1c!|*O:H/o,(& {cmQn\ q(ֽ: 3H̫x;!)2й֡yj:Cy3v Xi'0,V*pxg"Rr0+봇nZ]/ҥS :/a?K5"I6Q1ҁLEqZs=IV]Lڥf5:(ipb';lj|z=MtMpNryKc+l ݕ*Iz2W'f̝߿ 0,Zrf fr{qǘS@Dz.۟:e`_d:\n۩+GϽfgOQg^vjf",hUXH-)Vn;߅X-|'OP3H^kIBfLԁ'E"闒P/c=qVVfdMU-'~Bjb}B_b꬛#KR1[lӗN3h"pOR"a`I))nhA=3`>H Cjn|gC8:KuaTvI\omk䬉?` (D$qBݪדWG]r&W~St5RR% -e)O4wی]R>33 oI1^,#xc7(t$`!kj!`ptttpnׇ^֢h;L늖u_#XK=jN0X -: .GB1aY?v mC'uNDaZ-;ْ@=]O9U*h-ڝ" S9VGP#g >Im m\>DAIGHa`"I?:_~KV ɝ8 g/Dm>nN706:7=1?7NLˮPJW?lqKWj>3"R|)/rٖwGLu!Kqr3 oS|-΅;,C{'G8o<Xa$m;Q$'vyFrSYt\޼Nǰ&1D&9-MZ5׌2;H{o&I( m$i$z:Khg\REmf X4'.'1"`iZ=NCӱR*x<ծ!IyЀF푀@ԡNŪ4OEX< MJ"QfϺ9tK* 1fBVKMχZ)o!Y@LU_MOsnӇBizvQIRhSQFZP*L8ENnҗ߭d4P dMR5ņ:â=OXi `H5%22X%Ty'TҞ7m |?qN4:dq"1\͈ wR^ w48c)ږeVLOt>3۪AL=<78/Arfp*^,)5/F!~u Nw'xRRC38xwư  ݬ(Ck=' XuD+F|B~ik>`Eo9W]ca?toŦI,X[zJ,ZkbcX%͸*ϧsm]D5 Xj6J{ΕJ FSg39KCf:MO")pZҍaf@Oڂ%(`M*j_R# ȷ=yȑ,&,5fkx7VA)%k Ng4cb9 &x~.,.64raA&bH蠛efqTZl-j*;?JW #Wn&W<grCQ3B=>FЎq%RK܍Pzw܉oR$d]>&;Ge2kTٳË3$8A^`D?v #ڕ c@po _×Ui-E&5`Ӭ=]:Oc/2$Y#>$]-7o%\%m4(=LH̓iS_`oOp(:6}9n6{m<;:( Vᚂ` 8cJ e)p.BIs@_p >锫ftǣ"5jZh)xD@ÿYKHR~9'R0Ap5-U aj5݉1,ܱA\<ޱ>]`Zt<(ޙM {Q0ɩ7clT$X5_&B"vpy}9沚:,lj`Xf#݉$&Fb:ƍJb'BTDĂI$M1T^p Uʌa dpȠOpi*k$_ /Z\3۝DIp!]-&ǘUiHs~~/uC;?d_x5̋FBsskS-XU!P|)9 3TJ{`8׹qg#ņrLHkF XzPbЫٶFL]T( GQteOiium,̻ LۨK EYzUB68dE|y+ ^jJnK4>_2}>+Yǰ-'SK>=;Ic V#`]v cIfs.,eۆKɩq *:9=:xO =%$mE}[ rt9bzA}=~3@xGWՄQ^-h!E4 v~Ef6/D:i#;,pSӺ5D7q9:WpZA jpbc0UxP=/,ɶ*ڛv_[+YSD!bld;/UӠwy}9_}bW9=8V_/v, iP,ԾHFe{W!ꊏ_N~-e@68-`*$hSBu?1B |A#h$o\V/OUs4#ԕ  "9ɺOnqUdQJNeeeg }qL{Jk{X!L^/U+1ϾruD.l=b%t@YHP>[Ό/-kv4eۯT"^K IBTM  8^RVҙBlIEf}tǎ>7fr.#pmgsBEB 3BULIǖ3JgsY`'zU,osQ %̜7m Vb)Zk/CpaɕD 9"}e0 -nEHR\}v"y*%є批QkA+&!Mq谛gz~wu񢢈6 a7, 0:QXWI)5W j9%#R;W~$.Ijk*uK@Ӎ P'Gm'*cx0%.DRjGI4 N9m_;_J)H?"7/Oԏyآ QV@=PYsuZ w6'_BZ'fhO4 ,[V/9a1N[ bf ֚ LLIᵿ. T'-1Yrw|rxa@"JixcM(Q@JX,K@D|N|LB|ofh45& K0 _32 t?b _;U_ s_qύk@V1 Sڮazā.4Ӏr]Ncsio3^ $FahwweO /e_S,Xե^ >ј2) CC^_OF~OW׻^.rDއۡkoP۠',_hd|.LP> =S1иB:)N<~3w{ZvP$ t 6dDX>?ׁ,`/@ ]ԋB6̀%!.;EGwX"#l@kұ]*IM 4:-3ځtҖzm6~?{Gt(6ڠ33(ӛR'G/4ʏ˿.0O=,{C?(%)854rY\+h-Z*kae-,aLJ4|ZK Y8DOg\X󠰍p\T[IPZ[}c:DSe@B +^CK[AF3Vv,HeHPu|h|{ ew؛KAeUH a<>a!{Nfedb=qdORЪCvjpYF-9Q\.}g:lK{hnx313 [x b'[P} =z+ou}ğ|jMXU@h zXQ? a%SҬOQBHjP# X ۴6-V6?fe>LU}.'f>f,YPě_h\(J*h 33aAMw?Ao`24L+ӝrf6`Y3PWSJeS""U*=0D?ۋM%B%HRdkQҟFI4vf ,X B$y'9/4559Є+i@DΞ$Sl5s$5-2X>IHQWͫ3 RN&Jo4 cD) D2Ĉh)8Q̀p٫ 堵=ZJ?GZ-c8L#E HP <}=_T*>n%uN@]'o,ȉxg؉ĄT^Pɢ1߉ B| rb0 s@aU !"Wåt?眈"t@JڐVhZ,&!"X^3' ^nsieĨ̟UJ<ؙ4C:B.uX,Eltd#1svSt~1&>Aͬ!Ns{)C` T4}]0la 1V=l^}91/kj[[íZ v{OFqC[w;gM'K{m9婥 {YDe:/`aԭJ2uVM75Q1䫫7:X~ Zmt{nMA0ךue @өɍw7"ZK_I?xDe|tGVnfmqu,H 'a z |5bAC}+%_`4YCٚoV zʾ7AG=~Xe-6Cd l?!0V0km1r8Km-G[mW KMkRM5˜㱓|W]Sy6I.: ܧ#E16C VfU~@aSb3QH@1 JZYw6qZEq EќJrY0GkJfV)@~~nxuosֻD'a&&?_֤6[@Y]?iW[R _`?Vx_8<ؿqA"mYnHE\;G VCU4%glTXi!!"D}>mɰ'}5H>5RC,en⫙Z/Y!IpH毗 ~#"Q^w\lGev\IApK,I-ΥZS8dUE.fѲ+op̱fO4yBeWbca=2";Du0 rוDMrb{ǩYK8a~8:s ]vE=wЎ)XaoM_-ES|mBM1n/bi\xrׂF Txa~,5Ee_=3P l<ę `i3Q+1gcH^~RY>A Z;@\ p鞛 XY'SXh x6mܽd!.jQXZ0]d6*IFqGi%Oi= @`,}N>DF!& !%3F g;ޛrQgQPǮD0y_b # aPGC y?Fqu]+.fFJkg_c򢑾iI&^>YLz_ꅺPy{uP`HΕ/JYt)ZbZm 2gցϴ0({ꏼ6ngwe&LP%voLn|H`~wN.3ȹ|; YFgbs(ޯ.Fי^j/$4˃MԋYh"d](T # 8vQaQ,+mfNa3ΤbCOF,ZՎO qO^L}i:t8dN.A1=~㉴p, %bJ 9|L ~KwquO8,\&!S mP9e49,7öH'?&{?/U(n7&U̳~ky7ԃ37JJxÿ́,^,?C2 _i˜*cz3n2y Л'ji?iq̃0\+8sWs"r[*=<@IDAT}98ol95iE O f½w{+z⻙5*=N4bVm֢Q!ˍsK9@F~C$ l8vZhA,$ēwt6j ȵڠȆb.c o1.),B,2`W` l]4\9š7tQB݅;s"-Z=$ϳ4Fp , $-\r>#2ƋmE C:L(= kD{χ`\9 y iJ{5rL asnmkl5O"O`79P>aŗ;du\LvV!j  ?_E(Eakg%3!emN3Ze5k:0^Nb%zljx~Ƙz3R5("Fkr/?MUٳ9IZqR#HOŘ]-pe BU;VbLWctPM ǘl QȌ0w|ZH:_D}N+AXگB9pdcf\ef;:J.mvi _IY$79n m |?w]#\Vv%26yUm{;TtHD H$2w8] >(q!f)=/X+J} P"V8 EYV JXoڗL8cx-:7;A:c,9B M!]Eq̣F"6OA xHc..,Yܿ{ړ!g(PaA$L)ͤ=cF_A 1oŮHKzomo3{rJFq25ҋ؊Fym.7lf.,O'7Zyy8p=Txx-BcS>A3d1c=^6UT%^mUK+4#D49$у*@CXa<8 Z M]3 d!$P|Kp>}mH!V a E5TfA4j)ĸTSr!$1Ng FᣳHmq&Yu/!FRLjxAƃe!%4ag`jR tHjǙ5~L.j-K^ղ3uĠ#\\}yM/P}z>MPs@!y/7pQsK1.$0r0v 2 %U 1tdfb{>4JqͱS(/&m!-wXt[@.zc}xYǣ E͹'rꋆdl$rveg&J DSDIP@ ÉFR j,\j$I׀ b͒j6OW&鄐|c,= uö UƠ9vlSFޛBj3lB-&OiP>ZrulT w'0- (1稝jٌ+ Ϥ~a8Zm㒶MgW# Lu~w_,Ii7#%]mf9f2;QăpDԀ=a4Zh&ZEXQt1F.aqbNꭚb4I*z+T-)˨?YWt56`ECn-G4to}4)e~&|_`oW8'/_\ jRMC#ѱ")!2\?57;5j/wR=QXuh_kK)[i.Ml: 'Dv\ lf03z XBjz6{f ~-ѓGFˆ:mN.`qɀj;GR[(ng5N&hB2(v:r)|KɠU[[<*:4e3%"ygF2#-\q:\l2p:ApA +6,r%M3(IV_+js(F"1xe 0_q(`J"?&E1P0Ѱ05G+/0{O|'|TgUy| ُs5*p`pBUyI Tr<fȜaQ(, U:V kl ~,=P0~A+.i8E.GkL/up!O1 Sr`:}&8__-1,9%>4ob,VIH0U[Ȧ)b#!yVaH OqSacSbʲWyj+: ͂-*؊ŧp"b쬤!Y ;ru L7e^^anΝk K.wj\?':"WKUcp]Jnx#̀,D ?v/+j\iJFa!h<1rjUu u&M"Q(*3fE(dٖՙo/CAPhL;Xs>ߎ~!zCI4ZIJ.1ZӋBƊ|qA1a7RCҀQdxSͷ@p#F|n4![0X3PWa5,SQ?DZԇby;V]u7Z<nOXm(\1*zX \֌K^F'ZZWhVHϧpNrjrQe_9{FTg i.(g`@/5-45Jၚ`x_JtF[0UK;aO ~`[i {OfeAov;(H,4?[ GWYe{#قع&?:q Xj 0H"c49pZn<$w-/}EP.~b!_Lr9:av".%XhdcZgrqĦCc`4\dX0ځ]څA*0[zQB SȖ#PB(9t,ha1돶iaHW}&05TDXGzR[@! 2m!MT Ľ z1r]$)d<>.Ձ$jᨠ>n^E-{^+m(4::7`tsxy ;/z߂HBQ~, ciü-~gMOd~PEBܿ~;Dm>H $*NN@cTZk](i-03G|>fxI62FDi /Ar}E@AcyS"i?־ >^==@f*S`u%ˍIS;lPGmڛ&PV,b n<0hT\J_]qJJy@0C"Aykh 4չ|W,}=yI*5y-j0Uoֹt?;oDGmi|at ZE|h$$a/o܏nwF hW+h|0n~O:1)'6/W^+D~PGoR-+ ۃ)3kgb{wr~&P 1ql܍2xF|6gX NR\2:u+ZA;v[[yRֿGUЮ\aG L ܍5mRαARk;,HJ9Wؒɡl )z*o}@iDiOLT\ǫwa]3 uؾEʳtЮ&*uIEU etfx~u>ݰ_JTs φ3K0 [hpɦf*OS n pO`md_EgqqOY>Yd+|3~t'%4CnӚX SfL.>X4Qzp836!ڥ*2{x3fc!vJLMOp=p:O|ftE `ʣn,$-b c՞2߿?06Om񟥑zm4ۥՌï~DWqfCu^^P:Y9H=ӧ&2\'TpGBG;#G*i#q!5smng/MiW򂺫$Fÿ~qA_xs*7bbYi˷%dzϻtQ~tbаj r8 5sBuf6"a(5nŪm jNTN#qM)1ͧvG_R cvC)?XQhpH*̚a/'d6W`v̱c,`q.|!$/U1veOs2 XPk\<0֭$/#JZ) (׏7 @"1?t@uKaTgoζb9]t9f懬qX9Jvku4S-690t_)-ro7sz‰7 !|Ky)Hqw /2+JW}K%R_$!TPRrS?yt┗u8ۀmآaIxLmI3 6dP!? @(mǷ}K3tv}[naZ .|M*Mԋ.+!n(!%CA='L>-` +z }zQ% Ҟp54s1Б<3>"N($_Z//u(K6~>Oz2xCisrR%-bsaNp5l)`G]/P]LYL d(?mtWRbGٚg (9z0D) ڤ`&$5Ai3e'$;%`C0S#4hqϗ 1G〒q@`l30ܛ?3a"tۅdq'MbN9{ P p zㅍ9͠-2fW >Iq!:$g;MyOvXǧ7ĢMht{ϴ)prh͖oNúXu3ǃ#i5&7{r{=&^cd->N >N?#L'҃Nc}gC}AP=E>6rڬAIkS9`\Oc9$Y+$v,}ZOiv.S괨McNae'όބO5 Y#JL=bs}i՝O LDcx8FuikJHUIJFul٥v@SsjѿU7rUBA5TNڨs3.6Ĉ!ac g&[@7hb% b6ښ$g$*9?H^gle$< s.z'Lw+~ V)EfFxnۑbAV~v(y>A G吷Ċ=&CK~|V+\nۆb5ߋ@cfCoK3(a^&^оǃ !GN5g&+s66K4X tN׊q/,XZ_O+q jjj^3y~ڗjd?Z,&;h0"-y"碒tE>~W5_|H}{^e7)@K GLT,}eHϽߕ-.^ز֪&MѳM"9>QHR%8jk:xQpurN=m-u4] ]fWG۞ݗ#M7IT}-DAQT@ 7u.zJTq _8潐z1%68zjrlX*8!Mbҗ/s*DH_9:\DXBU8WLhTfIRTU]j]2 W'}$9$IlvQvWh!t2iE OAj4Gw{s{*_਑=.BwO c\t/ 7hA}g1ʢ#*%.h9t\iYS*094OMHژ lBT "x[%GR zAr hI ޼UnN2CC$9_W6U4X3wIlm`GʉЀvЉjyf }^DV,HagEA 7?D'Ho0:n_jtC^G[ojeho :y^1 3LA $"a,s$3wtL*O W9T?ut+P^ :"o>qY$:-$9UX'.*צϥկuE_YBXw%ćZW&֎ 2Vc|&iFlX-.HЇ6Vƍ4Q+;[m,(EV=Zq`L$2څ"l  ri_y_1B1%I@:&*X Q6dK]9ͤd@ xfUdس]ެ2K.3H7GqZ>Famt;Uň/[QR#BRah]D %%E7_sK+a35 } UE^ZOZ}KC!Zzf/j2B$-5=Qi_=ɁHD‘',㺞_TKǾ-SJ`D rwn4֝Y9pa1CVBwZ&Zcf,f!{Ai-2\H y#1&DhEUPHF\$X,؈H>UKiA'5u&>_qy! .A+CըofVZRhT4l#)UzY |7m3k{Js6㭙 z3365h h(,vA vܺڿ9bg(Y&33Rǘ(|_ G#k nU}Y\Cw=|Fb i$ڈ~UG`a!i͗ͽ1sVhJa8WSEMƷ2Cp*iPu/×>hCtMfBz?ˋމbX*EխOUpG]Ne$XH IHķLhza03,mYyqQ$h ƶ}MqcHlHUHʀHvxxd9& ,dNMX׸CRA8a!s~ao6 sz}x&ȹOn 4[ fw L +*,-PB†XF$h9=ʕ*RˢL ђq )᫒)SF43]rLA81>PF7̝m]Ђ:tjI\R JU08Ah}kZ#zjiR}?y$b2ݒij!WObGSc2ūuͦo{T޶q) C%%Y-M4Kˆny}3`j %$ zղ_CFDf,*hln#q{}ݬ*XXOlr;0BT uIm$~ JDаbI _o.|>|xxحipij&HL+BQg r-2d#d}qL7`;߾R]nCn%\ ?b-W-ϖ}T^2X sRcf)[ԆAYb)SYRezC,o*Ip (=(=%3lL2@uMJ<2zuҹ1ɋ_ ځ~H N sA<8-CST3>uLRS a2=)P>-߶pE\7Pa NҬd?4Ĩ8$pN>/(k7Z!  ȬkFhEFun E.=yG ԋV+Jdw?prRNm|x|{u~8V;'{C.aQ@%Xm˛19wf-T dDJHL^e RXH_ŖYOl\Q@f"WT0gWfE6Fw $݊^?Ī=I;3a, (T/.(i$[?DDªA=}CO3|Gȴ_"}@~VxPU~g\@HC2h@`0D>&݄r, Ԝ^Z&RInR,p+̖RrD(9Q:a[I‡UM߼hk 6yWЯ X-v6~ l` ܰ) aSRF$&(. L"1G&]= U ٶWGK-vV:mc{ji'C@DQ!p||ɝc00iXJr!FZe+4^Pي0A̕'C4g67b~]S@dQ>H1dT o+X Հ7W#Zc`2 Uu qUR~w##Hߝ f@C7]G.ӇZ͜isdMGgCy!LM۸,;CrȪ ސIq/XaČYUBJԘʺ26-zcBЦ E))&ר.=d@ʾe*Zdc[T0,/C,7;< )+-qyAc"ԼV|NDSҴ%. G]m챇"+1}rMVFVh'F͹߿a, on  b tV[K~7+$AhM'v%!?)bn 0, |Iؔ'\6\e9 QyuE1OS O5~,jf"!C>L§3YŪOݎ|D8FhzS,Kj8ݎ 9اw6!*Q-@ Gބ03LdiZe@"無BLvggՠ!62! MY ^A0$U|\|7k]zz &{Ԍ%BJccղϺɏM[+%꼔YëLF@j6U|#TI Wֿ@? J6KK~"߷cb05,2377zn)0( όiqImZߧ.!9 8`#HYn2byFQ$bͷ4L,\gc4Bgwؽ!36JU\!\=qFF?0r,oUMV(T^6>HY*i/4f^l(CDV+ g/ KdˀuSУK1ٗ9aj&@1_e(ć&f^+`6Fvɼ̜ǩv|^^X=md9Rn\0zPjj̸T@LDwǑP)8GCdjK߆RilhQ(127jBӾPSc؇x?<95haw0MQvtMu"Pi3aMd;(+Nvx:5T'╱CIwq4| a*n,~'dJDij +A@TzGk!}qL)Y G三 =t7{g=Ln4Fd5&C*92^H):leX87(8,{ C|tMk=(W5@U< p!SK ͬ^^:ގ*$"S]G81,'~;x$Gy1Juj?vul@VH[3V2[&u[?7xկEM3`yɧtAIMHH'W |jlћZU8ex%A"oMQ0D*kor&FΒg PA]:!,{s"D{~ץ O!c^Q*HD 50 dZ1YOPI,ǪQ~]l 5 ce:5cU?nM"Oy)΀H 5$L^{ ^EIDNWc" . D\ip6it;\Cw͍ۤ885z;Z̆8}TfȶT|[h%_j|S &v$`{a`EeFr;LQԑ?aJ8!i?ҁ8cF",|:~ǣC>$.W:}th*E1*cھO<< ?t5ژ吋rgZxb#liry?R"?/h'g =Һ:Սu L~^?6;gQ}(sTi5"cm'!%xXynFh --?6,BkeleI|ok_1: ܞ Ͳ$9$ǐ:f)JHB렘,7ail}r SP8Iyb7N1$d<s__qǡfG?p^>)jtu߂Mq/ n,iW8vDD_j-'A@ 2<22`dPhZ'9˦nܴl1nG"hSHbgǦ! %~nH2|BvGTf-U<p8HHa_Xiem#r`2uA q&8[bpY{Iק@˯avY_~ގbG(iCsЗtYa [=b>?M2XMtrSME^m ';fnIT |Rc}fR[S<4AR,Jǩ:AYRrFRbqV3?mK2pm+9DegBf{%7L)X ~%GWf|T5&~9)J&4Zhf3ʢEAA\&ShQ] ׏\_/̒[<QG5V&i۷VIehY=ݢ1L,] -ЩrHLH zxc#K^CYTa)D `r91<>β[55_|yi;+Y6knfo݄ C 4Z K:1v6TGE,qع a%5 `~(J\H,çQt`mb7^ِJJ{|MgӸK $UeqcQ[ħi) v=ߙoxx}]M"^>fzvmu1 PyC=rj~ЍyEATjӯcjOpTܫ!}%:m1 ! -P(q𐷥/T9tD:)G {R( &0bRDu4Ukz@J]yjϩHwDǀ-cK󀾒K)d|GFzEw{h vM0teP]úYṀ œ:z'l8W;d!! toڤ!iB -ećteEu3^ʘTEO :ϒg['R-{8tf Qqβ-(2?%QfKT0`,WNPU20Q $k&KjWN,c>q[4W"Fa>CRiOS,*J$ch5cDS@IDAT?'!‹߆ mM6=&jKR HCbsPش߯4И_k-,R#WQ%BL{ aO2}:?`1uRmK[zHh :Ns`tG,:e<}b!rkvÓ"#A~%+U^_M E*B<І_1*{t;ijnT=r_:&L5hm`C*@ԫ\J,aCe5CцϪ҇rxF,^eb*! Jłc>PY&‹foxɆif1;@Y0# 9 z Q?WgYK;Gn.0YVW1Ͱ3?tDع˸?65"|(RnID^٦`D2Amu9iczh:X@/ynL,FҪ10ؤ+o@*&dd%/Y;A^ 10*)d%`fM; P;9 OB)cI=Av,?)tA$,CA K1[_!@XP9Ige |4 XqzaMCG< %Xg*}k!M|bs(jyrod)[$C]>'_Sd/ᩱ+Fb62C Jd 0!mʎ)JK+H[^lғC[tg:^6-- jñy yoX5x"9P4Z]k^ +7$UC$J9t QQ.)ļC(-1 (eΐ4?՟MȅԨ;-I.[-- ʮ|c+%xJ?lksz Tȴ=/9MEO( Y8Sд3s8F6wDO i(=_P/%nZsGIϭ*z|i.P6/*%+PieLa#w~Eu<$F`_ lwV)J멭yǂQ6'rdUDk$^ZᖯP8rY11v0#v& (%a|P39cvv5e׳R,iA}u&>!{% 쓀.F j.N[kSċ_.нkC.rÃ!>ߖigt7*-*F 4p?2Bxql ]2TD稖N R |+ŏO ޷ y>e[ٖpFgU&305}=1Ml+L/?/ZSh[do?T2dеcjCPbjPVApQ\Sr5{I7J ~WKߑ,B0u*;-wAf{I-jQۀӂ!ڏhc252Cܴ4Ym4+7dJ=i.bF2iv0l|=AD\`rCZK|'>q٨>1M[w׍53dN ὞yY*A)/n} &ۄK>sEe{&5b \~r0;Oc`QMTRRs9 ,5_SēᶎP]pzٮv\_N2GbSa <7s0ZTNh~h$#m$4v|c+(X?+Zz2`0_~zјNԺCWrM6x !xxűk+2y黍(Y D O s6Bu.7#^YrUl܋2sDE UhWZY:5r _}j'ד8\STHeGq-3@QB󉪢$sc-~z@YfxS -:[=ӂ\ٶr0ͷlRd3L4c}4I +V&iⶡ+hzs $;qFȎ6DNNZe!=6?7d ndI/ Rb UňՋiM@57#ghMk!pTX7Ƭd쎠L?G ^ߎ{?k׀t@h5e H]E MЪBD8^w0t%=ke  5& ̿%=7 5A\U:t8-hBS`)_g*DUy~4n"[!5WC {K22ML Yצ-!)R uϤ zZ0v/{bλq -v^-}ul+>̲'>2e D1- 6j|s hFuBW閲2 7,lߍWd8wJxB, TҾTIi˖7nߕٹ+u 95l\đhwvH "ި:D˾U>{3WV_C?iFQtq$:m.A@Igtwe4# Fu9Y!sfpm+y6P)f}T&a1g*u-=O7| ,lP3DC}}2x8M +*&9uw۩k6 1ds3jkYĐ4o;}+TTj$. D}vʒZ!i`7YK(hlvO/ozy}nEVO`bM_h'Ex՗IяѹPht%k+fbRUi!o=I⇌!U?zUV3>(F$}OԒO*0 #SK0zaPLL X\M9l?I.~$V?fH[KP+*$P)UE응u??N c k4r6אre'[DPJ)"x4PSzM`ȁ.r'3*5l+" \݅Նȡf懓i!4a`OVv2d'KȔl0 m=x*Z+  /g~/4@`.l4kݞ^*g[C`/Ol2_dpʅ@uՓjؿaߏ| (dX0oz'V"픒z |YF7 jDY'$GN>T%<.!Ui/(g"*Q'z׻MZf/u'ɖM}˔j,,f14Y*X7{֜KFP]|>Jrf*E={3R T?Ap%dzzӈC_#`Bһ=Z+X-!L-0a~Fy@\lf)J~P}lys#GdYd3?$?/#NqLpuմ8|f,Ɗ$lvvc A`9ŨZ+3ÆdoD_ (`} v|@!B KAdGL^_ @$f?f\>RWؽMwiެf]$xaH$=TC1S&ka8>o)2z?ל *hwvTNɑed?%EWsjBR^E*'@ɘÍ^"'NR=x=-*򲏶ȷԦVX2:QBr3GY[3wD6*f>8~,v1x]9%k G dttM <')|r*Kē%jҚrx`Igd#f&١iKo8-+h/zGF }yv /|n_lJC >" wޛhVCɜ\3*_H"3`G WZ7Q$XʞI.ofS 6^l7QEPk.V1?H?@M=Qo(]ADFӳ–_6&pa=Yc^cr&ūzc%7ӨjQ$߹/}z3p x'`ѺI0#7ΐ&]NFtߟ֖Yhe/\Wj% E}D} Q8p w{+NwC%8 ԛ%nKYbqgCgY ^Y-v8nv-)Ml 0ez1ޅث `yw!eNLOoP'픘~ X' ۫ I|v7{4UQ-wwM,ᡉ)ѯ\>z+z֎CUԫwJ'Wb- '$uJh20d (0d,ਙUOr 005J%&S ](S>HUhN3 k6Z1 cJXhR?V 2D=s^I욻97&P%H4'TA辏o+T10 `H7ZU Eq qRV%Y˵oL,b0ei28u]PV: ,@m*$ 2-Zb D~̭m:k (ĀEiEJ5aCӵl^ fӠ8!YVE>S0`'c}wX}5)Ó;;2@;ͯPzs9l:3m {R/>Vvl͚T 6W-sZ0[O_;j}?2vT] YvP/Qdnwy3 U`$gCn_ BQ$|Xf׍wc"4/ Ώ.RJvgfG-MMn7og1/,EZ%:cY  v 5.|99Թr*ߐA tf P' *#,Jd"_YN3Hf Ɂ !NSpe^* o'褊WaYux֯-?B@wС}IJ[G7:k;:Am,IaىHC&3Dd'NtlH](ra혱>Xi:bҩd=bo{r䊐d:*Acnӓ!fVVz ܲ`$O+1q<[ d/fx><۞< L6)$ƕT-Ni]o_ZkH VZ)aY,"'g[^f gbo: GBuqn*z-%ELL% l,XR ʢ;Gխl,0[ 5 MԄ1L 5OEv|N5b?,"'_G0DgZ`};hv*9 cի6IѳK0G5djHqR]_cdfw#EO-%H'S 訙b%(s^ r6{MZ*b r\+QCkGw7.cqJTJXcG}.Hr#_˴ 9 g^ߡUF`iPde2)a6-Cc&pڈpXo gC lȘ`& ߿LYgɚ,ʹ1NmpC6;re2P& ]#`0~'Am*%>hugrscto(Ռ6Jif7`ù0>*W&WiOOa#'Жm jh.VkC{}I6RY+5Wz)DH;Q0,yv?X^LV wJclF$4%I8:I1ƹq4  .q.s &!6ڿHYi& L1EnUy|uJb_@J"i]^rߔ̙mc7+'}GPp٦Uܪ,J6MDEReXJuSC~K{]4pzOZř,E*\໱y^|xC2U԰"Jo S)ԙAEg3Eb)] Cd'HȑIzh" *NMQ9nl=4XZ/OF8u '#hk8O@Xm0CP`7a5,1 kNk^s|W?9˚ֽ`zXELViɌ+K5sgG, X>h8.f\FQNJ <9"{/fEy'=k NqV8e| ľlm{ IF&9TXvUU׼}Eч]&"E&`XیCmdoE>,e } Gg5;]ORCh 5v̒n97'f@$8`蒗&=g2L~i 6|ٱcLz & Vg(ۿn<B2f&2ʕ-3$j#ЄZBۤ"2٨y$(3(8׼w]G*MĦcoA,W[k㮫`!bTnʹLPKc"9*-5e=5isY ˤA%u8ggp0tAU-QzUw_P!DYӂnƲwAA<~9eCiUaƘrԔV?-N|ф8\812 钿L;S$i3Xj؄3r4;xf N."ґ.?ȯIAG[nz(c(QM[YEFW'XǘV=$TCMvu edyV %!ק73Z!eČ3?fd- _k^e<]4| h4M(G{^ elJ'FxI N1½1<1c f%76G?:@{/(5R4ۗ>ᣴ b֡^hy芘*+u;Q @Y&Ev5 r0 sS!ϖkaef^ 1j8JaQR LW5,>.-UCP:s&b֪|Oq]'.VkP~xܽt_^)XK6 lyxLւ6ǯ澘B#3 $ P_O{[ IcMP{ oIzJ(~LǺ̕4<n| nve}rcQ Nϐȡ$)s&5;Xst/[Ɯ50C.Z`Σ ?i F5IU!2R(S;XW9Z.g~7cX[?=\|)a 0Sp*zH F&!ͺLܙp4Ey,7u"ħA#on",SK+V R6\3[E:DcvE@H|A~*jePBfq ǩ a״%ikw펛KO%GKT3" D$`2 edR w83AJr˓GW{Đs<4 82_rV/!*5TE[' l"TvHS7#hY5s!/) |p`:+à*hM?"$,ryF(Se~lk80<^&C>ߍOvp2@Ӻ/̋!s(guţlg9~^Jٛކ7CETRS%xlȖb#8#rqC\*?#J>aSV^flX|ˆmaK?Z% 4|b7ԑEx&$SSBF#$z|1BB][ړZ՝x#0Mum5@qA0<^vs~O1Ɇx8˹&pV.׻Mh"HSk˜h$alHߔpz1M=7vC1-+mr)b엯Y^# -Mx7xPAnqSʼVlrg3{ߵ -U/.FfUhi hqs9pYpCGNeXfΔ(Lxb92jֽ`RvGrf{v4 ȯMclvt}?:竡&&sBTT6L|6:JkL'& ,)#)*U(v+%Z5gˬN,ybv.9hopDBz0ɬ/V"eZhkŭ;}NyS۰v̍.gHڶ1T!ГqKuu j3ffx4pb0&P XpFJ #YINpFZ͚sƦM D˟hFS=^"U#XZGE^=(kG8^RQD,EVU6BW5 zkD- ޱi^#LcJpCZ8Z0df>gCǐOTZPYQX;{L%b-d@&0;5I@Sd;6ƀ;μYaċyh/<)V HPq>^}~ ^ l9d"I-t ,Ap>x`g0͌%`X(9#ZR(/t8X[ ۔e2錥p[q:uH} W!d 2^_7Y;Ih% 2 f{U 9AE HL6q/sEI`QGڢ|bQ߆*!^JƔI]֩h0# GlD -`gPi ,UU48,A QA}[3R0UR`hլ3|>tyBvDŽm@˦%-宜mTQ~S Nv!UxS6@/\ /TT6UlXޛr2H,^rP`"xw 1Cs^Ҿ h Z?Y&o >9 R0T,T (cXēy4MHI-| w'MevrR )AX0ϕ!{r]T`aSbddENUMFnUdA7"TuIb!H龦xD\cFCDM;` H;)@:j]`a.6}f;;W!09 B7hrmEƚ SfY" )oIԳ,%LV[iJV/ljL`LS4D 2RiQy(]# ab=d>+Zwm }y]W02q"`j![t4( Vr wDjĺ 5v)>4PԔw0Hgn0:ͼ$dI$M' m66}[O 0%SѸGi,K1>QJI\cJ2ן'M 5H +W!>a]ɴ&Y m)UG@x2A0R˱)ӕaW_"o]^^g)4?Qgy,iH ߖ[2w,G:CS— ChÀx{}Q`*2N:-E彉 팚羦"kA2 rЦi2qzѩUX$B> x{Eg˥{Qsq,-fu9 gP,sؒ)U?LDQo({JS$Z< ~ٵ/VS<2Q U׳{ќPn N4ľLDIz׃/A|̭֗Z#Ug0t={XDCg+ "  ׌ǧ JP92zk/vS3<+xN?[ShK"2mv`% _4ɾeH kq k\_ADc)Jh-krTGyG hh?n_,,p{ 97G&-n΀={c:0M%,uoεyh? ˴Պ#_m.4K.VO?X>0F"$ rr^ BsLbQNPs_@.o"@RNpxx>g-x{pI"LYwJ7}tTqѰ#d{17y=dNA@Ci9fj_Ģ@R5|>jv.)u޲/pp>̞ fdˉ,ǔ(E_8]^jLV z{3z8{zԆ!F]~V(ф1p4O[؍)ޖ6=!?8JؖQ 7LGSH7iZy-sq(׋5,T,f(v¾ naC!#G30DΊkxZ)Ȅٔ ,]Gg=Xo}2'X RU]=cC3rJ9T-PXT@=]%UcwKĚy}kָ^iE[c?9g,3"EJ4HeU}(> ZUSI LHk^X75b˓5ANUr4,xa&[dc@i,_{w$1G0H v[.61>kTdh;F^a7RSv:{g!{H飿J3 $ 5E:f%z'`/7V>Q\[<$Nu&u[Tkn$` -U;]cѩ0n7=XetG',etxwE{֖aufOG +8|,le;L)0X@T/D#.ieotqb?^^ߞ_MK:`crrlǯ!;!i >Iõٟ*IYHXh/u/@d|-om,SbCvp%= 2{|S.b?]ӊLy%9TNn%J~ޞpqSsq5@IT"w9͙d5V1+K߼~X:K/ouv>M 2)DħU3_g -Q~E~o-T'Z [DUL\od;x&O/׎  RˇrlA%Avm_.g)*v ̓:# L4'E!MK(rU(a<l7,͵@zE,4d8InMM __!}'j~Վ|NwVY]qA$)*Pԁ "SeL ̅u;UF|>مvMB2ccBТat: X`o-c;s A]eR%BhBbksꛘ!uIL!Xsm3)V!ΰ 1OW-QJժbp 1JEDl~k$ZHe3|ؾ0va͚MPua}O'ɝ"J81uˑ1(th(s;KOz_iE ]XВI O#SB'hv 0i6~(P*InHuhQzсhJ&)8#q4pԳerSXh]HgOb)Xl!dq+y|ULVNV>;ٱWsܨeoBԣG&jqEwBU.~^ul`~GM^1N~?{%SJB.{!^k$Hljnd='%&ǯ??:5VN5 ѡfϑW'!7D4:TJRڧsYdY["cc}@IDATBI \c҈SUU^ m 4*,iL"T3#QWNSՙ@T8#VK򄡕wujbl2L`t[v>d-"fThc4 .M͝,7tTdTM 04y):|ӨtB0_P(b:=T/I$V~5Gq9)h"ھ7\Gx0ĵJzu965ݧ7N55{kx3{O&ҭK(Ic 60ЈJU'!&q?B:BE*L>9T#cA&-H5=DG遣M;^J>%-yѫ XHua=~2g!oO}7TWg+h T y*/W$9I=Qs ~gffI<Gs+!#u<9Ao:k8!io '#ԖMXX%AU-=3<4Oz%E&Gwmi̟I,N—@]?|uLӌ-h1a J %-c#Pfr (@Ztʨ|F,{4O$GKcP#j'OvQn'x QFo lDxJoM90afefIR\[JDwI9haaPB7]GŕRʴXCx`a$C/#B'gd|(Q(``~ܮLjV N^IQViIh߶.h%@1 0Xc=G!X`K .6 '^|J{ %'pi~MWS8}7GD=Z-"3bG̿/ TS ~􊼼XZ(((:rȢ_^ό7ARjf"U H 䲕`~J[pO+zCɧi.Eu}3ߐ.؊'W64@J9!ioOOoZd9 *QLZ%d, k*6RW[ Tq8bژ,ZGW.nl"Qሎ67n#/R12*'R<4%Gg/9!_` UphoYs,0)<#;ZǚUj"%qޞDWi$eMh8B浇Sp)CXUsocF&=+X"F\n#4 d.!0X#;!kK *q'}(9P˩o)7ZJ6OM ?zC1GDV&}Ss_zqWVYAUPMnȀFmߧwl 4'yk<ʗ_ tF&+hg_ɃQQ>crDt :@tP`N%)le"ۻj +T (y] C~.azRɦ!Ac݉gY,k;.Т?q XXs>gb PE-$ u%?ʚ&)=Ht$pnt4/99jUX=IG=#mw=XV@ԵE8E<\܊=F-I*\$8}=o!ZH*ҿ=l a\z;iVu3wUe["EԼ_$WNqF zU1.o.\Kԛs~JJQ6֐p_psu`r#bޘgP*\"rkЎuÄU%ѩ>1x5YE I׀ZąBByaԖ7B8<Fv% +boeiPa] bYi,:j3ldjݗ w^$GTAϗ^Ha2f_*M 7+%;hPj蠲g ߪ}R1ŴOsKHF5z D~Vuq(yxE4Eܖ^Gp, nfa6,1<@otB1-j0`.3|YwpI,ިf"c4 pjLe 6M{ǥYdpn㵏oyX+i"%Ff-;Q18iţ|- U!Vɶ@i#ѡؠL'z9҂dcwBiSQa4t:t<Yich. ձ6߆AaѺgaVZY;T~\kwH{=rCt(dZS:[:9ZQ~WRX(z,ϋY_iWl(=#ةk870Szy&P]K 5RTU$Ѱ %0{RyA ?0+pPIJCs*^T:x@xd!8πݼty7fC@-Gf2}S{> a~|11(͒!܇ 884D9FįYoF"G̥tǼ\t@gsl,6^2y;ǥi8kш&\msҔ8d <ګ^=VDxOKA% \4x P{Ҝ\ybʟ=36/ cibYi4q(|Ъ$ '~ jKT참*HhkՇMz0BI''nMyףwMegN-Ztx"e6 C-۱7| +Tyh"I-rcS7gm^$8~(vLt7 [+ Em%+t0d:j 2EvztG ` O`7muW5sL]F2UhP=Tt)p/X0.F8UDTA-AHe| PZҙywQ.ݗ" zWkE;N .dKY#*"5DGWʄxwX%B4mic$+Rk`zH:?/B%m0ꮃdp2zs~!u=~Hbaa\LAAiKn~O1Q7P9 GGQ $DWՔ6%ɉmTk:4^Ѳ`h314<8ܥ4$2{]QMxT` "k9C#Af zZ܊(W'=#PbǪp27 ^iĩ}X#ҵAhDa]r$o!Z8džw5ύQ`}~mG0NUm3@]h֬M Z[~$) '*"pllz)23N:]$HY Y58զPS…&ڧP2oTnQȎ$88qoA'3Ģ5l(S3(J|7z}V%HBgeTEd[,\-}~po)={w\TS*QtBWN4$LŜG } Hpˋ,k FGieiܦZ56t[]H2Yժ”=~Qfgl)FxFu䠅 0DSX;R0R܅@AՔP!2N* HF yG ul;͂Tr:2|45y_Ŏ1~<ۛzWҥ E/TQ-29s<5Kzc;t.k_v/(gUpX2L܊PV2OBmfn{>Ѡ#I:/CP  40Zd:D2#4$uf#0dAhbi`P#j,~&%?xa.6[='^唽P#u[ὴe&OpywFECGԠuVANxZR:H^aJ&uQaGG$1ZN)c`H L=^Hx@KŠcc&xAB#z +.muފ3?Nl4Olh*Y4/-,%p=D5Umc=_IyFU98Gw:8#My ٨:`~&pYO]h-pZTn<1M+~z:5[{QDi%GV @=\rlISK/t'ƥ2BNY`5?+;$ յ8 rԅ#kr\n!갯2\Q;C$k/ZNR FBԗiN@V]L, =UO_DMC -*vSG5L#j#* \YhPErcoiGR).7<2αRRc\WFX8 ;mWpC ٸTϰX_rLe['q23hFԛ;](OgcJ 8j6Xa`T<PUQst I{At>M"z;wH+OdAL⻉:X`‡gp>|=Y/hkn>4N+=Y֬7 Qc>m_B 2C"άATqlM/PF^hx=HcmX[g S~>V45,"иp6Nl5_&3Ze>"R{bn#C I^`NlqS5Y#L-/V*sHQg ~YI}]Ri1xmUXwa5<}=1`6DV]i):X LnvS5aXF] 4# 2x1ů;Z l Ԍ؃x^拏1!܃gγ(poƐֈ'3r֎Ad@JzeVpZg z~?2ҥtV90aA7ZVi6vdBtz5rys'B-gry_n;$DR\T]W/:I*ٯCZ\pFJs0||4븱*F!X]E򟕠~ =y!a ֔~)2v6ҁ C2J+7TƍGx",BYvHpZg.33a6a7T1θAe|"+=!KRI+5GԬTi,J YcЧgAnZTj`Ƅ>BbcGմ\)p@iv4N##~~o , MADPS h|~%R^Sl<|qőײ0rMRm⋙H0@zyzќmy`wf #(l^߽G2R2=yY59Nȭ(轠I(cZ?ѻz4uk ߍ;fL@V7'NbOIr}{7 =B?Q<7ZWX}u>.2S/܇6I >enX3@Oam qVvk 6>=mef:|mUa|, )cn4*74X*n帤lJǺb8c nej-秔9] NNF ٴD>j+,s ;]2)/F->ybZj3}vJigUoz!\f`cWduvhny_*zl6/ v~s|PQ7}\L Խ &ן6Y\ 2"L8Ypshֲ,NM,)l@֧D#:}ގxg{V֐`y9uμ%ǥ9@1`xI]I$Bd𐃲zv}:o {"K8i\tϔS1ɕE5d45+E$Bv|N`~mH'iXr~c;G2(d%!j³*;>_?Na~+v Qߟ2:4nlt&r䁙v{u99/|]?i{5sI`9dNu~h>=\6x- %@f(Gb|#&~jܵU{$}n̾sGoɉ$'G?m1r|]RPq=);SO@U:sBV`hld暷v: ~SLWzH'܎䌬PXl÷1nwPnh 1ꬖ%i͖ Po|Hb#8 wllIv~|Zq |O!G3|#=γ,Zu?ىx^ƕUA5*,y.?JȦ◧؆qdXڪ+/^@|ցT:?F9`, =8Rs}^?dҜߵ-l4kzomOoeHFk9zuI9MٚbdqӎʁpeiS씛x-BX Dl7˹ѩ^+s uR3x k4- hȊwaV"m}wrya'葢JAѯ>lhz)6 c82ɑ Jm>D)PFܟ?pCyK?>O;%a ZW}1Jiǁ?~i`'y쒐p%=9:;1u{;!{7+E =o9VwAi8Ch;6]n&#,T]zaV[~m[v]6> "2 e_8@٬bÑۯ7;$~֓!:n/ǝƹ(auQΨf$D!cq8@L-DX*a)ENY 6.*^37ÀBH.I]ܧ'wC4anOQ8̾0T~$:Ts^1׃ऒ6610s`p{; 1|^r2Mtd8e$/ 4,,jo"ஏdWH.B`_9ɭQ&# PhkC#J!SMRTa;/?hzIQvZ:Q<0N7\K~H_ A}X(m(w=}i̧C`s)H?j(z5P {x@߁|y@9 `1nY{|ӯ)h HeLA8P1F|LcpS.j) 4N#"e":H:I$2d4Rfd%Vyl~Rrn Ǐ XzjVW$/g&:7C<}M7rz-vɲ eSgD\ݷcr%yfI3qa>sMX,9͕sr0fLkOfB\A4mT t2%VYwFg`QOu {kX*E \:Nd/1Cy0q`fH-mXݳ xH[5v4[P7Ng`,ՇlIel0V^<=[>%8 `y{a҂)`b4> qx%.ћպϘ;`9_o9PQ |kr . vK:/#{~۫^Kt @/e{.Y7 и/&GQݦW6˖OeMbp5pgV{D `PmeF<0F87+ؐyNiwTW!xQL[(^iyzeX5!U18QW !MYeLe ^lV 0 ḽvK߰6"lR0#kE}W O3Pp#OKaUR nF!JM*!*`{L .QDTĐpsujnTØk$ BI"U]#y#/ \o+  E',$]KfZ6)C}Ŭ":{-f`+KΊh4Y͖<zZrdDZxBË:S@浲5moi#$>?bEAOᵚH#%D%WxXpHKl̗.+/u^Djh?ī|sHB)JBapf0i:*p}|J7I4bOrp[׋/Us;E#9Ǫo$!>Ⱥr\ۜf۽>$ݤ 7Иl,iV(:F %h:gqҫJ2lJ0߯r9Θ WvaRKϸ(\9Z3lӻ62: \zu5ôЃ#Ρ W.>D+9rf,2h|<i(fmCՇ! #2c8ZbВ;p#4cC |z }M&q]~-lv}&xVԙ9@2`į@c$bV0}랊BTP„wR菾t1 FD@9P\g^ŧ([XN ih?T$G0\cԿгCfM)CvWh_YGT(U<H6B#{ NU{aH=3eP ѿɠa:V4; [m!jUQ/ث\YN™IynGǩPN1CI]]bM;HRD:c ΅:z@њ!V%nr1hv5-W*<$iCWqg -\l#Χoө+;w'I f?!rh.[5Fg^DYWϿN*nPO 'HH*'t)YzCd=3#IpC+|(_w- 2d㏿}wh -!ɉHzm\cM'Ubv(P'\&4 ϖ&_să0"O1x ;&F<TZ3Lo~K/JOuʸ-(Xvu zD%vhQoR.7f߫G7cɛ7xZѮumiX}@KCb[Ɏ?Ii %@#-)Ijԙlu'njp fMY)0*QPL/iݎ@/ QXѦ3b֦$z׍`} 't۴䒒A{60p)chDJ IШ}XXC'WzrFA>Ƕ!Ƈ^iBPz( Izaq%F.w$RD ut)1 ς0+ AA>jW8YQ#T$p}}W׏0$dz[p.7G iکB` EvB<(D1?/ Pa+ Re'ۻOBѱm m;?Z1G&oԋ#Z0-XQjb&R. "HQμTX 5x&/jq2lٲXQqFECS0"A 2޼ V&“BzU-؜-7nL}rdPz "SM7G$L(jӟuWA2J3z05j%PWҺ% .N|q>_~c9v.Ā]l;CAzevxE@ iRF'h)cݹ36AW2SRtB}uTY*d(h͍ ciϲy'3$A4Z>{dzC k0ad4pl,vPBP\-sjje !~=cKnժTΕJ e]")O8<_"XqЦχ&/1ް!`DbCGFly@YqXue9p3Ӡrz4KKzYsf@|H;*3 ~(nHNX|N(D:oufjQ^ LS\F ږrW/uOU뀁OoDJCSL%E'aH &"By<|kcH9JSe1U x$KM)b@Jyd أ^(!nZ@ipwt:лmh&bÒ)Zs s4KftٕK$]ci W8Ȅj,(UbCԾ%36K @Bl I2Bcg"yGSJ8gEY6`E V/ODaM'G8O},Fo|tyZjmkN&Pi?3 Xec4 &x I6_3$(*@H"Y](ݮu>LIB֬Ei:Bj&m}[:2mo" Й2hC0 1&7$p^}0&ƐAx`HA3E_/x/@"') *NJxB1- @bL!_uTx"8#?4m`W6>=`ĻJs*/JC`~n (V^ {_ >ϡ}'Yh_;[PQ9+>(p`1`ƈubp6(p1ŨAөUKL#'鹝f Dn|cБN !~8Lܧa4/ M q;%О#UQ{zH4^%+ _.*UP:Tacp1 h4-7LQ&J&t޲\o љ] ^BZذ ZDQӍ`2"eh:Jmtzo/i 7ހ*W-@BU4f >˞{.߇q ]d1[I$&ku݂?麡rc/utNay4<~~ gb:F[ E`WgZ'ާ:(gudə]:릁)GFN\4X>WօEt^V*e~W, N uRIdp0X?-tˆl~GTvM< G%4 ȋLt8ڴ䯭ف`J/6%d[ C4b55[" qP"b*'huNm ͯ/OJU߼2VG-խK N.SzHٗrzi1p#A\*r VfՔYg%NCDc<)[w[Ң58N3|NZa:&t<Ҙ> ggu06p~FxRmWr具f4ƃד'nyA!$1/A/UȚ;r5JbTs[!Z@V1HJ5utG&SSj;<< &O8gFXNY7MvjovX¿Z|ZvϵC?}+'&"X  O`$oOљAFN;`iSlUn6c&fܶRhgdK-'8STqʜ%0C%z,ŨxAQ4.} &_vkݠ^9ey#h?u'@@FGJcȣZ33_lT?l} ^&$ hb-bznIJ{>[˒G|U@m&_|{i` Wχ?M8a> !2ζRmtpkus.D_/6`? N_~[EsA=`>-ARn]>n<ٚ]gW9 "8 I룝BlA Or:bF$l=~CͲf7JAg.Ў2=~@IDAT%٪OPi ct'RpeѢ{ 2~/@,ct5u[>>cRU2ndǗL8l3dei;9nO=$-_%cNȬV;y*U8/56Wmmd=&X",]gzrб@8>ֆփPF7VPA8i{# FTۇ3au'Bbԍ"N.~<=ip`ԏ܊u#\i}pkESDeMvAk^60_$>Agx*ӓϻ;m$m\fB~雄O y̦1U ue"4@1iJB۝]Ԕ4I3K?$%m~];wcY Cli?GիW|,;Ypy4{JhG]seq<e~>XO/#oT@Ep+mCpB+)}=w߫/),saV~ǟ02Tt/HA+¶j7dnl?'žy8/vS[{KI:}zXRJy.ZG&OIy,$=H_)BVTp0n^TmـFxYRfrT5RKZds@~yVRQ@2jЏW{ R2/cp ܱ&c< kE›<6gUGYJ_HWЎ9/r-$KđZjYpnoq'vw5N0S/fsU WCtQ)aol#X}+d!fP)`%k\ 1@luϬPD`a(~;&s Fa䌯e}GA^k I(U@vS|Bt|k-,Ea}n25'EwcU6K m@ypJ \M60أʧR3`h֛ԉ jJQ.;Ii6Mi V j! ۝~1#\ouaK]mWӹL|cHu\#~Si"j@Z#R>H Qʍ e얬h%;0Kwk9VM!7)e[oLC4MՙX&TԬB8oAeo^qeHRhAfևaBRkZ[ם u3sM{&i|RRMU"i0HyTTWHCsé!J#fFW"zb\`uG @㹩Zm*IaMρ/S`RP-#Z*t^[]q|WǦ5q妑ta#y  \*W _pH~PYX&DrEy,\ݛekr۟@< j" MlSi9N>ةkWf4bŭ')==*cbTOPGVYB>gn"%.s6 6EJ(VEz7gdf[WchQ/2/QeHRc$h̓ 7}U; óۘU jw|% p@]6+\uo~ 7B.{nV~gBjz(Lk[+Lx;oy 0CNвYmjCR0~h|XIYjI+9)`⹰LW ^l~S(Ԝޭϣi6*E&@ui~idx#g6eHWeD;\ k$*VY%z<>>7O8 n&PEF#no]fdPdfdوVb>g~,=͇TnWl ԗ*P]r@)t`yPqgg1A^\J.RP*4԰F$,uqq5D^uH#ro>98"!4nGu}~ X3h C^b fo%rLzڌŃ#ylos!Dt9^hY+dƁ$(`)B4Iy &,zrM9 z?㣀KSj~ i\FﵜD~N01)#9#)GF"lZsKZboagIɶ#ǣ^~wzW:5.ɞe߄Da@Aw7'o80+`63\M_htYܤ*vAodb@pYf?ys(f&qZduZUJZ^--X2=Y&|7'VB:i^{!Ɓ'X/F[4єK<` m5܈-cv r*jqH+|#Gc*Pa]K heup\CEG3nA!;r3*)ئZ$!D^P~M0aM"ܭdnqG43hya:-PQX6qvm&<<aE`i^P;Y8 kK!9v#o@ Z"l0!⋛삍yI;/3~&2`,~TP>SL?Vqg#d !ʝEW">m^[c2> E`5=aY#j1&'@FNc(7F5w/H.;a3Cf^?Ҥ~3 \!Uxd2rW0E> 6z#5 Z9aa#=;Qvvd8 u9hrҩdJ YtA#;)_fg̾JbTq P:AHa9rkT~1^dH|aX2bg7bBڋx~fTmO |OrW T K-D-kȸ{}YX@6LE}ijy:x6>oJ'Nz|^iBSC:I}?ڲxDҜÁ H6t֠THlQɒ} ԕ#ӈC-݁h?HI{*?U);9+bB&/@Y *m8V7;VfA0BM(D#tiho>/))r.Xsb]i2dM+Qׇ)Dk=$/R=s5ඹ[YA91=0͝QTo7T: 4J`?:O\Ʃ37Rej=K^yEz_9l2V %?*j_S'6\R]>"6PbU)uUtE2iصæhEC٤Apql }p;LM}! / Y[wZͲ޿ƠWLK8&LŹKF`c>א/^P̤BouZF$ފ^\#t(QȰvωk9SG(9p-9B`>%hiDYT#(y_%+rFQ&%R gUث X .vpa6Bv/9cRmJI̖bNVuo=$2$-~(& e0S4LӪa%x^k Khɒ:pL̶j?n?X]i•Ĭ8dSKRqN%ǍCoJV8,nDB˦򪑥f1߬hK , 1DzOkFjZ bG)*@ ˃0$丱_[ozɊ,S+x돽0$|OA{k)bi;«8Zh)Q*zK#f˃P Bl$N061mdC E"f3W ?+"pEj_D}(tKK9fԣuHo+ՎӶ?[8st#ˮr!_AA::`SV4:`TtD+ԩ,{V55?q'ML؞Lg%С6]'"YWcډCPD-[S\f*VcryUB\ tBogk $6}3پv|)>R٘]̜M͋QBv/NeAo!?9qw<쏇k^wpF ZnN_;[łBCj瞢.ʁmO_MAGj9GLw#}CV2nnPhY  ɒ u@WBu&MI0|0֕S&ߥޑI20T](Iѵ[>;iAGGuONs?~[*NGW[W2+ )dzƶqY|6<Ӧ=G]ﱲQ^B]_@h#)hj֦M@ 4SyvE*N=rBȚsG-L3-7bJHovz}gШ:-F1a7 7+9}B}g.K޶u~'VM/Gh4!s•͓*X܈ZAd`OW\ o_@[sOeCCYsnOKm ao#t?-;j\is?ZykYEYv<=}szܬ >6A-xyxT/my I,8]i|mЭwAyT`'jl C3K_ ![W=DC7A$\.1E{yz~uA 6hچg*^mBl,ψ r[U_5 mcB\o VL D83uRIeۼǏ= H5,@!+` !,9^h#>F)} GIJKX DTf`zrq&Ɠc0 Mg'wb^*1 P (fs%Gnkhm-Xc5VbBp#Z|H"{."NU05ܶ+P( X,IYZ\+yLJÂ6FΑvmd MWEÚo D?eu<7*put&j C oh@P<uPynbIDrM>"o~ bVg{ b/9PdCHH`bB1Fh_~z{77T(u2q#(ɦDW͈"TnàNK5OMIh/MR:JPUBl0UTUTe¬{D*Xjтq)ӊ1.>,W %8L xM:jE@tC\1 Tq]}|Mp@'bg}ǞHZE\.JLtʶ?9t6?\kLClO9T:+aG s\bqSeKW/|:Rq$* w>ȊX 7v5*RxqiBhAΪɌEXA!߰˽"- |>EBgO|?LrECteX4gOQ)Rv,f8s/vBWj* .uh6d"U2p{x] KdgW)Ze/[h=b h|U@SPNrka.Mj-ڄd Oƶ-8D2hr.ma Dtdc袒`LvJ{[.i&^lQz`[_ ]uرUYzWR2+._*sK n#~ sg"Di0xp#sW,HF^o7Uרc[Y; Vؚ61xio>">jP]phg.`k6MS2[{M {;R`7HHL M-hc5A<P֮C؃h:^ES 4O+28ѷEJ8Qk$oK" EA񻏭*[P}PEfGQ(PKzR"P;d/4mccVS]4Qs"v…ocF$AF5({\ZWҘ:U1{u`=D0 ^-FZVʆ!0J1GP//?yB=pPGņlz dr/zĵn'jzuԫIe!;n!CD5U Ӄzh_{I3 mu77mkqpbaWkˑ|EjypYM"D% 6&#:,1Gc{eLjvmn`j`(sB:p=og1oY~^Ѐn(OؚBE=z13󷳐-HH !&)w'qy eA /5 +1@YοOތX* A@X.pRF/͵u.ȣl,+Lc͛e\Ytq@p)涁P@uCoݙ҇r1QJQBR˭_.BKҷ8qQAQ%L@M,( Fw Ha;.z G P(IB[:3 هD5zo~JZXFU +d7O| %No`˥f!*Pz*SnFJx $-@j)J 嫹lΣZ~g+R?Io8((ܳ~z uZ-L * 2:𲿙cd?6[(v\jХt;pڡG=QCRjd+&^o.m9\lx3MZ:&1"_];Ib=ĀMO!¨h%s3x^LŖdpY}ewW)9\p:l3"c5b ~]8)>/M ,0R S >dliQq#k(4`v[gFXr3"Ո旝>Ux8]m@ah^pjRj P>LqvJ:|}ٓY|KrQ|و*q2ZFիKxf&r7qHIB]bQvu/p> 9AXZUkP&JzpnT}Vwc\TriuA,Y4/Z΋!/*j;!ƢM5Ҹ!E,cBL\h/c\ՆݷnT:h̶5ɗsU r>FRxpkSLPJ r{wonƱSj8S1ͪc`K%V5cvtI{ySpOJ˾7hz6-T3GkDE$;ud3dhkYzsdq,)@.uܸڧ!x|}&Etz* X$诘[ yz$qG *Z ~M|$BO{fi((  6l%*4,}@Tm^i|xu)x(c< 4glQwʅ=ئ$%̺Xv+$ed1!PjEE Qp0c&uі#&O># :ZAS)`cbCZ5;HԹn議Yʪf"L̑C5aT$Ʃ|!LG7G^6\nr~c׀KNh !UNkR?<@b{bD+F;tks It" mn}rܜ>?[XeJ_8h=&@fBqT)ۭ[n͊Lj$,V+wa ^^҇Jqvvyq+Wc}9򁄱 n;tB%ǥi[X -grY' 0dB9MܛōcFܫ hɯOx`X˴?yʶ0>Ƭy}El)~41 aܰIHӾV釩Il݁`R[8mG aP{0v1Osx!fsWƑvC&[-2ZeyOhP>h%ՊfA ҅"v[7bGqzB1@Rt8CUwykx$ %AFٱG\*0!Ku-H`# nO@c< PDGGtowh^`PP6Jfy b NJ頾HI}k&6OfBaqe-Ȑ"`6Z͸I! $(#NnB;= tb~N )*ecQ_MZfX. ׍XD[R֥[Sf: ZGahcனs8ߚLl!AkVvUAg ʹJi41,9ĤlS)FQup ,zF7X"ԪDX.* +-(nb;0e\SIRzDc%"P y1vTEugkb>];z 4%-Ɖ-fsQ)`q yLo~[tKSF: ^1رK9~>u?,6؆6KZE$8Хj Ce>0;oA/Fn+I{.lO& >Z⢖u5bLN1 U {Aµ6&ʻȧ~H |@g75%/?4.|\g3) Fi O yٝ(ė=k7 44bFD77RY:=B^4 u5# {B0UqtdMњ^P4¨>LOVl66`nWع؝m>6E̋^gSRJ{Ƚ=ACk/Iwh  So [~ZbgO3JzC2'|V2K/?me~(nXTf_YaY=stL8*[VµN A!4GZ88\q`6aǾIrvٓ(>c'e߾۟bMF^u`a։ Ivf}gJA !G}e8&"9 ء},& Pe{bkΡMy[S씸6V-{" rExS 5gmͧ|@5-GGA` j ǬʴnDa}Zn}ioEc,V] Gw|?mwlRZs2r ßRrhLQ>(,צ,&A~t%bnu޵b@R)w;$ܱs9ul"  7u9w:'gVOE0\N.{[8\1F$I'@\F&34 /y f0Uol?xc\A4|AѴ~Pq\lE0(B#yO.9$Qy! W_#0bmk )G@P-&Hy_Z~QuF $A @U>񺂊zր~|g 'Lpʀij1?pNDobjn P!&ɲ(y.]5Lg\~NkH(ڳ[+dQ/qN8%ރhO뷫 [5* y75ER"mAˇ2)E0z]R9'<&n),___Z!Z "9f_Y&f۝Yh+8\_>-wU_L Uxk: %m>@h!(Ut3 ME/ŒfbvjTԋPXGR$:A ǹ c\;Poƒ&g.Cpy)X9@_d5x_ |%Aw[sɂ ~tk vU"הH<:XDvO*?Oj LJ]{y ?UAC-fֵixP7Чy_b=E(cIE]V6oڢ_m(NC {] )r D:%la赓v}=8 WG3 iͽI#/)F~y,`G+ҭ0ŧM;øଊ9½Ҝʇ3i(s0])ljJH) Z`0aM?-o}^ʡFfS۫6Hw@Dq V8*C}oz*xʄDkXkT?Ch!QYBwpDUY#'-Oa| y 8 ]¤drP!9TcԛZ,}UuL}HXSiw5 h4f8:ݚtd:=^X_85s > )!UV{^zS>%Sܞz$<DڭҦwlK#5 ÁƝ}[bQJ?niwH@fB&mVHfX's&tSٙ2De f1 uc(YPƧǖHq*W5Տ5 fl|dkc"ix8tmBRU" bxѡQ)etYʐ^X< s"WgdvR`m3A >hrR5Qdo@TNZ,w)S*A}—*Ѽ,aā-Ռ ]wk05ZqIɪ.i^/ 0M,m&4àYq{ys)JHN+)2ֺޛ N${&3diɢ 旝`l-kv@R%0t2h7ndrq8}4 ƝdQVm}ao .#fX&.TpUA~_S_t6qNSU$ 5ۇߒH-jUdE^gkIi:$B|q{4i7UFD#MqyhY^ТaFL] @={^LS>(y^?:3ꌤUz#!j:QU2‡|l q:$F{9$rÈ+xG9Q 0oG:/yF"nmdv[ ̻ݙGW?\.#'_GAS$P79 $D;ߧiw#ϺMAp'bQd Ki*Ę{:l0m77Fx]?vb*\&U2iygiBo:pVGe;r4EQd0SǪfFar6iLq@ S!$]9Hug cp̿4" #mʧ`993i5M.'Gن`m"&)YjЗV)) ?ʦFMU21d3ak¯'g 9U21uMzs{$F I4NRY?=`R:DY:x=1cTo C?Jc+飺R2o!`4jz/} UXz)=Mf]6i@HYwN4 +j_)Z{8 nH8-U[3pG2ӈUo\"`c@}$ePᔰ$G(8 X@RQi>U'nܯ:(QFnxX&ħ_,r hf&h.KGhoĚ8Lb$arPc8"pcf~JVH}9V~SbxhcV ncu-L$ 1k5>ӯ|7ŠJ0IbfzN bH3 h,B3!j|xKB7*മe XgZ%@S/76z΁&' 7^W2 S5ʃ JZyklxd-|.RC̴UI5$Qs,kⳣaְb̬]&ޖњ5`$ ci$NX: (fdD ZZ%/ЮI@R~_S lruSQmp (yZ 9~r/ߤ=/*Au7xesxz~=wjaъrbF؀/#)Sa߳1J৵u"|!zLN4 ט⍍$!Mڭi"Up :|\ > )d=>Uq;tG ~t;kVIL2j$1lp R ȣu Na#FܵC:C](T~PPP`HfG2 rnNWn,D`85==)'\ NeJ%&A t*֙Zf 3쩏5=̠"5UӝgЈvU pIߡq*!jVx2ELL% ZK"̊*3^!flR=yZU/L+d=Xύ"O*ܩe ޻ +ϸS"mM u鈁ܯk.*;Chu~X:k=Q4~ld+(iW2G7ksk[ReKj.&'hgcTg3OtKam]77$~\7j) ȕ!1F[75T,ybi[^_vӁՉM].٫BdXoXLa*3oO`C XC &'P?ʮQ<߰\1(Y.cz(0!̅CJtkl Uyfc3$bؾH={A_p%aEU*?Ҙj ˸u)csK7t5K}FpDxБI}7φk}YxrFM)TpvĔ/RcNiEpc~B|9Xkn0Ykf?;: uos{\yԴ-[10D8 JfbecqgfF$L(@P(" %$tا|3w-pV'ݾ~>֛O8 6 3-ex?U1 i p#1 +*F"D;kh0B#j 8|Ϳ3[X٦rǢu ?P4r?>s԰sROTƐC1wEONn <+ 8=me-44Z p9\ͰB8 NVARnKƩdaOR *Ą X{#&ׯ\#I%i[FxT[eI"$i+OsF%bcjLpo}ޖ,ېL8:^Wn)qw #`zc?x'HpZkƹtf%niÀFBAgO$xVQ9G ʞ3KRڭe?!I@,ei(z|6<ԯat 5@:RrS3%=X}f>WkO>|Ki`m/KВS!-lGvn-2X[][baRd Fخm!*uIFW,txV~ h3d99PxZ4mgyB ~F`JkBsqd*7Q["n! AKXެISۆ$"dVō;p#֕*+M~?8> Fc Kդ wc`cDھ ?A5EDiJBsqK=O?oV+f/[`T%B5N `کPxWR-0&ɣSQRlИx HR+jŧƔU&Hq˫(iw#k [mm0]ͥ^p"űgi3jM 7ج2|wvX_OO>|>upD:$jjV̎SHbCU׶ŁJ)N3! |H@,O:Zs&)bG!3c \5W CȚ@q!'SWӬ²c<Ѭr{Fb񆒩r '9R\Pv%nL(KeOAM x4QKᎃQMa'};B qc kir!X LtzH0V7#dll&N@(K.mo5k_v'Eg P$wZX npqYƃ钗) }$ȎgM$ǖhxaGsfzaM;EtU™" OY wmsľ>!SR`xl~#v1 v_ߎt8K>aaf:=; (  4NPF,YysTPX:/P">J hnGw 8J)Ή1W yY[EEg A kqt;5:>;c&pZ*ubk Jg؋=쳓QE$n;ɗ6쌊m |붝P>:$qٌ`t. H-4 Q;Ylbf^jvsnDMŸAB|s7ci Zz[&M$:91ilpr;;Fn!l9Lᖀ`MQ>qM7=; %5ȟpx}pH"%FT-qno\ ]'6#_lU5c~.LA`Q ,CgiFt<ڤ('н4dS$N)tG :'o7;D}#׿dOVzie3"JJ~i$9DyI$(`C5'IеxJ<ƺ2/4c:7.McbO"IF$(^sg@NTZFca o`Ŵnsd2z4'js,%a/xڏzS 03#mK҆نۮ*ßk0xq 4.]@͐TyX!v8 ţ٘ ִˊ24j#ϫ:v*!;IVqm.`ñ4"́JT|f6?eo %wv Ib&۞n"WStQ!ZNm&k`ަ%Wv7OnNUKzb9;{ƐTX 5p2ѝ[qoNLɶy'kYeCʿלwk9\d]/O: 5e7gYH=MYGͧ(EMWԆ3Sk5FEvfC(h^'™'NEvhI>t=<<{t 8pl_@i w:{-lG9Q&-1gub:0_{JJ̵A۪ ] %B f7졝ηiT3p/vk[֬ۥp4ԻGYmrr+p{t"%!!ȖKAxxw&%)a98}"U?=:\_2lO?H" Cy% rܯS }-oo8:]5N9~xn+k]V OEx-q^[1%2\qFFeɬtj>bKnUE+펧pNcCf( ,Y yP8?z0U2}[hEtgݘ5x蜃0/:=1J}Z(' nfL96m8I֖N-gN8'֌9In/*Xgslfh|_8Ig0d<(dnry]; ^G<Y?^^e8 - S>O:LZuᚲpmA8V*jpwYL\;]olh.tc, m'64ra{4Ibt&V%0>9pos<8 Wd+_#1(IΞQ\@:ZBPg_O""OlOI`W 3Bzy4 Sk[{~y(>_)|s.5ն`I(;*7bkMn!]fOy[I82P1PCar_t`j jjeώ>>q@ n:;RRSi)cƭD̚wCkw;wN~Opv6cavSh(F:@ Qi|Ke(}&OvnȚ8@ J7,U zŚ?͚̂8z:j~%\%MuQC_&qe[MȟaH6@'_4k*$#t8C&NrN1PMaP^UͰRVc7ԪP:Sш2{Ȅ¹TnsDE78ï f]K # ~o1kHT5S/iщ-}Zin}Xwu9N܈CLcdND{<8Cb~H2 6|p8Ht4MΝ\Ҍ/pHKrPhZ._xYS4T\!p1ȯs" z;tDo ߿kSE%bfd]3VVn m>}r1@\6)|Ž עq«VF]k,qkW@ls{׼g AG CCFB6TVYxTs.݉'GyR}ZL$0 uweg toRe/S).SI0رQxKp?dHݏ3|.qn94hj:F0f,>wFRmb}dz:Jp]7c4EH`m1ϪAɈPZn?%5`NAH+{D%^LLq|8frܴ"aVͺ7,o[rюH8U@rZYϲP1^CЫӨE!(W/\& zςiW{ =j&AP>ok Ǭxhpd;cNO}VO3Ќ3yy#0_אߨrlG?f Bwε;P9m$ǟy2u \YHΣe G`z_^U/#k HDpq/tM S jjѐCRUlv'O]7=Z nY葔:NdW?sQcJmE vE0Ze)T\,KUn9|4 \i9dԱYݐ}r!5,Ey!M½H946hLkNkܘ lMⅈTmxd8 ECna|u^uOm+ ؘvQAH7W[ьXƌo(^Q*|T067N;L͗E 9a$5S/K_-v8aC7GU9^#o g;sUun-W |N[pL(lkI@rn{unDZ3:Ç4݀\xqVզ#oRۙI 5UCˌe]qA%Ukke[WaF*N$B-D X/-wb❦SP(7&Ă-) '#"P@JJ98C}t.ӑ9&n{?] dyx&:pȇL$(j@V sim$t>ET@nfp{7/o1C%V /+к𶖦w T#׆MB5Mh'yl0l;Ok}<Q rU<8vz8G&\g%[ptq3o8`)ޯ*n(Z xM, _ c1BńT$k'[Tqi'KK# F,U8=`̮fIn!iQ1{ A*L~!cWCN(ڕljR20@oHAȪKU4Dal20Z.%mѨq>F|k8Vz.@ۤ`yq6˜HhUS<6Ѱxa-O0C[9;~m yy#˧y4[XЕ:G7O#>x3leR q8kMhُpDwsMgxY&n6 -V}pnn-0,v;Z=Q!ǷF`EXQظ90f(OC:zx+Ztlm} B'#sF$)C*D 1f8 7p3ZrGoW?~PȺ #8lTC(& #=WK H,"ƜjQ y+-4Gl,'Y&ޯfD~E7 +l86K_"wivAkLn 4h~ya:eu#q~Z Dz3RJ4z?:3K ͔դk#Vf[HÆt ~_[L>hPc3Jhtpߘ/pǩ`Q^Shf|٩ 8yyl i 92D. C 둷\@h7Smj Nh [٨tXT#Մ{᷆xFw=R܀$3ϨE~=HIX'+d8o$IekGg*D#11}j=M[*6/Qq*f1uium?5qCrN Z3!G&y>Nj#=Y"Bq~48$pglzV[ʱzd{>:MLxՒ]eja s,EuH】*@ 4÷RR頥~cc7^/ KNM &>OǙh_֙#~YraSΡP C4caa Dxi*B6+.gX;k!\5Ǥjo'm<^"^3K[ĻkrWFbVBݧo iHok~'G6 5`u1)(GeGŷK+VAdIyx'x*W@⥏U-8q\Kls5tuoʚnnKo0x=%žK%Fw})ї` )[`؋!-<)!5m\  bAN:7J RLP SQ ؊ o IJhȞF6ڌ4d(a+Ț:Lc>j%7 Rgg\a')<? Hو -99%Pj+'qú- M"͵Vf{6cpd(C缵jz9C3\a܎ʧ)n`~ϰ^SC%&h 1ZKƫ2ur@%GސK ;mTЉ/b'p¾gNUWU%EGbX!'lwuX}81+8{ϩb5K 0YZ.sM?r0khLNNQ|Ett3|2LZX?=2,N5"s7TUXk5e\ sNG60A55decq sr2j%PCfR Ȅ,XsVu/d >Qn+,4" ~8fگPAy \Y>ҭ\v9Hw{v[x  %Q!L1:0D;:M?74 o4G~r;u;;Qcuuzm?f__w1/cؖ@tg o h9`*b^{Y+f\zqPLhHXzf| #Nh1+%%* lkښg3ld%,#2++u\yTB_ yVa5{rgl$SL^O,'tzlȔ93~KnI^ c:KCMP0$ָ;g5 ,;hM^{jXr_Ky?/G[l76U_$\E҄O/\>}kX>o?g5.*'yeqOΆ'蝮C2N6#ưkDv]r8pAy{=ƲvWW8ڦ.nfQ7/ uP":%ȏwoF8?[,,와18͸i~R:#x3?+|ɍȨ#k2JBNѵe\=a/cGH Hv1!l  F2W-!6z+{ v.L|8x.~6ƐqmspE- <4U$L+%?G -_5~4xfvԹRl^ۆDD)z{txr-b+l'^l{2Ba &3F4cV5,5藖D]bbBIkz11]գ! ȠSXB阄Q2qE+_FYa$kJ"R4k 1b\,2NjMUX*^#,術,胷+'&{1'ym ZjFig1t,I3~QJp΄Zn;9?/o4R'U ]"AHz*F,+xN.~>x%vY[70EV<wPG\$?[<Br85'闓ׅVJ$ج;M{7pI.ήs%KGD?M4Ӣ5bji?s,mNR蟍̵m?v)?~VU~%KF@\a. Ef8%#5湹Γw=T}؏k;3ДwCr K[KT,ĈjHD3]`t"OJWX"ę!b+ iQ: >C݆Iymjơ n:eH09 GA^ qf8LH2e6;#VZWBp?ʡ#F`}/mo%Ĥikph16Mpħ{BZZioPp$)I.l([Iia!@!4^L`k }>r1&ߪ v.s2F.|WXSi$\7` @4}% ̂9۬ĨU_(MW \gg=@@p?(>@S, pByvl BjiJ[0f2MMׁ-,@IPU0Nӥ,.`S*ĀE 01/w+]2;dXDuiD@+ֽ** 'K=cDk ,#?EޡTXrzNDtGFxHyMT~mv4Eg-ZU~xid \hi  Z)b|$ &[MRW%E _2*2BfD ԐcNwwti'0 p[S@o(.hސ!w/'cs_>7_Nan|4AOj7{AzqGתeA 5L/4CfC~+4,x,iӰF0ѡq:XzL9IF/990.M U.'CY+qt͉1奏\# WjlܢݯQÚUtJqDtrJH%D,,0 ʍ+J ^oJu: f r7J&gZOD!YGn30w;]?ckE z#4J'*ayäMsSEڃ dy-MttB 4+1i#NB9h38wFOeL(,06g"V(!j!Dh'd:$ru?aLo 8fJ&.ْar@R% 4F B8&T~R(T;-E%FQn{h @|g{F9P`м4P+A>ɸi@CD1ez|}%׊CTO2F={e<h@5SNЬzߪAR/0m.@ G |=J% ^. N ,z1hcMRi"P1<{>d p_ſo5Hlrؼ:/H*w?=fd8h\`!JG=j5cf;2.z8Y-MQbjw`]gqPw#ɸ|5]yk[&aQLldɪL% P8>5p;Ȁ50"ErH8{,QMàδ62 ~<>o{[1,7w=@hf]yҸK c>TC\f0#qܜl-عb)54EE$%0 N?2jA`?lmiDA15pNbBۺbP:͌3::8XV kQ"¤I|0x𢡊uaFeN$`ZU35EWaktYzM~dgޒW1F%ՍzNNB,rw*pQȱ ŒS OوLGm$,~wT-s;1Րc 0RdzA'WPЀOK{!$J> vRkMvcN/J씞5g! 5T,V?Eѩ%F̗Ԑ&-mޜ>H_F]1V9cM4gǻP'u^9{tEyiyP7"qKحNY.$ kLV \I^9%XANZ%cKU@Xքs$(# Yv I<_j Jgivdk~fp 10ftO8MJf*MR^ЪYS&%F,> u8i&>G| {D^SlAoP1:?ç J=L37fR:ՃjܽLբKҷ9ž0 D2<@ J+l u1[l(k$մ+|k/cct (8B®T5N!' ;pU2>pEְU6's5R-eΧ⤸pd¼,:>gyEDE@\d[s0f#D_#& i1KF%-S9^!":jT ITG0ӯ/W{e{vILe8Dݦ`"OS.~Ho qjM[7{ k#G!8 _m*MLwC`n~D<^BzI0aO xhXԕD.5?4ŜFx auoNASG?lXi\W3J *8ju>+MQm)x`L$zňa8phb ոkDbuT_=@7q`%=8q*ήBH"NS0F~ A=( a f= Pa~@xC&6LǾ7npy)ɒa/byk _!v|d <פb|.hGgg̞R: c5$&R;[p$Z<> ,\|qJ2wtpHGA֔p}ִXې0U:E&_֪!d\[Rcؠ|QΉ{B~bĈC &_k!ՃRHRNHP* -0yB|+:`. Xr.)=vH+z [w這䎓heF,ރAjg@(aXtk`⾘x!UpTDhJFQSΤŎNqPR*鸲;=_E1KG=jZYN^ ݐ_cj50q WD8ا?Qo_=|ԡ!^M0T n(6]ܝH*|L;B<_Wص[l@(,%M=$^ce(,gKapC}aSDWe8}×3aKRՆ 5j:0Nßv+29hE/`DoÌpܿBA0si $%M3kSyM ;e7S3ÀІ5h<_OON .#| 1)6$f#gP k؉9 Zs&*X"|6WKZ5eU7YVcG&d&LNF棞`!F)i\ŏ3gTj߱v7 aM Q e^}dD­'0p~tGAu1fS#^ӼfK3ln.d`\քqqɺihw@Bû_Zrͫ ;3ظ )sK#8j2%EA}t WzQ{|W `{|< co)C+rWIcݢ18Fhc)]2e%+H# }X`:p[Pꃊn,q4:!M3C6FFZ/HQ9w|^A@7@i:'gR >Pnlޣ H[mO)nP [Bn,B>MV08j==TDH;:;$(𓨁q 3yUL= C'M?#͛Η?@t 9؎10 j쳼o๙HU:To9>2 R3 gc z{jUa+ajzx1tKAOtg$L魐=R #f4eDX%)?EOw5ퟣ䚝 ehAKmCDnCz61HN)τP ؂瓮9W T Bc Y"$FLa3*у3 N&ȟp \`_Qd5?F,HDg6 :BkC3X&J=&׭Y鷼Ahc׮F`,jjLN4P6#8=Gf6ֶ<#anG"qLN?q=&×x\̎8F[6UHOo4VXHqysՔ*N6SÏ敭z.A;('6ٿr@XRwJS%L-f>=${L6ƛѦMUqyǖ+DE^Vk'=}thoj@_6m9/L@|{uaKuûȔM <Oy> Czu)$wN|g33^z9^MtI, ׎+R9N-L4TOq/ಿoqSRr}²KZ T֜aFbWl.jPة14/h4FŨlyq7D<{'M8MP .L4Vbpe©vW`Q3gߑA#,#=;IUN^Ȱw^8Α LR+X$*⍾6޷Z5`:ڭp@FM1T. Z33ʧ5y)8u3 1}ȻC؈F, !A#hCo8e R79 _UXo zv2vZ_k_իp9t O%JP !R3ґ=`)z0Le&h-0fV y>u\$ǾJ/h1TxԝJ?#ٯ8кũIlHY;QXt݂s'/Re׳`L ԷvJP[Ȳau?񧙅8Rot.@4iB"ʌva4'\䨫b:'÷wX7NέN(// A'94BJԘ&%O%Jگ%b3Y4fΚS:& 8C$ :7 фV,$ ߳WG(hajOU*/4"Z=LzͲ҆A %&s6iS?w@UF&Dxa:!!vvlPMp<-4cȑcZ<_*Sl ц@d޻̥r(I:>' q\2]֢JOgqiE͘1_w酀ύF㮛xKzBWA@' qU"a7yt6>y]7&Q:!WMyK8z`6?dP#)#ʗ.0l|KUT&2 l UOzj F!LX,.y%(lLbstDln6/,w::#ƭ B[` #͂ qNGHOfl070s 1W>ew7PW>D jyI uu Z%&A2!, Q h[w_G-!)7J|}Y*E~ qY!^yP*qD?Ӝ%< _t9&Y3 3\Lo29s?U`k~( UǦ448(T&&M]'%B+}RtɆx2u]D vy2٦9~^0 :@Z7퇝NauaAe([kU)e JV$Z\bE2r^N/z!x(0܋`<tՓVp00ܡ\tǥE1Ҥ30{ֿZۭnl|Dž# = z_v*MKZ}~5[{~K`x X܆:ov}?^W0u0rV"obn4`&GfO>Ĝ}p~ޖ;nF+^Օ   AdofedžZ3_ YDni7r&NVu`am#@C@'VA^P]-6(r_\Liʼ_$b.GRDCۮpI2QS?QW* T"^P 5O2\>>wS ymK9EŸl#l5V/uџk҆;oI4A|\>xpy3 e}寋#h~/xze0ZE0\ס; ^OnK1DNb?F_=rrq/624cutT}_戛SϹ Zggrv,%=)Ƙ^n=dGf]O!H9&_7'*Gј16uQZ;EKg%l-ʂj)Ǒk,2BgßVaBIAO2{B(=1Kh.ϋWh45jDN2mCwc;c7^PGd+"YP+> ]+))dl./rgwFD6IwFJFO.1z+A/{˧>H&<'za/7brWv4!7yYS Gp<~[uz&@dz7u몕icF-H|!`*Pw8IUNY3x^,eyYl{3o!Mye"4^tt,5L{ߊwP*Gs$iD |kʥF nJi΅NZjgBvZ0o]k)6OoKJ`Qy^?/2& `O?2\@7<-{f^ 3@%S)1ϒd mMFRHPH$h~Q\%b GR+ڃ^ZTJD|K?_~\a#jupe6ɦ1DOoI! uU. +i*)'tU6P4 eR y3hm 0xOwkFd$0S}4Bd␪Ɵ_[8[2.ޛiBk*Z$?oHEyF#yQaLNdz#,L aby)NǕ}&Ysu HR'l ."CvM~t&#UlR le mNoߕrǠ| ~6K-HpP;C6(}HK/OLҰ1`=6wF십[%0iJxdq"L!v(Ui?}ю z˿@4k4Bi:{ $"~\?qL· lY{pRv5mE>GP[k)hwi)C wUZ .PsU4/R)R"ۍD,Eh.OQ,!!]aGXPv}mJ&j;eA`^oao$F Nt]pXq@N&F!?A$`.}`AQΣs kjN]P}CDb8tt^g}5hc=.aDxsk6PS &QJ~.|K7[KS(N!iBxI[ +jbX8 Ueɯ"m뛻= )h٣Z7q3<m#$,a+ bBLjKI4&ҵ!t P%#D ! 8'̓j-#Ax9p gn-^!e:PyZ(\;/qA0Z2\B٨f*(NzT :tRmA<H,uil':3w|ݭ=K)@LaمZ'^2oPl*[z vf6kӆZMF[]> e 9_EM+>M<M2$bj hȚ rG[|I tA洰M4:6>n pC=?B7$Hr>WE·x>Oo3o?vh[2HCLd)Ff{H#\Zx3sOѸ19dF&Lm, zΣxlox qm cSn|_ ITFLB"SW7T58(Q鴸릓B˜"{" j8STHcsV!/ Ǽ9Il{Lh,jAx2kc[0D-gt֊.0ޢ䆼iaZJ= FF[:N0YS(/ZdM)$/qw`˓v=^# !imye/-z7MCE֬ߚrXW@4H.B X=ƚP&Z;b; aZ\,ӓɁ[YxR HȌ,(とחiՄUCSȢlhFHB}y̅Xdg0lt*!f]i'5h&g]gŴLz$&TF'TUjWMYyj#kUt2-CO:؋i{R޵jLENfx0kqjOB4תj44w/CJu3hUh mSRU5UNךZ~P5{|J ۲BRAC$yR#({5&cCUdBDthQ8cr2\_S7hH`t.C1t0|jcPhSO'VI=S&vv{[HK?yOlJW33ReH s! 7L8ի"*v|VƼj+℥9̗7 L9vMd4ߺ$MZe[ F+O(F%첼|US\#9ZCamhэ[fϋ`aBT ;5CG#{J0S=j'j1XX(zeMثaƁ"m'262Nx "Ns4eZiI^30}|g* c2PVgf=T31 Oc <0"A%uH nQ5i'nL˛ڛC٣7$a"}iȻuPf ~Bsח֝?ט[ \eO`W4>@'21J SM-xQYJP_䋌M،@o'ΜpNJ9ǩ7 R*SgSƃbՈ#T^SA@I= "eNC${Zbw, J |2bZvsaQ|ÂK 9V ` 2z7HI ٍLJv@ 9s~ZYJrVOEgH5)3^)N \X!/0'H-@P O-t vT ٻ#@DxQMJA TΗ9X}*P-t3~ӛZ=G1H|ԤLWzټ?E O VǢܾtI؁FX )@+4 6;+ ݛēh%v0x¦ŋ¼W88s`ZaH8aWQ~S/xF$ɛq3`E( F>u'Ï9%:FBC(8(Y%憩, YҟvJ`j=Fg@Y f)/lED.?g[6k:zjW_JIuK;0==Cӵ`bMn[јWNiդiYV4%+|,@;뗵kv uN5DeJefd40Iy{7)_.N\Ec m+qH+a=w{;MPj \djPaL\`,b*E^ ԸԨ Y(UG /DpHqp4dKNyt4G ph% Ш?=h8^2a{ÁōEh"z3ǯsS4B # ZKa,^\x?&i>KI _zd d6-{'\LGף">Ve޷- x^V)+AJ^ka{Y6$!h1*RL~쭗.mH haX՟ >: T>[s=.c]c:z@z8gs`C%Rj$~T9P,ifjs[ i-hD|߫%6p٬ŸpUMΥZYΖS!X!SphWơȢ#tmQ6joGILbM$ Z[Y@IDATk~2^ &;:oN{eG N/k +>v_`S=Q]*E٣,~<ZvGz7CXPeG5~q-9 :%,8ոDiM'ddpAWC@7{-#[6YMۖ`V58GfcM|(8hD :e3>lljFEͬavyAO=2ajml" "GN]=O/.Q qN1L8吢Ӧ/ VB3n$%dL4`婢$++-3; O1hDFlYek߭'>5|(Ʋұ\S[0I·`;ϫsޞ%SbCP̼;ApG:f# T7D_?۸,:4oe͟81\-ϴك?߷y^vPi#z5"6MeЈ ꖘ7ZwVy0AyV?~_xC͒~9_4d3x! wLo(ᶞDo<"^sܺ.uəG f-C/3:t-vҊPDG#PJi Mm= ƚ[[d_?[ 8_G"nZRWu6HMM g8[~BdՓ$h{s4q660P$4xAD4 N834%SM$0GMġ2òK9i~\?fMH^~:{AW0`%)Yt߽$"鱩a쩆ݖLϮ&yY+kimc9<X+jK%Be7.d;\tF1f㧰,wWT3n'Sŧ xڬ8+gٶEAdPގknI@d?"×e'F4L Fu.||䅂( ӵz4&X_e T"[AgMi9I>^S{[;XIwWI ]zK2Jԏa됫蛻QG?,'-Sf*]n93fýXE_&z7[Wq\JqYP [˭oޤFBTѥ`$͎&3SBmV=]-/ISXg@<.'sIf5ץ?m =%)f;)K˗6&u|H44OM8Wq೹t|״k4{7ѻPx?]mW7q6I4HZ<~R"\ ~M,XYy2=Z@f90lyûOV;ZOC$l~Oc0+G* ,Jϟ?~Igkf^)@SinR) b7&TUШyv GHy dxA6XNĀʛ+SÞWi[. @$HMC绒@SWfi0 iz)"Z9ce`R||+L]Vʆx>FhERdV*19KF FEMڼF]$>ϴU`OuL g`Bژ]=|L0J{v n`n5g@ {^Na"DͰ`>:]ŏϷD =7_LjȠT,٤F^iE>|[Y 0ѵ n߈PD5>Gϑ3 ưO9sR<-bVݰª)4 5QjB暊 D )<.j@3U69P7dW k~Y<Ʋ,FYqgg [T8,3RCf01'WdjP3e*T,sCB5\$t&N X `N,S8?ivnR$ֳaaI\*);]@poz,5;.0BKIHdLGhidASH<}ZC/8ZYvp6H߬ӽ `jõ $ahIP{15_e`25˝T` tn.C=, a[PZpBE;iʏRQI}QHMB 0)%IM}[)Wl1h:omR蕕d saDSڼ=mw+;IoV}SНw]j)FGk^L3n| ȚRr[p슢/2OlJUl.|fh Q ŀ)S"(GCv޶G߭XL  TRŊ֨7;+e5h O)6DhZB)CW> C":. oit T(Vzrd`a"'*%^usw(K >ЄH*`A7-O:] Uꃥ،1>B훥pQ@d}3P _ lxlJ./~.W#PܯkNS01}#3s'gHxұgg["´']>:cNĥ<^ C&_DXD z0 8@~{[NBwG.™!c,Z\80;tnRzFQxq}!IJCJ;& &uE\R% 3ٵK^/JR8l!M86S@C2x#ycj>o6s r:=Qd\."BbcYZf| sY;b#@{ *<ށ 9CKYR1bZ!:? @*)B|)lmM^R )[6g'f2y{a_dW; ]<3*5pU݂ZUˑ&bv RkQE[nNd빗VDlTF\4/ޏ\d]۴+ߝ/K6DcY&p%_DjQFk+6 +˯ϋ1Xux+\HqRXv%杰hL__2+P8Z0j8hN< A.Wi֊5bc(L;_>zU(LJר7BhQ@?quydYS禼xJF D#="3"t(Fj\VCKŽr3>GȔ30W<\Y=g!^:m\FyѻEL{ňL$*j:5 r~7yU 2O'3uū@\DO pB cLgb(%.:1r] PVcIΤ!DZó淤Hb'%ȀQ `Ck&5#s`RE頬xK[[E^Vqͩ]sM˂My} }0]-8k'GSSjI5erbH҆ ɥf?}|Rg$KJ/UgaBԤI^h<7h:7",X_8F,8ԬgDzqB՜0xkYp)*q(}iT~2}@%bY8Y`?ċWXzdQ"Rp6 yR$Sl]vy.:iU2'Wt: QpGoУP{ǐ|gQ +B4dRȰf ׯZOMqAlz {3&A1ݴ׌ LhkހUvYTZqa`cdakZ8cqȥC2Qz1#.Ȕcv9AkDiUyygœRl`!P }!fr1ژ_U~l W]yfgZu+AgFڦwm*&&hfՐP($Y"MxdL ?75:;]۴[`Pv_ǗVU7g F4|ãVҶ LǥEN)+j TH1oO@ڒ4O&4X:/j5ǁh\LwQ(CV]_BfE7HY'7 ly 9CJEi(&*V~'%LEs'rrvLk/2ü)}Ef 6dD^n+޶ OӠղa G$mo_i"hg?f.ƄglCRP,l)i)q'#t8$IvRه1 TXFeV+V%4#8'm0snϦ޲dE,Cm!6 '8*yZԠ~Zz.YKiДV(%I:||ߓbەH&jE?_e埾D.@K@T%b$P辌!ST{$~zpxB$%1=AoTIĩ:ԉHa[B LplUД6 z8L|j$2ڏ9!}DFxd Di(^WO5[xog58EdʈM^A/I> á0eOrInĺRP _.!?6yI10iisр/Sbj`2rfKm[TimufLXo 9X?nh[CɅZ4 } FK$3ܜ]~ IIv~l*B~ƌ+o5 X>!$NPjj+***D&`;PT1.&|?mHMyuF>ٍ!F6'St,o4_aGhBՅ ~F$=@YDVP}t?{ 7B oFUUHH^YnQAxNB \O]!%1x-L>-#{cT@/4+g;D$|C+pL#%W9,jYUu9@ך}-C;Vd0DN䝃968$h=d.Jٰ9A>ޥd'A69ȏeA4Gѣ HF$49Z{4".7[kپYfCR$ʏ-ڛ4NGQQ'qt )5569`Y.D0$M\)FK?@g y2/JQQlKEWY.biUbse, t߶82Q?{pGع-ZIV3BU(#`YZ?AQ|\ǠYex~vӕ:")gxSzjc%wyKXV?>d h;;_8^,8R̒1c7 y&cn5Z$sVm6Lߋ߻aOmދ#N'Olbjķ`~B8WOcVR/HxpPATjV_Y'`,)6_b?BucǥN^`PS!|(S޷=ܡӞ Snf}JS9uX9*rdlla'skġ,O9HH HKM&E{B!g}d9xʏ"faΚ0Rwχ==iN&,3,XZ47Ʃ%+fP5ȑ`g9Es`7[}<P߱D\[:~NookaMĒT2f+Jf V|2=,`tKřTAS6$U,9|6'D4>PP0!egdAx7݅5: ` Yi8dؑ](2ajCUbV;djWylgS:ZRx8 W;t :4.1Ɂ7Adaջ i gψxݖֶYN<~[!uǘ`b򖎤)ڀ#- 9;ךYLYkI'56 少OS᪍ _@0V֪}pU7sIǨvw6lpe.PqT{&hodE (0x8G+دXYmu9\}!9C!Sv_C\,6:dq+i5ax5}=QѤf&1v> `'@h`vݸf nܜ-_߭d5#nxEч5We~jQdzft%A_ 3H4Qo4^Nl9`?R/N cay5|)5MD6(9mc;N/qr#tcǛy|ݾx|{e^a󒦤jjۮs١@I\֛!wKMdX !Uiqʮ||XْO[dfkeg-U]# sJFE 7. % ^_XƖ#AM$Ҹg9y9q44n͟Y$.IһQdHw㼙Nwvt/#RG~PA\|A3犣CJl@Rgy\8ڬԷ(M0kX/qv"bLdFg=^ {jl1wHV;ٖ'T2cg_ zZ3@ˋΔ[e,+@`o؁ iq7/ h6J+WL-tp"cH-AvE(:W :z0 &a:s3aYv.F1 Rx$p"62`UF]OaC1DE[=Qy5B,J6G;._m,4"*E&_p8̾.<JUAҌ\KXd$ X% ;tN ŝOdtq,PHIhZwH}k-o0vQ,1 /& Y](Ƣn7go K 7R0u;9v@)RF{U[$@bb|G1M [X4Y3+FLz6q.40CO*W]u]3M6muE_-yk:֢2FFCT&-} l`ӓGi$:+-ж2;~c[xO`-ZlW =^f&v|^P 3(6{~~D`;9gЎLbMmŘ},!HD3v|By9m^O~8 d//SQU%MJ2$Z̩Z3Eix$:4UqzP@Lo|GvLR!DpRV2Ж #`5`hF)SnU\_xaQIG k#pZ_c{_"QߗՅ$1;\P Q<܌qCE. 9%9)Ekc{U$RӰB{J:?n\z r "Q8D_\8zjA^&AABT2(ƾ~9sf k5 뒢#hjBzr37U(@ͧg6a)k]eT4ޚe iA%@!#)+/;z@7CUכdD.G[ fgFnRETɅ! 3| |e2(6= M9R)BDloHPX{qgoxg˽rYj"pBu>$0g QR(nOH_EUj]! ~cS % :yv,3bX c2:["W!.#,I6W"ZO)$3";ALs 6%&:9667HN{8ǹjm:@b}3 cNLE}~3>rn;;y/Q].`)6|YA2pVjRqakoS ȻEo5c0Jd-S Gn(%yTP+j~1WOؕ5CUf 5 gC7 P{Rvtn3JwEhe]vJqT,LT\8|x#hMb1(6 ЀÄ ^.뜔܎S#зn KQ`S.(v1DQJ}dG'HkGΨpJZEޘ6>5tQnDkoG7aA#u)NR˼3-S?ET;5{NVMcبJ" 6%^I( RYeZ*X$/b%#@#NM+BBgOլB450O1Q ^ Z['nHc'tԓW55x>:~|BwMsݔ+ڔEkXN#mPgh)* Mːڲ 5 YP.\ PbI  wcܖmHMʳXGw ]08ƙۙ#9f~bd~6xذՑՕY9н*M[OzQ}(RF贰m/;+|y'GqM)s+Tx 2&!z'@6T Tfن;]K%ƏTzt,}FVsVe6sBIefo5`08(܉9 e_h;7K43)/:HD N^RIIW%ib_f\";3+2CpԩC'~i19K^=HmUlgSrf|\zy7c:b|VÃ]1͕/5x%mqf` )fZ% >OY KNpaQntREaPsܑ25ʃoƠwaU 9nC~/8e~U vR_e4 d˖+'[솙jǍ^&$cǢYL&# j+8{bZm-z/+Eu?17#bE5< (Re&ˮuDTpji޿ػб*)U̩m3BCLWM8 "!fR^ְM/6$):pHo6‹] ezNeۛenCkH[c22#MoHJ] ,7H yLNjx$#I\,ICh H$\~t2۽*ֿeEZs2t&h=%4n-6 1a @%\}I %"ARd2'DNLn6hI2 rX£QO|!I eQ&J֢FMX`SZ$F/m]v.1|`V?5p3-bH┯ | 2G;Qu'2Lc 4ʶ &_kV1RLi}hE_RK!VPJ:%3FM_nW P-e9Ux'&^3k6^W+:ûCmhF(F 6K"˺5iQ0Bf!rDZȔQ+0eä8'7 R;ڣg@>C|(BFKpELc eIoKbR=p@#yl0E-`9\756c a^!6$,H ReVN(+6sP{QMZ0Gf灖 U)VPc7S!GbS iMÜ&q͖yq?(P/0#g/Dž" "Y?B@H7Jގ~E؊ZαoAxϦH1p{*I@Uܛ}z]Kv+?PSMҤUشЅXym!␲z8 8%K|[2)Gߴ2im/L1L1$9 {Lj, ktWsM[/dFH@% Y gɔW?4 *tVTX0܎:1R ڣklTh=@IDATIXaE96590h1GPDU(1/y-ˡ'Wji}_P7&Q m'=mP v˂z`_e0ne)x'=D7tb.a20C+R8od'Rdt#=h%0^g*1gv'`hhҽ*6-̯t%Dt& =h"꼌|A,MM@ j.YP75z0_tn$8 WSFWm9&uu+fslAȫ NgIw|QѥكLZ bڐ-drq:|q$UJY*]ևS6uIJf&^ɳX%O4BFLE>Œ욑-;qnnG Fr[?1bhB 1,F)ɓ4U"̻.Ĺxѿ+F4;0]C[6nPQ3 r,ri'8)#C)\Aq0H1n }-KoV1{yIāZxcbJNX][SUUj8ԤA92Ԗ"DG(Vt5[32a2Ul6!QYg}OCka.7i iĈ'xO,JNIEsW`QiK P[=_A~L >TUa^dU96ާ rPD'4>-/%W)V< B3>Gis'j[\QJ^䁣~7JLK:|cgl}2# %kSN\/y7f*|21I7  3DάyI[E fzbg'f :H?4Nq#0x]K=8\qҫ/sܪSCzoj cbG>sj*O“U"'rN)'uYUgC4sޚ0&=ǾxXȎ滑݆]~!0"G72ÅX(,_CDtNL=$G1 'IJ Bb_=u`d3M5aS3Q]\IXYJK,q8Kdd^g& wӱ8\ͭ RZDŽ!j6>aH|[1+'n(OX)F阳,S~eȑGKJ(8 ͓.=N| 2`;뜇q\v&UOũ O"r@~e7N䱪|Ƨi 4!dr6*DĢj?`5-A L >e|Kf}dYfLna`=e `cpvBkdF3;OZ"iyqmZ̋[)6$$6TDW09MS@OfYc|Xi(z}@!E"ٟ Im[+4ީ%̑d;3m9 B6=2&AL~uDi] ?XUBa7Mc\0G-(گ؄z'B#ER~[8,t,{L@f_~dIl5q@??`YiO* ĉ "z AҦtLNQA*_ok3T9^:\@o2-U"~ aC k6w棁c_ŗgV՟-z +wAe#@"301؜xy"KSʰ 09jꆻc0r'6Pµ*p1Ž[XvJP/vDg7AÑ#q<^+=܏z_&W"Yx|'F>J4F>jE8y8X`:"(FeQOWU}b¯{4CǐyY08q?AwېjDDΓ&rX)una1Fڮ&}HG RsW$`R_/ܭ)*eV~{.]U4#hg}1SW- sþ} 75K 8_XҔ.ĩQ Rìr7N2a/Oűͼg"31A2g{yO4r2nW%tY*(|T!-|'D0S,(5u&yI` $SЙ8}i)3 !cvĠ44 t!QB:ѽ;C} p1"Co* y[wH vUsL7z/]2iHb!@}'je, d{xxDNEz8ZfB'a>>=Iԏ:ᨼQa!L\Rd4 9[X6" Yqt\~(+Ld%f=d)Q>'y)teWm_QZf;7R]s$m乽>V[ 38C2O"ytཝ/{9WUU-@` B7yi#k(s5 9f-@^`f^5ׁjX pKxC%t z{(PaDRݦJK&=1bѱ*4qD#mtFKJ@4Phlv)PKHOdF;[s9frXȧQlԀh|e}yklg`QT{sT`(-Nj55= 4~Rc<̓<2(qs/_Nلݑ#H9Zն쳑_חz6ԤH N$M`z|3L Qm0*0ϥR4Q' Xlj W1;/*}3H1F2 ^Y) ^:50P 4ӊ:vPNh?C<|CYƆcޡ_ -y )F!E4K^JQJ$$ұm-x!+yo2ghPxex)zH0(p͠qM{ᐰ)%T!CEr4850r ;Eo0qt mO05|~R be^Txb;ݤf׽ҬS(8l'rQ<GM#RԴ5%gI9פVVM@e 3{ T)|wzBg{J+RW͆\5C1|j7v T$ K tː=3k=@ B]jzˆq_(i2v<>4*yVGKb*SejSb *7JHxL޵ǚv '!5M L,:NIHA#K0XDcy{x9?`{f+ណ (r;<P!TVʌTF2.UE@(u.5xG*b $avǜ jL$EdEj"sU\;Im|se3S`DvQ sCk#̯y|&FS쇕ݖ0V2+MgUޟ)+y)$qZP#~]xY FtojbھB ͝D}@}E!bM:ЭʅLyD  "v~=) ~o8nJh!1t[s&PPF@ɖYV=qFD)bX,O| o7se]:J{A0(9rk?o cV-+UV@q],5_Jo;!+rA_qLTm Ae)E#ژFrMZP#+4(h=/Z-}8&Q "$vbE/#{YOr^М[|^7 8)Pli Hy(k{8@3#.N9rd)c)s!  ի[k1PKSV,cfa'r[1o ihPh/+: )&jER[|H5ܡDϸrL`,ɰ.Fe_|{,^QhHPLUM#lqfI>A.0rE(ŻѼ̓,iΔ9C6P>"~`5¤ͼE#:;^45f(,&(86B#rT'&A$Y"s3(%6D 4! 5i,T7"#Ps .(Krcrq`I@Ƕws:WіD'M91;̼[dxaBV=k ~(B AqFg-M$YvD'TB18h7kΏMirhUJU#'cgt'R e:QtjT'~lɃqY+1 SQR4\}N4OxvKo)1Mpc$ yXQ[@דy5HQǶik\7f B+y4%#ӘSw8'm1lS"ȹnd oҡΒ2l~c_qQe[T<3Kप/ 1v4SƐ[$./OoÈե %U Ǹ!ev G'$L3} }?B`Y/Ԕ4btUxX;]r#tb"wjTf)"ηz qFD "CXfLƌv-5V()Ʊk 8ZbXeN\&R)x\E7!ͻxZ\rEBB'5n{itQO&vȠGG-OV4{3s]䱥X`Q6>M+s.@]ka5E$VC3zM"TxaHc~YEXٴ^,|L!25 ئB䳠l$$ *?A$-*q`tұS^D LǪKf_i,XLv,4*K7#.Vx(a`.2h;88zŸC^^j5X B?ܲ⢍S=VI]PTuLJݟI`85IJ©p2w*y1o#[wHuU#Avd`{(ESmGd)!m9l faa)hWPC62@"k иѶe+~UH1O*>"hG 7VٻB&dIrÆL;~^>jO4}oӶ$k xmt易jee33&pقxCO]He'efݞAZ;kx]TbzcN#p *"vq3&s)d 83E1R5!j\1ru}6ɳ֚T&`m9tp>h!LY:`<$'ċ=C)Wtn*2vrN#\p D́X !ݩSz[IiSrasaL^xt!t[֊GY <~8aQ'MZKSXɘE ˰#8Ǎfsy$ŔdD\s7SvoMuxD4.ջ҈jZw5dhB[@zP&1 5J!Fh(l hj֢h0q0!J&zjKU8oF9,vn!?&%{h0rNpɧߺ&/cwR޷WlR,46PR,a*2IM3LTJU >6r +?ʶ0|<9%o&rjO# Noh\Ij%}l\ cKQ+DO'IRs KvJz dZWG?\mgoyO1) tyfV[bp@NI$3(f}Syd=`B]KɔL5Ҭݯ˼c@2hѱ~DD9)R.j0x2zܙ0gmwf pʡgH ށcC*2lb_|()tVzЙ=ak~.Z-6sY{pptҥfG[#9@Իz*f[iR' b q|*V-OZ#yl빟Lt4]X1:nRTma گn\3,-ٗqXLaC9 v>G` 87`< `QF>AH]6Кljʴ?R~*(Az4i +2F ៝͘4DmA@e/l ヹ,sqp3H aH}Իl[ʇ]s*jT)VeH|ɆbE8 }ZNVO01b " ]9-6 b(Pmv1}DPxϵ MgXZ9능@5WĠZH,tA#͆xu})cU㏅J"Dx/l.L_7=c* i (.xpPL@)"aQBJŇ =1zѮߤnLBk0%?7ikn*0> pZ3hwA-_> q|^ÀrÒS7޿$k3t2W2^P\1}lV˙ DkLſsF:*> GBpĶNaHIdʚ1"xjS)bPJcqN f3ĉ>a3u4'6$% ֘<*O="vCS;S_(#9![D+ۿVCid+bi0 ,،4+2+S0쎱)/lL %frؿ!~G;O kӯGIJ-@UtA`eR WQm?>_鋚Yǥ⻽^jT{h2VdR+ˁ Dpm7.{<ӜckK)rڑe[C/+pt\ apq"p4y{A1FWT=&"T Ǟ 5I̙9\\0& ,9,jBCmg iH2;BXZ%H 0bsWa+OoN?c-EȣXjÁ! m" Wpƣ$ixr&AgޞDH09!W,2?plLou\5*K1T93%hLcGhgjB3qp:n<8gҢ8gjtim {-̜+O!X"X4+*зbxZ%V=Hx9NӐ_anΫs,t'?γ!Qi@ShZ˹l2e/%2}WZ18[IZG0UWE3bH7LjG wsjZ7@PKog c1!w1uS԰b[Uk.D>ݦ@=Cf}/@@ 1UmN[]:g DWr> s#mW@ 4 iSǴL) \ eke,|9idC*2䉹:v^  )?ØqtU*V+,y+&%m&0iM=F +![ B;DlfWHL.Ψ#9BJissAMrXGu][ӢJR;T|gU c !ާs8]}<,mn}rz}sj:5xl~zz: t(S4+q+aT=ɝ )S@Er3e S)ͷ?XrGOƸP4 =i%S eڈ)25_+pM1Lq>=oQZN(&A$5etYI*yLTSihޗe~/(rcvE-ݾ= {D~ttygȃ*BV$")P|}4JsXbXpyەneP!|ezxOA5F.ʔK1TE=\o$n)az{AC@|RJ ʽ5l40.ײIw<.&WYw@L}G57Dp6fZ<lU}M!SFeiR±t0yǟiVn'=ޕ|^ʙc Wz2? ݅a\$pu:x`BF#8V(/4AJ0h(B12WmĠ/O__oD:Me|A%E;bs=da=$7l)ɢo3!NBgaVwZBJg@v 67/ h< [.UZ W7F1X䵩A뀞JY43|c}sq "Ľ*7BzDLPAJ';I@Ze@IDATwJq"CG/"3IJDZ\g/Gswq , dG sVk/j5R'z MO'mA^/W ߺZ7oQ#,CAaA;'-XIQ؝24[oZkM>= f 39 0f4a "6jƶ[`Emk$TJF4KA so tC'O)ymH^+(Wstg\hjUsc^G(;0xQ!2tIW$=.:=GA}|+—9BWeUiQxPon,l o56qՑ]6;5IF'oqo>ȝ1_>x=Ir *Hɗme,"~v*/6~kC1)>`Qs#yggk[H틏 ,"ɧ],3od)1H])_L$OR zt'8x#r ?SB* a# `MXIG4j`iazNbiԈ[cN=G.Ku[CP}ĢQd|.LZU-Ji߇3Zm b bx:lp:c8pX8xg-f aoh7oNJS_^ѠrAD~^*7Qdt>I{L>+!zb:n*&ސs$Ip|+j~ڡB08gV|bh~PǙUM6,X\n܊/8cT39qjpY<4*NtD 7Ct[1O @x5ƻ:gzݢL Cn:tDȮxj-3KȼB!]`I#?`1dq@]44^]c׉@47= q=ѪӡҒC)L^iTjkN^?^aµ odM}3n._wɯ4Vf& tnbh3*/昮 ,ْMhQƧE"$Tkq+7# 鋕_5oBwH`O߫6V,j1&n\ЖPy =ѹ5f>GGO{dIoEb71BIBFO6)l!##BzENMYc IJhr34VBPCTs5DNL/rY}X*?Ž*EW]k˵}ٿCl P@6X8N%n;`?s%z) ~G7NW~{iqtߍ}Y@[!LۻjfޤiFO{,sHYùtn6z2q1(aZmXzD;n6 33ƙ;Gx~vn `iJj~\ B}q Kt-ޜzq;(RόFHki8뼙jhtЅ^8@a С.sh9@{P3R!鰻ɒӿTըBMۛڋQhqBԛ42;e~~8QG_y/{4)2'ۖQѭ8Rk27%*J#OZo)Ebfa[zs%ڙ9qs,~,9rr4b0R6 k{u$ ּD"j[ m0=n eHho'@mF]@hZ06RB"@1b|ǥR,@e  ^h8_cc6KMƄAyjxjWz4x&l} pb vOGYoκ?"(;/ѽտEҬu(ח7K0[$ -I5twX+L)*@5^F̤ͫgžttvso^_6wppo/mQh޽Hl6`'ޗCoϻ7n; c|^ݾ@mO&lfaC3 (h %nXW-2!-㸑/y 6})QvrD =vHuE2"}@{Ek3"v*> q`X(؍T(1@k5Xlջilvd{Qz@}ɝyy)3ih!HlxwpiQ\[3ΟTk}v /`i:ŌQ6O$ ˹RUN v\s[zuJFxU#}Ъ1MI @K~b9;jZןrYG M%#\KH[: 7^+TɊ̈́fOr?,jmEo`2@?D7U].VJLK,3a&*9\+YV!~$c"H~8ģz[ĮMS+ts#x#Ot GgfΟ&MB,{e9,Zίمe)ytẝ237ݒ-N-C:̈́@t\3Qn|5"..NV:dkuW|[=-gt G*t<6 R3R;3zc )5LF0|Daj۸c)PrՌru4qׯŪd8+'ߒ[|1UKhb,As򁞻o+ۚ%8#µRI}@ @o?( k>`0#84f\"^:a,>5kS/E,=IvR* ..'))& fGBax@S%QEņ4zZ$YeE|z_MP` (6VG`!UC)gHJ {ozi(͉Zbթ Uͼql:K52ͅxּFU3UvǦ$Thyg'cKul*6ϭ}k^uo&nBYTc%ml8BЀ>n(Q댭[8BTFFjmE3kA6*n`a'v1H^>?llMfb(wh12"Y1[]ؤB;07r#2ଲ_|vW0bG:crrCL ytؐdc8#HB(eZp2]'OBH/\{oBC~I Q);!u0ZֳP<sQ~uԞijS46 O"ua6ʨgk#\]B>'0A$8@e -*9jlifx><~O?yڽZDaG_Dk{M`)~`L9!zL1k:hm-ZYL3o <P_ ;V *=5F &ʉ45#>:d`3s];Kw̒!Xw?ZJg2cWb(+$}d=Kz̦۩q^'Ԧk:J _?6e޽+.!`%"Zj czlwhA~R3i'^-l}FF0A]$hCQO->Ì Q 0vy[1nW$dn k5성^ an B=J,i)eȎv1Af*< Cka_bJW^F  Dz4P ]uT#@߇y9:7Br fD*=_%KݯJ6M6$0I݊=tNt]pR~|Q@/Hk|Q{LLfIj^9+|iZ>*iorMJl0Mfdk L$a(v?mG. 7PV ;*(3[\WE 8pi >J|CQ@~$l$$̕6^%lW2܊+Fz(j̔d8yڐ0{i^=i Cj|ILuÝŴ1 Ц4voZ/ݪ)וЂdt&a'/Y>4_iY_|:!IBEJ(k<.иIc| DX2XrT4tf%Xq`o}#%o I~䜻M0+.'yLA aa[0&uA֑~4 H'2Сq}`_lP0B`&p--ьWJ ATx"&Au{\2\fye_іZz gfK1ea=%Px'0bb\bX{`:0 1nk'阘:Q?r" ׿;B!A{ zDD:k H}yZ.Gϊq>!|WCTǺ!2!=,Vham\ɸ4LMZe=|hIK0sz3EHN455rFqr*.lo-= _O>+y5 !֑-bkւ34F =Ga!0}XBC@ÞkMb!%kPqep$IacQK5ǚ=Q(;@kgӈzy/(|4- *پ0P2OX5'Gp@,Tef)m.mye-{&n89cm=4:t &hq*u'P_ihaxM P''i͜BX=C!ϔ%P:m.)>uJmmjX쿵{z λ(Ф% 39^ HVX- .X'ΰbM z8g.bdt}&4tA*pB"k,PZA<ࠃ52A8|ײ901¾J0|"Z^ĕfuB$<+Rru k`*~c,mD38 AV?>YbvuOG'q'#j.,  . AuހM쎒vCa[ eZ;;[J "#%L!s2c3,)Hc컒.f5@(tWDT*~; ԉrb)b(yMv/8!p-USY9AK L‡4`EqUщrI8GCВB<;R(ľtmL\m|LqT:'АSND;5R LkqZ%oO?=*P  Q/I 0=[>_>~-ar93>'5IeFL{&{͊|"欟 8FO6GNITE1сxApc㟗oabnaHV]‰Zcr?NLP!^=y`"Pӫ4f5${hmmI(1D/`4V%Q Y$ peإ0 LSRLh+U 5nDNcx}~d![Wy(tXzMSdLQ:HMWm Xeaݨ9"-hJ0qr?^qZ Pz5`PmOW>^k/'.8uAV a~@گ;El@, B.icZ? QUkb+r48t]K}Hr`˗~7H闱)αSN`mCuik>'IGRj"`Tf*jzC@&iTsҨ d,vl,Q!.h= + %eH rVKl! qW(qE_m峔[_3_ A4h"DD-)ܼwPg Q1 @iB(@=Ksr)A&pVwֆy B;N2CQ\ @g4crȂGzx677F8zd,LJg%S5!V]4PX RPg2-Cs%(gŢ:R}Ka <BVB~q&E="EҒ[nKպoY0z6L9E` k^!Ejj0WQL2M:7uC"9h6B*]F/'e@41gy 9(Ỵ;lGv - y4SHTyČ$a7߀JOsIiOR!;;KvrɯaIZ %EB3xLbdBJwAkh DF[(I5b"wy]E : lx@ n zwNdQLg.$.kR SL_ ?X`UJU)`۱\61NJwIZLYG8fABl[Xa"Ql>P"C+ \guqa*oeUGBsj0Q;;O\pGKo0xH+-gjD0D8cg i~tC#$S ߠ\ [2bJѽ$]~|=p*yR,(m{i'|Nh Z#5]j;&g"Yhe&^M]+@X}wrmHq  wiW}M>;q;'} hm ~qE*=2!-V)J7% e1BU}Wkm. Wǽa۷&@B5TPpb%RA<җinF0sTx `|CDgZw\,2<ҥ[AapY'F ?I\M Õ\bE$BiE2>Cu A0]q&G''SG97,lzoi;axm`cێFٛGew9[K. JwXL̩9.v[8Sȍb;cȦRx#i$QDPZ]Y%@p#2=fp ζ֡wD[C^ sZ/q+43XMS2nzM֚Gb'wBQn@̩jVHcS:|}?V@Fۆ5XK <aDu°W(\۽pvVH' gI&-%di׺"@aąu0{yOgN{Ͷ~Wg"?bˬ1SrLm˃(kټ0ՙĄ >絓HHܫcܘ^޴}z"LB,.74 _&G`w'gPmY[MB}Ѥzti Ɂ>'i:vd ~_緟S' sYow(<;m_=oڼ6@B3sϯd^3WO-S DJR~Rr'#"Ngg(ˌІP v+ |PܬHrT* |c[9:j?l`Cò Q[[3bCVj־l+)N$k0<63OtV R{JidLR":a"zTsj?m7:wLGk5곩9Io禅~Mke: GB ,ײ]`Zo](X̓qb&|jLu`N4c<%}[DŽXM]ܤZӚԕcB)ocmLۦٌݢ@Nbt>mԔYן[o_hlJ}96 Ŵ!Ȥ&À>6lz@tNf挜0՟/Ά'B6RϋUf^A4r:wDdj-tjV¸zDm$ EOu4{+m\!p1;A:N7ז>'OpZxǪam,0M| ?hY[USU|'+xdM>UvcD0a=Fw`X|Ugfp%+C+qVa{d|ӫgG(֍V\4 ,>h6yP~rk_&<擿ݴK$Ql4ҘɤxP"MEf, O&lȩ#2dˉq'GH =ޥ@A#A?hOWj O "r=+4mMma%-=Ž(hGfC3gW`zYW2M{H._+)Ȭ^uI/ZN܌՗M!+& ?j2cgg$ I$xd9ntw 2z^>^yn/8-x,lQUT)NJyF즋j҉v$F\zS@HrFDeVnNCLsGHvNkB4kqs2\Jzn Xcm}QZ hf ­/5 }l 1GYo #?8Xb\bmH0y#(M5h&+H"v/ IU@Z\ e9ӡuJi7BO,_V}X"[бqyƭ^X٧VŤ> >cV4;l4c:Po"&V_Ìsx25SƬȿmIYTPCjmĀ*˓Ei- {#H:- ϻGi؊qÐ3j0>J5(˝; l?EoI(J x$):u?y@q BD]IH {ZBA*L`X?uYϝ\Nf߿}95~}xРKgw&ĹilS1~ΌV {8l"čԈrsبIג0(4a@;p<1 Eޘr,E p=~WK22.wynag:fEUm)j?fP{> V[fKb!6or*@Q%(LAT0l֟F xR-eD'Ex50~c3QBڝP{j_D%I(HdE=f٘_BԹnIY,Ȍ=<6B,m&>c5MU=bǤ˺|"([& D2G8ŷ]nIEeI+j5)?a5,mbv?*;Jg_2xQcnq.4'B4)_?f0^Hk|tp:]lĵrAV`p?Vi)[N u4ؚx0$541KizGD .HSǏ7EyWwFJE6cx UZJ];Zf@jFJ]<]ET1 [>X^ tҲ=ɟ9$_SڐЅ-,%I<Ply;itQQѲ mDAyƍQqCM:*T\7q+)\Z=M];q-Gi/LK=Y=F&P;c&l6'>)#Oow`PWޯ:rh'_mrO$0qO @?S_c,ndv1z7Y8asAS"nZʘ](nbc 3I*y"$D92l9 ]RuR4=(E¯-Q6#"7(g<֖lS')1Qa>,س۰,+69fM Q2nnCwf*uPջSzn9?Kom=1t&SDnq׋K#TT  0jb7y.l䩈ԩL=fXb}U Krd9~Q m*#9{Ÿ* j w)зU-"qXZ/ rX_oJnWNϽՄCm),m Qau$hS9 = ڊL5w;~Wo(¸d^ .=yc4gAt*}"w PHEudLz ~\ ^|kT<ÑA\eaiFzkC$xV 8np&LI81_6*Qiji/8GR`±9B[-7tek#)-lO5V^)"%sԐ4v FƝo? [KBm2%8J+u~,d)G$P?+iCqH,*oB5Qnh ;aQU,8όvUFFFDln`w}GZxN_ިr -'iy(ސ뜾WGz0ӿ-W-SڬWPج ֋%דCXpBztdž:ND) Zn=t0`ҘB^ ?e "h9N5tEC7Ix=Agf# $u ]d"Ҙ?Vx93g^YcWΜM~{S!+Po6'֝ZE *!2@Ʋ,&Y^Nq^Z v.qmNӮXv.+1&0rerm! *+g@| >`&g{bEپf}j`cVH2yNਖrH xYyrt^mêG~g/Tt82 3!}$=*gcZR'c Yo1d|: q$$j5AˠqMe uq&Hl~2$ʠhkH.ٌ,1~jV }Nh欽1%g@0r?lHNgjK(}4l|cg+7+3r ֏x(iA*bj-RS?q\w}4N.'J`t#Y4$V!x8qe3 XU&$_E_'f1&"ve< #dT$ oy/K@KG(t }P"wl#6Ik'W`h+kǽ'[橰*&j4} 5 (* (IPP6R 65?3"?nPPr a`'^}ol#ѭnqnvHO:0ѹă8qk/DJ#!\c,A|iKEpOkEt ;L*:OL ^:aC\L 4/IBycƉEs},•elǃ6mB`ʉuzrP8 Dp% >36G?9^YIdcf'S]V"A ىN"sByYwu‚oyUd8݇D;*ׯCb l;0T!.| hé*CP?LAdGUfQ'hW`VE&X}ĊlR!䴣Z,r ?0wuEm2Y.Ҋygve/h18}P&k@Uit@k 5HiJⶮׅICw X =ߗSgQ\T@:)sXt1]S9񹎆C&c^ľo/ QTsa߸$ybu?[baRfeutsl9NL H0df2yj_[MZ`vHEz[+K~ȹі\߻ΝՉ A:@G}*fV4R/x[ ck&C/9E4H4#Dd/~jɢ/<'%m\8<_n|x j~SO!y7--u?eNru4.!K>]Y*{e<0y7{BO))oUD.jK4]y"oasI^iIi3.5)_D\$Lݣ*ԚQn٘9Al,:ecDą"H,"=>-T.7//_gǍ?D{o,ց̋e*O4>ZfC\֥e^A.Ah =,᠌=pk;& R?ziHnp?Y3"%qCO1й5"f.z@=6ݾO'irI"}LH6|~irN؝p MYS"{ms˻Oo'q66&dpSc`3 N D2pd!n*hCR@H/q>CQ"܄Ree=!WkPJ[^dI-z'cՐ$AσmDMUz~ ؠ!`cֈJj{ {0rj+;Is)i|Y{/Ѯ˚gJG"UhFQM}rI?eFwm|BXqz6BF,܃2W J6P <| ,! E :c/:8vп*V}qm/>"[ q/ȝrNd:=L:YNvC 8#y8#ZߐT=RKWa_Y0܋@f^/.:'la=Da['NKiuR%BTp <KxsoAazuy'O?o,6~dr{>㮤&q|E/&5vhV? D TFFi&A FXP;4m:Pw) Ȳ/v0CD=M}ʘ`:O/xW.\O=ު~uӟI-mtj31M6=RL@m ):L@zp]V~_mp: H 4Z&$w&rP8{gFXkI*,u$:#3^p'{Hx(;iFINy|X |nh `*5$0[ią()'la#~Su:T/f@>20RK۶e-xq~i})eYPzSCK2|Wf\;РSɯCo.AU0uYf^?T"eo 9ʈe|Y.;\4X%.G;9MԲeQyOVEz؊x孤UZ9E=p$@B3u/"PDo-f3#3IzU {ʩ 5_A]&bzg"Ko AE@L!rIM6E(=%䓶(<1wJ1p+OXV8o1OaU8]Ԍl'/l<+Q~YXglgQ P ZݬS#z-2`fb|$Ԓs (WTo`D} Npp6Pb 3@%A6D / ӰC?<ḕp[0h( i u컜3mPI*O }GBeFg(Vӊh#x7gRRSOA#"x6?{&ڡNJcz2)I0=ft] h1_n6L=l+L VO s[7W?c7$B515>k:#/#%8[Ų/Q/hd^tHt(@Htu$(Kl$94C2 `iCήH 3 דNq j'PDIeڽ}gQV@jX^}/Vem:,"@&S7R@S%YB]Gqc2d~|9Nʖin0yj$(0}P] G@#'<}[D5k2yL>$2;kX}H ?} nSa CiȠ%LGeLhpCu}1YLjgUV\*zhIv@FTM0[ſHR~2UE|M5N`y XZLGZfBD=R΅}xЙTN2z/{ՎET ۠mMt10;߄`Ѫ֫ק}ԾĕWh,X>>!T.}diS{tRTІ(-ۯCT Gܦj8^V6Y|1`H2? Y JXK)~wz4=H:'t4M)HB;pvKYS]70u0u3RW#[R;Ȣ# J2\.#,v)hdb2yQ(-nHN:S1KbˉrN"ro#8S ` .b,&èy:Xv62d4O !Z Rϱ8F)*dee,)rղvY0c"q ՉJ4$;#I\7P< +!,dpP:qf>t 6#.SpVu#%$$#) rov ʑ0PbhjJ:8ݖ%U]!TلL۫尤 WK0 }Pe˭zͼ@z3Y(͎(=`!0(?"Vb-{uEK=i(ChU ;\21MM!rBTԭGvV0;iߧlWH(p]\#_Gf׈Ć]CPE~1h@uqR<7pj920HHq5VhN WHLՋ06 cրpMZI i42])oZA4DUԛd(DRvDu[rG~h,Ctŝ'<5?, iF*VV0[TS-Tzn@?#4/@+F! BAKďcD N(< \=26P`L&ahI@}~E0&w"|Sek1$mZ!ͷ[ #r )2u@aKGB\PWUB"jug_xK܇5x zk܇۬I{jm3V.jStDX,dX[nn݁z`q,(MmJC- bG0>^#qUUX-uk$VUKK5x#:+к\i^C>zF*|Q0O3g>޷7tJ8GuQ,Y)8R0$ ]6h^(H};B 5T@0/sNE1]YgވԦTB@*mC@5 ]CLi*hApc\F سexK耪V+u"`SRX10m:my)e+.XQ:Fƥ-ao(yK523ݞYxk[%F00H@G",ŌL6-~V *#3dCڒKн$ty9ͻhG m|FU@fݿD#QFs#Mr/XR `]@('m 9z=*iu.A3bXd+ϱZ&s)'ϔb ,d6o(51ԧha%P&D1K{'؛duJ@o|=JȺ pI,su![X+4z2 %h+Xu~#g{rFc3ιVR>o!5JIVSOCLpɣSv L eQ/2GpQ*>4P> ?\Mͥ H\L@ˡZgjīm9L ժꉖ%huR$PЏD*n5o+& ~,fp-djoNxe:YhyH"岨&NM6 HX1;絳bXOlִ23_㏗XޭIM(!¥&Īӱ[na FxPŷwD[VL ghPv8Ʋ.%L6[0LjI-\19[B~kg4Վ-dʱd2əWom0冂LO&>Y/eÓb%S`l*Q}'(PN}I5R`G p xX3ll2—{Z(DbB'f)3j&$I@.9/v@=񄶌) =y dpHyOcK`j - T Epii]7(Ŭf2}^gS < dgwaO̔|ȱyCoH5CA||pfZgA{I]v&kFWV'6Jඡn-XC$r^#CX~`t `N` 297-JzHCuLgHh!0g3;W=([zYB30Y?dC^S&2e0nF|(ݝ6R7Nd|$ܧ=)K0@7vߠRa3P?/̩Q_/d-@װq$3DF廘ъXrP?%  7u {y^dT/ތ3IO)˞VTWZ֙ '2{Ei[Dpj5AIٽ,i:婨 Stྲ.K)3yF/hmF4 *4v.10~E$3\bO{[SYu!0U;Q@BŨ_{dA"ZM(t@XFi5w %~> ,$R eV(eu(~ϪuBb̸  8s Wy`.g!MX`SZ9.Cߐ&Eǻ;~|=[ ɯ3 8AYF N UzE|4'Кm :]3-v;V)M6i0l_i5$L {U%jŕCGMJ cփ*`[LVиͩNR `(1ܨ>y?ѡc !$F$$V'=oqLRI .)oV#S0,h䟑4+b^q, \ j)H683re~.63O\j5ƍUSUY(RQhoӲʧڵi[)eVv ɴ0y+>mT\MV- l)瞬M%~mq{W2UFЦn\\nG0E-7:5'$AK=aWt3/:0rzN1BYccP ?zOё{ "W{}^)Fxv2m06WD4h`2 "*{pUόtg luZ%wY9gqGҍjq|AX<kO@-Ԃ#H =?ʸIdzz ,vÑ9s% %S`rĜ7T>,aatSG&57Й"jBvEi qO`-a@ bBwTqNnMcԞ13iU0T3UꅎLx !ғkPũẃ!KGf{qxbPjV9&K&k גe^HV;Auja%7 r(~5<>9[x;"p@1Orxmߎ^( dY溈~K:ꊷ嶄L;uu_ꎜ1{yFn؞9Sy jC_ qﯻͮU/H ᦙ&&r uηU̪!Mu^;>D)=>39oy"űSjmchO4qHATUuʦ_6+<@9auז$(6 wO37/%\#e*^1i[Z,^a1Az6bZ6;㝣JeV$2b2-c_0AU+z8gѦNP?;$z@'Q]z:AZ~kgәvGc/m0!t;~ifLLx^6[;h__.E|[ֿb݂yXe7Ϗ{/>+5iC3)L,T˱N :sce%m@ЧӕbP޲""M)cWhrc HNV0L409fbV dK 1vU+md/؄/M}0q|dS e{]@p]|1cBr@9"A0{>4cd76-k5F2(4DSf9~!xd%x.CfA2B>*r8yw<8iVINڞŐg2&BLx\bsOށzii5) [&+hv~ ~[Gi„&gg &NxVv7<{4qrൟ."Lu={|H$$gj,WԬ^Qi# jRlxymrZd^Ŏ:5'4cdcѱV6u x=,+FOŠG=|n~}+wi@kթ3O_r2ݖ)9XEfGy}hHুËh a#5j !ƸI/`դcg;<mڗ349 Yنc>*0@Q}#Mu Ov0i ;v/#dm#іc; C۝(1~xd؍Soe $C}Wolș=dy>pw3W#-kb_WM'JDNR"b=ԁ ϔc} -{E N`^IM9ص^"cݽ[P<#3bp~!N9>nQfd|5w M:flYK O]5Dzwy>Kx#.b<zu){N@aZ [-PKh>?5}:|*WΣIV=6S*JKEd$~,2F0RnNjS`L*PVC=R;_OX#2ЂgZCU';ځLHhfӪF5ɴ 2DND_Q㚟W9>5S 4IrdJյ n"1,D8`":N~u{hqVA6V{Sg-T9jsͳp[pO:QUpRv 4ב\a[ɏ]c>=kW[B*?3 v4W&AhSFG'"4(to% VhcgլXN bD7Aaf tdB:lbHi9zuQi&(dU3rd]0*BX*'YT5J[|F 󬑰,7dS'-h@yn@cLy>c=J}=rã&`#0(,eض!&i C{Ն0[S<)tl\V,Rf8bL=j$Y.J X 3:+,DOOzr+j ׺\/6`crheEjY83"5 DQ)Lbk^.j,| pn?L 84x 1C 9eHi #AC'cn.x!5#Iwů^9MT 5(;ҌبBC62 Ob 4d.4I vPk&oP%hZ{/+T{yjI00LU)Nֈ]?l@ɢs$Hځ" #ssDCՃ pSyoX kjhNTe#aذǛC{t0竐EQԵ4_q{)XXK k ǠRcL,LFK=6Mb(IxS"-UN|lU@jx@ B#M2jtfe!A 8RZXQuԓD ے~A0v;^{"Dq { Brs1촷y>ǿ{}r0,gY;asl)_DPOVQOfɣ-w'@cW}ĉcy ,q1Lh=(Ʊ?^t9W@$ #drkBT/+7YȑpVGJsHd<7,GƩJrDY#ek]/7KM jLȔix 3@v;'Ck4)sVPSD , 2^>RIOtI-5d5v<}W MEE9 ״&=e,U,M=׸we`y^xRFrmM[ ͺA7=X?_ٱvf*p4KJ5ω>8XC~\ e"DOg=菞A}C>Brϊ`+0Xx=2}Qʆ&o( 8ho]ӫz1&Z>:# .`j9!8* 6BZ~)w~m|%PW\91ٿ(D2GH5S! qPܜ Σ'"0Y{T{U!ܭVBd>Td}K;aKSo@J00/?5Q &)lv'Mt-,/5p'_^ꩪ>$7/{7 amnd$PhۂSo9N$%7.oec:+4`뾷'tZW x fN #R1lOo GrkB4"Gi8ƻ!3bnF-BTsϑHZ_5뷽xܠ,)ApTPHܖ9#(OcwX=CHWaKD 菉P[Sad@J;<ܫ5AYxI#4*qon%Zkyj*@ iT{J]D6jiS7- +P*'LlunϹW)h#v@IDATȢF{?nJv<TI[/xXx5O-bDݑv|`T^:W=1>Y&0#Q\ CЛ{l2 SuΞ0P4FA2%BH7Wϛ|`|P;M";P̀l> yGJ7%_,E!Wž"<&LvTi&d~~HTHekNTNa㈬ViAbno#:Ł,_>4@|ZgvtsHx7cN< iԐ {@ -ƍDAJ., U\ dbdwOJxnk]5S JBRHZ[Փ -VFU#X߭Kʞ&*ȕGa@%Ҫgx.=bi8Ǿ+.?ڶRrehXpf ٙzë̔_iO-(t#Ml0 f(1ͦ{G{h@Tz:V=|P4HL*ߑcŝ4f"r4`agd(}b *d`ɾ8it2fDu-Uxi{c)|a9C!d9vas;,j!H` O( MjR,?+@45 }$_E;u5>;4lC̑Z@֞BR4i=\R8{vAnޘ?*O\Gf藛A,| _z,@(zCmrv`*!Zm("B&VN+  ];WQ S|uoMh0S5Ulc`՚ƱA?CFNLÍQf=`Z,/*,^"_+JhjSI,@D;iv@)U`!bJlVִceNf=fl- [IBeJHʨ{ 9l?=Q{ePf溾1RWqnf2DT} =l3j`IO&vRi|1-;( mfXWg;'PV6X=-{yQRP;%eR}ʕ~qZ(ЌƧNrf!*,`F<8`tJ2 RXbR3o:N/r͹h6ڧD[h&չ*T,B zF0U€q.74PJuj"Pyԑ|6 ^ &TƐKbpm I"- R.~1)$Q1h^E=$[OPx;-TזKRoo  f  l \gI:-=G+U?L 225ƨ˒ܶa9' w*.% j{'M!s=x6E:BB Fsf-71iᾀ)Ƅ:Q5/ASba%So)xF<1a?hY!󱭾x7k_DH6 }f7 b(7qt_+n!JW&Yg[vK*Qw?wcܧ*J&́8V.{c%eDpi_hE~<Ȗb '1^v@aRGD#rWOhC>p-y68ST $A>k}Mkte|xHoniפn5hbD!(a4Ue8h^'1BrC4Wpد8s٤ tф*LoP!"vwvf4KeI7?Նh^e֖/cZOӸ,G/Ai9JVv`wVA(.7saLca宆)uF+1vk b ࣨG9茘<ѳq*&(‰><}N;'LV,bxUg}8¡eY+_lܿY%p6<윇fCh0? >_xV,3wҌ:rG9LtZ3Q6T%䝼l@{,,ҁuD1-0z6p-jA9Ŏ 3TekM+h  ijmCZTn,:H!MQ1ؾ0uY|=EK5-5c ջ:Mr䆍/:T:0Ń \ާ:*J瑪IJ.X9,&SkH=.eBF*[Z"LT5 ;cAzM'4I^vgJ/bﲟz:`&[2䥚3R5 0,BQz>)_ExOT n1?~1B\ϟ;)yA4+%"(mC8@ 9 +A .2t$ݳ2N'ƠfjQ:# sJ?[VC6I|`qu?ۚ4M@r` }w{ǐyluuljNM(/t8% ΰϿ/-k"f_oVf}z:!kH9GȮw#ڬ=r飇"~ʄ'.-[KXz3L궐@0}FZRAYLsKSXms_, 5<ּ[zD"]I yDv^*$sb\h7<+pcFp3 ci³G)2T J۷YHx,H:#Ŭ*$+n:D./eʚÚc٪;-[-+jd8w9ϏϻU ;rՊ{abX||GZ?47{=.-/-2*HfрPkuq{2M1D氹}X??%7gwz~>y~8\lqsmR0qہzz8c=̺$pY8Ipy3y:uY_~;hlTzۮSqۧoA`LVB|ђH^)s'VJ0I/tYf`&9E)C!liȳOllD `rN>Ž́%Ϥ p[U435~s|i K)&ߙuӋ{ mrH3iM0Zg[7 1|x!#>/W{1XШi1I7\B-gR Iʪ+,ڸa/ _~|:UMZq@ďKb mR 5|]*B4>|C5`Lg-RgHt) ES"o=6QFǖc.bAH3bVOtȞ>O61! '1眰:Xύp>p~{X=Y@"î;G ml}߭>X<6KL y6lu'XEݧ"]jok/Xk&y`?~?VGDSLC˩ˑq*Uƭc ߌQ+m$.eSvӇ}ƟrU\?f~hp.:%Y?xɣt$i| Kd}^/mR%SFoSkłݛP iHM ('&V@d=Tq=c lH,6ȫ9MN8 <K OwnTp7(Or iY$`-\20L6MmP% |%h!˼wWʄ0&ʬىڜFKg-RV~ О鄩!@Co,+&~V"ȑ$Y&SN_v5,#f.fNr7 0!~<i,QQ8r],`i(;ڎ_b(=)yhJ>om,3 =>A~ƏzZ!"$d >rXWb[t f*qJ058M2>< G[.jTezܾaHL#T4o/{1Y0dRV'UdM9[#ȮX w)$>G%'O1pP1}՛`]áO)'iU 11 F/%ȩȭDXz,OC ex}q%JZ&\f&!WZHcA VZᘚ}36x0P:4@JR@é=Je_q֥cSXoKg.3h9"8 "\D5h)\Qq j1a S-]%ZMW#v=UTpPsm5/RSt0ns4]N97Z-=$BhdhƑ&C}?!DLEriĠZ.&W4@QFzSf<0;mǼ+~*\*Vj>md d'-[<Ժ~#l JD `X q;gu!zK ; Ճb酥oiDuZ/C,C;C7`o\{>#ϣh)r&` aܐ`wOK1 UUәJKU 2E4snv5`X䠆SpnmĦl F?HqKV]Oֳ,UI_>ƒp(_@kXXȍ.:6NckȡC4ʣDbk$`*i=8"8F)ژ"VrJ=R'̸<AŲ &WiP}VV/GQ`߯1<灯5&кaQT==G%R1ck{t;]Hx=mpa zxeNֱDt7ϯ#3LM8CcK eDiB% 1 S,(a}Y@ =cXG-ya1⃔*J t4l()5q1hXͩ / c"8 e,:Qa *S}9 T!xLMcAZ,Kz1WEcFޘqb $Ū4:-ltQïH~`ZӒ0{׫ F1j z2KzSeP!wV<Μ,R?*bS.D4Zc\ѡӿvr׆TfeoِD٥#c5c:MF6|H*UkzJ Vy샑@izƤMRS]E"ŗ0gFzx Ʊ<5hi[]1#G4-ZtL4Kaj85O9\i &%tRn2r[ԍqEy &:I`222uYw NMpF,xAv48يΖډ]0.pšLeyu4FPL,K7x19L/qPn-c(f@6c}59fͨ`2##~yHC_j_"GeS$(!U"Cjb㊤qQQ D9UodKsϧy +Ք̣+P-q+6#vkBc0$mYZ.$*" S8g3ns`mA!hbgX rAo9Chx;jdGyoʵ̩fQ.IHA/BK*,OA1bjqV6 aIЛnBLnf ! lzl/٠%3 d(5~„n8656Yb`s4Xzi=W;8mKIJW )۽ZXQ1lpEVӤH1ۻ!$0YB:NEҼԱp&$ҐZj&sߢebC1 GF2 KPv۴/5}C<($@~~f&MYW#?d./=괌7Ixo;R;+H}ly~wŦgpSQ7^Z]M +>W»DPSA^c :I`V|\A 50,cFu$m["1.%^L[#J៯n Wu?gIa z̋wk3ۤNOGQ=̠urdM^A+`F rU͞W  QqޭcҤ7ZDm*X@,ǖ&!.DHxZRe`*wu Z_^9}"DJ)` 9Ca2dFV43Tᚉڠ:aq]iC5f E_ig84iNwd9 1s4ifO(Xpc̑(Cw{z߆_ O?ǒՓ1SAjkc.;I^Jh P(jMrkPęBcwgrlvtP~Tg>G2X3LCB}/gK5Hj)`oQ50Bi3;œ(qN46gE ~Bg DZ2YΖۭ.|ngDZ Ja*oo,a5f}\.P N{Bnz ǀ89Q*F$$^EV '7Ȱ#LRj.'kZzxbntPd&yiQ 2LNRτ ,zbcLsf\Pu 9'QA׍']DvycBTK2\U! v6`v4uՙR2(ˡ0-fDF.4$*AbBPhLypNuo?;Q|:ʵA0 70R-&=ؤ$-f5gd#L .s#R·ZN\ "? :O"4Sű{wIa> f Td9= ̂ W^x__-TL*7zs*󅐉z8;Uɬ4v{?G ^_bJ]c% Zz0ty@ 7 rܙLK\ XE  w  C4iZzXX4XrSg@|PP!J`H. AR?>JR79v$͞y@5]eNŊM+7 e*hKæY+d(*0Z՜6ʗو!@Tos=j͂ ㈣HW05E' سS%nk'#k: +[Ͼ*Qz^auj+$} ^ nJe~ CcF!&Vv`tmrrWGJb%3TssQidʓ53Y4ƭzP0&NBPv& E s:C7P#FWҡƓҰ(?ɣ_*"@ʤ-ك O]FaѤ7\;BAMN:1 -_j(cLSZTJ B@ʮ 뚑0yN/+@)RI Pw(\R(d0 m & ߞ7dw1\}G=DC]\ z" ci" 'tBDnPp2 Qd/)rWo/E,PhW76,!Zb9S^U>{0lϦ#id*SLS > bTcyD JhATy' z61k 5pɹ9 `e$d ғY@pqdiMFWлqߴO{V _Gzjw3?f(OP "OkZx_i9&fc J0v(NJzl. úѱ[m6jkէi twO H!1t-@0{r_?٩Yo_|">>F,l+ڂ&-J+|rȯn60ʹ+|,n sa`#V vƶEϐ E3S A{Tk7"he$.Q+W2pc& *x>mn5ņ'c{An$W4-JKRf:mmӋ-쎝ķ8<ӑUL{k09Y;z(([Ovo$y[vQ]Y$kGW"-z,mO98v b:@Ѓ oؤLC~\m`h;FqF[Ա 9^3Pm^3_((#4Aã0.i$ h.T8*RF8=Ud`uS7΅qG*m]&ܳ\>TH[H[ڠ1Xb"eXUKd0?׆-E8̑a6Bp/t\#lE]D{!qͅ \8ِ2_30hVRН;dcfKB1hvjb@hEt Qn6iQΒI`NMmX}{{$[X <Ob<׬z"ps~~ܬo$mDQHψoadEN`2; +%FVzlϴ]kmZGZvl,7NLeŠC hBHGw\arz$Ei.k8\}Դ#0դeeߦTrG<ۿ ;39XY}t:!?@k w=A[n^H5S$bd;4COlOV:2Ohn aQI6~I C3>A2s͖łFhlvӑ7W$ŞiO{fva Ʃ!-F0v T9Zߍ7 ( FIxh:$80&ZP;u%Dcep&-4=˜5Z\6ur+gU$сZp=ljJs%.xed|)B9>N~vmxw3l|ಭBTea3O()ˢ!}mI'4G=rY$F3X;(M0u1>:C{6 Wy[p",ךIȭiow]]߶DkhRxl΀Oz /y̍s@@_(ɌҭrI[1f*}k(?.WD7e+nfʄ۵ OK`K򜍧p\0ρ乡Q3lhZ1_#vSz"o-qy>7)OoWVzK6ئSk cG`$E9,%Z7CrKph} G}H,%nj.Ksn޸mwi_v(?,P)02Lww(ș+HDVٮHXM%yEsm'ǣv %,,hl]>WW؍ IҧJ)XvKSW8໏M iLN'" -ZByn do~ܟ .(l~ҦZp)YRr8} ߷+?|cBdN1o{a9K@h\¾u7 fV=b-llKjGQ$(D/5fZFz3>nИm#풁8xӂ(VY<9qş!ek̭{ "K+SZB.t\tJFl󦬶 㩗 |؄[ > &jGX;۵3v;cK`t}+mxFe݌+5  \Zj7i2ň(qzU(d/ JfeIF Kk¢Xc%2 Ք0w~h{g OQR]G*G!nj5qAA_v-7Pq6gu"dب bb7MP6R7M6~G`U4 gSQH2෧*,*K^^V޼p4GʛduNaý`!6"EĀ @ Ɔe&ըPQz)?|@J7ca=8C+ɍB6AI}q JtvD K*Sc︁j]fO6v"aOR#4sݣ@3j_JC&oEhTHdQx)8}-Znp|=2+X~B&. I/)TH!hp=objR}8~I#ފ>2xzYq}kϔ4l@: = in8` !ê0|P4U7!f|q%l(޴;G|`pM@|T{Zjzv|o=$퓭n~s$un1q4 hP9h'6^p:C.INIRMQMCijxbf )ەQͫX >1)v5按 |PKۋu wګ (4?E;0$%f{LxѾwhR#a Lcc&`Zޯ㭭26L̵ s1ASΗ$:#لKRcJM#0MO KʊPr) Ve!a ˜ABCu}:)yX+\+f-qReI0C!$d"B#I@uy[>vL,X&û1%jh$tyҟGS^.XXZp9җBb3 zVF8}X@+Jom)K$ҬnѫA <0~$zaWjg#Q5 l wMsF FT^CV1C+Of8c鈸hS0tJ -O V͵(ѓǏtJu}s\!ᴷj)RZa“k9!e4Ps@$f29{U=L pd"&yd-CYc~]s抯pބBԋc`@ plEKlQ0 KX,^XM]# xB.GJmx6b3;D7=$8$ƩA<ͮ׭*X |n[+в%WQ`3FHٞE;dF+o`[4^݅~x;o:'`? BGdLgYlSbE S`J ˠeHB(ȷ@xF% vb]O#c0447ՄD]P[ub5B@IDATcJKę=KWB{}C4CT yCvyq:q^CX.MpLb_4D}k3'[ K[L":lE<, OáhkA aRP*4A`(gSx9<ah EE\j,'.~AC4c س*N-y` )Jb<Ա[{!B<'5 YW <cbY]MYpf;W&]J +k.56ABƍs!袣ڧaMu]O"b ((~ IyG`{DڈHuჹC )pn dݔ}My.Bm֋Ġǂ0k=rR=̀t{A^A1fethّ[0̨h:f74ө&@xE &WGy$DGJ(24CmX4y<WKHTD3"ZoF~M+:}38T N9">2s])(6\Z ] CϟwSdjzgmپ@RrA6 r)CU$0 {7MWuEEUjfa)$dً")Y5LA@9 *'% Hi+Y'q>iϣ!wk)ߢ9#Cd \%k 43ٌ8́M$rRIpWcԬ蘶u]3Nϯέ0 <5vaVdYIG7 p pHT8c%"ۈb,ޏ%N&.El}ۈ\&dջXƩc#uDbz3b?fLlWrT{&N#RPHLPhHn jyttrМ&%1U .=åE\ӢeYaNô˹u]ٱIf:["^j+͜{"rIH3<V]|*嶴%! sEdY :< <Ȗ DV*KUU|e0V79:㨄Q BYg A[8T+.*:[Rc^[=>|̍f00^;W]l*E;*]Ds2("?*߱sX M\ZAwيԊ.`a ^+Ψ֡1<-_ oVP`2HH{*GGwu' -4;I+ g_\Ϳv p\!a.iT){ =n;^ϲLGmxWڈr]B>Gm *B~y4ERժ>}nG][ad0fT<"Z] L>,9{Si[:rD,lԱtrk٪@hP* %+y,z#?-'. G1D %q0NP7h-q&8T> |r}~E; ex<{5 Y8U.rž m0[J'T^Zu:t33O(ɒD<ɢ&*0ܺL'z~;U*.4!$ ͻ =Ҡʨ+,y]17;Z@W]Rq(fp3F1O XW+}g aR8TU "9.PIϮhWwɘ8l\ip [m5Txc0zu#n` 5C6drT uu!ɆżppV4%AMM Sr;m4i/sIzI5)Ds~"Ad="\SToDм9B-^OK"bWlk7Y T3O'lȡ ,J|epT!]@G0|c;D n5C$˳Ҟ4R2wȷ#x Y-īt{-tQG) $Tx*)~X0I2$Ϙnn^o~MMR 2Jl: ZQv KO4m?JO Gt" ƖDcID2/#H$"r#kM8qv/+YtUq^(37sb.flQσ!40B!;jP1!bPP`z>z5>EWb81@aMmsuW-㟦R~B)niሤ0kN@f/2թZ{'t"LԘQ^1t?>865KCIUhyd(-V$Iķ>;2ҡm jCЮ^Q˭c L`5`j>$PbUgiYX+zRhUĜCJKČDk0d@5Pc$B9 ;\iA9zJ/ao `xݚ-,RhVt+\6ϥz(Oz"^VZs Zi/Cx/,"p",0WWʰVz&Wb:ȲN$ >SaXIV/䯕 7߂9&R]&~I7zo?LQJRdFr\ ȿ=G< ?}RPބW-#7 茚sXdFzjPUOj a ;MwFԆnğ䣬=~эL,fޫTdT~TlO*5mխX!QpIםAZ$4bj& D1L0{KW:C(D\@zV@c]*gc50<8ve]' #nDX#cR{тOdA<|BJ&'QȨ/6"%GTly%ӣc쳯Yi)g{ @"{!s#Y"4AdWdM]nGa/}>F@rV _6wrJd4x1q@N4ybVKI{Q1ɪҦ?-U:gcAi*א)fnmm"QT^v>"?E(l֭4=CehwR]ּĜxSA7b!.23/سDQtָ5k"jYeD j 6p1SAy0(P:ueZD7W 6ۘӟAaLl$:YBi|ai=̜cRs8ߐn+7Af}ikȊv+-a*7&A' $}vnӣ-Z_!t>؝jRu8bt |o3opt\*0_i]쑏4\E!f5=0 ym[~xN*pk꓁ po[;΅G$ ?&ϟl=b!p' pmD97Ax*uH!^Oa1h2+ť!jCAI$JY,fb09-#EJ517N?^6l<2~.b@qDS(d;˜1IF{n|o&^ѵ4YDjlpk" QXd&|DWyMX,ڑh{NQ dbɃz1 smK0Js:Cy#ɬ yÒ"kK"l6&8(nUFCvV#}=X׻ā2#uz*|B̠<`EˎQ6o/rE7~ {vwqU~82`Q.p pq$lˈ ]7W 4|OgBgyEFi6N#a2z]o "=Xf:9Z\e{tOv!+hZ~<+G`;? !b*9ǜ _v0R P>?ߏĸJP9ay$<{ ̖,gRNr*Y1xY%1FzGhĩ+3&HmQ;b}LZ:XOn(+"Uq `K$q ]W ?Өh2 a?tO:>LlP%zD5.jXgS0y3xlI.0H>؞lZ|rs21\} hfܬy_Fz g95P OkX=ǚ!-D yh67Bbd4y)\߹ ĭvQʠB=kHp D^P;' s(Y!R˛[Cm+xք)r}dHiI,)Z9 ` J"$=EgRٞF8# p +8vo/v-pK}>9dj w~ܣpo|wr͓)=&w[ `HAF,C-VWM ctԊ/`8 O+e͗z#ĭҤPדIJs[@[h4* `ԱuV`d-0 EN}m8A)?.I6#J'y3eɀUX&#(&h#П2Tkʨ>TQC AhpketS?TYÖpS~I(Gy# Ҿfg: s]\Д͛@^u/`Ԁʧ1_"p(1oBmRc9O*{fi82̺hLiAԮ-B2g裵r]sd Q^gx'KhWs\再z|2d*`\yΉKY BE#xlF*oJ,"E3P9l ~s3 *By帞$7Ę 6kd]cMڪr1仹2,Jၒ׌dmN3@s$`YH/a&F|5I:l||&l)ۆ1  (+yOunQƚ!--OZV⤅ 8U8!M[ȾW+p/1~UMnv =jk!Lp m$SeﳐE[xYUtۅ";?>E3sǍXă'箅1Ju5xڊs P7jѸ.& Q4{z:@bS] r[XQ-4)#XVTQfsH,W+L 59_7&=QMx-HDޅiP2Xʾ PZ$醂 OF!9/{ɝ)+jk F?IEž`hT#stKN ~Rfc{g"g ]B /UQ͘C0Ҩd2sRKAܦ}A ^mr{AJvg'@,BtQZCFE7F#eg_f!5T԰^!0 ?j;A8jnxe9.\=@ 3 |^У1+k;Œt~EDi?H^計g]Pld:[o e}zpv?}:Ө)'5Tg 飊<5%211ru eJ- rrgkܶfX7jVzþ2ly~Fh:j$j ݛQA~A8O[1j>9B{Pt(` WIlI %ν_VVD;MG*(8,oύGf;*9AUzT ^VX3CAk^F;$zv>Q ͚6Qj9O52r0cn衽`+ݞm:C x-R[ gVOFN .T r2s,0]9HG9a?߳b`YQt^zw22XgkeL#E 8l#if/m~K(しck%EG]8G/Ȏ$^B`-0zE@* \AaC!o8*Ƽnu9=SAB8Da77Pd&Ҳc| Vg-Td5P4CkaXk9_ǚrZ/ʱӱ` FzRHoP R8h 7cOC ,[@3SlP%:eˋԭE(2x ◚IRI*oӛuMhWbyB n9]h "BpMj;kڈ-YhU[uƚOT39NVQ"NuTp "D>q~I8(XEx]qH0jԚYc/ *N6a·n㲰 [fiPJ҂ΐXpՐ GpTHOI&ɬ%rSc~`ԓz~ ( \)m٪H͆[bc nTjxx].״ޗWH)A " YijH,1z5!I6[&(^ XfB_`oly|rc6+Ѓ6SHM7{}ѝfw,<|J<&ϐ6Of*2'7"HEΥSfuY4kE2=\&w$8[f%7@ӌ7oZSxQUk,C]Bϻ.]R .OC\&֛:2?0WsJ mޛtu6%ڽI]LLHbtb*EdetzߣÔpS:? +D+iWЁP0m[{>.ek#*)$6 bLq٬1;CV#}g =СǏɜgEC׺2Gg=\ 9uk_؇gJ}#=kjBz[ z4mbߓ J:͂d`rUToOqljp0kXrt8\j]ubn*G`0`+Ey_q*bot֠ BDˠdV;{ ֮ϚZ@݈p\@/XՊH;Y$˂ԃ$e!QGI~n>G(hҲ DcP3}1j )W2Br,-zzJg#+0Ք^\B:\m4Vp=Fj/Y&$YHhKaVEBAҺxDkZPL55Blxx Hm 2mblec! :X*_Rfb(cR 4ʑWOR{$TG7[G`a0ԏzf#FE~p-G O*Gd ,\},W߆`;~V'+gsKz*=ZMq׋~G*LgO9[t{V:PwYǠh& ]uܢ.Ps>`nÉ $wŇ>Rv 4Ѹ|QklHrSJ֚kX73W}2H! x8x$=xG^ 79K4g71 D %ԅf)*lf95.'[1sCS&>j $\:hښ_0 "MDg4Y=~ń{ `Ղ;3oۿ_‘vpJ hXU8vBk)0 5i*(i.LeCc ͓6 #J\ŖHP"*QNM@(FSS {2-Qd %^9mxKFq:BQ8r1"3|OU')jP)Q].O67K!eዒXl0hgtsO&8:6kUe[UU7!?e YE]N 6A h"}0ѵ pS?BzIFƦqZ= ,!\$fLƀo@AWCZj r܆yw3E#dmuȮe*@nf6=O{k׼NHeTI aAkrɤ)ܓ2@ (/ .$/ːQ 3՛q @5u1ha7 #FWz/f2疐Yb"h2ŦaXf!ê.IR0r I6@f8Lc>wEi[9 ,&@ZO/%[DZMM (Yˠ˿*fE86/2b~̈ D 'f95 p%6Nlp1b%zMUZN*ULWE湲 "dՆb! ":NоPZꆗ#~blTND)xoz^"x/}db|Z| *?# ,: 3ād/)Y9fٯv@F[#:&,$;Ql?yP >Hi?>i+`h \hK.vEhe \3T+Ћr[Cơ_1At(az!K魔qw0qxc#Ҳ5+aV w *)^h͖W<@zB6\ v(n 5܌䤗4VN"|%8؜M'i\C|e W)NjY3r}2ttK@~-^+2ADPń<LN |E@]A/BNK5LR7XA.ˠ F;ue8ԴOg|"̽Huc1qlxR$Odc4c&갠jgmHY(RB +BQ9:nuPuE%z W!qXe=JfOF'lvr:صD5W>ƔE@8D&X"VTU0g]Wcy^8륧lɰ#˾v-4CI;?R6HK=-CW,~xxn` SAò6؎>F?ja3z4[SR}:z[A?# ĎJ2* &LKAZz4È=tLk#Z:"5-f^&YS4oݤSɳ߬WpՔ@m~|^%E68A)A96*'0E7gcAV;kv LKiSkMUG ';Y`WE ,c{x#9o.MrBjp>Ib(Eb|l*$BOSy嘷5F\k"G툥Uk XvDSFs c뷸h:O &rf zkp2B/iX|}>Q SALaӠ8#S"۟Ka4rME|C׬M#Ell+OheZh)#O40kkn ?",,aȖحuj"Z ޸rL4yPs~2(O$xgնR*(ɒ ~m|K^҆^hcȳ6Xn^{~ vڤ-k\U%P%YI'|5!KN4D4o+WI `Ȉ%do?j5Է}qЛviE'S\O;xrO{ KŹ4I nu8")c?;87/KVNP\Wn$|?h N3p:~ض\_v7`8M tWƈNoxܼH: FKQFrX yxui͉s=#lR:l@K/qw4kb+lbAay^acZ"lDyb!#! q߱vيF 1<) "Rv@v>˞_ <5vM«{$ =OLhVKM_akěfj+Նƀ-ł]Bh $Gk4 Ջ[.30ϡlXwcGYc\B8yjj |I3Ƥ!YuyKGO Ӂ5"ĵR iԤL%Gq: ^6lj!v^Uwbrm]Og{g摓T #A v7@?rv\nɼׅ>=_Yմx!5*q%i+Z؁4Dx@p޼Mc 3'*4U{YnGK<9Ά/u 6U??|}[`kR *n;^9mтUcC4Qǀk}5 +/+GPSͰ|*Z *O,lsl9ZY^L6b.UtFb_`jUPPlZ fv{p'+@Uɗ зCE2X= LWbit@頦O}): '-j/,hJ7oÕO?xR*S5> uqg ũxBY%˲}'tefK1.PYNND)iQϷK)#z+QDФ㖸`F\Lb K!X O]Fxq )hj!TV#ꙞТ`M9ЩɜU%͙ da^m 9 Qb9G'K;u`/OCERTq'!6:uCG~4QNLB%:D-$ Ll{o0r{kT\.Yd.P1]7{XC 8 ~Z?4t3~=?^ܭO$t^DvHAk1M@\Ȇml^P΢04O?q3yjR3.GU"(=Q*cvq$[]gb"mknmD`1ʨ 4&P.عhڴ3]*0oR L6pmWFDk<}| waRXU_Pۀ7lX:Da\E&Y6_ɶ"A#`ƞv~X[tw>E9cX]+ұ, bű_SDž%YDsAP52l_Ca,%*;_7 <[h=Î~q_4>mάo zTC>8K8e76TIY$H[m)R9SS`BS5uB=VV=9-%Z6*+"MD$pl{F`^£%; Uy'SG%FTѸjd~6ŠMəD4 d=Ε(ihBlHD(-B"=.5HEs)i3= Qn<=}DQ;j#auihsuO* '҇A*gƒ9 Hغ_aJ$P2@c$}I#L#A\T .Kz\B%rD87 xYTezp=J:T!pk?ynAǼaSTR,Ӵ*5'muywxnF_Qn+)jݴwC -gUHV u ә%9bE/Wӊ0z 8H.|Gڥ}4⒵~JA"7Y tUn絩H7A `L0ј&flƹ?NP6zg`jsHřCG P'Էig"A/3?Zf(8EjmvԹ") 9YB{yXƝJK8V#o?~2H@IDATln7\ ͱƜ)+87Y ? @SӠjR@~[|V~dk#&|L,) S >%jBS嚶ͯ {T`ҁP$6xCtȀPULi$P[n_'4[=M&] NK1ND0QnFS;R!>xRKԌW2:~Irɘ}G`H_IBi*Iix"AQ}:Va3ec#6%<^T>CAY8\LAB~-s ۡ+eEKdwA ͗@AAl藹)RbުXCXQ|s0G̸4t/eINe|@&7 S-\M$~WнQxTt@a)1{0Rʢ;>M(ـMcI eC[rS +*ϿԷQYa9y(C.*9vT)ĴipU2;RVl_<5ҙ2qu\&OOZ\v,F V{u]Vr.TR˰ظ4" mxf,MgpA@TYPjD82pM ۍ8q& Hb,4'UUUxG"L'-ExT0!q PT9P ~? PF"Cyy^6h&v$fFNED~7x@/1@:}ZŜ$g_{ ߗH :sM\GM&wU.v_oz_'C!t`Zm-%"/D5jܜ~UDxmAa^`_J/@ďǃ^lMОrE=⧥6pKMQ9̗^.T+&TtfPS&HȯFE- H"Ѿa!F׌I` ? Fϒx91J#.rYMz}uXH:Jv*t TГwjtHQJF4iAjVbbWVl9"{~af0NfƖI$ &ٞyw΍񼳲p?h =rS6 Y@NAi~弰O2*?Vd؁/Q<\c0-Aʸ&4Y;}ܜ%ӁtlnvPmI{MbF 9Bxe.x3ICA &@P|% v5]$j Yh^7?_ˏLdT[lpHn Wf}G(YD!"돇X_az㨸WF"c*-N;B9~dmd*r>|F@gz]FKG9jf2y>]̡JBҥ!T-(|`T,jH1{s^\n J %ہg06K\!ǓIK|#S_΄H>ww0`)7MD du"腲 `Y㿢gR"QJ;o-,.I7,ioxūh؍.Cᾚ*}mBFBV2m"<\Ҳ1/MN[`xqfJ[m0A[zQ̜[fCzPKtG4c,cw &#DdEgs,#fw5jԺBң,Sԟ$8o Q580CE-a$$ֈ6MJaȤb%'og*xc}@\mo2WKP &| vfty3aCk}ue2Pz#MzBDqWWA8חSz5ИX9Wqk@GuU{QjT[qҡuhIw-|[:ՙiP& rPDE6veBꧧJ(PZfP. eRqIg~ۇӉIぺQ%Q;H9.$*yz P$lFCM /IN[}pAtBTN.n8:= 4$EASl& m2Q5-a?(AǩsHB})OHnOd78U(OG}9AGO0x׏N˜CN1gDP < [vˊf3h0E+wV Ő46zo*Mo.~\mo^u5'#(٘m|:[T?Xx?4v;#f%^=X[VW> VRcڶ07A+y=z:^jUI/b((;=vV}eU9XcJ^3B[i<7+# ':(ZJK5j-E(Ď.s&蕜:40R.f7ݳO $1A$suG!+"2jZ. ׳S9AZ3}q*,1r} _5=V`p{ U;'[AZ 1Tn}C2xƧeQư]ٟ,)9s&ّt3&C@.b^QO187\S;NZq@@CEԩΐ蝒zB'.D+7lHE=JY774#_K O̕we-2b&a҅Xiؗl㊮eNr G{ULM21?vRiݔ(^(9t32*' %:z*ˈdiBkߎ!DXp)?M]&GЏHIbh]:^α+;p@AG0VLb&&@G4*7T{μm"~ Lȸ!xe'x#a^g# jAX5vM[FL kXg/^+pªvá)\Aɢo0App fr~.ԧb> m`hp=5%l8'<~A,.fN>Jc:w^p?~1Xrɹ֑[ڴSXt7BMֈv ,AT=g&TN=ώ*cFM: %4V2 fX'MkفP>a!/ˑeţ'j47!fGg<0x'uQ"ٌf=؊P5j Pc 6R@D։ br; [d8S ]<.! Z_x~8& J{z_8&α'IHbbkŨ|F"9QaPV3 Ѷ:)_ȎUsڅqϰe})X \s<#,π~EWf~>tj$7jY|g/[-i9e{Ff_1eD2?.sƣ1Rb ?BaNgqHx8|w3mٟ2y赘o//ilfp pzF܋5 g ?,[y陠4U._cTʠIɛ_]Z#m?b.+spUt2E2Q_(y&eu8_>Umq8O?:oz?-yMd( 9eG`%ԄiFPL%26\hבUurnvxS[{sD:Z'aS =]ϱu",M _/l(  qB7<3 /LIχDLBZp$)?-Q'^v=ն>W{Ӝ–Hx'Ǐoo׽m"Cה\4'Ӕm:%m*O~&zl5C*=ȞWۊ:ki^XPz`A,^467=B|fC@oMG/Z:B[qdN 0Y~$ PZF=ANżx)Վ2-o"ڻG1UBvRUMDoyn$z7XO؆F.9*ftLw1 9svW-[4PP$0h# 6)K<'P&uޑF( 0>5BwVWs}E.%VZU˵CWk Ļ`!'M/䙱RҠbs$xDq}IqVQ,W._᠅D7O_l4y/ 4Ұ6%GP>PK: Rݫ'7J%0kU5P#I>Z@Ch퍛u*&j9¾Fvmtdd[ A3wmnHu-ȧo+( my` r?I9K\BJVo1^wOfOY&K䴳pck+vho#ٯ|[O^`PKe``t*㌑D$T*_V?PP gLKmu,a3chۉ5.4S$0!~'ekdrbhNMxo,7<^MaX遪Jȴk?<Ԁ^8h-өmLT_l%1{RH?gb䀔h9pSoW<4&5d& G܇r;|s<Âc%zuu2|g@9fX ѐ̅2jIH TZ.N=QdƖ\BPRA/q %R"ToLMՙ4ﯖ1乂GFq:=_zC*d CwO--W0ofV=T@'5V0smV.e{F 2RjXo0Gd QߥmY^>alXUW5A @}F ssjw"- t t<]4Qؐ,dB4Bǵa"+c^߉b<&hľ20*[vcEՀT1LEd 1grl/{7%{;VLW*t\ ns8*K<Iu\1$G{1rO{gR:>z+yJkVdWm75"LytV K6S{Қ/I=G_=d"]H fC%;?!wஂzDzX:\5bH [  BzG(inwTͳ(<{RAQ|`FYF97ghG*6jEƮ@SV1j2l h`GEP2OAI@~rRa1YSHi QI%'=%i8 >9NgPO6Kcl@:daf#VꋩVgD݆D+Mnx*iIO:TP9O>Ec.ڄ;n ^Hq[V[.DFgWo 7$y [6_W$]2K oܠڋ(9_aj[&Ҳ_Sэso?2iuVӏ7tg{YA+b{:\glb\cc_߶7SeL=݌ͶN]P1O-KlV2)Z"тұ&(&-yr;^É_ٙ LM10 pO?R8`mQ*Wp2ȲZ #(&2'UxPŲ]5gþƟLfArYS=P" rr0E5ӰpiK_fUz0Z@.w 3{U~׬[Y I#J"O(STyu}VCGS(ozU J&-wt,g7~*zѹl&`DT6{xޭIO %TNdxז ~^rySBkμ@ͶQTQ kh _iMH !7 DF@P72\^m&]qe@FW7׆q+;ьUPVзy4l(o.\(=Hz+lhyߚн&jYR =+t>HzYҍ}D))B l%+Jf>1"k_Je!d!UAQy;g䄇)ʔiY\&~zݽ0@hP=fl?{zpoO4ƾ6{urQHǚԡá.z<k A#)ݏv \lX>bÙϺTQ06B-O]jN4#f\Dy(=ᷗf0c_ 8GJ^)=n9)TLRUcÞ]ա#;6#uUH0` [ZRc#DI C%&*~zSb.ꞭR׷l c3wS ƈ9r&QiazKn:9V" (C OPlh"<@z[fX;gV+q d Pڷ</X7-lt=MeX{3J6 ĸ="2ft}=9=>zyh 9ˌ1tB<%?uClQ;:X]`Ʌ<[m!3 l6$ќ{֏2P! v&^7iSH̰RM35 `5;UOAXd~>&6"MHElyqg%A lfhT2 .@T,DG[R~Hb$k?#w+`O E2'wZ/X剘[s$U8;4JJ*,7;IK8lT~&a9"\>Ho 0٤%H,N쐅- 5n^`x"rT^8$}~02ynӈr&HVzJ'8jM?zv& %Z$06[1p#)D\px ȹTO h/Z}!eAۼ&b] 0BX0NZ͈ln4`މ];-&J$|`1=D`rq9ϛ A%ͨXZ\M,XtEѦIӗX 3 Lۑ,KsF+3yiCfGü|D%7k$W}"׀%wdsX32'e+٪DZی[>h];F%.*BFe2l:Nc"ɹ(ߨMA@f%bH XH. pMz23w+2 p]4591$|W3:?&6Gv?j>Tw=}3fy6-J:ndr-^#f;ecƒ6 ֮StI^6~h1\" ½F㯐^O06EU)J92δQi|6P ȇՔ1KGQfq},˜_@ m$3LZRU! duD&V3y)8uY7dZPɤDծVRĭ~JbŒA!6G#Z;$W}2q:{=j׽t yzCEu O(MOQVsPF"/~%ĪKP\ҭv SWҩg܊tZd4qNh&1~[u]qBCyoQS/UT o20K\P;,m[OWM>3Z;A6.2#hU In[$'Y?}($fs<2#|~l:&ƭv&/Qs_Uj-WMŽ r 쉆4BGE;2z`3/G>,k  $`AC~ϤGZ@Fwh("i|D ߽y7ۏ$8Y!W*a]00ʱmlYfd}$,hdđ 3h2<닉WgE'iڦ?pVߘF`aJг"`5;8hqx?0_8 eڮ:-7M}ެzcaσu:|V g\B}!KT5p }Xߊ-2$#7V;p$8jͦWlԖUMXS^\(T@@CśXPDLlZq}D[|b¹XIv*/x.i. 3Ut߳$S,^L$X_}R%#)"džJ΂rTO^tz0iGA;52I[duǸwq?;%jq7_5@@,Im#*PPYaِRUֺ !ltfLָɋ(E":aE>OCh:A_W+["c^a`!Pq­f6ZaՃ_@ YRI4PJXd++o#R{Xw|niF먞.SK89tǺnIN FνW# W5vG0(kyl=t g@  EE[~l@f Z1ׂӻaSqX*0HELD㽾GBvVڏ3D ls\1UJUAYJ`X "pl@Zyћb=0Y=_#ZV,/60jNl$tc WAX3M.P+Bқ1qgf:άn3Ltn(cN% ;)fʁ%V N*5iR0h 4-y3K4j=؂ъxyQ\cܼħP@7mc(u7Ɉzj_A%LV9%e@؞6L @/h3K瑧@r[@Hp,`D& >4Gj_rc=&NGGo.yQG'M4Iw0Ἰ';@JYI$bz^i%o/nʚ)ȂKdRZ]eo=gOk ksԸ:f(HjoNmqu}Luٙ~X#1;[gB,Wt8FY ))!K+Ch8޹Yi(2 (401ln1݄g i}L<~яH]tDL23o' "vC 0LW8#O BzY=SnneLb'zV ObyD4:6aN汻~Q ==,l8ufZv378I?1I6߀oR):w_ 8}" ­es_Ws:!Y|j3*/:ә;ڽ]Nί88v Mϧ96-+` d/l Ix|^bz CیgDfYϏ]ф8UT8- Qf HҨ/p~%oѻ"7֡ފa+(Y l:82*`ɑgn8B YÃd 2D4c,i?'ĕDsH]Dq[8Prqh")v|S_dVg*vG}S}F%W\YUuw4J .$b{bq?@!-&.!`(@J߼2cE_ &0JFoUqsx~B5BQ;YiHM&GfLj[4?< Up?=hEdacDveVB-a/`n (a;maFRvɟRB )-ھT&0O+P0Kk2RcTl7t*R$Tn6VV#cFcyN`ǴK°Q!1F/R?̷!JUUу ۲r.$}k]@^\C=Br,E4 *0Kiq$\hzj' U+iF@c%_)iq^E֧9EN^֍ɯ/6@N ѐc 1Т۵3 Т`qGg{pkvx}y,~Z({$U3$kړzCQ fn.1jJa[ (O=|N1rQ&E@h?@GHЌhv(X %٪LSֶvY`Ou\j+3[hB4b$(:^sfHR`)Ņ_÷8M#2Y @ W|z!K$ mԥL/' "Fܴ+Maba`OtXp,]: K$*9J6t8T8~ #FD-zD\ Z|gxKE`ɞ\.3˘_ 0 >gG@IDAT+g+PU3*I]5}۾bT¡GɶVSsdpzD(qy*H<ۭ9SI򞿙&~%5j:[S}A`#$"xEP]Ҁ|"]e۪BE)ӛh(G,w1ˑ'@\8PɅ+[r+a&0EC($ VD }m"oe;J 6Ej3i%g5.#"?jH/rF2/10 AD0ݚlT0_笽d{dsNKЛ>Wc\U_vD,!nIS xڤR VmZ#N>Y"\y/6ٖHHQϊ-+!q*>J]Wv1@氜>Qܿl3& @%E^ ٰד 'gƁMb "O؃/e'h0~櫐т  '8~W>(Ig&aUY78ϣ#z0 y[G=+ܵknL0 %1*:t%?KġI"5SD1G lw᱐CVUd; J"ˢFH8ɨ䫡!#PӹOp"xG_v"74A@: 2}r/=t!TKV5d݊uB=M9ivo%Pat tP2Kco, jׇ9hSDqz ǐ4Kzn kMW G%O)/ hDTrsW `('O4Pk\_ʈUl5;p[}X[$5 H2dိ^ l |/4a1vyX7&0}cF3_މSSt`=EdE:piZd`;CѶ)dMcle78]֐F ,ڌk ,20ϳ*3C9n:88^>YX̦K[kD߽cMcI%6(G<3YN2 ݸ I]`/$J2(Q1̕?:T>g>fJLw\T)NňdfB"w-sgEQ8w8U 4¼|wD:*p~y^ ߯x,AkgLd@"oHi>̵|+.*T;]k&NB2=˰RzJX> K,НÅ]5\oL ކ2dxT^QGBɌ g#ѱt}vKdKgDIp _žMpPbXlnDwӰjJjҬ_1HE擇:ʪS:8jJ+zw//WnN ،d4YIi Hb'gBzLLc]ZčXߦJ#PkW8x4w< sUnyWhZ1{p4ANiy TГfʢP/hEVYg HGd ǁ uO8F!m*:>Y3]Ƕ'jVe+& Ip5}–ΞG;4Ь\ m"d'3ҧc6#`W=b/Pj.>v81^*ͱA@7lʸ#'8QH)*а 6ɣVtv #|sB=p@ .f(V7ΑW,edcZBIR$wz[mdž eˋGhf4i%aXRɵlڨȑ;D k`BřEeTW#/HkGMM6]R ^H$>=Ѓh&ULس[-(4bG"ZAmzU7׈!%T$4jibmlHyξ,A^.U.wEv3~LVHinSY*JB*RqK܇Mᙃ/XFQ F&vuy]T5Y7QJYFo,苀OrVKd8D}T.OsdQ5enKb^UDiM?}"H"TDIbXs A ڞϹM40MjR#&*z%<R)zo<_`ar?u{7:u)L@K<''h/t'P笒n83oNN>RÔ/0"D62VAF$o}GZ`FXU1QLpT{i[\߄'nHJgDfiTZZ0љ cU^t+q6Bw,oY Rnu~} _ ֕ Sj+ NѦ9wd ̬ ?hKebF%m,U1cSA᭤EMTFvUbɌ }^6Uh^$) /K~@Q!Y]]R 5,4<)$!fG#H^qզş!QFWIDAfq/0aG3sd@CŐGcQqٽIqJKdBZln.)Zd8ԄHo}=ϕ|[Pdnz&{81D޲7(fLzTԘru`QJoi+x=*:6۟AQطfRm['+63y 22q~rr28aբ2hӔBi6t1:eٷZߜёJDb]wӍde:W+8ۤz0.?}܆9I}@`iJ}8! S8HI+C+FoctVG\ Fږdط ,HL@p`^>RR{jy2; TZ>)-03h&%}H3etڻPyP?2cDRbXBPL$(}a<9 *@3aK~jO;g I66Ε(MAYǑޤFeH&)n1;NPl]K#m>WȚ'/&Cyd~|U<Ѷ/N/t E8FM0M7dTFJ¾|ͫyMλI^z^A^?G6݄J@O2.Io儯~=O~\XsQ5:Y[Ӝ$5?+8ܙVdP}ЁsXh/X<J v9^~vi"HC s(Eb!]nN.\UF_Ύx;V' 8GtT'?}@cLvEB`V| St-gum kbm!'y@.-PvIZ} ztoqc !#ML'\ M=8d(в;wKi9)1Սz!o9fZFTTJԖ$)NS2jIU@-;SImΐ,$;%e`Gj!/gckeO[sRNYiцqÈ3R6rIo"PXn ׯjg\*4L|wO:w -COt H}bӆY`}w5fo `ۦ>S_̩eZ̍]?΢Me<>?k@"&d% RX`:zNgOz ky#Y [6~ݛ+KI2XEyG>?~NnTBDB IR9ٹ2xU Ɵ7p=J[!MamFYnh(. R;#cOܲZf4݅#mPK$0{n~5NlMm Wljd@P!a3X2Q"iPժl}&$wDH[ͤ͡ݦL &Eh t ΐpɐH`R䚒hK`eX}L[2ؙٛteh8RCH%R|mJ (E`%gUHvJѐloF#= ąh8.&!^'Ծk҅jK)P2`DVxu@“Nƅ1nykE`S; i3.Vi )Fqݪ#ЕʰI68 HMDĄ ~`F㦽MaqpQDt'$jb%F?`4 ܾG@|NUa d0x:d:tU`WNd̤5_K)o z/Mٷ0i;15㻍lQv5X"%I2tB;U2Kwz-D UFe\ ^tXAaXU+L$ڀVAа9!BjneF3dlAp Z "H=bkʣ&ͼ.F/ʙzwhJEwTR̘;ӃzJ'\UXx^Gܔ1 PHH;Fz@z|710U^{4L HhޝM[B)"Ce#f O6=^uC"D\ 툆0w,W$H"@SȇHgO] xKK?.~~܎'}z \L,BVChb~UGEd kZV¡0~tD>aHc.칕yE,Ҍ U4;  i5> ;  6t~xG:+?hk=%"09Y /jI~]"_ Jzi\­Xĩ_iTL<ٓPOk;5U+3yJ2p-DS.tACħ_Oa[GFj{ڥl5>b9]nI{"|Zw2ZI)h&P@DNlD 6=u9CT}:BH ދyQ&.(ҵP}(<$ `)0nώA %< B[q4ã9G< aG h7tl6 P MRD({eH(}1a օVl(SapͅIJVf<<)-1UQJsv$^ӯ<K~ȭ7_lf$Q VDt(+iv_ešdN*I4Z|eCI̻cgtqZMD\m-MzfJU}l7! k\鲽xqWT03鷜L>LcgFEN@}a"4hW>.@ݷ_u#[;yqQ+X]}"Z^UTV iS* i;8UG˘y 4jk:fikvp]k?`ޡz*N&rȍ}cڬ@+[=@)Ov5N09Zd+`W$3 { (EP1 /'KKWd _w":l\k]`0NSфiBA8*LF܄P'iT=FcVΉ-3v;@.2kx|aSK4=y 9m.riL{]5Q6JnF*_ahWJdHZG ; cjijJX}VqPNH9rM-T"AI12t! J芒9 5WWʶR`VGeھN"-K 1k לLN/2j8s%" Dvi6hP 1/F+v+|?/zCE%{G:uةüacwZ2PFwF&"wr^T܋l pkVqs Pߺ7W/995Y S"&&U7ΣͶ6f,k 5 z1?J,75I Mxk9A,ܳzL0Ѷ;0MD|n:bP%MA%# ԑA}KrfoqɫWT?42N޳`,:y۱GK'!caQ&֔Iy%" `lm چ:=VV~*</2xf2mk$+Ӯ/mt{ix()JbnJX.{A&/ϤeS:(n?jb\FQj2N ZrֽoR1 cڨԳ/\](,yO!f6,@`0)"1ũUR>d>T,iRZD7·&5&I,ȡsDl>kSЧc Tz.ldp`^0)2lߴܟhPėnQdR mcVLͱ2񫽉ӆ+n`*(AwWFt0,;z(v!h> LR48LauY HSiԳ+j|[*>V b6=bBHCȟ|03/y^dp2Xj!Fn-F3 64]^n$4X&إJ/VNP -H]| &0pP\"xiB9-?v,9OA/iry Q. lXzZ$9"%>3tEcLb_r5Yيd,x)™8`l=bGtm_ ǃRU f_􂂦W̵P͍H@} U}# 6%y򠵘9Dk]7_)yN`Y8y^9O]5Pqm+]@߮ȃ$Wgכi`% ֳA[޴vB7*LmUDܮ`TvF1er4 sJբ7S[+YwQ+,Uw2eݴt(.!5jmH!}A;N;cY*00Q<&x229`CP2>;7%۠<],c(-HNڲu/C-PI`AS@X1.=H]sT@5mqR9!zw, [J4@y3R-%yH y"%\ (d_4q!.u.<"S2fH2ܚv{?E5`q~Q=|#;)j)KTwoMjc~4kޱ9"z֦C^pKȧpv[[_k mAF&lQ(̬c{o}KdbL*iЖdntq%y32Bu۠PT).%s1evʍZ&GKB88|HoѪ XndZHAF5C< zI? 5ɱ=b=Qw*u'ꇴH\*n֢sYۮPkR'g["g#|64+X [desMԭtO82)6*Rt[!9YB\$ݕWvb.cw'Ġ})t(Ts HS!CuI^TK+݋Q}ƒçQ Jh[٠LB$RUTAOfm.TlzI dlFd=ۚ[4FLZy\LpG#$='trv71BWϿTwjmTj yq\D~Oz ^DIXa;D3%m1" Z ͪYGfN,Gj (]+Ǝ0ZoFƔj$aZhh!o^*b06{s7sqB07*YF!.±z)΅[@B޲b@|;CI4J(ݟi.2hԄGm ҞSЋ^Ysh]ghCoMT!)[jNcIgX{nЕ,>MdU8Zl y_ 2T$ݯ'y9c@e'ǯa^{bx}޾vK+=_2fK0hgЄo)YrS^FfUmnh>& ,%_TㄸEp8dN,Z+(Ƨ/;5a HQE{ROюi!d;aŬ52Փa0DTES*M*tyCh <3*E<> ܨl@Q?Whqܳ$ _#,jJ,{OijL]GrZ5p_ QAr%Q%Ywlڥjva~NUJU҇i@1T|Hb4oUklX) ``Q @r>?h>+A8&h5 >o;y]$Oz|)*GUD|F~M5vIޙu}sUA'@Rs8bId=W x>Om;,ʬԅG?jin_;D[c3er?64f :_Q2ɫK"fՠd?rMםNӆ3M.Lth D}99 3k~X֌ Ļ: BEXS4;c@ ,P#[d 2* P;gʷ#\QE)~lB/A'{CHd@%1\ٻӗ4\j0Q @j~PqL4OO ܨ>n9sPS-.;yn!] Ċ2^8a5i)?|TVE/ߔ#57/afhnj W}R Fx,R۲DħsI6=V9K'\c[4 %Y;6E}9(VZ6G"7;2΍Imr |29Q)dD(a稀.fq%w&?;iE]'0k\gk@&Iu<G>b|RK<?N":O=Vِb^ :'SI0AR{,RIf :r̢oeD|;-S7&|m6o#/"LRU!ayMT1r$B'_M.XOsuej$&*9w7-mx֌ T?Wr݋ 74nv䗹cw`G7upׄ3wVMKO1߱Rpq,?_3[H@ܬb6 rbD,D'`'xH3 5~>45fㆡo+:1D9ʹ;;((Ե=Ӓ1bFu` ?'*;3?l>&G ,Mfj8|vyO~4x\&&hS)H6'ȏѹL_Q4tϋ) w{ȘX}o h ez557p9g! />w-cK9,\d6>m&А&dءLFnh:Y~1{9MO0)|k zUadaj#V5@9J?9m 1W-@:jFNUtblj izGaφ&u9}|<^&]mޒYjtHD˄/b_RSr#MOZk:m73DlA8H)cmV-zo|}~ Q w1ӑݏD0d`Q M91jObzb8Bz SDV1gΏ_ǐh8]q/L6?s͐vp6(d,E,r:[|un2vܚ¤} .e¤V/a)c9`x#!w:Qךui.UXQZ/. DJZ9'R.|P`\1^a~\j3 xIT?qT#וw;,O7Qȣ 7UnI˿f[8EpÍ=I uSPDT?ߗ'@xf[(3%B ѮܒSY'Ӑh.;5LI :rܜړ ey|F4>y&4L2v_ǟv]l}XdghgPJHcUeQ,j@bA=jr)Sը(`ΐ3Iq]; q뇙U7oi 4ȌF;g!9x_[+&c;r&6E3.ES'h06ASqhXُęp) ƤS;é&& U%|i\kÇ B͉kC`r -ꆬKIudX00|W `RvLgiTP %DDWJwg%`jkC|kHm1Yz>3k}™Fxh|H!9*'ƼfHDKq 7 TH~,hU RLԀ)pY{Y\c.t;?(- P-9;#q!46d@IDAThoKV8zerm +%*?M8@: 8ӭ-ĺDL έYB{I;Mc\lu2JwUVjd;I-a)I:l)R}F|!0j!,euڲMBz4!`^L:li(ْ;0\3X]0vGF&V,/Y=bng4ͥo ;n!US{)& w0"k8Y4DK(/Pp֊Wb(}gu2 E2*Ƕ 8'"^qD;g#pG_AG09:U#z2]+~?xΏs6OHk l?:Z6* @=֖O@RJP\Gf=fDTh\#BSb(g˱'L[4dsxxD@ԣ}ϔ_D8:ѡxc L$ ,)K=o|;de1 zHB܃;2xckו+!.6QͳT/]/Ƽ$Ff&/ϊpB9DKR#ǸQϝrmGqCGQB6 d<hl(ˋ_5P9.0$!`S aLfy:9O'g Gq{06@ wBRj ׉>s}),8u_.BΣ<ë@8c* 1,-TpRXozFTeoD:k1W @5zB@1z).~<aIIɇRΫ7A1_ko}4>zQh_ y8/lj96cE`WX7C/ڼ-G`9Akah07:F<93u_E"ݟW#:۬, کR?<5cmp~m̀GZdbZťIMjtQo.gn.aqe\ m\>ϟ;)Y;HIr;O;HUH79ϐk5y=elδrF5=jsIMZ8-'W4ɆrDTHWʭs"F |}mƃ~1&saĪtbRhcĭ.s\@bi"Mb.ad펬 )#Im&{}SXXbĆ(g8t4IU~ HxkDIe2oS3xy !8RCM&[}Ӡq[NG#Z+﫩Wjs֏aUZ) BuTi^Pf8We>K=ɴȑ~LBZ!!UHF3KT|o΁kO[MM5b;k{ؙKؓR}ʞj ia)\״l4'Ԁ_ʪtoޜՉ(,߼X-dXO\Pl],e'8SVJqq[r6{N:ɠ_tP5J3KF5r, vi|ªY9N"C&ASjXW6gijfx'ezI D M^4u"Ʉ&/=8#5@/8ܦTPh/T(|IcY"Q:4Oz;>iWRVA6/ KŔP,r3A9O,QӄItB2qCƮ˂L\R7DFp}H6p (6} >p/j~MeIXf,苬ѵXZ#$7VХ$Z5jdk?@\G 9^K,\#m]$)Ekԟll*?)RFsun6FCqyj#vFH}?_fIPf;+`3н%Fk:c W_0bHrm_%_^a9j?d$+[(oh]A5%˰MHD s1!BL 8cSY-[K GqsMdCt@댙@ .]b,~ЬO`D K4(;C{sV(c8{*)"0Oa\>P f 6P?yT~jߛ TUyx4-԰ӈR>`LMu)C7 *s $ffE~.nFgmc9 kE"hT㦲m'"n?[z:9s=֮6 MP:ѭv| u`Ϙ]MYrp:&hR#Ycm-.+04~˄|Ɍgh|֢<._D(I!j{~s}?SlX/\HպWTNz&mЩ!bdIgĔj)fa<$h\c8p.U/٫ɴb]9C*XYU jղjk6,`{GE NCZe!xOFs18*Fͬo -$h9*ڐm&_MQ ѧ`Ibƌ9 ;ŗqs%bFUfp N/~6Fl^ VJšetjVqG-~ V=GO/7F1KmrYvKy "(B0y{#c)6 KAlcV|0{h01ߺ0OLOA*WcBܴі1oK[K^ 4ŝ>r p/mX$Dёq_rr8l/*2 l -wlhef9C+T$GY-P`mxJ鶎*faxf7XѧbP"֛ǐ--2ETdL=2k8y9`Dш4(D3jؐ *I=Y:ܠ"<[$x(:F ibx+C=>:9TJf{P# SkHF2>y=Ihc){^Vl%'?S- T1qu GBU[Lru џj{ᐐװJ #Lh;)m3ןt>MO~p> Y*0+ $YV؟"z>#_ zoiSX%ڹ+"v.оX~U)b}䟛&Jm凍 BK$Y'#@i(6o> 5LTM\IaMJ G,QcCj[G\YD۾i0}ya9) R2ItonSR{҈qt;.("O]G yyrEL_C% f!y g|qx@&*uW7X 1d;i*y$z{`mHsٟESfB.0φn9(xڎ)5i>ZrT6lHe(>h^Ek.'3xYI"U.AL!D##@94I3h'א5(O"Am ;ܕR ע xJU5`vhUҿq^ĮeIƪzi5ӄQQdmy9FR$-t"-2{4pS7&95 I)Ph)K~ m&k$m񾴬:>"(Z1/>0TS өPxJ~ f!'ҧ{"j]ʐ{LIS*z#`'Ԥ`a 2L=0污'UGjȫy,l$S`2Zm1Y4C&(rqlV4v0[ X fdxl&3@a?fdEYx'd7mH9sX̂z|alk]*Ғ@4j݂ toDB=(CJ fnbRn^wH4]CZ~98=>Є.\7\zԗ^6&a>O>\H huZ(~՜%Зthj小iiG;$!L<%r,W6#[Sb )sPъyYbu&;a2߭?8!RbeJ;OH_-9n!=hpLҌ9 ϸ513$iJ>MI)$WXoBZm|U;r.k}Akk+dvwq|>nuo5O,g$]c7{|^|g\s/H^slWh_)&\jgxɠ={'佾/9i 0 ~;Ӻ$F趾xwjY69.K[_]𐋲ъYKc +@ ]8}{8s9vݿV9̾ fޑֲ=ٌF=m&8yEDkq{ǪR8(^BVLrw~S8h 6E4v8 Σ/Ğ[G< fm}t3]HS"Ñ8!9s2cn,j4/^8vTsЏ[N\Wt|qvnc=6vR'q.x<#P*,ҁ*tuߐ1n8GylgL}PZS&P[(w"a Pb\E 4Iq6f љWfKƗĺPGI0(&ndCլіY 2߾~r_8)S0a_u쌩l6;ox"9-f{Ɍ(j,|p-~6o"O`N/.J~,6<>ŀɉy /1^rme˿}\8NgjaeC1VZ]!A-'˽c,MBΎ_~\/o"H} h0̐+sYoQ4%~ jR&&7q.q0Vz@tv>(-*ޕQ+֠ d"PqW1NP]/°T@l u= MX =و![DžIo_mZ]SP; -e/5g{gg@eZ-Q#@S˫\BQP6hJ<r p^0]zlwt="Ը>G+x.HH֬usTH@߆%UVWJ<)K6o7<ICs,4|m<Ai(`#՚1 gyWKKS=' Fͫ[&F* < *L5u;DQ>)ZHG?f] 0 K\zHɋhN.jESȑ޼.IDhbb~[U4mv~zhxNS@^GjɿEtغDq$~%'KHɆ>tJ;R&l>A^!d7fЖs YhS_Y:lyP0:!r{ndc@MQMvf~<b猁>,{ִ!/E%:2Hy[1f#ŰȼlV]D7D蛺A9ajq|:R_#TWb~oQ#hdac}a"pKRV^jĿtɏܘTn3Sif_n&6^IwS8CɎwNj-0r_ $Z!pcO_[xۭ-Zkg ;|a>bq=~r>8i&oX[(\/v tX-d8D $FVKe 5ajL=4\3F>P0" ã^O Ѧ6B4z\Qhhp@ƍ0i $` /@,Gn=/_ _ŦeG|9Pxlv|@ ~41Xv9Vյ9'--?Ej( .ڡ։8aj XKRՍ3gU##,f |XӦ,A J]'(f" 7@hk ?@ГgF5*RAHd)FtV(MGu~?W 5\[?+85&;臥Qj2O@l QɊgOa?pzҨk,_pʩyI|La^ u m3,@"lsЩ3 :͖yH\żMX _9 o 4E3B*!@:kWJgi>> 8Զu>>;ܤ5fL\#J0 rp uCWpDг,QW54cT%Eiq q8XLDqoT 6du%r&L_{Wb, :ΌP#UL ek[F_*0ÅߐZnOxᄉ TȨ!L'} ^_ |e/ZEz)dql]ۃy!6f<Zis-He,q)=W@K1a iSizV9/5`z5蒟=o1 1."x n,4Y U?o(Q,f``nª] Mх;WX M0U3̺>*97~OCi:f^pa+aGpT\E!& ,tEt dFmE< rMS]ΣY9Ie@2a4nv9ZG*pѪv^@n%ra=HJ6Ȭ/"H`C]! Z)W؂ʰ:t6}yyI@FEPhaIeDix䎞V*Ҕ \-9GjSP`+[Qp2Bvh! L636Н$Q XeS$\NL3C92$L/2~a8 V?Q9QG0oC^mZt:8bԆ)$`JcD>Q l ;eoB`tqq_*P ^8t_h4h; 7J'YaA/??LJ.;|X.Ao<GR.u|ԕb 4,#s SR'yK0/IEF }d5ڜ7Q _q_с`09@0toᙢ(܌>k<=7-Ilf]|}Oe[â߽q@WiV iN+mWpR4N1,eO(\(1_K]l)U 1  mVBer  C7C苲T`ޫ02zyA`:UU/%1YGlzQqLA,2B QC_%5Ziw Z41~]Fh9{Fj,b2j N" ᚮBkl鯟Ƒ1<aPgUBξ@c*u3/nN,WWA2qx,|]v'7p)<- '?|'Idk/m FQ9jv}<!lS'nY](>f}ϴH`{ر1 >Jz`'3eU16!:-qAv@'C,cg yBR#eZBla\$n/7t>rthZ2`ؑ-i1dM#=A5sI=ʇfYiK:E+Zs?h.:' )b-J3i׉U˒J\Uz6j p\!C_fB=>8ȏy‴VMmA+@խqoƿYۧ1)k ig3YLD AAMP3ٍcp̌Μ(1Xa!46pLW9eox,i,p}z421jTaltэufzS_労Bi:6W#-(nײA -6[i.Ga>> `s<% ˻:0n&C0@h"xϔW;٬HƭQrșL\ƼP1ڍk \[X ^Uq82Oweb&dxmI"WQCufr1O[[PJIGvduv:wNy2#\#1# yY:-BG~yb/Vͤˠѵ!YumDR3;BM>U?kfސpjTP }ҶmM;c{xB!O =05גg鴘J(ECy 4l2$ *~1UoMbz hNE AkƋ>ڋw4jEa;7]uļ✐n.ַRdlg'iX&h=<*ZrSGFց2IZ1dm﫺+usu n=nF}3<k[gէ_fFX=# + /]wi0&LjSݦp*3Tͽ1hkZ}qu)X0o3 SŤ-XJZ+c4TA9B\)ԩD_~ZҼOwQ$1MB+A5}x!>vƒ94k#e1h}$5R‰k̤\ =S\Иx:őm saG[;^IzL akSDN 籼7~ t]5yT6(tOa)ۣчeѳk`#Ɖ'S!aZb b52beb#f;iQuo^ZfQ"P#|AԖF _q_)36 QznDLT^pems&]G:߬Sİ ˸;૭2B+* ^צS@ 쭶6m_1'%:㤁 :맸$ٶc 4@'F}(@Uc :pi h%Y7cyƢYH!LiaW.IjGMDM-_Kǎ]CW$ ƑwR<,l/6Kﵫ v)'L3Bg8^=ZKq!QY _gug.7ɋIRkS:_+q$95-cIIN:䷷hdpݚtgq#fFSXQWSM.lѠ$'4b t_qL3aq^yBqWfyhw]Ӳ{5%rewVOmPծ BW Jަ3?r/&|/#񕥡@N(!A_&XB&rغ|ϖjA1?πhzV>66d& ҈mKĐ(̓9Ĉ^4A:EE6DW3"4v 1dC|?| e' # :ER3\y2F~!bAȠ@S(;'F27C%h]3c#d:N̕"7<o`9H[a̪zWk} s]V[pO߂ayn$^^~yR^9Q%l Nq?mooGŋ#p\g?C,<ޑn|mX6Ri0ШbHT>EY=[#7XaEت]\1,hb; B hqH8l Fuc.ݏgr]o("}z4o * iir^NLPOro/P,W%P;zS X yHY(SƠqK, @TB˴Jja4F bQ𵇖T\O_?ЦfAPJ)Qk39F@F Ո]Mc ~R8p§v?\f&f2tM1iP ׈um\eq5/ˍ~gs`Fh~-_qDPuDgA?Q;b40/~nMW"^SQ%&f2C=Klm'<1,= IɵGnOG+KA3X&x[npB}R:g'#R`W1k&m&` (RX`"kqΚs$Z9MU A s8AJt4Pfͮ _z ?nb1yka%ls nd]dP  mp:{85<$̀0 6iZ' ,h"2`rQ2%|p7G6 Zs"d8Z\j&%d%LeE`CJxJV];}RLUFj.P.ΟVz//?q,UAİuTxA[I54XGBaZ~3J؇sѻ~7K#p0Oϑ8uߤY_Ⱥ>c [ە \~N4(1uυ0&UF?mk`ĥ$:z/,D9ԊgONgM*}y DL3E rpEco|NTlJ}rTSǒZmXgU·NP!dA12W4B{aeO83Xzf=)z3},xBr0^Y\.Bm #: __/h,c hTtlI-X.%-Z ;oyy Q,=ܫ܇/N^:BvJj oq*Z6hZk_n:L 8$ _Ɠ7 _<2~~a`I>֫ѱe?N9Ha"j5:EcbO<ӑ2Ut~nWm#GD3ct*QpK9֧+7ITwiR+ѽ~sё^yrl~NKA0Sq<"JfvGzqtj]h#; gYH͍lK9P{BCssLI%gr5=3V2@\;z7 g98+̣, 'EI"Y+|kGc=nS6$Ep:jaD `$2$n_PopI JH4uJ*j@Waz$TK%paM` "n{Znkb 󗳱 ^m tQ@*ƈ@4fLTV0S *OݐH4xp+q*/{ցK=ԥPf%5H74_1IZVm`3ns?S--YPz#{ugQ3Z@4 v&a<[td3Z6m7 oĦpW߀a(l;ئЀ$ŐҢ5AW/b|{^ Yi E Ȫ>~. 9)O!*(n >U}{3h9ے(89|# .!5}uOiE iPu!''k@*kERixK0T VNL nH#`9Cz? +Ur*3fZe;zŭ0a~5(" p@"T6=~ ZPYd~H:rIsE i0X*G+11M8 3z7f%{09 u~Q6=\]/H}N}qFo] )>'TO}=D1՘kwGK3o`Ekf Ď6 2U|Y@\m &|#NQ2T|c[;=zfsireX nDj'w׬*r|)g+:roO6ő  mS}c\-mjJ?c1_=G}@T, iHXQXx%I:]eg@29[ )@i oq@Q ppٖBֵ#NT"PqE9 dpTSgw@6r ub7]n❾βl NR9K=$ېed n(7Ev:@0;߃фt]}o$1H@ ~A$H2_(i!)'zu`Ê@U~801?|4uyɁgn<+胍[.Qk/K--D)Ewn*(\@~+K 7e}vO3irjꀓ%92۷k'F}- iPFDP\IE8`or1βo@ߛ+WS\teu_ ШVYZ}#7!RCO~R>3`?؞A9TT CHUz- ֗Rb齆/_ ;|6L2狴8!xVc k@LHz?dpw[f2H&s@Le%մ^CS_~.0_ ?4`_+ ~~\=Ѹ6 ;LWٞݏ% uҶ@S(bC9|+߽S (Apn]Q9 .'4@sx87q)E {GMf$6&2kNc4(i49ʿqN x, J(E,]d\KVLs^] 6f%(=&8:_{9j5OD{-|i@TB[1^kk]իz*7݃,YM \/Y͍$Sy9K *p3p)lz^=h]\jKz$W})DZHXL+1δ{j+ dg (J@t?qpcX6`T.ީ3bH20." Co3C#69b*_1Cxe6@ _Og/uVO~c?gNM ј)1-C5>Ju:`tLmOo/=m2\xJ?U3!H &IQ+ڲF62%ĮVhp(UwM,/7Ya@ UOE5>5|}f|1Rb{Mɴ2! Caa5A s!R $4>E|E㌑©=0ɟ~r<јR]?:)@Qok!Sё"*$*E 1D nڕ -J2$_GhXX~0؟!Kh(fƒBQs4r:3 /pc:&AcR g&*B5xZI Rpm豷کROGj2噐 E8, uhq$JEƓX4Cs"'k h2i4cYْR@ hj1*p>kIyo.gI|qB"..rR;o; X3{L.}3' *ׅ}la@d0҅F<'Ԯܐȕmdaٌ<;˄P4F@YpEԨ1S"71 <\<9(+&IyNyePTW6{N~:o&qLDz>=տ[*fn`_ehގ*/q}H^dm) e~?4FLVтJx c1HYiSm^% Q4lU"W(Aj& 8&Q4}sꟗ;̳yhEn' 028;" YT)M%+oˢ&֯&5Zg꼖ZJ`yk\滐3ڻV4?Фg#FrOl.eF9J#(P+%:(x]x_oWn Cl2#&6ny3py!?f;ֿGY Đr=f8HNvC!5-zu/ 5~xndM D"nOm-RmZSyD%"H_&Z0!q;nO/O9W#vp3}gCF $(L mP}`> SNNzrZ96창/0aI_Oh(s|5,&J F"#W n^9ezYvԽ~b_M aS x J9L. !gbzž>}3Z@u `dՍT.q!<[0a VXdεaPț "4-ҝ([zk#9q}Z%_cM[.JW_{)IS!b1 iRsQ-@-JFsꏃPhH𺟋@ka'![{M+fq Ac:3%.m SazSyJ p!Ic<Ѭ:J[7KPrVL0'?'ۖI_ C$煤sZ0\Pap>*jϠu0Lt4$~u%)Ԝ5’~Qv /+>3C^Jzm{ϱA"iR &XKg[i..EfZ:]wr?T$vb-J 1ipa rݸ{_9^&U g+vo^ÂW'f]NSॣ1X̡̀ď.a=a+'Q}{x@r]j %+\鯛0tZ樬-KGɲЛA0LZP1/Ԩ_!yېq A:J|ÄCgHF{"r 4lK;goћLp`$WWV'LQ5ww*%^ؕ/tv4F4y8k~>2^ O4/LVs8S B )yx3.e A撙LY;|lmTj6嚈GsgRWڟk9 =ÐljFbVatqA(xkط *h,ͿٲPț׈*d$Sf6Jϗhj]*ԝ.3TqT7A+Ë[d8H[h49dkQ318i8HFg\Xak=a F @k/X`kQ| H+C=8Ak!:8kQFIEq! K+rDj&u#ԕ:zFKiVu- Iq5Y6#~Z8>dB"jr@!Ip%;VSFQ^ r. j2&>]rcHSr=芶_"[Ћ8N3ijXsfPacX|JL`h5 ~]Y !},WjHv|`? tH#M309FHh8OZNZ;- Eע9_9_y6%(`wzW7 2djEu3nc:}@+; Fio۵N$l/U՜©`Yo<.Sc1^eчũeGQpsMu@@1 []5OCr~!_q^%g ٴT:hhM +ODKױ ׋AHo3 h|[TXN PHL'6U:C= 6#@)2Ͱm ͣ!@$@,Ƞp>6lP+nsVFC/Rɿ 8T[Yſz#&ZO9s_7~)yeY5ksf0r~rRPbFxW3 K8/1@ѐጄ!T@31 @b{5mqP1^?n;{ ?o lU=YlDΩ,1r8^y# s9Y$ҐA"]Od{RnɂP}b9Pјdڨ laЇSSyqU=eeՉ#E (9حd%"s쥧勎|FKY*OS_ؐ[ vBǀR)jT~VhtxЌ͇i Q/RJQtDX "F<CC\Ma[XԪ 2轨 ͙)re4$Ka%j7l]?~J⻚RJ֭>AJjuu޻aNҳeE L %_U]B}!I'QeXwzK"Q^>؁lmBm&rzka$ )=Iزus[HI2xאqF8.aNEDD 衭 _TUsɘx@7/s%V%E Nr(~)/$Âk$|iXДP&q&HM ECvf8kցZoJbd3jjT)~ Ԇ,S "Zd1r$!flLthV=OD 3|U'7.gg)Q5y=+܍,!W&A; 7n)?f= ڸ!^pI?@ƬJο>Wя"ϣөγyyڪY/?Ï)`[.jJf9өvMP$be6Εb"1bJM-v^s^B܁*F+LF%ďV ]_I /+ ul}v Q `V tdi?MA(c73@f4#Ԟ TZW1%Z3sƽ[ aǫt\J6S-r|RqEwP؁lF+֠ı|S~(j+e91luCkFQ(.B1 2HQJ(1 ۸9y;(9fO^ `Mwm{YQ@b<0Grp+i3GfB(D^9TO %F_B\ z5V`dK3 bJCuxC1zZPT41ծ=1ҸZ2%Wac_ZAAg-0ŕ!/bSӗUcN iAc,:ӯ S a 0OW~Ұ{TKͫ;8<'Bui*wm A e;b>b`ďnĵqB)Aq}}f[cjZ5&߇#i׊y@˚搧Ei^sTT3Ȋ;hxt0tF{`_!2ઉisͬ]KfHlD<#I0xy`eh v9]xpnq6Au3Lc)Tf-4+'c% 'iBOHa$hCfd&5єBy?] ­I"1-wqO9εYy RnQv|~ G~MY.Ib7Ԙ9$j_ .WrŃiTL_ GV\6%${:#ri u*FJuoͺFU%l4챵?$M;"0M:d@ ˬ.p#98#lol5Ɣ׈'ݞu#kF lNd9t$J737Tx)9q !Z^T'y ߠr6~/ Ŷߺ%"!ϰ#B\ &p!ߠh6ո&0BWۧݠs7h- b>@abKR0IS]j~:z];T{5mW\m?0we;ZfZ07 KGr(' ܨNo!w1ƨt͟09H*hMq\590Yhڂ석pOLYrlDzgdllƺ2@!hIVu!dD}/JIn #2':(`4W;)>/ﰡ1 :Gs`fWs0)srӛnݿn'KE*|"QI ZheeJЇ$]TiMefYAt5,3r&H~r$gXUɡzӄYͣ/]:T:;~$J2<*sf&O|p^/2qN ΀ǣ¸GRQ"qtxKEM\HGzZ$4yq!7L[?jvEI.끔A4a~^pq` id̚&!i5Ltv뺺,^𖈷|=V]vi%L@ y S$/.`۱r)w05 ?uxo 0|c# w 0C|,2ʱ9 ߙŬֲ~xBy 7&4yո8SJ[DžNUg,Ʋ͞ଙ"a}pcm"&AuY)cixYgq~v$"}pMs Es.Qx_MǿÕ+ENui'ohR*Og0#ʴ'‰rCgξ8sWFP$3nBlhto 1f7.2T]xQ0Q.4(T \l1u{G6[`CO;Kе!Tkuulb(4qu=S1T/c@52}0CfYᆱ ?Q!?knHO kmZq|q% ]+7_Hq?8m2g6PD+BC_Z SÒd42?ڊ^6K,@-'邙-POz"o(]>4%G-+;)_K$hEGcy . (tYm69>.edaD݆]Cdw PRn4i%/"A9^4"m|bXq`|k[s oN-eoRضc޾**Qפ@ecQT׮".|/rk4ɥYdntÆV&K kħ3ZR~wj^|Wotp7{׃=vE$^4|q\Gy 蔞lkynq퓢(78 !a2ˇXEi)f(_نAA}[5ԸzU%W+ow˄!dM@HƷkXK.("iCy^LJj"Em-Q:~8]wiX,&rݼلPx;sł"mn*!/OT]XNM6.Z"G:d<3ΎErRΊS Gϳ HQ_jL `;\" s%Z-#@DjJGqidE619R^ڔ!o ,/g]I 6̀Ӧ.ݡzj+|n@][98 uM:< PIux`IIID}+u7;A>V,; (sP9TژBlBуIwaxR[lA?1[ǖ꤁?YaA│|Zihea(#R3IЩI3.y^@IgǩmhރK+1_M%K ް#ܮ뼢y>gphj+[Rz4ژ inuNf6*L $Xmd4'Zc6w`{;@ܛKJ?#9~ܚSuse<\9<pa +A ;oHe[>9e:$)`oz5 %!* ^YXZ%pGgo鄓пvvbo>Q4 _ ^ GFpl^?dy -_z[~eU5dc3Ogh"xHDfKdy-8'DU,g'crgиP0q' 4ŤW8czaD s1Y'nstS0J^1>Z9F Fy>0i"sV>ϲ'1;fW'U`H Hɮ}^:s8-a ômEKwޞo+3?f<Na?{X6K| sJM=ē`j3ڦP j\[;T3pQMt~I!~cE&iYl`qt@|tVe{&awCIwn $o"_zY@IDATg@& k4-Ο#zU; ،?o\gvTӯ]n|gn.ɉ˲@qPNr9n(7ا]?6u{2-xdzc>:|M*"976VX]ϟ\kgRt"*'uaJ%nq8ooHGҒ.NOP%TBQl.qeˉp)cd'$DV0Լ Hb-HpD=GnVi2шh=_?i$&2WR$rE'ߴ]bhlT=EE?]>މOK#)Y7Ɂ|scvZZTյaU8 TD|z\LpI Gsaq꩝›q/; 5Igу ^ ]|`H6ܬTU2; m>^gij _6CgC9JOӔz *3LRL'i nC7 1ApDERa?-WHءg݆ijC. W5^ID$6.|')SȔ)zmq8BÊh>0-mX'miU#a QAfǷ0@B3+:7LB&?b2}ɞsecu7}9ks/>g"DVlGl=b_J1'уI3gz8&M>!# 2gVISb۷yN]qzbs=j?=la-ow7߿ 7Ě#/ʵL;2@xl ΂3Pۘb`"6wrZ9G4ut^0HDy78ujSr!!γƁ1d`E|ܼYoRF@4 cMVPG|oi4k3~"n5qs٥AdsoDUԕ>\CaFi-Vs~^8+PT*jbm"'! l󁵀 >^f|!N18%4iFХk4P2Z)^G$S_*S إ4@ ڼl0~MU0^N"Y4a5z r|3ee6 D%+ZfUkҘ3N !,wgqƍ7bCHKhiPa;KCɊH$,l6 `P /%K4A!)Yz8+忝flM&ҁՎQ(6jc3ؑX|G[^ $At+qxs=tA;`) ssxQ$&[m{TXFօS ' UE鵄Dh'?c ߯%8\K$ W@$paӋRM|Kmq&:67qUXffW.g_Bυ{ Mn)5% 6vb gv#̑~Fi qXg̑{A,yk Ga.T:czWk|Dj9Ã)J]U7:^aa&CB2Q/Ejed/N-}Ӌ60_:Xg==Yv$[ޣ{ g` cxq Y'ɤ44\=>ui-`qy'C.u1mV;[7ĝ熶k' S_.Lw]Y>G!OrғeBCrx1`^3~h@c-HW j?i'IAs̙1ݦA޸ ^ɣ0Xgclu_8"u0Z~kRI1wGje"IXA`hZ獠$! gb80k cJz9& 'b*!N ОFkO ɡ'qdzd Ȧk`)Bv$;^" (t՘Gbt-G9(]ᵀ۔w axS׼E <>ү WkSiȀkYmn&@BqSRdNߨ]UB ,\ SF `kj^gw}Kj]^*yY!tч7P8;QGTDd ʳbLp1Fl~&=2.Me2f 2spR.+f f '5h;Ao,%x f<#ըZ?}.ƨra\i]grU jdQ[ЊEy+Xue⋀#>~};}}4 ,Iũ (4`ZHL01'E)P0h Zo!y@?v4O Fb"%v\#|W; "4*ǭ]Z.4m)xω :ph5V UDlCXeJ :j:qWz~jM)ֵNG @7;6bJsjZlgxd>P2…€=`m<9\w4,,!!J KD(Pn!ֽH?e+==xC$tHWݽN&Lu 2"6Eʑ:䠺Ԇӕ"\֒=Li7<(M8: C?*t0N8 V'zCKriVtbsҙ-ӡei[8P۲ϕZ0:~צehwxO M/bj悝$Fʰ)5@0!J 녢*t>TM&0jVV8cEB^! }6p u(-agc<:'`XRLnTTm K$ $`J08!X0SG!<P(K(}kt߲9`aM^մM7}S;vtטy~j\2Zm:[IranR~QNnx\]Ȅ^HzT@2["1}`m~ l l9O}rwqҏmyJۗRhS /ALe3aיTf- PUX*mVt?jfSf!5V-|Pyhc8"F0IӥA4OUyiy@eETX;'l!h oLE_Erx(_+ ʴn3V7Leb=UTQ*Lŭ yRtđa/jWF(ڲ,/K{H<"`+k!t6=ugn{S){C÷y8WhXW"Xg) kE @)/31.| -GЬl2hoEDːD@Bu3tVm aW&SoP=c .WD9yP s,jS?e"ً'LI["J df1Df 2֭( {kZ0s,+-*[DnyyvANdOe(::zniӿ_ѕqr~LAI;BQkU'Ŏ`<-xP=܁0:"|%.`'t:oJ }հ]經q7 "C{#cj %t;Ϊe0ME -xy9C<;6^?LˤN5({Ϳn.qQĈ^0:EFM2ޜ|&)Q(i%A4FE\m{"0\XNڎ_-)I} '1r9BY˂SE0BUH0P83rk%zkK x?Tm8=vzFFD7BBKBhY藬`kk%E$#V I]m?LM:>W9b0F@!"f]N׏տ>nU(!6JAѨm 5Mjf)D30=_+kk-`A82F3hymBԤ.Ehr]2Y 0#`e"tkwJ+2R]ݞnGȄyQx KW&tknXMQ^m8̓#+; `4zU-jI5%/avG8|eq@$Y9$1!\ҼW%>XkD8[RvzWT+N$dH,{[9}8a~8wg@9{9M@x&)P &RPJ!7xg0:|QJjk"g9*4zayBj`sKQJ8ɿV㳷띮8Ȗ,KZ)T 75 gcsxJ$΋_ڷhOmkҽ(\v?/ r-/Z扎}:/5[KlAz8axyXQi([*Iy2F[[w2+0zc o%\%[hW籼Ê:?ZhN`b-+3zETxT$&<8Z?| zs Yvo*|7˴:+I*驑J{qP(4qܦryBݫX*j:$ 1k+v]4,ܞm| ]U=E|e< rzh4oce 88 PSx3m誓fJ=Rf$#mW'7͛%ٱY{Dsaq; v֮%i*?\P y\O*ttIBco Q&kw51{V |B~__.Rr1l3B=RX-ܱ~1M-PmܭrNd2p(r Œ8og\|lsDIa̞,ewXN' 5٨Sdct(n<F_jҭн3 w19; !qruJ?6ŔLIb*n ['eoOVXos蕣dPAa\em ^w[He/0F>bˢPdMa'K\ŗ'RUxu:,t{z52,?Ddf{ E$[}r-OmoE3b`8 NU KM&HƋ܈ =)zy}[ZIX0WZ[0HDFZ3+Ek_Kbin ~mt/rT[E<_zs/0OjQ/sL`v D"sϟNT7Z[9+*%GL;qġv1kT>N篜b%n_lj0c;{LVకc̩ eDv OMϵf݋,EBme?ͅ~ykAѺ B]_O913eZKGq0ט܃)Ojfep;rcUI=EHwjw#R*wp.r?t|i:{&g !oo03WX |8= ofGg\RzW}=zșbrL[&jg֨ r ڤXbY,\ 3PfOVGE(Ƚ1$li"!S-IJNy˸oǜG%& vP/J[42-%;6i sg&HA  1 k?1o=τ' eAN^JTcNj<%z_ *B&r[S2'g<;r=q*cbNg mph >R?5`=c88vZp6<G ]Ul@1}hYl%q#-0b>r S/NJ,[+?Xǧ',7;F\WznL0 }9g@6)8mx xyϬ==^C* qxߏc|C+lJo4)KlytQ!1fXܢ0EV9M@RM{;Ez$2DžO>Z<̗(8J6Etػ0tphh;hO-c =s^c+|9z07d.'Hlȡ)۴)#PFtVJ9tU;PkKwxj|H73BF49W@O^ T7gj$,hXM (ڡ2 !{M e16oVSW)Z\T8iCa!Z|0fYN{;-'K>~x GځxIGV V8Ul$*T=^ -v,tWK5>a6dQ NOgޗ9娭ېa\<$Wǂ#8S}"(uo Es@0Tri* \hab;m(zc.'HFZ(|,)}n/Ne@1XF &6ɇ:@G'oVL9T6`GZ5PB/o$Zc?aOJjfT34O'YKh%8a)1^,&ÿ:Ts*DgF&nftm!DRq0|߼߿'DSFQF<]kuj{f4~QaQÒAP1<7paXA8L b q q4COSx pf8.%$DXVWP?Y q+ 7>Z X3@>>/gCn>L~ISCMLWGӼ%(@Z2Qh@Ini5[CܱeׅѣOS%5|O%0B>4׍#yFNS:࡭\+ m𪛼l{6q9@ |u%*9F}&Te21 47g`h^uee8?M:AmTQ`' |{2rK׳ @L `31K A(lELIrAMp2AM07IelL`lwMYT_N#4fUMZJyNSrF>[C<u=m/}!?7ϼk+`(jYM;.p4)OoHM=H>KA>SDlLV`tI=m6_$Uf@`\/4|"2mhp}j"T ''>Vy}a S8ZE؊/GX7Ud(ҭj|#$]ޤE!Р]qθ)lBMr u/;]DƟ8DN [V? *y2sIؚP16iQܧޤڲ*FvܺclĹϢh1jՐ{X/·Gk<p0:#ߟؖicZE5"lsf`*qRDEj;HU@ Mc)_I1EQEKJګf 6 1v̬|ί)Sb7e~<|]-$lR@_0k:MH= dj T(95Bƫ">pESIZJ'o8?W"MM{זK0Zڟs )PCzXn2EeMpZdP2bC\$0v}{1j_6ٱtwyK%՞dĈZ)U:Oo-Zf [($zKA{ԜX*Ċn9Oȼ](d<@_Z@vi=g w~HSg}jz__>HUy%[ 3 7!{ʐXHK*Ukfi5wtBVw?,ϰ vz,%-p}73! 9s'PgIR 036&10.([,/G3}| R)4nihq&rp6Fj}"f &6<Cnh6Rjފ, U=oqNc_Jm^0E%$zt'9Pq π2b=gD=BM0.qLQJGbǞqˆ8ahYK҂ΊU}fmKa75@6" @aF&u6CAJ#|nG"Ȉ9Qi2:ʴ). W>L_{v; WR|աF][hh-7Il]v՜;UfN|P玉yV'Do'AL_@="5&;tA 6 Jqd >4hxZ%켧itUkW`NJ%*A&"1 P)IίTԋ0:cӽ ~\:sg[5ReZXn=3S̕hFO0bLEqJD)D Ă!>QQqdUʗ CTYFlnD&UoxӨ(.T!#jfc{j9]2~ @ D NչJP Y'K}rM!8R]/o/yuFxΣ+@UsnSDx Dα\M~_ߜdѩ(ҡkx.`\6enco7H?s7'9t^Q2jE|B2 (de8nVic"uveNk iGTQiDK^vyZi _~R(y@k+Z'puP;bNEiϞ1Dƥ퉕ᦒUp[ KWY;--92Ƙ`>2VYV7Eo%(FN)8Wid}jA!U],%ܺ(lxHpD,i.S)u[Tp;oc!g4mEV,Ew*t>sqUZ"ÿn V28*ʳ _݆_uA3#(*-bg. '7!C NiOgT8R;X:T3VMRIynDYGTd 򿋥Bh}74FزhvZNŰ7ϼ?m,v2"3RMxgՈ偬~诚obg4]Oi(a󆗢nsܙn@BH%0amI=o2(*#hf0[ɠ)$|p 8 Jj2_)|L+VOOSj]* Ol%\c8(U^1^]:TMŊSB.FIwƙ)b EK0T.-=IW9;jXz$KTqEl!S~GggGBt&Hxͫ d# 0Kx<O~89(ʹ{Dl %8V4CJaI ,Fm1zuAä*F%=^}h8g{dW!O3ShpmR!sؓAa+g=hu&`tn2 6\ KJvkd`+XPR;n;7+6h<,rt|3]1Q s 7, I$qL|86}S܍ ̙: ?ÁaTw}rZ? w*ڲ ؘ߫!:aq4 y~x{&C٪?uI8CPg| *gcƩ@3 9e1Oj!8>r @eȀ⹩Њ$^Cq )4ژ}lD _tGBߚ&\Vf0c`0Ȇf=3L ,x0)wLx{=lLzzSAVBRWYefteZ MoZYXAomH"fM0Bf/kMxu7mY(ofR.8״'hAPQ~+ꜜ,)5wu2FA}?S1SoVtxÚӵ9`9'Bo[EWJچ 衲v1U7Fh[H|*$o;ڈlpp>0LT_8Oxʎ@Tk)dɎHi:3~?z}iì >>'ڃlSy֬z0hP9 tãCwZXQ~S-<ĕLn0kgNl5<4p55f<2nG2DdfRUxH F d-pe1S.6UpuptB&vLoX'>@z;AVe{#%-s5b.FdL{^h(Y BD.I' 0ޱ'~PhW>ĔXB"^}f"_*u6~ h&};Jt r?+8#W_; JRib ؆hDLZ^CHL6|ry颔(q/iV#x}6HZg]c[(Gi 3C@53ip>UIqǭߵP0;AhsV-6v^v.HKgW|BE c6-)?fX{Xd hkaPJ쬅@A0W8fj q-tC<>&RkԜ{DH[0U=M:qmT?4K:YU K'haISrlANI1|THf]}@ӤIZp/nՀLŒOyF`|LC1Yy9'GjhP<g.n%NS9ʍ+SFlsR -ZۓupKaQ,|^4ˢƚ3MDůi0wbsJgg oCfl p '%Qp]JPMN] wH[|0:*HVB i$dN'yI(Q#t>Fh9jPNěOG 3Nfs&LD5quFH?K:D猦@IDATzl Maz>H@pH Nױ4`fJb1pN2qş(%5pcPj\ H V&-Dfx$xg!eNMv[N@eZرi?zyAʉ0@ !HeH쏇q{ۯ:dz+V!>}gxERf9WELq5H9ByUb*1ДC26ޟ/K/u̽DMa)j.B0ʓ&'SH;4#mo0A%~96wɴZO ds~eWxh"r<j+[ pG0OR?Oia겨foXXKI#xFEWئ׎}HS̅_]j0z |$V="RԹٹ1 h].z` 28rM om1Sjn#߆#9?Ta*s0^ua6`+H4qթkW˟z{�۟Sb _y âu O@iS/b(')'|.5خ cTYڂmXn-x3?_ {4/hͧL3W3X2<۔F \Ӆ s/ h?L@)b`^[1 X*0E>2/-"t*.:ʺ{ ԃ&)L^09UC' VO*)3[kşնbm7W)mWjxJZ[x}2qvɭ$e 6YHdBM[9詊RG8#JTґ! +|es"  ̍*[ѣWT׸0i~ RLb cH'%* 3kto/ݥH$P3iqb i*H8%E$opu *̎btp/޽Fv]i2{QZ#];(~P{PAIh%l%bC?qon0lB;ݣ~.n?io$EV3>m_ʮ[ðI֬78CP\YdPWNL_j&43⺟Hc~GN [:44Fb90JwO56!i^\ KFC%qVmM|ٻTLdQfA2i0bXU3'PI) cD|˥{S44a&qBDeqyN^pSPŦ}_z}4ojA4/gh #KՍֹS>|Y߆ea!D,Ud86//LXQl|c\Ga9ϻ2 sy壷}d T&,%_o`@ge46MRd]9Ws-[L6a5c݂D(m*if=@ R H IzGϬR AI@MjImE9G1ݓZLreyu1X]?*n#0З7Xk^Ɵd2k>82m leXN2ʰpCZ {5tm. :45RйC/zp@m$#$n35ڙ7}"- Ą"E8NiJ @tZu-lxἿ4A<| ]7̲D"GNDF $,9saگs JAQ0F!URKTC/Qq -7 i, 0Dǩw9VY&`7>R3O' tq0NyM V[.f6UVg:6ň';ۅ7 ejJ%*?_hw-HZ}O=QAA }ҘYg" 7g ,.]&^qHh5cK<1McURiw.~/eWH ^UBt.λ UeJRQ[tn;,[rj Q>k8"p2m|8Gʹ]U ݳYSE.9,\JzVr GǬ@'`TQl7\%9P$j3dLfh泝P Hijܥ Bib؏gݼv.xQ #Nnp*mLKzJ>5 Aզs:<fYȯF ԶLRݭ;~!4ýq9 \@ip1#=MS7C[0Nsx'@MK8zl5%ΈoJz߀/p{3J!`@9oLc,4k~W_ hґݜA- tilI@foT4^,gO^)q|g8xC'%|e5-Lsiud'fG1 7`E5OSAFx]L& Hlې*pOx+(wfZ[z9\eZ0p=7]LY0IR}) #fe כ#t@(BiKqp H$2+McAOBZ`%,;YT5M݊ U7CW~! @9%q|?}בɹ3'nӶb\z[( :83Ilxsmi- RM2j"Oc\㈉ lX ?a ne`sl QA^&MYhMҟFᴡ2r6I}fJFЇKQ{1&=h9$RDr3k,e(Px.ɶξ=NտvƒP1|ZL5K*ba?_DՌ (&3:|#a1pDHDo]uw#1Fl2AhH1ļk3~Ѓ>YȔ{݆ $&(4b>4~ S5ʚ]Bi@\'vߨN},؍:0DF}|Y BQm ,4Kyfz '1j$J-SmLՠҡ3seOi?[ǒ4YEfģrn=CWMQoH~ 5!whTQhaɃJtz-'ԴK>GӞ?`1<q)BuAMc vP!~:w[ZjZCOe4J ,d&Q$(>j6 /ZU\sES 3m-s~0U4T($ GTӒ3$DTCc݌*mzhLF^XjfohhnҌ7 5(N͈Qx)K\nWyOkS(SȈNT1c"hW:ZA 9zX:qO,ݲmpm(GFdƓG1\svU@یc`6`K?DHv,r4v7"i7Z~I[tx`hg^A}UWiiWF y sgJ"8#KML EXoUxgzh~ƂoƘY[AsuOsGFm"^ 0?\5C)AM[hשb)&ELKTfK4I2>F<+zeuUCT[vMሆkBixwvXsgVbV%j,vO]$pAڙ w*#j/b\4pҡApd<4C.D߯gV꘎+4-X>HzSV_k6M7;lOgFWՁ:%4ZbX@5)i5z":ӑxD%9+B:K`HLf`ܜƇ~YD[ k|73B: B*|=,9;EŶ΂$. gNn;grEè2]I ;xYr (" ^6Ghj 9rM3~z4"PIu:OJqWs y5nY/ hy%NK|JY7-4}Kڋ4q_6naN&(ِʈ4f8+JLdq M$!X8RJ-FFǓ|O׷ Zq%TM3ct4 |+x6R MWE$c06m#U>"r0_䩔 ◽i瞴Ґ{Lc;?jLq' ;GK_4H"[c—.X 0[ ۿP~ 5`|p,9Ƃ[7~߅$f.4呾YQ2!؅ j.")*{կI8`wk⹧/GT!MX7/W| 3|E{xaޟYt.#qƺPNF]hȱ]㊐_M. k$n޺>5A?Ӑc¼j| f1'ZL\=Onc4P)` $+F[i\!^5Tl6>E%ߦ6ۗq-^,-R,G&U{_L[b#Iiĕdf9҃iV0H]ą}5H& "nJ-;q^hрUv*t\6}_Fv:.6͠ADduRl+1}(*fSUQalR2+E@B u8B̨Q4؏ QԪ$E@X%oV`qORǔQ\buO'+VH'-DtWkSB\Z-y;@5!U s T5G9]?RgpA}nbt 0;>㽽H$6[s-òTj(r‘IM shNXc/7KaX,iv=+'hׄ*}\HJ8S\{4Wep~"&FE( GZ'ƺ[b>KJ( DMi<&>Y%:7_ -" )PV婛 ]Mĝݠ{ TjɵGjQq5A(c$_xmvpb'~"' 3r?< %b|,0Ud  )"%s쨣C;~e5oW U.CU5б:,kBTH;C+O[Txu7䶴@p 1[ voh=[3];`qEw:]".v$b9 pC+i8c(Q+%Q 0=yPū72>: h76xEМ3>BCa՗ݫWlXy5󴹼IDH"QWmշ%RlL)'mx+&7v_ۋuhyν>JvƄydL).Xc/|Q۰ T+zX ܊48RDDH1I52ډ^*}4Oнև-'k =c`{Xf2i:|_)\O5zP~؊PWxE 7ܶV֣(M8O 7×=?e٬!"F7˩o/@6Bؼy}dW/Jͪr qKqPׁ| [7Xu&1K=|VrdY.|7H~!K&[B2%ՂaaaQla 6T!7@v$%'v$y=2R[KĪf{lJ"T&ﮤދHB;5e&+4nVJP4]0W.a Yvɿ_.EɟI B(hQ;{|uϭL'PBhs Fz ,TL"Gt+Ao'e ¤ m6/P͞6sFҕ^4d)Tء+D^ĚxؐAɉ0cBz\ wGJI@cGdL{Cr< }O{b!^}g2eehY(!'L֌ȠGbDֻ_|˙LxUy9oiwvҘ4R?]j>8`Ҽo;Q%P?\@Ҵ^CE=?胡- H ޲x<I;)bhkT%0ep>DfUPVl1rH/kE$`#$4B*AæڨIŐ63_mnPTu;Ȑ!cr#.d-!A1~WaV 2{=)<ᢝMibe arhH9n'~$ߥTnn@|; Fl, d߯v= m_s ux/~k-_Peڂ08tNVeVQ9$ca:J)eC42E-j5 >}Y֓ʼ =bԀx\Q,һR!+0S <{pʤT˾C;=WK)8Mr&D't6.Y!Xv.xڌV|="]O a,tZ44ϩ\FՖv2ԠUv$dկ|pfJYdv- p$U,BLA8@n~]^QFrl}֧XTn0C6ol/x5_Gİ M7, \{o=A&iz6}qOlF7~X]WFbzB&rºȋ@@b+qa)mm`_20 BS9~C$mm;g^}CyPa+V+o^,Gb/ށ'hf!G}Z͍tI;NdQm@nvV6&WK<}d ])a>W[wCZ !4r1 ܣTeZ'wL`d\{u41IQZ(Ta+#`sq:J]M#:ÀY-$5WE\a-Ճ_ ġI[o.S(heQ=#0r@.`u6sgƸ5z%̑ h4vY&ѠC#)16x(t\g 0[dNeNt6$1mYk=ԅJz#^Ȍ< ϐ`0*Mba1c4M7 W1۷!hj"Qޭz$pĂd!p$dIzBħ`ly,Z@$3@ C0qi!l~ި.B]흷_= {&וtaN)/9b'ߟf5 g *4k, MށX?|^c=|!-78+iO {*b#bΠ70}0@] qw6ۿ Ah 'WC,L4:P~i UA#ܐ%hssthD9 K{@s9AzeP]k5 NwX6>ָ;&e5-閰DfjhJƝ5xX2Мuj8 d)9'Bm xi췭(-1JzR: _,“&SP_"'wr#4,r3+^c 5m{ 7֟?d1<;yB&pps mya[v·3 PEvֹ/dt'(sO}o7ɴ$87KN #:Mj 4Ze JAZG2 1MʅC@52m8Wv`vޟ̀2ZWq2|7M viWvi>b5g660u~iܙ!OPFZr[iX:|42HN9 "+˚$?t4Wr*2qҩro>lp2d>cH :Y&He%ҠYLjf/`4X'~ŋӏF,XJć0(+%KcCt*FG%y;IJZkM`nr1@a]& I\Яc^1ZvWk<`=ChTUAǘ ֓+HB!OpPëY@@&T-^}N?jds(qD4"mgsκ9AS,qyDas]?J "b5&/oJm1>s_X87Gûn~Ԩ3SЦ-CoAoG5־i`('Ag3Q?e|2M y9i fdmMpgn T/[LJ4<uu 2b%u5 iق8)AN6iwoѴy.kpK| Zo4'TͿA&\85^9ΙC4ęjn&.gУ1]XU6I@2֖u*Ƥ~LV{IEp=dH=UO1=?Hh#7#T#OXӶZ6KJ-0$4S63Dɴ6RT~CXPy-:P,$|Ku ]mRoE76*Pd4R:Ƀ|)`w^߰F.#SBSXPLOz&Z )%{K|dÙ(/9em)p Μ҆i/W]٨I'a2. 7xሱz`5V]M)IENy+%/$cqOgqݖZ yNZqcLjv`R$rBгnf|G{v@Ôy-a)УpxbTF΍ cciLx{H<&D}IM00kȁp#>8D:h1}_5SnD=uFG @XagTdȳ C/ݒAǯRۑʴ;RJ 9z=vj7gC{e&j?rgFOɓ!c2>TfM*s{9)d~\x*e%|IRVbNE,z݋PqR `Qn ųZ+O_>ږGlI2NH^p=VuwQ{KeIѮKZJ>N܊UdI)##FoH&?tX jV\7 EuW$tm<DHr"N}yGX.% ^pAON&q7% 9+_o̸PyE!Y7<9m¶k,=733D3vRWw^kf1DQ eHXN$EmjQ Ȃ^ ~j0nZx!3hh© H'VWtl -(!hNQ@i奸)j,.zˑ0S<1N +)Ot OPwNq|Y<<wbՒe,:؇v i 1pg](`떤'{T_Q'?[%]PY (*}mLr]E,FW"b; %n/6!Ion-ۥ領1T5*#\׸W!Ҩ5N_xBc iV˪+ B ݉Nq^M?3t8O;8WΦNâ;W,S4[P;1{ݝ$ӈIk4uhmүQrEep\oəd*nj:\eC:uИk a vRb1:蜅Z Ɓ`Yt0rXNQcUBk07*\Ѐmv~Ղ^yDۂFrLADRhkȝsmE8a4zj 'SFG(]a4t!&Dv$ H`ŦvfJ V!k̡,iш-wy\ˊK̥ʼpSC%3ɰČۜPsJ[+#V, ɏޘ=Roׂ$ۜpx71/ra!7K'k17z\5h.3B ٍod'sXby ,ֆ0 yZ\sqɟiqznIa/r;ZQÇZӾLQ*s,"[~p|e1ŭXsy d<)B3i +$׳&o_^qPG+S-_WAW7Q`⫘EbY@{f|1`=KCPRC\l~۴p51sC a)tG %A~1:0/+w`TТEW5Kf25g?l*$ȱ$clc #/;md@(X}im|s¶p WpDfx`QBx&v@w|C,Yң?:n ~\1j}=>ODi'f^"Hj!/h-4)C4iejr4-]G*DSͣF3.G2_hb4K=9{8/ݞjD%'yp"b=+ grD CM_ƺc20!|X?n*7o HTsA)MGswڀzhV:2Fї%_#`mw"bώ}ScB)g5Jq/eIJZ+pC,.þukKA BZ U5 e ÂﶓL[ OQhWg4If;;Sw%m}{|7GB45UP?JC{ꗡ/9fB[iσ7fC+OQ`HJ/!%D{C]Bz摤8B iֱkM=2e2p6ֶ1c㤞DQ7ҷb0Z10Aϔu!u<5F&48T5]D'i2W/̀#|0daһT Fa p=Qt 1aʠGhmH0$CR RÃu6L z SIa?׻g H2${b\Lv_㎿,}P7:^wgot4O]\]V;5ud E/ L&\N0>% lX.FȽuOSzx aːUBufhq E@IV{lqƔrC+Em(l԰èfDrXF3E$^-^5Ƭ3b0jzd-(zv4ce0z.zWAkS&9>U`EQ z*j+&:W y1a*b =U=,VH:/ =dao8ѽR PX"!Rޯ޾\+ykL#1qpus}2Z!>pu^C] xU%`N`mP'w ;aI_5nGOA}iSbBw2% ]~J zzU"{!'TbLH~uc9 hALrbcC>Ҝ,8eSUUMڍd S n?ͲDNz© k_ Px3+zTRr6ΊfB8?5W0ӵT}:LϕG}93Sl!0vl!MzŶ~^]:>rgD6sB=r (io&+*Y"d57-䎓G~Yѓ6Ȯ0-j ҤJΒHdNq/OÆ! cKDmIH"〥pb1pi. 5F"~fӚ1u(CݟQi ]Oa("i+U,AAȒ_$(n eck sMuΧN__ ]+cs3Z`Y`kbxa(~[MAVeugi_eR=*vtN蟯,+<,وgfVnշ.`A ##/۷=/-Jic}UJ1G2]mY`z!_m#_e_UMqԄ0i>2i) ^͜T"grǧX̞EMk0b;N0c|ۼp3@bjXݹr-,qݛ$ͩҴMB`Y9l ΊFNb4I[T{0x& $Mܬn~UC|1%뢟/fBgc\6䈩a"y8%ne}FB4^H֞3a2DqmߝN|?WHh5,q39bH#ٔ ,Q+F@gMUsލ7ʬXeb/Pwƪ_ ^HEx'mNeU(FPvŸmfra0!8 ˗>hWe\I^yfJjH1Jteyٲۢt[vo׉CpYu6*ίqq&OPe/J@Nw\ج2𕡝Oz^-1,zBJ%&zbkf4hf# -~&-_kǟ?~G6w\($.t8TQTvr,G%ԩ_aI!6cKd;lB$ >nU)E|mc~ mY_mh,IAbK DW(PIz~mrM]њ[.ڛ7)Y`(+Zia-w9G`0C0-ӛ^υoԼUkrF4V"1l\aB<ԸfT['p|#%#Hyt|F a뤻X%׎Zr̢yA-LGINw#49J$w0A3eJWcp JQ<ĂbV;)/^Ai+zc=KZ)'ra^CM `*bB RkP ?a)괬Mpbu*" Hh,waU9^۩ l"2qq+$1>wdt͠ᴍN/ѝ}D%54M9WWI˙i[? zx<1 h"k8It!lO܅^I_( RWf]/č'[AjujT`J.;vȮ?% uÉ'@ W#Jliї&;C֯K L\Hpt,U$lJ3fd5^/W,]fX ?"nE1xIeBL4{fH) r E"mp<ә\yHukq΀Jw:ćni#7i")Kp’`ZdI-S VHz>;$ظ lyNR.+ py39d/WgL#Q ASqL*G";PS0p+y]/M)Zg"p ZH tҤFߎ鳒ŋ Ī[[{Ĥ`&,rZJsŷ-JED \@7)D>.?=!+':q(+[^Z2isg(6j!Sv-"Szg&0 O|ڼI+k/N#D$9{'NL wNQAVak1A( 5 S,lM6QBLKO&TF^U,Ng5lTK .l})}RHt]k2xX@ ;@;fey9cW= FKv1%#07GtzpJ!QƵ %чU>q(njAA3FStE; i'b^2_WtV 43PmF(ba{Ykȋ]n Y8|a&0+[0u1g+GB@H~>Me9Tq_2|H]paAʹce&ŻU" ?2DzW^@`C!₉if@ CaF5ˁO nYڳW9G%ɺQ( +XQ'iĮDՊ", D @qj/BP6^<)[D)Q.NY*DT@{[Cbjc弡<%=4u>]At|Yϗ|y2}["YM쩚P3b ? @ rq k/d&ʚ,.N*H}xʖCHQDwJ0ew=8Rqag氣)T۾0R%Õ@JE!SH^wkՅ!$ e1rO!DCe)eք-mi<H2E9P wn71cy dE_p, d,&J(eҢ] X Wޛe3:"@< 煥huHZ`$^d;MA^I^bj'BB{`R6B},XEON Xҧd R2ULVD$Ykƌ'AE/*#ft'2i %fܾ 2k LWA{;!='l,gD>qOmd&ޜnA99w+Pd`<.epC#Ŀ͗(8%}҄c= *x*}>J0ld358~w[ C^HԠLTы oM1"0/a,\[(h^r$wwU}VFCW9IF#r P ?c0Eƍq.ͨHD-]ZcUÅߊBL8Ok3;QU{3Y{m*7Nvy5_5K5ج>G/pfހ_Í~pp a&vRι^~|Oa|6İ#+}6 @A"{E#,.mQNIܚ&.X8/-i(hg n:{-ApWw3 ᲠF#4ʪ D0:zfK)[}/vVP:FP~0q-= D67H K(xWw*;ʹ<7fОD!  D-'_w!,p%y,=VwP@K=2meбS5yׅAXxHXB[}Map[_+a8ZDFMUa4gu:\L8 oT "`E")$˜-ŧ-?g!w@spD_;&o8S^x#HpN ogO\}+͘j?җ^ Tdž)Ck$XO'*1lծܜ\Hf,A(Nun'[ |ii^ n\w L'xѷ9<ӓchX! [lk#8a&D LmxPqq=J&8Fj1@%f63W@hҍAc$0VVE o8NGsl>&wذ%(TKPgt.\*0LJÌ7Cq9# ?b`ȦKdiMy80w{7@ m  &iyN7f>csi%hI^rW;<2ޠ@WVӮ}:=}hw`-1D>pQwx86$}^VH4p/s WW.D55wpV8PD:R*3m`gJ@m?T@ 2~:J8pn/űd[I (/-^L"k7;d^Q:Nb8A;G& &4ܔj@2\ѻ h .f)gE?LC}{y*"_~gxnU[.`Z%s  JX#:>qu]dJAڵ7kJ_EV_n2:Z" v@541.>0uȴpPf4hB.>#S7HFdه ^bԑ>"Df~K{JB%*pNM5aO_&"Q[A8F Q yIrƢz}}$ UgZCaP4oҮՋ),zOUتRz!b̠„eу,\@@xx<2`A/+A%pb4PY8nC{8JNyN`HZ͸ v&<BYxþW9 .C,C"@s"j8:ؤCۣ3OjH_&J W0q#¼?9hk,kyqjwI **'/;,Ktyhߴ0Ŀ),/{J9's?K 71)BJB5ՄF\Mh- G*ݕ-7$g޸Ҏ^LZ-zi iBG}޺-PC9f=Hsx\ƌ9bBs8 du iHÝxG۫>([;.Hdm24 @ Z+5Scvb8)cgayP||ЋBtHCU{ip$40f)fB"vu]^RfTqC# s9|MsU.[tI>ӀȊ0>!12XI#0.*?/p"l(/,Ko3٦27-9kz ÓC'&,1:@Cn p7z&5 3n*qwں,gDfœäz2I+[7ߥMi6.bYd\Mz(]\>{cdw=Ε^^`EGJ|=&d|8`lF.2Y.(0iH /'"BNly֙`dKMYH8 ]4 TFk Ѩ>E`w+E'XοWޱAϫi {n}ٔs;>D22PBb~A5uYg*iA!||9tuږ~z 66JjRuUj}Th1k !@8ebޛd.Q Wv~uuZmTBia\<ݵ΋c 6%iXzӓ;o6LL y86!4(Q`35ȿhCtI8!wE^Q.!d+2s S] ֺ^ ;G zSň)"vLzJ Oŵ<6~r=>xရip?c1|`l93rfm f8-Z-,dW[*3rgUwd]p) ?v&LbjNX\?f;M%iNVw1_mn@/㊯`h|—NPnPyI:P 0K@1k>, gFAӄ֯慇'>~Kx^c$Y1.8;TհYN?6T$Jw?,@LSSf 2 g0f$Y0":8VZ no95@2h^H@ qVM=%8;n*J*,&Mb<ʂvGcEHmN|C ۛcg$Tt8Ǭ9&aȽ1PDt(e$X~ߖzTBNmo5' w{ً]"⢲O,QwI5bPgd/oM_7w WHqp]ujtq~/ #UV qM]鼽 //Y M"/UvRC[kF*b"gTF{Y%v+ga2+-5.3- xx}J9f-CtV1^NVDܝoD|8җX,C2=#o:2!FjV:%qIfFL8qBްAO?w^o?wv`[^ ۨFgQC_xNUXZY$ C N7O;1ߖ& 7njO|%i9xHr%>6N7/ItRH)10cF0DOBT-6uUlLP&HDW91i}BQp]*3m&5+␈ H^VYc4*>`}ƀ"9giH~)zZt> $IX}[PR;QLqg˱ք#!uh>oݧeimݣ4]M@A[b- 9?r;W]+6 1Js*xU?3Ro5]D4Ze岣 T( Hk΀)_m?ani'xƞw(Ϙ!ᕽ@bŇ222y'GafLT("ˑkG4o(P//7tKT$$2ˮ#r8f'X˂5Dg}\F7Hn}s\.a\kO-YG@Q߄jFW)3C+ 7ɶ ) +SꉥBR8AG dY]&!'j6^EViB1L&1X'btX{ůiaVQEu' ɇ: }>Yi7t9>ao>Lߗc5DG VqP6d^tgz}n/ܼpͤE+oj<\7RC7]\QZ\IQL=O T3ud; C|U|^mayA0 4Oƅ (j'HֲnhIxC a^E&OuGa3i&~^k5G mt<2!-CA @t ^@=%1]}q|+_ lҞ1P&R96h/A6)64+tq ,빾hC`f +J|SBc.e}| zטQ;&>vp1zk9j@!郙jUrx%~Yv3x&}$"/GK>z [l&lI @QӴkoү>n_₸Ara?/ vVט@fԭ 䡎rӨIf(N%3Iمn+JK _R&YKb1.>66W1= R/R;6 r6Q%ݻVٶO'6dۈT[]eOŏ~XYN%eL0 CNP"rFCW673n\(ԊB̔H9$xLJ85ѩZ?F(dSӥ-J0,^Q>MoаYޚscҳtF][7ڒ .?"!A͌Mڀl;A"!*[5Ed vһ 3Z? a-S=:[>ͶqDB*(ߣ'"&]utԻN3 $ 4Zn[ teL]^#y"Cp{&3QWtHFka&w Zx7Uw7r< E)H]1Q\4@\"/BlG[Omj , xHP8De./,H3` (-`}VD 9"ڊLQ'4_V!Q6G7&1 z6;o=YYRe #4ANݒjɰd&> O$?U{B_x_g$dZ=JF:  H^N1E?^/lM!l .xPKrc# +GinyDԏ ~$coS ]1TR)suѺ(pw^.FP6hF#S+Q\d\Q1++%-H 0jC k>X2gP ~6~,/&;"juq8dE䢭grçhņ\|rC8#Y.2o18>ZN$M=t_ݦNQQ{|Uo hZ q+ޔ3>G<8}-f ;뻘@(t )A*]@U3olT2dP:j_j˴ D_%5Q%}l*f2V1arb}JKzHˁ[`|J½z`j8 )V ~=H9eH17?0 eH xGg2|Lͩ,>2L dfKYbi);;-RXE?Ifx#q1rǴѸ΁؁~8sA7>ZLV5@uFDR s+J<Z` 9L }z ʝ5K |kr2KfwδGv[~І*OVֽ8Q-㰷B֙Բ1#% f|#C&&gw}Yf }& du up6`Y߃[NBoH+w˅rkgv >Z 5ݓSM>[n>l/9};ֲ3;C]Ǭ HoG߃)4ra8PnJ {{m0Y`m6b8;LhOKeszqa"۔L_snBZ<_W[sm``+^P+OsS)vFo*Cղ'`a~\>17srBHass3z8M{+mj/@vB,mͽdK>iL)/lF@B mZNbakFgTx~qӭd z0>Ns Y":I$ɏ6_ҰwNk|N;xr+ <BC&mԢqRV:D8m=Zh 8掐j+e%yP ^= J{%tb \U5QW7@!ԿA}TVC` DU$ O$0a,Pת̗iC$7R@'w\fǤVwFi#3ۍ UW㉇ x vl)2N*K?T)_~\ c(Mˎ(7j؃)TR[~k*"ؼ3FBqf"ΗnrExE~?<+LH6|*Ž ݽQ7u\r*gxļ<%3z`){꾩fiD[UYV<8&A.kIڂ.وy1pxXZx& e܄]7] .˶sW&K8[D]u!){wb |?NW| z >,!XTv],s. [&ӯ:}6q km#koZy/#VH>WՊ6ϊ BIWASV?6M+W-Lp7=d>2&ǩ~"Mŵ|$v#TRCOO۰i ,]ok)"+c"$pQc[ShmC4U(!g?eW=pFUQhqINt]?S!c b F%Tyr2qf,u9VX}3ӡ?#oBZj90'&\@po*ByNzE@C%Q)7|,X FW=ڥoK_?ub! 7RM93)^aI.1hݦPg=;Cjpm!S]1Czz<(4pqP(gR.X3q `$ ʐsg; P>9Х@ *,rbG0$33{]!p% *l.8AݺLhNGl2_̭ш 6Nȅc?33 ?p'6@"!m?=lN]ڱLkF(a qg8c=+KG&y T8 ZbU[ׁ>:H!H%^]-?НѤ("YXe "E?T? w(EDĕME{TᇮP"w;+@IDATF$8).ϏB2D0ր-?d`0O}Wl_1E8kmGǻ&Zt\ :쎛!6F:wJ9 Q7j(7m.G"~[B4I e{842".E s|X3K g0{^՚ 콇(ah \Ch/\0U/I(H]} 8F)kl^\riKWypr[S"0XcTJӶ{bgK.*lQW2`Ј-vI^^?Wݬd̹TW`cJ_ɋH&fp\#j\JO\Yq'2?j^RQ6˄y+dSRFC9%$F~ה^i\ X=]HF!Fa-jj`lX^@bgOQU)V @ֱy'RI cy- OMP&ɐۯ΃c)S\A#l8AUdk5JՍ^2~wPangv~6aH0֑4HpHw[X:5 Sf&)H=aݔ"UE}ѾW8#K{dY&>xQ1<; x*-q)|Ǵh iL~=VBhhn{.<4d/}M`@\x\3h:< f |"}NrC &腗"ո&j T͞?kU9 ABd=g𸊋D#*(گx)6s99C k6hܤzDy?,h Rb \$Krh*Ş!i \<^H |DSri$$fTH̰y2r[ Tlד;@ 'v 0K%@_5kz~kTpThz[9Kc@Pxc3axU |t966fϾ  SHD2!#!0"ʰIw9fs!L$2|;ScJߧ Yv:U9'(f(@yE-6gg0w1~@b뤰k@j{USc* bW!Z${0QTR]x^] O7uPiWj/MůVcTԐ|0ś+GvNnM^?SɋM04er Z?VJw;DҎ!<7Gf>.Ot}m\SxVe>l-HꀶԚx.V"#TRίĒ2%2zpsa+@Dv'V %m@۟!!پ0"W*fk<`Ī~%w) e0gRp &NB>IgUQw~f@Kk^UUP\:Hlr L0T Sk:}qh/)eYmH$y!д4đJ߼u ӳ#n yT[ry 2 (+mGA<cvp+׎1CYuged#zCQsQ۳ C(\m.D$FIfcX|@v`Va:Ft~x 9\*`<eCϫ^TֆL6$t_ۍJ%zRR9jbj֚LNf?F6@ |zw͒}XOѦ] 'Hl\Z0dA|B1=O$5OgAa9޶֤0w_%$ejO֤X;Jv_IyƇNͺ;b_ʫeo/o&:9X7,j;DjTɷU-j{G'?F63c>='nN|M1`[jzBD_AaN5WPPF(pCڟc8dK#*3 Ψ9_(ѡ_[bdSi"W8Ty %`Q#5 \!W2Dt ꁒUrxKj@ hpFtF X(G11ѭr7eduvʃ9fScr>fۋm w֏^~W p< ']$uq]خ̆\H >w~ruc43Cz*4SF0ȝ:ʑїjtz~~9OxOOL8f!|%9r_v&*3A$sYO'x0h1r@%gl$|,+6>_75]*s}8f4v($Hr?A5Y/Ns VD" Gfp_a4,X+_h4%n0Vvn?)/*Ne:;f4e?NBmutumƂ1 h\7AMޢRϻ fYZK)c츐x[i5V2}:HS )Z=͇_ߥ$m?=UָiPds K/4Qoo-,@URd5Ù"N_i~N$bi x^?R5ɚ ,Gݧ( ;ȭ)pxT1k:OV8y%qHN}&Hܛ࣭Hz(mLetY,DӜxO+LJ; 89\ {ۜjҷ'-cDqW _-ZC(t88CbJ n?C =0:$f5yIA PJ^e O< TCdZS( 4*V| S $NzјE 9{*Y0+"˛r= GW(1*3k-ϜS,ưJ)ZYpGIu_[_ x:G&Q7T#/~7d՝E% C/ xY~ ~"' zQQRlRoho\LX )`5yM3aS{e~ZPod1VT\vG Zeg_Znmu9Db4cS9y d?|xW@ RjݩCC34yYe`Qqc=+# 7gkըlobww&M33N rE,RJ# -3D 1^Kf?Ǟ&2AFR=C~tu7;͝cS w\8JKbꏈwة'׬cᘬT#4R^L,"VjyI.v)P?\4Q ^sЈ|mV.K@'PS`= .~I}ҡ*#ă5mڅ~rbIgXʰ87dȢ@˲NjH#=r7M`ryCʀTSXO@ܯZl }d@gz:qL'ğ6q0 jc3dm^c) 2f"24gSG<礂\EtwH[ JS|)}J7WM4&IuUD`XF0G/j~/)|DD`= Xn$;O ,&G0oϻhKbh:!M=ڦ&Ќ"Gp3Kp HK,n3M[{)ՇtqalBt4ϤطCP:tѦcrIϢDUڃwz7\R~iJ6Cs PQk"چSnxvӛ`ttM:֚ KeJ5&y/z 5ZDCOQ]<" A@̙|VߏvszE|.1ԛt\ 9ND^$G.p ߰%l -yZf*o:< : pdŀ ly'Hn< 0=z%?Pj#[rv@RkhX5Nl`FРi(3(Po3a]U y̶a O{#e8ӦGaLAHJoޠ 1&qI(:o)n670wnu"A^$D )a BC~/DjxƁPWDµ=q9{皟V@UJ,#DbX5meXO@ L4UһMPt7JyW'=]yDV]Dt8n/h D%=·h473"H53\=`:L |M [/>xΨ7go}cb0XWC3$aPlJ\>P^1hՍTS:zH V_ cRd>iX09p40TXC41,zTS1?GN%s0HAjq2s)v.|PC?i+")]?3Yf`n_2H7pX:Ã~2=)@w4Ʋ3GM@=> b[7 KZ1 898(IhR ւt:UO/kiܗ :Qo1jȧ֏zW*ZdAzzY8vFy 7=PnapvIpdt/2}Džr淏fl:iQ^׈ިpLT9ϳ_߫Q4v? z$'3 ^1]0DȄ9Lx ȃYk٫dd0lWd_662~T/#F<[NF+); BڣO9} xRzqשI?2@.7kMV%"8 g h5^9^}S{nZ%؝d0د< vm t0 jmccΏ4B `f8vR_6yT4 w!jLwy6=daE^A@<81CXhl,KjA5$!n6iwsF:u!lqF5q6qXPڏrx0L Iܜ@'!esβ/E\Xwrii|ӯ|`\X{SrR=絔Vy_8 R.H*l8U{r@yڥLt7z$vPiyy9m'Fqh0^QWUq  kLA ѪU2[J{bP8+X˗Y^.mjÝʼnI#e^\)H^( d&c@f h#G}׉{f6Nc-ɮFYNg̾"mIAv1 ]K^s66}?,4 9f˨5ۘ,\)b匳ǎaBETi{y941:SsmIO 7p]7UkGh˼ȒV?ՠl$W/ )}hgBQWx D:( qy)ՠȴPwۚ:6)^z/]Y2FZ &OSW[F$#JAI%ׁڙs0`zԍׁ7ͧfQ˔CgR)glMwL XI+ZLٴ }xbk6^T˲;7+%"4S.mwL򓼎,!(׳ y=m(7MYrtڸ9h[aXepr!KbHT,#%0h9RUζ`H@A0=~'5{8=|cg:$H4d{Pqlvj'%b5 7GjRMģy?K#ߍ7ߌ Z|YE&"1dqnYg(t|`'ӌ%)6vӍ(h]$_m;e-U=R6v=Y/7γ>N4щ[%&Z 9:28fqU"01fuD#g*2).JRy(ވj.RnM˅ӾnhuA(hp0%ּ:RCĕi#5Fe41qqx{j|YijY\t7|; cdP7" Iw㶈j)xyM]nKkJlXWqF0nvKGڬaY 68 mQU{8b$( 햽jZT O3刍(˗Ty#N!1Hb-2HPb ͏'((8쟞b r>J+84=<ْ#dP=\G8짡2{FƏOc%4ˤ)]H njjE~ﲢr*Β[Ҭs.ȉq*kyTZ#zeLt62+B9`mB|+ e4ժm^:/7_f4|,Q ML: 7٬3j<}De_gԖ,G 4F,zswˋj/Lv7yy|<6jAS4.LU~ eYQ5C<$|}.odSlA<6mR^ńioAOB&7YˇU{/ZgĬt*Wv-VSe ü> ծCw fpTH:ff8=) uBґ*`!Bp%͆ e91ԕ2@azY/̢7H9q4$1˒p<&cͭ-!3>2Fa45=5umjFf[(Qw>IwM ,S*,l:NJ :>ݛt+u!'ơ?Y% rD0;5EU&Z|fre;oahX[m^2I#>q791.@Džm"2()Rfc0`?" $ϡ:l,dwdH!ROQC"l3R ~4xG30STL;yv(dKWGx\0I^@t@p ,T4K^}Gr\,PNjiX3s6ё1K:Caʝ 7X6`y̯#}J ;W CFo<`xcRhUtE[񷻩91UF(:&T~m=l)pD8lWD?\$2sS6jMqh/V7$0֢AJlA fdyAݳĹN v2vW8zݲe:lcLyc[zW,Zxa-O`);<.Of6qYQMi7`t8OϏyM$ }r1_gCkq ݛ<4k L#G=lL&,tcAK1vOl2#A)qas_=,8JPl8x~߷=d"lD V/fa^@ۯÉc-6|9XlXj~9=?=b'Ʋb41k&Gg7A}mptjz* l*()@&ZQ}sz.J~~D`d+'/S5eo{QCUE'.ly'YNȔ8z3rPV$$DL1"8 d8(Io>riє=8f"F%!Pi9ë cr~Z?(7 QhW9`-%/Ƿ9bVZc;3E/|b@"&ʥGZ=TbGzp|YJ{هÂ$rz}\m}bNk! 8ԡ""xS-uXətncdt.A6j}{aǻ+ /ig޷//'Pa7LHj$6J^^^Vv?r>2:LJ,ѩZOΒģ9qZ"D ۦJ?wx];5`܎N&_ĢM5e6 D#o/9+g (Z!剂醆Bv72^z)! JcØ)[6,kxABV`2&йq>=;$=E iVr9̰@CkX]E&كwvDӮa*8/Hβ7-tXQˏ,`c6'IQX8,Tu}cChǟ_m i+CbUJ'iC6J8 aL&{l_\ڂN/_ \EvHiGơ@|Pnqs܂jlL$F^CCk|:wI1Zoy],TSNFxLK8w3CH.OruSxĴ&ʄ;8w+8cx\E{gi..KraE@jI^ (k"h)qD?Q )Ro|d3Ѧw ɸTԘ+tjj_j/s5"O.1 }GK [HWLKaV2VYpjR@3'׭8#Ji/qQ¹Pu&lJ+@P291i/1 !Jb.,"'ã֋oCt1| :+ǘ \#dҰ`v CN/4"CMYX$69_ pu[IuP" ,ShIg7dN?mx#9lPc"ae bX1"/ *a0/lǑ#ȓ:] 'VUm2sQ>חњݯ/hş4r 7X=q !2dO+8\1#NҒx21Ylk'/0d |!P\zٟiddE\|dG@5R@sCX{!eHRh  [ɞUC^ݾT6FnA.*$)j_ &n#g28i2k+SA4exZ 1h~L >)"ʧت^M>*r~blCPD]gIV$m(QxtH2`!F$T9@Lp{;s'!C}¦WVet-P$ e oH/GQj=VLgHR9 O`x(mg˄S [zxѤJǹMGi+z0FP LAha諎`jR0LK lfDQ \A4{djxMXh`YI!\nN L:v)NJ#'_Dqlhivl80yS;8Ʃw%$6R2<$E RLF沈hWDƙ 39Z)a:<ެO+r&u{m6}O@[ߊAX0mpyU\^umsTJ (l5<\ }7< 䅦dw$.-=&ڏ?b:4[K*AgK'ɜi򕢊.; ޡqv] H6QTZC5jz(ZRqQfNmJ|WF8&0(Bƪ_TKaPtۻqe<0'`;wQJř$h1P`v*3.)A9)=VB_[Ua>*TM=8Q.Y\Ωʆf|ֈ[ #e/z`VGvGPI&G]^]Y)rlk? La.~0Ïy0 z6ͻ!lR<զ\"io F ;6L%#Vs.ĂY)e< j-\!$q7龴&j':Gg5쬥@aeVa9oWSG4ޜZ܉P AA/N`63wa*R3bpi.cR 0PXt΄@J,-N83ڎR>eܾlH>4#ck@#}݊vd NDiW _Hg1M(Vp5ϕŧ<9<=L, Qx 7  tCDX4Rn"}=JҢL/[0 Ǭ/h` j]{lR Z.wkNj>ؽF'h$IRTpL8cdLԍƖO)IkgA"GC\né8OX4CfgɄF<%ve{_;;5*җ(o | Ğ>",-Gs4RZi|c[NL߭qT`WnR= 2(~?s<]+wx*4p4Dܞ#6'>:]'6v0]x.g-1P]@ѡ?f YB)0a-<"@x roAp+p&՘wӉ;sf* %N |1H8K1Dohy1L栒Y3"=X`H(.9}*bjn>&*|ZIѴ OuK[ #emu@>>R`[Ijhs"]PTeEur4AhlٝM>ȾȖ˙G1Kȿ J8P1v Zxt7;Wdލkx KsSmDc2?ay+07R3E0W((z;@)~^fGkW/J0_s1&q wOT&/H= mW<>4S3XZ3(N;C%);I[2|ĿuH fQ0yŗIj9msI`J˖U>mQCn/违2$L7?DĽ9l.]cAҐljEi'j|KI_ f򹪤FMƯy*TC2 ㎯!.@kU5.`ܼ=~R3v8fJHh8&_T=Krގ-_F@DDb УBn]]ic>7Bg`:yJsw϶%ʿxQv)D <DZz&!n3HF!(Mvͣfk!G%ucw*I<$M `S%ѷqւ*kmC{c(dk]@>"+˴|C>JBKcֹWRxL{ Q͂C{ƀCO3&n](=51e֗nr CgԔ$t:Bg8˲i)AMx/d!0U;N#\yKl%qL&\7ED:[+z{ɢWS] V R\q;iB; rPV$uND| сV]!֖p;69{'` }HT.™(bXxp&7avGj019b|N!)>,)ꃗYi'8XazeYT5f 1moQh) naD10H04w~Eh ud/Nv0 )3)30<$mFvlsNb=5'rl[?\ehnZq2qhb\ RPY{TNtQU$yYsn^`Ş>EJ 'T$R߀hNVNjPB0>Ȉ,n\a"tQͬ%6f^mVGDPLfSqA(@VVDs*!i7+*ߍ \Hs*T`*@kGBnȃEғAAv&h5^v5`JkQ;Rgq9|:UP v P8]S GMYe'nS*i)IiJ>֛Q|r38VP,`,a>+}Љzgj 'vVñ6Ͱ,5GLqIS2x#q0c[K[+碚ƙtDwWmJB(ʼ*Ne;2,|6 xqpʒSEVHY_@ `؀6E46DPs?zQ, .deQiT^DË, r3؇@W[ju֮LUslJMy`"ڎg5g=F6?.[o M*=@hNPݤBADL:\ߌC1P`Qbe r?rq3~h~s2HDD<ƀ=#Nlqal|/TOO$Tbxw$YcSݩ!RE_SӅl|baplS!JI :o+KI~8U7)G k0"[q(= U4g0v&a9;#Il CeQj.#8Mr_,d u=њkQ# eh0xYΪqV|aBj4K$ oe25^ZZ_%D|PSNT'уk6F;#!iz:'<8ipvOmUIĶF!G7tlMsONi9L6.7/*Sha83 yT`!7]󝃅GWFS4o'ϏorJre7Z'N& :Ma/weg)ߵ?cNOs`:Y9+ʵr|SZ.q∛QFf FAxTѲ!}O ~qqˏ;[mi<H)sbR+9eFtFkcw;˩Z!ny_~EWBu&e0Tz kpqpb4-pհ Ȼ9K.1Sa0QrR%,-y{I~Xŝiַ"_tk'ާ)UMCG^b$jvFwO k?ʶ-=[[ ߲lgs !Od^J~ k* P|̈aZ5,qU PP_ibŏ(k,Qd({=gS͸5eTӃtD+gVN'iI%Vmlo6# Bf$~)ۦ3iS86GA 5/b%ZBַ7 \4_j"r[~}I%ЍH3۔Q+U;S~iût'{r{X)[qoĮVd0B bOu!Xopk<(S3PFK*N#ZA'MAX #i8Ř:J z\mm󪨉lr5,j%]HR#ۉ(]zTV*=7瓋>3+c@Nj_/ iِ՚UA4VaK th]f4:f R.%bzvS;, N=a= 9L3CKwMkU'}am|BS7ø[dz~ Z4#&^Hw褗 ܹv"dŐUٖ d9D}CsPHZu^:rT9uH"Zpw))l"Z'r% :vYK"ဗaVF y_\O큩55'!bHK#4Pd%Zt`|c .f%3uJ> Ƴ!Jh6!qV gt@ƅeb7v Ղ{!`-NJw䜺&%Nl* ʖE #vkdrIL10f8#R;Co)utc?E;pVG# ݙ&Vch Xu@LEw=8hԳexԵDd1)k# i,yz/kNW`gY 2LvEm*J')_P]Ɖ ̱Y楂:*)*_(NM p\g/A2U4o+TIܿe !O%5Es0W^p|m` O!hRwtH'zoEa ͖(a1p[q#uG4RGƫYx n b enɮvn)8@dQ*dAΰNxӔ"{K72P¯+* PҴ Xq=N+*t}S'$iNɪPP*Yuy y}%az6Jw' v<*Hqv3nVi'(a5#3 Jh@="Gs2 ԟ)VG9DF2|e%-a6ߐR#A0o=V0͐P gf{SDy~yw bڙ-1 8ԩDw!ߔleԻ l2뛂}O5V,dMIݶW\C(9Hh.K%'[ȕĒI^R3헃8`Դ[>mC Z7w`;+xwz2Tu\pz^)3 ;$`ꊥ5:IKW\Ff"idyߨV՟s&i=0(P-l>/JUPnkdNnȉp\LAJ!rzQۈo| wE]Ki/FZ\&1CifI OKI&'gX$@# ,"ɼcJ|QOIN֋E8O{{>x%fzhq<2@"]_p=bj-~Ѡ#Mv`V"_j@[?=TO7cV\c߲ gK#3 ~ZuD1($7`Q m h$0ƌaqȚPi;۩JԲJ SYNZ(VD]ylb AbK`;ǜlAY.z.mع|3Z?$լa}73n 4\:Vxi5e @-2ȧ fR><`}s*Vv6 3% 4DG`:1PZF2r Z?Mبh<3h-Т<7 "q3\O;*yGKtY۵01nȇ-GDX/V6cAߟP?VH _ZQ n0mz!dƯY7^ 0 u % wR2oj<$OIu1r} X&ܘ +6$}"N (Z1D2LjHށ)ZSmv0xEF AvŽSK39[$aYNG8CpiFD'eP^>GNS! tڛAWw _G,&) 'UVrQs"AZkíIuQZ(^ ?K)Q 7%zhA\ N  +yW[ a,`vԶ#=󗵯jC,}a؋bugK)W\tTz{ฤ"[#UM7GE4U Dއ· 0 1g8P"&aS*t먏XxpY" 3)_@(U,4u|=qsөīG됰ic>0e0cC0!KM^(zҍchnH8\,> O< sX %(>zDRJG r; iIդazZ>{ULvM7:4dhONe +<^9U7 խŨd.C5tC4ZG^j>p\vɽT -hKO-}tQ吓a4K%ɐ;[* Sg}Mn8Ӏ731k'j5oQz1 ›m$8Up8xeM,W؃\"B)/j dREM5G 0Ne/ņ4t<&)!okgYi$X wm4cBT0kC%6(rRЙm6,liJQ$|qmGܽǭ)g?`A rM]R9qyq=l;j .iI~a1^t_ JSXNFX.$$2 D cA& X25b $Rn6X+eMvXl<@C Cfd`'ˊQvJB,ź 8EjOVdD圎~ղ2kq]' h6 9d #|곫1IE9w %m05z02a0(̴ѼI_ `D*ڇc ݘLT jqW [vR_Lp#ݫy T&5V,U#vgF0z!TgjY%ϧ1p٥{viĻ7nub Q5?0d)됗;%a] w؇zdܯީFy,NjGE4%9==)i:.ޢݥ/i1ܢ:=73 ("!jqbcis +74jUxtLU,0#!Wv1LڌdHj*bPøl)XFK." eOO"[2ws3uTJ,.KKx, zΡy!3u> x`%mN]%:(ZbQ5b % ]~9^#F)}s5QIotF#C9'BX/Lፙ6cMUkmՄ`90E[T,o@t4D#}~ڜ9@Rf1"n\y/=s[<Aȓ`driNWjP^-<9<'V4{!tvmA&Q-N4d;vkn,bkRy&1380kambV3jFl}d|W닅x̘$Naʹ|$z])98Uw2"6Нl3LÚL>77Rv+Xc2p Q־̆Wp\ HO;4mhD2S': I-6AE8s@Y(+FZ#"s#0>DI9/>*^;uꢃ3c ?euv ?ȃn܀n'H)qZl5ɔ[c PLl_0ñ$#ZEDHЯ ˂muBTl*:6:--9q&'`i&0)j'ec,%\ؙq#hϯqna4iO-r~niyAIImv]]sp1őE`22q}zJej_A4~*Ʃ1RBnHOPZ .\m'Cjߒ%w( Oy՘gfb>I'PXASdô F/Qt8H(_\HmCE$|9NmS jog3f_ R܂aPۇZ3Ş*Mscy8q-4L0W˰lܰh4_D#!vyõ`ՄLjc2!4 c.gH20o&νGr'1RKR3y jUvN1/2&LjmsXoUH-AG ݬnM ~^YInK3 ڲjr[̻=\YHX:=Tu Es`-g ثn;%Q\c:~ݗJ Dr~O+'ڢPHA]rkwRTր0P+~yIs=u|0p~7 3P14C>s ve?[fCV+&+uRϒ@Z-׎8,PьOirimnCC|.9s<5FhIsUg&@LnaWIFʶۑRbTA,Dh#869dtYE`N.z<;:ʵ q9m:i!8o~r48?15:uq׭Ve<8/˕f6Krh )566RxQf҇ӓ5/l|?X_ CoY\^{ -Y 5YplF B`zn$ n&y^f%r⫛aֽsa{s¢Wb'ä/3v"h q0݀Pl9XΞ†;~{Rm]8h]47Ml^7pܽ8xW-Q2JԛjIC,2 T N]a?*25#w=ן.\ Gnb{4N" 0ZaBFy1sSLi9ƙ|/h !--'sIvI̪/J̝yq}P pډ?HGᄃ*YpB+r3Ӯ{v|~ri'HNL%F1J}\?o?loYCmMvPXJR].Z}>K?^%{}?z$W MVʲACZ?bޝ]XFnO?6AYU<<g=3w2d DؒM&VCRJ1UdSy x""s{r8>?q+rr =D+ah{'M= bZ)ݼ*5 4j A|:S1E5YфbDF1-aJq+HZ{GZs֫L"wՊWgjJw|3oFC/Eᡄc\~Ah/8+'*h9[4OfbcQ1){q7cOD;!K'#HYlQDV7S@!pxNϚBDDRovi#,[yx,Ύ+{FB-k-`$G48/\택A+ZodZn.R4" iXgX/Gc U4K~{:~Pϓ6sXRޠ4Bdi8̼Ogn2@(cwd/V~䦠͵gn6U3C298,.TV򍫖k$6r`kBL-5e TE|C Ie <밾e)w6!Ӆe,(=R,M˔渮RHj;V tDDOyƜVv'_y"7aANnQb+ih%-q܋z" p7LN]nkF|T-JCꄽǿevH/PSIY?-`#'|R]C}/ <7<+ca\}=9Cż}ɰEq8g|' `a٦6EətͤTehP{9wZ2bh}onib= OUe`?1DiOjɋ5ȉi!}ǻG#2.F(s@8cc,׸PlP3-'y'C`R%̘;QoF4JI7)mt?ɼ 7Ueg9\hD=0J_@nv;ȓF "F)I}C{э ٿbΌD>Uh*H:I~нr32?v{~&dA`"MLh!sIKy8Q$ZvF`&2"qDp 4.e)Hen4j]I,wwÀI0.#(NEA>@2+eCy H)0Hʾ eKΆZ%-ՉИf!S7NÒ4&xF.Uۜ w "eL#,N/3NOJ鷭ɶ`Cy㍂+.p{2Fhur`"¶  e@G1i'_x^Uu#=y א#'Eytfx|C7lHj,312}"%j(q1IJ1rZ"syj*z1@{d(r3"z76yKf3O&0zyndk}L0o_(65<@}:@*K.Slq(<nj5k-X(Ȕ{#GF4,͔Q3hxqX."ʜVDֈG :mk"뙕'-ۃ-\P8E(vAeu.PifEZdC)*IOߣ2cy<,*z2]L*Chov, ^6s]SsFZö>sogጸ4W| eK#._-j?h<~z/Щw33e#9\]JGb͗NAu 옒*`53O`G\nB T3'v2T' 9_1;L65 p sy [|w>[,k#܈DfGXϩbB<$KJ4۹uzLǎQObK&bVuhWu5: XUDi?jJ)@Ά[*iw|m7!"[ }&뚪h,GnrY6bz5$ vx|텈)B*āg =qdKu.5CWk}nr~DZ?Z9F~DMOum8ąs}B,Ylr|Y5<:lIQo,P-K}?ym=KUYONy]|PGPΒC mtzƻYnkBCOFMh˻pduʞU O4{[N4c2`0 z%0hYihuh)x843Var.M9~.$0@6,F!es8{#wR6PC:7&*FψB- 7+͒WҀ8]ft!uvP7S3߯mT=@(uلtw(q~ "<(ڢ<׺Ը ydءy ܜMڙG <}R!z1yd 훨]։ Eur8m ۍGTWRdeqf[nAȺU[J' 5Ă0W֩Iө+5ʔ4CVKtDo2v(kZgt&z>89*qd6]}q =g+?[*wB#V#tqX|3EbEL?|/۵T0k1rA> 2TzL} H^> ӯܘ-Nb콠m4O@Jc}p 01~1}Pvm4nH|K5GB9ƒ@)P:h$xztzMF4L F8l; G5l 5J͌["FkK2L@POmQwt3S!1HNڇd,̛"A' L 3pI3'+.MׅJxE>j'[ZB_b&3Q ݤbE|-w?F1rR푬1ڔ kFa$p]>E$H֡<2ЛC"|^ +p>;rR¾뉪DE kSHlY^pS m &`/vhsYQ=pQ#D8 v#&SF.}$! {Cdγm6ʡQ󢡑Aq(x-tua=4R&R-)x\3&"S4N 4K!4DA;2&H7=ŋn'6AЛ鲑{BmeE5KRRQ3hH}T%tr:S'@MN DD^`::Nٽml+Kso#c61Eˆ ߟEH4}m0 : d=fʿTFCl-縷VH=e n(ްГioo6}L@ hv @IDAT6s=#>n@|aCnW6bcE0/KTDyJSob(o]ڣ 2;ٯ<*rhCXYЎ^oR53#zTط|FQwLW Ur[ښ/'L$1ߪhHfںRTQU{AAtpC 7 2VCiBb!W"W5V">(f,BzYaKmWzN:FHmpo"8.'yɬkZ +}UWm f)ĭӦ;z^@)#5/otSZKy@"y/m, <>BVb"/ G<[3 a55?Jħl@οQxZcj:G"6Rh -nCHY`g74 ݠHHEDu'&tI@WhaB70nG4_hb҆^ sE7LżǛ߶k9`=h,TӋJX"1t"ODZyt";?7S;!,q7Ps Hh.kнLMkw Ez!E jQlOgFY#b-w1Lo <ن${D(_2-r~( uEHP_4 Od9PPTnb܎63 |.ØLg30AY2rqg]m j!aj (L@<9O¯n Ձ*;tE\Ol{\݀I3?<^W?){ɍ reCsQ ORŤOYLy,O$Ϟ!09PiQ3PLq˸RwKΤm`;z9Hn͟^EMwhɿ.2E-zm"^\&#kUegӐBs$`U$c b(Him SC_ ?y[ϒFѱ4(ȃsii&|{NQZ1P=|"pmk:A߻8f >0W7Lxg- 5+hL&uo7ݨ]Jexo U'\[2`LhUFi~ah*Mx3Q7$RM)0Alq*a[(0)c4QӰaXO8>gpn0t>Xm2{YpL&"vxJTVqTXA5;zPTfP%ӞĝiEH VȽ ?bCHqG Z¹dh{1 Yѕ: p?9(A_vN5ٛ<"֠T4UfinDYfX\@?WmM9u$]ί$1,fa-)s5ك8Vcq&J(̑Tw(s餁j@PkrԞ2OqČ">a9:?)b^INLˤ9gU,L֣øb{8Qmf җ*@T84GXO0W 10=U4`# 4Z:TV%A$x zr~cA5^qUՉS/78ckP>N3y-%FA4IJۦO:ͦd#{#0O",B0B,)6YRkteUGQjJbM5~DJFkEԛ'ܽuD̊z |pR;\L8,c^,6Vp?d4@=%K *h0x6\3N+]T_SF?#WD,|t 4Pp"UZćt&b~/O8 5XFV 8Ѹ {2CAW8FU55$X /\m9f ].O۝4 1M%V/gwhC֫w~xX8?5=JFh.҆ЈZ V5xN[#x0ڀ\Mx^,5M8x yK&rV5[d:ًO=FatP0#:3ufP7Kj9s]~~BκS@ӘC- Z Kin?~U̐>fccWfgΞړceuraokg|S;9 /֥UXk 0#1|5-0t^մu-㣑nT&;^ BEыBp $3k72ǻ M֔&"$B+= 4v:M.Q~rˣttN}^7yoNn`jT<ٿַ2J&G|&ǿTYzu|96&@V0.7_Tj%YlX#F3*`;h*b.W=ܠKS,譍 ?WGfk[FMq62'a_b2\dAI2r۷ Zm6h t9Z<79[}hhxa0Gi<7y.+a Mtµr!@xÅD*0{T7WRuv57ڻÑe޻ y {`7ZpF`^zaHMc\Npl;禝5*9fgv e$P3.I9YPYu"Sdp\b ޶;5,j6h6|1!Fz M)o/ i׮GKOo2ƾl\?-kGr; 4Md 2N x.|$|̲/!%R5_/?`eQ#._i8=(~^o>okd HϾnooRGߥaV[[jöbn7v+f9PiܞvQb)"T }z;&9øFg;/ >v)/?@$R4yߊQ(|' QCcod_% Up\ -DPS$GOp H/[&᧏a[f\/rh[`hۑze=m(sW]dc@xz59'<=1oE $2|:6-`I#[JC;ME}qv[usb`Gbe%)IN(9}XDT6 PSe\`yF3^@5),r5F+(2.W錚BVj75jMF#ʑf6#!B:λ"3<:~;|GU& FDʁ17HZYb3rp]G,xd +0iN״ |Wq"

    FLa{ő%j#`0(6ڪG}?-!k GQ>C!lDEҮN)@0`*u>)y=9;̼^m3YLh%0m/_$*y|M`km7id@sA0$. %"lgc(=A¡AN)=3ƺjq{~ ۸eY8Sb<7ŭ(r|4S$C-D(1%́]r,bS95A%U&q$/N)*i`E %F,HשV8 z%N|bP0VYaߥgS94+K)e( >=II;G)u3p q0^rT:n`x)[4;!M|ք[6 6'pe,KTo6~b  "a9EkHfLC=QF(f~ u8>*)o^VΉ@ nw?oLʐī/K( xB{ocXFv=_ٍ2ؘ 9C:teQKy'U|"ː34d1"2?Yږczj$Ca=# -ex#h!BsXrnE$GT2- pQ'2߈bQ,,bf-\I<%T>dG+tю,_ :ߢj:lP.͑g iA䳩1[p5S"bhfy $. DmAt+nDsb `g<5Ɖ!Q hP lVmE5('Q2K#*0|xʭ\8@fr}d8瓍tqe-^  馚B?7FeIlL< % (tէ\;*v&96>x%y\Hz ucLK0Pd,@ kA@H>EO0\rܱtAU#"Bmet+=-ʤ HW긥CIB4'Vԍǧ~g\֧AJ>vȷ|z,3@EcߟM58fv8Ca:ys!"~:WȈҌ(!p}]\Q܁$+H4<{ f%1#FƜBE[n$ η͞g1 jgz_zI d>1;8m} lQ@`/ Zob[sA<<~x`hMbUxT[2i<Ƥɓ7@)A#v͌C[n3m_I vAvW1ǐCX$F&3ɦMS,EY:f-0?B;AyvY9AT= Z&M4Z)>a'f0Ɗn>X=[}1aDDb{Ez0?< QϿՔ'ayqXar+gy+ӰFigoߛk/^%>~Dm.2V𾲲œ$'̰U# e_1p2&2"*r-_^KCFM*F Hh&dlev 1+Ph"#I#1Wg`CAG06J$/}h\̑"x%1TYuV5[6*A!GR!%V\KWtot둥Hލ,\ah93rt5oHpYwi㠉TL.W,tZ sL!-#+{j$Ú$ҩj{d/g4 _U<*^Dt,.TDŽ6c' ̓|Zym=\ >%TI@"{?+cAn(KbpcMes_Pm݌zsE]< KE%,dqxx}@fa &OVTj#B叶K=3Er,n~؛# <-[NFzTҕJ5!Ej }%D]-*4E1co6dq[SL0iY Ԉ 9hѦP g=YK+v!todB/ǜ@[OJxh^u$qe4ѵh((4'Fr?rb٪(llY^ȝR̓}rZiR /EEDVWԛI(|11@)6-NjxݤQe&tqD3ٱsFL0ɿ%h(A2ROKa @>s-ׅ9yMe  *g1-{0WDx]A \kq`A ټ*L%}@=|;0)^>ZH,ĥ! ]!&r$ZV :l3:%_^|] zSC?3+l'!GowFfXH^Pw aR:SZ{M Y?++KGljqA=MfGPZW䅓aYܦs_`DltpwmxA9)Ӑ8$YKQ1+ŤvlWJ1JŔ(`'Mď1N-I0jEHCQĭ~9&Y7FaMD*HZ f(&-@ma|ηE&Qo*c"S՚Wc4'$zJʷL@QEOBjDpįь?馩:W$$5~oʸ<ʰfmpCw``]ra_iTjׄw%r!t<0꤆jdk#"4,@+ztP/`* щ"o#;وIrѲ8:j(bx}ΘČpbN@x~ (-auk:w9)8bJ٤KFY4 8C_2c 8=P"?P): h$SămQ߭rL`B:f&S0 Ym{$d )-=y>q@aAk+Ph:r)=Э0lRWc]ţ Eû يм#eocT1$"0T oԫb $ \2ċNt־;*4 -ԡɱMB 0M]]ZB4w.gw#>R.Qo22Qhky<>BƦzvHKN 7 F?ܯI|ZTmVJ%qK??Z g$ߙY)3ԭEhŐ{Lr 8AބJcBL|er^C_@Bk\C*bx1*t$S!LwT*<Q3{\~rhM EYv3d s:#=,IT'CKg[̅6 8SCs )Dy4PqE"KI é6ʿ]>n/o2HT8Z*)e$tRv\d=kB.ydI Wncd>F%gߢ8AJ>^";nؔ82WT Em"ja)xܑchK5viRrMT )S :nD/8B u||Oc#5  Bzx ngVx}ef׊IJ:k;2s{"@+F!߭7Xpy~u ‹!NEJNʶmg`y×}+߶TcQm,M-@I,5h=WY$1^g1P)Br/aXLW`_L ;"A%s{VpvЃ%ɧ",gA:.Vj M[s7v# B.Q)/Co&Bv'8gםƩ/1M KlR+= ! g.SZP-esR!=.xS*JÚ4QBo6.v2돟6"PDTJK?Objk^*MQe"@`M~Ӵіmv{G糓<>B:IRzh4u,ۙH˸,v^wdħ$BC]pR׻oe/)|M ɋH…в0Q#a] wT o>*ә=ٽzgmw|N?Zr"+Y0?-%bu?a+.;+jPq\&OђA gLFO`uY`bU*A9eWzxO!8n6J?2]R*Ar7i8GO aғz B"ťoxc,sc1Ba]f/P`ܰcAoO/ )pEqɊX&OCΪiu32(ę 6( zln| XrNJ{KUqjd:~aٯW|~؛-b~5& >AJd#y{$U%k [Ow ڳt9,L}g#':'"a_/=1e/<3t$OeTn+)c=㟖@ 6[xյ8 [JhGՃw 'ΟX5ÀՖڳtj`% tz~([lm۬0 &ζ~wcg{7G+֟ah',2 TDڀh2r=x+7rBֈ P  d !Бco7d0%-2#r-&rhfXEz+R@¥4?-I0H-qYIe lgA{pH:] &=N DXX }0:|j>`DVIwI9n;t|66aDتH0kIUo^2UҊo#ktMalA:*l.Lx rWOhbL=4> >;+#KJ"A`030M)^*f׃hڈE-H?^y/?r&lzX預2ɺP~A + E@zLӟ0 KmJ*z`DD1W,Z%G^U1yJ &8G5'`(>}*;sM%3l%65`ІlQZE=oFoikV;%f8d`78(`^H*)Z|޼sզ)s-4D>d?iȸZf)ԹFu >3OSqeIh0TW~z !Up3Hy9QF&y}{>_OAa Ր>7?EkD{C%m3c0@!/W*)zȕAqGQnh"Qj1 M!:0"Q?>yp9'xQ c4yU-QեI\b8/aX lV#St0V nPPrX%_@'},~-ER7g3*祷QwpZy_vfCJp6+,-Oʸfc|d!#o2b׈&+1uamx:892GDgBTO MOaՄT(x3mN5>KXzd2F$n$5tJ#q %>2Dt xWXwT_kޕ`v2dD U [7iBW'P+@\CpTe=6ʠUp0> ͵DqפdShP֔&'+^*x|c--\ 0s7YG=n\QOe&uN$"L47L3l) +kg.~RԘ7 `n~qCAm~||^@y>86Gm32gn2\g03ȵAD,n7OƺL+Of2xlx^5jAxV:<-kVP$!="jc>M _S SNfCGLҠBv3 js {yYuiʷA˫eMq=3 - A$թ fI@JJ/;2Y-.7Q#&,l_%d|g ş]ǡ  Q$Y^MLk 9Q嵩kS0.(.T(D2fӀ$ ,"cMJB ssnmc>V:IaR(=GiA=nDP'gRxOr6#ǭ\g1umq{HGj˫ݦ,w7$GiUYc%2km4vY"5 gX̱:e& rњi6nC%+L]M6#Y2&L^8j %1cl|XOJDl46Y9NtA;CxAR~GIzO5ߟ(#_0SK0\zWj=v8X>"8gþW擞cj ~zڛ\Z QX:|Dw㍼Vs6'=gDҷV RCYYپ6\TjGB1$L6" " o9XM7X`M,K-J G]Jk^֊V3E"k h\Sy+"NԵbHHZEa>TX{ip A.wc>1ۆ^]lI蕗=rwdse HŚEȶkZ!~4o 1&͇|=!`*㊽ - d[Ɋ4ɸ7|w3<SNFM A$G7'9ra%kP'tJ!>,r܀;Xq0'٣jvFs0Kt戍a svft 0! "R%"Ȱ4|p~߁b0R[jшԚpM-NtV"^4,`UQ:BS\K(15mmɸiњi5oz9Y^/"LږHu:iPVӎP|=EIk%f._D!&H%gs' U"Fs&< =0?$<`F{;Dr̺KqE )Ӹ vE]&8(@IDAT$`ޟTXS6*. lŧnRqKNSGuIehg&"Ҭ"Fv3k^=G{ܸ}-hޛ$AoVi0ez*BFpCҺp@3)BD-(ğّ9 8tCQ?IJ&DeOO&D̩MD!<U 10CȊ_pnѻy,^tݚI| I" 8ŪUg Z0ôKƹ| I#?є)eԏR!;mB*x!}?I3cnT,iT%Fղ>7j'PƬ:篬{ngP>zv¨TX`;avLO RFX#Bҋ47i8gzFf7rU6Q6ͩl\DDOvple_ӌ33P73)KJWz'j"WӘSTb+IŚnRԀ՜:EIh响 F$5q-jff; (d spFElrdpGCؐ Hg4>&I&‹Jɼw0^h58y!E fU80TvMX765JG2im" vИk(\+Hu#_Qv ZHH2n+ :v쳍`̇؇: U[* =w8ʋ~hYw~YH8ձ.p3U71bAQeL ߊx/[A~F e P%dY&4G]l8iTRPw0W"-: ^ֿ({g?tƤFIkds(E:.OZP?yz3V`I ́H-319 BRӼB C*1S_r7ΊCdJ x<[0gh\إ"uKLIQ#nᴯƿlCN7Ey @j[r >`|,g"og\|+ b .j?oн&"r+it>]T)\o@.f"{I:(A1xKςDv^WWdTB~涿R0>~e < 4˧-_>2W$#ob+"_5.Wb'['(?J}9z\L^?A;/ve.Mz5r~L$DkE=K.l,Ėѩ{&XNd !f@*:& M&>,@H"Fˡq+3٪t2- Ғ@D?\/GO_ &⵮˓0d_/8<4g9xӳDv^i*#Y%vXCit6)H4Gp!x `qa /L1Vn#֣zT6cVqG/ެDhB aǛX 0VP&B_Aw$?gBV=db $bk~2U0W*,1𾟊-hS' ⴕ̥AE #GHjM8lȑlT6OnW͍s:`m2ɉFɧ}BH_ܜ?+|lEwj0+̰$ ]_PvZ]f}zU,cf{#qbYZhHsMUp G)H&T䠆^LBݫ/ޕY*6I$D!J ޥSW3 JK:u5Zy0aʭry@*ox5R[Ml`&HG1a6A'U5-ANC[v@*Jp?Md1rHMI]H3;ꕛ*PfJZާsƗ:).}7<;Ό hPp_ϮKPGKȹ+TfBD=G:oJzG4NE@8A`U0>ҋZƔ"6 VF (8)SlY-JJlS(*]Z3'4EgHd襈qv'z-2G\`} `HC@sk9OK d߷ iχf.AMa-rCZ |}f'Em=Li޳c,q4۲ev1<(v#4٧ͼd~XO ڡZoW4(I(nk^xu=s]E"2{g[zvK$Q"R9(z Yo6 8%n\bg9E1Z!@,ӘR8Q $-aۊIUldJƔ (?YŌDsTdT9q[z֢_iAEKdk#Av1Y^ZٳMQfc7;_zr1)An}D]:}a]Dȩr|@D *2b .@[Sh4]@@N?ㄫMl c5ZXmZnBo8\k=IPOޣΜYVo`g3٥,)`pAsbuAe~=$qlVh\=L8P0!?nߋ,Oػnx[@@ϋ! 0;zֻOCFj3\] ~0 mJa m;1}_a +OFkȴ0M !d$+ 3iNLy`9$S}=\!GYg k{q9" 2X/2 ]&wx _($kŹ˿>3?sJ^>; NV?VC^?ͺe<ޡ"<Nܦ-&s.(s:YmaCPJeԶ5Cރ k;2МuĿEȷEIL^v{4;5e|(խ}t@O&PeR B,i@l mFk QYj1 "'9{É76;r*(ϬUP\TH(Uq)4`xY핼x* *?z8mlTs9I&YUkZ-F%gI M[g-ہJͨOiCy]'lՙ_beqUNH o&v` F>|\GH';…Qқ%aYDH4 sEyYOd%K..S l`\=+4a@}a|3LboIHnDVQӐ*X?z_9wÝ>fˣ ryb]ֶY/;D2*/3% @ A/?a ,BmzÁR ~ʭXָm#.$؝z#XՉ֟?m?b6'%T@m6{b';PkN2O7V?:8_zhB=kڑGbjr|mgSO[!]e)lV@,w}b |[qjGMb(rhozs:¥nwo .h#f(8w ŤS;uf3*"_T\L8Y bNJg"^AOc\¯k)D_|<.!;^x K~͇'lDq˾QQu3Z2ui ߯nW(Uk0w !DjBdMM#@rS٥m>tqÒ!`=k1ƿďZ#I\lc?A~C;|YPHm 'k, c@^v1XuR.1q\#< П_**]TYߕ>_lL:[Dj n[X.EuWF_X5lnhf{m-exZaI+gAE a. މJ.07>y䙘7%F ^r|FY d^ vڊev ߽k߁lao;.HΘY5%\Q4RӔFZndkT@ewR᠐[]y}fB8ly?[θ0]+R(-Ua[+XoX:G2Ie 面't(gǸf}9i/0BsvUp"B$d+5c&N MKr Av)s~^k eCǷW"|Q{{9VdԠ¥#==X/S!\VXd,H]o$d. e,`ovˆM13$Lk@$L;ms.qSDLM{? d:TДDa=0舣KZC  n3y% cg-)Fjm3[͙:T#}t39bhcy sjs`&sgZ~/2+ mQ %?jEI&4/3/ T'eb WT# @@iO3ovSkN<$Dv20kJ~RKUl'!/.Es:G"\|~?b.DŽ"\ J\9f!88jP@|9ڞ Xh܎%£ A}9"pt}Asi_vIIzCFViS4-i`e2~Q2i>s? c0$f9#À(4zkD*HW:\V 0 i ng"`eeh\jkI^\vnE<6Fla^LBN >Y8ak71K n a4$wd^aHa\Q1-\xq-1(' `!>qڣdO@MEOߦE0u(WH{BHË`2X#PPl]FyHX"Ȋ}66."jkJ:Z ;FdF] Ӆ(O_^z-EdZ;K~^>w锂}HE ŴҤ˯̉ԼUKJSELBC&hI8H$R금M8BPRlabBL%]E~RLu1ϳ*.2t=fyG$i@eΙ:#P KԙEI?d]PK61d͙s0*p5Ngtm,IbAX)3o'a$b!tHP{DFf <õR© _ hFW 5ӸKx)c4 SݺI  vTMH?#%77H eI2`bcj-΋ PgqڎuYX!׎ Р,(޹Ո)N iCCeja1ӵ>,24EŦe F 5;ĚO,Gjn*̖fGeP6JhR91ba0*2X:$(f?z]ɐ(WBZ_yr9}j7U ܸ^yhR"wN}HE<譯 SZ@(Mi>$Ο -.UWDpjJo "R cʦiI^dy`N'`c:T](_'p2cDƧ $ 5z/æܲ)~hcyI:&u <5+w"dBv|`zum굜66 !U%^JQ63b%:>h0~2DHkY "|{=O*WXM0AcrDEAQ=KS0%3Ƅ.GGC- $L2tsp5,"1alA( S ACL'A5-1D yپ^/}x.jQoocy042E:J#)O x:Gr}l.;Éjɚqˋ+]oV <) QMUCq $;®3q +2"23Mh/30ġ:Btb`@(Ki&uR'ܪ3?,N#GzpϩZȤd7/gRJr;tBSƻXΓ%1=?1%6\)[7:BzwP#!)I'7(F^(oD6@ XAl .%ʟ& Bi"j,WH# "[,}7{tmn!s& l4-A7oÍqT[Ofx G0 )1NSZ}6VDGe4[ʧW9Hc\ 6Mf`,#.Xڥh2<|PA W,!ߺچ> 1ؘ2;r:\m'E~.]KñgJ+^N|}rNsw~JRaꠠr_,mnqʡ?'lDJ8 dA') /4]2C)j\X+K [r! ·RPe]=j&MX\&myu-?j1} @0㼬: p9)~X}` ɤmf ]n"NŞ7fٌ*g޲$R Oغc7+ZgsW  1zg%F<|!G?Fѹ1Et ܥIOY1Q%Q-נғ!YD%Vϸ7Ю+>ȓx x2U]9t}+wP7@|o/M4c_jC}JD4Ls |x4AO0ݯ[U?)b&չ4*C{Q h[Gٯ#M!{]F*i<9niL 2G <) hP7IװGT >kr%/l'TOaTLd`CdOD_w ;-&YQҷlˌcDxcU rX8e(-oZE\g`XB3‰W%Áu ͸Xm+T*4Y gՍ n]W 3ʎs \̽*OmƆ0꡿rW Ԍô< qWԌ]1ҩȈδK:Iv~4^MNw6gYĦ VF)5{a8}2F5DwfNm un@MD!@k m!UXI=f{m|:CJv>NMi~@X]Ԗrp*bBM۸4hWo˫%>~Ԟ` 4X1 Kvfav+~*M 2{m7-x.N `KrӚ:kd&o N+˯fϮ'R6qu_ng{!ݐUk =7p&_D1ˆ<<}u9{_-) ǙQCH Pt'pÉ­ҥU%ha :H531O;H Nͣ!ΞKa~/m\"F﫲sMHh I~mFrt] 8At)ړi]*Xg$ݮ 01 |jȴwl&^tϗ*dfZHRshSWUT.A(S<4jqP5>ZU@F1&eRxV9\z~\k̴cyWgË̕s[c0CanpEzW5d4ÔJ?|q7-@:퀦0]ۙѕSiPdY4{G{ѱ;r 4 - :I5lő/QV84^)hjnr9ZF7oG$?7,[}~*Vv IEQiCXUZEcpH$dT*i܎鸧(EPIgwUg6>e>-(؛?hcwxBIq .}C7L&Լ̆Ar6b^H&Stj9Wu>&2}zam[<&O''x/0ZY&ۙԉ1d 5uwE°;RI0u 6بa_e޲' hTvUdjn1b3 w6KY[|S I1??mD8%m*aTO}h6|v~OJzZTeϊhm,P $OU]ŵNj~^|B}\Pׇ4?n/lCi.VöDwɡt&y;\ +LXR{bJa>31JZ~OPuOQ="K]I>DQޮR-a>wx?MB) f_8CC`, LK|b%z-KQwOPLC<.t2w;Wlkڪ6= O˯L TMۃהu.&EvǞIM65P{ tHc̀ ־_u .D Mʜti/TY3PD^~XDE,u))trc1C+ق6;3@E%uwW@P4;FUnr'_7L00d\DFD^ ֫J)npڂ20"1Ĥdlh#LaexyiX6qHus4t9r=_\ 9[ܔ?Pgw4-v|P+ǨaݨIccLUV56ae rv"rӴ^|T² fk *H1l5,o!]鎠Fhl2'eoG)FTG`oxʎuC}7hVøp)Pe4HNi`FҢvE5 pczR#űpȟn(,$.x8.5$(cXw#c&76^=F˨5[6\*N_90K%`1G,^xPN`vr&/>&OH Ɂaą9<#7-5- [\LT?*?>K QybO<ߙL3ov%GawAί|72Dp_6׿GhPS.WU5ud 7 L0y\ݢpwJ`Љ:%qwxR1*X!kW4D = /JY à#Eh Aa^%'{uo@Jw^ %-zCy_HMb)0[ 4a;Ε xLe (L&י(9[C#7i_3֍RU!?9D3 *tA˹A\לjCHΗÆ4JAH p;E:I7n4iP9 qQ咱0XFDfq! Ҳ¯瀑.)1kՈAY25 ^,R/ύ @t+l|ެ94}udF܍O8Da\!<ަ@;XgjH5{0S$. 7 9B5} w9N_çf翨[G#6P{ CX e/1ndTS*nH\RoFb c,~0խR{AcCOtfXK iA _S.UnKlGYNj'ݯWցg@IDATtq)LM:J+kKZrJlh]l(5s2u<+\FR1)M3%zCHq,֠ax_aK8BW GBbj X^FZ%y  WU]:W@*^?@u̥>nx<"lH~o`n* C aO-fqN iܯ]%Уr=EeIlqIQ;e@h=+HS A+*隽j,ņ9xx$C]U"RχZkTz }<D>EjJF/1IG#׈"opF,ڜ4֠՗$A<*FغZ.bJ,G }lttQR~ e!&㔱R7F1UeݮUKz˩@y? 2 Z/`Z V58ӆp& AwA1r/ lk}T)Z0M8Y9짪3 WnFR\v\QPܒ~GQ-stLa27KmG9ḐǥvM1d%-CnaRC|rReQ7(uDMѩZQv('\]TdeX&zB0* tîc{O\ YisyI(^@c:cEڴ]Yp8|?|w~uOsRC:wajÖA=a}Ba7pz]-Ptl4(7Dhn(=_ť2~ GcyU(\eI9,;HeV(uQXA/뻝AkF4i1%EJQH1)l(i|~39PN“9+M)JnҔۃFREaphN |)EI}:@q`9exLu~Īd#]l3>sMb U?tBx0Œ D(hzem<p˯x^ e+(Nn8 _>HOT0OcEq>dCNϥJFy / đ!pk6ŔnIP/wϦ\d3GT VE.xik oM;Ҝ*Nq2"pdDG$IKD,hvpi]w-F1kPʪe=،Õue0a]SdL^(xhA52; xlH8/'cq 9;zt0 V%ҿ܊u//ѡ^ShǠo d=!ɋEA PUǩ:P@TEèPy?5 <a&yi4FiǏ$(08-Rn#m])a*ǏhjB ǩ&\"6u\!uiݦL oydP#]dD-Lj9,pOS,X!b6 EzboKûgƦH0dYly|tD 7&S0$0Hb9>ʫpD`<9AF-w2 qӺJRh!N#榌ya&XV-X,@f[̃g%dz~s̚$,'iuz;W)GƜ]h?U#V|*0^g1)pƅ߬w(^M8H@} ,)c.)oڿ#nW"UrqBflUyr;TcP5U:!B?2q ^2ǫf.`INNތ]ox-N˔p qV/\GԶ8 ɘƳ=AJOGOȉ͸4!A]P? n$lOG%B$euk2-LZ%_,syGAF:fnP3<9a<_:- ɑCuwALnKU @8a摺i$$,Y Q!+pGOAiFQ5t{4  ^K]%҆[rj4V}tyExWM.6B>`VzYݦjj~  c㓙֎\d* X(Z5{hw[bjS?Z^d.Fx/z)9zg\1t*%q-I4"@G07 ': K"'6+uS("3V#*r)i#&%mZdx:Sj` 6M:A\^o̶qrr3pkdž-vHl6ƙSTWCTņE?a}s! ~RQd! + `Vg_=%;Z t2\B0;)Hb*&(6Rzf89mN ͲC u?@,hY8.sM -ˎ]c=3[fIb6$vk ƷD揢8^?# T *oIWP<+.[v&N3zςCy`Gbf!&Dp~@ 9x̼E9RnJCwEPƴ T!T v"{DQ`,uu_q'#Ln6U*Mב{#e%zXFA IֈlQuaWV.eX*V!{e>&<^ &[‚dv׺ }6mqFZKX!ӳq&TKۍ8!+!W8w7 nOU6@xݍ}衾@^$;2UDdH sZ)9{A(ѦÞiI:c \t7/!g "p^ a=qNsQ3#.TvntOۍ5MzOn" `ZW*,u:=/ Xb&S x,t5(xiP$ Ri2PH(NʙnUpzZ6=!.{k-:pq99Ƨe`raPO+AQ8h) jiJ} (/`Khm0dM'jB&`0gCJ$S6ZQ!jx<ќg"n2N9m\#BҬfEW]O1~MfFXF㪦T3%_&f Q]nvvVKO$wVav" |~` ?4AJ /AP2sDYx {%VglZy`[JBUoü_K O.l1v8Q[EtKH-eKZ` A^~gc;Vߛʞ5GiTYg+AN&T$Hܨ\1"E W˂@v?nFKTb4*8[NW4h$V)@'([vl˘`[ěedx!J$^A҂o &G2]G-ɅOs''G]EOAC/g^?}~V䋅+, `;($qRHh_eB MGU;/?4kSn[۶#Ny&.E.O|.bv:0'/M=л%\W_?7"V+llӪ67_?J؞^{~` IH<˷v_w*X@=  ws: g4{vH2!=Zܱ(@> eyBeΠ_6zIUMe_Fˇօ$U2JտDP+9`ݔy{džD9Jkۃ_v`z6K3ȓ.=Z5o" έ*U^_Z'6&c`P6_כa.&OtDSFT\F|O>_~۰a; ]35ݴWf|#IOUb+Jdw]UF&IB|nVY ᰈOCn?Zv#ϛ6 W?6ϓvl@ҸyաhDJ>ž&=0} ]*7]T>-tdrLp1Aޛ`;Xd63ё"e1c ar/ e)|˝6\^0 kf,9Z iʾD=4VWvcurnӃE1s'i8r#V+9!<5;<0Sy"?F6Zlh{ o{;edסp.5.aΜt7{ԓ¸2 KA7(Rs^ 3CNQuS0q.7W]À@Ơ%l`xi{< `/@60ܕ75TuNm9[Z=">,S/{U -0HW3!1R8ѱ{MăQ.nueOȡUE?x˴b[To8I-z#2"j0]-o6^kFwK)(@?z>j %7#]{yɱ9qnxAD:=C]1$\ 0$Yn5iUO|bڹjc}ȗ8 xAҀb|X 2n/nD{gTk#QM8-rTqbىw2MƄ2rW^[82dW4f"8%9dGV1VWEB]i 8tpulƺq/)%$L!>h?77*M.בMp+ 0WUV"Llep 8JSvOD<܆Z, 9oG<*]AE!ΐ|OLq."nv_7B.5Wmλ™$ʌL^+}sF*Ekܒ&yC) 8VnNގ ߥgav(6xG khК(4j#vDٔɋ@RmsDC>g>/~1jxE'\dBӺ h j;|L.yPHh,3 &ى ԴU{iAKzn ؃1QW2$b/ˬRy~0mAW<Di͟` C,}JkQ8˨(05nŐ17Qg)I">ፇ#r]fN_ u9/酄26q'݉)ddϧt09e (4TY4LǮ5slKrP}aLwN獧I7c3ݦIbOR!󚛺al(e1j)} mml1CވwoѩfMݤli.x}#@^M6n7RUԂjiCsLsR`'{tzCnG>wߕzꗲ (+)fxVC=(EM;TUYӣpNd76 m/1 YkB{Y #@hJk4Ial,asV{{= ҩ% v1Y= - "/DWeًh=vՆ)x7+rg Þkq i'%nw{ZH$EJ$=efa[vnA|x Q1$3>SV\V#$^Њ=80Su80 <5/C59M895@,nONtٵDzLK)5Em)O=:1a+>f̬/0Z];VBFvfa"֡dFc$s3bى1J L[0~A7K.ْB5U=Lg8{|{zrV`{d͍٪H2_v-7̹Bgk Q <~pF@)yP `Bc4='d;eꮪ|qU/~˯(1b|3Ɔi5{hSh!1 "B\Yp[)1R)[jbǍCA F5W~1`9]Kt9[B +3N#.ß: LE#5<1GuM6l=m8@J/$;UGE q.Y`#GsOso3x c9ѽkmm/MR^NBCns,,Gn`e }̌&>qdԔ,50/< xFn騮HbrSe\!j*UH 4žj. >chST=Z9בF} ƕY%NDO[v{{HOQMcW;U1F>'^ftAK.3#uG+T1/ڟ"omSyZ~'d|%[ɰό[?id(~1BujM1yB4jfN;M/nHObgx%-3z}B?~$x(S`5xvg[9$0/j$ڷՌ V"+ŇE;U]#4[e-(`m0YI7R2l вŷ +h ׹\qVt;*}(&3ti`yCB;9AHEE/_a0TfqtZ`I  oh1E ȦKa(f*Z oa+No݅Af'Z$v WP۰}E|%`z"yޗ쥎, ;l\`" H6GZK3z5,$K% -٩z93mWgܖ1H3:-}/6؀/hnͦÜ7ha;B+s+3=tt$#Q㨼k|q6Q|U3Ze\#+ImQFe? E/y&'Sfۡp!zaXIRg6eXx(z9f<7zm;"dD9B-Ō-Zed 88\_ge^]u:> cq0ˆ%@Ί3ᗗoLa^3cZ/AKj&9dž$\/Xs1F '$61C),;IP1iL${Gq}Chq6+:ˣ^pRˊĴ$@2_z)*J # * j:C,%/D|n uSua&;I<ݜmQs}׃u75E>qI13U꥟Fa4Uf =nl>/n].vJJZ 6Mx5j`q"I߿rȫE ?wՠ`Y4q=00 GI $t",jЌ!6tΫ3QAc`92- -$|[@)w>m^pͰ*c%GYj5(M\ŃK xDXڢhp&Gc1umje`zS Xfn$v㓛797GO\Y+BPXC3:_ y1@hvһ&=sqzsG`s}']Հf|dbu۰tp62ߺBABR⹽qo 2M3qs)s# kw=@ .kWӱ,lSH03n fƛr:h&_)qY2UJQO4Ϩ6v a 64f ߍKY|+>:v  2r{ք&O0vsLOEڟOcHFR17MG /D%7"=Wk\@Ɨ)ͻrR Z:>d0JtA@7˾;R|N2Q z+@-5 V?&0LaZzA4~Bn=iU+!Gv/)ϴ^}XQdR Bih`@_F&#a%qK~ ȋ͚3)Q>'ҼN$BCc5@wN\UWoeB9DTvݍ@G6°"M߹?IF Ҩ*OK66bH(LM5r@uLk*~N lex ݡ{>8;F(nh灉d[sBR}v(ʦ\&V,$ y0ʪD|ʯJOSܒy:tf0r/`@hzE3j 2z5Au øӗvs #ezN8GZ(۩aiF-bDV_fv?'DYHky3rDi8cJJ㗂v;Լ~(P+Gl# (`g'DL!4/#D>&jwѵW$7A RAiAIxU$*)=vjI{ +JC1 ?SI;oۅAT[SO=DYXT0(iJEY&US͆G! [nw:eEei7X$`l=GpJ`ܿ[qߟP6B)y~*2&Q:o{W$ho.ʲBKr6_|2:zɼtEf h4SK2(A,$0*m޺_]ʝ 2R,B  :شZA5~vPkW-ss:kC-6ΰhƞd3V4r$`#uz{Wp+MZ )hȧ6i-2\) $-O,W}=JФFު+V<1q?=9ItPա8 "Vll,;T [WKPeQ25\m1M}fO(g-]y3ҔkǘՀn+Lbv`+q_Ib9~LaHnd~,;-^@CwiujwA}=oߔm!''ti<N~W}[դfUYî( Gf ^6$WV~,'zˊ8ݯo#gЎn5v-sYCļޣr#Vbb(gܾUIw1RfrߚHpf>XPm6C<8SbC>L='2oIlp1Mmj|XČ s6ff\?4M[]y&0gfk.Eyq%0^}㴶  u?f_)~%sU C=pܦ %`I`,M* K,qO#QxW+""YSѧdM{ޔg5bX*kE,Il#EiO2ZׂbۘoQB RG#$ZR{)'\XىiC j{)s.qoP9?Xi &2QHHV)uh> Qhڠ7[#JەE8e?BKA~&ʁ֏Zհd 43yAqV"Am5@IDATvI~a*?::Wn75/B0 aS`q$]pmaN8cv :z>a!yigt _žЃfrfq/ @99pEфN Gy=^f>}"j;mG+32cC tɭ!P6STE?iUbHw<'0 gƎ HjD,Vo5^ xV<e 4[KC/@~5)'b4 "aĻ{N~G9#n `>y9uV ԊB\ɉ`z2jdE6ZRaj1AR i8rà3X׈ 1:aAbq X2CSRhؘI+ld(zCQD.r  @g?whC/iRi ۷0 H}f ^$$SEsnFm1A ~'%BѧyadP6\ м :*!?Eͩ:jcA"N%P7XOÛ{8 жu^=qJV߮7|΂h&E⪹ΓH4J=*A NRE'B|E]69GPoc,ws%%I%nL᫞ʣ ] YXtS]ɳ( Jwлm;J<Aa.jI sߏHwԥx(7c`. aknh|> ¢ ؀Ӝ-ich֝뗊0Jt^hSfFI<9O-bĴ]AQxПփ@#a0#e2~7X H"߂0A{OdXrg!@9>Z`Vd 3!}}#ncA`{Hepsš#c}NIx9=1FG~\1/zh gyK X@PV&T@.C+VcAb|e5tWxLg6Bm5b&a7бy#G.G=nً>){{iЮ;RԾ6m!kAҔ#D[t"dؖ 谎z(`G)(3y>y@ś%< %1.HyUuFLGSr$U]۩.jWTze#T$ 1hhY8암 Ɔ"i5ӂȈcaEISY6x+:d\NɬΨ|OQ!t' V F\KkmC'2,WI>d8x.EFek!=hW~} VNOɝ~_ x*jPκjQu/s+h+A(^P4wn֐# apg*BzC=kxx (=il6N"W6'N<5LMhhTsa1I 7ǐBb|f&"-i- T8 h1 ?0 2i1>|ؕ^H7(1[e,#O(mA@32LM~{$ 9e*B7/qL/CxrJ[;.16nc7_BUk9pb=,21캭߿_Rr2:S]抏^q]"@)a@COYtϻ}h=}z!JimD54(C+B̢81j4%S1{ȆIC|w#j0>u DxfOsրpRw 0<:JmBgg`u~6ydQ^,5mZ|>οMt^F imZCBK_~/v=Lh3fq땎E<9C'R>2%9 %"9{¿(Ԩ¸\ y2ȷ? J"&U>x?ko<_MQg~IHfx)u͘c~lCg U+ q6gf3-bW>(z&7a_wiA Q䊾qy6 }mٝa'+En\$kW$k%E i)u>k:TlVFL_3dʲ4bTB#ZDCJ0匒,N_|Rj՛(wH b< ]8kTĒ)yli@ւ')bdD=,fV/CZ%Fm "W&0IwK/Վ7Th.S$ms;P!=A̽snCL_KN#- ` ]ۅGϞȈ gs{5:mj4L喜+x^(O\0jV>X M_"lXj!ZսT&K(BORa=,ꍐInZjxX 0C.ZqX(:W#Gi?/xsf΀[ʼ s\#qAroxQ(?I[[OW/?jz񭯩PJ~6#LfC~v2tnLh!h!em3yDFgMa ˑD!zD*}JQx &*,.Ƥ>RwTMb(7?$ -  HÔ{U2"VF8S>*Jw6Lw<_sG>WwnuN-:A6rشVWP hy 'fhZ2RѺrh%% MWr0QQH}&~8M(0IgrI+b.'iLp!6RMKwTQ8VA|rQ#UYAX*@/L~IfH X0[PI_C,lJA%rrj6|>7窕9M30T1Z2~(ӝ4(c f8œT,G0,[8Lfm$|^4k`UP>͋ߐLfJϑO9- G:~ɱ W<W͜wD7ckY0|OHWJ ^qWHַ!Y\Htsr`"P۬I팃# bNl|b^<@E,lG\ w#84@JMLsSJ8bŲȋc0. 1c!Cavbؽ ̑|u%5ᡤSZ3+vvƎI5e1wGME+yrs{@m_ca\.(iԐ92V OUC55%i5ٲaE"Q0tWBiSr ʜ$2Y S 8E200KF2Kp[^LSt-=<¹mU'ʼn 1 E1jLlD6brҰFjl| .guBx>}~0vtJA7P %66IǴbĂ>ZL2 a$o3ppDmX)jp_OX^x.*9&t=XeNH57Pմ"N驚lkHP+Cuc20P2|{*(C}]]T[)cΛ bGϳnD_r[ =91e:I0*wKY7m3Em^_ 'Ldԧ!7΍tO$ʂt9o߿1YiA#͌~`LCG&ivvy5Rog |m.p9$m>` |:?󻌔ߖXi7e/$#*ln܆#ISJQ$8VPz # o5$Nz6 lSGL9M89v3 x ڒbT<X@pr(o2~l+ J&^x_U%<7mz<*5OH?&DM(XpUV"(?vWt"h6 &~mB{x˾&ol Z@ 3#iv_TW)2iMyCvW|WP{X%-o.\>_2:t(Ǘ'< G5"Mg !mRN( E [z!,DeY{|W>ڔwX@N^ g=ѽ#LY{ҭuz^LH*)~4u/E=GvRWItj L ՍY7SwV@,dߞxzX'0M;5~j>zwz6m_B{Si :RCa.G1}gYHu?}~8?HzUQWƙHp@&6) rOMk(r]6J`fcaXv4N[PL8w|-bwC৮_fX ] 5[=\SqA4-E U_9-QW%W]vƇF~嫤_k}}9sM_I{ozeGB@cpdow+!ߕICr=طK߀VVx{!7ʚ{, T3luM'$RHUZ'n%@ |F2Ȉ\)cQ2&bFSS1?skx]cBjGrn ?xXzf` C+{-$;=˅dwpDr_3 tQ1 ˶\pg55 3,E#ZP⫚]uwjNѳ:'<]:))逖6E $ YcKdž(/w OsgUV_SrF y=.X)⇔vFؔ+ˀ[GV`m ]T f=pr5[# 1An ~ڙCNN G›| |<ܟE<'fO2&Ѡd`j&dScH7>x8EF 5ǀ$hGuri޶&5 Am"?P8.h&eQE}hk3P!ە}#X8p H^ʴH_zȭCy4!3Y.ff,SY~3)>t;54qz52T3 !`p@Ptv <ţx9m<_ԜK+5*19.|('`q,cM@OR3K4vI=8n$I>Ã@\EFwcƣt<)Ïe9D U@xDmd!ᤒr7H#ﰯaWoO?)5ˍQ`hO(} 4z?jjE~naoO5y(#2wh_}.6ܿ _96pT &s49]2*F_V]Am:~rէh~*aU(Mt/C{cQ> 'C@PŃ!zyGQ^+-h5tzV'Q'9AjGMYt 2`M@d.}n |l ]s1Pܺ ,C+Y4WP\)B-4F(^įO&Rߗ#[z )i.L G%HIӬtMtGZ4(.9xOXvJ\.bz>*ۄ-.Ux"ﴩ?[~bAS Ҙ2.c+*bdִǸqw!?f]16W"({fw#K_ D I?% Co23G5f(a;6p]oWq $pQ;3vQ) T×񅁷0<4Bd``%? , 9p  *Wi-jf\Yy 5k}^#4[A`JL 󬘏#ne [H ShnF^^2N'i9oVj`^5|U(y؎@O.-]Bad]_yF>h:oͤi .|h]B$ ŅuBqJֲ)Kx}vi;[ٖLt5Ks S|i+%^MG)l;ٳʿbZS0S &J5,扸" l 3'nCʘ}1}7AcglgS r.1HьA&=<>Tu[$w:zڗJ!J<>+(vb9JRW IpShr~O|idWR-~h<i1yHq k:V܇XBm<`(^:W$= aK=Ha8%E,@~=, 7e+A?95Q( tZ lDeT@߃1QRfk<{OB;`ܭdZhǘ~mLoj)۞Z R Ԭx%r+OAfeb"C&R)NbiQ+غ} ?U?_R2 &nVU1%+D@q*#Ӭa:-&-]nG7ISn Z%զ*cLuQ]bg[N?6nd.d2Ai9X+V%ntEt:g1.McNkƝ' J<λ+=rSSPAOVA%-s|7 %.M4H}G 6:4˳W(!e0H'my Eztp5mX'Du؁bQT&#^>_ۿᙚL`ecuK9D5"m"S @Z\[F f:/.΄¨S3=~:,n+,Y;SL9ZT 5K˓I;?@g"5Nt' PEQRch o: <V ЦuEdc|Pv4#|JHL@H Y)!TucT,!-\<M =ΰú#Dӌ"y e2p WBq'@:B.w~&*H&Y '|8Oa`z(5 }DF'7U'%Veߚ`HpҸ|+ލS*8V2 icI|*R_/p11tKԼ@1TU2Q;@I2O)Z7]LW;n$2UEN&2֤UTU}UB\zИc t6 M50՝QE7vqm'GXLzrsĸRi=N㣐Iw@H0!r /$㺯޴/Y< [SG[Q2tkpS4 P2&5P'B+[ tS~g4hҥJɭ^P2ngU< S/ۊ!}P2|?#ͤ7K8n/zU(0X>F"J^6)abE,[Kͷ c"YZ}HY`'yq9?rbk)Os<j`L/SkIeĚEHVIed6w$\ehzs*蜱%AuFgTQyd\j:%ηLGO.q0'#{H⠈.ڟsGf7$@pB9έP8Y TCV=A˅9)TfwBzqyY-ERw83~9NԅFAeL1) `)t0/DF/\P!2Uxv*BMO1I2I^r7퓣StˤbSBhPC7pc}Zoѩs^UdՖF,eeP"A{1@vJ/"Zd_T7J z5na@͆t8.J^beteE \匠blXtii<^X_iUkB7 /-0!/n;;=bF*b޴40sen)S] \s3TjSkadLvJMóM葬Za#:AyC`ˢ6xY&GND<659~1$$D7WHÞjnL;k o*Ѡl<" iTh~kHe6.d&|h|sw1Ty!A;WYU,B!m&v%6 ,k.&\p liXqp@HJ6ylɷ9&`  tU 衸5eG0پCip&q*Q+5 LAllSO~f,ag˧=]oj醨OB&|dnhvPʝi#4TiD VA|{Cޜ8_rEKH?)m\"iib.<_u܋?[?RFqvlS(;▎9-@^@?@$}g6ܼ}߭m4!k@$^; 2bZxS~,|y>Q@2nlmmln٤341y.R(pFY.6Zjw٘~sي%*VZ c۹vP8r*%({tʔclm_v$ ,;!ZvZԕyjFN/][ V`Nث  [5ܵʓgVD*hG>KDT؆sMy,4練%sF@`dLgt."~6 8AC'koP'Xܗ wMtjF羯&( vWM;Di_b~%ZL)y`j"HTFSd(L.<~sˋ抐MurZI])h8SQF&uTjL$b:xtUtԆ9)RZ `Y-A^ނ7CL,uT$3"p3Ff|Um`#5~lNw%(_X~jak{4(-^xgإ_^qͻLNYs^m_/ʆiI&ns&E XcOBXH0{XՈa  G=\%QJ/ t/8mg?G3cR3-?HO" K^z/zcnc0Hܧq܋TA BHނm IbJsTv)>C=uf~2]^Ǡm9|\_, eՠ44@*/[Q5 g)M;r,n:bU18+qM;BFIQxÏ͑-USACc0W?逺2)SdvY7J40K:[_rTƹo9vfa[tT߾)m)_/m684#u8\qT{p1>q6o-JYO/^o9j#f׫e ߾ֆZin_)%hFE"]+dɑnVѶ %&fl`adAF'~if䘻ᠫ(ыc1VNO D܋F=dCs1o_T׿BK4ε~h ϣۋdD(nnj͈ð(zGL͆{[>lq+4bC5fLWvtld|CG$oa1۫?yϗjذ1@kQ,FI1S@:i"0QzZ.!%#904Aբl/4߳#8]HYZ c( |ApD2g=?K^ZӮ K90qxU gmv QapaJtl b0E.[T۸iX#EQv+{Ia;D;6W*c_#6\ TncU+z>Z:QēX3#pbzla='(""X{Ěp?';8;$BYv =ө@OӾ6g ?%KwlM0*R/,/;T\=EZ8$iN! q(&#Qb]j)Nv>MS1AVۣa;zD`NP9="!EL?驓IgTm7@_PB_jnUOt)b6܌ЎGV36!e7 DCb4 $ulfpO\Xrɫ6eb.{QL%2T%YJx48[?]޼OP;uW=jN=h{xKJ]uN*C]U)_q.KFLJE1Rx8}ScKΠ[XR4'lF3 [|j6)Iz[p)qE.B@|ƒA QOh3eC5asښMۥe\DC" 鎥4 Iͣvac <]78{EBkjE8.`(ha.X+QIkOQuk\p#2-~ _Ù/hϣV|W0-1:+OrnBz=@Л&G٫B4{‘P78AnLJud ~ hI :i߁?T&P!e"dM:`KdoȅKGb/2a_~ %,M1aPv=+-fo-\}; +u#jF5 K@PkjT뿩fމB\h6gِwpRL̳TV:r Kwm[s4¸[MX=b};_i?`^ B{J݆\T )ǫÂɮw-ع@2ĘDKI$ϏPFFL.IH5mo6+ "j9nohߢ[q&F=.ڥe(kck7֜fGJ%*sGͽ@i8<ڦjQ+sai·U-a-lG= )c lh!Q2>,5H76+1Ì|4SV "/.f3Bj]; e>|-,QlXOނvXu.CQLA)4}h-> ᾿d2gk`u#lM涁49gUb3:xtCX9]ۥosJg:,@h.$&e/%mw6'~6V<'Pl@^Vmy%kX$EVdѕ6F ✟s$XGXH,Jϻ0O V&&7iv<9T X*h9^~5[>G2ַÕau99a8(r3,Z&bv bP;q*s]VhFU3+.,"sU(2XRG`_>3)bra,gAxYi,.'G<_?߸tc`N4TxarZd~#1[@2Z .ƻv$-Td3x-"u# fY4aO Sh,?4_WJ#W2sTqn#ΆtWլu$\T,?w$иVg`1'!(lք;K(8jhcI,# #$ncEkTpms`泭Ld y(NÜu0 \dD\q3U`pe\S"#Y1T|:Mő w<@4 Y 6̅| XD#eP;(w=Էrlߌux.-@t w{~,ljVu|e_ulgKzytOZ]_Zb dѮ@u1fWW2SY IS7"5a_X& VMkmb3Scy{E$C,q"E3C wm_VoMWv-g=5`-Fym9٩[VƝVo=p/!u!L2Bj%*# 5B0 4PY?Ϟg`2;C}}xMG2ǹBIF fyE)9u@vd1(:E?!D}u#ftn2ު5]Bv>Z*KE߈*^k~_P5e#Bjn}MckHjIe />wt4+YEfIݐ͗n6,q*X`(ZtK2<;;&"!1U7c#^@= _n3dPu@@>j_p_TԨ:X{(*v& hoO7<:H 5;7ю9*U}w\+d ĪPiQ g6gˑ= 9+M/XݦW| ; K0,sA|Yo,c,6.d" ap.ao>odH;cc}xaD]63{<+az|' 7\MSCd<Δ1k [Pug6Jjį WhH CbtQ2?9R6=/EV̰֚/0ļ[{\ HVߺ* U>ƨ؄i.S0&}!kwي֝' ?t9-UR!gsF5O SAw(\d˓ҖK2njFgT`.)%568ǡ?xWcO\қ'H(}^eSHUFV'7ji~zJJo`S! uG2skЈ.ꍟ%{qG$nmSj*b΂6\1Dү mCڞUsYMogtݟ%FV<>f'qAsHD T P!L(A uK8i\Z \~'ʽ+4Vi]Ag徖xÓ3OB; RvHyg=ưcv13R bCGxږes7{" !e1- S9M? УX A!e1MkZ l8<`$X7R6eC]JUw\=uLu9p:%I RtNS =74*7&!Hq;*| ߜQ"FOcI}S*օP !s{5zޑoݧ(־ӂ_CĤ=M`=~ QQj3_+~{L ny_qFgX%j)A-RmAc =$' <}7\jj/uUԘ3p#Ly1~RK%~AQbsjWR,uUǷT͢]ZDV5(jmٞU{ u9.(%a@̉akNzPd̙\Ovr&|G8 K5_enE1fq|Ù z# 7,Viݑvro:Yd9Kg-N I zp)0Pt9-{bD̟F3m"BumWi(Ss|ĐM`q3y`1<Qb2qQCImzQ Rlz[ʫ6F!oZL;2ȝ;Dީ6-/A"iDRVZ⵵s/g'2 JE#CDv.Cxy {WF&c^Rƅ!2rݳ&`.2`E"pcꚾ [` rTIA@ ಫ0؍sArs@X`\ u`pG@J^SUMa,Nav3=+}1Uΰ6G7IdK{A@p6ⷌ-TmغWY=!p !\=,f;Nʱh27ifR 譗PضGRpژ]N?*6P~y G@4/;;kn#RK0`CHٰAFDHh<]"/e-l?h7&q)iѩDѮƪΊ5q;~C]4F9 #,leQ 3ӱ/$J,a\tA nM6C ^}m75.qBJ*Dќ:ٴx_͂%y]P G3׀j뜺ihCĽ]>ztq֓ZP݇_3C},tB>ÀxL nd`vhqAL1_0#[u:@y&Vk$˖d#1Eb,\Q3[n{Ⴆ$j `&]DҺ+d;jzѺ1bwaD lEr9gi*$\Wdl1lh~omKry?+[Y`m]RTZ+ŒH30UuRclʚD@v4o+a6D?pai3sKAFKx5ܖ'3`om^]MS4Iu n`A_4a})[=sBvsFc7'O޽nש+"x$@EE>4]{X\ JPrY=^-uCsUҔ]V'K  Nlv ٘& K'XA& %;q%2{L(.̮5 cnާE8C_.m<^ϵd;wdDwG9 ewl#a]Q44$7t#85,z9BmY\Q˟Y |Nϼ|t5F B3@{L(*&[ Op?9'<.5&OZL"qt?YvpKܔi*SW7 L6"Zv7I16CnU Hs˨68a3]Q9c?\+*E%36N4S8|~B(d/u Erda- XzU};+rkfOVJ[*m 3`I:p*ZWhus]*;+'0]ac#O~[/k Pbيf< l&O*U1U}5rbr@\$e`+H6[-i xB߉x$M>8p)'|/%Pv~a=lWOtYJHTX{)2A~c;md+"҃ҝ^L1(3XR#ݪut }tT2ȗqD:„a\%@D_$ D7g aN11U ^ vWOPt5v=rA `h X: H{Saq2Ac08(^tv6]m(fe,aٶmM u5 ň#պR9e:MdE_&†EP!y?~<9a<- CQ-mȁΆ`HPj>X6F*kpebZ"}onoήinC0z?oy~*_X6 ^-&ןV ]?lArzD3gSxyu]?Ey^_L/gzlgzʔ< *zmC6Jˆs"FHS1'8U iӆ*DDcfl8nP]|\d?l~ L3HApV?-׼I)zQE{vPr!)&pT9b֛&wѷ#N.jHZFRSi: I<d#n@P$0玅cߚ(0Y,ȑUi*,K4#♆=fظkݶ8)4pW?[acB5ӽ3:%M2kIYG ihAy \VD~GAgY ["z(5IfS/ _ِGw,sn۽LNl-R *_\5U"lkPAShGS *;"SXB: ~ʝ[7I 9 mSqti[>]*̖x,D;.`+߸!iy0ԥ+l%ރHK̖ V?#ܐM:f W;|)ؒ#KO Nzvv6}0eø72 @$1Bh0l#"m: {̞ܥb<7CGz0)l|'LOvv1K;(Fc _/3::ֿ;<5V6 *`PPOsL C@z@nxH)AOO.~HsoHprsΐ>5"u F2ʇb3^h8C\[B8*lOTRԶLηH 0qz3EU1V@T _2Rr}8Z?e5QTOc2FdseռRcRX-}%{o{$Q?XE&oāIăˤ *H'5j4KlZߙc ܲ j5u,뿾Ty'v>^t! '1*I 3gv ôEFVM#)y.]ﱑ.RX\4>$HKe@j#@AdJi;UKїpeE瘓eh-9PIC7 \ Q4Ӆ ~=HR|A R!F$wi5ѶuYt>,axYrFFq%!VC)f>)e;;7 W9)\)}#TP9gk"mr+P}')ih )^wh q=_Eu\^XkNF\x(n4,S&Դο,lݝY|ThX܊V$W)>,-BjJkZ Wߟ#-[ UNX@WizUiLBЮ.':eŔЕК+U^JG'=k[metm tC'tIշ9'[9!5VMhVpȦ FB JCbɻ4V̛153udc(>bϰ*qP҇e3#;j*FK6æ@eO?g ˱)HMNN6D!1![qg"KF9 | li[G=]rJifEvFyg>\OP؎ܢK]tIȿ:eD3de$Y[z1Rg.s|M}7ZԭTi{dXۍsn (XmQ\iP"2B|w<< (re3b=ʴzpPN}{(d43!+,}zaMEN %,?,xUKh=)&ZМ%%+k,`]۴kx3[W%:Xxa/>; 0 ?L$MGwn4@T'qa`>L``KT ٪Mz\H w-[ad{*Cc1hOzH`IKDYM9730.pF(K71žs%`h^#_:~K$(֯lzƂDJ@DK,FOdC*ޭ}72r ҧ^j= ep%%hX9ԛ|)aTF觨U4AEGoc~Whv}rRHT"g։892TDNy*2*P $ľ |6_Wb7Ĥш*RH@2Alc4DWsFˡKCp.p9)c|aR٭S?{F'Vyb2 s&j̻ljG -OQsh՛ĨeTrQFYf<3pl**”S2NXgB[jLF{fl915쁃S3C7jRaK9dÄ@4v SLJjs 6q 1nG2%@?@ޞqHP: &Is}A4bf1]!Z"$arz9=zqtY_-&݂,뢌GmEU?͐H7 cJGA@VQ 1p nE>2RJo2_Y}# @3c@5Бhcƫ=kЙ%M[<~kIc(f6 4n3sRC.hf4i+ Nh'Ɩߺ]N RE^bȢ(Q}R hָDr0kC;'m uthjnP+++1` 2*҇!Qq'g `@*iX7 8|O~iV9ZskZhÀ piळ RD)9Vu$@_U-aS\Npk-'`Y2q;RR@ .}A5s&$_}VxGG/u6fpUSWp 9vh_ǥOmOE:'Ll  ~iP\rRUp7)&szw漠0Z6'_oX7̇+; P;%'(KXe(02Fo~tAE8e zb9ڐ5ǣ%Xt.ԉ(tOfulW4S.:3řQ%XԜAÏ"U#ӳщL)ŋB"-vCo\*_^ئw4v wdgh"=rzfg:I u h cv(OE$M,c Lb.c_Pn21/M%3鄤Mexox"+ٍQS*B膒RniD^>F l':F\1k z[W7;ϝyplS%bv9ԹAzoj%BRy#r$7&Tq߳my%V 1V4ZXhR ];D6ʮmxLO` 1h+-E3OPkNÑ=c+n~-*vdM) J/98`0>HIyKDy0-FWr ::&0pKjV~4%sUTd'P$6>r1'S Q 2 o&F q/w!-aޓԥy ,4̷!,{ޞ%a/dKflpyڹ!Y_^A[s*Un<2\x4Q%j'^ #e5TV q-z'e壛oCnuЪX1l{Lil$N %RUtcR6am1=ѣ"6J|ÞFAϼx)92;Cz<+BEtGvny2-MIsMԔi.]k.i'Jk5D*l Gq f;KNx󐌍mKeWZsϬ" {Y,!ѐ `xQedqsh]OŬhć5)B`Cl'ҽ/1mR艮,eSpx4ث1׾'ȸL^K 82 nmd҂M!rl\mS*CIPEk[IWyu G~ѯoDOT'$1&7R=)uAәBwt=ߡc fAUͰ2slyYr&$IL]*ce+z@8 Jb ί Cgz1W!De5Q 276BxzцqjЀpT*$s`Q(]r&GY4"Q HEug=`"n|ahۿKg&u*abk .E9R\!$c"+ȿ,RbJwyJw/JE'mpT0o) .s>+RzR"¸c=?\ JMDͺD$9!ya`ZA[ z+hh˺S#K}iˇzr\̳)J揂6hJH<u_5P˫Q_eiBŴD'  .z1LS뱥ti%:g $ĐW>6c Xh[WĸY Xo`iQىhn-$pa;Z<6[b)qW]$LgYRbղۭoG^QO0`PT&١KKѓa@#Hgf?_Fؐlͧ-3(4aŗqiszG6k˾0[ cՉxZ K5OiJJX&.@IDAT:H(>C~Hk:Z~%݊eFA]\Iqgj۾\S?'/0jmi†I.w3U ]_GPY Y)j,Nu]ێY*Zc !݃cME E5]V`(RDy9;K3|/]Ht~Jc-T؝99~azjA?GA"lMR<(/co7뮆$'S/$c6w #U_* Ig" F{mK#PȐdZlMw1 K]~ʯPsvQֽc"ɬl;E]GfXwr39<͢&!H2z}r<$&juձ@K6)fV c,;(h Q0DU,>F3Zk6x -+e_1fGTmSsE)Uf|I6NSEw9}TZvaZkwǀjnKWױjEubr![sG-9*8؁ 'Ύ5a/=,+a7_q~ ޭ1x$yS$yZJRA63Q#"J \ |x6#5瘐tZY'fq~̹3Χ :ԭ3=;,}CRQyY #GN4CK %*bx?mջQ)lqOgll0ᬦp_{: ?eu&? ܸ7ƍ3a[N[lඛ<"5LPt`4qSoRIYcf=+|c< uo-isN&ǔ*)5%dňj/\  4t{ŭE_KK" 'gߛQ@+ Å5&mނ"5z6Y"'PRȒ5gن-?XRM?pE fdN|ev!o=ٛ$꓇΂`+"N+χq!1zMۭL 23 RbEJzɪbw+-q:\^\zd94+|[%\)! |wKb Ѽwq(S'!j4 (pt`}3M9v ya}fGyBt>Kf |3b'gM-́%KSR!ݡLkAЋDg%ۉ{vaˏwzcn2kOwRAX9jdny{߿5#@A땉JFk0k-əLD#qPBLgo/N%eN{:;*[;%>R# iխo7V8mǵŝGrtkع DmQ=DrMo,?).BQN‘fW kSbj?rsl@*5(#ǒ6<;d}L\iUZһH'͙Q(1" n hcnd$,Y3-N-5; nF]ol?3FD)tS ,aHiL< W9Iu|MRc &&+sK ha3}gnL/_// _F`01Sc1DIŢc$uªaz5'RLh"R/=2j_Am<_/XՇR*IF;χ3˺r)/3[$ e3oƕ,y9|Ee=ظ@]V *I - !dM|Ȟyc=\FMM{H{ݹǼQt‹@~0Hi\6rp{ vP߰sq\hbAUoAU<l&Qy9BH|9RqMCAF+dsto:!7>noDK}x%Zu{Ģ|Acap˷ yG[^m5v;- SNGg4: (M6'S-17ɉoOOC~mGp̥ pX-)38x= o%Bq"|kE1`S#X`ijZ7$-Kψaa &a\ME$ACQHHI3 uMq]*NGfMtشR%2`n덲r|, qB~`2NzCVfkA6N7UБYiV_ F TZ!0,odP!(Q9@Yk,b689sUdp] 4Bopu3' &3\ UG,cLd:7&dٽ]$K1prb},Bvx;|vZ:bز1#w%= Wc{)"+S2[P-?8(e: ~iXڊ8Xp>֑sqR8}>iVUZcPN~;ɰcCXQ[5/A<\ܐh0n'd~5{( OM9[S3Ce_7\QS>%Ot˝ÃE[yT}6x9+d TPʜ-G#eFѨaBL1x(<k*Np }mX u1k\݆Uet[ ^(^܉xrT$%Մc ,*\H=$4 ~4KY!,V5q>V#K0:\ rI*!`ښM9rwZ9j)C ɉY_Q븂t5 e`ޛ:Q`M^J7kE*ore4bȁ qvi3+gLw &| TM izps t6rEL5Cthotm\+!NL{L*~L(m82>uҼ I=Ԓ5`fű5x{_B5?/(n>LBHF(B9SΛXŽ=UҦfi/_YpЅpbNAx#%͠|e;G+@TRVMf=>EgX| PB$`Їi8ԬYwyy&CfIܕu/SA0*c"UixNE3Z<K]X`Fa6, ~bL׽luq%?JV7_#iº/IW@rJ)yLIØ~bC”nt׏G%}Q掔h8*a$2hp15ehD(SsLXKb SzaCyBmA+ ̧m"\HNg Ƞ @^P#lOl:qkEj}y}oдǣ],%}8Jz b*iqR߹%+*0P{Ws;PDJW?iRd 40O#/ {f]r/fRI|SkgcEOg:q5aɐ DzH=uo%t;D.0Q 'Ha) ]2N,(iĢ1S[d-K(|T̥Ğ;4fJoeT0l{J^<'<2Ek"$Ҝ^k=zvDoL+l-ӽ NKZBhXÛa@P^QF$V򛟣s+h{8,)) #z0] >uCM .w"\0UzI{"[ k/RԎt g.(G 5?9+9clv4UFT3^Oq+ f:X:2Th}Fg0ؘ1#P_T0غ',3lodž ~e Pq:Qgu( u92jI2JTZpzB-j;,7h!%|ܲe31wcH$ck*Rj@EA\q n!ϹG $U rLEE5veGt8g8EdT }12-^kdGԷSf+Te CؿGaJ:H~pr84Y6y!z) a͡h߸+poA s'!8koTtgI_c~T+[3Fn_ 60V=5b%SX0kD.llŠ4mt*f2:/fF֢, J@zTN-NVLgP`K)J:`y9#o)FY\3Эǵ5CeBbJLTm'ɥQ; ftZ4itm4Ui4O#aI1(b hc?*I?֜ؾM0eYz,#U@~%dxaHf{K!`MYf[)g3rSCV'Cf2#ʫ$3pRP?('_7>!5ՄQwI(<)VQa"W!h͒`@b>%Tbe*|FT=SL| Bb N+vB6tna^&W)Y#Ў棆P(l)f-fMt6ZudX$Q,B$BgAm $x[cb#52~ئxڟpwrgom'Z@x$aX*$TߐGpREc_s-3_7 8"'%f{ͣ2s(@1z s,[ ュةRS8b%#t:ʌ_K_lWd BEw eSe6؊O(,I0D"RUȻ%Βen<]ׯ 'MsP 6u OM-h*;8/[Fƚ%w#dvdj0!;Va y98M||::ӭp,>]dc?SzIfA 4Z}@")fU A=O4#l9h'Dqm/EvED*zLΓbg5P^A~20&PpC1Lf>kD!#$qWEX|Ḝ/ؿ u)%b(_ aM%ҍɕBvY<̧i^t&rXD`]_7&XYҎ+~{6&V%(c\^)zƼbI۶U).'d=Dܱ;5Nm`}M [1}M({`€Ŧ׮21{}W$fU э [Oxc}+:!IX޽tyV4ƷD"e!g" G6A)gNjYPb#$.Ӆ.3Q3F$6ѬH۴Bmz[T &Ԋ@}:M+4PzOB]-΍,֭D̨vxqTu5L;HvLǘ<^0Ron1UgDRĞw6.{&M`-^2rdb0ά %ӕ>”②=> @&JOq35'kכ59^@ i#Oa"T[$+iBV*ixlj5hW",YLx -rMq$"v:.0jLO_[VICg,/,tk8 3,fc5E(]d +5*iBkC2)Zc$8MpT--=&]8n$aOqL<4'[ɣ7^ T/d)H9)9gB egۯCt$}΃ [F(ҡP@sC`~=.b.o'.x9 6|;%|n^: I l r'l ec#IF5Q8Դmmvj`k[(u`?]xʖ)ؿS7(Y}1XwO᧪#,c8٨}QOnwRt@\ P0hXފZY `vq9K%nZj:V3NPl 6Önj7) lJkWrMK -fP.,X;PDZ&s;}D h|D/>oG•"5 B\&fT+&}V&$J2e"S=_gc||"V'!\e_} ޿1tm(8~- e%e ml3LM7NJH J̲xRmijoY$HRn5ĕ#7৅9զ*Ԡئjnn^YB H^9ñ:A(`:gnOIt%ygF/WNȦFLӞ'ڜdO4 \tVXLj];}_N3-xVy5 ֲܑiA "/~1xj@=j<(HH \zm t[8 '0bޓ;=B'"[= -`ũp|2H{@x?);=a׸ }z\Q9nu7b$Eeջᎇ+fP:W2_^M8ЋVZٴXۘȾN p"Z9 DU`Yd(yhE T9CQfl$b-}} ͷ]!J'r t;3Ӝ\RY0ύhzȄ >ye/>BR1,I2W |;^#W,yk Nth#1TP8>>ONHpMs)2 6 1*یXYY M++<˟!@Le8?!מD A5c <1Uk2: )lOLy :=&~tHXI {(u_]JӸ SՏ~MXƒX:i ʋdW`s`(N uV߄>GͱruԼ|repRsh.EslQ#vf"$CxoO9mb#ՙ,:@ ;JC^uDS P)7L„@9cpɨz}J 5Ёˋ٦U}:xS#,u9:5!pgp>*f):RlL')d$a}%ĄZ "@!<\T0Qnf-Y3ok@yJ*8>&_N]4w;d\901B.E},_cWohT! k t]/MSE) 1hq eӫ X0c^PōO159ܪx4VL3Hb8D=O/xĖkW(FS Fh EJ;7-!uaEAc0oʩHf(L}*@PKe!ZMFJ-}TjBx}~qFl e"2]WB I} @ j3>]JvF5@ )A$m\MHUL6>PNb:$D8#E^N+p^#=QƠ_@9hR:(P] 9[gqtn*DL`8}*ct$?ؠ2T/E*o^E-%U[eqa]@頞KEg{ -yOO*`vKtJSÜRCxέ/mzWx ._Ї]}}@;hsL'Ϩ.=8Z0v4,!e{llk˹wz nxf>U JOJbcH"3;V^G\ ښPjHfB=:[ wfL€c2}M}UO/HùmD8Xsư\$ Lݭ]Oy7)K7YwX8} b%*N#(Pi3ެ>Ga]\3th9,` b"8-"66gi,fRp1K8}&7mf@' L ,G:$wQdR0 -ޫR'vՃ .ƙ2Z_kb`IT\p=STNKY;gE (;vxhEJ>6n.OB|c;ۋֶHh r3]K>. 2ճ=kkKҾDrA6hswG'6 9U+M~`jvDhmm\lf5^:/xg&ff863lԪ]hJo׿fM@˸6zwc}u؝oJlcDDjDn;?6חdHֺF3 =( i0#MFk)s糡*CB) hB6^ Ò,$[ia+9gXϡLo;A vyQp 1M[ ̱٘HXgbXӕQ%9x$7<׬lf[/pU$`co/Pl7`{G;V&,PRPHR`X.Rd5"6j3TK!<:m?x@noFq[ xP|aGEJ{3rttVAV[j 3+cpIhŘ9G&Ybr<Ώ sԣLRןuF}=l=[42!1U0 &#:ãΒ7*nga޻֘!MYcXEaR]ޗg{=6bO6nH7yPGt쀨/)mz=N $m7`[SQɴi:ZRHƠA`[03Tbl~O$Ne9Ć:/0-\ye ZQ$h$z}z:;ݘ\ [da3ΎXBDְ.w,ٙͯhS-egnljq>KCJ{\xIN*ׇ͕[{DZ/$0Jx Z{eX|hgXpiY{ ^x P@Gshk{`vUH[|[{,RD(cJ(bx]! /R)`ݼ-%dzuǹGV@N p$J>|!b=@㇐x|I-gHRzjzOC q_A0c¦7n>a:r~ AWԵQǍ*O| ]?u4dR, R?# dk<nb~%׃wEB#{utÔH0ׯ \0%wu*C>87i:VOB`2IÙNGq N[H?4& &AijS(>C nefGd5pԊ{ڜ͛{hwk]羺$%V_Z ^Z&?X9#^3dTr<:0sXzd3%#I_( iOL ^]6-1h x `pszކbhxC(=(}{]U㝔.{}S&α EB ݎs @pb9oKvh&wk6׿y|UYl6̯LɨhV!k 'G3U$ Ƒ$@B~=WAH"ZLB8׍vA f@E UEbҸ0#9.v4rrfŸ,?cZOX#mk5_G]2햾%8186fXߩzP(067CueqGxeZ1?:Kwq|B0S !cR2(h26dS7Z:jlw*_Iqay3춺g| HǗ9hߴLLJ2UXmu~IԄDq?u{o؋ J!9֬AFn QO4rJg`Vljr9nS)1+P-IZxUY5ΣBޚL eanm6:gC18F26 -bJܹOIDW`"0$g-t&gY'a gL/a $Zɓ~P ߹ʄCO2KN3/= a3(^` >`!3 k̙!JEJ*_2q4e-DxZ7ZH9NkR"l7L~Γ]'b.}ؚKE De%Ss !IӸ$xg^qE-BI_#fL e, "$PR:'W 2퍣-O+[2V;^,54`ըq.G!lE|M \=!\#0@A ZiDlwSv:$w/d=Ldsj4tp L~3#:L`}!1zq5R xK2S)әI.+$8?U&? =;hR#4#\Ӟsp*{r%~!+>W8? 5NjQidn4s~|:@IDATV}X(R Gzx)ݵv D2kֶeݮYyp?FK> "F(E0몎CnjWPexkmv3q[MI&ؚ5.D\2NSC9Lc9CLۓ"=VSJ-` yXlhYrӀBR 3aGz@l|}<_j^cKb@/ٗSqL ͇}T9ZFLKj_ʈZSOSD&L=q=dMAx,oPa~9-eRʨA] 8S!Ufn'z܀cBD?‚@/P')%P 2IZÎ̩:21ma׍Lgi{@g+!qm pzZ@Qmit`τ(C) !M\#cQ} Z^?h\nUUS\:w̻S@A*rH]W S*`mX|_dq!i9rwy'C< #ˁ.V]tAQyMCqJѶyh*ׇ812QCHb$-O=% wFƜZ^ 5cz;wzPƨ\v‡ԃ>i , 8=ŪD4u\~&z07'NQ=OڒF:y!OHr:YMyuW䄋 YMGM&1g_IjۏGiݢm+Zhu핝)ʪ= ? ,~"oVBO1'9`z9U0SI_Jt`{_[j ﷤,Z~%-8O" 5.cIѓi +Θ;[ssI0"U7KnGy":+z vweA^"SC">Rs~]=$b1#KK栊)sBjD;JZY5d"h[1gޝ\ݶU(TB:Pb@S#,{[`8lٲu&' ɟbyabWǎkC'UT4빥]zs'5EbgBJJޅ߻[ æRDJ|:\mN_f}rL>D/C [0-ʕeZѯ듔 vIOFn)ÿ! V>Ok##Rȋ1Pfԝ^bVd\WY 82]C/9h?6j|W|(d֪mā';pCShIm4 46pL xgzqi x%h"R&ix^3~#c 1"u&c|28y.[wRMg~O܋Ǎ{8l/G}L82 ?;b,|umβg8hү;ݩ_'Yֈ~ʅ͉9o'/1>̎i=a5" gqcn8# b2m{޾]m{0a{7zs}*)=+ٓ;&Up !~GOu`y:u6㴥7dwfv`7|{Yx;|owo52o]gYdU|-Aol(6g0Exl4qb 6< ;G]s/|",IE }$x,[heY᜝3T``@϶:s4WuBlx OREi e {OP%vvKӭM{X :"#L9A?똚TZȃ&E|@^O6J7fgWJ$ X,cqrx}ٴy*4 jդ5Jx)N^`d>9C ^? bjzsM {G1X ߬u9>b p44:⮍6/B&Q.Q=0SAԥ/-5fgϗ$T8@J*?vƞF,yLMgHd#>zw}?НEwg޾U&j ӺArx6)㣉c $#0.|9i:^0-"N/-Wi|dY{J[n}]} E)|Y&?mjI(Rvxp+>P{ DXB'RP\?1|@Bk!TgY+XRb*H}hxdXgs*rA +% ǯntO ݯ1J  t_$"PTu|s_yb];_:*Z98R2f~$3ʅT< h0#db&Gp5 *E^ `Q:SNSyi9VP RvF}f3{! F15'@7oW( L$tׯ,h}3(ȍ@KUT"mY OVD=q0c:iR 5֎Ȓ? 2ٱ{@XVm)ٕ۫GqT?xL[BrBxk`I!'"q_S& qdY}1)ewDuZQlߞ11.iDtZ47T'VS/wvV蜆}cEZjs+v§>|wGחGTpNMfՐ s=&9ض`wf| `i%ǘ9|h(q2wL!j|؛@܎,f7AMpiU_\ qP`z\ ]8j8J7F.$60nY;m=|\[GOCl,}iW} -e*BGg8ce+ x?i">DU31~ /zx_/[9M1&> E4j~\S7e@3R;  @t@l cLIY,2IM2zc)ݜA3&{;.!XFV&!Oaۜ\E4EN%O${CGc1~ '(ZiC?=demplɬ1NdD=z{cR:,Q`5V퓒ГqƩnJ[OY)S"H[gt5ye&>@4S"tRBS# /3̂ `&?*Qdʢj7jsh0hFC]Ȃc^o}o4jL-)XmhLͰL uN %A3ilH}/4f?Ai5J2#*yM M@#i:#:1Kpum9$A& ]7p,D*M09XC  $7)%%>n)ڎf{G5Vxe$=`u}vƪsyd!,O4Z >-I2w%T`Cc؂'s Ү8˂ctIjK0gtRUMJB- +y`wr=vwkndID8ˏ^ 9Y 0V^(7܆ ;s-+H8)nh-`Q=@* (ܶscs1uݤ_uN+x "1~ i^cHJbUmv~Ta,s q(H7Ƭ7IGeNLB/vҵf\LDQ~lUU?*#G頌 }j:mU#|y&M"<`7Gh2@cO2@ 'W'`Iq:ŽQN yuf/}@Y(VâVm!"fQ=PEFтIԇKzG 0CmðI5j5:tlvJHk Y]|_ + vH`rxTɗ;58ќf -\/Ro#Qp& (D3`m`$ƖC]0ajeMә˝U%F S9ARu%{) @۳rr bG 4ENKc]d E0L/ߛȡ irNú;&⎣T-2wI fgJkĜ >%CU@&ۡ`0@\)Eke؞򩈢4$jeZ=>r`/@s}Dq+ ‚5дf  3b$c"vlw5Jr$e |a V`$՗1\ݘUHК>lvL|F1- )LcNǠQR1'} 58q9 Vvi&hʪ,%0-_,(IdUY&2Ajf ? F*ZɁw+8g0S͚^t+p!ѻ}`[% E/N?LKm(09p XFT̗yI@IdHѤs֮ yfehb_n>u\xc@x&K@| HCBV{U*&6M\} A waҍ=_ =G~l=(\ꓑαZpII>XR3/OEa.LQOp$( %\r,r8$Dag.:¿84rϧs-ݫ1fF p edb: bwE3ECd2&q@XϓD $Od+XS76$I!6?1}:J( i?WLHBD)϶F('3s|Ø"$ұBa3x5^G[l$Jf hR,P㑃Ǥt?.8U+Ieoe^nR ļA aYO1̶4>x.K;lPt`6 hYaͰK!."vʓQ/ˢ;ZyY!)`&ZtsL]WPj3HVBr+9rD%7^ he.s/b_޼0&!0|tTFgHxeH-!p:{$#ia/ uk^ qg6/|i.I9Mz+[KͱjMFUFVΪ2{> ¶g*yrD7p[ 5+Nf-5$f[ w=]*؆F]r65t$n5OKNVQwdiG7}e\ĩ`1ʶIt{iHxn# cpqؚ tݸ+{+xXRz627}nxv$s78 $g#|."!|4u{ċ8%4D5fwPr!lTEr Q))T+ib4LB,VG/Uk3єg~P)?)1^O*B豯 !(5:y}>56Pv#,0=k,hil|EVXk|9(^M/Hmn֓GWw:碗:$J,EUM88|\s>PG]װ,V R@ͩ'=PjF?(0*ֆCh!Í: >iHP=40S=`xG›G]脆%cTt ⾆B9p jE9O%7ZbW9빊8Q :2(Gx)3Ҧ&Z\Vh*#p5MGo/w'* +A\kL_ox}hP9 5s]Io ]W7\:qoFJzrQ"I托 XP1DYa-i!(șL%$a90ۯ)~ Ϙ$Nay+8]}LiB6%?ozd7u(k=k*G!Kv`$,gAc.=zm|CY/39n+7{p|ҖJ 'LΫoY96I;.|.6Ȩ(;E|x ұ~z2*h2߉xi6~ m`@8~3#sv7,;5nlQTWL8m_3Z*$*cK fj& jiJIcxldvQ-@M՗9DWޮ}BG@`|Ĉ^p xOف+G# >z/%S1#(]ՃnTϧ.5Y;!Q{ j'b&)ĩH::fx6c[o&c4u@e“"g'$˜ȓF.EutED3t5cCRK1N|ӻڬ6I;Ady$RKdW(DW-_ߏV̡꤃VB -gзt8qߣ9L5}ߌܶMl';%nsr,!e`9nO?z Ucy{r:cISgx(D2/oTl3v=<\QM_=oK.'eJp͢h}-w"ɤIt(wQݞ5zqSu/_3n7)csnevQkG&8<D.6F1)Vk"$͕1J4,[]%T)nW8@큛Po,#r/g܅z* 3I]Ͷw/msh;4iW%LͥW"(6ն+0. mwnXZkUz*k$:mDq4bxжeo "/(G`M"}9A;Ρ*43G2LN|{U34Z0RW~@sfN*^A{Y!QXˡ-wwNYw{q7H̓*+-}Rɱ &WHb&HT*r;q0ϳ7g$/MQ%Jt& b9o?4P^4zoDt7r= XMw&BĈ;w2 BPm;̰~>0XtYB)$(u ۨJDX?^*є9J 9_t4E'| wA +u ls-+heW>P *ytpDH`Vur8ah n&pف??[ (r0_2OX.n?#P\o^_>QH`vyȒ$A7]=2O#|p[+e23*UMLO ,<$L<0}9f?~%pA8ޱ~x(T.uV%A7yd%FPl֑4HiXw chgi ;(+mLvĪI^L~2CDӘaSQVQv6K9`״VϾ-ڍwjHm)?˄1$%HL}\c/nzD3+7̗|{s{6~eh6 Q܄C\;\(l}u7[sTсʓg swE:Zl4n^7C՟*ڰM/P%~y56 Y^œoϩOO׹mR;ѧ,@?бj&x܈_=(Zs_?^^_/ooDi4oEc2PD}rb6˽$V&-rS>qgk\dP1XFi\]yDBѬ>zgx^ 7L dsRb6{uKܜx`8UoaX" 8Gs<Kۜ@Yi fp0&'XKsv&A0B=2cmF&7vA3j\ˈUx9Ez$cd=gՎR 4߄H%*V!IabR`x#k4G&] \IGe|OD]Us6Vc4.>lf&喦u[_rtMcL?)8zUe^"$QbQlTqHҋ"jF2!XL4 GCi&wlLk_g_V@聄u/ zZ$lRF> ^5W:1x4 1יIW1F P3e5H gRyb>#VQ8,yM>_"'>',QӶ`78zzb*ߜ~ݡ> |I>epLX;:cfj؋2FʥfKBkKEduRUп0Pu[4maou;pu͈FQڹPħ]29ye|xT u|J=,sbfm3#i0A,T6UN]D0gYv)o3tחs}unmDlRļ-gq,R1'R))v &ntmM)E7p+ ۮ\qOzG v hiGp#!a!ЖOPc4k68AO#,:+5Cz%PNEN@WWeT"n 4Et2( 8@FW"P=k,_& =#R3Z^_:WO mn7֒jeBl$4o2%ZDZt`pFA"S 1je{PA.9}Ҧ'N.Ou;F/,VCx5 DL69"pG[y8T6(;Dr9t"\.5fZdQ1(N=lXpCZaуַ"jE!Y!3r`GX@# oak- 2RO+7zCtm{a pꠇ Ytm YK>cb̸)YC<CEH h:xXy~FbtTa|JX1Sh '~o bC@jpdPV|M, >cE58)l*FzjGO%5q? k!A)L-|\UqYm3R|잓%w< FbQ`^(J\zEֲ3D:^ c#mPT;'~??3nTDY[i74 `b'L/;:?AV3Ȩ%ظMd D%RU|[,2q"PD ЙZ%ĞhF/[0سf:&d,QN0UMa!ۤ859)yoVf;X*o,)z,8I&3o[ᴶy ?$ O_Jh}*U|8Fmw 8 oӆ̦=`AIJkBA +TE-1Bz73LƝ"ck oᔂG ]:dKeeCM-)[I2G+v)dlFK^\/r4@$JTfXhn[}}탖Ol5Hf{7w&t=)JQH$Rb0{[z1>(;PJ Z`.!)X!02QJJ.w^n-@IVt7`$ Λ5 l>iѼd'\P bh #aY2gatMyoc>EÑ!`bq3k]-]-|&׳2)? bpqr9&Q _eȥ-wOrNRO 6]䎳%Դa ޥ6D.~bYm?/CKրz,LhUugu!/*k֫oïQ9 W{Mq8PRm-u'w#v^v]EȠ_[`S1yxf%6 2*`y'bFK}rWIAyv'@e6{gcMۄs)3Ϟ)L 2͖&!-#ԉЅR:~+P8iU+LЂ_=4I󎭜YCR4!%7Nv3}~P˦Mi9YdO7kf$1@$L3TrZjY}jŠJdLkz"?FcA)x Cϓ#JIxcKZ}Ika L/.4P:ғWM8>mRt(#H'}@e0DZh BlFVoUyKZ^oCyxQА!X%)r2? o|4۾Tr3gIشZ"BL.Sp13CQ>z4֒ ɿ62Oj`e+]JAa& S Y@FEEn]^d!H",t}>ݧ<1IojEz%Cߏ;b^!߿u{h\\nNLCFhAi_ӫ=D@7$B*(=Ǻ.W=1;~fZfk)N9VX!Z*y߅-ǹLD@$ۿB@45Ǽv,M㌌2 ܉ O_%\2i ?z0xpr8 saoFSs]F~҃%CɨhnjFv@Ш'Eqz =SyO~ Ow$CXXnjB<=Sce$J1ΤGK$-5L4ddrfO':ehx֌j`҂ 7Ͱ> ɼh4C}^WGC0Hduixi@G|Ucm4,)!4DžLٌtD*-]X` X{&/2qTc$LMeѸ{C)'i=4?_-t'GLTra]rUtd0ݥ,/w_W,Yʼy.SRNWT'Bf-G/Y:LZp^as}ЖBa!.i%iq--^fdFɄ Q'zM& "cDų E랣5!L7ۗNu D6b084bX{MMkչh+‰=i ]?Fۦ$3 j]W7 ]PBYs)^^j^)Yq0#&ZXӄ <7Mcq mY;;: m3zNKre lp>Y3=q0nNd/JiQ^D0ܕ`'`."~?~?/}cö=UVs wvlXs/AG ]Gk'mS~ۥ@G^=]:[s'4Un+Ĺ3﷾)ww=tKN*r D^dh%$b]_g:.AC|_O&S6_@kٴI LC@'_4+76Fߟ78WPh[lcCmⅩ~p8 [ ƭ.鰏 p=W|R9 I[•Zi,%>]%EqRzZ{396}O r- aJGlgÑ05"f*œ$'#~,GTIIl47X4hn]0*RJp<Ӿm̂# &#rщ'!8!;2 G 2yN/!5/V0E ^Z#lJbK&W[LjFNAtUt2okg8UJS.7% 0d˲iش~Z0PKm`vkqۇgh  W`ƹ)B\(IYJ=B'k0jZ')!DxZ8 VK~:22g"ꔠ:`d˶XKDy_1Ur֎E]TzeDz,Ҷ=\8\YkO1-55}+YQŜrue,_ ?k:'`! ڄW2SvWaz8%xhƩk'Ш{$}Ћyh6Zy`#9GhfHό"Cˠj`9KwmմQBBW)zjm}htEZr!lA3>Dky(͒--jC"N@%]9b0׬ 8@m: wD̽b6AJtS~,8 R+V _Nݹ'^ZS+|wxq Z{.3%t=s%!n%ms{޻Sܾlu}5d#r锜l$Jٲ|r}z& 8[*]|^UL(<^y{KFH`?βR?ڥ /耼 ]ILG]Sn*d[;QF́!(7@cK#c ;`c!TO? _Z3X(ZHh6Gkwgk+vS̅p;ڳCL ØZRR k%OcndÇpA=NNG $frj쒢{gGzVTUV3C`l3ɩ 'ᰤ"=zDnUԴ לL'7BAnô-W2O(;{C~D  ډ_ KK p=b6R c@wBgE`VBiQvAxnbVƆ7Ԗֻ-SF00-_F~!;:L CCx0!pMl[(B |` l6Om cSьyѮ7Qu%.iCgB(z'56xqmo(q* PC;ۣҨ7ˏV>~tJ@IݷWZLFdxLJg'P=m; %I1cY:9";B}Ӱ@OC@ԏ /}_˼a9|/O琥''q'R (mm>A7&(ɿ̬82Jݶ߆`/מ(ǐytno c=[ha0q'qbNoh~ GjHocc[xB@!dj}i+M*C0-Mփunp+z 4#D`;x0+[WQL28_WԴ.lAI]sw/"yeHpK oU =ngi?.9"z~y:D/߮ߋXޜ"rzYJKG__wL6_xӀȔ_^ȣi Ot(M4)Ⴓiï`O_߇?7{!K(lEk?L1'U/ЬX1rjA;vMß%LȌ>8lg8kg!>=7>ר(Mih`z!#邮^chAY&ц|@`~ŠF=_Hֵװ̎d(,e\n/CȥkZ؈p{`̓Gd}Ma^5<0V}0aQNBR!R^ePWr zⷎRT6T?z.ysR[DP V5h8}bMl, jS}fr:pHB_wYfJ$vH'$+>*y1;\%#rtHDBUvN2o5@܍؎G?X ik6GͤyQWZB[" jGqj|t:RG7axf]0?΢R5A5U,{a; W(X#cT@ҼެS :Qn`PȐXrr=r~*kUi}k[bdߨCфj(q }F Fh鉌RlIflފhb>GAT;W Tp=%tՇx],t4g2X7cRyکr6n\m1*5bO[,ʥzvP eC`Ld#yP5bڠ Da }p6kZMQ|фAU@Xgt[YUqcz _T:֏_ᨌ`VriF|D]BB9XոQdHϪ fZv"^Rv,O=(n9B&"g Eѐ@Vh/Qf"y"B=B-gΏsOJs^'rCOas֐oSN )/%5]\PJl Gɦ4K|r0ZKL"QRNW|i`N;%C<5E,yn 3Ff ^N{!э^v mzn=7^/0_K!X;4.sXA Tʕ ;‡~5Gk57#WFW9sTp5 H-Kb  0a:`3UukB(H9hJBt_|a.&Cyg m{Wn ԑpF j;HѨ/֓ "/aB=4cvIn{bh)4q= *klRҡwV `(uZ0Bz>_$ qMe']frn.^^6 WWEJĖLֲ7w/Y?K<@b) 1*(9JHaitñjdNnt%BS5OP)'QdPΤ\( lipCDŒ}d 譿>4T?뾵㧏`G`>ȀZDIjŸR"VuwAweeq <SzMRl)&4tji_/&5@^9e~+@yXJyW;U3wh1%#C!C*$ k:\'ZMrK'hbqBzp,[D":!@4e0\LL3f7PzCz-_\J9*K|;\(gpSUF.|X2w&2<%jai=yh2#g;EZagT~mR{^-K1>B: d׏sKc1ZLfRF 9C*P(g`Ɂa 2 otQdwu*V,Ĵ^(BI^&5 aLCPUMN@ \ 0 #u)w7 R,,0bghx|2w&-*PE~~9t1uwJ„XsIv~FoO}M"ǐW%& qoQAB03]f20%ֳT]QO@(4'ؓd9LYM&DdK1r' AX m,v ivA~/ 9my,(9̛ T_/=#C&/aؾDžZZF&Ѕ' t&{ ٴ"-ڮJ\iaw0;]>uT `|&1~|<2;,&M5sHOurXњS1D֘ D$ٚ3/1,e!:)x2H8aY)7^T(~W]9Di>7jK1#014}&2U.mޞNk7S8@HqvG wC@Q-9= ]vYd m"T K!+IZ0BuV kXvöc(ʨyFyrZˉEТ*8U' 3C?{ v ^#H$攌48՞2QtN`@ nOOFQJ]clJKF1:uctGRPZP-QoO+'5ck0q{6@ΉNB8iھn*536:襧z14'P頾-Z,\h5yAr{S3_)8DaK|@OI7o($+'׌Im8fa6&ڻBo,7nRUAVo,~!ɹ'ԉ4J9[wޗo 0ǯ^(opf㼢Y'!=|ʱZS}2m6 k />JV*A W,cNv*]-D̪'D!u31ؾ9Fn,0GEr=E$O:<=8Dy n\G'bWː(Dl뎋hhaa/k_8]i,RnCk lwEl YrmX#W % s'gw6MDu/ͅ)le v:~8DZgkgkWU7ul2'͈z/ND#5'=BS~ BSB[j u}PL?#6"׍v *n_ɰ>y'4"/נ6K6P1ejOFJ5 +&T/tUvYkD%CJz,rlkU;[M0l B !$x6V˫T4P@3ezJB}ߡ낻ˆa&].GiBJMTH=U.]a,YF?KE|V`L5Bm {N oNRcKK4YdśDt:A"T^J@ #OQ\p1LቤXup᳤yL'B5.ADfJ:dߧ-hw`x^̘!*FdhE1j C )(j.fr¶ s_}vAT6tsl6I')/'o[cwQIb-pC#5OiBt;#*tKd(Y?4 `*=u]ZP ۉnpDJČ (fh6h3~JtMn$B!`ڪ~BVߏu_zez{ XxK2AUcRK[m0F!㫶:t2e`< (ܴ+ v-9;f7fC"0FD հq% (Dlp~/c_}bOb)$_gIZj tZK<#6ܽ&=f^; BaICiMde0 D_pP>:\i>CNL޽۴.??"ej,Y`BohJ:;/XhpC/6<TWU JGRB(5>DXWȓQO +k6Q׽_o0,&:Tj:Fj+M*R aik!oZvǏwspiWtAS!z'QZmrc/g/6AQv󤰿}-Pt6^m"h3L]1pF{N8 ur:tk;L؍->A41<Ń6S[۠J%)U<%(ⲘwLGQK χTϥpj\dIw<()[>P䫵+.gj, dBل{%4d>F4T '&s.;Ivq\d~=8hFUbml+~O;<6dsO0ruV[W!&sdN|h<͹i ?S/S>HAj1:2u7hw?A92n@Sl\qB!3 fDys9 iv.kAshz79)W?qz Q/y>ҥl#!!d.n1!4<TR kk+$XP U_u21p љ-' Ug?-.a޸O1E97sY,i.%]@}Ay^?y:r *MeRQQ U#XNC}|o/%Y.3Ÿr2kkY95mSbN29jƳmxěR:|7o:hg'7de9LڥHFR *X'i@Zqv$nϪMXi.Ĉ-gxّ%&3,@ naQܭm:t`sd+OjC贳uǰM׶,a0_ V6'_ b:b\AYH'HR|>6l惗$l52vG8#"E2PODr,>ccYWeXsؖ( K?=%rǤT'ӷOJDx'U#vwHq3hla#u0D_Qi"fwR^=LzÂ<*$78<[aPu6wSJœCɻ?yV}hű ,z<6R'*,>*EruR=]X=y(8߻%V}S<#rI5 Y]MA3Zιt[5„vpC]WE֋`'RMQ80dNW\!ܧ0V$< Y$zk;Edpj̬, ׼gYNAenӭ_O;Yzy LHR)-$vI}' JuNw'Csqg|϶=JHxmui?z ,vT 6oh{-Iq&!H, P0JcǠ2MNE%6" X>٩&E uO>[` 㬔(A6J| o^^vw(:? W`~^ g,30kik|@ڱC*{o'n{"G|#>4\9:[+l3{TK  <µ=QWhL(gg}u Z,Ƒi'ӉÓu"Ln**Vx}J,;h/碛V |Ō W\?ߔ>P^ml "^R),#*R1fI%\5Y8`HM&2{W:)熣N)|S%xO ¯74hwIn} N独H|y;\DgD_oc]˫@Xԁn6lCz*!lW`8Ӻ-`Nd?O&F'g*ېE>nm3?q,H8Iq0_ =~lT$]U_7hCHvωГX~q"e͎!xt,JnAhne?κŹkQEQتuPYÍǾ?v~džvxbMe]0y:x}v~?Ǐqx @a.9CWJv{EåC~/o\I˒// S NBK<:q\ DKo^ /@7v5OwEыZ10b;pnmΖrw>TX^4mȤ|qhV+ҌSg< 1u-59IG3ٌ[їT0M (}4b NJˮHZ c)͗O:&& =ZJ{O<ET|ldy`rxK7тM=ǃA ?%ZUĞ@9 u i4 ^ƙ+`pzFYr,a`xSq*[ӌGZQMMzD3h&lz O2ZnNtXɚL &?қ>çw$UWx _'"i,<*EB1_\C-XSH.L UBLi=`ç~BbξvtXi*>z+"ƝjdHA%O]⤠!_,?J]9[T?vqd\daYC_9܁XH<v͆&eUǺ7 ïXBm-CW>f 6/zOsNƠA9*, d]k3פ@KZ( 9&f4i | #t0&uQ2l`&8 DInFK}婬#E<&ZGԣ,G* bNt?D*xyW\)ak*t74, pt;CIZq/$J n>Xޑk֖;N[N J:_L7 [yes4/#H~z*› >mxi87ti,34x_+-1SW9ynLs#fޛGw@|)z0Ш3v2,{/WH!%fX`cposp:!GѶU^'WhE(|RCya-KψALy z^䈕B5!/qH^KȽi^3L%$SM٠ KޝBI(jtUk6$DP`Ckj](QetGs ׁ銣31%1Yb᛬i/GWf1Ͻ:HpGY@(f;zԕ[4KtgFQ5'$Ct~CmY6QtN!0!SsoS!0`B}l!2HE:G~F^dSZeVBƮ8&Q~Zѥ}KwAeµk"@_Y'$~lSs^J`>-Nu#pr8Žh%!k"W~)xͪ^9)gf: 0\UȈeWQˋ){jA,&rFS߾Q*"% py?z6ye Sb7Fqxjf%Ia OLQH ,$b4Teh|_ 'VY&A.x(A!*;jG~RO 7#4Ĭ%Vlp:#|t<ةKM$XK~(gsbٔf>$XL/!`C?:q|ag{ĪnLIJ%sdD%t]dhUw=uL%7/-AHpXGrw"R'h h֘4ڒֺe`zІxvyUB$4蚷6S| __BNo`o1qWoECxfLC??^U*z:ө#a#@ ҩW|c4uoQ:MHҔ};ClX.{L/΋1}oxpNԴ z~ֻxP|j*cIK]CoRvz3~^N*1Fo^1>16cްEw'x@ش 9PG"B|mPBLo'=:ÿܴ:*2uG p^a/lXm*=&U&i9D!R T$1NGHlE]^3  b3(Є"  MSS^4ɻQ?+"瀑h2f3!j2 #{زǼpq_gֆOFN*M~Ȗ4̵z>zֲX.Vt!? Ay~$eg->7 -n͚Zzf:0@]dB1DQbD):~U[QpJa Y[`>2z풑zf c]D̓EYlH; Z SP.K'By=S46flZ 1)} &DG.vA/M@3v%8,@EJӼ<, =T2@04'G|oyԤ5梅ed檡8݇6萫 FtǒsU;_~[+%W03-E .Q!M6nŞ ҉xe 11enozg @IDAT1OSՁ}ç՞?Nf7: H9~"JýmqnpwnWՒF^jdcχʵFFA"YyJ1@H{\"]ӦO4H{E|UJx\uWAzQОeKI`%kC?iq 8J"CGBZj:G#jz5 ]%e$ϤxU+?:#}śV1(6w &49a`ļE1@Rr5m,5RAQhպ"Za/Sֶ+\ DFS[Y*JA:: *\(8¾u2ОˆG~P@~~IzC?+!h$ܝ)bz}s9%e0y]aP/Cҹ`Fm=WZ9MpU|v{s1OѷDkϡDJRB`Gܶyc yN[ xuR֔ Ѩ5as6 S<Mll W)^hYm[6q[ӍI1ƥe&gpLLSXi.H,fhPNRQ|)]`.(⡑Y0քx g̻Ѡt!D+iERs U|`xmgVm@;pYۏ=!=4.gM2KYoشslI="c53%qZbGE}ڪӧѽ?pȘu-J1Gb f<4hQ$cBg:y\V+JY?:oQ]ȗY#tzp#NNj= + u23qrؔl&#yWi+VV*"v'9"3Qɧo#Ȉ6oJ١_Gjcbϖ VVh?(| Ik|:7gyeb4ȿ"tCEOu.-H&/rs\9С. )82$1"IB18 Rtj-2)Ÿ&:LX:&'efA}.y\ _SgTx~gO`}n#[Ju?xW\F$=8N ߇9:6 σI⪎'g*0f!GOP8@dKvyI В .L q[Sp_N˃}v E= 8l/Bqzsû0+_otl"=Fc3z̆"wh@yl B#n35zqOX^ŸnJ>y۪6MP?K6Q=' ˑ])&c-z ùE+ś4m4\SDe q Q$aԛ/bn*17<1ת ia4?|ܙOI)hmA5Jf1b$ 4 aJ9l}~Rugz܀XҗyXp (֘M7]o;ly'aֱۆ.l|(3PN|IR>'Sfop#@o9^^9AC# @4 g7*: t J?=hJ L4e*blqĊl=&AsTܛ=$,a^Xn#e4$J6toҎƜ-Q-eΉ)N<&D\7#40`<1L(w)0lPH5k3!`.G}B d&~ƻ}>WGH`tmg2n_1"iasyӬ-o#;Xit(ƅzr\B"RepJfgؠACaRW] d / i8YT 7G\Hc,韁04Qn暱>I*҇0IA,U0O3Z]SK&Igy9kK}vndTm9D)C+bP4C\^7yί>U|vUN e<7@sf+""FutVͨH sg}D|]$ޫOښ*1%_8PtEu\29M vmq>uyŀ^l ׮\P ݯ;o ntLO!6GzeuAcN"3a4y.e>r"k`@ &Gf"!#Cp K)_ƹEm>6' х Qa*Cȼ 0=Ї 8f ;VTdQ ~ Qs(`T}W"`c68Yz{v8w%R,Л/P^?/)Oh3#{@pؿf) LDŽ"SjvXӁ ʇ#y1dU$ŷgUHVK5j\̶=(aX7L7ӗ:hv5qT-S~?#W4HZ2K3u2N."`>xF*#Қ'U^GS78p!3EV!d+Fmu|$8\Wi#p|ejx'3dDW{:WVfI08:ؤ0\V1i?!'¬Z"XB 0$%bF]WSv҅@`fv`/:{6\S>qEphy ޕכ(E6Wx4)@%[goG+,pqه 3Ɣ:! ђ1AI(twsFж6DB9 0cbTKkk]:n!r #ZwvW;>omΎo^*D#Ga k -Ċa#vYt x7/Jt%&3l-INt>rL蓪CಣM酻5N5~eY2a{T8V|9R O?c\9 qd>Nsa3FWr/^`=ǼZP1g%%h 6m p䏫GY% ?foլCCFRC?~x}PI{ݪP`Y4tn\gwS)ɸVf&lk_g T2~m'zqAH\$z-;cIpK+ p &"z Adykk Y|' F`!O}\l{5{%.ɿȝba98k 5f1 ڱ&ߦK.[2A0.$] CO v H(R}lk;YSقz^.ѿUtCoR O?V ׍W>\4_pQMk$tهIDdsȂ='3t|-޶JӔC+:~"M n}diSIL ՗,(s.u3N&+*RWQǒ]䶭_N76>(66I}'Z| 4opQc<|1)rmDV :ndK%&z{X>0{PE!i>SYWyȇDߨZ2k@p& ʚ`k>wL`3Sp0x[6n"=INłI2H?&SnlxO"p|8GċK$X1l}0vJmBJp*@ZǯЯK"ϨVu2;Ѡv: =Rsa2Z}!P.-(ǔ!^Gjx+a݂'P"'E}&M=A)bnO*F%51l30[P@0{}([!(he@ %j̺(dҷ&> {ƢF]!e [`cakM! 9ĬGR!Chqv5FCFmh)$ J2Qr<߆4bsw^'50(+LEQ `sB(30[Cp^G}fܱreyR>m0Podj&E 3 ǡC͐,W‡%:D6/`mOǗ'6n6 0PV<=*`ՅcsTb@8 WGARcjXsK4nC|wl(] T'i਽7`q" #vg'M{gճ&yby% +e+Ez2]SFB+P^wRG!Qqzǐƞ=Ep[uPn%E-FՉВof2XC:IS< j^ws]"M-tO4<`Eybz -]NMb^xYIMβmA{qbHgZ#rJ6Foaz>νpP!AZ49jjrC!ZPXi6_WOsܽk`q,'޲}Co&ֲ|ңjJaѦvmO]0NnDȿ e*VWt/B:cc]h5鲏cPA~[FC/-ߤ""13'yJMӨujޏo,Ơ~c]D <EkvqI##͗<~htT79Q# $Ȥ&1̼_ '3nG}/ciDN`.~@< 3S#6 ~&u<)IGuY$DYn 2T,< =c]GD# dS쉯j6eUǨ$U!r c8p=fa'r1wY{ޘ=5? yp/6$k6$tEln"4 @ NTH&l ;@u*_÷:Y_yGAљ=z35ALN2HPNo'b`Z˓Q\SMJFHUAF=A"Js(u0zo 'ȑ-ógs*|}pHjNtي]2? diskK2z9p\ʣ6eƏ(ZX!DM*PJ(BE Kj j%H>GgJl<N `*qz}Jkp\b@r)k|SjSd*QS>v<̗P]"g=RIzmTWUP;8TcUy~Aw-wtY .D%lO|5Zrޛ"qՄ@=exG==㇋gAKXf*c,Akz)JV T9%f)La$YtK({>*6O1X&ɴJ!qE`Wc9#Y}ϱájdO"O_+SսDM7LIұ!=>Z[oW1ـW;r>mٮյ-z/2WXFK'h511YR yL Xu[1D,qQ`FćN${T mT~Q:Zl8zibX@a;ӟwF!#ԉȕKL9 C_" uڌ՞vҊ!VC,0W姮lFE%^gdg,`xJV9e$$R3C!@Od\;M$L^rR(g )(zb{3q L*ET.CgO,R/ MN_k8zp?4:]Px)TJ-zHB.Kzo9OS pig1EBPNXނL;xhC#&e^(  n?m[$4[і#6y: P-"e֋%UnܛRq}B$ 4PXApFHAr~C{s`Z1: +훁2aUcH{NX^c۫UÝ]&E^r!~0$Xć0Mp$ !Q`@Kws^]0(>HFs><2a'܇3Gsmֱ3g ]n`(^M*E>>^Jߟ]Rs{";v!/x_I$vD>X9c Zˈ+nl2xI|ONݧ|Ce"+w:"/Pɐ>S)ӈ=\4Q.&P!ts; Q“aYCfX j*rfh:QV9I4Y h`G+BshTS3`-0y9_[[^:Ս1=myЄ̲*ҘG8ϼ?e MΟ5J6`3`?\dha9OM"QSĺۑqNYm:AH$lLq57+.i*m5_V 9y@n˰%pniaNe"pZxbL*F3-  ESA4L=d㋍eIw?R\npa43Old0IVAjdmzQwa ֤GeBS`!ݿ6nxV6ٯz`3<fbЅelbvPox\VO DQ$fq>, :e3w[ V= {=ADeks3+]6)Y([T&-" z" ;S7fy*; q`_(Ecm D* Ғ_ u>j.IV6Q%Gي=G{ 7g.ƃș_!i\q $*.MF: =A{yriAKvVTh^jGLcUQYI99i&.QF|rx:&Zڜ҇4F{< !X C5#od M؎Bz,b,/x? S$H#%s2<@''{E16-eZgSޟΡXqKμO1v8T ߅=}Ƈr-d&WZ?[3IcHSbG@Oy}]l[,SD]( ~4bX3SKFNM^l6b~H͹4F-I3Y$Q}QnBӘµMG>*aFL 7s0l@YLHqOaV#x# 79iͤcmt~ˣs D^|^[•vXZGZBJ$H;4LЊri Fqή & >ʼ8DAVn_[RdPѳӳ;Y2( g KxC+6OO?9LwI V,%(.8gQg%el!žl5 )$76ʠTY`_]~<;|ST<>5-=jB$@e9";DлLpj+ brօfq`5[-S,['8LV{<-R^V9 w/AϤr =ZMnvJjvy E>ER<@zz)nrj;A[,`NghEjվz^9|L7H~ G)) 3zdc%[MEYXFҔ@Ky_E^Ȋ(cAC,>ohB}PCn)C9ѽX|;#?ƍi&TXq%ݏIcZ`3QZ!XUEas|t駤bxѿ7$>ɇ?- z  @cUmG7id44NȨ&H5jaod-;CPc\9lD*9[48Jy'#4t ?Q\(*wA\(Ө  bSMlgjfdvD겿fꙓw[jI~i1'I¡.t)FOZXUy+>ݲwL};cUC}#{qHPTeDKY#SIVZ#ѠHPFixk5J J~$m_lWfY!nW2k4Ex(i>;n:*Zyt[2"Lv&Wj KVȄp'g/%S. ~,[?#d %o 3`6wXc#Rȗ #]qvtLhJB4bǕeBi,&8 3:~?Ɍ*j N}T&ɎeAJ=ñ+9q˔q9sta[,>Or7t K_aVq#jU(TYl-_7kwb蕳_/6RBlR8lzufqI3 -{=äh:It #R s('K凁ɠE#Tn@[|qRلUd,ȌZʡ.D wu8S%W\m7l5$t@5^v\tʭ5`[7( fvv/#kh 3^ilBNUk 0&r2.[PAZDj`U9ܤu=5AݤØ& ;W8"i#`xA{sGjy`Hx#h^s{exGf9<_V,,)G |fROC@NtĴpx'X;S55 6X~+qaʩ%J4 @p9(8'qM]=jпJc0x3H+ 4,jr͚7c&UMdE]z],D N\ޓfSv0Sg0qA‘Ji.b Tb|#*NS%U2Ȁ8y:֛f=!!ǔ"!1 Iǯw*ty?|˞Q1ж~CHBRғȉTQZ&ib(O=8 akj}iv!FDq\?#k*rY0g:1܊P~v%xHK%mYolp!UQG{ri| ұ8`c9d&7kmEYm&`^1DX\0y,ؿ|Ob.O2dXe])ZG;9q#G2sNMŊ]]) 4m(D V_tVb&qaMN#µ!;LO}~qo7b2ivV_·ǃ} e&~|LHmrbx~: itJDx+HB6q$PtfXKJ?y:9|.0qW+_vksx3Tr RY[>05fP ف)5B[@)]vb!t3/aRPƩ83K3\1L_zN[gO ؔ;|?R5Wm$Y'P" t(~LBhlxWՈ.bo'S/T -Kzl̋~τC`'jnLde%`|NИKa$f ;qFFLL+׏V4fia:,5ϏTxcgIA1Ui9m5bgK<^M-Pu1m4RRɞN| ⮋HUD,#єU1U zxh%aY\@[֨ #`\;oK 1"9Bjʝ_B9y8O^LZ*#dTcPOL 565go\DK1PWWԽƩ;_fm X}{|$T2Ӈw>HeRdOk { eʟQ&8@ŤM4h[G< % 7Ʃ@mkA4kӂג/JDy3Nzj6 [>쎧1>=ZW"evQ2䱀\Ft נS@7CA l1 r-LY"Ճ;!6R~HWy/J7ͯ??_V׍ufܛ67qȑ0Æ I_ 7(`GfJ.4m)z]rjO C6za#qgI:G党218l~k=ۉy:)6R3qa܊7ޢ䜕G>xa<@F[{uN3>K37hK(~=esO#xյ3rkj,BWKX͐at*<־-xO| ;363LIWt $c6ajx=$A?N3xA+xONg]vϗjvݑke9kKpnq|}T\[|&9eAי]h?j űDOJv^@\".:ZNۇMg!~)x[SJm} j]Jb:u c4rrz!"vFuOq*Ub7)~彝BP.b<"N?i0T`q3YǮ-. 0Z؋noQrڔS\dW;ި ʀQ)}mj>GCM}b51L6(R(4'Gh]d Ăj6~sRaLK98 I a4FuqpU&¨,%f&[ݸRPXm۩Saa2=d(*4| 4j ctQܐ/j Vfyq0toz6MTty13`NTo#2T{W[ ڶS:.v9|gh3#L?>i:]HYjt>_}% p&҆LhƋ2uaifGOrZi`L5BdgxC_*ԋ{ `#Q9~IH'1JBFR@)0* MJ' D~-l/}8sCnq$ʼne;uN[ReON( b9P4b]R[9ojųyv*HZ]7+c=$ k'N2a~LBqej Ff&K h԰R<ͧv 7.B HEuj)j/t2`$ C]5mh*"lt6qA_e#Juܨ d9 2:6UbLǥ,ڝ?8ߨ ҖME'bKa-A@q@\wgΕYЬZTw^q*Xxdqj6:8M6Ûomշ̨ڮoo\PhVy6%TY2|Y\UEkۛPJTVeưs+uc] .t!*nwև" LLʼn]q~CF @zx1R%6UR%i="w -Wc"ec 0 o]IJ)oO y6e(N& d8{oE# ht9-"iMuS` o?`~Mcoq<%hH=}CjRvZTV~w=$1P-F%(tIsqB Tɥq=3_Q2eNeVc>U/Hx95:]7q#/ }rz`C24azb}^ŢYaV20p4d IY\=ORJVXt\8x!/ w4#ѭ "'Èk<r@':\[]}T.zY[3 ^k7!U +*QZ$qbV(u7-vC,Y2 SL_%ϸ8DKJĬc Cx!w/茋 vT.;uG Rey8e+b`I֭eH +bEU {~4@  ע^.*?L&m-TK}(UEog3`8e-p`r76yLe߀hnHh2 F"ՀaU})qh)%#z 639 b>R5 &'EZKf2[mĬ7\C' T8& J\^bOZFM*CC:mnjs`(g}A!`:]C=J{Iwgqb6Z.^䈣ar\p< h %M%!6y\Nqy{;[3.ˋQQ^5LYj]xW =(|{]u-F;f'= sԪd;d(QCpsy-[<\`NoO3~j:YO0mjM ~,ofdMHmɻgL(P'!kï7::&*/Eps3Yr_M5dw3G -)Kp8{suŌ@mܞ?>ϟ9든rYAh*-;l}V"ڤۖ꠿?G\哾'R![%^^)xlh濭$WQY8JȚ1*l;"< 0}/&kcyh O pTsRExX5 "j [u(/qX!stv->st~o6艎$ނΪNnG'AgN4ᑒZe!`3#nP(B hob[&݆WrF箼B*kk=!Ž>ukP9|c>:yϺ-/x^92Yo"kd)D--ᔖ)wYi=J}&l(Ǩy{?{9DФӔKV4"gW 8t+ú,O&m@nE C) % # NH3 M\ 8>~kczBLP8BT/jagjy>l 3ޝ+d8)簯ӌ/!mݡ3o|hX};OZʙܫɘ s2Zu~mpv,MψɃLtWՅN-dB-7kC04OD9 Pv3-oX?"G՟'Ơ@"58Rz e'.e:-6'j4uvvψ 6Nhd$-l&v2zk@e (+#}cQ)Mh,1Nu13V[mH@>* (_Kz}}+ccAY[3ߟ*+ҿm}2 ^_;hʈ' Z -6i؝~'3);fjS󟟯׷[L{mowh2Rvcq!]]r䶸&el{w84}m ? > &(j덓dMmB;7|~[{EmEߧ-%_Έ(ۓUvc˓7)ϝ#> umª|.sR$+R/}ī)wA}MRi-* HwJgy:k(مW!rPHX0$s`TrpߖmTAf/x+9z ')öXRÊ9EVF{חtF99]fJ!X_qzݨ |Cw'HĞ+@e]"XOl5k{秡30h 4GKwU{iB@yTHIAAYb&Z7a=8j톐pQ\shqZ~T~r DwN8"Q@1R%|S4ŝ DFBe2Q+b`ҧ/m9J fhoRDj\NNtnm|Ͻ2dV2rۈ!"=8gi dFFY!99G.PyΆ0hmYlF .`MExg :ĢF g{ S)Fv27<: ʿԖOLN^e)5VWӹ_K#X~oCsθLɋ^ȫ_o&Wo 1lP@䔙:/Q iX7*o˞8D܄3+A޹D|N}lLxl$~d8 N3…ٮ)Cvڤf F @~3I],(FeXU9d᠒c;U|2aKr]Րӥ6{f-N9RLO0wUPAU(Da$({Y ,@з+jŧX[, ~羄zL {eJy˹ziQ~2|r/L-yjU$/mc{cC{ ~iݢDB I)s&}D N>26?wqtP O8z66# Hlt >TؙNt)z._4 ?6SH~E8v<b6;й\#C\jgOE ϾȲ{2"(D|nE2Jl?3Fj('QBR+%蛆(u^ށHh$q+b6z̒̏YSxЬ̴< '2[Xaf:<1 )vܩtnhplx5,Z3 }v ) +p!'U5v=Qǵ<`X65;EcMV;E\+C+(&- 5Te axb×aPo70.SiDe"Pفų*&B~ھ_6UËaxͶt(Z7/Qa|<|VV'61tav 0δX`MғQVUp[ƈsdhc]+k*[vC_78oߑAr᫝a,V]C%(ᇭv%v!B켫ahD\%\Q5+ȖX`k&AzO!Nr%fnm5 ϧ@,Oj09nᅺVD͘.k+VCl}B7}R$hO쨚?<f}gݍLcq;FTLeUCT!!xH5jC5-,;2S@ 3قGSRcp Dl)@CKb6J쨱-g|_F9kN5fXB@ ꬄx'$Cm!G 88[V肥Qq fkVa1+3M|)BwrY8`e ;۔ 3B~LW$(cG[F8=HMh\SOp O+R1/V_@ n11Ouo0M p9lVT0DY͗~ ZP6 JLz YU#Cma՜°{ bh#'ZvF夙BB&UE hT Fכ &KK*@91%^10B+ Wl8ݏhZ)Ѕ! !] ir0,)\:5j z'ivJ幰QfA%ѥRvo\Gq2(l׈ei4pr-b%z9jJY´yO`#$5mTA5|ezMzdn&T6KLVf5gT5K.0\JfڵlLttC֚}AU:_~KmteŃw:VB)@,BYL6SP"701G0^ .k݃ se쵮Js@hq7eM}I:z=S@h82SQnb1EZ~ry8lexҴZ\׆{ kgeպpb neAYφ6@#~=W.!Bso0[:+$ɠ-r:] a42S2\:32H0A%3\Xq _ DïxP Q?(ѦEZW:iN BsA4|3PSV#BlQ9![T K[t6MTVԪD'"I5$1 C9XHr f=LD[`㳕hpy`"R(V\W?=,KNI7y@$\G#}Rnۦxqg{ec:== SޘM.=>Æ+u͌ohATh\ *juL܅{(50AJa:ų͹yQ ::V#PP$6$@Tk8H:H k x0W9 ڨ ay/=/Xth \\F#[p"0e$ǓgfUm{ (ũbn?ĢD)>ChRZ/h'8MgE.w2Jat\Hd-;5[T)BA0EI /&fI<:,SxΕh- *#āaaTx<6Z2@PʅzmƘ YiITRiڄf X[dlfyfzGC*%]B-V*S>4[ 'mL`/U;xf jdlZ&V=Vi.I=dDOUBW*mJm,E`a6^j4^EehmwG:n#rtKӒCS,@Ap$0?x4׫]C.NA7BVHP${ Kef @ X#Z)ys1eO 7KԚTߡi` E - n4yv2H?kjH@'EVxsdC\ܞ\(,A09)AlL(Y+1Ri>d)l5DK` z8|hY) ޱ~qj{4!~ a T:xBHrB|O3JǶB7S*ͰtP/D}cůĂ4LSh=c¡ql˽Wt.?/y"BOznjm4C$STx@;1zlY >|uBI } fckZdZ8);<ڑ<*Q Jr) ç #rDF(O=Fk1'} Y]4Ӕx#Z[n%kN?1 NJ(`.& \Ǟ-[NK Ik3 S$x*[JҨrQS5y\pQȺD1 A CƔZv3PǦ˛33|ln#ew= &zR3Hq򷷯of,[·) y~x{I8 ѫEdtJd얼RE㻂:_i഻CԆLdIpx cr8M;ↃWM }">%ޏ9$:Zfbc,kGPTJKG)y}d`kQt`[V z2OmPod[ZMJgG/T s5~&m1"Y_V Lh+?SDNDVB0^'vDna uJ""K,UҟѪyvܝ҇]a!q'ʱ7-ܴu_OiMz 0Q(@á? U50`gãȰUٲ?S `};=̀7x/Đϳg=AI-LV^I|b06kgvZ: GO/^*Oov$A("5S8r!a(_3:gbqĂp׭t-r#6'tdQS@w*SW&$пu7-'$E$74ȱ=ĤwxFvEص[O[bk&/gRpE3Pys|" 0 ِs1ov`}G+xS)\t)|u&34G#I4 xh6|ZqzBY,ґ3r xxƟI]ƠV+ r"Z ǔPUog򄼶diCCP0.C57fh Wkϯg61e6dXqrÑ^9F]zOa Hn*q~/ tVyO!0j~9PTW~_]XdHJsڠ&]vx7`f8K_/y@ Z4v0yTC |5QLōeO7BQ`&D1vmOj“֓v 3BH硴@|Sub4aWkgnR)yzM7_= Z؁ x޽~㯗[YdsယYێId7Ĕ 2G-W#.9.9DrI؍uAl|؜.rDXt0V19]I͘G0s _9SU0| vi[8 Ѭ6BM(@X@B)>a!H3=&[=-L/š6r^b)`btz}= ?io )]aWJovλ:H"V z0X [aH`@.5i~z~lw1OYo^4=~=~^?&yy`E(DJD:>{ ˷'g?[D%v}}x/l9W¡t-bgwNؽqx9riM+d[ѿ JXBZOEePX ([U쪭,oՓa}`+cwX""w3z6lŔ@,sю櫛+NmRnSC/r}8}cT#s~KD':$/.tq T6gj2C_ /R,_#I}A%OBYBL3vuP&-pJSn pw[=& ]U胨f[v ,zĒѨZIt>Rgߢ6y201ܐ~S CxRї^wWl8`Ma=A2j͸bwGA,ә_].8lG\` ?򧨩 ]<@a'C}F}6Rb و VF{_H}ShZx|\=;6$e48c$7 1{2w@ 3ф,dO482&-]snu'O_{zIn\/NҳoqۛSL<)6><̋9!~' es)oA_#t>r7͘*0^W/ݨ]>>ڈZѬefrG{;RHÂE_Smj*I(X^ ͝K3i:aۆ;,K]9xE`j s̽JuS6H3ᦸbԠLS:3Dzc'~^ס1H>I6v8 Ciݵb@ BۛHp4ȑpW*%d:T <ƊSJ& Ote0#yb $aD@,6JSc}F9FAOW.DĻw/4Lٙo?J)i%G+0DI* }".ɶ$:bdx aڼ91q,q*T/|v4ojw$n=c쪿׶!6&HjqJ:щc7LdڥFd"A>e,xLgt7۠,_ähxFz|:ZW>CeNAլdi ok2?#Zs^dHIE8hfׇ2yژ!4t>#Q=o84lsk "MA̸'Pv{ 3~ %~;S j \΀c;2W0lj2KwǓs; \ѽI:5ʢ3+Tb Ir>'i%R ;]n4W4-RHu_P I\E-ww8čCٗ epL Q3.,oSe o.60#0*R&aKW=%ȡ$Daq-a%FI35s43$e随ƽX~8mC$Y2[٧B* Bזo`IOYXuvf溩B#::\I{4)(=01P,Fh3DGjӼI8Ba V$TUwmlwtt2.!`_6D]C@?|5Q= ky5z1٫K KutNFHH+)i킛%6/[ƒwLt ZΖqx^̾&F!*Y nɘ"_*o1Dv88͊ZhrO+_DBe}> (po& M-JYU{;=*Ĕm--l/:{Ӂ&)Uի5;M Z-&߄NaO{35L)O/&*6s <դ$yMf8@]֬#,v 47$q4Ň/w(^&Pd _pJ]+[".~:T\+ˈ'E ( 9*e1lu(h(Fl P BLZD?㚑&X":Sv5,7SE1q()r=#Xi**=fhs)ҔQx%I&z-fA_Ɩ~dDL:XMEv\)#OM 816 VbĞF#ཀྵ87&rj+Y5 a{^\1EtUs' L}艢Kdu("ǧPH~[ؔʰ/p DN|mcO/9՚&GD97!U=rK(>إ&v "a$dzb[`} EZAO|XmrYxspRiY. 7 DJ2'Ɔ.Z_# wd H=l S\d ~D?Ftsܙ^7VaJNomV&KO8 ozmϡS663tviF׶ u`7 ( +"2)ZhGd \),y{惾>?}Yc,j?_ Pψ)O֗/s7·@JJ̦e'VT(d R۷x,cxTD߮UtC-k)YRwuJԀlMhm>4P$r۳v:[wykVHQ##W2q_9i>H */]&g ZpA]OVBşd?]߹6TÜiJLs WEBՐRF:zaҰNhHq&pDv$xJ3 PTX!\IQU|Ԟ2OM'd0Ls/R{#AD>pCXKCld!={ q]I̳7{-g'KJ5=:e讶6qptkcQĀgix"mc`ʌ0ܛωixEk-jߟQгFxM-'&i"˦Y@JBL}8\=AsώضbODhJsbPA+)]od J^s6ǍSZ* WfTɛ&K 5 `笛,-<L\s]Rvycjb Mz""h₴ 'CS_0KG.$Cސ${1,rbXUoK붫fa>K| IQofZ9 *^H< 4[/@!4mh>= 9Q&5\%,W`ibhT|NJZdXˆI3I>y!iҫJfU[9>@,QjTŁ=kK.dP}r:=T‹1!}7^ 'Û祔8v߷ϯN|a@_u`H9k,n6㬶kĂ7N+ֽz~R?Aϸ/ν0R1X ]ji_k({;SuI=6GHj$@6D8Hvc2Ծ@["iA3z/>EbJd/ ({Wx=e谴=9%8S-8,gwbH1$.Sodbx %[|l  %4; B%L /WqGTvkDBe|?R|K^,_Fxyb `b`A0 ;8,PxЮO0!M~2i!EchkJb$*4@(]!A4l!{| y-QALt `RH90 M@ ^/w&s3Kh+zTh8e xP[rFXJ MV⃮v&:_H =V!(Z@XlT)p-C?Sw)vb002qK T18'd"hY 3 jXȨBZ=ƌO EG3iKbd1]bLqvdZ9gRmhTMHuu;8 d㇂^@o6^ v!A%t<+ma"Ã==O>Z|ĿoyBHX6WeA͉6ReǃMѾڽ-C46nRO5Z!?ͺ: ܏ӻr˭drp6""SD/z\hxv6))LS `5xQHDx.@gk!>ejra8a]y/i(/=Bc"UdV5Dbظ =񽗨'POZ51't#%p*&~أ ʼnҧbSP-BM1W' t><(D+ 2o?xVEjp$p57 iImYpZᑾ݂#$.0kyOm@g*_5B %rnU &].uw$czQ%zTqu*+ H1u8GvMٌ;Cx|,7̏"~ ٭ZLV皍leQ<0it(DhuRVgrPj"p65.<n4|9V"EnG?'LOSɄW4Tȿ~ b; #Go-p2Щ'1ظ5`~-vj6ԬE2p]JM5յ2ŷE~ }l&b~RP dh~/}/,lZNU0o=0!^3GSBK浒pHjGR$7hљсEӲiۣIJNTHoxQO撄S@-վk6kcZ2JVuc(+)g[ cpC[ufeqAI\vtJ81e訯!Nlq[F0l,wه3ĭp,T"XSp ,zJyZ&t=~l9(Ge|Wu Vqhpf4C-Ofl g0b$-mS"@ FA{G@,&7,I%($PnV%ܝQ (:??bo#:>$ig .L1Je7GgKĘ%Sי J!*O鶜_$0{wg1iS8~5t2줴-/GӰIxp3|,zV Ueo &ưo&n0!J~JN~|l^W1KpP 3!&AQO;V OV>*&' &jK*1<!1U֕6qv2:qizSml$m!ahVi {/IfyLxAϊ;?CE(iO&bUcU"=Fu L]+}ߜUvoK{S~—nrt`G9UI-at'~왚}TÙ1Zi?A6zCG 5知 ׮QO7X&E^xy5օfL%['teÑQ%%LA]) @;haB,J'f 騙Js|n<0Vwxa%g~L̢\f`!р>lnQP0fk1#;W./S u,q"n2)6Ufi` P[½Ed)NB*<F ^2tlMp?M)氡ּsE<2e_ ̵ߪݫ=SEzQ&+j&2L)c߈ gaoh5™x-Fj]P"Qf ݹ@#v"|Qю+ydbo4ȇ55's)SXL9dZd+B.i &N(8.<1*2/

    1'Z c"o֓)*{i}F繑 #,U+z-e2S 2"|ʤZ HhApM8հ%TcʍMV#OBYD,inA cQ0SjKٌ㥈zU^/uԀ|$:. ͑p=S'.A|-u0`W5:]hyb \l(å7V/\ qhO [&*`=Ot ȗz2 *(~JIN[oZo?< qsp̂?ЁZe|XV]U+mao]4ܑp3Dl4H׫/Pk.TEӿJV? -gx4,T !)0֘΅{^EWiwL5n"J4 }C0H ſ~%CFF| 8SMpaPy@d 8J7lЩe0bn:ߥe }*Y\DO6o΃iGGk7 ?7>p vDc]?%^(:6aV[cFK%`.G0߱F\ō'H:8h^_GEa"sV*AsG0Q^]ЍN|bE8Ԑ9_[c"kSE _4}r,See<r i^ /vN, X!Z\ra#qANDzMH]ZUo,a]j-cFң7] yc;VkZxǟL1r.k7m: -U\e38H[}y82%( d 'JJŵbum}\N{"o k6B96O*iOwPwĤ߿lt_R=oTpU1*nOAbX lcLJp doMA`ˣXۜ4AhV=an~DuwRvDAo9lu3B99͚IQ/'rukRPH&B"ەcz|mA?l`nlqM鎢yf8 e SCӚ`vh f|||CQ Nxz_:b ˼Ԥr]+VRHaiȂ0ed{V΀`5'\pFqsN",<$МFTgmb|}+&yB=u7냟I5%+_vBVV5jyB#rN5`-! pG;JȋYfs oS(?J ^D 'iO] bY*`</צp2&9 Gtjv?KgF4n."~_ R.)䉸Bi >nj[ue9 λyPkPC,ăcgL0Frqs\u4\]i%( )S4=`Hiu &&Ɨ oCAzUb@5׍ $"]aDZ>UщbY 척p&Ffiri4ǐąGs4k dh evv o` y[ۋ@ <"%uA.\DR8.eDxxq=;0ae:ʜ^ ppkH>fF2 dS4jI-Ko>}Kx˔KY nOa{nZ!9Jzu; 3[t܀9!̌ 9s\OdMf 3]v:(V9s`a<6W!dX ) ЇFh8,|M (kÅT%NX-7QP 2WH[#ʢe14>Sb⠵zմR4 ^j,Kh Cwj<T6 %#`y S)"~}"@6*qn6^R 8Zu:6ߓ4: V H$'m $FN7 @~1C-(*N؉Iqn;GQ:viF6*t!3$6ɟ8'MYS*1OxH}\h?)hhUlfke04ۡGЃo<ϤCң_57ߓnOrrǸ)^ R^ʔbry1߯yk"KYj+ tx?!Z1n*{TuE:oŞWa Glk;KjOh}=đ7{"U?lXYeem-pȿFsEK((c#Q$w b&8!^L]79 Y%7ɯL63]7(V2 L'[`/L2:~O)6j4Xn]/C^*ǮYjJZO$Y4@@b$ԫ 06"G 3feRy!t {fIKZNoݫ_uS vZ0>C 9 ^)R0G44SlR?jlTц@K,C0P1p;'3Ѱ >#"4o vCi&Xf;ҐZaD2@?^,h*IDsR&>?6dPFH0U>|D>N =16r2.I'5MZP^k8_OZf?AX?f)Eߖd"[)i 6zA pr)B<'umt殑G"wofA'B+~5OGd@DcBj aٚp^d;=gaCig#i@|/4]҆v%?d(t6Dɾ3x*K1$HbM#zn{FK!|'/q VD~N~4XVjT<%rqQ"il* X!f?tl}9o;m 8@"78+_)QN+ UuQioym]R,iOR/.&{6D XM{ԣRC"χKdЉ1:SW6 qxO0Sq%+ c썲dj@jV{~U (A`MGR.@A\Hw@`\)arkb!܈pSmQmΎ0}JǔcVǩ?A:XN^s!:%; Gb[h =a8 PHnCpֈThU8Z z 0q}/ %%a6=`! Ɇ|oGk} I3O:7\ R|vL{U*0II `!N%I5,} yl9GЛ34:xG>ͦc(,5R"/.c@LC f=ɃoVc~}U4PSYvIJ*.0N1Q1`?D:Ktx= td΃])p=(4Ee+^;Vv)f$O{NTX /B9s9XÊUJV;Ey T_,E> ~[ai^췓6?iTt-G8yUY_挄rRG'_KVі\DqVF!^eL'E ZLR@Wh%a4|ZcK}.2*p*Zxu"Y#$q9xR%T F0U͈uQ$a"FY?|۵QY@p*" >dšޑ[ϖ57%ٮfv̈"KWE\t>~(PM˺^%CS915e %y2.0y ).*/*:df3iSP/pA\ٚ`XΝ)tp_6;f[Pbsh;\-㶠pb=wR>2ןb ߔ/5Wl0iNA=)s+^߬k^?_)nkTק/D&xH.rEFJư< <[ 93vMʤC1!_ '>th\T~XIE:9VTTl2fJ>Y:MjL?~ZI,|'`M>O'qZ]k h\8ۃ)XOld4豳I֧GAx,g n뛥{cDbua p|̆N!2PNrhPvJĒIsٙjK.Aqv_*'Kld`/4,kS (5=Xĺyτ^`h͊#Օī4oB&CϠgnAԧ…̥flA<Ie*:GLo0@o__GHaNf\}>=oQ 6 F0Р?NNoO_MW1/wGZhXWOdٛⰵ͞KenÕLT"܍Q HB[;;nwѰcGsjrh6V25wv7]]]>CX:[!:h L1; #̷vD`ʪ$D4j9j;8R"s n_mFH}Cјvm?bژ5G*Y̊J¨KN3CvM_2.\#ԡe*\ լ7!gqFd L 4S5QG=ǽnJ̟EPߚvwTTh4M[?q~X!tLedrsT40H3]SY ;Z`I7=d{3WXx/Y`wk|$h)"nh~}?{iϜD@IDATڽԾr ( J!1B%g"O/*ICϿ}$},8ogQu4ۏ?8n~؁̉N=+/mF ]^wjs$%[ntu{J#?7>V2:˧iGkfMۮ8؁r^Ag<]?~e09\OXَCFpjwRζ#Fg@0 'ìDXo?pC;2BGT,>|$#NpuCp=WƎNf.MxOI#UZ1HG@wmF Nx;)ηeo`N?Kdyt>Xz2)9{^ُ2ʥČ:!Mɘ>{ѭ "ԇ{lM?/PTA.*+Ev2c[à*=(DŽbib?[C1\1dȸx 7YފĊIu26)bVZpfYoG_s[+7_X1%^w{:D3vtMF#͐-c;q'b'kt Gu! `OXDgRƢ#Oכ/yf_{brj`< J+E^iQ– Z3uv:AL.p2nUfN-]W88BSI5T+V",ădr\08rC:7}QJ>[)JJaO,sB&nGgg^n֕qqPAtS+@4A. =@T?>kDB xZ(gܙV$ߔ-M܁>&hvF@CXRNcpn<墶8iעd5뿋ǣ7qbq)fp~SPWĴ Fb,$Y-:Bo#ds:L Kπ/ ZhSw#Ca@|b# 2}^~BO;8\ln#D|'ʞϣyK,8V gc$h91@-wv*Zl3.'\Q8 )fDڄ@.uG%i!6)x> y~TnBĥ QtXT2;,H1my243Mߒ<&9hid`-,XK$ŷsމ Sŋ+.Po^; BgMTW<9{v>KIU3kK ZV5Umx<5u=a#qΈAu=WekH>cLզ GT$kw_P`^ @vFR*l{jE9Z[jDnke~5(aB]ތ@c]O?9D,T"D[JUAigOOQ6 !@1iЩ$erX^3FĄ}D hM_@4E@dZ|ij#=ҙ#HdY~xn3//.>;Q5*FBQ$YKh%'sEz?Vj}\4p# ;qoGf jEs!,x$5%U7@Q0pNgKN*c`OJTiFkxvCj=!.."ike`.M_$SpR-l9(C85NOZEExu懲GZ&dvL? &la f5pſJ1|Un tE <='*2AȄcK5dk|tJbJА[Gqmç;>K:Տ+Sz'lVQ3䘐-FaxЦqD`z2,I UNDTfː蛎(^ T7vhQCd+Ay(a?;vܐfތ_ YXTaӥl&'j2ӋSA2,loT:"F=@uZJY]+a-bpr2t|#ȻK3x:#x0FaC Efx >BI2]i g4ǵI?5OS6Q#b`ɨ̴9⪤YN_)`6} *K,(I %4~ ~x`yp:uC>z&60-aD!5L^'g,daQ9)F0MQ 9FeFTr02ak5N@_tyrm&.L :`Rik`I Pro^VCTO kF9ęth(٧Tř63CwO牄<`8:I׽bs2މm}<8E4,El '}|kx>֐vYE$]Ӂҍ F ",ISأqU,,SkW`N۶3 Zi+UP]{ޠdfbEGn%o:n3Uaŀ8{]m 8#}gNb~TM@`i'=I !ycNFsEv-g|8 /76H7ra_ ܯTz`^:Gk |IVv.Rd+%3Uদf_,SL-gh9:M|@8pv6L[Ůg{O:l jGxfW1V{l'/Nk9ePP(}5\=!D';J;El@0%b:tT ӣē}NI#k>roNcyOijuu% >Ms!9 i&F>6 1 P񛑶hĎ1'ru Za:NC2Ҥ.Ꜽ!"h 9oӴeMR  h|m'Ǒ z4]`rzt]-jw*lJ]NFWFO߹MU&b b){W 41{ec($7]ehHV&Ek?Sl0rDɏ8Ē9 21DpܹU-_bCGb O,I#l+C : %-ݢ=sH+n'^h=Fj9U[qXgxr^ҋlK^2nO_ۖs(ұu4x 0ȊgVČpioig0pq+=MwDo)B(WbݪF#tfT64yN3?ᵃř8U{aa%asNOW榀btB'O 81\pa j˱'k6s"sHQ0O~\T Rkt A@?xgT,CmsTVI>߸T?(Xލ [oGnF?.q1nHш\YxXh8zITҟzeX%lysĆ@mWxT LGIn 3 {E<F.oi".uf:H $.0fF$!ڏ:آ ~e_ dyDـ_/#"\9.&)24(!tpS|Ga+vR4 ؉4ֶׁۣ-A4drKUA2 @'!Xf96E"4 2 ŋsv X: _t>Mĉ;y}* }+GZ1UI~pdheÔCދ p8[Yx&]`٩1@?%Lehs9FVi0JѴabC e <[t C(wd+*&8C])rÜptK)u?$T4 R d]#-D~,(7NV~A# 3z 2th~k1^сkEt9߆9Xpm: ")(yF h $if!JxD:375S}ƭgw ^p+ } + # FB}=*_. CDյK KgS[? L*84Ѝg[/ߙWebaեcqimUC >w3\(p|c{l kuA݃IBڵH KBx8:*ǒ\xb@AUSTOO [!Gܥ7Dt(Ž^'%d"h7)1ȫ+ȇJlnqmu9fh>F0[OU?b>[ZH8]"ӖP !Bt[sQxtAmۋ "(qSg3_]|Fxƒ#6LE(^V7S%v9~R f^尢jj>>LC42"aJo0#q{:qJކ#&&! QKǫe3[ G'vQb[2EnsILH&^X,\zĕmf|jGDK/u;5RXiklJld؈G/q7`AJv gBc 0Z70Zt0?b!]4P*po*|nqYrd+AbWsMX֚ۂ.ݛ΋>Fa;@`}cbu?^IHZUv پ{_$0Dŏ(bUvyovcu<3}6'(R.|~]6fa&cgPnF+~9 60J-v~u% dakl`|Ԫqxv/R0ܡ2e0y&aċؚO6I]yMZN4@0)7=]Ҡ5_L$+ܙ+5iA;D|98w#lr1CN俶?=oo ZRgfy[c; AȅUۮF2Ïx=o=~Ln&4GF/V++|O}Hؕo-fץGq×Jѭ㈱ٔU4D#$Aŕ?Nl( |CuQh4Uw?;&?ag6ֵn'12Ũbv@cj'L 9EtYVh!g+ {L}:E/.SUkh{VY^!^A0Z{1^:DXH`b>` ~y)0j#ڼQ#F늘+ HOq;%:OӛvfDNpM5KU/YEDy*6G(%RC:^ŔK7sNN@+/ %)*C5"{`rǧx> 1eATMvw|N7pel=څcU#n:.xMqՆ _XU1trO5[׀H8R/̷t8h>8]GR YUئI(o8Ȕǯ.5Jȋ& >wyeHQ|$)%Ye-a5fz fE'|Q"czy>9daMWA:d4'C2Zgdj xD@,,ɪ+7kL7;-ōߨ7[Rd_Vܐ˷XF 0SB@OH~ljdwA*^Dl YBX6R{\Nx,xi},"@0٪}>yB)NZ28M6S;cm5DZNu >cD?`L BsQdI]̔[09Hp]cG-sqVi]{Gڦ 366 7)£3CYe;HpRA+Ѱ"h}`+C.=ވ 1+UEy\󽄆3@b o 4Nnp'9O̩VAm_VC`FR^4Մ޸4=RKU֯}Q(ZԢ:l`Ǜ̷lF #_^Z.*3 hE7e.Dg1NЛ @p_4 44@`߂W{[(Q <<GֲYiZ BG}Cg^1cC8Dz9>Ej=RKO>V CēMM$i{2Νc< ~̺mR1"oa+_7em3qRiP}@X ,jq?μc{<#[ 7 ,]!ZK:1pƨʑI fx1` r ,uhIj5a^󛛾N K>@ q[J*xȿRI*$aXQ[7qmV.W?Pxnm,f |WGAuU{/CU\*T=|<t{P̏Q9h#{gJ6.n,?2D@4P2 Jۺm<Szw%ބq%jijԏׇcMMBy)*1 "I<@Hӆ'l!Ub ݃)4;ҩ7"2OD  oenلX1% }%pbE鮝 Š^s8!y\џO_mb:;E& Z ht崱LZ$4 <8]i #uptlFRZk-zXVͰXUL ;`y,pV{%(@ T%aaaʩU*~<(p@ȎccR9.V8 =spdҎT +,T곱=%)Uvx6xIRK4 ;3[ᓱ߳A FBqfj ]kFý9HG-Z5H!t@;ygجU`*XF۹<&Q: aIC^b^ШdS[z^\V]}{M*^3U})@1B_6&feC!Վe:;2։뮿+䃞ܧPl9圈9w[Xy[˔厪ܼ%ǒ̦rҪj2 dA·՝6A_9 ݺT]aJjop~!¨F^ω&̈́‡ x%%eF3<|vzߎafGZ =ubO9گ:rt_@ݮw 9zqT VTwOs@ЂuT%4OzybG5ǭ[Is~8ĥn1g^>]?!ߖéɟ*".¤W)dS!ӳ.JÞ92bFAk(?ʢ6eGdPw*o<h7߿ʇ$$OCv{,`v~Ƹ80n[V]Ѻ_p C/1GM9?o&hhe\$6֘R{tAe{3냿|ÔZO'hx kҫ P\zzO$KӶ\gVj|s;tcx *>`ֵ NL;G ڹϿ&%納My8͈FiZ^ΧY? #uV-q1aۊݟ*xnNd٨2.tE[ ro90 rӎ:irp*@ھܬQ63xД>;{rkY:L+g)^zj$I(P{A]KRlJo_~Ip|f9MjQ q|Bh pUf.;'N7kEF[עrS s#8DSx@ias׶:բ#.]ʨlkDFOg뾾0JNܑ]JY+t?֪Ѕbzna$jr6EO7N(fVoJuٔ@-B=PP_♔Jݩxg jc `d&QF4HHFG;sd`ַs53. fbH$2NdPxC/W%Dm-SZy=~/_H( *x|/^]:VnԔJxfiu$ùmg4q ݰ vw\Tס5VNŹrBn|h c+.2N)*-T16E;:KWFczlh >\ecL.*(QPPt׍{-1ʍMǪsbTCfy<=-[3G wf|sCc#k4rT, w@ŁLVaqPdQM$d3EA'n l1.s,g7X5b;2AL DÞkc\j^ _F"\j k]SpQws86|^K.SGt3, nO܊ su3993 4QtD*i2 {8FM xG xje\m!ýrǘɯCkD5,/i)ݺ6ද2p4-+&yX1#{:AuPOΡ<9j)|LFq SԊC6;El:LĦ ?j6 (;AG?'%-G0ѐB|hzo [Zj WmbHY &(y ԉLMEv'*زߠڛ@=|?;B.ېr2 $qPBĭ!Ut \H;/Ea< &mT59—uU襠 T ZT4) ,5(eɖrQzx6q|!bVR"j F,3>[%T/! 3NöSƵ$ y@Id]NX=W ;Ԇ+9|].Ֆ+J9cS0+m?B\Cu|Arz/4hO 3ƣ)C9Z)lVz6#i)\& D"9W} 5r~]RzسF4(I^q# W&ZȪ298MW00W+tRʶUv!Ws} GR*+qUH$R-P fɾa4Ǥ ńKw _Kp rb7`3CLhzcV+OPw2魳LA|_- -nfb 3+&." E.<`"{nSGėf]/VžqmF5vN7EPLhQeyJ3OWˣH;bWHCMyV]%P܌ s٪'lK C|0qW"@YC_oUp__aosG[R@pQOD_ WTŦ'w6ؖiݥ,ulIpKJ_nn b jz6 _{:5O+Se993gڼi4һb+TȔ R8ۗp>7cHǔeL/hlFQ($Lu~QZ¢! QqiV ;eMG%tFwT YQZZć{."aBvs9\7ětŗ]ݑZ6f0^kd@~r Th'/$8Zw3i6('gq[sb\Tx'#C*)653ฺVPxKZ[ $K}rPϖm2cR럺IQC9A< E ږ&o/nI< ,.60PV0K*9h0j 8Eev(,KlzfeH#Ԟ% aS"˯Z&2dNwpˋuOK7dArr6[ZnsfoGD% RG_e+50As ZBPC~҇}vŒA$Fjku՝Q~>MbMGYh:uV48yPY VߜoZ:&ۣlL%N{}wG0!7,&}ywnorJq473G$ZThFrHni+!\ں|bl.#8;]$$o@z>~o~?rkȐIj/ U0uEB6+{L1Ɗvd\C[`LzHidboVzV"ݶO"Vi.8:)Cn74̲++' s3?S(qRB7ф53+D8|[t|Hk(Jd~+$Ȃynh!EήFm6=Nߠ/ehx._fCTq1ᐽ^>ռ>3QTnL:c) DbgWdûM f+q'8xZjGJ&iŁGkB53篏teڠL#2hOq[Eq_5/ lyj#cvPEl*|˜@GYHAV@P'yzu@؜MJ8GH  Mؾai/ULAJP\L0K}B^%K?T//{ FZ|91O|c]ړ2|14JIҜ(cCLzQ4TB7Ҏ1l~OC?d_ SQEQE:>#b&zҦ0$bP ^8Ie6!Sq1HӋgt!jźNynRi"v`1);n $b!B||ᕲn";V2YEcK$ vsZ|VP"Xb jǍ3/)HhCp+a8m2A(uHnA` KKz^~& ewl'mk2+#r:4>@C԰AV1B'ܥ͂R7I$/u%@fnogxcmW=ПtRNvgm <Zz j ૒'a_Ťp 'A,'^/)tCҼIpT+|kAh~卛eJ+[χOCuh*Qai0 6aB:QMSo :ɗb A,ڀo4qȹh7t !6߁e1K^6q>dS^{R*`ίbL~.6eJ/p ЂP@Ci]ڃsـYapU 2{Z:#i S*M@Ta|$iȃ$(oddfLȄŜE&&'-Q Q~π5àڎohU@_8XIE)%Q^rldG5nV?mǕTr41iY(mh}lKMk_)s| ˥q8K*3X.P=5ftMsAZ ۩x83ЎבZmCN.Fպ%H7eo|yYFku4a<:n{5pL9L8I uZ'YFYCx3ClL QXH<ȑ&!v],`ȱݔE̘%5NyJaGJQ"{1a[ \oj4|ӾkժA50 Suph[<;SCkϦPCkڮ vϱ=D%ֲgl \&x!`DYu鯋PQ+wS*k {0s-L a\ߺ;߹M*':N"k|[1ˉ(Ivb '<J)SDa-0 jQ<:Jv .T9^K%bTR i:G&ԈVTW'n bf+<`^)aX}dF<ȴ*^ 9Gqe /Ogec/ÑpSG}#h0> f>>YfZ&T7CGHϲ)7y+mW\9M)|cP/Ϣ F>U"}MKdX 0dqDz ㄇ9T{=@UW+|:υmo{q0dM`MjyȀ @]| M%In AbM?j4 SJag%\qP!"oz#^I{ '-g Q;R.*<{U40T?ɾ\BcaTFjXHZ2nj2&JrcXQju+ps8ɳV#!85g Nށ236C F\jiTFt:ޒ` AU؇dX!8s2 [&a>$Rw[1mٲtb C>a2a:f{)CPE8YgoQ)eY.8$X!Z%9_x /mK>2 5S0NA\#AczUW/b=C'6C ]#rh_,޷ClA)YK#K/׺yd+/cg~ƀ^%iLWi0'0*ķQtO_tpPmSr8UQp sŢ㨠V+3<*%`%:mN1Y*1pKG^o;r9O l6b2ESGh|R >y T\%CRDl?xN\Tek,] 9ܔ#5&LɤÀ~[r&l0u[|9PP!2|)lHİ {LjӖ™f!2Y5c]OKjyM!xWW.4o\ A??l/HW;al vʰ*# )wySvs:-(.o|,2~H/ˍCLl`_3*E8}IŎ۟ xU!I1Ct,ne0]pstrl.4?=]" ~}wS$or.ǣԵ?_N@P~A06:4Ab6< _T$,Iӽ7uwCa(U&zwP,1Q(<UscõHFv SS|jN,YeZ@KSVzZfrpY0iu1B픾͋U2K3DȞq1a]"ɄZRNW%~oߡ,>ˢ8eɦNvC>q3#jD~-MMmZю0d<:=o?ydZ^##h*0 s&)8p@5{֬Ʌb'vK~>KtslֲפW}c@jz&ѿ 1sN')|֦F*ȉZk憛3KcbH=) mCe!OyELYӇf@bYxi^ %\CPcE6KUS enQ 1[͹jD8=#d^_pj8p9r`ֺxեWFph`*S i( /Fh6Dm%xV6d&ys][c혇G<zD:KҧtDbo" +a tKKh1Ռ[q^ E$O}>1^muŀM4ݮ<'k;$̕aHANEbZ-~_|"HG1uTFXeEYܥ/ٶ}col9̪>j<[RV@6N«oI93_FE~ꩄeқI@l 8IU䵧r z7@6"&zJ@I oD $4ƒ]< LV{'gy+ȯd# B&qJ#Jb|JǸ1&t9Dl3sS*i^_(_96sd"'SKb<) =a9|ֿ`own /Jň#mZFSL ~v'dRFMpYz}܉`IʁFzeh7&} S #9،G,\ont$~Kx KJՔx:˻izE>|srČz{eӹHr~\6XEItF]C8Xs-_;'{oQ&$S0^`jghNVK>D fntsOMhl WiŜ02&b& B$eS#Lb)\~f1 BhиR3tQj2nX )XeS'ynstejMJTX7i;0083.N2>M'|=cG ¸ HP]^w058(G"!dP S]ÈyNE o S^e̠e }| *6+AR%0p~|™?$2eZyK%9qXҋk\lX ӓ~i2)a<( )H[V@mĞwT*g9&K d~@js&Y#(6m4Sh}vdoJ3k <Ɓl> _h2Ҧ/pVcb v 9eK(U3ӊ%-轰`7tW w i2Z- KJ"Y̌dnG(oLshbm)̑Ϫk0"-q%6 MvKIKJCDu3m5~&U3 (]kV|~ 01!pUՇt{A%\~Xkj&7M/y252'jg=r2 vVY9/맬HoJBLmƈ"( T̆l7DhC{S=k=/ )@aC N gvidrބwߏ2ё|u3ݗB)nj4e8pT(|A "F*Nx.Q.*0:e6{1wdi|N mpd @@!$[Suſն6&8Ҹ]w2z [>M*Ei>׭_;Ox(}߽-AE)H9!,%n p;fV8ֶfL̦[l%J4FCs4=4 ȝՄp7![ GԴa221)SrO'Y&+|<ք@ϗd89}<>m0fbï͏fRz &<2[ @J/'ј=ĜbK= !bݖ-KU,u`-7x$2 䧈:Њz˹;|A5U$CH'g>ofQYKgr;rF7Cl/;SJevĬbgjC7PrԖ6gʌa# ǩL/!se{A\́7;0r݅> ̸p5b,X/$dI"yO(́/f ]pUT>Ly*im7]߁"Vj2*_}zvEz[l5t]6б с&GEu3@e"-sĶ:5!ϫnq9ʤ"Ňz/_LTM䙴3SBMJPV߂(0xyۻrj_ؾ{y:ytjkr~Tp,҂%G?aͰ󄲌G:yxEc`>pxGPF7vxcl)dza88՚-<Z8;*9(UR$MqZ>Ydq1p r$0uYםJe۫ Քnv)щ ?u'n~Z_v;ܗmZۏE4flr"e~8"DPBĔSMn.;8fV-\ď$V L-VVK9mE?S;k+Zgyyy0XrzuTK:ʢ WtXnp?{GD^r_;Wd:!Kry{[sP^X(ch]b*;ePlgFB[[Uµ;h)צ)L0LlVJԁP=#UHQ'UaP&jD@/\4/Eq]Y֭K!#yy,z' h"]UmðrV߷b>]d!)R񔞕&?qvD=0JZnNS&O/j{%[齋?u9)hدJ4-բ:0ViYvVrߌkUὙWjq_^Z/߻M3.Ok~&3)#pc1) Xb̺թI! @p@g^fPAf\M+]. eq iRbD8*b. tƥԇMh2Ja/`{nޅ\|v)_h,PJbAt9tch:"wŝF4@9hCG.VX@XE){@W.0'TrjW X.`)N< GKG fPDt,K#z= Y6[JP)RH&M)]e[OR U4 RL[@;pepVp$U)\!Îrdݲsj T ^!K xxqc) p\=dBovYaL28 z"Kxr !_ZKrSG!^0[[4/*t( )@Vg}5)dCw=:i'xQG.x>B+rP1M ns {>3Y܌3W'EHooN ѯ^*ctn8rsZį0a8-ÚO2nCZЉHH+p7!3`?F|?ܥ3Od΀7H|6k,>]tqlH1$LX[ឿi*o^E?Rg]*[칞((M~2q;%K)ӗ\]oV?ۜ̚5T8@)x@Xøz_|:L@ڐ [9Xu};] EHRȤO X8VgxI1nEe{p8*A  _Z١Zpl4\léݑlh"~M7AS M _bS=fRZ7ѸbXAC.>y sP b1TRK=L#NVSIyVG6*l^vcy^dh6S w;R eXSL1g'( VLH7$ݔuKjTS󘹓zU_`,'rECm> S+;A`bȸ:ミMCP#$#23H;FLxI( r]Xm]@=2KdI 8(ƒHސ\Rj/$U"+eRz)w9}$Os5H@Wr6Ht A)!B2x}Tۣ9bjea ^safdžʄeʂ"k"bƣAfW O]M\@JjS4~a5OBd<h[U-)b/TtESHÈ/s%; RxO.n?!Jh׀~MDbm Cr)@,a"0D\6YawEܸRr@aJâ f9{ )\kHbXlpkZW0<^U̵n`R zr%^950)#T3Pc!XqH/8ӂVQj28 h0fFIM0-~8J1vu )Q}ܼ %gSSq:Ö/&Nny"D?֪r"ꔌe +@ Y y j%ki%EMSz(KM"ܟ^m6o?6rtv^ຳ5-@l@͕x|?9ѹv>"@X90 Aa[(ap݅IT+o"jly!_9+<?MfiJ^zJ -bn5AOsJn;XAQ|?U٤m~F?'3FA xG>9,8gMmҏ;ܖM,_M9+rnXHRDˌLBx) %؄ќYFI] o~b5;F(3( |8PRO]5POI{wڮ;՘ٕ 4Η{TSBLc }m&lRC+r^"ȵDE2lg- [|@ݡ,YbzAh&44>Z?ckWH xg>WPhrޛN-l\a;7m4R*^ՆԈ(]UE3 + Wlp{T^yA&};5O\w?;5k!Qu&g4팕;ؼpRmd6]ɥҳma $dqpLޜ$uE3ܸϢ)^LRƁ9ηֶZ5'eBj}7> ߀zoU3 ]'gNUcfn$>ڷ-zPDr4o$T)SӱiA`ͬ4Y1A*hqe) cF\j- D~F1i53>O7zNAvW܈&ͨlfGS$#<Rś^v$JnF M#N(1ܳ$WJ9VܒD2! /eu@ 2R#A{iB)Պ -<â?'l~bh5նoIZ-X~7 6J9_>ׄG"g.^(:LoRϸ `<@5Јa<GCI)ݢ*J̣Xe,4Xp**͠7QnƟTXЫBߔtLmUo8(:ܨ~a ۸,rP2oT15R8Xwp ) fH<0MhrAd:J|`js2IG?Ђ><; x鼘?׋wOi0:$i2ψjר\4HšL2=_Cm(FCbRӑީ2ťTt#VQYT`'ƨ!7~{Fe Uc]!)¸/ ]H:'c++d7r譜ɮATI2&۴4kzv85at)\՗#_ {\[~*.ġ Jc`ֈ&c  mUza<{ԫTg̘W8l aAڳ ܊'nq`@Bb@kځ.H̔>sRkE1{|XRAEi!WQ@@؜ObR آ^Hm2Ff{ #'y +4#"*ļPYB=&U zM9fL#LMgA2k?:C ! &^0 'fl}iGLOfI2aFG`70) Y m$gT\LkمIRkͣ'9F8'q!_Q (⸟Ǥ}@gVzf@oԥ)~Տ5Нls\?&mj`<N}ɭ. X#:ɋX2oxW˭Er[ T`,E9kY pvЩ$KTI 0⎿n^_^s0F!־^ ܸGtɆq_4{ =|G'v͏nh\5!6C(c1]Z1Grt9 a>bjFn$o}Eي,g O10%uLSG8- L?ؔ~zxȦe ׯaM BdG#R4uAQQ_*dz㣾CǞyLb I.[.AlzL8R"Lp I\r3-5A#Ǟ7Im`sHoSf"@ g Sqp!V6W1&“H >ca>2)jc1]F Gƍok~)͜鯱l0f܁Vv϶uGOU_^$ i8P_ ?#=ZWm~t$@IDATrrJ [`MiݦLJ)h< ElT +^k$\ou=+07u4M}UMBuIj}hٴL 14n[ȵ"`|+T =tHbH% ds]W? B QTGZ&ohi IۢD\j&(֩m .'f*GF)o?^vmk ?U]Z3' m)Lt B!* 5r28L{FQ(:؞Dg@tۣlMX1hJrH uluo_x\wI7"cl{kmeR@j/q5;0l;r d,PbtE.Z[x~nwooy3jƸ]tnC``/;4ry'}-`sKPCL&Z~r8ڡ܏eU8_IWzԉ?T BlMn#R@Sk~;-m[{_7ˤ_x>v2+ovZxl{yU$hf|=ü<>^6,G-OAФ~ yC6Wr ud0_7dRiXþת-YѪiқZ C9MV- ].w2<9)¨G,/P#|ZTbo2V\jf="7$S]bժ̹fz|椬 zrҕBsqU|yu !DSȹVI$gۧLYMڦ[l>5Dcl< |W@?Z#3;6V$ݩć6̈́1f<ĭG\U܆)V`2jZy @Clٙ%#]ɲL`ID~Xr;"t267J.(|7Qc642.#um fo\1!,. f Ֆ7iQߟܖ)(cVFju騚ϷUڟq=ٔw9u;l182ʔ ],XO"=S[~zAg|?ylv48mgMЙ|^"O@bvcc?; 6[wB *&j|/#|2wy:-[F'LPTu ;~L3N^h])Qrޝ;u- q7L1fS̲(}ڲg#`CgGAY}*7rVvs7+<"u^kQ}M[Rd%&c+9]o,l2-M%oRVq`˃6&c63.OEфh֊ٺxrdt*Y~bc-n^~px"IbaDO? Nə0t%gdE|6w0Do|*+ImQ5UJ`72Vth3rx2Tvu:biF+:|&﮾ UZ_w֗E߶BB;-_6"\#Nvo:8켥Ot:%2P+y>V/in}(Y2 |߷븙W_?1]t֗&l,X}^ǝ%{}yOQ{J$;s~9͆]v;ݮ;]Dԩ) ױW?6Ŋ")"=@HbupQ53K|Qgo'p?K70JZZ\&lr4m=2;4ᑒ) #IxWPI'$N,H/@~mf<7$2]-eJW2?t}3m;,y+K{p]$9m].xuc&gJEcѬ¤!:Ոh}t:3E\ KS RDk5hKzXZr)ؖ0Ē@^Ɉ ࠤcJWZD` zib۞-fT Cr z\?"OQ㭴Fl18F9rJ@׻Z׸ $Ix`'kyFsj [hLt7j*)5L JX"OM3ȼHGGi3,`vmIm--0Szbz|R9M R16Q 1})tOuWoL*F+~'p!3F[u Ɍ cnqޓiuָފs!mfs_v-ס#-d~SݴbXr-`1:I<*<`p3H5)0]C!cQN2#CUqcHM‹1/lIh})`ݤƒ\{5ϣ4L-Gu |gIVQK}&Ѐ' V |l -mn_'@gKxSx U!0 \KLJO?vg|(nrCʊ;&ULlh4٢^/Y&;N_ Q?r[u3Uqu}Һ-[EЗt$nP]tN ]a=i)gz|~[^i$5>7x%V(*%u*t]??~~=ߎf@h¶~Sn*沚SMf#WC>7`J|0g׽Y$2G9fݸqua![%^%y.! xp_C6%a+ک&|&NKo[Ogk(p $7][W [V{z/wk.7j|3+!EI{E EB&V꛸Hev998^HMUjlI== DqdXR:ـ5 s0mY{séUT.| m%)ȃTD78ᾛj>hA'.U(p*6QV2iǐ`̋f.n(4褖^~ YQYR}+/T&|JȽ@-ыL,t$zu2 ŧuĈQ%RkQgrN{`H]0-ejPoy 9ڙGm[hOf!^qWO& tx"Ԡb ZaBu cR RZu8%lD 0Nyaqp &6gxpߔd~ Ynl(xi- [SF)*JWSJ8*##RiޭXf׆ (J>ϲ^ =y+ye)egQ0`AxCm4r/L ˙p]Ȯ[f"eB+ujT(iIx6@ $ .NVy_s@(KH='? H0O:?~R9`.Υ̾^7?l3%T#g>:Mt4(;|έp*Qf:QK*7Ui X.(-8H/E~-7 y鰄 N"N׳Ϭ{t։"~.'%{~Ȑ m8a:C T XM1ް0a8?+V8h*'Nx(W5cOx?N/5C%_cקd֘ԇV,E9W펩ƜطWV# ڒΔ0Ac>p ] sBL]}r1V5lZ d ~׋$_i(#ץd$pg3sh]sfc=ۗJ[iIq%&Ko` ed\g2P)ɥ(Z<%,Me'2fJ)Gk5Bd UmP-~deH8$.4jr+׃H%xx{M3(pBdaBtDY;:Tr+O5k;vBP b'(JZC=_- 1xSU ߬P&.VUvJϟ 0G Z.C@݈Bb B>)u5 F]ƌ/]5Brh.m9xzzi]V=uVqTAtDcUF҄40h>!1V)T^9k)w5#9xr%˙~س_9}!O!?4ԺF]9xxׅغW{*!u{]3fbmcȶ\%c2p4hp㭆 MPmDP`c _/ĭ/6k {V,R^@3ZuPAŷ"K$kԯA,h(f[.v!@8ā,D똟!9!!$LG~ڙOX7߲]`5& 68a8G8UB@i-i",Qu}аf1Gs5`.CI0Ht_9/9hPweqpOc$AZ!`-l:g2Pa1< _[7TqDtl,6 o4IN-<,%~@ ulAt&faR 7D ~cdirc:^捚cobi2CﮨNBA ׋)IbZ?)ctl3z;P#1"2|.>ꄞ3CMR_ʷ9"B S"}A;V똘S rՇHm"/bٚ;QȔnM 35@ TKt:EXINQb!!~b-5f2S]v9 wr{C޼լp@D+TmP&VXY@01K W=8rTOc^ެa(R>GT޾'#[\KҾ@`!{6У02O؉c/N; yӓ%y M"MށO0rPE>e;t7*c<}^ Iw߇wܻ\ڹDTpYnN+[v\B],rCe—&u "*[``brܼ%!z!90&/:ZC\C5rfbY5d# &Jt՗|hW3]7Q:lz)[P)PS S1du8O*K r=z/4*Leo-yΫoz%$S=(uwq{Sy4U jdⱙCO瓇t@ﯫΉaxpn4u 1S~lT,!+3 `6r}sگOДvPŎ-dMTCR/o_pHIZf\3m1*LbC`kN2.}`  ˕N 8:RTyo){C,ӱ F0N"S~/ׄf+ŞQ~h16Jn"H 8WƖT4 Յ3]넻n5 K8gJ짋T$d0zlh?qysAq̓yv/7[CgCCn2>[JRjuhx {(py"[h4 ǁ?"d_/<4p\ۗ%ȚjYbdQ|F/rc#|y&UKNGtv;a,X!5qo`baJ  U0[ )@4R`r iXgq 47r*G# k{>޽>f?D?]5vvj&냯)&X7$\؊,sxks%R'X@ #}z)צK6*9!"fY0!PCUۜu6;⫯a9{H2vLB r˳pnM^ʼګ@1!Qǃ>=ĉA83ΦRltqaqRljyeyL7QLtzZ᰷!"Jp|$ P]Le;%(>De506` +ޖb) v~:悑.RԚ>(Xy!iH9H ƈwSGOåR[R~P ).l?CcX F/ Wu1ѭXx4^g\}Pf y:*@ @Fu<|& @qb 9ev~b<6b<#c xsCi9L(Hkpr>MCkNxNk4`8rQ2B[螀)hx o.~)]||ۉc(Ԙe6&.hI ]@Z$Ed 6VcK?\@wElyJGp!%ύՏ0,4i/].*ZnCԬ@4Ȉ8\Q]?=9M`4Ayq Z:,\3 39iCɮ35nC5Bvût% 7 /q7E})caXj4<АY@a5%v8ÃT.+12Gz2\g7bDL'#yfwnpdB5Օ}J*D }|X!MC ^BݑExEe+*b~/tp ~;)jA**UOSQ>R͵=WA*6p }SQwu֌a;#V>`@"'c ,Ut僵LH[̔#3Lr22r>vDREQ uEa^>9bPzS01̭ӷyue]G3 Il& pZ$ `1c7cy&Ъ*e{Q1buseo4ZW߆;/AMvgum^()'",8]Gԉڞђ6 ;}Oar "3v6?(u+K&RѐҐ |Kٗb_AҮo`v_<(,];B i {K b |;xDy\ڒf_<АKV` kŐȈ`n$/1v}1yKfWAG.ܦOA+m aX'Cbyz  zdO zwr2ܱ :Qq{08D)h$Φ*9!M Tol/NԖ?[Wkph8i$8,ZI7X#AL[fok&Q?>ғ ;J'%vjbTv@ .{hbsNEpiJPNay!"GfTȅ];v̍"^lp`O>mlC{@.-MTQbF+T;}sU uV[6{F%H+MKمpC#i˭e>&zP, !S fKS ZWƘioMmmmpj0fvA0)=DŽ6)V胟0{3?ϟ~/O| :^KhGIh#ɶ)dВaVB֩qztPbʴ9` PtB F g`eP9,cK}s(Z$`itmFٜX/72c- lp<i8)ɈgI&tu N𜁔 WJ|2\6fij>vI|E)Teџѧug;‘dF8ƾ+]ȐKׇC$t@Q9LV!(wi#6Sϙ 5m2#TY,UL_2l(gG>ڟ#DV47>pS!@x3Fuėy`6NZx:|oYDȖelan` >0.S?e-v1GF^27:3$pPZCk[Á?碄J-/DNJb-^XVXzFuo&܋QAh(4[Rij@NAHk@?gڗyA4&|ա?ׇu~0\X:fIITtD$S%oܓS~'FP:ï!*Ek:%T\ `<(dxI,TZ/JDM RcD h w@k*EڞB_NlM|5^ lI0 ofqGoyLDMTch}4˱XK]#‘p4‰0$u9B&&$^&Chbi$Wogj5b9-Ş5G0g@[9I)g67>jN(R wX-='f_.r8k8]Eq,qT)*يtU;01D]V&2q3/lҧ].q1tg1l`oPz3*Hkk i @ Q0kD7ta0Ƶ CL(s*NEVb-a `f}%@IDATCy 2EMLHkq=T!FopMdL@5 &բ}cc)qHX0S|<^FN[E;TQ EZw߈XH?G)4l||L>3$nZYcAZKGQHN➖E& mk-Y.Iq2g6&5=b?r5}$R>8!CtG6>$Ώ9첂͢R_1BmRz %F A%17Ȟ& Ĕd=f}%1I:!A [ҷ>):GW6z%MgKU1It6wnjIĞKoZY=^uݭ椿^h e*%BE]ař2{FE\W Q*YƖ'I&\diKw?͚ _3=`W۝XfR:SIQ%Ke9@=q\X11R:JdI召x1$NC!odGBaeqưWes#щ,C7D;*e8&s ^Lޗ gd^VX^MZ0K(XǶ|>Dʓ1]%,N2489, t}0v{w{+В%y(@@c ?мa?ijzB?G$qYǃFw :BĂ0M@B@[´ %li6Uyc! Hzޕ2Th04KJ+'>lI-% f/v t6btYƤ87P[!T>c0D\)D0S@h4ܟ'uRBM- ohq]Km#pZ˥PK8)FW>mf~nį ˧b@l`5(˳Zj@&HݺfQ6 a(-v4AI)Q4o&.`{k,R\F2?J-ijxbs}lp㏝h+p ň\ 鄔 (>k2sdE=:ejZ& G,X  %";$̱ c޵ZqWw_]:֑~Rw"c#UҀyD<^Pz#~55z 7{6\3 JM7g<&笽N<[3W(>JY820C$NCR3@YeI/V@NCÇhWmŃ/DzkW=vԶI3ǝZIbJ޴!5rɭbրO1= %2SʋE<|RϟBgϙ%+1ptc#H( Ak=\6]S=#L=]N+5 A4 F֫X-'lI/!hnWL"(N(5u2(/±NaA qrTf/->\̟߬Qn^~|a: FzU2)ϣ2S@Z3'0b&)kf.s}=k'1ֈ6Þu:⻁jۡ:ik;WT+]ˋKn` *2E*X~pī\Z)Pڃ[>zPfq\a-R{uX{K<"_ i_:~Ŭe9:=oނghS@ $#,s1[N/[9FGSg D%H,j֓gmc#hNA7z W@3RU㖅V%x5=q֯~/ $"js[Y'fEp﯀’FgΒxEv$%_Qez&tN\ WػA?֭VKTFrO"l.Wܮ5#1Iڎ%ULS^/7+R"Vj0Ui^/Ŗ -J6}9ԠV+"B)jex#>lyU`/B3)t[ vn ޗ]Y'q> 7c$Q6 VݧKX_e} ?M?'LU7651f %yǽ%<Ѻciov}:Z&*e+\V1S6hc}:9N߶IX Ү-3!1@w /ަK;n~I-Zmjg[8-SlIW4(Npbj F>Fa'+XfYk;ީfa?O62ЎMҒ Kq<9[@Dzy0]I"K&_Fhq1w,|,HC9-AlA4T9z6k,{,˳6FA#'vX3^L0Ez!{Eg]+c QYpB!=dTr1 IaC׶3%X&`#QnS)eٳ :c FYmD;G% u(m.6k83%tdaq$UB20D#2yE18(N'fw`f WNG PʈyKŲ'P|l]!+,Le[D1 e7Aԃ:˝_?Os#KJ."Bcprp$ ?1jEBFV}kn{q2u$>=x{W嗺_ڂ2&'^%ޚ7Ĺ?TܙSo囚2# [4 N|1B #ro9~Ɏf/ЎY]#SI=ρkDZ-`ff<8BO-g`AH}aj#-9o5R.Z> cqzE*~^݌ ĸI2I24!&tP[OFx"͑N(OqKJ|T='WJɥHJ[`oMjⰧr;E`gHPQȒ@f70!W{C@uHGEn*PLb~S{j t+hA1j"W{V^`"0M`NWa Wh%"R8\T@'R4e 5,Wh, {_tė!z/݂d|M'hpdI߄#xhJ2glR>h*т6g=:O-D$ 0o  NS*0Y2jӕUuh#1'F="Ө5Ho *b{͗k K%,;J<$\HQ3#W؃ru+7,Kf`p` =uiJOAGbl^<=gpzooe9$F f {%=IA(>TG=hE ͥa2 &D XE*RC-)FYZaG Rxp!h(Ō9h|dQL-Je-նYv!hSUb~Y:u{zpa:~`3`%;[#_&# EdћW$DO9iHk JbmX5P6C,{*ˁ d+-]DF8KcxDrhէjl'2Ȯ[" \c8:n EJqd]E>p[t[ֆD(^p̅=#?4֧tr^M-Nx*y1ARҘꄦ PF4'$!i"lؠVC$k6FTLhFH & &>VionP'@כ\B}E#ۜ8oF <Ԇ9_CUx+3DmJ(r[4ۻCZq ӆ)+ʙ։;T|sВG!Ӟ8e%T N8c@8%V5}v0 jC@j!u4QHB?|?y^ DՓ/9I$P @cV4k WnЖ;oeV~s/a~cb0D~8sAG}+wavb<\w0 h vDLVڃp3<t8sp<0.=~ӕ!=DSHe VZg"EŖ%"Wȇ5UBؒG0n(m'Un-KǨܽUp>[*@Ϲjׅ%ܻwpi.Fy|\ Hg?.a K/dM#ާR<CF?Soo>(D BPz WӶ9`m`mBt2Zy[Qn'.b1`#P1nOp6 Tf*~h mG#|ܞr"ߌDo0 ƻTD fTKb4w,K Ā$X>xt ŕ DEXbu<)-9$OJ jC.\铼ad5i>jxR:LrD*')vhgF.iSAɤ};=1 ztTY[m'kBR%:A~I;=P !]Eirom\w(0i0CȳLX&r BbԮbO3 TX YZ@?sԨ"0,Br}M͑+PuB`[u^d#ԝ^7ЋȞ83 sqtg^a Jx#'Ŝl6d {Nb߷W*ј'brmM(\+VlTP%x@ 4gKUwtRt3xZ`CY"vhŽv57- eOoao{Xr&eOK: !^Jˎn5! }0dW]NaB ux%&1H.5=;jP6tu-+}ݯ(i-y WqƟ!ͤ g#?]mǚZoE@xUĘKO҇dỘq'| geO ;!yё^}#U,{~qB1|ʈ]f\3ת;>^TSm( `+-?߿jX,kl)mYI}Y˞j~U2$7"<UT%A` PsxTKgTi+9V^678x0w6|f,P-2 MǢ6(ю" -l3M6]t.|l;:鉑V˲d];܈X߸Wo̳{| >sMi@a3Q#4/,r/18"5 |p)m0ᦁLޱ"H z4eϗB#P&!IM &ZB@x:Z҃rH0i&@J98"iDN6v&f tJc#EE@<"dgiG{#u1Pzf7y;m(d|3[(wI7mz #Vφ6 ZP3X.FԛH˽K0DdȈ[y:1\CN)X՜h_dJ2.7ɉO|󥚷܀è"e0Tx1 R5Sb} ~h?i1,WeG֓.Np$lq 9+! +7@}$mI'JWTNe jkܞUhR  rUj^e t>b_ŷ4.γrvhμLD08sAZ]J;⑴WMˌ6'"m*}|E_#ƕz8Z>ՁSgZWƍKqYHE8 Po rpv0 2~_3|;FU부k[ _#XP  0. .tNߡ~_'ӟV 8q$ y(0N^4@QzvOtGE_?[fj1sеx$mАkKUa4rHvtM&3UD#>@We70Le@#x!?#ϟ)[#Z:+89}ޫby1yW3aC5oIrQRzAK_ (LZ(cBMSx:JPKlqU[ I] QVoX^yvѯ:#uzcu.)%"Rk7fbX~JMEhJADlJ 4- fd͓ ,4 ~sxg`MNYx mk2}wC$ҩ,,yǝ\đso2bխ;١h G5e%P< w"6 RmƁwaA2t}l7J!4 C&Ooƞo)8 [h9CtΞ2f<;$Ӵ9fV~}PUkܻCU$g[~#b.%'5LcU/Nv0YoѴ *r[+&j2-1¿䪘ɰ o9[YLKZ+q:X 6'Zf˖o B#nwW$"7\s"!%qE_0h"؝}ij_̌$M &S0(.[c-4?E#'q5\Dm:;1TɩM cTvNBXUYDmmy?dp'_滌%7 gaku?J.9ygNjS͖fz*U<ۙ%f([N1T@cQ_GAEBZnBx#Vۂ4Sa.1Ĺ)U$RhP""SPϵ.° {hhT0e]੆"1D6IAaf($:G^x-Į+gK]lbMܹ^icQ,i7:EIwg1JМĻB+)Oij 5ܝl6^351~ao̲28 2OL~Zfl\-;ajRsxM太N?vI;=p{NJ~-چB|``'a뾿_mO:ZHqusBk#}c%2Wui$zM쥩NW+ԡb}c _~c|vHeج<2Xx ,T*[YO#&qR4\UmM(<;[fOd6e#s tecYۚnirɔ3jk=.*+TKSb)? ڳI3_<F܎_fA)'ˁh#GjV⸛ jvM6v.oezW9nif3`d<-Tw.Ԝ΅}Q^[Y#Tz!Pe)Qyy6X#[yvc^x5 D,w@]khݝhZL*0xl.8˜2jAN.4w|I`x;YMhF+ 8+k'x&oH1_!"#m0X8e>5{ۉ_Zf}Ǡ̘|‡O'|m<6y߭w0jƿ|j݀nv]Y[zECBRn{z'XiRA5n>~~ϏiH(Ķ`,Br~fw{v(iR q颜/x~V@5F:(!Zَ4$-smb`Gp/;8[Wͨ Y J L,*STrI;vJɣ,2@.YX=F<שHHiNǁAz[16QI)fڅ$%?* Hz"!*tzToK럨8(rkzū'p3&_5,+W(KO3}Y#\BZ㌵9N5FֱEch5Bʙ p ;ҥU D^Mv/)p+ wt?me46og*+mWZQ >~yT \E1ӂF;JHn_ߢļ'O}/ݒ6.[?i.N5y#@J(6%'!:l7,l&8#$У0 BN{YVɳ""1l#7T>0qJp9cp$kWjل ʬҹ$0uWJSs ,3X M\d s`{2OE\h” #:ئb'R .S:JV8m Q)+ɥQĠyaԧ"'Rfb~'C-:" =%ʆDEbc\f,VFv/4Q(i_XE#ڰ&S"`$}y4Z䴭y T?J,M8Xї2W/vD#:p3ѪRt*'3sD %If2ANq Eڡ-OFCyBӚID]dsy|au+"`k-{UOknl*ʝq5QPA*1sEZ{kUHjC*,3R@`lUc1 '8-e4_IA:J*6ٗM9;2TDܡ4;"I K-tZ˭3b..=,B}ss9p -.y;6MshnOO {WDpQي!H8? RmLcѺY[&' r^ =ZF!YUByR/" ' BuRfX+E89|d͙RkER$5_g SR hOE_Rι6q0r2rչ4o[]j#5td^/gC,ollml j3ݙ(1؇~x0J`ˁ* p:{.?CIROtl6J~r|--pdJQDST>jVߘ=8A={ B$5h9D94DHS|㆜<%^5TFM6y[}DlBU4KU d2olT\𓗥ZrkFNgMĤOv䏩o#wBh{aA*бT]YH]A0:QspO@[0%!L;u3ĎC0PπT+{3cEXK5őFnN ZJ8`N̲l>K:p,mszS^AreM(N$~@38 U7Ez9S@WAZb7+7B3-Ri4dDO@v})(-v=G;$&d3OjVu. t34k$2cR ķͳa>*)BuLug x.݉{d[ؐbөRmx<0Z(ZA>/:TNweM#)!6@XR8C$Y$ODVĚ&&XZ>= TŜl^A\ ]9"͌Z)З-Jr\m\&ʄ4iΦf"d}Ϧk}}" ލ"u┿|Q% :z /f% fĝ)p2]7>PHH ;]nK5t]&$y5W!qN$ՒolZ6>3zOjri0OAf4y/6""~0a,H).~.mb仝)J!fJ~n[(jrivTi;7=#VZ<w 4gJ(q}EsyL$֨L\y#Ba䁩g?3wN)p8{xN?HQ4t;_'eKݿ<]S=[_zWZ\OsRS} ,n_VXƝAPM)W_ 8FK{hG JBJx;M eLS4ݐ: )dɛ%&`kSpY `)7իr$Ta6hqCc7aj|SYM҄!9[A%A( &H#(U U϶XLN4&7eY(*RσIBRem2ܠ Y%W)d@l;R8*jgXT! ? ى4uʨ?UǏ%*@IijQ6]#G% Y([a)rpG &S =VB*cZP<R3i2PjT[8{iEIGDKLzxy<} 219O2O>zqWNy o ?rȤZd(Z`E9JH68.e(`{29F$Hߥ8jI8(ia\>w۽ oK聤D[31J,XrЭpNeAWhE72L-D}:uӳ+Q8q.H*\kl6J1}|=(@|Wi*Qݥ0d|ݑ|hGC9Tܕ3E& ;`d7*?ܘ/*J-bbsT RXr˷,m;}lt2.&ykn;+e :J4F\ayTVuu=2p U٪e%2fߒM\KJTGgh[ *M¡LZ|:^N/f}m3KV2S=svT-Jdn4Gخ] )%;h0g6ExfJ3XO)X.kU0H"9T8"Kw/BJșRGFc! )KԙzğsZ=a/̏2J)kҀhhnRS +̉gd$FFLNuA;O P)G:IԎ#ـF,5Q>KN`D3V1UeJ}R] k4 θ-g1Q4kwGEb(n =`INBZz | 8&u0v $C O/>^ eqc~cfM9,Y ѩf~E. V|Q ꝫK&@=,MEzO3O`0 A]Kt&y8D60^yh0Kmʟ&HqfmOG2eПnLh 3CF,v2̉R5sI!(L7rJUB} QigR\_(`"B;jD?مd [tXP\OF-] y|?S "3-j\C@=>0ldȂ^`#P~9]!cRB`.XI8EJ JT7\wsK9p;#Tv֏_˂غol7GIrrQ_ YVPO~)-PAX⡈jO+%B(<__Pzܾٴtd!i߅k89[D_d)FMߒ,/j 6䴠"!Je*c 8w䑺*U\8 竛s9 Djb߼i6a8D4e= orqBgN2 #- Iĥ꜃4RtETxzc FD2)$wx=Qhu`*$~pv9oM+/A)]Yz Ɣ% kSs(89ٓD۞ǝ~p eC`,f;+Ć r>3z׌)@7o4,zc>JhVStWdVea'0I8Ld-C>4$J5S]Fu˾0cuϷ+٢OF m.Y?c ncV//L3DE,T| `1'=kzx5%!Ϗ2_5 :lrna7x\n??z`?' s‘ k?i#lf) ܾKaӒG8q#x| U\t <XX6szȕ &WD^Y" SB,#`7E6ߐV|Cauxf#<\Fx:?W/R9ya3!JQ3{#{PqכFIVtA X@1^N#iAl9>h{Q8 c )n>j gXPa 䴈q3ؐ +˾BiYxV1*m?KCх HaI :PYiܘoűHˆWc|{CFM'VVڜZC*%pѠGCY]RDnSƲm'[űEm?YN*C3׮(pxHR{gd-D9V%K/ m}n>(m_;{sn{ETRjF?&$W?wﷷ eg܎De#܈L#}OH}Z=%ҨJෝ{XrDLcY"Z9𛋡 Y$"D,Pb$Z컳z 8=HxjNw̤ [hV„`n |XYkNxԖ4=l ĿNfG &{H&ܯY ׊au*dI)/ٙ_f覮UaC[r+o&/މ^̩}6^^N#pdrz{_LmvʦbivcipLVNZs]194>-#Kʡp U<$LbzjBV*>i>Ȇ'rm|+:$`}ޞFYfV,-?Jxv%Xȩ1zqXi&vfأ7Ss)Te7铺mM[cic&c9V,PʌIWyٚ)k :'Z;<#"m%VcL|&H $ IIGRaAD:36ǜ'@/z6'h# " T[kVr009\p.Ɵfb+4L] EY0:6OGp/k'-6njWX#U ĴhDV G -T }r6*F^JÑR5[`:ft ӕ>*S#)uHMTVA0 ^h >O˷yYJKQqǢj)oBѬXO"&n\PqYsk;H?iX'\8xį!9(N)xl kR0FZ>[Ң4&nMqU4 h57?PPhci<*ɩ.7/J59FY[PGQcXK)@mJ~ƧyqUJ+x܄FE7FO5wjƹ#ZDC a }Qt،pLţ2+Byf+΋BVl(S9qOdY͌1 `M 흥763v)Iu)nTY4gY핰s>Ugd2 BQ>6NJrmm"k\C6 Tȟf*Oz_BY0ܔQ{ YFqĈÍ_%5B4dNWA;EÃwD Pi@CpBTы3!٭&N XBі4^?B!;[r q<ίm.p1j8A.x" \rXv>BŀsIVRicK3hWaxi_ y#[?\7H$I f=ϢHL_ ]{`N؞3P 2 *we+AQd[+%m ~5_-Ǥc9̂ 2'@ۼ7 8ncSpƐp-5i 1 )E2eP>8.R^&IKĭpp7u_{`&  Īy`{%1&ƥп .HR_ ?W*?l抜'm1zX5hJ+Sf-9^i2\bi1>M,m dcD({ۭ 1eNԔK#V1 81_^>s \EZ>_MW) ,b}=JW+TftZ#YYӰ<ͫBn6P*.pE-'AjϏK}=^&D t_!a@.=yVеKM\"&Lj58888fKBb xJjEgl>$B\ 0(a_xHH0Fm#(J*DXr0cih?:8$_ +zt(?y]?hr# "TfP@Nn|5I3N$a7&'0YL֎| !\6a=btmLgc&}ԼAn>uZ}P_>3zkڵWz+F9v<3c!|.mpU 4ѧ-, E|O9Zؚ5=Z=⥢~,w^6IWhQmUqs2pp߼G6۬IYkN(M  Y_'gneC圌jɜ7-.v6go7/WY( 5LL_[ t^jNcwHe{R ͆0wݿ˺D,`Je- mGzhn/sK^%OY%Y0z ܽ0Z"(KMWgjk醱eN9CD}c1SC,TPD&b)Hyy>)Ա KNb5nd4ɺd7mn_p 7mWYDih%tPgi7ޘ?GE/ 5!u5]ʚiُ<.1~e$$ʻu/atlYcraH/ ͗߳4 &BTE. 8e)HiPHSN7v3GZ*œ搛@S:tq ^2{$Cp'%aVi ml@ M\CRbԝGob Mt=1&܃DT f`g ߁ŻKS8a 5*mWY*& 4=(r ϭ FEk }tqEWxtfSpf|}J׈Wq nOhb&=X0R|~qMDSr ?k+,go!Le5͐Mqk8I>Řϳ<\ q:۽?3cpڟߢ3:]/'^$O=zL#c]sǿ-h1-N|"TB+eÂvY"@ C2l}[Os1_+I3>Ok&ѭpbvPҏsG@R6>Q@}/ 喤a AA mlsBlɣ#'^q;A`bKj&', ( 7 3cd!pKX).D$Q_T!4S/.tz3?4zLWx8ksِa#Gb,Q/bQ ײʃ1 cƻߥZoh [<Ծ:li uQ+f7+83&rș`m&!ԵWA) ba _ƷZ@v !RҮYu*!CձE~$x_vG_+7:Z86rRLhaɳMXY ,wa2uP:Aމ@18MU1mw,'G2!\ZOwFXHQ@֠|ănh(Q++Þ^@Phȋ,J)j &8]c'8Dm8_>h6WS^o/(pUBe]߂DIfǐ\m@^ -v۬$K 7 t arOrGjt飹ӂ?zK<r^>Y56hЦAc%ؤHxfʀp~)'C`$x79OG 1߯C*Ն -q<:.DS-.RM@HRɢnaZ;s}/18%0f SkD*D&f=PqN@.o67Il0Dt16Lii pKk+#q扱'.-?'1eQHS>I6  I9w((V$xÐ tE]_QhSPCK]/~Ayɍ,7,JvR9: _#~;ފ0 Zz?؝ڜ֗(j P)[#`\Df]砃T N&^rn؈4>R!H8+(O6cF<Ɯ6t(z@c\ݪ{d1y2\F׉Ri#;$݁v+{vq? FчHBIhLpdu XVP옔 %_(0L3R)񭱬S3,_J@Et#sU0ݡP3;/ hDWNDw|фff-e]Q il;572:5t3Q(-\ZD7ogBfil%yXs .)fIs 0JNP ,Y.K {D2g@!=54Mx4Ș[}^;l LFؤ6,LW=:;6Mhֳ)5+Ʈ1/A3Z[R(R=H Uwϗ/qkrf dt+afƟrÑɳ }#1>?ޝex}S OHU7ImRP"hp5wƖ;ILZTaùIlQ;s9ڸ ŝ^PNcL̗.-4glSNXB53CL4nQT=Elzv_ $> iAxCu ÈUaQ5%9Jw233iO)d%UJu5! 9{qMsLoA g" E?_Ԉ_ k-*F҆.L&]RgfΣ%JI.Y9#[z5Hr EO0B-Y.2T*eB$9MpqMd¯.C8!Rȿ5[9nPݬ\ooJboߗX[QZ3 Kx9dBaN9Dk÷ lq-MNv%fzA@c n,Mk-u{=dkfniltzp6yf$2$ݦ&\Ū0аÈ*@aN[:#Ûª ,0Q#_ =]WC YA{]ns'zɤ!t69f~_:Dh3 iS{,h?IGJD89r7'fEr^[ 1 zg[;)@eyC&x|`HֿerR~fOVn.lXˎH)Xq8 6u۶ͪ)To4Tbp 4ߎkb+*٘_Ds:2C~rc>;JO؆q Udgxo\8oc K[nF)‘/kz~B@_z)@R$-a;G>=qbƀ|!4*[$7+|ry<:a4%IөMho 0"u 8 yW'vzSP ϼxIԽXlu?ܠN|LG ߕBtjWD\ .'{|M̊#„@/EO@t/n UyH`*YcE)C0/He^g-5$ܟ8>>u 9]v1 i|W-{Tj {qvvӲKo/wSBYP=hb%DI Ҏ*>߆yɣGI7D?=YOSRKl̢{R?a^C \r`!D y93?>`UAˑEs(2p˙liM)q?;$ʜ>ŰR_ٶDkݘB 2GAb[ØNbaYgkϟ08 >[UO\6DT$1Wb/ 97%amQ y?:n!6n3!lP qN#@Y\dA0XKVilS#(͒HO%B.Fq+`_aJIducF4Rƭ2X^4 @V#(1fxX՗fZN~"v{OiG1 c-ً\Xs`)rsf*f\sFy ;U9H*ٟܔ>4.d;$fK=dFdmS;i[3$xnC}EU_|x|HۖwiZwV"C#!S z|RʠG:$4@4^ѾJ>6hb-rդk‰~RcDh4Hml)𭣝Ж@mwam9T~*u~YEKs_[#lv)~R.K7ǦuKDh_2 f(eC]0)QVC-fk{D2(jvӈR oP[ۛ%}Uj#ɔdgv}@Ai[ys@~M>U!; ɏ+w PԈS":z;:cΊx p2}*VfbmNhwwe+d!rDܣ*:±ykj<9]?? U-ﵑ]v ͡/4k!9Mv]Wka 58?];*rz9^xWn8{qrF)S^@R [NQD;DwcB½[#s5k5hU`^p]ø6:_]ތ;FI.L7f0ʝh2&רccY=2*EܻV3)Q畗"92JN' r ){]S >@S }}zK1[Il][5ҬF;]SxFmN8d7SM}E i. moy5 Q 6hWKݏnyG'}f 3rɶG~l|9>r`K"v/7V(.L^Op쬗^a x8NX6 _NFx24еTv3O{@ƃǷB!6l׊le4%بÑ/v3_;X0JqAk\V`$Rsi۸stsϒ4*)C DW?Q*pn[ڇ 0Eէ_j @؆J~>x7Xì7 6lNx$8p^"6焹g=vkFLtk'\'JIn$% EK!K 6c`Aff\4gB3T~UEBW\ٚZ 𚠣MnnVZ]Dyy/3@E}}תTNs *N%S1(lL蛢H<:!>*CP˒8x^n"X`gteSևօ^G[o9!ERG\]=P'xo0_ 9,&W9,pu0-TC Fߋ@hy" k`; F|sywfqQ!i"q޶麲"PĜsNp7% K-2~@,ťfFH%<}9y_sgVȤqũ&# OYЉ wpc\\H;~ԕWqj E<$4Nkn!o[^2j~0 nֽ)ӖBSoevv+c+(`8LZRy sag ,=ANWs߲K8TX={-V " eeBD-s!e?=*#Gkm:.*p!1x~h5FMKn,mc ]9jx#Iǀ:pL|y$I g6 4{uAT n"-Z}b0˒?IL0d@IDAT9݀{ <JNβrx wPՄ+JH'.1zZj<'l7tCF]HmXRoKrG`*:<Ce2ܹxFM[ 0`'#S3xi*?\0KYs6Al`<Q$>t ~ٸZcb2⢺ߎG H)˟Z OMA)HsPlZ>gX㺙zkbFE{~n;(O fJ IK[g^'T2m3<^0`$O|,§PA3Y{ c;j{?=XKb-ڪ(#vA̴O|)'I[B,B~asl!9pPho9G+*wOr Pè[bQYGn"cjv{Kk:ę*LA׾lȾI% -^)?`eD]r"5|zpF&૰?!"?8l/_Fn*|?Csb 0+_/?"'A+<w{.hFO|7S;7~w5̩ XqM \a<=1'A(#[ 8GKqMHD+u.H;4 LҀEBnBud3"Bٲi,MAVc뎇kB|g3Ԡ^ y-Dc) =/iR& v0;(S>shrp 1Og=D4 Hw؛ |J_Mx'8,wMXQtjՇ>?V` -Dp倣"Z8>u_ nBWJ4#f%FY8xH5l8 xqzHS"539n-#n9^md*RΗ!(gn&Sǒ4kd8&D~8IB^>b/#*rkAڠ 'wӻlU$;$VP_KJ )S]o+R s Rw&G/tZ0T;#*W( C>b84AHd1 Vv .l!c_=xoѳ:0!;Mާ8 X}矯3䧬!C^".z̓?"AQ+ej$_n|Ѝ=7c!ŝ\i)/^Y r];Q + ޱ$wevthda|\;>$OLۂFx8T͂]|aKnP|31'DMl1'c̬CS1tA$9JZr7yL77&Һ̫OXNQ̣,ip&`6IE陸:bi,aV%x;%HRL#Y'e]Qe}=ُϿg-\--7E!"Fl!q Cv땣ل?LCdR&VuBZhE+5?<˸<<hbVa pN˖1_ɧ8-}l|+0(mv~45*uq1KN=>Ds.K*YUl#s0 7fum ,d)@wj.+&d9 }splqk# F 0>nR̴U7+dX!zzgl U]2ӣS^]_%ZVگDZ?9<~质= V=:fX"Y!i'SXix7s߆ZWC]v-,dAϬ҇^ @<8vJjo͇3ȡʗ@Nx;` o~Jg3z l/CcG 'ɦ4C 9nPyGaGԨEPKްmi_dUm&n4_ߋ?@3rCъƸ:mxn<؁%GEd|Z>̅/pkw;JDO'd{qih$ Hd^2(ʄaCX@lu֘9Ih1џVcT׆%~/HrkKxNt-ʴ_giW6*U+ v"B㜚$#R]h:O/,bR~z4D쯗́hþ՗ 'j4 Fz1h LS1q\UE!@:gu^h&<7cM5*5RnPTV;3ǩw>QW2'˽V%d_Gp1Ry[ER ZJ%e *$Z^܈NSĤ2j ~f[Q3b ">FWg˳H{,1m1dߙ)mtVގ(v4Aml'>'ffh2ZL#ҳ,*ILXҬPaIpe " r^n ^(]_xQe&p! MeҖbˋkeC#BRؓ˾ѺCrݗ˕h)[3 Ftga5V5^7'`0-X}b~pY=_V,YekkS~C/,~=G5g /i8O xf9`CZx+H,ġh&^uZK 0}!?;i v\I;~ZR0nіcYG=lI@i+v\7T X;e ;#d'&6bi88)7~jP"!}uEތHWiRJEJo $oBLX27l'kx Kƒ&dyOHǩyZŹ?gKch#X0RBl]G+&vI?PHܐ ::,!$qDΤ4 M",Te!x#KM c9}I7(ęq[[rj|o89aDD"7 Xʐ !Nr,#y}*ݎdqiu!qǃ/obD#՟zx8"DHGQLA!+KOGg$9B5#P#N-rG/&ubJ/ /aLǹyt?}{L TДnf73q] & r"*)m$aggeL"[ t<Ȍa/9X4wL7<Fߊʶ:H D~F9VPl VkZr?Q*&{0jN $p"(an;Z_105vҞKp Yx"e^0K#?KJ-\&n>䇃I D(1X7 nD WڼLϲdZ<4R{GL }8ʗP-ku~~7*WMeC˛ 9EKg)P{:I8SLSd2=OVDme#r(7P"IG46O98I|ڏ%-y?cZōMȭ('CQVF:>᱆I }[q)%H&.6y,%)c col}9oԹVVQO~ؿ^%˱{?->xc/ c縃ej,v3L~q!ګ[!""'e;i(iv?/| -3U١E8~?tkއlͬkX?58ZK FenHrw0Q")H9^- N6S<˂(9a>6% Q(NXI(_C܁bXH/K,¸ݡI(~Plᾄ$M';d@Z " fyհ_F4g!@QTY36Ґa[JF;춖8$X8fTzz1G0jp,k+B<:6s`gqM-1aL+EQ6!2!!- $;zIRf rptD6* (>ZwqQ TL>IBKkk,!ZЂZq+p*+d4G E.}^eEPeij\,#@x=']ȴo/\bLD%n ,+^m1v#\4G Z(OH^!VB Я{}hji'1ԨMw36fQVTS/?8fL} ]tG*ňoea&nHbGCkCmҘ͙-sF0,5^#} JA4%qgLW$n 8Auڵz+A*ቡ2vg~?Z0ϧ8n?r+ˀ&ds,aA, pn$;A襔rTK $O j>pJBI9EDA%ynE|>ˆѶd#6[dxDRTC%J$qlCLVfHಡ,ДG; 5$D#xdu3!_g@^k(f& [?bA,u`5DB?  _4LЄ7jGr'YM]w4iOsY9w»!8]*J?'v0D9$fdFmqe?̥<D+"2RZ4]F,gnA4fpk|ezEӑ4g]n10cɖ^+u`DwX{ P,|_r}Bz"Nؤ C0v0NZ/8D`t_)ˁf^fcFYg8p4Q@u7-_fl~0|N5ÑV4Nrt!]M >I(2EjLJ=ZVT#_.t:J>o ׶ѐBq<ЀB9F'aH!kD0l!JMpjR;YgkƟ:h|:XŘG[{w7 w>5[Zr ̪4D T6opB3l5\17Ks3q>>,9c{/w f͘>ۡ}j:5y ,ՔÂGb d!~t(\M+g~?d=<={KpXVqkZ%^$Xx"ڏ8jM؈JiZ &hd=aEk{o4xktg-J(;UYxP.AIMhmB@ahBSlZJ v#ej=k)sS)fXE@/[&<3ܟne޽j|nkE4Nܸ:[Ԑ3G:6(:,Hfl_fͧ®v=6mҰ0_f+o8>.6<9FK i,Aq\.p1n08gq,P59?`itaBL[-;9䜢ϯ7!HpB%Bф.ڭRb:eN`1 PdVmBAy^-D~D+w) 8:*Fb$wecyotNCdڂ U``P)*e!5P}w0U݄Q 8?t Br$G5Ncb70E 18v\mבVD&(׸:2qx16JpnQVǭL5XG~?" 63*"F@HaEp?Vz`](P(,ǻ@(뜎GP5MH&HXܕAorɓ,{3mU tѶ'͔Pf)L%}D9^| Ҳ;;iv '>HZb@5lp,O%|;(2B9ni"Yig`ժ_6 !>3+`92Kd$ָqOx,r=& `ڐ}r$^Tn1!foy|%$d H57奄gqADܧ6HA}S0az!/io:Ӕo?ݾ ӼA{f&O?=xo?ZI4a-PN҄sJ 41΁wܠ:&m{F|p*3HfY28VfbgAGB=b^T+2Еɴk֓,pkt6>kdHa!p^rhJ.=ۄkY3ڍ$QwYרF\hKKP8qmoɋqXBۅfS UXm1:``4"q{HHQȞ^9ؽ,4Cܟ,sؠ=UgC4#XMT%=]ГPrm>  x3j{$M}Y n3 DJHaƌ.ѬE-+d ,G=7 GPQI>G:MDyqX-cT(pD>XrvYԆpI8>rŀx9) mo矜!j29>[m:FTADDHEGX|qrѰgy9 B[X$Fƙfҩ~ODGϥ ?dǒ9hSi(PePU{Zdi;t+q!RŜ}^_6~w0! P=ûzwVvP5K )* lr0L%JiU&NWݺ$bPRKNCrqf(ܧ[KBDI5ҺBF몄 +0'd<[H)Z@$*)#k\JSv5'd>?_o&1llUx$'A>%9hp%rRjx!ڲT.i*}lI/c4eC2p@_MY<w5b'"[dA| i`b\̪#5%k{N>1~?$ "#0B,RgYF_e 1G0\|!^&'jk.Grp30P.IyҦˬ)O "@idCl:Uh'RW^"!cYI\Z#(|CLL-/"3^:0ZQRO2f4pֽz ->d `4T6ǔn%j#P]D08'D@eej(] c,_.c/Z%%Mw@Vt餋dsWI!A NN\H^؟_ؚx>G)xjNX'?ib9p6c Ccư[i?Db!"ö//Fp~ 0lЌX=o(Fi? l2Y"H<2Lx.e|Մ[%`*mFHgbJ3Dg8KqM֫,M}=XA)壳ܷFⴧLIϏjN%6uXq" ʎ υ N+o/SnABh(YQXa9 nF8kJ>%% >PVd’a Ix>SK{ \h:<WNQ(p9}t ->LrcIҠg VYU-iLt[[ݍdf$:MLDxC_qDhXf,c "I;&ЃՄ y ~9&ksN^zi}=zbRN<*#=WIt 47imxX^ZNmdJ8m-@./r0 Tx.H|:p GMɇ<3aVq+'?ynLiVOcZq7Ы"v؆y=G 0|+-϶u`W1;l/&U\s ZHq"nB_?߾^H3jpQb{KK|'*g-S8@)DhQVrGHn$TYÿjp?8Ed:ͽ( Rܯ;C9EC$%utBYhf2XORO01I\ΦD)"EҶgJ&ۄ 3)xH׳: W?#* ;MP}G|VP^4/MKQ 2/P9nA )C~ڝÈQkPCDrv'fk'wtq;r'(΋?*/BF,5 :NES*gG_WCUBIAs{0R/Y~֌@'EEltv.׆=(ĤmbSZRi󐵱~tvc~(rOkf`!b).gϐ'2Va)ڏvNYH ~TFk1:#eOZnsv'TҢeFXwQ^'ȬlnWUԬ3]2\mVd/e8.T|TnrQ_˔ۿoiAfv#墊\kV<;Hr{$1'n,fpvpXZ[YUTg1s|˵rlRΩ$he~[Qzg^|hKitsSOn;zĤ=;>O^j c_ʣ+[ >gdˇԞUs?[A{#M}i쏢_g!itJ]d "'mO4=`|dmq~nxR<|;‹`iҶx-ՑC{67-&vǍ/Yn~W abXS"%dyD̞)th\XAؚ,PWc!uX!G9 GxIƶqaV?M8S܀=S5̾[R(k=/úT8<"!i1 C9\ <$l<ĴV60CC<$#[1THLrpBA!$ Iބ}ѧR A@IDATurCJ Db^W@>r@䍨#a,:8J9)"EB,|Y)$G:;a i za0 ihܘ `TRF.M !bCL833&#q pτЗYgd9Xpi),I:8X9&"8`' !D4gC>M'&3H299K1[L?9sX7t0 *z *s`I<|deTw$P4A~wN@4V AQ-'%i*M qkka1fpL 2Sf/MOө7a1ryQ}zpNeU0H+ _|㧁a$6J;lនv4Q_`ҒFP'Dy+}z=Lx+KW~TQmNdqvZzΒFve.X<)?-B޾s++x5>y؃Bf:SUA؝%\D吨?0p4S,^|8l .C6 mLeɿۢT]_m$tcP۹f> Kǯ-G -yjτx\.*F겗wy=iٵFS(u ٌf۪TBDsĢSɫxU !z}*u{*ă}ěIwT):a%d h.Nqo 艰i'O22LKX F~ӾciapY@-_f*g]ڣ`Y6gHyuU=T 6j\Wh>d.fEDNREHg {]yR8r3Lm[Agis#tȠ9]- !"dq"g0,ă;i@ar5&^{d4ÓZ/E,ed$cC'\`'~r2xQ: #GmG!Ci}@ BFl 4Mhfks 1h[?  Ј̛Wg I& XtNK zK6ˌf rZUjmxC36坸G>|Cëˤ>H^}f u7&5 i)LxBN;d YksnbKǽLkH Q'p{0,-VbNKft@vnUfw{Ï1TW%k&)MDO#l͔k?) Fl$|;)^R桜wO ,єA^OmJ<l\Dh UVncU}0)ض枪BhD { Ql~ g͎qn<5) `&btG  `$VЇ!0t(FvM[z)`H,I!;|"{u+CVu~NxVo@D?I0fL:z"1eU~7m_%Ȩ-D nx3N!zFV&m?F,5PQY5>ej@,0pUJz7 .Ed\2&stkJGbQ$=L6U?HWTf"xx/{\^3̏+lAT4TXșɍc$8l,C[1d+ZrL+DodJu_[|\!a\F&;fNPd+#裏ܞ˚ W^$;vQ%Σ_Q!K3R\,U)lCIgc{cmwΜM;?zJO60o\,_j|X7(N6Ee6V)׷Dd&8 %(V[{ <krڏ Lq`v սyNG\J\珷"W*v"<@ECl/00 0bύ[L1bh6_g37PO٥EImv A0:8GpK;z/;h|r ĩy3;URN夸Ee٠ P񏹀teSvf5ReTMB" pDbI^L1凯4b>5NN]>0POI9a( rIRMq: Swb j"Nl""E)=g6?k_\!WڿǨ88Si \LB{hkKlsJ|Ż[r\:W"|~KFò}1_%FtfCkۼTUv/+__=2g9&!}:m:M~Z‰Qyi4qv$e1(^HpzyوTi4u*lҾJ;. 4GހcEʭxю`tۻK| 85rsK{Qk4_'e%8I;|feAAX]k#ڨq570k=~,1`\h֧@q4L96NfS{^2 `c8F1A)ov%Fmxx{*4>,Gvd|R(ȢN)JyČp FW~5۴I;nZ`t,PoYݝ @LMbT/Fm>')93?#H0)11J{DOLҍM &(՞><-o?!DFi8xxp ^ f^yII0ҽh>Djv۲esD"M&7??aoO>=eMݶ*κR'qfcqSG̱DnuB F-f_KT _kz"Ire,ª{bok|Fd9v}o.%z!BF8Kuz0 vG}.[$.cIZH>% ฒf"R#U>QI]pm&Oۺe ޡBG-J$k>r<16Ry# à.e)x#/ a뎺>/Srk`6*m(dlwa()QX43OW  R:>߁"^)zyOkNm R>'AN)pi R_Ú :W ~FaTxB}vBdus*=nrMTPd.L f\v$U7h?a͓U0Z_?&8yD <$lVZg5z=n,rE9ZwzUl;AbBHJu. tS Ɔ&x<K!h$^wVl6kԱ,Ez{C+h(ob;@^ŸvI!x"ݼ"fU.;_畑$FK=s{WJbH_sZPz‰)t8n{A#ʋח$.\`4E_ZM_:Ј$>!V`U #o8>]tK@pZX"q_r$Dz? (ʵz\C>CǪڷ6Jd`>_f!cƇ;Q#Lc6bCUK\[ȵ6?ouf,DWk,I"$'4ƺXEx-(9`@:^,SRF=߿?pF']؟8:mRة% д2Ǡ1wsrbXLRI' 9m 4bRr$X3%ߴ)0sTdhW^^o~Tc(ͥtEiM9 SB0"@ޞ/*k-e^}2UI._7(8)% }zavSVCFDk$gX YHN%GGDA\S65Oc;2~)"mM[ĵ-whmO%bi,9>vyLA@SO(tGb{ (T@*It[Nxl^3%7:7H ]VO.9?ߗښ1T0](X'egi]%'] ͺ? <$9et@HN[8e*Tm[Kӎıp^fik.U'n_haliz]tȄZ9||( 5"˳[ZE T7*TB2'yl;Ogz PűU+ɩZ |6W|0/"wX_9Wb8)@r[gp:$i%$p<1u빑ƸvE1 ×ZҦ*,;|1'J|.S0]:֟Y9vr %3tVψ-8ڹ6NsMFվ ; o(:SN*La8}W>4R VZW7v#)1 fdsp(%Y$,W|7tk"ޗŘyyz}}:TI$gD?^C#m'd;ivFӽh)n9dBa"=Ky^Y#/NпO_#?e,:#oa.gZt%I9cq|@ @q=+>(ZWǮf*#;`sfI`8oBkq{FE|zVQ>s$^4m:,|wJ;r 6ŰwDd,fr$tz~ĬľB7i1pNN&^WKpF}2&@uٗ0C- BqF=<ў=2l".22%-y?Mm}l_K4Ϝ>w=vߗ?P%Y:_? )+xd}Ѷ6}P邨Ͻd8| _7?[ I9Q1,c'UD?M~~)d˟J1:8iM4tDŽTC%8H>"-c]ZO%bӇ?w_婙V:vGjb@Tj5[ ܯ e8$ˇ^NK)XVQsjfbSg*nO j-C "oSEɢtl_l}7BSswO_&m$onOnA-jfViYddHЀ yZp~o;&nhGZn=i-9;- 6t6?^w֓ߖnnaFߔr8ğA~Yrܕ/Hѝk];.?d"l4 ֢r!iM s7sDb+pcdΨS޽fISN w~iZ.q~V1['N:Q,{yU1m@11<ÌZ>[?nTfvxkVN;̞N9jKdà aK-OAWJ&LJ?uCXA LZ앉fFF9$syKaO*s)pqR0sxRVo܎c Tn\>zbٝ2H{`o= Ulq):ӄY0وj^G裍=OF"}]19tM8?M3&ټ!\WBU4'f@ VZEx8Kc`ޔwi' F>'WĀK Tنl kEz3cgVH$# hAUy( %Zvdݑ#fv[fSK8HFe 3eY\r9ʳ~(ImWŠL$GOh<wҲ`TܴA&* Fˉ[K V%RG4ڛD)Br6#/R8*g8 tq">~tΏh TD"S9Ar-)pET]ѧ7Ӕ MW"RPDGKo4lپ~1`FE 87 n|8LAAe|DT  [DlBL؊a C MGq0dГ`( ʉd\%t[c cbaԎU{Ǡ#avD7_mg} `DOD ʒh[ "+- ,ޣ-FշTSҔGS2޺´yu邜*A ^ޯ})~{X %k"Ci@GY,%8^p-7ySR7O "i[5BS%89QKZzFZ{ӎBy8/>QCME dNZjcT ߽ܤr昴!˷)BŊ_>&PE 1Ρ)"so݌'|&) n:h/=3rR-%ǭU;FqaY4[ 6hsH`Joe*K'BX1W\w3M[&#L&:K}5Ϙl @Sho8n6MtAb (1փٰxq mdq"dz W Ugrȴ%%ERZ%BWdQ|dDk6&:X74rc !3^tXp4*kF<|q$pǏ̔EAaxI+kYtk8c*6Q,:dٮF1ٝ終 S΄$51GJ2~dN !8_SYA-,t9\t5@:8ЈO70)Ly?rPq0hZ\\ F}}%k $IFJx@ir s&Bq>@ pI]z=/n^gJ6]Oo]6 ^:uT%[._m(,v'j@J٠E>aN#c"3bBQY֟;dXqO&4 B0g[}q'3ۘdruatߠTs =ÅCdwAt@B@q r;UG$aB}8E 7y$+|0XDhMwjx WhjaS_ xd}ZpqH=7<AO0e᱈C5x5,KP(0T5- !z !~BlZ] YDxLޛ =c5.u$:<DEnȱ84PFLmD2~@"pڄ#%ilMw" C]Xs9@N!<-5vi61PV ~dU=K%ʌ Ai" R:d'+)!_/3UK0Np"(4@!S@5rldEoJ~2uIl)m4!%#z]A ڨYEANv[7Tb1c:#V%2HCSs]fAz%0yI3}tRXadc*>TY9(,ch_&bZC=#AH{%ȖG %_zѼvݵuS6cf8nFo}bH> 򝩞:VTF"l 48912abm:x RXL -&9.9X$RZF.ސ/B{-4G9i ą(PO 1@@D=Rm" Lt2d8Ǻ /,Ղw:**)Ez^:eh} nG"|9瑪a)3iAJ68GU,Vlx׶pdgRqgd2|kM}Φ,]p7XV(AH|^J̕B.5!((f*拶L\^.l6j4^?TX{CɌ"= MZS="`X5 _(ۨ/pXL <qCM##'\">2([(6OZӐ蒛i$ MDrVSƕ"7cu+4wokY'e <1jUc̮%eZp!/A ;֫_:& Y!R-+q-^clE5R5y{߁xUqHdJvNY3YbUH쟷?w›]{~VJ6&h8+s_~/χf> +37s[خaOYy3*Jȩb͞:!MEw -.2@yr 580@PR*8cS#fR|Ӭ =g ^L0"1?=f63_1+O4bSV 04.jӂ>J? X,ĄJЯBY?2A1]:_u/ |ײ[%@uJ# =}?XZ WxmeJ ]d_֥ߜ\-ȐPr[L1)R*-I!5G AICKmWHySO4!E@×5!zzɱTG) VC]OxQͿkPJ*:w=SۭU^_׼u0&~ x760Db< )>en!}l ||O ͔Uv9$TEAzеUzTdiL>?/>A1k,B y (\=i-&{N3CU .('¥7ږF f-ll&)ӄB01Цv;٨1!d$Ҳv1'lܝ'1d4#.8SʜŋrpT6F$}0I1}(ֳvJWJq-^4ɳh[<+Sl2~-Ί90u0ÅH$>4[ .ڏ!4W]σCu?99X+*:kxsyә7sxRR1jԒ?jL3r6_2C.BB+ +k(!q<.FX~+fq}vApa) p'ADjm.^CNt-ziU3k1X:'C-3 4򪠹䖎(,ߓD-b Qg֟asx uOnK} H`Sm˥mKtqP DUYnbO_4^Ymkglg:l]dsKmJR)< ;FߺN$xD9;M.Uvv\:2(iI^S{rѯ4z>VwK18Nj U!p~1~N3 &M kAb=ߜyNK.-y I y2UG|v@Fpo8pqY?T.DXIɦT}#-CZ@| Au3^)}5#rz8HǠb4 v~gy\YrY@"dZRuW:?| ѮWYSt6Χq uȸZXt), r=mur@OJdif?8;}2"T?1 8:X,H19s:h%2r"#H)K!nQiQYPO;)R&ż(9D]N;WPoT~v#i|ZXEO#{q`RL}u %vԺ0 b˝ĸ^WK];var#2%`)b{O?\Htݖ, elG Dtf`*ϕR~2#~I[a &$Aes20 >BG8]qx.M I|cV'B9l~q&0UIagT~{:(OSK yKy3F_Mx^IhM˨z&#~?9'\A8ʪJhd0-u1 9|<*qQ\%L8QOoj^+E 7WR B)R.Eni933di 1Q`'-c[gn =ţ̙)mfVǙfPJ SP1y=4jil gqaxgDً`z}mZƤ40Lؼjh{'be=A 60K 52 1}H8tLh* sGteRl2smI3PUH_%WO%S֜h/bFf؎o9y85udٳ}P.S3 W$lDά]V1<j7p&C-biOHAY{?R]riXxEr[V8&B"8Aa</y)wo`vHV[wY pT>$8;A+KrS)ݢeWLaDjMc"& @0bV_n$]FR*ՑRАt"n"QF2ZmZj$̰% K(ARɴQ=Q@ Ny?7%KLD}X}$\/vQZ01URc԰7ĞUWJ(x#x\) XS2a oX4+m9l*f1lT*#ױyQ2QX>=[ŮSq070$iOIPj`J?Ȟw90iC0#+/Nxa\K~$ G$@*K=e?b7KʙCfeicP?my1'KqphSHUlbriP) ȏ`󴟼ݱ-֩e} |dDeѕ/A k.b ȤPG?F5TE/E XieIrko啖`~CCOaX@ [ [qFrVgnoݜʕ"zEk0/=‘2L;Eٮo'דETU D8cNgҭpȱ#l9v2wj)1#)leFlHoȁ;1~_, Z4*y_>1S,%L&TJq\A#ůG Q$:“'T*Fol8Ӂ[^PRpw7?#γsН&/ێWVN ]5O b 7`@J_$,a"`puyԃ8za`RWGJs*_@CzpX㳾E֭ p㕷bۡxwqE=pd`n!3(z/o 9iIUJ|RϷ~<݃ґAeQj!5wzFX22^8cG3sRs>^rŕ9װs^qJqo( Fgno7`)8X 5o0ɖ]_ߨ$UZI 3~U0_2GU*bJa@ x<|9@.T_ C)|ɰL=3̗LR{%)bT?(HXСYs#9ƩB/PP-d(PF0zF 7,] mǹvջ-?ă=rRzb:臙t;IkA: iRoR'+$B*M:f% * ?D' hC;юl8mvNM @@]zA1N9\% Nf)qL?nHGck5z'Sȡ't b+eniI^ CxC%l1N_,RXbeޔ2 Y[Jι)~^y/k= P?֛;b67BU!+^ݳ%1-: Un"֞y٠9ĒBQ0gϡΙ˷U[^*р6ֆ9>sD4))`\_y@dG^ O>|OcR>b[3x|o! Y9c:p@I0 oBZ4M2P~S}wX]ٌm Kn9ڱ[&ű}7 )%2*ٵN@XW]'rr=e,D+vf/v0azY3E|h,%rK2 (Ł߯Lk, E wK܄HxǺ$\ڔ"+pأArI*ӱZN6RBʅ&YPB1Č|fLn<i Vi$wq uk`SKϧLӧ::ݦ=*LBV6!n')YQ7q*0Ѭ@R u <6-Ŀ 5!hTĴfa+0.Nzr2's<2_{y:# MC{|^1>Z@S~U?Yl}#txjg]q&j{B#UI@+FrR-l~Y]  <0ZZ_wW~6SF{vQR/Q1,(WdEdD.tGv>*̞>K6}vmEWj)?׏R+FRPuWN9+72<8έX; ݖ},OmZn4DvѾoLHT6 +:۔-_fY<:U&~pH N%lX9vDx ?xA(rA!fn<Ɉ׷m?Of6%A\XT> u58@H5 d'B_0Aܩ^-8\e~(˞g=% [$@ja*~$ǫ->=d 0cU,톕Z"ΐ-=1T\SLgi5P=v+Bq곾V3 Lrfo +>-Tm.(2!-9s]hCOBc[]t2Du#L=-}%Έ* q*`oPZFA"Pdi"x#t% -L/U㹚SH eR=Ꮅbyb˩jZqD~:wLc/Zd05'gg>ūׇɘYP$@Dilߊ3$=rΎP}m H7ӪX".,Hq5 Hbת;V̾|S壈NPR8?${⅜V=.G7n!Ů5 `X{<5<šˑ%[B MIP^xRƺ=6SXRx dxDq%K% Öd0x"l= Rz*LgXKmxv9JB9A=OrUO 2,ra' 91ĸ:M} ;ږT xY)IؤV3t:m4YV>,WZ!g9J=d !j~@pdC"OdrBZOi=t62l5Tm;!Kf)"2Cs<.!peRRBJ(Fg?0 s-4`]+L$u"L .8됃l#k`3R*?!B:KD4/=E y?}hӦTOŧP(v.O;2ʒr󩹘{n'`ŭ^cΠ }:>L%+=$(ЊRWiI-3J%#+4 $`GN6NA87io5`w bTO1\`FMTIj(m9-656SieQ;R>)o3vlcJ~XPVrcRs %ǹh2DR$[M tDnd>K}8LHd%GJĘȸPر⪕) gS$GEK!HBUG]l_%V*ZO^Ӻd[!@Q0z.s &sRw$SM$}TX̝"* 9N`jX Z󶴨K3M ;0Å[)L)iDOĉ*oזYnfa-C;P֖G1,,Ω(^Osl9eK^mXyO/Τ廭mcEx];YN_^uWhoǃ3Ojs!I5Xy,%vh:ϖd q̙C4_\mlه3D`r|I䙒p3A~vF{'umtP|7&,F{ R=MΕ!Q ~Ӹ [Pib"d_5+,>K@,5EE<<ñS{ZidXSŊ|'׍gⲆ b"-KQۘUg`a*QB>aog,z}~?D瓢`a_߿ᰱ8[/ujUڄ'<ܖa=Nq~hnE|a#2Z[Ex{، ?Zlޘ]=Opw2;_VV$y,^1 ۬:b=V sB ns2ZPಳKQCsrǀkAyf՘2e.,"."'2Ȉ~ &X{y(CNRc>[}Tm)8)>CO0sÃ]_P$ )ňPd4or^fa:"m <S;$A~$zHk2h1h{")&݈JR>HuGx%8;EY,\U`"XTZz g3i)և* ]Wz&BA+ Am LNSvD4s̵Jzl7~-s^gr5yQYҌgrs/J"*h춖%Q t[ϳ{-F$z (;wdj},+Io~s{fA*H[e }t?l#PwR1R>Foy gCxn9$*᭾!|rI>& H<=ND+!Bnű&WoC\#<@?MKp,lz9|r+ȔrXسV dD BG.6ݲ.+ME~:X~ͷ^?kYuY*~~ԙi w.!9dGɍ\ܴI%m3\ĺc*I)b:VIo_`-;QKlGk4=VK} ^}Sȍ5ᦐJZҲs[@ٯ(p^<_ċ=6d¦~dBIG#"HcpM0z\ɍceXS*3vhI!\.fR)*湮rԫ mauC&N8L-/ -G2xlTphb3i (5\v< Y&F5vmY:1:>R!'RZmgM86??~.ndw<3Gڣ- "Wh[XRYý`Ef=-CH}_KCB <`ʵy.JBZmƓk{/1?'Lɒ;yk)!E&lw(1je`ƜQXtR[50&Y>wH^m}B\~gr>Dh(PU.r9ݒ[lz@/g2Fe4BRAxr~<ۧl^,aIF8EryZ'Ɯuu^J /G"/ &ďk& R,`(8f29K[nhN<#!{:<7ǶAѸf>g xŗK9l|ʵӯ\ Ge9Ae6Q?'k= . 囹b-",SX GLդ< 'WĘCD -ܛKP %N!"]q> //L7QydžS }rk"O2EHNҶ?vk95*\KH12x{>o}B=?AfxL WjTp߹@=KѰ&)E\i*t* Jv\W_3j BT4>5tAb#֝VzQq6wo3bE4g`m-oBhNT=n >|SК7h4*>dUL.A74ADkgMDxEN:4NgE7!.\0O1346&s5(j=kw0oqȌ4(86qGE sB zD:)UR){)!|&=ychzR @t dHK#7O7"k`/ɘ幍$RxU  Dójgi6/8m]և=#ɳvXcd\.KX>1-g+ښ^e@?5/1 G 9tsrVUz0fiO66"Xn2:+Be,v(7D)%5T,;ZHȏo6mfVpDvhq5ʶ#D=g}Dy6ňkmR2 6Ĺ гӶQ "ԌI^%No7Fb?L{Tf>۠BY8UF#NK)D-ӝA~UR  CO`K^sbH WjP:"{c$_>ب*&kIWg*ps9L q1'iSy{to( hFv-hrk/ b+=0ŵ ^QPգCv~g S^'#1 Yb.w z8:ŋcg䄋2=/L1njMz "nDCzU!xD%*6i{0݃q21`O,4I2Α=oU8<,֥]lu 3e 4:Nq! Acj|HS'YxJb1 O(OCm ×|;fPftAEnɁOR'&%G g;?-u=(fэ%FpiSeHZ'vz3,BwTlTDpt@Sb>*+-{㢹Qto;,z@ x1(K5Ң,Lh)bWMY(2G*ӔcjQ`3>Mt矛!;f$pX…ᅱǍVءB0e܄$/ A/0 V[b^y|&u\"߬ 63e~ZQ (1vL덟~F*wt]z1g>.5W3͎Vr"J.ycu9B/gʄMMƷdj̆>DNCO+M+|]?;-c+U]QCVP-6J~_TF?Nا̛V $`,Uv~dҸԋׂpiAsaG|V^vy9 ɢ!-}1@\32p C!CX;Ƀ'xѳRjyHb"(ʱsGd]( A10{61-1=˶;HeQ9%^E#@=~ :n#rϣFny;o| jc Ȩǽ4#Dxr МCGJnp;&O6.b:0t)(I9s1>6>\y[40()g*oSz .4V0K7U z!k}= 0lL\[Q~8;b ĵ݈q{~m+\5+qCLr 'T'H%=u P8O8F! @_y)"pq/-| >tnl32RM"żwp1I_3&`iVT{^{RbABTd&jw.wIV 8Υl]혵l>iIS _}-HXIiIzY 3&gbRV>Bt@mEiM.j31QC⹾} ư[yjv*褵:f!s%a '0TE2|c\bT#w03RG~"a-RT#L3Hv|^{Y_"b] =f(`~KR rGki|(6|m=囬3'ub*/þ^ԳA B<#9NKd˧@4L| CzC8y34 6W#HA&P{7&1MxN9ƌ(2mˑTRVi5cL =!ktkvdnO9$zRxL9otb5\SAN|)Y9b)+\i)RJs,SS)Qd,]b:!!;z 'P*>yh~x.9Br?) {$tz o8-]`D]Cz/Hbˏig Ax>^NSSB6"v)ZdRS:|fiC02Ӹj%%Ah8M<eb=1dyr-xQFLliZ(ϔ 2)ӗ*c…)%`rn a,_Da 9f;5|% +-ּ5}mP%o$^D=Ia {G0[\yB6 :>wSRק@Z]!Ln %=2fֹ i"\,cÇ2[Z11LNJڠr%R圗l=7䅜F*{G&3}@IDATLǘ忖%MÔ`zU0G'EeI0CTxb r }}:_8AsΆvSHޤ}vgN/y+vލbW]Z|Մe!1)^uXÃTϳM*R~G+q.C :x$mˁ"0|c묬sOُJM.KG »`OD'}N/q27>Jy&ݤG+b!nwk r hؾl!?t왩ghfQTVu:' k0;m<Ǵ&;8!OMT iѳYݸ85 &] %k,R͙zNlD[TWLhHŸjas`uz=!@N#Kqjӯ™ݱ#ˑKn d$Uhm@)׉no/{/vL;XRA.wm]b)˞L:XS#`ufW6#Uzlc !:;JD,;? 9M؅QNc$ =AqӸ+$ŘiURڃ»]vd5HScɤXl[I_m$DAWN_NlRг]/4,؂ 'WD] p |iJkeP79B@?a!K; 3 -R4e9v€ϼScc8F}f|F6~4%@@7HAb`W0~IRiZ[b<ȿ{sszQ ZfDpP^sF ]Z ꍒyv> /GNJy1m:>w4q:fKTMi6vYk+&ЅnmhXo{A^8.9޶M^=HZ\L _1EXy8G/ QTr85 l^Kg~\RhiyQ,juw0Lꬋ}- 6uG~,_ f!JZ-t/?)#ߡ)a|o;4hxٗN>]2 `Xk Y$4d)mi' 0MmmLj+܎Ù5ia =YհP)YasYC j/+6OPT3)itL(“$xr2 ۆ 1wձ/K'X9T#":l4fވ(nO_-fle.UFř& WMwN^|}q58hA~&%pjyD\~ ^o1l;Lk4 Y{|k\E^&\K]wJ IQ/ Tv-Cnj^3%"3^\@YRl #lNSX\o?8V0yzW%Y >,]V@-oE-ֻ"<0Y 3YRL*v#7 >_w׍l,'9kS2#Nƶ ,gCTRc(CZb& ^^BsiW{_ V%u;=ZLDp׾귈Nn-fOB( 3fB\ū)ovgP#u`!v=!`Ll+>5* jg*yZG!30 -&4 G\x&$?t,7qt.\4*avp`W2Yfd'$h#t)e(y L3x0Ȑm. 糺4\ y^$В"f,LvP] ,qA+9>\Qs(-cbnV"u6vU$ yta \=J5}eTZV5ɜ4^)NTIsA@yۯwMs@t^R~Z.Ă#&N.A|˅!I%%ڙ|֑8Ja敍\8Cw !PZrT[ I%DjfL4N[)cj~wxr4큕cX`VqwIC:t9tw)|PK26(< އ6@VcJ+ERR0*9B*.iKTH܄x 8:]yp;i4R3]FVs|B\,T^sBȌxLZS[rIտX6?!mh7J!iVqvνKz[ۭ|;|STUe&)LNdžjoGt}}V|l']2J >OjbW6K>qUN_V_KyDc,8؊[EY}d'f[[)-fܱ,!P Pk2 ay\O$vvX%Ԇg7OqKaU^{oG{~O+6"k*i)窈HiyS$ (8[K3@ 6J-Pkń9'@@>9(ЄJ彠)_uVo>ٟQi?p̷͙g9sjcC#O3AsݓZ$3mZ3*J%_~!]_2U,i",J wph4~֩&nNDYmŔ \ckK S iy8Q|)!UG0|2U,X_'!=%wPsșt2)l5M oA+O(FY|CKě+!(b)vFl+[p~:(*-oSC8Z1$$DbLZj'Si [-ތZP^P8n0p׵|M:*$[S婉E"4 L21e=(kks~0~u-1Q< 13CDؤ*ƹ}K-i\IZ QJC/h!{wT{ uX XT#XDj}`6c<8!8FI6J)Q5(j#pzE>.4o0-myMjV}ah&`'xPj`?+ ;>P4P\\([ wZeVw_ xwݖ#"߭N.ںsD,q<|(x,dTXZtp5* 1I5! Q: ;ZnVfښhG$YC*˛E [ka<2`E>mR_Z">pVI"Gj:` UgnuxJeeٺA:SRʒskE~)MA{Cې痵s3#8j U<"?DI``æ_$5]|)@*brQD.^n\-?0-@C2EE È+'/5 (F?r^yn{z]"+̿"D\qW~䞠zUXu% 86I4߇M3_*vLU*OF@Bfw}wPw'8:}ZJɅ$dZLz~Ê8כ*+6X8LrOJ Q)8ت2$nfi_=JI8ԢZ_Q/"*N/}csB}7v֎mCsl` C:j Ղr"~­v;ҠqT q'uTЁuƷ WsID$ jz|Lv5"krQiqU/. J|VG͓e&LY,Ŧ4 G.G$@" Ւ &*E_SvیZTfZ"L̖R*kY[9 ]BH/_"*O(U%S:̥<gF"Q^M@H0J~BI#hd@_c 1_,VT&S 'fQƘM? znj1-d0_K~>Ta|U & Xc(&Qn'sӞqJx+ů8z@ $bzzrVcFոwn/N|X,bw pˁ$hC*;k<=w$_if9rP̈́oV3q\hd+֖`c)aD7*'Y ۞|=YhwE㊦%0(p)o|yE O7u=5YK[A%ЬK&=#K^7OKQT5͒T<8.;4&i\' 2<݄8]xx٭k iŻZ:md!bZth"0TLMH kpB )1=Cjd;+;&qEr>϶&[#Z >K^7yKI ;P<zX=NNSç>]by0ѭnA8VYEF4;ļ)/r 3NR=Q@R8e^*&1mVKh>\цkX* k_I 4ADM9i05$"O`arMn] Cԕ+r9l~t 0C^f"0Q|%z?RIkΘ9K0PiZr_8o0̏4<])1 MHN.0{B\mBa-OS \㩤 !$Z4J(Xn (L̠;AJwVr_S@`>kZѺ> "]}s^ebK^8NF|77LF,jZpRE-W,=̴2i%a~wt*sA;zHr im dW RДL_ 1(LZFL[E*50)ŵq*c`o\^&dI戲"pIh'S.X6ɁO؝{2T\ %I7V"դ_Ø80%D]5S?ƇD֗_%qr>>MDp\_Uې`uwt j]>f::}| 6QPcPJo} ]}xŶpMelgcnP@/k۩qv1ḿōm,E6Aj+S =v CNꑸu5|])AKKpc 0 .H;?@% Z|{8nBtЦq"Q 0@mhna_>R&Ǐޝ`俳FD SSx);{T|TɆ95et6VPFڣn*Qc]^| _j V%FE>!#;MuKAWhB$TƲTSdYu~xO^ BB0bޜ?k8ʾT6%@0j/?i]>=)K Kq,b te~FPeY GT88l;WLMܵ$(y錯n4V*ԨZ[DM/ 2KVhyc]I$[>2 PKb2Rf6+tQ44f7d: :r&pτKƩEA&ÚAE$g>mBK~<#onH!v۴! 0ū}W2"(|3tUtO( 1Q /u8]ڈC+Wg}YI:";{OY{{O߿,Q+Tg\1\.XIdxG1{xv>ʢyjA 5"\ڿ_"lV)0y:Jr7זS d  ̖NLAz/W˃3L HdR]#YD9%R9HH-P[okU7- #n@O[ro@a WoIǃqOKRpv@F(qIr~kޢF5}TBR 1T¹RWK4z:}jآ+nz ֊ \p;I1Yc|f1Uᣒ箴gQ:/M1H0e4 hMEC<*M3Qt d1s6f>hvۊx} XlJf9Q% uܼ\0Z=q4i=^v@b6cL~[=Ħn-}ˮ,ARmTJ6G*d m?)m79Bx1.|c8ʹP܂vީٕb'F FbWb.L}B|2YāUL{fl+|vFpfZ# Wc9e 큶S& ps^t!IqyΰvLRH #jO+-A7b#ua.8ըoRÎǷCIӋ.y|rC*O3^((Cό⦰/qN)b(3!l!Θ?ɚXe4v)^U6#?Zi +R7-Ek_3c& ?oʜ~g1ٖawq2 냂.wηdDTmϡWrzڪղ֤m̦[ zx긔R۫0^C_ V^>ɑXsdI*/˷C߭'`p*""3v}`r yiOȣ i c%Q7DsԶN2L*C",'ڗu"a6m?|~\i<{d7KL !-M1.ם 'Z꼀N`J7AaeqU5ΗAAIܸ]vҵZ+@=<19\ w"krRn$`tY[Rnckey<8 d5Lx׷*ٕJ NlY||M>e}IP^&lR_@|ZB] +_eȒN):nvG?feub3 \cFo"uzml>BbpZmO׿ B}fsL`L-"0K\LSҬ7Hx.ᙶOwg adtv45"ƖpU 3WLI9 Z :]'`DX0Z6dA|By f4v2'bKK)|wPc?/BÚ}pcvA#ԺxhquXɽdPDsv9j m$PX(g 585;jtFC" Rt. †[.IpyP|w;w/GγxV *_5ղY%^vkHfEQ)_cqYog7nr2CCU.piPInF#Aئ4Exï>>408",ww1Jc6_6g<.t;R{.TJK/cW(7:"㧶|-Qr⨶]scHKL"3?f+?D\9*Umį!wgeD{* s)O,UN4:!\N|i;‰v~T rpdGQ5|5;ΓbhsgUT~(o]2rCR ioeOzπSm9a7ee^L[Fϡ{JY e=r0l(jv=b` !UxHU#2&J.Nm z>1imy f8ad)e3pлC$x{g[%kV;jPAn^#ȖbYc]*(3GKQ0oK,[–tk˒A2V_b+i]fy_.#%+ua*,q I!Y>kʑ`s/GQleh3R%KRQ ˕scС{ru])ՓfHh=qȓ5.$ Z$*pP0]?OqA?' ]}'HYEsd<0 4c|ݠ3fkSw4Pޓ<#zb!cT X_ьgYcfmvQ&f$.2{ 1!XZ[VNqU8葼ʳGL05 \(csbpF@d ; D* 8QIǤ]ǀ74z~cPkI:`YhIPa!͓%Ho`Az/b)2'$g EI1@rꐣW@ߝ^8Z!014(]- \ʏؙsrVEQATlşgD\ӆVZ#~֚H~PjѣQ lo =C"uM4{@7 ]WT.K͑%H͘ K1oui쨌$ЃH+U S.j4i+'IN#ܘG@3AhisRJrGR̔gv8D&6~|F{ 5aPڽҩ=;p'OU]&z5"2$p01 Sddh %Z/[| ü#F%މLt˓>o\R &Sij,,@>0I_A.Tln i #n69U¼ }h].ՀylI]jAi6qz'Y3 =*mG/KI0W _P!, PԭP"/Fd(B*pCrH*vky~&PЙh3LqP\Tj[h &lŮ! kz9% Q!x#ajS&>]έEjktK#ſ1tJ6}aIN[Fa 0J''AhRPo%)5/;x  "0W{0Zl77]q-m\Zri&&쥬qc['\yq|fg=|iʟlVč45Ѽ HsYIE2i\b%d円v";a|2!w!7Op ;޹)FM>ˤb)OGQ,oL"pxkЋsOrf),x: '-tp;XRt>JKf,,G˦\q'*%WD,l=Y7L+("9K ɋsq]#(f, 9Y NAl@t?ݶNÊ}hHCHÏn}'ؾ$`o`8 U!XY"F28 ̓`hZ@g>| Q=-Hp=2jƞ}ZBGyIփ_z48G/{8̏-.8⊃ɾ%ɬnxnaNhZgaO{, < KW$ț-RUx-ӯ}[8, D;(PewѴT],pj5Yd&v1Nl0)uG U25܎?Pl SbCbA -t(!' 9n0 AK?D0ljL#,vrSuŒqfFeGQlUQA [S W,o1O>PD8H$CN gT a Oe^jd`.,A V2Jłƨc ?7JFm)VLA  vk8f-`Bk&@S;fY c ݣ\p0^:J;}JS `'."O=|΀e 0'ӑ,y){M`:XS\gh1gg{Ihhp uË^0dm<ΈDegV)3KP3?a}6Ɔg?"VpLmh\Z p}aX%~R,.JFЗG&M?hS>!aF*[ڳS*cӄGYl-+~⡗KɴߊJiB]TxvU ip-4tBqe#8:P6}kF;?Ur\22\`lj_Wn ]1hg2HzIxX)za> stz؂5$CM EPPI쵿(LE}O/F> TbFhIU*82_9N(rεz0蕵D,)4go3-9R@iWo !%7e$BӒ M0 tI9¹Tx)yDn%>Z \7oqK,Dɞ\sL:/\MTГ*,5WJi:"%g5vD\H.qjYJs{o {p$C$ח]oy@ۃMB8' Sr_jȖB-RiO|NO5ԧh7y}` K-#>ղl^#[w25Nt#N{W<ND c5Th3_8|Wl/=daB`" hd'*\B7#+ D7>֪4`i-^:+[!ZP$2TQY%bNP6\#Q/9m_֍U$`)nr *`{{-]п:CٚbΊSnQ{x.=3/=}DckحC"ovmAM :Pmzھ>N_Yyt ͼBhZK+p%϶Zýh"lwlsbE v%ـ7_J:{ DR.!< iK%>\$#6.KO{ U1ܔhCᷨS-7A\p2K`%TF7!ۊ¾L]\@]&%LuM U:;v`] ap^ܘwF"D0p0;Lpi6&lR񅐦Jڿ(!CBɖN/Klm ?k$4©k YP|jIc2ȕ׳JAjeIq? ꋹ!q.k3ҏi;l?;SUCᏹFrPAcq =iCW(%*)]dm<( U[ ksPҰ 8KZ?>^&U^-쏧cߠ͟A,鱙u)lj0ʞ]!4HEa&nʂ-;q][ik֫4Y(Q}fy%fo _ a*f B8\gQ;WѲDu@TEL9|s hH >aѾrڮd*ИH$0:_<*=9RmLeL&`b ~][{瓃I8N&b VhmRJQFq4 yG2.I?bIe//>H-'bǏןNwoʣ,zc0#-oZo!*fv8QM⚵>wLPzaY_m:D[z^Pd , +:|Z.Sx9[{DC((v!j lZCGB*^| Zm@o [ŧP~?v@;ZH%1P{-'Vro]o&[ "_|v E0vxTt]; 72z7j`W0ڄgqf>VՄ^2^َ\"fYŽ3Ϝu2L&2RI=R׶Yuj'jQ@@CUx%;!rۃ{]|ђX?*H,S[-ڀubg/e}AZI`J=ɲÔ ph}:*T gP@R 7O|=Ylq\!cazC Jvޔb*@;Z(q]vL6*-pFH9s5aE`[E8"hb #YBH]QrjJ!|um{!Ev96zqbM=xt]c BݬqVC kiCv̹@5 Ku7̑1O fq#.WIYΆ1UG7{nz9~Te%$F9"mN T*Fp1 -[(@Q8 Y C GU▚0̆cxe-`wTѷђeNզ$(EO*l\] ^Nl|F<$=ymm&]rŒ?,<\yT+*?o&s/2X&irqHW&IBq?ݏ:!dm9a L _c#'@ҧF̱hA-M!xm-,3*2IB.H0\ZF J8.%>ʼn@HKBrD3T!süۼi-uߓc+Z6wf!ڔ;Y=TqZ{oYrȤ\gͯ: x<_m UOd3Eڂo,_:w ߸ l=t?)dy.qw}`ku?sZ'y6$AF,|<U~UI"𾙑Gddd=6Չ}8CV/Ngun)J8ɏe]isZu4{$|z=*%08,H)d/E_X&;š⫶t[WHܾ=B7/4eo73`K? 'H'~]_(O%`_^ˡ]>o#אLϲa鏃#hxŐPj[%~y=pvkxcZ@٣rpEx|I'O2[a]**ﱒ^,8٣)b.`*ΖN^bwe'Uc>-CA9zM7xȼYo}E#T#(Bp};ڴEu\erP",O&:(٦=^~=yGV tVBбۘDbXR8KͫibqT+)P Uf!7K]R*qeX5ҐL㕹)3 5< /y2R]lcJ+ a\;]A F7`(4Ko`>H=U3}\ь>)[{kS jCJ˩<>UPNeDkƨl_*VhA~O"mugĄ(\;^w 'uQ;4ͫ? ǝ|F/r[2 Dd%^i'96FZ8" T!V栗4 K[:&%M5*W C-|SU`/A :B|t)LϖQH)I 0 emmHoyqYn&^ALIeaJ(⦉a<QRP̳?^ukuȲrDw 0{5.D '%jԕ!M]< F#o( @@^ZcTѹuV~o3"baQgU|5F+q(~j/"!DVF4)|KW#Gڹz1*F@%lq!MlNj y!6@faOi8 {nǂ='5J)EjWXkIG{d@#N^on#IQV17UѨ%1%Jz:`KHN]f;Si00қ<@fHb`u"4\w.ivG՜J !+yӑL6iER*e{6D <]N3Ǩ@L"bq1նGC2(BM(I{"8:_X B9'cQ-l@$ 0|/ћS_ex#Sk.Fi_܅<W :Xi){~Ŷ2 ֏=*i>2Z$?y=6 *W>!a>,WXA\ˌ,'2lKww0M 8v|7VBAN.U\`gH+q:RXMNEK=^c+ vUBv #ҒR_USp7[cJkTRHiJ}CBP KV_^xDQN *@_\hX/ˈ( M}I}3`IH#x$wOy#[jx) #ؔsI:y 8!9ld)^԰%i !׃qO4Nǰ-a#$GjhNAxߠle-<[3މ3^D+ꢺ_IsUb8n"Qljeڮ; *$T/0(ĞAC‚^&KzxsO2!_<۶ikCg}\oF˭a#"DA4}"^Yzy):~JR"}BY>]g4.ւN~ךCn ˭I ^VZtԅza Vإ( @I1JU~Ax5RxRHQ'I{?0B fBe4%rqrvP?緧f Lx?O$kQՅLy(4 } 7ف9sY\dI,di <ϙƶnǑ>+%5$IJdsl Mt[Yֻ2í,*bmMfSXGEvg1l 1'9\CNcz`^H,?G 9L+k<PS2AG#N݀KkhE :.wއţ%ۇ덄A?F3Ef-L_X8t_H%6.|nga{a)Djb+Ѧ(Oϯ8 ǒ$'a(5Bʞ $ k ;MCa?uolYdո1(J w|nV> hYJEX<5-]q:F4[]O&V\gA̯$HN 1Σ@z* {]ouU@n=/%-\)6~.4Y&Ol1!52P6[VV& Z-ڳ;|NN޳)V(RZ;Ő"*P7=@;[XZw v[|8~ҧC_!vFIX dQ EnJ)v &P βm$!,I8qzbԫ$ Ж"$E?^av="~f39>+F5~wr=BPiY+O %3PpUlIlcS_=San+{>,Sh'Hy9 +#E~ 6:ŭP)ZpZJuixz `B|1Ρ@7%r}A!)ph|| ipK8y!:?/@JL-|!DG`j98#0#r2<.#ε"Fo59/)'QqvF%CNiR&BN4a,kB7]3a$.MG|K]ܣwӀ6tp/q"Hw8g%=e19BA3Kg,A.'KG l*Iʄv'Ȳ'R?ksBW XDlowHԎ_8Iz2HЩJJCy{!r^/j=FW5QlXA6)"c. l6gz-/:0\+} (-L)@pBQm1s| (3Bd b~Q㻻[w@lS&1<(0|bS~oG/}vcgB>v,'Δ45ex5;kCwьuWR0ĩZ<%!g;I {-H8f4@@)sŎ"_lC'[ *!h[)1B 7_ώ\)ڶvZDc&~MϨ:Z54iLR17 vQ3]r$D fXQdoOZ,xY|IR~8˧lOdNKmeP=ndo'9n(Y7R6rW1QkŊyJץEYK}ikjZs[9]Ʊ h'6JOh5t9m]`q&yZ yt˅g8-E6q|E&APg_22L!CaJkg8$mwbH2Ss}hxD IʡQ/pu;H^\;QϺ.F6*S 1ULn VEM'(c@#ت{9y:e虇ϗ/Oi}QT*S\̿  ]mІ@߳T1IVE!|n>_K̇Vz,-ǕpyCg<էƗblNTu\<-O֣YB%qdtuTSܞrk嬍RkY =m@n"cp<[GHrk`rrmgca*63.Ro\QB;AuWKtwk[))MMF٩x3<5vE1rTv꒟W7Cp! 򪘱Lh'L:&~{7=y&} J?G2`Ts9rSM*]țCVf[;1}\|BU:o 4DJ/`QЏϯnwi?!_>I^sȚ$K2|\-jiCz:^q-)'5/mWtޕ{_$AbsﶱδazUvlt9_K TvH:%%Mo#f[B*̂d),YReHs_dz}{|{T-v`AŬYaSbݓ)P>6 & =M;w6E VC+Lpݪ3e1yƇ#(bٱ!IxȫmL,Mo*-f_eS0{udMsJSry˃L,d;2R94èru&lDšiiC2pRWӌ*: 7 \&L;%U &u\\iu P huAIEάi#`xPÂkN1F#\b,! UACF>!Lg6u Yc5`D*ᨩy3R{hxxxyeB yJɈ;w~YKʍ܍65c+=ޣ6(ߥi9_{&MbU0NIwV:U_n/ttFS̉!'錂rTXbrWeNj{jOwB"_td0H1R RUlt!bDscJ,>*^]W0j#_,9[ZȨ]O'`@|GZR,u~YgbUНsWAypTY˫ bms2o)[ 0ؒMl%V*<ŝJ׼C[UY H]ByyiVl~Gouk_?8@)'l5R):EG_r>Ej睊qysM}_17p#^F>yBbq\| ntze7X[Wjo~-_ΟP/ 3پ8e]'U\ #6ZEwEݠd<׮(BbdA Ae#]w^nqȡ=CzFЁ!_1.L$X' #al})Npi"okJGŠ V\tʙ:H^0%y^Me-Ŵ_.ݧq38)nūB*nBo|4O6}ڡvXHx߂3]x_+D蒴0t-(av|i$H?LpDlԆOS-/UUА&‚RNnRb?8sbs35Њ@zs]Ќ_[S\-xP0y1PIwj/:[J:Qd۫:uǦBie4-Zqm$tp*R?`GJbۛGBիsLe#^SUYO#UtWb \mKC&C=П0-F*^*{ ) o:3T B=GV~6e2B4O6lv2K)V)m@0jge9LN/yύ_ۂ.)ŸòmLxvMO6~auys^yowr9hϮEWB)ޅK83cKf]),tZIi]PۆY} r_>% aX^~/2H)G0MaqGSĆMv"%@6/$bcp)qK:BssL۰>: ?wIL[YTzDmWUkV0X\y9ቀN;4'͖KDS P!h lszQ?F xxTO M#E\bPq¿ U7_Ռ8TDí0Ӳ` -TU%gQڤ/%b"9֝aU/ly78.|b++ـRDP}?R2Jyƃ’C$V"}٨" iIZѯ H[ySu([h[8omM+1-sk٣fgP0lx2g/m+lb,S{q)?dHSP4ηPN=GJaoV)Ö I[<]b";ĈbUɖ?waڃnْ.YtF-Zxqպ6TfұS$ e!&Is:\@wA0pJFJ1\թa.1Fg )΍+J%|ԄIt >ܮ/CS?ؿƀ+5 YpL/Û1q3eo<9Hq=ޱ%61}BU2ȓ b<}`ҽ) ;( d"E6"PݶpU1,/lIs85aH@ԱU.\D ƣ͝k/[_MÛh eY>)_?WqszӽHa2f,8hײ-ힰl )aW7{^m~?q3^G!{02{@2Ɣ 6 O6NF ,"eS@Xޜ538ګS/6yڞp- BBe*7Oޫ\b ˇ.&mxYnʑD|-QUﶧ#oèLӯ}ԴH>0Ϸm ;uPa[-Q.~\Q&%x2f86Oc~/z8*h|8̊GaJP'S$ŖIY<K#7@IDAT.vАs\E z=@A fD B%2 ΌI-1ʽ~X dFzneѴ|=50X"w֙+NLeG*x Z puBRGFQ,KaU{ T 7*f3Y琻1e巴G=/T]ZC7Dad]MT}̕J=}+8qp%^c[434-(e` B/M ,"lR^zzw >1}#sb3O)X gL_f#ri PT@5Ak"{̙eoS46Κ nMX^̵??ZaJP Q,)Riι4M\eFG "%gd#8Ǒy]]SےOfr30#Qq@F)W@XO"kDV@UnH.: (ybҦ;d@HVՌ,L1StMDenQ QL ./8%PoY~]3y.ol$$}hB' ȑx4M!69yrU#v~ u= 6tMns?~5ezYD³ׇhpv뎋qV&;-|iT˾`HRLשԝUFw*@I"RQ9R Z(]ꀤX1.*F(«F(u<,5*ܭEV1Y՘sXg4N^⭪8>G*U!Ve<#ZͥqEq >`覵a2(1Fk>?LZtǥsuLFA0 -cܬj Aa~xQ+H W *4DRLy0Pca;.l>W`a6g 4% AqfSPe30~EI&& 4;Vn+\1k/U&[ɯ)D:آqco42ć,?OM",2^u 7R3BqR^`ѡObc^ Q?;6b'cIZWY2XsVu>@'%x,P`9skϐ 4Ȩ21QrFj*o$ ;UCZ;i1u"3ik6*tUxq&YjS\եm]Mwa$dyܮ*oe>*:x#|{gԪګj#TOiӇ*b0<[sCÆHx{]Hkm%d콗˃Di_XÅf`s /Ysý.ĺWv92Aq HqCx0,Ao?JdmlUϫ0ZEΡ;)\T1[Gj 2f.!nrY ' @TxEUBU6s5hpEȐe_م0Yd9*op%:^5 m`8%BsU<t•2BI"pVmbZnuV ;1 YMٜ'B aFBb#ߤK|0,*[q63I,E}J+־FRO"@xr^qZȬD/[R Rf-\"6ut&)Qb, exЛwIgsy XԠԴ- ]}Gme,DKMQ5 1(.JKgXK*-w(] ̕:4As4}<|<% ֲw$ d(-Ca,$; ĭ7L ;SN)=#;,D9ETH+a# %x=F @<$Wcx'&na* +3@9!iXDA gA *&?H Q-%Qa4I\oi2rKR -gvm8b(8؛Jџ(@Y>& ,8O*³^g.Zyv.u?zv2QX$NhJĐؔngePJ X D_zӼ`twxW(5hRCq (̃O\Jfta1~ؐ[\ F׀Qd11~ 4 WtGF ߬!/en-SwpQlٺ'`$Yh^ficT]Al:Ik ](̹2,aD"`߆*|9uWNa%ALJ =c:9 '0AT-/j鹨1e3&dFSa(y7siMBK+d i91.i|XLlL)+rdhK'I޸<`ԫ->N"Y icaE@Q?Wigk>n.sS*Y\?.oT?ްqpjr3(:9a>&+T^P%d ʙftMiSvu7䥎2z:8uE.z+S(+Z9oV2̲bt)n"|;\e:saGatKVDHibLd?hijZTIV}oѼ1vjʳfX"o;1t'4&ͱ6Ҁݖ36@v(a02`j⼐j)3E~,ft 10l-ఞ(NZ gDž#TpV׭qfל,O X8^f`` |45!{ƗLt 7ڜl2U#f*5-t4)aZ[M,褮2.~h[ENGQR8< +z _1@װ ?3fU9ܡB_=)(F5iDCR ]O61~I,k;Ƽ{!5?%h#vxI"@ɕ]1bDQYnheobFE4>/5fU[B/YJ|Z6b 4,9q4`Ku\lŒj*|P= sBqX=JvLj} PTUt0zk:QGER\3LJXյ*Ze=iG-cr5買Ez,(f|)ฎǾ!*s¾xiܡRy~^]; r!8Mp-4M\WQUvqy0`s]Զ+_-vXz'-1uBqOP}9 ~\ݎ]r\]1LY[ϓ )~=von[%уƶXj̋V7+DkaDi PTrQCtIYή8o{t")OQv|]nzᰝ.^uk+V-5b:S1WwȻc-qzf#x8QnSA,h CzJeb)F췽GR\ڡC2@߆ahțd VLc G31͞".w2ד(?(͚(dz=O[yJ]Ubn01D'u9,h+bgˆ XkMz}[x/7Ֆ\vQԤ8) G [P˼F$Oj:-j6[-/W#-DstvxS=S% EtC=<4P,r?HC(Q\a[c^ݼ )草$RWx7Z;-- (3i,@5䥨ƃ4 %i$g=-F 'Ax:] E Sܪ3- ]Ky'%_K`W˳8x _@bXmh-+~r2a+IX{fwE,7O>J+8bdl},ԉ1 .@Z fpZw.8K7NZG. \/"~pC7 mBi*iİe:`Jד% F;&JR`i+˒tWɜ,;X]%4-RUtBP^.E)o:ȇD!&p>s˵ސ\ F5NO Gsz'JMoA1?OEn|Z ~5~ ZRF83%V.4//? q>9ƎKv  MˏQ]ث|eN, ~S*>;뗙/!M`EJ1pex|MAe}?ML ۽/@~Q;g-=%ۢ*^Rhv6.,߼}0id#𓵸rjΨoE:i](|iou$`1;LejK-Ts dg2nzCLJ~CǨ:r)&N8Z4g5k'<:>y4:, SO's8*a7 f= W!s.Y0r@a ¿.Q_NAWQi r8(\Ż8#^o$Ա>C:ӣfPB'$*SŃ 1;% ~C9/n5RmL~s Awx-^nMOc*m}D~&REiU򓛓htɉ,W8hXso}shˉN hyltckڟSRko%5v&"$0ENUM&>@ د,('4d_NF_Nz hTCP Af[Sys|/< 񬒮VOMr(>R()$$NSLW)fx !Cԛ&c/:w-(85@tde.{=@:P`o&oۥE(.|c˾*M4G{S2h Ga:PWO2Uo7΄hjW=o.I8OS"I‚*oЪƏs >0V9MQq4e[ZE*Yocԩi(^Dr>|#0x$΀2`MP:%!sJ8S^di(T5DeY0xYV۠MRfFhc!AJ*cv2$}`&Nna%$=gݷ9tb=%-6&Xi1_C|fmsw )Yr.2r,c7I`59ڳ ݪwŷ-?=ž@W y=$t@/AX&2>vHH'pt#zdZ.G[EN׭]^PiY*hxJf n,6p?Wp E:rwb]{5{LP0zp˹zB̨rpYXaa=g]=-DPqsF1Lm{\ 8l9` z ȩׯθ㠂$%8lvఋRP9`CTo^m72a0N*H` ^I%h%o,{pKdӯOM4 9Xiv0/]$yŐI02l私@0 XcTTe+?{ROETdE.$&Q:D$k42Iu| ĉo7 ȥ-u9PrX(e* Wa-m[Xf>?͙.s/="!L.OM.Kf=R'?Zy.H1q~|a]AGhя*tEQF~OSRS;}N~#cq~|sg%r?&eXyk`51Û2A4džF_ftOClB~:9ytL ~R8>"Y(bn1ZZz_nyntPީ]3 O$ s#i~gl# 8fanj#F&b<Kd 8__oɟ-?g^(ts6Kp5Iv+OϢ9W,rڽwW0z~͐[VˉqɁ`Xyn|dkA6 RZ uWIWZ L6 7`f>э7#} ށ2*{!#ܭ 9 eΐG Ed\ W` |!6֫ dX"M_8'#ǝ)@CT,S LHOz(\nxA[Bw? +rL܅ `#hY -?hmJUD S#E521,GL=C]I\60;(]'j*gKCfQ4B"^GG*py:CJ4vZ‚L?JV>)X]jX5'11nf[Y)wgf,B !GnvjXb"C!}~Yam?A~s?+\KmnY-6oȞtzLaT WtCg&xh)XTHɀIG sU4Np^L-$K#.EW>{ M杠Bkj,:eZ\VQM}3S+7rzA@Ɲ,.8:i^ }d{~W֦nq I*#!ȩbw6V+lt40fT+7[Փ\U@'(J1NVȕyy @d70D}NeWjRcV^xXa#,?k)YqehບV(JX`{ *B%TH\B}&>>mX 0jAF7nJ!@ =p~ƅw6Nb%-Cyb;uFmOW)YVBDpѣ/,DBDyy@8?v.j[7'[{.0nKu︨ E-Q$tNW06g5v 2 QIoOQ/M I)j(CFLٺ]XEQ758NTh\]aTaXxl޻]-Ep;un|iYju,{FgѿhD/EV|[V67%kTnVk/ ΣИ]|@]Sx=Pgm ,`pӦK?d!p5f(C+DuNd%(!Drh,r<OEh57o ©31g^U(A263)zV&^;̍o%~U!nYD MO=FSCz 0̓;Z"u`x䭳(WWI{s{R@93fVm-:+ytl9(-9 ẕ> $Yzwד=(A-Dq"E,RIa_RoT[~?d[ne15'-fGaz|Ö|Y~ēAoTi]&6P¿-Fm2I$'Es$^NbJ yL?2#𛜦8maC쁝^E0 |"< vLsQ IaSl-21LCDIK([mZz;\muqTRhXbR=1BO N3R@]xҮzYe?;8kBQhEhF~cدPF.Aa&L.jsWqBʂMFq_R@rEeS>,Z>,"m Vi(L5O* 93HP<4ZCCaxGe$K%TB#ukaO*$XiOɁ36p:|,5Մ1r<ۖ l}z2g?G78Pw({읻|VC|0)Lo+PJ\\I#c"^YjMS_h/1 m_IJjөX gM+Br732j P)}sc'jI2}(欷^mï Z (W@ٯ }I˯Jpvmo;I} p􋻟Ίir?Q>^tv:7&mT *t%!LhxByPX,ApH4+鞈IȂ 2@Bﬤ,Np ,'d2*O~oLtVpYu_nRXd.2w G$HzwW\%Q$ UV~IfިUINYSˤA2H`p%K(6HQ0؁bA?HX!<ҍ$Ȁ b ݜ?Wے ^< ,%f 7 y 4%cJa:%]zdдTZsr4ˎqqZθC* hޢXcn_o]n~#vn#9)d+RK%d̕J`(Y!RgZm4Q~=9IJgNOo-oAqB\v/^6B$-gf~-BRȤ3?(AԴ6vH\~HSVٶQOҪ8G{_AF+.z@H ܔ%A|VF~rgU"i[;ӧ/t 'EK,jqâ#+%K,֏nG͈o ;{Hv̧q\`hX Y9^2ywV~@Z&wr'mZkl- R|3[6F.dZڶ(>ܶnͰB'`~prnJ[*}&+28Ŝ8i|KCڸە@(شRyNCʋW*+4_hۊg cE"hotvԇ~,#ot(1 +ߩȶtF pH!ڿ\vYVrXV.U9+0V婳ZhV[/$P+RP8ܖkwWhq~c< dJ|c-6s(ۏP.Q%9^g9l+хzJrMXǹDMBTIJ)CJ3J@`=AA pE| )\ OFR^)!z:e!9n)Cm,jݸү(B퍃s,/Nb9d$5xkJm3ow{[\R_5:sy8*=F߯]V";>8H5 !MӝlխE#cDZѨjt=0ʫp OcHR.麨@6ۙA&3w"~`"P7w6rEX^ 'bľLavO7V{JFڻmyءؙ~P0Q5Q}djZWGLD47<0 ؈|NG:5'#Ggg*Y1,D L;R! [p) lQ~xQRX=d8BR`NTj7s` `ޫ~d{ \a|}R%KBc&]OJ(¬(L^ VpD+Ay*e;)N/83-ea ֦L7-H~\duuVs)7NsIPM9du1>US}0SK,̟3Jrn@Z1i=caXx?%)+l~PxL5zY̤ط ̥<R.PJJW4D3bTno3 E/XTY:*vtaGU0Yͭ("jCF[deHWR4@lT^[z_וC|5 W.wci|pX.ݵGO83x)%gETMxi}44=9v6T>$Yk^~! )A}uFmkuv@{`||]X^Tmˎ4᨝$GFLxhS%hǿ@?t'3SG\ 8S*(0ӦH!8`V4 [A[ exgzDyNښq((V(,"e&SM tSEK#"LpGţdFh3~ {!-җ8EE p1KoOC py:TF uEcNnŮN}e[՚n$NO `N 1֑Uђb:tVeԯM/n];>F:/Pled `~T/'ߊyV^8'HEURKK-CD )Z3}۹[/II(8%| {'k* l"ÜsӁcV!NBQ8&Xoe-ʹq%C²X(`3b&N.Sh(NàXp+"@`aё"&=4Kccf6j,pm"Fj02&1۲ɝM}ht0JX4+QvkFڰ4KNmMW#T=|eCgY9#hPf3e@Wmhsz#K*>G:9-}4`\6 "B?:`hrٰ3>`J9%dKuCék[/3K$9+g ],8HSFM3\W%gFru c6iiշ7LyTvс#Q7~Po\W ohޥu]J_`Rn NlqŲWm aOX g[;=QPl qVI&u+WW‡]1tFhh.Up돢T;IPR-u E!< 2N#}X0 X FV)я<9_ 4AIr0&3VXX>x2"^[ujLuO 9i +)cV^!o9P nr[EoCWDXg:zKj&@6XBI msSB9`TrU8 '9HP1EL\sR qI枾SʖL M4ҎM8a<ƫ+/<6ӁC&O^,]ۭݭ5r\O3:gu&eK'ڥ χj,HBDmk,8gwXm3RXćo:K?iB\)QYOZO M{#Ln?k4/zzL4iPPncfWhwlaT#RUrd2@> K`sz? ? A۫1>wnӈSy8]iޗ6.{*=~ U& :"k~}"dU68>Rν1ݴ qYs 5-)c耟s (x RԺfe:[OP`ORoY4zc(#p$%%%l=)N~U#Pද.2c[v ` tD/`0d.MjVR^J(i9Jt)|U.xPJ!1HS|m#9ػȹ.}f>ν<+cCdR8 9#K|bRD6d͉X(҃5p7PX\6h&(ZW}+Ykdȟ x٩! 2 9g*S`0ZrCx a_뼺}hk'$/G CoR < lg~w c9 6ʾ=} &Im^O u&JǵވU I5AP?!b ɼ#X<O`E1f(cjkU߅dQ*@/רy~+9Kk5ؗwumF[y3 $52oԕz"txwpoVjx?6 !B~bbv +ߨ$-LAL5.&o8+ZVAXi{O5D1e/JU'I;bs4@1R):Ǵ[Gsls"ҝ`D;6 Q,ӻ\RiM]p#BGS)6dө*42-O\CTe=@'N` cLbܘ.l\HŤqm[۫A m4E+'NZ? FBGc~ 8AH n&=jҫ˛+wJ JVM34=GorSe ܮF %jãbX0u{H, E欕7xCPϖ IÔsCQ9!%1;,3{0O 4TW 2XYI:JoHJJ^3x{h bm1/HJq^SXy mPVkZY\g!vuL-ҏtLU޼/'ul841Y"OJ-7x$xƖT]aX=<.'%!9E !81S~[ɓvAX rP9 8qBsxp/itbqިKCDJwKȄ2jkW^d6ðݭ N:9alJ`FCh;KW(c/c@,FKXQux;ro-7T"3iJ愻 W0Ug5كE OI( OAl9Qho;Z׆Z@c ydJ=c ߗߝJ! x# طdƘ@tN)W_9|ĂB`xW!Wg jkX^Ѥ3P5;* &^Y~Y NE.ҵ.=^ѥ7 =.}GrT:Ro)b%ݎI":Ո? DmQ| 9y> M65 ŕv k}ߠ8gmuaqgVFCMB8)= Zi&:= aL>4{xNh۷EC1QH_ vqE\h,'84F3FlY$5TQj)Zd_Lć {'?XT\rЪJ'h dո Z@4D^!9gl νR Mxqok=p@J '|zTe.s^5=/ HUDv|{R,L-=0 R i^B+iĚVrh@EEwdK{/[Mjg -NDY丒ˑ哾d W!6v 8^Ż ,$"SCi86`0,3m?j='D/+wID T]Lo9Rԉ.dvSgXԢbQ1I@Q_VgQRy 9kGko8GfZ!I"()20rOamp8O1|RUfduVy5mݡ {'^A~HoFt4p)r3ѪC챖I@. _9rBۮP!L3T[F;O"98Yt oC_㠄6* .!U}N, %a /d$J1%RabJ恝T0У\ =P1!929Gۧ `RC.C!띹޺g C ݮPlwJ!N?$)4r~u[5܂ne- 'w8?rb8=ht2e{泬}&+=Ђ2ͱE_V,0c*E8䔶LǺkF}Ѿ}$M¿MU^;pÿ=A,DV\0qCaJFC&\ɩ=L:!d#_lN~bS#utd!Yqz=^7j`yie12'}% /nS[?}Dʔ X DQ[o7\Ii ܞ?[򁢕j_Ze c%lx ~ށ_mbTteͨTެY:ʷ[gًKmKX532kݤ>2âz0.n΀uj o鉵y|ܕ'n'Ze83MKN (%~8rg/90+(4TVC|򘞏y4/ϯ#Lsq&?}K~Y0J]#$X^g~g|7s_vřO $Gtغ3SpO[Н %&j*yX؈O+ YB͆ M؏J玅svy|e-RyuQv)`*10jD 13 ?e&^w3R?a9{`;; [ܝ&ɛLIu&b>m![c9|m<%9qH#GEpDi,7Nӈ2&(Pݮ'3A-4C.Ӷ8J.)%nJEvѾW~#r$zX;!AL75Ӗ9Kz=,Q47NtqZ_ E!tPar(^L u ;e1|*luqu\*h%wF?5Yi('Р].eH>zo7۪H 6e"|;ߚ;(wF`+ǃҮ <}"=wP5&ALaGMn:롋Y ɕ%+N2m5sE(Lu Nra7#3El!:w?۞U Z CT"gbvI dUNUW+)st~~h7~%}(K 3՛Pp媑UݐpѢ(p6,*a)-%EE+;AK}." |>v<[}W~rիfՄf)Z;rL~8D#QiuE(`{|ƊȺ*EyUFw-OWAjWp&- Xegrh?m\~q"R§”~_vik7-zEsLsQ guWf'YA>FJ=#l41ίI3xd@YkJYoQj呋xET)Ad I0r4g27g{v3Ֆ@2n1- 3ns}bAq|S'XYWT)~Dw+eJTS&6|@%V.2K7/ǣ\Pn-v_j[@;'}{ҕAӸ$BSQ'oYc߇Aoׂ&j0FՖOF@oJGs១LuƓ,rLsz}'kE6;I1pd2:QPH `d|j%{cۃQ}W%N2=&dJYXsu2o"$͈ڿ>-)h.CH/G@ul3,k]C1c|D.@Б##=SE;8,=C8Hd&iXYMWeAL"UaN:/sP @A1% y4/1f&o8!/"eTQ)Ug9aNVjb48A  \qbWh+BzrƁz.nZ*54śwgI$, P2h>1+޳\+L6ځ{{tJEJT2[y5~tl:IAH>JGdKl^0я*R81M48Φhfd,W">0Sv,Ot(H,,BV$9FW 8b]GL#?0g N|FV%]RΧā@k)HT>N`dm/P04sIF(_@N#\dLm?+2f +@dZkJ=|c[ceiOqoɣS5`+/Fzq n(N.yvƻcBMY dᦴ='A.fdpĨQJ~eJs 2XRL $GsZmȰ=]"$gn? =DO^}l6MB]6lȈx3KłB-2XIjTٖj_lM7.=-Px*ӂ9pd9oDxiTl˖mK<ٸJ-:Yp ]E ( Ŏ`G'c762|Ly\ЮhyOw 8(Y3n_۝$vz,dC;Z 9{ᜰ T2C>s%-vnt޽PAary??[԰vFCqL'$`//V'+Ty%AēTc_5!x; `x,7fE;S!eL>tᓔp-pJOjJq )!@>FT@KP3))v:h}XˮU,+/(KX4gb_5H{U ׯ' G/<mJT{qPn ;@dI1Q؏URT៭h-:E+΀_Q"sp; f Mo"قͦ DbZf'Z&ځnlQ DFWgZ+|h+iL\Bwq"y_pj(oQBT'^$a2?hٮ $ ,KPL?ڢ QWZa>=l*x6e;zT_6 XV_B_*L+BđORF*b8C0--(FJC9*Li`?0Sņ?n"!B@m% W:ZǐKtOxodHUcEd01K֥9&5JELp2$*~j=2 J{oq*KC:.FwhO0z[Vz)e~`<8$(X$A3Ǘ_N@BF JRȽȶfu i)rl+4FvWj  U0r>oT(4J! (ORܟ6&"lM ^m -a{y뿨ҢeY# 3M>Ow}$~a[)8ډ݄M)C$i3 wsГ on"g'>`ҹ+_[`0^eJ ʶ &gJD[r:E_ku>X! /o 7͝sfi["odKJ+i,Q /kIalbgS!&['bھKݨ |p)IitbQ DlBF R6Q{s ص1lޘX4MudGd:!9fNihb|A/͋hXмv,*dwJVw?Q?GQr4Zc3,5&}F#FV W"H2rH6vTOҡ&"1 ?irg{gTtN=O]h{\ã xfp,p0)?.bgN,wTclDwA ^ O pvKUIT:*}1Xdi{tSMHC=wS$sJ>:ث GPrȿ?MJ4T%֒Yխ+O$섭'FyLdX50ɞʻ+ٲg6ġfHa ~6A30;55pc }^Ay}p+IexM m#B2SXI>(O{9KNq=U(aKHA(K,~4dɄ8~Vލĥ2 2ܔ@g+<$?>ED4au>&+>Xal'km|V"QiZ9&xBzb[VZ՚8ԱcxQIzpSZS-?T.#NȰV'K(/[nhx;TvpϾ2 Ag ~S" *"2$@ Ý}[|>V;R;r%C q;FJ財'bOxJRDbyw"ΛJ1"&]9I'Ÿ7JVv L0}g+4fa[(9DN/Ạ,09ƙg#rܮΩLP`3ǂR!ҨD5MІmTm&@qxOq ֋Yn1her?8C0,VBfpLWSfZ@nO~ K&b*cDxp:>IpmxF$!gό̞ͧO|J`Ðlo֙qK}t<)v( ix_GZ\:O̡wcg8rp&mH+f]P P-XNK7baF9.15p׍~Y:?q~0[Ԉ Bd&|^P˔1հbwd4VFhQ ˮ訐_hΉ|/uǻ)})rfJ~V]j[Ee[N&jL1D F=5 sX%H SA2@l 5S97yKx% 1g㦼+0yUFƫQظa a .?XDۉ*+=šaPan1'j]f3s#C9?d+m6u~s<1ӅV&tjNtb0+ Ô&Obnw7Z:bp)cvN[#P'=0Q;LQTB@,s>ݘ(p ?B?&}|Ј"pQiDF@2=AoH4 F;/*Y([`/wbP{Z1I΋,$j ӪVũUaX8)d`oɏh$4/r'amzAߒk+[q߯H@RPXuBewiCd]6bEЋKC=^ŏ8-#Uw1|GȉG覀;ʺGȎ['CfCGB~O޶O TaƳsAⱂ߀%Ybj\`K| r#it<*I'E5KlU[*U(x 8aѩ-AN˂7,fxj롖ClIݿ4R[R^`.CI;SX'\ w8L8u%"rL#:ZzSj%lo/5v`O\ֻ '-X{nje6V5p|*-0[\ gY?͂=*i'.41?}dGNAH ǯP 'D"DKE:+-XHHi1ع%m^ z"yML w^.ɻR}p sLi=5@'A6YzlzR =tƀiDaF>s;NwY:憣DW9~g\N$tq'CN ]IA[8vbX?F,~x>w.˲;LcB(.` (J)kVיQk 9uHyfp&jsBiR7,/ZW!. qWx1 2o_`Dy~9Vuv۵|XRKA\*vXu BoW(c!&[ף%'+Aדn_~PP nXzIj 0N\^!ש(Ku`aBN'_^ 80~XP*m$u&Mv/n 5^>H=ҒikwB<ĢEuVDžU>1 ?CR-K%XQMd!q-_q<<񙺞67k*)y5 }:>;S[|xB~9q6<2_K͋bzPZمr+S4eyt۟r V{caM˕0>05l4&.6JQ ~'t˓QJ?Vl98y<:# y*XǸ+36)_=Llc\i"kʣa1,hx9@9>qp~ۿmw{id'iׯ餙NrR:v&￾ϏT(FWL,II9m?_ MozɂNP WvƐAGȦnm t_nbkq#futz:]>Utdn|Y?oj\o.awi[Е"^@N9/Jm*2lRyqAf Jũ[j lM@>b>zx hi$`ܤ}ːQfkLW7:h@IDATqr. Dcq2&8g<0S5 Iƈ8W'={.0"-[ ?YmA5M`xE@őZDGKA^ N72O+D(ȱiR_A4m{<8kTu|[+ v2V-B,bzK"az_KM(@Q!-kհF_Iu~?LO=#Dp3y\,#8SV5GHR$o ^"'r :WsT@o@a{r+{<zo1-N[SymZ892jI"ZP--&T ћ S,B}o[mLJr!WQΝq92a9VxWo;y o_8?e`jB2\F+箧vR %#jR:Wm)@v?k v 0!""((gF,=f?KdW?9eZ&mpHsL KMAⲙSRcܗ,1@9ؒ\mTX5 (@LoS+P=݊>ƾm%ޔ.u@pp"Ǔڏ6XK:$V?\G /]bh~{."` $PįC$xYG1 Ti:Qi-vği{S+|"lGL &D,:AjP޴*{d2[G `CPs<v$3 sW'=;50\6`%UqP%n_x%m,?P#p\#0u~K4YRm 0ў)%]57P oPP,Z}*_pхu8nOW%=X+(H+L)-3܄P[c֧,EpIP1[ORxp>X>$̑TC|4F TSP'pHBDD 21`oDQx$N!nIvƃ5$@|DB1}\O^JIkMTpX<ڵ8ܒ)Qa3T T5)S c 9O5(=YM[ʡ4&e*uRJutGiy72GT2r~.byK %KcB*&a& )C5YpA&%V(Nq; kF]চ2aaM Uo XjBK h1Uֳ`H"I9 {̘sػ& 3 c~] ǞC$#?b١3c|ـ[ ς_:鱔Dŧ0}m*B[I$>aT᧓`nyUL>*,ոel1^D.+*1Y[SUs20,"_ҽh (1Wʩ+C/"S˲u Aȭs<ҸS HFXHp# &6Xܠ"8[5|ٲeKeŦ" ;HqNR=Yz~Dۢ!YNݓ!dabo"6Ulg:L0J i(qE@S:fe!{}cG'Bi4ۣTćh&Go9_Rm:tM|WFR(26p:ʳ0f0xzR{eٻՇj ?wh2a~%ѳF˱<`;]n`%08y'3x}_"@(2Q~/[::?3bDvz!IU؀f.PxUc>um="Gɓs!ȔMشWp':DŽh|$D2rkߥEE>ey]1WuK*XCLyqZ$c*Mwך5`1CR&z&\ݳ޴uoT 3y3Nqž#A,LUK- [ҒtѰ9œؒͼҳ``8#I qW˘QٖK9zѐ&w>΄M1!*dN6e/@NDAR;_8Wpao'&6@*qGc@ؽI{үT`6 NgИm(NKSJե:JXn睇A`.iE*Lۆܲ,j8c|nWGO|ӯ/۝{#$=9SPo2)- *ț,ӫ@S^O>Ky54v6[1,{é6VUU78'S87mMj:* K(+@Sg\Zβo{OїYyHd1&ho*pi̇!F<@=38Guþ ly@Nz8oCpԱJ+=) B#9#yy@i? )am@zJHy^>ƥ;'Yh4ߡS5(G)39˯YZ2 BfyBC!y`f/"lGM{¬* ў,eS];U)$.0 1EXFEj+3a5g3_mbsrL*bQX.}vw2k֑B wrјQJ C;BwRMc3|2pNnG(%귃M'IqvhRLXJ4%Q-Le1Rxڊj{]:p@0 vӱ"0oi_cK:>iև;N6FdX\_ډOKgܚƭ)pu씙ٺ ]k1V:xj ⸬`#Ŧ؞"R_Z#t6[UE@ ˚2'xZ<J>fs[kl- 1>ܻ!-x ȍG:`=$t{zptd F(dLٴJgWwΟƃC8+ #o h>Fj3F5-B D׼Ggr;gM 1T*=OcP3.VH,: -+w󴬺m֑)T. 6я?fgq.R8V<*&PzVO@Z=ۋxp@y۩xVDPy N&;0I6ţwF5EVa432r Kl (#Ё{ItL}o[ykY NVR\6#1P+~5/Y*@iz8|0^짰S˨L ?ON),=dG|~ȋר''(fF዁TO PPܣH ?u'twFt&30-~|h/?@kRq\G206@ҒV'8\&dZUD@oኁ(-DC{/Xĥ^ ޑtpT;ȱrP9l)[!7Q"0Q 9 _ hk/1O0 A5)LP~20=IO@N[#f~KBK#%[0܋ld, Vb$u4wG-p [kT2d!Țf<* \š( TN2C;t#lU\RoeCgR `0`,i1]Sfmt$ DA":2ǀxrWTñ@Jꮄq=GbB7tx.3 g rjbƌe"{K!/|_ t]%Ҧ&倱[؀ E3܏aM1.&o#u;A)rP!>?CenɳE \gwS_y{A6pi`ȵ Fe x4G&7#ZpÅDCu < :E;G1*#-' 6-6X8LqpВ:ͻ%!iզ ܶςzSEA<l(brO!0Qxd"NO T!r欒NF'wO 儀jKX..Tԅh0PKI|AMߗJ&/%gAd"Xi=1I? o4$Ȓ};#xř͝ r@8a5˘Wg4ΜۈeU^UsSqS-@&Jp p⊝S'2pYN[wGpzIG!7'Zv[Lwd{`-(ty#DAI'f 0߯B{ׁԩ$~ΙTͼ=+~Tb2Dwre1 =Ѧ&Jُ@(KVJ@QM9-Dۭ۫9jY74"I;T/-pl bkXDWdH 0R ønJy MaZGM N뵜d_ad ~tO(s(ⅶX*z^U$%尼~us< ՁxWC0p~K $?iG g=Ko>Bt1g sԩ͓Ue"Sm6y 'k'Q{AW.fr㈈RZ2EPp*OcF_D_?]5\Tj7b!{-.i[4!#EC'(^`nZ<}}(/#_x|V\+xzxݘ%` dE4VSj`F{EytsȻ\ ]!}8ر'=L%:gR̔jX&N}`hͿ*K@!S~޵2-%i/g>BɄP ۱>Ǭ=` lds<6 eMO1%PA|VQD+Nʸ 2 ?>7e@߰^٢L3KBeރ )v@ڛ)b6QY=U<Ԉh,Pψgqvl"ZU " OՄ3DVx'UZx MymGHE3KW>Aʥk3y י,eNDK"\Ш$+Oz(нdʣ:t(*!Spq2 4B~ n"5@p5r>Ι{LR3LYR| f;ܘ;!h!ƁFYzym5~7)l˘UNd++tgXv,='-R @W FŷZ=1 xDhl]GWarA[Ĝiv!ROSeʸǥ0+.LvNz]`P ] GK5,aq|ѢEGUwtj`Ltv|MT\/׏4@)~@?4bUBAeGs]EC\}Z4()4o)^^`>cG#;EBg:&_.>D^rPp m_є{6_rZ [[m$}(}JXNECwobF!`xPԹv&vExfС{z:R -t VG^~wi8|eӥMϓkG: D}6.'+{@+SF^ 6$CǜyTd{bAI9?;ysxR9fOYUOӖ"bQ" ’j9ͻ|8M#mUB8r?j/g|jRxw?;a][Cʢ&{HR @)-4jY>褔QzѪʑ_&Ұy>w}ws:OGw47*BCԐSO1(+2 }젖ef,}ʖ(   7uM.ñ.l'W|gb545-eUBTwХM8-Ǥ{L&,f+gq3F r֎Szk2{;ٱ!!0[aF*ghIjц779_Ny bnZ射䷁Pzݪ=<n1rW.GDCMVH*.ëvR߱AkE2@sDr='M1^QC(7|'ZCThSFi8LlNs#bBZg] !LvX HU]6e;/^6qdBWba#lvX# +LOeb0mhנ}9~<@SnS] 'Z[5L,3怘0_@Ii𔘏+[H ܳ[=LoHCxϹkf YE/#Z_O 2m5-P)bm6$ _`9iLz٨pfY_D4[4B+iT&i$=SZ% Zh\ m47zqRyPU]'S#>\$[r :e-g+W+O'bb(Osr!ywҤwFSD J4 G}SeIx&r!سK_JGRmG&oرk7Yƻ^9bUa~o25^iz‡ڟfw% 1 _TgL3AeDAFDx[1la~W++3n%nD7R50iHX0aBYp *yfEeedG3Jp9#pb?jwkyx+-m ;=CC硦E4$"B\|y?99eK%Il-ZèEh]ʡdj F,=]}BzfJ@W1jxjh,I%NZC5qA$Lb%U27!⁝Y3Zamz ֘֓KeT8qׂ*hi6 F-0q}X-x}&sw͏I}Ѐj:28@w~H,g>m`ܽQv_:8RL[ ըe /ӄu1e)Pʌceؘ0)T=s-\jSAbx8bY2BAAW&'"+o@} 0ħb= {uU3)[a;HĹnjMLҠoME>4tx.Dɵ ;]d\!1cǓڌMva!)Z_izMDW$W3`Y=spEg)Dw2As/z3}[w ,߆%mڼI Bx ͭiI;ku`WkGE. GSn/$VЌZ$Ҍd/&lAS,k) Ӥb^6Zа/7$sWZ$hLvu|2'lP-C /|zY4t; 82kjg)p?U¯08\-'@@eH ߏ9[m6ˋ!?+(n7@ '^P#Sab#i?,wmgu%Q̇̆$%i ( t*R9R7ױ^@!kleȲD9CO/>aܚ HIŠԧI$}zs,x]ohE,heK{˙bj M~KetSr,tԧ.tPsU6rBĮJ_IMRJ0CtSAb(Khɬv8 v`l\4wN z)v4 F=u6MZX/xc"& Gj%#kJݓ\{9zʎM_ '% "_d] #k}`“ty6[ @$/Vsߥ:#~Dw(6S_1w2FȆY"7隙!:Mkrb*@̲'\-:Ntn7Z|uNWQAv7Zhk[!gAex4ύ!#'pD^3A2nl^89wJ1V # 9 ޝ2D5ӗ"b) G'xZ  ?֝x>HX4@m ai3!{(VJJ(˻Kz}+lN+1Or9;4,yڰvvؘDJ*aE6|K/$Ph+T-̥9 ]) vlx@wd288i1"xrq `EF&J!?~- ̧b~lUM>k5{RoԆ[ҝM!:^{3C5 a~kA xYqb0b+Eas䊇Rb gDnjQw&}2z#-;n+I4K3(EdZHuWoЫ!$ gG Iq7)z7a.'-a$-]ɋUXf=j['vdcFqZPM{Q}.{ޮ'CB19?`Auօ Š$B: Ep9Q&N (Mڝ%syјE鼭7}![ٵ %cقgAP[187/8wvY>qcx6!+m*G(О'TWKy"wj0tZOho[ɐ~Ar86&RFab=)[~Rvii瓨!zX1Tg&\ *k{~*޳"Wό`IAAk2\\1rg!#{X&/cc1@0)7uqM'JCێKﭖ/\ 0EVs_p/!PtJi VFߙF蘘Q:pPBN1BpDUZ8l{7j[`';Sux& ٰ!$C#ZFMbK ?/,?:W*<]mJ}ǗsAZ#wP.4`{w<;s7ÝG/:Cɚkv[ast64E' 8P-G_:ҦItn _XWȸnfhet:k# Z69=ޥ3\{] 'LC/256=B*YmɯjM+I,e~U12%!U:b T:\ϕ|KWei+ :wxqmLX) O*CpRcxZezlecw,$v br4~@mi.KR )@+$7dB|PpTI\5BTlj*kR!뉭'X-3y:eh] 4=ར|$Beic$MgoPxշll$`^c3.zKsAfGN-7is[̮wrJGPHMޏJ^LAn}u|yyh(.m?WוN+GY%p19Eƾ;S\ʯ80@=Yn^Z=0 *oYp/0.pgIȯt,M̩Xچ?x+U+p~{ ܵˆȋ9v}O%O52XR| 0ޚD5#n(ŀv_QQ&}۶i7b]E XZh:tpsrB(}oYGm[1ƋO Vt#qrɠEOdzdN2j\h$#찏H[F4˘~wCSjES]95"ưBE]PDS.-B#qFυlj%orZDxcf90_/`0W" oTT5-DyK+yۻa-)KQr6J (\T#JLT"_|ϰc<XQ )X@xUEucu 6` 6 =~\ݧ\3jmzy#X$l;}7D( |aD^bdƋü$wh}i3VH/9 #^Ū⇶=:| S%"1E13E m[wҾ"XP6XcC&>'U27XVe͹,) nf5[1)l v m5'͈q V!F$q :NX|GAIP2CTOZ/ ?6e^eMKs2w-LAw<B`Y]н0rK9s4$(8,ZGeް]zz< 63 aE9/Z+n|RO}g5?,RR j &;vn@zre8fH{ &mǬsh@Y u81(Oppǚ@oPS|Q"FDn^͑XP aS9U{׽"@ ģ%>XO+vW]K$E p,&7;qS _2?J^#WȦE|mq{R5Rى"&"ܐ*R-]"${ !kt{MS_.4ṋvQcܝ]x:*׬ &MXaz$.8p̍*6' ,kU;m4] ErXlxF-lw\'ϸ1ht3"r3&|և ~Kourؾ!|PԹ:JFX,ofboUf<[J} I9}L)u,Sۉ?ǘ,Xݖ7 nTǵ+~*51wOKagW*dM$%w"I܎wZBsI7 A?C>G0_0W=hӿZqxq(4w;[M*wj$[z<BiGނ{gцǻ[МJ%2;0/Ўkν,D pޔWb[=C;ݏWS$/3@vMRS'L-{PbXS)/tPt-ab'|mz?\0¿SYkg5Nv-?6_1pA5Adt:H~s|i7tJPi;1ss',nR+K`r%D-}i,pm2$p.Dk}G<(7BT$˳3 !vl|VRĔMIZ_@Ho⫱qg+s$\VElD4U)aeج*jmCF^F7j"ng3dP,!aqnbsr;.`)ۭ( G䮧KvǷ}]/Nh?t g~l2^Y/'+(X'?*Jū2fr29hbPCdg{| XXkrԠ mAӆV Ÿ iwKbh(\*+~#fTT6>YhA_;?L}moFU^O3Kpee!pDhKugp Dx}LDʲ?-0[p ]SEaAr?U4epY fH~}19!y֡L:ib`%R-bxV*+|E D<_aJ ૓Q1S mDӖ9qƐ/hXAH:Bpb6Qs$siO<|>ڊGO >NtVJLi5{Zh~ā*0B(alT YxUA49U4e-]b+)qx 9D:ORJ/Ÿ\GH Lʃm3dnpm5:5]Gu_)n5َɌ/G{l#q-[[tH6ճ/C?A*4K/K@F4fp& |(9v@M ?kEYptAu'Cz^`[DHz(?cSN9@JP@DS 2ٞO_ZpDV k捞VBf@cO$DBBD>5tȲG[7AYƣxU@nPY?5dy[Ht/YV#F#x"3jc%B$-HGm9,W&o=iϵ>_xǂ8s)S&Hˏԣ*d&Z:r~f*ȶU5,U9?C.La=ߢlA0Ee6CzyhsZ-!0= +G_f"\^Xj[6=Z5{B ={uԗY1aS͏?%9FJ@ !ǜV`QXn:D8 h*vK7YHG#V)^@"[6řjm* $;XO v .}=7v,; 흀 ef8x&.1`̋lATtj(H0K}4IKHJ*B4uf|z_E2a֫7Y'i^Ǥ«8?GM%/1"&#g0gz=ep&a^ iAlʥy9qC׶Pj<H )jV2`= Y2.+zafuV0=k FH@1Ԝ`\|ʮUһ>^κ7|k @g.jRt٪{uwR $iŕvD v%QEQo[י[7iacG E`sL"F,|[)҅V"WZ%_dT ׋qrp ]f'tr`7?x5L~NejE} eY^Mc}3eR0u?9kRȍi*H%Sޓi>a\{=R)dlp(.JAb;~OwpZ[! (8;DcU3Z)+C5Qajde[~ha9 ;έ 5GHZ]u;ω/˷7e0ݏa_'i#@9b> L/##-4/}eLcbMW'B AMLtxWbR<Iݰ/LSmD~J{ n֊,2:-U>?)İFHkx VS#PΚEHX-)A_잧)&kbp*N 3 ק%y+b+(I#F<;#"c݁Al>XzXv/A<5b6$%w d߁L@ͨ[1EΕ^8 p(wa÷ɪ15T l4Ԃ4YKAxL ~CgD B0s =Ax , :Ѕ1=iQT4eZ<)ڑB 1͆*?l^':/stLUȣ^Б OVQM)')ZdR@`'ѯEn=׏i 5teTo8cZF f_#˗rwrZrS:UElA.? !)9<|+'0_4p֎gQy/Q1ڴi}2. fz^XN!fuԲ(V_;/Nt)[)}* "xdV{aEJ@uڋ ] ʚY4\ptO3Cb{^l=r.$W\{VA"Y].'w~_.{^)Ȼ,=LDs9 IwZ逬D˧c6!zu2tM03FR3ϫrYȯf|ۉȠܿ']a|^ (U S2w"ٯEoF:'sϋaG//~ HZ V" 3?@ѢȺ&FtCE+wm 8guz?i_]Lc.ByKEsϬ(ed(-HL/ᬙHKV% ,F8ʩ9Pwbˎ@]6F }=-1J6uA p'2mAѽ\\N0z͍4h?pFbr-Q}%iAO z1^C7!s^cv~@}&80,dR{ aFoW1tm=UeYMD`gF>D,UKz xAU5TBE|CRCGx6UChb3|ԭb(Gd m|QAe(is[\2eƬHͩ6Frm6!O˛ʷVYVkZX`ܙiK,p!n܃}W{cSVf7@)q$vMep G2X q 02 50#k\?Fe(J0 IbJC3 [A*=${TCe f)Rxp?~2@Ul]A^OcypA/>R5-p7[cu[3DR3\Vӽv`Y]Tڹ>w aTf dغaZ-4m u0NOupwA :'-c3x/Ne~c.P@7А䈐C:^,F_Xp=2Sˉ=83^_}! RŬ1K'I1l&MXilԊ uzTQ!6i|Zw- ?۔-2;eT:4>9s_-tR8c|+X ōܮYګ#z@hDU5I{2΃Y9'?/mx$j c=yF_o|s\$^tc ?|O0Łavɣxws js06/VĜ$)īV^FlWn8#3 Zi"C k\>gك@p?iЗh7G^S\]5]cr<˜T7`4IBLډ e{uĩvjZ8u0q\{bWB5ĺh u/*oÅs&L7 Coʸ㣒F JӔܖR}}Rq Y+p6ݸ un+Cg-Y̰0sBQr[5=Kf@H݋ b3Zǖy,@`n[Ekw GEE , O{HR_rLdyZk[3#$Ɉ!< r 9>KhЖ#K/tBN bZ` /?-_ZJ"@ÀZm$fxQH6qanz-\dxLƠi 7w՗%q [B➮ e7Jm2eqb2]cٖ<1_K!TӞYo04V.av#E6a!<6+[ԧܕpΠơTi]~ˢ`sTS̈́ " wzDG!q^u_|B_^Q $ɖh\(`HBȃ L(79LcOdgfLK7;_\b2ЌR^C- ֐ȃi6r1- 7zH *G!IMBqGJ )RTYreh6W+2Ιa1`R\f?>A~kxgtƼ4u|lV# '4hhk#D7tpn 9(YѢxӥlˁ݇2$$tʍAR #E53.}T'0/|-̫g!MPҐ9t|)V \χ cT }Pڙ<àf_ +9@ #6hP[v8f!2&ۀh_%eeH վ+$/~|;m7Zqy XcT[r D5:zu/񸑠 iS/kNO wp˭ ?hiQefUf'7I${eZTVuay$"dF Փ\.؃,LixGS|*_DO :r#/Rtى;t=c5kٸqP {_~JB{BF.G0nP#.*gzuW*T1}VT Čޱ>s %~0r,`#h,VZ:Tg˥䦂 $z;VH#Et.2frsP'A7vA珣cLryuV!Zka!twN^G5ߛ6uÌyƃ% &d*:(&Ce#1!fY)|; i]e7PR)nrҗЙ#HOՠ'_uCNoS'CcRRPQn_Ԩb Q $X3M~,ܢɮ8!x(90i`Y>1|m>{rg:sO'8T[ ai1qkej?8~O7qcZ'e}sc~?*q[SC*EGJN K 29%^"T<ؚ n >{{ sRF;O誑J+{w)'@ԅJ1?W`CӉ¡QX61(Ұmj$Q)p.P`c7V ZNdɶs1? o7_tq`D=o4{XOm Yu|hP3%qAX2cKW#vWI?Zfw+ZGu9L$8vC b0!6]Cc[NRܵ~=a5"lME:i*69l;p5¤ASkЯf(vi:M{j""PWYU׎mg];:^[Y5-A _)OasR~%pN%v..j{wô!Κ,L B+.A- x @ 4l96`8퍡hKCuy;y/ .jv ٫Cew8 DK8\A*M82jdAK(b)zbؘQ,IPM v\qH PXQU6Lab2P.JѮ.sU Ow%ۼzD"30HiTAy.,nj$塒9o8pz.~o)oNFGpOL{Q_v'X YÕ㺡yK!O-@iu׍p{<>ܠ,k{ѐJGmlV OQQ:N9ܡQA3k{XS{ر:H9bl:ɶI9E%''˃ hCތ5BB!á]uAI`k`iPh\YÉWLk*l=o5Z%ӹ25Є3YJm ~v|]~Ӂ\ltoXE(7}]NlEVզ~*:Y ޖ U |X~ (_Q/3Q{e-9Hq?#s',;V >8T Ҷ Z\/z&/u`ީ9k XJdιK6FЖIKIX|~-jL t<%`HshRU%8⭏G J㺺~徭NØ4 wqkAjx<#z8J84B?7__~(C'. ;KWAj O)A%p }AU2xZT Dhʅþ pds1[IϟLޖO+Ȯ) v8֋bn'|YVv}=PŸi̒['rCχB1bP_mk@F4a5 GkһW9Vzsr"";|N#c `vBQLXdz1?xiAEJ"`VNx@I1@ 'GFEI:m g e/.=\0 W%W8yq1,e``p4f bԫ87N 3! )@`[mN ..Qbf>Ȗ؏o 0@jTǶ‘f@6: &{ŸR Yq?qEaZgd4\W[nѷqf.m3aF4o5ڤ|s Dڦg5S?IP/"Ϊ"{À_o0gYm_w"L&(VŨ\JgIe:}BRn<qk GT4j[%gJ6+֛'uOJ'T%*H5*VKX$oώ 9أCjR%G}NJJ}_G||,I- Y  Ô9ɨP'C&oe8( wxHʌrhq 4lhO7ف Xh8c[MwCx 匛(H+-3 㘤u )2. -s4 T37gs}8,=  k5F !;T  ,;+tlҬOc.nD߆#t!-O׃dTG#ɱIg}~#Eß d wN. CHcB"h#Pe@ 4C|Ε"0Z B( -\X& tbՓ bbnc :_""H}-B-euA?PjbdE/r{HTLN(c P"p̹uyoNy6a {|kF-ן"bGC`.á Qg͸D":sPRh\=h`Ş닊G%/eD!䚤(g:=4Ȩmo&cv){c=X*e 3B ^wߪsӝWQQI* &@ h[vd`BՅܫt gSjPOkI׈~yF.C7$Ñ)3Dv,9X-LEsm_KV2 fH2^6&LsJ*unk[جES"r *a%Gznbt]JŅRSP1RFy @F)Ix) zr`p[6^vRAh*ОW,%%ȉ04,;VH[lp=ǘRFK'(sop*mcg 6V}F%}~_ɂ}bn*2*y{<ӲrZmk-<7_p`J#pDjIqJ- {b\zk'X)5'WL,:@I1#<'ȳX9 ^u,H>u#q"#i\:0}Jv2Lv}gHx RQ=\LMJOР=%b^m|݃LOP\~J)[Ul5fu|OUD+pʿ <=YVV1vXf񋏑,V&-A!Q)"&F1K뇪"E9瘀9:VIeCmYR 2tϷFO,.?&NC o@bs >Bkh }m.1!jad_n;nSMk#3:uMCPkhbol=>7UU&D26 R$i ֶf*`$R)u1051<=Q% lCvs7{4u6b[sۆ5zeXm?$Zcӕ/O[).OTns%9TV #: H| ,IfD.? ҵyLAvң%ڜ]F3 |(tE[B2ϛ[3hx%V {e4 Lm`0&Ès@|8# Hd0OxVH h܈l4gNQ+߇EY-.,c>B!Eb' %Uakãtcoxv*0R, `u*' ; AUEQ:z*.RYSvKE-F#ЁA 4]p:*m2>hh:FzDI^L"_9gOjX*@h|Z |@e+J6%K^Y9a p{N<`E!Aq$L;[Ҁ5@S6MPcKl޸fSp+wmA#T'&F@QuQ<07G"\ت7H'YhJi-8 z̊{Qзh(Z$zBa#鰳; Q Ѵ|fgy;, DKEm.+R 7=)P/rZy(m,0[F: `f;j~K*3LTlbC%iJi~lqf2qm E( 7NY."qo=ɾo#vw{uB^ }L$9[JhfND|AZkoq$1nD/09>5x!ԩ($e ]ؚ ! "J_?W  Lء8,\L3AP;) 7|D7Sf(sV2{[p翶HWw{1kkʑ-7`<*"tƬ2fNaﮒV@3B1Q,yEhJO|N"lίaV6+>N؁]'UItMk٩HnŇpD|Q$9`:!.̯ p$^*E$ahM#ӗ>.V7Cp@fl(Xux?`4!Ki&\"i%ch4QZ1$Uϗ)9(٪45jaޜ}0>c 31ՖOự[dC -+'`m;3]IΈ*"jYVJ]׌ FO(Sq v2`ӄ!pC n*U)J@qgSW!'${ ߁(y(^ƊK;ًp|uF{qbރC8wangPþrV"`Yfzy~hm9M[~ORrBH/Pi>XVz!%kbpP{"phBaP%f8@ep"ۊB9n9 85nة^_3T6eЏ R0JDC#NO'XT "b;g]DG0 m)-gh 0 BMBUNc2B42hKkjYJܔ@``'Ҏbzc -T4xcrrKfRTg5!oXT,p`}z&6~(7> CbP9o'0g/1loĊ0tŗhqMBs 6Ű9YfV,EֵpDZbdg @C>Wj `0*! Dw*Q4x;-{xDC FbbgX$$"-_S5ꈬ5'7byě `t\m D@'&cr"0Cb4,D'>Gn OLT#0 oaES (. /.BV ܦeo R0#w&BU9ۨ`?}˸#ʓڙ]8Y}(jLq^i. efVBVByS̊IN38pu_wB0wj+;/Z懖q8ȤBHd<.G62Pt~1w)P@IDATBGds|ƕ\J.pB~h?ikyƯeW/R067C1)rPvx`HxLM0uIPmyJ&qڱa[5 ;??6e~ړ#GdHª}jR+a\8 %m9 0k\`5m;Lk5߂C: DqEJ#wut: -.8FTd.'Vg5NF N}GF- ?otM02'.L1u\HMb~+oJ4֗?[v(/*'/C"RMݗhRD bInNZij;u\}_pqjrc `EaFʪX%O^Pr%Z qE9Xzn~wGfh jy7&b4˦j1k9 W*yBQ3ACQipj^0%-#6rjQ??_sJQW⤵u j! e$tإdD%M U$ ݗ@b\ @D#aF #\ v-B#D|kZ%NZJʇdc45sx>ĴL_f^H,q(' $c_3Ȱtǔ$Ò-+TyJYC_ RZw6|lifV)E%ˊa_o$O2.ɸi2:WBUw'Ed;$nÁLQ2ƪ<l" 39 ;uj*TMNlNW`>0kz7g.v3Dl 1r:e_*S2TZm84hcٯԟV:xnEdomȧAڹo˵2>OD\CnO_X<VuÆ@%69y*@Qd&~8z9e,›s:!PWJ3;LH\qQgD!t ]v"spv66h~3.1տٍʑ\)X-\>B,1t!fDU\Юbdemk$E1S MP !AoK`#RX^ؾ0_c2{MHkԿܫξ`SBb ]L<%!vPRhGCeJ 汗AS޽8SHGhiq 8"WԗTxDPKFnc <&:vZ꘯k^F}f/WgxhhM[HEclX0q(Y&q庹~}MyFW).=)ȱèM ͯo[vMcv]|}P l?=c[āp?/WWR+;"¯r:MwK'r]#i{q2Xfd LhzR/q +s==kƠciD7&B]ܪylmޥ\ƫC7qv,E&hy1V@N,/DldpUL1947*çEc$\}6?ey`G: 9٠ 7XA?.ӭbԷߒӏGQc]>\k\m;  .ak+yr!aZGS_I^*ZhW7ʴVC61B#䚬.IAPUA$GKW㐯ByED1˙4}0fo`iџ~EL$+ z=j5CDJ1\@s]l^ זd#SZ`:  P{#JX_Zz9vcGA'jLVlV>{ GwGУ&+)5(B Z_'1~ED7ifɹtڀ-b>|8}۱q_qZ :3?1k|np? 4js+t{G<L<6n1U"(]# 3mI`,H hE-x te+AC{B)605؂BDUJUq-iCBT>Q_uq5ةUDIʊI#9J.NOB́zˆ '~@+s:јi=&K$Kh^_7@LzIQz6[eKu}ː( ˈ_{bV 9q(d\[*%^djґz4,ʚ^땲cƍ˒|9cUX@B6I*)q=MnJEG4kQ8$;S:%o d7O `ߌ*CtaTTT`[Y"a"&f=_5c, 2 03X@Mp28ÞMv|@UwA%b<8!Mc\:+[SS>ݦF3+t,n~7PezXQJM6lA [6"^S|Z@BIM`^(Pfl`ʅ;]/Be+uFol%A{ETɬy*y#5ZV+p+[E}=?&36}Y_uD&&PZ`&_439cHyB@K0s HNӟ0opz8Îm.6vI-ZXD}#lg,=Cz\+a =T5Q~8yE&C N5d 1g%1ykJwO~ύD# gW7;ެCGktHC,ri qȏ +tsR͠FOųqKغ۔B/T^7[NX`'Ȁ:_cѯP{ Fl5=1Ǘ|iX]jf- ܅6K3.:i QV )3<^% 2yYLdS/}*'ߦ/oѯԳz"3Ûڞ>dtlyl̜4CSPtV_oYrF$NQ+R/+Fl5~R-k(^NpDУi $H& 1#ȱ >T!mmy0DZN̬^ڰO=W$g:F)2S? Xx]FbfɰMm > _'OѲe0t04_#!824abT-a$ctz ``iǍ<</5^&'j+zy~FB T~`tf3xdHSme~W&m[)Af,a2ygـ1^XRm/ʐI'װ܊rPgYգcC9mY~i އ$%> 4a/-?*R sJZ4QWK_=2EEn^˻)ᔟHH@1EǗZD0d 32߅QՒ5 &aa#/[)@Ӡ =T0 wMUTg D69<0VǚyRA&z“yy\[U<2qgH&a \P4?P| NhÔ~ &ũ׍WO 궗[ދw#s0L$fI\\[؟١+%gƊu b9uFYte^Y)9PkB)QwDyښYd>mTz7T6ODtٮWuKa0i]vR}}YJ ;#сUL~+,c,x. ]vR1K'zv53(0%||"4< )ݬSLGAط\ }\瘔Z퀸^-ZNoTCB`)67̞,kxTJ.D xDS?tT+5l;>jٟ`_0puwG]E?]I^$]X!Aާ 'P_IM[T<0zXϤ0?U Lf(Luʗ# +SmܭiAZ e̺Cs|G牏V{()ʹR}d~ds:ysZBK$T !8# ?l4D4c˱ن.9J'MX,'՜!3[gUv vk/hvb6*ޝZE:A4F o2,5QjP´J;.w*[EGӟŀc|F 3_(OAM0xFAD$3iZhMEYd]UIbuQY$ >G(w7KO- cq|~V3 P:PCR( 12_76Ö"$dIM._oɣ/1S' _e0]p5pu&NE֋i(w`8&Pِ A h[3$$e ,JzHc1ͧ'BżFF//D\Xf7?29T<Fe DjWos`Jf`M4Z{ez>ZsBzf,QBUI+M#s[g}`]@yУdwg@ FX dگO$iѢVȩk7i1^F2$ R鉛dS}zdNICHrGMr}=9 H KՒl-# bQSh'Adx/ucm3 H 2,W&.%{%,lylgf5bPQ KE{^ǏvlK2F|IL8"~YٴN2POJSt>1גMUyYNF)Z I+U?,Nzi9xG3$ۛG"$3L@[57&9]EkZc> ސ;7e0f\wu(M#\ 6l5>X햭X0[oJ\./UL(z'\ YbD`9cpUge ȥ &@X28'b, ̴ C}(wvX"r)%W˺`9W~\!.5]P6z2ǩfZК5PU8 'iAGP㳌ϓpMHQ6ݳ@րM8l*U?)y/&(%ѼO5 aM'u_L&.NF$` $ÝgS(OcS+[xzYU})=sw\SŹ;WIIho[qsKp!H9<4cPӇqm0t!Ƌ/e;ȇ=7kb{>K /-˖+(a1KvLSY#98vv[(+F|Z8upiхY!"jzpⲥQdՒD4D.|Re\3^p.y1Gq=$1>F~@Š1I]Nc&7ak=CFt.++Q|(*Qd6cǯ#zj[@b9Z^,hˆik"r/sBYĖ(3/@D;0 Spt \Id/kJu@;Fgi}T{3Ż=0ӝ%c8Bjӏ1?*{@t?HDQ9fMX>;DX  \rg=!, #PzTNcp5|+J2J]˘ZwLt8]2] -RN6b+F8Ld$jagnU-Cel@^ JM&RYAW&+o  G ˾BNae39&(4'@`$0f$QF&(`ZT}9D(>6y$Z9am0OHŁ{M}ICi҆U #tFϪKlIDOSe#5*<o\ #ΪCx>l>?z8<ް"_k5c *-|9P:MN'tqDq+YaF92_˖NJu0?q!6RPVvtA @Pl)aɘ(Ox*sXrI )Vsc QO_WD.TX5w0y(4ܽ{xi@[fd3xMM.yx>6,m,QsT_Ѐ8x L^8DmV E^}"Yߏ{ڿ7Ɣ3zEPL\[smV~p'чBR6o?_f >8i4,&g"BI}% _;H廏֔k'=qƲjnOG$•iR;k{`&UF<=Mrdh'˒LxP@Ց\!?́oVr^Z0t={[y49TK]#,?9L⭈KBqqǁ>)",'6زgfᓑF&QV H>WMM¢Cd(2lMd^ ._?2aQFKƱU/b>MI]i]^rЦwt-5-5UTƕb@Jĺz7%bUL\$-{8>{Ê=q hϯ&R5x^O%e/W)2֚AhۯSHvaGU.~t,o6mˑ^pvu/ X#$Yf>ahW#uu>cƕ&>4 [frPzOR mV -frD (<6NDAa.e335rs*9nU9<ܓ x]X yƂ/l1HW3gJ\.&UAkx&GOĹ=AI"ұQD0_JJ6-[Xulb%uWyW=Ѡ؜ؐ 7,>C4Ymy-KSdXSPZ k.-Xrn1<4=ԺoD^|poN(+q5^E A}om"٪gSxZ<b>?n בAkz80"TJb'|3g?D-lT(DcӊHq 1c?"8/q^Mϱ ży"eZ'%$ ?$PUNߺQT}beA5m<"2mٙwG>:1L  )Wzy ׈H) "t@g,ۜ 'HHN~ S.R2"Dl[8 C. ED,@M鹜OI_`Χ7RёEu+6R@ L)gPW*Ĭl?4vlLL^^ ]i.Pm#"ڧ!I)tR@Th 0c3e&D8PStQŦhwz]93ĈS_&s-7HN\&aEV3 xCwh\)_ .:@ў:Ÿb#zug AⴡmԬMT|1e[;|pt2!lFnDU Ý/H]5!t± nfc6N4xZ$b_B UIcqLi<Řz[y-P&R Z[QհCLxazC*%cKD^ɅԚw4O0C!0 [dOS P(? alݻYɴ=zѢ!:>ĵ%(!8Xv?1A-P6 0#L MuijN|:7Z=JZV%c0׬wN;;,3 #@={~D 52ԏ0 3?*;E\B}6-JpAwLӥ6uQB,9t`$x+)4=at @:M%ϛǻ<\9=3Sjb4Hl)n a@?=OQbMl,;╘ HC#<9~e\UҖ c@FΕ걞{+bm" (n, UVI˰k3XFW`.օ-SirA:l%Zl*4DcETgٖlg2S[H!1A?m`&3g=5zj+f$$)Vv:UJنp$ 񑚴6&"|T!pPPjtP#%S*qBC6HNHMW\pXk@~&wns&$sڟ5\`:Dl@aN*ѸLjc/d4 A=s҂6nJ{дg6tF)+0s ̳K&C9:Z$] `^R7I 3UCkF^SxhR v&# R81.Q2>fl7WaА=hQˤ2D;% W}(3iK'5Q&bMFC¼]? ˀ4V:bGgH8n8}-VD2K4?#A,{=LjLYsMJq0̖4#0`mҤd\=%Q2KW*NxhrN1l0Ը%I2fHaxei'vl`ڻ1 "$Ctr񁑆%gXY=/Y" #n+]3PvOoБ%^-e`6u(e|{sJ]0ءwEJ:uٸiƹf౑ lCUVG %3 Z3&M[N@< z nrp8Uk tG0 BN5,_'#q"hwtT?V_,kAmMBf5X}0 q+5׮$)~y/6Nd~i ڈ4Aa!$PUI`0 En̯n6r7{+"Y.mt`^4QBo*C,G+y2 \!7e I57n]pA=Z1o9 rI LM>[VP='̔rIF U8EL.tby_4ݩGnج3r_™n8k;aw:Zh cDb1G,TBa&O'61Z+}UuM _e¼0$I;) ) jgov^dDoN&c;y9VdSW~cFm R[X5]Lh|ʄ߂ IV@ƵWc=)]vRp|{xjd\OF*}Ǚ`R>X9YwW "i~ ]~8 !c.y47ޣnPoLDmˇG@yNwn E4Eh؋ |*a𪫳1OUa!ioU]ڱ)8/G{sI W) QpJ2ya(<=zcx6SL{\=KGWS.,AЇ0[3JFTs Vk~>*ԩ$B `5qa4aN x3.A`lQ-.jFhizH7pAhٷ8y6[.L*H!PF>@  K<=wh4)q!N& Btܲjg nC,Q@ oa>qf:-hTO8hW/{p^x광K|EYV n#.1 wrLFm$uTO= ‹5BhaTr #[6#g< 3A'ؔXYIhJ &SftᏠCQxou;/ $lr#HG%s*;JhTk!@IDAT>[XJi$$` V1䟿ojdU1ȖS0W;f" -Ҿ܂p}%24Д!%tdjcd$IJ$X0V-b㓟[VabVa H)vL(O.:1S|hȐh(?-4C:~7m["4)qd^B1.'vK% QcdNABȠZ0q1WNcLk~Ɣ^`8_?07_rz? Y/78gcB~]oh7"r\n5 F|b2Q$MK*/xs^pa8vS9$CJ ;LJ]P7eJ%xvŢ@r$n]naNQy\.#A-ҷ}nvx@Oe_a3.kj!=VaD;uڕfȄBUWSK{kvEn.;T3o'j-|`7:'ru HytxiX:;PSj>2<"&a!,XMj {SƼyPxLbR$$3Ǡ!  >2cGKB dr?Sه>PGy-7\ԏpՃL?2Pn^ǯӗ#966>NSNTQYJ(7#BrPVv"X8;5B7Cgi[.\ٹ9~(:Z,R Rǔ-P4V2?UKա'2 R7e3x6t)딞/]&V5h(H.'gЛkg?5ώ@#/5T BĉI A(nO<]PBśE>.糝᳆xBi.Fmczs9)˛(M!^lS֦ _Ŗ%%Y)It0-"i% 8Kp]}nY0dhĎ`'iN3$ Y=0'dC'-Hcwk9f:{pYyIexm8̣h;c3oLZ}VL7J}9z#%2|Fyt(k8͵?#COeH1w]9,DbpE׆ ́5Rkdpsx aL6bbsHg,:N_h$s_~mVo'SUs{rR_&Hi,{Y?Kaҭ(TBMv@ #v}w;PE!gK=3;˄ނ5[?=*%7c9gזW+"[ XJQEc}P =AAA)RCD-7@,oܳdl N{"݇wf3C. 9 k+Žb!ZN)x侇Gə%WYwY"'M9Y2lyv,B{LjLFV*VLXMXo6,?U{B' [pdLbCVsvj7[.[?qbρj]g T d kGwMac5hFj) K2DjUzE:V.UYSV(_M -3G4~rIi2#pz{w8/m,DY>/YDZl# fN E(,:7#Sa_9U <ו dIv7n#)H[ʰ|-{S~\ީ>x-VqEvl ><+"|}| %ը˄qB)uct F-t_v‚!7oǜ~46&BXi$=:i9^vjl@xnavsCd 8ZDᘍj?+>Ջ8NHN~`UHNuƴL0;S(m`F:I"i7,'&"? ,~2)fAgtjmpG ocHtbt*W-חf,7ō/-FT9N<^]̈em'@My}y ,uc(sƹ!w5^s^w/rq(:\)cuN:T¼ ؙ_vx~_-CM}c2 Ԗ~UbysUr^HYjY*1(\v_[_\w*-KD=݆\R*Pl,bʏ)- )"6VU@SD{u(i)@}e?eiZBh'DbShu [- B#!մQ#J$07l|<EMh8*gr,b㨍]88kֻ5)Ơ=P VGj&s'=Md{m[AU48)>s`!gE klhPU ?I = 9hd#QJx|>L(NIiX}vimnJH#8pa"ܼOt>p^{j* [%c"}&z< ,Hibo6n43Ƈ;ڼ)|Mt 2;>8߃qX%\eTkWGV,MxnVգ,xΔUuSMiV-ƣ#=h2reD _NC(foΧԺ)GW]4F0OvBnσ}t{*>j #j(0RD;Dx~}t gٶ^g9"U3T֋inؠ4sv&]xpA31g3@-W}p)MeأL:.Yy|<YZXu،Arc1ֶwlӦNHO͋[KQ֍q>|AJk9jG%44RDfehrky#2{P$TAKmNWXSˑZu \&ğtje˘Ϧ^^EȉgAR#x\/,G~"7N?44[}P7@X .AQELg.bg9C/$h$ H])C* eu@U;o1Pgo| 79T+0TxbH6b7/Hz1*ʆ!Ah [i 8^dYNdAಖ1/  ?4%HMYJKoSK<u{zL 4 xPAebOqw&[boJ"ӊ0>Ea"q5[=eI9}!5Zl}MI64TEWq,Ř~>6eX"W L^` У%&rC >( H\c t1=%N{LXc&$uh Ϙ^R|NmA4MY 6hSʡ(u>ߘ#)-l9m.YW!BRBC~7Zez4-MH1|8\AcVBCdl l M" 4+݊_0 s-d^=ԚqXmA֊X; 5cwTn\UW/r˸ؕJ^v6=2 w K)䁔0f{J5;PޣSLIR qe>1װ ذQ( |2[]KJ?L FlD->𻮭 e0(K7;V [YظO]`(ڗ`@< tV5 Nnyf cg KE{`\dtDϼ_?kA Z^ojSpPKA h5#ȓ +c)잰f?T| w< Tfq5F 5FRn|\#S g;H:j_3\8kT&AP;])/UY:J-T(d ~Hn/9!R8j0r![kQU,x׎N8Fmz қƇﰙCnRӸ,(OƋr ?q9X7n›) '34i;7栉T^t %OS*M'Bx=u'M m1 c&ݠYmQ>؇NEwmn٧ 2ꧤN'"EAh…Nު*S| }͇YIaPtr ^zTMzqgJ]҅w29 x1jx)3ߘ2MYdC {"sB]34~Lbpը"{Nj,e/B"0ԡ́1ڢO7tUsM@4.~^`Dx~Ȫϟ?PTe7/]5|dyu~]\NesHgf5Up$H$XO 7{Y* M85>XʼLGmǀ 䈚v}4ԡ=Z'Ï.\LxK3%yg\Fd ohSiLJL8uy[yP;?U/S0h N֋0UE0J閯li,GN#˟Ҝ i\=jx1sԂi. ;j "kPk'j;s*DX9Lj5y= 1ϸN//Ġh iH:lnAqA Z,RӸ`543J=D΋o#Zsجwc7mߏodf枳5ѥIܥM#/De)A:a>m5zJlG; USyV?K=;"Et"~FDtAa(Il'*Uy \7w9Am&dErc7VϷl52]Rj7 6NNę}F,ah¸&&z`+F3΄hO)"" I6N06p/b<~Q6ZYWOЙSJ Nf61^pQsz@kT6ǫoO LR,0V2xʸqFG=+{j8KfX]d,c}U*X4nEfa삣 q.$CA?osd(AUbQJЅIȜ5;0((Wpڪ|zQ$53U8Z<0~<̏siI:Jh{7-Z0aU8j惻2@D7b!݈q䎿4Nl6a$i@!n1-2賜L;Ӗ]XšFMdSut%@簃$& R#FEbϒT+Ч.M`dP\pe 9 =TcF!Un`;3Qy; {7OS1mqIg x)wLdo(hpR 6P!tPFPmt{Rv!*E'q<0Py#aP/4#3a]bI`VR4M0{tD͕E>}oMdEQnS9@0r)AVڑ C ,Uԍł)ɪ8Qr,|i>Qz 0DSϵ7Pl6ÃڊR*#ά/ip>?!/ްo=P kggzXE r (LImp0"$ ;31㞈^oE)] лTu 8LV؅8r F ,Ko0N|K%^q NyyDZ3Dy}ВOEIĵtzf]}kCj)ãVk k9`Q&"_Ѹn{+tՏu$oC!n)I`U?v s/y6^&Xۤ/@Kx#V9=@{E*mۤмTh,ҍy쑓%1a)+iYTltgy!'IZp/.Οov\PwUOMZPWAgɡr*A$q" Yr*@;+AxfR :q;/KڍۤccH \OztS6܈˅z {aņD(e38JvƧ3J Mŏrl*AzօܬS!QPmf ^ʜo{ЇVYrĹhTHVb{*~^}O5?tsZ|+H3k0%\iW$/Sa`suBS !RB=@ǐM޹Y q!Ɓwj?%Jf ]SLG}Qr׆tD+RȘLhPuU |vF  80 r@as{7 MsÌ9B))Y[9lZB8e-ubVM@!$CZT* (N(–Z<0;>,T2KM` $;BЖ0O)MPRHE}QS9>>ngWCR$X8mLλȭl O0"%_~aFqvƦxQ>hReId.[D IrRj영 -sh^ 8a8:X: qZDK(VbR{ѿ}*Z|b^phF"==m[̉aFTH5iQ'9-9Ϭ΢0tkN9^%"'歄PԨbwi<\=YRy}(KCE*ȬcT +k;ZuD d޲BVZHQ *p E"#x=m-7wbfƕag{Jg*%f;\,^flG5:6MΓǂK 2Q[@3/% ; H$λT2,4d}/{ulqJu4(IKREŁ8~ihqMQ^Χּ{9lLxI2 w@j !#8ࠌY_m㵻(~s4xxE66xޙ9իSIOGGT5sPF mԎ)&p+]U|eRRʵ^ i6&|Xk!b_G+Ә6Yi-&`}ϙĂogEdh\DMw\Ĝ:IDcWMtF ?i[oFB9%%ZIq9Ro֮.nH!᥉gp0xGՖN6IE'8x{پmr_lGlC!cA=txsQf8GvI呿c4r nR;̹%jǎ7Y INaGl;d{ &/O8f -i~;B|B3[XH)QR ? ?aI;29` vt{kE$pM} 90vXl;[m)?Sl^hDZ/~1[HKpSz{^(_XAW`VXًao%(q0h w[_.T&ٺdJI㯯G YYs䉫O.MjԾ/]P+VhIs 4 vb$|% .:Ny::LwBbO;AX :a4N0hW1Y`.E;ڄ̎WC o 1+PI_x<ʢh/g3ظR(@hvq!e w1]"D8-wTW>`vifziY -I6Nq́&49$=9``mBa plƚ r9 H13-!9 @k]Klbv~80޴\V-NLd攇Tk;byrnd ( kTކP8FBuW)&B-V"J4CgHs1,t7%S$ėϯ.` yKlIw3[z]R;Sfq苩tx+ȃ8eJD{ZuG߫Se;.vEMc~\h?9&+QQn"mgrVCȒJFbUS| f+Ƃzjr=}Sރ:fkX=(.Tf0E^.[@Nڦ2rMmqex&daP<\z9<]9Dc>r'Z%M6h`D Y*q,Y#9i㰡tʾs'R—^|f{F({_+=Dj7ɩ4d\$i2c p"RPJLÅpFM@T>0j!'Fd{Dz&>{hR[P(D[ryDbdE>@33iWr68 ,C$<h~\a&H2; k:z Fɻnĵ,"RBh4iG44P}%fzW8݊tIJ@5%s<"~{fI8NQ,wҫPsr9mWPa^q=6g ʯ"Q)S+fbWD'LNvRhnĠHБQj:鹖Fr2-FU/;+[%"+i9ӢFerE7R< c1 TI,`ȅpm, 8׋Crhsva@x!E pDhڃp;Rbi{ U,YѨL &}+\GQ7562Sf19^|,Ƕy\+S2SZ֟ ܃h3UE)q82Tq>)ͳ2g1YUo9Vw)A"Iy)RqzKLũC0} ;&YHޓvz@8d@řڰ'GcS 18a~1(d()cUVXA${(F?\}Hoj uJvX*-̸`x STѨ1UQa$2mE#C )4s}S}M}tmRtfP+ A~fW$܇m*~0> 2u쏱}!3fi}.y4)/h˜dp>R9ghLwn/mj]WDluفI]i)LSMdw;X)I 5T ឮڎomY3(feڟGj8eS($zuh#yX2&"Q< {T[3 `a0ÁPR\eJ *d0j=J=^X<E4(s  qMV^Z!7,5I^ D)|pJ$I\D*Y #" d'9e$4(PLUK4i tkdy[5PEHI5CPT/'gr_z8uEtDԗ?4R XEh B#Sj(8f&M ;39bτb `Z }cZK F&Ũ2ZyNUe(-C]DW<)mpbmErLLfmlũ^V92|hCm ;?: zr2,:95Р9.1ye4)טZ7tZEf0ێdZ95DELo^ U`܃8#^^JqX( 3JͺȊ,&UD&Le1b/7wdrz, ۸i{n! A5;um|M9_@)W1#‚R45Bbʸhtul u?&34!'vڛ!|%Ei20`੃ ^@IDATsgk"J ~m.01f_43yBO[mӍM!,4 eӌ:0jUY>PCahM̄tcy$CC6ʗ^ӦmL\KmT9:0tJS~:2j8@q y7k]!vNxl.M<OqǑNQӌRچX8l@W [$CJI8'raelugZbuN𣆻IQ䡘 TQ>PȪh[+b#= H7m=Z0LBq}q z>`FJ*/ *r.4;G"% f g~GH2 45DS $z=ܘId?RT__?^b/9Ӱe0:Jqħ6-[6UzpÝs"ebN8!Ue䴆`; 64g->2V i5DIzjRfuksKk,q.4XsbȄoV&"7]%baGXux~RL P() _+d\kY8@Y3ol{ [GP "Zn*AH_[m`QG^`N>6JIz#i]=wyrY E`}<"oz}" u0Sx)(3T[l'o l bjJ`^K3#x;h.%_1I^64p]MR#- a$VF*Y'7%F!Ndžx=?`6бPb#&+ccDd5qQ ,懌DOUzCm#@(1g:,(5Bفf=[T0 rMaй _V \X܂8eh_VHhT+gmz,cЏ hb,Őf4NC[C ۍ6_`89UC(Y$ 2Od6`>"*iLJX .f қRE6s@#e/C$reS*1 s tSke*6hKΌp`oJP&T\)YfCP j+Td4J   w Rh`A y *(&=Љ°$S[Y=ahg 3lY,2Ļ$Fu椊K6Q9([05mOVʲ`*`gН2Wcڰ*0!-3c޳aYmn}z5=97 e<*]$RD^ ,B`aayUS٤Tf{yuB?w wl3f)L VǬ 8( b0iFQ)NRD_u]Cfy#ȏp̀TU@krF>*OaZJ=uR{9vT uC9Q8z~b`'ȭP2<<Ţ(OE ƣȾ G51H,=JQ4IMz=\,|;8|CyO!*ȶk{&2/>KN%O <-vȑQPb7jȹKUTTʃ b~_,903s/j?8Qªb6 -1F.! 4gݏS*PLt~ۅ~ͅ& ~@G@ /9fs/G*7FVlD#c e"մL(ؔFSK|4 R,VkYŵtaށ`j'gcpb SJ9?n̊n']=g/:! N~Ca{E\x)j򃨗=V|YF[]aGsޢDg Ge#_9^([Pӗj6'*JqsHц-9^U$HR0#q,.~ yt.uZT矅0!M:r$ ]2 4q-v7-%8^sLR3sQ$/':CPXAu3p_}~~qkoUelj> >{x,ؤ]\ So܀n M;_HW;LMn[p9hDŽӆļ!s/mU }Qz9>⤄goQWINHRo7z>3j}"6&>L(? Bԧ&_\9`!%ˏac),߳ͅ^[liʓ¯~=6/F/?I~`f[&|H;x1 6?*6]wنs b!'<z2FZ}qӳp{2K}>иe]|{hM=o.`Mv9ٓ94PlvwJEki[^o u1FvNA < -Os#Ŧ҄WC+n2L֕hȋ;Aӷa9SeudZZ|>'+D^| @t"DAlWZn,%{3Z?$h 8vpP7|D|l:ΉTdqhB 7?%Y tq P,ܸLKel(.1re srUEw>=E5Hnc.tv $ΥCZy{f:+j=vl !H_mE~ p]Umm pƛ^RjůU]/6Ev6Sl|:oQkJ?R;-HGEnY F>Ȕ&!$('gvoƂ: W62~=0WU5w"x grqnG2PvÀ% K\&+u*%lQ,vP<# eGqhy]}ԇr; Ԑte~ݏv |z*Tq!CМs﻽ъpX-pͽGfFQ$lR6inXZGZSTUeJ)ޏߗ먜}86sR~uZ|f,~"mp֝we?>otbabH7_0}W83im.3͹xJ 6儍>ubv) 4]-eVҍ}(F XiWe/aZZG%<}OuŁꀬ]u4_,wEZTUUc; #H-rIp>puo^Wn8]ٳύĹ-r |>l.`S`C&%˪' %DxzgmkC_/,9Lۄ>"$ߍi)8(&a;!ȇy>R`Dc:VVdž@6 :ΰlty?rtxŤQ˵V8@d<.yV#).yf; Q)&?g!<0@<29К 7}s/j(.P%"*﷜5gwRX5NCt`RV %1#@U< [jȝ]yWCӃDd=a<:<~HZ]L٢2HkzS>wv[/TChp0g\6ږ <Ή5I~-" >KVݚRfCR]w+֌k|E>y^tH?HPԯ t[Y_oOb:Z6fqXM{N_ܜ(,>`{6aڎG@ 65urgr8NuE8cSa9'(::lT獢B+3]Yvw?hM&)0FhϚI1}9p0hofuqz>c>!̌ZuG0*_挬rܭn~ŻS+(-nS Ш Eu0NF^B?k1ȝh2Si+ةiF4FT# ="Zs|+B?D/m!:iC@B^vֈ2/Ћ±_ 0:Fk;b8 {; `}鎎Zj5f>}G&!W~HY_Nk[y.Sҳ4p^6ezz|}ނI U K o \G%~vżDw`l@$p-Y-F'Fl^b1 (QlAF@IaSEĉ_"ϡMϵkǀHWC3>z66> `_5 K@, Z{>Qeg!+t=|'V]}|킶)!d&]EWf3|)%1| fHKDdHXz3\/(ruHIĹHv0_ 5,a"ۊc0?{h՗a4/)I+6? G: ɴ1FTi)b (klBz LSB|oOCIĠ`edxiƇ=-BqC't̾2qfH~&e|4 X؃Vc?&@ъqbNÞͦ?,"B0#xֱ2|W],ȧ-ÀRe,YI[5O}=j,+  qdJ9#-Afo5gNb+tyG()% MdL@AfdȑYZH㙽(I~ڙ{k;F\hBK~}R\A{ghΩY l"#v>ہ>$ QXz!ï}#RAИ [1S քee07ñDE(:#(bЋ8ho{ (Lbɹ}4֤h`7i[x0/+hT^ LnKBOJF,Q"͈%LZҌp7ff2ZCV,D"aJ՞adX^)W&HXb4!j\))e5QpڈJ24Ls%S1Egs]imOm{-O2pt 7ٟˑ,j}yߗQSpV HjœYj%Bxv4ݻ BCQq@`:fߝ Hc&x EartDKf}@3^bVj3U".M c(56]D7٢gJ:4E|B_60 W m)-@Cp@b[9S=KQjUBlJVsUؠ!F+}з`HĤ}zӖ '}@S,SVfcd\*{'$INx! ~#q~[xӏl2|Xb4K w'Tƪ$FZKls>˙CMKd:1EȖf2 v)f@PXZ}*A"J2btrGiT_hlIR*L av`RM8JT{B/TJAJ#iJr :mNNyBx_G`A @G)'jx)dBO'F- 5o2aE ҠìA&jchNAkJ J"!6`Y7+`jԥUpYVi`1aq[[q>P$am 3_9BfT4(jͳt*)  :Q3kO:vi 1i`ٓ7RXoi5`2o%l"wѵ?pJVi^H 0&3=6ϖZF2^QQeEj/`AuXv` !@)KKG!=1W.ۇ؆O"Qg4 KPV˰?7n v2jR9/c$]b4vR/ 4֘jo-PFIT NI`jrTiK-(4U֣ Ev'&P Fd$%dP v(e9/"O.0:Y|h>( 2ET_Qe2vs|ICfU?z*lAfgKqZۿʹ&ierv34&|@ӈ7螫>&F@ɡ3#W'Oes#4 ϒCS^]H 8jN%&:Ί|ݭ "ʚ9F?,9?AQNX*ͺijpU<4 N'"Is@gņ~h{+xDhag 0^W"ˆ_:t.4͗8`X{؞KI'#v#QM 1bʁ S8043IM H*=gHX Qb\=K`fff6ieh Z2r#TuWZ3B\wR5dp\ILg~E]KM .dW(2MixsI he jqfrtaY|.T>Iz%R V"*i{єF+^~KJI_;aWs Ỳ3oš㚥^2;[8(+(ydjvV0H뽟&ٖU:DžgٺɆu(d}(dRkEU5seמ8j܂p>cs9}"f':֐ |KŤ/؂ηQ菣=kcؤj*C.8|*v Ǒ:" 5*w ͕cHqk``[K@58}cy,g5SҘS`!HNrE kiӜ$.& ӲKm2=#(tmi!#PgLڟn_Xl I# Ex9*gQ+<|iy1Fg8Pl[Dp|_?kJڏ)E^V¡ ÿ8}^O68icwցJٙHL&i{>,ݛG:M7+ő&d7C!lC̥} e/A?8c/1)5ɩsɁ8;U ! Oqɔ#Sb1I1oRo98yw- {S)bX NrNPma~k"Ŭ q|Яk֡{E<DHAQ*Ē&6M4ށ/oJ)hީCw:8rԒOPģbZIColh-osC]~qiB8èYARȁ7ԄCFc]kAY$+z2~h@ dPL InRZ9fgKWˈA϶, 7,,Տ]쟌rTEit/WVJ<&21i_+cř}IGIyćn [o~Shgնev:>ɥ[ ~?l0INN:,[\wh^bh;`l˜քde/M BwI.k!Aqf4pnw?8\,lCncRH|.Ea 1_r:; ;CA.u 95ʤe{B9xϋn3^_ -J.PRfgUIecN$;~xv;Yi)%:!qⳤV ;.c:4NZ)^h)jsÁ~Vn9qNi(EB9R;աUEtW?=w6d7q}"TF *w0ߺdL 4\q2a]oQ"2]/q6*m"8Tl黀lswt}qZ>ԧZu$j/]o{DGT-um1h| t xȌzO,&Ry2 V+r4m)|s6_?1r}K>>(ӛ@~BǒB%;u9RJ#'L@S42yC򗬝N;XDgapjE#)^"9ZHC3)Gh6[<ajg֊.w>-F> pS(ON|{Z&NI2Z~'[⣉Z}8~̕bONv#5YٙvA];iZvmc]O'&8j"IX<[ZPvHV >\,vzcri_ت)<:*S^pӥ)Q/K*I *J e:)RLqK.<(R^AGm'@~5MVཔGQ͏O{^C}M/ڜ!N4ӑL{n6m][,{.bG'KTLbS)Zrr^<ñ#M)>o\j -bGgH$P%k%"h24T "AYv6ezcE.jEKx}S51c>9e1m&+rlw[l!IJ@o?>N MIC0& Ut@,fP$fsM9`Rq-[+Apnm(G;E'xT !yu.%Jegvঽӵ5]coy$ĭC iȽDWɀ89)*} yҜm@L?EOWg҃C0#i cb> ng)eĮGvYgJ!|wtN0)%(%j P0ЄLI?FiT ]1C[7L_0x\K^$RB5?eBKLN=RưlΩCs:CzB4\b XU4(F-y8[qv#8*o_@ ralpe=~дCs^/'({ Emnt)/US:88 eBJP S&TW>F6@7_Df̉BӰ4|0U0}hڒa0}7 |xAam!kC8SޖU08n m>)z7%5*k -:A) kC9˔*Սk͉_b|kq=kȕ9`;H:`zmD صuEru9kH,<1|A҂P~#jZk@k?Y3iՀRZp0FkK{QI\Vmp "UbrB1}'].wQ<&HqۯVDx}њLB[w8/K#K߲`5  a4κRH5D|4A0,3j>NrBnS[7q2b8_B+tj`Bd_1_sZ=cHcR08ϞF:0;j@IW*XKnC}# l\{]7 "鑖o P>HR*WΥ qHҤ-a >MF:y봙 WJpRMGT =1JU~Ụ(+ a *P40U 4^'ѩXu;Kchʁ_2H}~cotK xo41Q#fyms'Wj>!cObJhւQ1-k7>).0c2c`9&VWr'g+>C%fh<.ul^rGǿWno030V*Ny[+M253/'?wt3h6߬+nA"E 2OvoQMi>& )EAHJrH7d!ף֗*҄^IDHysE}OA4-$O+*㇎nƍLeBpNq$=P"V>D,"azX C OdUɟ3d1 x/.ζ>RïʈLOXjP]=RPڲk ![+CԾ=t{E*. r=vK?{Ċրc)>Q>!cqy u#u . " j),6Uhs0it8z(j y2R Z޼,A@޹..0n.I!@u4 gEА ($?GM1ҕ^:x%CSmkN+)YPȊ%CX_AVIy-O!:^w0ypΑ-찾҂ O {C' PuG{+*cp؂ROdܬM B9Ґp穣; ƠxxHr$:jf/3>n +d/7U>3o X*D8w1Si v tp$zHp5yZіS(жyf1_}M[ɣKj((>/-k٠G?2UW3EalSm==O! $5덌 {c>~I]Z"ՔG\-u`U9aa\|h||j,JX*>gP#r&sBWo=WЖfT׎-9!~ <Rv˃6r 4ʝ3iCkԘZRʈQ]j_c„dS@#e+UQjLGG?tj E 쳤,nۿ96<|t*F`ml^: g9*Dn15^dLjuIK&ԆB8]Q)y|;8tb-"fM!F=znX#'|[P/S'Zhj=Zz7vm;ҡL%~?(ͯ"VTA|GϤzC c|qB^#Gl*'f͎l^Mg{()Ag?S[VȚIX*eFh\KW`ؗ> JёQ(82`Z{ӺG*pQUdjB ZcM Y2/`0ErT@- 4Y=2\mBQ㷊OIZqcfHt(DV&dygRF%",9hYcj zS}<  [E fWR̩&Q"xVBtr0@KU@iYO3 z9<'|iŦahKD.NIm b!.ŊvO~n',HZ\o jsQq4I) >L-'@qpglGTYo"Pdztd3c4 s&8B;xm)IQdہua0fb4b N$':#QP¨q]IQ(=y%I1>UXt=@nh^C$~C hXÞ1p6d;Tǥs\ch&2i1# %-^.cayYsL_F/ܷ2-Q 0׀֥ȍҽĂf ,QA8c nx-T2kq@$k^.hv;Ǵ#NwAK="J֚ވ( 5yR/9@0<)a1a|2>Qd}|~,,jJȴ1 7SW,nbjG#1y2n ^DجU>,O!:uv<<_VAjEm6 Hiߋ *G &pآ5/CCS^*'呪w2Z?MRE&a8Rm{G<\I"Ȍ1͊(;G{ ҟS{oBk?>ͅ)j7xr`X ghZWczS 8ST3T%ox_-k+'A$C#?Lnf۵^.&ˋPȬTE |H+1o/ 9x gr\|i5FUEpNʼ׊HF33 WXO iW곍JhX#aH='ƲWʗ5 au :|トi>O+u\Y\RJ:gGu3*ϭiI7b`龜2&-8GDؾѓKvCPJ#2\ "D񡊟\b1?c0A5Rg$(܏.1:bՠ\tјm ܒ)9C0Y)6 .)n*E3jySmd]Yѽ6FkO,b UnjmO̸ M֒[I/2h䛥h IbU?I;~Ȧ`VKɜCt-%f2';9A\\굔r&̒DV6A3pB?yV4?|O$"USSɪr8׮խ|hIjN RWni[)ҫFnv7!|%qu){EżbjHEvOVSÊ.؉`36Kt^;M c;`' (#wjRsm ⶶU;" $b6ϿXrOo{Z7EWFcܪ~;-0L o@4Lh o򙨀m7o}:clջ'R/7![oA<} _U r8"CTVmP #Y.$ÍH~(ـ7Mf/oۂFģlzjiJML3RY13lvncݵ wr}_ϟR2w"{VN,2y!a@Hi=.{ĞݧFf9I;XLMw(Ź=u2<Z_ˁfHm=9a3Y,|0[.e+Pr_7"g7+/m0n̾=VϡJٶu0pGh.e.5$ xa3{~@|ڍE_'_lu5$2ν#<p O; ]t=n@H;/ئRw0Ss/):x?vVDs{K'bIO֟[?[~8i0~ЛP]nֹj :Êb1cv筳}[B, T)]BN`S"$8Bs@860/Ns)6gy2:Z 5 . !NoYCܺY:}%`4q?6+K Bqc+)BqoxV4i+slk'IXo7F1)oέ,n>ˁAnu20$ڸVF%a`8Q\#n2z$.h}㙕iUOA-1NV5.kˍN8-O'\A5% fy0%%/_#`Y ?v?!LwyL7PDV'.qr<k?0[r< }+:`.jCl@/@@ h/ 'Gjr{Ĺmq(12miMDCV>~Ũi(mT+/zuQ'V6N2+ůTsG\DT[{f=v@\Xy7#R8d:_g.CcTa Nkqq@CEd(Xnw/} cC|L٧p$L)(KbcŇ % 1S݁1o?'ʖ4&4MrMTB VnPhfN7HMpy#HWU-p48ʛR68UKpZkkXoA*נ$x2Vm+ŗҊJIy-.0 K0y$>$>Oe3. eвUN'I6$:D#G1F5_9sʸ{4<%P}xXz@U ";N1*uI%&$,жz3\F83x}]PF۳?.,Wͮr!J! 4Smlq'UH@Y!ZZRAƥT&$%cx콮wrI$?S~54 |/olӛ1th/h73ao_ϋ"GW詵OQ08.^\씖MQUcAJӈ?K&7#vqpu gF U1ʷA\llfZ8rye#y7p`8g\U ]|:XڼVZ`!qc戇mihI bp, ѣQ%sRK"++8z3~+Q m) {J&Ze{ +&1xC3-BܯgBCqZfI G}[:ﵫZ|ݤ6gJv[TA~ȑH5^TI௳ 5-Ӻfx3aW5AzveaL:jmqrНݐ8r >خ7 Pә^B~hL%y:();aH_6*@:?m;7| ïr # ib2LCoBaMI$3,qfɕKzIcV+۳^ ^FT̫O*]ypZx2 4);fMő\X ]gDu¨9~"[@loBZ0[ 7[T &@2c}+,^-G8J4I teJ_EH'Nr-mQ~Bu&eXxOʿPWdCg9eo2%NTjdiHU,FCsdٺJо%M$14ˁ`u`k <Ý>$8QѢ@Aq.3|Fvtq v4;|y^kkv~!pF8lb/-mR˟#`?Dz:R#LB*rOh>{㘠F (2)yGVY8 ],G[Rf_iEO8a/㒲*pki}lnr<iY28#=pq@)^R~^y*B%t<*3b]bq; g1T)hOD!c鲊ȇtY|F#1eh /S@>;uxT%oc>sx׳cM>&83EA?EB(en3Zy_rC3F<<,P#wx3ҶQٍ#42r~tdL +y66rU-KpFNޞL,x,I+Ir7;gK:WF-MrO(պÕvj,GYP k[>okh҈ji|Tŋ0sǏ#_K~q@^WB/Qf}2 t> <%'ka\!tͲ_fY,P]|780Ћm]˟aohbwu}Iqƙauv+!`g<_h,фE6Љ{f<N[Djcv\bX\vQ0+*&}:|?␗g pWSwWzũtoa`;M_%ѦCKA*M^,9G R2i^f$$i dwvRH:s. C94H4+U?SOEJ`E}hu+`*X+-%'EXijMH&Eɨ*u=hϥVK AuFk؋,>DI)amL,>ZQahgm]k)TW!w8Pz2t]G7z1=}\f^R@amMxIZ@j.y*i&Ug{Nsk= ryZRElȧEޢwFA1HP$E>Z'<' NdIyy+[7xG٪dgf/ MH亵'_% /9E||-c;0pؖ0$+ ^.'ֺPN^Z uI0::T)'0IT$ *t9G">ЖAywa6ϏI~PZ7goԯdr=tiۥ !F'<")d7FtK4q*`Ezg=b: 8a$OTE)_wG=@~C 4t|I9GLD|2ߖq˕C{SPZpf2qh[E~gX'LR0ȏgg2{ލ-i D#%Xn S0X M * "2, H?S&ܐv'D1 ՞/567g{^ wdO F+YN+Ӟ(Ha_Z%NqFc4?Z&qHTF(P4 'e)8%Ui[`"|Il)Z(PPY’p S1a7ޙC(&c9DC Wv'M s-Y ypUjE=t+)6p"P0?"ϵCfp>QQrV7,4pЋJLZٵE5 h8DKXOS 5g޼!i2" C/]J/n LE*iƲjoO(97@@'MO6k\-ccNVc|0{k`lV#8O٪ȇ p-$T6hX̹(24#)#_OH޶)_ 5 a_ןV0P5C#NHk&--LWW@b%(9N:1Q65A)/ 5DCdʰ0po;n|3*RDm%]4*ViMط{cɯ֘6fl$eЗl%8~:b>sAw02 yt'&%JMԤ؅S! i-ETP%)$AB?;bm.GK@$܀CW3I0!&KT co)#]{Wxri(+% Å{Uw"0O!2Io;j#?mǧV)#`@ndrN7`2&<:1.M4'|Qz8jXznom!g2"Hhl'gH26Gs#O0~S r |TJ|.| +3CͶTq ]d0>WHMVN\mO+=tG3^4_97#,uΚl ؒ8Јrh#.Ex'߽ #bN cHIq:P#E`ti ,?D%A *)c~>1CϹfI=zcZ-i#*v]^%+Gr`|:8xEK"/9nqLXKcˏ_dsR6e}~\d ƲchTpƵ4946+5FK@`'t۞aԝH")9~ݕi2UmD @h{L2 GbJ{P&5ŁGЛD|:䟤: udcpDKƩHC\?Ȃq2}ݾuզ~B璝OgѐR..k?*xQ.e,@x*"A[vm1$Q"3 .bc<҃p`NHZ9%1ʩ~Iv\$q| kj Soȸ~>,S,<0bG(gb8̈́L6ň^NEMRaA-W VF8N7#X8(!O?evWHGBZ b2A~=t rQ.ƶus2 EJTXktˍܭXJ@RwĸaLȪ]ÈU Y/\)RS,D{G>HwmkI˃'2SI&x׮ ϧlfBy\+/B9)%8+6VO1NKAJ&T|b >2R_TB~:v-@- jsYG~Kӱqyߗ %E = GEp++%OϤH r:ٚ:a_a {E  DȘ_-W dq0A&6O_P/'ko.ҽ+ܻ8J)dĤx1o%;Py)DWy0SF&~JHyiWJONq9|4ֲ-Ydcj?gq< o,ʀ{NTTIƿv,>!r d0#Y(ks|\yeWوp0i%h[|N=zfcr~EK3/n?~Hb we%^!9@)WȬ ;W4:gut}q2?_зUZْP|"JħN|pm6:|=˝VǂX(X᏷$,CŤƥlq+X<%`sZAÝ$5>0x[4R`%^` ;5~xA/CyHe `yٟq4(NjX%Ԑ^dp+1Y}{΢%빢dI4߱]Vw)0:?\3k5p-y8g<$mr A _x0Oz8J]bni0W$RLQRc#!Y*ԟIIbeX &BPd%HٻGk+ lOn@g2q(9Ǹ{M G !x~eN_ t\^KX?=֌.yd.V4( xޑuL TaEY4`9SMtP^qɘm-1QaU_k<3X߹vWgl!X-BT21 Gԓz -fߍ'CUYg.bvhrWa]UGl> ]II4G/1cH@IDAT4!v[Qs= &~%DeDZ#Ux0&`/`7o$ $$on)v0}smynDlI5i7Otpq]t_bJR^3irSlBUjwE*I9:mt^_%2b딗YquGL1T1H0ZTH8˒.2#P*zW`WM^XZ}zelS̢4hj𔱉BiA{25KD\\^"t;Kgإ10X}ή͚&jWRY#W=D&lJi^c}FM&9s;ߢ}d.# ;kq1P,{Y!B_U򼗼n\ؿ)uZ)$(EtߺEXfPދ8vx'Ijlr"O`H8w}柊%H,վ k Aw-㰡QŖJnfjsf ,֤<(`IdAk@9FAl7dH36}0;U2jz;ywJS=YjJGZijI B=_-D.Io51Xhhl$8jÜcU() TTz :[%Y_`}LCK&l4^$NFѯX(jy|93]l4VCFu;1bpu]*DܩH+MsSC.*2)5+lO(!&),=*~lqGB%WWNKq _HVE' NUY30GfH?_; ^4? s$ S&xʋ]>̛H>k0BT:9'٦f^8S[u"䠭=Pj-I#O2"z;j|i#:ĵ X0.GvOwNUEo-g!0J̕Iqu{V'֜qaz濋2ۑ2gOR6L[Ef㌵o)Eg#syA JYlI]-E}Ѧ+De19Z`Б^% ]e1YC-C;%>F^oA6iM 7x_ҎF\x8|dl4PSB57==4h#9236JMzX1U>ʜ(k8wHQC7Zka9qaƇI&i{1Z2̃0)v Q9 =O2,&" ?';ehZx(^d L$S!]K,OO]Rs! (.2!b#P[G5,H 4s x[mGEOV˹_[VaM*%jLW*J+ zxrT2S 0\-ζ"XD 3\ꆭ,M)qIJ<|sMʺ#Yj1joCWFShc[-E>֤&8FkZ`#oj)/!4r>rs.)}FNm($`STD8o-'EFuc)Tx=, XUƐYx,~v6R.a;Db tnf֒FQL=g SJ(\Q$=Y Ju}1NK)^DZZXxaO8褞SK 3ߠ(͐$)(=?jH Зb2a="L+!Tȹ ѧ&_ơ u!|_0yUFwMe<О,ngdOB3 7Y '@Gz>o)k]Q: ƣٙM (xXT6))"v5cuw{|v$f-HoIF`=YޏD0*b ţJ QsΧ<HPyœE NF!*qGBf #z% gC[ؑ‹4<[d;(MΏ'sej1 \Ԛ7ӊv5#)xw-0py2n7gs Zb'쥛hX, ϾE˒ob?،~̓8C=< 9`s W}!Xt@H r~4;[,4 ˹;j #D-{dWq |;E&aE7eTH֒NrSDIf5v+JZ QP?80ڂ"ҿZ@|;}TF@d"ȉ-LfAC^@b48/ɒ#c0mI]y+ЀU j1"Fb@ zŠօSE LkzG<E V?)D!QtӝÉ>.N:I:qC2f;U] =[BA^ m:];! pKd!BŒ.29JE۾:d-\-<ʿ!φ^]ӑ;=c=7pipъz 8*X)dY,x+ Q c.zH*Z8P[}-dCQyWnyD;x؜0D|Zo"QCZ)04aiՄ %ˣ*ZsqRPxY^n)b EF/&K+u)a{6]GA;M4#AL̤&<a)SW! 8R)aFr]1b^JUS ;z, ?1|(w-r|q'aV$rN)1I@X:;HR7dI%J,-M A)1m. V-ړb(-S!M:"_}ոwWĴ7>=Zmer>Z< 祝5x,1qWo&Zے5&\Q{*K'=ŽeXོʮ#Aچ7ry'?PѰiVj2EZ.L4V]'1L΁trfo a_^Yi˥-npVڳ<֚7~$9?%ReʕƩzNY՞Gr@"diKNZERW8G7݊e+l6ŰtsŚ VEƄf>2S?~C|vQ.&$mz(\hJ @a CdB±(7sz* i;LiHUFLP]y{|Fo]@UV@~"OTgj~KyN J}iiV;k[#pV0$ +{gd<ƻ-|J!B.h`|H5/$j}N1/qXFL~lYVƁ*J*'D+0 O% qő߀jyjMU*6S<A0(RBK~Hp/͐39| =xFhNlH](Dd<_yW2$Ms:= :FY1Xx,D(X߇^;kU"9،`v etc~+Moa}UpcVL_t"%"RDܽ2X9"3ct[$0e ܐbfL;03vqF|EL,rHјC**. CX6kVnEC f)#B_1D>ᙤ:(IEs|[~Gڛ1+pH<&a6}{>6Ssk 2YR6TreL:04zJA(4Gxɉ#[vs\~ hZ-Mu-0g@=UfxE's ΣaBBm~Vţh(7vNN渥F[u )CM¥8k4&lZږHv,*b*aZO{`Bg:r[*?O.f{լ3 i?#ȫ ?ZGIF-Rb$Jݓӷ0'=8 9(1uؓS!o)n8COX}zOMMA;|j(uLk'6+sMx)ƛAL~c rgVlUR`TrSZakV+F!@ 8.jѨ2>CF9mssc<@#tJcG{gܛK3 | M;q'w=>JWŵf4\t_z 7)~Km ΎvV%4X#WZm{{jy#`KBWq7[c'nejL3 f{&E##k }<-%KX֤) ɔN_jH.E_y#,,HʒK>w!55!h8|7z?QU%Xˌbq x{A_ ǟO>g|svYQ!D┥bXIvwP\hU 6CN( Re᪫]"%Y JEN{%81ߩ)дfkdDVA*#>;;\l_)=X j<&Z]~]7{JcHJ)FJdSbqlbI?Yt͛cPLc7k{+:!>__^^.հW0򊴓 S ͦk8 hpvD,?/њ}9hQIvy s?rYG-Nk,7p,CQ#ag/l؈%=QC- O(S*wՐHgR@2$|$]n>>p*ƫ?@i6g8s01$dNَF;R|Q/gY~۸aǼ`%V1> > ,ryh}^{ng4(%~֦8yiFoX]l8=e:vl (FK;ܖۮ_O)fgÍg+O}ˢ9o5[?m}[ubT4$c_/Uǣ?8f5moiԂv+8(3z_w+'{Uϖlp?^aDoҚ=ܘ o$Uo*ĭ!oCC|`J4͋U$9-OzG6N_Ȯ2CxM,C&^KogXRD.%N2**JO%9jUج}n;E8\53Vofq˳N-/ < AZ"ݕYӿiIE=&!m4Ha؈ {\Xc_w"21a.))C8H>Ś(z/|Vv槺DsԌCZ=n?vquq6O־mE_ ܄u$_ъc:D.:UfJĻZ& ׅsi4Z1q6)ݭڿ|ZWx.2)hr#<2$(fŖ *6*[ϱ^'.:5!zÒoۚl!D~*C'nB*>o;y`LJhjauʪ`pY\sA覚Y?6C@KYNLW#Wq9,xn_ Wn[̹jPF# H9hfoOUSI?H:ERK8ӾӶ M E\`#г8u_ /)lnl[p=8gЇ~YYLk+rCW;`9p۞c_n|BLʔ~jadzk@1@Ϸ^~;8ˑc8Aݟ-ޗ:r{Qb"@ZYLn&;x8MxsϹBk),Bm-"EȺёKR&3+1JS&<JX~Z_|\ (SgQ Q<]LG`$b~riGF\b[;*Ad῏Շs|VWlSRYGM7`m}\D۲Ƚ?J[I*0"<Nȥ|y[ -ǣrۅMU{1$Re~+xF|o Huz G#h7F yj yhxܲ]8(% %3鹶HK1ڌTL2:F09|m. Ħ(Hz5ha ;Kb/N-7B) gE񨜁| /B7$U,k2\iοA2޼*N<Δ`S͋TSYV`SU:)Jr S5s@]dکA+Tp怙/-EMxom,bc;>gE^#CfX~PQ| Ϟ@SqVmwN:/<8 ME>DO\*(~)nSɩ ,~{# UX*{>.l |hs4wh<:>8m{g'i`wǏ?LAtX H8+ Pi8(gM ͅg6 jޣ,+q}gyqBnƦo\& [Iv*Zii.d _e OP=sjfu\$O.p2Kƍ?T \?QW&>2$4/'bKˤ lZ '96Cn[m8:nNlK'l4 c}'K,,iH D`ve @ a@ rJy}E=$|Zry٥r0p9AP*}_,ׂu8|:_q- T񟯔y+z[z,o#Bܯȥ)I"M;XPlX| :xAv}hAD k%99o8A9D9#z1pl\戮S ZɲA6Πg}, w E`[GMO[Vz:ZǑz9/&qɆ`L µSQ>7İɑuzi7>NIԯA|Tij`npIdӓ1H+sx#$#XZ{}r KJg#a3_g>^?Y6]3=& (}ǟ_6kr2/Dcd BhJ4 Y%{cUWoe {(vr$%sV|z)+/\Zp W9òҒ{69ow!8ޕ^>1=TvċR Şg.N =)9'bpfKm$3w+*), VZNc]t<5' Q&(Q,3+kĺ,s&[]Y2t<ViV_u9ga$ m)j팾~cpAI Crć&N}%y vo *ehAs8^nmkG}w#lNjET_ĨN3t_+FY#pTZ`2oon?ˌv 6[(7+A11\]-:FWHDkp >#8C%l5&1?i$bc+LTb(Z2XhVWĂP Ӓ)ARr5WpԜ \ca K"Y5Z;/' .BCriF.% A%d0@x*c%Z͚R2.q :eB8:0KTc["K ӭu+l~Zv[DE5/ ek?8 ,wt3b5V A)t.ӽB> W1lz(`U@ԙaPzIc:L@ JO,#^ɋ?zLP09mtZ_YqH5\:9j7=1Ab>Ԥ;|èd# lZ^*v[pQJcCUl-Nk׿ΆU z\CuYOXq:q[q;^+k灛[;%DIxڥ7c|RXpLsrB:|٦t֙T+1`>Tc:^LCi= W\@[;:UKM Q&\bEr սFiXwv9,'Yx fQ}N=B} H>Ao%s r[{%ÈlWE"?y|>JrAuTze85CwOBC3nwZ+6ڎ(,ϙ^kJ;X4< F!Esb 0GFXI)#}h!ԹԿ35aTGKn0B!u*0~QAo:IaOI7?Dg_pb Kvt2,he>Kӷx^BTVEc9hI6l8J<#lu ~ k͢?֠dyZ튯cϵ?_Nb>0k}>8yY&6p½)i~xcs"S=7ҏsWQlĞ9LoņHᎠh.ެLS}dcd\ ahPB$N.KzJ_IzCC1 1/)?lk:hw[Rb"@Bx-I)wEny2z:@Z, |uY lgU2spC3 )&"<cJ潶8[7GF7Hї< E] +8%˞5Gۃ'"9\=,ucr0 F׈ /w('90 a"Ts:0` =jx}YS"N"kٌҶ r<&Nb~z(BMC?~CJPf4&VZ՟ltEQhŒxMŗqS)*y[*I& -{V:wcY0=Lg v΀M*c,rZ{ii>3]uIC;f.ˉC AiK")WAdiM&~ 4Uuct|I1z1V@@Hȟ'V?UUPy=U?z RW1y=PoP1c NQycD 0,:]6`xtS؛Zl.39As88ԖrNaMo-͖vG61u2z+e2xPO9F8EQ_9 ?;V1{z=ka9Qf#ZEw )f9B-:]+ !@}PG 4tn*]2d _qtNwٟm~LOHעJkUiTLLIxQI=j} Cr*C=]d,'|Ĺ(M#+](>j>/P_.kCV5Մus8}%n*}9N|V!-S$׀p}ɣ$"j. :y*{&``@[pI{Uwz綅1I^`>c`jpR;10;~X3yx\iD`2AԬ$׆Aƨ_ŘA >\`sQ %!f''?@aHv\>w`HRg\X'\s;U%ߠ/CIn =#h O#ȕ|j^SRD;fd`@_\RC 7Z~Tj9` 1Zߡ9hS>-DaȐ31Q‘Q1Wc},F!Sb` .ZUԦ~,AeFQK"R`3|6 W{BפTư҃k/ 0 2-C$-8r9!v?*U kLqICk=]|'rU*_DDlg"ds&?G1 17  -gkq12-Q*ݔ KQGVN69xҝw-E "1M6Tί0,6m.NǝPSԮG]L#x8t;F-Qzî6 NL&)ط#"H'Q.5Ћ@2jys]^LGxWvVvGmXA #BgY{np!~0Ц45W[)Kz#ZMX^"@pBK7r=*R hUʪSrsbv(Ӭ#d*<7}q02j%pܙAUyKJ>\"02e U2o>Lnヨ&pSM5. %leHt,5{Erk(;GsjC$zm.H1jKW`=t׋"N#D(gBSapD8H]בSVuTlr hi.™|d@6PBmI7!:Ntv߷4c GV @'vQv+6} "G ()0%7Y{m?VHUZl8b񇬿C֜ʀrc:V|&})%-)r*~PP>of*Rɛ.e.HąYlĎͤVzNsߴ/qY"lp`_8uȇE=%to/NGȫBڛbNj*5K)dN,'@N;7O_GGL@҄;4s+3B.z0==\WC#M5{:IL<6[{8;Xqk߸i=ĉn-JfGj,Qnu|saSd8^ko[z]:>nd)e l&RQnv8pYd겶vVҺ.G@IDATyScRT pWw;lTdcd\'>d攵 l$<3@BC[M_tvOaCq+!2~QCZDЗ+F2V7>'Qf͖Bq ЖD[c<$ ֘Am!?[L>ڃJ>?6?p ۞ SOb$ݞѦ/F`O 4#0-+ #>wuscz m'wk>훧Dc~(W ).vRy ty6# a1}XGq'9 .ƿpʬ\[O#\uЂ+9\އŋFW>->^#p~'U~GxlewAC8VSWHs$Bv OPbnjE5DOr<+ێ? jcAA}!2<`D'pvsFeNF%%-gY:> cuԳJTIIZҝ]<"+Zmj;檳^$rrjo2X8F\.#8s*H`rU_:8Y]2?%WlџF\3s$wGg&Fh4^ctǵs Qrq8ͨGC'f.of>͞j!"$JXqFn8=<ө0z;meߐ].*R~WK y:-Eȴ.>E2QG# ]h#CVߓ2 㷍߽>'9$4Bh18e>Dqy#ˆ6Az R8qT*4ԇ!}kH~'D] #RsGMNIT,yGFOCb<Ɨq-Urc6?k8ᴕ*' tè2ƑMo m\9ҩ&+hМ̓l U"/S(uM\sY,F i@$\ .qb2ooq"eHⳒS ?\)NQu<RK: gA( )4[F J`=Om b"|,ċ(^n~͒2#i}p.^.'TN4b(X L_oB˓cUl9.tKQ@Y8t. {TOooAv|01$Isc9{셋:ysgljlZ/A .SK 8|T:geT;G 6UsndjIP;?dZ&Q 3?A_GO5+]Nݙk @Y9(8 IS{nx-$3NoYm)뤒` z'm_ј>AkDڶ͎1!* 06F(9i)Aӳ<^w:l850 Y8UeZLxÓ5fjͥF_  $ yroO XL0a?J,{?/ǮOoejLS-ESx22t|O#[ SnPӡ n}L Hi@ye ϕ0(Gɨ=QgjT3 { bx1Lv}ZsJ:®%6])4~ 0#-~yE_&?DB^o)l}#(h(02|A;n^iMВw[6i@:;P`>N%;ij]"*I%la+L(x~_~ꑟrTP7tW;?~КNHalMqF +>09aJ8`# LK>Ҍ6RfGe]L!PS3[$3!Ãt\'#c|p [ڷC`Z)Ytf9Yh<ƒ j#TF$B*&FI´W<9 #VN"Xx`:Ф/uЬf]-S.cvwֆOTm;hnǼI$L&]1G?Ov; _>bJצ% D*8hP&+} +ʆ2}[ ^}w23mBG'xЫ=9f>9b "XnafM y-U-BmJ@01@ީ1~OLQ89[/F,!rۢZ?F:@>x=E6ͱFJQ-$-|/"{dԩHSŒ3cQs>@_ Y6C7+A4} {'"bŧuӋu c'c)E,m> qDJJ9r(뻐-w\_qȥn/c&7Y MZ uXj0G(:{{úZRZ-1d(c+}UocFȐzIDr S 卌3<;LAnXd'ǁ e (1>'%HJr=T[6^H7·^R3ךmd` ~"Ѳ&Go\;^v%*VMi$$&rz,wiŠċ/%$T^6p̛4nX߶oפEt3:5/O2[2h.% ڔRgr-JQmsClFydJ ,aC'rPLR| Xt@r X@#%ly}mN3cܗć@bq=fC@ L@O?&mW FC ̥3_K,@H6Y hz%|1 g}to'm1б<& LUgpa= ƾh13=Dn~׼=@{K47v; O#eCCz9n⬔eG(1B4@_1x`dcqD޿P 2RZ%'3Rj?C7$JhVu(Z-|_!kwbYmZv, ̷‰.)˱pNbI V#,eNUZz׺;I!|*SG2[i|Ty٣T mW[8,̠YXo^n5V(q1*:G}367$lā!x9#삹Wի+#@rc + FbV}B Q0J.)!)1qˈ< W`[!{Wf\ bU{c(Q~eix?mŁ~%Oq UXCRQOeܞ_ۿ[OgVCl=J"CAa_`ز_ JbSc,ڶ\q-U6hXx?ujn㭾R "R}eJ:ԧqu/]oqiQGiE"_jGHhvҰҳ͖Buq9*2d{2`A=qD' {}O(~Tq/GLcM}Sq!Mνr͉^")uj5q |PCKA!eYk ?2`ק6ʖ DKȘ3W f(cթsN#eu7f0S87yȂF\ !* |5>vBǐU+So:U$ !8Kk?eXm/Gl۩jzɾG[D+ Ї,4z{3 N VT0F㞏3aEXpٰ2 :ݵBk] DWlر8/kjpn:8<R\Q ~D&3{zAD~Z:#˺&;Z|OIN/"<y,3p }$v;̛_$j_?Fb۫ G:?H]AQջ;A4שij\^[ cP8KR@U7`ْ\ä Dgg7ngQ6($KYpcf T <rh6rm6mV op4Hp(2DLԎf~׏˖D@.˜RRQOTA'64 Q<zYn~`ݍE^YjLR!!^Ett3,P47YM?v6|?B Ʒ{B 2#1k.^ooA7-($z)o%gԘ +t0G ҧZl@tVʎ%LӍxCqٸm1lӗmn:v5vyi c\ 6e6]0gϗqAe*n4Wkg' 3 Mو/">|uwAPb4 {g9cbp;`n_C;N:c뜢158NKpxX;>.!Vw+^7&4ϛӏUm) 4Ġs0pnk^t̕5&@ƒhjTUBK;jJ:p NlFWs[#P٫dZs0=S͟r S#oB0=?? w/wGwwזAI/#얖7ĩ#qá]I! tiG-1N{'k>;i@ߥ VJIp8_fiIKҵoiS}rK?x MGiU{V*ȋ.keQ3{9`IhTlխ4Qo J.z1idCj;s5iqᙿTs^.QMOyX% _#];y ֍':<0~iheM``zΝaXR?wr’IK;^-ĦsܞAi_\w{㙙 )q=卺nsyMVZՃ3M"t 6QܙV֒`pZS,\7ݸ:"9XCev6OVp4QFc8h&@/˺9xX8ѧVOdە͞CpJEj׻ן1?_sOFͅQ6<@gIP4.jU5G_ߝ*`x59s +!کET[T?<_{ʲ)mOrDP~ =XSzٔ뱳i/[hx wmpoV.t'ຝ4t^x8-Co:qx 'bxԎ̉&;onCyesG1j#bә1Td.vf}'CSbF( ida+hb ]RY$cr뢁5|˅ɬjd>J{v4T>xr}xXPAo-.5D=/OV+f"%$g'Ͼ˯陶-Lgl\ 3P(n;[OE.D4q_J2Jgۜ (CaCә\`-V3B'xRy]U/ @ѫ"J+-ؠ-_uٻ֟ZeO-+ׅ.P;|ӈR'dtAU/-AX*LoaNyN*>oje_;ƃ+< ;8ph]?v'HZ}[tmҊgRo2mγQ7H2Xy7aD{Jbf7%=9;~ünq1OzBtN-8l4P3|qF2?v }}~euSAW\sqU#aJ0 t݊A >`ҧT/r ;dx;n L=}yLMzI0b7y[,LAR4!p "L!`(>.H vχNp#Zru]7?) =ϊ*y͏edarxV2Z;c y9 N\ GRaڜyjLy' X2zAet1FM)-gq64j(1:i[\c)hf[&3UF4c6Y:58jFTgHgb3RmX7Fa 7aZxM)~ rɈ&pnMz(26ats̓T=E`->b4o;7[:)OROU F7(GYzW4j*p>f1g-:=:UR$Fi"DSfG9y2~ߥr;LsH} ;).تY䠑;E,"t̑=Sc4Zxniƭ=PM2[|lLF _K\ـ`sf"0݈ k `eٽyIq"W?6'XԴg>Ǜ}iP9J-VRqF"HGo`}7ikh:ϩȄ927o !Rpİ_0jY!QcZRaƵO W *:bF;-{#VxޥJH,丟^ ;MJHQTrUFBF%#b5G'GЅ u.IeuDp}!fZ}b|bF~2xcR<ϖ\ZO!ϡ2 7sP;-'l?_7o1j0mvmdD^\dǩAh"nH=X2lpsR×C<&▢ 2SRKsKҥӒFCT`pLl5h8N u$jq?b=Q1MvL+Ǎe_sG᷇H0KA\ȯb#7QwN5YeTh~G< COyF? .1** m E |KBnc^{3XPܹ$A^NhvS" I[j7xy@ xի3:mQ ?,KT$]lRo(}lg!@:ϢZG+ksqp99FKp1*U>]S1Jh žeH7)FH:['Jb]Z{K9Q|5G|3:m?,oMPV\%o")$n) j<"N|11AL;1%B́-2茠 1 ?u4WeŴ6UBvzőDM1h t"Fyso/Gn$ !;{CyȕCu["^4وDm57hnl,IXc\ )}o iAo6憐1WaxĕV!G,P~ĺ?[o 4TC}2kD:-9Ksk蕖 ZER>ӼMYNlNSveGdo!;c'{O7K?tkD?\ /͒iÊ)u$?1@`nlw {8;1"T-?r!Og@"t9zj'| _dx]!$Xϔ*ذ %:q/:tFȯ8Ʀ`[m'rA9;W$JۑlzRg l<~d9QNbML;KaV! j6zɈYjW05M`1 *IS!Aq~ (kSj#A~Ky*-K)<շ7F5M/4@_/ESo G?UyR׆?#5:TPY":71yPc ӠY2< L.Nil;9#_pϑ$z3ef40>;b spTVxA9kqܟr|7Fqx! rYIGLŔ_6 DR|!\))bؼffoAC6 JgFS#YvKG, ?l$OpiHXՁӮti|ܿl~^ {Ҍ9EKDCa B&CoԙEYnHH٧V^xX&+,SG_ ^[ϔz6أMD?LÿžaEQ`jOʾ pr%_)mҁ:A˗]IG^NvNWch3025\_R\GH4E@RB3xcU\~yyT qalǴ~3j((QG%o2޺*7#SqdӮ#RUWWt܄mK >gR( &q_^ĽśfYցьn)c| E c6"7Ma\l"XN{s"N|WFwԳ VbIJj5O rJ\~_O {p'U R61O-jG#"SFW[Umd[v5:1ڇ/^/m@?v.Z6=@)"M: eEh0 zc#e+,菠EZW%Q `@ jlCq:T.;ԍ'Uxw^96lY)C?n'P]30,pX"&ʎgF* @fJə\zF$C<&*%#A봐jR5`OxbeIĈH/'#xbަ'THv' ,7 Mz6;g 5 ΒM=32 &GjăoBW\*8SGy-@gXu0y)ås <}t ,r10n68=t$yA;t-ӑSc Qm(mkKF یy0 MF7=AX_,L-hm~wًn~e27P<Ҿ'֠j2x`ĢZ1/rN%{dMJ| Pfs PS/x}dJZdGXSezҺ5x)bI5~SLJc{+Bg!TU?+4M?bSjϠOT[ZlDBBN(XT~L]{bLj{>tT#3108h8), nj$$H ?(qZ|qHnۑ ./|@ݜA/lŧX#T,o\Xxhzq"4ٹ8ȵ'KJᷘ*f'jOA{ʳam<w;Yu5 B; .mnYXh9Hō4XMau+U\l`H载' 0`B f?&.m;*'q OAl3i\+)N~M \?sk0AY/] Ԝų{k\HF125,{(h[ٱ6y,w)ph5F㳦GXFYaou0Eڽ ڭ+PU4T5p}°V( k 8h%+ݑhfV/ӘB$Fwy! q kn}[׫2,aYCf&">= 85!VG8" iCUpFEWabѪգ91%A?52더3ڒ43^J÷qYm =LftUUH^%5/#`pz,غ[V'Xq 8p(Di(( j Q1ͭ…n D qK(e6ϐ闧 \ݝd,+"9A0-I= 0SFsiՀga<ȷ ' *s/5gAD&NEXx8v[}<"@$' [\lƬP$ZĤU' eR ES*_:MQoSazIv* MX R78-S=,xQ1+%Uݲ}-À #\!>k&?-V%bb8!GS| I{G9K?f *|ipdyfnخJ#f!X$7E;B|/q c!or9=.s*H!H;rfjDf'xK!8 %S40=_l)W%]G4$YRtD]U% p.KjRL>+(P lk̽sdDp/=01_#Q^ e$-x',BEaIփz'vKIAF$cީU٬%[e~jD#Oؾ[bF^³Hh'jf;Xn.,a7A ֦+;oʚ]BPܔPo}1~yhK z,a-0ƹ0̓t$D P<˫/GUfJ-2:jjt"r"<,~"!!ڀ(e|G}d8^1"\AU l*dʿ,oֻYޚﰛ3  "T;~ q#ؑCe~1TTx0 )1^FRf7;o!#vFm@IDATkڰFcL1h^5>=-P /Y—on *Pqe͇ EoX8q͋~ =Yo̥TYL\Wߏ'`=߁< !K.dyEeb&-DGh ``<-(SbI} N&-kgbC)/&dӒ)&n ,UǕGAN`?ROmTxq؜6V? qt1ro.B&/0H:+[Y9y<_d|%]ȗu2/9t\#)VuxOn*sBV}CyFOJ7((4JmujSfc* h,XaajP`Oљ~Úk@m%i*L'yAX?HSpM)a3|+gDoo9y)sSTW%}0xt@Ho$%lVꙻBy9c~\zY`z?.99ozYɳ#U١kP`C!jѠAA øqg*7$mlƴ G-{hp@wR ?(*|:V%^Cd2B48:a#T 7Na1rHuR@]V1N*̾ |h^yr֖ƒ]q6o'!ߪXQ~o[efSAst']| V5"c>ׅBa^E)pTL?]MCBcZ] %=bE\Tt8s[u!m ]KI7CzQN`}ޙʔ=u'C6ܷ) 8G$|&h?,? w?/Oޘ%r< ^)-lQ6A1 A3J3 S)|;G_qop-u~Y$wo2|*z}_6eA8݂vb;{ 0e]{=W xNXiYyAʂ9@Њ !6\\r)Zv 3s9V"_%Z̗^pӗD<˜˾Xفj0~譀z~"j rS_Cث>r\(1iJY{ad1jДAJ őv9 A/$tߑzZcb̭M|bمb-ta)|mNzկ|碥Y|T(8kl*"Ju@tE? 23zOi|YV:Yq{Rn fAPyC;`7E80α$Kԓvg ¸JDn*ngܬ1 r@K3)Hx{j[B]6 ;4ǒCңU^I#Z "KX@l6 ]l2fcNܔ|3x2޷'ˑE 2~…!?,?S-4ȕlV521 ]vgrt`&JϾC5{x#u-HhS (>EPf"hXdk|wnBŠ=rA !¶"-J"!- ,c{>6W?${ƅWD;JL*S8Ώ[ZM(N`c)]2/|( (P@k(o4sqe[Bb::4EBqlV i8J, my ͫx`eSZ'2sڃcYyAJ9403i07 8@ E]cǑ3e`øA8&؊#R#QPIgRQ3-f֎dc tPQRd,ԵEV3І_1Dx (.߬0WK03O*8Ez/7't4%-*lEk47-yH}_]_zk9.孒v[[MG*k:`$yE}o@ejc'fU':R$Pu"ض#÷=P%ug"B*"{=U?ˉ{kXnȌ)=H"`^r&GHҞ:!Hۆ~/"Y;}Q߱#H4P^r+DӸ84yRl'v)fwg/Pqu\;,y5[mY܈&[%ϴ^(!jɞŇq"AlP>掍kNKn-n2mP(m/)lcYg 63|DO| @7Ԕ6:@dR,utvi0K7WZ =V5|9zGϙf-Ũߖ%(lb7:%ImZ_r$)P_CK 9rÖD0tRYad TQǓ.ݸ^G,k"XJ,5AcA6PVy }{HM?8oRjt\u IBjC!6xHt~>$S3[Muo>Dt#DxlF`@%MVAC`]È灣7)5M ̐!w:'Ɉq8 Vq%n)3:IH{1w[\ֈÌL#!_:3N4UxeZ :OIj~u^0Fl&Ր562[k6#?c3{Y])x42YLjޤfeD~kCڳKO&XVTxpFMC 8+<ѯ3G?G `xկ q*V/=cP_mZ5.nae,8@GilfM7 cbv.ۥ9 c5F'I  '@8qn"- T$MFc586jIaBD 8q%ryw`evGnIYkCr?qޤ)bG;ʶmHCĞ3lH{KNGRn΋⿦kXuNNQx*ZȬ:by_ 1_4mKor ` Ԓk 7EZZfS13tT^ tI'9uŽ0' 7AkLkjZ4*xNǙ Wc\^ϯ?T=l!!\`n%FD/ׅFXьⵋӾE8K[&~|,DIqT((F,r2KfQ`q \ L~"Ě31f%R+grsmB9YNy&xyv;oƈ+e^b3 |.N ##a2kץ &=vH Tr>0:Dg]9 JEpф&Hö)6FD-1~)&^ixZ1Lhs8 O2ɏ?WmyB ƋC%K(S;ּO@Lwe:x86q-|Q (5 jIZJ (E/(*E)yOPmȦ  j]X""$iҽa72t-̂RԖ Ry p; pi3Zaim@㞶㔃>?Qf$؜7o3eq[~:^fߍ B^ -=P2 Prx]6VC"0_Y;f,|tqX$ڰ_ CPڼ'Ʃ (yz$3 D ғ$47k6"i>#Y 7&62ƅ:$By'*BH$>G|mrcN9Lhq8ٳ*T Jg(J~Tb=s `ސ'q\olK!.ZDkc *kjIX6{D㘽Š&" O+pZGv$a)ySTj.wGMa$i9FD(YCyB0r*2;9F+ ?K_<5oqDWί[,P=܇3GAPLUMn[&(B`\g^d1 rR =#b_i VׯC7(5 b=ڣbk芋L\[ÂOﭞnk1sanAP_AbxTtqMs-.Ď0f%HۘEŮ)QigPPpY] L W^FYw<['8/ Đ^-)CE]z賌CI_RL;-zJ(4!0,k>&q.j7iFEzA?AqX%J'Jz^}'V7ťQ391F)q>qy4JD6Rlr@M0\k))8n $z|/ ^_X<$ed8 dPZVa;'ӣ{8&r|vۼe:T~!ZtX%})10T# Xj缉82WqtvUWahqL:G7a8:g.ɥ  x -I0۴!̀}|؝»C0)j3|J ;H@ƷF`qBa"l S>ʮNy+mKL:vuzZ-qA0v(ƌRSBT '*MӝsKjFQAk2Lu_]ExKĆjG Gu9oE ;ctm0 %:2}6sTIlcpgTDyrKTj$#QH&ebz~p%U;?xdtH.eOcyQV6I˾ۆֆvӴ4k(}aSVMڨh-s;8-6ԕiƑ08-8daf~0e۔cc? TԀ @gG5[>Y8U>Nb@\}h 1=˞d-$}$l0vijS/t5UR٩CHIp _%t`'-gaƚv9ڻB& I8|d&!{sEj,k +e?a:K_)}:zQr*4U?W}ѳQ.-; ju<\ ZB8vT/c4 IR- 6 8V%0 CF Ld>2K:]r27:^.#s>MhY7I!] gC,5@[Mʀt:2oeFxb=`B9v|Ӯ 2h }yʕltb4fCD"9bqe2ER I*Ơ.;)e#$/lt@U%c&#mtB+huG:JFuڢMv:s&"K!zW zLbx00%t#U-1IGv1OqR@ Gˣ&wWsͮ-܂G6Y$@w=!e.$ ~ O3NӒLɎeP1UcGO;:ɪN!}ۻB,KE--Ƴ} ڃ&g5hS&^WV@" R{C0;rY+;kp KW @SPRT*eU#-M0) *jö5%=@s9%wVVz:`. ?tq@%%oվo_@G k UP罿 <ē9^m2z.k?7u^k?0wji Rxn=*zl%l#췣+@V~0|,?d:'٘Di9{8F0%?(,#O D$POS. qr:LZxLYP(>>V UCFGDKuj0PtO kҚk$a|[pwx*r RqA3+7.;uM`DlF%[}"Vn1m-%#>;6J|"nRəF;oj:㤤ľ0N0>D14 5 a5.>kq&\6ͬKShmRdwJWt=0QFhz[3oJ-<^l4znYӢ!y˿qm x؂ppq^o7(lmBAυ ~4\>UhyBlK'8xaNRGyolP(>֗7AZzRlX8D5<8Ftθ̅>5ĴVe&bDWeKW4@|$:e'%XDWŖcc\MJ*8+;nPIC͑w"?CBeFL1F{WW2!!pӱq{wap)e;i@޶ If>`طprTu 4 Ͽ/.n>2~{WW#!e7;-U#xYvRYgm9W_ o3R,WF7Vk$ A"Pw ^Jvn).slUlsP׷~YƱ[ѵpixR"gzLA}oUFS)tsal[ ;zqi35r^oC\j!ٱ4kw;Vg!J(>sZcӱۗ}Q=65ҾIE:. ]KZ| e .\RF[ЛԾB唰0*jȅ+_JUZ^7#G w:@821/W\Lq tkkMt;U!b$Eո܇"i0d>w -)l<{v-Q^m%NQc0F);p5=F0.c܋T2p/&u E m8nU?NyL~l~WC$4Q<{9aţKs@L Pp2}}g2_(9:fݷ[ rg^t 8 Q :IOY|>~FF.F&\Xȭ%\)'AXҺ8*`ץuoާ:B|CZ>%V.̼E.GRmO&؃&ߔ“ct]g5X;i-Kte&p_Od"k );=`e,ԞF)0'Dvr9tpɰZ+'g{(CGhJP̷ EOߑ -E&͇gQtԬ{8tX&+!J>ct /'Z=Zv[[`er|78A8"´DU#AzKv@5֘ 6зou\ u|z~R@]d,[x<) fregI\0S:SYj>&A#c 8 7G|ybf8JUVHxDt`wTAҘp<R8ľlˆ$A:H౽YqFs}[aߏH9Q=|0OTodPaE>D?L ]ba0=i ^'KQ@}+3t~JCqCN\5o!UBN(,^ɻ1=韏ۯ M9rp)@@u9fuưN~)4栘=2dSnz-'xATa@ql w4~5pv3%9~becvM3/v.Y?SYiZv9"xM266>!)T M% /^VRPD 1(Ţڥ_߿r' ^4%”S}ġS 7vgJk_Y)pi$l܀ yl1c_/b89mÌ PO3Ǻ+hn|^4R W.KFc4 3M(K)vZ65{^D=C"PPj #dQco~jh(g\XkNV cVS#:z݄HT6d'gْȍ**SF٠xI@G .5`h%5 Ns3w*_-LhHVϿ7[-oko {C 8:0`,cbJ5l3\(B^eq>O`.5=>˻ . @V5"4.(>sjbV1rD`^H+4+o8=R>6hLk6[2CG8c#T<j^/`]I^Kp[Mɗ3TLXT4*qmA-Fu\&>3+^'f8ΓXdJ&b+ r93:h Vm vX1K4-_a rԮKӴdW@{|9A^#bm }<90Xpe< c伢@b iBϮm w"_Uő'@SnTQ=Y'yF?-w"ȃXxL9TKA) Y22㒧˒,;ԎUԶ_6&N= ;i'A%,eJP{,Y#EȥgsL5]{RU17^J H\ c{Ľ>#*5eoG<vOh?4xd%|bjp΄<Cp N꺄a|bQ_GC ^VW{T퀔|\1:9HHP]µ~4#kQ(# ԛK<ֶhʽ)r"\? gbI $^BɐSeS0hyI^(Gz BqBxAd,*Nᡮr}YI-{?ReؓgX3NNbp g2#a{-ň̨ėF''6X+uV ndyt3RYF3u$¤X n8Ҟt_䀭>&B RAG)>Rj.1^Z=PDOFP&)}oq dm 6W @`I}<39ߚXšQ_-! ŋru^$E+eA!b3j41ƹ=URaϳJ<׫;ŒQ-?,·mMaW5@ ߺ0N96_ض|HEX|?"ƃ#£1RPOb$fXɓI#=Aߺ]ͯijgWW8nYÑbB4Q1P,s_ka ֣jw@#t5,O rA' !3$Snp:/zyG{;M1Fz~JNM=%ɴTb`l=Kg}q|JKM<0PX;d0$E@zXpMZ_WI)M`4 ňnFg2g90w:ť>ouUc[bS3&ೳ7w.Оdm܅rcG7Ks@PEZ9 w$"oE` HjﲭUJ~Ebs#@UTVsmdP{?j%)OvS0gowIB\l>?쏐nC;ٟ$뾄0Fn/fw45^ajix`3>g@@$\qbf[gW6- nni u7LS9'Z_O裁D<ѹ /~*APy6|О6Z.ˎ3!őc4qDy b?36NdcE잂MƊvռ\][rIiD8A08FR(,a]:'1 2~+DmPuR<4]wBpvw sExOX嵜`[\x:1夊@ yE'LG4OAHqw2X,gp﯐7WFuψPx0Y-mو9#]13@9I?JYbAș)'  ~dk~6ERio̰z'4BߊƎg屩w=TGRd 5|2v ,1v,hbcv%QW}Y*Poب" 4+ZgvE,E r+8\g}Vt,{JylNȠ79!8" *j:`PCh՟|Np\W| x1{KV*-3C߱~Fstz2;`DP̭( ̪@"zry5OD)PujCps #xrhI\ 1L~Tsٹ7& qzx N{5Xr'=ӏFQ& x).vf[t}9A ۗym~ktY*;\k3"8~N>‘9~c] a͐` :ZS|1(L~mǨDm'UU쌿BMY`;8%֌o@ ?xn#7 Xx&"ǯB,JmR$DvA4l61@,7fNa;]+/ff C !.e*-P̡D3ίL)vtZ5)]nCEq ьc` tw'E1%bO Opk4bmz5-_=bYkt01}+N:Z8U/nJTf| (NC4.F[I'BX2چT ? '1EI@-"7F0x=G< !OA" Ԗ238q,K~ !WF0GFX Lr"hi~I"$d noOppBݙ(ڽfa٣MdjZ;l("['MVdA?%C++dU_j+_C8,vj@ )b0A5cdW{a ( PO#RjN F8 ZASr^"dUJj#h$^eЫ'ƷBѶ2,U@i 3:])&v4_ѯɹ,LyݸjjXB( VgXJʭ'lΡd =WsDvSscO88j/!$#=-7&|}:aV'L%'_6WD|C4|L !͛˄ΣL" uW܋󋄤5D =$P kmyH^[wd䩎%L: -Uu7%}E<&h"E{UP,ݥ-.Xawۊ:w;$~G"; (kx3|E2Gq֮w;\dx](NCE=N ifO1C1g\`UkMٹ҂"7iL")2ΉVǔN8`#c2 $\1(@ԗ!Gdx}KJ!!EBNι'빸ߜH)Qgyj\q41 5-ד;I49e2T%Tׇ0m+Th3sD[-:Gl wfZAdXVwקNdm2j1C_l?/<af.*'K8㚠Y4@*289a%E[4s{oyVD7TJrxcb_AamK~1dy 7~SLa3?@ u8mT #L~0_\$At(@  ^r:gKm;ջ:EBH*(ƫ`ARS]9?b 6bA4%׃c" gnk{le_HfjQ'VPFn H@1$Ef:\.G^KIIwj[{$6={Ɲ^2$=.Л=u]z g6m~q0&HiQϽ#&Y-Bk@hik#'B' ^$悄7wlhG!1$KȢfP] hanHJ6oN@˚zbs\tuRA|#~/0}2_Fc! Iekt^.X֨w6wq;.~b\RvӱYSF0WW0rtz+u87?[[m{ߴt~ϿfEYfHzL;nBq >гtcB r ӻ456KfGXz$2 frud^v,.P$ʑh=&CL_`iUQnO}qGȢxy/?/1?RJ)Zl럎ژxFXkmRe'JL-q H+O(Mqe/y tdiw d匥:L13P}P:Q0z^8[{;ǖMbT5 F-rc(L IKG=ߑ~_Orʻ1*e[}Q߱L£fEWRvxRe&A%yw (/HU{!/U{ΥX\A 0M}C,`2%&?QدG݄̐J @کabI$%SlUu$!,kOn˔bSz`Y!ic.Ff%4a}s>]z{~T.̅4P?͝M(fH!VI T|B8s_>:?"9$O6= iɉy% ,0аOjAyJz2槗"2iBe@.a0z.Gџf9>'>X^DН3Vcp@`LE=9Q㼎CZlUfn;?̪un3XUgͅfjl6RwGR^=?' $1V)dJQɀ46%i4U%<ׂhl,*8͑,V/\/[AH tz!ВcDiKs$Ƈ愈etl5yKmo v{w{c;&G҄s ThR7#"Ü5 }ačvcӓQ^DO ͞1_ k'm מ͠ M.n 1'a5'9ȥ6æO-30XɈ~KnNS:t'm-IA)ݬ*6μ|Cͼ)9`A(VDe.6皩 >\!x<_6bd==L ]7@K`ש|Y%X*6q917+ץ1y hj^ä??;|} BjRL1H`?р*-`#D04@aK'-TnL>4zmHf-up=mNSM^?MEcwAwVpۨuw/N(ęށC_md.j*)IAro"P3u7i86\:>?QbpzN mRMQbZ^yWLJDfb^Fs-$e^2n"Vs|zr"cƤ{k?0?\ܷ8a$ /]8"1Z/.HbYGSlE__dc+w2x2TĖ(@e%u(MpC\2+$)Eɤ{mo0!Ӆ X)m5A]֎;pMs1"ֻZ2s6ѦRQVo}GR_$Ɠ{ꝭl/)U n) 0^4s}a%y]T=ѵ !:>'~'TlյcX0L[/cmȯ:z(1DhH9hB`{,$=tXk2kM+g>g c"^R")8+OFyD8>}5gۓ 09/mb@zm Q癐mGYO£&6z57W-ƒiOU}5hʌg]K*ʇ&> ?=yՄ΅b#h6?yfI`=jtpF7A~=OZ-@T(rEq. s*Hİj/TdfNN&9vi ByK)Ĺ#hI@tH )wj @/jN=UK.LJO Z3'm%֏?=b4V1L'"",PF헍_Pa'6 L0m.Rؙ/vsv(1pdon_4S .L⒴dk..ǣiHOKqcoǙ)6{H0~1̔|YJ\ԔNF9$ j\ч@/HEn0"GHo.FP*15Ĉe󩝒V{Jrm."oK 2?Pp>dXJRԽ@'+gƐټH >sK<Wʘ"A5ဪq,)W Oh)GR2OœkOceİ7|MSB)?, r"em9,^erKO=%s@`󴯪aD5g-]L]6AHլX'F8Pcwb3?8 2wy} J.y~>APB$XgR7̗?lMR"#Hy;ra9 Mbx"|5è" zj_d.,oBȋ k]kFtgMJo6mS㑸 43Digܫn5ƃZko~4Oچl?Bq!Droӈ[dK fJjǫ7M ɞ sWlG|KϜ.L|Wa/%ozA/t:U ADDJ8w';_F :xv,AO ޳n'A u)C*LoFs3*I+4T)(|+{ުs(lP=ַ-ܟ2a.~o9*=<SKW$-g._ʆ0P;|Anכ{unLbo5@KaE<٨lcaHydC[U$p v3Ey)N $}YQIvTTT"ԓ -A_3u~$NG xT\ )H^׎:8+5+9Oj( :g/YSj&&5Y;4%Q֬{jg"! \1?RB;gYԞkg.bdY$:VOw I(e\V,WuX9 3JҺp=ZʵmGx!B׹\N!Н҈ lɾG6q:/q4]`~OXA褥<,( s]vS 菨'd?G;Cw=nvU30R6tCua}f.kVS%S+01h!;uׄNP1X88ER7qj `j$@+hBH1D-lZ"2 n]V.JaBW`}EBj'66FK聞D'RB!wS fԚ&nfPi d5Vc3s?Őp`Ӎ cVhLEpٸEɣn/Tv*KwIb1 eAaC,ƠdJ}輌o(%WBQZWdopy1'lմwG ~JT@-0!*;Ṽ&.s.u4mXj1`"d Qr28ؽF˨#I.mB6_6v|o& _"ehOfM-RyFI>#oLWfbUMvš!'$JЖ#u / ,g0s\a/f8|Gî^=IQJYR{0^"u>)&0!PLQbP!}Ś/Հ'񼂂~f匜67򣢝IfcdCe4!3p X騟۔Q$Cx}6x*ȗs^r!5,w &SJH E-!}d6 y`(2^>$U^R.}E!w!DfZ`HpX% FPnݢZp}ӑ?g[~0 9"J ~,-͗yItmaA5Oy]0@oX03I՟4\tW֑nIz!R p:{[rE7B/,ʚ$iXwbA;PwƸq-r"@QKW<7-n9QM~0 lo>D>IQOᝆP=R=I謰s!R(PVOҋ5 F˳z ַ4XczKDZ[_;s}2X @ pc!bPŌFĠH7Ř19/~msz0rt{b>Yْ,|`roa-nXN6@"'o5I xa%E5!t;F 0_Sz)Fs9ێV׫M^r3<(UԶIdmӴ>#CEUXW&4QBmS:&+_lh?ō|4ete0xW(2A!xx$3 2iTf{$ͻv0AтF_< }ǘD#ֿ=K_p RT^G*n P@KEYj`0RHEq2~8Y!y)u`#}m^X4^ ab2pLtE+xU;vI|| -(", +T@:x* Xd^$/huPX_7ELF-W㼁lqo J,Oej^Jg6 E h89bS1B TX2hI#1!^ '?$Ho5YokՓ':}JW:r*'A#E:-X?8( CR@%Q/eFjN)hj54|mmx*YYLM*sٶ_+s!׈{Cްl\Bxf1 +feJ ;"ʙ:$)*b ?Gz&l:Eܖoő#@oIVZ6>0O :ycs8B_VKҝҷY Te{{9i^{;e # ÓENS5 jS[g9^YآSld".*uXal,^.6uhҦW|$QGH<6Jq$1fC%!P)i=CAZv"ΆC3Hr=̊:T8#~xdDq#&)0 4 5l5.0w`R>*+V! 1t)o7E}S7xyրע#8:͵|ODr]47Ű8#h*"!lUU*2֙~u&N< 9;GjZ+ȗy88NZx[#+X;ܒcy'~%qߘ 73̂k-ԙw (Ia3}-W5Krc'/yRz M Z@"&#:xq YTo0'mo}zSBV^~kaG]pW{dzC̐RșQe ( 2ۙV5+ʣ/WS&B),`6%e8h$XO:$GC`'1l#IΏ+9M\aO+q {RԇDHp_D:+9 j)bu;G?3}ݞ/oİ!8W4cd*]ntAC>.VR R}uF"2E+O,("Qut8:B2r]ɬ,s z=i.G K%urǵuӻH(YDXM Xo;ׇ\e6}[&H Cǁ-:KzйY_\=?r}lh)6ELLVh.NlRM~ 3}Q>O 2=_ʍsԒwGW| cԈ]b/wߛNchmuc"UT]yi'ΚVqJZRŲ Cu(b-FUE#뢃<PMFK ڑqPǺyzMy|fz\h5VtABEc`2¡;ŝm~W ʊ֬6vnq]Ȣ\鶲E-1Zlo@G)2 +4ޔ*) /f>[rdAQqs!KU/dE*g9|z;K'^e1LghUguus6 o~<;oݱ [gSϩ"8ȷ~tSLQȔEYIiE<9Yp$ΕYB Z\@~dYKr>nd5xtGJha9AXNg3 C(=j60߃_ 8If$#OX fNQ>Hyn?⡘)jw+H5T&ܔmKut"C'voStsbM A qL1HH9j d)Fx#?FN`,Ҟxe+9MYaדB`Rv E"  mqz!$µ+6 !zbYPiDNJbkm{X@"ʮ1Դeolex*rGEM;  #UXn)@} 2 (])t ɞ)nӫIAFl@T#6di&8m=ŏw&V( c_@ !K16iC,~U B Mo]ԈlꠓHݓ{~%'2s`b)IhZ´vT5gÌĨDZ(sg Hw&#j"B締*e%9ȵ@X!!Qv w㙱Ȓ}ęM@9{9+?&a#HPR.a'VD>mjdRq] [`q|b963qc"NϞa\J E\X?fV ʦHTScStF-&Ŧ韙w4  idy:Uj˵?az/z=nu W A9g|!+:8%р M)gӬZ;_?sCdGƷ~ahk~uj\\@FMzrF EG^#{9zXw!b)eB=N%1N"^44hȹm T XDR:Dlsrݙ>l6WVPm#AOHnnU}t(Uw{48?i%K!ZR>(%3[Gq7o P!-YRGZ(5#HZ69< V­^>Wl1@%j] Y 7.Wt--O"Έ-D S7*;L@p1\e8aXi,ƴ $x#ic=#ϟpJL:o.xq){PS,D3ZlmlLhJHEP| m=юE0V^G(n 95&ܗ"tlOS-FZ)p[\٬n <)HHGiv__x0~y]gF+Fw$5{x;<-Zhb[_mY9{% ?RªSm57 2->WWS1(=Vїoyv2ɠYĊ͠ Wa !`#| c|mX_0 MQ4 0BiXxxcE&|yL?{ :f &+P#E/z$ГmmĈسR)6VVmcҴ9M!Nĥ =lKCd5V@~}"I:xjX@[/#2.Un*W,K[[pZP3fT>D 2qwu >~e"k0!0Q> Bt^HEd3kl쒜 @ T|6ZEIv9⽑ $S%!lk5?؄VԎy<"7I "@3TEh$AT-Ya <4W 24WԼU<ۧ$߇\"EOC;㺆X&5 7P@Zg'hIA ?)1rTWZo) G&*$ך pkE~0>D7p~Sry6wmxe`XIMhMUBȄrՈHyg  =6B }R ;0?U^+}[?DXm_PH:^XXDKt?'-JiBQ J`e( +oHyQ[EbSEE}v:yEuQp챆䵷8sDE*k>ʒkEUyy=uNk[*Nu`./4. SG _dy2`g.7oX/ ,nhzX$zra5j-Yn(a1_#~U',kA1 h|$M B$R+x=rfks&@ j^a)@[$UyO$Abѐ̚Z*1w$ O m9ENPX81o{89(oT#NM.??՚ʣ@OB,p1ɸ0ޜYsC|,k`)nvil5lU㈰l.@X'U)&KDJ5ԨD֗#!aۨ0hޢG?HSnso|(*fKk! hrqBlq_1i'N I٧KSĈ qޒHtphl?w>a-*ϱގɒw9^7]@4{Կ @sv/br^ H1BRU$%#àa89e/ݑ:x|)i.nYYO)2r n[O CTvsl&qxr6)E߂,"L@:'] b* 1s",4h_y-Hcxb}G< >b~Æ[Zxӓf"|4t|giy+xkUa2ၶ&i><y0 ,04d~MLH3TUzfHb5u0=1SI*Um鬙N dޝb*3"K\AxCKZ> pU.{M'#qBHJycӐ~XKjr-R0x6GR"5^%b?$ާm_m.Cl8_iSD"bҌ R6`'kWYbx]y A?x`O|Hlw4\:kƙ/n{q/{69:\TDE d0d_c>Kh}9)nQ` P8UϷύ*n]!0$e&/b8Zz(@ l]"rHQu=N6B|Ʀo&uRi̳NF>x'1N"!k2i0P ̼ߕTXCT*Y1ذcg "(8!}$(&P x 1JڲcΊA`f\wإfheHvMg.F„d{9ZWCGRTPd8nE2umNW¹,cWT{m*7a:ABxâNwW\F"1P45o6͙OпֈZ&h N: b"z 6xǃ3\[ - Kyd$+)BZ:)j@]g_4TY.@dH ٜb|'gn2#$U@[qӑnyC~a Dzϑ(>fo`5C8:2D26׷XcEX3~RA+YSR% g8.l{ y8)oӝt5gHICT,CB t(ܩtƋaD `p! OThU ^/c1@u-K7Tb fjbǒ|P.pHkH*ǧ3gՅK_rV1yc4V5VKUnʬ[.ya^e6eVtd'ISblO[ҁDa<=oL2tAMF'{ _mQHd[ Q*ovtL)y2|DORt lE ƨCg/y&ױH2)|f&یo1<x?&o^I@`L9[^B0|jrK;zK?/Ôș$ "ՓsqX qcoP4^͸;)Zr鱯{}!ɘbӐ" ^EMƃ\!t=WWNCFר %*IGPZS3CYg`+!=2Q(K)@ĩjplzIJ{GH/h^2 mXbI+r2!߱^VR: wVh3y{h #>?L]BnTPB~uVةym},"<\Yo7om|J.% Bi[f^S_S66-;N0~w[-7H1ڱT%?;?{6SUJh,qGS1p$tUV9k A a$Z},"Mi,ÿRbA0}8+uU99gե?>?Nweξ qG*ǹr{%7gEb󶜭40>EbI#JH/sX ns!{ 2$aGam El *#-@fĺ ZO|DTCE ,`JMHL@X2&@댣'?V[&pԴ4ng \߭?2X}dG-6R>d&΀[l IL\E3xe_=Ko9'rTFk.Z 3VL.k;t1{ <(-~Kv; Mۃ ] ЯX{yEV.E[ݮ[g֨oeJWyBteuV3Ow<0~@HLIbژBxq )׸eS~ҲPy:zl]-uBD OH{/B8\3Ƿ(N[}&W6-mkǜ6G<{$!@AcӗPj5V|P⴯e}q<L%С#;! BN N#hx9im`INQxwf)]T:뜶y^kZ\n$$(shi՘xvPyGk FT\,|J"FC/ݬ u%WM\nӡz3_t`ſ VYH>RGn;v:?JT#Ϗ6(oa-nhKN4 y0yq7 Fn/Х3f͵z#-n4]q>3l͏ ϠWS0ےn_fE`3YWa\߉'YWY %8!Gԕ^RB2\,Q;\?NoyoB{E-~9QIj;EHo ę_.[}-*rs/1]4/1[RPl$;۶p\hxfՏ̼(6xg?g]ק#>kW' Tb랧Xk;I9("- [Q X+]$Ql .m *^[GשY-jyhO%Ӝ X W$Uf2JӉic["дDVrCE?7^^ys"Ij A8$A=  $rPʔ1Ɉ\=LDDF1;*qa5® m:Hll%ҨTť|iLT!,*B nY[QgHavy>f#';rSI-SnDRN8DT@ ګaA*P)o GhCJ {H""Qݤ~SfBA@*P@<YؔعׯTj"1c0,gW'ȺҲչ_P4et*8TS 6-tvn]fpAzStjTM-!}hopEH$Xy ˣ4/tRƩ=G% EٰmR3P&,}iӛQI[ G!f e#1e;| iT(#Bߣl}v,7،޹E þAH|x'.0yR`{ Q #oֿ@`|/0qy05%wpBhBB\c`4pRPSd5{}5`*@ٿg)n?[N~煒Q3.\փmXXL8"hJHstkCCiavrc}׽f`ZThX_klF(]z H@fJqRoLb|B'|ߠy+y =O 7\ ?Q4&gq1vL AC`;N{Ls|I  TuW;ǚɎ&>hNZha_3G/J1˜K@xF35M0'3@ ?3T;BAB?y(`rma (2[Q< p tGnZDz`6RYػi,[d &NiS.Y01jZe`-JY6dpz`X]&2=Ƅ5o7ad8wG FƟ: i,e4d@/P݉k\^.x(:_EBᬇ E nAjRCXBuըZ:)Iӎ/~KϊWݪU)T?Rٸ+Y/˺=6l,V$㛡 Ouƣf8| %,Y}]KF!$3'?}j% <#E>Lc$ h\J"ؾO@bX(G;$*l&yjY)E^N*0P||6?eĴSUbxX/cENxέ!}1@nں4})2E֋a;FMXr f/ RZ[΁ زq1a>;ֲXl[{v\Z9Æ7;Zt˓Mۉg(ԣ\ e5?TaO*A=X# Oč 5Yq H@X[v]@"AAuZ3L;[< S y#F4 AVdv |m5jEKzlN` JJqf)UBIٺTYYn;アms@VBHRi#aN^ӲWuKXa\u(%ID7|X6ʫidG|=> @mS3B'|x"fex C ˗COO϶aR^ =-,e )diK a"'1jS ~inimYϼXb b,H2_EVeb:dH]w;¹?Kb~+vPC8SHR,?31G XOid`bo;=s O9.Qm/t~;F'Z#6Oy^aIXQ=q8v l׾ȸA %@@ &+CY RVUD%%Cs**@nwibA Ė=0enpApd }F] N78֙S2QEd G7J#Ne܈-VKa0w)Գ96w94]s LΫ93W;`"'6εZU_:a}Lp*-rC_J,N![,EbRTP̈́t +n'2yt)1jYRjbM:\؃eayC[A5zN Gƫqn"ˀ ⒌CLWƈšfZ,{5Jп4ecX ^ <{iF{~s T] ٜSym%c>F7yXru=`Qh@Ri_ o'8ͭ{,N;)":Oϕ0:J.C1vL/xIgs,( R|D;^`{lO>g=q%c,]G5O BElu*Y'w0XOU r*lV SRf74AOA &9˘wz}%Ji0%ȧłD%t blE ͸\s:EV `%NoS ·PV_;6O8 dX3Yx6UT l>LV  ^S x^[rԌa;j7bo\#}Vgm/ƥؚb̟saa4 mNF&CVچjʯ*4(cAnog+6g͇kwҭdRJD <Kfi"k(h9$G(N8{%JqUo&bq$)x=io屯&FBކynA%*զQAXvluMr2Ln~r8V2Ƒ;bqYǽ[qiwTA;+16JY_Ci^&}fշ(k ~#Stq-v_h]#;Js4и_Q#?~BjíaA;(5O?2drW7b؀@錸M^OKe!E-P ΤLR()!G<'F`v$˺e3_Fl!?րsiICG14鯧G]EJ?}9<Վ#-^#~D)6g$6jcT<)nX,@ 8l@I|+R$Nk˞ 4q4^6穊3<ߎ5"L]37ć+#MFR55 SGblRU4v|KZ+>it!f˂DEqޥy72^2UAXx$ϡbߏo{usi4d-OfV,P_+8Cⷍ;479{ke]KIUPʛ3Ǚ) ϘO۱L~kr"ENG:؞jXRu<8cNPZ';t4@(RoHM~kM:[oAO~IA=$~cӋ@OlM"Nk(6l],!k{{Z#E&DƋMrrX1$vlE~67J.&;IQsϊ6aFClmaF~F:q5\4/-0}h5ȶVH oFb> rwo$Tѹmw `9fnn2N'hv^ihN􆥷<%x9I\)Y{`CvFйI$my4.aºg-( L ð V03Տqz)˗cJ5W ZBKװi/p0 PX27 Tkfz a~7{*3SerNT{M1Qˆb ;5.?_@߅X4" eO~`PEά+ lƍcsG3F`"ėB]F~1no J4_k- `DgX _Gl_|U(l=@^!#qX>NH 39o=&s*17^OU(bEO~2"Ы0Qg?{՞ʼnx1! ߫wR\r:N}:dBywtN7 Qg]?ktz/, 7ZQpZc)pϬ# 6\oCȝ(:&j͏sAKJhښNYQ\YۅJ+֝i_|TG>ksd wʰ׏_?εJsDD.LBt%B2?[q>hpuթ-Wwgl`,&rQ%jtRK(kpf3)!6h\gK:aR< QLs NW@6#Bq^5w8.ow {_˽\ )crJ5q0N_'LILB{>.gF2Y=_m@ *(FcYC`RqVjt({Gä_팼H`JG=ͤY FrJI!yTrOZ`OhzV3"^Jt{!+ǟ>Q֍Aϴ#9.0~zRHs|ޮuÐ"i{ 6wǚJ3@Y$ٛ#ާw7kc?`WeH4B;LvC?1b%8R i_Wxt7籘[}cbz [O<2o^w;k=6B b(a+fXOsM檯ħF,VWފdӲ#(sz hR'=ڛ.ctGJvͧ2c!˿$4#si3y-lt2 )bjK}4+p;%G a;q7e1|.Wo@;[SY)oclIK `j< O^m(+lY/*`eѰF[ X9]&S* Ɩ %Qohnh>#Dmˈ.(AB84d|k, -"̱?}q/i,}(M M^EEFzS$ i}RY:K5 d-cx&tC Đ YѰ)_Pv)ބ'ri}`a?YW("gtNb5pJ!W[Q7RW4g7PZM,%u%O"TVgWhhM" MQkd(m$LxJлZS>ar{#kyhZ=tcC `0mJn̛Q)Bd6򃶅]fP%SI%Ԋrq4=cZSDNW #uƊ X5,|,1j,tu) )yJs~]ϵ%8b6|ޣלyJf`42؝+?EApeKu(+VamJBϨ𖻾ۻr)uPE^}ԙ ph4?x^VWױ>Ts:,C4\q6 1Omf@B{&N:(&0vr}nC]g#/qzRdĿQ0jD/pٕ9`-4-ia8MMǨ4v~*Dȵہ݌Q3ӕe4|fzUxþ?D̚#E gx CkMVY+֒-IN^J әA46ƌ)&x 鳔^ yJ(Pk#YʠYV[yC?g|5ߝGCO' /{ #;4UA-+p d11R5!tac_2=#vCE 1FO{' #UFCU($m`•qYy/['@m,8VeV %7xbN_!#.Ћn=\u^ho_7[ma3`HS{Ϋ0#EO`ŴKXT!T.ERuOO}_71@p=h0Z5_5Ȫ5menjO$DB4Kk`,X9|Z?vY6 UTF`10coYBܯ; F?#.,g䢮qt-Ej3tC)ظ0lt&N҈S0ڄ KJ(+Pw bJK_F {GۧQ0ưjԊaV9ގ(q`A H(&=Ҡ2ii[{ϳPQxӞJW,H:kfcxo_s ~(*0-2e%C3PqF{NW(R"ZKƬ[RR2+MkW!-8ZS;xn~DrIg FRjǶwؾ/ {U%~Z\)3C:c&6_`zTF!CY"*?T\TrqיQހZH.Hk,JV#QE{yv]FpQג/ƴ'FHhU&C\ֹ03@|Z=%_X]wSBg " #J$c =ݏM)Em3),鷳+:o,Zm@΋]7FOΰx)DwbM1@IDAT0`>t(BLU8/FHs h/_2ë G.Ugx! ~OȚ&`\ƥsK  l>^4C1@+OMcUIZ1 1lkzz䉫Bt&֕亦XutЦY#C{tNJi l5ɗ@v]ƇrUaDnn7 amUsBzzg3 T[lXC15xyh i"9, Ѱkv#p"B {f03y4\)> dh|UJe!4n%Quw*50MkGf* cF!>󔜹ăkr+%aM}j{0XD bŽ6NA34G균=JPK#%Mf:e=?_ A)D#r!y2k{ +P }thh)%'h^`dNf;|79'*CL(8"\S6#h)2.t >^̃zT0XG\d6 lCW : N' qt/&9~6Q]WBOJcFr )I(ilK$Ls:R֦XMİ02nskk4?8My ˮf2CBDuSu0cA3})#$ki@|rF1WڑTDJ8=U&vG5.*"RTX(&Qhi󴜽bW\ 3*ךiRcv>^~df dòl@)!LA';je']!(s4Y*q m*T3js5_bm։1PPq!0.N37[n:}q]16XG%>1h`'ZXakѩZ-ctєRЀ>S)5äýc{s={JuhQcQFJ$~RP&tAI{.ϝՔ*[ķt,gBTWNwǡZY(PMJTR2*R!bϯz8ްfd-vueuIyb #ys&آ[ñ 17L_zZ󧮟6c>JRn_mXmU(ܧoZz{GLDJGϺ.}XAxb)NXUu|Ʌq+ "'=iީ1;E/zBf-?_Z|Z)ZZ4*k)HP07#g =o (CX^?s_k߽,4TqVɫ rY_"W4)jbNL.L>GYƹJ-X|Y0.^"D4jWYB?eOkJܜk`7LB"O[I?wBˇFtWTaiR".𓵃|TtiZ?$cEx HXWߧ S/T(c:'kgw&&cDBfBڃ"Dޤ&=1s|8G'na{ou\6vcEcɁگ|xFIa10`Z4j6>{wμgKwVyb~rJZSx|;ڴi TФRυ# w̏l&fK4R眪4"oIG Ok>%FrxrX\jʋ Dӌ$Ty5Z^ ֽ%GF̻R}nooAKtduW#Fhn| ;{-hq]ni1YJs@}8= cmqX x*raV2ā]ʫ;[] t1{xn(n; 8tɞƃ""%g&=tQWGțc\b,"Dki ŏ5dL衫U`.0(2I{IA|EMmEol\n&y:t x}{连8pC9Ή2 CEb!8qPf %kg Hf_})1Q(  n[U4 M`5`H 󗠚~&;Ճ'4Զ*b?ǦF,.O[X<Dv9gP`#|{F|vls!] A\uN@*vH 4KX8]( 9m}MŠc4Fo 沟u V&B [y 8;@Kt%V6JrBj%ŀE #U%&G='hezu$Np5/,IT kXԨ2xö,_YVwꌃYrp6_ NN378NJ*@}U8v*\i& Rr0| 5T7 ;cTeBQ_? WO<ćts7;KJyiܯ`(;af:Td W\9WT}t,%d$C;zh1Ε.?6u~p#)"=tZ-δ3=_ i1&r x xH_#'埐=';3kHJ л9;0t?a}#M: JO>#\wų8AЅ[ݠgѴRxuoXRW9jfz\?7q.I"ʣJ/Ƽ}SOo?C {cRAt5t~IzT U0:ideI$y18v"PHs>4u<%9/'˻tL~ul ngçG/@W EBWKMj1T V2*-9 Yhp"ݐ -oIbȘ'X},x[VA>> S?wx|c}V|#v1:m1x40(H\z[pFTgq:i1VAHSmor}0'Rlu*6ĉn>9xFaT71;x 5X"Sf_椦/+F`b̙զDh:fŔb^2O*sp o^=:obmA4@d RXETA7B5 E/*]< A/Лl!͊kus6r:#[5tO7×FC~EDM|.ѩ!]];dx*^(ɻ<Gߟ9:+R'K]2-Qvw6՚"%P?g|wߝnf~z|olZ/A| m˂XR6mޔHkDY7wfz8d843K>ƌVYÎg "GڴU1O+\Xe~;lc0D֞í5桥>5^/'0O|n'J'^G4tۍ[]]VA=?-z{~sA]76I$9T+m~9Ny:x:hjt9:=֋ pe13|@7!bަJN$&f:M#~]as;@{%*]+VݗwMĿT:n|Yp t2JŎ[r,z?hU Jwk%] |[ҽ4EidHO{\Hؔ9 IyΎPܓh3Q'Äg.c|8Bm:\ FQ`R7}0bgia &]O?wey>׏Ӆ˽{؅aQn/{J^V*n$lN-_+^6ʛ;=*Wo_"FFfW*-PNł TǞXLvq!؂7l g)E 65G I~->_oiw'щ"VWKɅ5jSh%5HqQq/ؓ(gӈsO5<ҁA,3 5B| Th$Z5>X"JYx]Ub(ʜ)خhf q-4.PB0<-a?}s<`%#E.3h{/ *cWog[\ ۲\~KTce,L32 M+(F^΃Cz'OriSne};-[25a/͔4fn6|1ߟX %Ƴ~h,A7 =))'Ox,soUokB QXo0ITȻ<3oWȻTb#"=ϙ(t%/KY DW+^.;$.i͐pGzwz#\[GBqE<6^0wv4"<_w6Qh_CffNg>5>{d,7% mKgPs) ?-MI@~C^eAav߆c}+%MB$pr͈5Oo-4pf9G ӽẸ%. gwLϔMYFQkՄBt*(cp! hV6 |,)Ţ!c(w94>v{HF[p;jKH'|d +ϠRTT. ph W\-?}H kSSւ4tH '8>2nAFTDNoz!|dqke ^s>Xŝ&5pt삅VȂ3ƞnAuBqA:ozN(u$@}k1z,4@y6،cm>PSHe)&7~211`F)>)Xy7L#N0܃^>ep!@)6h|}})ّ"Q 2lĕ*HMm}/X?(ly> ׭6`ѰuaTʼnDi+ӴkwVLl$p5`'L <@W] I#nC>ڨ!2r̘eX0{׈i[;t s[V>=ND!pvKY0兡)NȢX,Xl}K3f)6,kv,>öGi~ mCNT(ȅ4i- Ai" &K×DƎgH 5bPySٷA'TVe` 7!O*'$0㴷yG_.@Y59bj#5&Qy`%cۊf<ԏ,ĭ5@U2tԁXaV8"/SwZB 1Z~J~sA : 7 ߢjCsV CdmYdFw'Ai"0L2D娀4"Ifޥ]&oe*hݮw-iMr} ׆\MۂN h4< e C<8j!S1O ֘Idb D> lz810L5U)no~Ͽ*>z7ogNct/kIeh5oPUE?域:F4ucp*>fY)Z2ĵ Oyը? ]`qs1Hm`7FD|1pRUF%jo;=ԗD J§TN@ƎNV,lXGp^6?nĕ+eT ?>mӸ+KՇh65'ͰvmMkxNzRA IW]UT'',cgZ>oNNs#hqb}zBa;v(ds>-'q9nԔ˪F'mcP!U; Z>kAeR gzχ!9(x9Ӻ-Q3OOx/X&q".q5tOP.6xgc+fRE 0`P*YZ}Rt7ڕsJ,< L,{<9Z}Y ؼ0: ?ٻ%_~%cV9.J${8./1H@؋MYclEÑI A!lS"Fp|[*ˬTJ6N ^@ Zzlk&K|u~a<A%t=%He vػ d"|9p|D&j>"On3WN`8 gޯo jd.6DJ袙4=y~p}|.iư6eUs?6wֿ.,LnAT"cBPID+HvJ950+JsrJ5hX ݭ|!RDe4)Z:Gׄ0wP}5vkfhD w:Muvf,-j7cADQo#!='L@' `4֖86pF5ymz=WElbq:r -2 %xg"WHQ=_gePk5cWTʝ[hkkh0 H"+dKYڵ4d m>ͮ񗈦TF*i c,WVL __Du%'-Ha*o{yۣwYv]h)R?=vNHa `@@7jz#(Z4Cf;r)Uo ɸao!%'n# ʯP!C %XV9֡-udCM X([*mwՙ *&,4Z)yfpEJ {-^ 10mCQQ!lq5JmztJ_ NBaߓLOUz6ow;&w~L|%Áu K#.|`:"^5AR$'ЮYV!WttHW+]WwrWDxcTLp Vкń ΪauxxyryF== 0c;^eE;Ҍ(wuJ-_XwRO[fY*M%B&[&ʢKOC&#>ڗu((f53˰=IZ@0I3dOG5nh4 KAE)xJ$`$ҽ4we^-\FOGb'j#0.P Lɨ |2ynFOF).~eF=Jr}S.1 H=)~!y%@*qv=uc75H[rO]Z:=h)E.~-Z.~}-y@ &j%&oz#1-+M,AV}-Ӄ$@ё6f˗3B&3^//N#]W<To>B5no^׺[s2t(9zU'D4q"r4>|q~j -vhn$멕soCV3ZJB/@ϏjnN n%JM|.?wM0&CizO[jQ޲!“V``3@KL'w@vP%ӯwJhH]6Pʼn(QL)88HR̨.c!z~b r Uw!RRhhdԝـ-[i(e>ً~@J&1KtLcF} pJ+_8z}vɏ[m}7[>I_ ֑Ѧ{[ÁG.H9 (Ԋ KJk_K@l=\Vj|Qj0'-(8^2Jk_&(X}+Ɓ>QExd}*9uQ dpD^qD{x 'P(fX("Ƨ(hŜϫfOu%%DܦĹw%4ƶ|2sqֳ Ofe&!9gٯ6̗AIwT*q}iHQ+%`$r{xt M:Rt<3g[oi5z7ƼCl蛿bEa6hM?qq`UؗX/N5]HiNF .3T-Qk:*l CRS#J'6[Ι;\-r7+n]- !<(1[BV gnH˟}Zd7@ϻ[ʽRgr";YVaR2r:Sc;rXP,b(- iũI%LP^ n_$x#dt~>5(=[, r+)c#;nJ(2"D$8\.ƹ=EnLKmmHuNon FTM{L*Jh8'm稐)(Al_>J-J8C~EX_ Fl߫SHACBLa>O{xkOCt~t v!]h'WPKH,X8I0C"D1f1\pf<}鉚bnge" Qq_.WVR_j @VJ.kp$ʃŬJ(\gn#%^x!fw攈3]wHˎ|\C01FlwSDfH.#_:3ÓnBs3A,\'J@9z/9O&6'=[twy'Ʈ[|8`̜^t}Au iѠ9v:éD.`sbal *u2I˲8%{P ]%OnE[[w|+Yv&e ?)|I&E9kD#b(1m'*s_O/K]/\N=TVX'h[-8Lw@wv"<,yoN+QMDljFo+sKh K,v!TB~`Ğ:eu+ ٖ5LͮLN4R2gg^2TbJ?mln?{VQ,fBeԓFoc[Jd.u??oo?ώ䃶-69^x #:wCfQK*>7wGSű/7y?sɫخ#D='":- Z>Rm.IԊ|f/yk[CC.)O'KuEțY%8ඵu~vym{hvD`N0T!myl@!iaFA(?+c" "֠Hp&?T*KTq ;id}¹6. 9=|wD,N:N_tK[@d2.e2Nnz\KRsGG&3<L()'6oC(9"iwfCse?@ŞSBw"RyJlOҫ:X48G`lB <.TlQˉ-J*屢r9+~!;8cezw_}$eJF W,?_NmOB59f.M#zPO{; i;(ϯe 1?s>o31>s$嫋k)j+wI⼧VمK I榪^BS"Z^Fە wB Hp_)ÉVLDU4W$NnAdMK Bi6^Aw|Zk"5:`7Quc$bS /oo9u3)wEI9urd:vgsw0Q-z#ĥ ww.MWW +:O??(@wvR.kB>my}m=jk-)rJ VZNڕ.݆p)I_x)`j/z$Ơ 5+9Nmߪ x 5!@g}kq,l9O 櫻Ɂ}_OD"t-9}9-"sQLؤKHa¾&JKMgYM3ξ5))7Bij V2ņZB^vƋKbd:⣦R˷Y#:#0ت:Xl>υݟkBGAPI7fZ\8:Xlf#N#13}‰y0E7ԛk_xmי?M͏ʜ@zSc}X{L]ZD6&յWkI:$'jNS4Kb\-LX>Y[c\ou8nw'R쐖9 ];~ۧM%8玐H9:n{r1ybJbtY-5?G(H(m#fܭYˡ:"h\Ңݞo1}!nʏx'~wGRZo}^\|^ON\ FDyɍ3g'?rrxlp蚡]ooOUVǣD Lk'xhDOLϏY3o7xEq^dpN QƯ9Iym;'@NI w5gٞ?7&xj{_KdoǷ8d7|"hfG4rUJ>O+RiTl,Q41%Rn? /N>]pR'NQGW%oo[m kG{$T\m-~wYP; ]y~zH$TN?@3U`Β/p k+cpv&G7Sݗ)14ƩDIzt~=a%_"=9*gZ‘ SD) Sx bVbl M+e;3@_$Vnu?>gh=Q ,>(a겉mU #:!{,gƎJ$VMmXr6c+C*B: Xybj}1h}k 7P Hq1Ijz'.hVE;3Wjf50Ll4ڏόɋ ȓ,'RXRI$y#o1.u9yI*{W)=eNV[RB6:-ܫ#b\ a ʀdkP%q/i-#1LK<=& f3Y|Xf+| 6*<*CA)ۢh栏_'oUˤb%\  ſ&`r>VFhY]˙v (TAuDY' 5ri,x(`깁\i(5 E~!n\1P\PY{C,܍N@w [`IĈRg&'x\zPw?A[)w'".ьhLo$y>i,2 Ҕ *S`n~~/n^+ͮ!kJ{A槕o2b~!gntp"n iihFv{D}sz!\15A =#f.rQL%d(?^*TWhN:Hh"Le[Q.z}ݏuݦu1u")GAe=F>ȫbpo fѝ_?u)9̿t[O7CˮfaC/,Yb~H$-b UIX8T)lWiězE!9:]?7L) Ư@ROJZf[L-&$m`;s&p.A,: mPt aD,Τ-3Z*KmwFH%ll:=b‰Qt'SSo$15$~ѶxdJ! sm0ey:BA:1šj~m2:mKqg $j)KR4) 391Z9g|vm3@*TnL6@wqG)6dcOA[Q:=ۈƇ9/$:4ہait4NN \s@VQV7{`jnd 0H! '_Gij`"1*EGt()JO8}fp[BCLbXr:b%)@VyߍDcd+rU\؆Ok@:ݲx8>[P2ѣ˂bsmWj3] HJnfc,#>y-;$@4̨xp^t8GӑGk3n' O UnIٝq¼%\J{ƎA'UgQ j2su! uI4ЯBQ/1LvG2yi<>' ܤQ؈&-0U_묃n Kb;w3 뇘; 茅3^/„{i᚟թ1W7v ji>Kѕծ6,0xa|եG} 5i*75g-<GK`!g٘D&% ]I/ID*8Q>oТX1nft,DS-"G*' ۾=灉v3a0dF59I\|^?2CsCצHFYC% BUEB$%0J>~VDS=y? L;S{3ӁM@%&갔_ YBĸr.F>= YԴx.#gyB7ޥ;Ief$(yn$=7;rRmx$pRElvhU :Ce#\;U=.Y>wATw3k">&v5YB%)~mvsbtp4=^A=q +hMcH#J4t:=⻡`$'=TlaMfJ5 Nr#q اJ;8y}ja֚Z1{XլE6#cK"v.c`N(&,gU^ƒ@L3V~~Sj f .1kڤ.YTmwՍ @@UN*o* -YjқQN,eHc~(īҌ2J =30˚xB魼GOjU 璡)ktmp0RŠʖ!4 (eCG||abscB*[cGXTp.{Qr8f4FBw'v7$Mb fԅiCq':~Ź,8a3Ek{e=wJH͵rP+fq$h N=Lp0IJN!- ob]FwgZR/h\oNZ/lp}O^rp7tosH]b˜DS 'a ݨ?y&U{`T则 eiCruNbV F v({_tQ{ P)/IEB5mֆ?ڭJ²zspYd qTζoFºEpyW !sa"ȑרOeDøa^qO*|5M*&݃+GǪ ٔPyo~Y,DXUpRrD6fWFʝ ]B2dQm Qٺ ӻz˶ՉKW'^Q"giVb:yys=LM",兤TCg\J t/ [:@לDݽs> ؼái-ŋClݔ|A.W%<=ОL=U-r66%rSN1a15S]Ff4k.=nFoqkVW^ic# WK2iIi'6?r}BPn/Z ?|ϡEb#~hjABL+}| #Wٙ2+R6sZwܘ  D| ; 3ZedA\ii?U>/l7o4h<{&Z7+lPj HB]Te%ᴻXqͅLД)O,d]VS%!;{|O Ss?iY;d.z4jr #mkmCxM;}JhAZҼ)=Q"pPqEՃ0u<0v j!ւ 'COAM/QG#JcV4__ڎ,A+ '@9rfu'c/6>gA0F\\°/f)_3|:9dp MH7]E /~zYIu=ZB~kz?=}[CP8b$n"M -C2Bz%𗳡SBe~o?3_C{261V(J3)OYG߷vcgG n)3Tr5(t[u:nG5?&NM, EôQ2R*9gTOenJRvHV8ni_ lv^*{IcO&l׷(|wS1JnVī6qLf\荲h3506 -[јSdvw}E #q[7,'{}ksX`Й8ws4ZT.|R jwް$%ͩ!^}!H/RY80Nnf9:r?"vP͋~_JTg5} &-笊O)&ٮ6’I+%b hG4'Lf, /Q^6#>^'M8)PTT4ܛ gQ뫏4,jg#BO<IR)!VO?g`( V&>z"FyXHs@ p!c?H<)=\ @ aBQȣm-Yw,#ϳ+=Cv@D r~? ki0~ L\0]tlq6]1^^gFqWn=Hէ0|C>eEX„pG{3 <0nRu%N8+ŷ/GLPrWnDZs戝aPO=:(.f}|c⋌N3Hƅh~|]%.Éܖp[]mX<.k^i0Ip4*7S#O),ǐ1Vo§}tSZ7/@!?n,?.?kf)*>4f";]2.%eItr+ ൿ;k$iAAYuY!|4 P-h ugGvi G~^]H׎jJ Q1FKVCoqgMAsBg%vp a~3>8s< axШTht1KA=הȁH5@b>D-).@֑1Zfՠ5/?o&bCq>(81!V)@1_G˗ Z:5HZ]B%+P2,pj մ}€'E_m4+>KDs _ q_Zn}p *&slϨ. E5 S ݝxErL1̹:6lLn2<'";AueS4 C(E[Կe2ڐpۚEo=S;+=?^ #S5KиLESj!c9.述CӿJ%'^sݻ)Re\eK媻\f8D\# iҙQ;ytroɺv\kY#E2A:|Y^܎`H۵2Ҷ(Lx yC4{˴mMhTx+DQkGG(;6FwMb@Τ߅CQ(nUabaO&,gc=63`hV1V@JPDedxD|6!L8::q:>-Bc+bbީ<=Md\ Z%JA饺Α~`$Lct bwj־_*7`7OtLy^/ T*ö!z&FezwHˆ<0w##Ӵ[B$ Q@|҂ujigx>~fQ{\9:2LV=S 2IJOTbױd`ϧ;#:כeo=G Z lJ".ne)0Y~Ë˪V8xAx#ݘbAX2~vE۳O׫xt0f#l"0ǰU DOݫ qWWkƗ06BǙÝzaG;斧Ɇi{l?FgH+CkuԲWWUw[Lrmi>oR= 8̛AʋPn eCDJ#4[V<=_,Х>t(^ "&Yn8V9.uݘ&tHAAyV4yq-pwr<&y@`@jJt!vzfYw$1.\3ܪX?j[doi0G12Mu#D:M w4Z<cbktz]-vjWQ4{W 8^vOKZZ~DCp-꽀\e@'mX|>څ,-5=Uf LggBy 8~|;^L!xrҞ=XtBN߻pȰLΆ#ͲW%r>!sd p(U z\~],ʍࠠ929[ޚ1Xu׶ð1z 9B:1db29˵֖1g .Թ\ oo;zY],=Ma:JXzͿtT4c.75 aWspQS۵9F7.{I/ۙ ݮ}C6-N&h_; Dip>A1DDxAJJm n+Vze8n \&y% {J*aj95^y?EuS|r]aejq)5/ujA#79wnJ4"΁h|䓡hNQiw`uJO[L>rS3=+F|5\lț~lFv1*syB[!Yi}K( K)#6NVxryH۔[ ;ma ל.E4}XV5$v V ybῂa;nL'pc\/jv S֯]Gh`|2%lIXD˵]) T&Oǁ9hsKzP/!l.ȲtIJk!3(?t-b/e4镀Ef1ipavu E{jɍN>i_~C ;BDNm[-:[u]5qƫjtUߜV{$8bO)c9~ƉȩEqMGe,ub(C4)5tw!ڜ<0*8H@RF|Ha!uFB|&iQF;+pql㺴|~S,kxL Z/R.;퍸=Ƀ@A>5VCdqi0.U$)_wRB#@htrZg{MI}=̔%"G9(&Z9>EnHoAڂub/I50:aɃ ~e$ VxN?)j3 1C1_|!1>|//ܱ Džx1#P!QfP$}iUb9{z.ZdQ"y#mW:i[N'ex-ZSȴ *NG-U"j2:! O7?@`ՠ>Vpsro/Q)T#? =@J8<1΍VS'HG BlN*R0>wb^̀ scI#5J' 3nM=Wd*~P*P %J77^;>l aĴ6P1QZ^U4Cu"nˋJ9g^`]^#%T90fvZ4#1J)’K]):7)°r&(χ0Ãc~HnQpgUUT( AgHYIV7o֎+&I`eZ߾yPL>iGIAmAZ1T4GqjhHv8|/ "n>ϣ; SE)" ,smIV#K&6{9#a-]ğKZd/+4;PaYȣhfCdP_7\ylQuhGm_tH#/M{Qjd#}B"*`ߧ[6cî8SO-J[-Lm`A}>-0}&g]RL6Z$˛:'m4e!ET⺡XJaTg8"H.[}eRBqmY⩾/ >WP 2 :=22hz۶BS;Y0ב@,6U$s1P&ti_8fC ոD:[ ړ͡oEXC7`6Paĩ힨ʠ460:ՒOO o6t3,@.7(w8O's_;6 k4&@#aE/g)SgNusZPM$;9'أ!@Qi~g`QLY>Ox~)Q,J d矏|tX|{s)Z:X7D=@ oX߇ALL.m0Ș0 S U^-Oa*H_#rh*I;K֔V:;&3˫jv= Of_ϴVF٦ %gϯ62QsǍ2~f9ގ]mOC"%=T6vByT _f}orCslv!O.`cKP6bqB+|?":MD=@ 6YR0%մSyf-w_ez-{# " _闶Yr`n0ܮr!~BF_&5>CE?`>*Fy0QH/D iqؘ/A ̡Zdwh|j2fLL'UU 'RزOۃh6džRd&Rxz~~vK7 FP7Prx;B͍X߁E UM/jj8z(#ߧɢH99.1Ah.' D 4 x!#I+i!Ǜ0XcEY)Hѭ﴾QBοd2R"PAP@g*5Yz4PkJ#Vi(tů%t~,h]g'9^$Ld[r2Y%ڼj[a޶ˑ 2fR)ʒ}q@0_Sz Gyhָ^#n66P]D*U>dl}q(eQ26uX"Dj"tj) Gpdtj+e6c)B \rM>$E ,C2GMXҞ Ӿpl턔X_oϞLE Dڀ<#"4x)* OL.ZX_C"y‘\vz[qYߊjzarfݙ"sen5F.UDMiZ'_`&r@vԙ`9t)~s:l=u+9n?~TRlfcuSPNjx8A僙X f ?GM1Mhk3Bd{ Y#Ռ VÍ:)eڔfr"-S,@Uh9$R&(%0ܒ ]DJ)S LTwm2J2)qa VSk_t!yugr*;Z/4_f#MZnH4I1e@A y,ȥAGEk)hYaAģp)>ɉʑd@ NH$ TtUÿj{AsFJ"U G)$D oϩVs QOY&H>P]=C#/)P7牊Oâ͒k&<a $3v✹\LץI YޘQRZͰgu'%SAF5b8D(&%l@^~i wkc cǬXeS2VWoc8h[ |p1,(4DPIdc}`5gԋ{ o ~M{;2MSS Q-dSe!.A>O_<7Bsf&LyjqtF}Ǡ  “ Hu>ߨVo(`rRӍDD 2V㤳{p<04C0 o%qx*)5̉%\׮)?PE7rrj\RW3k{817z>m\(rg|N:Thn8 *켘'45;h;B+0ezrL֓ү 7(I=aw )j&Kiq2ف踋~lW#pؚ֦E_R:Q6v=$ќ-:1ZqX^MeGiQ>n/ս21_ufyZ,яQ˔1nc4˄Fbǝ:H;.Nҭ"IVظr^]{-2Da)gӖƷL@>E4[<90NZR(Mo#'͎fEYʡ` @P=hax 9_jT*)tz(]鐓=+[:y{dhmsܓ%01%pGnjF@z;c)q;z2 D,ADNs@t`B]`&/;l$\yj`ۅ'1E kiń81h{@4Ŝ@L4cIvQ[M\'BrV _ho8 XŜ|@RZ^a-dA,Dp3=eTθH}/\:*5\9IEŹlG1Wh'j]2bh(EZn ?pj,;ud^g00dpr;0{ <Ůc ].\!QTDlZx%SU蛆3|NCR\֯JGHh :)/˓J@AA(eRcՑÊKzTc@SavU+3Tՠ;Cx<" Tc LƖ"ht(oUƟ3^g*S hOJ^LO=w=Aaݞ`#.NSPAxb~nًnD^&U%@fH? ;LeF8Zj(9+'xtTcr_V4x1b9#,ea 0EIIb85&p/( i9=EpijتȂuA:Qtq9Bg [!: sˡ(/C\~b| ݼ, Im y(W=-OwQm-C Хzm]ԒWȁA )2.B# J@j';Z2>EAYo(yE_ cK[y}>.o)1qVɘ w/&_(<-XPmIOjXp,`x EbDCHiRD&qľ*"ie)?ř$(hj:ZY3injb@\TFXvIi˥`Ǽ  W;L4{(uҨMTˈqo7UdA1 _$Ѷ}w;r jNlOQ`ƣ{3o~n?ڧo+hI =:T-f[?A[Ć`rR_mtblAUc$ WC1e,F^CC3 57r3b=Pn!ẋr(V?[){x9(E:6ү.c97 (Ο{n4vLt6% sڱ9BP,#{~=~ԑ6u/5߮3ۑ!,xcqx`ChJ&8NoÖ즓|i'v`)]4]h"rګ%FXSaD>gb''6Ll ]}T>[?an{[@&v?e:Tl@IDAT1rR i(w=:TyCk~PTayks- "w+)xa%lтD!#QxNRm@>M$^mK }~՞w+JP5 g<4UjSvNl:Ŗ8ia(o7XT 5dA f,Ơ˜X}6]p y$j#æJҪ"ͶɂR8ӀCkVh. 86xGu4Oy|HIReW2O Ȇ`ykFƹFvCSyqc{Iq;|0X77D 0 n/^DLGl&ɳ JO~LRq{_AsAć- -ubh.D܌Ђ{;^Dc9:Bqgb&M7py,|fHqg`m lU[|G?qJ5>J@!5X\rDשlzvH]r) Oo. ^m'J ݂0l E2E(iϺ)ɦ6}/t`4h#@)LySҧjo>}ɥt~"tB6HQw/7fwl?퓨;}X7RR1a|:v"e6(  Y?m?_KZH(v=)B!5;41$hSnu@}@tebP06Їh/~0Tk_[^hi0tDMoan CKpr'/p~A QkcApk3dCt3۷kF/4C0i x@t~sWD'$j$;Dl:ofTQ),PYak:Ratf;&(/cF|8FBp^n !㻬=1 WF?؄  =^ZD`Z"$(7$ bH#S\NH::+w\)}l b=LӥӃ^Zh:pfi.KJGv;O)LuzhI҃}]f(<ϻy!90Acga(? e Fz )>ح+MOhiTg0b >RC9]mM ͕uٖF Fj¦,I%Uש|YojgBC* [􂧳L 92rM5v@U"غW5[Htx.b<ڟz&Wg>J:5#hČx"qZ8ZnDKIJȪPsHoXW>Ky9ֿlJء7M77hU@o, M(il0W:8M1^5(h]q`8^!>&c3O[H:{R]j,Z<M`y+nW0gm5rii3d]F hG:hNh."9THRz"`9S~r/4\|p %^aYuO:E(fPr#w<dw;fLrj")Em99x$s&vr."l"8K5?ټ*Dx+J/#f2EMܼfCi n9#zL< /cZȞE QO88cF؁;P=5^Id)ұe׌2[᧶WQNģ?>CxB3p̅),6}s0HI_P vgTӼ905?oO;m*f2dc%MK4^yt4 OՂEEY=?490@_nTմ|>&,  fQRF/# 3mxv"|T;Ȱw(\#ףraMpZ JRSR <0R=o/'*dr -aX ݛ9͔5h-Ҳ=>HH ]t 4S]X׎=aÃYONɐE{i0l b'عjP $%PAO>FIEY%ѳOE}&g=Jk{߫ee},tݓФRQ2?PmeOz!OH յ1h4^{eڕ0*j` Gw'rRLFc.#7=#H qj۪kAr&5ۨt: Gj\#-2d`0-z~CI};>+Q1oYˉkr ^og/sd&ҳfeטqJI$!4xw6%bw?lq] f%37ZJ=v LE3΀Q`CUCYj9ʤ-D) >"hcop8M[?}=z7(?th f!p L#saDw||vvdҹJvwrp؏ "c큖Z42KAÈә'3[i,oK2 Q)&=_K1*c:"IE܈@y~!3V ך310S@+%^gC1~Ҝ8\oһ2 qQ٪tnkg9DiI'IM^Qo&_u-YGnG`slg<7(M,M,Iao(OdVS\c/pDz-کpՙO)C*]iScqd/s17^p`36!{HETOY@"@Pm ETgķnpʝ@6.aֽTt`niL.$ eFbqS@c(2D=ϭOCa)ց2=hC ǧzK&hE})3p`OhLM%JvϕOW|<1PY#;$['=1I>v!EAOK۸'aq n1 | >YxM|cҢY\|"f$a? cAvm.e=[Zn9Vtχ!)I:)6U6Z7S0eEq^ < 'ᑯ;LKK96V_$#cJ0rclEgc$-a$yvx)RYJMj8.K -#S.gц`eu*8J`-[)#"ȝRcB͇m:ˊ_a0yuD 1"[2Go78mYffbN Nsj%,bɢ4 ? eM:8-tnic0S2 $҅T-P#q`uBU<"03WZlUd"@PLi4#ma,KmځEǝNʖ!l-aDT!xiAlM @ܟrPKs,<>ZcqwkULl{O ߖyI0(35P65tMſ !(bisa4" kqL9#auXlLfaz:(̍|u4%+d|iA?`ÁFgѳU 42&:ʸȬb JN9 <<Ne$Cn࡮ *WW \G͠F(-ob$2b6sbT#oREQ '"żgYqU0a>8KN $mNǵ+YPeQA5Vw\gN `K1S񸕗d;'8_c*o?4T n?>h}rTlMA3pF^gm8PS-',!^!q> j@C"QsN%}% Ÿe?߯_5^W0k TTH[.766kn|d'W5吃I D"`1̀_A8Ԃ)0r &Hen2Fb̭S|H<2ߵ5_;$ b*֙^ef\g{hZЁ樑''`6?܂%Q(ӯaYCIe=U[RJL=dHn4"Z )ożK*skk8Ձ QWNﴲfN FP}xYddR0Y E- ցxelEomHjuen]5hb(˖ \ .@|eTpSQ'v6P/E(TwDZN2EDudơNI~}~"~{C/Xޔ۴}}y~CS!ѢoF#D.E3hٹ@@*Β,58sn!rrUȔ=q4 26C&#HkZ!)l)NgHFh#\tBV]%uv0Hn HnoAX&ť诟&߿aPΑ{aRMP0Y7Hq)-B"JץT3[MI\?V⡼lY gp&}5 k'# ѝvڜZu6M+!@\hfwZӾ"*Gz_\{mOgZ9N!d^$AJNj[0gOK~ܭTR^m`$ģ:Xɢ_rSQ-g7ey2I8$hz #[W} -7߯"Fۮ Vl|Uo򋅖sbQ/\O->΋Wd9Ӊl J0Q"u_K"VV7XKs,kV?x^N_?[ Ll .F->M=l'=nYѽ9+cǒAmnޯo"2H͵7-:~ |<9sz]n>VqZ1?+U(ESkÒHTR_( QĔvt0gq"qrli" :+\xF)rl̗QG{!bw:%T^^P178 j:uDDz )"/\sʁxf4ZpQSAԕfb( :xG9+NTO`0˩o_~w=mꭱ%%W6Vvs_Cڜ'p3F3J3Z 6j0hUȔq%BMoH[`{(1:<*qBMX0f?v܁]}c\윍R6fO@!QEАc܋cth7KCۧ#?qh_9y&hI%9^ljQðF(fw/K\B~[-5&8Ϲ E@d-?'?)< $j9ʽ.f%l&MoAhCx0vIJ9ma"Ί7؊KڢO7)6X.tx{*6S(Uʹ~\N0?bYk(5d[U%p NECSrGk:wOc]L&v\!1aWp!2:a V_?L!a_*edFʶ~vMeaH`;-Ԑ {M+'8-O2 D/Gg`6c*cG4;+9F^x|h%.z{ <<Q6RANڅxޒY ɚ0}?!=A ~q1m)y~|F.IIRY_Wp熘~W n8[ZWV1eNx{FqTȪy}?S9djgg_~E{"Tb@ps?M~[Ae~Q$T-;HyARmAqZF;|srq5sHxU#L0M;tTȰv@#yKxypmHp/|PbWrVQ))ڜ[cHm(: ѵł<0MqX4ᶄ4bE?RzvY yr~'O`ʯbD QN%p;:`NUY{Ԋ̐zJQB'Qᘅ9'kqE)Ư* 3Fa8;]V%i*͊C wܭ{K^+MuAU%'UAFBf^CSګڈRDz(gaL CBNQ(8SiLCz}5o]k4(I=Ũ6טD -)h`_Ϳp#`9oZkz7p_x'_ :֔w Y!ǁ\Pe ݜTdDV)'2_C…6CX]Al Pgg5K8 >[ZYFԙΦd?mB(Aզy^ ޯոS*I?ԮE!;@34F*g I! Lzwǯs"ؿ!GšlMP4l,‚DSf\*kKv@sG*SSa wQneġeV/ofڑE??IPuQ?#S 4zRކ$VdbkSZhW3Tl1hqsIBA{g6jxa "APz Zp"(Dbktj(aJJՑYC8Ie1HNlo+u*8W"!^`:15v*8\VO8RÂu+$V>M$C. xj:@DǬHǒ@] ,緁Z4?$zL2x+y#]z5t2NUXib҅O;øv\b?8(aC0ruUmLEbB.Y QthL8sa"ּg}Yv!uxmK@:V\^y6qF]⟑  > Cu[fz*d4jfcu-V´ODɤl#w K7lkx60e֗֞k <>O)-QVJO79ђ@9H})=%H>z}G'-s0$挧11nIcFV~t˷vWﵣ"teſ.**kd 5jq8e `3T60#O[q}|J1ݩ1T2 qyO#=  +u+#(Z ئgU u9OWy1uP*@Ral(xm'o_KADHٝ:)Fؑc~9D)\.!-v DWQ12l7V , Ss~NQy^5leQ$$Q8b!68zIϣP'E >/ڞ|*Ĭ[8\qbY0cE#/E>WRj٨C'ߣBy#cu 2õg a \q2rf=ahy ]:=wƜ<(DAr\q0R KSdpw<ӛ>Nxߤ 9N}* px._0p7=4#:'?⤷hΣL&~K]L N $mL3Z{M4٤Nؚ̋f1"RßB jh" OWlyY[E)<5CZ ^Q:R/Y/^sX\7s9 DF]PdgӕqScTfF}CGZ7 ;3>}<"'),jkjc2]>d9,/V<|?n`߅p[~*ya]&Li|m)ntro:e қ8ㆼD] ䷬LeP2CQ"5*aʇ~0EAPTb4u[ٗnWqx[OYh1~k?[à4j|9*2jkoilkDRK%sMQ2vS\x^Cl)J 3 AYQެse{;m Ve}{\y@{nb,irF|  w1I3壴]s-J4OSp\ol"_Aj8a3Lr3)"ClTKV$o ~p #C"Ն% eX0 NbC[F*amC#kV:jLp 3WܫeSIf zgENn8X&  Jmnq 68Pum7F50FK w0T+IXrϪى @5զ`Nj$ӍT(S}m95>#[R1:JQt\hR=CWe>4FJj6.G4Jbzv1L,L)9Yc$fE~:=.r>-k~bͭA#h"_d+.PȠ8iUԱ_puHsŶIweLP= zSOWo½_>iS/kRiiF+Wa>QCO-<zReGrZ 6jy >;TozcCzArwv7N]Q>e*#mPU5];0^G#<Ǒ\քՆ,NZҰo|TuȪ[i{teU9M.XHwAa^!K&LxD4BUËDH.Yhte~J(AUZ9VV܊_4z)0 4]/ |]1Fxg. Y sWrL􅌞n&[1Ȝ/u|T-!]K!'dٜVA gŭ-COAͪ"TdO-p̗=Ç`@zdv^NR~PڸSR`HL{h'Q5zp k-p(pTzE< )OTe|,9r $@|9Q8 XBcjIyR@)Ď 6#ХtJbȡ`UV8gE~ˡ90 5g.11ꐓkjӥ }^*2ŽHeS^w>n)#zxV0ȞUk\,ҺT n6ge a9On%;mp6Ч>GGRJs|#P(I?R}?!ZJmEݠtKIwl$ZyȠ̯Z$$ytq(?SN +7X 9P+E 2'20AXM30Sk\b`5.^E$)T&F.9ICNsyFEiˆ=AXdd LaN榣p@ֻKH$I}jgD\4dD D&֪)k 3T^Ll(0dw5hifjG,Zp84Kd:*OP-j>OVR J7XT+xfh0y bS~} m)nuMlp2S >%Ad9  g:S̈́뤴OҌ, JM 0,H}Wam\yYDW"` Ҷ41I21$8F> O$җp#ׄiHP@"* ֮+j ?/.pMHȠ=sLӐR$7חz#xCtҬqa\4"Ҙe9:Zj*GP%h?3TL~J2v^\ p>gΣ9be(6C 0U @.#k☏sOjT%&į-pr%S>"=]_\do@箨|O:tFkdF6~'kV3g^t%81dd[!LJ: d0qΊKuKH -aW2F-u0)A(TFlZE%OݍJ4g*7M>߾X}ZU%dUp3vlQ+4ʽb TUH"X_f'!|9hc~ ?%L^4EN0)@C$7\l9^ Jh?yq\tj+e"Dpn<$t#r)UW"}OF[Ò:doa?,ͺgr,8/ 尖~]9^gR U#!|;u|s%rʯ' _mZz`:S)8Mۨ u6 0sĔ›dy.ߟ9V7,kӮo ›6x^[D[wZ[,h罙R w߂p*̨,T=ac痋yt ʯ|Z/v(|JԨ 9ZkP]S ;:ue?}D>4%"W1p;-Ah/Q%pCu{|k@IDATvg(!h -mCV_ЄfgsY\QObOS._v9QF60*)zt>9y}r{* ǭ |盇QՇY,@<(05ST@e = $#㬀a<:uWcZ~czf]4<K`C ~ͬ~;>.DTX`Iŧ4|5fVΆ'BhxJv5gճN_X_y0Mgj+cGԂϪ8uFx?wN~y/KcBD[-fw'[ri{ Q4G;@AbJ}FhV5$̧eOD+ .9u8) d,Ֆf -74H˶}V n{}s|y֛ZUHӹsE'_ȏ'9uf'mq[~bk  A*x%5dy(^t#W”"XorRVH"e{'dWmkjz@W|, eفrRbSh{'?( P\^Yc"deN[6x+f4f}Od?dtq?š''Q+ 4Yvi'hBu6?ϝ*9SN6ʖ@PXb!f6zl䩖%4f^rQZn;ے) {^U}siy_^5ֽ]`S a۵lڬEBC2D߻dBZv<;r <^bmD6`# iM[qe-́4Vˮz_dISX,dE eX-/"d*C@7$Nl2[' ''̈́`W!*acyY ~ * <:)KvOc!EtarGkT^3wG-sA*? |$Os[Ug6Mw$1=edQsIEi%q-9\LX Bw&e,mv:~ #V&X< ܓ27{H0r)L<+6ئrEW,ZypTXAancAȌw*.˲ܬ2W`;rb_0)Q~TFKzt5j5wgnX!Ȟ~M{C|PE3`xt\'|1,bO$ px g։NOmW1[tiN#}0rQdZy[ $x.An]1T$Wݩ8kjyTfl9"Iqsc!_;]j`i"ڴ ϝ)]@:J};%s0a'mDH7/:]{ϛ]]LxyEb{}vc-Kk ){r2hRs9SH?w[V߿o J-p=r]*XW޴ Aڒa'Q5zNS̝ uor:wmD3] JRj¤B"dMUw*Xըx L%%]U=t}?Ɍ;!mp,>D29$Ձ=D݅tFE\)V,6ꋹ|o֩eT2>'YaKGBQuԎl2L騛 fgR+?bfe,R`0J*P+KOq3}dz1xl3ʆJj/o ;>1>Qj"-U}GW*?`{(Htܮ?fW6:+Oo"i2 н|m\E%Z^uaL 2sLӿg & BI>Xa1ChDN`.:t-7 xgv@(78F1'GgD=>[&D;X: ܅VIb@!'[iGW1I~ˢr{F7S݆ 2&i0s^uR͖}*Xp4@bE"s!]R*o5FaB/@J _Ek+VRMMnh%fH h'zpG<23,d8fM'ӞbIyLF*:/8D^Oz]ӾӿW``Rzr 06ym0 Pg+v"7T;&د$+͢Rd8hD4*ĞGg39Be@lR$|RQ4DH-)z#@jy"[8V+==>q:MCƔpGKn%dd !vȦ5uOr=bh%hPA[h)^ :4HV~W'9nLl!xMl\Y<aŽ) l/%: tf2}cay*V2ٵ ܆acimZzciS+FU ˪2}IC**HCm^͡Y$@H<R@aNM  ٍ\3Շ\N#FE5! f?aG kb-CIV*a'Iİ Q CSYWК?NH(!΃wapAB>-V2E_tMaTqe@SfǀJ!7)~hLj:G/_ֽJٲPoTvO3L<GQ@r |ƬLK)!/#[.J*(gB(Sjwqx/CrA ~B`$gRcq)˫oN灛04HȅvcRs iZ.05eey)S!3,FqqΎ"Iǖ\w﷞i‘$"'9DI`TjW> : e3UxS@ =#bĄ|fb0]ELUkm*xfcsJ_9VGR .@' @աlGfbȨhx&x´5!ywJV,ac" f`)|%#5S". e1$,TQ59n̙a|U@¯n}UO%=虏OT)p^D2CR[7$87,Pxƥ q\\nx;{n~d`"~;A8s)?eRMZ Q:Ǔt'%5*Qm^X D>P+C !ખ}[I#-qY\2 ݯպf0⎐I1@T4NBԙǚǧ4UBTJҸؘ P~$|<ά*FvlΡX>>>AR24lX)=pf(և .;lبai%')9l@HKFӔ!-yCI O\L %QEu=>2r>?hin֏ʱF*h e|[kO)/D{`\q=Vzy-,M9MPX's8lz T([mSܨkAukI m|T$ %O6ua_$]Y>Vޜ5o֖)%xhl.EGEzf#5tjY^Dț(d a Ș^IK R="w`e.c㺒L#AGhtſ=E ͥq/sۢ 8zw3C|-1qlZMqOw%vaCA*MYBMtyݖ}JM&чx9Ij@ ʦiLձװpG&N@oL#ih>ٽ@!h)*-NW}"t2/Ֆ)t %j!a êj f@`b, F48 0dpJ 0Cվ*nO?5L%c1[RYar=NKſ: Wze54~m(aqհ́"f/4L\jKySrli{DRuSӭ!S|7&G ?GUN j0ЊfӧӞNDS,kY&40Ub &PGsRjUs}7*S9*hҕH7 V%^bhã4y~&R0P;ƿ<1i%D⻦{#S)&5᫓lfS*4ѝc^ی4έE<얟7oJE֎jfE&߂(m Dx-Ũ9w.*v󹶖U7!2Z Ī?@Wƫ :qy+h9yI1M!c{ VEKY5Z*JzGĪ9nܦsR)8S,KFűB(=ZVIpoN?\ƽO~7{x&XX9Hq LW30^vqH`v<>w:'Yؿ4f }5hI_b!S-K=NŤ@kdVh(:}+I;6*4L (z*5 R Q5EwmCC߷[ӪLY:֨5[VBPv{]K*ҹuj?6U<΅7E ZDC 6_=%bUJHH]v {9}sV%ǞP]q}3YA" )Eujq"%Fc=P15%=ք1^p')߷!,E_-ݢ,%`p*K K"&KtSnv,Z[WP$)⟴)-#PqNVa>J8i*Mz$#2ݔGw >IYSn&Evihx|k kr*&()xk߁lpNLp͗dRCA5##j0NV' PN1wx1;7dT1"XA;vp3cQo80!]rXW5 kYo 0Ӕq$m"^KwbUɁ‚x;x8ӯkQO>~sZ `QRЎ*& # Au N*LJ[E!^hĦ\9)$##̺ VQsW+euZ"zu'Jd*Z/ږN\ BfB;;TDDqA]%{==8+!e%w~d%癛%z7Q(ٽ!yW,˗t a0nndU!p꺿!qgAjb|i뗼.bwE&y*/֍e Tޠ#i_ד=,﷗ڹ%(HV [5(KEa $U8!) ч!%4eF8(C$|&]٦[.hIgϫ{,/*<Α5{WٝV(b ]A*34 yJZ+$Vիpr8PۗϟߛT e6i.yW"MpB(Np˻ NJ04GPiy:SBv-Ck"CAN A2T)>)S8IY҄y)jY7\Túe8-R @.A ˎIF(c. 1-%c:宲:;|/ȉOt_co?7dqS7GyG#Bo6ZS(Y:Y&R.ʍZKSJDTM+˳Zhv3ia\!`8ʹZNi! I;땢`)ŧ)R,c\azՔܤ_cE`AxD^2$ ]*'Ca!${qKoQ.Ft ̂՝j;?w=wM0\t=`̒'xg_|+Ѽ^vCxO`UIŽ]8MI{4 d;jhYĕ7o {;$0Z;N霄=;vT ww }2gub\ezjcjLd<E֨AQˮJps{sHY?rn$0^9sÿljRP7`G--orpiDͻ_. rηJ) .z^,&xFl_Du4\w|[/jZOu3%B /kGuq7KqTb*[MZ`MִQt %f-!Uys&r:/'Үj$7AD#Qz 0Z:Wx̦(mW4O:-g[KQZspUL_aLSm ׎sR4dXB7Eˊ8lhX;g{{ڹ-̽6'nG 06.ޭ߻(@A U]O*,ID2ۧOÝyB![ShrWϦ&=Wz󺺾ڼpf DW4ίO=}|fj ^k$Vs^Adо$ c`GD^(zvF͋SېsNKbk|B"PW +@4')3^+y?c^/n{o=U{J5Dԁ\!8EyuJ@| Bu]D PŊQCh Y’&\;%dݎnub0T$sD`;V/ /u_lsa^~*6e> ޝL޿?/"2q@dj+٤,N)~J_7YS๽^9j5L+?!l::M *Q7Ō &H{񈷭w8.2;\=@gv%KD& ܆V .s\.7c|Wܒxhr Y ɻbbmFV_&Z͖ .&0no2e}0d%&5>"*cԕwMsCO!&0!&{鞴qpե.^o5uQO2(^pM,.. rzc$CTGY,J]xRl(|`CﮅE=qbPW=|?|Ḱ8}- Xr ^RN??ZYDnϖwϱpڜe"-pCjP y!-AWejGF:BY\G&56)ě[v-Plϫ?tc/ܺ۠4Ho!dV0y؀,k:Kui)Q=Dc!%m SSn9s'т֮T,ɜv~j y'T: `ˈ#&*Y^`F 1D))sV$x~%]S`ze@޾?1tQ;Q S-pzY>n|g{lC`Fj$̗!g 1l[<)AɋWUVc  > inf!a."+<9(w٥:o$}[Y5qCo}@3*H\,P'X?6 610jBŹQJAT>n[N_X)b/ApICsCVʖ%#9g0f| X XO_Q&3uOü xƶg!/ B,,PD3Dٰ;(QtmuS>.nn PǍ}Lpxw2π{bŅ~UN@d# Qz8* ᷖ9ΨH- oz?@6C`5pw(;>i p|5 g/N`OvbDlmXDfFf8%3,:L 8tt`3UF`= $\(` ˔QMtؾZ_q8 v= 3xG9i )" ִQXeŨ[ ꈩ-&Țq+'EIOkB~׺n5İ+\sxjgg%}$US^4 F^2a ʏh3e$9̤r0 eDX% !PX[Xjw2 G%Lܿ".[7|8K8"Xw V`XWHELe\)W?dza4>"*^:15(P;;ys]钺TmcD 5xGGwM1ƈW\H* %>U V9A3pN&|djDHAq"]KZYYJ™}Ӵ9D;T\^+‘x`%2u_a1bԖ6}e7), b'+ܺlp"zWWZ c2l sjߊ)Õbv {|NH)N0T̐yyjJ?U}:~9" 8rH E%jHj OfY|' iխniډexV tj)JTMj6s&4->F\r.2-N'?: s:04jxʃ >rzlX,kIEq!0B&Dƍ4e:5Әhd k_nDl}%mv/vꎕa8Y߆'Gn14ڰa$*p('gzD ?>~fehGT+Ɵ_}/&A6qQy{ޝQ0I, E^T\+p& LTl4 djC#q'c7ѡϼ+Nx<)b$q5Oe:*5 {l*- aefuh>#Pa#BpJa Ѕ>QOW8mPFek2pi.a 7!82ra"@ nѬmoȴ`Up4LFx?R ڴj"Y ,BLD Fޖ ћ)"Wy,k"Ȳ (7O0xDz<_dx̄PjjccXp9`=ZCStiޚ|klƩ(vdYor"o[Q0N`V a8)܎<_̄:B6:kbK؁m_֍zIRj!grÐ>i7Lȹ@ú9#5#hK{h'|'m m44Ł6 M ivR:#e*1喎ߚ-Feݚbp#NTlA@\J 8}5P{J˲ؓ-RU!,;lBzMCXwWth}τfwˤ@GEZxܖ?>=l8w41GA(Ƈ+L& gxE\Ua}t ;tn>398˜\VPL mje&S; mq{\m(ظnN +EΩ%r=ꮒ Yc![,>%b%/cXi"ukۇ.ZT^MP֛J4UBp 8[2qRg mkʋT] T e#V8\ƇjVz;ZÚCfwX6 Dѫ(b q0]R"0wmBEzC{='cI6]n%Ȧ9[>DиӏY WitN?$6Mݒ:lC8(zR_ _MK U3v-,-kVH_SlSY,mY<5Ł"@17-G^|2 -GJ&ӆ <S=&8)_!PL{ņPpcj8<0돴Ni 9q}"1>Mb 8f4F8T9I~({sΡbH!9Eӊ3(5/NګT"5r$nD5w,$g-5SOtaZ#$1֓+X8/v0WHmB]b-D80еŭJҍB?B) BVIUż-Xu0%|*r 2 $ɊEvs/pl&206Bjyτ7*QWd(A=UDh'5n0ĥqCGXR+!DRd(OBb `|z(ayW\D{Dhc4eZ`xKs~&lӹJ:CF'g!R|-s<Ɖcf"[U+20j$Ymwoؽѫ@.EJ-b46͑Z)N!=Ap Sa!ȎNaRfeT@QwS08džra,LDjn9Ӥ4RxE6{l`Ep<1rʉƂ_Zra#Wjcӆ6 Ŷ4@0ef?Tof ۧ TɈp-52 +NBZskwf3LVM4<Nj:F #erZ#[N p*]Q' lX +YEY`Q7$>!+mtbwrAhtB( hM7X ρn~wB%kFqę@˷-UpC!W1`'3o~peE2)lFXfZv#x3܌2hP/HNMU#WA `/CV3C*Z=eJ|N``6 2s!0Tfγ}~cHzxQPaK b)>2SU/9P?E{s`CB G1j hf3ŸsHS+ޣ{*?>wC{ رy"Ir >RD*ľFQh?>K r<{("W%DӬWVx%`? h (EUnkJwlݐVW|b|%>__QX7Dd؛,vP>MG?Y} ~E7#I&̹ ?A1(~bO h=3q!D}/r`Hq>7v'#Y~A@IDATt;FC*rq[ ,p5Ȑ9% wM"dA1ْ1iÄ,z Eى q&URj<$Azo4Rjj"1,펍zmi66I1G%zjWGH:sUscywDf{ d۠lX3"2CĶxѣFfCry+na@! ~}:u]/;ԁqQL\a ,_@2 f>u]N@aޒRՔ#d%Iom'ͪ 6Zc'"9M!CY)$am`&{Uړ]U."./XO #˰:vPٞDDkZ1~ cRF{Ɠq2y/wU|^ڪ c=/-^kgA 5 n;qiŶڜ?Q_7yztWSKJ! Nk嗛bcMΤʮ$/ƔBqh\WkK[x!(׻\O"1x 廊!8'gRi:0NbrXǯNp?GL@kmAT.>v pn ChZXqf]9gMf=)/cfIxtsY~K,~ "Isʝyf$!=ai+ƲifFjZ.2C2K9vר*p'tML3gڢ>0T"-,9+ϧ-r_g}FǷJ}qLq[vKB1UeC!s^A{${`uv-c O#lOcۺB_krfUi':,N_4u)7=֥ ,\ 9-۶$,h *>JyctHp5>O{h]ԑW;r_o4R`jM@6ӜXkmANOi_#p5 XPRm~S&'>c 鋍Cj~AJ3<Ըo0'&/޲Z~/H׉sМ@TA+qAH;CG*J02Pߩ>r›@ $^nnp<~|ٜ'| +sLQw7jU8;{6N\Yݬ?'nƣbW#E )"r&ix:Lo5k$c|$hJ^㓎bsaZDzO{.۷W~˷Xl{P`ɪms 3䆺EWkCKT1 A<>W1o2i1d,#TRCY<"sNnaV '$\)F0 k z[o j!- _N* VN_y~vz)H`g 9}3|e mY8nրCZxc*K#ؚ]yH@z26U,Wݗ/Oy1t+#j~ݿ,=Cx,GЅ]=|MkM(PtVϑ_QˏܶPV0` Ǟ3tp]2a,;$W2j-0jdcPQuF*-P/dypmKk7e jkՌp/̴6HK/}R`VY7}GdW\I<"$XT2Rm#vFCp0n*˦=lBxc@Wͣb<"Ky.6? :UԷ)D#tF˥!E򫮧:2LTk lj)%)M< r)a<"OD`T&0u-0JkJ4Syoz|S&LYU%/D|?:ӆ`hr}q _a\D;5[ IZba"B( Rq؃R2r(r /\ W/_K oME^$BȚ^-B%q;75oR׬Nt<$IQüVxqʔ7#&mSυw&F~.8I";<؛s Oe3ֿ”*L\pkb5a$T<2gєI_ ʾ.#u~}ۿ^5/A&b4gD=lNpO6&4(~Z#0Gٱ2ʌ"F1!jNRQÒ+?*'e+j(kH٨>e?ACFi7e0_ /SicHЃ[ K /tD靽U\#4KLP[WR Dy{l0> qɉ?pK$Jdamr㊈L&dsrK*(KbD'O[@Zëd q<3)up!F|>-䵗netB{Pz'$璾 "Α$։ M W 'kWcE@.A8ǟ(B/B: %~!d0#lzuŭ--"TEJljg*A϶-Ќu}cR5cհ3zPW[/قQ\S+w*}EE azX~ \b&Fy^ 5Tv`qOF. O[)q'1*MsڿzgW} DS˲ڶKg~ks̊"QcmӨg SE 3Y6&Z@qp6܍8N&L?썤_ 9 .NBȕ .3\Qaa&X @oUb1<!ߞ ӯcr"LA^)дz>x",U /e[^A@0"5b˚1-&=mA'=MO5;o:Rm-ܓ=̀ZRB?"`YhES~ꣶa#{w 0bZ>yn&rVA鹡no'7Q>MC@"koKCL\Mo@Ic wKFKrcfY߹gމ)%Ws\i4 JOGlVJu'%rS2d_n`\_k 'z!LV՛$kZK)t&1%J*l{tdw$Ç' ҸHE5Fa@nPjo3UDwo¹(9Mܐ!SRC2Y1?h+(yzגôQ~ P_f$D0VX.N(ו@!+R_]o.T! ထy ^$lqWTݎXHB؁'[E A[ ܋%]fiNF:r 1R,cIϗOt==85[(t :7|9Ym=To·p.0ocx:V{OVdS4.O/$Q%c]cQfJM\&II~j/Pt=fGYˈ [bpVMZI+C$խKf X&GڧPY^&Lʴ^ZjӜ&F/YUFnVCe(pi# A01Gg{%4Qt7CR)4&?d1)n%VI8Ύ9=e[OVD͝_chXSMCI=9 <*YP!jwTo̙݀BcB"Zp65=-U܏R~@ێj4?dB]kL/րsz/j{Xd8x 2@)IP RM/Zq/=?zHRO7d2E3cQA\ouZ6{}hm^o~.'TB>DQ,à SPX"9Ņ s̗~E67J]$1ѭmyCb_ iö=؆;nF:Wf_$9i =tnO dFι>K[:U!Dz؉` IBBױiK  uwGUd3DZ܂G^_|YF![@&>jM&R.\>C=񍯡9jSc2<,-~m)y-6ls=ZG8Ilk~_ZrS,E mM1#5Fo.U\_H"lKNL7/w䇬NA?X)"^KPF[59u"WIMv Y۶#o` \e٦Be)oo|k"8B'=q.&G& o^5F&w!..^ y9?CE}@^sOVP@ lR$ꭟ&G ß;팤$hSZ[ѶئZ1!{~betI,eB,]N+]"ƌMm̧z@m13P%ue.J?eQg 6Y=ۓH;v Xj |]kDxk=lٽdӅܬ 16WS(K{)ZZwyY0f&xP4PE]Z.-z}PT, &qPdHѥZL?S6T>BQ Z.1b{z=!e^5@T4r8Gn= _`3#P2Xosx gJ⽟(anjS7IROAL2|y8pL7Lj^$oo푷wh0l~<0A-_z4\ϯu)uP[2Ԧ5C,ElwAdhAuZ]逖Z.5 $xxu Ԅbh(TɅ7z8<2LH83$X<\f8STfQd2'>&:G_tajl.㽶rv]_O}аTQ(4uep%{$=-_3d/s x %Hjfm06$B T$1SPↂM(JC Yᑶ|y+~J6 l=}g]zJcNh(VA0wMXxkh5_mS9(m]I uYG"8IɌ9X|7= :}yTJ3 ({;=~Rڏj!B'wqjH$gcf՘:PDGn+*:#sǔs+Y Тo(S%a,u҈frkH Ǭ8UaێyͅzjБYԙ$Qw+P#A&VAA-Q 7L5:-r#h2sax cl'[Y)zc*%XmS٨$[ $<36 /sv>#ɐEA9Q<ovٙfhz`QD:B)wA7$F8]/zLzf}4e&Q g[8϶,?&h`n *}+c oޅ^<`ؗ1P`BsDДL2Jd 7|Pd2`^h!3g#XBSɉpKBWp!*b >Tr6NB%(Nq͡@Zp&(ru Mbm “a`E}Vpejȏߛ׽eHIثשA 'pv]bWx+9swk)4.N~i Vٜ3hb'%ZKt\%?=!{(;\j 7e4j":N'uqI-@L#W_R&QL}ϥݝSʌdv}A<>bC KJO, p!oO}FmL:< +)-J=OEb {ߗa<\mHKm[Rq:dgGeOJ/@ɘ[zѭ7x@# ђqXplE_N&Wiqpf:X]!#6&1YSР^t%h,Pֽ+jpSeiw- O2+#07CpfOj `>cx$$i2F/?gy%ܻH|u1vqbIx,2츛G[}au.OS g&֝6 ɯP$DL L 7aU adL x>TƳ=Sz_0llƩB?`DtQg L3KƁ#Ŧ[1⑕՘[Ƌ [Vt9pC٣x'5 2ͼp@>,s9`8t 1E@A22XsE;'9^ːoM y|.;AkAp `3;N}U/, Ǧq.|dWw4~~w, R@@gNA nmX@:Q#(WCoAl ='0lJbh4k.qa.0C!gH/ <.GۤT{il U̳:ܥyG)DD}ҁ 2ᗨR:RPXYjTgѲM|AݲV񸰉ZPW_qz;ՙg9ה?*Kh-0ܞ0# g!y6 _Z ^,mźc%$E$wA5>!aԕEx! ِ !VO;I_l_߈$Xt%%yQTWeȆl[^f @90:dٵ]yWS;ǜ5s./HalJSo[ ܖlKwz{ 9T_bLc`Nȸ42al$A&ad0*Zo+uM~^X/b/7tܥܖ#5/\*]<䟴Ug=Sm`L lYa3 /h.Bݹt0y[c,[h!U`,aSI#9C\E!IFz?X0; 7m9JsV_A$3XRDL@Ba؜"W|FWe-T9ߓ.]l1䉄"P,c0K"s ,PVz5ǑL.:)M ӱ-΁b@DgAJi\v,"dkkm]kacr=)67;PwKVQp/Tx젡Sh'+Tē5Q/aw]MM6&#f yŞf^P,g2ZSXe:=PO:у"ѣPZXι>𳼈VN/u&<FM"ۿf_TGzM]uKL1o-ZaD>.u"=ݩ|iK t k>X)4ԫ¢йZO$ϟ1Hé5vU:#ढ़,q";!ߗn%H|;u $Kf,& 6?.\âj]>ao>qOv%ϟiVOp9M.9q,O}Iphld}KD,hV~ kh;+SR1F-ǒ AZw矋1ģ&aKo_uT͘4VKfʷz $y>8/YL@tL:X(qkgK-QNjn ˜iRJQ9 1bRr_֤![$v鷼6C9j 0uQ7ICq93(lUdAN:5wdd ۴?+eMDgsqcܿZ;F Vs9 SZ.r}gmcǴ [tBK!%5S>a afBKgh?m}J]+lfv@.upK=nʼn8:Ϗ\z:S.*L ^W4SdW1FyR:KlLb«{_t/9_S@IK3Ƨ(gͽ ZtNYOMY(Yi6qc]|O+4p.di4&EQ,#S]1ï&002xPĄ-cwIm \= _[5s@ oO,C)$"_9FyH8LVVZxb; &b<pI+#zRR'拥l tAt~EEѧ6&<R5OȘVA4Ҙ?a1k`_Rρm w䂯:N "~M=6Tl" KcrU.Đ[6W,qQTcI@Y8oVSgN$44l J 3 Ў {Ԃn,dJk QsVmCcpx[Cv(@yCpu,O-?ԤfJLce=n6A+{d恰wP"!1_x֟F]N(CQ(xU{'>nJ~UaI9 ϰ B`IFK闒INj)I;6WHhA8K)bqޓ=oþq3tp|ZId5SjZsK@V0N!Hr8i4ÉL1.V`Nn\ݯxkK]0[-CjP4]ѤsE~ v>c7 I<8!l )M(,Cګ-!<339A6*IfdD?`Nla9r!ESKLLtw{cdG0IB-bdӴY[C|BAqN@adU6,qw{\؁1p 75t`0Vҟθʝ*dgV ZE1y*]U0%:aͯͥ"KJ'o>\1lNǿ"L^h|@Wn6mH<QK/15hk]:/f H]ZƯ\IjڃˤUh)K7mrآ[2yj$BVgtĈ2vg- kZ@llbU-bfiΐj"[pҌF,7O.%(l~MEY:L jnO²Ծ'[?z PJFԸ'4J R)B"U8bE߇}N w8εܩD Rn09n֒kvsqEfϱYq Czj$B? 6YpaL2DH p/KΠϛD0)?Mje2^CX m/Ɖ%#cہiK4( ծq9u/w_C+55/$/&o/J$ n/_Y/GPpXHl cjզtN%a8@r03߷?r _u (hk!DdKZ 9V!F_ A'r&Jf>ԝ /e7r Y)yM-Al`@~ʈ=*g`N(*3|< q`o*<Y5`ERfͻyUM}LFQg_S}Ɉ b.9DگYk3cmnA/ 4qwWyu2^1$&% =Vq'zDNz η[/N9wy ;(8&[j=BCBj~ɧ`V@> ' I2jiQV:ͣϠ~D #X;4C L@>t ~e/h`Ry0W~a[h$*ah<)zŒYh4|WS`LM b/R1-i8 9xp  ~G$AcU b fyd8KBH1z'`H=*I&fXMp[[kF+T|ZWwR62+L1F/|AulӴn=ؓh6I Ulp5Z5{3A{TDLM4s&HGb}r=0SZ@ꝴfW2f1<#z(Oȶ1-kķ?V.(Ĵ`2;aE໽H|4px ~'>[+S>uxb^mkE߶u旹(wԌ~_!fR|JԈnrl󕺔eƃn^86,E⯞Ar(Gʤ2ݖ U Ex ?EanO;qRt m|"Dw$6O[#f s2cȬ$oΒV)|'*-lpˉR>aP-Psu^A+=RiER d<>S)L8(8!RL">ǂ#aAр"`_>Th8Pk*cjs¹FK8ZVa /Nf5T)t{7<;[o/`pxy?ۡQg`n}_u Ć];oHö+nЎ p M" lID͗OZr@Ɂ^C}|K -:kl_3v yzV;)vh0"Y1L TSxggpD=s6OA?f<Ǩ|Dޕ$1p[x"fҖժ!mMʱ?3qU6#f]C F#f$h,P,e,?;K6 0Id FfȚীbb%R.5-r fC\pDgzXHh4̟by_-M Mqc-VQ^=t b ڜZ*ELJF[&i8Qx,/mRvaGlv%sRD\kٓ.c|sg'myuQ\}n>=N, I83LAixTqp%#/ ϾL$˓kC(sb*bnmJWs_ tȉe~sCl:ey+ LLh{s8IBN tDl&R"~No^DXY~׬зɝ%+'cY0l8>leʜyӿl4sZş:yN)x:7mWP4\4@Vtnטye$ Dbn{Bc˖Ұ3["EQmVUD=U?I + 1OʄݱMei# Ҁcd `MSMI=Evn dr_;%c\ŭCfaR ]rz$I }Z&!PkO7FZC'Sr_ Xr/)\>)3+CXayU&\L(hwnf=TUe-$d4Ug P;OJGJkT0Vuy &"0xE˸o%4ĈSAQ)0ӺE۽=qBclˇZ.䣨`n(ԴN\Rr7~֊}dOЅ+#f6n*7#{Bʸ u WyY A0t=~ ukS.!K­g1=g&@L^2Ahuej&6"@.jD],H ~*Wq>b-#6\.2A;|6ىK*F̌F?ᓄ1Ag1mʪP./0b/"ȼ Ig ]E-Fc ϷUDxQȋ􊹢2zE[?ADsU8\q- Ze( /$ИN{u-0<,\#xE{ C WaKagŕ3naþ:@k.2,Д~}FKAr1c'Ɣzlv@JXFi@IDAT*/hhfI`; BWllnY el쇽Q(Pa$gj$4wBeg@6 0~`if uN뷽+gDaɁop zo꾁Alzc,Agn}iY>%LQʆ;EEP+X(pɊf3OI0‡v"0LcC*h`49V8 (cV]+$J;|>$!Z@e-ɨ/g}#Yol"kjEAP;9!4Wa`X7qLo'<*3x=P_&8(c ۛ dNQnabX*t?FCn[ }Il\R\.J;/( # iЌGCQ( SL.kBlpܒk#~@[, ׾๾&< wT:nnH- n!tp,YeJmWH#cKi&/E7)H!*XNs,3a%`xg5Z0$ f ' QddjQ=FL K27G:JZtT9E@%$}Ј҅T-qEu`ixV(l5G"KFcVq+Ps glr0QOG,@LREX^6swpYķq\&pf}:^"*) $+PP*X#a;'ZP2^;*0˻oz>sx@Db]0k`M ȊYFÞ$Aey8 B I' ^fg*ӣfɴ^nV 4aPDkOk& =DMFv˒9/m|j ,8C%q34+( :'%n  K&u|s.Esnr;s.i&192[CG-$X.'/ "j'qO2kngMpE!C jq$HFZj5BV>Y !:_ɕ +w35 U`M =ScETDb9g.eVw{||oSU); f۬, {@I추kNegDo%昳QQɍju$hbTa協HY/ND lWfW/75Oؙ¶NOȿ1 ΋Jj_vu3(o*ef2e4[si7V E֫%a.!h9}dq}`y(͹gJ7_%{f ⶓX\P͛Ǣ 9`dHӊvrK钧PFFw.-@E?>>ӗ>{xXXJWI'˅n~RQuXƹ*O)MPtqMUAEHCl~mw;MpїjJ r&83w5-D$2:^olNEd/7MBI .9Cfl \v-O'9 ǤZ\92peVFc~ɶy~dҙkZZ[O%7poUf OY* iiphc)8\- 3a8ݰ^a#26]k|LEkE~gf>TFB~X^1hEϘ.dS"ϥ ѡձECr,yd,|Q4OqT԰Ta6He.*Ðd=:ɢQ#:o|C =qzw2ᛰ sŜe y5K׬ ;;7^lƈX{o 6X7?[2͛0Cc1ZLQwF0)Dž_{/"Ԙ/ܕy,!cVs^sScAHI\/ kpjL̵9rЬ 9O%ygoP@5g]MM¿ucZiZ2'4a {s64Kd4Ղ6f|2YɈm:s ѧz+*J1z4+R5&!)RrvhA;~yMZ:ەYĒK[̖)꥕@~8 "b<SP@-Y_דyKSM]t+6kqY\; +hͬ eRQד+3HѲ>:vt3۶S]vtθpj^;S -6Zflgo:nlt'Oו!-E$n #;(Jx_G;γar ҆&ޜu;N4Kp|Y_{[[BmkRhr.JuW@QW}z,h߾V}ҚVKnY޵RMCO+jL`wIގNȅHkLJ3Ћ_ Y S_2m~C4*l'$ؗ(kxc1CU`o?c._@=NpuGȵYC7k+i5cD[x] 9줹NxWCp֋]H9<;aT@iwפ:;)acK0v G8vB6|`ɰѼ?%*~}^RCGcRz;ր/Eķj)gq.J+,9r&1auS=s_o޿SL%"2i5^dlKYNtѹW3xΗIh&υsz3$KpcB#SiVxCc @ ]8瓐A9j7iwz*;(pmkvrF;c_#vWk!?X/?Dv㻽͏S/ }V,v ypxyrq\`ڌb S֥BNgOʊ<qd"!>)SӮ3 |/NpJ٬M5ɥjӴw!хPsiܽCn=+rÆ͎X?,&dAU_l2M,6|(wLX )*n8m[/TD/Vd69ٓ\\:ww>.^ QRu!1yDe\|lvLeR@(<' 7 Uv9Ie)52)t18I E&?n#K<B3/ -'ZpW@ !St ew<; 8V=ŋ dڂ0)$ITtIRsE1ů&%=ٟV:x[?nND`Ǿ H, C?EΜa ' A8lȻLq^l;7cL1>D(JM&6 <Kx袖t6>-#r& wZ.^'–<D.8Fs5jѾ/w܇NCo8{X:})$~6 xiN,9W" 6 bxG}.-^~YT9Kb0 GucݤKV4ڸ*a,!zCZQ!9oԔ:#B;֔qY%ǒ %c-ð&~)WsW$>\j| jd(g "39jGmzI.L0 Y0p, nV-?6_d dgx=XY\)nPۇ7fa@9tw2T2_dESXx> woHK.䓅fuG}&JO:tk5 ~Ug5{-_m6 әD〃 ϟ+3&\Y*@ /gg^yew`XyN!5Dt:Q@a Ro$˶~*j¬HqO|]@5ѱ+(Qږ)`Ck0,2)wz )oȵ>œ#+ɇã\gDA"GX@bC(!c?(c_NT4|@<Z[4^`J]d97q(}]^EF[@.J zjsh~9R7#VE~Ǝj$r=gk+d e0Z*?UF13#xcHӤeAŒ~:PqPzKhT߸=sl/_ 1%yQ=7thA>rZ :g}EK& -j&  ӥ1C#DQ)Ȁe!E˛BcĢ }|M0+W G!*H:_S?R b;)K4!Fr}brX/-%-FS- G jyrh(2Wy}sL!TM3Rmho17FMeo ш:)P:*.*3U@)$׽lM^Z կĪFZL Q.IJ܃d y _NH U9 vV)bmTDӯna ]߿ 6NQkei:#݊7 A_N)r:X- Qc}Dn*K7vob3V57 |PLz\)Р%ڎ^ZK\1S%18v>A<0͚GZ#JD@7c"™0RبjyđYV$5ˆq]vmKg>eiUX+䙑5Qφ{BvZT:@W\NDQh0k!v 8.j}1y~c[R{x$M4J:" ؙp YGy(cs?y󧱊 [LbȚ֓Y0z_N,PڳoTJ1^{;ǎΔxң{f +`Xd n:m`M𘲿1Ⰴ=OG>O;RVVk`;_F'cH>˜tw+bۓs+ˑ^ɱol-Qf*Qa 1(W')jEώcVܘ8g0[ӌIi4giLѵ\墝 M kJ%w4f=+gcS}1դGG@ pq;A>Zu&Zr]R` C>3°;kp &//0/IY'g:KV2ƃ=p9.y*"jV ߰s,Rx A (x,K]Y^_0uEl$r"=2Xv 5dz5AF̃yr%ĭIev]zm!LQ{8gE B'nSp sm£*o_\&_"eC0-OߜC@0Ҽ)1{I^Z?oRLAoHqzۈUu$:}ATFHJ׆ .ȹ&Tmkē/UN+?Sut/+: *Е 3[Igˀf"{WZvf9pE$Əh 5.\͵x_0':q/ši@CU[>V̟Ӹs?" "(LTgo֞c h||$k <֋NkmR1ְ8^Iw˛v <aNh#.͍I؋Fd;G&NE}xث4r\'Jb0fN{A)Œ^}Kl>ZlH_*sO;/IX}Mh `V k1cg:Q-C?#>ȦQAhȑ} 3OkCu)Ҕ&Gahܤ0iAЗanSiEK1[=rOSOcFX[q5g7ԆF58S2->%]3ryYЈ?+OKly#XF(s`LXlҙ x5aIIŚԏAi)!pI:SfnJЀN|O!FQU!? UH~:޹{k>/xOPDX`ב$ØH3 kyjOjai=y $7G{cKhGF#qO'p yOrRf[B=Ȼc`+ZDۖ8˽4u[(N,Y)F o¹q:=\4æ(RHP7dx%7˿ؐق =lNxW#ֻx I |),ďK2D4?zAB2&V΍$a E\#F3b*!n#ԍv8Cuse85SQ i>{$~8$S~ڛÖ(=V7vPS9E:IL'Mw?g4(m̄ @TXK"xaH.U/4]Omq a֫rIU˜\dM1#;t#A7Q8Vfy'V5]sjԼX7z@B`oGPm䇛୩fkPL0bp4f", bN/I,'UJ=2-2Sp9Yx?FjR0 ,M u$s}pr@<}sN ^Rվjr"FMsYJ;I@txf¡%{Btr%mXhlKC~3ϑB~~]^] (Cl?ZwVEu LeNC'oA [`Dxx_0X$D@gB~sAaPziLfхކqAktB,Hg_.ƒqA`Zwi(OxP lYҎDڄ( c˄-MF%qSF.X-`'Xadr;0+[]L<`5>oͭ6uq$TK@ 2T! iFM(L$ˬ,~:?v~~/}G@NnN{yC#sOPqK#^m*aCgfT&JB0Z-GҺ73;39:9,?,p 9›w8G<젇!)7V/ԋ5u{143l iT%qfwB59V4>f^'M,8@|c RƐ(7ߧCNh8l[F,GcW/a|o)Sr*oME{_?jAemtT@h:. Nfl.a!=>o30$:UC 4qN^i]:Q,F$D^j$蘒NGzDQ2BdW>_#sg3ϴX'[rCA?aD;Db76 x̹\#OĚ7XfsvH OmGV1V:/ @Ntĭu )d~AWD='WRc6$"λ4n&q@$d=_C`⋵,݁q,}zN|HS4l> Hz+MGY_{]j?v+a_ kP;/՚'ut Fz(hI%>(J0:-q9L4QJde.*ƛ-'Œ~?@LWje5X8_mqd>n4tڠg!r'6:|BY:56*t)*)4o/I0@]n5kCQraz>"SYeƸfv@JiJ3ڷJ v40_75zv_V' 1vz#DZczRf1#9f$X9Mi.50XNoZk/NQ``Nzam5xSxe }cP=8G~Ux'1[MviK3ϤEјmK(`zn!AesqӟޟE`VPUΧu"_KX!oBd.9v#ݿ׍3W>hijܜz۱ĭ] ?Sm4lc7_#D6J_J^EFT&He9 --5YCT$m D2}9} 0Ɏ;ytnIe9IשF$M˂D(G2h7idUg9Xz’Ж ;siן҈4`:락cL0/ m)_wPwg;`Ǯ5ʈ*1xZ+"``V6ZUޚ2m\:oy;C}|yhu HJȶIn])b+MKgL@2c=gʹ_FԺe[U8A\/7-im>1ӀT20aujv;S %"SO 93m'-7j >zg/B^OFV P&l'))bj)$"ox|QHj,Wi)raC^oĥT)Cb vzys)jbf;. mYr[*E>W^' SI:1see:{K1EHFڔ[^j0*5LR*E 2p R`^C型ezEd?љ3yК8TzY_V3cs2~Yr9^ښicSLJ ZNn6,ِ,}v=IX䪉HH@ކT=Bs{Z*;f,`x߽/;Ȥx mХ_ .1UMZ)O> cF6,)urR&c}ģZWt?3@ 4{~_:f =F4\x;@-sG0'A!!eֈQۣPy߉P`UV'=^6ZxF1 C@b|ַsJkמlC9!DScR̢G{6+Cxj[r@3+1Z^w4.C,FҘoc~vڗ۠1XlrGazױFHCaQ.x7U\[XUHbdڡ8m2neSXn6zIrV7XuVM(W%', &CHhoy6\Oϧ|֐ !3qL1J|B7%%(w5غZpfTA:)vzgOOB.#u< u>[9׃x\t)8U5P.y3}1TH4!vGv L zxES/=_eOyPGGH o5|P; $:b ;x:rn"Iȿ\BÑI fKvy[>L72ZjYR(7׉ݤo 5._%LNT(7(=BQ? ~sSszo!5d<%`3 k}9U󓑦Z1WJ36TL ył~g|SħP3FGCqQhȇ9sCN:660>U?<8&hsaSgU ?w$#%c@@p xd3>V)B0aGEZ.2W *$j$ TjwhZu[˂pc_GҊ Gq}n/u<[æ21RԳ%`+JJyMUh{jŁ+q}/0,g16%?^9=8z ws*"8H[AYNvad}0, WP{so؍kf`|tDZH]H&< ƒɝl+'`z&J 5VPJcs͆U063țǤya.tVMhZ 1iO`T{8js(%`}J0aٛ®VPP 3MkNͳ_%67M}i*[ާp8#vV5f<A+[-j$ȱ /Q4Fh-_Sč/1ctjO5Z P_I@r-.tvN{"ھ=#H Pڢʉ&5T;Weͨ2c7݌aRP~z@<8զz"=_ *% h -܍B`yON|^ vj=y1Ċ*2.m0M]#m KIpbm'E>wЖ@3[%!8DWz/ )l-, J]8{7*)"e"kgFB+Zivc:M}P$030ۓ+qh^Lq*^j~F*)&˨6aYnid^u"9*N4g17ZV#y4E|+VSԓcƟwԛT'~Ŧ]+S Ղ,\#X,o꘸h^VmNDPqLX{=A9`/ӳkr2IPp3ßsQWyt.cΪ9ZA]w R:lJO [nPH t <9=4Gmc?<\7>I|,: xOͦTƓSJbE鷾BD `{Jgq(*ŦZf-qOjvadr\8" +}mN/$t x T(% Rɪ7Dݘ3EnbC0 8QǦ怀X#Hu4oAʳB45Q8-42y(wbv Z\y",; c&'(:zuU,#L%\m:Uxx^ExPrFRnSilDڜ@j'# :<3i@!<Бrimh>a,`ב`*g (G2'RdhUVcj/B9吢:V%¡hW*XSWFR#ݮD3~zMpѱ];Iq8x&mր<s)e"Ǭ 7z~yT`#'53]W`ۮ+_J7T3(\haՆ1soEJ+ū5̢8v#(vք@ "T8_ u{,a"i4U= ӄ om_ŠDx/ CA<ϩ9O1_]wq<]ڄTNe3S:Ala#Dr\ӗ =ϧaȠf?gTVx11ʹ FF  Nu''LԲ7k{/<45!Lk@Ѿ):w4Gt+`%vJCE@ L90K/,p ፕ &k%roN_H-6krQRJ h=Wкb8FAbߐ78En5Ti$;D,a:ce(,RN%ެaMQ\ !'8K2bEHΏR' ^/Ya>/z<3Cv/N=q31bSH&n )=@IDAT*Y^o Ȼ#=D`6DdhGyoW)XH8ć+TYZΨ!gO/'KK,=X5B$?%jYjౝH/E"0+b`"ϘV >GZ=F-2I:uhxPTMe'rZA X^?A_+m;za2R与0'WKݳ, AnY}?EqNÁv0jgB&yfmi .ʐ)ibBzy_%/fBǛI̹#6eN VʱgZSNe{8>pwb7OxC;-u>"Þ 2 ²,08?Bx~iI\5p#(huLeyPm41VO8[ cqy2ۙ1y4Np}'"=0ZUV!w<]; }9w!S20[]h T3 Q)?nh2[FZ&S+Zv1Qn;.C*4ݷ6p:q2FԉM[o T>Iw5pF(ЊA:pYpL; f!)2 gO 71,|^ q1-|#hp1 FS|rӏB`"yz\*$h@{&Wy\A,-cROmY Nh *PRgJN8AGbuW@z gˡ5 jTA-VbjwF9qxX8(ҰAe#|Fkx+9y9%RE> Bfn9uE.Kh^^8A8}h$j/)ތ] 6U:X3*l);~@amSCUyB GdFk>_Ng#3tolg:~eGMe\,A`n,/ȎV=? itĠ'}A \ryp!n~ AdOT* ws}zC<2ajg <Æ|fl56:%hUklkAՁ-*I0/҅_#9۵nDw!A`8TV";W7ıg 3XDC?$h#E >P|qkO$x\fm 5 HWrFF 迌x@ 2rD(3<+(nmּbgSgbf_/*;4 8e}>&'0&HHr# (_ qK|!zg||vؑc@7$}XɭP ч`"l)@;ihi␂3Ad%'r&[G@:[pLd`f+iMGui!-shV)`4r8Tv]Tՠ:#  @" %zw%(IsxH;;d0x6? U|TȖ!yZG^0]KS]%xw`K߃*eL/^ Cp> #,@[[{q2"m-t}hhJe\y+lJ q,+ӟ14wˠD iPnR$1NVX(6W0چ75\G50*J5LU`9,%â4|q289*_ /*tA3«olJc:~#K9e*o{0zt92 a9^M`P1sz)Բ@bGl1 l &(IiQFKHG4\tQ둛OGTa؟wͷJEf5K?֑:%v0Sy|p&vtDtjNmT8䯰= 5mB( ڧ[O4SD@~*#$]&:Ʃsr )'lo{+?^ǂk~IJmƩ""7:ϐEʪ`̷`kHNAJ-rHX  YH}H@q-* Գڇx6<0\I)h"Ra9ZKu't8ܸB4~8,ʐ(mS rF}w||!\0"A|0 X ` ? ~L!!{1}17?Wi{\dEyDFåiT+پe ^_~^QA,lz;3>{Vxƣ.kL36([.KDx,a 1-E+$aQ!s1ZfkM! ~UuE !;EB$PTJ"XWFƣ LAhz]"i+Z𑏱 [R/S (VUsFZ[p4a7/?Ha3!'l&s3B[~+Gn ) oqDreq:X:Q\*S%AjZB?g;8F=_Cm?SCYN닌m'#l&H`gnrGK$:,tOfq >\#sV,O#`j!##cAc!+nѢ Ѯ6; {i@Ҁ?MhKy [v`ՂBvG۸]B/%mP$N+=-t6ޚ?=\sk&H)$q4{z J2IyVb42+v{X\WUPN\0jrb1bIJ3R:P-#~ o$rò4mV@rOZn7BH| EGa^c0w܄_[٘midzOSVNrTS-]e{]'~{0:[līɜ _T˫c:a\ (#Ovc,)\yFI\%OdwػHlU` 'gο[ѻ3`@K¦(G57[X9ԁeϯdHfStj06II[|ABCRʼV>dFԏ'm?Dg^u~0qC:QyRsy ̔E- EJ+20a ``}T:]\5DX/)↕;ʚZ2^۫U6w2slRniSu|)MEQޱ"7kpc&`7ݨi{Ke 93-9(g֞&dW6>9P L+ɥ67k,)?(.I7`e'wEZVz|Q5pI;qwY5lb>{[_` T$mזEG夈KwI6Zl'ǡ+g}=dx{u:%LړVw$'R%1ضT/ԘVUM.Q&)h}W;BSP"ۣ'N.lx[79*Bҟc7˥7SJ0*E$6Bm- 8X3$~MIB Q1VEd8keh3*׿^f!4?Tp6y'O*O|e}bE<#K\ؙ`L<J{-;\xѮjWu ed)wsA?tݷ!jH3nQeDGe얗_ay@e^6Á/\8{MC:63<ڛ2x3|_f^SJx|]G %-aq܂h\,?eԀqo~LܫEM'1YhՏ] i% YiӮՖv7;jv:*Ľw)Yi_Dq>ZG)hpI/ڝog M, [k u l ]1gJA i`:^B. P*lYeY(7.|'[oJ\s&NF-* e<]V< O^H\ `&bpFUեCcnؤW")WWY͞0$4^N,G\Uux?@)D#d x}H9S dz>j դy N=&C: -{6 #^g;zyJ)C+ \cBSS  S,^#A(|ص&c# RvJAM6Ta^7Ha+pN]4A-FR!_zHy!,I l 7>9?rhI݃<"z.d&pR%pg-E;Dx!";p$4&mo }XURa^IOOi&o~Q@&?]mjB4B5YCLHK 0[,%i-+LiH;[bL]m!zx"v S'e[S?4hp0cVbP@栤L`5pZNla3j4fa֡4r r'Xq&n)bT[o\@[0oR QAZ%-$ !B/il`An{JrTX[J2^+QUx{OdmB !sWjgi@LH>)_=Oy=s T 25I_a|AXmbO0j FIƭ< هMSi=<_hE(/㱺 ,C:!:Hj{8ǯv9Ioq. MїdQ2-3D E );2,IC\nf!bzq?c^fY 3%Fc «,KHEl鏘\~p_JME.Fs[xQf:tyox&ʶz <_kU1qZ\OgcZpT2u]Tu#<5hSшB54DːᙼN֎Zz>\[oҡC٘S;U-dz#^C+FEu_G)?ȈgkB.APv}EX,$l:ino"v|>0^zs'@r4mT\hp)9S1c7c?][۔gN7IChEV8oQǷ^Pt9En^*e@ӻqBzf!Cο`nB!g#ZLgP\F+;ұoޥ*[IZ&@QPExSM65ߺ_n"_ O3a D;!M­F|+ڑwh;n!`Lk5,za*\4";CD}5;fES7©^j;TF2UWb)6蒴Vρ ? z͐"$BiR6Jrq6Z*R1c浛q5SY4Qvs1<6Dܗ."OT%IVA2LK 1 ?q~{AG ,؏:M b7}@<|7(@#-Y[m?kN-~d@~ G?k-`,voZݣE+KdkkTbe3~16X@| R 4'[P lSzBa]8 fdxѪjbEDMK}3*Qjf"ik4@aEOʱS;! ""'9z +J MN;{pfgwC'Ll {ߝ"p$9PBN>S*ΉJȏz%ԾF*c1D;|BQǙCXB %;֐b'5#y|}~Q!aDQGkE]5kd-d2u|[v NO?\J}3hЎG37ǻ5ѷ oh b&&&~ uOH#Oɓmu@/s匉c=e`!$#L'2`>)x .xar_cmDkRV8 {8/#$.Kb{)RՕYꨞ@8yC* |W߈4J BCF|ɿ6T)>3b:xz3+p|mlB_dDđɊ0RGlj0H瘂Z3$E'83 h=䶑 2jƥrL0kwf86,|3TtW"؊itV Ab!dqm7z([+ȕ1(Ī´XrA.Sib0T -Ts~#nCAt | Xp2c*GV1|!yf,徲zoNuc=xAGwVEvlaZFk1NäpeNg1`o6/^0" Қߘr9qsy@7c*CUNeNhޠ)|.5 0? ANP|x}]y;Ρc7A}מy㇣Y}R6 Kǔ« yy_+'XY-x@RЍQql^eKm_l09l2(WAaJ,44 ~$!w_4L#)oQ #kOH\kc׈7|Q%qtz-0%QqH2P>LB"NNNppǶ ~wsgf2BN[ ,D_)ϣ-דv7D#tn\,-QBMS*6VUQO 4#sH"% +jD;_~s%lws9FF Mr2CnL5*tHOޅM=$¾ŗ3%fTݎO|~:ɐe ~h-/ v?(FW(ujVJƚ[ u^g3o}"54fC<3:BOIP1AG֌I uR*Fy"-9DMJof4 ᙽj)CޓUUFt~"ϯz4Dk ٨vK!OHnB)G )|B{&2ƢiGM4;J|4'@J=^4B> +m VXe@Iɟ=y=x%?}Z!].\balLIxz ;m+r{*D^otKoة&;ʼnW>pϨ),ÓVJpU ض}X"P0' T%eTg`k(@^2W$h,l v3C_\IY:вoȀTa8> q-zpH`f% o Rgzje"ƊZj(M"Dx=븗kq;1T .'H| uIl/w~9 DDm\aqeh5)i>K*Ѹ3OMll(!(FXFÀ0qP+%ֆ ֐o(aS`U< ʖVl\4QnB~ těB&V/pf4"FP6"4d\}&OtFoQaԂ􅔌v̑Z0gvF婙hA{qݯ>%˯5Ii bJ}*ѻR)4z=4GiLp @3"5= Yd2ŢذYH\:iM-1m Bp u ]iS0]MUX<4υ'^V)Op%xk DQ!}6&;[#}8^j4=%xC0S0ϩ"O 'KGZ3F}PlVy{!(I3#L;*| a78'4L<ծh/Cnֽ,5V"ď'eZ~4N "JN-s HGu,#kҤ~=諓Mo~epi^Ra2NHEQZFm&p)+)`6e<7:ж^^(YF}D5ʽIrm5JZ ;nl{"Lw9/P̌5k@̀ĦhAl}q \gǻeVO<ۻuǍn!Ùi"zNZ{;z3HK]y\2D歯 Dk1p=-L}(şo #BS _i*%{7;^>V~C q"I=<V;hU5.G:K0K%|t$8o8t^9hh@⿻l<+88ڄ/ ϤX81l)F>ЃPF2`c í&%z!><2ڗ?Q|-Z[!t:GOϙJxHF +^etPA^$|7$Mko߾ 75sF +]wI|-W6τҙSp*򣌵&[iTE}ۊ7צ0 ;B]]6K[[*_QaYYdab0wM9.q82#򜥛vgt=t\c8*\8;y PѨzwɎJPyP,Xo~3>"\t,v䏢5GĂFz6 >ʮI2FCK^qw7m7S$!,%<5)NӔ+oyZ-5DdbF)BBV֞#+I`:2Ns1B  !x҇C'e*$Y:`錋-DI4h|p ,ipț;H)UIُ>#Z7r}A{wnXEXbʥykBy$fUҰD!16Z'\`bdD/)2T<t%-iLS?m ;7@*ަ-T&cys%و ^ɪ:bp)US彬9!XO! N+7G,ՅFOo{X Qd_bI\rZqq5@7mbgLBlIh[av2R8'R@a> )̟}|ۢV-._z5"U*je9cc?CA(-w%mҺ;@߂wWVfhpA[meuܞܽRRtîgݡr@ acXn_S"Ӫڧ=Z*m*w %a*nq@>]ݎޙӸW eLJ:&'։E壆B;+ʮM ]+ƠCSaw_as5pKӝ.7$Yd&_Ki*I9L7w72 ~ao6B`R$NTr6{qح8BLx~yU\)h $֝Fв139=*ﷲQP iY΂^FڡFuӺ]j(:| [ߎ%uRcPdXHƕ'-ގۂ POԈuJU Ֆ ]?25>Oޥu6;I('Xa)DF_/o^U]k-[5w;C=?Fqn2vSuZnOu")p(IO03X><|»+P'+is>K]DH Բ1#ђh;+=d{^X ph -o+C7 GZB YH?{գXBi|8#氃Dv3bmK%w(ocE',sUlK4WYi9eZm|zg^tDV'ҊZ8a(ڴ.ESR&CȭT&A1~HzuVEνܵ`StmǶ9ˉcwr/59Gx;jmC)US;YBnoyն9F%$0fr9ha9W/".=E4Bd{@^ e Lݐ΋q|bJP=wDd3.NMH e02öet3`-eJ͓+ծ,i G*a,SGdvgFyiP$}Thۓ" L3W 6O@ Gϲ[yi!{0HةK:q{G > 1M?@^K4곕? o.1;̓MWtx+w ٦* [0X@id&C<YC*dTYoBseHZJ(g>SzW 4`[Vx/K!ە*rٹޓ\b00N`D| aCr_ڣٵd7za$(5:!0>=\( 7(сZA %ܪW+:=qOk,_.C'ӡg;Qpї3OYȗbi.ndf9m8xy>hF}OϦ!x Jw;@rb<<&0Ipk-/@'HNNUgiISfQJhC8gނHCs s Ȭ)tqpsX00ȯW a-bz_%b^`DrPE\Z As,-fQ蒛J_H~RUbJAwlf?ѿٹ=8LԜ#` Cϥ֚≡XYE a]H_knXߧ0ΟJq/<`ܥ">$x6)Xk&9zR9&& # /favV2lZx>eL1C:6aLfhź╞7+~7,>/{EXJA9IN |\)FUVА#cVG+? 6Oa-em^=[0f(\@c4J1-Ԭ(u PNO-"I4 dkx]{Rޅ=$.zc7zg"K4j0pf!@ZnbepËqМ~~ lA5 \p!4vǐz; HiI7ˆa0:bpx]FA@Z |ӘpG{عs59R}cyv!qWU=.c?)m^ wüY F8 !#cD=x.s\h|" oC 4`"o}K{r@9 JFx\9?D>,:QfϝYo[po҉fu1؁X)4(/:8d|90 /d &Fzcez{HEj7:G@i{{ՠ_w`XR"Jd>7JGjbhȗ[S`ү >"_4* Ŭ;嚒3 {L (D A 94FAݮ׎W:ޘ>H.cMc"!Zo|m9S6g(qK,.Ě'01l=~A*h $O:zz.Z0< BC[UUeȚp)i1wq[^ ՙIN)ķY~vH0/Y%o jki#Q%0U@B5U}!@IDAT܀|ѴDZN,͏L`xSQ[3P][v6GL(mɖ&+&ſgേjAk$ PҪ\  YalEV<32 z{u•#Xt $O8ʞ6VC˖6c pxոܭ 9S0RܮQXR`6G:vEYjxE}mfU>3JCz5N0^0"_Vuh:,g>;vAWyέ؍k^* cqaF*Rфl&fVU򃎜fN̗obm妊)T;XF1_l}-CK@$!g=JP0cМ& ⮵sZ,ÓcyhCQ&m]9^]5/LTG`d)qxA !%F(uΒ%sG'Ífx3'>U`?bԡߧ+Eb r 0f_ZYӶY{!(qfAAy5R6mi5Xȭ@hq:Rshk-XRKTF<?H?MD9\7l&QAVmE@7Z4~3*#kV jۭPgf3z/&8MJk]WMrNPmȁlIp* Ǐ7b2@7/t>Wث.W|deU&a8 1 db=p×%*,0{,P<`|(n1͏7!c+2{I0"N(kx3߮Mm@I};_~Ir|m$b I8r珶Rѫ$kbD@JI\N¬3D.ӖtUD7bKrt(H0:jKM0Fy􂃰c#o\S);L =EU!YV:y'?!ȳD#@Y裞J~"Η'[}Rk(2$w DFi@Y U/r8R\|0b2 \#O;{[S"2=MdYR s-LA}fBNsȱae9,刊o s7r34R{ QG@RK 6F%xqu=gy(0Amtioj/WBӢͤ6e +3Ȣ!NS``B4wlދO"^ւIE45l?%EQ{g~NJF s$ fs+K1ys(eӟ_[/ :t9Ȟr] P5x/ߛ jn=SR63I*g(aJ{A v*:D&yL;7qxbg |--xǹ07X?J7 8.6b{("VWPAƉ^Z%pGye_^k6P̙,*#sjY9 ꊯo˫L4l1+#ZLF6 ʸt7xkYile<"ksLVY0="!lFdI̕N5jCP L?0qۓLH™6'X)}j3Mkj |ϗ_cWc/ %d |ns-; /7'F'T d "QmBd?guWEA7;ZuJ4e fnLxOJ qA7N0<!С.#q}"#e9FSBŕʏ`|:/3btlb:ɰ H2[#*=({cb \JOJelV" DtP L 1{vb"YVkg擠֨t2Gu%H&씓c;E`/[FGV &;vqj 3b rʖy≶3'hPd(evB&jnB^\ >ܞʍހN#G>QpGt[=}2VJf1߯`(#!9t p5%0GkeNU_d0\')za9%rJ={%оV/E H)H5{t/k #Z] kfL\ǣ4 q +2P9Je%>h>BTnCȐB'S Bjai&DY;LZU,[b*8 (p5)ܴ. 0[#SQkdA aiYaeL*|) vb-\iS`c=` `G0^:̟Fk(ˆSZ r$" O\ MOBBRPk-S~5~@ G8~)u1OsvI`4XdlM@㶻[ P;R*Lرay9鼖E|g3lc6"v_XvTddJ&m-%Q|d5B kj 3h=Z4]%Z8}jM;rR$"SbI#KVK9wr$ UP+ȸab]`!Z[tQmN&]eeB{-Ț?&|Nc?l@{P[B#Tޝ/Mkɕe ;/?N+?8Oc^`K {Lj0y*dAh g N{I;%xz(~N_6GkdZ[ U*UwP1!jC;DNѣ ǜ>Hcrpx3:0Wˆݟ]j{m9!dWFE0DFLVPN|Ur5eSۘI Ö=pGXjt-)`q4YRfZC~yH b}P+0 O,mky|&aĎ/:{u2YR+Ӟs*} S\9I]Wj;|w\Γtqx]Bi?1@pR#Bx8#I׊'ӡ1NK#)(ą=4[C0zt`؍@hYq]9 d]e%{El#G>ڂYƝ\jcnhC n/n5U'V_7.)aD59@^.;\U{V1oFh;x~5pܬbNv; Z`Avy)Nt%و$Jy,a_P@`ޱ*X"؇8Yfgrk9 ʹ ⼘*|1̓2:yAcY[ߛa{K\œ"A{46[=C=9=Ifc:bNJ&<I5}ZnUJcdћIUPj9I[ 1f\ƠGχRa nN`H!-l8(5㪜4KaEuv 2@C6*{oo7 15(OF2\J 2˨ Ƹ ~xǾ ݬhDΓI fjr10[t.Mʁ: e:{ʺ|S0[~@6j/vsw&0YgBk4u BGVS-u8&ɬWJRAAlE+7?7Ȣ=CeihWF55h$~󃺹 0/V,m:AM3?-W||QhE_o17.cXOE"!2(Ttt./߼Xa l1˰6=B:CA@##nL$N,A?< |G9z[2 i,GT!tҨmE]"`b i+fPjpT"XЉ^H{Pboebjl^S?~nX.^ϲu`{ ?)=ͮTDk<#[`J\Cɗ#ϫ'-pV mE74[jج.]wZ$&bV8gy>%9/N^@ NQ\萨=S f(_Y.۶GZ`k"Tp?Usg1pPbfdhLf*f &s՞I[?cg'ꈜ:vjx&-xlJyp2q! e-Z|2ry(S^Lw]lo4h=_J:LQqmEϰd20"N E/+=}P2aH|e guq@"sJ.E#NumnomQI(.Q,zct+yqL9w6wy:; 7w t;Xf5 0) ,D̂nWs_]*Ld@[!l_M;bj~r-SlItSAg܏"yzM"S_Xݙ+ 6 `:=mE*  .GO0fGD`a)-&S'׳rr{?_vOnzǗ(m&uh"i騸df\YXQ6'iS#Y ^n^5p@etLȤ[q6x`WK@DOaV5=!|ښ~ގ'[jR'Ʌ]rZ7KL4}ɉ*z΢T8bWz;fUBř*.XtEpkG#Gl-ҾtK>cHrje}]R8xܒjKOdIR1!8FJ zdZ;HQe10s@Ϭ"=aNth@JR%O闡)Uς(M9F%>T|)%| E}w(otrUv].y92_ƑQޮ)tSfoŭZ[V x{{?ʯ8ܯ^rJ/g\TZ5o $ŝ1.$HD4"ih4MX*Rgjm\Eެ|{%erdTgMzEֽc1=6f7Ő,GrcT=?/ƓC!|:PT7崛E(:6KUyUt%Z^S&m*y/^S"Ebٯ&b [Bny}UMpO/@e:x1WozNBy 8*% .=?0ޙkxo6⸓ˋ5}ABЊ(XZ Fv5ѢTl ȃt&/ޱ'g<këW27?XmimU4#Ճ n k~:|vVYJ`|c&c-u.#-ÀC.4nfGП}> &gB=ėA^[<76 GBl\~1+\owoϰ c."_X丧XoGssR{pյfRn%;'[~=s#!^o50 0"0t [Q|5ۼg3:X7(JxF?OgYDNT[ 'ڐNdZKF(@y-m6"RVByF oJ'2ԗzHtt"mZ!!:/*ܶEH-ݰVv#pI7A%o5NafJ]'s2լpaSE`G,(5xqfХ{RbyZ\.Xn_xG3]@M|q  WCjmj} J91g/!=>9q mK.8kXfը(@O{H5!r.ےZίU *X0'~*:}<;p1̖N2ʁnޣsyG\L`&n8""y_~~ty="JZ,6R0v\\Ubڞ(2YoBt^H9@k]@?a7 ~qvOj̐HP\:-sr-Hb H[PȢZJqˌ;"-8o4=M>pА#Q-V{%?k+ohzs2YƑ]D}k=!;;=` @`5/Vkǎf&T瞈(]AB^Gw4k6H-'EWD%푫?%th;pu>7S檽Wysn|ZEdMB6v2r=6!HVV7L a3nK8-GJL OIP18FoX$3Guc0 PB Hf4FBC%6[(bhTh!9,|Y^gQe 6A@P1Xq+ }<-(GHa _qjDz$؞y@y@F &r5YF[ӥ:EQe,`CGjJ%n Ni,^V3Ik5-C0ߎM,Uq?Jch1p[Y^kJCXf@10MSXM"G) gHA}wskaJ2{c7a"D-Ƕ&w"#B?T <{%R,-5/iR:7 u ;GG,8>r=D)>B }DG 1Y_R"Ӑ!7f֫j^{UX\ʹ3}*ad!wG vv$j.i7џ9dIiyG2KiP_h2Uʑo !"A'5ʋ*u`KS|64}/+ Pgb+UY 4+pvSxKͤDJ_ț@a@m7!~vEF_,reb.g*1BOkB꾄)~K_l-VX[i=A~#ec/݃cbDd`aÁd5\>f%9Ux#~S;UpI¸@?c,ʖ)gDwKkf6T `ZOv$$ְtx^H)-.\:K} ^d|#QDԷG:&0VxE.QnI^_L$k D;$K13t݂j҃`m=!#c G6 ==8/D0{#VfV8"%j))ag u C{ڟ%;kL{U"e a4?x?GeaĬzc!줣rdRLLn%+XbhOs<Э Tvvj?0X{kB>oRF m.'rWvGeZC!Lh`ռ~k&6KT+?p)җ'O6Y)&t]?ƚ>^` kЩY 4p (MSд3@x,Y<,?P(c^!5>Љ}#b/P4qfmYz0矡"S>!y+lOφ(P(YH{Bu& !e\)#5Z{XۇIC!VPOR!7K"9e{y#x"\+߄]>3ԌMou6V) #4=܈#Ucnϫz;sCtLjz)Cu+ 9(<$fLȱp9&YAҗ‘,GFj] a!\@'8j&Zfa[nUP3Tzѩ/cBV߻mdl^ f*,AmY~ccQz{qUGyص9^쨃F<+v$|vE#U|:)I_BR"XXC:7Ig<JR-1qOԱҟa]VgOǴY0oy&U+] fxQ{#R@vofC=ܺ#㆐K2#Wh̒s<}IKVaY>~ i~ SZ +uvتB>)F.q3Y?Y l^y~iQBZTћ{{CG1(IBo-jIyReC=QRvLKJtbd/](uRsY B P2C _ ğf4Db8S Zbߑ_x[ 9͵d ľ1'zjs` ikom5]9\r%Z'Lݔ![? u 1;R՝{OH1TQ9-Uf MRY߬h//.!_cU~cAmg^ 5EZ5(>j/Z ?}\j$>28 PɋdЦJxP(̍kI-yXu<81O G o-cYuҾ9S_2=eF8rO5M2nTo(dB+cɳdDZC6y7,&uaku8e&35"^|I,"UfUxC`s㷳jw$:\ҥQEˠfkU\v7 dBunH\RRi/w9qViOuŪ2{~LN(ɾ:"̒ͱ+H[7 %+E9P+(vĻbN:nOXzCCyۦl GaD,veF>԰9&,k91h72S&Z{L+UUr&F+{>%н@OqYx)v^2C'hp3IG ˄FqI-p.8g5Ap5!V=&g#7fcx"_rP+pmN ?]s4wChDB;|dp6tFL^`(1mOR-Lbz),ZW.+٭ܾ>j54DY+'YwLX\&VW m P !&V9CK=Ad]Shanxs;iWqYcf8GYAqys嗔i)0FRj`SE{paK&5:ABS!$ofKGJ^w\@hzO0: ރql,+2Fn]AㄗkPm&`eBƲbھx.-&/%2^eV8q~[$9몷}ZyXuYqGN0l螰F(kX AݖWn ;YiY\k*/咗H X$11tk#0c@.2 > :@^LeM0U;ky34Q|(B ~Wx9_sbR`*jsv,ю\BR ͬv*_N$ X;kL#J/jSbWBpd.B d[QZX k`7EhMO*/!O(&KY0_Y$QI*ESCX vHʠy!]iFɵTyw I716Xy:D(Nnu"ʴ\x272KGB Urق̙>Pk\iM %0R.*۱Qj7 8(ٷ|l O&"p*t(>h5jf]&(%E&i..y|s~52 t/ߥOK`:Pc4M1\N1v%= y=eET$4Ԥ<ٙC6󣛥h2K'*tmx 30k!VFg-F2NMɆ[_džY}R~1 NXqR?㯣S|қ?&#_{T(Nc'IB3p*Oi󖟅4 /<Aϐ:Tz>g45›?Y Du{# س~4㈪ \tdu;p)% 2.ְ,_B ~M$ak!G*woI*$P"R`M~Ƙ  gCX$Nbe~ 8ñZ븞V9ήovGSM%H&GC.?tyO\6|xGw9QGs0茫)+q-$Ð/[Bj Hv"a4Em<x^`S(1L2mNT5jCu"%-vl4uz8nBM Bbם%-r:-y3]a #p5LXb-ybHI gd L3aC\ɕC穧i _QE8vkHK*|Acgkj2+7{fh|ܺ[57HQn>"u,=Xr8!Vx뗃O1PMi0i9 a; 6twmz'E1"_,;N~Da-ljnwSSƉ H8DorB[éh󎵮Z :լU/!L-<YKKL`27KNOLhqwLTr-g!^W7 ,H;8n)u~_P./&k0y^?j OBr@?vj\Eϻ$aܚ\ײ&-uYjEѲd< OA"J ݲ{lA;1xntԎtu3==e㉥7b`CWYŚyNOUY^) 1Y:\|=MFPIJ*,Gf@CGy2ЌXjhb/e5xx88Pj}, ]LvK 6;UzEu|.O.xEqXaE0:nwuE!v"trzt6HxVͼK`7y Vp,'Ă?5q o9:껱niɾB%H qbXEH$!s]zuT:uM6 Z7u4|oU cY4 J"m}wVg\l{_*h:h/YD?-T ʫj(5fR$Nԍo0N~p%!Xbʐ|9L;B]#Nʟ~|/MɲRs׎%Cڱ5ϺL[ nb@!+MJz`e?\jc>.$;d5c2R"V)Tn#3%/Z V@D$pcWZJ/v+=:Ijk%wym+|`9WQqm &yuB q940덬:WxNlPQfɩT#V 0^v["ټVn}u^w˛K|k$PƧu+N5E<<qgXgzCq|hPLZSj' joTDZF;E͍xO:@sWAr,rw/G I.E;5$^E5myq|G(Z89ě AFwA+Z0kNR_h<+W8Z((kC d pr-.& "v:uDLt9/J[8MרÌn-r3l90G7 pehT3S&"dcuR>^" H viRZzx'|_55f.6$/O:ca,7ViT1_YWYvvnGJXJ4}UXc,x_TTy8+.-V01,#KGOs8q/V]u+מxqe[ўs>tn`<7-âӞ$O@W@9Yf2#*7[f"'~W)IfuD)mdUY*-#l@YY*ZѥYByWC&@[Qc-ͻ B*q,Txy,m?N { g?U1Dypn]XzTǃ~4 #)SءSAJmUr\92u%x:F<_ `Ux]H@IDAT 6pM'34`٧C'aK% sGQcÓl}KRď. -u)CDQ`rlb8OaPFs`1b}p%j_oa=* 2*?R-})ӸW9O(diC+r<lk;a: hp!V vmg%B]뚍[ϓAig =R?qa)42t@IM XOR\U+%a/QF 5W\Ϊ)KұQғPb)xz&ż>ZZZTU*2yI"1D̈́Ú)!P0'aQg;>v'GT֋Z-9N]Pf RQR+ԩ i*L1 hO]uZ%!CJ|.L+ Ui S,-uqKVąx*:L1ZM @9T~N5S8H+R5wF)VltP#CwBp g!툤')V &d£PƠ1meX}.8s@Ofȶ !$kSCP(x {HuDc1˶=/#BZd7?ύZDli*$CoWN.2 בk^"d]cRY*xǬuImsz\ġ? 'Ȭ/|T'956 +Nz-.6ԣ( `J,u F:gw .nr(Ë Rr5hjC 1]_-LNdHV‹RRWOQ_c,f`6|c1~%vUF<lL+U咈(^|iħm]$zLjk2Ś5\%h&;($3_IXG-n(.n7(%&AOƯZ$u511ᐴ+s¥): W98)'oB[DQmJ9䊄] t ȣpwwE`?_Jy@Zx.0jkG3&s_7*Zs2SFkmblS9vm5ceK.GHFSR1֎P +ɰѳS9ݑ$NGF9Sh")n*jb??Ñ"/SokF]+Ԃ3[ TƼ8i46Z#PJTVtj%zA'ON2džᛳ+A5<(h}UlJ~RJHQs'BmthB|?-(m~mGbeHnG٠ZO!~#N*_Se(I:0 {؆d+=f&U(4_đrҴEx'wiWB;J@feΏ 8;mc'詟=9v7#Ev|k.R $1)A8lNcߋmjLzWOFB Acg#$KtljLbo 3(-b!/~'زfb,BlS9tg$,^LjA{d\'Yʬrɢ:5g6cfS}-`oպ0 |__OWU/Wu3 3#NtK[𔗍e>qoe47[úMWD a2S|0z(*_CfvWJmQ2 2c#kĵ=a:qS+zm|cp6倓(cN)@z|LнڪHN\T|H&^pC@TRC2M6{K:r$cs*_C($`CQK ?ux %`sWe׻~ZbI~jF6:;\^Q_<:lk'>S' V?c?>"#2 ߚ+UXir`X?*^(1ŪO6Gf逩I%x2MLQ-V75uJM58KZjMfʄ')h9,dDƨ[pt_I4 ;>R.HM2 \{2>&c2M$/PN䪗DyWmu+M!Y,QEvs (>R K57O[w>rޟE,.Ь&15byś'ta{gv=$A|1@DL8PkiT$# 7aĀĿ0.|&5OBVb$ɑ}`*M+yoɆGvTD>>'|v L"]asp9V@7764j!o ㅐfÉ`p7@:ѢңͣFZj tl2N4  Knba0'Rtڀ]+:/]lBKq

    S$KYNYyd ZP&5NE 5#1DvJǔ:+CeR3a=aaPo7gdf9M&)u 9lj|\.vl21J#pH4$Fζ.H֡ƑӡļFNc㋝{)rȋ, hYBˑw{I;CTא=eeTIӴ? Ӊ3}|{ǐ|kqX5zhAQl33]j>/E:v߸tib%Tg=l%&,P!0cG J ;-Kcho˒S (vrdJQ{eHT:߃՗k-?ӊ5r#Zƪ5-r05o5=L0aCfTqp 1'>^Ӫʱcx-v;4:c64.ꛇIs+IŸ4& bv'+vJY ,M>]E4uv*a:Q>uXLuäOC"c}ul j;A,ֻ|k;Azĝ kdd9INDgiKC7>q>"URj/׶QcVX9XSҥȌJ ^#j)➄l΁hc|׆TfF7>EQ@;`RT^v|,[˳@В-v2FTT˩.k>}n?<%v4mBHXܯ_މPںY$S|p[u }p%BG=8@Rt%/]BO:i[}v$#2s  N y?k!>@KcXXEgcH 1u#ǢVw;L9cg8 }~JEE%J3=2msm藥= ,Z@-"@b>d4rd$ J~9ܛ^#'K1RqU`!I=&eU(cÀ"CH2p=X~݉oDDØ(PABͳ`0Q*Y|ρW@..e":*PUx?/mFΥ-$WhҧV0U+Ű`it8?6u4lAa™.pqꥀ N\kJ9'ӊh- =~˔( :tOu]qv?GC☞:J+iw &ny9(F,rD9VRm4>o6hXN]JDo@IfU ӡ|%cß[× 4g āb M~: ϓXji[q#4t c?I.-Ӓ_y @(Nti>wΧetZH*\j8x5[ߏ땳Jct lZ)Y/ؖ1kcbZ%>}F˯Ld[pvWG Oqx+ʔKe!rm=efM12Aº80"SQIit\FW6qUad' v=>5%Ke+4=eklmj@$'oy}WōVjUQ*8hˢ)k"f47iZ0qފ5c4zR0ztLLr_~u7?+ei6_j[[keV4b5K,۷:\ڟW uXP2VМji12?8ל{SN`&肰m9U*>oSy2 {Ff" 8J#USO;ӹ! tDatK93(seYH0A,$jWgۜRd!}8%ώ3f3Eຕ\?""W0Õfr˶flno[VԼde]ޘkTK?Υ $xD;=?;jh =F$}utgw3TKR\=8y=9qBAbั%㧦!YFDcKts:KrZk?ē)B~i[}*T)Ɉh 'mV=uOGs=^MӜmua/a3u yeOr3E^R&uC3ݧ9;] 7b:_GdTˤ{A1ihk$1ag|z{ur23٥0㟌]+/`*V&+Xg ^%G?gέK#zpbCOɵ?wVqyM;?Նy' 얶6Ū4Wb)#S2doTa:vSG~xV8)^ BRZt+hWj7ɣn!Ue(g+͌vuSg%M|!vƁ\;]B,!e'Fne1Js3foP¢'L.:?.e.^. zDZp [A-,i)-;2߂x˚uG4cK S:MOM~֟cQ3qҬ[)u&ZX_;\5Z^^]"tVz?s3 7z&`n 9\04T?}~i}(vEdy(qNNv䥢61U5ƢkȆ|I9z?T} ʅ6D9I@y+>\XQuKA "g '4_ [QOŕ78fB2;bEH?&#r*W`N8c?:`/RZS7l]& .9"Be/P䁰U 8 QVre!%Փ\HOj3o6YJގ/}6}6c=Ryv@tˍJbEqTUs&Gg^.I)?o̮og"(RxA?WS)K@S#[jO҄\8BW g6'ZGHLj7&,p!]p7el=Ҧk(٣/OZn*d5g 7P4c(ug]*^MA99#O/v98NaZ阴.Ge:"8ո-":M=h7uH9|H+L=#faOMƃL>DNC~!ً{{ Z;4',=BȐg9 0=y\E?KV&Ρeb%ɕ OXN Uӌrx RQ[F(`3D$p1P:>eF?9U;]W/ Φw:2-5 U|D{o2hDD5ETxW2kTE[-t;rq^v+L ՆOiJ.[&9Aeh>%' >{,$ASMYA9V:W^#MINoi`N?b!6 JD_SY 7-e9 D( _qrצ>ӧj\AK83]o4lo ;j2;٠+Pa_c2 qQHSxlwZcNޘ#HąW:V@Ed՞ΠIs] uX3Yo?LlZ\Xzlt?{QNQll=t &n( ĎBouG#DK5mK B%M-qp@BD›O)&4#:z2p&kD~4/ Hes?XZd!uEY0I|mxş(RiF]ä6zt$hC_=QtKg{ /ꅴ I{mO(GCP73݇7t14 5{2 4?|i4i @!U0JjQ q^hH9Ls>:0+IW%p9rYnĂsH @\]CC}ZP=4a`[I[js%7:m oAc\Y51EBJA}j iުA#?AICpnGRrF3J0`Dc.p6Il$t`0V6mI:_Fq!=OQPZUKkM3@ gG>BB7٘x* V/ROˊ1ƋPpg8\7Q!KtYhnlep(W=$KR 5ƠvV'ΦX?A^aݮC601Χ?NKeK7!iL.B,ό'Λ )n7CN*Ob n" gh G T"U,QL\jߙǡ@T,4rgzDڽl`oy#Ů ?hHv9DD ՚qV sˠƂR^2[j< 6z{X!-ⵞL uҮԐc GtU^a[6dnFD80ƈD(OBQPjK9rVsWq;4cDRF"Ukc {kQ9y43E_ci31A3!2[0,K()LwrcR7dn^njo n;(8`RH<vEhs_MX2;2EI0OY (]o6t/ࣤה`((1󤞴+K{kPhPtdj6q1>!,IdC)]"a3~2c_{I2@4 _=s [SdTo.I;8#KBF`wlk]+&Ƈ-vKD±OeGȺ!Co*i,X_ n-KQ)P_8GD@Į]æ]]&!_ա`a#9|n#5wl# fNbi~iI\^6 c0խ&òA>>@l9`M ՝SLTi%Dp~ccJ N07e5~Rݿi$ _*H6<:dlަh6E,yP3e [)X]ҰF$uhp$] D-6z2Wؒrrʫh/pk5$#+~Rjw>L \Zn԰FB HPzmcLu G8xi-C(ϒ1ىR RQ6-jWeRѿ _ ^Set5n#|Y"E"Y~? )G2_0 y5HsE@0DWSWF(<&ZQ N f SĤc嬨ؾ[k>ZRk2CL éGÖ?CݠaPf>4 /O2]YVpH&KZkR8=C^ t0cG!6.<1NID{}P>`-'Ȼ)\Xx(^;@OL<ļ-SC>5s8ذȟ! Yƃp#s qrO]$gyRTI)E3^f۾I|?F9ZE-ā$96<.BRsZzA^;(2xd;͓oHJnJ/n1RIv|Rl?7`ˡt hiW+ K. .矄 C7י\uj 4GAs09oS!Z6x ݲNDD[~c.9.| W$F02P4O|zgql$3lU1cšisXnL"<2ѳ[ѱ w)<N CȝM1g͖J3qsekrCqBcL=<*ȉŠ"ӈA|KS;MBzw{M\8F.Lq/RhیHa8182Ah7~-NԤ !<@j9#˶5v;yȫ4.nd5:@S b *]viDK,`9_6fVFE&%-YӐ3NދK ٔQޣIѰ3&:9ǭ\zoht,Ƿv5k$5=;Z$0(1/#{ R_2,u6F4)S-W&t@$^h1- I~ZU Ɔ!j;?zCG8V/]+,2TэdE uu.s.J^IR0ڎ&K"T0$'hZ!,=v)\{OxShyWNv >UsL 2IV#{,=rԱЌn$L0J2ޛʓQOgI8"sj2f(08ĵmϟ'+dr;n7. . bA^h)d:C\ Đ)Ƭ'JGI]X LgMA-n2P˱\[!DJQpvYȤG*:%S$8f56JdR!s/M]!8ޘa"NtPIs&_Rm?A3uD!CV7M4c`f2bFTTlK9Ki(h0P5T;V#Ç0?_֎'sP4Bb8yk"m՛cci0Zfaf[RPE!k Rvj0k|Z[#C`HthV.*] np]P|{5Pclh*G pЄ=&rS ЌZ)N ʴS<  -;L6/djOv[g~"LCeDhFPHAbœ@!h.%n-铚xX`ܐXY{B,Pt jwb (I!܈js |?;^& iБ0%Vc`(茜К1A5wB@ 8M >N_Ƽ!LCxv$sw%;[TDa=.+v K`P8L3Oӗ]1WE^Ҕ!ĂIJAE7z<ƛcUOs,$\.cF|XlV"`d> hMۚ| JUӿ/''I6BP #4!}SZc(PkG )K^nY3eN3)JS:qĞLfF H&qhrt{k@+,NbCWwn]'@l$'BY^Rl%[O8#P۝7 E%iΑ|.Fz8O;4gtTi{z@ R'Q=\F >چ79?'ga2H,h+豫Z%cM*HX )`d Crp(8.03u?*1~d"kЉ^8I:UԈ&*B=4`f ql7 P0$@jW׺nqhm( kFlLe{8Hb83R*72^l^/~N^S;dq6$'^T'R4NG5@SF 骎'JTMCI+I`#^;"G}?~2A\yf&7[T?$pD'2ņSȪ텢i?dG[`cJ,Dp"(NzԵ$˵bsq[{ ^ْҒjq: <{?EZM`*<}~;J*.& 3J'Nd(ٌ:pd>uRzD BSB);~w;YE}ʲÇ+WNd98(# V %l,qȡ"dQgEyy%Z¡O{b8N(Z "?R6=nÀ5LD!,rϟ3:+OCSQ=C`ϭEYL0wϰ~t)SWBHM&RR\-"] f$#TXPޓ?%EC WE`+S6/q;-T_q Y:\n:;8%c`fqD-ExFCk! bcс4T,ey@`6¨ANcNfݻ3m`a#JI0f"v΅yѬE*=VV#/j}NgNeP꺱ay:쁭EkSSXm)r]EOO^.q^>lQٔL, ]xm~:dowʙ[TA \wjb@`_@BTO<)pJw`rx_N. O ˪F,* r{h#E֌YEW(LAYUIQ9DP0t{}3~Ȱm$Kh7t7ْhtBC24)8@!4uA_9jUu\mҜ^Ktk9t0 dULtV&Öh勬"'=m^,!uT47ms4235UEC,yho] qbas^8~${sQ̤idy?6.3Y%FN`KM[3dWYeSYD&]qk0BSI0Gso OF{bb،zߖV@ћT*ךm6bYi-CmmkZ;{V[<kK#%=jտN2M8 ou?*3r5[{ 2Ďf mk% 'W iQ$PtK Avr}F@IDATX}V'Xgre?o,av"Ь\(WBv1㝥xʰB{A -ՖhtF"[3Mؘ.<2 ʘ2_BJ ɔ *˄m"d{'v)(ˣc56vˆqL TdGE!l V΁91obL=Ụ(Di=ᘤSu:#~KjPzQ Y{-QG `)PvBnp_Cc([{"ݩic : 2t(Y)9' >ƙ&)~6FۛQ*lϙ@kJ;v#f|:G,% tj;9ߘZVIۛbiv.!u>&?8ݿ>>?h./||__iφ*{jffn"Bv /U-a 8?t6A3 &䷦S3n#YtXw5NsՋ';2DZtV  {C-k~n y Q'PgҢ:2(jp`„ tsLt@ :"OD0Gn!)`GԜeZ{y m#@B}RkÅQ/Ÿ|qhQpP|nMpzB)nDMd(n]Xάo`Oդ]ς;URE'/ ':M'X2-2R)>nRǬ P'+.~78<:xO0V-pWz n&#^t Wp=p</p]_É 1S HΪiz{y9Y \hZQ-QJX{blꗲo1%S7s M)DHGGrVqi7{5_,*\P9/cW*]L[C RGkV'KS| 0 2- r٥ȧz<>BN4'¤g}r2D:n0)k6#Fx!1t- g){T\osQ vOW,@|] Q|KbGD,pv]) AP鶒-|j7yؠq{Vib ][HA")-8`< ~62c&6D|O'.G7fOSR@96r NQPM9t)FS&*"3 x#SbZ<ɯ&Q>K)8sJHv*Pg(ól O+ԿltW /{aX-Dfqe70g rž-!0IOy~axJ;ڃ!jҡOqQ}c5MU$q#rq`O\9|Gr fʦ*K!DB3`Z |\M5rU@[ZƓ藐dꧫXEYO=n? )шLȒV&jr`)<:* 詒F /DQhH#L"v55-F0$1"5ߒ\ӑ  `=<4wa<ٹd&SM#m5ѕ,npA"NW HVNM@W۸lQSA5*k"]!GI_'B9ǷPDBɾN?TYmߒ"lÔ~7&54  5fkK>rwlno6ab'F` :!h9 MfBB93y\)n BR#lҸj5MVvۏ7a/GS6>*kLO%(39ϺtazP7GEX]㍰zѥTH䴩j9B? OE@s\4LI\3Bz {,fT`K_\9*?b$EPCqG7WM-ПyُT%D@KHo #fR)tt[Lr^o TRE}aD` ~=.E })Ѝ-sq`7?py6 ho?to8z:W _Yfyfum`1~ho'|5Ɋ,eZ3|y5VW`'\;37 4'gX:fbvyr:k+*zeڋާĄ-/.vZsW&+$8GR:cwMEh!I@MjЧjx&TT/ĺ4GGLZLЂ&_*D!Sx>wM5Du) +NҀ/C0Ξf5 g&d3G>7xk}`%UJ&wؕy}J&mwMP:WJB"fT/R fܚ%?Yj;juxUDnE`q~!록<&A=\FMԅ jm#$N {kU5ZtE?i]H2Kf$"ѨS9hj4~8rO4`{T+L'~y vaKKԒ4xx, n`ЈAS${w[/PĒ%_DE̸ï/SOkDDX*E,E=)C+X9]͌h=o2D.WTչv>:AN\4Yj[1dhxt*GKdfj7.Ik< z$- dq8$ߪ< B\9 4^v O<(G˞gxWN%{kHWFjD6KuO%iP|Alۊ:4QV0$F 'G}BIA knjązOyb=k@ jn6>/([dh {d]Ceޥ5F@[ x%{:R%:/ n;GQK18}礸h3r&j8["Bo;DTR~8'o4OW%.Zri@ ^!š]K^pc@ej?aaw#! ī ڽ͒^RF'wFx0r$qXaVh 8Iշ v%Jw$xCմ"=`V4N[xIbWA43U`jlYs w{? f(|Tf dj}E r9%Caqşx`a (|5U,pCc_ϻ`jm\zv+LA`hTG6"Zœq֣,AYo*9e5QFA*KtF=JJ0e'͙KM̽WfN%-$z2{Vmg 1c\;cf~< ǫx%TTs˵!W/bO ]&ʢ)վ̈v)wQY̿˻* %y9OB EPa6T^jSQE:zt9. `傽KbYu-Om",ik|ʔVe>WBr g> W5L)@qն'..p 5?Ėj@Ml's7,ͤʁ CaMGXPsJVcGUڰ{%(| Ĭ2r ~7L ְe0Map qjW% !m Ŝl4a4 \;Nس.Ě2J1PDp>GځS&x(2]4P+V8 Hy: {:o0mA5{e%)ENvHZǒ|o*K>Tc6%+p)cAR P x W6I,=iˇ 5Q U׮w,$ɐq|>em{xǏ'2UEס+p=tC+MO0-S Mmٹ'#H%"c;cs>Hi"ߔN6b#)*mDTĎll+ZA$ſVly*g9sP/XA\DsKNI*>1 LqM}4uGX+$!w$O󠍅e֧biHssT:y3'ZBִ3  % }D)( 4M JMMW# ֐œ$6'AwTexXuhC#SHjNiir 8ZmT 4LR`sҁ@16R:nCei Va^IŨ'BEI-]AUńr9U!\E|=9S>&|ݚ[̅S 2ՅҾ=rҹĿy68G(78h-)&E_f;)Z`~9vT $ۯn#CbY@Wݛmbk'ΖͿBtdPPx;(P|TYN$ɹB2^̀'ZpTtdYuٟٸD.CVvCeEfGB?<‹P""SJ3f{:eV~#&oQv> L9׭IOaqW\ah݇$K.>\y%'w%N Ōyco7SrmjK)o{mQMXQzO+#t ] Hˁ>3CHt.MaN.=E2ҝ tebgtUow!Imh#ؗ[ڴ|n>aס~QE%$F,''!3ieF)7G ͞(H_*2sVoJ)#X·4w?ՠ5KF[ʓPV^bdF]}[b{llߵNL&!%r@~ VǡPpabNwPp?Ov6'0U&ZkTv-NIO7vHams7?,vw܏?5(~kzXЊkk\pM[>ݮ#pA5ld0}gLk~:Þ@U!l6z7̵K!bbp?sԈooXӎ5͐4"ة=E2eeꕰ"p]ul/ܘxь'vYe Rw-D Q0<<a?=hN'ֳWl7\t+`](涽LMTŖduBP{[qN;YVYZˡ]جA/ۑL$FlaI㌯TѺZMeWsJôrz*n%u<@9R,tb{?~z6B1WS4&LZflgCڱRK0& 0W]|4@\ |/5a2b3/S?eH#3igD|l1@2]68ӛPͦtL5`jgnf8%1D5 JK؜\ FJ~R&S=L^$È M (*γeX)NKEi9^֔RfA2! Yw[YVP8h>(e)}roqtIF)Br#[gCD3IR,Me2PeubG.i=mϲ<|B9-Sj)<ܭ*kM܋M9L_C̅/ ”2<'c8-0zL~{H?mi7A*Uw`g$ӰFqe]t84͔I;4{yY$cJh"AQ|P=HL+`WGAϡCXl"h 3 ~:] PrBT\?MF]5E.?ec|,J+; |ouX>-j:TlE>Du/%/^8uf\Lx-!ߢkmCF?i0HSҔy/#JF)$]p4sE_ȤIA "6cP~Ktk4Y{~L5b)HO߁ֶ9R!57`zm+&2xE+7bgbn n3UCaTԪ!byQɈg^DP21/d;Rb>00 p|W\ ?]I(0ŋ/ρaĐ@UOz`J|')Zq|4?`{ |/S}uk$" O+ub^n^& *q=9<2<>"ޙހBm`kYKID&xS$* 6ÀQBsXz$t7qp~-]pTT]~c9 bjQ^֮ĀFiL-A 4وԈuXʣJ瘖֒jT #*c;t"4jɸ6Ek/!V3Q9`W4g θPt'MT|eh'Ï:%`x1/e6D>_ nULk5{T17]a-`diݶцEOX1v60k'U;u-g834oMNF2t352.q;HQX >iOkC13C%ZC;ݙ-x%Bפpra/0dR ([C4^Vd%T4cZo\G M p>V2a|xM,>ր/ҚT u VDַHxu-9ramj[5j*Li/!IV+ khXfǏ^8z9ޝ[.`bh̄BH Gzn~z W@*lMYDA*`7'gPJv>9߻1C)&`Ү,y>!ş= 70U)Gi fFM5 *ibanA3z ,_!_ߠO:kE}D9? {|ꖅb8P["?F-dL*R'`IakZq2Xmcfjhۛs9Dv#Ǯl=shƿj"5Pk`ÞEfJ0tK n*fUNpQm0q$Mg ;U,,d)z[A|L` j-FćPHBH9Ƣ4D 3s9hkKJ9gkd=Z'Ӧ2àj @DpԂX ^i2MDbXy&D **O&K1Vy@ ]s%]Ua|m0B9TW/TjivP&?PqT=jo=V|psIW6a^!5fm$v 1mgaY0|]9XڄJ{18 XxxﯾγƃЪki%4:\A 1DpZKٕ)kg8};q"~XQEdȩxEa'|-mTq_b ίU- 3V`RK?eh;8 LG簓nAi0 "D>k"k%"V ޲~lK,Y+p` 0I?_CЙc` GS0fDF/ Iz"Ht8Fu%)Sk 8bbo ÛKy_rMO̱uc҈C,&[ѿJKRBep ~x! nSN=:o᜺DiT'ጷQ.Ohn^nhMu J@k*5]^iG1X:aBIYǐ"m8=v;/e"4,7X+LcY 0*!>*0'qh0B\0xgQeZ9cئa0ex)xCM=H.c&lvP'_\,&xF-c"9A-[w?)r$^뀵|ޡ7@,!o7 "=[xpIvD Y)fbts}9OUPUiQX9N͵P e{Lr<9(_>[OFfV6FaЗP/GF(0RN{+">edKœYi"0N\(%vuiĻ\|"Z,2p%fijXԍBmK}2d"DP%ʆM!LUUΉhחI|$-Y씈j'RE$,Ԩ'cL =^ ʽtSXʡZ||i(j벘59'PSJ`R$M6NF+ *?rRv+hdע ^k`Sؚ_O:nvAm,lXWb^ *'ʯ!cX=U?~E@ʼT썟#9,dH)K ج|=O? 2d-"׻"[*G2mp#TIqV%țJeŀ4IMiURslaئ^ڌ;{[T* ]"bKbg9 1v#JMd;?x<hIGv41_nK^ĘQ#wg IDATAzR?"q:լp|ubbׅXmpl!j" ԩ@ڪŸفSqSYQ7񭮀*e>`3`etB?ixŤ$;8֑4‚S `L;Uƃ)WL޹R6#\X~6!3 nNoٽY sa-^K1mF *-r b6p0wq;WyT ~aR~q8YPfi5fCA>ޘtDudC&$X\=Wn<`²ESK_;}qeLI`ȐPk 7`e {$cHcťgu2"$?RK@?HVjc|6NW[Z}mldIRx%é|!nng݃~,>DLXƔ$`z/Ч5d<"nm+=ch~=԰-_/_oO'#KGHm˾o{-ڋ5 WsaxXK7[*Qǥ;~6t͞'ULSfeTY)Q۳bT %y1Ar۶~̽hX!QM&N|"u)3cJ^ +D|8r0$%7`,c4wI[]g/T;APid:LX c'^[v`:$kV&+r;?з%/ؗ3 šq hm ug¾12Tڢ̷*8x;ցNvC!#dBLf`I_>Dm#.HshH>L{𽷶t<o!ppM7]Vjq='?OOp^(YُEHcKle@4ZklH a6P mq6ָ*[l ?y_}xO |-rpvKY5UK7b3EWU D U$Jw~KX|6ёel׳gmuxHg&y l=Ӯo4IDa E"_~f\aؤaAUoZ#ڈgMq;r+z>cr2yܮ滨ڴKT|?fgF Co P`/#nf5)>hyi$2Z~V^yoA!XIONT0k,mK)KL *vyy{㝞E&_|«HbHXUXNoقӌCVHjW!GlT^f9VAGR5R&c']ˏ>,|ʁsw7'ؑydNe/ :NgR 0]s )49g)ˏg.GZ ?~Qr CzМª}rn/Z˽w΀YۗØ!6׮ڂ0Rha~W^qP)6 ƃqyנuU@y'TB@~BN> $GKNmNn-6LRPE}8r`GjRK_H0LaVZaH_!aJ [;1/\(gG2'6];겐%pZnGʆo#K[W3_dg8I'l;wP&|XԊo?|w/x(WaZL6` u1E9nr"y->"WTjN )4Ɩl@ш?%s AA/!^y<1-0rSP< 0m)Lj.8,x;!V(4BFe>IU; ”?1JE3wUջ/҉HJ,$ift.NmL]CX57ّ]b6fR}.ˆgx! @3 mes uZmӸuK8ۂyTD+gt̗"j῍^r%{(! d.-C <2SL`%dwn j83$e:Dk2?5[\f9l+E>!2nl8Ƹp/$HSW{SΡ^fNvNMu# 0yO0moN׈gxT1 Oɏ []h9^DNRc`Ht,DQTMGyq6ۘ h1@n}Hi= Y}t:յO*~ib'>e!@a C&&P9сNd&ތ̔#Q_l_;a#bo<@?7)0I U=#{\؏~+Bd5?ͤ<_U4oe:` / 5{>lht/IENDB`traits-6.3.2/traits/examples/introduction/index.rst000066400000000000000000000013571414270267200225510ustar00rootroot00000000000000Introduction to Traits ====================== This is an interactive tutorial to introduce you to the basics of Traits and to give you an idea of what capabilities the Traits libraries provide. This tutorial assumes that you are comfortable with the Python programming language, object-oriented programming, and the core tools of the Python scientific ecosystem, such as NumPy. The tutorial starts with an **Introduction** which gives a realistic example of scientific code; then talks about how traits can be used for **Validation**, **Initialization**, **Documentation**, **Observation** and **Visualization**. This tutorial is designed to introduce the basics of Traits, but also to explain *why* you might want to use Traits in your own code. traits-6.3.2/traits/examples/tests/000077500000000000000000000000001414270267200173235ustar00rootroot00000000000000traits-6.3.2/traits/examples/tests/__init__.py000066400000000000000000000000001414270267200214220ustar00rootroot00000000000000traits-6.3.2/traits/examples/tests/test_etsdemo_info.py000066400000000000000000000014701414270267200234110ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import os import unittest from traits.examples._etsdemo_info import introduction from traits.testing.optional_dependencies import requires_pkg_resources class TestETSDemoInfo(unittest.TestCase): @requires_pkg_resources def test_introduction(self): # input to introduction is currently just a placeholder response = introduction({}) self.assertTrue(os.path.exists(response['root'])) traits-6.3.2/traits/has_traits.py000066400000000000000000004213061414270267200170640ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Defines the HasTraits class, along with several useful subclasses and associated metaclasses. """ import abc import copy as copy_module import inspect import os import pickle import re import types import warnings import weakref from types import FunctionType from . import __version__ as TraitsVersion from .adaptation.adaptation_error import AdaptationError from .constants import DefaultValue, TraitKind from .ctrait import CTrait, __newobj__ from .ctraits import CHasTraits from .observation import api as observe_api from .traits import ( ForwardProperty, Property, Trait, generic_trait, ) from .trait_types import Any, Bool, Disallow, Event, Python, Str from .trait_notifiers import ( ExtendedTraitChangeNotifyWrapper, FastUITraitChangeNotifyWrapper, NewTraitChangeNotifyWrapper, StaticAnytraitChangeNotifyWrapper, StaticTraitChangeNotifyWrapper, TraitChangeNotifyWrapper, ui_dispatch, ) from .trait_base import ( SequenceTypes, TraitsCache, Undefined, is_none, not_event, not_false, ) from .trait_errors import TraitError from .util.deprecated import deprecated from .util._traitsui_helpers import check_traitsui_major_version from .trait_converters import check_trait, mapped_trait_for, trait_for # Set CHECK_INTERFACES to one of the following values: # # - 0: Does not check to see if classes implement their declared interfaces. # - 1: Ensures that classes implement the interfaces they say they do, and # logs a warning if they don't. # - 2: Ensures that classes implement the interfaces they say they do, and # raises an InterfaceError if they don't. # # This constant is used by the @provides decorator when deciding whether to # do interface checking. This behaviour is deprecated. In the future, the # provides decorator will no longer perform interface checking, regardless of # the value of this constant. CHECK_INTERFACES = 0 # This ABC is a placeholder for the TraitsUI ViewElement class, which should # inherit from or register as implementing the API. This has to be done here # so that the metaclass machinery has something to check against when # filtering out TraitsUI elements that are declared as part of a HasTraits # class. class AbstractViewElement(abc.ABC): pass # Constants WrapperTypes = ( StaticAnytraitChangeNotifyWrapper, StaticTraitChangeNotifyWrapper, ) # Class dictionary entries used to save trait, listener and view information # and definitions: BaseTraits = "__base_traits__" ClassTraits = "__class_traits__" PrefixTraits = "__prefix_traits__" ListenerTraits = "__listener_traits__" ObserverTraits = "__observer_traits__" ViewTraits = "__view_traits__" InstanceTraits = "__instance_traits__" # The default Traits View name DefaultTraitsView = "traits_view" # Trait types which cannot have default values CantHaveDefaultValue = ("event", "delegate", "constant") # The trait types that should be copied last when doing a 'copy_traits': DeferredCopy = ("delegate", "property") # Quick test for normal vs extended trait name extended_trait_pat = re.compile(r".*[ :\+\-,\.\*\?\[\]]") # Generic 'Any' trait: any_trait = Any().as_ctrait() # Mapping from user-facing strings to the dispatcher callable in observe. _ObserverDispatchers = { "same": observe_api.dispatch_same, "ui": ui_dispatch, } def _clone_trait(clone, metadata=None): """ Creates a clone of a specified trait. """ trait = CTrait(TraitKind.trait) trait.clone(clone) if clone.__dict__ is not None: trait.__dict__ = clone.__dict__.copy() if metadata is not None: trait.__dict__.update(metadata) return trait def _get_method(cls, method): """ Get the definition of a specified method (if any). """ result = getattr(cls, method, None) if (result is not None) and is_unbound_method_type(result): return result return None def _get_def(class_name, class_dict, bases, method): """ Gets the definition of a specified method (if any). """ if method[0:2] == "__": # When name-mangling to handle the __ case (for _private traits), # leading underscores in the class name are stripped out. method = "_%s%s" % (class_name.lstrip('_'), method) result = class_dict.get(method) if ( (result is not None) and is_unbound_method_type(result) and (getattr(result, "on_trait_change", None) is None) and (getattr(result, "_observe_inputs", None) is None) ): return result for base in bases: result = getattr(base, method, None) if ( (result is not None) and is_unbound_method_type(result) and (getattr(result, "on_trait_change", None) is None) and (getattr(result, "_observe_inputs", None) is None) ): return result return None def is_unbound_method_type(method): """ Check for something that looks like an unbound class method. This is used in practice to identify magic-named _name_changed and _name_fired methods. """ # The ismethoddescriptor check catches methods written in C or Cython # extensions. It excludes things that pass an isfunction check, so we have # to explicitly re-include that check. return inspect.isfunction(method) or inspect.ismethoddescriptor(method) def _is_serializable(value): """ Returns whether or not a specified value is serializable. """ if isinstance(value, (list, tuple)): for item in value: if not _is_serializable(item): return False return True if isinstance(value, dict): for name, item in value.items(): if (not _is_serializable(name)) or (not _is_serializable(item)): return False return True return (not isinstance(value, HasTraits)) or value.has_traits_interface( ISerializable ) def _get_instance_handlers(class_dict, bases): """ Returns a dictionary of potential 'Instance' or 'List(Instance)' handlers. """ # Create the results dictionary: instance_traits = {} # Merge all of the base class information into the result: for base in bases: for name, base_arg_lists in base.__dict__.get(InstanceTraits).items(): arg_lists = instance_traits.get(name) if arg_lists is None: instance_traits[name] = base_arg_lists[:] else: for arg_list in base_arg_lists: if arg_list not in arg_lists: arg_lists.append(arg_list) # Merge in the information from the class dictionary: for name, value in class_dict.items(): if (name[:1] == "_") and is_unbound_method_type(value): n = 13 col = name.find("_changed_for_") if col < 2: n = 11 col = name.find("_fired_for_") if col >= 2: key = name[col + n:] if key != "": arg_list = (name, name[1:col]) arg_lists = instance_traits.setdefault(key, []) if arg_list not in arg_lists: arg_lists.append(arg_list) # Return the dictionary of possible arg_lists: return instance_traits def get_delegate_pattern(name, trait): """ Returns the correct 'delegate' listener pattern for a specified name and delegate trait. """ prefix = trait._prefix if prefix == "": prefix = name elif (len(prefix) > 1) and (prefix[-1] == "*"): prefix = prefix[:-1] + name return " %s:%s" % (trait._delegate, prefix) class _SimpleTest: def __init__(self, value): self.value = value def __call__(self, test): return test == self.value def _add_notifiers(notifiers, handlers): """ Adds a list of handlers to a specified notifiers list. """ for handler in handlers: if not isinstance(handler, WrapperTypes): handler = StaticTraitChangeNotifyWrapper(handler) notifiers.append(handler) def _add_event_handlers(trait, cls, handlers): """ Adds any specified event handlers defined for a trait by a class. """ events = trait.event if events is not None: if isinstance(events, str): events = [events] for event in events: handlers.append(_get_method(cls, "_%s_changed" % event)) handlers.append(_get_method(cls, "_%s_fired" % event)) def _property_method(class_dict, name): """ Returns the method associated with a particular class property getter/setter. """ return class_dict.get(name) def _create_property_observe_state(observe, property_name, cached): """ Create the metadata for setting up an observer for Property. Parameters ---------- observe : str or list or Expression As is accepted by HasTraits.observe expression argument This is the value provided in Property(observe=...) property_name : str The name of the property trait. cached : boolean Whether the property is cached or not. Returns ------- state : dict State to be used by _init_traits_observers """ def handler(instance, event): if cached: cache_name = TraitsCache + property_name old = instance.__dict__.pop(cache_name, Undefined) else: old = Undefined instance.trait_property_changed(property_name, old) def handler_getter(instance, name): return types.MethodType(handler, instance) graphs = _compile_expression(observe) return dict( graphs=graphs, dispatch="same", handler_getter=handler_getter, post_init=False, ) def _compile_expression(expression): """ Compile a user-supplied expression or list of expressions. Converts a list of strings or ObserverExpressions to a list of ObserverGraphs representing the observation patterns to be applied. Parameters ---------- expression : str or list or ObserverExpression A description of what traits are being observed. If this is a list, each item must be a string or an ObserverExpression. Returns ------- graphs : list of ObserverGraph List of graphs representing the observation patterns to be applied to the relevant objects and handlers. """ # Handle the overloaded signature. # Support list to be consistent with on_trait_change. if isinstance(expression, list): expressions = expression else: expressions = [expression] graphs = [] for expr in expressions: graphs.extend( observe_api.compile_str(expr) if isinstance(expr, str) else observe_api.compile_expr(expr) ) return graphs # This really should be 'HasTraits', but it's not defined yet: _HasTraits = None class MetaHasTraits(type): """ Controls the creation of HasTraits classes. The heavy work is done by the `update_traits_class_dict` function, which takes the ``class_dict`` dictionary of class members and extracts and processes the trait declarations in it. The trait declarations are then added back to the class dictionary and passed off to the __new__ method of the type superclass, to be added to the class. """ # All registered class creation listeners. # # { Str class_name : Callable listener } _listeners = {} def __new__(cls, class_name, bases, class_dict): update_traits_class_dict(class_name, bases, class_dict) # Finish building the class using the updated class dictionary: klass = type.__new__(cls, class_name, bases, class_dict) # Call all listeners that registered for this specific class: name = "%s.%s" % (klass.__module__, klass.__name__) for listener in MetaHasTraits._listeners.get(name, []): listener(klass) # Call all listeners that registered for ANY class: for listener in MetaHasTraits._listeners.get("", []): listener(klass) return klass @classmethod def add_listener(cls, listener, class_name=""): """ Adds a class creation listener. If the class name is the empty string then the listener will be called when *any* class is created. .. deprecated:: 6.3.0 """ warnings.warn( "add_listener is deprecated", DeprecationWarning, stacklevel=2 ) MetaHasTraits._listeners.setdefault(class_name, []).append(listener) @classmethod def remove_listener(cls, listener, class_name=""): """ Removes a class creation listener. .. deprecated:: 6.3.0 """ warnings.warn( "remove_listener is deprecated", DeprecationWarning, stacklevel=2 ) MetaHasTraits._listeners[class_name].remove(listener) def update_traits_class_dict(class_name, bases, class_dict): """ Processes all of the traits related data in the class dictionary. This is called during the construction of a new HasTraits class. The first three parameters have the same interpretation as the corresponding parameters of ``type.__new__``. This function modifies ``class_dict`` in-place. Parameters ---------- class_name : str The name of the HasTraits class. bases : tuple The base classes for the HasTraits class. class_dict : dict A dictionary of class members. """ # Create the various class dictionaries, lists and objects needed to # hold trait and view information and definitions: base_traits = {} class_traits = {} prefix_traits = {} listeners = {} prefix_list = [] view_elements = {} # Mapping from method/trait names to list(dict) # where each nested dict provides the input arguments for calling # ``HasTraits.observe`` once. See ``_init_trait_observers``.` observers = {} # Create a list of just those base classes that derive from HasTraits: hastraits_bases = [ base for base in bases if base.__dict__.get(ClassTraits) is not None ] # Create a list of all inherited trait dictionaries: inherited_class_traits = [ base.__dict__.get(ClassTraits) for base in hastraits_bases ] # Move all trait definitions from the class dictionary to the # appropriate trait class dictionaries: for name, value in list(class_dict.items()): value = check_trait(value) rc = isinstance(value, CTrait) if (not rc) and isinstance(value, ForwardProperty): rc = True # Create Property trait from getter, setter, validator getter = _property_method(class_dict, "_get_" + name) setter = _property_method(class_dict, "_set_" + name) if (setter is None) and (getter is not None): if getattr(getter, "settable", False): setter = HasTraits._set_traits_cache elif getattr(getter, "flushable", False): setter = HasTraits._flush_traits_cache validate = _property_method(class_dict, "_validate_" + name) if validate is None: validate = value.validate value = Property( getter, setter, validate, True, value.handler, **value.metadata ) if rc: del class_dict[name] if name[-1:] != "_": base_traits[name] = class_traits[name] = value value_type = value.type if value_type == "trait": handler = value.handler if handler is not None: if handler.has_items: items_trait = _clone_trait( handler.items_event(), value.__dict__ ) if ( items_trait.instance_handler == "_list_changed_handler" ): items_trait.instance_handler = ( "_list_items_changed_handler" ) class_traits[name + "_items"] = items_trait if handler.is_mapped: class_traits[name + "_"] = mapped_trait_for( value, name ) elif value_type == "delegate": # Only add a listener if the trait.listenable metadata # is not False: if value._listenable is not False: listeners[name] = ( "delegate", get_delegate_pattern(name, value), ) elif value_type == "event": on_trait_change = value.on_trait_change if isinstance(on_trait_change, str): listeners[name] = ("event", on_trait_change) else: name = name[:-1] prefix_list.append(name) prefix_traits[name] = value elif is_unbound_method_type(value): pattern = getattr(value, "on_trait_change", None) if pattern is not None: listeners[name] = ("method", pattern) observer_states = getattr(value, "_observe_inputs", None) if observer_states is not None: observers[name] = observer_states elif isinstance(value, property): class_traits[name] = generic_trait # Handle any view elements found in the class: elif isinstance(value, AbstractViewElement): view_elements[name] = value # Remove the view element from the class definition: del class_dict[name] else: for ct in inherited_class_traits: if name in ct: # The subclass is providing a default value for the # trait defined in a superclass. ictrait = ct[name] if ictrait.type in CantHaveDefaultValue: raise TraitError( "Cannot specify a default value " "for the %s trait '%s'. You must override the " "the trait definition instead." % (ictrait.type, name) ) default_value = value class_traits[name] = value = ictrait(default_value) # Make sure that the trait now has the default value # has the correct initializer. if value.setattr_original_value: # Set the original, non validated value value.set_default_value( DefaultValue.missing, default_value) else: value.set_default_value( DefaultValue.missing, value.default) del class_dict[name] break # Process all HasTraits base classes: migrated_properties = {} for base in hastraits_bases: base_dict = base.__dict__ # Merge listener information: for name, value in base_dict.get(ListenerTraits).items(): if (name not in class_traits) and (name not in class_dict): listeners[name] = value # Merge observer information: for name, states in base_dict[ObserverTraits].items(): if (name not in class_traits) and (name not in class_dict): observers[name] = states # Merge base traits: for name, value in base_dict.get(BaseTraits).items(): if name not in base_traits: property_info = value.property_fields if property_info is not None: key = id(value) migrated_properties[key] = value = migrate_property( name, value, property_info, class_dict ) base_traits[name] = value # Merge class traits: for name, value in base_dict.get(ClassTraits).items(): if name not in class_traits: property_info = value.property_fields if property_info is not None: new_value = migrated_properties.get(id(value)) if new_value is not None: value = new_value else: value = migrate_property( name, value, property_info, class_dict ) class_traits[name] = value # Merge prefix traits: base_prefix_traits = base_dict.get(PrefixTraits) for name in base_prefix_traits["*"]: if name not in prefix_list: prefix_list.append(name) prefix_traits[name] = base_prefix_traits[name] # Make sure there is a definition for 'undefined' traits: if prefix_traits.get("") is None: prefix_list.append("") prefix_traits[""] = Python().as_ctrait() # Save a link to the prefix_list: prefix_traits["*"] = prefix_list # Make sure the trait prefixes are sorted longest to shortest # so that we can easily bind dynamic traits to the longest matching # prefix: prefix_list.sort(key=len, reverse=True) # Get the list of all possible 'Instance'/'List(Instance)' handlers: instance_traits = _get_instance_handlers(class_dict, hastraits_bases) # If there is an 'anytrait_changed' event handler, wrap it so that # it can be attached to all traits in the class: anytrait = _get_def(class_name, class_dict, bases, "_anytrait_changed") if anytrait is not None: anytrait = StaticAnytraitChangeNotifyWrapper(anytrait) # Save it in the prefix traits dictionary so that any dynamically # created traits (e.g. 'prefix traits') can re-use it: prefix_traits["@"] = anytrait # Make one final pass over the class traits dictionary, making sure # all static trait notification handlers are attached to a 'cloned' # copy of the original trait: cloned = set() for name in list(class_traits.keys()): trait = class_traits[name] handlers = [ anytrait, _get_def(class_name, class_dict, bases, "_%s_changed" % name), _get_def(class_name, class_dict, bases, "_%s_fired" % name), ] # Check for an 'Instance' or 'List(Instance)' trait with defined # handlers: instance_handler = trait.instance_handler if ( (instance_handler is not None) and (name in instance_traits) or ( (instance_handler == "_list_items_changed_handler") and (name[-6:] == "_items") and (name[:-6] in instance_traits) ) ): handlers.append(getattr(HasTraits, instance_handler)) events = trait.event if events is not None: if isinstance(events, str): events = [events] for event in events: handlers.append( _get_def( class_name, class_dict, bases, "_%s_changed" % event ) ) handlers.append( _get_def( class_name, class_dict, bases, "_%s_fired" % event ) ) handlers = [h for h in handlers if h is not None] default = _get_def(class_name, class_dict, [], "_%s_default" % name) if (len(handlers) > 0) or (default is not None): if name not in cloned: cloned.add(name) class_traits[name] = trait = _clone_trait(trait) if len(handlers) > 0: _add_notifiers(trait._notifiers(True), handlers) if default is not None: trait.set_default_value(DefaultValue.callable, default) # Handle the case of properties whose value depends upon the value # of other traits: if (trait.type == "property") and (trait.depends_on is not None): cached = trait.cached if cached is True: cached = TraitsCache + name depends_on = trait.depends_on if isinstance(depends_on, SequenceTypes): depends_on = ",".join(depends_on) else: # Note: We add the leading blank to force it to be treated # as using the extended trait notation so that it will # automatically add '_items' listeners to lists/dicts: depends_on = " " + depends_on listeners[name] = ("property", cached, depends_on) if trait.type == "property" and trait.observe is not None: observer_state = _create_property_observe_state( observe=trait.observe, property_name=name, cached=trait.cached, ) observers[name] = [observer_state] # Add processed traits back into class_dict. class_dict[BaseTraits] = base_traits class_dict[ClassTraits] = class_traits class_dict[InstanceTraits] = instance_traits class_dict[PrefixTraits] = prefix_traits class_dict[ListenerTraits] = listeners class_dict[ObserverTraits] = observers class_dict[ViewTraits] = view_elements def migrate_property(name, property, property_info, class_dict): """ Migrates an existing property to the class being defined (allowing for method overrides). """ get = _property_method(class_dict, "_get_" + name) set = _property_method(class_dict, "_set_" + name) val = _property_method(class_dict, "_validate_" + name) if (get is not None) or (set is not None) or (val is not None): old_get, old_set, old_val = property_info return Property( get or old_get, set or old_set, val or old_val, True, **property.__dict__ ) return property # 'HasTraits' decorators def observe(expression, *, post_init=False, dispatch="same"): """ Marks the wrapped method as being a handler to be called when the specified traits change. This decorator can be stacked, e.g.:: @observe("attr1") @observe("attr2", post_init=True) def updated(self, event): ... The decorated function must accept one argument which is the event object representing the change. See :mod:`traits.observation.events` for details. Parameters ---------- expression : str or list or ObserverExpression A description of what traits are being observed. If this is a list, each item must be a string or Expression. See :py:func:`HasTraits.observe` for details on the semantics when passing a string. post_init : boolean, optional Whether the change handler should be attached after the state is set when instantiating an object. Default is false, and values provided to the instance constructor will trigger the change handler to fire if the value is different from the default. Set to true to avoid this change event. dispatch : str, optional A string indicating how the handler should be run. Default is to run it on the same thread where the change occurs. Possible values are: =========== ======================================================= value dispatch =========== ======================================================= ``same`` Run notifications on the same thread where the change occurs. The notifications are executed immediately. ``ui`` Run notifications on the UI thread. If the current thread is the UI thread, the notifications are executed immediately; otherwise, they are placed on the UI event queue. =========== ======================================================= See Also -------- HasTraits.observe """ graphs = _compile_expression(expression) def observe_decorator(handler): """ Create input arguments for HasTraits.observe and attach the input to the callable. The metaclass will then collect this information for calling HasTraits.observe with the decorated function. Parameters ---------- handler : callable Method of a subclass of HasTraits, with signature of the form ``my_method(self, event)``. """ # Warn on a dubious handler signature. The handler should accept a call # that passes a single positional argument (conventionally named # "event") in addition to the usual "self". handler_signature = inspect.signature(handler) try: handler_signature.bind("self", "event") except TypeError: warnings.warn( ( "Dubious signature for observe-decorated method. " "The decorated method should be callable with a " "single positional argument in addition to 'self'. " "Did you forget to add an 'event' parameter?" ), UserWarning, stacklevel=2, ) try: observe_inputs = handler._observe_inputs except AttributeError: observe_inputs = [] handler._observe_inputs = observe_inputs observe_input = dict( graphs=graphs, dispatch=dispatch, post_init=post_init, handler_getter=getattr, ) observe_inputs.append(observe_input) return handler return observe_decorator def on_trait_change(name, post_init=False, dispatch="same"): """ Marks the following method definition as being a handler for the extended trait change specified by *name(s)*. Refer to the documentation for the on_trait_change() method of the **HasTraits** class for information on the correct syntax for the *name* argument and the semantics of the *dispatch* keyword argument. A handler defined using this decorator is normally effective immediately. However, if *post_init* is **True**, then the handler only becomes effective after all object constructor arguments have been processed. That is, trait values assigned as part of object construction will not cause the handler to be invoked. See Also -------- observe : A newer API for defining traits notifications. """ def decorator(function): function.on_trait_change = { "pattern": name, "post_init": post_init, "dispatch": dispatch, } return function return decorator def cached_property(function): """ Marks the following method definition as being a "cached property". That is, it is a property getter which, for performance reasons, caches its most recently computed result in an attribute whose name is of the form: *_traits_cache_name*, where *name* is the name of the property. A method marked as being a cached property needs only to compute and return its result. The @cached_property decorator automatically wraps the decorated method in cache management code, eliminating the need to write boilerplate cache management code explicitly. For example:: file_name = File file_contents = Property(observe='file_name') @cached_property def _get_file_contents(self): with open(self.file_name, 'rb') as fh: return fh.read() In this example, accessing the *file_contents* trait calls the _get_file_contents() method only once each time after the **file_name** trait is modified. In all other cases, the cached value **_file_contents**, which maintained by the @cached_property wrapper code, is returned. Note the use, in the example, of the **observe** metadata attribute to specify that the value of **file_contents** depends on **file_name**, so that _get_file_contents() is called only when **file_name** changes. For details, see the traits.traits.Property() function. """ name = TraitsCache + function.__name__[5:] def decorator(self): result = self.__dict__.get(name, Undefined) if result is Undefined: self.__dict__[name] = result = function(self) return result decorator.cached_property = True return decorator def property_depends_on(dependency, settable=False, flushable=False): """ Marks the following method definition as being a "cached property" that depends on the specified extended trait names. That is, it is a property getter which, for performance reasons, caches its most recently computed result in an attribute whose name is of the form: *_traits_cache_name*, where *name* is the name of the property. A method marked as being a cached property needs only to compute and return its result. The @property_depends_on decorator automatically wraps the decorated method in cache management code that will cache the most recently computed value and flush the cache when any of the specified dependencies are modified, thus eliminating the need to write boilerplate cache management code explicitly. For example:: file_name = File file_contents = Property @property_depends_on( 'file_name' ) def _get_file_contents(self): with open(self.file_name, 'rb') as fh: return fh.read() In this example, accessing the *file_contents* trait calls the _get_file_contents() method only once each time after the **file_name** trait is modified. In all other cases, the cached value **_file_contents**, which is maintained by the @cached_property wrapper code, is returned. """ def decorator(function): name = TraitsCache + function.__name__[5:] def wrapper(self): result = self.__dict__.get(name, Undefined) if result is Undefined: self.__dict__[name] = result = function(self) return result wrapper.cached_property = True wrapper.depends_on = dependency wrapper.settable = settable wrapper.flushable = flushable return wrapper return decorator def weak_arg(arg): """ Create a weak reference to arg and wrap the function so that the dereferenced weakref is passed as the first argument. If arg has been deleted then the function is not called. """ # Create the weak reference weak_arg = weakref.ref(arg) def decorator(function): # We need multiple wrappers to traits can find the number of arguments. # The all just dereference the weak reference and the call the # function if it is not None. def wrapper0(): arg = weak_arg() if arg is not None: return function(arg) def wrapper1(arg1): arg = weak_arg() if arg is not None: return function(arg, arg1) def wrapper2(arg1, arg2): arg = weak_arg() if arg is not None: return function(arg, arg1, arg2) def wrapper3(arg1, arg2, arg3): arg = weak_arg() if arg is not None: return function(arg, arg1, arg2, arg3) def wrapper4(arg1, arg2, arg3, arg4): arg = weak_arg() if arg is not None: return function(arg, arg1, arg2, arg3, arg4) def wrappern(*args): arg = weak_arg() if arg is not None: function(arg, *args) # Return the correct wrapper depending on the arg count args = function.__code__.co_argcount - 1 if args == 0: return wrapper0 elif args == 1: return wrapper1 elif args == 2: return wrapper2 elif args == 3: return wrapper3 elif args == 4: return wrapper4 else: return wrappern return decorator class HasTraits(CHasTraits, metaclass=MetaHasTraits): """ Enables any Python class derived from it to have trait attributes. Most of the methods of HasTraits operated by default only on the trait attributes explicitly defined in the class definition. They do not operate on trait attributes defined by way of wildcards or by calling **add_trait()**. For example:: >>> class Person(HasTraits): ... name = Str ... age = Int ... temp_ = Any >>> bob = Person() >>> bob.temp_lunch = 'sandwich' >>> bob.add_trait('favorite_sport', Str('football')) >>> print(bob.trait_names()) ['trait_added', 'age', 'name'] In this example, the trait_names() method returns only the *age* and *name* attributes defined on the Person class. (The **trait_added** attribute is an explicit trait event defined on the HasTraits class.) The wildcard attribute *temp_lunch* and the dynamically-added trait attribute *favorite_sport* are not listed. Subclass should avoid defining new traits and/or methods with names starting with "trait" or "_trait" to avoid overshadowing existing methods, unless it has been documented as being safe to do so. """ # -- Trait Prefix Rules --------------------------------------------------- #: Make traits 'property cache' values private with no type checking: _traits_cache__ = Any(private=True, transient=True) # -- Class Variables ------------------------------------------------------ #: Mapping from dispatch type to notification wrapper class type wrappers = { "same": TraitChangeNotifyWrapper, "extended": ExtendedTraitChangeNotifyWrapper, "new": NewTraitChangeNotifyWrapper, "fast_ui": FastUITraitChangeNotifyWrapper, "ui": FastUITraitChangeNotifyWrapper, } # -- Trait Definitions ---------------------------------------------------- #: An event fired when a new trait is dynamically added to the object. The #: value is the name of the trait that was added. trait_added = Event(Str()) #: An event that can be fired to indicate that the state of the object has #: been modified. trait_modified = Event() def _trait_added_changed(self, name): """ Handles a 'trait_added' event being fired. """ # fixme: This test should be made more comprehensive by also verifying # that if the trait name does end in '_items', its base trait is also # a list or dictionary (in order to eliminate a false positive on an # unfortunately named trait: trait = self.trait(name) if (trait.type == "delegate") and (name[-6:] != "_items"): self._init_trait_delegate_listener( name, "delegate", get_delegate_pattern(name, trait) ) @classmethod def add_class_trait(cls, name, *trait): """ Adds a named trait attribute to this class. Also adds the same attribute to all subclasses. Parameters ---------- name : str Name of the attribute to add. *trait : A trait or a value that can be converted to a trait using Trait() Trait definition of the attribute. It can be a single value or a list equivalent to an argument list for the Trait() function. """ # Make sure a trait argument was specified: if len(trait) == 0: raise ValueError("No trait definition was specified.") # Make sure only valid traits get added: if len(trait) > 1: trait = Trait(*trait) else: trait = trait_for(trait[0]) # Add the trait to the class: cls._add_class_trait(name, trait, is_subclass=False) # Also add the trait to all subclasses of this class: for subclass in cls.trait_subclasses(True): subclass._add_class_trait(name, trait, is_subclass=True) @classmethod def _add_class_trait(cls, name, trait, is_subclass): """ Add a named trait attribute to this class. Does not affect subclasses. Parameters ---------- name : str Name of the attribute to add. trait : CTrait The trait to be added. is_subclass : bool True if we're adding the trait to a strict subclass of the original class that add_class_trait was called for. This is used to decide how to behave if ``cls`` already has a trait named ``name``: in that circumstance, if ``is_subclass`` is False, an error will be raised, while if ``is_subclass`` is True, no trait will be added. Raises ------ TraitError If a trait with the given name already exists, and is_subclass is ``False``. """ # Get a reference to the class's dictionary and 'prefix' traits: class_dict = cls.__dict__ prefix_traits = class_dict[PrefixTraits] # See if the trait is a 'prefix' trait: if name[-1:] == "_": name = name[:-1] if name in prefix_traits: if is_subclass: return raise TraitError("The '%s_' trait is already defined." % name) prefix_traits[name] = trait # Otherwise, add it to the list of known prefixes: prefix_list = prefix_traits["*"] prefix_list.append(name) # Resort the list from longest to shortest: prefix_list.sort(key=len, reverse=True) return # Check to see if the trait is already defined: class_traits = class_dict[ClassTraits] if class_traits.get(name) is not None: if is_subclass: return raise TraitError("The '%s' trait is already defined." % name) # Check to see if the trait has additional sub-traits that need to be # defined also: handler = trait.handler if handler is not None: if handler.has_items: cls._add_class_trait( name + "_items", handler.items_event(), is_subclass=is_subclass, ) if handler.is_mapped: cls._add_class_trait( name + "_", mapped_trait_for(trait, name), is_subclass=is_subclass, ) # Make the new trait inheritable (if allowed): if trait.is_base is not False: class_dict[BaseTraits][name] = trait # See if there are any static notifiers defined: handlers = [ _get_method(cls, "_%s_changed" % name), _get_method(cls, "_%s_fired" % name), ] # Add any special trait defined event handlers: _add_event_handlers(trait, cls, handlers) # Add the 'anytrait' handler (if any): handlers.append(prefix_traits.get("@")) # Filter out any 'None' values: handlers = [h for h in handlers if h is not None] # If there are and handlers, add them to the trait's notifier's list: if len(handlers) > 0: trait = _clone_trait(trait) _add_notifiers(trait._notifiers(True), handlers) # Finally, add the new trait to the class trait dictionary: class_traits[name] = trait @classmethod def set_trait_dispatch_handler(cls, name, klass, override=False): """ Sets a trait notification dispatch handler. """ try: if issubclass(klass, TraitChangeNotifyWrapper): if (not override) and (name in cls.wrappers): raise TraitError( "A dispatch handler called '%s' has " "already been defined." % name ) cls.wrappers[name] = klass return except TypeError: pass raise TraitError( "%s is not a subclass of TraitChangeNotifyWrapper." % klass ) @classmethod def trait_subclasses(cls, all=False): """ Returns a list of the immediate (or all) subclasses of this class. Parameters ---------- all : bool Indicates whether to return all subclasses of this class. If False, only immediate subclasses are returned. """ if not all: return cls.__subclasses__() return cls._trait_subclasses([]) @classmethod def _trait_subclasses(cls, subclasses): for subclass in cls.__subclasses__(): if subclass not in subclasses: subclasses.append(subclass) subclass._trait_subclasses(subclasses) return subclasses def has_traits_interface(self, *interfaces): """Returns whether the object implements a specified traits interface. Tests whether the object implements one or more of the interfaces specified by *interfaces*. Return **True** if it does, and **False** otherwise. Parameters ---------- *interfaces : One or more traits Interface (sub)classes. """ return isinstance(self, interfaces) def __getstate__(self): """ Returns a dictionary of traits to pickle. In general, avoid overriding __getstate__ in subclasses. Instead, mark traits that should not be pickled with 'transient = True' metadata. In cases where this strategy is not sufficient, override __getstate__ in subclasses using the following pattern to remove items that should not be persisted:: def __getstate__(self): state = super().__getstate__() for key in ['foo', 'bar']: if key in state: del state[key] return state """ # Save all traits which do not have any 'transient' metadata: result = self.trait_get(transient=is_none) # Add all delegate traits that explicitly have 'transient = False' # metadata: dic = self.__dict__ result.update( dict( [ (name, dic[name]) for name in self.trait_names( type="delegate", transient=False ) if name in dic ] ) ) # If this object implements ISerializable, make sure that all # contained HasTraits objects in its persisted state also implement # ISerializable: if self.has_traits_interface(ISerializable): for name, value in result.items(): if not _is_serializable(value): raise TraitError( "The '%s' trait of a '%s' instance " "contains the unserializable value: %s" % (name, self.__class__.__name__, value) ) # Store the traits version in the state dictionary (if possible): result.setdefault("__traits_version__", TraitsVersion) # Return the final state dictionary: return result def __reduce_ex__(self, protocol): return (__newobj__, (self.__class__,), self.__getstate__()) def __setstate__(self, state, trait_change_notify=True): """ Restores the previously pickled state of an object. """ pop = state.pop if pop("__traits_version__", None) is None: # If the state was saved by a version of Traits prior to 3.0, then # use Traits 2.0 compatible code to restore it: values = [ (name, pop(name)) for name in pop("__HasTraits_restore__", []) ] self.__dict__.update(state) self.trait_set( trait_change_notify=trait_change_notify, **dict(values) ) else: # Otherwise, apply the Traits 3.0 restore logic: self._init_trait_listeners() self._init_trait_observers() self.trait_set(trait_change_notify=trait_change_notify, **state) self._post_init_trait_listeners() self._post_init_trait_observers() self.traits_init() self._trait_set_inited() def trait_get(self, *names, **metadata): """ Retrieve trait values for one or more traits. This function can be called in one of three ways. In the first form, the user passes the names of one or more traits to be retrieved:: my_object.trait_get("trait_name1", "trait_name2") In the second form, the user passes a list of zero or more names of traits:: my_object.trait_get(["trait_name1", "trait_name2"]) In the final form, no trait names are passed, and all trait names and trait values are returned, subject to the given metadata filters:: my_object.trait_get(transient=True, frombicated=False) In all cases, a dictionary mapping trait names to trait values is returned. For the first two forms, if any name does not correspond to a defined trait, it is not included in the result. Parameters ---------- *names Names of the traits to look up, or a single positional argument providing a sequence of trait names. **metadata Metadata information used to filter the traits to return. This information is used only when no names are provided. Returns ------- result : dict A dictionary mapping the selected trait names to their corresponding values. """ result = {} n = len(names) if (n == 1) and (type(names[0]) in SequenceTypes): names = names[0] elif n == 0: names = self.trait_names(**metadata) # Sentinel for missing attributes. missing = object() for name in names: value = getattr(self, name, missing) if value is not missing: result[name] = value return result # Defines the deprecated alias for 'trait_get' @deprecated('use "HasTraits.trait_get" instead') def get(self, *names, **metadata): return self.trait_get(*names, **metadata) get.__doc__ = trait_get.__doc__ def trait_set(self, trait_change_notify=True, **traits): """ Shortcut for setting object trait attributes. Treats each keyword argument to the method as the name of a trait attribute and sets the corresponding trait attribute to the value specified. This is a useful shorthand when a number of trait attributes need to be set on an object, or a trait attribute value needs to be set in a lambda function. For example, you can write:: person.trait_set(name='Bill', age=27) instead of:: person.name = 'Bill' person.age = 27 Parameters ---------- trait_change_notify : bool If **True** (the default), then each value assigned may generate a trait change notification. If **False**, then no trait change notifications will be generated. (see also: trait_setq) **traits : Key/value pairs, the trait attributes and their values to be set Returns ------- self : The method returns this object, after setting attributes. """ if not trait_change_notify: self._trait_change_notify(False) try: for name, value in traits.items(): setattr(self, name, value) finally: self._trait_change_notify(True) else: for name, value in traits.items(): setattr(self, name, value) return self # Defines the deprecated alias for 'trait_set' @deprecated('use "HasTraits.trait_set" instead') def set(self, trait_change_notify=True, **traits): return self.trait_set( trait_change_notify=trait_change_notify, **traits ) set.__doc__ = trait_set.__doc__ def trait_setq(self, **traits): """ Shortcut for setting object trait attributes. Treats each keyword argument to the method as the name of a trait attribute and sets the corresponding trait attribute to the value specified. This is a useful shorthand when a number of trait attributes need to be set on an object, or a trait attribute value needs to be set in a lambda function. For example, you can write:: person.trait_setq(name='Bill', age=27) instead of:: person.name = 'Bill' person.age = 27 Parameters ---------- **traits : Key/value pairs, the trait attributes and their values to be set. No trait change notifications will be generated for any values assigned (see also: trait_set). Returns ------- self : The method returns this object, after setting attributes. """ return self.trait_set(trait_change_notify=False, **traits) def reset_traits(self, traits=None, **metadata): """ Resets some or all of an object's trait attributes to their default values. Resets each of the traits whose names are specified in the *traits* list to their default values. If *traits* is None or omitted, the method resets all explicitly-defined object trait attributes to their default values. Note that this does not affect wildcard trait attributes or trait attributes added via add_trait(), unless they are explicitly named in *traits*. Parameters ---------- traits : list of strings Names of trait attributes to reset. Returns ------- unresetable : list of strings A list of attributes that the method was unable to reset, which is empty if all the attributes were successfully reset. """ unresetable = [] if traits is None: traits = self.trait_names(**metadata) for name in traits: try: delattr(self, name) except (AttributeError, TraitError): unresetable.append(name) return unresetable def copyable_trait_names(self, **metadata): """ Returns the list of trait names to copy or clone by default. """ metadata.setdefault("transient", lambda t: t is not True) return self.trait_names(**metadata) def all_trait_names(self): """ Returns the list of all trait names, including implicitly defined traits. """ return list(self.__class_traits__.keys()) def __dir__(self): """ Returns the list of trait names when calling the dir() builtin on the object. This enables tab-completion in IPython. """ return super().__dir__() + self.trait_names() def copy_traits( self, other, traits=None, memo=None, copy=None, **metadata ): """ Copies another object's trait attributes into this one. Parameters ---------- other : object The object whose trait attribute values should be copied. traits : list of strings A list of names of trait attributes to copy. If None or unspecified, the set of names returned by trait_names() is used. If 'all' or an empty list, the set of names returned by all_trait_names() is used. memo : dict A dictionary of objects that have already been copied. copy : None | 'deep' | 'shallow' The type of copy to perform on any trait that does not have explicit 'copy' metadata. A value of None means 'copy reference'. Returns ------- unassignable : list of strings A list of attributes that the method was unable to copy, which is empty if all the attributes were successfully copied. """ if traits is None: traits = self.copyable_trait_names(**metadata) elif (traits == "all") or (len(traits) == 0): traits = self.all_trait_names() if memo is not None: memo["traits_to_copy"] = "all" unassignable = [] deferred = [] deep_copy = copy == "deep" shallow_copy = copy == "shallow" for name in traits: try: trait = self.trait(name) if trait.type in DeferredCopy: deferred.append(name) continue base_trait = other.base_trait(name) if base_trait.type == "event": continue value = getattr(other, name) copy_type = base_trait.copy if copy_type == "shallow": value = copy_module.copy(value) elif copy_type == "ref": pass elif (copy_type == "deep") or deep_copy: if memo is None: value = copy_module.deepcopy(value) else: value = copy_module.deepcopy(value, memo) elif shallow_copy: value = copy_module.copy(value) setattr(self, name, value) except: unassignable.append(name) for name in deferred: try: value = getattr(other, name) copy_type = other.base_trait(name).copy if copy_type == "shallow": value = copy_module.copy(value) elif copy_type == "ref": pass elif (copy_type == "deep") or deep_copy: if memo is None: value = copy_module.deepcopy(value) else: value = copy_module.deepcopy(value, memo) elif shallow_copy: value = copy_module.copy(value) setattr(self, name, value) except: unassignable.append(name) return unassignable def clone_traits(self, traits=None, memo=None, copy=None, **metadata): """ Clones a new object from this one, optionally copying only a specified set of traits. Creates a new object that is a clone of the current object. If *traits* is None (the default), then all explicit trait attributes defined for this object are cloned. If *traits* is 'all' or an empty list, the list of traits returned by all_trait_names() is used; otherwise, *traits* must be a list of the names of the trait attributes to be cloned. Parameters ---------- traits : list of strings The list of names of the trait attributes to copy. memo : dict A dictionary of objects that have already been copied. copy : str The type of copy ``deep`` or ``shallow`` to perform on any trait that does not have explicit 'copy' metadata. A value of None means 'copy reference'. Returns ------- new : The newly cloned object. """ if memo is None: memo = {} if traits is None: traits = self.copyable_trait_names(**metadata) elif (traits == "all") or (len(traits) == 0): traits = self.all_trait_names() memo["traits_to_copy"] = "all" memo["traits_copy_mode"] = copy new = self.__new__(self.__class__) memo[id(self)] = new new._init_trait_listeners() new._init_trait_observers() new.copy_traits(self, traits, memo, copy, **metadata) new._post_init_trait_listeners() new._post_init_trait_observers() new.traits_init() new._trait_set_inited() return new def __deepcopy__(self, memo): """ Creates a deep copy of the object. """ return self.clone_traits( memo=memo, traits=memo.get("traits_to_copy"), copy=memo.get("traits_copy_mode"), ) def edit_traits( self, view=None, parent=None, kind=None, context=None, handler=None, id="", scrollable=None, **args ): """ Displays a user interface window for editing trait attribute values. Parameters ---------- view : View or string A View object (or its name) that defines a user interface for editing trait attribute values of the current object. If the view is defined as an attribute on this class, use the name of the attribute. Otherwise, use a reference to the view object. If this attribute is not specified, the View object returned by trait_view() is used. parent : toolkit control The reference to a user interface component to use as the parent window for the object's UI window. kind : str The type of user interface window to create. See the **traitsui.view.kind_trait** trait for values and their meanings. If *kind* is unspecified or None, the **kind** attribute of the View object is used. context : object or dictionary A single object or a dictionary of string/object pairs, whose trait attributes are to be edited. If not specified, the current object is used. handler : Handler A handler object used for event handling in the dialog box. If None, the default handler for Traits UI is used. id : str A unique ID for persisting preferences about this user interface, such as size and position. If not specified, no user preferences are saved. scrollable : bool Indicates whether the dialog box should be scrollable. When set to True, scroll bars appear on the dialog box if it is not large enough to display all of the items in the view at one time. Returns ------- A UI object. """ if context is None: context = self view = self.trait_view(view) return view.ui( context, parent, kind, self.trait_view_elements(), handler, id, scrollable, args, ) def trait_context(self): """ Returns the default context to use for editing or configuring traits. """ return {"object": self} def trait_view(self, name=None, view_element=None): """ Gets or sets a ViewElement associated with an object's class. If both *name* and *view_element* are specified, the view element is associated with *name* for the current object's class. (That is, *view_element* is added to the ViewElements object associated with the current object's class, indexed by *name*.) If only *name* is specified, the function returns the view element object associated with *name*, or None if *name* has no associated view element. View elements retrieved by this function are those that are bound to a class attribute in the class definition, or that are associated with a name by a previous call to this method. If neither *name* nor *view_element* is specified, the method returns a View object, based on the following order of preference: 1. If there is a View object named ``traits_view`` associated with the current object, it is returned. 2. If there is exactly one View object associated the current object, it is returned. 3. Otherwise, it returns a View object containing items for all the non-event trait attributes on the current object. Parameters ---------- name : str Name of a view element view_element : ViewElement View element to associate Returns ------- A view element. """ return self.__class__._trait_view( name, view_element, self.default_traits_view, self.trait_view_elements, self.visible_traits, self, ) @classmethod def class_trait_view(cls, name=None, view_element=None): return cls._trait_view( name, view_element, cls.class_default_traits_view, cls.class_trait_view_elements, cls.class_visible_traits, None, ) @classmethod def _trait_view( cls, name, view_element, default_name, view_elements, trait_selector_f, handler, ): """ Gets or sets a ViewElement associated with an object's class. """ # If a view element was passed instead of a name or None, return it: if isinstance(name, AbstractViewElement): return name # Get the ViewElements object associated with the class: view_elements = view_elements() # The following test should only succeed for objects created before # traits has been fully initialized (such as the default Handler): if view_elements is None: return None # Provide a nicer failure mode when upgrading to Traits using # TraitsUI 6.x check_traitsui_major_version(7) if name: if view_element is None: # If only a name was specified, return the ViewElement it # matches, if any: result = view_elements.find(name) if (result is None) and (handler is not None): method = getattr(handler, name, None) if callable(method): result = method() return result # Otherwise, save the specified ViewElement under the name # specified: view_elements.content[name] = view_element return None # Get the default view/view name: name = default_name() # If the default is a View, return it: if isinstance(name, AbstractViewElement): return name # Otherwise, get all View objects associated with the object's class: names = view_elements.filter_by() # If the specified default name is in the list, return its View: if name in names: return view_elements.find(name) if handler is not None: method = getattr(handler, name, None) if callable(method): result = method() if isinstance(result, AbstractViewElement): return result # If there is only one View, return it: if len(names) == 1: return view_elements.find(names[0]) # Otherwise, create and return a View based on the set of editable # traits defined for the object: from traitsui.api import View return View(trait_selector_f(), buttons=["OK", "Cancel"]) def default_traits_view(self): """ Returns the name of the default traits view for the object's class. """ return self.__class__.class_default_traits_view() @classmethod def class_default_traits_view(cls): """ Returns the name of the default traits view for the class. """ return DefaultTraitsView def trait_views(self, klass=None): """ Returns a list of the names of all view elements associated with the current object's class. If *klass* is specified, the list of names is filtered such that only objects that are instances of the specified class are returned. Parameters ---------- klass : class A class, such that all returned names must correspond to instances of this class. Possible values include: * Group * Item * View * ViewElement * ViewSubElement """ view_elements = self.__class__.__dict__[ViewTraits] if isinstance(view_elements, dict): view_elements = self._init_trait_view_elements() return view_elements.filter_by(klass) def trait_view_elements(self): """ Returns the ViewElements object associated with the object's class. The returned object can be used to access all the view elements associated with the class. """ return self.__class__.class_trait_view_elements() @classmethod def class_trait_view_elements(cls): """ Returns the ViewElements object associated with the class. The returned object can be used to access all the view elements associated with the class. """ view_elements = cls.__dict__[ViewTraits] if isinstance(view_elements, dict): view_elements = cls._init_trait_view_elements() return view_elements @classmethod def _init_trait_view_elements(cls): """ Lazily Initialize the ViewElements object from a dictionary. """ from traitsui.view_elements import ViewElements hastraits_bases = [ base for base in cls.__bases__ if ClassTraits in base.__dict__ ] view_elements = ViewElements() elements_dict = cls.__dict__[ViewTraits] for name, element in elements_dict.items(): # Add the view element to the class's 'ViewElements' if it is # not already defined (duplicate definitions are errors): if name in view_elements.content: raise TraitError( "Duplicate definition for view element '%s'" % name ) view_elements.content[name] = element # Replace all substitutable view sub elements with 'Include' # objects, and add the substituted items to the # 'ViewElements': element.replace_include(view_elements) for base in hastraits_bases: # If the base class has a 'ViewElements' object defined, add it to # the 'parents' list of this class's 'ViewElements': parent_view_elements = base.class_trait_view_elements() if parent_view_elements is not None: view_elements.parents.append(parent_view_elements) setattr(cls, ViewTraits, view_elements) return view_elements def configure_traits( self, filename=None, view=None, kind=None, edit=None, context=None, handler=None, id="", scrollable=None, **args ): ### JMS: Is it correct to assume that non-modal options for 'kind' ### behave modally when called from this method? """Creates and displays a dialog box for editing values of trait attributes, as if it were a complete, self-contained GUI application. This method is intended for use in applications that do not normally have a GUI. Control does not resume in the calling application until the user closes the dialog box. The method attempts to open and unpickle the contents of *filename* before displaying the dialog box. When editing is complete, the method attempts to pickle the updated contents of the object back to *filename*. If the file referenced by *filename* does not exist, the object is not modified before displaying the dialog box. If *filename* is unspecified or None, no pickling or unpickling occurs. If *edit* is True (the default), a dialog box for editing the current object is displayed. If *edit* is False or None, no dialog box is displayed. You can use ``edit=False`` if you want the object to be restored from the contents of *filename*, without being modified by the user. Parameters ---------- filename : str The name (including path) of a file that contains a pickled representation of the current object. When this parameter is specified, the method reads the corresponding file (if it exists) to restore the saved values of the object's traits before displaying them. If the user confirms the dialog box (by clicking **OK**), the new values are written to the file. If this parameter is not specified, the values are loaded from the in-memory object, and are not persisted when the dialog box is closed. .. deprecated:: 6.0.0 view : View or str A View object (or its name) that defines a user interface for editing trait attribute values of the current object. If the view is defined as an attribute on this class, use the name of the attribute. Otherwise, use a reference to the view object. If this attribute is not specified, the View object returned by trait_view() is used. kind : str The type of user interface window to create. See the **traitsui.view.kind_trait** trait for values and their meanings. If *kind* is unspecified or None, the **kind** attribute of the View object is used. edit : bool Indicates whether to display a user interface. If *filename* specifies an existing file, setting *edit* to False loads the saved values from that file into the object without requiring user interaction. .. deprecated:: 6.2.0 context : object or dictionary A single object or a dictionary of string/object pairs, whose trait attributes are to be edited. If not specified, the current object is used handler : Handler A handler object used for event handling in the dialog box. If None, the default handler for Traits UI is used. id : str A unique ID for persisting preferences about this user interface, such as size and position. If not specified, no user preferences are saved. scrollable : bool Indicates whether the dialog box should be scrollable. When set to True, scroll bars appear on the dialog box if it is not large enough to display all of the items in the view at one time. Returns ------- True on success. """ if filename is not None: message = ('Restoring from pickle will not be supported starting ' 'with traits 7.0.0') warnings.warn(message, DeprecationWarning) if os.path.exists(filename): with open(filename, "rb") as fd: self.copy_traits(pickle.Unpickler(fd).load()) if edit is None: edit = True else: message = ( 'The edit argument to configure_traits is ' 'deprecated, and will be removed in Traits 7.0.0' ) warnings.warn(message, DeprecationWarning) if edit: from traitsui.api import toolkit if context is None: context = self rc = toolkit().view_application( context, self.trait_view(view), kind, handler, id, scrollable, args, ) if rc and (filename is not None): with open(filename, "wb") as fd: pickle.Pickler(fd, protocol=3).dump(self) return rc return True def editable_traits(self): """Returns an alphabetically sorted list of the names of non-event trait attributes associated with the current object. """ names = self.trait_names(type=not_event, editable=not_false) names.sort() return names @classmethod def class_editable_traits(cls): """Returns an alphabetically sorted list of the names of non-event trait attributes associated with the current class. """ names = cls.class_trait_names(type=not_event, editable=not_false) names.sort() return names def visible_traits(self): """Returns an alphabetically sorted list of the names of non-event trait attributes associated with the current object, that should be GUI visible """ return self.trait_names(type=not_event, visible=not_false) @classmethod def class_visible_traits(cls): """Returns an alphabetically sorted list of the names of non-event trait attributes associated with the current class, that should be GUI visible """ return cls.class_trait_names(type=not_event, visible=not_false) def print_traits(self, show_help=False, **metadata): """Prints the values of all explicitly-defined, non-event trait attributes on the current object, in an easily readable format. Parameters ---------- show_help : bool Indicates whether to display additional descriptive information. """ if len(metadata) > 0: names = self.trait_names(**metadata) else: names = self.trait_names(type=not_event) if len(names) == 0: print("") return result = [] pad = max([len(x) for x in names]) + 1 maxval = 78 - pad names.sort() for name in names: try: value = repr(getattr(self, name)).replace("\n", "\\n") if len(value) > maxval: value = "%s...%s" % ( value[:(maxval - 2) // 2], value[-((maxval - 3) // 2):], ) except: value = "" lname = (name + ":").ljust(pad) if show_help: result.append( "%s %s\n The value must be %s." % (lname, value, self.base_trait(name).setter.info()) ) else: result.append("%s %s" % (lname, value)) print("\n".join(result)) def _on_trait_change( self, handler, name=None, remove=False, dispatch="same", priority=False, target=None, ): """Causes the object to invoke a handler whenever a trait attribute is modified, or removes the association. Multiple handlers can be defined for the same object, or even for the same trait attribute on the same object. If *name* is not specified or is None, *handler* is invoked when any trait attribute on the object is changed. Parameters ---------- handler : function A trait notification function for the attribute specified by *name*. name : str Specifies the trait attribute whose value changes trigger the notification. remove : bool If True, removes the previously-set association between *handler* and *name*; if False (the default), creates the association. """ if type(name) is list: for name_i in name: self._on_trait_change( handler, name_i, remove, dispatch, priority, target ) return name = name or "anytrait" if remove: if name == "anytrait": notifiers = self._notifiers(False) else: trait = self._trait(name, 1) if trait is None: return notifiers = trait._notifiers(False) if notifiers is not None: for i, notifier in enumerate(notifiers): if notifier.equals(handler): del notifiers[i] notifier.dispose() break return if name == "anytrait": notifiers = self._notifiers(True) else: notifiers = self._trait(name, 2)._notifiers(True) for notifier in notifiers: if notifier.equals(handler): break else: wrapper = self.wrappers[dispatch](handler, notifiers, target) if priority: notifiers.insert(0, wrapper) else: notifiers.append(wrapper) def observe(self, handler, expression, *, remove=False, dispatch="same"): """ Causes the object to invoke a handler whenever a trait attribute matching a specified pattern is modified, or removes the association. The *expression* parameter can be a single string or an Expression object. A list of expressions is also accepted. When *expression* is a string, its content should follow Traits Mini Language semantics: ============================== ====================================== Expression Meaning ============================== ====================================== ``item1.item2`` Observes trait *item2* on the object under trait *item1*. Changes to either *item1* or *item2* cause a notification to be fired. ``item1:item2`` Similar to the above, except changes to *item1* will not fire events (the ':' indicates no notifications). ``[item1, item2, ..., itemN]`` A list which matches any of the specified items. Each item can itself be an expression. ``items`` Special keyword for observing a trait named *items* or items inside a list / dict / set. ``+metadata_name`` Matches any trait on the object having *metadata_name* metadata. ============================== ====================================== All spaces will be ignored. The :py:class:`ObserverExpression` object supports the above features and more. Parameters ---------- handler : callable(event) A callable that will be invoked when the observed trait changes. It must accept one argument, which is an event object providing information about the change. See :py:mod:`traits.observation.events` for details. expression : str or list or ObserverExpression A description of what traits are being observed. If this is a list, each item must be a string or an Expression. remove : boolean, optional Whether to remove the event handler. Default is to add the event handler. dispatch : str, optional A string indicating how the handler should be run. Default is to run on the same thread where the change occurs. Possible values are: =========== ======================================================= value dispatch =========== ======================================================= ``same`` Run notifications on the same thread where the change occurs. The notifications are executed immediately. ``ui`` Run notifications on the UI thread. If the current thread is the UI thread, the notifications are executed immediately; otherwise, they are placed on the UI event queue. =========== ======================================================= Raises ------ NotifierNotFound When attempting to remove a handler that doesn't exist. """ graphs = _compile_expression(expression) observe_api.apply_observers( object=self, graphs=graphs, handler=handler, dispatcher=_ObserverDispatchers[dispatch], remove=remove, ) def on_trait_change( self, handler, name=None, remove=False, dispatch="same", priority=False, deferred=False, target=None, ): """Causes the object to invoke a handler whenever a trait attribute matching a specified pattern is modified, or removes the association. Multiple handlers can be defined for the same object, or even for the same trait attribute on the same object. If *name* is not specified or is None, *handler* is invoked when any trait attribute on the object is changed. The *name* parameter is a single *xname* or a list of *xname* names, where an *xname* is an extended name of the form:: xname2[('.'|':') xname2]* An *xname2* is of the form:: ( xname3 | '['xname3[','xname3]*']' ) ['*'] An *xname3* is of the form:: xname | ['+'|'-'][name] | name['?' | ('+'|'-')[name]] A *name* is any valid Python attribute name. The semantic meaning of this notation is as follows: ================================ ====================================== expression meaning ================================ ====================================== ``item1.item2`` means *item1* is a trait containing an object (or objects if *item1* is a list or dict) with a trait called *item2*. Changes to either *item1* or *item2* cause a notification to be generated. ``item1:item2`` means *item1* is a trait containing an object (or objects if *item1* is a list or dict) with a trait called *item2*. Changes to *item2* cause a notification to be generated, while changes to *item1* do not (i.e., the ':' indicates that changes to the *link* object should not be reported). ``[ item1, item2, ..., itemN ]`` A list which matches any of the specified items. Note that at the topmost level, the surrounding square brackets are optional. ``name?`` If the current object does not have an attribute called *name*, the reference can be ignored. If the '?' character is omitted, the current object must have a trait called *name*, otherwise an exception will be raised. ``prefix+`` Matches any trait on the object whose name begins with *prefix*. ``+metadata_name`` Matches any trait on the object having *metadata_name* metadata. ``-metadata_name`` Matches any trait on the object which does not have *metadata_name* metadata. ``prefix+metadata_name`` Matches any trait on the object whose name begins with *prefix* and which has *metadata_name* metadata. ``prefix-metadata_name`` Matches any trait on the object whose name begins with *prefix* and which does not have *metadata_name* metadata. ``+`` Matches all traits on the object. ``pattern*`` Matches object graphs where *pattern* occurs one or more times (useful for setting up listeners on recursive data structures like trees or linked lists). ================================ ====================================== Some examples of valid names and their meaning are as follows: ======================= =============================================== example meaning ======================= =============================================== ``foo,bar,baz`` Listen for trait changes to *object.foo*, *object.bar*, and *object.baz*. ``['foo','bar','baz']`` Equivalent to 'foo,bar,baz', but may be more useful in cases where the individual items are computed. ``foo.bar.baz`` Listen for trait changes to *object.foo.bar.baz* and report changes to *object.foo*, *object.foo.bar* or *object.foo.bar.baz*. ``foo:bar:baz`` Listen for changes to *object.foo.bar.baz*, and only report changes to *object.foo.bar.baz*. ``foo.[bar,baz]`` Listen for trait changes to *object.foo.bar* and *object.foo.baz*. ``[left,right]*.name`` Listen for trait changes to the *name* trait of each node of a tree having *left* and *right* links to other tree nodes, and where *object* the method is applied to the root node of the tree. ``+dirty`` Listen for trait changes on any trait in the *object* which has the 'dirty' metadata set. ``foo.+dirty`` Listen for trait changes on any trait in *object.foo* which has the 'dirty' metadata set. ``foo.[bar,-dirty]`` Listen for trait changes on *object.foo.bar* or any trait on *object.foo* which does not have 'dirty' metadata set. ======================= =============================================== Note that any of the intermediate (i.e., non-final) links in a pattern can be traits of type Instance, List or Dict. In the case of List and Dict traits, the subsequent portion of the pattern is applied to each item in the list, or value in the dictionary. For example, if the self.children is a list, 'children.name' listens for trait changes to the *name* trait for each item in the self.children list. Note that items added to or removed from a list or dictionary in the pattern will cause the *handler* routine to be invoked as well, since this is treated as an *implied* change to the item's trait being monitored. The signature of the *handler* supplied also has an effect on how changes to intermediate traits are processed. The five valid handler signatures are: 1. handler() 2. handler(new) 3. handler(name,new) 4. handler(object,name,new) 5. handler(object,name,old,new) For signatures 1, 4 and 5, any change to any element of a path being listened to invokes the handler with information about the particular element that was modified (e.g., if the item being monitored is 'foo.bar.baz', a change to 'bar' will call *handler* with the following information: - object: object.foo - name: bar - old: old value for object.foo.bar - new: new value for object.foo.bar If one of the intermediate links is a List or Dict, the call to *handler* may report an *_items* changed event. If in the previous example, *bar* is a List, and a new item is added to *bar*, then the information passed to *handler* would be: - object: object.foo - name: bar_items - old: Undefined - new: TraitListEvent whose *added* trait contains the new item added to *bar*. For signatures 2 and 3, the *handler* does not receive enough information to discern between a change to the final trait being listened to and a change to an intermediate link. In this case, the event dispatcher will attempt to map a change to an intermediate link to its effective change on the final trait. This only works if all of the intermediate links are single values (such as an Instance or Any trait) and not Lists or Dicts. If the modified intermediate trait or any subsequent intermediate trait preceding the final trait is a List or Dict, then a TraitError is raised, since the effective value for the final trait cannot in general be resolved unambiguously. To prevent TraitErrors in this case, use the ':' separator to suppress notifications for changes to any of the intermediate links. Handler signature 1 also has the special characteristic that if a final trait is a List or Dict, it will automatically handle '_items' changed events for the final trait as well. This can be useful in cases where the *handler* only needs to know that some aspect of the final trait has been changed. For all other *handler* signatures, you must explicitly specify the 'xxx_items' trait if you want to be notified of changes to any of the items of the 'xxx' trait. Parameters ---------- handler : function A trait notification function for the *name* trait attribute, with one of the signatures described below. name : str The name of the trait attribute whose value changes trigger the notification. The *name* can specify complex patterns of trait changes using an extended *name* syntax, which is described below. remove : bool If True, removes the previously-set association between *handler* and *name*; if False (the default), creates the association. dispatch : str A string indicating the thread on which notifications must be run. Possible values are: =========== ======================================================= value dispatch =========== ======================================================= ``same`` Run notifications on the same thread as this one. ``ui`` Run notifications on the UI thread. If the current thread is the UI thread, the notifications are executed immediately; otherwise, they are placed on the UI event queue. ``fast_ui`` Alias for ``ui``. ``new`` Run notifications in a new thread. =========== ======================================================= See Also -------- HasTraits.observe : A newer API for defining traits notifications. """ # Check to see if we can do a quick exit to the basic trait change # handler: if ( isinstance(name, str) and (extended_trait_pat.match(name) is None) ) or (name is None): self._on_trait_change( handler, name, remove, dispatch, priority, target ) return from .traits_listener import ( TraitsListener, ListenerParser, ListenerHandler, ListenerNotifyWrapper, ) if isinstance(name, list): for name_i in name: self.on_trait_change( handler, name=name_i, remove=remove, dispatch=dispatch, priority=priority, deferred=deferred, target=target, ) return # Make sure we have a name string: name = (name or "anytrait").strip() if remove: dict = self.__dict__.get(TraitsListener) if dict is not None: listeners = dict.get(name) if listeners is not None: for i, wrapper in enumerate(listeners): if wrapper.equals(handler): del listeners[i] if len(listeners) == 0: del dict[name] if len(dict) == 0: del self.__dict__[TraitsListener] wrapper.listener.unregister(self) wrapper.dispose() break else: dict = self.__dict__.setdefault(TraitsListener, {}) listeners = dict.setdefault(name, []) for wrapper in listeners: if wrapper.equals(handler): break else: # The listener notify wrapper needs a reference to the # listener, and the listener needs a (weak) reference to the # wrapper. We first construct the wrapper with a listener of # `None`, then construct the listener with its reference to the # wrapper, then we replace the `None` listener with the correct # one. lnw = ListenerNotifyWrapper(handler, self, name, None, target) listener = ListenerParser( name, handler=ListenerHandler(handler), wrapped_handler_ref=weakref.ref(lnw), dispatch=dispatch, priority=priority, deferred=deferred, handler_type=lnw.type, ).listener lnw.listener = listener listener.register(self) listeners.append(lnw) # A synonym for 'on_trait_change' on_trait_event = on_trait_change def sync_trait( self, trait_name, object, alias=None, mutual=True, remove=False ): """Synchronizes the value of a trait attribute on this object with a trait attribute on another object. In mutual synchronization, any change to the value of the specified trait attribute of either object results in the same value being assigned to the corresponding trait attribute of the other object. In one-way synchronization, any change to the value of the attribute on this object causes the corresponding trait attribute of *object* to be updated, but not vice versa. For ``List`` traits, the list's items are also synchronized, so that mutations to this trait's list will be reflected in the synchronized list (and vice versa in the case of mutual synchronization). For ``Dict`` and ``Set`` traits, items are not synchronized. Parameters ---------- name : str Name of the trait attribute on this object. object : object The object with which to synchronize. alias : str Name of the trait attribute on *other*; if None or omitted, same as *name*. mutual : bool or int Indicates whether synchronization is mutual (True or non-zero) or one-way (False or zero) remove : bool or int Indicates whether synchronization is being added (False or zero) or removed (True or non-zero) """ if alias is None: alias = trait_name is_list = self._is_list_trait(trait_name) and object._is_list_trait( alias ) if remove: info = self._get_sync_trait_info() dic = info.get(trait_name) if dic is not None: key = (id(object), alias) if key in dic: del dic[key] if len(dic) == 0: del info[trait_name] self._on_trait_change( self._sync_trait_modified, trait_name, remove=True ) if is_list: self._on_trait_change( self._sync_trait_items_modified, trait_name + "_items", remove=True, ) if mutual: object.sync_trait(alias, self, trait_name, False, True) return # Callback to use when the synced object goes out of scope. In order # to avoid reference cycles, this must not be a member function. See # Github issue #69 for more detail. def _sync_trait_listener_deleted(ref, info): for key, dic in list(info.items()): if key != "": for name, value in list(dic.items()): if ref is value[0]: del dic[name] if len(dic) == 0: del info[key] info = self._get_sync_trait_info() dic = info.setdefault(trait_name, {}) key = (id(object), alias) callback = lambda ref: _sync_trait_listener_deleted(ref, info) value = (weakref.ref(object, callback), alias) if key not in dic: if len(dic) == 0: self._on_trait_change(self._sync_trait_modified, trait_name) if is_list: self._on_trait_change( self._sync_trait_items_modified, trait_name + "_items" ) dic[key] = value setattr(object, alias, getattr(self, trait_name)) if mutual: object.sync_trait(alias, self, trait_name, False) def _get_sync_trait_info(self): info = getattr(self, "__sync_trait__", None) if info is None: self.__dict__["__sync_trait__"] = info = {} info[""] = {} return info def _sync_trait_modified(self, object, name, old, new): info = self.__sync_trait__ if name not in info: return locked = info[""] locked[name] = None for object, object_name in info[name].values(): object = object() if object_name not in object._get_sync_trait_info()[""]: try: setattr(object, object_name, new) except: pass del locked[name] def _sync_trait_items_modified(self, object, name, old, event): n0 = event.index n1 = n0 + len(event.removed) name = name[:-6] info = self.__sync_trait__ locked = info[""] locked[name] = None for object, object_name in info[name].values(): object = object() if object_name not in object._get_sync_trait_info()[""]: try: getattr(object, object_name)[n0:n1] = event.added except: pass del locked[name] def _is_list_trait(self, trait_name): handler = self.base_trait(trait_name).handler return (handler is not None) and ( handler.default_value_type == DefaultValue.trait_list_object ) def add_trait(self, name, *trait): """Adds a trait attribute to this object. Parameters ---------- name : str Name of the attribute to add. *trait : Trait or a value that can be converted to a trait by Trait(). Trait definition for *name*. If more than one value is specified, it is equivalent to passing the entire list of values to Trait(). """ # Make sure a trait argument was specified: if len(trait) == 0: raise ValueError("No trait definition was specified.") # Make sure only valid traits get added: if len(trait) > 1: trait = Trait(*trait) else: trait = trait_for(trait[0]) # Check to see if the trait has additional sub-traits that need to be # defined also: handler = trait.handler if handler is not None: if handler.has_items: self.add_trait(name + "_items", handler.items_event()) if handler.is_mapped: self.add_trait(name + "_", mapped_trait_for(trait, name)) # See if there already is a class or instance trait with the same name: old_trait = self._trait(name, 0) # Get the object's instance trait dictionary and add a clone of the new # trait to it: itrait_dict = self._instance_traits() itrait_dict[name] = trait = _clone_trait(trait) # If there already was a trait with the same name: if old_trait is not None: # Copy the old traits notifiers into the new trait: old_notifiers = old_trait._notifiers(False) if old_notifiers is not None: trait._notifiers(True).extend(old_notifiers) else: # Otherwise, see if there are any static notifiers that should be # applied to the trait: cls = self.__class__ handlers = [ _get_method(cls, "_%s_changed" % name), _get_method(cls, "_%s_fired" % name), ] # Add any special trait defined event handlers: _add_event_handlers(trait, cls, handlers) # Add the 'anytrait' handler (if any): handlers.append(self.__prefix_traits__.get("@")) # Filter out any 'None' values: handlers = [h for h in handlers if h is not None] # If there are any static notifiers, attach them to the trait: if len(handlers) > 0: _add_notifiers(trait._notifiers(True), handlers) # If this was a new trait, fire the 'trait_added' event: if old_trait is None: self.trait_added = name def remove_trait(self, name): """Removes a trait attribute from this object. Parameters ---------- name : str Name of the attribute to remove. Returns ------- result : bool True if the trait was successfully removed. """ # Get the trait definition: trait = self._trait(name, 0) if trait is not None: # Check to see if the trait has additional sub-traits that need to # be removed also: handler = trait.handler if handler is not None: if handler.has_items: self.remove_trait(name + "_items") if handler.is_mapped: self.remove_trait(name + "_") # Remove the trait value from the object dictionary as well: if name in self.__dict__: del self.__dict__[name] # Get the object's instance trait dictionary and remove the trait # from it: itrait_dict = self._instance_traits() if name in itrait_dict: del itrait_dict[name] return True return False def trait(self, name, force=False, copy=False): """Returns the trait definition for the *name* trait attribute. If *force* is False (the default) and *name* is the name of an implicitly defined trait attribute that has never been referenced explicitly (i.e., has not yet been defined), the result is None. In all other cases, the result is the trait definition object associated with *name*. If *copy* is True, and a valid trait definition is found for *name*, a copy of the trait found is returned. In all other cases, the trait definition found is returned unmodified (the default). Parameters ---------- name : str Name of the attribute whose trait definition is to be returned. force : bool Indicates whether to return a trait definition if *name* is not explicitly defined. copy : bool Indicates whether to return the original trait definition or a copy. """ mode = 0 if force: mode = -1 result = self._trait(name, mode) if (not copy) or (result is None): return result return _clone_trait(result) def base_trait(self, name): """Returns the base trait definition for a trait attribute. This method is similar to the trait() method, and returns a different result only in the case where the trait attribute defined by *name* is a delegate. In this case, the base_trait() method follows the delegation chain until a non-delegated trait attribute is reached, and returns the definition of that attribute's trait as the result. Parameters ---------- name : str Name of the attribute whose trait definition is returned. """ return self._trait(name, -2) def validate_trait(self, name, value): """ Validates whether a value is legal for a trait. Returns the validated value if it is valid. """ return self.base_trait(name).validate(self, name, value) def traits(self, **metadata): """Returns a dictionary containing the definitions of all of the trait attributes of this object that match the set of *metadata* criteria. Note that any traits with a name containing the suffix "_items" are always excluded. The keys of the returned dictionary are the trait attribute names, and the values are their corresponding trait definition objects. If no *metadata* information is specified, then all explicitly defined trait attributes defined for the object are returned. Otherwise, the *metadata* keyword dictionary is assumed to define a set of search criteria for selecting trait attributes of interest. The *metadata* dictionary keys correspond to the names of trait metadata attributes to examine, and the values correspond to the values the metadata attribute must have in order to be included in the search results. The *metadata* values either may be simple Python values like strings or integers, or may be lambda expressions or functions that return True if the trait attribute is to be included in the result. A lambda expression or function must receive a single argument, which is the value of the trait metadata attribute being tested. If more than one metadata keyword is specified, a trait attribute must match the metadata values of all keywords to be included in the result. Parameters ---------- **metadata : Criteria for selecting trait attributes. """ traits = self.__base_traits__.copy() # Update with instance-defined traits. for name, trt in self._instance_traits().items(): if name[-6:] != "_items": traits[name] = trt for name in self.__dict__.keys(): if name not in traits: trait = self.trait(name) if trait is not None: traits[name] = trait if len(metadata) == 0: return traits for meta_name, meta_eval in list(metadata.items()): if type(meta_eval) is not FunctionType: metadata[meta_name] = _SimpleTest(meta_eval) result = {} for name, trait in traits.items(): for meta_name, meta_eval in metadata.items(): if not meta_eval(getattr(trait, meta_name, None)): break else: result[name] = trait return result @classmethod def class_traits(cls, **metadata): """Returns a dictionary containing the definitions of all of the trait attributes of the class that match the set of *metadata* criteria. The keys of the returned dictionary are the trait attribute names, and the values are their corresponding trait definition objects. If no *metadata* information is specified, then all explicitly defined trait attributes defined for the class are returned. Otherwise, the *metadata* keyword dictionary is assumed to define a set of search criteria for selecting trait attributes of interest. The *metadata* dictionary keys correspond to the names of trait metadata attributes to examine, and the values correspond to the values the metadata attribute must have in order to be included in the search results. The *metadata* values either may be simple Python values like strings or integers, or may be lambda expressions or functions that return **True** if the trait attribute is to be included in the result. A lambda expression or function must receive a single argument, which is the value of the trait metadata attribute being tested. If more than one metadata keyword is specified, a trait attribute must match the metadata values of all keywords to be included in the result. Parameters ---------- **metadata : Criteria for selecting trait attributes. """ if len(metadata) == 0: return cls.__base_traits__.copy() result = {} for meta_name, meta_eval in list(metadata.items()): if type(meta_eval) is not FunctionType: metadata[meta_name] = _SimpleTest(meta_eval) for name, trait in cls.__base_traits__.items(): for meta_name, meta_eval in metadata.items(): if not meta_eval(getattr(trait, meta_name, None)): break else: result[name] = trait return result def trait_names(self, **metadata): """Returns a list of the names of all trait attributes whose definitions match the set of *metadata* criteria specified. This method is similar to the traits() method, but returns only the names of the matching trait attributes, not the trait definitions. Parameters ---------- **metadata : Criteria for selecting trait attributes. """ return list(self.traits(**metadata).keys()) @classmethod def class_trait_names(cls, **metadata): """Returns a list of the names of all trait attributes whose definitions match the set of *metadata* criteria specified. This method is similar to the traits() method, but returns only the names of the matching trait attributes, not the trait definitions. Parameters ---------- **metadata : Criteria for selecting trait attributes. """ return list(cls.class_traits(**metadata).keys()) def _set_traits_cache(self, name, value): """ Explicitly sets the value of a cached property. """ cached = TraitsCache + name old_value = self.__dict__.get(cached, Undefined) self.__dict__[cached] = value if old_value != value: self.trait_property_changed(name, old_value, value) def _flush_traits_cache(self, name, value): """ Explicitly flushes the value of a cached property. """ self.trait_property_changed( name, self.__dict__.pop(TraitsCache + name, Undefined) ) def __prefix_trait__(self, name, is_set): """ Return the trait definition for a specified name when there is no explicit definition in the class. """ # Check to see if the name is of the form '__xxx__': if (name[:2] == "__") and (name[-2:] == "__"): if name == "__class__": return generic_trait # If this is for purposes of performing a 'setattr', always map the # name to an 'Any' trait: if is_set: return any_trait # Otherwise, it is a 'getattr' request, so indicate that no such # attribute exists: raise AttributeError( "'%s' object has no attribute '%s'" % (self.__class__.__name__, name) ) # Handle the special case of 'delegated' traits: if name[-1:] == "_": trait = self._trait(name[:-1], 0) if (trait is not None) and (trait.type == "delegate"): return _clone_trait(trait) prefix_traits = self.__prefix_traits__ for prefix in prefix_traits["*"]: if prefix == name[: len(prefix)]: # If we found a match, use its trait as a template for a new # trait: trait = prefix_traits[prefix] # Get any change notifiers that apply to the trait: cls = self.__class__ handlers = [ _get_method(cls, "_%s_changed" % name), _get_method(cls, "_%s_fired" % name), ] # Add any special trait defined event handlers: _add_event_handlers(trait, cls, handlers) # Add the 'anytrait' handler (if any): handlers.append(prefix_traits.get("@")) # Filter out any 'None' values: handlers = [h for h in handlers if h is not None] # If there are any handlers, add them to the trait's notifier's # list: if len(handlers) > 0: trait = _clone_trait(trait) _add_notifiers(trait._notifiers(True), handlers) return trait # There should ALWAYS be a prefix match in the trait classes, since '' # is at the end of the list, so we should never get here: raise SystemError( "Trait class look-up failed for attribute '%s' " "for an object of type '%s'" % (name, self.__class__.__name__) ) def add_trait_listener(self, object, prefix=""): """ Add (Java-style) event listener to an object. """ self._trait_listener(object, prefix, False) def remove_trait_listener(self, object, prefix=""): """ Remove (Java-style) event listener to an object. """ self._trait_listener(object, prefix, True) def _trait_listener(self, object, prefix, remove): if prefix[-1:] != "_": prefix += "_" n = len(prefix) traits = self.__base_traits__ for name in self._each_trait_method(object): if name[:n] == prefix: if name[-8:] == "_changed": short_name = name[n:-8] if short_name in traits: self._on_trait_change( getattr(object, name), short_name, remove=remove ) elif short_name == "anytrait": self._on_trait_change( getattr(object, name), remove=remove ) elif name[:-6] == "_fired": short_name = name[n:-6] if short_name in traits: self._on_trait_change( getattr(object, name), short_name, remove=remove ) elif short_name == "anytrait": self._on_trait_change( getattr(object, name), remove=remove ) def _each_trait_method(self, object): """ Generates each (name, method) pair for a specified object. """ dic = {} for klass in object.__class__.__mro__: for name, method in klass.__dict__.items(): if (is_unbound_method_type(method) and name not in dic): dic[name] = True yield name def _instance_changed_handler(self, name, old, new): """ Handles adding/removing listeners for a generic 'Instance' trait. """ arg_lists = self._get_instance_handlers(name) if old is not None: for args in arg_lists: old.on_trait_change(remove=True, *args) if new is not None: for args in arg_lists: new.on_trait_change(*args) def _list_changed_handler(self, name, old, new): """ Handles adding/removing listeners for a generic 'List( Instance )' trait. """ arg_lists = self._get_instance_handlers(name) for item in old: for args in arg_lists: item.on_trait_change(remove=True, *args) for item in new: for args in arg_lists: item.on_trait_change(*args) def _list_items_changed_handler(self, name, not_used, event): """ Handles adding/removing listeners for a generic 'List( Instance )' trait. """ arg_lists = self._get_instance_handlers(name[:-6]) for item in event.removed: for args in arg_lists: item.on_trait_change(remove=True, *args) for item in event.added: for args in arg_lists: item.on_trait_change(*args) def _get_instance_handlers(self, name): """ Returns a list of ( name, method ) pairs for a specified 'Instance' or 'List( Instance )' trait name: """ return [ (getattr(self, method_name), item_name) for method_name, item_name in self.__class__.__instance_traits__[ name ] ] def _post_init_trait_listeners(self): """ Initializes the object's statically parsed, but dynamically registered, traits listeners (called at object creation and unpickling times). """ for name, data in self.__class__.__listener_traits__.items(): if data[0] == "method": config = data[1] if config["post_init"]: self.on_trait_change( getattr(self, name), config["pattern"], deferred=True, dispatch=config["dispatch"], ) def _init_trait_listeners(self): """ Initializes the object's statically parsed, but dynamically registered, traits listeners (called at object creation and unpickling times). """ for name, data in self.__class__.__listener_traits__.items(): getattr(self, "_init_trait_%s_listener" % data[0])(name, *data) def _init_trait_method_listener(self, name, kind, config): """ Sets up the listener for a method with the @on_trait_change decorator. """ if not config["post_init"]: self.on_trait_change( getattr(self, name), config["pattern"], deferred=True, dispatch=config["dispatch"], ) def _init_trait_event_listener(self, name, kind, pattern): """ Sets up the listener for an event with on_trait_change metadata. """ @weak_arg(self) def notify(self): setattr(self, name, True) self.on_trait_change(notify, pattern, target=self) def _init_trait_property_listener(self, name, kind, cached, pattern): """ Sets up the listener for a property with 'depends_on' metadata. """ if cached is None: @weak_arg(self) def notify(self): self.trait_property_changed(name, None) else: cached_old = cached + ":old" @weak_arg(self) def pre_notify(self): dict = self.__dict__ old = dict.get(cached_old, Undefined) if old is Undefined: dict[cached_old] = dict.pop(cached, None) self.on_trait_change( pre_notify, pattern, priority=True, target=self ) @weak_arg(self) def notify(self): old = self.__dict__.pop(cached_old, Undefined) if old is not Undefined: self.trait_property_changed(name, old) self.on_trait_change(notify, pattern, target=self) def _init_trait_delegate_listener(self, name, kind, pattern): """ Sets up the listener for a delegate trait. """ name_pattern = self._trait_delegate_name(name, pattern) target_name_len = len(name_pattern.split(":")[-1]) @weak_arg(self) def notify(self, object, notify_name, old, new): self.trait_property_changed( name + notify_name[target_name_len:], old, new ) self.on_trait_change(notify, name_pattern, target=self) self.__dict__.setdefault(ListenerTraits, {})[name] = notify def _remove_trait_delegate_listener(self, name, remove): """ Removes a delegate listener when the local delegate value is set. """ dict = self.__dict__.setdefault(ListenerTraits, {}) if remove: # Although the name should be in the dict, it may not be if a value # was assigned to a delegate in a constructor or setstate: if name in dict: # Remove the delegate listener: self.on_trait_change( dict[name], self._trait_delegate_name( name, self.__class__.__listener_traits__[name][1] ), remove=True, ) del dict[name] if len(dict) == 0: del self.__dict__[ListenerTraits] return # Otherwise the local copy of the delegate value was deleted, restore # the delegate listener (unless it's already there): if name not in dict: self._init_trait_delegate_listener( name, 0, self.__class__.__listener_traits__[name][1] ) def _init_trait_observers(self): """ Initialize observers prior to setting object state. """ for name, states in self.__class__.__observer_traits__.items(): for state in states: if not state["post_init"]: observe_api.apply_observers( object=self, handler=state["handler_getter"](self, name), graphs=state["graphs"], dispatcher=_ObserverDispatchers[state["dispatch"]], ) def _post_init_trait_observers(self): """ Initialize observers after setting object state. """ for name, states in self.__class__.__observer_traits__.items(): for state in states: if state["post_init"]: observe_api.apply_observers( object=self, handler=state["handler_getter"](self, name), graphs=state["graphs"], dispatcher=_ObserverDispatchers[state["dispatch"]], ) def _trait_delegate_name(self, name, pattern): """ Returns the fully-formed 'on_trait_change' name for a specified delegate. """ if pattern[-1] == "*": pattern = "%s%s%s" % ( pattern[:-1], self.__class__.__prefix__, name, ) return pattern # Patch the definition of _HasTraits to be the real 'HasTraits': _HasTraits = HasTraits class HasStrictTraits(HasTraits): """ This class guarantees that any object attribute that does not have an explicit or wildcard trait definition results in an exception. This feature can be useful in cases where a more rigorous software engineering approach is being used than is typical for Python programs. It also helps prevent typos and spelling mistakes in attribute names from going unnoticed; a misspelled attribute name typically causes an exception. """ _ = Disallow # Disallow access to any traits not explicitly defined class HasRequiredTraits(HasStrictTraits): """ This class builds on the functionality of HasStrictTraits and ensures that any object attribute with `required=True` in its metadata must be passed as an argument on object initialization. This can be useful in cases where an object has traits which are required for it to function correctly. Raises ------ TraitError If a required trait is not passed as an argument. Examples -------- A class with required traits: >>> class RequiredTest(HasRequiredTraits): ... required_trait = Any(required=True) ... non_required_trait = Any() Creating an instance of a HasRequiredTraits subclass: >>> test_instance = RequiredTest(required_trait=13, non_required_trait=11) >>> test_instance2 = RequiredTest(required_trait=13) Forgetting to specify a required trait: >>> test_instance = RequiredTest(non_required_trait=11) traits.trait_errors.TraitError: The following required traits were not provided: required_trait. """ def __init__(self, **traits): missing_required_traits = [ name for name in self.trait_names(required=True) if name not in traits ] if missing_required_traits: raise TraitError( "The following required traits were not provided: " "{}.".format(", ".join(sorted(missing_required_traits))) ) super().__init__(**traits) class HasPrivateTraits(HasTraits): """ This class ensures that any public object attribute that does not have an explicit or wildcard trait definition results in an exception, but "private" attributes (whose names start with '_') have an initial value of **None**, and are not type-checked. This feature is useful in cases where a class needs private attributes to keep track of its internal object state, which are not part of the class's public API. Such attributes do not need to be type-checked, because they are manipulated only by the (presumably correct) methods of the class itself. """ # Make 'private' traits (leading '_') have no type checking: __ = Any(private=True, transient=True) # Disallow access to all other traits not explicitly defined: _ = Disallow # ABC classes with traits class ABCMetaHasTraits(abc.ABCMeta, MetaHasTraits): """ A MetaHasTraits subclass which also inherits from abc.ABCMeta. .. note:: The ABCMeta class is cooperative and behaves nicely with MetaHasTraits, provided it is inherited first. """ pass class ABCHasTraits(HasTraits, metaclass=ABCMetaHasTraits): """ A HasTraits subclass which enables the features of Abstract Base Classes (ABC). See the 'abc' module in the standard library for more information. """ class ABCHasStrictTraits(ABCHasTraits): """ A HasTraits subclass which behaves like HasStrictTraits but also enables the features of Abstract Base Classes (ABC). See the 'abc' module in the standard library for more information. """ _ = Disallow # Singleton classes with traits: # # This code is based on a recipe taken from: # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531 # Specifically, the implementation of Oren Tirosh is used. class SingletonHasTraits(HasTraits): """ Singleton class that support trait attributes. """ @deprecated("SingletonHasTraits has been deprecated and will be removed " "in the future. Avoid using it") def __new__(cls, *args, **traits): if "_the_instance" not in cls.__dict__: cls._the_instance = HasTraits.__new__(cls, *args, **traits) return cls._the_instance class SingletonHasStrictTraits(HasStrictTraits): """ Singleton class that supports strict trait attributes. Non-trait attributes generate an exception. """ @deprecated("SingletonHasStrictTraits has been deprecated and will be " "removed in the future. Avoid using it") def __new__(cls, *args, **traits): return SingletonHasTraits.__new__(cls, *args, **traits) class SingletonHasPrivateTraits(HasPrivateTraits): """ Singleton class that supports trait attributes, with private attributes being unchecked. """ @deprecated("SingletonHasPrivateTraits has been deprecated and will be " "removed in the future. Avoid using it") def __new__(cls, *args, **traits): return SingletonHasTraits.__new__(cls, *args, **traits) class Vetoable(HasStrictTraits): """ Defines a 'vetoable' request object and an associated event. """ # Should the request be vetoed? (Can only be set to 'True') veto = Bool(False) def _veto_changed(self, state): self._trait_veto_notify(state) VetoableEvent = Event(Vetoable) class MetaInterface(ABCMetaHasTraits): """ Meta class for interfaces. Interfaces are simple ABCs with the following features:- 1) They cannot be instantiated (they are interfaces, not implementations!). 2) Calling them is equivalent to calling 'adapt'. """ @deprecated('use "adapt(adaptee, protocol)" instead.') def __call__(self, adaptee, default=AdaptationError): """ Attempt to adapt the adaptee to this interface. Note that this means that (intentionally ;^) that interfaces cannot be instantiated! """ from traits.adaptation.api import adapt return adapt(adaptee, self, default=default) class Interface(HasTraits, metaclass=MetaInterface): """ The base class for all interfaces. """ def provides(*protocols): """ Class decorator to declare the protocols that a class provides. Parameters ---------- *protocols : A list of protocols (Interface classes or Python ABCs) that the decorated class provides. """ from abc import ABCMeta # Exit immediately if there is nothing to do. if len(protocols) == 0: return lambda klass: klass # Verify that each argument is a valid protocol. for protocol in protocols: if not issubclass(type(protocol), ABCMeta): raise TraitError( "All arguments to 'provides' must be " "subclasses of Interface or be a Python ABC." ) def wrapped_class(klass): for protocol in protocols: # We use 'type(protocol)' in case the 'protocol' implements # its own 'register' method that overrides the ABC method. type(protocol).register(protocol, klass) # Make sure the class does provide the protocols it claims to. if CHECK_INTERFACES: from .interface_checker import check_implements warnings.warn( ( "In the future, the @provides decorator will not perform " "interface checks. Set has_traits.CHECK_INTERFACES to 0 " "to suppress this warning." ), DeprecationWarning, stacklevel=2, ) check_implements(klass, protocols, CHECK_INTERFACES) return klass return wrapped_class def isinterface(klass): """ Return True if the class is an Interface. """ return isinstance(klass, MetaInterface) class ISerializable(Interface): """ A class that implemented ISerializable requires that all HasTraits objects saved as part of its state also implement ISerializable. """ traits-6.3.2/traits/interface_checker.py000066400000000000000000000133711414270267200203460ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ An attempt at type-safe casting. """ from inspect import getfullargspec, getmro import logging from types import FunctionType from .has_traits import HasTraits logger = logging.getLogger(__name__) # Constants: # Message templates for interface errors. BAD_SIGNATURE = ( "The '%s' class signature for the '%s' method is different " "from that of the '%s' interface." ) MISSING_METHOD = ( "The '%s' class does not implement the '%s' method of the " "'%s' interface." ) MISSING_TRAIT = ( "The '%s' class does not implement the %s trait(s) of the " "'%s' interface." ) class InterfaceError(Exception): """ The exception raised if a class does not really implement an interface. """ pass class InterfaceChecker(HasTraits): """ Checks that interfaces are actually implemented. """ def check_implements(self, cls, interfaces, error_mode): """ Checks that the class implements the specified interfaces. 'interfaces' can be a single interface or a list of interfaces. """ # If a single interface was specified then turn it into a list: try: iter(interfaces) except TypeError: interfaces = [interfaces] # If the class has traits then check that it implements all traits and # methods on the specified interfaces: if issubclass(cls, HasTraits): for interface in interfaces: if not self._check_has_traits_class( cls, interface, error_mode ): return False # Otherwise, just check that the class implements all methods on the # specified interface: else: for interface in interfaces: if not self._check_non_has_traits_class( cls, interface, error_mode ): return False return True def _check_has_traits_class(self, cls, interface, error_mode): """ Checks that a 'HasTraits' class implements an interface. """ return self._check_traits( cls, interface, error_mode ) and self._check_methods(cls, interface, error_mode) def _check_non_has_traits_class(self, cls, interface, error_mode): """ Checks that a non-'HasTraits' class implements an interface. """ return self._check_methods(cls, interface, error_mode) def _check_methods(self, cls, interface, error_mode): """ Checks that a class implements the methods on an interface. """ cls_methods = self._get_public_methods(cls) interface_methods = self._get_public_methods(interface) for name in interface_methods: if name not in cls_methods: return self._handle_error( MISSING_METHOD % ( self._class_name(cls), name, self._class_name(interface), ), error_mode, ) # Check that the method signatures are the same: cls_argspec = getfullargspec(cls_methods[name]) interface_argspec = getfullargspec(interface_methods[name]) if cls_argspec != interface_argspec: return self._handle_error( BAD_SIGNATURE % ( self._class_name(cls), name, self._class_name(interface), ), error_mode, ) return True def _check_traits(self, cls, interface, error_mode): """ Checks that a class implements the traits on an interface. """ missing = set(interface.class_traits()).difference( set(cls.class_traits()) ) if len(missing) > 0: return self._handle_error( MISSING_TRAIT % ( self._class_name(cls), repr(list(missing))[1:-1], self._class_name(interface), ), error_mode, ) return True def _get_public_methods(self, cls): """ Returns all public methods on a class. Returns a dictionary containing all public methods keyed by name. """ public_methods = {} for c in getmro(cls): # Stop when we get to 'HasTraits'!: if c is HasTraits: break for name, value in c.__dict__.items(): if (not name.startswith("_")) and ( type(value) is FunctionType ): if name not in public_methods: public_methods[name] = value return public_methods def _class_name(self, cls): return cls.__name__ def _handle_error(self, msg, error_mode): if error_mode > 1: raise InterfaceError(msg) if error_mode == 1: logger.warning(msg) return False # A default interface checker: checker = InterfaceChecker() def check_implements(cls, interfaces, error_mode=0): """ Checks that the class implements the specified interfaces. 'interfaces' can be a single interface or a list of interfaces. """ return checker.check_implements(cls, interfaces, error_mode) traits-6.3.2/traits/observation/000077500000000000000000000000001414270267200166765ustar00rootroot00000000000000traits-6.3.2/traits/observation/__init__.py000066400000000000000000000000001414270267200207750ustar00rootroot00000000000000traits-6.3.2/traits/observation/_anytrait_filter.py000066400000000000000000000013131414270267200226050ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ A filter to be used with FilteredTraitObserver for observing all traits. """ def anytrait_filter(name, ctrait): """ Match filter that matches all traits. Parameters ---------- name : str Name of the trait. ctrait : CTrait The actual trait. """ return True traits-6.3.2/traits/observation/_dict_change_event.py000066400000000000000000000046171414270267200230500ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Event object for representing mutations to a dict. """ # DictChangeEvent is exposed in the public API class DictChangeEvent: """ Event object to represent mutations on a dict. Note that the API is different from the ``TraitDictEvent`` emitted via the "*name* _items" trait. In particular, the attribute ``changed`` is not defined here. The interface of this object is provisional as of version 6.1. Attributes ---------- object : traits.trait_dict_object.TraitDict The dict being mutated. removed : dict Keys and values for removed or updated items. If keys are found in ``added`` as well, they refer to updated items and the values are old. added : dict Keys and values for added or updated items. If keys are found in ``removed`` as well, they refer to updated items and the values are new. """ def __init__(self, *, object, removed, added): self.object = object self.removed = removed self.added = added def __repr__(self): return ( f"{self.__class__.__name__}(" f"object={self.object!r}, " f"removed={self.removed!r}, " f"added={self.added!r})" ) def dict_event_factory(trait_dict, removed, added, changed): """ Adapt the call signature of TraitDict.notify to create an event. Parameters ---------- trait_dict : traits.trait_dict_object.TraitDict The dict being mutated. removed : dict Items removed from the dict added : dict Items added to the dict changed : dict Old values for items updated on the dict. Returns ------- DictChangeEvent """ # See enthought/traits#1031 for changing the signature of TraitDict.notify # instead. removed = removed.copy() removed.update(changed) for key in changed: added[key] = trait_dict[key] return DictChangeEvent( object=trait_dict, added=added, removed=removed, ) traits-6.3.2/traits/observation/_dict_item_observer.py000066400000000000000000000152241414270267200232630ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.observation._dict_change_event import dict_event_factory from traits.observation._i_observer import IObserver from traits.observation._observe import add_or_remove_notifiers from traits.observation._observer_change_notifier import ObserverChangeNotifier from traits.observation._trait_event_notifier import TraitEventNotifier from traits.trait_dict_object import TraitDict @IObserver.register class DictItemObserver: """ Observer for observing mutations on a dict. Parameters ---------- notify : boolean Whether to notify for changes. optional : boolean If False, this observer will complain if the incoming object is not an observable dict. If True and the incoming object is not a dict, this observer will do nothing. Useful for the 'items' keyword in the text parser, where the source container type is ambiguous. """ __slots__ = ("notify", "optional") def __init__(self, *, notify, optional): self.notify = notify self.optional = optional def __hash__(self): """ Return a hash of this object.""" return hash((type(self).__name__, self.notify, self.optional)) def __eq__(self, other): """ Return true if this observer is equal to the given one.""" return ( type(self) is type(other) and self.notify == other.notify and self.optional == other.optional ) def __repr__(self): formatted_args = [ f"notify={self.notify!r}", f"optional={self.optional!r}", ] return f"{self.__class__.__name__}({', '.join(formatted_args)})" def iter_observables(self, object): """ If the given object is an observable dict, yield that dict. Otherwise, raise an error unless this observer is optional. Parameters ---------- object: object Object provided by another observers or by the user. Yields ------ IObservable Raises ------ ValueError If the given object is not an observable dict and optional is false. """ if not isinstance(object, TraitDict): if self.optional: return raise ValueError( "Expected a TraitDict to be observed, " "got {!r} (type: {!r})".format(object, type(object)) ) yield object def iter_objects(self, object): """ Yield the values if the given object is an observable dict. Otherwise, raise an error, unless the observer is optional. The values of the dict will be passed onto the children observer(s) following this one in an ObserverGraph. Parameters ---------- object: object Object provided by another observers or by the user. Yields ------ value : object Raises ------ ValueError If the given object is not an observable dict and optional is false. """ if not isinstance(object, TraitDict): if self.optional: return raise ValueError( "Expected a TraitDict to be observed, " "got {!r} (type: {!r})".format(object, type(object)) ) yield from object.values() def get_notifier(self, handler, target, dispatcher): """ Return a notifier for calling the user handler with the change event. Returns ------- notifier : TraitEventNotifier """ # Unlike CTrait, when default dict is created, there isn't a change # event where the old value is Uninitialized. return TraitEventNotifier( handler=handler, target=target, dispatcher=dispatcher, event_factory=dict_event_factory, prevent_event=lambda event: False, ) def get_maintainer(self, graph, handler, target, dispatcher): """ Return a notifier for maintaining downstream observers when a dict is mutated. Parameters ---------- graph : ObserverGraph Description for the *downstream* observers, i.e. excluding self. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. Returns ------- notifier : ObserverChangeNotifier """ return ObserverChangeNotifier( observer_handler=_observer_change_handler, event_factory=dict_event_factory, prevent_event=lambda event: False, graph=graph, handler=handler, target=target, dispatcher=dispatcher, ) def iter_extra_graphs(self, graph): """ Yield new ObserverGraph to be contributed by this observer. Parameters ---------- graph : ObserverGraph The graph this observer is part of. Yields ------ ObserverGraph """ # Unlike CTrait, no need to handle trait_added yield from () def _observer_change_handler(event, graph, handler, target, dispatcher): """ Handler for maintaining observers. Used by ObserverChangeNotifier. Parameters ---------- event : DictChangeEvent Change event that triggers the maintainer. graph : ObserverGraph Description for the *downstream* observers, i.e. excluding self. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. """ for removed_item in event.removed.values(): add_or_remove_notifiers( object=removed_item, graph=graph, handler=handler, target=target, dispatcher=dispatcher, remove=True, ) for added_item in event.added.values(): add_or_remove_notifiers( object=added_item, graph=graph, handler=handler, target=target, dispatcher=dispatcher, remove=False, ) traits-6.3.2/traits/observation/_dsl_grammar.lark000066400000000000000000000027551414270267200222110ustar00rootroot00000000000000// Grammar for Traits Mini Language used in observe // After updating the grammar, rebuild the standalone parser with: // $ python etstool.py generate-parser // // Simple name as trait name, e.g. "a" trait: NAME // Keyword for handing items (in list, or dict, or set, // or a trait named "items") items: "items" // Syntax to indicate name is being used for matching an existing // metadata name rather than a trait name. metadata: "+" NAME // Used to match any trait name. anytrait: "*" // Series connector used when left item should notify notify: "." // Series connector used when left item should not notify quiet: ":" // Atomic expression ?element: trait | items | metadata | "[" parallel "]" // Rule for joining elements in series, e.g. "a.b.c" ?series: (series (notify | quiet))? element // Rule for joining elements in parallel, e.g. "a,b,c" ?parallel: (parallel ",")? series // We only allow "*" if it appears in a "terminal" position, in the sense that // it's not directly or indirectly followed by a "." or ":" connector. For // example, "b.*" and "[a:*,b]" are valid, but "*.b" and "[*,a].b" are not. // Here are variants of the series and parallel rules used for expressions // appearing in a terminal position. ?series_terminal : (series (notify | quiet))? (element | anytrait) ?parallel_terminal : (parallel_terminal ",")? series_terminal // Start point for the parser ?start: parallel_terminal // Matching Python variable name rule NAME: /[a-zA-Z_]\w*/ %import common.WS %ignore WS traits-6.3.2/traits/observation/_filtered_trait_observer.py000066400000000000000000000142751414270267200243300ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.observation._has_traits_helpers import ( ctrait_prevent_event, iter_objects, observer_change_handler, ) from traits.observation._i_observer import IObserver from traits.observation._observer_change_notifier import ObserverChangeNotifier from traits.observation._observer_graph import ObserverGraph from traits.observation._trait_change_event import trait_event_factory from traits.observation._trait_added_observer import TraitAddedObserver from traits.observation._trait_event_notifier import TraitEventNotifier @IObserver.register class FilteredTraitObserver: """ An observer for observing traits using a custom filter. Parameters ---------- notify : boolean Whether to notify for changes. filter : callable(str, CTrait) -> boolean A callable that receives the name of a trait and the corresponding trait definition. The returned boolean indicates whether the trait is observed. In order to remove an existing observer with the equivalent filter, the filter callables must compare equally. The callable must also be hashable. """ __slots__ = ("notify", "filter") def __init__(self, notify, filter): self.notify = notify self.filter = filter def __hash__(self): """ Return a hash of this object.""" return hash((type(self).__name__, self.notify, self.filter)) def __eq__(self, other): """ Return true if this observer is equal to the given one.""" return ( type(self) is type(other) and self.notify == other.notify and self.filter == other.filter ) def __repr__(self): formatted_args = [ f"notify={self.notify!r}", f"filter={self.filter!r}", ] return f"{self.__class__.__name__}({', '.join(formatted_args)})" def iter_observables(self, object): """ Yield the instance traits matching the filter given. Any error occurred upon obtaining the trait definitions (e.g. the given object is not an instance of HasTraits) will be propagated. Parameters ---------- object: object Object provided by the ``iter_objects`` methods from another observers or directly by the user. Yields ------ IObservable """ for name, ctrait in object.traits().items(): if self.filter(name, ctrait): yield object._trait(name, 2) def iter_objects(self, object): """ Yield the values of the traits that match the given filter. The values will be given to the next observer(s) following this one in an ObserverGraph. If a value has not been set as an instance attribute, i.e. absent in ``object.__dict__``, this observer will skip it. This is to avoid evaluating default initializers while adding observers. When the default is defined, a change event will trigger the maintainer to add/remove notifiers for the next observers. Note that ``Undefined``, ``Uninitialized`` and ``None`` values are also skipped, as they are unavoidable filled values that contain no further attributes to be observed by any other observers. Parameters ---------- object: object Object provided by the ``iter_objects`` methods from another observers or directly by the user. Yields ------ value : object """ for name, ctrait in object.traits().items(): if self.filter(name, ctrait): yield from iter_objects(object, name) def get_notifier(self, handler, target, dispatcher): """ Return a notifier for calling the user handler with the change event. If the old value is uninitialized, then the change is caused by having the default value defined. Such an event is prevented from reaching the user's change handler. Returns ------- notifier : TraitEventNotifier """ return TraitEventNotifier( handler=handler, target=target, dispatcher=dispatcher, event_factory=trait_event_factory, prevent_event=ctrait_prevent_event, ) def get_maintainer(self, graph, handler, target, dispatcher): """ Return a notifier for maintaining downstream observers when a trait is changed. All events should be allowed through, including setting default value such that downstream observers can be maintained on the new value. Parameters ---------- graph : ObserverGraph Description for the *downstream* observers, i.e. excluding self. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. Returns ------- notifier : ObserverChangeNotifier """ return ObserverChangeNotifier( observer_handler=observer_change_handler, event_factory=trait_event_factory, prevent_event=lambda event: False, graph=graph, handler=handler, target=target, dispatcher=dispatcher, ) def iter_extra_graphs(self, graph): """ Yield new ObserverGraph to be contributed by this observer. Parameters ---------- graph : ObserverGraph The graph this observer is part of. Yields ------ ObserverGraph """ yield ObserverGraph( node=TraitAddedObserver( match_func=self.filter, optional=False, ), children=[graph], ) traits-6.3.2/traits/observation/_generated_parser.py000066400000000000000000002470451414270267200227350ustar00rootroot00000000000000# The file was automatically generated by Lark v0.8.5 # # # Lark Stand-alone Generator Tool # ---------------------------------- # Generates a stand-alone LALR(1) parser with a standard lexer # # Git: https://github.com/erezsh/lark # Author: Erez Shinan (erezshin@gmail.com) # # # >>> LICENSE # # This tool and its generated code use a separate license from Lark, # and are subject to the terms of the Mozilla Public License, v. 2.0. # If a copy of the MPL was not distributed with this # file, You can obtain one at https://mozilla.org/MPL/2.0/. # # If you wish to purchase a commercial license for this tool and its # generated code, you may contact me via email or otherwise. # # If MPL2 is incompatible with your free or open-source project, # contact me and we'll work it out. # # import os from io import open class LarkError(Exception): pass class GrammarError(LarkError): pass class ParseError(LarkError): pass class LexError(LarkError): pass class UnexpectedEOF(ParseError): def __init__(self, expected): self.expected = expected message = ("Unexpected end-of-input. Expected one of: \n\t* %s\n" % '\n\t* '.join(x.name for x in self.expected)) super(UnexpectedEOF, self).__init__(message) class UnexpectedInput(LarkError): pos_in_stream = None def get_context(self, text, span=40): pos = self.pos_in_stream start = max(pos - span, 0) end = pos + span before = text[start:pos].rsplit('\n', 1)[-1] after = text[pos:end].split('\n', 1)[0] return before + after + '\n' + ' ' * len(before) + '^\n' def match_examples(self, parse_fn, examples): """ Given a parser instance and a dictionary mapping some label with some malformed syntax examples, it'll return the label for the example that bests matches the current error. """ assert self.state is not None, "Not supported for this exception" candidate = None for label, example in examples.items(): assert not isinstance(example, STRING_TYPE) for malformed in example: try: parse_fn(malformed) except UnexpectedInput as ut: if ut.state == self.state: try: if ut.token == self.token: # Try exact match first return label except AttributeError: pass if not candidate: candidate = label return candidate class UnexpectedCharacters(LexError, UnexpectedInput): def __init__(self, seq, lex_pos, line, column, allowed=None, considered_tokens=None, state=None, token_history=None): message = "No terminal defined for '%s' at line %d col %d" % (seq[lex_pos], line, column) self.line = line self.column = column self.allowed = allowed self.considered_tokens = considered_tokens self.pos_in_stream = lex_pos self.state = state message += '\n\n' + self.get_context(seq) if allowed: message += '\nExpecting: %s\n' % allowed if token_history: message += '\nPrevious tokens: %s\n' % ', '.join(repr(t) for t in token_history) super(UnexpectedCharacters, self).__init__(message) class UnexpectedToken(ParseError, UnexpectedInput): def __init__(self, token, expected, considered_rules=None, state=None): self.token = token self.expected = expected # XXX str shouldn't necessary self.line = getattr(token, 'line', '?') self.column = getattr(token, 'column', '?') self.considered_rules = considered_rules self.state = state self.pos_in_stream = getattr(token, 'pos_in_stream', None) message = ("Unexpected token %r at line %s, column %s.\n" "Expected one of: \n\t* %s\n" % (token, self.line, self.column, '\n\t* '.join(self.expected))) super(UnexpectedToken, self).__init__(message) class VisitError(LarkError): """VisitError is raised when visitors are interrupted by an exception It provides the following attributes for inspection: - obj: the tree node or token it was processing when the exception was raised - orig_exc: the exception that cause it to fail """ def __init__(self, rule, obj, orig_exc): self.obj = obj self.orig_exc = orig_exc message = 'Error trying to process rule "%s":\n\n%s' % (rule, orig_exc) super(VisitError, self).__init__(message) def classify(seq, key=None, value=None): d = {} for item in seq: k = key(item) if (key is not None) else item v = value(item) if (value is not None) else item if k in d: d[k].append(v) else: d[k] = [v] return d def _deserialize(data, namespace, memo): if isinstance(data, dict): if '__type__' in data: # Object class_ = namespace[data['__type__']] return class_.deserialize(data, memo) elif '@' in data: return memo[data['@']] return {key:_deserialize(value, namespace, memo) for key, value in data.items()} elif isinstance(data, list): return [_deserialize(value, namespace, memo) for value in data] return data class Serialize(object): def memo_serialize(self, types_to_memoize): memo = SerializeMemoizer(types_to_memoize) return self.serialize(memo), memo.serialize() def serialize(self, memo=None): if memo and memo.in_types(self): return {'@': memo.memoized.get(self)} fields = getattr(self, '__serialize_fields__') res = {f: _serialize(getattr(self, f), memo) for f in fields} res['__type__'] = type(self).__name__ postprocess = getattr(self, '_serialize', None) if postprocess: postprocess(res, memo) return res @classmethod def deserialize(cls, data, memo): namespace = getattr(cls, '__serialize_namespace__', {}) namespace = {c.__name__:c for c in namespace} fields = getattr(cls, '__serialize_fields__') if '@' in data: return memo[data['@']] inst = cls.__new__(cls) for f in fields: try: setattr(inst, f, _deserialize(data[f], namespace, memo)) except KeyError as e: raise KeyError("Cannot find key for class", cls, e) postprocess = getattr(inst, '_deserialize', None) if postprocess: postprocess() return inst class SerializeMemoizer(Serialize): __serialize_fields__ = 'memoized', def __init__(self, types_to_memoize): self.types_to_memoize = tuple(types_to_memoize) self.memoized = Enumerator() def in_types(self, value): return isinstance(value, self.types_to_memoize) def serialize(self): return _serialize(self.memoized.reversed(), None) @classmethod def deserialize(cls, data, namespace, memo): return _deserialize(data, namespace, memo) try: STRING_TYPE = basestring except NameError: # Python 3 STRING_TYPE = str import types from functools import wraps, partial from contextlib import contextmanager Str = type(u'') try: classtype = types.ClassType # Python2 except AttributeError: classtype = type # Python3 def smart_decorator(f, create_decorator): if isinstance(f, types.FunctionType): return wraps(f)(create_decorator(f, True)) elif isinstance(f, (classtype, type, types.BuiltinFunctionType)): return wraps(f)(create_decorator(f, False)) elif isinstance(f, types.MethodType): return wraps(f)(create_decorator(f.__func__, True)) elif isinstance(f, partial): # wraps does not work for partials in 2.7: https://bugs.python.org/issue3445 return wraps(f.func)(create_decorator(lambda *args, **kw: f(*args[1:], **kw), True)) else: return create_decorator(f.__func__.__call__, True) import sys, re Py36 = (sys.version_info[:2] >= (3, 6)) import sre_parse import sre_constants def get_regexp_width(regexp): try: return [int(x) for x in sre_parse.parse(regexp).getwidth()] except sre_constants.error: raise ValueError(regexp) class Meta: def __init__(self): self.empty = True class Tree(object): def __init__(self, data, children, meta=None): self.data = data self.children = children self._meta = meta @property def meta(self): if self._meta is None: self._meta = Meta() return self._meta def __repr__(self): return 'Tree(%s, %s)' % (self.data, self.children) def _pretty_label(self): return self.data def _pretty(self, level, indent_str): if len(self.children) == 1 and not isinstance(self.children[0], Tree): return [ indent_str*level, self._pretty_label(), '\t', '%s' % (self.children[0],), '\n'] l = [ indent_str*level, self._pretty_label(), '\n' ] for n in self.children: if isinstance(n, Tree): l += n._pretty(level+1, indent_str) else: l += [ indent_str*(level+1), '%s' % (n,), '\n' ] return l def pretty(self, indent_str=' '): return ''.join(self._pretty(0, indent_str)) def __eq__(self, other): try: return self.data == other.data and self.children == other.children except AttributeError: return False def __ne__(self, other): return not (self == other) def __hash__(self): return hash((self.data, tuple(self.children))) def iter_subtrees(self): # TODO: Re-write as a more efficient version visited = set() q = [self] l = [] while q: subtree = q.pop() l.append( subtree ) if id(subtree) in visited: continue # already been here from another branch visited.add(id(subtree)) q += [c for c in subtree.children if isinstance(c, Tree)] seen = set() for x in reversed(l): if id(x) not in seen: yield x seen.add(id(x)) def find_pred(self, pred): "Find all nodes where pred(tree) == True" return filter(pred, self.iter_subtrees()) def find_data(self, data): "Find all nodes where tree.data == data" return self.find_pred(lambda t: t.data == data) from inspect import getmembers, getmro class Discard(Exception): pass # Transformers class _Decoratable: @classmethod def _apply_decorator(cls, decorator, **kwargs): mro = getmro(cls) assert mro[0] is cls libmembers = {name for _cls in mro[1:] for name, _ in getmembers(_cls)} for name, value in getmembers(cls): # Make sure the function isn't inherited (unless it's overwritten) if name.startswith('_') or (name in libmembers and name not in cls.__dict__): continue if not callable(cls.__dict__[name]): continue # Skip if v_args already applied (at the function level) if hasattr(cls.__dict__[name], 'vargs_applied'): continue static = isinstance(cls.__dict__[name], (staticmethod, classmethod)) setattr(cls, name, decorator(value, static=static, **kwargs)) return cls def __class_getitem__(cls, _): return cls class Transformer(_Decoratable): """Visits the tree recursively, starting with the leaves and finally the root (bottom-up) Calls its methods (provided by user via inheritance) according to tree.data The returned value replaces the old one in the structure. Can be used to implement map or reduce. """ __visit_tokens__ = True # For backwards compatibility def __init__(self, visit_tokens=True): self.__visit_tokens__ = visit_tokens def _call_userfunc(self, tree, new_children=None): # Assumes tree is already transformed children = new_children if new_children is not None else tree.children try: f = getattr(self, tree.data) except AttributeError: return self.__default__(tree.data, children, tree.meta) else: try: wrapper = getattr(f, 'visit_wrapper', None) if wrapper is not None: return f.visit_wrapper(f, tree.data, children, tree.meta) else: return f(children) except (GrammarError, Discard): raise except Exception as e: raise VisitError(tree.data, tree, e) def _call_userfunc_token(self, token): try: f = getattr(self, token.type) except AttributeError: return self.__default_token__(token) else: try: return f(token) except (GrammarError, Discard): raise except Exception as e: raise VisitError(token.type, token, e) def _transform_children(self, children): for c in children: try: if isinstance(c, Tree): yield self._transform_tree(c) elif self.__visit_tokens__ and isinstance(c, Token): yield self._call_userfunc_token(c) else: yield c except Discard: pass def _transform_tree(self, tree): children = list(self._transform_children(tree.children)) return self._call_userfunc(tree, children) def transform(self, tree): return self._transform_tree(tree) def __mul__(self, other): return TransformerChain(self, other) def __default__(self, data, children, meta): "Default operation on tree (for override)" return Tree(data, children, meta) def __default_token__(self, token): "Default operation on token (for override)" return token class InlineTransformer(Transformer): # XXX Deprecated def _call_userfunc(self, tree, new_children=None): # Assumes tree is already transformed children = new_children if new_children is not None else tree.children try: f = getattr(self, tree.data) except AttributeError: return self.__default__(tree.data, children, tree.meta) else: return f(*children) class TransformerChain(object): def __init__(self, *transformers): self.transformers = transformers def transform(self, tree): for t in self.transformers: tree = t.transform(tree) return tree def __mul__(self, other): return TransformerChain(*self.transformers + (other,)) class Transformer_InPlace(Transformer): "Non-recursive. Changes the tree in-place instead of returning new instances" def _transform_tree(self, tree): # Cancel recursion return self._call_userfunc(tree) def transform(self, tree): for subtree in tree.iter_subtrees(): subtree.children = list(self._transform_children(subtree.children)) return self._transform_tree(tree) class Transformer_InPlaceRecursive(Transformer): "Recursive. Changes the tree in-place instead of returning new instances" def _transform_tree(self, tree): tree.children = list(self._transform_children(tree.children)) return self._call_userfunc(tree) # Visitors class VisitorBase: def _call_userfunc(self, tree): return getattr(self, tree.data, self.__default__)(tree) def __default__(self, tree): "Default operation on tree (for override)" return tree def __class_getitem__(cls, _): return cls class Visitor(VisitorBase): """Bottom-up visitor, non-recursive Visits the tree, starting with the leaves and finally the root (bottom-up) Calls its methods (provided by user via inheritance) according to tree.data """ def visit(self, tree): for subtree in tree.iter_subtrees(): self._call_userfunc(subtree) return tree def visit_topdown(self,tree): for subtree in tree.iter_subtrees_topdown(): self._call_userfunc(subtree) return tree class Visitor_Recursive(VisitorBase): """Bottom-up visitor, recursive Visits the tree, starting with the leaves and finally the root (bottom-up) Calls its methods (provided by user via inheritance) according to tree.data """ def visit(self, tree): for child in tree.children: if isinstance(child, Tree): self.visit(child) self._call_userfunc(tree) return tree def visit_topdown(self,tree): self._call_userfunc(tree) for child in tree.children: if isinstance(child, Tree): self.visit_topdown(child) return tree def visit_children_decor(func): "See Interpreter" @wraps(func) def inner(cls, tree): values = cls.visit_children(tree) return func(cls, values) return inner class Interpreter(_Decoratable): """Top-down visitor, recursive Visits the tree, starting with the root and finally the leaves (top-down) Calls its methods (provided by user via inheritance) according to tree.data Unlike Transformer and Visitor, the Interpreter doesn't automatically visit its sub-branches. The user has to explicitly call visit_children, or use the @visit_children_decor """ def visit(self, tree): f = getattr(self, tree.data) wrapper = getattr(f, 'visit_wrapper', None) if wrapper is not None: return f.visit_wrapper(f, tree.data, tree.children, tree.meta) else: return f(tree) def visit_children(self, tree): return [self.visit(child) if isinstance(child, Tree) else child for child in tree.children] def __getattr__(self, name): return self.__default__ def __default__(self, tree): return self.visit_children(tree) # Decorators def _apply_decorator(obj, decorator, **kwargs): try: _apply = obj._apply_decorator except AttributeError: return decorator(obj, **kwargs) else: return _apply(decorator, **kwargs) def _inline_args__func(func): @wraps(func) def create_decorator(_f, with_self): if with_self: def f(self, children): return _f(self, *children) else: def f(self, children): return _f(*children) return f return smart_decorator(func, create_decorator) def inline_args(obj): # XXX Deprecated return _apply_decorator(obj, _inline_args__func) def _visitor_args_func_dec(func, visit_wrapper=None, static=False): def create_decorator(_f, with_self): if with_self: def f(self, *args, **kwargs): return _f(self, *args, **kwargs) else: def f(self, *args, **kwargs): return _f(*args, **kwargs) return f if static: f = wraps(func)(create_decorator(func, False)) else: f = smart_decorator(func, create_decorator) f.vargs_applied = True f.visit_wrapper = visit_wrapper return f def _vargs_inline(f, data, children, meta): return f(*children) def _vargs_meta_inline(f, data, children, meta): return f(meta, *children) def _vargs_meta(f, data, children, meta): return f(children, meta) # TODO swap these for consistency? Backwards incompatible! def _vargs_tree(f, data, children, meta): return f(Tree(data, children, meta)) def v_args(inline=False, meta=False, tree=False, wrapper=None): "A convenience decorator factory, for modifying the behavior of user-supplied visitor methods" if tree and (meta or inline): raise ValueError("Visitor functions cannot combine 'tree' with 'meta' or 'inline'.") func = None if meta: if inline: func = _vargs_meta_inline else: func = _vargs_meta elif inline: func = _vargs_inline elif tree: func = _vargs_tree if wrapper is not None: if func is not None: raise ValueError("Cannot use 'wrapper' along with 'tree', 'meta' or 'inline'.") func = wrapper def _visitor_args_dec(obj): return _apply_decorator(obj, _visitor_args_func_dec, visit_wrapper=func) return _visitor_args_dec class Indenter: def __init__(self): self.paren_level = None self.indent_level = None assert self.tab_len > 0 def handle_NL(self, token): if self.paren_level > 0: return yield token indent_str = token.rsplit('\n', 1)[1] # Tabs and spaces indent = indent_str.count(' ') + indent_str.count('\t') * self.tab_len if indent > self.indent_level[-1]: self.indent_level.append(indent) yield Token.new_borrow_pos(self.INDENT_type, indent_str, token) else: while indent < self.indent_level[-1]: self.indent_level.pop() yield Token.new_borrow_pos(self.DEDENT_type, indent_str, token) assert indent == self.indent_level[-1], '%s != %s' % (indent, self.indent_level[-1]) def _process(self, stream): for token in stream: if token.type == self.NL_type: for t in self.handle_NL(token): yield t else: yield token if token.type in self.OPEN_PAREN_types: self.paren_level += 1 elif token.type in self.CLOSE_PAREN_types: self.paren_level -= 1 assert self.paren_level >= 0 while len(self.indent_level) > 1: self.indent_level.pop() yield Token(self.DEDENT_type, '') assert self.indent_level == [0], self.indent_level def process(self, stream): self.paren_level = 0 self.indent_level = [0] return self._process(stream) # XXX Hack for ContextualLexer. Maybe there's a more elegant solution? @property def always_accept(self): return (self.NL_type,) class Symbol(Serialize): __slots__ = ('name',) is_term = NotImplemented def __init__(self, name): self.name = name def __eq__(self, other): assert isinstance(other, Symbol), other return self.is_term == other.is_term and self.name == other.name def __ne__(self, other): return not (self == other) def __hash__(self): return hash(self.name) def __repr__(self): return '%s(%r)' % (type(self).__name__, self.name) fullrepr = property(__repr__) class Terminal(Symbol): __serialize_fields__ = 'name', 'filter_out' is_term = True def __init__(self, name, filter_out=False): self.name = name self.filter_out = filter_out @property def fullrepr(self): return '%s(%r, %r)' % (type(self).__name__, self.name, self.filter_out) class NonTerminal(Symbol): __serialize_fields__ = 'name', is_term = False class RuleOptions(Serialize): __serialize_fields__ = 'keep_all_tokens', 'expand1', 'priority', 'empty_indices' def __init__(self, keep_all_tokens=False, expand1=False, priority=None, empty_indices=()): self.keep_all_tokens = keep_all_tokens self.expand1 = expand1 self.priority = priority self.empty_indices = empty_indices def __repr__(self): return 'RuleOptions(%r, %r, %r)' % ( self.keep_all_tokens, self.expand1, self.priority, ) class Rule(Serialize): """ origin : a symbol expansion : a list of symbols order : index of this expansion amongst all rules of the same name """ __slots__ = ('origin', 'expansion', 'alias', 'options', 'order', '_hash') __serialize_fields__ = 'origin', 'expansion', 'order', 'alias', 'options' __serialize_namespace__ = Terminal, NonTerminal, RuleOptions def __init__(self, origin, expansion, order=0, alias=None, options=None): self.origin = origin self.expansion = expansion self.alias = alias self.order = order self.options = options or RuleOptions() self._hash = hash((self.origin, tuple(self.expansion))) def _deserialize(self): self._hash = hash((self.origin, tuple(self.expansion))) def __str__(self): return '<%s : %s>' % (self.origin.name, ' '.join(x.name for x in self.expansion)) def __repr__(self): return 'Rule(%r, %r, %r, %r)' % (self.origin, self.expansion, self.alias, self.options) def __hash__(self): return self._hash def __eq__(self, other): if not isinstance(other, Rule): return False return self.origin == other.origin and self.expansion == other.expansion class Pattern(Serialize): def __init__(self, value, flags=()): self.value = value self.flags = frozenset(flags) def __repr__(self): return repr(self.to_regexp()) # Pattern Hashing assumes all subclasses have a different priority! def __hash__(self): return hash((type(self), self.value, self.flags)) def __eq__(self, other): return type(self) == type(other) and self.value == other.value and self.flags == other.flags def to_regexp(self): raise NotImplementedError() if Py36: # Python 3.6 changed syntax for flags in regular expression def _get_flags(self, value): for f in self.flags: value = ('(?%s:%s)' % (f, value)) return value else: def _get_flags(self, value): for f in self.flags: value = ('(?%s)' % f) + value return value class PatternStr(Pattern): __serialize_fields__ = 'value', 'flags' type = "str" def to_regexp(self): return self._get_flags(re.escape(self.value)) @property def min_width(self): return len(self.value) max_width = min_width class PatternRE(Pattern): __serialize_fields__ = 'value', 'flags', '_width' type = "re" def to_regexp(self): return self._get_flags(self.value) _width = None def _get_width(self): if self._width is None: self._width = get_regexp_width(self.to_regexp()) return self._width @property def min_width(self): return self._get_width()[0] @property def max_width(self): return self._get_width()[1] class TerminalDef(Serialize): __serialize_fields__ = 'name', 'pattern', 'priority' __serialize_namespace__ = PatternStr, PatternRE def __init__(self, name, pattern, priority=1): assert isinstance(pattern, Pattern), pattern self.name = name self.pattern = pattern self.priority = priority def __repr__(self): return '%s(%r, %r)' % (type(self).__name__, self.name, self.pattern) class Token(Str): __slots__ = ('type', 'pos_in_stream', 'value', 'line', 'column', 'end_line', 'end_column', 'end_pos') def __new__(cls, type_, value, pos_in_stream=None, line=None, column=None, end_line=None, end_column=None, end_pos=None): try: self = super(Token, cls).__new__(cls, value) except UnicodeDecodeError: value = value.decode('latin1') self = super(Token, cls).__new__(cls, value) self.type = type_ self.pos_in_stream = pos_in_stream self.value = value self.line = line self.column = column self.end_line = end_line self.end_column = end_column self.end_pos = end_pos return self def update(self, type_=None, value=None): return Token.new_borrow_pos( type_ if type_ is not None else self.type, value if value is not None else self.value, self ) @classmethod def new_borrow_pos(cls, type_, value, borrow_t): return cls(type_, value, borrow_t.pos_in_stream, borrow_t.line, borrow_t.column, borrow_t.end_line, borrow_t.end_column, borrow_t.end_pos) def __reduce__(self): return (self.__class__, (self.type, self.value, self.pos_in_stream, self.line, self.column, )) def __repr__(self): return 'Token(%s, %r)' % (self.type, self.value) def __deepcopy__(self, memo): return Token(self.type, self.value, self.pos_in_stream, self.line, self.column) def __eq__(self, other): if isinstance(other, Token) and self.type != other.type: return False return Str.__eq__(self, other) __hash__ = Str.__hash__ class LineCounter: def __init__(self): self.newline_char = '\n' self.char_pos = 0 self.line = 1 self.column = 1 self.line_start_pos = 0 def feed(self, token, test_newline=True): """Consume a token and calculate the new line & column. As an optional optimization, set test_newline=False is token doesn't contain a newline. """ if test_newline: newlines = token.count(self.newline_char) if newlines: self.line += newlines self.line_start_pos = self.char_pos + token.rindex(self.newline_char) + 1 self.char_pos += len(token) self.column = self.char_pos - self.line_start_pos + 1 class _Lex: "Built to serve both Lexer and ContextualLexer" def __init__(self, lexer, state=None): self.lexer = lexer self.state = state def lex(self, stream, newline_types, ignore_types): newline_types = frozenset(newline_types) ignore_types = frozenset(ignore_types) line_ctr = LineCounter() last_token = None while line_ctr.char_pos < len(stream): lexer = self.lexer res = lexer.match(stream, line_ctr.char_pos) if not res: allowed = {v for m, tfi in lexer.mres for v in tfi.values()} - ignore_types if not allowed: allowed = {""} raise UnexpectedCharacters(stream, line_ctr.char_pos, line_ctr.line, line_ctr.column, allowed=allowed, state=self.state, token_history=last_token and [last_token]) value, type_ = res if type_ not in ignore_types: t = Token(type_, value, line_ctr.char_pos, line_ctr.line, line_ctr.column) line_ctr.feed(value, type_ in newline_types) t.end_line = line_ctr.line t.end_column = line_ctr.column t.end_pos = line_ctr.char_pos if t.type in lexer.callback: t = lexer.callback[t.type](t) if not isinstance(t, Token): raise ValueError("Callbacks must return a token (returned %r)" % t) yield t last_token = t else: if type_ in lexer.callback: t2 = Token(type_, value, line_ctr.char_pos, line_ctr.line, line_ctr.column) lexer.callback[type_](t2) line_ctr.feed(value, type_ in newline_types) class UnlessCallback: def __init__(self, mres): self.mres = mres def __call__(self, t): for mre, type_from_index in self.mres: m = mre.match(t.value) if m: t.type = type_from_index[m.lastindex] break return t class CallChain: def __init__(self, callback1, callback2, cond): self.callback1 = callback1 self.callback2 = callback2 self.cond = cond def __call__(self, t): t2 = self.callback1(t) return self.callback2(t) if self.cond(t2) else t2 def _create_unless(terminals, g_regex_flags): tokens_by_type = classify(terminals, lambda t: type(t.pattern)) assert len(tokens_by_type) <= 2, tokens_by_type.keys() embedded_strs = set() callback = {} for retok in tokens_by_type.get(PatternRE, []): unless = [] # {} for strtok in tokens_by_type.get(PatternStr, []): if strtok.priority > retok.priority: continue s = strtok.pattern.value m = re.match(retok.pattern.to_regexp(), s, g_regex_flags) if m and m.group(0) == s: unless.append(strtok) if strtok.pattern.flags <= retok.pattern.flags: embedded_strs.add(strtok) if unless: callback[retok.name] = UnlessCallback(build_mres(unless, g_regex_flags, match_whole=True)) terminals = [t for t in terminals if t not in embedded_strs] return terminals, callback def _build_mres(terminals, max_size, g_regex_flags, match_whole): # Python sets an unreasonable group limit (currently 100) in its re module # Worse, the only way to know we reached it is by catching an AssertionError! # This function recursively tries less and less groups until it's successful. postfix = '$' if match_whole else '' mres = [] while terminals: try: mre = re.compile(u'|'.join(u'(?P<%s>%s)'%(t.name, t.pattern.to_regexp()+postfix) for t in terminals[:max_size]), g_regex_flags) except AssertionError: # Yes, this is what Python provides us.. :/ return _build_mres(terminals, max_size//2, g_regex_flags, match_whole) # terms_from_name = {t.name: t for t in terminals[:max_size]} mres.append((mre, {i:n for n,i in mre.groupindex.items()} )) terminals = terminals[max_size:] return mres def build_mres(terminals, g_regex_flags, match_whole=False): return _build_mres(terminals, len(terminals), g_regex_flags, match_whole) def _regexp_has_newline(r): r"""Expressions that may indicate newlines in a regexp: - newlines (\n) - escaped newline (\\n) - anything but ([^...]) - any-char (.) when the flag (?s) exists - spaces (\s) """ return '\n' in r or '\\n' in r or '\\s' in r or '[^' in r or ('(?s' in r and '.' in r) class Lexer(object): """Lexer interface Method Signatures: lex(self, stream) -> Iterator[Token] """ lex = NotImplemented class TraditionalLexer(Lexer): def __init__(self, terminals, ignore=(), user_callbacks={}, g_regex_flags=0): assert all(isinstance(t, TerminalDef) for t in terminals), terminals terminals = list(terminals) # Sanitization for t in terminals: try: re.compile(t.pattern.to_regexp(), g_regex_flags) except re.error: raise LexError("Cannot compile token %s: %s" % (t.name, t.pattern)) if t.pattern.min_width == 0: raise LexError("Lexer does not allow zero-width terminals. (%s: %s)" % (t.name, t.pattern)) assert set(ignore) <= {t.name for t in terminals} # Init self.newline_types = [t.name for t in terminals if _regexp_has_newline(t.pattern.to_regexp())] self.ignore_types = list(ignore) terminals.sort(key=lambda x:(-x.priority, -x.pattern.max_width, -len(x.pattern.value), x.name)) self.terminals = terminals self.user_callbacks = user_callbacks self.build(g_regex_flags) def build(self, g_regex_flags=0): terminals, self.callback = _create_unless(self.terminals, g_regex_flags) assert all(self.callback.values()) for type_, f in self.user_callbacks.items(): if type_ in self.callback: # Already a callback there, probably UnlessCallback self.callback[type_] = CallChain(self.callback[type_], f, lambda t: t.type == type_) else: self.callback[type_] = f self.mres = build_mres(terminals, g_regex_flags) def match(self, stream, pos): for mre, type_from_index in self.mres: m = mre.match(stream, pos) if m: return m.group(0), type_from_index[m.lastindex] def lex(self, stream): return _Lex(self).lex(stream, self.newline_types, self.ignore_types) class ContextualLexer(Lexer): def __init__(self, terminals, states, ignore=(), always_accept=(), user_callbacks={}, g_regex_flags=0): tokens_by_name = {} for t in terminals: assert t.name not in tokens_by_name, t tokens_by_name[t.name] = t lexer_by_tokens = {} self.lexers = {} for state, accepts in states.items(): key = frozenset(accepts) try: lexer = lexer_by_tokens[key] except KeyError: accepts = set(accepts) | set(ignore) | set(always_accept) state_tokens = [tokens_by_name[n] for n in accepts if n and n in tokens_by_name] lexer = TraditionalLexer(state_tokens, ignore=ignore, user_callbacks=user_callbacks, g_regex_flags=g_regex_flags) lexer_by_tokens[key] = lexer self.lexers[state] = lexer self.root_lexer = TraditionalLexer(terminals, ignore=ignore, user_callbacks=user_callbacks, g_regex_flags=g_regex_flags) def lex(self, stream, get_parser_state): parser_state = get_parser_state() l = _Lex(self.lexers[parser_state], parser_state) try: for x in l.lex(stream, self.root_lexer.newline_types, self.root_lexer.ignore_types): yield x parser_state = get_parser_state() l.lexer = self.lexers[parser_state] l.state = parser_state # For debug only, no need to worry about multithreading except UnexpectedCharacters as e: # In the contextual lexer, UnexpectedCharacters can mean that the terminal is defined, # but not in the current context. # This tests the input against the global context, to provide a nicer error. root_match = self.root_lexer.match(stream, e.pos_in_stream) if not root_match: raise value, type_ = root_match t = Token(type_, value, e.pos_in_stream, e.line, e.column) raise UnexpectedToken(t, e.allowed, state=e.state) class LexerConf(Serialize): __serialize_fields__ = 'tokens', 'ignore', 'g_regex_flags' __serialize_namespace__ = TerminalDef, def __init__(self, tokens, ignore=(), postlex=None, callbacks=None, g_regex_flags=0): self.tokens = tokens self.ignore = ignore self.postlex = postlex self.callbacks = callbacks or {} self.g_regex_flags = g_regex_flags def _deserialize(self): self.callbacks = {} # TODO from functools import partial, wraps from itertools import repeat, product class ExpandSingleChild: def __init__(self, node_builder): self.node_builder = node_builder def __call__(self, children): if len(children) == 1: return children[0] else: return self.node_builder(children) class PropagatePositions: def __init__(self, node_builder): self.node_builder = node_builder def __call__(self, children): res = self.node_builder(children) if isinstance(res, Tree): for c in children: if isinstance(c, Tree) and not c.meta.empty: res.meta.line = c.meta.line res.meta.column = c.meta.column res.meta.start_pos = c.meta.start_pos res.meta.empty = False break elif isinstance(c, Token): res.meta.line = c.line res.meta.column = c.column res.meta.start_pos = c.pos_in_stream res.meta.empty = False break for c in reversed(children): if isinstance(c, Tree) and not c.meta.empty: res.meta.end_line = c.meta.end_line res.meta.end_column = c.meta.end_column res.meta.end_pos = c.meta.end_pos res.meta.empty = False break elif isinstance(c, Token): res.meta.end_line = c.end_line res.meta.end_column = c.end_column res.meta.end_pos = c.end_pos res.meta.empty = False break return res class ChildFilter: def __init__(self, to_include, append_none, node_builder): self.node_builder = node_builder self.to_include = to_include self.append_none = append_none def __call__(self, children): filtered = [] for i, to_expand, add_none in self.to_include: if add_none: filtered += [None] * add_none if to_expand: filtered += children[i].children else: filtered.append(children[i]) if self.append_none: filtered += [None] * self.append_none return self.node_builder(filtered) class ChildFilterLALR(ChildFilter): "Optimized childfilter for LALR (assumes no duplication in parse tree, so it's safe to change it)" def __call__(self, children): filtered = [] for i, to_expand, add_none in self.to_include: if add_none: filtered += [None] * add_none if to_expand: if filtered: filtered += children[i].children else: # Optimize for left-recursion filtered = children[i].children else: filtered.append(children[i]) if self.append_none: filtered += [None] * self.append_none return self.node_builder(filtered) class ChildFilterLALR_NoPlaceholders(ChildFilter): "Optimized childfilter for LALR (assumes no duplication in parse tree, so it's safe to change it)" def __init__(self, to_include, node_builder): self.node_builder = node_builder self.to_include = to_include def __call__(self, children): filtered = [] for i, to_expand in self.to_include: if to_expand: if filtered: filtered += children[i].children else: # Optimize for left-recursion filtered = children[i].children else: filtered.append(children[i]) return self.node_builder(filtered) def _should_expand(sym): return not sym.is_term and sym.name.startswith('_') def maybe_create_child_filter(expansion, keep_all_tokens, ambiguous, _empty_indices): # Prepare empty_indices as: How many Nones to insert at each index? if _empty_indices: assert _empty_indices.count(False) == len(expansion) s = ''.join(str(int(b)) for b in _empty_indices) empty_indices = [len(ones) for ones in s.split('0')] assert len(empty_indices) == len(expansion)+1, (empty_indices, len(expansion)) else: empty_indices = [0] * (len(expansion)+1) to_include = [] nones_to_add = 0 for i, sym in enumerate(expansion): nones_to_add += empty_indices[i] if keep_all_tokens or not (sym.is_term and sym.filter_out): to_include.append((i, _should_expand(sym), nones_to_add)) nones_to_add = 0 nones_to_add += empty_indices[len(expansion)] if _empty_indices or len(to_include) < len(expansion) or any(to_expand for i, to_expand,_ in to_include): if _empty_indices or ambiguous: return partial(ChildFilter if ambiguous else ChildFilterLALR, to_include, nones_to_add) else: # LALR without placeholders return partial(ChildFilterLALR_NoPlaceholders, [(i, x) for i,x,_ in to_include]) class AmbiguousExpander: """Deal with the case where we're expanding children ('_rule') into a parent but the children are ambiguous. i.e. (parent->_ambig->_expand_this_rule). In this case, make the parent itself ambiguous with as many copies as their are ambiguous children, and then copy the ambiguous children into the right parents in the right places, essentially shifting the ambiguiuty up the tree.""" def __init__(self, to_expand, tree_class, node_builder): self.node_builder = node_builder self.tree_class = tree_class self.to_expand = to_expand def __call__(self, children): def _is_ambig_tree(child): return hasattr(child, 'data') and child.data == '_ambig' #### When we're repeatedly expanding ambiguities we can end up with nested ambiguities. # All children of an _ambig node should be a derivation of that ambig node, hence # it is safe to assume that if we see an _ambig node nested within an ambig node # it is safe to simply expand it into the parent _ambig node as an alternative derivation. ambiguous = [] for i, child in enumerate(children): if _is_ambig_tree(child): if i in self.to_expand: ambiguous.append(i) to_expand = [j for j, grandchild in enumerate(child.children) if _is_ambig_tree(grandchild)] child.expand_kids_by_index(*to_expand) if not ambiguous: return self.node_builder(children) expand = [ iter(child.children) if i in ambiguous else repeat(child) for i, child in enumerate(children) ] return self.tree_class('_ambig', [self.node_builder(list(f[0])) for f in product(zip(*expand))]) def maybe_create_ambiguous_expander(tree_class, expansion, keep_all_tokens): to_expand = [i for i, sym in enumerate(expansion) if keep_all_tokens or ((not (sym.is_term and sym.filter_out)) and _should_expand(sym))] if to_expand: return partial(AmbiguousExpander, to_expand, tree_class) def ptb_inline_args(func): @wraps(func) def f(children): return func(*children) return f def inplace_transformer(func): @wraps(func) def f(children): # function name in a Transformer is a rule name. tree = Tree(func.__name__, children) return func(tree) return f def apply_visit_wrapper(func, name, wrapper): if wrapper is _vargs_meta or wrapper is _vargs_meta_inline: raise NotImplementedError("Meta args not supported for internal transformer") @wraps(func) def f(children): return wrapper(func, name, children, None) return f class ParseTreeBuilder: def __init__(self, rules, tree_class, propagate_positions=False, keep_all_tokens=False, ambiguous=False, maybe_placeholders=False): self.tree_class = tree_class self.propagate_positions = propagate_positions self.always_keep_all_tokens = keep_all_tokens self.ambiguous = ambiguous self.maybe_placeholders = maybe_placeholders self.rule_builders = list(self._init_builders(rules)) def _init_builders(self, rules): for rule in rules: options = rule.options keep_all_tokens = self.always_keep_all_tokens or options.keep_all_tokens expand_single_child = options.expand1 wrapper_chain = list(filter(None, [ (expand_single_child and not rule.alias) and ExpandSingleChild, maybe_create_child_filter(rule.expansion, keep_all_tokens, self.ambiguous, options.empty_indices if self.maybe_placeholders else None), self.propagate_positions and PropagatePositions, self.ambiguous and maybe_create_ambiguous_expander(self.tree_class, rule.expansion, keep_all_tokens), ])) yield rule, wrapper_chain def create_callback(self, transformer=None): callbacks = {} for rule, wrapper_chain in self.rule_builders: user_callback_name = rule.alias or rule.origin.name try: f = getattr(transformer, user_callback_name) # XXX InlineTransformer is deprecated! wrapper = getattr(f, 'visit_wrapper', None) if wrapper is not None: f = apply_visit_wrapper(f, user_callback_name, wrapper) else: if isinstance(transformer, InlineTransformer): f = ptb_inline_args(f) elif isinstance(transformer, Transformer_InPlace): f = inplace_transformer(f) except AttributeError: f = partial(self.tree_class, user_callback_name) for w in wrapper_chain: f = w(f) if rule in callbacks: raise GrammarError("Rule '%s' already exists" % (rule,)) callbacks[rule] = f return callbacks class LALR_Parser(object): def __init__(self, parser_conf, debug=False): assert all(r.options.priority is None for r in parser_conf.rules), "LALR doesn't yet support prioritization" analysis = LALR_Analyzer(parser_conf, debug=debug) analysis.compute_lalr() callbacks = parser_conf.callbacks self._parse_table = analysis.parse_table self.parser_conf = parser_conf self.parser = _Parser(analysis.parse_table, callbacks) @classmethod def deserialize(cls, data, memo, callbacks): inst = cls.__new__(cls) inst._parse_table = IntParseTable.deserialize(data, memo) inst.parser = _Parser(inst._parse_table, callbacks) return inst def serialize(self, memo): return self._parse_table.serialize(memo) def parse(self, *args): return self.parser.parse(*args) class _Parser: def __init__(self, parse_table, callbacks): self.states = parse_table.states self.start_states = parse_table.start_states self.end_states = parse_table.end_states self.callbacks = callbacks def parse(self, seq, start, set_state=None): token = None stream = iter(seq) states = self.states start_state = self.start_states[start] end_state = self.end_states[start] state_stack = [start_state] value_stack = [] if set_state: set_state(start_state) def get_action(token): state = state_stack[-1] try: return states[state][token.type] except KeyError: expected = [s for s in states[state].keys() if s.isupper()] raise UnexpectedToken(token, expected, state=state) def reduce(rule): size = len(rule.expansion) if size: s = value_stack[-size:] del state_stack[-size:] del value_stack[-size:] else: s = [] value = self.callbacks[rule](s) _action, new_state = states[state_stack[-1]][rule.origin.name] assert _action is Shift state_stack.append(new_state) value_stack.append(value) # Main LALR-parser loop for token in stream: while True: action, arg = get_action(token) assert arg != end_state if action is Shift: state_stack.append(arg) value_stack.append(token) if set_state: set_state(arg) break # next token else: reduce(arg) token = Token.new_borrow_pos('$END', '', token) if token else Token('$END', '', 0, 1, 1) while True: _action, arg = get_action(token) assert(_action is Reduce) reduce(arg) if state_stack[-1] == end_state: return value_stack[-1] class Action: def __init__(self, name): self.name = name def __str__(self): return self.name def __repr__(self): return str(self) Shift = Action('Shift') Reduce = Action('Reduce') class ParseTable: def __init__(self, states, start_states, end_states): self.states = states self.start_states = start_states self.end_states = end_states def serialize(self, memo): tokens = Enumerator() rules = Enumerator() states = { state: {tokens.get(token): ((1, arg.serialize(memo)) if action is Reduce else (0, arg)) for token, (action, arg) in actions.items()} for state, actions in self.states.items() } return { 'tokens': tokens.reversed(), 'states': states, 'start_states': self.start_states, 'end_states': self.end_states, } @classmethod def deserialize(cls, data, memo): tokens = data['tokens'] states = { state: {tokens[token]: ((Reduce, Rule.deserialize(arg, memo)) if action==1 else (Shift, arg)) for token, (action, arg) in actions.items()} for state, actions in data['states'].items() } return cls(states, data['start_states'], data['end_states']) class IntParseTable(ParseTable): @classmethod def from_ParseTable(cls, parse_table): enum = list(parse_table.states) state_to_idx = {s:i for i,s in enumerate(enum)} int_states = {} for s, la in parse_table.states.items(): la = {k:(v[0], state_to_idx[v[1]]) if v[0] is Shift else v for k,v in la.items()} int_states[ state_to_idx[s] ] = la start_states = {start:state_to_idx[s] for start, s in parse_table.start_states.items()} end_states = {start:state_to_idx[s] for start, s in parse_table.end_states.items()} return cls(int_states, start_states, end_states) def get_frontend(parser, lexer): if parser=='lalr': if lexer is None: raise ValueError('The LALR parser requires use of a lexer') elif lexer == 'standard': return LALR_TraditionalLexer elif lexer == 'contextual': return LALR_ContextualLexer elif issubclass(lexer, Lexer): return partial(LALR_CustomLexer, lexer) else: raise ValueError('Unknown lexer: %s' % lexer) elif parser=='earley': if lexer=='standard': return Earley elif lexer=='dynamic': return XEarley elif lexer=='dynamic_complete': return XEarley_CompleteLex elif lexer=='contextual': raise ValueError('The Earley parser does not support the contextual parser') else: raise ValueError('Unknown lexer: %s' % lexer) elif parser == 'cyk': if lexer == 'standard': return CYK else: raise ValueError('CYK parser requires using standard parser.') else: raise ValueError('Unknown parser: %s' % parser) class _ParserFrontend(Serialize): def _parse(self, input, start, *args): if start is None: start = self.start if len(start) > 1: raise ValueError("Lark initialized with more than 1 possible start rule. Must specify which start rule to parse", start) start ,= start return self.parser.parse(input, start, *args) class WithLexer(_ParserFrontend): lexer = None parser = None lexer_conf = None start = None __serialize_fields__ = 'parser', 'lexer_conf', 'start' __serialize_namespace__ = LexerConf, def __init__(self, lexer_conf, parser_conf, options=None): self.lexer_conf = lexer_conf self.start = parser_conf.start self.postlex = lexer_conf.postlex @classmethod def deserialize(cls, data, memo, callbacks, postlex): inst = super(WithLexer, cls).deserialize(data, memo) inst.postlex = postlex inst.parser = LALR_Parser.deserialize(inst.parser, memo, callbacks) inst.init_lexer() return inst def _serialize(self, data, memo): data['parser'] = data['parser'].serialize(memo) def lex(self, *args): stream = self.lexer.lex(*args) return self.postlex.process(stream) if self.postlex else stream def parse(self, text, start=None): token_stream = self.lex(text) return self._parse(token_stream, start) def init_traditional_lexer(self): self.lexer = TraditionalLexer(self.lexer_conf.tokens, ignore=self.lexer_conf.ignore, user_callbacks=self.lexer_conf.callbacks, g_regex_flags=self.lexer_conf.g_regex_flags) class LALR_WithLexer(WithLexer): def __init__(self, lexer_conf, parser_conf, options=None): debug = options.debug if options else False self.parser = LALR_Parser(parser_conf, debug=debug) WithLexer.__init__(self, lexer_conf, parser_conf, options) self.init_lexer() def init_lexer(self): raise NotImplementedError() class LALR_TraditionalLexer(LALR_WithLexer): def init_lexer(self): self.init_traditional_lexer() class LALR_ContextualLexer(LALR_WithLexer): def init_lexer(self): states = {idx:list(t.keys()) for idx, t in self.parser._parse_table.states.items()} always_accept = self.postlex.always_accept if self.postlex else () self.lexer = ContextualLexer(self.lexer_conf.tokens, states, ignore=self.lexer_conf.ignore, always_accept=always_accept, user_callbacks=self.lexer_conf.callbacks, g_regex_flags=self.lexer_conf.g_regex_flags) def parse(self, text, start=None): parser_state = [None] def set_parser_state(s): parser_state[0] = s token_stream = self.lex(text, lambda: parser_state[0]) return self._parse(token_stream, start, set_parser_state) class LarkOptions(Serialize): """Specifies the options for Lark """ OPTIONS_DOC = """ # General start - The start symbol. Either a string, or a list of strings for multiple possible starts (Default: "start") debug - Display debug information, such as warnings (default: False) transformer - Applies the transformer to every parse tree (equivlent to applying it after the parse, but faster) propagate_positions - Propagates (line, column, end_line, end_column) attributes into all tree branches. maybe_placeholders - When True, the `[]` operator returns `None` when not matched. When `False`, `[]` behaves like the `?` operator, and returns no value at all. (default=`False`. Recommended to set to `True`) cache_grammar - Cache the Lark grammar (Default: False) g_regex_flags - Flags that are applied to all terminals (both regex and strings) keep_all_tokens - Prevent the tree builder from automagically removing "punctuation" tokens (default: False) # Algorithm parser - Decides which parser engine to use Accepts "earley" or "lalr". (Default: "earley") (there is also a "cyk" option for legacy) lexer - Decides whether or not to use a lexer stage "auto" (default): Choose for me based on the parser "standard": Use a standard lexer "contextual": Stronger lexer (only works with parser="lalr") "dynamic": Flexible and powerful (only with parser="earley") "dynamic_complete": Same as dynamic, but tries *every* variation of tokenizing possible. ambiguity - Decides how to handle ambiguity in the parse. Only relevant if parser="earley" "resolve": The parser will automatically choose the simplest derivation (it chooses consistently: greedy for tokens, non-greedy for rules) "explicit": The parser will return all derivations wrapped in "_ambig" tree nodes (i.e. a forest). # Domain Specific postlex - Lexer post-processing (Default: None) Only works with the standard and contextual lexers. priority - How priorities should be evaluated - auto, none, normal, invert (Default: auto) lexer_callbacks - Dictionary of callbacks for the lexer. May alter tokens during lexing. Use with caution. edit_terminals - A callback """ if __doc__: __doc__ += OPTIONS_DOC _defaults = { 'debug': False, 'keep_all_tokens': False, 'tree_class': None, 'cache_grammar': False, 'postlex': None, 'parser': 'earley', 'lexer': 'auto', 'transformer': None, 'start': 'start', 'priority': 'auto', 'ambiguity': 'auto', 'propagate_positions': False, 'lexer_callbacks': {}, 'maybe_placeholders': False, 'edit_terminals': None, 'g_regex_flags': 0, } def __init__(self, options_dict): o = dict(options_dict) options = {} for name, default in self._defaults.items(): if name in o: value = o.pop(name) if isinstance(default, bool): value = bool(value) else: value = default options[name] = value if isinstance(options['start'], STRING_TYPE): options['start'] = [options['start']] self.__dict__['options'] = options assert self.parser in ('earley', 'lalr', 'cyk', None) if self.parser == 'earley' and self.transformer: raise ValueError('Cannot specify an embedded transformer when using the Earley algorithm.' 'Please use your transformer on the resulting parse tree, or use a different algorithm (i.e. LALR)') if o: raise ValueError("Unknown options: %s" % o.keys()) def __getattr__(self, name): try: return self.options[name] except KeyError as e: raise AttributeError(e) def __setattr__(self, name, value): assert name in self.options self.options[name] = value def serialize(self, memo): return self.options @classmethod def deserialize(cls, data, memo): return cls(data) class Lark(Serialize): def __init__(self, grammar, **options): """ grammar : a string or file-object containing the grammar spec (using Lark's ebnf syntax) options : a dictionary controlling various aspects of Lark. """ self.options = LarkOptions(options) # Some, but not all file-like objects have a 'name' attribute try: self.source = grammar.name except AttributeError: self.source = '' # Drain file-like objects to get their contents try: read = grammar.read except AttributeError: pass else: grammar = read() assert isinstance(grammar, STRING_TYPE) if self.options.cache_grammar: raise NotImplementedError("Not available yet") if self.options.lexer == 'auto': if self.options.parser == 'lalr': self.options.lexer = 'contextual' elif self.options.parser == 'earley': self.options.lexer = 'dynamic' elif self.options.parser == 'cyk': self.options.lexer = 'standard' else: assert False, self.options.parser lexer = self.options.lexer assert lexer in ('standard', 'contextual', 'dynamic', 'dynamic_complete') or issubclass(lexer, Lexer) if self.options.ambiguity == 'auto': if self.options.parser == 'earley': self.options.ambiguity = 'resolve' else: disambig_parsers = ['earley', 'cyk'] assert self.options.parser in disambig_parsers, ( 'Only %s supports disambiguation right now') % ', '.join(disambig_parsers) if self.options.priority == 'auto': if self.options.parser in ('earley', 'cyk', ): self.options.priority = 'normal' elif self.options.parser in ('lalr', ): self.options.priority = None elif self.options.priority in ('invert', 'normal'): assert self.options.parser in ('earley', 'cyk'), "priorities are not supported for LALR at this time" assert self.options.priority in ('auto', None, 'normal', 'invert'), 'invalid priority option specified: {}. options are auto, none, normal, invert.'.format(self.options.priority) assert self.options.ambiguity not in ('resolve__antiscore_sum', ), 'resolve__antiscore_sum has been replaced with the option priority="invert"' assert self.options.ambiguity in ('resolve', 'explicit', 'auto', ) # Parse the grammar file and compose the grammars (TODO) self.grammar = load_grammar(grammar, self.source) # Compile the EBNF grammar into BNF self.terminals, self.rules, self.ignore_tokens = self.grammar.compile(self.options.start) if self.options.edit_terminals: for t in self.terminals: self.options.edit_terminals(t) self._terminals_dict = {t.name:t for t in self.terminals} # If the user asked to invert the priorities, negate them all here. # This replaces the old 'resolve__antiscore_sum' option. if self.options.priority == 'invert': for rule in self.rules: if rule.options.priority is not None: rule.options.priority = -rule.options.priority # Else, if the user asked to disable priorities, strip them from the # rules. This allows the Earley parsers to skip an extra forest walk # for improved performance, if you don't need them (or didn't specify any). elif self.options.priority == None: for rule in self.rules: if rule.options.priority is not None: rule.options.priority = None # TODO Deprecate lexer_callbacks? lexer_callbacks = dict(self.options.lexer_callbacks) if self.options.transformer: t = self.options.transformer for term in self.terminals: if hasattr(t, term.name): lexer_callbacks[term.name] = getattr(t, term.name) self.lexer_conf = LexerConf(self.terminals, self.ignore_tokens, self.options.postlex, lexer_callbacks, self.options.g_regex_flags) if self.options.parser: self.parser = self._build_parser() elif lexer: self.lexer = self._build_lexer() if __init__.__doc__: __init__.__doc__ += "\nOptions:\n" + LarkOptions.OPTIONS_DOC __serialize_fields__ = 'parser', 'rules', 'options' def _build_lexer(self): return TraditionalLexer(self.lexer_conf.tokens, ignore=self.lexer_conf.ignore, user_callbacks=self.lexer_conf.callbacks, g_regex_flags=self.lexer_conf.g_regex_flags) def _prepare_callbacks(self): self.parser_class = get_frontend(self.options.parser, self.options.lexer) self._parse_tree_builder = ParseTreeBuilder(self.rules, self.options.tree_class or Tree, self.options.propagate_positions, self.options.keep_all_tokens, self.options.parser!='lalr' and self.options.ambiguity=='explicit', self.options.maybe_placeholders) self._callbacks = self._parse_tree_builder.create_callback(self.options.transformer) def _build_parser(self): self._prepare_callbacks() parser_conf = ParserConf(self.rules, self._callbacks, self.options.start) return self.parser_class(self.lexer_conf, parser_conf, options=self.options) @classmethod def deserialize(cls, data, namespace, memo, transformer=None, postlex=None): if memo: memo = SerializeMemoizer.deserialize(memo, namespace, {}) inst = cls.__new__(cls) options = dict(data['options']) if transformer is not None: options['transformer'] = transformer if postlex is not None: options['postlex'] = postlex inst.options = LarkOptions.deserialize(options, memo) inst.rules = [Rule.deserialize(r, memo) for r in data['rules']] inst.source = '' inst._prepare_callbacks() inst.parser = inst.parser_class.deserialize(data['parser'], memo, inst._callbacks, inst.options.postlex) return inst def save(self, f): data, m = self.memo_serialize([TerminalDef, Rule]) pickle.dump({'data': data, 'memo': m}, f) @classmethod def load(cls, f): d = pickle.load(f) namespace = {'Rule': Rule, 'TerminalDef': TerminalDef} memo = d['memo'] return Lark.deserialize(d['data'], namespace, memo) @classmethod def open(cls, grammar_filename, rel_to=None, **options): """Create an instance of Lark with the grammar given by its filename If rel_to is provided, the function will find the grammar filename in relation to it. Example: >>> Lark.open("grammar_file.lark", rel_to=__file__, parser="lalr") Lark(...) """ if rel_to: basepath = os.path.dirname(rel_to) grammar_filename = os.path.join(basepath, grammar_filename) with open(grammar_filename, encoding='utf8') as f: return cls(f, **options) def __repr__(self): return 'Lark(open(%r), parser=%r, lexer=%r, ...)' % (self.source, self.options.parser, self.options.lexer) def lex(self, text): "Only lex (and postlex) the text, without parsing it. Only relevant when lexer='standard'" if not hasattr(self, 'lexer'): self.lexer = self._build_lexer() stream = self.lexer.lex(text) if self.options.postlex: return self.options.postlex.process(stream) return stream def get_terminal(self, name): "Get information about a terminal" return self._terminals_dict[name] def parse(self, text, start=None): """Parse the given text, according to the options provided. The 'start' parameter is required if Lark was given multiple possible start symbols (using the start option). Returns a tree, unless specified otherwise. """ return self.parser.parse(text, start=start) DATA = ( {'parser': {'parser': {'tokens': {0: 'NAME', 1: 'series', 2: 'element', 3: 'LSQB', 4: 'STAR', 5: 'metadata', 6: 'trait', 7: 'series_terminal', 8: 'anytrait', 9: 'PLUS', 10: 'ITEMS', 11: 'items', 12: '$END', 13: 'COMMA', 14: 'DOT', 15: 'RSQB', 16: 'COLON', 17: 'notify', 18: 'quiet', 19: 'parallel', 20: 'start', 21: 'parallel_terminal'}, 'states': {0: {0: (0, 29)}, 1: {1: (0, 19), 2: (0, 34), 3: (0, 22), 0: (0, 9), 4: (0, 3), 5: (0, 30), 6: (0, 12), 7: (0, 13), 8: (0, 24), 9: (0, 0), 10: (0, 18), 11: (0, 14)}, 2: {5: (0, 30), 2: (0, 16), 8: (0, 8), 6: (0, 12), 4: (0, 3), 0: (0, 9), 3: (0, 22), 9: (0, 0), 10: (0, 18), 11: (0, 14)}, 3: {12: (1, {'@': 10}), 13: (1, {'@': 10})}, 4: {13: (1, {'@': 11}), 14: (1, {'@': 11}), 15: (1, {'@': 11}), 16: (1, {'@': 11})}, 5: {14: (1, {'@': 12}), 16: (1, {'@': 12}), 12: (1, {'@': 13}), 13: (1, {'@': 13})}, 6: {5: (0, 30), 10: (0, 18), 2: (0, 5), 6: (0, 12), 0: (0, 9), 3: (0, 22), 8: (0, 33), 9: (0, 0), 4: (0, 3), 11: (0, 14)}, 7: {13: (1, {'@': 14}), 14: (1, {'@': 14}), 15: (1, {'@': 14}), 16: (1, {'@': 14})}, 8: {12: (1, {'@': 15}), 13: (1, {'@': 15})}, 9: {14: (1, {'@': 16}), 12: (1, {'@': 16}), 13: (1, {'@': 16}), 16: (1, {'@': 16}), 15: (1, {'@': 16})}, 10: {13: (0, 1), 12: (1, {'@': 17})}, 11: {13: (0, 31), 15: (0, 35)}, 12: {14: (1, {'@': 18}), 12: (1, {'@': 18}), 13: (1, {'@': 18}), 16: (1, {'@': 18}), 15: (1, {'@': 18})}, 13: {12: (1, {'@': 19}), 13: (1, {'@': 19})}, 14: {14: (1, {'@': 20}), 12: (1, {'@': 20}), 13: (1, {'@': 20}), 16: (1, {'@': 20}), 15: (1, {'@': 20})}, 15: {16: (0, 21), 17: (0, 32), 14: (0, 26), 18: (0, 23), 15: (1, {'@': 21}), 13: (1, {'@': 21})}, 16: {14: (1, {'@': 14}), 16: (1, {'@': 14}), 12: (1, {'@': 22}), 13: (1, {'@': 22})}, 17: {}, 18: {14: (1, {'@': 23}), 12: (1, {'@': 23}), 13: (1, {'@': 23}), 16: (1, {'@': 23}), 15: (1, {'@': 23})}, 19: {16: (0, 21), 17: (0, 2), 14: (0, 26), 18: (0, 6)}, 20: {13: (1, {'@': 12}), 14: (1, {'@': 12}), 15: (1, {'@': 12}), 16: (1, {'@': 12})}, 21: {9: (1, {'@': 24}), 0: (1, {'@': 24}), 10: (1, {'@': 24}), 3: (1, {'@': 24}), 4: (1, {'@': 24})}, 22: {5: (0, 30), 1: (0, 15), 19: (0, 11), 6: (0, 12), 0: (0, 9), 3: (0, 22), 2: (0, 4), 9: (0, 0), 10: (0, 18), 11: (0, 14)}, 23: {5: (0, 30), 2: (0, 20), 6: (0, 12), 0: (0, 9), 3: (0, 22), 9: (0, 0), 10: (0, 18), 11: (0, 14)}, 24: {12: (1, {'@': 25}), 13: (1, {'@': 25})}, 25: {12: (1, {'@': 26}), 13: (1, {'@': 26})}, 26: {9: (1, {'@': 27}), 0: (1, {'@': 27}), 10: (1, {'@': 27}), 3: (1, {'@': 27}), 4: (1, {'@': 27})}, 27: {16: (0, 21), 17: (0, 32), 18: (0, 23), 14: (0, 26), 15: (1, {'@': 28}), 13: (1, {'@': 28})}, 28: {7: (0, 25), 1: (0, 19), 3: (0, 22), 0: (0, 9), 2: (0, 34), 20: (0, 17), 4: (0, 3), 5: (0, 30), 6: (0, 12), 21: (0, 10), 8: (0, 24), 9: (0, 0), 10: (0, 18), 11: (0, 14)}, 29: {14: (1, {'@': 29}), 12: (1, {'@': 29}), 13: (1, {'@': 29}), 16: (1, {'@': 29}), 15: (1, {'@': 29})}, 30: {14: (1, {'@': 30}), 12: (1, {'@': 30}), 13: (1, {'@': 30}), 16: (1, {'@': 30}), 15: (1, {'@': 30})}, 31: {5: (0, 30), 1: (0, 27), 6: (0, 12), 0: (0, 9), 3: (0, 22), 2: (0, 4), 9: (0, 0), 10: (0, 18), 11: (0, 14)}, 32: {5: (0, 30), 2: (0, 7), 6: (0, 12), 0: (0, 9), 3: (0, 22), 9: (0, 0), 10: (0, 18), 11: (0, 14)}, 33: {12: (1, {'@': 31}), 13: (1, {'@': 31})}, 34: {14: (1, {'@': 11}), 16: (1, {'@': 11}), 12: (1, {'@': 32}), 13: (1, {'@': 32})}, 35: {14: (1, {'@': 33}), 12: (1, {'@': 33}), 13: (1, {'@': 33}), 16: (1, {'@': 33}), 15: (1, {'@': 33})}}, 'start_states': {'start': 28}, 'end_states': {'start': 17}}, 'lexer_conf': {'tokens': [{'@': 0}, {'@': 1}, {'@': 2}, {'@': 3}, {'@': 4}, {'@': 5}, {'@': 6}, {'@': 7}, {'@': 8}, {'@': 9}], 'ignore': ['WS'], 'g_regex_flags': 0, '__type__': 'LexerConf'}, 'start': ['start'], '__type__': 'LALR_ContextualLexer'}, 'rules': [{'@': 16}, {'@': 23}, {'@': 29}, {'@': 10}, {'@': 27}, {'@': 24}, {'@': 18}, {'@': 20}, {'@': 30}, {'@': 33}, {'@': 14}, {'@': 12}, {'@': 11}, {'@': 28}, {'@': 21}, {'@': 22}, {'@': 15}, {'@': 13}, {'@': 31}, {'@': 32}, {'@': 25}, {'@': 19}, {'@': 26}, {'@': 17}], 'options': {'debug': False, 'keep_all_tokens': False, 'tree_class': None, 'cache_grammar': False, 'postlex': None, 'parser': 'lalr', 'lexer': 'contextual', 'transformer': None, 'start': ['start'], 'priority': None, 'ambiguity': 'auto', 'propagate_positions': False, 'lexer_callbacks': {}, 'maybe_placeholders': False, 'edit_terminals': None, 'g_regex_flags': 0}, '__type__': 'Lark'} ) MEMO = ( {0: {'name': 'NAME', 'pattern': {'value': '[a-zA-Z_]\\w*', 'flags': [], '_width': [1, 4294967295], '__type__': 'PatternRE'}, 'priority': 1, '__type__': 'TerminalDef'}, 1: {'name': 'WS', 'pattern': {'value': '(?:[ \t\x0c\r\n])+', 'flags': [], '_width': [1, 4294967295], '__type__': 'PatternRE'}, 'priority': 1, '__type__': 'TerminalDef'}, 2: {'name': 'ITEMS', 'pattern': {'value': 'items', 'flags': [], '__type__': 'PatternStr'}, 'priority': 1, '__type__': 'TerminalDef'}, 3: {'name': 'PLUS', 'pattern': {'value': '+', 'flags': [], '__type__': 'PatternStr'}, 'priority': 1, '__type__': 'TerminalDef'}, 4: {'name': 'STAR', 'pattern': {'value': '*', 'flags': [], '__type__': 'PatternStr'}, 'priority': 1, '__type__': 'TerminalDef'}, 5: {'name': 'DOT', 'pattern': {'value': '.', 'flags': [], '__type__': 'PatternStr'}, 'priority': 1, '__type__': 'TerminalDef'}, 6: {'name': 'COLON', 'pattern': {'value': ':', 'flags': [], '__type__': 'PatternStr'}, 'priority': 1, '__type__': 'TerminalDef'}, 7: {'name': 'LSQB', 'pattern': {'value': '[', 'flags': [], '__type__': 'PatternStr'}, 'priority': 1, '__type__': 'TerminalDef'}, 8: {'name': 'RSQB', 'pattern': {'value': ']', 'flags': [], '__type__': 'PatternStr'}, 'priority': 1, '__type__': 'TerminalDef'}, 9: {'name': 'COMMA', 'pattern': {'value': ',', 'flags': [], '__type__': 'PatternStr'}, 'priority': 1, '__type__': 'TerminalDef'}, 10: {'origin': {'name': 'anytrait', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'STAR', 'filter_out': True, '__type__': 'Terminal'}], 'order': 0, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': False, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 11: {'origin': {'name': 'series', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'element', '__type__': 'NonTerminal'}], 'order': 2, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 12: {'origin': {'name': 'series', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'series', '__type__': 'NonTerminal'}, {'name': 'quiet', '__type__': 'NonTerminal'}, {'name': 'element', '__type__': 'NonTerminal'}], 'order': 1, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 13: {'origin': {'name': 'series_terminal', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'series', '__type__': 'NonTerminal'}, {'name': 'quiet', '__type__': 'NonTerminal'}, {'name': 'element', '__type__': 'NonTerminal'}], 'order': 2, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 14: {'origin': {'name': 'series', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'series', '__type__': 'NonTerminal'}, {'name': 'notify', '__type__': 'NonTerminal'}, {'name': 'element', '__type__': 'NonTerminal'}], 'order': 0, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 15: {'origin': {'name': 'series_terminal', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'series', '__type__': 'NonTerminal'}, {'name': 'notify', '__type__': 'NonTerminal'}, {'name': 'anytrait', '__type__': 'NonTerminal'}], 'order': 1, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 16: {'origin': {'name': 'trait', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'NAME', 'filter_out': False, '__type__': 'Terminal'}], 'order': 0, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': False, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 17: {'origin': {'name': 'start', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'parallel_terminal', '__type__': 'NonTerminal'}], 'order': 0, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 18: {'origin': {'name': 'element', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'trait', '__type__': 'NonTerminal'}], 'order': 0, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 19: {'origin': {'name': 'parallel_terminal', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'parallel_terminal', '__type__': 'NonTerminal'}, {'name': 'COMMA', 'filter_out': True, '__type__': 'Terminal'}, {'name': 'series_terminal', '__type__': 'NonTerminal'}], 'order': 0, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 20: {'origin': {'name': 'element', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'items', '__type__': 'NonTerminal'}], 'order': 1, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 21: {'origin': {'name': 'parallel', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'series', '__type__': 'NonTerminal'}], 'order': 1, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 22: {'origin': {'name': 'series_terminal', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'series', '__type__': 'NonTerminal'}, {'name': 'notify', '__type__': 'NonTerminal'}, {'name': 'element', '__type__': 'NonTerminal'}], 'order': 0, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 23: {'origin': {'name': 'items', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'ITEMS', 'filter_out': True, '__type__': 'Terminal'}], 'order': 0, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': False, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 24: {'origin': {'name': 'quiet', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'COLON', 'filter_out': True, '__type__': 'Terminal'}], 'order': 0, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': False, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 25: {'origin': {'name': 'series_terminal', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'anytrait', '__type__': 'NonTerminal'}], 'order': 5, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 26: {'origin': {'name': 'parallel_terminal', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'series_terminal', '__type__': 'NonTerminal'}], 'order': 1, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 27: {'origin': {'name': 'notify', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'DOT', 'filter_out': True, '__type__': 'Terminal'}], 'order': 0, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': False, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 28: {'origin': {'name': 'parallel', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'parallel', '__type__': 'NonTerminal'}, {'name': 'COMMA', 'filter_out': True, '__type__': 'Terminal'}, {'name': 'series', '__type__': 'NonTerminal'}], 'order': 0, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 29: {'origin': {'name': 'metadata', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'PLUS', 'filter_out': True, '__type__': 'Terminal'}, {'name': 'NAME', 'filter_out': False, '__type__': 'Terminal'}], 'order': 0, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': False, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 30: {'origin': {'name': 'element', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'metadata', '__type__': 'NonTerminal'}], 'order': 2, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 31: {'origin': {'name': 'series_terminal', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'series', '__type__': 'NonTerminal'}, {'name': 'quiet', '__type__': 'NonTerminal'}, {'name': 'anytrait', '__type__': 'NonTerminal'}], 'order': 3, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 32: {'origin': {'name': 'series_terminal', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'element', '__type__': 'NonTerminal'}], 'order': 4, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}, 33: {'origin': {'name': 'element', '__type__': 'NonTerminal'}, 'expansion': [{'name': 'LSQB', 'filter_out': True, '__type__': 'Terminal'}, {'name': 'parallel', '__type__': 'NonTerminal'}, {'name': 'RSQB', 'filter_out': True, '__type__': 'Terminal'}], 'order': 3, 'alias': None, 'options': {'keep_all_tokens': False, 'expand1': True, 'priority': None, 'empty_indices': (), '__type__': 'RuleOptions'}, '__type__': 'Rule'}} ) Shift = 0 Reduce = 1 def Lark_StandAlone(transformer=None, postlex=None): namespace = {'Rule': Rule, 'TerminalDef': TerminalDef} return Lark.deserialize(DATA, namespace, MEMO, transformer=transformer, postlex=postlex) traits-6.3.2/traits/observation/_has_traits_helpers.py000066400000000000000000000101061414270267200232700ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Module for HasTraits and CTrait specific utility functions for observers. """ from traits.constants import ComparisonMode, TraitKind from traits.ctraits import CHasTraits from traits.observation._observe import add_or_remove_notifiers from traits.observation.exceptions import NotifierNotFound from traits.trait_base import Undefined, Uninitialized #: List of values not to be passed onto the next observers because they are #: filled values for uninitialized/undefined traits, and no observables #: can be derived from them. UNOBSERVABLE_VALUES = [ Undefined, Uninitialized, None, ] def object_has_named_trait(object, name): """ Return true if a trait with the given name is defined on the object. Parameters ---------- object : any Any object name : str Trait name to look for. Returns ------- boolean """ return ( isinstance(object, CHasTraits) and object._trait(name, 0) is not None ) def iter_objects(object, name): """ Yield the object referenced by the named trait, unless the value is not defined or is one of the few unobservable filled values. This function should not introduce side-effect (e.g. evaluating default) on the given object. Parameters ---------- object : HasTraits Object from which the trait value will be obtained. name : str Name of the trait. Yields ------ value : any The value of the trait, if it is defined and is not one of those skipped values. """ value = object.__dict__.get(name, Undefined) if all(value is not skipped for skipped in UNOBSERVABLE_VALUES): yield value def observer_change_handler(event, graph, handler, target, dispatcher): """ Maintain downstream notifiers when the trait changes. Parameters ---------- event : TraitChangeEvent The event that triggers this function. graph : ObserverGraph Description for the *downstream* observers, i.e. excluding the observer that contributed this maintainer function. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. """ if all(event.old is not skipped for skipped in UNOBSERVABLE_VALUES): try: add_or_remove_notifiers( object=event.old, graph=graph, handler=handler, target=target, dispatcher=dispatcher, remove=True, ) except NotifierNotFound: # The old value could be a default value that does not have any # notifier. pass if all(event.new is not skipped for skipped in UNOBSERVABLE_VALUES): add_or_remove_notifiers( object=event.new, graph=graph, handler=handler, target=target, dispatcher=dispatcher, remove=False, ) def ctrait_prevent_event(event): """ Return true if the CTrait change event should be skipped. Parameters ---------- event : TraitChangeEvent Returns ------- skipped : bool Whether the event should be skipped """ if event.old is Uninitialized: return True ctrait = event.object.trait(event.name) if (ctrait.type == TraitKind.trait.name and ctrait.comparison_mode == ComparisonMode.equality): try: return bool(event.old == event.new) except Exception: # Maybe do something else about the exception # enthought/traits#1230 pass return False traits-6.3.2/traits/observation/_i_notifier.py000066400000000000000000000031241414270267200215360ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import abc class INotifier(abc.ABC): """ Interface for all notifiers. An instance of notifier must be a callable, i.e. ``__call__`` must be implemented and cannot be None. The signature of that callable should be compatible with the observables the notifier will be given to. This interface does not define what that signature should be. """ def __call__(self, *args, **kwargs): """ Called by an observable. The signature is not restricted by the interface. """ raise NotImplementedError("__call__ must be implemented.") def add_to(self, observable): """ Add this notifier to the observable. Parameters ---------- observable : IObservable """ raise NotImplementedError("add_to must be implemented.") def remove_from(self, observable): """ Remove this notifier or a notifier equivalent to this one from the observable. Parameters ---------- observable : IObservable Raises ------ NotifierNotFound If the notifier cannot be found. """ raise NotImplementedError("remove_from must be implemented.") traits-6.3.2/traits/observation/_i_observer.py000066400000000000000000000164741414270267200215620ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import abc class IObserver(abc.ABC): """ Interface for all observers. Each instance of ``IObserver`` can be a node in the ``ObserverGraph``. These objects are considered low-level objects not to be instantiated directly by the user. In order to support equality and hashing on the ``ObserverGraph``, ``IObserver`` needs to be hashable and it needs to support comparison for equality. A subclass of ``IObserver`` is often context specific, e.g. for observing a trait on an HasTraits instance, for observing items in a list, etc. Given an ``ObserverGraph``, observers are visited from the root node to the leaf nodes. The first observer (root node) will be given the object the user wants to observe. It knows how to obtain observable(s) for attaching notifiers. It also knows what objects should be given to the downstream/children observers in the same graph. An observer defines the notifier that wraps the user change handler, should notification is enabled by the user. This allows the observer to define how the user should receive the change event, e.g. what type of event object should be created, and whether a given event should be silenced etc. An observer also defines a "maintainer" (which is also a notifier from the point of view of an observable), for maintaining downstream observers when a change happens for an observable. For example, an observerable may not have a defined value yet for the children observers to handle. When the value is defined, the observable is expected to notify the maintainer, which will pass the new value onto the children observers. An observer can also contribute more ``ObserverGraph`` via ``iter_extra_graphs`` if they require support from other observers. """ def __hash__(self): """ Return a hash of this object.""" raise NotImplementedError("__hash__ must be implemented.") def __eq__(self, other): """ Return true if this observer is equal to the given one.""" raise NotImplementedError("__eq__ must be implemented.") @property def notify(self): """ A boolean for whether this observer will notify for changes. """ raise NotImplementedError("notify property must be implemented.") def iter_observables(self, object): """ Yield observables for adding or removing notifiers. The notifiers are contributed by this observer's ``get_notifier`` and ``get_maintainer`` methods. An observer may observe many items, e.g. multiple traits for a given instance of HasTraits, then the observer will yield many items here. An observer may also observe just one thing, e.g. a single trait, or an instance of TraitListObject, then the observer may yield just that. An observer may also find nothing to be observed and does not need to complain about that, and it will yield nothing here. Observers are allowed to raise here if it is appropriate to do so, e.g. to help catch usage errors. Parameters ---------- object: object Object provided by the ``iter_objects`` methods from another observers or directly by the user. No guarantee can be made about the type of the object. Concrete implementations should do the sanity check where appropriate. Yields ------ IObservable """ raise NotImplementedError("iter_observables must be implemented.") def iter_objects(self, object): """ Yield objects for the next observer following this observer, in an ObserverGraph. An observer may yield many items for the next observer, e.g. the observer is observing many traits on the given instance of HasTraits or the observer is observing items in a container. The observer can evaluate whether the value is appropriate to be passed on, or skip some if the observer is expected to do so. An observer may yield one item if that is what should be passed onto the next observer. An observer may find nothing to be passed onto the next observer, and has no need to complain about that. Then the observer may yield nothing. Observers are allowed to raise here if it is appropriate to do so, e.g. to help catch usage errors. Parameters ---------- object: object Object provided by the ``iter_objects`` methods from another observers or directly by the user. No guarantee can be made about the type of the object. Concrete implementations should do the sanity check where appropriate. Yields ------ value : object """ raise NotImplementedError("iter_objects must be implemented.") def get_notifier(self, handler, target, dispatcher): """ Return a notifier for calling the user handler with the change event. This is needed if ``notify`` is true. Parameters ---------- handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. Returns ------- notifier : INotifier """ raise NotImplementedError("get_notifier must be implemented.") def get_maintainer(self, graph, handler, target, dispatcher): """ Return a notifier for maintaining downstream observers in an ObserverGraph, when the object observed by this observer changes. Parameters ---------- graph : ObserverGraph Description for the *downstream* observers, i.e. excluding self. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. Returns ------- notifier : INotifier """ raise NotImplementedError("get_maintainer must be implemented.") def iter_extra_graphs(self, graph): """ Yield additional ObserverGraph for adding/removing notifiers when this observer is encountered in a given ObserverGraph. If an observer needs support from another observer(s), e.g. for observing 'trait_added' event, then this method can yield any number of ObserverGraph containing those additional observer(s). If an observer does not need additional support from other observers, this method can yield nothing. Parameters ---------- graph : ObserverGraph The graph where this observer is the root node. Yields ------ graph : ObserverGraph """ raise NotImplementedError("iter_extra_graphs must be implemented.") traits-6.3.2/traits/observation/_list_change_event.py000066400000000000000000000037021414270267200230720ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Event object for representing mutations to a list. """ # ListChangeEvent is exposed in the public API class ListChangeEvent: """ Event object to represent mutations to a list. The interface of this object is provisional as of version 6.1. Attributes ---------- object : traits.trait_list_object.TraitList The list being mutated. index : int or slice The index used for the mutation. added : list Values added to the list. removed : list Values removed from the list. """ def __init__(self, *, object, index, removed, added): self.object = object self.added = added self.removed = removed self.index = index def __repr__(self): return ( f"{self.__class__.__name__}(" f"object={self.object!r}, " f"index={self.index!r}, " f"removed={self.removed!r}, " f"added={self.added!r})" ) def list_event_factory(trait_list, index, removed, added): """ Adapt the call signature of TraitList.notify to create an event. Parameters ---------- trait_list : traits.trait_list_object.TraitList TraitList object being mutated. index : int or slice The indices being modified by the operation. removed : list The items removed from the list. added : list The items added to the list. Returns ------- ListChangeEvent """ return ListChangeEvent( object=trait_list, index=index, removed=removed, added=added, ) traits-6.3.2/traits/observation/_list_item_observer.py000066400000000000000000000154211414270267200233120ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.observation._list_change_event import list_event_factory from traits.observation._i_observer import IObserver from traits.observation._trait_event_notifier import TraitEventNotifier from traits.observation._observe import add_or_remove_notifiers from traits.observation._observer_change_notifier import ObserverChangeNotifier from traits.trait_list_object import TraitList @IObserver.register class ListItemObserver: """ Observer for observing mutations on a list. Parameters ---------- notify : boolean Whether to notify for changes. optional : boolean If False, this observer will complain if the incoming object is not an observable list. If True and the incoming object is not a list, this observer will do nothing. Useful for the 'items' keyword in the text parser, where the source container type is ambiguous. """ __slots__ = ("notify", "optional") def __init__(self, *, notify, optional): self.notify = notify self.optional = optional def __hash__(self): """ Return a hash of this object.""" return hash((type(self).__name__, self.notify, self.optional)) def __eq__(self, other): """ Return true if this observer is equal to the given one.""" return ( type(self) is type(other) and self.notify == other.notify and self.optional == other.optional ) def __repr__(self): formatted_args = [ f"notify={self.notify!r}", f"optional={self.optional!r}", ] return f"{self.__class__.__name__}({', '.join(formatted_args)})" def iter_observables(self, object): """ If the given object is an observable list, yield that list. Otherwise, raise an error unless the observer is optional. Parameters ---------- object: object Object provided by another observers or by the user. Yields ------ IObservable Raises ------ ValueError If the given object is not an observable list and the observer is not optional. """ if not isinstance(object, TraitList): if self.optional: return raise ValueError( "Expected a TraitList to be observed, " "got {!r} (type: {!r})".format(object, type(object))) yield object def iter_objects(self, object): """ Yield the content of the list if the given object is an observable list. Otherwise, raise an error, unless the observer is optional. The content of the list will be passed onto the next observer following this one in an ObserverGraph. Parameters ---------- object: object Object provided by another observers or by the user. Yields ------ value : object Raises ------ ValueError If the given object is not an observable list and the observer is not optional. """ if not isinstance(object, TraitList): if self.optional: return raise ValueError( "Expected a TraitList to be observed, " "got {!r} (type: {!r})".format(object, type(object))) yield from object def get_notifier(self, handler, target, dispatcher): """ Return a notifier for calling the user handler with the change event. Returns ------- notifier : TraitEventNotifier """ # Unlike CTrait, when default list is created, there isn't a change # event where the old value is Uninitialized. return TraitEventNotifier( handler=handler, target=target, dispatcher=dispatcher, event_factory=list_event_factory, prevent_event=lambda event: False, ) def get_maintainer(self, graph, handler, target, dispatcher): """ Return a notifier for maintaining downstream observers when a list is mutated. Parameters ---------- graph : ObserverGraph Description for the *downstream* observers, i.e. excluding self. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. Returns ------- notifier : ObserverChangeNotifier """ return ObserverChangeNotifier( observer_handler=_observer_change_handler, event_factory=list_event_factory, prevent_event=lambda event: False, graph=graph, handler=handler, target=target, dispatcher=dispatcher, ) def iter_extra_graphs(self, graph): """ Yield new ObserverGraph to be contributed by this observer. Parameters ---------- graph : ObserverGraph The graph this observer is part of. Yields ------ ObserverGraph """ # Unlike CTrait, no need to handle trait_added yield from () def _observer_change_handler(event, graph, handler, target, dispatcher): """ Handler for maintaining observers. Used by ObserverChangeNotifier. The downstream notifiers are removed from items removed from the list. Likewise, downstream notifiers are added to items added to the list. Parameters ---------- event : ListChangeEvent Change event that triggers the maintainer. graph : ObserverGraph Description for the *downstream* observers, i.e. excluding self. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. """ for removed_item in event.removed: add_or_remove_notifiers( object=removed_item, graph=graph, handler=handler, target=target, dispatcher=dispatcher, remove=True, ) for added_item in event.added: add_or_remove_notifiers( object=added_item, graph=graph, handler=handler, target=target, dispatcher=dispatcher, remove=False, ) traits-6.3.2/traits/observation/_metadata_filter.py000066400000000000000000000032141414270267200225340ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ A filter to be used with FilteredTraitObserver for observing traits with a given metadata. The filter is defined here so that two observers created using the same parameters compare equally. """ class MetadataFilter: """ Callable to be used with FilteredTraitObserver for filtering traits with the given metadata name. This filter returns true if the metadata value is not None, false if the metadata is not defined or the value is None. Attributes ---------- metadata_name : str Name of the metadata to filter traits with. """ __slots__ = ("metadata_name",) def __init__(self, metadata_name): self.metadata_name = metadata_name def __call__(self, name, trait): # If the metadata is not defined, CTrait still returns None. return getattr(trait, self.metadata_name) is not None def __eq__(self, other): return ( type(self) is type(other) and self.metadata_name == other.metadata_name ) def __hash__(self): return hash((type(self).__name__, self.metadata_name)) def __repr__(self): return ( "{self.__class__.__name__}" "(metadata_name={self.metadata_name!r})".format(self=self) ) traits-6.3.2/traits/observation/_named_trait_observer.py000066400000000000000000000160361414270267200236130ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.observation._trait_change_event import trait_event_factory from traits.observation._has_traits_helpers import ( ctrait_prevent_event, iter_objects, object_has_named_trait, observer_change_handler, ) from traits.observation._i_observer import IObserver from traits.observation._observer_change_notifier import ObserverChangeNotifier from traits.observation._observer_graph import ObserverGraph from traits.observation._trait_added_observer import TraitAddedObserver from traits.observation._trait_event_notifier import TraitEventNotifier @IObserver.register class NamedTraitObserver: """ Observer for observing changes on a named trait on an instance of HasTraits. """ __slots__ = ("name", "notify", "optional") def __init__(self, *, name, notify, optional): """ Initializer. Once this observer is defined, it should not be mutated. Parameters ---------- name : str Name of the trait to be observed. notify : boolean Whether to notify for changes. optional : boolean If true and if the incoming object is not an instance of HasTraits or does not have a trait with the given name, this observer will quietly skip it. Otherwise, this observer will raise an error if the named trait cannot be found. Useful if the named trait is added after a handler is registered, or when the context is ambiguous (e.g. "items" in the domain specific language). """ self.name = name self.notify = notify self.optional = optional def __hash__(self): return hash( (type(self).__name__, self.name, self.notify, self.optional) ) def __eq__(self, other): return ( type(self) is type(other) and self.name == other.name and self.notify == other.notify and self.optional == other.optional ) def __repr__(self): formatted_args = [ f"name={self.name!r}", f"notify={self.notify!r}", f"optional={self.optional!r}", ] return f"{self.__class__.__name__}({', '.join(formatted_args)})" def iter_observables(self, object): """ Yield the named instance trait from the given object. If the named trait cannot be found and optional is false, raise an error. Parameters ---------- object: object Object provided by another observers or by the user. Yields ------ CTrait Raises ------ ValueError If the trait is not found and optional flag is set to false. """ if not object_has_named_trait(object, self.name): if self.optional: return raise ValueError( "Trait named {!r} not found on {!r}.".format(self.name, object) ) yield object._trait(self.name, 2) def iter_objects(self, object): """ Yield the value of the named trait from the given object, if the value is defined. The value will then be given to the next observer(s) following this one in an ObserverGraph. If the value has not been set as an instance attribute, i.e. absent in ``object.__dict__``, this observer will yield nothing. This is to avoid evaluating default initializers while adding observers. When the default is defined, a change event will trigger the maintainer to add/remove notifiers for the next observers. Note that ``Undefined``, ``Uninitialized`` and ``None`` values are also skipped, as they are inevitable filled values that contain no further attributes to be observed by any other observers. Parameters ---------- object: HasTraits Expected to be an instance of HasTraits Yields ------ value : any Raises ------ ValueError If the trait is not found and optional flag is set to false. """ if not object_has_named_trait(object, self.name): if self.optional: return raise ValueError( "Trait named {!r} not found on {!r}.".format(self.name, object) ) yield from iter_objects(object, self.name) def get_notifier(self, handler, target, dispatcher): """ Return a notifier for calling the user handler with the change event. If the old value is uninitialized, then the change is caused by having the default value defined. Such an event is prevented from reaching the user's change handler. Returns ------- notifier : TraitEventNotifier """ return TraitEventNotifier( handler=handler, target=target, dispatcher=dispatcher, event_factory=trait_event_factory, prevent_event=ctrait_prevent_event, ) def get_maintainer(self, graph, handler, target, dispatcher): """ Return a notifier for maintaining downstream observers when a trait is changed. All events should be allowed through, including setting default value such that downstream observers can be maintained on the new value. Parameters ---------- graph : ObserverGraph Description for the *downstream* observers, i.e. excluding self. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. Returns ------- notifier : ObserverChangeNotifier """ return ObserverChangeNotifier( observer_handler=observer_change_handler, event_factory=trait_event_factory, prevent_event=lambda event: False, graph=graph, handler=handler, target=target, dispatcher=dispatcher, ) def iter_extra_graphs(self, graph): """ Yield additional ObserverGraph for adding/removing notifiers when this observer is encountered in a given ObserverGraph. Parameters ---------- graph : ObserverGraph The graph where this observer is the root node. Yields ------ graph : ObserverGraph """ yield ObserverGraph( node=TraitAddedObserver( match_func=lambda name, trait: name == self.name, optional=self.optional, ), children=[graph], ) traits-6.3.2/traits/observation/_observe.py000066400000000000000000000135341414270267200210620ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! def add_or_remove_notifiers( *, object, graph, handler, target, dispatcher, remove): """ Add/Remove notifiers on objects following the description on an ObserverGraph. All nodes in ``ObserverGraph`` are required to be instances of ``IObserver``. The interface of ``IObserver`` supports this function. Parameters ---------- object : object An object to be observed. graph : ObserverGraph A graph describing what and how extended traits are being observed. All nodes must be ``IObserver``. handler : callable(event) User-defined callable to handle change events. ``event`` is an object representing the change. Its type and content depends on the change. target : Any An object for defining the context of the user's handler notifier. This is typically an instance of HasTraits seen by the user as the "owner" of the observer. dispatcher : callable(callable, event) Callable for dispatching the user-defined handler, e.g. dispatching callback on a different thread. remove : boolean If true, notifiers are being removed. Raises ------ NotiferNotFound Raised when notifier cannot be found for removal. """ callable_ = _AddOrRemoveNotifier( object=object, graph=graph, handler=handler, target=target, dispatcher=dispatcher, remove=remove, ) callable_() class _AddOrRemoveNotifier: """ Callable for adding or removing notifiers. See ``add_or_remove_notifiers`` for the input parameters. """ def __init__(self, *, object, graph, handler, target, dispatcher, remove): self.object = object self.graph = graph self.handler = handler self.target = target self.dispatcher = dispatcher self.remove = remove # list of (notifier, observable) self._processed = [] def __call__(self): """ Main function for adding/removing notifiers. """ # The order of events does not matter as they are independent of each # other. steps = [ self._add_or_remove_notifiers, self._add_or_remove_maintainers, self._add_or_remove_children_notifiers, self._add_or_remove_extra_graphs, ] # Not quite the complete reversal, as trees are still walked from # root to leaves. if self.remove: steps = steps[::-1] try: for step in steps: step() except Exception: # Undo and then reraise while self._processed: notifier, observable = self._processed.pop() if self.remove: notifier.add_to(observable) else: notifier.remove_from(observable) raise else: self._processed.clear() def _add_or_remove_extra_graphs(self): """ Add or remove additional ObserverGraph contributed by the root observer. e.g. for handing trait_added event. """ for extra_graph in self.graph.node.iter_extra_graphs(self.graph): add_or_remove_notifiers( object=self.object, graph=extra_graph, handler=self.handler, target=self.target, dispatcher=self.dispatcher, remove=self.remove, ) def _add_or_remove_children_notifiers(self): """ Recursively add or remove notifiers for the children ObserverGraph. """ for child_graph in self.graph.children: for next_object in self.graph.node.iter_objects(self.object): add_or_remove_notifiers( object=next_object, graph=child_graph, handler=self.handler, target=self.target, dispatcher=self.dispatcher, remove=self.remove, ) def _add_or_remove_maintainers(self): """ Add or remove notifiers for maintaining children notifiers when the objects being observed by the root observer change. """ for observable in self.graph.node.iter_observables(self.object): for child_graph in self.graph.children: change_notifier = self.graph.node.get_maintainer( graph=child_graph, handler=self.handler, target=self.target, dispatcher=self.dispatcher, ) if self.remove: change_notifier.remove_from(observable) else: change_notifier.add_to(observable) self._processed.append((change_notifier, observable)) def _add_or_remove_notifiers(self): """ Add or remove user notifiers for the objects observed by the root observer. """ if not self.graph.node.notify: return for observable in self.graph.node.iter_observables(self.object): notifier = self.graph.node.get_notifier( handler=self.handler, target=self.target, dispatcher=self.dispatcher, ) if self.remove: notifier.remove_from(observable) else: notifier.add_to(observable) self._processed.append((notifier, observable)) traits-6.3.2/traits/observation/_observer_change_notifier.py000066400000000000000000000157141414270267200244520ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import types import weakref from traits.observation.exceptions import NotifierNotFound class ObserverChangeNotifier: """ Wrapper for maintaining notifiers in an ObserverGraph when an upstream object changes. An instance of ``ObserverChangeNotifier`` is a callable to be contributed to an instance of ``IObserverable``, e.g. ``CTrait``, ``TraitList`` etc., such that it will be called when an observerable emits notificaitons for changes. For example, suppose changes are observed on an extended attribute path, e.g. ``foo.bar.baz``, where ``foo`` and ``bar`` are both instances of ``HasTraits``. There will be an instance of ``ObserverChangeNotifier`` on the ``CTrait`` for ``foo``. When ``foo`` changes, the notifier will be called for maintaining the observers for ``bar.baz``. Similarly, there will be an instance of ``ObserverChangeNotifier`` on the ``CTrait`` for ``bar`` for maintaining the observers for ``baz``, when ``bar`` changes. """ def __init__( self, *, observer_handler, event_factory, prevent_event, graph, handler, target, dispatcher): """ Parameters ---------- observer_handler : callable(event, graph, handler, target, dispatcher) The handler for maintaining observers and notifiers. ``event`` is the object created by the ``event_factory`` and is associated with the change event that triggers this notifier. The rest of the arguments are provided by the arguments to this notifier. event_factory : callable(*args, **kwargs) -> object A factory function for creating the event object to be sent to the observer_handler. The call signature must be compatible with the call signature expected by the observable this notifier is used with. e.g. for CTrait, the call signature will be ``(object, name, old, new)``. prevent_event : callable(event) -> boolean A callable for controlling whether the observer_handler should be invoked. It receives the event created by the event factory and returns true if the event should be prevented, false if the event should be fired. graph : ObserverGraph An object describing what traits are being observed on an instance of ``HasTraits``, e.g. observe mutations on a list referenced by a specific named trait. handler : callable(event) The user handler being maintained when a container object changes. A weak reference is created for the handler if it is an instance method. If the instance method handler is garbage collected, this notifier will be silenced. target : object An object for defining the context of the user's handler notifier. A weak reference is created for the target. If the target is garbage collected, this notifier will be silenced. This is typically an instance of HasTraits acting as a container for an observable on which this notifier is attached to. It would be seen by the user as the "owner" of the observer. dispatcher : callable(function, event) Callable for dispatching the user's handler. """ self.observer_handler = observer_handler self.event_factory = event_factory self.prevent_event = prevent_event self.graph = graph self.target = weakref.ref(target) if isinstance(handler, types.MethodType): self.handler = weakref.WeakMethod(handler) else: def _return_handler(): return handler self.handler = _return_handler self.dispatcher = dispatcher def add_to(self, observable): """ Add this notifier to the observable. Parameters ---------- observable : IObservable """ notifiers = observable._notifiers(True) notifiers.append(self) def remove_from(self, observable): """ Remove a notifier equivalent to this one from the observable. Parameters ---------- observable : IObservable Raises ------ NotifierNotFound If the notifier cannot be found. """ notifiers = observable._notifiers(True) for notifier in notifiers[:]: if self.equals(notifier): notifiers.remove(notifier) break else: raise NotifierNotFound("Notifier not found.") def __call__(self, *args, **kwargs): """ Called by the observable this notifier is attached to. This exercises the observer_handler for maintaining observers and notifiers on changed objects. Note that any unexpected exceptions will be raised, as the ``observer_handler`` is not provided by users of traits, but is a callable maintained in traits. """ target = self.target() if target is None: return handler = self.handler() if handler is None: return event = self.event_factory(*args, **kwargs) if self.prevent_event(event): return self.observer_handler( event=event, graph=self.graph, target=target, handler=handler, dispatcher=self.dispatcher, ) def equals(self, other): """ Return true if the other value is a notifier equivalent to this one. Parameters ---------- other : any Returns ------- boolean """ return ( type(self) is type(other) # observer_handler contains the logic for maintaining notifiers # in the downstream graph. and self.observer_handler is other.observer_handler # graph is an input for observer_handler. # Unequal graphs should not interfere each other. and self.graph == other.graph # user handler is an input for observer_handler. # different user handlers should not interfere each other. and self.handler() == other.handler() # target is an input for observer_handler. # it goes together with the user's handler and self.target() is other.target() # dispatcher is an input for observer_handler. # different dispatchers should not interfere each other. and self.dispatcher == other.dispatcher ) traits-6.3.2/traits/observation/_observer_graph.py000066400000000000000000000071741414270267200224300ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! class ObserverGraph: """ An ``ObserverGraph`` is an object for describing what traits are being observed on an instance of ``HasTraits``. The most basic unit in a graph is a node, which is a context specific observer. For example, a node can be an observer specialized in changes on a named trait, an observer specialized in changes on a number of traits matching a certain criteria, an observer specialized in mutations on a list, etc. The most basic example is an ``ObserverGraph`` that contains only one node, e.g. for observing changes on a named trait. An ``ObserverGraph`` can have branches, e.g. to observe more than one trait on a nested object. The attribute ``children`` represents these branches. Each item in ``children`` is another ``ObserverGraph``. In order to (1) avoid hooking up a user callback with the same observer twice, and (2) remove an observer when they are not needed, once an ``ObserverGraph`` object is constructed (e.g. after mutating ``children`` for constructing branches) and is ready to be used against an instance of ``HasTraits``, it should not be mutated again. For the same reason, ``ObserverGraph`` implements ``__hash__`` and ``__eq__`` and requires its nodes to also support these methods. An ``ObserverGraph`` does not keep states regarding the HasTraits instances and the user callbacks it was used with. An ``ObserverGraph`` can be reused multiple times on different ``HasTraits`` instance and with different user callback. This object is considered a low-level object for the observer mechanism. It is not intended to be instantiated by users directly. Users will be given higher-level wrappers for creating ``ObserverGraph`` objects. Parameters ---------- node : any A context specific observer. It must be a hashable object. In practice, this will be an instance that implements ``IObserver``. children : iterable of ObserverGraph, optional Branches on this graph. All children must be unique. Raises ------ ValueError If not all children are unique. """ __slots__ = ("node", "children") def __init__(self, *, node, children=None): if children is not None and len(set(children)) != len(children): raise ValueError("Not all children are unique.") self.node = node self.children = list(children) if children is not None else [] def __hash__(self): """ Return the hash of this ObserverGraph.""" return hash( (type(self).__name__, self.node, frozenset(self.children)) ) def __eq__(self, other): """ Return true if another object is an ObserverGraph with the same content. The order of children is not taken into account in the comparison. """ return ( type(self) is type(other) and self.node == other.node and set(self.children) == set(other.children) ) def __repr__(self): formatted_args = [f"node={self.node!r}"] if self.children: formatted_args.append(f"children={self.children!r}") return f"{self.__class__.__name__}({', '.join(formatted_args)})" traits-6.3.2/traits/observation/_set_change_event.py000066400000000000000000000031561414270267200227150ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # SetChangeEvent is in the public API. class SetChangeEvent: """ Event object to represent mutations on a set. The interface of this object is provisional as of version 6.1. Attributes ---------- object : traits.trait_set_object.TraitSet The set being mutated. removed : set Values removed from the set. added : set Values added to the set. """ def __init__(self, *, object, removed, added): self.object = object self.removed = removed self.added = added def __repr__(self): return ( f"{self.__class__.__name__}(" f"object={self.object!r}, " f"removed={self.removed!r}, " f"added={self.added!r})" ) def set_event_factory(trait_set, removed, added): """ Adapt the call signature of TraitSet.notify to create an event. Parameters ---------- trait_set : traits.trait_set_object.TraitSet The set being mutated. removed : set Values removed from the set. added : set Values added to the set. Returns ------- SetChangeEvent """ return SetChangeEvent( object=trait_set, added=added, removed=removed, ) traits-6.3.2/traits/observation/_set_item_observer.py000066400000000000000000000147301414270267200231340ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.observation._i_observer import IObserver from traits.observation._observe import add_or_remove_notifiers from traits.observation._observer_change_notifier import ObserverChangeNotifier from traits.observation._set_change_event import set_event_factory from traits.observation._trait_event_notifier import TraitEventNotifier from traits.trait_set_object import TraitSet @IObserver.register class SetItemObserver: """ Observer for observing mutations on a set. Parameters ---------- notify : boolean Whether to notify for changes. optional : boolean If False, this observer will complain if the incoming object is not an observable set. If True and the incoming object is not a set, this observer will do nothing. Useful for the 'items' keyword in the text parser, where the source container type is ambiguous. """ __slots__ = ("notify", "optional") def __init__(self, *, notify, optional): self.notify = notify self.optional = optional def __hash__(self): """ Return a hash of this object.""" return hash((type(self).__name__, self.notify, self.optional)) def __eq__(self, other): """ Return true if this observer is equal to the given one.""" return ( type(self) is type(other) and self.notify == other.notify and self.optional == other.optional ) def __repr__(self): formatted_args = [ f"notify={self.notify!r}", f"optional={self.optional!r}", ] return f"{self.__class__.__name__}({', '.join(formatted_args)})" def iter_observables(self, object): """ If the given object is an observable set, yield that set. Otherwise, raise an error, unless this observer is optional Parameters ---------- object: object Object provided by another observers or by the user. Yields ------ IObservable Raises ------ ValueError If the given object is not an observable set and optional is false. """ if not isinstance(object, TraitSet): if self.optional: return raise ValueError( "Expected a TraitSet to be observed, " "got {!r} (type: {!r})".format(object, type(object)) ) yield object def iter_objects(self, object): """ Yield the content of the set if the given object is an observable set. Otherwise, raise an error, unless the observer is optional. The content of the set will be passed onto the children observer(s) following this one in an ObserverGraph. Parameters ---------- object: object Object provided by another observers or by the user. Yields ------ value : object Raises ------ ValueError If the given object is not an observable set and optional is false. """ if not isinstance(object, TraitSet): if self.optional: return raise ValueError( "Expected a TraitSet to be observed, " "got {!r} (type: {!r})".format(object, type(object)) ) yield from object def get_notifier(self, handler, target, dispatcher): """ Return a notifier for calling the user handler with the change event. Returns ------- notifier : TraitEventNotifier """ return TraitEventNotifier( handler=handler, target=target, dispatcher=dispatcher, event_factory=set_event_factory, prevent_event=lambda event: False, ) def get_maintainer(self, graph, handler, target, dispatcher): """ Return a notifier for maintaining downstream observers when a set is mutated. Parameters ---------- graph : ObserverGraph Description for the *downstream* observers, i.e. excluding self. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. Returns ------- notifier : ObserverChangeNotifier """ return ObserverChangeNotifier( observer_handler=_observer_change_handler, event_factory=set_event_factory, prevent_event=lambda event: False, graph=graph, handler=handler, target=target, dispatcher=dispatcher, ) def iter_extra_graphs(self, graph): """ Yield new ObserverGraph to be contributed by this observer. Parameters ---------- graph : ObserverGraph The graph this observer is part of. Yields ------ ObserverGraph """ # Unlike CTrait, no need to handle trait_added yield from () def _observer_change_handler(event, graph, handler, target, dispatcher): """ Handler for maintaining observers. Used by ObserverChangeNotifier. Parameters ---------- event : SetChangeEvent Change event that triggers the maintainer. graph : ObserverGraph Description for the *downstream* observers, i.e. excluding self. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. """ for removed_item in event.removed: add_or_remove_notifiers( object=removed_item, graph=graph, handler=handler, target=target, dispatcher=dispatcher, remove=True, ) for added_item in event.added: add_or_remove_notifiers( object=added_item, graph=graph, handler=handler, target=target, dispatcher=dispatcher, remove=False, ) traits-6.3.2/traits/observation/_testing.py000066400000000000000000000103041414270267200210620ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from unittest import mock from traits.observation._observe import add_or_remove_notifiers from traits.observation._observer_graph import ObserverGraph from traits.observation.exceptions import NotifierNotFound #: An object that does not get garbage collected until the very end _DEFAULT_TARGET = mock.Mock() def dispatch_same(handler, event): handler(event) def create_graph(*nodes): """ Create an ObserverGraph with the given nodes joined one after another. Parameters ---------- *nodes : hashable Items to be attached as nodes Returns ------- ObserverGraph """ node = nodes[-1] graph = ObserverGraph(node=node) for node in nodes[:-1][::-1]: graph = ObserverGraph(node=node, children=[graph]) return graph def call_add_or_remove_notifiers(**kwargs): """ Convenience function for calling add_or_remove_notifiers with default values. Parameters ---------- **kwargs New argument values to use instead. """ values = dict( object=mock.Mock(), graph=ObserverGraph(node=None), handler=mock.Mock(), target=_DEFAULT_TARGET, dispatcher=dispatch_same, remove=False, ) values.update(kwargs) add_or_remove_notifiers(**values) class DummyObservable: """ A dummy implementation of IObservable for testing purposes.""" def __init__(self): self.notifiers = [] def _notifiers(self, force_create): return self.notifiers class DummyNotifier: """ A dummy implementation of INotifier for testing purposes.""" def add_to(self, observable): observable._notifiers(True).append(self) def remove_from(self, observable): notifiers = observable._notifiers(True) try: notifiers.remove(self) except ValueError: raise NotifierNotFound("Notifier not found.") class DummyObserver: """ A dummy implementation of IObserver for testing purposes. Parameters ---------- notify : boolean, optional The mocked return value from IObserver.notify observables : iterable of IObservable, optional The mocked yielded values from IObserver.iter_observables next_objects : iterable of object, optional The mocked yielded values from IObserver.iter_objects notifier : INotifier, optional The mocked returned value from IObserver.get_notifier If not provided, a dummy notifier is created. maintainer : INotifier, optional The mocked returned value from IObserver.get_maintainer if not provided, a dummy notifier is created. extra_graphs : iterable of ObserverGraph, optional The mocked yielded values from IObserver.iter_extra_graphs """ def __init__( self, notify=True, observables=(), next_objects=(), notifier=None, maintainer=None, extra_graphs=()): if notifier is None: notifier = DummyNotifier() if maintainer is None: maintainer = DummyNotifier() self.notify = notify self.observables = observables self.next_objects = next_objects self.notifier = notifier self.maintainer = maintainer self.extra_graphs = extra_graphs def __eq__(self, other): return other is self def __hash__(self): return 1 def iter_observables(self, object): yield from self.observables def iter_objects(self, object): yield from self.next_objects def get_notifier( self, handler, target, dispatcher): return self.notifier def get_maintainer( self, graph, handler, target, dispatcher): return self.maintainer def iter_extra_graphs(self, graph): yield from self.extra_graphs traits-6.3.2/traits/observation/_trait_added_observer.py000066400000000000000000000201571414270267200235670ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.observation._has_traits_helpers import ( iter_objects, object_has_named_trait, ) from traits.observation._i_observer import IObserver from traits.observation._observe import add_or_remove_notifiers from traits.observation._observer_change_notifier import ObserverChangeNotifier from traits.observation._observer_graph import ObserverGraph from traits.observation._trait_change_event import trait_event_factory @IObserver.register class TraitAddedObserver: """ An observer for observing the trait_added event. This observer only offers the "maintainer". When this observer is used in an ObserverGraph, its subgraphs are the graphs to be hooked up when a new trait is added, provided that the trait satisfies a given criterion. The criterion should align with the root observer(s) in these subgraph(s). Parameters ---------- match_func : callable(str, CTrait) -> bool A callable that receives the name of the trait added and the corresponding trait. The returned boolean indicates whether notifiers should be added/removed for the added trait. This callable is used for equality check and must be hashable. optional : boolean Whether to skip this observer if the trait_added trait cannot be found on the incoming object. """ def __init__(self, match_func, optional): self.match_func = match_func self.optional = optional def __hash__(self): """ Return a hash of this object.""" return hash((type(self).__name__, self.match_func, self.optional)) def __eq__(self, other): """ Return true if this observer is equal to the given one.""" return ( type(self) is type(other) and self.match_func == other.match_func and self.optional == other.optional ) @property def notify(self): """ A boolean for whether this observer will notify for changes. """ return False def iter_observables(self, object): """ Yield observables for notifiers to be attached to or detached from. Parameters ---------- object: object Object provided by the ``iter_objects`` methods from another observers or directly by the user. Yields ------ IObservable Raises ------ ValueError If the given object cannot be handled by this observer. """ if not object_has_named_trait(object, "trait_added"): if self.optional: return raise ValueError( "Unable to observe 'trait_added' event on {!r}".format(object)) yield object._trait("trait_added", 2) def iter_objects(self, object): """ Yield objects for the next observer following this observer, in an ObserverGraph. Parameters ---------- object: object Object provided by the ``iter_objects`` methods from another observers or directly by the user. Yields ------ value : object """ # children graphs are used in the maintainer only. yield from () # get_notifier is not implemented as notify is always false. def get_maintainer(self, graph, handler, target, dispatcher): """ Return a notifier for maintaining downstream observers when trait_added event happens. Parameters ---------- graph : ObserverGraph Description for the *downstream* observers, i.e. excluding self. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. Returns ------- notifier : ObserverChangeNotifier """ return ObserverChangeNotifier( observer_handler=self.observer_change_handler, event_factory=trait_event_factory, prevent_event=self.prevent_event, graph=graph, handler=handler, target=target, dispatcher=dispatcher, ) def prevent_event(self, event): """ Return true if the added trait should not be handled. Parameters ---------- event : TraitChangeEvent Event triggered by add_trait. """ object = event.object name = event.new trait = object.trait(name=name) return not self.match_func(name, trait) @staticmethod def observer_change_handler(event, graph, handler, target, dispatcher): """ Handler for maintaining observers. Parameters ---------- event : TraitChangeEvent Event triggered by add_trait. graph : ObserverGraph Description for the *downstream* observers, i.e. excluding self. handler : callable User handler. target : object Object seen by the user as the owner of the observer. dispatcher : callable Callable for dispatching the handler. """ new_graph = ObserverGraph( node=_RestrictedNamedTraitObserver( name=event.new, wrapped_observer=graph.node, ), children=graph.children ) add_or_remove_notifiers( object=event.object, graph=new_graph, handler=handler, target=target, dispatcher=dispatcher, remove=False, ) # There is no mirrored action to this. # ``remove_trait`` does not fire a change event. # see enthought/traits#1047 def iter_extra_graphs(self, graph): """ Yield new ObserverGraph to be contributed by this observer. Parameters ---------- graph : ObserverGraph The graph this observer is part of. Yields ------ ObserverGraph """ yield from () @IObserver.register class _RestrictedNamedTraitObserver: """ An observer to support TraitAddedObserver in order to add notifiers for one specific named trait. The notifiers should be contributed by the original observer. Parameters ---------- name : str Name of the trait to be observed. wrapped_observer : IObserver The observer from which notifers are obtained. """ def __init__(self, name, wrapped_observer): self.name = name self._wrapped_observer = wrapped_observer def __hash__(self): return hash((type(self), self.name, self._wrapped_observer)) def __eq__(self, other): return ( type(self) is type(other) and self.name == other.name and self._wrapped_observer == other._wrapped_observer ) @property def notify(self): """ A boolean for whether this observer will notify for changes. """ return self._wrapped_observer.notify def iter_observables(self, object): """ Yield only the observable for the named trait.""" yield object._trait(self.name, 2) def iter_objects(self, object): """ Yield only the value for the named trait.""" yield from iter_objects(object, self.name) def get_notifier(self, handler, target, dispatcher): """ Return the notifier from the wrapped observer.""" return self._wrapped_observer.get_notifier(handler, target, dispatcher) def get_maintainer(self, graph, handler, target, dispatcher): """ Return the maintainer from the wrapped observer.""" return self._wrapped_observer.get_maintainer( graph, handler, target, dispatcher) def iter_extra_graphs(self, graph): yield from () traits-6.3.2/traits/observation/_trait_change_event.py000066400000000000000000000033741414270267200232470ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Event object and factory for CTrait change event. """ # TraitChangeEvent is exposed in the public API. class TraitChangeEvent: """ Emitted when a trait on a HasTraits object is changed. The interface of this object is provisional as of version 6.1. Attributes ---------- object : HasTraits Object on which a trait is changed. name : str Name of the trait. old : any The old value. new : any The new value. """ def __init__(self, *, object, name, old, new): self.object = object self.name = name self.old = old self.new = new def __repr__(self): return ( "{event.__class__.__name__}(" "object={event.object!r}, " "name={event.name!r}, " "old={event.old!r}, " "new={event.new!r}" ")".format(event=self) ) def trait_event_factory(object, name, old, new): """ Adapt the call signature of ctraits call_notifiers to create an event. Parameters ---------- object : HasTraits Object on which a trait is changed. name : str Name of the trait. old : any The old value. new : any The new value. Returns ------- TraitChangeEvent """ return TraitChangeEvent(object=object, name=name, old=old, new=new) traits-6.3.2/traits/observation/_trait_event_notifier.py000066400000000000000000000200421414270267200236300ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from functools import partial import types import weakref from traits.observation.exception_handling import handle_exception from traits.observation.exceptions import NotifierNotFound class TraitEventNotifier: """ Wrapper for invoking user's handler for a trait change event. An instance of ``TraitEventNotifier`` is a callable to be contributed to an instance of ``IObserverable``, e.g. ``CTrait``, ``TraitList`` etc., such that it will be called when an observerable emits notificaitons for changes. The call signature is defined by the observable object and may vary. It is the responsibility of the ``event_factory`` to adapt the varying call signatures and create an event object to be given to the user's handler. A ``TraitEventNotifier`` keeps a reference count in order to address situations where a same object is repeated inside a container and one would not want to fire the same change handler multiple times (see enthought/traits#237). For that purpose, a notifier keeps track of the ``HasTraits`` instance (called ``target``) on which the user applies the observers, keeps a reference count internally, and it also needs to determine whether another notifier refers to the same change handler and ``HasTraits`` instance. Since there is only one reference count associated with a notifier, each notifier is expected to be added to only one observable. Parameters ---------- handler : callable(event) The user's handler to receive the change event. The event object is returned by the ``event_factory``. If the handler is an instance method, then a weak reference is created for the method. If the instance is garbage collected, the notifier will be muted. target : object An object for defining the context of the notifier. A weak reference is created for the target. If the target is garbage collected, the notifier will be muted. This target is typically an instance of ``HasTraits`` and will be seen by the user as the "owner" of the change handler. This is also used for distinguishing one notifier from another notifier wrapping the same handler. event_factory : callable(*args, **kwargs) -> object A factory function for creating the event object to be sent to the handler. The call signature must be compatible with the call signature expected by the observable this notifier is used with. e.g. for CTrait, the call signature will be ``(object, name, old, new)``. prevent_event : callable(event) -> boolean A callable for controlling whether the user handler should be invoked. It receives the event created by the event factory and returns true if the event should be prevented, false if the event should be fired. dispatcher : callable(handler, event) A callable for dispatching the handler, e.g. on a different thread or on a GUI event loop. ``event`` is the object created by the event factory. Raises ------ ValueError If the handler given is not a callable. """ def __init__( self, *, handler, target, event_factory, prevent_event, dispatcher): if not callable(handler): raise ValueError( "handler must be a callable, got {!r}".format(handler)) # This is such that the notifier does not prevent # the target from being garbage collected. self.target = weakref.ref(target) if isinstance(handler, types.MethodType): self.handler = weakref.WeakMethod(handler) else: self.handler = partial(_return, value=handler) self.dispatcher = dispatcher self.event_factory = event_factory self.prevent_event = prevent_event # Reference count to avoid adding multiple equivalent notifiers # to the same observable. self._ref_count = 0 def __call__(self, *args, **kwargs): """ Called by observables. The call signature will vary and will be handled by the event factory. """ if self.target() is None: # target is deleted. The notifier is disabled. return # Hold onto the reference while invoking the handler handler = self.handler() if handler is None: # The instance method is deleted. The notifier is disabled. return event = self.event_factory(*args, **kwargs) if self.prevent_event(event): return try: self.dispatcher(handler, event) except Exception: handle_exception(event) def add_to(self, observable): """ Add this notifier to an observable object. If an equivalent notifier exists, the existing notifier's reference count is bumped. Hence this method is not idempotent. N number of calls to this ``add_to`` must be matched by N calls to the ``remove_from`` method in order to completely remove a notifier from an observable. Parameters ---------- observable : IObservable An object for adding this notifier to. Raises ------ RuntimeError If the internal reference count is not zero and an equivalent notifier is not found in the observable. """ notifiers = observable._notifiers(True) for other in notifiers: if self.equals(other): other._ref_count += 1 break else: # It is not a current use case to share a notifier with multiple # observables. Using a single reference count will tie the lifetime # of the notifier to multiple objects. if self._ref_count != 0: raise RuntimeError( "Sharing notifiers across observables is unexpected." ) notifiers.append(self) self._ref_count += 1 def remove_from(self, observable): """ Remove this notifier from an observable object. If an equivalent notifier exists, the existing notifier's reference count is decremented and the notifier is only removed if the count is reduced to zero. Parameters ---------- observable : IObservable An object for removing this notifier from. Raises ------ RuntimeError If the reference count becomes negative unexpectedly. NotifierNotFound If the notifier is not found. """ notifiers = observable._notifiers(True) for other in notifiers[:]: if self.equals(other): if other._ref_count == 1: notifiers.remove(other) other._ref_count -= 1 if other._ref_count < 0: raise RuntimeError( "Reference count is negative. " "Race condition?" ) break else: raise NotifierNotFound("Notifier not found.") def equals(self, other): """ Return true if the other notifier is equivalent to this one. Parameters ---------- other : any Returns ------- boolean """ if other is self: return True if type(other) is not type(self): return False return ( self.handler() == other.handler() and self.target() is other.target() and self.dispatcher == other.dispatcher ) def _return(value): return value traits-6.3.2/traits/observation/api.py000066400000000000000000000016141414270267200200230ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.observation.exception_handling import ( pop_exception_handler, push_exception_handler, ) from traits.observation.exceptions import NotifierNotFound from traits.observation.expression import ( anytrait, compile_expr, dict_items, list_items, match, metadata, set_items, trait, ) from traits.observation.observe import ( apply_observers, dispatch_same, observe, ) from traits.observation.parsing import ( compile_str, parse, ) traits-6.3.2/traits/observation/events.py000066400000000000000000000015141414270267200205550ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Event objects received by change handlers added using observe. """ from traits.observation._dict_change_event import ( # noqa: F401 DictChangeEvent, ) from traits.observation._list_change_event import ( # noqa: F401 ListChangeEvent, ) from traits.observation._set_change_event import ( # noqa: F401 SetChangeEvent, ) from traits.observation._trait_change_event import ( # noqa: F401 TraitChangeEvent, ) traits-6.3.2/traits/observation/exception_handling.py000066400000000000000000000067431414270267200231240ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # This module provides the push_exception_handler and pop_exception_handler # for the observers. import logging import sys _logger = logging.getLogger("traits") class ObserverExceptionHandler: """ State for an exception handler. Parameters ---------- handler : callable(event) or None A callable to handle an event, in the context of an exception. If None, the exceptions will be logged. reraise_exceptions : boolean Whether to reraise the exception. """ def __init__(self, handler, reraise_exceptions): self.handler = handler if handler is not None else self._log_exception self.reraise_exceptions = reraise_exceptions def _log_exception(self, event): """ A handler that logs the exception with the given event. Parameters ---------- event : object An event object emitted by the notification. """ _logger.exception( "Exception occurred in traits notification handler " "for event object: %r", event, ) class ObserverExceptionHandlerStack: """ A stack of exception handlers. Parameters ---------- handlers : list of ObserverExceptionHandler The last item is the current handler. """ def __init__(self): self.handlers = [] def push_exception_handler( self, handler=None, reraise_exceptions=False): """ Push a new exception handler into the stack. Making it the current exception handler. Parameters ---------- handler : callable(event) or None A callable to handle an event, in the context of an exception. If None, the exceptions will be logged. reraise_exceptions : boolean Whether to reraise the exception. """ self.handlers.append( ObserverExceptionHandler( handler=handler, reraise_exceptions=reraise_exceptions, ) ) def pop_exception_handler(self): """ Pop the current exception handler from the stack. Raises ------ IndexError If there are no handlers to pop. """ return self.handlers.pop() def handle_exception(self, event): """ Handles a traits notification exception using the handler last pushed. Parameters ---------- event : object An event object emitted by the notification. """ _, excp, _ = sys.exc_info() try: handler_state = self.handlers[-1] except IndexError: handler_state = ObserverExceptionHandler( handler=None, reraise_exceptions=False, ) handler_state.handler(event) if handler_state.reraise_exceptions: raise excp _exception_handler_stack = ObserverExceptionHandlerStack() push_exception_handler = _exception_handler_stack.push_exception_handler pop_exception_handler = _exception_handler_stack.pop_exception_handler handle_exception = _exception_handler_stack.handle_exception traits-6.3.2/traits/observation/exceptions.py000066400000000000000000000007701414270267200214350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! class NotifierNotFound(Exception): """ Raised when a notifier cannot be found.""" pass traits-6.3.2/traits/observation/expression.py000066400000000000000000000432101414270267200214470ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import functools from traits.observation._anytrait_filter import anytrait_filter from traits.observation._dict_item_observer import DictItemObserver from traits.observation._filtered_trait_observer import FilteredTraitObserver from traits.observation._list_item_observer import ListItemObserver from traits.observation._metadata_filter import MetadataFilter from traits.observation._named_trait_observer import NamedTraitObserver from traits.observation._observer_graph import ObserverGraph from traits.observation._set_item_observer import SetItemObserver #: Maximum number of parsed observer expressions stored in the LRU caches _OBSERVER_EXPRESSION_CACHE_MAXSIZE = 256 # ObserverExpression is a public user interface for constructing ObserverGraph. class ObserverExpression: """ ObserverExpression is an object for describing what traits are being observed for change notifications. It can be passed directly to ``HasTraits.observe`` method or the ``observe`` decorator. An ObserverExpression is typically created using one of the top-level functions provided in this module, e.g. ``trait``. """ __slots__ = () def __or__(self, expression): """ Create a new expression that matches this expression OR the given expression. e.g. ``trait("age") | trait("number")`` will match either trait **age** or trait **number** on an object. Parameters ---------- expression : ObserverExpression Returns ------- new_expression : ObserverExpression """ return ParallelObserverExpression(self, expression) def then(self, expression): """ Create a new expression by extending this expression with the given expression. e.g. ``trait("child").then( trait("age") | trait("number") )`` on an object matches ``child.age`` or ``child.number`` on the object. Parameters ---------- expression : ObserverExpression Returns ------- new_expression : ObserverExpression """ return SeriesObserverExpression(self, expression) def match(self, filter, notify=True): """ Create a new expression for observing traits using the given filter. Events emitted (if any) will be instances of :class:`~traits.observation.events.TraitChangeEvent`. Parameters ---------- filter : callable(str, CTrait) -> bool A callable that receives the name of a trait and the corresponding trait definition. The returned bool indicates whether the trait is observed. In order to remove an existing observer with the equivalent filter, the filter callables must compare equally. The callable must also be hashable. notify : bool, optional Whether to notify for changes. Default is to notify. Returns ------- new_expression : ObserverExpression """ return self.then(match(filter=filter, notify=notify)) def anytrait(self, notify=True): """ Create a new expression for observing all traits. Events emitted (if any) will be instances of :class:`~traits.observation.events.TraitChangeEvent`. Parameters ---------- notify : bool, optional Whether to notify for changes. Default is to notify. Returns ------- new_expression : ObserverExpression """ return self.match(filter=anytrait_filter, notify=notify) def metadata(self, metadata_name, notify=True): """ Return a new expression for observing traits where the given metadata is not None. Events emitted (if any) will be instances of :class:`~traits.observation.events.TraitChangeEvent`. e.g. ``metadata("age")`` matches traits whose 'age' attribute has a non-None value. Parameters ---------- metadata_name : str Name of the metadata to filter traits with. notify : bool, optional Whether to notify for changes. Default is to notify. Returns ------- new_expression : ObserverExpression """ return self.match( filter=MetadataFilter(metadata_name=metadata_name), notify=notify, ) def dict_items(self, notify=True, optional=False): """ Create a new expression for observing items inside a dict. Events emitted (if any) will be instances of :class:`~traits.observation.events.DictChangeEvent`. If an expression with ``dict_items`` is further extended, the **values** of the dict will be given to the next item in the expression. For example, the following observes a trait named "number" on any object that is one of the values in the dict named "mapping":: trait("mapping").dict_items().trait("number") Parameters ---------- notify : bool, optional Whether to notify for changes. Default is to notify. optional : bool, optional Whether to ignore this if the upstream object is not a dict. Default is false and an error will be raised if the object is not a dict. Returns ------- new_expression : ObserverExpression """ return self.then(dict_items(notify=notify, optional=optional)) def list_items(self, notify=True, optional=False): """ Create a new expression for observing items inside a list. Events emitted (if any) will be instances of :class:`~traits.observation.events.ListChangeEvent`. e.g. ``trait("containers").list_items()`` for observing mutations to a list named ``containers``. e.g. ``trait("containers").list_items().trait("value")`` for observing the trait ``value`` on any items in the list ``containers``. Parameters ---------- notify : bool, optional Whether to notify for changes. Default is to notify. optional : bool, optional Whether to ignore this if the upstream object is not a list. Default is false and an error will be raised if the object is not a list. Returns ------- new_expression : ObserverExpression """ return self.then(list_items(notify=notify, optional=optional)) def set_items(self, notify=True, optional=False): """ Create a new expression for observing items inside a set. Events emitted (if any) will be instances of :class:`~traits.observation.events.SetChangeEvent`. Parameters ---------- notify : bool, optional Whether to notify for changes. Default is to notify. optional : bool, optional Whether to ignore this if the upstream object is not a set. Default is false and an error will be raised if the object is not a set. Returns ------- new_expression : ObserverExpression """ return self.then(set_items(notify=notify, optional=optional)) def trait(self, name, notify=True, optional=False): """ Create a new expression for observing a trait with the exact name given. Events emitted (if any) will be instances of :class:`~traits.observation.events.TraitChangeEvent`. Parameters ---------- name : str Name of the trait to match. notify : bool, optional Whether to notify for changes. Default is to notify. optional : bool, optional If true, skip this observer if the requested trait is not found. Default is false, and an error will be raised if the requested trait is not found. Returns ------- new_expression : ObserverExpression """ return self.then(trait(name=name, notify=notify, optional=optional)) def _as_graphs(self): """ Return all the ObserverGraph for the observer framework to attach notifiers. This is considered private to the users and to modules outside of the ``observation`` subpackage, but public to modules within the ``observation`` subpackage. Returns ------- graphs : list of ObserverGraph """ return self._create_graphs(branches=[]) def _create_graphs(self, branches): """ Return a list of ObserverGraph with the given branches. Parameters ---------- branches : list of ObserverGraph Graphs to be used as branches. Returns ------- graphs : list of ObserverGraph """ raise NotImplementedError("'_create_graphs' must be implemented.") class SingleObserverExpression(ObserverExpression): """ Container of ObserverExpression for wrapping a single observer. """ __slots__ = ("_observer",) def __init__(self, observer): self._observer = observer def __hash__(self): return hash((type(self).__name__, self._observer)) def __eq__(self, other): return ( type(self) is type(other) and self._observer == other._observer ) def _create_graphs(self, branches): return [ ObserverGraph(node=self._observer, children=branches), ] class SeriesObserverExpression(ObserverExpression): """ Container of ObserverExpression for joining expressions in series. Parameters ---------- first : ObserverExpression Left expression to be joined in series. second : ObserverExpression Right expression to be joined in series. """ __slots__ = ("_first", "_second") def __init__(self, first, second): self._first = first self._second = second def __hash__(self): return hash((type(self).__name__, self._first, self._second)) def __eq__(self, other): return ( type(self) is type(other) and self._first == other._first and self._second == other._second ) def _create_graphs(self, branches): branches = self._second._create_graphs(branches=branches) return self._first._create_graphs(branches=branches) class ParallelObserverExpression(ObserverExpression): """ Container of ObserverExpression for joining expressions in parallel. Parameters ---------- left : ObserverExpression Left expression to be joined in parallel. right : ObserverExpression Right expression to be joined in parallel. """ __slots__ = ("_left", "_right") def __init__(self, left, right): self._left = left self._right = right def __hash__(self): return hash((type(self).__name__, self._left, self._right)) def __eq__(self, other): return ( type(self) is type(other) and self._left == other._left and self._right == other._right ) def _create_graphs(self, branches): left_graphs = self._left._create_graphs(branches=branches) right_graphs = self._right._create_graphs(branches=branches) return left_graphs + right_graphs def join(*expressions): """ Convenient function for joining many expressions in series using ``ObserverExpression.then`` Parameters ---------- *expressions : iterable of ObserverExpression Returns ------- new_expression : ObserverExpression Joined expression. """ return functools.reduce(lambda e1, e2: e1.then(e2), expressions) def dict_items(notify=True, optional=False): """ Create a new expression for observing items inside a dict. Events emitted (if any) will be instances of :class:`~traits.observation.events.DictChangeEvent`. If an expression with ``dict_items`` is further extended, the **values** of the dict will be given to the next item in the expression. For example, the following observes a trait named "number" on any object that is one of the values in the dict named "mapping":: trait("mapping").dict_items().trait("number") Parameters ---------- notify : bool, optional Whether to notify for changes. Default is to notify. optional : bool, optional Whether to ignore this if the upstream object is not a dict. Default is false and an error will be raised if the object is not a dict. Returns ------- new_expression : ObserverExpression """ observer = DictItemObserver(notify=notify, optional=optional) return SingleObserverExpression(observer) def list_items(notify=True, optional=False): """ Create a new expression for observing items inside a list. Events emitted (if any) will be instances of :class:`~traits.observation.events.ListChangeEvent`. e.g. ``trait("containers").list_items()`` for observing mutations to a list named ``containers``. e.g. ``trait("containers").list_items().trait("value")`` for observing the trait ``value`` on any items in the list ``containers``. Parameters ---------- notify : bool, optional Whether to notify for changes. Default is to notify. optional : bool, optional Whether to ignore this if the upstream object is not a list. Default is false and an error will be raised if the object is not a list. Returns ------- new_expression : ObserverExpression """ observer = ListItemObserver(notify=notify, optional=optional) return SingleObserverExpression(observer) def match(filter, notify=True): """ Create a new expression for observing traits using the given filter. Events emitted (if any) will be instances of :class:`~traits.observation.events.TraitChangeEvent`. Parameters ---------- filter : callable(str, CTrait) -> bool A callable that receives the name of a trait and the corresponding trait definition. The returned bool indicates whether the trait is observed. In order to remove an existing observer with the equivalent filter, the filter callables must compare equally. The callable must also be hashable. notify : bool, optional Whether to notify for changes. Returns ------- new_expression : ObserverExpression """ observer = FilteredTraitObserver(notify=notify, filter=filter) return SingleObserverExpression(observer) def anytrait(notify=True): """ Create a new expression for observing all traits on an object. Events emitted (if any) will be instances of :class:`~traits.observation.events.TraitChangeEvent`. Parameters ---------- notify : bool, optional Whether to notify for changes. """ observer = FilteredTraitObserver(notify=notify, filter=anytrait_filter) return SingleObserverExpression(observer) def metadata(metadata_name, notify=True): """ Return a new expression for observing traits where the given metadata is not None. Events emitted (if any) will be instances of :class:`~traits.observation.events.TraitChangeEvent`. e.g. ``metadata("age")`` matches traits whose 'age' attribute has a non-None value. Parameters ---------- metadata_name : str Name of the metadata to filter traits with. notify : bool, optional Whether to notify for changes. Default is to notify. Returns ------- new_expression : ObserverExpression """ return match( filter=MetadataFilter(metadata_name=metadata_name), notify=notify, ) def set_items(notify=True, optional=False): """ Create a new expression for observing items inside a set. Events emitted (if any) will be instances of :class:`~traits.observation.events.SetChangeEvent`. Parameters ---------- notify : bool, optional Whether to notify for changes. Default is to notify. optional : bool, optional Whether to ignore this if the upstream object is not a set. Default is false and an error will be raised if the object is not a set. Returns ------- new_expression : ObserverExpression """ observer = SetItemObserver(notify=notify, optional=optional) return SingleObserverExpression(observer) def trait(name, notify=True, optional=False): """ Create a new expression for observing a trait with the exact name given. Events emitted (if any) will be instances of :class:`~traits.observation.events.TraitChangeEvent`. Parameters ---------- name : str Name of the trait to match. notify : bool, optional Whether to notify for changes. Default is to notify. optional : bool, optional If true, skip this observer if the requested trait is not found. Default is false, and an error will be raised if the requested trait is not found. Returns ------- new_expression : ObserverExpression """ observer = NamedTraitObserver( name=name, notify=notify, optional=optional) return SingleObserverExpression(observer) @functools.lru_cache(maxsize=_OBSERVER_EXPRESSION_CACHE_MAXSIZE) def compile_expr(expr): """ Compile an ObserverExpression to a list of ObserverGraphs. Parameters ---------- expr : ObserverExpression Returns ------- list of ObserverGraph """ return expr._as_graphs() traits-6.3.2/traits/observation/i_observable.py000066400000000000000000000020211414270267200216770ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import abc class IObservable(abc.ABC): """ Interface for objects that can emit notifications for the observer system. """ def _notifiers(self, force_create): """ Return a list of callables where each callable is a notifier. The list is expected to be mutated for contributing or removing notifiers from the object. Parameters ---------- force_create: boolean It is added for compatibility with CTrait. It should not be used otherwise. """ raise NotImplementedError( "Observable object must implement _notifiers") traits-6.3.2/traits/observation/observe.py000066400000000000000000000060021414270267200207130ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.observation._observe import add_or_remove_notifiers from traits.observation.expression import compile_expr def dispatch_same(handler, event): """ Dispatch an event handler on the same thread. Parameters ---------- handler : callable(event) User-defined callable to handle change events. ``event`` is an object representing the change. Its type and content depends on the change. event : object The event object to be given to handler. """ handler(event) def observe( object, expression, handler, *, remove=False, dispatcher=dispatch_same): """ Observer or unobserve traits on an object. Parameters ---------- object : object An object to be observed. Usually an instance of ``HasTraits``. expression : ObserverExpression An object describing what traits are being observed. handler : callable(event) User-defined callable to handle change events. ``event`` is an object representing the change. Its type and content depends on the change. remove : boolean, optional If true, remove notifiers. i.e. unobserve the traits. dispatcher : callable(callable, event), optional Callable for dispatching the user-defined handler, e.g. dispatching callback on a different thread. Default is to dispatch on the same thread. """ apply_observers( object, graphs=compile_expr(expression), handler=handler, dispatcher=dispatcher, remove=remove, ) def apply_observers(object, graphs, handler, *, dispatcher, remove=False): """ Apply one or more ObserverGraphs to an object and handler. Parameters ---------- object : object An object to be observed. Usually an instance of ``HasTraits``. graphs : list of ObserverGraph Graphs describing the observation patterns to apply. handler : callable(event) User-defined callable to handle change events. ``event`` is an object representing the change. Its type and content depends on the change. dispatcher : callable(callable, event). Callable for dispatching the user-defined handler, e.g. dispatching callback on a different thread. remove : boolean, optional If True, remove notifiers. i.e. unobserve the traits. The default is False. """ for graph in graphs: add_or_remove_notifiers( object=object, graph=graph, handler=handler, target=object, dispatcher=dispatcher, remove=remove, ) traits-6.3.2/traits/observation/parsing.py000066400000000000000000000130041414270267200207110ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from functools import lru_cache from traits.observation import _generated_parser import traits.observation.expression as expression_module _LARK_PARSER = _generated_parser.Lark_StandAlone() def _handle_series(trees, notify): """ Handle an expression of the form "a.b" or "a:b". Parameters ---------- trees : list of lark.tree.Tree The children tree for the "series" rule. It should always contain exactly three items. notify : bool True if the final target should notify, else False. Returns ------- expression : ObserverExpression """ left, connector, right = trees notify_left = connector.data == "notify" return _handle_tree(left, notify_left).then(_handle_tree(right, notify)) def _handle_parallel(trees, notify): """ Handle an expression of the form "a, b". Parameters ---------- trees : list of lark.tree.Tree The children tree for the "parallel" rule. It should always contain exactly two items. notify : bool True if the final target should notify, else False. Returns ------- expression : ObserverExpression """ left, right = trees return _handle_tree(left, notify) | _handle_tree(right, notify) def _handle_trait(trees, notify): """ Handle an element for a named trait. Parameters ---------- trees : list of lark.tree.Tree The children tree for the "trait" rule. It contains only one item. notify : bool True if the final target should notify, else False. Returns ------- expression : ObserverExpression """ token, = trees name = token.value return expression_module.trait(name, notify=notify) def _handle_anytrait(trees, notify): """ Handle an anytrait element. Parameters ---------- trees : list of lark.tree.Tree The children tree for the "trait" rule. This should be empty. notify : bool True if the final target should notify, else False. Returns ------- expression : ObserverExpression """ return expression_module.anytrait(notify=notify) def _handle_metadata(trees, notify): """ Handle an element for filtering existing metadata. Parameters ---------- trees : list of lark.tree.Tree The children tree for the "metadata" rule. It contains only one item. notify : bool True if the final target should notify, else False. Returns ------- expression : ObserverExpression """ token, = trees metadata_name = token.value return expression_module.metadata(metadata_name, notify=notify) def _handle_items(trees, notify): """ Handle keyword "items". Parameters ---------- trees : list of lark.tree.Tree The children tree for the "items" rule. It should be empty. notify : bool True if the final target should notify, else False. Returns ------- expression : ObserverExpression """ if trees: # Nothing should be wrapped in items raise ValueError("Unexpected tree: {!r}".format(trees)) return ( expression_module.trait("items", notify=notify, optional=True) | expression_module.dict_items(notify=notify, optional=True) | expression_module.list_items(notify=notify, optional=True) | expression_module.set_items(notify=notify, optional=True) ) def _handle_tree(tree, notify): """ Handle a tree using the specified rule. Parameters ---------- tree : lark.tree.Tree Tree to be converted to an ObserverExpression. notify : bool True if the final target should notify, else False. Returns ------- expression: ObserverExpression """ # All handlers must be callable # with the signature (list of Tree, notify) handlers = { "series": _handle_series, "series_terminal": _handle_series, "parallel": _handle_parallel, "parallel_terminal": _handle_parallel, "trait": _handle_trait, "metadata": _handle_metadata, "items": _handle_items, "anytrait": _handle_anytrait, } return handlers[tree.data](tree.children, notify) @lru_cache(maxsize=expression_module._OBSERVER_EXPRESSION_CACHE_MAXSIZE) def parse(text): """ Top-level function for parsing user's text to an ObserverExpression. Parameters ---------- text : str Text to be parsed. Returns ------- expression : ObserverExpression Raises ------ ValueError If the text is not a valid observe expression. """ try: tree = _LARK_PARSER.parse(text) except _generated_parser.LarkError as parser_exception: raise ValueError(f"Invalid expression: {text!r}") from parser_exception return _handle_tree(tree, notify=True) @lru_cache(maxsize=expression_module._OBSERVER_EXPRESSION_CACHE_MAXSIZE) def compile_str(text): """ Compile a mini-language string to a list of ObserverGraphs. Parameters ---------- text : str Text to be parsed. Returns ------- list of ObserverGraph """ return expression_module.compile_expr(parse(text)) traits-6.3.2/traits/observation/tests/000077500000000000000000000000001414270267200200405ustar00rootroot00000000000000traits-6.3.2/traits/observation/tests/__init__.py000066400000000000000000000000001414270267200221370ustar00rootroot00000000000000traits-6.3.2/traits/observation/tests/test_dict_change_event.py000066400000000000000000000033751414270267200251120ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.observation._dict_change_event import ( DictChangeEvent, dict_event_factory, ) from traits.trait_dict_object import TraitDict class TestDictChangeEvent(unittest.TestCase): def test_dict_change_event_repr(self): event = DictChangeEvent( object=dict(), added={1: 1}, removed={"2": 2}, ) actual = repr(event) self.assertEqual( actual, "DictChangeEvent(object={}, removed={'2': 2}, added={1: 1})" ) class TestDictEventFactory(unittest.TestCase): """ Test event factory compatibility with TraitDict.notify """ def test_trait_dict_notification_compat(self): events = [] def notifier(*args, **kwargs): event = dict_event_factory(*args, **kwargs) events.append(event) trait_dict = TraitDict( {"3": 3, "4": 4}, notifiers=[notifier], ) # when del trait_dict["4"] # then event, = events self.assertIs(event.object, trait_dict) self.assertEqual(event.removed, {"4": 4}) # when events.clear() trait_dict.update({"3": None, "1": 1}) # then event, = events self.assertEqual(event.removed, {"3": 3}) self.assertEqual(event.added, {"3": None, "1": 1}) traits-6.3.2/traits/observation/tests/test_dict_item_observer.py000066400000000000000000000221611414270267200253230ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from unittest import mock from traits.has_traits import HasTraits from traits.observation._dict_item_observer import DictItemObserver from traits.observation._testing import ( call_add_or_remove_notifiers, create_graph, ) from traits.trait_dict_object import TraitDict from traits.trait_types import Dict, Str def create_observer(**kwargs): """ Convenience function for creating DictItemObserver with default values. """ values = dict( notify=True, optional=False, ) values.update(kwargs) return DictItemObserver(**values) class TestDictItemObserverEqualHash(unittest.TestCase): """ Test DictItemObserver __eq__, __hash__. """ def test_not_equal_notify(self): observer1 = DictItemObserver(notify=False, optional=False) observer2 = DictItemObserver(notify=True, optional=False) self.assertNotEqual(observer1, observer2) def test_not_equal_optional(self): observer1 = DictItemObserver(notify=True, optional=True) observer2 = DictItemObserver(notify=True, optional=False) self.assertNotEqual(observer1, observer2) def test_not_equal_different_type(self): observer1 = DictItemObserver(notify=False, optional=False) imposter = mock.Mock() imposter.notify = False imposter.optional = False self.assertNotEqual(observer1, imposter) def test_equal_observers(self): observer1 = DictItemObserver(notify=False, optional=False) observer2 = DictItemObserver(notify=False, optional=False) self.assertEqual(observer1, observer2) self.assertEqual(hash(observer1), hash(observer2)) def test_slots(self): observer = DictItemObserver(notify=True, optional=False) with self.assertRaises(AttributeError): observer.__dict__ with self.assertRaises(AttributeError): observer.__weakref__ def test_eval_repr_roundtrip(self): observer = DictItemObserver(notify=True, optional=False) self.assertEqual(eval(repr(observer)), observer) class CustomDict(dict): # This is a dict, but not an observable pass class CustomTraitDict(TraitDict): # This can be observed using DictItemObserver pass class ClassWithDict(HasTraits): values = Dict() dict_of_dict = Dict(Str, Dict) class TestDictItemObserverIterObservable(unittest.TestCase): """ Test DictItemObserver.iter_observables """ def test_trait_dict_iter_observables(self): instance = ClassWithDict() observer = create_observer(optional=False) actual_item, = list(observer.iter_observables(instance.values)) self.assertIs(actual_item, instance.values) def test_dict_but_not_a_trait_dict(self): observer = create_observer(optional=False) with self.assertRaises(ValueError) as exception_context: list(observer.iter_observables(CustomDict())) self.assertIn( "Expected a TraitDict to be observed, got", str(exception_context.exception) ) def test_custom_trait_dict_is_observable(self): observer = create_observer(optional=False) custom_trait_dict = CustomTraitDict() actual_item, = list(observer.iter_observables(custom_trait_dict)) self.assertIs(actual_item, custom_trait_dict) def test_not_a_dict(self): observer = create_observer(optional=False) with self.assertRaises(ValueError) as exception_context: list(observer.iter_observables(None)) self.assertIn( "Expected a TraitDict to be observed, got", str(exception_context.exception) ) def test_optional_flag_not_a_dict(self): observer = create_observer(optional=True) actual = list(observer.iter_observables(None)) self.assertEqual(actual, []) def test_optional_flag_not_an_observable(self): observer = create_observer(optional=True) actual = list(observer.iter_observables(CustomDict())) self.assertEqual(actual, []) class TestDictItemObserverIterObjects(unittest.TestCase): """ Test DictItemObserver.iter_objects """ def test_iter_objects_from_dict(self): instance = ClassWithDict() instance.values = {"1": 1, "2": 2} observer = create_observer() actual = list(observer.iter_objects(instance.values)) self.assertCountEqual(actual, [1, 2]) def test_iter_objects_from_custom_trait_dict(self): observer = create_observer(optional=False) custom_trait_dict = CustomTraitDict({"1": 1, "2": 2}) actual = list(observer.iter_objects(custom_trait_dict)) self.assertCountEqual(actual, [1, 2]) def test_iter_objects_sanity_check(self): # sanity check if the given object is a dict observer = create_observer(optional=False) with self.assertRaises(ValueError) as exception_context: list(observer.iter_objects(None)) self.assertIn( "Expected a TraitDict to be observed", str(exception_context.exception), ) def test_iter_objects_optional(self): observer = create_observer(optional=True) actual = list(observer.iter_objects(None)) self.assertEqual(actual, []) class TestDictItemObserverNotifications(unittest.TestCase): """ Integration tests with notifiers (including maintainers). """ def test_notify_dict_change(self): instance = ClassWithDict(values=dict()) graph = create_graph( create_observer(notify=True), ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance.values, graph=graph, handler=handler, ) # when instance.values.update({"1": 1}) # then ((event, ), _), = handler.call_args_list self.assertEqual(event.added, {"1": 1}) self.assertEqual(event.removed, {}) def test_notify_custom_trait_dict_change(self): # Test using DictItemObserver for changes on a subclass of TraitDict # that isn't TraitDictObject instance = ClassWithDict(custom_trait_dict=CustomTraitDict()) graph = create_graph( create_observer(notify=True), ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance.custom_trait_dict, graph=graph, handler=handler, ) # when instance.custom_trait_dict.update({"1": 1}) # then ((event, ), _), = handler.call_args_list self.assertEqual(event.added, {"1": 1}) self.assertEqual(event.removed, {}) def test_maintain_notifier_for_added(self): # Test adding downstream notifier by observing a nested dict # inside another dict instance = ClassWithDict() graph = create_graph( create_observer(notify=False, optional=False), create_observer(notify=True, optional=False), ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance.dict_of_dict, graph=graph, handler=handler, ) # when instance.dict_of_dict.update({"1": {"2": 2}}) # then # ``notify`` is set to False for mutations on the outer dict self.assertEqual(handler.call_count, 0) # when del instance.dict_of_dict["1"]["2"] # then # ``notify`` is set to True for mutations on the inner dict self.assertEqual(handler.call_count, 1) ((event, ), _), = handler.call_args_list self.assertEqual(event.added, {}) self.assertEqual(event.removed, {"2": 2}) def test_maintain_notifier_for_removed(self): # Test removing downstream notifier by observing a nested dict # inside another dict instance = ClassWithDict(dict_of_dict={"1": {"2": 2}}) graph = create_graph( create_observer(notify=False, optional=False), create_observer(notify=True, optional=False), ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance.dict_of_dict, graph=graph, handler=handler, ) # sanity check test setup inner_dict = instance.dict_of_dict["1"] inner_dict["3"] = 3 self.assertEqual(handler.call_count, 1) ((event, ), _), = handler.call_args_list self.assertEqual(event.added, {"3": 3}) self.assertEqual(event.removed, {}) handler.reset_mock() # when # Change the content to something else instance.dict_of_dict["1"] = {} # the inner dict is not inside the instance.dict_of_dict any more inner_dict["4"] = 4 # then self.assertEqual(handler.call_count, 0) traits-6.3.2/traits/observation/tests/test_exception_handling.py000066400000000000000000000051441414270267200253170ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test the push_exception_handler and pop_exception_handler for the observers """ import unittest from unittest import mock from traits.observation.exception_handling import ( ObserverExceptionHandlerStack, ) class TestExceptionHandling(unittest.TestCase): def test_default_logging(self): stack = ObserverExceptionHandlerStack() with self.assertLogs("traits", level="ERROR") as log_context: try: raise ZeroDivisionError() except Exception: stack.handle_exception("Event") content, = log_context.output self.assertIn( "Exception occurred in traits notification handler for " "event object: {!r}".format("Event"), content, ) def test_push_exception_handler(self): # Test pushing an exception handler # with the default logging handler and reraise_exceptions set to True. stack = ObserverExceptionHandlerStack() stack.push_exception_handler(reraise_exceptions=True) with self.assertLogs("traits", level="ERROR") as log_context, \ self.assertRaises(ZeroDivisionError): try: raise ZeroDivisionError() except Exception: stack.handle_exception("Event") content, = log_context.output self.assertIn("ZeroDivisionError", content) def test_push_exception_handler_collect_events(self): events = [] def handler(event): events.append(event) stack = ObserverExceptionHandlerStack() stack.push_exception_handler(handler=handler) try: raise ZeroDivisionError() except Exception: stack.handle_exception("Event") self.assertEqual(events, ["Event"]) def test_pop_exception_handler(self): stack = ObserverExceptionHandlerStack() stack.push_exception_handler(reraise_exceptions=True) stack.pop_exception_handler() # This should not raise as we fall back to the default with mock.patch("sys.stderr"): try: raise ZeroDivisionError() except Exception: stack.handle_exception("Event") traits-6.3.2/traits/observation/tests/test_expression.py000066400000000000000000000603611414270267200236560ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import inspect import unittest from traits.observation import expression from traits.observation._anytrait_filter import anytrait_filter from traits.observation._dict_item_observer import DictItemObserver from traits.observation._filtered_trait_observer import FilteredTraitObserver from traits.observation._list_item_observer import ListItemObserver from traits.observation._metadata_filter import MetadataFilter from traits.observation._named_trait_observer import NamedTraitObserver from traits.observation._set_item_observer import SetItemObserver from traits.observation._observer_graph import ObserverGraph def create_graph(*nodes): """ Create an ObserverGraph with the given nodes joined one after another. Parameters ---------- *nodes : hashable Items to be attached as nodes Returns ------- ObserverGraph """ node = nodes[-1] graph = ObserverGraph(node=node) for node in nodes[:-1][::-1]: graph = ObserverGraph(node=node, children=[graph]) return graph def create_expression(observer): """ Create an expression with a dummy observer for testing purposes. Parameters ---------- observer : hashable Item to be used as a node on ObserverGraph Returns ------- expression : ObserverExpression """ return expression.SingleObserverExpression(observer) class TestObserverExpressionComposition(unittest.TestCase): """ Test composition of ObserverExpression with generic observers.""" def test_new_with_branches(self): observer = 1 expr = create_expression(observer) expected = [ create_graph(observer), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_or_operator(self): observer1 = 1 observer2 = 2 expr1 = create_expression(observer1) expr2 = create_expression(observer2) expr = expr1 | expr2 expected = [ create_graph(observer1), create_graph(observer2), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_or_maintain_order(self): # Test __or__ will maintain the order provided by the user. observer1 = 1 observer2 = 2 expr1 = create_expression(observer1) expr2 = create_expression(observer2) combined1 = expr1 | expr2 combined2 = expr2 | expr1 self.assertEqual(combined1._as_graphs(), combined2._as_graphs()[::-1]) def test_then_operator(self): observer1 = 1 observer2 = 2 expr1 = create_expression(observer1) expr2 = create_expression(observer2) expr = expr1.then(expr2) expected = [ create_graph( observer1, observer2, ) ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_chained_then_or(self): observer1 = 1 observer2 = 2 observer3 = 3 observer4 = 4 expr1 = create_expression(observer1) expr2 = create_expression(observer2) expr3 = create_expression(observer3) expr4 = create_expression(observer4) expr = (expr1.then(expr2)) | (expr3.then(expr4)) expected = [ create_graph( observer1, observer2, ), create_graph( observer3, observer4, ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_or_then_chained(self): observer1 = 1 observer2 = 2 observer3 = 3 observer4 = 4 expr1 = create_expression(observer1) expr2 = create_expression(observer2) expr3 = create_expression(observer3) expr4 = create_expression(observer4) expr = (expr1 | expr2).then(expr3 | expr4) expected = [ ObserverGraph( node=observer1, children=[ create_graph(observer3), create_graph(observer4), ], ), ObserverGraph( node=observer2, children=[ create_graph(observer3), create_graph(observer4), ], ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_join_expressions(self): observer1 = 1 observer2 = 2 expr1 = create_expression(observer1) expr2 = create_expression(observer2) expr = expression.join(expr1, expr2) expected = [ create_graph( observer1, observer2, ) ] actual = expr._as_graphs() self.assertEqual(actual, expected) class TestObserverExpressionAnytrait(unittest.TestCase): """ Test anytrait function and method. """ def test_anytrait_function_notify_true(self): expr = expression.anytrait(notify=True) expected = [ create_graph( FilteredTraitObserver(filter=anytrait_filter, notify=True), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_anytrait_function_notify_false(self): expr = expression.anytrait(notify=False) expected = [ create_graph( FilteredTraitObserver(filter=anytrait_filter, notify=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_anytrait_method_notify_true(self): expr = expression.trait("name").anytrait(notify=True) expected = [ create_graph( NamedTraitObserver(name="name", notify=True, optional=False), FilteredTraitObserver(filter=anytrait_filter, notify=True), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_anytrait_method_notify_false(self): expr = expression.trait("name").anytrait(notify=False) expected = [ create_graph( NamedTraitObserver(name="name", notify=True, optional=False), FilteredTraitObserver(filter=anytrait_filter, notify=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) class TestObserverExpressionFilter(unittest.TestCase): """ Test ObserverExpression.match """ def setUp(self): def anytrait(name, trait): return True self.anytrait = anytrait def test_match_notify_true(self): # Test the top-level function expr = expression.match(filter=self.anytrait) expected = [ create_graph( FilteredTraitObserver(filter=self.anytrait, notify=True), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_match_notify_false(self): # Test the top-level function expr = expression.match(filter=self.anytrait, notify=False) expected = [ create_graph( FilteredTraitObserver(filter=self.anytrait, notify=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_match_method_notify_true(self): # Test the instance method calls the top-level function correctly. expr = expression.match(filter=self.anytrait).match( filter=self.anytrait ) expected = [ create_graph( FilteredTraitObserver(filter=self.anytrait, notify=True), FilteredTraitObserver(filter=self.anytrait, notify=True), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_match_method_notify_false(self): # Test the instance method calls the top-level function correctly. expr = expression.match(filter=self.anytrait).match( filter=self.anytrait, notify=False, ) expected = [ create_graph( FilteredTraitObserver(filter=self.anytrait, notify=True), FilteredTraitObserver(filter=self.anytrait, notify=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_call_signatures(self): # Test to help developers keeping the two function signatures in-sync. # Remove this if the two need to divert in the future. top_level = expression.match method = expression.ObserverExpression().match self.assertEqual( inspect.signature(top_level), inspect.signature(method) ) class TestObserverExpressionFilterMetadata(unittest.TestCase): """ Test ObserverExpression.metadata """ def test_metadata_notify_true(self): # Test the top-level function expr = expression.metadata("butterfly") expected = [ create_graph( FilteredTraitObserver( filter=MetadataFilter(metadata_name="butterfly"), notify=True, ), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_metadata_notify_false(self): # Test the top-level function expr = expression.metadata("butterfly", notify=False) expected = [ create_graph( FilteredTraitObserver( filter=MetadataFilter(metadata_name="butterfly"), notify=False, ), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_metadata_method_notify_true(self): # Test the instance method calls the top-level function correctly. expr = expression.metadata("bee").metadata("ant") expected = [ create_graph( FilteredTraitObserver( filter=MetadataFilter(metadata_name="bee"), notify=True, ), FilteredTraitObserver( filter=MetadataFilter(metadata_name="ant"), notify=True, ), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_metadata_method_notify_false(self): # Test the instance method calls the top-level function correctly. expr = expression.metadata("bee").metadata("ant", notify=False) expected = [ create_graph( FilteredTraitObserver( filter=MetadataFilter(metadata_name="bee"), notify=True, ), FilteredTraitObserver( filter=MetadataFilter(metadata_name="ant"), notify=False, ), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_call_signatures(self): # Test to help developers keeping the two function signatures in-sync. # Remove this if the two need to divert in the future. top_level = expression.metadata method = expression.ObserverExpression().metadata self.assertEqual( inspect.signature(top_level), inspect.signature(method) ) class TestObserverExpressionTrait(unittest.TestCase): """ Test ObserverExpression.trait """ def test_trait_name(self): # Test the top-level function expr = expression.trait("name") expected = [ create_graph( NamedTraitObserver(name="name", notify=True, optional=False) ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_trait_name_notify_false(self): # Test the top-level function expr = expression.trait("name", notify=False) expected = [ create_graph( NamedTraitObserver(name="name", notify=False, optional=False) ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_trait_name_optional_true(self): # Test the top-level function expr = expression.trait("name", optional=True) expected = [ create_graph( NamedTraitObserver(name="name", notify=True, optional=True) ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_trait_method(self): # Test the instance method calls the top-level function correctly. expr = expression.trait("name").trait("attr") expected = [ create_graph( NamedTraitObserver(name="name", notify=True, optional=False), NamedTraitObserver(name="attr", notify=True, optional=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_trait_method_notify_false(self): # Test the instance method calls the top-level function correctly. expr = expression.trait("name").trait("attr", notify=False) expected = [ create_graph( NamedTraitObserver(name="name", notify=True, optional=False), NamedTraitObserver(name="attr", notify=False, optional=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_trait_method_optional_true(self): # Test the instance method calls the top-level function correctly. expr = expression.trait("name").trait("attr", optional=True) expected = [ create_graph( NamedTraitObserver(name="name", notify=True, optional=False), NamedTraitObserver(name="attr", notify=True, optional=True), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_call_signatures(self): # Test to help developers keeping the two function signatures in-sync. # Remove this if the two need to divert in the future. top_level_trait = expression.trait method_trait = expression.ObserverExpression().trait self.assertEqual( inspect.signature(top_level_trait), inspect.signature(method_trait) ) class TestObserverExpressionDictItem(unittest.TestCase): """ Test ObserverExpression.dict_items """ def test_dict_items(self): expr = expression.dict_items() expected = [ create_graph( DictItemObserver(notify=True, optional=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_dict_items_notify_false(self): expr = expression.dict_items(notify=False) expected = [ create_graph( DictItemObserver(notify=False, optional=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_dict_items_optional_true(self): expr = expression.dict_items(optional=True) expected = [ create_graph( DictItemObserver(notify=True, optional=True), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_dict_items_method_notify(self): # Test the instance method calls the top-level function correctly. expr = expression.dict_items().dict_items(notify=False) expected = [ create_graph( DictItemObserver(notify=True, optional=False), DictItemObserver(notify=False, optional=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_dict_items_method_optional(self): # Test the instance method calls the top-level function correctly. expr = expression.dict_items().dict_items(optional=True) expected = [ create_graph( DictItemObserver(notify=True, optional=False), DictItemObserver(notify=True, optional=True), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_call_signatures(self): # Test to help developers keeping the two function signatures in-sync. # Remove this if the two need to divert in the future. top_level = expression.dict_items method = expression.ObserverExpression().dict_items self.assertEqual( inspect.signature(top_level), inspect.signature(method) ) class TestObserverExpressionListItem(unittest.TestCase): """ Test ObserverExpression.list_items """ def test_list_items(self): expr = expression.list_items() expected = [ create_graph( ListItemObserver(notify=True, optional=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_list_items_notify_false(self): expr = expression.list_items(notify=False) expected = [ create_graph( ListItemObserver(notify=False, optional=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_list_items_optional_true(self): expr = expression.list_items(optional=True) expected = [ create_graph( ListItemObserver(notify=True, optional=True), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_list_items_method_notify(self): # Test the instance method calls the top-level function correctly. expr = expression.list_items().list_items(notify=False) expected = [ create_graph( ListItemObserver(notify=True, optional=False), ListItemObserver(notify=False, optional=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_list_items_method_optional(self): # Test the instance method calls the top-level function correctly. expr = expression.list_items().list_items(optional=True) expected = [ create_graph( ListItemObserver(notify=True, optional=False), ListItemObserver(notify=True, optional=True), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_call_signatures(self): # Test to help developers keeping the two function signatures in-sync. # Remove this if the two need to divert in the future. top_level = expression.list_items method = expression.ObserverExpression().list_items self.assertEqual( inspect.signature(top_level), inspect.signature(method) ) class TestObserverExpressionSetItem(unittest.TestCase): """ Test ObserverExpression.set_items """ def test_set_items(self): expr = expression.set_items() expected = [ create_graph( SetItemObserver(notify=True, optional=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_set_items_notify_false(self): expr = expression.set_items(notify=False) expected = [ create_graph( SetItemObserver(notify=False, optional=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_set_items_optional_true(self): expr = expression.set_items(optional=True) expected = [ create_graph( SetItemObserver(notify=True, optional=True), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_set_items_method_notify(self): # Test the instance method calls the top-level function correctly. expr = expression.set_items().set_items(notify=False) expected = [ create_graph( SetItemObserver(notify=True, optional=False), SetItemObserver(notify=False, optional=False), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_set_items_method_optional(self): # Test the instance method calls the top-level function correctly. expr = expression.set_items().set_items(optional=True) expected = [ create_graph( SetItemObserver(notify=True, optional=False), SetItemObserver(notify=True, optional=True), ), ] actual = expr._as_graphs() self.assertEqual(actual, expected) def test_call_signatures(self): # Test to help developers keeping the two function signatures in-sync. # Remove this if the two need to divert in the future. top_level = expression.set_items method = expression.ObserverExpression().set_items self.assertEqual( inspect.signature(top_level), inspect.signature(method) ) class TestObserverExpressionEqualityAndHashing(unittest.TestCase): """ Test ObserverExpression.__eq__ and ObserverExpression.__hash__. """ def test_trait_equality(self): expr1 = create_expression(1) expr2 = create_expression(1) self.assertEqual(expr1, expr2) self.assertEqual(hash(expr1), hash(expr2)) def test_join_equality_with_then(self): # The following all result in the same graphs expr1 = create_expression(1) expr2 = create_expression(2) combined1 = expression.join(expr1, expr2) combined2 = expr1.then(expr2) self.assertEqual(combined1, combined2) self.assertEqual(hash(combined1), hash(combined2)) def test_equality_of_parallel_expressions(self): expr1 = create_expression(1) | create_expression(2) expr2 = create_expression(1) | create_expression(2) self.assertEqual(expr1, expr2) self.assertEqual(hash(expr1), hash(expr2)) def test_equality_different_type(self): expr = create_expression(1) self.assertNotEqual(expr, "1") class TestObserverExpressionSlots(unittest.TestCase): """ Check that expressions use __slots__. """ def test_single_expression(self): expr = create_expression(1) self.assertFalse(hasattr(expr, "__dict__")) def test_series_expression(self): expr = create_expression(1).then(create_expression(2)) self.assertFalse(hasattr(expr, "__dict__")) def test_parallel_expression(self): expr = create_expression(1) | create_expression(2) self.assertFalse(hasattr(expr, "__dict__")) class TestCompileFromExpr(unittest.TestCase): """ Tests for compile_expr. """ # The complicated pieces are already tested; we just need to double # check that "_as_graphs" corresponds to "compile_expr" for a # handful of cases. def test_compile_expr(self): observer1 = 1 observer2 = 2 observer3 = 3 observer4 = 4 expr1 = create_expression(observer1) expr2 = create_expression(observer2) expr3 = create_expression(observer3) expr4 = create_expression(observer4) test_expressions = [ expr1, expr1 | expr2, expr1 | expr2 | expr3, expr1.then(expr2), expr1.then(expr2).then(expr3), (expr1.then(expr2)) | (expr3.then(expr4)), expr1.list_items(), expr1.dict_items(), expr1.set_items(), expr1.anytrait(notify=False), expr1.anytrait(notify=True), ] for test_expression in test_expressions: with self.subTest(expression=test_expression): self.assertEqual( expression.compile_expr(test_expression), test_expression._as_graphs(), ) traits-6.3.2/traits/observation/tests/test_filtered_trait_observer.py000066400000000000000000000255301414270267200263660ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from unittest import mock from traits.has_traits import HasTraits from traits.trait_base import Undefined, Uninitialized from traits.trait_types import Float, Instance, Int, List from traits.observation._filtered_trait_observer import FilteredTraitObserver from traits.observation._testing import ( call_add_or_remove_notifiers, create_graph, DummyNotifier, DummyObservable, DummyObserver, ) class DummyFilter: """ A callable to be used as the 'filter' for FilteredTraitObserver """ def __init__(self, return_value): self.return_value = return_value def __call__(self, name, trait): return self.return_value def __eq__(self, other): return self.return_value == other.return_value def __hash__(self): return hash(self.return_value) def __repr__(self): formatted_args = [f"return_value={self.return_value!r}"] return f"{self.__class__.__name__}({', '.join(formatted_args)})" def create_observer(**kwargs): values = dict( notify=True, filter=DummyFilter(return_value=True), ) values.update(kwargs) return FilteredTraitObserver(**values) class TestFilteredTraitObserverEqualHash(unittest.TestCase): """ Tests for FilteredTraitObserver __eq__ and __hash__ methods. """ def test_not_equal_filter(self): observer1 = FilteredTraitObserver( notify=True, filter=DummyFilter(return_value=True), ) observer2 = FilteredTraitObserver( notify=True, filter=DummyFilter(return_value=False), ) self.assertNotEqual(observer1, observer2) def test_not_equal_notify(self): filter_func = mock.Mock() observer1 = FilteredTraitObserver( notify=False, filter=filter_func) observer2 = FilteredTraitObserver( notify=True, filter=filter_func) self.assertNotEqual(observer1, observer2) def test_equal_filter_notify(self): observer1 = FilteredTraitObserver( notify=True, filter=DummyFilter(return_value=True), ) observer2 = FilteredTraitObserver( notify=True, filter=DummyFilter(return_value=True), ) self.assertEqual(observer1, observer2) self.assertEqual(hash(observer1), hash(observer2)) def test_not_equal_type(self): filter_func = mock.Mock() observer1 = FilteredTraitObserver( notify=True, filter=filter_func, ) imposter = mock.Mock() imposter.notify = True imposter.filter = filter_func self.assertNotEqual(observer1, imposter) def test_slots(self): observer = FilteredTraitObserver( notify=True, filter=DummyFilter(return_value=True), ) with self.assertRaises(AttributeError): observer.__dict__ with self.assertRaises(AttributeError): observer.__weakref__ def test_eval_repr_roundtrip(self): observer = FilteredTraitObserver( notify=True, filter=DummyFilter(return_value=True), ) self.assertEqual(eval(repr(observer)), observer) class Dummy(HasTraits): number = Int() class DummyParent(HasTraits): number = Int() number2 = Int() instance = Instance(Dummy, allow_none=True) instance2 = Instance(Dummy) income = Float() dummies = List(Dummy) class TestFilteredTraitObserverIterObservables(unittest.TestCase): """ Test FilteredTraitObserver.iter_observables """ def test_iter_observables_with_filter(self): instance = DummyParent() observer = create_observer( filter=lambda name, trait: type(trait.trait_type) is Int, ) actual = list(observer.iter_observables(instance)) expected = [ instance._trait("number", 2), instance._trait("number2", 2), ] self.assertCountEqual(actual, expected) class TestFilteredTraitObserverIterObjects(unittest.TestCase): """ Test FilteredTraitObserver.iter_objects """ def test_iter_objects(self): instance = DummyParent() instance.instance = Dummy() self.assertIsNone(instance.instance2) observer = create_observer( filter=lambda name, trait: type(trait.trait_type) is Instance, ) actual = list(observer.iter_objects(instance)) # the None value is skipped here self.assertEqual(actual, [instance.instance]) # when instance.instance2 = Dummy() actual = list(observer.iter_objects(instance)) # then self.assertCountEqual( actual, [instance.instance, instance.instance2] ) # ------------------------------------ # Integration tests with notifiers # ------------------------------------ class WatchfulObserver(DummyObserver): """ This is a dummy observer to be used as the next observer following FilteredTraitObserver. """ def iter_observables(self, object): if object in (Undefined, Uninitialized, None): raise ValueError( "Child observer unexpectedly receive {}".format(object) ) yield from self.observables class TestFilteredTraitObserverNotifications(unittest.TestCase): """ Integration tests with HasTraits and notifiers.""" def test_notify_filter_values_changed(self): instance = DummyParent() # Observes number and number2 observer = create_observer( filter=lambda name, trait: type(trait.trait_type) is Int, ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance, graph=create_graph(observer), handler=handler, ) # when instance.number += 1 # then self.assertEqual(handler.call_count, 1) handler.reset_mock() # when instance.number2 += 1 # then self.assertEqual(handler.call_count, 1) def test_notifier_can_be_removed(self): def filter_func(name, trait): return name.startswith("num") instance = DummyParent() handler = mock.Mock() call_add_or_remove_notifiers( object=instance, graph=create_graph( create_observer(filter=filter_func) ), handler=handler, ) # sanity check instance.number += 1 self.assertEqual(handler.call_count, 1) handler.reset_mock() # when call_add_or_remove_notifiers( object=instance, graph=create_graph( create_observer(filter=filter_func) ), handler=handler, remove=True, ) # then instance.number += 1 self.assertEqual(handler.call_count, 0) def test_maintainer_notifier(self): # Test maintaining downstream notifier # Observes a nested instance observer = create_observer( filter=lambda name, trait: type(trait.trait_type) is Instance, ) observable = DummyObservable() notifier = DummyNotifier() child_observer = WatchfulObserver( observables=[observable], notifier=notifier, ) instance = DummyParent() handler = mock.Mock() call_add_or_remove_notifiers( object=instance, graph=create_graph( observer, child_observer, ), handler=handler, ) # when # this will trigger the maintainer instance.instance = Dummy() # then self.assertEqual(observable.notifiers, [notifier]) # when instance.instance = None # then self.assertEqual(observable.notifiers, []) class TestFilteredTraitObserverTraitAdded(unittest.TestCase): """ Test support for HasTraits.add_trait .""" def test_trait_added_filtered_matched(self): instance = DummyParent() integer_observer = create_observer( filter=lambda name, trait: type(trait.trait_type) is Int, notify=True, ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance, graph=create_graph(integer_observer), handler=handler, ) # when instance.add_trait("another_number", Int()) instance.another_number += 1 # then self.assertEqual(handler.call_count, 1) def test_trait_added_match_func_correct(self): # Test the match function supplied to TraitAddedObserver is consistent # with the filter. instance = DummyParent() integer_observer = create_observer( filter=lambda name, trait: type(trait.trait_type) is Int, notify=True, ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance, graph=create_graph(integer_observer), handler=handler, ) # when # This trait does not satisfy the filter instance.add_trait("another_number", Float()) instance.another_number += 1 # then self.assertEqual(handler.call_count, 0) def test_trait_added_removed(self): instance = Dummy() integer_observer = create_observer( filter=lambda name, trait: type(trait.trait_type) is Int, notify=True, ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance, graph=create_graph(integer_observer), handler=handler, ) # Add two traits. # If the maintainer from TraitAddedObserver did not restrict its # action to just the added trait, when 'count' is added, the previously # added 'another_number' would have received a second notifier again. # Then it would require two *remove* actions in order to clean up # notifiers on 'another_number'. instance.add_trait("another_number", Int()) instance.add_trait("count", Int()) # when call_add_or_remove_notifiers( object=instance, graph=create_graph(integer_observer), handler=handler, remove=True, ) # then instance.another_number += 1 self.assertEqual(handler.call_count, 0) instance.count += 1 self.assertEqual(handler.call_count, 0) traits-6.3.2/traits/observation/tests/test_generated_parser.py000066400000000000000000000041141414270267200247630ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.observation._generated_parser import ( UnexpectedInput, Lark_StandAlone, ) PARSER = Lark_StandAlone() class TestParsingValidation(unittest.TestCase): """ Test parsing text using the standalone parser, for valid and invalid text, without further evaluation on the meaning of their content. """ def test_invalid_examples(self): bad_examples = [ "", "1name", "a.b.c^abc", "[a.b]c", "a*.c", "a:[b,c]:", ".a", "a()", "-a", ] for bad_example in bad_examples: with self.subTest(bad_example=bad_example): with self.assertRaises(UnexpectedInput): PARSER.parse(bad_example) def test_valid_examples(self): good_examples = [ "name", "name123", "name_a", "_name", "foo.bar", "foo . bar", "foo:bar", "foo : bar", "foo,bar", "foo , bar", "[foo,bar,foo.spam]", "[foo, bar].baz", "[foo, [bar, baz]]:spam", "foo:[bar.spam,baz]", "foo.items", "items", "+metadata_name", ] for good_example in good_examples: with self.subTest(good_example=good_example): try: PARSER.parse(good_example) except Exception: self.fail( "Parsing {!r} is expected to succeed.".format( good_example ) ) traits-6.3.2/traits/observation/tests/test_has_traits_helpers.py000066400000000000000000000222231414270267200253350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from unittest import mock from traits.api import ( Any, Bool, ComparisonMode, Dict, HasTraits, List, Instance, Int, Property, Set, ) from traits.observation import _has_traits_helpers as helpers from traits.observation import expression from traits.observation.observe import observe class Bar(HasTraits): count = Int() class Foo(HasTraits): list_of_int = List(Int) instance = Instance(Bar) any_value = Any() int_with_default = Int() int_with_default_computed = Bool() def _int_with_default(self): self.int_with_default_computed = True return 10 property_value = Property() property_n_calculations = Int() def _get_property_value(self): self.property_n_calculations += 1 return 1 class ClassWithInstanceDefault(HasTraits): instance_with_default = Instance(Bar, ()) class TestHasTraitsHelpersHasNamedTrait(unittest.TestCase): """ Test object_has_named_trait.""" def test_object_has_named_trait_false_for_trait_list(self): foo = Foo() # TraitListObject that has `trait` attribute self.assertFalse( helpers.object_has_named_trait(foo.list_of_int, "bar"), "Expected object_has_named_trait to return false for {!r}".format( type(foo.list_of_int) ) ) def test_object_has_named_trait_true_basic(self): foo = Foo() self.assertTrue( helpers.object_has_named_trait(foo, "list_of_int"), "The named trait should exist." ) def test_object_has_named_trait_false(self): foo = Foo() self.assertFalse( helpers.object_has_named_trait(foo, "not_existing"), "Expected object_has_named_trait to return False for a" "nonexisting trait name." ) def test_object_has_named_trait_does_not_trigger_property(self): foo = Foo() helpers.object_has_named_trait(foo, "property_value") self.assertEqual( foo.property_n_calculations, 0 ) class CannotCompare: def __eq__(self, other): raise TypeError("Cannot be compared for equality.") class TestHasTraitsHelpersIterObjects(unittest.TestCase): """ Test iter_objects.""" def test_iter_objects_avoid_undefined(self): foo = Foo() # sanity check self.assertNotIn("instance", foo.__dict__) actual = list(helpers.iter_objects(foo, "instance")) self.assertEqual(actual, []) def test_iter_objects_no_sideeffect(self): foo = Foo() # sanity check self.assertNotIn("instance", foo.__dict__) list(helpers.iter_objects(foo, "instance")) self.assertNotIn("instance", foo.__dict__) def test_iter_objects_avoid_none(self): foo = Foo() foo.instance = None actual = list(helpers.iter_objects(foo, "instance")) self.assertEqual(actual, []) def test_iter_objects_allow_object_cannot_compare_for_equality(self): # see enthought/traits#1277 foo = Foo() foo.any_value = CannotCompare() actual = list(helpers.iter_objects(foo, "any_value")) self.assertEqual(actual, [foo.any_value]) def test_iter_objects_accepted_values(self): foo = Foo(instance=Bar(), list_of_int=[1, 2]) actual = list(helpers.iter_objects(foo, "instance")) self.assertEqual(actual, [foo.instance]) def test_iter_objects_does_not_evaluate_default(self): foo = Foo() list(helpers.iter_objects(foo, "int_with_default")) self.assertFalse( foo.int_with_default_computed, "Expect the default not to have been computed." ) def test_iter_objects_does_not_trigger_property(self): foo = Foo() list(helpers.iter_objects(foo, "property_value")) self.assertEqual(foo.property_n_calculations, 0) class ObjectWithEqualityComparisonMode(HasTraits): """ Class for supporting TestHasTraitsHelpersComparisonMode """ list_values = List(comparison_mode=ComparisonMode.equality) dict_values = Dict(comparison_mode=ComparisonMode.equality) set_values = Set(comparison_mode=ComparisonMode.equality) number = Any(comparison_mode=ComparisonMode.equality) calculated = Property(depends_on="number") def _get_calculated(self): return None class TestHasTraitsHelpersComparisonMode(unittest.TestCase): """ Test the effect of ctrait_prevent_event """ def test_basic_trait_equality_prevent_change_event(self): instance = ObjectWithEqualityComparisonMode() instance.number = 1 handler = mock.Mock() observe( object=instance, expression=expression.trait("number"), handler=handler, ) # when instance.number = 1.0 # then self.assertEqual(handler.call_count, 0) # when instance.number = True # then self.assertEqual(handler.call_count, 0) # when instance.number = 2.0 # then self.assertEqual(handler.call_count, 1) handler.reset_mock() # when # This instance cannot be compared with 2.0 for equality. instance.number = CannotCompare() # then self.assertEqual(handler.call_count, 1) def test_property_equality_no_effect(self): instance = ObjectWithEqualityComparisonMode() instance.number = 1 handler = mock.Mock() observe( object=instance, expression=expression.trait("calculated"), handler=handler, ) # when instance.number = 2 # then self.assertEqual(handler.call_count, 1) def test_list_equality_prevent_change_event(self): instance = ObjectWithEqualityComparisonMode() instance.list_values = [1] handler = mock.Mock() observe( object=instance, expression=expression.trait("list_values").list_items(), handler=handler, ) # New list, but equals to the previous instance.list_values = [1] # then self.assertEqual(handler.call_count, 0) # when instance.list_values.append(2) # then self.assertEqual(handler.call_count, 1) def test_set_equality_prevent_change_event(self): instance = ObjectWithEqualityComparisonMode() instance.set_values = {1} handler = mock.Mock() observe( object=instance, expression=expression.trait("set_values").set_items(), handler=handler, ) # New set, but equals to the previous instance.set_values = {1} # then self.assertEqual(handler.call_count, 0) # when instance.set_values.add(2) # then self.assertEqual(handler.call_count, 1) def test_dict_equality_prevent_change_event(self): instance = ObjectWithEqualityComparisonMode() instance.dict_values = {"1": 1} handler = mock.Mock() observe( object=instance, expression=expression.trait("dict_values").dict_items(), handler=handler, ) # New dict, but equals to the previous instance.dict_values = {"1": 1} # then self.assertEqual(handler.call_count, 0) # when instance.dict_values["2"] = 2 # then self.assertEqual(handler.call_count, 1) class TestHasTraitsHelpersMaintainerHandler(unittest.TestCase): def test_any_value_followed_by_list_items_new_bad_value(self): # see enthought/traits#1277 foo = Foo() handler = mock.Mock() # list_items(optional=True) will excuse the CannotCompare which isn't # a TraitList observe( object=foo, expression=expression.trait("any_value").list_items(optional=True), handler=handler, ) # when # this triggers observer_change_handler foo.any_value = CannotCompare() # then # no errors def test_any_value_followed_by_list_items_old_bad_value(self): # see enthought/traits#1277 foo = Foo() foo.any_value = CannotCompare() handler = mock.Mock() # list_items(optional=True) will excuse the CannotCompare which isn't # a TraitList observe( object=foo, expression=expression.trait("any_value").list_items(optional=True), handler=handler, ) # when # this triggers observer_change_handler foo.any_value = foo.list_of_int # a TraitList # then # no errors # when handler.reset_mock() foo.any_value.append(1) # then self.assertEqual(handler.call_count, 1) traits-6.3.2/traits/observation/tests/test_list_change_event.py000066400000000000000000000032771414270267200251430ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.observation._list_change_event import ( ListChangeEvent, list_event_factory, ) from traits.trait_list_object import TraitList class TestListChangeEvent(unittest.TestCase): def test_list_change_event_repr(self): event = ListChangeEvent( object=[], index=3, removed=[1, 2], added=[3, 4], ) actual = repr(event) self.assertEqual( actual, "ListChangeEvent(" "object=[], index=3, removed=[1, 2], added=[3, 4])" ) class TestListEventFactory(unittest.TestCase): """ Test event factory compatibility with TraitList.notify """ def test_trait_list_notification_compat(self): events = [] def notifier(*args, **kwargs): event = list_event_factory(*args, **kwargs) events.append(event) trait_list = TraitList( [0, 1, 2], notifiers=[notifier], ) # when trait_list[1:] = [3, 4] # then event, = events self.assertIsInstance(event, ListChangeEvent) self.assertIs(event.object, trait_list) self.assertEqual(event.index, 1) self.assertEqual(event.removed, [1, 2]) self.assertEqual(event.added, [3, 4]) traits-6.3.2/traits/observation/tests/test_list_item_observer.py000066400000000000000000000250151414270267200253540ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from unittest import mock from traits.api import HasTraits, Instance, Int, List from traits.observation._list_item_observer import ListItemObserver from traits.observation._testing import ( call_add_or_remove_notifiers, create_graph, ) from traits.trait_list_object import TraitList, TraitListObject class TestListItemObserverEqualHash(unittest.TestCase): def test_not_equal_notify(self): observer1 = ListItemObserver(notify=False, optional=False) observer2 = ListItemObserver(notify=True, optional=False) self.assertNotEqual(observer1, observer2) def test_not_equal_optional(self): observer1 = ListItemObserver(notify=True, optional=True) observer2 = ListItemObserver(notify=True, optional=False) self.assertNotEqual(observer1, observer2) def test_not_equal_different_type(self): observer1 = ListItemObserver(notify=False, optional=False) imposter = mock.Mock() imposter.notify = False imposter.optional = False self.assertNotEqual(observer1, imposter) def test_equal_observers(self): observer1 = ListItemObserver(notify=False, optional=False) observer2 = ListItemObserver(notify=False, optional=False) self.assertEqual(observer1, observer2) self.assertEqual(hash(observer1), hash(observer2)) def test_slots(self): observer = ListItemObserver(notify=True, optional=False) with self.assertRaises(AttributeError): observer.__dict__ with self.assertRaises(AttributeError): observer.__weakref__ def test_eval_repr_roundtrip(self): observer = ListItemObserver(notify=True, optional=False) self.assertEqual(eval(repr(observer)), observer) class CustomList(list): pass class CustomTraitList(TraitList): pass class ClassWithList(HasTraits): values = List() not_a_trait_list = Instance(CustomList) number = Int() custom_trait_list = Instance(CustomTraitList) class ClassWithListOfList(HasTraits): list_of_list = List(List()) class TestListItemObserverIterObservable(unittest.TestCase): """ Test ListItemObserver.iter_observables """ def test_trait_list_iter_observables(self): instance = ClassWithList() instance.values = [1, 2, 3] observer = ListItemObserver(notify=True, optional=False) # In the expected scenario, the ListItemObserver will # follow another observer whose iter_objects will yield # the trait value actual_item, = list(observer.iter_observables(instance.values)) self.assertIs(actual_item, instance.values) def test_trait_list_iter_observables_with_default_list(self): instance = ClassWithList() observer = ListItemObserver(notify=True, optional=False) # In the expected scenario, the ListItemObserver will # follow another observer whose iter_objects will yield # the trait value actual_item, = list(observer.iter_observables(instance.values)) self.assertIsInstance(actual_item, TraitListObject) def test_trait_list_iter_observables_accept_custom_trait_list(self): # An extension of TraitList can be used with ListItemObserver instance = ClassWithList() instance.custom_trait_list = CustomTraitList([1, 2, 3]) observer = ListItemObserver(notify=True, optional=False) actual_item, = list( observer.iter_observables(instance.custom_trait_list)) self.assertIs(actual_item, instance.custom_trait_list) def test_trait_list_iter_observables_error(self): # If the user chains a ListItemObserver after an observer that # does not produce a TraitList, raise an error instance = ClassWithList() instance.not_a_trait_list = CustomList() observer = ListItemObserver(notify=True, optional=False) with self.assertRaises(ValueError) as exception_context: next(observer.iter_observables(instance.not_a_trait_list)) self.assertIn( "Expected a TraitList to be observed", str(exception_context.exception) ) def test_trait_list_iter_observables_not_a_trait_list_optional(self): # Test when the given object is a list but not an IObservable instance = ClassWithList() observer = ListItemObserver(notify=True, optional=True) self.assertIsNone(instance.not_a_trait_list) actual = list(observer.iter_observables(instance.not_a_trait_list)) self.assertEqual(actual, []) instance.not_a_trait_list = CustomList() actual = list(observer.iter_observables(instance.not_a_trait_list)) self.assertEqual(actual, []) def test_trait_list_iter_observables_not_a_list_error(self): # Test when the given object is not a list instance = ClassWithList() observer = ListItemObserver(notify=True, optional=False) with self.assertRaises(ValueError) as exception_context: list(observer.iter_observables(instance.number)) self.assertIn( "Expected a TraitList to be observed", str(exception_context.exception)) class TestListItemObserverIterObjects(unittest.TestCase): """ Test ListItemObserver.iter_objects """ def test_trait_list_iter_objects(self): instance = ClassWithList() item1 = mock.Mock() item2 = mock.Mock() instance.values = [item1, item2] observer = ListItemObserver(notify=True, optional=False) # the observer does not filter if the values are observables or not. actual = list(observer.iter_objects(instance.values)) self.assertEqual(actual, [item1, item2]) def test_trait_list_iter_object_accept_custom_trait_list(self): # An extension of TraitList can be used with ListItemObserver instance = ClassWithList() instance.custom_trait_list = CustomTraitList([1, 2, 3]) observer = ListItemObserver(notify=True, optional=False) actual = list( observer.iter_objects(instance.custom_trait_list)) self.assertEqual(actual, [1, 2, 3]) def test_trait_list_iter_objects_complain_not_list(self): observer = ListItemObserver(notify=True, optional=False) with self.assertRaises(ValueError) as exception_cm: next(observer.iter_objects(set([1]))) self.assertIn( "Expected a TraitList to be observed", str(exception_cm.exception)) def test_trait_list_iter_objects_ignore_if_optional_and_not_list(self): observer = ListItemObserver(notify=True, optional=True) actual = list(observer.iter_objects(set([1]))) self.assertEqual(actual, []) # ---------------------------------- # Integration tests with notifiers # ---------------------------------- class TestListTraitObserverNotifications(unittest.TestCase): def test_notifier_list_change(self): instance = ClassWithList(values=[]) graph = create_graph( ListItemObserver(notify=True, optional=False), ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance.values, graph=graph, handler=handler, ) # when instance.values.append(1) # then ((event, ), _), = handler.call_args_list self.assertIs(event.object, instance.values) self.assertEqual(event.added, [1]) self.assertEqual(event.removed, []) self.assertEqual(event.index, 0) def test_notifier_custom_trait_list_change(self): # Test compatibility with any extension of TraitList, not just # TraitListObject instance = ClassWithList() instance.custom_trait_list = CustomTraitList() graph = create_graph( ListItemObserver(notify=True, optional=False), ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance.custom_trait_list, graph=graph, handler=handler, ) # when instance.custom_trait_list.append(1) # then ((event, ), _), = handler.call_args_list self.assertIs(event.object, instance.custom_trait_list) self.assertEqual(event.added, [1]) self.assertEqual(event.removed, []) self.assertEqual(event.index, 0) def test_maintain_notifier(self): # Test maintaining downstream notifier by # observing list of list instance = ClassWithListOfList() graph = create_graph( ListItemObserver(notify=False, optional=False), ListItemObserver(notify=True, optional=False), ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance.list_of_list, graph=graph, handler=handler, ) # when instance.list_of_list.append([]) # then # the first ListItemObserver has notify=False self.assertEqual(handler.call_count, 0) # but the second ListItemObserver is given to the nested list nested_list = instance.list_of_list[0] # when nested_list.append(1) # then ((event, ), _), = handler.call_args_list self.assertIs(event.object, nested_list) self.assertEqual(event.added, [1]) self.assertEqual(event.removed, []) self.assertEqual(event.index, 0) handler.reset_mock() # when # the list is removed, it is not observed instance.list_of_list.pop() nested_list.append(1) # then self.assertEqual(handler.call_count, 0) def test_optional_observers(self): # ListItemObserver.optional is true, meaning it will ignore # incompatible incoming object. instance = ClassWithList() graph = create_graph( ListItemObserver(notify=True, optional=True), ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance.not_a_trait_list, graph=graph, handler=handler, ) instance.not_a_trait_list = CustomList() instance.not_a_trait_list.append(1) self.assertEqual(handler.call_count, 0) traits-6.3.2/traits/observation/tests/test_metadata_filter.py000066400000000000000000000077421414270267200246100ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from unittest import mock from traits.api import HasTraits, Int from traits.observation._filtered_trait_observer import FilteredTraitObserver from traits.observation._metadata_filter import MetadataFilter from traits.observation._testing import ( call_add_or_remove_notifiers, create_graph, ) class TestMetadataFilter(unittest.TestCase): """ Test the behaviour of the MetadataFilter """ def test_metadata_defined_vs_undefined(self): metadata_filter = MetadataFilter( metadata_name="name", ) self.assertTrue( metadata_filter("name", Int(name=True).as_ctrait()), "Expected the filter to return true" ) self.assertFalse( metadata_filter("name", Int().as_ctrait()), "Expected the filter to return false" ) def test_metadata_defined_as_none_is_same_as_undefined(self): # If a metadata has a None value, it is equivalent to the metadata # not being defined. metadata_filter = MetadataFilter( metadata_name="name", ) self.assertFalse( metadata_filter("name", Int(name=None).as_ctrait()), "Expected the filter to return false" ) def test_filter_equality(self): filter1 = MetadataFilter( metadata_name="name", ) filter2 = MetadataFilter( metadata_name="name", ) self.assertEqual(filter1, filter2) self.assertEqual(hash(filter1), hash(filter2)) def test_filter_not_equal_name_different(self): filter1 = MetadataFilter( metadata_name="number", ) filter2 = MetadataFilter( metadata_name="name", ) self.assertNotEqual(filter1, filter2) def test_filter_not_equal_different_type(self): filter1 = MetadataFilter( metadata_name="name", ) imposter = mock.Mock() imposter.metadata_name = "name" self.assertNotEqual(imposter, filter1) def test_slots(self): filter = MetadataFilter(metadata_name="name") with self.assertRaises(AttributeError): filter.__dict__ with self.assertRaises(AttributeError): filter.__weakref__ def test_repr_value(self): metadata_filter = MetadataFilter( metadata_name="name", ) actual = repr(metadata_filter) self.assertEqual( actual, "MetadataFilter(metadata_name='name')" ) def test_eval_repr_roundtrip(self): metadata_filter = MetadataFilter( metadata_name="name", ) self.assertEqual(eval(repr(metadata_filter)), metadata_filter) class TestWithFilteredTraitObserver(unittest.TestCase): """ Test MetadataFilter with FilteredTraitObserver and HasTraits. """ def test_filter_metadata(self): class Person(HasTraits): n_jobs = Int(status="public") n_children = Int() # no metadata observer = FilteredTraitObserver( filter=MetadataFilter( metadata_name="status", ), notify=True, ) person = Person() handler = mock.Mock() call_add_or_remove_notifiers( object=person, graph=create_graph(observer), handler=handler, ) # when person.n_jobs += 1 # then self.assertEqual(handler.call_count, 1) handler.reset_mock() # when person.n_children += 1 # then self.assertEqual(handler.call_count, 0) traits-6.3.2/traits/observation/tests/test_named_trait_observer.py000066400000000000000000000441061414270267200256540ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from unittest import mock from traits.api import Bool, HasTraits, Int, Instance from traits.observation._named_trait_observer import ( NamedTraitObserver, ) from traits.observation._observer_graph import ObserverGraph from traits.observation._testing import ( call_add_or_remove_notifiers, create_graph, DummyObserver, ) def create_observer(**kwargs): """ Convenient function for creating an instance of NamedTraitObserver. """ values = dict( name="name", notify=True, optional=False, ) values.update(kwargs) return NamedTraitObserver(**values) class TestNamedTraitObserverEqualHash(unittest.TestCase): """ Unit tests on the NamedTraitObserver __eq__ and __hash__ methods.""" def test_not_equal_notify(self): observer1 = NamedTraitObserver(name="foo", notify=True, optional=True) observer2 = NamedTraitObserver(name="foo", notify=False, optional=True) self.assertNotEqual(observer1, observer2) def test_not_equal_name(self): observer1 = NamedTraitObserver(name="foo", notify=True, optional=True) observer2 = NamedTraitObserver(name="bar", notify=True, optional=True) self.assertNotEqual(observer1, observer2) def test_not_equal_optional(self): observer1 = NamedTraitObserver(name="foo", notify=True, optional=False) observer2 = NamedTraitObserver(name="foo", notify=True, optional=True) self.assertNotEqual(observer1, observer2) def test_equal_observers(self): observer1 = NamedTraitObserver(name="foo", notify=True, optional=True) observer2 = NamedTraitObserver(name="foo", notify=True, optional=True) self.assertEqual(observer1, observer2) self.assertEqual(hash(observer1), hash(observer2)) def test_not_equal_type(self): observer = NamedTraitObserver(name="foo", notify=True, optional=True) imposter = mock.Mock() imposter.name = "foo" imposter.notify = True imposter.optional = True self.assertNotEqual(observer, imposter) def test_slots(self): observer = NamedTraitObserver(name="foo", notify=True, optional=True) with self.assertRaises(AttributeError): observer.__dict__ with self.assertRaises(AttributeError): observer.__weakref__ def test_eval_repr_roundtrip(self): observer = NamedTraitObserver(name="foo", notify=True, optional=True) self.assertEqual(eval(repr(observer)), observer) class TestObserverGraphIntegrateNamedTraitObserver(unittest.TestCase): """ Test integrating ObserverGraph with NamedTraitObserver as nodes. """ def test_observer_graph_hash_with_named_listener(self): # Test equality + hashing using set passes. path1 = ObserverGraph( node=create_observer(name="foo"), children=[ ObserverGraph(node=create_observer(name="bar")), ], ) path2 = ObserverGraph( node=create_observer(name="foo"), children=[ ObserverGraph(node=create_observer(name="bar")), ], ) # This tests __eq__ and __hash__ self.assertEqual(path1, path2) # ----------------------------------- # Integration tests with HasTraits # ----------------------------------- class ClassWithTwoValue(HasTraits): value1 = Int() value2 = Int() class ClassWithInstance(HasTraits): instance = Instance(ClassWithTwoValue) class ClassWithDefault(HasTraits): instance = Instance(ClassWithTwoValue) instance_default_calculated = Bool(False) def _instance_default(self): self.instance_default_calculated = True return ClassWithTwoValue() class TestNamedTraitObserverIterObservable(unittest.TestCase): """ Tests for NamedTraitObserver.iter_observables """ def test_ordinary_has_traits(self): observer = create_observer(name="value1", optional=False) foo = ClassWithTwoValue() actual = list(observer.iter_observables(foo)) self.assertEqual(actual, [foo._trait("value1", 2)]) def test_trait_not_found(self): observer = create_observer(name="billy", optional=False) bar = ClassWithTwoValue() with self.assertRaises(ValueError) as e: next(observer.iter_observables(bar)) self.assertEqual( str(e.exception), "Trait named 'billy' not found on {!r}.".format(bar)) def test_trait_not_found_skip_as_optional(self): observer = create_observer(name="billy", optional=True) bar = ClassWithTwoValue() actual = list(observer.iter_observables(bar)) self.assertEqual(actual, []) class TestNamedTraitObserverNextObjects(unittest.TestCase): """ Tests for NamedTraitObserver.iter_objects for the downstream observers. """ def test_iter_objects(self): observer = create_observer(name="instance") foo = ClassWithInstance(instance=ClassWithTwoValue()) actual = list(observer.iter_objects(foo)) self.assertEqual(actual, [foo.instance]) def test_iter_objects_raises_if_trait_not_found(self): observer = create_observer(name="sally", optional=False) foo = ClassWithInstance() with self.assertRaises(ValueError) as e: next(observer.iter_objects(foo)) self.assertEqual( str(e.exception), "Trait named {!r} not found on {!r}.".format("sally", foo) ) def test_trait_not_found_skip_as_optional(self): observer = create_observer(name="sally", optional=True) foo = ClassWithInstance() actual = list(observer.iter_objects(foo)) self.assertEqual(actual, []) def test_iter_objects_no_side_effect_on_default_initializer(self): # Test iter_objects should not trigger default to be evaluated. observer = create_observer(name="instance") foo = ClassWithDefault() actual = list(observer.iter_objects(foo)) self.assertEqual(actual, []) self.assertNotIn("instance", foo.__dict__) self.assertFalse( foo.instance_default_calculated, "Unexpected side-effect on the default initializer." ) class TestNamedTraitObserverNotifications(unittest.TestCase): """ Test integration with observe and HasTraits to get notifications. """ def test_notifier_extended_trait_change(self): foo = ClassWithInstance() graph = create_graph( create_observer(name="instance", notify=True), create_observer(name="value1", notify=True), ) handler = mock.Mock() call_add_or_remove_notifiers( object=foo, graph=graph, handler=handler, ) self.assertIsNone(foo.instance) # when foo.instance = ClassWithTwoValue() # then ((event, ), _), = handler.call_args_list self.assertEqual(event.object, foo) self.assertEqual(event.name, "instance") self.assertEqual(event.old, None) self.assertEqual(event.new, foo.instance) # when handler.reset_mock() foo.instance.value1 += 1 # then ((event, ), _), = handler.call_args_list self.assertEqual(event.object, foo.instance) self.assertEqual(event.name, "value1") self.assertEqual(event.old, 0) self.assertEqual(event.new, 1) def test_maintain_notifier_change_to_new_value(self): # Test when the container object is changed, the notifiers are # maintained downstream. foo = ClassWithInstance() graph = create_graph( create_observer(name="instance", notify=True), create_observer(name="value1", notify=True), ) handler = mock.Mock() call_add_or_remove_notifiers( object=foo, graph=graph, handler=handler, ) # sanity check foo.instance = ClassWithTwoValue() foo.instance.value1 += 1 self.assertEqual(handler.call_count, 2) # when old_instance = foo.instance foo.instance = ClassWithTwoValue() handler.reset_mock() old_instance.value1 += 1 # then self.assertEqual(handler.call_count, 0) # when foo.instance.value1 += 1 # then self.assertEqual(handler.call_count, 1) def test_maintain_notifier_change_to_none(self): # Instance may accept None, maintainer should accomodate that # and skip it for the next observer. class UnassumingObserver(DummyObserver): def iter_observables(self, object): if object is None: raise ValueError("This observer cannot handle None.") yield from () foo = ClassWithInstance() graph = create_graph( create_observer(name="instance", notify=True), UnassumingObserver(), ) handler = mock.Mock() call_add_or_remove_notifiers( object=foo, graph=graph, handler=handler, ) foo.instance = ClassWithTwoValue() try: foo.instance = None except Exception: self.fail("Setting instance back to None should not fail.") def test_maintain_notifier_for_default(self): # Dynamic defaults are not computed when hooking up the notifiers. # By when the default is defined, the maintainer will then hook up # the child observer. foo = ClassWithDefault() graph = create_graph( create_observer(name="instance", notify=True), create_observer(name="value1", notify=True), ) handler = mock.Mock() call_add_or_remove_notifiers( object=foo, graph=graph, handler=handler, ) # sanity check test setup. self.assertNotIn("instance", foo.__dict__) # when foo.instance # this triggers the default to be computed and set # then # setting the default does not trigger notifications self.assertEqual(handler.call_count, 0) # when foo.instance.value1 += 1 # then # the notifier for value1 has been hooked up by the maintainer self.assertEqual(handler.call_count, 1) def test_get_maintainer_excuse_old_value_with_no_notifiers(self): # The "instance" trait has a default that has not been # materialized prior to the user setting a new value to the trait. # There isn't an old: Uninitialized -> new: Default value change event. # Instead, there is a old: Default -> new value event. # The old default value in this event won't have any notifiers # to be removed, therefore we need to excuse the NotifierNotFound # in the maintainer when it tries to remove notifiers from the old # value. foo = ClassWithDefault() graph = create_graph( create_observer(name="instance", notify=True), create_observer(name="value1", notify=True), ) handler = mock.Mock() call_add_or_remove_notifiers( object=foo, graph=graph, handler=handler, ) try: foo.instance = ClassWithTwoValue() except Exception: self.fail( "Reassigning the instance value should not fail." ) class TestNamedTraitObserverTraitAdded(unittest.TestCase): """ Test integration with the trait_added event.""" def test_observe_respond_to_trait_added(self): graph = create_graph( create_observer(name="value", notify=True, optional=True), ) handler = mock.Mock() foo = ClassWithInstance() # when # does not complain because optional is set to true call_add_or_remove_notifiers(object=foo, graph=graph, handler=handler) # when foo.add_trait("value", Int()) # then self.assertEqual(handler.call_count, 0) # when foo.value += 1 # then self.assertEqual(handler.call_count, 1) def test_observe_remove_notifiers_remove_trait_added(self): graph = create_graph( create_observer(name="value", notify=True, optional=True), ) handler = mock.Mock() foo = ClassWithInstance() # when # The following should cancel each other call_add_or_remove_notifiers( object=foo, graph=graph, handler=handler, remove=False) call_add_or_remove_notifiers( object=foo, graph=graph, handler=handler, remove=True) # when foo.add_trait("value", Int()) # then self.assertEqual(handler.call_count, 0) # when foo.value += 1 # then self.assertEqual(handler.call_count, 0) def test_remove_notifiers_after_trait_added(self): graph = create_graph( create_observer(name="value", notify=True, optional=True), ) handler = mock.Mock() foo = ClassWithInstance() call_add_or_remove_notifiers( object=foo, graph=graph, handler=handler, remove=False) # when foo.add_trait("value", Int()) # sanity check foo.value += 1 self.assertEqual(handler.call_count, 1) handler.reset_mock() # when call_add_or_remove_notifiers( object=foo, graph=graph, handler=handler, remove=True) # then foo.value += 1 self.assertEqual(handler.call_count, 0) def test_remove_trait_then_add_trait_again(self): # Test a scenario where a trait exists when the observer is hooked, # but then the trait is removed, and then added back again, the # observer is gone, because the CTrait is gone and the trait_added # event is not fired for something already defined on the class. # given # the trait exists, we can set optional to false. graph = create_graph( create_observer(name="value1", notify=True, optional=False), ) handler = mock.Mock() foo = ClassWithTwoValue() call_add_or_remove_notifiers( object=foo, graph=graph, handler=handler, remove=False) # sanity check, the handler is called when the trait changes. foo.value1 += 1 handler.assert_called_once() handler.reset_mock() # when # remove the trait foo.remove_trait("value1") # then # the handler is gone with the instance trait. foo.value1 += 1 handler.assert_not_called() # when # Add the trait back... foo.add_trait("value1", Int()) # then # won't bring the handler back, because the 'value1' is defined as a # class trait, trait_added is not fired when it is added. foo.value1 += 1 handler.assert_not_called() def test_add_trait_remove_trait_then_add_trait_again(self): # Test a scenario when a trait is added, then removed, then added back. # given # trait is optional. It will be added later. graph = create_graph( create_observer(name="new_value", notify=True, optional=True), ) handler = mock.Mock() foo = ClassWithInstance() call_add_or_remove_notifiers( object=foo, graph=graph, handler=handler, remove=False) foo.add_trait("new_value", Int()) foo.new_value += 1 handler.assert_called_once() handler.reset_mock() # when # remove the trait and then add it back foo.remove_trait("new_value") foo.add_trait("new_value", Int()) # then # the handler is now back! The trait was not defined on the class, # so the last 'add_trait' fires a trait_added event. foo.new_value += 1 handler.assert_called_once() def test_notifier_trait_added_distinguished(self): # Add two observers, both will have their own additional trait_added # observer. When one is removed, the other one is not affected. graph1 = create_graph( create_observer(name="some_value1", notify=True, optional=True), ) graph2 = create_graph( create_observer(name="some_value2", notify=True, optional=True), ) handler = mock.Mock() foo = ClassWithInstance() # Add two observers call_add_or_remove_notifiers( object=foo, graph=graph1, handler=handler, remove=False) call_add_or_remove_notifiers( object=foo, graph=graph2, handler=handler, remove=False) # when # Now remove the second observer call_add_or_remove_notifiers( object=foo, graph=graph2, handler=handler, remove=True) # the first one should still respond to trait_added event foo.add_trait("some_value1", Int()) foo.some_value1 += 1 # then self.assertEqual(handler.call_count, 1) handler.reset_mock() # when # the second observer has been removed foo.add_trait("some_value2", Int()) foo.some_value2 += 1 # then self.assertEqual(handler.call_count, 0) def test_optional_trait_added(self): graph = create_graph( create_observer(name="value", notify=True, optional=True), ) handler = mock.Mock() not_an_has_traits_instance = mock.Mock() # does not complain because optional is set to true try: call_add_or_remove_notifiers( object=not_an_has_traits_instance, graph=graph, handler=handler, ) except Exception: self.fail("Optional flag should have been propagated.") traits-6.3.2/traits/observation/tests/test_observe.py000066400000000000000000000426201414270267200231220ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from unittest import mock from traits.has_traits import HasTraits from traits.trait_types import Instance, Int from traits.observation.api import ( pop_exception_handler, push_exception_handler, ) from traits.observation.exceptions import NotifierNotFound from traits.observation.expression import compile_expr, trait from traits.observation.observe import ( apply_observers, dispatch_same, observe, ) from traits.observation._observer_graph import ObserverGraph from traits.observation._testing import ( call_add_or_remove_notifiers, create_graph, DummyNotifier, DummyObservable, DummyObserver, ) class TestObserveAddNotifier(unittest.TestCase): """ Test the add_notifiers action.""" def test_add_trait_notifiers(self): observable = DummyObservable() notifier = DummyNotifier() observer = DummyObserver( notify=True, observables=[observable], notifier=notifier, ) graph = ObserverGraph(node=observer) # when call_add_or_remove_notifiers( graph=graph, remove=False, ) # then self.assertEqual(observable.notifiers, [notifier]) def test_add_trait_notifiers_notify_flag_is_false(self): # Test when the notify flag is false, the notifier is not # added. observable = DummyObservable() notifier = DummyNotifier() observer = DummyObserver( notify=False, observables=[observable], notifier=notifier, ) graph = ObserverGraph(node=observer) # when call_add_or_remove_notifiers( graph=graph, remove=False, ) # then self.assertEqual(observable.notifiers, []) def test_add_maintainers(self): # Test adding maintainers for children graphs observable = DummyObservable() maintainer = DummyNotifier() root_observer = DummyObserver( notify=False, observables=[observable], maintainer=maintainer, ) # two children, each will have a maintainer graph = ObserverGraph( node=root_observer, children=[ ObserverGraph(node=DummyObserver()), ObserverGraph(node=DummyObserver()), ], ) # when call_add_or_remove_notifiers( graph=graph, remove=False, ) # then # the dummy observer always return the same maintainer object. self.assertEqual( observable.notifiers, [maintainer, maintainer]) def test_add_notifiers_for_children_graphs(self): # Test adding notifiers using children graphs observable1 = DummyObservable() child_observer1 = DummyObserver( observables=[observable1], ) observable2 = DummyObservable() child_observer2 = DummyObserver( observables=[observable2], ) parent_observer = DummyObserver( next_objects=[mock.Mock()], ) graph = ObserverGraph( node=parent_observer, children=[ ObserverGraph( node=child_observer1, ), ObserverGraph( node=child_observer2, ) ], ) # when call_add_or_remove_notifiers( graph=graph, remove=False, ) # then self.assertCountEqual( observable1.notifiers, [ # For child1 observer child_observer1.notifier, ] ) self.assertCountEqual( observable2.notifiers, [ # For child2 observer child_observer2.notifier, ] ) def test_add_notifiers_for_extra_graph(self): observable = DummyObservable() extra_notifier = DummyNotifier() extra_observer = DummyObserver( observables=[observable], notifier=extra_notifier, ) extra_graph = ObserverGraph( node=extra_observer, ) observer = DummyObserver( extra_graphs=[extra_graph], ) graph = ObserverGraph(node=observer) # when call_add_or_remove_notifiers( graph=graph, remove=False, ) # then self.assertEqual( observable.notifiers, [extra_notifier] ) def test_add_notifier_atomic(self): class BadNotifier(DummyNotifier): def add_to(self, observable): raise ZeroDivisionError() observable = DummyObservable() good_observer = DummyObserver( notify=True, observables=[observable], next_objects=[mock.Mock()], notifier=DummyNotifier(), maintainer=DummyNotifier(), ) bad_observer = DummyObserver( notify=True, observables=[observable], notifier=BadNotifier(), maintainer=DummyNotifier(), ) graph = create_graph( good_observer, bad_observer, ) # when with self.assertRaises(ZeroDivisionError): call_add_or_remove_notifiers( object=mock.Mock(), graph=graph, ) # then self.assertEqual(observable.notifiers, []) class TestObserveRemoveNotifier(unittest.TestCase): """ Test the remove action.""" def test_remove_trait_notifiers(self): observable = DummyObservable() notifier = DummyNotifier() observable.notifiers = [notifier] observer = DummyObserver( observables=[observable], notifier=notifier, ) graph = ObserverGraph( node=observer, ) # when call_add_or_remove_notifiers( graph=graph, remove=True, ) # then self.assertEqual(observable.notifiers, []) def test_remove_notifiers_skip_if_notify_flag_is_false(self): observable = DummyObservable() notifier = DummyNotifier() observable.notifiers = [notifier] observer = DummyObserver( notify=False, observables=[observable], notifier=notifier, ) graph = ObserverGraph( node=observer, ) # when call_add_or_remove_notifiers( graph=graph, remove=True, ) # then # notify is false, remove does nothing. self.assertEqual( observable.notifiers, [notifier] ) def test_remove_maintainers(self): observable = DummyObservable() maintainer = DummyNotifier() observable.notifiers = [maintainer, maintainer] root_observer = DummyObserver( notify=False, observables=[observable], maintainer=maintainer, ) # for there are two children graphs # two maintainers will be removed. graph = ObserverGraph( node=root_observer, children=[ ObserverGraph(node=DummyObserver()), ObserverGraph(node=DummyObserver()), ], ) # when call_add_or_remove_notifiers( graph=graph, remove=True, ) # then self.assertEqual(observable.notifiers, []) def test_remove_notifiers_for_children_graphs(self): observable1 = DummyObservable() notifier1 = DummyNotifier() child_observer1 = DummyObserver( observables=[observable1], notifier=notifier1, ) observable2 = DummyObservable() notifier2 = DummyNotifier() child_observer2 = DummyObserver( observables=[observable2], notifier=notifier2, ) parent_observer = DummyObserver( next_objects=[mock.Mock()], ) graph = ObserverGraph( node=parent_observer, children=[ ObserverGraph( node=child_observer1, ), ObserverGraph( node=child_observer2, ) ], ) # suppose notifiers were added observable1.notifiers = [notifier1] observable2.notifiers = [notifier2] # when call_add_or_remove_notifiers( graph=graph, remove=True, ) # then self.assertEqual(observable1.notifiers, []) self.assertEqual(observable2.notifiers, []) def test_remove_notifiers_for_extra_graph(self): observable = DummyObservable() extra_notifier = DummyNotifier() extra_observer = DummyObserver( observables=[observable], notifier=extra_notifier, ) extra_graph = ObserverGraph( node=extra_observer, ) observer = DummyObserver( extra_graphs=[extra_graph], ) graph = ObserverGraph(node=observer) # suppose the notifier was added before observable.notifiers = [extra_notifier] # when call_add_or_remove_notifiers( graph=graph, remove=True, ) # then self.assertEqual(observable.notifiers, []) def test_remove_notifier_raises_let_error_propagate(self): # Test if the notifier remove_from raises, the error will # be propagated. # DummyNotifier.remove_from raises if the notifier is not found. observer = DummyObserver( observables=[DummyObservable()], notifier=DummyNotifier(), ) with self.assertRaises(NotifierNotFound): call_add_or_remove_notifiers( graph=ObserverGraph(node=observer), remove=True, ) def test_remove_atomic(self): # Test atomicity notifier = DummyNotifier() maintainer = DummyNotifier() observable1 = DummyObservable() observable1.notifiers = [ notifier, maintainer, ] old_observable1_notifiers = observable1.notifiers.copy() observable2 = DummyObservable() observable2.notifiers = [maintainer] old_observable2_notifiers = observable2.notifiers.copy() observable3 = DummyObservable() observable3.notifiers = [ notifier, maintainer, ] old_observable3_notifiers = observable3.notifiers.copy() observer = DummyObserver( notify=True, observables=[ observable1, observable2, observable3, ], notifier=notifier, maintainer=maintainer, ) graph = create_graph( observer, DummyObserver(), # Need a child graph to get maintainer in ) # when with self.assertRaises(NotifierNotFound): call_add_or_remove_notifiers( object=mock.Mock(), graph=graph, remove=True, ) # then # as if nothing has happened, the order might not be maintained though! self.assertCountEqual( observable1.notifiers, old_observable1_notifiers, ) self.assertCountEqual( observable2.notifiers, old_observable2_notifiers, ) self.assertCountEqual( observable3.notifiers, old_observable3_notifiers, ) # ---- Tests for public facing `observe` -------------------------------------- class ClassWithNumber(HasTraits): number = Int() class ClassWithInstance(HasTraits): instance = Instance(ClassWithNumber) class TestObserverIntegration(unittest.TestCase): """ Test the public facing observe function.""" def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def test_observe_with_expression(self): foo = ClassWithNumber() handler = mock.Mock() observe( object=foo, expression=trait("number"), handler=handler, ) # when foo.number += 1 # then self.assertEqual(handler.call_count, 1) handler.reset_mock() # when observe( object=foo, expression=trait("number"), handler=handler, remove=True, ) foo.number += 1 # then self.assertEqual(handler.call_count, 0) def test_observe_different_dispatcher(self): self.dispatch_records = [] def dispatcher(handler, event): self.dispatch_records.append((handler, event)) foo = ClassWithNumber() handler = mock.Mock() # when observe( object=foo, expression=trait("number"), handler=handler, dispatcher=dispatcher, ) foo.number += 1 # then # the dispatcher is called. self.assertEqual(len(self.dispatch_records), 1) def test_observe_different_target(self): # Test the result of setting target to be the same as object parent1 = ClassWithInstance() parent2 = ClassWithInstance() # the instance is shared instance = ClassWithNumber() parent1.instance = instance parent2.instance = instance handler = mock.Mock() # when observe( object=parent1, expression=trait("instance").trait("number"), handler=handler, ) observe( object=parent2, expression=trait("instance").trait("number"), handler=handler, ) instance.number += 1 # then # the handler should be called twice as the targets are different. self.assertEqual(handler.call_count, 2) def test_observe_with_any_callables_accepting_one_argument(self): # If it is a callable that works with one positional argument, it # can be used. def handler_with_one_pos_arg(arg, *, optional=None): pass callables = [ repr, lambda e: False, handler_with_one_pos_arg, ] for callable_ in callables: with self.subTest(callable=callable_): instance = ClassWithNumber() instance.observe(callable_, "number") instance.number += 1 class TestApplyObservers(unittest.TestCase): """ Test the public-facing apply_observers function.""" def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def test_apply_observers_with_expression(self): foo = ClassWithNumber() handler = mock.Mock() graphs = compile_expr(trait("number")) apply_observers( object=foo, graphs=graphs, handler=handler, dispatcher=dispatch_same, ) # when foo.number += 1 # then self.assertEqual(handler.call_count, 1) handler.reset_mock() # when apply_observers( object=foo, graphs=graphs, handler=handler, dispatcher=dispatch_same, remove=True, ) foo.number += 1 # then self.assertEqual(handler.call_count, 0) def test_apply_observers_different_dispatcher(self): self.dispatch_records = [] def dispatcher(handler, event): self.dispatch_records.append((handler, event)) foo = ClassWithNumber() handler = mock.Mock() # when apply_observers( object=foo, graphs=compile_expr(trait("number")), handler=handler, dispatcher=dispatcher, ) foo.number += 1 # then # the dispatcher is called. self.assertEqual(len(self.dispatch_records), 1) def test_apply_observers_different_target(self): # Test the result of setting target to be the same as object parent1 = ClassWithInstance() parent2 = ClassWithInstance() graphs = compile_expr(trait("instance").trait("number")) # the instance is shared instance = ClassWithNumber() parent1.instance = instance parent2.instance = instance handler = mock.Mock() # when apply_observers( object=parent1, graphs=graphs, handler=handler, dispatcher=dispatch_same, ) apply_observers( object=parent2, graphs=graphs, handler=handler, dispatcher=dispatch_same, ) instance.number += 1 # then # the handler should be called twice as the targets are different. self.assertEqual(handler.call_count, 2) traits-6.3.2/traits/observation/tests/test_observer_change_notifier.py000066400000000000000000000457671414270267200265270ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from unittest import mock import weakref from traits.api import HasTraits, Instance, Int from traits.observation._observer_change_notifier import ObserverChangeNotifier from traits.observation._observer_graph import ObserverGraph from traits.observation.exceptions import NotifierNotFound def dispatch_here(handler, event): handler(event) def create_notifier(**kwargs): """ Convenient function for creating an instance of ObserverChangeNotifier for testing purposes. """ values = dict( graph=mock.Mock(), observer_handler=mock.Mock(), event_factory=mock.Mock(), prevent_event=lambda event: False, handler=mock.Mock(), target=mock.Mock(), dispatcher=dispatch_here, ) values.update(kwargs) return ObserverChangeNotifier(**values) class DummyClass: def __init__(self): self.notifiers = [] def _notifiers(self, force_create): return self.notifiers def dummy_method(self): pass class TestObserverChangeNotifierCall(unittest.TestCase): """ Tests for the notifier being a callable.""" def test_init_and_call(self): graph = mock.Mock() observer_handler = mock.Mock() event_factory = mock.Mock(return_value="Event") handler = mock.Mock() target = mock.Mock() dispatcher = mock.Mock() notifier = create_notifier( observer_handler=observer_handler, graph=graph, handler=handler, target=target, dispatcher=dispatcher, event_factory=event_factory, ) notifier(a=1, b=2) event_factory.assert_called_once_with(a=1, b=2) observer_handler.assert_called_once_with( event="Event", graph=graph, handler=handler, target=target, dispatcher=dispatcher, ) def test_call_with_prevent_event(self): observer_handler = mock.Mock() handler = mock.Mock() target = mock.Mock() notifier = create_notifier( observer_handler=observer_handler, handler=handler, target=target, event_factory=lambda value: value, prevent_event=lambda event: event != "Fire", ) # when notifier("Hello") # then # silenced by prevent_event self.assertEqual(observer_handler.call_count, 0) # when notifier("Fire") # then # it got through self.assertEqual(observer_handler.call_count, 1) class TestObserverChangeNotifierWeakrefTarget(unittest.TestCase): """ Tests for weak references on targets. """ def test_target_can_be_garbage_collected(self): # It is a common use case that the target is an instance # of HasTraits and the notifier is attached to an internal # object inside target. The notifier should not prevent # the target from being garbage collected. target = mock.Mock() target_ref = weakref.ref(target) # Holding reference to the notifier does not prevent # the target from being deleted. notifier = create_notifier(target=target) # noqa: F841 # when del target # then self.assertIsNone(target_ref()) def test_deleted_target_silence_notifier(self): # If the target is deleted, the notifier is silenced target = mock.Mock() observer_handler = mock.Mock() notifier = create_notifier( observer_handler=observer_handler, target=target) # when del target notifier(a=1, b=2) # then observer_handler.assert_not_called() class TestObserverChangeNotifierWeakrefHandler(unittest.TestCase): """ Test for using weak references when the user handler is a method of an instance. """ def test_instance_can_be_garbage_collected(self): # It is a common use case the user's handler is an instance method. # The notifier should not prevent the instance from being # garbage collected. instance = DummyClass() instance_ref = weakref.ref(instance) notifier = create_notifier(handler=instance.dummy_method) # noqa: F841 # when del instance # then self.assertIsNone(instance_ref()) def test_deleted_handler_silence_notifier(self): # If the handler is an instance method and the instance is garbage # collected, the notifier is silenced. # Create a dummy observer_handler otherwise the default mock object # keep references to call argument during the sanity check. def observer_handler(*args, **kwargs): pass instance = DummyClass() method_ref = weakref.WeakMethod(instance.dummy_method) target = mock.Mock() event_factory = mock.Mock() notifier = create_notifier( observer_handler=observer_handler, target=target, handler=instance.dummy_method, event_factory=event_factory, ) # sanity check notifier(b=3) self.assertEqual(event_factory.call_count, 1) event_factory.reset_mock() # when del instance self.assertIsNone(method_ref()) notifier(a=1, b=2) # then event_factory.assert_not_called() class TestObserverChangeEquals(unittest.TestCase): """ Test ObserverChangeNotifier.equals """ def test_notifier_equals(self): observer_handler = mock.Mock() handler = mock.Mock() graph = mock.Mock() target = mock.Mock() notifier1 = create_notifier( observer_handler=observer_handler, handler=handler, graph=graph, target=target, dispatcher=dispatch_here, ) notifier2 = create_notifier( observer_handler=observer_handler, handler=handler, graph=graph, target=target, dispatcher=dispatch_here, ) self.assertTrue( notifier1.equals(notifier2), "Expected notifier1 to see notifier2 as equals." ) self.assertTrue( notifier2.equals(notifier1), "Expected notifier2 to see notifier1 as equals." ) def test_notifier_observer_handler_not_equal(self): # Test notifier differentiates the identity of # the observer_handler. handler = mock.Mock() graph = mock.Mock() target = mock.Mock() notifier1 = create_notifier( observer_handler=mock.Mock(), handler=handler, graph=graph, target=target, dispatcher=dispatch_here, ) notifier2 = create_notifier( observer_handler=mock.Mock(), handler=handler, graph=graph, target=target, dispatcher=dispatch_here, ) self.assertFalse( notifier1.equals(notifier2), "Expected notifier1 to see notifier2 as different." ) self.assertFalse( notifier2.equals(notifier1), "Expected notifier2 to see notifier1 as different." ) def test_notifier_handler_not_equal(self): # Test notifier differentiates the identity of the # user's handler observer_handler = mock.Mock() graph = mock.Mock() target = mock.Mock() notifier1 = create_notifier( observer_handler=observer_handler, handler=mock.Mock(), graph=graph, target=target, dispatcher=dispatch_here, ) notifier2 = create_notifier( observer_handler=observer_handler, handler=mock.Mock(), graph=graph, target=target, dispatcher=dispatch_here, ) self.assertFalse( notifier1.equals(notifier2), "Expected notifier1 to see notifier2 as different." ) self.assertFalse( notifier2.equals(notifier1), "Expected notifier2 to see notifier1 as different." ) def test_notifier_graph_not_equal(self): # Test notifier differentiates the identity of the # graph. observer_handler = mock.Mock() handler = mock.Mock() target = mock.Mock() notifier1 = create_notifier( observer_handler=observer_handler, handler=handler, graph=mock.Mock(), target=target, dispatcher=dispatch_here, ) notifier2 = create_notifier( observer_handler=observer_handler, handler=handler, graph=mock.Mock(), target=target, dispatcher=dispatch_here, ) self.assertFalse( notifier1.equals(notifier2), "Expected notifier1 to see notifier2 as different." ) self.assertFalse( notifier2.equals(notifier1), "Expected notifier2 to see notifier1 as different." ) def test_notifier_target_not_equals(self): # Test notifier differentiates the identity of target. observer_handler = mock.Mock() handler = mock.Mock() graph = mock.Mock() target1 = mock.Mock() target2 = mock.Mock() notifier1 = create_notifier( observer_handler=observer_handler, handler=handler, graph=graph, target=target1, dispatcher=dispatch_here, ) notifier2 = create_notifier( observer_handler=observer_handler, handler=handler, graph=graph, target=target2, dispatcher=dispatch_here, ) self.assertFalse( notifier1.equals(notifier2), "Expected notifier1 to see notifier2 as different." ) self.assertFalse( notifier2.equals(notifier1), "Expected notifier2 to see notifier1 as different." ) def test_notifier_dispatcher_not_equals(self): # Test notifier differentiates the dispatchers. observer_handler = mock.Mock() handler = mock.Mock() graph = mock.Mock() target = mock.Mock() dispatcher1 = mock.Mock() dispatcher2 = mock.Mock() notifier1 = create_notifier( observer_handler=observer_handler, handler=handler, graph=graph, target=target, dispatcher=dispatcher1, ) notifier2 = create_notifier( observer_handler=observer_handler, handler=handler, graph=graph, target=target, dispatcher=dispatcher2, ) self.assertFalse( notifier1.equals(notifier2), "Expected notifier1 to see notifier2 as different." ) self.assertFalse( notifier2.equals(notifier1), "Expected notifier2 to see notifier1 as different." ) def test_notifier_equals_graphs_compared_for_equality(self): # New graph can be created that will compare true for equality but not # for identity graph1 = tuple([1, 2, 3]) graph2 = tuple([1, 2, 3]) observer_handler = mock.Mock() handler = mock.Mock() target = mock.Mock() notifier1 = create_notifier( observer_handler=observer_handler, handler=handler, graph=graph1, target=target, dispatcher=dispatch_here, ) notifier2 = create_notifier( observer_handler=observer_handler, handler=handler, graph=graph2, target=target, dispatcher=dispatch_here, ) self.assertTrue( notifier1.equals(notifier2), "Expected notifier1 to see notifier2 as equals." ) self.assertTrue( notifier2.equals(notifier1), "Expected notifier2 to see notifier1 as equals." ) def test_notifier_equals_with_different_type(self): # test the notifier can handle callables of different types. notifier = create_notifier() self.assertFalse(notifier.equals(str)) def test_notifier_instance_method_handler_equal(self): # Instance methods are descriptors observer_handler = mock.Mock() graph = mock.Mock() target = mock.Mock() instance = DummyClass() notifier1 = create_notifier( observer_handler=observer_handler, handler=instance.dummy_method, graph=graph, target=target, dispatcher=dispatch_here, ) notifier2 = create_notifier( observer_handler=observer_handler, handler=instance.dummy_method, graph=graph, target=target, dispatcher=dispatch_here, ) self.assertTrue( notifier1.equals(notifier2), "Expected notifier1 to see notifier2 as equals." ) self.assertTrue( notifier2.equals(notifier1), "Expected notifier2 to see notifier1 as equals." ) class TestObserverChangeNotifierAdd(unittest.TestCase): """ Test ObserverChangeNotifier.add_to """ def test_add_notifier(self): instance = DummyClass() notifier = create_notifier() # when notifier.add_to(instance) # then self.assertEqual(instance.notifiers, [notifier]) def test_add_to_ignore_same_notifier(self): # add_to always appends even if the notifier looks the same. handler = mock.Mock() observer_handler = mock.Mock() graph = mock.Mock() target = mock.Mock() notifier1 = create_notifier( observer_handler=observer_handler, graph=graph, handler=handler, target=target, ) notifier2 = create_notifier( observer_handler=observer_handler, graph=graph, handler=handler, target=target, ) instance = DummyClass() # when notifier1.add_to(instance) notifier2.add_to(instance) # then self.assertEqual(instance.notifiers, [notifier1, notifier2]) class TestObserverChangeNotifierRemove(unittest.TestCase): """ Test ObserverChangeNotifier.remove_from """ def test_remove_notifier(self): instance = DummyClass() notifier = create_notifier() notifier.add_to(instance) # when notifier.remove_from(instance) # then self.assertEqual(instance.notifiers, []) def test_remove_from_error_if_not_found(self): # Test remove_from raises if a notifier is not found. instance = DummyClass() notifier = create_notifier() with self.assertRaises(NotifierNotFound): notifier.remove_from(instance) def test_remove_from_recognize_equivalent_notifier(self): # Test remove_from will remove an equivalent notifier instance = DummyClass() handler = mock.Mock() observer_handler = mock.Mock() graph = mock.Mock() target = mock.Mock() notifier1 = create_notifier( handler=handler, observer_handler=observer_handler, graph=graph, target=target, ) notifier2 = create_notifier( handler=handler, observer_handler=observer_handler, graph=graph, target=target, ) # when notifier1.add_to(instance) notifier2.remove_from(instance) # then self.assertEqual(instance.notifiers, []) class TestIntegrationHasTraits(unittest.TestCase): """ Semi-integration tests with HasTraits notifications. """ def setUp(self): self.event_args_list = [] def handler(self, *args): self.event_args_list.append(args) def event_factory(self, object, name, old, new): event = mock.Mock() event.object = object event.name = name event.old = old event.new = new return event def test_basic_instance_change(self): class Bar(HasTraits): value = Int() class Foo(HasTraits): bar = Instance(Bar) on_bar_value_changed = self.handler bar = Bar() foo1 = Foo(bar=bar) foo2 = Foo(bar=bar) def observer_handler(event, graph, handler, target, dispatcher): # Very stupid handler for maintaining notifiers. old_notifiers = event.old._trait("value", 2)._notifiers(True) old_notifiers.remove(handler) new_notifiers = event.new._trait("value", 2)._notifiers(True) new_notifiers.append(handler) # Ignore graph, which would have been used for propagating # notifiers in nested objects. # Ignore target, which would have been used as the context # for the user handler. # Ignore dispatcher, which would otherwise wrap the user handler. # Two notifiers are added to bar # One "belongs" to foo1, the second one "belongs" to foo2 bar._trait("value", 2)._notifiers(True).extend([ on_bar_value_changed, on_bar_value_changed, ]) # this is for maintaining notifiers that belong to foo1 notifier_foo1 = create_notifier( observer_handler=observer_handler, event_factory=self.event_factory, graph=ObserverGraph(node=None), handler=on_bar_value_changed, target=foo1, dispatcher=dispatch_here, ) notifier_foo1.add_to(foo1._trait("bar", 2)) # this is for maintaining notifiers that belong to foo2 notifier_foo2 = create_notifier( observer_handler=observer_handler, event_factory=self.event_factory, graph=ObserverGraph(node=None), handler=on_bar_value_changed, target=foo2, dispatcher=dispatch_here, ) notifier_foo2.add_to(foo2._trait("bar", 2)) # when # the bar is changed, the ObserverChangeNotifier is fired so that # user handler on Bar.value is maintained. self.event_args_list.clear() new_bar = Bar(value=1) foo1.bar = new_bar foo2.bar = new_bar new_bar.value += 1 # then self.assertEqual(len(self.event_args_list), 2) # when # changes on the old bar will not be captured self.event_args_list.clear() bar.value += 1 # then self.assertEqual(len(self.event_args_list), 0) traits-6.3.2/traits/observation/tests/test_observer_graph.py000066400000000000000000000063601414270267200244660ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.observation._observer_graph import ObserverGraph def graph_from_nodes(*nodes): nodes = nodes[::-1] graph = ObserverGraph(node=nodes[0]) for node in nodes[1:]: graph = ObserverGraph(node=node, children=[graph]) return graph class TestObserverGraph(unittest.TestCase): """ Test generic functions on ObserverGraph.""" def test_equality(self): graph1 = graph_from_nodes(1, 2, 3) graph2 = graph_from_nodes(1, 2, 3) self.assertEqual(graph1, graph2) self.assertEqual(hash(graph1), hash(graph2)) def test_equality_different_type(self): graph1 = graph_from_nodes(1, 2, 3) self.assertNotEqual(graph1, 1) def test_equality_different_length_children(self): graph1 = ObserverGraph( node=1, children=[ ObserverGraph(node=2), ObserverGraph(node=3), ], ) graph2 = ObserverGraph( node=1, children=[ ObserverGraph(node=2), ], ) self.assertNotEqual(graph1, graph2) def test_equality_order_of_children(self): # The order of items in children does not matter graph1 = ObserverGraph( node=1, children=[ ObserverGraph(node=2), ObserverGraph(node=3), ], ) graph2 = ObserverGraph( node=1, children=[ ObserverGraph(node=3), ObserverGraph(node=2), ], ) self.assertEqual(graph1, graph2) self.assertEqual(hash(graph1), hash(graph2)) def test_children_ordered(self): child_graph = ObserverGraph(node=2) graph = ObserverGraph( node=1, children=[ child_graph, ObserverGraph(node=3), ], ) self.assertIs(graph.children[0], child_graph) def test_children_unique(self): child_graph = ObserverGraph(node=2) with self.assertRaises(ValueError) as exception_cm: ObserverGraph( node=1, children=[ child_graph, ObserverGraph(node=2), ], ) self.assertEqual( str(exception_cm.exception), "Not all children are unique.") def test_slots(self): graph = ObserverGraph(node=1) with self.assertRaises(AttributeError): graph.__dict__ with self.assertRaises(AttributeError): graph.__weakref__ def test_eval_repr_roundtrip(self): graph = ObserverGraph( node=1, children=[ ObserverGraph(node=2), ObserverGraph(node=3), ], ) self.assertEqual(eval(repr(graph)), graph) traits-6.3.2/traits/observation/tests/test_parsing.py000066400000000000000000000155661414270267200231310ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.observation._named_trait_observer import NamedTraitObserver from traits.observation._testing import create_graph from traits.observation.parsing import compile_str, parse from traits.observation.expression import ( anytrait, dict_items, list_items, metadata, set_items, trait, ) class TestParsingSeriesJoin(unittest.TestCase): def test_join(self): actual = parse("a.b.c") expected = trait("a").trait("b").trait("c") self.assertEqual(actual, expected) def test_join_with_colon(self): actual = parse("a:b:c") expected = trait("a", False).trait("b", False).trait("c") self.assertEqual(actual, expected) class TestParsingOr(unittest.TestCase): def test_or_with_commas(self): actual = parse("a,b,c") expected = trait("a") | trait("b") | trait("c") self.assertEqual(actual, expected) def test_or_with_join_nested(self): actual = parse("a.b.c,d.e") expected = ( trait("a").trait("b").trait("c") | trait("d").trait("e") ) self.assertEqual(actual, expected) class TestParsingGroup(unittest.TestCase): def test_grouped_or(self): actual = parse("root.[left,right]") expected = trait("root").then(trait("left") | trait("right")) self.assertEqual(actual, expected) def test_grouped_or_extended(self): actual = parse("root.[left,right].value") expected = ( trait("root").then( trait("left") | trait("right")).trait("value") ) self.assertEqual(actual, expected) def test_multi_branch_then_or_apply_notify_flag_to_last_item(self): actual = parse("root.[a.b.c.d,value]:g") expected = ( trait("root").then( trait("a").trait("b").trait("c").trait("d", False) | trait("value", False) ).trait("g") ) self.assertEqual(actual, expected) class TestParsingMetadata(unittest.TestCase): def test_metadata(self): actual = parse("+name") expected = metadata("name", notify=True) self.assertEqual(actual, expected) def test_metadata_notify_false(self): actual = parse("+name:+attr") expected = metadata("name", notify=False).metadata("attr", notify=True) self.assertEqual(actual, expected) class TestParsingTrait(unittest.TestCase): def test_simple_trait(self): actual = parse("a") expected = trait("a") self.assertEqual(actual, expected) def test_trait_not_notifiy(self): actual = parse("a:b") expected = trait("a", notify=False).trait("b") self.assertEqual(actual, expected) class TestParsingAnytrait(unittest.TestCase): def test_anytrait(self): actual = parse("*") expected = anytrait() self.assertEqual(actual, expected) def test_trait_anytrait_not_notify(self): actual = parse("name:*") expected = trait("name", notify=False).anytrait() self.assertEqual(actual, expected) def test_anytrait_in_parallel_branch(self): actual = parse("a:*,b") expected = trait("a", notify=False).anytrait() | trait("b") self.assertEqual(actual, expected) def test_anytrait_in_invalid_position(self): # "*" can only appear in a terminal position invalid_expressions = [ "*.*", "*:*", "*.name", "*.items", "*:name", "*.a,b", "[a.*,b].c", ] for expression in invalid_expressions: with self.subTest(expression=expression): with self.assertRaises(ValueError): parse(expression) class TestParsingItems(unittest.TestCase): def test_items(self): actual = parse("items") expected = ( trait("items", optional=True) | dict_items(optional=True) | list_items(optional=True) | set_items(optional=True) ) self.assertEqual(actual, expected) def test_items_not_notify(self): actual = parse("items:attr") expected = ( trait("items", notify=False, optional=True) | dict_items(notify=False, optional=True) | list_items(notify=False, optional=True) | set_items(notify=False, optional=True) ).trait("attr") self.assertEqual(actual, expected) class TestParsingGeneral(unittest.TestCase): def test_parse_error(self): invalid_expressions = [ "a:", "**", ".", "", ] for expression in invalid_expressions: with self.subTest(expression=expression): with self.assertRaises(ValueError): parse(expression) def test_deep_nesting(self): actual = parse("[[a:b].c]:d") expected = ( trait("a", notify=False) .trait("b") .trait("c", notify=False) .trait("d") ) self.assertEqual(actual, expected) actual = parse("[a:[b.[c:d]]]") expected = ( trait("a", notify=False).then( trait("b").then( trait("c", notify=False).then(trait("d")) ) ) ) self.assertEqual(actual, expected) class TestCompileFromStr(unittest.TestCase): # Most of the complication is in the parsing; compile should need little # additional testing. def test_compile_simple(self): actual = compile_str("name") expected = [ create_graph( NamedTraitObserver(name="name", notify=True, optional=False), ), ] self.assertEqual(actual, expected) def test_compile_serial(self): actual = compile_str("name1.name2") expected = [ create_graph( NamedTraitObserver(name="name1", notify=True, optional=False), NamedTraitObserver(name="name2", notify=True, optional=False), ), ] self.assertEqual(actual, expected) def test_compile_parallel(self): actual = compile_str("name1,name2") expected = [ create_graph( NamedTraitObserver(name="name1", notify=True, optional=False), ), create_graph( NamedTraitObserver(name="name2", notify=True, optional=False), ), ] self.assertEqual(actual, expected) traits-6.3.2/traits/observation/tests/test_set_change_event.py000066400000000000000000000033301414270267200247510ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.observation._set_change_event import ( SetChangeEvent, set_event_factory, ) from traits.trait_set_object import TraitSet class TestSetChangeEvent(unittest.TestCase): def test_set_change_event_repr(self): event = SetChangeEvent( object=set(), added={1}, removed={3}, ) actual = repr(event) self.assertEqual( actual, "SetChangeEvent(object=set(), removed={3}, added={1})", ) class TestSetEventFactory(unittest.TestCase): """ Test event factory compatibility with TraitSet.notify """ def test_trait_set_notification_compat(self): events = [] def notifier(*args, **kwargs): event = set_event_factory(*args, **kwargs) events.append(event) trait_set = TraitSet( [1, 2, 3], notifiers=[notifier], ) # when trait_set.add(4) # then event, = events self.assertIs(event.object, trait_set) self.assertEqual(event.added, {4}) self.assertEqual(event.removed, set()) # when events.clear() trait_set.remove(4) # then event, = events self.assertEqual(event.added, set()) self.assertEqual(event.removed, {4}) traits-6.3.2/traits/observation/tests/test_set_item_observer.py000066400000000000000000000163571414270267200252050ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from unittest import mock from traits.has_traits import HasTraits from traits.observation._set_item_observer import SetItemObserver from traits.observation._testing import ( call_add_or_remove_notifiers, create_graph, DummyObservable, DummyObserver, DummyNotifier, ) from traits.trait_set_object import TraitSet from traits.trait_types import Set def create_observer(**kwargs): """ Convenience function for creating SetItemObserver with default values. """ values = dict( notify=True, optional=False, ) values.update(kwargs) return SetItemObserver(**values) class TestSetItemObserverEqualHash(unittest.TestCase): """ Test SetItemObserver __eq__, __hash__ and immutability. """ def test_not_equal_notify(self): observer1 = SetItemObserver(notify=False, optional=False) observer2 = SetItemObserver(notify=True, optional=False) self.assertNotEqual(observer1, observer2) def test_not_equal_optional(self): observer1 = SetItemObserver(notify=True, optional=True) observer2 = SetItemObserver(notify=True, optional=False) self.assertNotEqual(observer1, observer2) def test_not_equal_different_type(self): observer1 = SetItemObserver(notify=False, optional=False) imposter = mock.Mock() imposter.notify = False imposter.optional = False self.assertNotEqual(observer1, imposter) def test_equal_observers(self): observer1 = SetItemObserver(notify=False, optional=False) observer2 = SetItemObserver(notify=False, optional=False) self.assertEqual(observer1, observer2) self.assertEqual(hash(observer1), hash(observer2)) def test_slots(self): observer = SetItemObserver(notify=True, optional=False) with self.assertRaises(AttributeError): observer.__dict__ with self.assertRaises(AttributeError): observer.__weakref__ def test_eval_repr_roundtrip(self): observer = SetItemObserver(notify=True, optional=False) self.assertEqual(eval(repr(observer)), observer) class CustomSet(set): # This is a set, but not an observable pass class CustomTraitSet(TraitSet): # This can be used with SetItemObserver pass class ClassWithSet(HasTraits): values = Set() class TestSetItemObserverIterObservable(unittest.TestCase): """ Test SetItemObserver.iter_observables """ def test_trait_set_iter_observables(self): instance = ClassWithSet() observer = create_observer(optional=False) actual_item, = list(observer.iter_observables(instance.values)) self.assertIs(actual_item, instance.values) def test_set_but_not_a_trait_set(self): observer = create_observer(optional=False) with self.assertRaises(ValueError) as exception_context: list(observer.iter_observables(CustomSet())) self.assertIn( "Expected a TraitSet to be observed, got", str(exception_context.exception) ) def test_iter_observables_custom_trait_set(self): # A subcalss of TraitSet can also be used. custom_trait_set = CustomTraitSet() observer = create_observer() actual_item, = list(observer.iter_observables(custom_trait_set)) self.assertIs(actual_item, custom_trait_set) def test_not_a_set(self): observer = create_observer(optional=False) with self.assertRaises(ValueError) as exception_context: list(observer.iter_observables(None)) self.assertIn( "Expected a TraitSet to be observed, got", str(exception_context.exception) ) def test_optional_flag_not_a_set(self): observer = create_observer(optional=True) actual = list(observer.iter_observables(None)) self.assertEqual(actual, []) def test_optional_flag_not_an_observable(self): observer = create_observer(optional=True) actual = list(observer.iter_observables(CustomSet())) self.assertEqual(actual, []) class TestSetItemObserverIterObjects(unittest.TestCase): """ Test SetItemObserver.iter_objects """ def test_iter_objects_from_set(self): instance = ClassWithSet() instance.values = set([1, 2, 3]) observer = create_observer() actual = list(observer.iter_objects(instance.values)) self.assertCountEqual(actual, [1, 2, 3]) def test_iter_observables_custom_trait_set(self): # A subcalss of TraitSet can also be used. custom_trait_set = CustomTraitSet([1, 2, 3]) observer = create_observer() actual = list(observer.iter_objects(custom_trait_set)) self.assertCountEqual(actual, [1, 2, 3]) def test_iter_objects_sanity_check(self): # sanity check if the given object is a set observer = create_observer(optional=False) with self.assertRaises(ValueError) as exception_context: list(observer.iter_objects(None)) self.assertIn( "Expected a TraitSet to be observed, got", str(exception_context.exception), ) def test_iter_objects_optional(self): observer = create_observer(optional=True) actual = list(observer.iter_objects(None)) self.assertEqual(actual, []) class TestSetItemObserverNotifications(unittest.TestCase): """ Integration tests with notifiers and HasTraits. """ def test_notify_set_change(self): instance = ClassWithSet(values=set()) graph = create_graph( create_observer(notify=True), ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance.values, graph=graph, handler=handler, ) # when instance.values.add(1) # then ((event, ), _), = handler.call_args_list self.assertEqual(event.added, set([1])) self.assertEqual(event.removed, set()) def test_maintain_notifier(self): # Test maintaining downstream notifier class ChildObserver(DummyObserver): def iter_observables(self, object): yield object instance = ClassWithSet() instance.values = set() notifier = DummyNotifier() child_observer = ChildObserver(notifier=notifier) graph = create_graph( create_observer(notify=False, optional=False), child_observer, ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance.values, graph=graph, handler=handler, ) # when observable = DummyObservable() instance.values.add(observable) # then self.assertEqual(observable.notifiers, [notifier]) # when instance.values.remove(observable) # then self.assertEqual(observable.notifiers, []) traits-6.3.2/traits/observation/tests/test_trait_added_observer.py000066400000000000000000000223471414270267200256340ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from unittest import mock from traits.has_traits import HasTraits from traits.observation._testing import ( call_add_or_remove_notifiers, create_graph, DummyNotifier, DummyObserver, ) from traits.observation._trait_added_observer import ( _RestrictedNamedTraitObserver, TraitAddedObserver, ) from traits.trait_types import Str def create_observer(**kwargs): values = dict( match_func=mock.Mock(), optional=False, ) values.update(kwargs) return TraitAddedObserver(**values) class DummyMatchFunc: """ A callable to be used as TraitAddedObserver.match_func """ def __init__(self, return_value): self.return_value = return_value def __call__(self, name, trait): return self.return_value def __eq__(self, other): return self.return_value == other.return_value def __hash__(self): return hash(self.return_value) class TestTraitAddedObserverEqualHash(unittest.TestCase): """ Tests for TraitAddedObserver __eq__ and __hash__ methods. """ def test_not_equal_match_func(self): observer1 = TraitAddedObserver(match_func=mock.Mock(), optional=True) observer2 = TraitAddedObserver(match_func=mock.Mock(), optional=True) self.assertNotEqual(observer1, observer2) def test_not_equal_optional(self): match_func = mock.Mock() observer1 = TraitAddedObserver(match_func=match_func, optional=False) observer2 = TraitAddedObserver(match_func=match_func, optional=True) self.assertNotEqual(observer1, observer2) def test_equal_match_func_optional(self): # If two match_func compare equally and optional is the same # then they are the same. observer1 = TraitAddedObserver( match_func=DummyMatchFunc(return_value=True), optional=False, ) observer2 = TraitAddedObserver( match_func=DummyMatchFunc(return_value=True), optional=False, ) self.assertEqual(observer1, observer2) self.assertEqual(hash(observer1), hash(observer2)) def test_not_equal_type(self): match_func = mock.Mock() observer1 = TraitAddedObserver( match_func=match_func, optional=False, ) imposter = mock.Mock() imposter.match_func = match_func imposter.optional = False self.assertNotEqual(observer1, imposter) def test_notify_is_false(self): observer = create_observer() self.assertFalse( observer.notify, "TraitAddedObserver.notify should be always false.", ) class TestRestrictedNamedTraitObserverEqualityHash(unittest.TestCase): """ Test _RestrictedNamedTraitObserver.__eq__ and __hash__ """ def test_equality_name_and_observer(self): wrapped_observer = DummyObserver() observer1 = _RestrictedNamedTraitObserver( name="name", wrapped_observer=wrapped_observer) observer2 = _RestrictedNamedTraitObserver( name="name", wrapped_observer=wrapped_observer) self.assertEqual(observer1, observer2) self.assertEqual(hash(observer1), hash(observer2)) def test_not_equal_name(self): wrapped_observer = DummyObserver() observer1 = _RestrictedNamedTraitObserver( name="name", wrapped_observer=wrapped_observer) observer2 = _RestrictedNamedTraitObserver( name="other", wrapped_observer=wrapped_observer) self.assertNotEqual(observer1, observer2) def test_not_equal_observer(self): observer1 = _RestrictedNamedTraitObserver( name="name", wrapped_observer=DummyObserver()) observer2 = _RestrictedNamedTraitObserver( name="name", wrapped_observer=DummyObserver()) self.assertNotEqual(observer1, observer2) class TestRestrictedNamedTraitObserverWithWrappedObserver(unittest.TestCase): """ Test the quantities inherited from the wrapped observer.""" def test_notify_inherited(self): wrapped_observer = DummyObserver(notify=False) observer = _RestrictedNamedTraitObserver( name="name", wrapped_observer=wrapped_observer) self.assertEqual(observer.notify, wrapped_observer.notify) def test_notifier_inherited(self): notifier = DummyNotifier() wrapped_observer = DummyObserver(notifier=notifier) observer = _RestrictedNamedTraitObserver( name="name", wrapped_observer=wrapped_observer) self.assertEqual( observer.get_notifier(None, None, None), notifier, ) def test_maintainer_inherited(self): maintainer = DummyNotifier() wrapped_observer = DummyObserver(maintainer=maintainer) observer = _RestrictedNamedTraitObserver( name="name", wrapped_observer=wrapped_observer) self.assertEqual( observer.get_maintainer(None, None, None, None), maintainer, ) # ----------------------------------- # Integration tests with HasTraits # ----------------------------------- class DummyHasTraitsClass(HasTraits): def dummy_method(self): pass class TestTraitAddedObserverIterObservables(unittest.TestCase): """ Test sanity checks in iter_observables. """ def test_iter_observables_get_trait_added_ctrait(self): observer = create_observer() instance = DummyHasTraitsClass() actual, = list(observer.iter_observables(instance)) self.assertEqual(actual, instance._trait("trait_added", 2)) def test_iter_observables_ignore_incompatible_object_if_optional(self): observer = create_observer(optional=True) actual = list(observer.iter_observables(None)) self.assertEqual(actual, []) def test_iter_observables_error_incompatible_object_if_required(self): observer = create_observer(optional=False) with self.assertRaises(ValueError) as exception_cm: list(observer.iter_observables(None)) self.assertIn( "Unable to observe 'trait_added'", str(exception_cm.exception)) class TestTraitAddedObserverIterObjects(unittest.TestCase): """ Test iter_objects yields nothing. """ def test_iter_objects_yields_nothing(self): observer = create_observer() actual = list(observer.iter_objects(None)) self.assertEqual(actual, []) class TestTraitAddedObserverNotifications(unittest.TestCase): """ Test the core logic for maintaining downstream observers when a trait is added. """ def setUp(self): def match_func(name, trait): return name.startswith("good_") self.observer = TraitAddedObserver( match_func=match_func, optional=False, ) def test_maintainer_trait_added(self): # Test the maintainer is added for the trait_added event. instance = DummyHasTraitsClass() notifier = DummyNotifier() maintainer = DummyNotifier() graph = create_graph( self.observer, DummyObserver( notify=True, notifier=notifier, maintainer=maintainer, ), DummyObserver(), # to get maintainer in ) call_add_or_remove_notifiers( object=instance, handler=instance.dummy_method, target=instance, graph=graph, remove=False, ) # when instance.add_trait("good_name", Str()) # then # the maintainer will have added a notifier because notify flag # is set to true on the single observer being maintained. notifiers = instance._trait("good_name", 2)._notifiers(True) self.assertIn(notifier, notifiers) self.assertIn(maintainer, notifiers) # when instance.add_trait("bad_name", Str()) # then notifiers = instance._trait("bad_name", 2)._notifiers(True) self.assertNotIn(notifier, notifiers) self.assertNotIn(maintainer, notifiers) def test_maintainer_keep_notify_flag(self): # Test the maintainer will maintain the notify flag for the root # observer in the subgraph. instance = DummyHasTraitsClass() notifier = DummyNotifier() graph = create_graph( self.observer, DummyObserver( notify=False, notifier=notifier, ), ) handler = mock.Mock() call_add_or_remove_notifiers( object=instance, handler=handler, target=instance, graph=graph, remove=False, ) # when instance.add_trait("good_name", Str()) # then # notify flag is set to false, so there are no notifiers added. notifiers = instance._trait("good_name", 2)._notifiers(True) self.assertNotIn(notifier, notifiers) traits-6.3.2/traits/observation/tests/test_trait_change_event.py000066400000000000000000000033611414270267200253050ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.has_traits import HasTraits from traits.trait_types import Int from traits.observation._trait_change_event import ( trait_event_factory, TraitChangeEvent, ) class TestTraitChangeEvent(unittest.TestCase): """ Test initialization and repr of TraitChangeEvent. """ def test_trait_change_event_repr(self): event = TraitChangeEvent( object=None, name="name", old=1, new=2, ) actual = repr(event) self.assertEqual( actual, "TraitChangeEvent(object=None, name='name', old=1, new=2)" ) class TestTraitEventFactory(unittest.TestCase): """ Test event factory compatibility with CTrait.""" def test_trait_change_notification_compat(self): class Foo(HasTraits): number = Int() events = [] def notifier(*args, **kwargs): event = trait_event_factory(*args, **kwargs) events.append(event) foo = Foo(number=0) trait = foo.trait("number") trait._notifiers(True).append(notifier) # when foo.number += 1 # then event, = events self.assertIs(event.object, foo) self.assertEqual(event.name, "number") self.assertEqual(event.old, 0) self.assertEqual(event.new, 1) traits-6.3.2/traits/observation/tests/test_trait_event_notifier.py000066400000000000000000000370211414270267200256770ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from unittest import mock import weakref from traits.observation.exception_handling import ( pop_exception_handler, push_exception_handler, ) from traits.observation.exceptions import NotifierNotFound from traits.observation._trait_event_notifier import TraitEventNotifier def dispatch_here(function, event): """ Dispatcher that let the function call through.""" function(event) def not_prevent_event(event): """ An implementation of prevent_event that does not prevent any event from being propagated. """ return False class DummyObservable: """ Dummy implementation of IObservable for testing purposes. """ def __init__(self): self.notifiers = [] def _notifiers(self, force_create): return self.notifiers def handler(self, event): pass # Dummy target object that is not garbage collected while the tests are run. _DUMMY_TARGET = mock.Mock() def create_notifier(**kwargs): """ Convenient function for creating an instance of TraitEventNotifier for testing purposes. """ values = dict( handler=mock.Mock(), target=_DUMMY_TARGET, event_factory=mock.Mock(), prevent_event=not_prevent_event, dispatcher=dispatch_here, ) values.update(kwargs) return TraitEventNotifier(**values) class TestTraitEventNotifierCall(unittest.TestCase): """ Test calling an instance of TraitEventNotifier. """ def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def tearDown(self): pass def test_init_and_call(self): handler = mock.Mock() def event_factory(*args, **kwargs): return "Event" notifier = create_notifier( handler=handler, event_factory=event_factory, ) # when notifier(a=1, b=2) # then self.assertEqual(handler.call_count, 1) (args, _), = handler.call_args_list self.assertEqual(args, ("Event", )) def test_alternative_dispatcher(self): # Test the dispatch is used events = [] def dispatcher(handler, *args): event, = args events.append(event) def event_factory(*args, **kwargs): return "Event" notifier = create_notifier( dispatcher=dispatcher, event_factory=event_factory, ) # when notifier(a=1, b=2) # then self.assertEqual(events, ["Event"]) def test_prevent_event_is_used(self): # Test prevent_event can stop an event from being dispatched. def prevent_event(event): return True handler = mock.Mock() notifier = create_notifier( handler=handler, prevent_event=prevent_event, ) # when notifier(a=1, b=2) # then handler.assert_not_called() def test_init_check_handler_is_callable_early(self): # Early sanity check to capture misuse not_a_callable = None with self.assertRaises(ValueError) as exception_cm: create_notifier(handler=not_a_callable) self.assertEqual( str(exception_cm.exception), "handler must be a callable, got {!r}".format(not_a_callable) ) class TestTraitEventNotifierException(unittest.TestCase): """ Test the default exception handling without pushing and popping exception handlers. """ def test_capture_exception(self): # Any exception from the handler will be captured and # logged. This is such that failure in one handler # does not prevent other notifiers to be called. # sanity check # there are no exception handlers with self.assertRaises(IndexError): pop_exception_handler() def misbehaving_handler(event): raise ZeroDivisionError("lalalala") notifier = create_notifier(handler=misbehaving_handler) # when with self.assertLogs("traits", level="ERROR") as log_exception: notifier(a=1, b=2) # then content, = log_exception.output self.assertIn( "Exception occurred in traits notification handler", content, ) # The tracback should be included self.assertIn("ZeroDivisionError", content) class TestTraitEventNotifierEqual(unittest.TestCase): """ Test comparing two instances of TraitEventNotifier. """ def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def tearDown(self): pass def test_equals_use_handler_and_target(self): # Check the notifier can identify an equivalence # using the handler and the target handler1 = mock.Mock() handler2 = mock.Mock() target1 = mock.Mock() target2 = mock.Mock() dispatcher = dispatch_here notifier1 = create_notifier( handler=handler1, target=target1, dispatcher=dispatcher) notifier2 = create_notifier( handler=handler1, target=target1, dispatcher=dispatcher) notifier3 = create_notifier( handler=handler1, target=target2, dispatcher=dispatcher) notifier4 = create_notifier( handler=handler2, target=target1, dispatcher=dispatcher) # then self.assertTrue( notifier1.equals(notifier2), "The two notifiers should consider each other as equal." ) self.assertTrue( notifier2.equals(notifier1), "The two notifiers should consider each other as equal." ) self.assertFalse( notifier3.equals(notifier1), "Expected the notifiers to be different because targets are " "not identical." ) self.assertFalse( notifier4.equals(notifier1), "Expected the notifiers to be different because the handlers " "do not compare equally." ) def test_equality_check_with_instance_methods(self): # Methods are descriptors and need to be compared with care. instance = DummyObservable() target = mock.Mock() notifier1 = create_notifier(handler=instance.handler, target=target) notifier2 = create_notifier(handler=instance.handler, target=target) self.assertTrue(notifier1.equals(notifier2)) self.assertTrue(notifier2.equals(notifier1)) def test_equals_compared_to_different_type(self): notifier = create_notifier() self.assertFalse(notifier.equals(float)) def test_not_equal_if_dispatcher_different(self): handler = mock.Mock() target = mock.Mock() dispatcher1 = mock.Mock() dispatcher2 = mock.Mock() notifier1 = create_notifier( handler=handler, target=target, dispatcher=dispatcher1) notifier2 = create_notifier( handler=handler, target=target, dispatcher=dispatcher2) # then self.assertFalse( notifier1.equals(notifier2), "Expected the notifiers to be different because the dispatchers " "do not compare equally." ) self.assertFalse( notifier2.equals(notifier1), "Expected the notifiers to be different because the dispatchers " "do not compare equally." ) class TestTraitEventNotifierAddRemove(unittest.TestCase): """ Test TraitEventNotifier capability of adding/removing itself to/from an observable. """ def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def tearDown(self): pass def test_add_to_observable(self): # It is typical that the observable also has other # "notifiers" unknown to the TraitEventNotifier dummy = DummyObservable() dummy.notifiers = [str, float] notifier = create_notifier() # when notifier.add_to(dummy) # then self.assertEqual(dummy.notifiers, [str, float, notifier]) def test_add_to_observable_twice_increase_count(self): # Test trying to add the "same" notifier results in # the existing notifier bumping its own reference # count. dummy = DummyObservable() def handler(event): pass notifier1 = create_notifier(handler=handler, target=_DUMMY_TARGET) notifier2 = create_notifier(handler=handler, target=_DUMMY_TARGET) # when notifier1.add_to(dummy) notifier2.add_to(dummy) # then self.assertEqual(dummy.notifiers, [notifier1]) self.assertEqual(notifier1._ref_count, 2) def test_add_to_observable_different_notifier(self): dummy = DummyObservable() def handler(event): pass notifier1 = create_notifier(handler=handler, target=_DUMMY_TARGET) # The target is different! notifier2 = create_notifier(handler=handler, target=dummy) # when notifier1.add_to(dummy) notifier2.add_to(dummy) # then self.assertEqual(dummy.notifiers, [notifier1, notifier2]) def test_remove_from_observable(self): # Test creating two equivalent notifiers. # The second notifier is able to remove the first one # from the observable as if the first one was itself. dummy = DummyObservable() def handler(event): pass notifier1 = create_notifier(handler=handler, target=_DUMMY_TARGET) notifier2 = create_notifier(handler=handler, target=_DUMMY_TARGET) # when notifier1.add_to(dummy) self.assertEqual(dummy.notifiers, [notifier1]) notifier2.remove_from(dummy) # then self.assertEqual(dummy.notifiers, []) def test_remove_from_observable_with_ref_count(self): # Test reference counting logic in remove_from dummy = DummyObservable() def handler(event): pass notifier1 = create_notifier(handler=handler, target=_DUMMY_TARGET) notifier2 = create_notifier(handler=handler, target=_DUMMY_TARGET) # when # add_to is called twice. notifier1.add_to(dummy) notifier1.add_to(dummy) self.assertEqual(dummy.notifiers, [notifier1]) # when # removing it once notifier2.remove_from(dummy) # then self.assertEqual(dummy.notifiers, [notifier1]) # when # removing it the second time notifier2.remove_from(dummy) # then # will remove the callable. self.assertEqual(dummy.notifiers, []) def test_remove_from_error_if_not_found(self): dummy = DummyObservable() notifier1 = create_notifier() with self.assertRaises(NotifierNotFound) as e: notifier1.remove_from(dummy) self.assertEqual(str(e.exception), "Notifier not found.") def test_remove_from_differentiate_not_equal_notifier(self): dummy = DummyObservable() notifier1 = create_notifier(handler=mock.Mock()) # The handler is different notifier2 = create_notifier(handler=mock.Mock()) # when notifier1.add_to(dummy) notifier2.add_to(dummy) notifier2.remove_from(dummy) # then self.assertEqual(dummy.notifiers, [notifier1]) def test_add_to_multiple_observables(self): # This is a use case we don't have but we want to guard # against for now. dummy1 = DummyObservable() dummy2 = DummyObservable() notifier = create_notifier() # when notifier.add_to(dummy1) # then with self.assertRaises(RuntimeError) as exception_context: notifier.add_to(dummy2) self.assertEqual( str(exception_context.exception), "Sharing notifiers across observables is unexpected." ) class TestTraitEventNotifierWeakrefTarget(unittest.TestCase): """ Test weakref handling for target in TraitEventNotifier.""" def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def tearDown(self): pass def test_notifier_does_not_prevent_object_deletion(self): # Typical use case: target is an instance of HasTraits # and the notifier is attached to an internal object # inside the target. # The reverse reference to target should not prevent # the target from being garbage collected when not in use. target = DummyObservable() target.internal_object = DummyObservable() target_ref = weakref.ref(target) notifier = create_notifier(target=target) notifier.add_to(target.internal_object) # when del target # then self.assertIsNone(target_ref()) def test_callable_disabled_if_target_removed(self): target = mock.Mock() handler = mock.Mock() notifier = create_notifier(handler=handler, target=target) # sanity check notifier(a=1, b=2) self.assertEqual(handler.call_count, 1) handler.reset_mock() # when del target # then notifier(a=1, b=2) handler.assert_not_called() class TestTraitEventNotifierWeakrefHandler(unittest.TestCase): """ Test weakref handling for handler in TraitEventNotifier.""" def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def tearDown(self): pass def test_method_as_handler_does_not_prevent_garbage_collect(self): # It is a typical use case that the handler is a method # of an object. # The reference to such a handler should not prevent the # object from being garbage collected. dummy = DummyObservable() dummy.internal_object = DummyObservable() dummy_ref = weakref.ref(dummy) notifier = create_notifier(handler=dummy.handler) notifier.add_to(dummy.internal_object) # when del dummy # then self.assertIsNone(dummy_ref()) def test_callable_disabled_if_handler_deleted(self): dummy = DummyObservable() dummy.internal_object = DummyObservable() event_factory = mock.Mock() notifier = create_notifier( handler=dummy.handler, event_factory=event_factory) notifier.add_to(dummy.internal_object) # sanity check notifier(a=1, b=2) self.assertEqual(event_factory.call_count, 1) event_factory.reset_mock() # when del dummy # then notifier(a=1, b=2) event_factory.assert_not_called() def test_reference_held_when_dispatching(self): # Test when the notifier proceeds to fire, it holds a # strong reference to the handler dummy = DummyObservable() def event_factory(*args, **kwargs): nonlocal dummy del dummy notifier = create_notifier( handler=dummy.handler, event_factory=event_factory, ) notifier.add_to(dummy) notifier(a=1, b=2) traits-6.3.2/traits/testing/000077500000000000000000000000001414270267200160205ustar00rootroot00000000000000traits-6.3.2/traits/testing/__init__.py000066400000000000000000000010711414270267200201300ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Scripts and assert tools related to running unit tests. These scripts also allow running test suites in separate processes and aggregating the results. """ traits-6.3.2/traits/testing/api.py000066400000000000000000000010461414270267200171440ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from .doctest_tools import doctest_for_module from .nose_tools import deprecated, performance, skip from .unittest_tools import UnittestTools traits-6.3.2/traits/testing/doctest_tools.py000066400000000000000000000041221414270267200212560ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tools for having doctest and unittest work together more nicely. Eclipse's PyDev plugin will run your unittest files for you very nicely. The doctest_for_module function allows you to easily run the doctest for a module along side your standard unit tests within Eclipse. """ # Standard library imports import doctest import unittest def doctest_for_module(module): """ Create a TestCase from a module's doctests that will be run by the standard unittest.main(). Example tests/test_foo.py:: import unittest import foo from traits.testing.api import doctest_for_module class FooTestCase(unittest.TestCase): ... class FooDocTest(doctest_for_module(foo)): pass if __name__ == "__main__": # This will run and report both FooTestCase and the doctests in # module foo. unittest.main() Alternatively, you can say:: FooDocTest = doctest_for_module(foo) instead of:: class FooDocTest(doctest_for_module(foo)): pass """ class C(unittest.TestCase): def test_dummy(self): pass # Make the test case loader find us def run(self, result=None): # doctest doesn't like nose.result.TextTestResult objects, # so we try to determine if thats what we're dealing # with and use its internal result attribute instead if hasattr(result, "result"): doctest.DocTestSuite(module).run(result.result) else: doctest.DocTestSuite(module).run(result) return C traits-6.3.2/traits/testing/nose_tools.py000066400000000000000000000054441414270267200205650ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Non-standard functions for the 'nose' testing framework This module is deprecated, and will be removed in a future release. .. deprecated:: 6.1.0 """ import warnings try: from nose import DeprecatedTest, SkipTest from nose.tools import make_decorator def skip(f): """ Decorator to indicate a test should be skipped. .. deprecated:: 6.1.0 """ warnings.warn( "The traits.testing.nose_tools module and its contents " "are deprecated", DeprecationWarning, stacklevel=2, ) def g(*args, **kw): raise SkipTest() return make_decorator(f)(g) def deprecated(f): """ Decorator to indicate a test is deprecated. .. deprecated:: 6.1.0 """ warnings.warn( "The traits.testing.nose_tools module and its contents " "are deprecated", DeprecationWarning, stacklevel=2, ) def g(*args, **kw): raise DeprecatedTest() return make_decorator(f)(g) except ImportError: # Define stubs in case nose isn't installed. def skip(f): """ Stub replacement for marking a unit test to be skipped in the absence of 'nose'. .. deprecated:: 6.1.0 """ warnings.warn( "The traits.testing.nose_tools module and its contents " "are deprecated", DeprecationWarning, stacklevel=2, ) warnings.warn("skipping unit tests requires the package 'nose'") return f def deprecated(f): """ Stub replacement for marking a unit test deprecated in the absence of 'nose'. .. deprecated:: 6.1.0 """ warnings.warn( "The traits.testing.nose_tools module and its contents " "are deprecated", DeprecationWarning, stacklevel=2, ) warnings.warn( "skipping deprecated unit tests requires the package 'nose'" ) return f def performance(f): """ Decorator to add an attribute to the test to mark it as a performance-measuring test. .. deprecated:: 6.1.0 """ warnings.warn( "The traits.testing.nose_tools module and its contents " "are deprecated", DeprecationWarning, stacklevel=2, ) f.performance = True return f traits-6.3.2/traits/testing/optional_dependencies.py000066400000000000000000000035561414270267200227360ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import importlib import unittest def optional_import(name): """ Optionally import a module, returning None if that module is unavailable. Parameters ---------- name : Str The name of the module being imported. Returns ------- None or module None if the module is not available, and the module otherwise. """ try: module = importlib.import_module(name) except ImportError: return None else: return module # Commonly-used unittest skip decorators. cython = optional_import("cython") requires_cython = unittest.skipIf(cython is None, "Cython not available") mypy = optional_import("mypy") requires_mypy = unittest.skipIf(mypy is None, "Mypy not available") numpy = optional_import("numpy") requires_numpy = unittest.skipIf(numpy is None, "NumPy not available") pkg_resources = optional_import("pkg_resources") requires_pkg_resources = unittest.skipIf( pkg_resources is None, "pkg_resources not available" ) pyface = optional_import("pyface") requires_pyface = unittest.skipIf(pyface is None, "Pyface not available") sphinx = optional_import("sphinx") requires_sphinx = unittest.skipIf(sphinx is None, "Sphinx not available") traitsui = optional_import("traitsui") requires_traitsui = unittest.skipIf(traitsui is None, "TraitsUI not available") # Import traitsui.api so that client code can use traitsui.api directly without # an extra import. if traitsui is not None: import traitsui.api traits-6.3.2/traits/testing/tests/000077500000000000000000000000001414270267200171625ustar00rootroot00000000000000traits-6.3.2/traits/testing/tests/__init__.py000066400000000000000000000000001414270267200212610ustar00rootroot00000000000000traits-6.3.2/traits/testing/tests/test_nose_tools.py000066400000000000000000000022761414270267200227660ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.testing.nose_tools import deprecated, performance, skip class TestNoseTools(unittest.TestCase): def test_deprecated_deprecated(self): with self.assertWarns(DeprecationWarning) as cm: @deprecated def some_func(): pass self.assertIn("test_nose_tools", cm.filename) def test_performance_deprecated(self): with self.assertWarns(DeprecationWarning) as cm: @performance def some_func(): pass self.assertIn("test_nose_tools", cm.filename) def test_skip_deprecated(self): with self.assertWarns(DeprecationWarning) as cm: @skip def some_func(): pass self.assertIn("test_nose_tools", cm.filename) traits-6.3.2/traits/testing/tests/test_optional_dependencies.py000066400000000000000000000014361414270267200251320ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.testing.optional_dependencies import optional_import class TestImportHandler(unittest.TestCase): def test_import_succeeds(self): module = optional_import("itertools") self.assertEqual(module.__name__, "itertools") def test_import_fails(self): module = optional_import("unavailable_module") self.assertIsNone(module) traits-6.3.2/traits/testing/tests/test_unittest_tools.py000066400000000000000000000345521414270267200237030ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import threading import time import warnings from traits.api import ( Bool, Event, Float, HasTraits, Int, List, on_trait_change, ) from traits.testing.api import UnittestTools # unittest_tools provides a reference to unittest for historical reasons, and # downstream packages may still be doing "from traits.testing.unittest_tools # import unittest". We keep this import as-is (instead of doing a simple # "import unittest") to make sure we don't break those packages. from traits.testing.unittest_tools import unittest from traits.util.api import deprecated @deprecated("This function is outdated. Use 'shiny' instead!") def old_and_dull(): """ A deprecated function, for use in assertDeprecated tests. """ pass class TestObject(HasTraits): number = Float(2.0) list_of_numbers = List(Float) flag = Bool @on_trait_change("number") def _add_number_to_list(self, value): self.list_of_numbers.append(value) def add_to_number(self, value): self.number += value class UnittestToolsTestCase(unittest.TestCase, UnittestTools): def setUp(self): self.test_object = TestObject() def test_when_using_with(self): """ Check normal use cases as a context manager. """ test_object = self.test_object # Change event should NOT BE detected with self.assertTraitDoesNotChange(test_object, "number") as result: test_object.flag = True test_object.number = 2.0 msg = "The assertion result is not None: {0}".format(result.event) self.assertIsNone(result.event, msg=msg) # Change event should BE detected with self.assertTraitChanges(test_object, "number") as result: test_object.flag = False test_object.number = 5.0 expected = (test_object, "number", 2.0, 5.0) self.assertSequenceEqual(expected, result.event) # Change event should BE detected exactly 2 times with self.assertTraitChanges(test_object, "number", count=2) as result: test_object.flag = False test_object.number = 4.0 test_object.number = 3.0 expected = [ (test_object, "number", 5.0, 4.0), (test_object, "number", 4.0, 3.0), ] self.assertSequenceEqual(expected, result.events) self.assertSequenceEqual(expected[-1], result.event) # Change event should BE detected with self.assertTraitChanges(test_object, "number") as result: test_object.flag = True test_object.add_to_number(10.0) expected = (test_object, "number", 3.0, 13.0) self.assertSequenceEqual(expected, result.event) # Change event should BE detected exactly 3 times with self.assertTraitChanges(test_object, "number", count=3) as result: test_object.flag = True test_object.add_to_number(10.0) test_object.add_to_number(10.0) test_object.add_to_number(10.0) expected = [ (test_object, "number", 13.0, 23.0), (test_object, "number", 23.0, 33.0), (test_object, "number", 33.0, 43.0), ] self.assertSequenceEqual(expected, result.events) self.assertSequenceEqual(expected[-1], result.event) def test_assert_multi_changes(self): test_object = self.test_object # Change event should NOT BE detected with self.assertMultiTraitChanges( [test_object], [], ["flag", "number", "list_of_numbers[]"] ) as results: test_object.number = 2.0 events = list(filter(bool, (result.event for result in results))) msg = "The assertion result is not None: {0}".format(", ".join(events)) self.assertFalse(events, msg=msg) # Change event should BE detected with self.assertMultiTraitChanges( [test_object], ["number", "list_of_numbers[]"], ["flag"] ) as results: test_object.number = 5.0 events = list(filter(bool, (result.event for result in results))) msg = "The assertion result is None" self.assertTrue(events, msg=msg) def test_when_using_functions(self): test_object = self.test_object # Change event should BE detected self.assertTraitChanges( test_object, "number", 1, test_object.add_to_number, 13.0 ) # Change event should NOT BE detected self.assertTraitDoesNotChange( test_object, "flag", test_object.add_to_number, 13.0 ) def test_indirect_events(self): """ Check catching indirect change events. """ test_object = self.test_object # Change event should BE detected with self.assertTraitChanges( test_object, "list_of_numbers[]" ) as result: test_object.flag = True test_object.number = -3.0 expected = (test_object, "list_of_numbers_items", [], [-3.0]) self.assertSequenceEqual(expected, result.event) def test_exception_inside_context(self): """ Check that exception inside the context statement block are propagated. """ test_object = self.test_object with self.assertRaises(AttributeError): with self.assertTraitChanges(test_object, "number"): test_object.i_do_exist with self.assertRaises(AttributeError): with self.assertTraitDoesNotChange(test_object, "number"): test_object.i_do_exist def test_non_change_on_failure(self): """ Check behaviour when assertion should be raised for non trait change. """ test_object = self.test_object traits = "flag, number" with self.assertRaises(AssertionError): with self.assertTraitDoesNotChange(test_object, traits) as result: test_object.flag = True test_object.number = -3.0 expected = [ (test_object, "flag", False, True), (test_object, "number", 2.0, -3.0), ] self.assertEqual(result.events, expected) def test_change_on_failure(self): """ Check behaviour when assertion should be raised for trait change. """ test_object = self.test_object with self.assertRaises(AssertionError): with self.assertTraitChanges(test_object, "number") as result: test_object.flag = True self.assertEqual(result.events, []) # Change event will not be fired 3 times with self.assertRaises(AssertionError): with self.assertTraitChanges( test_object, "number", count=3 ) as result: test_object.flag = True test_object.add_to_number(10.0) test_object.add_to_number(10.0) expected = [ (test_object, "number", 2.0, 12.0), (test_object, "number", 12.0, 22.0), ] self.assertSequenceEqual(expected, result.events) def test_asserts_in_context_block(self): """ Make sure that the traits context manager does not stop regular assertions inside the managed code block from happening. """ test_object = TestObject(number=16.0) with self.assertTraitDoesNotChange(test_object, "number"): self.assertEqual(test_object.number, 16.0) with self.assertRaisesRegex(AssertionError, r"16\.0 != 12\.0"): with self.assertTraitDoesNotChange(test_object, "number"): self.assertEqual(test_object.number, 12.0) def test_special_case_for_count(self): """ Count equal to 0 should be valid but it is discouraged. """ test_object = TestObject(number=16.0) with self.assertTraitChanges(test_object, "number", count=0): test_object.flag = True def test_assert_trait_changes_async(self): # Exercise assertTraitChangesAsync. thread_count = 10 events_per_thread = 1000 class A(HasTraits): event = Event a = A() def thread_target(obj, count): "Fire obj.event 'count' times." for _ in range(count): obj.event = True threads = [ threading.Thread(target=thread_target, args=(a, events_per_thread)) for _ in range(thread_count) ] expected_count = thread_count * events_per_thread with self.assertTraitChangesAsync( a, "event", expected_count, timeout=60.0 ): for t in threads: t.start() for t in threads: t.join() def test_assert_trait_changes_async_events(self): # Check access to the events after the with # block completes. thread_count = 10 events_per_thread = 100 class A(HasTraits): event = Event(Int) a = A() def thread_target(obj, count): "Fire obj.event 'count' times." for n in range(count): time.sleep(0.001) obj.event = n threads = [ threading.Thread(target=thread_target, args=(a, events_per_thread)) for _ in range(thread_count) ] expected_count = thread_count * events_per_thread with self.assertTraitChangesAsync( a, "event", expected_count, timeout=60.0 ) as event_collector: for t in threads: t.start() for t in threads: t.join() self.assertCountEqual( event_collector.events, list(range(events_per_thread)) * thread_count, ) def test_assert_trait_changes_async_failure(self): # Exercise assertTraitChangesAsync. thread_count = 10 events_per_thread = 10000 class A(HasTraits): event = Event a = A() def thread_target(obj, count): "Fire obj.event 'count' times." for _ in range(count): obj.event = True threads = [ threading.Thread(target=thread_target, args=(a, events_per_thread)) for _ in range(thread_count) ] expected_count = thread_count * events_per_thread with self.assertRaises(AssertionError): with self.assertTraitChangesAsync(a, "event", expected_count + 1): for t in threads: t.start() for t in threads: t.join() def test_assert_eventually_true_fails_on_timeout(self): class A(HasTraits): foo = Bool(False) a = A() def condition(a_object): return a_object.foo with self.assertRaises(self.failureException): self.assertEventuallyTrue( condition=condition, obj=a, trait="foo", timeout=1.0 ) def test_assert_eventually_true_passes_when_condition_becomes_true(self): class A(HasTraits): foo = Bool(False) def condition(a_object): return a_object.foo a = A() def thread_target(a): time.sleep(1.0) a.foo = True t = threading.Thread(target=thread_target, args=(a,)) t.start() self.assertEventuallyTrue( condition=condition, obj=a, trait="foo", timeout=10.0 ) t.join() def test_assert_eventually_true_passes_when_condition_starts_true(self): class A(HasTraits): foo = Bool(True) def condition(a_object): return a_object.foo a = A() self.assertEventuallyTrue( condition=condition, obj=a, trait="foo", timeout=10.0 ) def test_assert_deprecated(self): with self.assertDeprecated(): old_and_dull() def test_assert_deprecated_failures(self): with self.assertRaises(self.failureException): with self.assertDeprecated(): pass def test_assert_deprecated_when_warning_already_issued(self): # Exercise a problematic case where previous calls to a function or # method that issues a DeprecationWarning have already polluted the # __warningregistry__. For this, we need a single call-point to # old_and_dull, since distinct call-points have separate entries in # __warningregistry__. def old_and_dull_caller(): old_and_dull() with warnings.catch_warnings(record=True): warnings.simplefilter("always", DeprecationWarning) # Pollute the registry by pre-calling the function. old_and_dull_caller() # Check that we can still detect the DeprecationWarning. with self.assertDeprecated(): old_and_dull_caller() def test_assert_not_deprecated_failures(self): with self.assertRaises(self.failureException): with self.assertNotDeprecated(): old_and_dull() def test_assert_not_deprecated(self): with self.assertNotDeprecated(): pass def test_assert_not_deprecated_when_warning_already_issued(self): # Exercise a problematic case where previous calls to a function or # method that issues a DeprecationWarning have already polluted the # __warningregistry__. For this, we need a single call-point to # old_and_dull, since distinct call-points have separate entries in # __warningregistry__. def old_and_dull_caller(): old_and_dull() with warnings.catch_warnings(record=True): warnings.simplefilter("always", DeprecationWarning) # Pollute the registry by pre-calling the function. old_and_dull_caller() # Check that we can still detect the DeprecationWarning. with self.assertRaises(self.failureException): with self.assertNotDeprecated(): old_and_dull_caller() def test__catch_warnings_deprecated(self): with self.assertWarns(DeprecationWarning): with self._catch_warnings(): pass traits-6.3.2/traits/testing/unittest_tools.py000066400000000000000000000426351414270267200215030ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Trait assert mixin class to simplify test implementation for Trait Classes. """ import contextlib import threading import sys import warnings # Support for 'from traits.testing.unittest_tools import unittest', # which was used to make unittest2 available under the name unittest # on Python 2.6. We keep the import for now, for backwards compatibility. import unittest # noqa: F401 from traits.api import ( Any, Event, HasStrictTraits, Int, List, Str, Property, ) from traits.util.async_trait_wait import wait_for_condition class _AssertTraitChangesContext(object): """ A context manager used to implement the trait change assert methods. Notes ----- Checking if the provided xname corresponds to valid traits in the class is not implemented yet. Parameters ---------- obj : HasTraits The HasTraits class instance whose class trait will change. xname : str The extended trait name of trait changes to listen to. count : int, optional The expected number of times the event should be fired. When None (default value) there is no check for the number of times the change event was fired. test_case : TestCase A unittest TestCase where to raise the failureException if necessary. Attributes ---------- obj : HasTraits The HasTraits class instance whose class trait will change. xname : str The extended trait name of trait changes to listen to. count : int, optional The expected number of times the event should be fired. When None (default value) there is no check for the number of times the change event was fired. events : list of tuples A list with tuple elements containing the arguments of an `on_trait_change` event signature (, , , ). Raises ------ AssertionError : When the desired number of trait changed did not take place or when `count = None` and no trait change took place. """ def __init__(self, obj, xname, count, test_case): self.obj = obj self.xname = xname self.count = count self.event = None self.events = [] self.failureException = test_case.failureException def _listener(self, obj, name, old, new): """ Dummy trait listener. """ self.event = (obj, name, old, new) self.events.append(self.event) def __enter__(self): """ Bind the trait listener. """ self.obj.on_trait_change(self._listener, self.xname) return self def __exit__(self, exc_type, exc_value, tb): """ Remove the trait listener. """ if exc_type is not None: return False self.obj.on_trait_change(self._listener, self.xname, remove=True) if self.count is not None and len(self.events) != self.count: msg = "Change event for {0} was fired {1} times instead of {2}" items = self.xname, len(self.events), self.count raise self.failureException(msg.format(*items)) elif self.count is None and not self.events: msg = "A change event was not fired for: {0}".format(self.xname) raise self.failureException(msg) return False @contextlib.contextmanager def reverse_assertion(context, msg): context.__enter__() try: yield context finally: try: context.__exit__(None, None, None) except AssertionError: pass else: raise context.failureException(msg) class _TraitsChangeCollector(HasStrictTraits): """ Class allowing thread-safe recording of events. """ # The object we're listening to. obj = Any # The (possibly extended) trait name(s). trait_name = Str # Read-only event count. event_count = Property(Int) # Event that's triggered when the event count is updated. event_count_updated = Event # Private list of events. events = List(Any) # Private lock used to allow access to events by multiple threads # simultaneously. _lock = Any() def __init__(self, **traits): if "trait" in traits: value = traits.pop("trait") message = ( "The `trait` keyword is deprecated." " please use `trait_name`" ) warnings.warn(message, DeprecationWarning, stacklevel=2) traits["trait_name"] = value super().__init__(**traits) # We assign the lock eagerly rather than depending on a lazy default, # since we want to be sure that the lock is created (a) only once, # and (b) on the main thread. Similarly for the events list. self._lock = threading.Lock() self.events = [] def start_collecting(self): self.obj.on_trait_change(self._event_handler, self.trait_name) def stop_collecting(self): self.obj.on_trait_change( self._event_handler, self.trait_name, remove=True ) def _event_handler(self, new): with self._lock: self.events.append(new) self.event_count_updated = True def _get_event_count(self): """ Traits property getter. Thread-safe access to event count. """ with self._lock: return len(self.events) class UnittestTools(object): """ Mixin class to augment the unittest.TestCase class with useful trait related assert methods. """ def assertTraitChanges( self, obj, trait, count=None, callableObj=None, *args, **kwargs ): """ Assert an object trait changes a given number of times. Assert that the class trait changes exactly `count` times during execution of the provided function. This method can also be used in a with statement to assert that a class trait has changed during the execution of the code inside the with statement (similar to the assertRaises method). Please note that in that case the context manager returns itself and the user can introspect the information of: - The last event fired by accessing the ``event`` attribute of the returned object. - All the fired events by accessing the ``events`` attribute of the return object. Note that in the case of chained properties (trait 'foo' depends on 'bar', which in turn depends on 'baz'), the order in which the corresponding trait events appear in the ``events`` attribute is not well-defined, and may depend on dictionary ordering. **Example**:: class MyClass(HasTraits): number = Float(2.0) my_class = MyClass() with self.assertTraitChanges(my_class, 'number', count=1): my_class.number = 3.0 Parameters ---------- obj : HasTraits The HasTraits class instance whose class trait will change. trait : str The extended trait name of trait changes to listen to. count : int or None, optional The expected number of times the event should be fired. When None (default value) there is no check for the number of times the change event was fired. callableObj : callable, optional A callable object that will trigger the expected trait change. When None (default value) a trigger is expected to be called under the context manger returned by this method. *args : List of positional arguments for ``callableObj`` **kwargs : Dict of keyword value pairs to be passed to the ``callableObj`` Returns ------- context : context manager or None If ``callableObj`` is None, an assertion context manager is returned, inside of which a trait-change trigger can be invoked. Otherwise, the context is used internally with ``callableObj`` as the trigger, in which case None is returned. Notes ----- - Checking if the provided ``trait`` corresponds to valid traits in the class is not implemented yet. - Using the functional version of the assert method requires the ``count`` argument to be given even if it is None. """ context = _AssertTraitChangesContext(obj, trait, count, self) if callableObj is None: return context with context: callableObj(*args, **kwargs) def assertTraitDoesNotChange( self, obj, trait, callableObj=None, *args, **kwargs ): """ Assert an object trait does not change. Assert that the class trait does not change during execution of the provided function. Parameters ---------- obj : HasTraits The HasTraits class instance whose class trait will change. trait : str The extended trait name of trait changes to listen to. callableObj : callable, optional A callable object that should not trigger a change in the passed trait. When None (default value) a trigger is expected to be called under the context manger returned by this method. *args : List of positional arguments for ``callableObj`` **kwargs : Dict of keyword value pairs to be passed to the ``callableObj`` Returns ------- context : context manager or None If ``callableObj`` is None, an assertion context manager is returned, inside of which a trait-change trigger can be invoked. Otherwise, the context is used internally with ``callableObj`` as the trigger, in which case None is returned. """ msg = "A change event was fired for: {0}".format(trait) context = _AssertTraitChangesContext(obj, trait, None, self) if callableObj is None: return reverse_assertion(context, msg) with reverse_assertion(context, msg): callableObj(*args, **kwargs) @contextlib.contextmanager def assertMultiTraitChanges( self, objects, traits_modified, traits_not_modified ): """ Assert that traits on multiple objects do or do not change. This combines some of the functionality of `assertTraitChanges` and `assertTraitDoesNotChange`. Parameters ---------- objects : list of HasTraits The HasTraits class instances whose traits will change. traits_modified : list of str The extended trait names of trait expected to change. traits_not_modified : list of str The extended trait names of traits not expected to change. """ with contextlib.ExitStack() as exit_stack: cms = [] for obj in objects: for trait in traits_modified: cms.append(exit_stack.enter_context( self.assertTraitChanges(obj, trait))) for trait in traits_not_modified: cms.append(exit_stack.enter_context( self.assertTraitDoesNotChange(obj, trait))) yield tuple(cms) @contextlib.contextmanager def assertTraitChangesAsync(self, obj, trait, count=1, timeout=5.0): """ Assert an object trait eventually changes. Context manager used to assert that the given trait changes at least `count` times within the given timeout, as a result of execution of the body of the corresponding with block. The trait changes are permitted to occur asynchronously. **Example usage**:: with self.assertTraitChangesAsync(my_object, 'SomeEvent', count=4): Parameters ---------- obj : HasTraits The HasTraits class instance whose class trait will change. trait : str The extended trait name of trait changes to listen to. count : int, optional The expected number of times the event should be fired. timeout : float or None, optional The amount of time in seconds to wait for the specified number of changes. None can be used to indicate no timeout. """ collector = _TraitsChangeCollector(obj=obj, trait_name=trait) # Pass control to body of the with statement. collector.start_collecting() try: yield collector # Wait for the expected number of events to arrive. try: wait_for_condition( condition=lambda obj: obj.event_count >= count, obj=collector, trait="event_count_updated", timeout=timeout, ) except RuntimeError: actual_event_count = collector.event_count msg = ( "Expected {0} event on {1} to be fired at least {2} " "times, but the event was only fired {3} times " "before timeout ({4} seconds)." ).format(trait, obj, count, actual_event_count, timeout) self.fail(msg) finally: collector.stop_collecting() def assertEventuallyTrue(self, obj, trait, condition, timeout=5.0): """ Assert that the given condition is eventually true. Parameters ---------- obj : HasTraits The HasTraits class instance whose traits will change. trait : str The extended trait name of trait changes to listen to. condition : callable A function that will be called when the specified trait changes. This should accept ``obj`` and should return a Boolean indicating whether the condition is satisfied or not. timeout : float or None, optional The amount of time in seconds to wait for the condition to become true. None can be used to indicate no timeout. """ try: wait_for_condition( condition=condition, obj=obj, trait=trait, timeout=timeout ) except RuntimeError: # Helpful to know whether we timed out because the # condition never became true, or because the expected # event was never issued. condition_at_timeout = condition(obj) self.fail( "Timed out waiting for condition. " "At timeout, condition was {0}.".format(condition_at_timeout) ) @contextlib.contextmanager def _catch_warnings(self): """ Replacement for warnings.catch_warnings. This method wraps warnings.catch_warnings, takes care to reset the warning registry before entering the with context, and ensures that DeprecationWarnings are always emitted. The hack to reset the warning registry is no longer needed in Python 3.4 and later. See http://bugs.python.org/issue4180 for more background. .. deprecated:: 6.2 Use :func:`warnings.catch_warnings` instead. """ warnings.warn( ( "The _catch_warnings method is deprecated. " "Use warnings.catch_warnings instead." ), DeprecationWarning, ) # Ugly hack copied from the core Python code (see # Lib/test/test_support.py) to reset the warnings registry # for the module making use of this context manager. # # Note that this hack is unnecessary in Python 3.4 and later; see # http://bugs.python.org/issue4180 for the background. registry = sys._getframe(4).f_globals.get("__warningregistry__") if registry: registry.clear() with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", DeprecationWarning) yield w @contextlib.contextmanager def assertDeprecated(self): """ Assert that the code inside the with block is deprecated. Intended for testing uses of traits.util.deprecated.deprecated. """ with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", DeprecationWarning) yield w self.assertGreater( len(w), 0, msg="Expected a DeprecationWarning, " "but none was issued", ) @contextlib.contextmanager def assertNotDeprecated(self): """ Assert that the code inside the with block is not deprecated. Intended for testing uses of traits.util.deprecated.deprecated. """ with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", DeprecationWarning) yield w self.assertEqual( len(w), 0, msg="Expected no DeprecationWarning, " "but at least one was issued", ) traits-6.3.2/traits/tests/000077500000000000000000000000001414270267200155055ustar00rootroot00000000000000traits-6.3.2/traits/tests/__init__.py000066400000000000000000000007211414270267200176160ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # required by simple_test_case.py so it can do an import traits-6.3.2/traits/tests/check_observe_timing.py000066400000000000000000000424031414270267200222330ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Perform timing tests to compare the performance of on_trait_change and observe. For details on the varying scenarios see the description strings throughout the file. For the original motivation of this script, see the related issue: enthought/traits#1325 """ import textwrap import timeit # Number of iterations to perform: N = 10000 DECORATOR_SIMPLE_CASE_DESCRIPTION = """ Given a subclass of HasTraits with a trait defined, e.g. name = Str(), compare having a method with no decorator to one that is decorated with @on_trait_change("name"), one decorated with @observe("name"), and one with @observe(trait('name')). The timing we are interested in: (1) Time to import the module, i.e. the class construction. (2) Time to instantiate the HasTraits object. (3) Time for reassigning the trait to a new value. Times are reported as: (#): absolute_time relative_time_to_control """ # Code template strings to be timed for the simple decorator case # General setup not to be included in the timing. BASE_SETUP = textwrap.dedent(""" from traits.api import ( cached_property, HasTraits, Instance, observe, on_trait_change, Property, Str ) from traits.observation.api import trait """) # Construct HasTraits subclass with decorated method PERSON_CONSTRUCTION_TEMPLATE = textwrap.dedent(""" class Person(HasTraits): name = Str() {decorator} def some_method(self, event): pass """) # Instantiate the HasTraits subclass with decorated method INSTANTIATE_PERSON = textwrap.dedent(""" a_person = Person() """) # Update the trait being observed REASSIGN_NAME = textwrap.dedent(""" a_person.name = 'name' """) def get_decorated_method_simple_timing(decorator): """ Time the cases described by the decorator with simple trait case, using the given method decorator. Parameters ---------- decorator - Str The string defining the decorator to be used on the method of the HasTraits subclass. e.g. "@observe('name')" Returns ------- tuple A 3-tuple containing the time to construct the HasTraits subclass, the time to instantiate it, and the time to reassign the trait """ construct_person = PERSON_CONSTRUCTION_TEMPLATE.format(decorator=decorator) construction_time = timeit.timeit( stmt=construct_person, setup=BASE_SETUP, number=N ) instantiation_time = timeit.timeit( stmt=INSTANTIATE_PERSON, setup=BASE_SETUP + construct_person, number=N ) reassign_person_name_time = timeit.timeit( stmt=REASSIGN_NAME, setup=BASE_SETUP + construct_person + INSTANTIATE_PERSON, number=N ) return (construction_time, instantiation_time, reassign_person_name_time) DECORATOR_EXTENDED_CASE_DESCRIPTION = """ Given a subclass of HasTraits with a trait referring to an instance of HasTraits, e.g. child = Instance(AnotherClass) where AnotherClass has a name trait, compare having a method with no decorator to one that is decorated with @on_trait_change("child.name"), one decorated with @observe("child.name"), and one with @observe(trait('child').trait('name')). The timing we are interested in: (1) Time to import the module, i.e. the class construction. (2) Time to instantiate the HasTraits object. (3) Time for reassigning child to a new value. (4) Time for reassigning child.name to a new value. Times are reported as: (#): absolute_time relative_time_to_control """ # Code template strings to be timed for the decorated method with enxtended # trait case. # Setup for constructing subclass of HasTraits with a trait referring to an # instance of HasTraits CONSTRUCT_PARENT_SETUP = BASE_SETUP + textwrap.dedent(""" class Person(HasTraits): name = Str() """) # Construct subclass of HasTraits with a trait referring to an instance of # HasTraits with decorated method PARENT_CONSTRUCTION_TEMPLATE = textwrap.dedent(""" class Parent(HasTraits): child = Instance(Person) {decorator} def some_method(self, event): pass """) # Instantiate the class INSTANTIATE_PARENT = textwrap.dedent(""" a_parent = Parent(child=Person()) """) # Update the instance trait containing the trait being observed REASSIGN_CHILD = textwrap.dedent(""" a_parent.child = Person() """) # Update the trait being observed on the instance trait REASSIGN_CHILD_NAME = textwrap.dedent(""" a_parent.child.name = 'name' """) def get_decorated_method_extended_timing(decorator): """ Time the cases described by the decorated method with enxtended trait case, using the given method decorator. Parameters ---------- decorator - Str The string defining the decorator to be used on the method of the HasTraits subclass. e.g. "@observe('child.name')" Returns ------- tuple A 4-tuple containing the time to construct the HasTraits subclass, the time to instantiate it, the time to reassign child, and the time to reassign child.name """ construct_parent = PARENT_CONSTRUCTION_TEMPLATE.format( decorator=decorator ) construction_time = timeit.timeit( stmt=construct_parent, setup=CONSTRUCT_PARENT_SETUP, number=N ) instantiation_time = timeit.timeit( stmt=INSTANTIATE_PARENT, setup=CONSTRUCT_PARENT_SETUP + construct_parent, number=N ) reassign_child_time = timeit.timeit( stmt=REASSIGN_CHILD, setup=CONSTRUCT_PARENT_SETUP + construct_parent + INSTANTIATE_PARENT, number=N ) reassign_child_name_time = timeit.timeit( stmt=REASSIGN_CHILD_NAME, setup=CONSTRUCT_PARENT_SETUP + construct_parent + INSTANTIATE_PARENT, number=N ) return ( construction_time, instantiation_time, reassign_child_time, reassign_child_name_time ) PROPERTY_SIMPLE_CASE_DESCRIPTION = """ Given a subclass of HasTraits with a trait that is defined as Property that depends on a simple trait, compare having the Property be defined as Property(), Property(depends_on="name"), Property(observe="name"), and Property(observe=trait('name')). The timing we are interested in: (1) Time to import the module, i.e. the class construction. (2) Time to instantiate the HasTraits object. (3) Time for changing the trait being depended-on / observed. Times are reported as: (#): absolute_time relative_time_to_control """ CACHED_PROPERTY_SIMPLE_CASE_DESCRIPTION = """ Identical to the simple property case only using the @chached_property decorator on the property's getter method. The timing we are interested in: (1) Time to import the module, i.e. the class construction. (2) Time to instantiate the HasTraits object. (3) Time for changing the trait being depended-on / observed. Times are reported as: (#): absolute_time relative_time_to_control """ # Code template strings to be timed for the (cached) property depending on a # simple trait scenario. # Construct subclass of HasTraits with a trait that is defined as Property that # depends on a simple trait (with option include @cached_property) PERSON_WITH_PROPERTY_CONSTRUCTION_TEMPLATE = textwrap.dedent(""" class Person(HasTraits): name=Str() a_property = Property({}) {} def _get_a_property(self): return self.name """) def get_property_simple_timing(property_args, cached_property): """ Time the cases described by the (cached) property depending on a simple trait scenario. Whether or not the property is cached is based on the cached_property argument, and the given property_args argument is used in the Property trait defintion. Parameters ---------- property_args - Str The string defining the argument to be passed in the definition of the Property trait. e.g. "depends_on='name'" cached_property - Str The string that will be used to decorate the getter method of the Property. Expected to be either '' or '@cached_property'. Returns ------- tuple A 3-tuple containing the time to construct the HasTraits subclass, the time to instantiate it, and the time to reassign the trait being depended-on / observed. """ construct_person_with_property = \ PERSON_WITH_PROPERTY_CONSTRUCTION_TEMPLATE.format( property_args, cached_property ) construction_time = timeit.timeit( stmt=construct_person_with_property, setup=BASE_SETUP, number=N ) instantiation_time = timeit.timeit( stmt=INSTANTIATE_PERSON, setup=BASE_SETUP + construct_person_with_property, number=N ) reassign_dependee_name_time = timeit.timeit( stmt=REASSIGN_NAME, setup=BASE_SETUP + construct_person_with_property + INSTANTIATE_PERSON, number=N ) return (construction_time, instantiation_time, reassign_dependee_name_time) PROPERTY_EXTENDED_CASE_DESCRIPTION = """ Given a subclass of HasTraits with a trait that is defined as Property that depends on an extended trait, compare having the Property be defined as Property(), Property(depends_on="child.name"), Property(observe="child.name"), and Property(observe=trait('child').trait('name')). The timing we are interested in: (1) Time to import the module, i.e. the class construction. (2) Time to instantiate the HasTraits object. (3) Time for reassigning child to a new value. (4) Time for reassigning child.name to a new value. Times are reported as: (#): absolute_time relative_time_to_control """ CACHED_PROPERTY_EXTENDED_CASE_DESCRIPTION = """ Identical to the extended property case only using the @cached_property decorator on the property's getter method. The timing we are interested in: (1) Time to import the module, i.e. the class construction. (2) Time to instantiate the HasTraits object. (3) Time for reassigning child to a new value. (4) Time for reassigning child.name to a new value. Times are reported as: (#): absolute_time relative_time_to_control """ # Code template strings to be timed for the (cached) property depending on an # extended trait scenario. # Construct subclass of HasTraits with a trait that is defined as Property that # depends on an extended trait (with option to include @cached_property) PARENT_WITH_PROPERTY_CONSTRUCTION_TEMPLATE = textwrap.dedent(""" class Parent(HasTraits): child = Instance(Person) a_property = Property({}) {} def _get_a_property(self): return self.child.name """) def get_property_extended_timing(property_args, cached_property): """ Time the cases described by the (cached) property depending on an extended trait scenario. Wether or not the property is cached is determined by the cached_property argument, and the given property_args argument is used for the Property trait defintion. Parameters ---------- property_args - Str The string defining the argument to be passed in the definition of the Property trait. e.g. "depends_on='child.name'" cached_property - Str The string that will be used to decorate the getter method of the Property. Expected to be either '' or '@cached_property'. Returns ------- tuple A 4-tuple containing the time to construct the HasTraits subclass, the time to instantiate it, the time to reassign child, and the time to reassign child.name """ construct_parent_with_property = \ PARENT_WITH_PROPERTY_CONSTRUCTION_TEMPLATE.format( property_args, cached_property ) construction_time = timeit.timeit( stmt=construct_parent_with_property, setup=CONSTRUCT_PARENT_SETUP, number=N ) instantiation_time = timeit.timeit( stmt=INSTANTIATE_PARENT, setup=CONSTRUCT_PARENT_SETUP + construct_parent_with_property, number=N ) reassign_child_time = timeit.timeit( stmt=REASSIGN_CHILD, setup=( CONSTRUCT_PARENT_SETUP + construct_parent_with_property + INSTANTIATE_PARENT ), number=N ) reassign_child_name_time = timeit.timeit( stmt=REASSIGN_CHILD_NAME, setup=( CONSTRUCT_PARENT_SETUP + construct_parent_with_property + INSTANTIATE_PARENT ), number=N ) return ( construction_time, instantiation_time, reassign_child_time, reassign_child_name_time ) def report(description, benchmark_template, get_time, get_time_args): """ Prints a readable benchmark report. Parameters ---------- descritption : str The description of the benchmarking scenario being reported. benchmark_template : str The format string used to print the times for the benchmark in a clean, formatted way get_time : function The function used to get the benchmark times for the current benchmark scenario get_time_args : list of tuples The list of tuples containing the arguments to be passed the the get_time function. Note the first argument should give specifics about the case being timed and will be printed as part of the report. e.g. ("@observe('name')"), or ("depends_on='name'", '@cached_property'). The first item in the list will be used as a control. """ print(description) control_times = get_time(*get_time_args[0]) for index, args in enumerate(get_time_args): if index == 0: print("control -") case_times = control_times else: print(args[0] + ' -') case_times = get_time(*args) relative_times = map( lambda times: times[1] / times[0], zip(control_times, case_times) ) print(benchmark_template.format(*case_times, *relative_times)) print('-' * 80) def main(): BENCHMARK_TEMPLATE_3TIMES = ("(1): {0:.5f} {3:>6.2f} " "(2): {1:.5f} {4:>6.2f} " "(3): {2:.5f} {5:>6.2f}") BENCHMARK_TEMPLATE_4TIMES = ("(1): {0:.5f} {4:>6.2f} " "(2): {1:.5f} {5:>6.2f} " "(3): {2:.5f} {6:>6.2f} " "(4): {3:.5f} {7:>6.2f}") report( description=DECORATOR_SIMPLE_CASE_DESCRIPTION, benchmark_template=BENCHMARK_TEMPLATE_3TIMES, get_time=get_decorated_method_simple_timing, get_time_args=[ ('',), ("@on_trait_change('name')",), ("@observe('name')",), ("@observe(trait('name'))",) ] ) report( description=DECORATOR_EXTENDED_CASE_DESCRIPTION, benchmark_template=BENCHMARK_TEMPLATE_4TIMES, get_time=get_decorated_method_extended_timing, get_time_args=[ ('',), ("@on_trait_change('child.name')",), ("@observe('child.name')",), ("@observe(trait('child').trait('name'))",) ] ) report( description=PROPERTY_SIMPLE_CASE_DESCRIPTION, benchmark_template=BENCHMARK_TEMPLATE_3TIMES, get_time=get_property_simple_timing, get_time_args=[ ('', ''), ("depends_on='name'", ''), ("observe='name'", ''), ("observe=trait('name')", '') ] ) report( description=CACHED_PROPERTY_SIMPLE_CASE_DESCRIPTION, benchmark_template=BENCHMARK_TEMPLATE_3TIMES, get_time=get_property_simple_timing, get_time_args=[ ('', '@cached_property'), ("depends_on='name'", '@cached_property'), ("observe='name'", '@cached_property'), ("observe=trait('name')", '@cached_property') ] ) report( description=PROPERTY_EXTENDED_CASE_DESCRIPTION, benchmark_template=BENCHMARK_TEMPLATE_4TIMES, get_time=get_property_extended_timing, get_time_args=[ ('', ''), ("depends_on='child.name'", ''), ("observe='child.name'", ''), ("observe=trait('child').trait('name')", '') ] ) report( description=CACHED_PROPERTY_EXTENDED_CASE_DESCRIPTION, benchmark_template=BENCHMARK_TEMPLATE_4TIMES, get_time=get_property_extended_timing, get_time_args=[ ('', '@cached_property'), ("depends_on='child.name'", '@cached_property'), ("observe='child.name'", '@cached_property'), ("observe=trait('child').trait('name')", '@cached_property') ] ) if __name__ == '__main__': main() traits-6.3.2/traits/tests/check_timing.py000066400000000000000000000130371414270267200205070ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Perform timing tests on various trait styles to determine the amount of overhead that traits add. """ from time import time from ..api import Any, DelegatesTo, HasTraits, Int, Range # Number of iterations to perform: n = 1000000 # Loop overhead time (actual value determined first time a measurement is made) t0 = -1.0 # Measure how long it takes to execute a specified function: def measure(func): now = time() func() return time() - now # 'Old style' Python attribute get/set: class old_style_value: def measure(self, reference_get=1.0, reference_set=1.0): global t0 self.init() if t0 < 0.0: t0 = measure(self.null) t1 = measure(self.do_get) t2 = measure(self.do_set) scale = 1.0e6 / n get_time = max(t1 - t0, 0.0) * scale set_time = max(t2 - t0, 0.0) * scale return get_time, set_time def null(self): for i in range(n): pass def init(self): self.value = -1 def do_set(self): for i in range(n): self.value = i def do_get(self): for i in range(n): self.value # 'New style' Python attribute get/set: class new_style_value(object): def measure(self): global t0 self.init() if t0 < 0.0: t0 = measure(self.null) t1 = measure(self.do_get) t2 = measure(self.do_set) scale = 1.0e6 / n get_time = max(t1 - t0, 0.0) * scale set_time = max(t2 - t0, 0.0) * scale return get_time, set_time def null(self): for i in range(n): pass def init(self): self.value = -1 def do_set(self): for i in range(n): self.value = i def do_get(self): for i in range(n): self.value # Python 'property' get/set: class property_value(new_style_value): def get_value(self): return self._value def set_value(self, value): self._value = value value = property(get_value, set_value) # Python 'global' get/set: class global_value(new_style_value): def init(self): global gvalue gvalue = -1 def do_set(self): global gvalue for i in range(n): gvalue = i def do_get(self): global gvalue for i in range(n): gvalue # Trait that can have any value: class any_value(HasTraits, new_style_value): value = Any # Trait that can only have 'float' values: class int_value(any_value): value = Int # Trait that can only have 'range' values: class range_value(any_value): value = Range(-1, 2000000000) # Executes method when float trait is changed: class change_value(int_value): def _value_changed(self, old, new): pass # Notifies handler when float trait is changed: class monitor_value(int_value): def init(self): self.on_trait_change(self.on_value_change, "value") def on_value_change(self, object, trait_name, old, new): pass # Float trait is delegated to another object: class delegate_value(HasTraits, new_style_value): value = DelegatesTo("delegate") delegate = Any def init(self): self.delegate = int_value() # Float trait is delegated through one object to another object: class delegate_2_value(delegate_value): def init(self): delegate = delegate_value() delegate.init() self.delegate = delegate # Float trait is delegated through two objects to another object: class delegate_3_value(delegate_value): def init(self): delegate = delegate_2_value() delegate.init() self.delegate = delegate # Run the timing measurements: def report(name, get_time, set_time, ref_get_time, ref_set_time): """ Return string containing a benchmark report. The arguments are the name of the benchmark case, the times to do a 'get' or a 'set' operation for that benchmark case in usec, and the corresponding times for a reference operation (e.g., getting and setting an attribute on a new-style instance. """ template = ( "{name:^30}: Get {get_time:02.3f} us (x {get_speed_up:02.3f}), " "Set {set_time:02.3f} us (x {set_speed_up:02.3f})" ) report = template.format( name=name, get_time=get_time, get_speed_up=ref_get_time / get_time, set_time=set_time, set_speed_up=ref_set_time / set_time, ) return report def run_benchmark(klass, ref_get_time, ref_set_time): benchmark_name = klass.__name__ get_time, set_time = klass().measure() print( report(benchmark_name, get_time, set_time, ref_get_time, ref_set_time) ) def main(): ref_get_time, ref_set_time = new_style_value().measure() benchmarks = [ global_value, old_style_value, new_style_value, property_value, any_value, int_value, range_value, change_value, monitor_value, delegate_value, delegate_2_value, delegate_3_value, ] for benchmark in benchmarks: run_benchmark(benchmark, ref_get_time, ref_set_time) if __name__ == "__main__": main() traits-6.3.2/traits/tests/test-data/000077500000000000000000000000001414270267200173735ustar00rootroot00000000000000traits-6.3.2/traits/tests/test-data/historical-pickles/000077500000000000000000000000001414270267200231645ustar00rootroot00000000000000traits-6.3.2/traits/tests/test-data/historical-pickles/README000066400000000000000000000007621414270267200240510ustar00rootroot00000000000000This directory contains binary files *.pkl whose contents are pickled traits and trait-related objects of various kinds, used for testing backward compatibility Traits unpickling. The pickle filenames are of the form: hitp-t5.2.0-p0-.pkl where the "t5.2.0" portion gives the version of Traits that was used to create the pickle, and the "p0" portion describes the pickle protocol. The "generate_pickles" script can be used to generate pickle files for a new version of Traits. traits-6.3.2/traits/tests/test-data/historical-pickles/generate_pickles.py000066400000000000000000000031721414270267200270450ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Script to generate the historical pickle test data. """ import os import pickle from traits.api import Float from traits import __version__ # Filename template. PKL_FILENAME = "hipt-t{traits_version}-p{pickle_protocol}-{description}.pkl" # Dictionary mapping description to object to be pickled. PICKLEES = { "float-ctrait": Float(5.3).as_ctrait(), } # Supported pickle protocols on this Python version. SUPPORTED_PICKLE_PROTOCOLS = range(pickle.HIGHEST_PROTOCOL + 1) def write_pickle_file(description, picklee, protocol, output_dir): filename = PKL_FILENAME.format( traits_version=__version__, pickle_protocol=protocol, description=description, ) output_path = os.path.join(output_dir, filename) with open(output_path, "wb") as pickle_file: pickle.dump(picklee, pickle_file, protocol=protocol) def generate_pickles(): # Write to the current directory. Could make the output directory # an option. pickle_directory = os.path.abspath(".") for protocol in SUPPORTED_PICKLE_PROTOCOLS: for description, picklee in PICKLEES.items(): write_pickle_file(description, picklee, protocol, pickle_directory) if __name__ == "__main__": generate_pickles() traits-6.3.2/traits/tests/test-data/historical-pickles/hipt-t5.2.0-p0-float-ctrait.pkl000066400000000000000000000005031414270267200303660ustar00rootroot00000000000000ctraits.traits __newobj__ p0 (ctraits.traits CTrait p1 I0 tp2 Rp3 (I0 I0 I5 NI21 (I21 tp4 I0 F5.3 I0 NNI4 Nccopy_reg _reconstructor p5 (ctraits.trait_types Float p6 c__builtin__ object p7 Ntp8 Rp9 (dp10 Vdefault_value p11 F5.3 sV_metadata p12 (dp13 Vtype p14 Vtrait p15 ssVdefault_value_type p16 I0 sb(dp17 g14 g15 stp18 b.traits-6.3.2/traits/tests/test-data/historical-pickles/hipt-t5.2.0-p1-float-ctrait.pkl000066400000000000000000000004521414270267200303720ustar00rootroot00000000000000ctraits.traits __newobj__ q(ctraits.traits CTrait qKtqRq(KKKNK(KtqKG@333333KNNKNccopy_reg _reconstructor q(ctraits.trait_types Float qc__builtin__ object qNtqRq }q (X default_valueq G@333333X _metadataq }q XtypeqXtraitqsXdefault_value_typeqKub}qhhstqb.traits-6.3.2/traits/tests/test-data/historical-pickles/hipt-t5.2.0-p2-float-ctrait.pkl000066400000000000000000000003311414270267200303670ustar00rootroot00000000000000ctraits.traits CTrait qKqq(KKKNKKqKG@333333KNNKNctraits.trait_types Float q)q}q(X default_valueqG@333333X _metadataq}q Xtypeq Xtraitq sXdefault_value_typeq Kub}q h h stqb.traits-6.3.2/traits/tests/test-data/historical-pickles/hipt-t5.2.0-p3-float-ctrait.pkl000066400000000000000000000003311414270267200303700ustar00rootroot00000000000000ctraits.traits CTrait qKqq(KKKNKKqKG@333333KNNKNctraits.trait_types Float q)q}q(X default_valueqG@333333X _metadataq}q Xtypeq Xtraitq sXdefault_value_typeq Kub}q h h stqb.traits-6.3.2/traits/tests/test-data/historical-pickles/hipt-t5.2.0-p4-float-ctrait.pkl000066400000000000000000000003141414270267200303720ustar00rootroot00000000000000 traits.traitsCTraitK(KKKNKKKG@333333KNNKNtraits.trait_typesFloat)}( default_valueG@333333 _metadata}typetraitsdefault_value_typeKub}hhstb.traits-6.3.2/traits/tests/test-data/historical-pickles/hipt-t5.2.0-p5-float-ctrait.pkl000066400000000000000000000003141414270267200303730ustar00rootroot00000000000000 traits.traitsCTraitK(KKKNKKKG@333333KNNKNtraits.trait_typesFloat)}( default_valueG@333333 _metadata}typetraitsdefault_value_typeKub}hhstb.traits-6.3.2/traits/tests/test_abc.py000066400000000000000000000052271414270267200176510ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test the ABC functionality. """ import abc import unittest import warnings from traits.api import ABCHasTraits, ABCMetaHasTraits, HasTraits, Int, Float class TestNew(unittest.TestCase): """ Test that __new__ works correctly. """ def setUp(self): self.old_filters = warnings.filters[:] warnings.simplefilter("error", DeprecationWarning) def tearDown(self): warnings.filters[:] = self.old_filters def test_new(self): # Previously, this test used HasTraits(x=10). That has the # side-effect of creating an `x` trait on HasTraits, possibly # causing interactions with other tests. # xref: enthought/traits#58 class A(HasTraits): pass # Should not raise DeprecationWarning. A(x=10) class AbstractFoo(ABCHasTraits): x = Int(10) y = Float(20.0) @abc.abstractmethod def foo(self): raise NotImplementedError() @abc.abstractproperty def bar(self): raise NotImplementedError() class ConcreteFoo(AbstractFoo): def foo(self): return "foo" @property def bar(self): return "bar" class FooLike(HasTraits): x = Int(10) y = Float(20.0) def foo(self): return "foo" @property def bar(self): return "bar" AbstractFoo.register(FooLike) class AbstractBar(abc.ABC): pass @abc.abstractmethod def bar(self): raise NotImplementedError() class TestABC(unittest.TestCase): def test_basic_abc(self): self.assertRaises(TypeError, AbstractFoo) concrete = ConcreteFoo() self.assertEqual(concrete.foo(), "foo") self.assertEqual(concrete.bar, "bar") self.assertEqual(concrete.x, 10) self.assertEqual(concrete.y, 20.0) self.assertTrue(isinstance(concrete, AbstractFoo)) def test_registered(self): foolike = FooLike() self.assertTrue(isinstance(foolike, AbstractFoo)) def test_post_hoc_mixing(self): class TraitedBar(HasTraits, AbstractBar, metaclass=ABCMetaHasTraits): x = Int(10) def bar(self): return "bar" traited = TraitedBar() self.assertTrue(isinstance(traited, AbstractBar)) self.assertEqual(traited.x, 10) traits-6.3.2/traits/tests/test_any.py000066400000000000000000000053001414270267200177030ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the "Any" trait type. """ import unittest from traits.has_traits import HasTraits from traits.trait_types import Any class TestAny(unittest.TestCase): def test_default_default(self): class A(HasTraits): foo = Any() a = A() self.assertEqual(a.foo, None) def test_list_default(self): message_pattern = r"a default value of type 'list'.* will be shared" with self.assertWarnsRegex(DeprecationWarning, message_pattern): class A(HasTraits): foo = Any([]) # Test the current (but deprecated) copying behaviour a = A() b = A() self.assertEqual(a.foo, []) self.assertEqual(b.foo, []) a.foo.append(35) self.assertEqual(a.foo, [35]) self.assertEqual(b.foo, []) def test_dict_default(self): message_pattern = r"a default value of type 'dict'.* will be shared" with self.assertWarnsRegex(DeprecationWarning, message_pattern): class A(HasTraits): foo = Any({}) # Test the current (but deprecated) copying behaviour a = A() b = A() self.assertEqual(a.foo, {}) self.assertEqual(b.foo, {}) a.foo["color"] = "red" self.assertEqual(a.foo, {"color": "red"}) self.assertEqual(b.foo, {}) def test_with_factory(self): class A(HasTraits): foo = Any(factory=dict) a = A() b = A() self.assertEqual(a.foo, {}) self.assertEqual(b.foo, {}) # Defaults are not shared. a.foo["key"] = 23 self.assertEqual(a.foo, {"key": 23}) self.assertEqual(b.foo, {}) # An assigned dictionary is shared. a.foo = b.foo = {"red": 0xFF0000} a.foo["green"] = 0x00FF00 self.assertEqual(b.foo["green"], 0x00FF00) def test_with_factory_and_args(self): def factory(*args, **kw): return "received", args, kw args = (21, 34, "some string") kw = {"bar": 57} class A(HasTraits): foo = Any(factory=factory, args=args, kw=kw) a = A() self.assertEqual(a.foo, ("received", args, kw)) def test_with_default_value_and_factory(self): with self.assertRaises(TypeError): Any(23, factory=int) traits-6.3.2/traits/tests/test_anytrait_static_notifiers.py000066400000000000000000000122671414270267200244120ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the the "anytrait" static notifiers. """ import unittest from traits import trait_notifiers from traits.api import Float, HasTraits, Undefined class AnytraitStaticNotifiers0Fail(HasTraits): fail = Float def _anytrait_changed(): raise Exception("error") class AnytraitStaticNotifiers1Fail(HasTraits): fail = Float def _anytrait_changed(self): raise Exception("error") class AnytraitStaticNotifiers2Fail(HasTraits): fail = Float def _anytrait_changed(self, name): raise Exception("error") class AnytraitStaticNotifiers3Fail(HasTraits): fail = Float def _anytrait_changed(self, name, new): raise Exception("error") class AnytraitStaticNotifiers4Fail(HasTraits): fail = Float def _anytrait_changed(self, name, old, new): raise Exception("error") class TestNotifiers(unittest.TestCase): """ Tests for the static notifiers, and the "anytrait" static notifiers. """ #### 'TestCase' protocol ################################################## def setUp(self): self.exceptions = [] trait_notifiers.push_exception_handler(self._handle_exception) def tearDown(self): trait_notifiers.pop_exception_handler() #### Private protocol ##################################################### def _handle_exception(self, obj, name, old, new): self.exceptions.append((obj, name, old, new)) #### Tests ################################################################ def test_anytrait_static_notifiers_0(self): anycalls_0 = [] class AnytraitStaticNotifiers0(HasTraits): ok = Float def _anytrait_changed(): anycalls_0.append(True) obj = AnytraitStaticNotifiers0(ok=2) obj.ok = 3 self.assertEqual(len(anycalls_0), 2) def test_anytrait_static_notifiers_1(self): class AnytraitStaticNotifiers1(HasTraits): ok = Float def _anytrait_changed(self): if not hasattr(self, "anycalls"): self.anycalls = [] self.anycalls.append(True) obj = AnytraitStaticNotifiers1(ok=2) obj.ok = 3 # 3 calls (see test_anytrait_static_notifiers_4): # 1 to add trait 'anycalls', # 1 from the constructor, # 1 to set ok to 3 self.assertEqual(len(obj.anycalls), 3) def test_anytrait_static_notifiers_2(self): class AnytraitStaticNotifiers2(HasTraits): ok = Float def _anytrait_changed(self, name): if not hasattr(self, "anycalls"): self.anycalls = [] self.anycalls.append(name) obj = AnytraitStaticNotifiers2(ok=2) obj.ok = 3 expected = ["trait_added", "ok", "ok"] self.assertEqual(expected, obj.anycalls) def test_anytrait_static_notifiers_3(self): class AnytraitStaticNotifiers3(HasTraits): ok = Float def _anytrait_changed(self, name, new): if not hasattr(self, "anycalls"): self.anycalls = [] self.anycalls.append((name, new)) obj = AnytraitStaticNotifiers3(ok=2) obj.ok = 3 expected = [("trait_added", "anycalls"), ("ok", 2), ("ok", 3)] self.assertEqual(expected, obj.anycalls) def test_anytrait_static_notifiers_4(self): class AnytraitStaticNotifiers4(HasTraits): ok = Float def _anytrait_changed(self, name, old, new): if not hasattr(self, "anycalls"): self.anycalls = [] self.anycalls.append((name, old, new)) obj = AnytraitStaticNotifiers4(ok=2) obj.ok = 3 expected = [ ("trait_added", Undefined, "anycalls"), ("ok", 0, 2), ("ok", 2, 3), ] self.assertEqual(expected, obj.anycalls) def test_anytrait_static_notifiers_0_fail(self): obj = AnytraitStaticNotifiers0Fail() obj.fail = 1 self.assertEqual(self.exceptions, [(obj, "fail", 0, 1)]) def test_anytrait_static_notifiers_1_fail(self): obj = AnytraitStaticNotifiers1Fail() obj.fail = 1 self.assertEqual(self.exceptions, [(obj, "fail", 0, 1)]) def test_anytrait_static_notifiers_2_fail(self): obj = AnytraitStaticNotifiers2Fail() obj.fail = 1 self.assertEqual(self.exceptions, [(obj, "fail", 0, 1)]) def test_anytrait_static_notifiers_3_fail(self): obj = AnytraitStaticNotifiers3Fail() obj.fail = 1 self.assertEqual(self.exceptions, [(obj, "fail", 0, 1)]) def test_anytrait_static_notifiers_4_fail(self): obj = AnytraitStaticNotifiers4Fail() obj.fail = 1 self.assertEqual(self.exceptions, [(obj, "fail", 0, 1)]) traits-6.3.2/traits/tests/test_array.py000066400000000000000000000033411414270267200202350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import Array, Bool, HasTraits, TraitError from traits.testing.optional_dependencies import numpy, requires_numpy if numpy is not None: # Use of `Array` requires NumPy to be installed. class Foo(HasTraits): a = Array() event_fired = Bool(False) def _a_changed(self): self.event_fired = True @requires_numpy class ArrayTestCase(unittest.TestCase): """ Test cases for delegated traits. """ def test_zero_to_one_element(self): """ Test that an event fires when an Array trait changes from zero to one element. """ f = Foo() f.a = numpy.zeros((2,), float) f.event_fired = False # Change the array. f.a = numpy.concatenate((f.a, numpy.array([100]))) # Confirm that the static trait handler was invoked. self.assertEqual(f.event_fired, True) def test_safe_casting(self): class Bar(HasTraits): unsafe_f32 = Array(dtype="float32") safe_f32 = Array(dtype="float32", casting="safe") f64 = numpy.array([1], dtype="float64") f32 = numpy.array([1], dtype="float32") b = Bar() b.unsafe_f32 = f32 b.unsafe_f32 = f64 b.safe_f32 = f32 with self.assertRaises(TraitError): b.safe_f32 = f64 traits-6.3.2/traits/tests/test_array_or_none.py000066400000000000000000000136761414270267200217700ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the ArrayOrNone TraitType. """ import unittest from traits.api import ArrayOrNone, ComparisonMode, HasTraits, TraitError from traits.testing.unittest_tools import UnittestTools from traits.testing.optional_dependencies import numpy, requires_numpy if numpy is not None: # Use of `ArrayOrNone` requires NumPy to be installed. class Foo(HasTraits): maybe_array = ArrayOrNone maybe_float_array = ArrayOrNone(dtype=float) maybe_two_d_array = ArrayOrNone(shape=(None, None)) maybe_array_with_default = ArrayOrNone(value=[1, 2, 3]) maybe_array_no_compare = ArrayOrNone( comparison_mode=ComparisonMode.none) @requires_numpy class TestArrayOrNone(unittest.TestCase, UnittestTools): """ Tests for the ArrayOrNone TraitType. """ def test_default(self): foo = Foo() self.assertIsNone(foo.maybe_array) def test_explicit_default(self): foo = Foo() self.assertIsInstance(foo.maybe_array_with_default, numpy.ndarray) def test_default_validation(self): # CArray and Array validate the default at class creation time; # we do the same for ArrayOrNone. with self.assertRaises(TraitError): class Bar(HasTraits): bad_array = ArrayOrNone(shape=(None, None), value=[1, 2, 3]) def test_setting_array_from_array(self): foo = Foo() test_array = numpy.arange(5) foo.maybe_array = test_array output_array = foo.maybe_array self.assertIsInstance(output_array, numpy.ndarray) self.assertEqual(output_array.dtype, test_array.dtype) self.assertEqual(output_array.shape, test_array.shape) self.assertTrue((output_array == test_array).all()) def test_setting_array_from_list(self): foo = Foo() test_list = [5, 6, 7, 8, 9] foo.maybe_array = test_list output_array = foo.maybe_array self.assertIsInstance(output_array, numpy.ndarray) self.assertEqual(output_array.dtype, numpy.dtype(int)) self.assertEqual(output_array.shape, (5,)) self.assertTrue((output_array == test_list).all()) def test_setting_array_from_none(self): foo = Foo() test_array = numpy.arange(5) self.assertIsNone(foo.maybe_array) foo.maybe_array = test_array self.assertIsInstance(foo.maybe_array, numpy.ndarray) foo.maybe_array = None self.assertIsNone(foo.maybe_array) def test_dtype(self): foo = Foo() foo.maybe_float_array = [1, 2, 3] array_value = foo.maybe_float_array self.assertIsInstance(array_value, numpy.ndarray) self.assertEqual(array_value.dtype, numpy.dtype(float)) def test_shape(self): foo = Foo() with self.assertRaises(TraitError): foo.maybe_two_d_array = [1, 2, 3] def test_change_notifications(self): foo = Foo() test_array = numpy.arange(-7, -2) different_test_array = numpy.arange(10) # Assigning None to something that's already None shouldn't fire. with self.assertTraitDoesNotChange(foo, "maybe_array"): foo.maybe_array = None # Changing from None to an array: expect an event. with self.assertTraitChanges(foo, "maybe_array"): foo.maybe_array = test_array # No event from assigning the same array again. with self.assertTraitDoesNotChange(foo, "maybe_array"): foo.maybe_array = test_array # But assigning a new array fires an event. with self.assertTraitChanges(foo, "maybe_array"): foo.maybe_array = different_test_array # No event even if the array is modified in place. different_test_array += 2 with self.assertTraitDoesNotChange(foo, "maybe_array"): foo.maybe_array = different_test_array # Set back to None; we should get an event. with self.assertTraitChanges(foo, "maybe_array"): foo.maybe_array = None def test_comparison_mode_override(self): foo = Foo() test_array = numpy.arange(-7, 2) with self.assertTraitChanges(foo, "maybe_array_no_compare"): foo.maybe_array_no_compare = None with self.assertTraitChanges(foo, "maybe_array_no_compare"): foo.maybe_array_no_compare = test_array with self.assertTraitChanges(foo, "maybe_array_no_compare"): foo.maybe_array_no_compare = test_array def test_default_value_copied(self): # Check that we don't share defaults. test_default = numpy.arange(100.0, 110.0) class FooBar(HasTraits): foo = ArrayOrNone(value=test_default) bar = ArrayOrNone(value=test_default) foo_bar = FooBar() self.assertTrue((foo_bar.foo == test_default).all()) self.assertTrue((foo_bar.bar == test_default).all()) test_default += 2.0 self.assertFalse((foo_bar.foo == test_default).all()) self.assertFalse((foo_bar.bar == test_default).all()) foo = foo_bar.foo foo += 1729.0 self.assertFalse((foo_bar.foo == foo_bar.bar).all()) def test_safe_casting(self): class Bar(HasTraits): unsafe_f32 = ArrayOrNone(dtype="float32") safe_f32 = ArrayOrNone(dtype="float32", casting="safe") f64 = numpy.array([1], dtype="float64") f32 = numpy.array([1], dtype="float32") b = Bar() b.unsafe_f32 = f32 b.unsafe_f32 = f64 b.safe_f32 = f32 with self.assertRaises(TraitError): b.safe_f32 = f64 traits-6.3.2/traits/tests/test_automatic_adaptation.py000066400000000000000000000105151414270267200233120ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.adaptation.api import reset_global_adaptation_manager from traits.api import ( BaseInstance, Bool, HasTraits, Instance, List, register_factory, TraitError, ) class Foo(HasTraits): default = Bool(False) class Bar(HasTraits): pass def bar_to_foo_adapter(bar): return Foo() def default_foo(): return Foo(default=True) class TestAutomaticAdaptationBase: """ Mixin for tests to be applied to both Instance and BaseInstance. Subclasses should define the class variable 'trait_under_test'. """ #### 'TestCase' protocol ################################################## def setUp(self): reset_global_adaptation_manager() #### Tests ################################################################ def test_instance_trait_automatic_adaptation(self): bar = Bar() foo_container = self.create_foo_container() # Before a Bar->Foo adapter is registered. with self.assertRaises(TraitError): foo_container.not_adapting_foo = bar with self.assertRaises(TraitError): foo_container.adapting_foo = bar foo_container.adapting_foo_permissive = bar self.assertIsNone(foo_container.adapting_foo_permissive) foo_container.adapting_foo_dynamic_default = bar self.assertIsInstance(foo_container.adapting_foo_dynamic_default, Foo) self.assertTrue(foo_container.adapting_foo_dynamic_default.default) # After a Bar->Foo adapter is registered. register_factory(bar_to_foo_adapter, Bar, Foo) with self.assertRaises(TraitError): foo_container.not_adapting_foo = bar foo_container.adapting_foo = bar self.assertIsInstance(foo_container.adapting_foo, Foo) foo_container.adapting_foo_permissive = bar self.assertIsInstance(foo_container.adapting_foo_permissive, Foo) foo_container.adapting_foo_dynamic_default = bar self.assertIsInstance(foo_container.adapting_foo_dynamic_default, Foo) self.assertFalse(foo_container.adapting_foo_dynamic_default.default) def test_list_trait_automatic_adaptation(self): bar = Bar() foo_container = self.create_foo_container() # Before a Bar->Foo adapter is registered. with self.assertRaises(TraitError): foo_container.not_adapting_foo_list = [bar] with self.assertRaises(TraitError): foo_container.adapting_foo_list = [bar] # After a Bar->Foo adapter is registered. register_factory(bar_to_foo_adapter, Bar, Foo) with self.assertRaises(TraitError): foo_container.not_adapting_foo_list = [bar] foo_container.adapting_foo_list = [bar] self.assertIsInstance(foo_container.adapting_foo_list[0], Foo) #### Helpers ############################################################## def create_foo_container(self): instance_trait = self.trait_under_test class FooContainer(HasTraits): not_adapting_foo = instance_trait(Foo) adapting_foo = instance_trait(Foo, adapt="yes") adapting_foo_permissive = instance_trait(Foo, adapt="default") adapting_foo_dynamic_default = instance_trait( Foo, adapt="default", factory=default_foo, ) not_adapting_foo_list = List(Foo) adapting_foo_list = List(instance_trait(Foo, adapt="yes")) return FooContainer() class TestAutomaticAdaptationInstance( TestAutomaticAdaptationBase, unittest.TestCase ): """ Tests for automatic adaptation with Instance. """ #: Trait type being tested trait_under_test = Instance class TestAutomaticAdaptationBaseInstance( TestAutomaticAdaptationBase, unittest.TestCase ): """ Tests for automatic adaptation with BaseInstance. """ #: Trait type being tested trait_under_test = BaseInstance traits-6.3.2/traits/tests/test_bool.py000066400000000000000000000046731414270267200200630ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the Bool trait type. """ import unittest from traits.api import Bool, Dict, HasTraits, Int, TraitError from traits.testing.optional_dependencies import numpy, requires_numpy class A(HasTraits): foo = Bool class TestBool(unittest.TestCase): def test_default_value(self): a = A() # We should get something of exact type bool. self.assertEqual(type(a.foo), bool) self.assertFalse(a.foo) def test_accepts_bool(self): a = A() a.foo = True self.assertTrue(a.foo) a.foo = False self.assertFalse(a.foo) def test_does_not_accept_int_or_float(self): a = A() bad_values = [-1, "a string", 1.0] for bad_value in bad_values: with self.assertRaises(TraitError): a.foo = bad_value # Double check that foo didn't actually change self.assertEqual(type(a.foo), bool) self.assertFalse(a.foo) @requires_numpy def test_accepts_numpy_bool(self): # A bool trait should accept a NumPy bool_. a = A() a.foo = numpy.bool_(True) self.assertTrue(a.foo) @requires_numpy def test_numpy_bool_retrieved_as_bool(self): a = A() a.foo = numpy.bool_(True) self.assertIsInstance(a.foo, bool) a.foo = numpy.bool_(False) self.assertIsInstance(a.foo, bool) @requires_numpy def test_numpy_bool_accepted_as_dict_value(self): # Regression test for enthought/traits#299. class HasBoolDict(HasTraits): foo = Dict(Int, Bool) has_bool_dict = HasBoolDict() has_bool_dict.foo[1] = numpy.bool_(True) self.assertTrue(has_bool_dict.foo[1]) @requires_numpy def test_numpy_bool_accepted_as_dict_key(self): # Regression test for enthought/traits#299. class HasBoolDict(HasTraits): foo = Dict(Bool, Int) has_bool_dict = HasBoolDict() key = numpy.bool_(True) has_bool_dict.foo[key] = 1 self.assertEqual(has_bool_dict.foo[key], 1) traits-6.3.2/traits/tests/test_callable.py000066400000000000000000000151111414270267200206540ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import inspect import unittest from traits.api import ( BaseCallable, Callable, Either, HasTraits, Int, Str, TraitError, Union, ValidateTrait ) def function(): pass class Dummy(object): def instance_method(self): pass class OldCallable(BaseCallable): """ Old-style Callable, whose validation tuple doesn't include the allow_none field. We only care about this case because it's possible that old pickles could include Callable instances whose validation tuple has length 1. """ def __init__(self, value=None, **metadata): self.fast_validate = (ValidateTrait.callable,) super().__init__(value, **metadata) class Unbool: """ Object that can't be interpreted as a bool, for testing purposes. """ def __bool__(self): raise ZeroDivisionError() class MyCallable(HasTraits): value = Callable() callable_or_str = Either(Callable, Str) old_callable_or_str = Either(OldCallable, Str) bad_allow_none = Either(Callable(allow_none=Unbool()), Str) non_none_callable_or_str = Either(Callable(allow_none=False), Str) class MyBaseCallable(HasTraits): value = BaseCallable class TestCallable(unittest.TestCase): def test_default(self): a = MyCallable() self.assertIsNone(a.value) def test_accepts_lambda(self): func = lambda v: v + 1 # noqa: E731 a = MyCallable(value=func) self.assertIs(a.value, func) def test_accepts_type(self): MyCallable(value=float) def test_accepts_method(self): dummy = Dummy() MyCallable(value=dummy.instance_method) def test_accepts_function(self): MyCallable(value=function) def test_rejects_int(self): a = MyCallable() with self.assertRaises(TraitError) as exception_context: a.value = 1 self.assertIn( "must be a callable value", str(exception_context.exception)) def test_callable_in_complex_trait(self): a = MyCallable() self.assertIsNone(a.callable_or_str) acceptable_values = [pow, "pow", None, int] for value in acceptable_values: a.callable_or_str = value self.assertEqual(a.callable_or_str, value) unacceptable_values = [1.0, 3j, (5, 6, 7)] for value in unacceptable_values: old_value = a.callable_or_str with self.assertRaises(TraitError): a.callable_or_str = value self.assertEqual(a.callable_or_str, old_value) def test_compound_callable_refcount(self): # Regression test for enthought/traits#906. def my_function(): return 72 a = MyCallable() string_value = "some string" callable_value = my_function # We seem to need at least 3 repetitions to reliably produce # a crash. Let's hoick it up to 5 to be safe. for _ in range(5): a.callable_or_str = string_value a.callable_or_str = callable_value self.assertEqual(a.callable_or_str(), 72) def test_disallow_none(self): class MyNewCallable(HasTraits): value = Callable(default_value=pow, allow_none=False) obj = MyNewCallable() self.assertIsNotNone(obj.value) with self.assertRaises(TraitError): obj.value = None self.assertEqual(8, obj.value(2, 3)) def test_disallow_none_compound(self): class MyNewCallable2(HasTraits): value = Callable(pow, allow_none=True) empty_callable = Callable() a_non_none_union = Union(Callable(allow_none=False), Int) a_allow_none_union = Union(Callable(allow_none=True), Int) obj = MyNewCallable2() self.assertIsNotNone(obj.value) self.assertIsNone(obj.empty_callable) obj.value = None obj.empty_callable = None self.assertIsNone(obj.value) self.assertIsNone(obj.empty_callable) obj.a_non_none_union = 5 obj.a_allow_none_union = 5 with self.assertRaises(TraitError): obj.a_non_none_union = None obj.a_allow_none_union = None def test_implicitly_allowed_none_in_compound(self): obj = MyCallable() obj.old_callable_or_str = "bob" obj.old_callable_or_str = None self.assertIsNone(obj.old_callable_or_str) def test_non_bool_allow_none(self): obj = MyCallable() obj.bad_allow_none = "a string" with self.assertRaises(ZeroDivisionError): obj.bad_allow_none = None def test_none_not_allowed_in_compound(self): obj = MyCallable() with self.assertRaises(TraitError): obj.non_none_callable_or_str = None def test_old_style_callable(self): class MyCallable(HasTraits): # allow_none flag should be ineffective value = OldCallable() obj = MyCallable() obj.value = None self.assertIsNone(obj.value) class TestBaseCallable(unittest.TestCase): def test_override_validate(self): """ Verify `BaseCallable` can be subclassed to create new traits. """ class ZeroArgsCallable(BaseCallable): def validate(self, object, name, value): if callable(value): sig = inspect.signature(value) if len(sig.parameters) == 0: return value self.error(object, name, value) class Foo(HasTraits): value = ZeroArgsCallable Foo(value=lambda: 1) with self.assertRaises(TraitError): Foo(value=lambda x: x) with self.assertRaises(TraitError): Foo(value=1) def test_accepts_function(self): MyBaseCallable(value=lambda x: x) def test_accepts_method(self): MyBaseCallable(value=Dummy.instance_method) def test_accepts_type(self): MyBaseCallable(value=int) def test_accepts_none(self): MyBaseCallable(value=None) def test_rejects_non_callable(self): with self.assertRaises(TraitError): MyBaseCallable(value=Dummy()) with self.assertRaises(TraitError): MyBaseCallable(value=1) traits-6.3.2/traits/tests/test_class_traits.py000066400000000000000000000031411414270267200216100ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Unit tests for the `HasTraits.class_traits` class function. """ import unittest from traits.api import HasTraits, Int, List, Str class A(HasTraits): x = Int name = Str(marked=True) class B(A): pass class C(B): lst = List(marked=False) y = Int(marked=True) class TestClassTraits(unittest.TestCase): def test_all_class_traits(self): expected = ["x", "name", "trait_added", "trait_modified"] self.assertCountEqual(A.class_traits(), expected) # Check that derived classes report the correct traits. self.assertCountEqual(B.class_traits(), expected) expected.extend(("lst", "y")) self.assertCountEqual(C.class_traits(), expected) def test_class_traits_with_metadata(self): # Retrieve all traits that have the `marked` metadata # attribute set to True. traits = C.class_traits(marked=True) self.assertCountEqual(list(traits.keys()), ("y", "name")) # Retrieve all traits that have a `marked` metadata attribute, # regardless of its value. marked_traits = C.class_traits(marked=lambda attr: attr is not None) self.assertCountEqual(marked_traits, ("y", "name", "lst")) traits-6.3.2/traits/tests/test_clone.py000066400000000000000000000205431414270267200202220ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import HasTraits, Instance, Str, Any, Property class Foo(HasTraits): s = Str class ClassWithAny(HasTraits): x = Property _x = Any def _get_x(self): return self._x def _set_x(self, x): self._x = x class ClassWithInstance(HasTraits): x = Property _x = Instance(Foo) def _get_x(self): return self._x def _set_x(self, x): self._x = x class ClassWithClassAttribute(HasTraits): name = "class defined name" foo = Str class BazAny(HasTraits): other = Any class BarAny(HasTraits): other = Any class BazInstance(HasTraits): # A BarInstance owned by this object. other = Instance("BarInstance") # A Foo owned by this object and not referenced by others. unique = Instance(Foo) # A Foo owned by this object and referenced by others. shared = Instance(Foo) # A Foo not owned by this object, may or may not be shared with other # objects found via owned references (e.g. other.ref). For the tests, # ref will always reference a Foo that is not owned by any of the objects # reachable via owned references, and therefore, that Foo object should # not be cloned. ref = Instance(Foo, copy="ref") class BarInstance(HasTraits): # used as circular reference back to owning BazInstance # NOTE: Setting copy to 'ref' will mean that when BarInstance is cloned, # the 'other' trait will not be copied, and will still point to the # 'other' attribute of the original BarInstance. other = Instance("BazInstance", copy="ref") # A Foo owned by this object and not referenced by others. unique = Instance(Foo) # A Foo owned by the 'other' object and referenced by this object. shared = Instance(Foo) # A Foo not owned by this object, may or may not be shared with other # objects found via owned references (e.g. other.ref). For the tests, # ref will always reference a Foo that is not owned by any of the objects # reachable via owned references, and therefore, that Foo object should # not be cloned. ref = Instance(Foo, copy="ref") class CloneTestCase(unittest.TestCase): """ Test cases for traits clone """ def test_any(self): b = ClassWithAny() f = Foo() f.s = "the f" b.x = f bc = b.clone_traits(traits="all", copy="deep") self.assertNotEqual(id(bc.x), id(f), "Foo x not cloned") def test_instance(self): b = ClassWithInstance() f = Foo() f.s = "the f" b.x = f bc = b.clone_traits(traits="all", copy="deep") self.assertNotEqual(id(bc.x), id(f), "Foo x not cloned") def test_class_attribute_missing(self): """ This test demonstrates a problem with Traits objects with class attributes. A change to the value of a class attribute via one instance causes the attribute to be removed from other instances. AttributeError: 'ClassWithClassAttribute' object has no attribute 'name' """ s = "class defined name" c = ClassWithClassAttribute() self.assertEqual(s, c.name) c2 = ClassWithClassAttribute() self.assertEqual(s, c.name) self.assertEqual(s, c2.name) s2 = "name class attribute changed via clone" c2.name = s2 self.assertEqual(s2, c2.name) # this is failing with AttributeError: 'ClassWithClassAttribute' # object has no attribute 'name' self.assertEqual(s, c.name) def test_Any_circular_references(self): # Demonstrates that Any traits default to copy='ref' bar = BarAny() baz = BazAny() bar.other = baz baz.other = bar bar_copy = bar.clone_traits() self.assertIsNot(bar_copy, bar) self.assertIs(bar_copy.other, baz) self.assertIs(bar_copy.other.other, bar) def test_Any_circular_references_deep(self): # Demonstrates that Any traits can be forced to deep copy. bar = BarAny() baz = BazAny() bar.other = baz baz.other = bar bar_copy = bar.clone_traits(copy="deep") self.assertIsNot(bar_copy, bar) self.assertIsNot(bar_copy.other, baz) self.assertIsNot(bar_copy.other.other, bar) self.assertIs(bar_copy.other.other, bar_copy) def test_Instance_circular_references(self): ref = Foo(s="ref") bar_unique = Foo(s="bar.foo") shared = Foo(s="shared") baz_unique = Foo(s="baz.unique") baz = BazInstance() baz.unique = baz_unique baz.shared = shared baz.ref = ref bar = BarInstance() bar.unique = bar_unique bar.shared = shared bar.ref = ref bar.other = baz baz.other = bar baz_copy = baz.clone_traits() # Check Baz and Baz attributes.... self.assertIsNot(baz_copy, baz) self.assertIsNot(baz_copy.other, bar) self.assertIsNot(baz_copy.unique, baz.unique) self.assertIsNot(baz_copy.shared, baz.shared) self.assertIs(baz_copy.ref, ref) # Check Bar and Bar attributes.... bar_copy = baz_copy.other # Check the Bar owned object self.assertIsNot(bar_copy.unique, bar.unique) # Check the Bar reference to an object 'outside' the cloned graph. self.assertIs(bar_copy.ref, ref) # Check references to objects that where cloned, they should reference # the new clones not the original objects, except when copy is set # to 'ref' (as in the case of the 'other' trait). # When copy is set to ref, the trait does not get cloned. Therefore, # baz_copy.other.other is baz (and not baz_copy). self.assertIsNot(bar_copy.other, baz_copy) self.assertIs(bar_copy.other, baz) # 'shared' does not have copy set to 'ref', and so bar_copy.shared # should reference the new clone. # should reference the new clones self.assertIsNot(bar_copy.shared, baz.shared) self.assertIs(bar_copy.shared, baz_copy.shared) def test_Instance_circular_references_deep(self): ref = Foo(s="ref") bar_unique = Foo(s="bar.foo") shared = Foo(s="shared") baz_unique = Foo(s="baz.unique") baz = BazInstance() baz.unique = baz_unique baz.shared = shared baz.ref = ref bar = BarInstance() bar.unique = bar_unique bar.shared = shared bar.ref = ref bar.other = baz baz.other = bar baz_copy = baz.clone_traits(copy="deep") # Check Baz and Baz attributes.... self.assertIsNot(baz_copy, baz) self.assertIsNot(baz_copy.other, bar) self.assertIsNot(baz_copy.unique, baz.unique) self.assertIsNot(baz_copy.shared, baz.shared) # baz_copy.ref is checked below with bar_copy.ref. # Check Bar and Bar attributes.... bar_copy = baz_copy.other # Check the Bar owned object self.assertIsNot(bar_copy.unique, bar.unique) # Since the two original 'ref' links were to a shared object, # the cloned links should be to a shared object. Also, the shared # object should be the original 'ref' object, since copy was set to # 'ref'. self.assertIs(baz_copy.ref, bar_copy.ref) self.assertIs(bar_copy.ref, ref) # Check references to objects that where cloned, they should reference # the new clones not the original objects, except when copy is set # to 'ref' (as in the case of the 'other' trait). That is, the 'deep' # flag on clone_traits should not override the 'copy' metadata on # the trait. self.assertIsNot(bar_copy.other, baz_copy) self.assertIs(bar_copy.other, baz) # 'shared' does not have copy set to 'ref', and so bar_copy.shared # should reference the new clone. self.assertIsNot(bar_copy.shared, baz.shared) self.assertIs(bar_copy.shared, baz_copy.shared) traits-6.3.2/traits/tests/test_configure_traits.py000066400000000000000000000136431414270267200224740ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import os import pickle import pickletools import shutil import tempfile import unittest import unittest.mock as mock import warnings from traits.api import HasTraits, Int from traits.testing.optional_dependencies import requires_traitsui, traitsui class Model(HasTraits): count = Int @requires_traitsui class TestConfigureTraits(unittest.TestCase): def setUp(self): self.toolkit = traitsui.api.toolkit() self.tmpdir = tempfile.mkdtemp() def tearDown(self): shutil.rmtree(self.tmpdir) del self.tmpdir del self.toolkit def test_simple_call(self): # Minimal exercising of configure_traits functionality. model = Model() with mock.patch.object(self.toolkit, "view_application") as mock_view: model.configure_traits() self.assertEqual(mock_view.call_count, 1) def test_filename_but_no_file(self): model = Model(count=37) filename = os.path.join(self.tmpdir, "nonexistent.pkl") self.assertFalse(os.path.exists(filename)) with mock.patch.object(self.toolkit, "view_application"): with self.assertWarns(DeprecationWarning): model.configure_traits(filename=filename) self.assertTrue(os.path.exists(filename)) with open(filename, "rb") as pickled_object: unpickled = pickle.load(pickled_object) self.assertIsInstance(unpickled, Model) self.assertEqual(unpickled.count, model.count) def test_pickle_protocol(self): # Pickled files should use protocol 3 (a compromise between # efficiency and wide applicability). model = Model(count=37) filename = os.path.join(self.tmpdir, "nonexistent.pkl") self.assertFalse(os.path.exists(filename)) with mock.patch.object(self.toolkit, "view_application"): with self.assertWarns(DeprecationWarning): model.configure_traits(filename=filename) self.assertTrue(os.path.exists(filename)) with open(filename, "rb") as pickled_object_file: pickled_object = pickled_object_file.read() # Get and check the first opcode opcode, arg, _ = next(pickletools.genops(pickled_object)) self.assertEqual(opcode.name, "PROTO") self.assertEqual(arg, 3) def test_filename_with_existing_file(self): # Create pre-existing pickle file. stored_model = Model(count=52) filename = os.path.join(self.tmpdir, "model.pkl") with open(filename, "wb") as pickled_object: pickle.dump(stored_model, pickled_object) model = Model(count=19) with mock.patch.object(self.toolkit, "view_application"): with self.assertWarns(DeprecationWarning): model.configure_traits(filename=filename) self.assertEqual(model.count, 52) def test_filename_with_invalid_existing_file(self): # Create file whose contents are not unpickleable. filename = os.path.join(self.tmpdir, "model.pkl") with open(filename, "wb") as pickled_object: pickled_object.write(b"this is not a valid pickle") model = Model(count=19) with mock.patch.object(self.toolkit, "view_application"): with self.assertRaises(pickle.PickleError): with self.assertWarns(DeprecationWarning): model.configure_traits(filename=filename) def test_filename_with_existing_file_stores_updated_model(self): stored_model = Model(count=52) filename = os.path.join(self.tmpdir, "model.pkl") with open(filename, "wb") as pickled_object: pickle.dump(stored_model, pickled_object) def modify_model(*args, **kwargs): model.count = 23 return mock.DEFAULT model = Model(count=19) with mock.patch.object(self.toolkit, "view_application") as mock_view: mock_view.side_effect = modify_model with self.assertWarns(DeprecationWarning): model.configure_traits(filename=filename) self.assertEqual(model.count, 23) with open(filename, "rb") as pickled_object: unpickled = pickle.load(pickled_object) self.assertIsInstance(unpickled, Model) self.assertEqual(unpickled.count, model.count) def test_edit_when_false(self): # Check for deprecation warning when *edit* is false. model = Model() with mock.patch.object(self.toolkit, "view_application") as mock_view: mock_view.return_value = True with self.assertWarns(DeprecationWarning): model.configure_traits(edit=False) mock_view.assert_not_called() def test_edit_when_true(self): # Check for deprecation warning when *edit* is false. model = Model() with mock.patch.object(self.toolkit, "view_application") as mock_view: mock_view.return_value = True with self.assertWarns(DeprecationWarning): model.configure_traits(edit=True) mock_view.assert_called_once() def test_edit_not_given(self): # Normal case where the *edit* argument is not supplied. model = Model() with mock.patch.object(self.toolkit, "view_application") as mock_view: mock_view.return_value = True with warnings.catch_warnings(record=True) as captured_warnings: warnings.simplefilter("always", DeprecationWarning) model.configure_traits() mock_view.assert_called_once() self.assertEqual(len(captured_warnings), 0) traits-6.3.2/traits/tests/test_constant.py000066400000000000000000000046411414270267200207540ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import Constant, HasTraits, TraitError class TestConstantTrait(unittest.TestCase): def test_initial_value(self): class TestClass(HasTraits): c_atr = Constant(5) self.assertEqual(TestClass().c_atr, 5) def test_mutable_initial_value(self): class TestClass(HasTraits): c_atr_1 = Constant([1, 2, 3, 4, 5]) c_atr_2 = Constant({"a": 1, "b": 2}) obj = TestClass() self.assertEqual(obj.c_atr_1, [1, 2, 3, 4, 5]) self.assertEqual(obj.c_atr_2, {"a": 1, "b": 2}) def test_assign_fails(self): class TestClass(HasTraits): c_atr = Constant(5) with self.assertRaises(TraitError): TestClass(c_atr=5) with self.assertRaises(TraitError): del TestClass().c_atr def test_mutate_succeeds(self): class TestClass(HasTraits): c_atr_1 = Constant([1, 2, 3, 4, 5]) c_atr_2 = Constant({"a": 1, "b": 2}) obj = TestClass() obj.c_atr_1.append(6) obj.c_atr_2["c"] = 3 self.assertEqual(obj.c_atr_1, [1, 2, 3, 4, 5, 6]) self.assertEqual(obj.c_atr_2, {"a": 1, "b": 2, "c": 3}) def test_mutate_affects_all_instances(self): # Mutable values are allowed for the 'Constant' trait because it's # impractical to do otherwise - many things are mutable but not # intended to be mutated, and there's no practical way to test for # "not-intended-to-be-mutated". Nevertheless, actually mutating the # value for 'Constant' is inadvisable in practice, despite the # existence of this test. class TestClass(HasTraits): c_atr = Constant([1, 2, 3, 4, 5]) obj1 = TestClass() obj2 = TestClass() # Mutate obj2; check that obj1 is affected. obj2.c_atr.append(6) self.assertEqual(obj1.c_atr, [1, 2, 3, 4, 5, 6]) # Check directly that both refer to the same object. self.assertIs(obj1.c_atr, obj2.c_atr) traits-6.3.2/traits/tests/test_constants.py000066400000000000000000000016321414270267200211340ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import ComparisonMode class TestConstants(unittest.TestCase): def test_deprecated_comparison_constants(self): # Check availability of comparison constants. from traits.api import ( NO_COMPARE, OBJECT_IDENTITY_COMPARE, RICH_COMPARE) self.assertIs(NO_COMPARE, ComparisonMode.none) self.assertIs( OBJECT_IDENTITY_COMPARE, ComparisonMode.identity) self.assertIs( RICH_COMPARE, ComparisonMode.equality) traits-6.3.2/traits/tests/test_container_events.py000066400000000000000000000110431414270267200224630ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for Dict items_changed events """ import unittest from traits.api import HasTraits, Dict class MyClass(HasTraits): """ A dummy HasTraits class with a Dict """ d = Dict({"a": "apple", "b": "banana", "c": "cherry", "d": "durian"}) def __init__(self, callback): "The callback is called with the TraitDictEvent instance" self.callback = callback def _d_items_changed(self, event): if self.callback: self.callback(event) class MyOtherClass(HasTraits): """ A dummy HasTraits class with a Dict """ d = Dict({"a": "apple", "b": "banana", "c": "cherry", "d": "durian"}) class Callback: """ A stateful callback that gets initialized with the values to check for """ def __init__(self, obj, added={}, changed={}, removed={}): self.obj = obj self.added = added self.changed = changed self.removed = removed self.called = False def __call__(self, event): self.obj.assertEqual(event.added, self.added) self.obj.assertEqual(event.changed, self.changed) self.obj.assertEqual(event.removed, self.removed) self.called = True class DictEventTestCase(unittest.TestCase): def test_setitem(self): # overwriting an existing item cb = Callback(self, changed={"c": "cherry"}) foo = MyClass(cb) foo.d["c"] = "coconut" self.assertTrue(cb.called) # adding a new item cb = Callback(self, added={"g": "guava"}) bar = MyClass(cb) bar.d["g"] = "guava" self.assertTrue(cb.called) def test_delitem(self): cb = Callback(self, removed={"b": "banana"}) foo = MyClass(cb) del foo.d["b"] self.assertTrue(cb.called) def test_clear(self): removed = MyClass(None).d.copy() cb = Callback(self, removed=removed) foo = MyClass(cb) foo.d.clear() self.assertTrue(cb.called) def test_update(self): update_dict = {"a": "artichoke", "f": "fig"} cb = Callback(self, changed={"a": "apple"}, added={"f": "fig"}) foo = MyClass(cb) foo.d.update(update_dict) self.assertTrue(cb.called) def test_setdefault(self): # Test retrieving an existing value cb = Callback(self) foo = MyClass(cb) self.assertEqual(foo.d.setdefault("a", "dummy"), "apple") self.assertFalse(cb.called) # Test adding a new value cb = Callback(self, added={"f": "fig"}) bar = MyClass(cb) self.assertTrue(bar.d.setdefault("f", "fig") == "fig") self.assertTrue(cb.called) def test_pop(self): # Test popping a non-existent key cb = Callback(self) foo = MyClass(cb) self.assertEqual(foo.d.pop("x", "dummy"), "dummy") self.assertFalse(cb.called) # Test popping a regular item cb = Callback(self, removed={"c": "cherry"}) bar = MyClass(cb) self.assertEqual(bar.d.pop("c"), "cherry") self.assertTrue(cb.called) def test_popitem(self): foo = MyClass(None) foo.d.clear() foo.d["x"] = "xylophone" cb = Callback(self, removed={"x": "xylophone"}) foo.callback = cb self.assertEqual(foo.d.popitem(), ("x", "xylophone")) self.assertTrue(cb.called) def test_dynamic_listener(self): foo = MyOtherClass() # Test adding func = Callback(self, added={"g": "guava"}) foo.on_trait_change(func.__call__, "d_items") foo.d["g"] = "guava" foo.on_trait_change(func.__call__, "d_items", remove=True) self.assertTrue(func.called) # Test removing func2 = Callback(self, removed={"a": "apple"}) foo.on_trait_change(func2.__call__, "d_items") del foo.d["a"] foo.on_trait_change(func2.__call__, "d_items", remove=True) self.assertTrue(func2.called) # Test changing func3 = Callback(self, changed={"b": "banana"}) foo.on_trait_change(func3.__call__, "d_items") foo.d["b"] = "broccoli" foo.on_trait_change(func3.__call__, "d_items", remove=True) self.assertTrue(func3.called) traits-6.3.2/traits/tests/test_copy_traits.py000066400000000000000000000216011414270267200214560ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import HasTraits, Instance, Str class Shared(HasTraits): s = Str("new instance of Shared") class Foo(HasTraits): s = Str("new instance of Foo") shared = Instance(Shared) class Bar(HasTraits): s = Str("new instance of Bar") foo = Instance(Foo) shared = Instance(Shared) class Baz(HasTraits): s = Str("new instance of Baz") bar = Instance(Bar) shared = Instance(Shared) class CopyTraitsBase(unittest.TestCase): """ Validate that copy_traits """ __test__ = False def setUp(self): super().setUp() self.shared = Shared(s="shared") self.foo = Foo(shared=self.shared, s="foo") self.bar = Bar(shared=self.shared, foo=self.foo, s="bar") self.baz = Baz(shared=self.shared, bar=self.bar, s="baz") self.shared2 = Shared(s="shared2") self.foo2 = Foo(shared=self.shared2, s="foo2") self.bar2 = Bar(shared=self.shared2, foo=self.foo2, s="bar2") self.baz2 = Baz(shared=self.shared2, bar=self.bar2, s="baz2") def set_shared_copy(self, value): """ Change the copy style for the 'shared' traits. """ self.foo.base_trait("shared").copy = value self.bar.base_trait("shared").copy = value self.baz.base_trait("shared").copy = value class TestCopyTraitsSetup(CopyTraitsBase): __test__ = True def setUp(self): super().setUp() def test_setup(self): self.assertIs(self.foo, self.bar.foo) self.assertIs(self.bar, self.baz.bar) self.assertIs(self.foo.shared, self.shared) self.assertIs(self.bar.shared, self.shared) self.assertIs(self.baz.shared, self.shared) self.assertIs(self.foo2, self.bar2.foo) self.assertIs(self.bar2, self.baz2.bar) self.assertIs(self.foo2.shared, self.shared2) self.assertIs(self.bar2.shared, self.shared2) self.assertIs(self.baz2.shared, self.shared2) class CopyTraits(object): def test_baz2_s(self): self.assertEqual(self.baz2.s, "baz") self.assertEqual(self.baz2.s, self.baz.s) def test_baz2_bar_s(self): self.assertEqual(self.baz2.bar.s, "bar") self.assertEqual(self.baz2.bar.s, self.baz.bar.s) def test_baz2_bar_foo_s(self): self.assertEqual(self.baz2.bar.foo.s, "foo") self.assertEqual(self.baz2.bar.foo.s, self.baz.bar.foo.s) def test_baz2_shared_s(self): self.assertEqual(self.baz2.shared.s, "shared") self.assertEqual(self.baz2.bar.shared.s, "shared") self.assertEqual(self.baz2.bar.foo.shared.s, "shared") def test_baz2_bar(self): # First hand Instance trait is different and # is not the same object as the source. self.assertIsNot(self.baz2.bar, None) self.assertIsNot(self.baz2.bar, self.bar2) self.assertIsNot(self.baz2.bar, self.baz.bar) def test_baz2_bar_foo(self): # Second hand Instance trait is a different object and # is not the same object as the source. self.assertIsNot(self.baz2.bar.foo, None) self.assertIsNot(self.baz2.bar.foo, self.foo2) self.assertIsNot(self.baz2.bar.foo, self.baz.bar.foo) class CopyTraitsSharedCopyNone(object): def test_baz2_shared(self): # First hand Instance trait is a different object and # is not the same object as the source. self.assertIsNot(self.baz2.shared, None) self.assertIsNot(self.baz2.shared, self.shared2) self.assertIsNot(self.baz2.shared, self.shared) def test_baz2_bar_shared(self): # Second hand Instance that was shared is a different object and # not the same object as the source and # not the same object as the new first hand instance that was the same. # I.e. There are now (at least) two copies of one original object. self.assertIsNot(self.baz2.bar.shared, None) self.assertIsNot(self.baz2.bar.shared, self.shared2) self.assertIsNot(self.baz2.bar.shared, self.shared) self.assertIsNot(self.baz2.bar.shared, self.baz2.shared) def test_baz2_bar_foo_shared(self): # Third hand Instance that was shared is a different object and # not the same object as the source and # not the same object as the new first hand instance that was the same. # I.e. There are now (at least) two copies of one original object. self.assertIsNot(self.baz2.bar.foo.shared, None) self.assertIsNot(self.baz2.bar.foo.shared, self.shared2) self.assertIsNot(self.baz2.bar.foo.shared, self.shared) self.assertIsNot(self.baz2.bar.foo.shared, self.baz2.shared) def test_baz2_bar_and_foo_shared(self): # # THE BEHAVIOR DEMONSTRATED BY THIS TEST CASE DOES NOT SEEM TO BE # CORRECT. # # Second and Third hand Instance object that was shared with first hand # instance are the same as each other but # Every reference to the same original object has been replace by # a reference to the same copy of the same source object except the # first hand reference which is a different copy. # I.e. The shared relationship has been fubarred by copy_traits: it's # not maintained, but not completely destroyed. self.assertIs(self.baz2.bar.shared, self.baz2.bar.foo.shared) self.assertIsNot(self.baz2.shared, self.baz2.bar.foo.shared) class TestCopyTraitsSharedCopyNone(CopyTraits, CopyTraitsSharedCopyNone): __test__ = False def setUp(self): # deep is the default value for Instance trait copy self.set_shared_copy("deep") class TestCopyTraitsCopyNotSpecified( CopyTraitsBase, TestCopyTraitsSharedCopyNone ): __test__ = True def setUp(self): CopyTraitsBase.setUp(self) TestCopyTraitsSharedCopyNone.setUp(self) self.baz2.copy_traits(self.baz) class TestCopyTraitsCopyShallow(CopyTraitsBase, TestCopyTraitsSharedCopyNone): __test__ = True def setUp(self): CopyTraitsBase.setUp(self) TestCopyTraitsSharedCopyNone.setUp(self) self.baz2.copy_traits(self.baz, copy="shallow") class TestCopyTraitsCopyDeep(CopyTraitsBase, TestCopyTraitsSharedCopyNone): __test__ = True def setUp(self): CopyTraitsBase.setUp(self) TestCopyTraitsSharedCopyNone.setUp(self) self.baz2.copy_traits(self.baz, copy="deep") class CopyTraitsSharedCopyRef(object): def test_baz2_shared(self): # First hand Instance trait is a different object and # is the same object as the source. self.assertIsNot(self.baz2.shared, None) self.assertIsNot(self.baz2.shared, self.shared2) self.assertIs(self.baz2.shared, self.shared) def test_baz2_bar_shared(self): self.assertIsNot(self.baz2.bar.shared, None) self.assertIsNot(self.baz2.bar.shared, self.shared2) self.assertIs(self.baz2.bar.shared, self.shared) self.assertIs(self.baz2.bar.shared, self.baz2.shared) def test_baz2_bar_foo_shared(self): self.assertIsNot(self.baz2.bar.foo.shared, None) self.assertIsNot(self.baz2.bar.foo.shared, self.shared2) self.assertIs(self.baz2.bar.foo.shared, self.shared) self.assertIs(self.baz2.bar.foo.shared, self.baz2.shared) def test_baz2_bar_and_foo_shared(self): self.assertIs(self.baz2.bar.shared, self.baz2.bar.foo.shared) self.assertIs(self.baz2.shared, self.baz2.bar.foo.shared) class TestCopyTraitsSharedCopyRef(CopyTraits, CopyTraitsSharedCopyRef): __test__ = False def setUp(self): self.set_shared_copy("ref") # The next three tests demonstrate that a 'ref' trait is always copied as a # reference regardless of the copy argument to copy_traits. That is, shallow # and deep are indistinguishable. class TestCopyTraitsCopyNotSpecifiedSharedRef( CopyTraitsBase, TestCopyTraitsSharedCopyRef ): __test__ = True def setUp(self): CopyTraitsBase.setUp(self) TestCopyTraitsSharedCopyRef.setUp(self) self.baz2.copy_traits(self.baz) class TestCopyTraitsCopyShallowSharedRef( CopyTraitsBase, TestCopyTraitsSharedCopyRef ): __test__ = True def setUp(self): CopyTraitsBase.setUp(self) TestCopyTraitsSharedCopyRef.setUp(self) self.baz2.copy_traits(self.baz, copy="shallow") class TestCopyTraitsCopyDeepSharedRef( CopyTraitsBase, TestCopyTraitsSharedCopyRef ): __test__ = True def setUp(self): CopyTraitsBase.setUp(self) TestCopyTraitsSharedCopyRef.setUp(self) self.baz2.copy_traits(self.baz, copy="deep") traits-6.3.2/traits/tests/test_copyable_trait_names.py000066400000000000000000000066051414270267200233110ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import ( HasTraits, Any, Bool, Delegate, Event, Instance, Property, Str, ) class Foo(HasTraits): a = Any b = Bool s = Str i = Instance(HasTraits) e = Event d = Delegate("i") p = Property def _get_p(self): return self._p def _set_p(self, p): self._p = p # Read Only Property p_ro = Property def _get_p_ro(self): return id(self) # Write-only property p_wo = Property def _set_p_wo(self, p_wo): self._p_wo = p_wo class TestCopyableTraitNames(unittest.TestCase): """ Validate that copyable_trait_names returns the appropriate result. """ def setUp(self): foo = Foo() self.names = foo.copyable_trait_names() def test_events_not_copyable(self): self.assertNotIn("e", self.names) def test_read_only_property_not_copyable(self): self.assertNotIn("p_ro", self.names) def test_write_only_property_not_copyable(self): self.assertNotIn("p_wo", self.names) def test_any_copyable(self): self.assertIn("a", self.names) def test_bool_copyable(self): self.assertIn("b", self.names) def test_str_copyable(self): self.assertIn("s", self.names) def test_instance_copyable(self): self.assertIn("i", self.names) def test_delegate_copyable(self): self.assertIn("d", self.names) def test_property_copyable(self): self.assertIn("p", self.names) class TestCopyableTraitNameQueries(unittest.TestCase): def setUp(self): self.foo = Foo() def test_type_query(self): names = self.foo.copyable_trait_names(**{"type": "trait"}) self.assertEqual(["a", "b", "i", "s"], sorted(names)) names = self.foo.copyable_trait_names( **{"type": lambda t: t in ("trait", "property")} ) self.assertEqual(["a", "b", "i", "p", "s"], sorted(names)) def test_property_query(self): names = self.foo.copyable_trait_names( **{"property_fields": lambda p: p and p[1].__name__ == "_set_p"} ) self.assertEqual(["p"], names) def test_unmodified_query(self): names = self.foo.copyable_trait_names( **{"is_trait_type": lambda f: f(Str)} ) self.assertEqual(["s"], names) def test_queries_not_combined(self): """ Verify that metadata is not merged with metadata to find the copyable traits. """ eval_true = lambda x: True names = self.foo.copyable_trait_names( property=eval_true, type=eval_true, transient=eval_true ) self.assertEqual( [ "a", "b", "d", "e", "i", "p", "p_ro", "p_wo", "s", "trait_added", "trait_modified", ], sorted(names), ) traits-6.3.2/traits/tests/test_ctraits.py000066400000000000000000000262351414270267200205770ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import sys import unittest.mock import warnings import weakref from traits.api import HasTraits from traits.constants import ( ComparisonMode, DefaultValue, TraitKind, MAXIMUM_DEFAULT_VALUE_TYPE ) from traits.ctrait import CTrait from traits.trait_errors import TraitError from traits.trait_types import Any, Int, List def getter(): """ Trivial getter. """ return True def setter(value): """ Trivial setter. """ pass def validator(value): """ Trivial validator. """ return value class TestCTrait(unittest.TestCase): """ Tests for the CTrait class. """ def test_initial_default_value(self): trait = CTrait(TraitKind.trait) self.assertEqual( trait.default_value(), (DefaultValue.constant, None), ) def test_set_and_get_default_value(self): trait = CTrait(TraitKind.trait) trait.set_default_value(DefaultValue.constant, 2.3) self.assertEqual(trait.default_value(), (DefaultValue.constant, 2.3)) trait.set_default_value(DefaultValue.list_copy, [1, 2, 3]) self.assertEqual( trait.default_value(), (DefaultValue.list_copy, [1, 2, 3]) ) def test_default_value_for_set_is_deprecated(self): trait = CTrait(TraitKind.trait) with warnings.catch_warnings(record=True) as warn_msgs: warnings.simplefilter("always", DeprecationWarning) trait.default_value(DefaultValue.constant, 3.7) self.assertEqual(len(warn_msgs), 1) warn_msg = warn_msgs[0] self.assertIn( "default_value method with arguments is deprecated", str(warn_msg.message), ) _, _, this_module = __name__.rpartition(".") self.assertIn(this_module, warn_msg.filename) def test_bad_default_value_type(self): trait = CTrait(TraitKind.trait) with self.assertRaises(ValueError): trait.set_default_value(-1, None) with self.assertRaises(ValueError): trait.set_default_value(MAXIMUM_DEFAULT_VALUE_TYPE + 1, None) def test_is_property(self): trait = CTrait(TraitKind.trait) self.assertFalse(trait.is_property) trait.property_fields = (getter, setter, validator) self.assertTrue(trait.is_property) with self.assertRaises(AttributeError): trait.is_property = False def test_get_set_property(self): trait = CTrait(TraitKind.trait) # Get the property, ensure None self.assertIsNone(trait.property_fields) def value_get(self): return self.__dict__.get("_value", 0) def value_set(self, value): old_value = self.__dict__.get("_value", 0) if value != old_value: self._value = value self.trait_property_changed("value", old_value, value) # Set the callables trait.property_fields = (value_get, value_set, None) fget, fset, validate = trait.property_fields self.assertIs(fget, value_get) self.assertIs(fset, value_set) self.assertIsNone(validate) # Ensure that _get_property does not accept arguments. with self.assertRaises(TypeError): trait._get_property(fget) def test_modify_delegate(self): trait = CTrait(TraitKind.trait) self.assertFalse(trait.modify_delegate) trait.modify_delegate = True self.assertTrue(trait.modify_delegate) def test_setattr_original_value(self): trait = CTrait(TraitKind.trait) self.assertFalse(trait.setattr_original_value) trait.setattr_original_value = True self.assertTrue(trait.setattr_original_value) def test_post_setattr_original_value(self): trait = CTrait(TraitKind.trait) self.assertFalse(trait.post_setattr_original_value) trait.post_setattr_original_value = True self.assertTrue(trait.post_setattr_original_value) def test_is_mapped(self): trait = CTrait(TraitKind.trait) self.assertFalse(trait.is_mapped) trait.is_mapped = True self.assertTrue(trait.is_mapped) def test_default_comparison_mode(self): trait = CTrait(TraitKind.trait) self.assertIsInstance(trait.comparison_mode, ComparisonMode) self.assertEqual(trait.comparison_mode, ComparisonMode.equality) def test_invalid_comparison_mode(self): trait = CTrait(TraitKind.trait) # comparison modes other than {0,1,2} # are invalid with self.assertRaises(ValueError): trait.comparison_mode = -1 with self.assertRaises(ValueError): trait.comparison_mode = 3 def test_comparison_mode_unchanged_if_invalid(self): trait = CTrait(TraitKind.trait) default_comparison_mode = trait.comparison_mode self.assertNotEqual(default_comparison_mode, ComparisonMode.none) trait.comparison_mode = ComparisonMode.none with self.assertRaises(ValueError): trait.comparison_mode = -1 self.assertEqual(trait.comparison_mode, ComparisonMode.none) def test_comparison_mode_int(self): trait = CTrait(TraitKind.trait) trait.comparison_mode = 0 self.assertIsInstance(trait.comparison_mode, ComparisonMode) self.assertEqual(trait.comparison_mode, ComparisonMode.none) trait.comparison_mode = 1 self.assertIsInstance(trait.comparison_mode, ComparisonMode) self.assertEqual(trait.comparison_mode, ComparisonMode.identity) trait.comparison_mode = 2 self.assertIsInstance(trait.comparison_mode, ComparisonMode) self.assertEqual(trait.comparison_mode, ComparisonMode.equality) def test_comparison_mode_enum(self): trait = CTrait(TraitKind.trait) trait.comparison_mode = ComparisonMode.none self.assertIsInstance(trait.comparison_mode, ComparisonMode) self.assertEqual(trait.comparison_mode, ComparisonMode.none) trait.comparison_mode = ComparisonMode.identity self.assertIsInstance(trait.comparison_mode, ComparisonMode) self.assertEqual(trait.comparison_mode, ComparisonMode.identity) trait.comparison_mode = ComparisonMode.equality self.assertIsInstance(trait.comparison_mode, ComparisonMode) self.assertEqual(trait.comparison_mode, ComparisonMode.equality) def test_assign_post_setattr_none(self): old_value = "old_value" new_value = "new_value" def post_setattr_func(obj, name, value): obj.output_variable = value trait = CTrait(TraitKind.trait) class TestClass(HasTraits): atr = trait trait.post_setattr = post_setattr_func self.assertIsNotNone(trait.post_setattr) obj = TestClass() obj.atr = old_value self.assertEqual(old_value, obj.output_variable) trait.post_setattr = None self.assertIsNone(trait.post_setattr) obj.atr = new_value self.assertEqual(old_value, obj.output_variable) trait.post_setattr = post_setattr_func obj.atr = old_value self.assertEqual(old_value, obj.output_variable) with self.assertRaises(ValueError): trait.post_setattr = "Invalid" def test_unsafe_set_value(self): # Regression test for enthought/traits#832. The test below causes # a segfault (on at least some systems) before the fix. def get_handler_refcount(): sys.getrefcount(tr.handler) # Anything that we can create a weakref to works here. weakrefable_object = {1, 2, 3} tr = CTrait(0) tr.handler = Any(weakrefable_object) finalizer = weakref.finalize(weakrefable_object, get_handler_refcount) del weakrefable_object # Reassigning the handler should trigger the finaliser. self.assertTrue(finalizer.alive) tr.handler = None self.assertFalse(finalizer.alive) self.assertIsNone(tr.handler) def test_invalid_initialization(self): with self.assertRaises(TraitError): CTrait(max(TraitKind) + 1) def test_initialization_with_keywords_fails(self): with self.assertRaises(TraitError): CTrait(kind=0) def test_default_initialization(self): ctrait = CTrait() validate = unittest.mock.MagicMock(return_value="baz") ctrait.set_validate(validate) class Foo(HasTraits): bar = ctrait bar_changed = List def _bar_changed(self, new): self.bar_changed.append(new) foo = Foo() self.assertEqual(len(foo.bar_changed), 0) foo.bar = 1 validate.assert_called_once_with(foo, "bar", 1) self.assertEqual(foo.bar, "baz") self.assertEqual(len(foo.bar_changed), 1) self.assertEqual(foo.bar_changed[0], "baz") def test_failed_attribute_access(self): # Double-underscore names are special-cased. non_dunder_names = [ "non_existent", "__non_existent", "non_existent__", "_non_existent_", "__a__b_", "_", ] dunder_names = [ "__package__", "__a__", "____", "___", "__", ] ctrait = CTrait(0) for name in non_dunder_names: with self.subTest(name=name): self.assertIsNone(getattr(ctrait, name)) for name in dunder_names: with self.subTest(name=name): with self.assertRaises(AttributeError): getattr(ctrait, name) def test_exception_from_attribute_access(self): # Regression test for enthought/traits#946. # Danger: we're (temporarily) mutating global state here! Check that # we're not touching an attribute that actually exists. self.assertFalse(hasattr(CTrait, "badattr_test")) CTrait.badattr_test = property(lambda self: 1 / 0) try: ctrait = CTrait(0) with self.assertRaises(ZeroDivisionError): ctrait.badattr_test finally: del CTrait.badattr_test class TestCTraitNotifiers(unittest.TestCase): """ Test calling trait notifiers and object notifiers. """ def test_notifiers_empty(self): class Foo(HasTraits): x = Int() foo = Foo(x=1) x_ctrait = foo.trait("x") self.assertEqual(x_ctrait._notifiers(True), []) def test_notifiers_on_trait(self): class Foo(HasTraits): x = Int() def _x_changed(self): pass foo = Foo(x=1) x_ctrait = foo.trait("x") tnotifiers = x_ctrait._notifiers(True) self.assertEqual(len(tnotifiers), 1) notifier, = tnotifiers self.assertEqual(notifier.handler, Foo._x_changed) traits-6.3.2/traits/tests/test_cythonized_traits.py000066400000000000000000000115261414270267200226710ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test some usage of Trait classes when the code is cythonized. The tests reflects some of the patterns needed in different applications. They probably don't cover all of the user case. Each test case is written as if the test code was in a separate module then compiled with Cython Inline before evaluation the produced object behaves properly. The tests need a Cython version > 0.19 and a compiler. """ import unittest from traits.testing.unittest_tools import UnittestTools from traits.testing.optional_dependencies import cython, requires_cython @requires_cython class CythonizedTraitsTestCase(unittest.TestCase, UnittestTools): def test_simple_default_methods(self): code = """ from traits.api import HasTraits, Str class Test(HasTraits): name = Str def _name_default(self): return 'Joe' return Test() """ obj = self.execute(code) self.assertEqual(obj.name, "Joe") def test_basic_events(self): code = """ from traits.api import HasTraits, Str class Test(HasTraits): name = Str return Test() """ obj = self.execute(code) with self.assertTraitChanges(obj, "name", count=1): obj.name = "changing_name" def test_on_trait_static_handlers(self): code = """ from traits.api import HasTraits, Str, Int class Test(HasTraits): name = Str value = Int def _name_changed(self): self.value += 1 return Test() """ obj = self.execute(code) with self.assertTraitChanges(obj, "value", count=1): obj.name = "changing_name" self.assertEqual(obj.value, 1) def test_on_trait_on_trait_change_decorator(self): code = """ from traits.api import HasTraits, Str, Int, on_trait_change class Test(HasTraits): name = Str value = Int @on_trait_change('name') def _update_value(self): self.value += 1 return Test() """ obj = self.execute(code) with self.assertTraitChanges(obj, "value", count=1): obj.name = "changing_name" self.assertEqual(obj.value, 1) def test_on_trait_properties(self): code = """ from traits.api import HasTraits, Str, Int, Property, cached_property class Test(HasTraits): name = Str name_len = Property(depends_on='name') @cached_property def _get_name_len(self): return len(self.name) return Test() """ obj = self.execute(code) self.assertEqual(obj.name_len, len(obj.name)) # Assert dependency works obj.name = "Bob" self.assertEqual(obj.name_len, len(obj.name)) def test_on_trait_properties_with_standard_getter(self): code = """ from traits.api import HasTraits, Str, Int, Property class Test(HasTraits): name = Str def _get_name_length(self): return len(self.name) name_len = Property(_get_name_length) return Test() """ obj = self.execute(code) self.assertEqual(obj.name_len, len(obj.name)) # Assert dependency works obj.name = "Bob" self.assertEqual(obj.name_len, len(obj.name)) def test_on_trait_aliasing(self): code = """ from traits.api import HasTraits, Str, Int, Property def Alias(name): def _get_value(self): return getattr(self, name) def _set_value(self, value): return setattr(self, name, value) return Property(_get_value, _set_value) class Test(HasTraits): name = Str funky_name = Alias('name') return Test() """ obj = self.execute(code) self.assertEqual(obj.funky_name, obj.name) # Assert dependency works obj.name = "Bob" self.assertEqual(obj.funky_name, obj.name) def test_on_trait_aliasing_different_scope(self): code = """ from traits.api import HasTraits, Str, Int, Property def _get_value(self, name): return getattr(self, 'name') def _set_value(self, name, value): return setattr(self, 'name', value) class Test(HasTraits): name = Str funky_name = Property(_get_value, _set_value) return Test() """ obj = self.execute(code) self.assertEqual(obj.funky_name, obj.name) # Assert dependency works obj.name = "Bob" self.assertEqual(obj.funky_name, obj.name) def execute(self, code): """ Helper function to execute the given code under cython.inline and return the result. """ return cython.inline( code, force=True, language_level="3", ) traits-6.3.2/traits/tests/test_date.py000066400000000000000000000123061414270267200200350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the Date trait type. """ import datetime import unittest from traits.testing.optional_dependencies import requires_traitsui, traitsui from traits.api import Date, HasStrictTraits, TraitError #: Unix epoch date. UNIX_EPOCH = datetime.date(1970, 1, 1) #: Windows NT epoch NT_EPOCH = datetime.date(1600, 1, 1) class HasDateTraits(HasStrictTraits): #: Simple case - no default, no parameters, no metadata simple_date = Date() #: Date with default epoch = Date(UNIX_EPOCH) #: Date with default provided via keyword. alternative_epoch = Date(default_value=NT_EPOCH) #: Datetime instances prohibited datetime_prohibited = Date(allow_datetime=False) #: Datetime instances allowed datetime_allowed = Date(allow_datetime=True) #: None prohibited none_prohibited = Date(allow_none=False) #: None allowed none_allowed = Date(allow_none=True) #: Strictly a non-None non-datetime date strict = Date(allow_datetime=False, allow_none=False) class TestDate(unittest.TestCase): def test_default(self): obj = HasDateTraits() self.assertEqual(obj.simple_date, None) self.assertEqual(obj.epoch, UNIX_EPOCH) self.assertEqual(obj.alternative_epoch, NT_EPOCH) def test_assign_date(self): test_date = datetime.date(1975, 2, 13) obj = HasDateTraits() obj.simple_date = test_date self.assertEqual(obj.simple_date, test_date) def test_assign_non_date(self): obj = HasDateTraits() with self.assertRaises(TraitError) as exception_context: obj.simple_date = "1975-2-13" message = str(exception_context.exception) self.assertIn("must be a date or None, but", message) def test_assign_none_with_allow_none_not_given(self): obj = HasDateTraits(simple_date=UNIX_EPOCH) self.assertIsNotNone(obj.simple_date) with self.assertWarns(DeprecationWarning) as warnings_cm: obj.simple_date = None self.assertIsNone(obj.simple_date) _, _, this_module = __name__.rpartition(".") self.assertIn(this_module, warnings_cm.filename) self.assertIn( "None will no longer be accepted", str(warnings_cm.warning), ) def test_assign_none_with_allow_none_false(self): obj = HasDateTraits(none_prohibited=UNIX_EPOCH) with self.assertRaises(TraitError) as exception_context: obj.none_prohibited = None message = str(exception_context.exception) self.assertIn("must be a date, but", message) def test_assign_none_with_allow_none_true(self): obj = HasDateTraits(none_allowed=UNIX_EPOCH) self.assertIsNotNone(obj.none_allowed) obj.none_allowed = None self.assertIsNone(obj.none_allowed) def test_assign_datetime_with_allow_datetime_false(self): test_datetime = datetime.datetime(1975, 2, 13) obj = HasDateTraits() with self.assertRaises(TraitError) as exception_context: obj.datetime_prohibited = test_datetime message = str(exception_context.exception) self.assertIn("must be a non-datetime date or None, but", message) def test_assign_datetime_with_allow_datetime_true(self): test_datetime = datetime.datetime(1975, 2, 13) obj = HasDateTraits() obj.datetime_allowed = test_datetime self.assertEqual(obj.datetime_allowed, test_datetime) def test_assign_datetime_with_allow_datetime_not_given(self): # For traits where "allow_datetime" is not specified, a # DeprecationWarning should be issued on assignment of datetime. test_datetime = datetime.datetime(1975, 2, 13) obj = HasDateTraits() with self.assertWarns(DeprecationWarning) as warnings_cm: # Note: the warning depends on the type, not the value; this case # should warn even though the time component of the datetime is # zero. obj.simple_date = test_datetime self.assertEqual(obj.simple_date, test_datetime) _, _, this_module = __name__.rpartition(".") self.assertIn(this_module, warnings_cm.filename) self.assertIn( "datetime instances will no longer be accepted", str(warnings_cm.warning), ) def test_allow_none_false_allow_datetime_false(self): obj = HasDateTraits(strict=UNIX_EPOCH) with self.assertRaises(TraitError) as exception_context: obj.strict = None message = str(exception_context.exception) self.assertIn("must be a non-datetime date, but", message) @requires_traitsui def test_get_editor(self): obj = HasDateTraits() trait = obj.base_trait("epoch") editor_factory = trait.get_editor() self.assertIsInstance(editor_factory, traitsui.api.DateEditor) traits-6.3.2/traits/tests/test_datetime.py000066400000000000000000000073071414270267200207210ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the Datetime trait type. """ import datetime import unittest from traits.testing.optional_dependencies import requires_traitsui, traitsui from traits.api import Datetime, HasStrictTraits, TraitError #: Unix epoch UNIX_EPOCH = datetime.datetime(1970, 1, 1, 0, 0) #: Windows NT epoch NT_EPOCH = datetime.datetime(1600, 1, 1, 0, 0) class HasDatetimeTraits(HasStrictTraits): #: Simple case - no default, no parameters, no metadata simple_datetime = Datetime() #: Datetime with default epoch = Datetime(UNIX_EPOCH) #: Datetime with default provided via keyword. alternative_epoch = Datetime(default_value=NT_EPOCH) #: None prohibited none_prohibited = Datetime(allow_none=False) #: None allowed none_allowed = Datetime(allow_none=True) class TestDatetime(unittest.TestCase): def test_default(self): obj = HasDatetimeTraits() self.assertEqual(obj.simple_datetime, None) self.assertEqual(obj.epoch, UNIX_EPOCH) self.assertEqual(obj.alternative_epoch, NT_EPOCH) def test_assign_datetime(self): # By default, datetime instances are permitted. test_datetime = datetime.datetime(1975, 2, 13) obj = HasDatetimeTraits() obj.simple_datetime = test_datetime self.assertEqual(obj.simple_datetime, test_datetime) def test_assign_non_datetime(self): obj = HasDatetimeTraits() with self.assertRaises(TraitError) as exception_context: obj.simple_datetime = "2021-02-05 12:00:00" message = str(exception_context.exception) self.assertIn("must be a datetime or None, but", message) def test_assign_date(self): obj = HasDatetimeTraits() with self.assertRaises(TraitError) as exception_context: obj.simple_datetime = datetime.date(1975, 2, 13) message = str(exception_context.exception) self.assertIn("must be a datetime or None, but", message) self.assertIsNone(obj.simple_datetime) def test_assign_none_with_allow_none_not_given(self): obj = HasDatetimeTraits(simple_datetime=UNIX_EPOCH) self.assertIsNotNone(obj.simple_datetime) with self.assertWarns(DeprecationWarning) as warnings_cm: obj.simple_datetime = None self.assertIsNone(obj.simple_datetime) _, _, this_module = __name__.rpartition(".") self.assertIn(this_module, warnings_cm.filename) self.assertIn( "None will no longer be accepted", str(warnings_cm.warning), ) def test_assign_none_with_allow_none_false(self): obj = HasDatetimeTraits(none_prohibited=UNIX_EPOCH) with self.assertRaises(TraitError) as exception_context: obj.none_prohibited = None message = str(exception_context.exception) self.assertIn("must be a datetime, but", message) def test_assign_none_with_allow_none_true(self): obj = HasDatetimeTraits(none_allowed=UNIX_EPOCH) self.assertIsNotNone(obj.none_allowed) obj.none_allowed = None self.assertIsNone(obj.none_allowed) @requires_traitsui def test_get_editor(self): obj = HasDatetimeTraits() trait = obj.base_trait("epoch") editor_factory = trait.get_editor() self.assertIsInstance(editor_factory, traitsui.api.DatetimeEditor) traits-6.3.2/traits/tests/test_delegate.py000066400000000000000000000210141414270267200206660ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import Delegate, HasTraits, Instance, Str # global because event handlers are being called with wrong value for self baz_s_handler_self = None baz_sd_handler_self = None baz_u_handler_self = None baz_t_handler_self = None foo_s_handler_self = None foo_t_handler_self = None class Foo(HasTraits): s = Str("foo") t = Str("foo.t") u = Str("foo.u") def _s_changed(self, name, old, new): global foo_s_handler_self foo_s_handler_self = self def _t_changed(self, name, old, new): global foo_t_handler_self foo_t_handler_self = self class Bar(HasTraits): foo = Instance(Foo, ()) s = Delegate("foo") class BazModify(HasTraits): foo = Instance(Foo, ()) sd = Delegate("foo", prefix="s", modify=True) t = Delegate("foo", modify=True) u = Delegate("foo", listenable=False, modify=True) def _s_changed(self, name, old, new): # should never be called global baz_s_handler_self baz_s_handler_self = self def _sd_changed(self, name, old, new): global baz_sd_handler_self baz_sd_handler_self = self def _t_changed(self, name, old, new): global baz_t_handler_self baz_t_handler_self = self def _u_changed(self, name, old, new): global baz_u_handler_self baz_u_handler_self = self class BazNoModify(HasTraits): foo = Instance(Foo, ()) sd = Delegate("foo", prefix="s") t = Delegate("foo") u = Delegate("foo", listenable=False) def _s_changed(self, name, old, new): global baz_s_handler_self baz_s_handler_self = self def _sd_changed(self, name, old, new): global baz_sd_handler_self baz_sd_handler_self = self def _t_changed(self, name, old, new): global baz_t_handler_self baz_t_handler_self = self def _u_changed(self, name, old, new): global baz_u_handler_self baz_u_handler_self = self class DelegateTestCase(unittest.TestCase): """ Test cases for delegated traits. """ def setUp(self): """ Reset all of the globals. """ global baz_s_handler_self, baz_sd_handler_self, baz_u_handler_self global baz_t_handler_self, foo_s_handler_self, foo_t_handler_self baz_s_handler_self = None baz_sd_handler_self = None baz_u_handler_self = None baz_t_handler_self = None foo_s_handler_self = None foo_t_handler_self = None def test_reset(self): """ Test that a delegated trait may be reset. Deleting the attribute should reset the trait back to its initial delegation behavior. """ f = Foo() b = Bar(foo=f) # Check initial delegation. self.assertEqual(f.s, b.s) # Check that an override works. b.s = "bar" self.assertNotEqual(f.s, b.s) # Check that we can reset back to delegation. This is what we are # really testing for. del b.s self.assertEqual(f.s, b.s) # Below are 8 tests to check the calling of change notification handlers. # There are 8 cases for the 2x2x2 matrix with axes: # Delegate with prefix or not # Delegate with modify write through or not # Handler in the delegator and delegatee def test_modify_prefix_handler_on_delegator(self): f = Foo() b = BazModify(foo=f) self.assertEqual(f.s, b.sd) b.sd = "changed" self.assertEqual(f.s, b.sd) # Don't expect _s_changed to be called because from Baz's perspective # the trait is named 'sd' self.assertEqual(baz_s_handler_self, None) # Do expect '_sd_changed' to be called with b as self self.assertEqual(baz_sd_handler_self, b) def test_modify_prefix_handler_on_delegatee(self): f = Foo() b = BazModify(foo=f) self.assertEqual(f.s, b.sd) b.sd = "changed" self.assertEqual(f.s, b.sd) # Foo expects its '_s_changed' handler to be called with f as self self.assertEqual(foo_s_handler_self, f) def test_no_modify_prefix_handler_on_delegator(self): f = Foo() b = BazNoModify(foo=f) self.assertEqual(f.s, b.sd) b.sd = "changed" self.assertNotEqual(f.s, b.sd) # Don't expect _s_changed to be called because from Baz's perspective # the trait is named 'sd' self.assertEqual(baz_s_handler_self, None) # Do expect '_sd_changed' to be called with b as self self.assertEqual(baz_sd_handler_self, b) def test_no_modify_prefix_handler_on_delegatee_not_called(self): f = Foo() b = BazNoModify(foo=f) self.assertEqual(f.s, b.sd) b.sd = "changed" self.assertNotEqual(f.s, b.sd) # Foo expects its '_s_changed' handler to be called with f as self self.assertEqual(foo_s_handler_self, None) def test_modify_handler_on_delegator(self): f = Foo() b = BazModify(foo=f) self.assertEqual(f.t, b.t) b.t = "changed" self.assertEqual(f.t, b.t) # Do expect '_t_changed' to be called with b as self self.assertEqual(baz_t_handler_self, b) def test_modify_handler_on_delegatee(self): f = Foo() b = BazModify(foo=f) self.assertEqual(f.t, b.t) b.t = "changed" self.assertEqual(f.t, b.t) # Foo t did change so '_t_changed' handler should be called self.assertEqual(foo_t_handler_self, f) def test_no_modify_handler_on_delegator(self): f = Foo() b = BazNoModify(foo=f) self.assertEqual(f.t, b.t) b.t = "changed" self.assertNotEqual(f.t, b.t) # Do expect '_t_changed' to be called with b as self self.assertEqual(baz_t_handler_self, b) def test_no_modify_handler_on_delegatee_not_called(self): f = Foo() b = BazNoModify(foo=f) self.assertEqual(f.t, b.t) b.t = "changed" self.assertNotEqual(f.t, b.t) # Foo t did not change so '_t_changed' handler should not be called self.assertEqual(foo_t_handler_self, None) # Below are 4 tests for notification when the delegated trait is changed # directly rather than through the delegator. def test_no_modify_handler_on_delegatee_direct_change(self): f = Foo() b = BazNoModify(foo=f) self.assertEqual(f.t, b.t) f.t = "changed" self.assertEqual(f.t, b.t) # Foo t did change so '_t_changed' handler should be called self.assertEqual(foo_t_handler_self, f) def test_no_modify_handler_on_delegator_direct_change(self): f = Foo() b = BazNoModify(foo=f) self.assertEqual(f.t, b.t) f.t = "changed" self.assertEqual(f.t, b.t) # Do expect '_t_changed' to be called with b as self self.assertEqual(baz_t_handler_self, b) def test_modify_handler_on_delegatee_direct_change(self): f = Foo() b = BazModify(foo=f) self.assertEqual(f.t, b.t) f.t = "changed" self.assertEqual(f.t, b.t) # Foo t did change so '_t_changed' handler should be called self.assertEqual(foo_t_handler_self, f) def test_modify_handler_on_delegator_direct_change(self): f = Foo() b = BazModify(foo=f) self.assertEqual(f.t, b.t) f.t = "changed" self.assertEqual(f.t, b.t) # Do expect '_t_changed' to be called with b as self self.assertEqual(baz_t_handler_self, b) # Below are tests which check that we can turn off listenableness. def test_modify_handler_not_listenable(self): f = Foo() b = BazModify(foo=f) self.assertEqual(f.u, b.u) f.u = "changed" self.assertEqual(f.u, b.u) # Do not expect '_u_changed' to be called. self.assertEqual(baz_u_handler_self, None) def test_no_modify_handler_not_listenable(self): f = Foo() b = BazNoModify(foo=f) self.assertEqual(f.u, b.u) f.u = "changed" self.assertEqual(f.u, b.u) # Do not expect '_u_changed' to be called. self.assertEqual(baz_u_handler_self, None) traits-6.3.2/traits/tests/test_deprecated_handlers.py000066400000000000000000000024531414270267200231020ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest import warnings from traits.api import ( TraitDict, TraitList, TraitPrefixList, TraitPrefixMap, TraitTuple, ) class TestTraitHandlerDeprecatedWarnings(unittest.TestCase): def test_handler_warning(self): handlers = { "TraitDict": TraitDict, "TraitList": TraitList, "TraitTuple": TraitTuple, "TraitPrefixList": lambda: TraitPrefixList("one", "two"), "TraitPrefixMap": lambda: TraitPrefixMap({}), } for name, handler_factory in handlers.items(): with self.subTest(handler=name): with warnings.catch_warnings(record=True): warnings.simplefilter("error", DeprecationWarning) with self.assertRaises(DeprecationWarning) as cm: handler_factory() self.assertIn(name, str(cm.exception)) traits-6.3.2/traits/tests/test_dict.py000066400000000000000000000112211414270267200200360ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test cases for dictionary (Dict) traits. """ import unittest from unittest import mock from traits.trait_types import Any, Dict, Event, Str, TraitDictObject from traits.has_traits import HasTraits, on_trait_change from traits.trait_errors import TraitError # fixme: We'd like to use a callable instance for the listener so that we # can maintain state, but traits barfs trying to determine the signature 8^() def create_listener(): """ Create a listener for testing trait notifications. """ def listener(obj, trait_name, old, new): listener.obj = obj listener.trait_name = trait_name listener.new = new listener.old = old listener.called += 1 listener.initialize = lambda: initialize_listener(listener) return initialize_listener(listener) def initialize_listener(listener): """ Initialize a listener so it looks like it hasn't been called. This allows us to re-use the listener without having to create and wire-up a new one. """ listener.obj = None listener.trait_name = None listener.old = None listener.new = None listener.called = 0 return listener # For convenience class TestDict(unittest.TestCase): """ Test cases for dictionary (Dict) traits. """ def test_modified_event(self): class Foo(HasTraits): name = Str modified = Event @on_trait_change("name") def _fire_modified_event(self): self.modified = True class Bar(HasTraits): foos = Dict(Str, Foo) modified = Event @on_trait_change("foos_items,foos.modified") def _fire_modified_event(self, obj, trait_name, old, new): self.modified = True bar = Bar() listener = create_listener() bar.on_trait_change(listener, "modified") # Assign a completely new dictionary. bar.foos = {"dino": Foo(name="dino")} self.assertEqual(1, listener.called) self.assertEqual("modified", listener.trait_name) # Add an item to an existing dictionary. listener.initialize() fred = Foo(name="fred") bar.foos["fred"] = fred self.assertEqual(1, listener.called) self.assertEqual("modified", listener.trait_name) # Modify an item already in the dictionary. listener.initialize() fred.name = "barney" self.assertEqual(1, listener.called) self.assertEqual("modified", listener.trait_name) # Overwrite an item in the dictionary. This is the one that fails! listener.initialize() bar.foos["fred"] = Foo(name="wilma") self.assertEqual(1, listener.called) self.assertEqual("modified", listener.trait_name) def test_validate(self): """ Check the validation method. """ foo = Dict() # invalid value with self.assertRaises(TraitError): foo.validate(object=HasTraits(), name="bar", value=None) # valid value result = foo.validate(object=HasTraits(), name="bar", value={}) self.assertIsInstance(result, TraitDictObject) # object is None (check for issue #71) result = foo.validate(object=None, name="bar", value={}) self.assertEqual(result, {}) def test_validate_key(self): class Foo(HasTraits): mapping = Dict(Str) foo = Foo(mapping={}) # This is okay foo.mapping["a"] = 1 # This raises with self.assertRaises(TraitError): foo.mapping[1] = 1 def test_validate_value(self): class Foo(HasTraits): mapping = Dict(Any, Str) foo = Foo(mapping={}) # This is okay foo.mapping["a"] = "1" # This raises with self.assertRaises(TraitError): foo.mapping["a"] = 1 def test_items_set_to_false(self): class Foo(HasTraits): mapping = Dict(items=False) handler = mock.Mock() # Setting items to false effectively switches off # notifications on mapping_items foo = Foo(mapping={}) foo.on_trait_change(lambda: handler(), name="mapping_items") # when foo.mapping["1"] = 1 # then handler.assert_not_called() traits-6.3.2/traits/tests/test_directory.py000066400000000000000000000100331414270267200211170ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import pathlib from tempfile import gettempdir import unittest from traits.api import BaseDirectory, Directory, HasTraits, TraitError class ExampleModel(HasTraits): path = Directory(exists=True) new_path = Directory(exists=False) class ExistsBaseDirectory(HasTraits): path = BaseDirectory(value=pathlib.Path(gettempdir()), exists=True) class SimpleBaseDirectory(HasTraits): path = BaseDirectory(exists=False) class DirectoryTestCase(unittest.TestCase): def test_valid_directory(self): example_model = ExampleModel(path=gettempdir()) example_model.path = "." def test_invalid_directory(self): example_model = ExampleModel(path=gettempdir()) def assign_invalid(): example_model.path = "not_valid_path!#!#!#" self.assertRaises(TraitError, assign_invalid) def test_file(self): example_model = ExampleModel(path=gettempdir()) def assign_invalid(): example_model.path = __file__ self.assertRaises(TraitError, assign_invalid) def test_invalid_type(self): example_model = ExampleModel(path=gettempdir()) def assign_invalid(): example_model.path = 11 self.assertRaises(TraitError, assign_invalid) class TestBaseDirectory(unittest.TestCase): def test_accepts_valid_dir_name(self): foo = ExistsBaseDirectory() tempdir = gettempdir() self.assertIsInstance(tempdir, str) foo.path = tempdir def test_rejects_invalid_dir_name(self): foo = ExistsBaseDirectory() with self.assertRaises(TraitError): foo.path = "!!!invalid_directory" def test_rejects_valid_file_name(self): foo = ExistsBaseDirectory() with self.assertRaises(TraitError): foo.path = __file__ def test_accepts_valid_pathlib_dir(self): foo = ExistsBaseDirectory() foo.path = pathlib.Path(gettempdir()) self.assertIsInstance(foo.path, str) def test_rejects_invalid_pathlib_dir(self): foo = ExistsBaseDirectory() with self.assertRaises(TraitError): foo.path = pathlib.Path("!!!invalid_directory") def test_rejects_valid_pathlib_file(self): foo = ExistsBaseDirectory() with self.assertRaises(TraitError): foo.path = pathlib.Path(__file__) def test_rejects_invalid_type(self): """ Rejects instances that are not `str` or `os.PathLike`. """ foo = ExistsBaseDirectory() with self.assertRaises(TraitError): foo.path = 1 with self.assertRaises(TraitError): foo.path = b"!!!invalid_directory" def test_simple_accepts_any_name(self): """ BaseDirectory with no existence check accepts any path name. """ foo = SimpleBaseDirectory() foo.path = "!!!invalid_directory" def test_simple_accepts_any_pathlib(self): """ BaseDirectory with no existence check accepts any pathlib path. """ foo = SimpleBaseDirectory() foo.path = pathlib.Path("!!!") self.assertIsInstance(foo.path, str) def test_info_text(self): example_model = ExampleModel() with self.assertRaises(TraitError) as exc_cm: example_model.path = 47 self.assertIn("a string or os.PathLike object", str(exc_cm.exception)) self.assertIn( "referring to an existing directory", str(exc_cm.exception)) with self.assertRaises(TraitError) as exc_cm: example_model.new_path = 47 self.assertIn("a string or os.PathLike object", str(exc_cm.exception)) self.assertNotIn("exist", str(exc_cm.exception)) traits-6.3.2/traits/tests/test_dynamic_notifiers.py000066400000000000000000000236761414270267200226420ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the dynamic notifiers. """ import gc import unittest from traits import trait_notifiers from traits.api import Event, Float, HasTraits, List, on_trait_change class DynamicNotifiers(HasTraits): ok = Float fail = Float priority_test = Event # Lists where we accumulate the arguments of calls to the traits notifiers. rebind_calls_0 = List rebind_calls_1 = List rebind_calls_2 = List rebind_calls_3 = List rebind_calls_4 = List exceptions_from = List prioritized_notifications = List #### 'ok' trait listeners @on_trait_change("ok") def method_listener_0(self): self.rebind_calls_0.append(True) @on_trait_change("ok") def method_listener_1(self, new): self.rebind_calls_1.append(new) @on_trait_change("ok") def method_listener_2(self, name, new): self.rebind_calls_2.append((name, new)) @on_trait_change("ok") def method_listener_3(self, obj, name, new): self.rebind_calls_3.append((obj, name, new)) @on_trait_change("ok") def method_listener_4(self, obj, name, old, new): self.rebind_calls_4.append((obj, name, old, new)) #### 'fail' trait listeners @on_trait_change("fail") def failing_method_listener_0(self): self.exceptions_from.append(0) raise Exception("error") @on_trait_change("fail") def failing_method_listener_1(self, new): self.exceptions_from.append(1) raise Exception("error") @on_trait_change("fail") def failing_method_listener_2(self, name, new): self.exceptions_from.append(2) raise Exception("error") @on_trait_change("fail") def failing_method_listener_3(self, obj, name, new): self.exceptions_from.append(3) raise Exception("error") @on_trait_change("fail") def failing_method_listener_4(self, obj, name, old, new): self.exceptions_from.append(4) raise Exception("error") def low_priority_first(self): self.prioritized_notifications.append(0) def high_priority_first(self): self.prioritized_notifications.append(1) def low_priority_second(self): self.prioritized_notifications.append(2) def high_priority_second(self): self.prioritized_notifications.append(3) class UnhashableDynamicNotifiers(DynamicNotifiers): """ Class that cannot be used as a key in a dictionary. """ a_list = List def __hash__(self): raise NotImplementedError() def __eq__(self): raise NotImplementedError() class TestDynamicNotifiers(unittest.TestCase): #### 'TestCase' protocol ################################################## def setUp(self): self.exceptions = [] trait_notifiers.push_exception_handler(self._handle_exception) def tearDown(self): trait_notifiers.pop_exception_handler() #### Private protocol ##################################################### def _handle_exception(self, obj, name, old, new): self.exceptions.append((obj, name, old, new)) #### Tests ################################################################ def test_dynamic_notifiers_methods(self): obj = DynamicNotifiers(ok=2) obj.ok = 3 self.assertEqual(len(obj.rebind_calls_0), 2) expected_1 = [2, 3] self.assertEqual(expected_1, obj.rebind_calls_1) expected_2 = [("ok", 2), ("ok", 3)] self.assertEqual(expected_2, obj.rebind_calls_2) expected_3 = [(obj, "ok", 2), (obj, "ok", 3)] self.assertEqual(expected_3, obj.rebind_calls_3) expected_4 = [(obj, "ok", 0, 2), (obj, "ok", 2, 3)] self.assertEqual(expected_4, obj.rebind_calls_4) def test_dynamic_notifiers_methods_failing(self): obj = DynamicNotifiers() obj.fail = 1 self.assertCountEqual([0, 1, 2, 3, 4], obj.exceptions_from) self.assertEqual([(obj, "fail", 0, 1)] * 5, self.exceptions) def test_dynamic_notifiers_functions(self): calls_0 = [] def function_listener_0(): calls_0.append(()) calls_1 = [] def function_listener_1(new): calls_1.append((new,)) calls_2 = [] def function_listener_2(name, new): calls_2.append((name, new)) calls_3 = [] def function_listener_3(obj, name, new): calls_3.append((obj, name, new)) calls_4 = [] def function_listener_4(obj, name, old, new): calls_4.append((obj, name, old, new)) obj = DynamicNotifiers() obj.on_trait_change(function_listener_0, "ok") obj.on_trait_change(function_listener_1, "ok") obj.on_trait_change(function_listener_2, "ok") obj.on_trait_change(function_listener_3, "ok") obj.on_trait_change(function_listener_4, "ok") obj.ok = 2 obj.ok = 3 expected_0 = [(), ()] self.assertEqual(expected_0, calls_0) expected_1 = [(2.0,), (3.0,)] self.assertEqual(expected_1, calls_1) expected_2 = [("ok", 2.0), ("ok", 3.0)] self.assertEqual(expected_2, calls_2) expected_3 = [(obj, "ok", 2.0), (obj, "ok", 3.0)] self.assertEqual(expected_3, calls_3) expected_4 = [(obj, "ok", 0.0, 2.0), (obj, "ok", 2.0, 3.0)] self.assertEqual(expected_4, calls_4) def test_priority_notifiers_first(self): obj = DynamicNotifiers() expected_high = set([1, 3]) expected_low = set([0, 2]) obj.on_trait_change(obj.low_priority_first, "priority_test") obj.on_trait_change( obj.high_priority_first, "priority_test", priority=True ) obj.on_trait_change(obj.low_priority_second, "priority_test") obj.on_trait_change( obj.high_priority_second, "priority_test", priority=True ) obj.priority_test = None high = set(obj.prioritized_notifications[:2]) low = set(obj.prioritized_notifications[2:]) self.assertSetEqual(expected_high, high) self.assertSetEqual(expected_low, low) def test_dynamic_notifiers_functions_failing(self): obj = DynamicNotifiers() exceptions_from = [] def failing_function_listener_0(): exceptions_from.append(0) raise Exception("error") def failing_function_listener_1(new): exceptions_from.append(1) raise Exception("error") def failing_function_listener_2(name, new): exceptions_from.append(2) raise Exception("error") def failing_function_listener_3(obj, name, new): exceptions_from.append(3) raise Exception("error") def failing_function_listener_4(obj, name, old, new): exceptions_from.append(4) raise Exception("error") obj.on_trait_change(failing_function_listener_0, "fail") obj.on_trait_change(failing_function_listener_1, "fail") obj.on_trait_change(failing_function_listener_2, "fail") obj.on_trait_change(failing_function_listener_3, "fail") obj.on_trait_change(failing_function_listener_4, "fail") obj.fail = 1 self.assertEqual([0, 1, 2, 3, 4], exceptions_from) self.assertCountEqual([0, 1, 2, 3, 4], obj.exceptions_from) # 10 failures: 5 are from the internal dynamic listeners, see # test_dynamic_notifiers_methods_failing self.assertEqual([(obj, "fail", 0, 1)] * 10, self.exceptions) def test_object_can_be_garbage_collected(self): # Make sure that a trait object can be garbage collected even though # there are listener to its traits. import weakref def listener(): pass obj = DynamicNotifiers() obj.on_trait_change(listener, "ok") # Create a weak reference to `obj` with a callback that flags when the # object is finalized. obj_collected = [] def obj_collected_callback(weakref): obj_collected.append(True) obj_weakref = weakref.ref(obj, obj_collected_callback) # Remove reference to `obj`, and check that the weak reference # callback has been called, indicating that it has been collected. del obj self.assertEqual(obj_collected, [True]) self.assertIsNone(obj_weakref()) def test_unhashable_object_can_be_garbage_collected(self): # Make sure that an unhashable trait object can be garbage collected # even though there are listener to its traits. import weakref def listener(): pass obj = UnhashableDynamicNotifiers() obj.on_trait_change(listener, "a_list:ok") # Changing a List trait is the easiest way to trigger a check into the # weak key dict. obj.a_list.append(UnhashableDynamicNotifiers()) # Create a weak reference to `obj` with a callback that flags when the # object is finalized. obj_collected = [] def obj_collected_callback(weakref): obj_collected.append(True) obj_weakref = weakref.ref(obj, obj_collected_callback) # Remove reference to `obj`, and check that the weak reference # callback has been called, indicating that it has been collected. del obj self.assertEqual(obj_collected, [True]) self.assertIsNone(obj_weakref()) def test_creating_notifiers_dont_create_cyclic_garbage(self): gc.collect() DynamicNotifiers() # When an object with dynamic listeners has no more references, # it should not create cyclic garbage. self.assertEqual(gc.collect(), 0) traits-6.3.2/traits/tests/test_dynamic_trait_definition.py000066400000000000000000000027331414270267200241620ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import Float, HasTraits, Int, List class Foo(HasTraits): x = Float y_changes = List def _y_changed(self, new): self.y_changes.append(new) class TestDynamicTraitDefinition(unittest.TestCase): """ Test demonstrating special change events using the 'event' metadata. """ def test_add_trait(self): foo = Foo(x=3) foo.add_trait("y", Int) self.assertTrue(hasattr(foo, "y")) self.assertEqual(type(foo.y), int) foo.y = 4 self.assertEqual(foo.y_changes, [4]) def test_remove_trait(self): foo = Foo(x=3) # We can't remove a "statically" added trait (i.e., a trait defined # in the Foo class). result = foo.remove_trait("x") self.assertFalse(result) # We can remove dynamically added traits. foo.add_trait("y", Int) foo.y = 70 result = foo.remove_trait("y") self.assertTrue(result) self.assertFalse(hasattr(foo, "y")) foo.y = 10 self.assertEqual(foo.y_changes, [70]) traits-6.3.2/traits/tests/test_editor_factories.py000066400000000000000000000155701414270267200224530ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for Editor factories. """ import datetime import unittest from traits.has_traits import HasTraits from traits.trait_types import Instance, List, Str from traits.editor_factories import ( _datetime_to_datetime_str, _datetime_str_to_datetime, bytes_editor, multi_line_text_editor, list_editor, password_editor, ) from traits.testing.optional_dependencies import requires_traitsui, traitsui class SimpleEditorTestMixin: def setUp(self): import traits.editor_factories self.factory = getattr(traits.editor_factories, self.factory_name) self.traitsui_factory = getattr(traitsui.api, self.traitsui_name) def test_editor(self): editor = self.factory() if isinstance(self.traitsui_factory, traitsui.api.BasicEditorFactory): self.assertIsInstance(editor, traitsui.api.BasicEditorFactory) else: self.assertIsInstance(editor, self.traitsui_factory) @requires_traitsui class TestDateEditor(SimpleEditorTestMixin, unittest.TestCase): traitsui_name = "DateEditor" factory_name = "date_editor" @requires_traitsui class TestDatetimeEditor(SimpleEditorTestMixin, unittest.TestCase): traitsui_name = "DatetimeEditor" factory_name = "datetime_editor" def test_str_to_obj_conversions(self): # Roundtrip None -> str -> None obj = None obj_str = _datetime_to_datetime_str(obj) self.assertEqual(obj_str, "") self.assertEqual(_datetime_str_to_datetime(obj_str), obj) # Roundtrip datetime -> str -> datetime obj = datetime.datetime(2019, 1, 13) obj_str = _datetime_to_datetime_str(obj) self.assertIsInstance(obj_str, str) self.assertEqual(_datetime_str_to_datetime(obj_str), obj) # Roundtrip valid_str -> datetime -> valid_str obj_str = "2020-02-15T11:12:13" obj = _datetime_str_to_datetime(obj_str) self.assertIsInstance(obj, datetime.datetime) self.assertEqual(_datetime_to_datetime_str(obj), obj_str) # Roundtrip "" -> None -> "" obj_str = "" obj = _datetime_str_to_datetime(obj_str) self.assertIsNone(obj) self.assertEqual(_datetime_to_datetime_str(obj), obj_str) @requires_traitsui class TestCodeEditor(SimpleEditorTestMixin, unittest.TestCase): traitsui_name = "CodeEditor" factory_name = "code_editor" @requires_traitsui class TestHTMLEditor(SimpleEditorTestMixin, unittest.TestCase): traitsui_name = "HTMLEditor" factory_name = "html_editor" @requires_traitsui class TestShellEditor(SimpleEditorTestMixin, unittest.TestCase): traitsui_name = "ShellEditor" factory_name = "shell_editor" @requires_traitsui class TestTimeEditor(SimpleEditorTestMixin, unittest.TestCase): traitsui_name = "TimeEditor" factory_name = "time_editor" @requires_traitsui class TestBytesEditor(unittest.TestCase): def test_bytes_editor_default(self): editor = bytes_editor() self.assertIsInstance(editor, traitsui.api.TextEditor) self.assertTrue(editor.auto_set) self.assertFalse(editor.enter_set) # test formatter formatted = editor.format_func(b'\xde\xad\xbe\xef') self.assertEqual(formatted, "deadbeef") # test evaluator evaluated = editor.evaluate("deadbeef") self.assertEqual(evaluated, b'\xde\xad\xbe\xef') def test_bytes_editor_options(self): editor = bytes_editor(auto_set=False, enter_set=True, encoding='ascii') self.assertIsInstance(editor, traitsui.api.TextEditor) self.assertFalse(editor.auto_set) self.assertTrue(editor.enter_set) # test formatter formatted = editor.format_func(b"deadbeef") self.assertEqual(formatted, "deadbeef") # test evaluator evaluated = editor.evaluate("deadbeef") self.assertEqual(evaluated, b"deadbeef") @requires_traitsui class TestMultiLineEditor(unittest.TestCase): def test_multi_line_text_editor_default(self): editor = multi_line_text_editor() self.assertIsInstance(editor, traitsui.api.TextEditor) self.assertTrue(editor.multi_line) self.assertTrue(editor.auto_set) self.assertFalse(editor.enter_set) def test_multi_line_text_editor_options(self): editor = multi_line_text_editor(auto_set=False, enter_set=True) self.assertIsInstance(editor, traitsui.api.TextEditor) self.assertTrue(editor.multi_line) self.assertFalse(editor.auto_set) self.assertTrue(editor.enter_set) @requires_traitsui class TestPasswordEditor(unittest.TestCase): def test_password_editor_default(self): editor = password_editor() self.assertIsInstance(editor, traitsui.api.TextEditor) self.assertTrue(editor.password) self.assertTrue(editor.auto_set) self.assertFalse(editor.enter_set) def test_password_editor_options(self): editor = password_editor(auto_set=False, enter_set=True) self.assertIsInstance(editor, traitsui.api.TextEditor) self.assertTrue(editor.password) self.assertFalse(editor.auto_set) self.assertTrue(editor.enter_set) @requires_traitsui class TestListEditor(unittest.TestCase): def test_list_editor_default(self): trait = List(Str) editor = list_editor(trait, trait) self.assertIsInstance(editor, traitsui.api.ListEditor) self.assertEqual(editor.trait_handler, trait) self.assertEqual(editor.rows, 5) self.assertFalse(editor.use_notebook) self.assertEqual(editor.page_name, '') def test_list_editor_options(self): trait = List(Str, rows=10, use_notebook=True, page_name='page') editor = list_editor(trait, trait) self.assertIsInstance(editor, traitsui.api.ListEditor) self.assertEqual(editor.trait_handler, trait) self.assertEqual(editor.rows, 10) self.assertTrue(editor.use_notebook) self.assertEqual(editor.page_name, 'page') def test_list_editor_list_instance(self): trait = List(Instance(HasTraits)) editor = list_editor(trait, trait) self.assertIsInstance(editor, traitsui.api.TableEditor) # regression test for enthought/traitsui#1539 def test_list_editor_list_instance_row_factory(self): trait = List(Instance(HasTraits, kw={})) editor = trait.create_editor() self.assertIsInstance(editor, traitsui.api.TableEditor) if editor.row_factory is not None: self.assertTrue(callable(editor.row_factory)) traits-6.3.2/traits/tests/test_enum.py000066400000000000000000000243541414270267200200720ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import enum import unittest from traits.api import ( Any, BaseEnum, Enum, HasTraits, Int, List, Property, Set, TraitError, Tuple) from traits.etsconfig.api import ETSConfig from traits.testing.optional_dependencies import requires_traitsui is_null = ETSConfig.toolkit == 'null' class FooEnum(enum.Enum): foo = 0 bar = 1 baz = 2 class OtherEnum(enum.Enum): one = 1 two = 2 three = 3 class ExampleModel(HasTraits): valid_models = Property(List) root = Enum(values="valid_models") def _get_valid_models(self): return ["model1", "model2", "model3"] class CustomCollection: def __init__(self, *data): self.data = data def __len__(self): return len(self.data) def __iter__(self): return iter(self.data) def __contains__(self, x): return x in self.data class EnumListExample(HasTraits): values = List(['foo', 'bar', 'baz']) value = Enum(['foo', 'bar', 'baz']) value_default = Enum('bar', ['foo', 'bar', 'baz']) value_name = Enum(values='values') value_name_default = Enum('bar', values='values') class EnumTupleExample(HasTraits): values = Any(('foo', 'bar', 'baz')) value = Enum(('foo', 'bar', 'baz')) value_default = Enum('bar', ('foo', 'bar', 'baz')) value_name = Enum(values='values') value_name_default = Enum('bar', values='values') class EnumEnumExample(HasTraits): values = Any(FooEnum) value = Enum(FooEnum) value_default = Enum(FooEnum.bar, FooEnum) value_name = Enum(values='values') value_name_default = Enum(FooEnum.bar, values='values') class EnumCollectionExample(HasTraits): rgb = Enum("red", CustomCollection("red", "green", "blue")) rgb_char = Enum("r", "g", "b") numbers = Enum(CustomCollection("one", "two", "three")) letters = Enum("abcdefg") int_set_enum = Enum(1, {1, 2}) correct_int_set_enum = Enum([1, {1, 2}]) yes_no = Enum("yes", "no") digits = Enum(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) two_digits = Enum(1, 2) single_digit = Enum(8) slow_enum = BaseEnum("yes", "no", "maybe") class EnumCollectionGUIExample(EnumCollectionExample): # Override attributes that may fail GUI test # until traitsui #781 is fixed. int_set_enum = Enum("int", "set") correct_int_set_enum = Enum("int", "set") class EnumTestCase(unittest.TestCase): def test_valid_enum(self): example_model = ExampleModel(root="model1") example_model.root = "model2" def test_invalid_enum(self): example_model = ExampleModel(root="model1") def assign_invalid(): example_model.root = "not_valid_model" self.assertRaises(TraitError, assign_invalid) def test_enum_list(self): example = EnumListExample() self.assertEqual(example.value, 'foo') self.assertEqual(example.value_default, 'bar') self.assertEqual(example.value_name, 'foo') self.assertEqual(example.value_name_default, 'bar') example.value = 'bar' self.assertEqual(example.value, 'bar') with self.assertRaises(TraitError): example.value = "something" with self.assertRaises(TraitError): example.value = 0 example.values = ['one', 'two', 'three'] example.value_name = 'two' self.assertEqual(example.value_name, 'two') with self.assertRaises(TraitError): example.value_name = 'bar' def test_enum_tuple(self): example = EnumTupleExample() self.assertEqual(example.value, 'foo') self.assertEqual(example.value_default, 'bar') self.assertEqual(example.value_name, 'foo') self.assertEqual(example.value_name_default, 'bar') example.value = 'bar' self.assertEqual(example.value, 'bar') with self.assertRaises(TraitError): example.value = "something" with self.assertRaises(TraitError): example.value = 0 example.values = ('one', 'two', 'three') example.value_name = 'two' self.assertEqual(example.value_name, 'two') with self.assertRaises(TraitError): example.value_name = 'bar' def test_enum_enum(self): example = EnumEnumExample() self.assertEqual(example.value, FooEnum.foo) self.assertEqual(example.value_default, FooEnum.bar) self.assertEqual(example.value_name, FooEnum.foo) self.assertEqual(example.value_name_default, FooEnum.bar) example.value = FooEnum.bar self.assertEqual(example.value, FooEnum.bar) with self.assertRaises(TraitError): example.value = "foo" with self.assertRaises(TraitError): example.value = 0 example.values = OtherEnum example.value_name = OtherEnum.two self.assertEqual(example.value_name, OtherEnum.two) with self.assertRaises(TraitError): example.value_name = FooEnum.bar def test_enum_collection(self): collection_enum = EnumCollectionExample() # Test the default values. self.assertEqual("red", collection_enum.rgb) self.assertEqual("r", collection_enum.rgb_char) self.assertEqual("one", collection_enum.numbers) self.assertEqual("abcdefg", collection_enum.letters) self.assertEqual("yes", collection_enum.yes_no) self.assertEqual(0, collection_enum.digits) self.assertEqual(1, collection_enum.int_set_enum) self.assertEqual(1, collection_enum.two_digits) self.assertEqual(8, collection_enum.single_digit) # Test assigning valid values collection_enum.rgb = "blue" self.assertEqual("blue", collection_enum.rgb) collection_enum.rgb_char = 'g' self.assertEqual("g", collection_enum.rgb_char) collection_enum.yes_no = "no" self.assertEqual("no", collection_enum.yes_no) for i in range(10): collection_enum.digits = i self.assertEqual(i, collection_enum.digits) collection_enum.two_digits = 2 self.assertEqual(2, collection_enum.two_digits) # Test assigning invalid values with self.assertRaises(TraitError): collection_enum.rgb = "two" with self.assertRaises(TraitError): collection_enum.letters = 'b' with self.assertRaises(TraitError): collection_enum.yes_no = "n" with self.assertRaises(TraitError): collection_enum.digits = 10 with self.assertRaises(TraitError): collection_enum.single_digit = 9 with self.assertRaises(TraitError): collection_enum.single_digit = None # Fixing issue #835 introduces the following behaviour, which would # have otherwise not thrown a TraitError with self.assertRaises(TraitError): collection_enum.int_set_enum = {1, 2} # But the behaviour can be fixed # by defining it like correct_int_set_enum self.assertEqual(1, collection_enum.correct_int_set_enum) # No more error on assignment collection_enum.correct_int_set_enum = {1, 2} with self.assertRaises(TraitError): collection_enum.correct_int_set_enum = 20 def test_empty_enum(self): with self.assertRaises(TraitError): class EmptyEnum(HasTraits): a = Enum() EmptyEnum() def test_too_many_arguments_for_dynamic_enum(self): with self.assertRaises(TraitError): Enum("red", "green", values="values") def test_attributes(self): static_enum = Enum(1, 2, 3) self.assertEqual(static_enum.values, (1, 2, 3)) self.assertIsNone(static_enum.name, None) dynamic_enum = Enum(values="values") self.assertIsNone(dynamic_enum.values) self.assertEqual(dynamic_enum.name, "values") def test_explicit_collection_with_no_elements(self): with self.assertRaises(TraitError): Enum([]) with self.assertRaises(TraitError): Enum(3.5, []) def test_base_enum(self): # Minimal tests for BaseEnum, sufficient to cover the validation # for the static case. obj = EnumCollectionExample() self.assertEqual(obj.slow_enum, "yes") obj.slow_enum = "no" self.assertEqual(obj.slow_enum, "no") with self.assertRaises(TraitError): obj.slow_enum = "perhaps" self.assertEqual(obj.slow_enum, "no") def test_dynamic_enum_in_tuple(self): # Regression test for #1385. The previous implementation of Enum # did no validation until trait-set time, but for an Enum inside # a Tuple, the inner traits are never set. class HasEnumInTuple(HasTraits): #: List of valid month numbers. months = List(Int, value=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) #: (Year, month) pairs. year_and_month = Tuple(Int(), Enum(values='months')) model = HasEnumInTuple() model.year_and_month = (1974, 8) self.assertEqual(model.year_and_month, (1974, 8)) with self.assertRaises(TraitError): model.year_and_month = 1986, 13 def test_dynamic_enum_in_list(self): # Another regression test for #1385. class HasEnumInList(HasTraits): #: Valid digits digits = Set(Int) #: Sequence of those digits digit_sequence = List(Enum(values="digits")) model = HasEnumInList(digits={-1, 0, 1}) model.digit_sequence = [-1, 0, 1, 1] with self.assertRaises(TraitError): model.digit_sequence = [-1, 0, 2, 1] @requires_traitsui @unittest.skipIf(is_null, "GUI toolkit not available") class TestGui(unittest.TestCase): def test_create_editor(self): from traitsui.testing.api import UITester obj = EnumCollectionGUIExample() with UITester().create_ui(obj): pass traits-6.3.2/traits/tests/test_event_order.py000066400000000000000000000047671414270267200214500ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import HasTraits, Str, Instance, Any class TestEventOrder(unittest.TestCase): """ Tests that demonstrate that trait events are delivered in LIFO order rather than FIFO order. Baz receives the "effect" event before it receives the "cause" event. """ def test_lifo_order(self): foo = Foo(cause="ORIGINAL") bar = Bar(foo=foo, test=self) # flake8 complains about unused "baz", but we need to keep it # alive for listeners to fire. baz = Baz(bar=bar, test=self) # noqa: F841 self.events_delivered = [] foo.cause = "CHANGE" lifo = [ "Bar._caused_changed", "Baz._effect_changed", "Baz._caused_changed", ] self.assertEqual(self.events_delivered, lifo) class Foo(HasTraits): cause = Str class Bar(HasTraits): foo = Instance(Foo) effect = Str test = Any def _foo_changed(self, obj, old, new): if old is not None and old is not new: old.on_trait_change(self._cause_changed, name="cause", remove=True) if new is not None: new.on_trait_change(self._cause_changed, name="cause") def _cause_changed(self, obj, name, old, new): self.test.events_delivered.append("Bar._caused_changed") self.effect = new.lower() class Baz(HasTraits): bar = Instance(Bar) test = Any def _bar_changed(self, obj, old, new): if old is not None and old is not new: old.on_trait_change( self._effect_changed, name="effect", remove=True ) old.foo.on_trait_change( self._cause_changed, name="cause", remove=True ) if new is not None: new.foo.on_trait_change(self._cause_changed, name="cause") new.on_trait_change(self._effect_changed, name="effect") def _cause_changed(self, obj, name, old, new): self.test.events_delivered.append("Baz._caused_changed") def _effect_changed(self, obj, name, old, new): self.test.events_delivered.append("Baz._effect_changed") traits-6.3.2/traits/tests/test_expression.py000066400000000000000000000104631414270267200213210ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import pickle import unittest from traits.api import Expression, HasTraits, Int, TraitError class TestExpression(unittest.TestCase): def test_set_value(self): class Foo(HasTraits): bar = Expression() f = Foo() f.bar = "1" self.assertEqual(f.bar, "1") self.assertEqual(eval(f.bar_), 1) def test_default_static(self): class Foo(HasTraits): # The default value set in the class definition is "0" bar = Expression(default_value="1") f = Foo() self.assertEqual(f.bar, "1") self.assertEqual(eval(f.bar_), 1) def test_default_method(self): class Foo(HasTraits): # The default value set in the class definition is "0" bar = Expression() default_calls = Int(0) def _bar_default(self): self.default_calls += 1 return "1" f = Foo() self.assertEqual(f.bar, "1") self.assertEqual(eval(f.bar_), 1) self.assertEqual(f.default_calls, 1) # Check that the order doesn't matter f2 = Foo() self.assertEqual(eval(f2.bar_), 1) self.assertEqual(f2.bar, "1") self.assertEqual(f2.default_calls, 1) def test_default_method_non_valid(self): class Foo(HasTraits): bar = Expression() def _bar_default(self): return "{x=y" f = Foo() msg = "The 'bar' trait of a Foo instance must be a valid" with self.assertRaisesRegex(TraitError, msg): f.bar def test_default_static_override_static(self): class BaseFoo(HasTraits): # The default value set in the class definition is "0" bar = Expression() class Foo(BaseFoo): bar = "3" f = Foo() self.assertEqual(f.bar, "3") self.assertEqual(eval(f.bar_), 3) def test_default_static_override_method(self): class BaseFoo(HasTraits): # The default value set in the class definition is "0" bar = Expression() class Foo(BaseFoo): default_calls = Int(0) def _bar_default(self): self.default_calls += 1 return "3" f = Foo() self.assertEqual(f.bar, "3") self.assertEqual(eval(f.bar_), 3) self.assertEqual(f.default_calls, 1) def test_default_method_override_static(self): class BaseFoo(HasTraits): # The default value set in the class definition is "0" bar = Expression() default_calls = Int(0) def _bar_default(self): self.default_calls += 1 return "1" class Foo(BaseFoo): bar = "3" f = Foo() self.assertEqual(f.bar, "3") self.assertEqual(eval(f.bar_), 3) self.assertEqual(f.default_calls, 0) def test_default_method_override_method(self): class BaseFoo(HasTraits): # The default value set in the class definition is "0" bar = Expression() default_calls = Int(0) def _bar_default(self): self.default_calls += 1 return "1" class Foo(BaseFoo): def _bar_default(self): self.default_calls += 1 return "3" f = Foo() self.assertEqual(f.bar, "3") self.assertEqual(eval(f.bar_), 3) self.assertEqual(f.default_calls, 1) def test_pickle_shadow_trait(self): class Foo(HasTraits): # The default value set in the class definition is "0" bar = Expression(default_value="1") f = Foo() married_shadow_trait = f.trait("bar_") reconstituted = pickle.loads(pickle.dumps(married_shadow_trait)) default_value_callable = reconstituted.default_value()[1] self.assertEqual(eval(default_value_callable(f)), 1) traits-6.3.2/traits/tests/test_extended_notifiers.py000066400000000000000000000166671414270267200230200ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the extended notifiers. The "extended notifiers" are set up internally when using extended traits, to add/remove traits listeners when one of the intermediate traits changes. For example, in a listener for the extended trait `a.b`, we need to add/remove listeners to `a:b` when `a` changes. """ import unittest from traits import trait_notifiers from traits.api import Float, HasTraits, List class ExtendedNotifiers(HasTraits): def __init__(self, **traits): # Set up the 'extended' internal notifiers (see module docstring) ok_listeners = [ self.method_listener_0, self.method_listener_1, self.method_listener_2, self.method_listener_3, self.method_listener_4, ] for listener in ok_listeners: self._on_trait_change(listener, "ok", dispatch="extended") fail_listeners = [ self.failing_method_listener_0, self.failing_method_listener_1, self.failing_method_listener_2, self.failing_method_listener_3, self.failing_method_listener_4, ] for listener in fail_listeners: self._on_trait_change(listener, "fail", dispatch="extended") super().__init__(**traits) ok = Float fail = Float # Lists where we accumulate the arguments of calls to the traits notifiers. rebind_calls_0 = List rebind_calls_1 = List rebind_calls_2 = List rebind_calls_3 = List rebind_calls_4 = List exceptions_from = List #### 'ok' trait listeners def method_listener_0(self): self.rebind_calls_0.append(True) def method_listener_1(self, new): self.rebind_calls_1.append(new) def method_listener_2(self, name, new): self.rebind_calls_2.append((name, new)) def method_listener_3(self, obj, name, new): self.rebind_calls_3.append((obj, name, new)) def method_listener_4(self, obj, name, old, new): self.rebind_calls_4.append((obj, name, old, new)) #### 'fail' trait listeners def failing_method_listener_0(self): self.exceptions_from.append(0) raise Exception("error") def failing_method_listener_1(self, new): self.exceptions_from.append(1) raise Exception("error") def failing_method_listener_2(self, name, new): self.exceptions_from.append(2) raise Exception("error") def failing_method_listener_3(self, obj, name, new): self.exceptions_from.append(3) raise Exception("error") def failing_method_listener_4(self, obj, name, old, new): self.exceptions_from.append(4) raise Exception("error") # 'ok' function listeners calls_0 = [] def function_listener_0(): calls_0.append(True) calls_1 = [] def function_listener_1(new): calls_1.append(new) calls_2 = [] def function_listener_2(name, new): calls_2.append((name, new)) calls_3 = [] def function_listener_3(obj, name, new): calls_3.append((obj, name, new)) calls_4 = [] def function_listener_4(obj, name, old, new): calls_4.append((obj, name, old, new)) # 'fail' function listeners exceptions_from = [] def failing_function_listener_0(): exceptions_from.append(0) raise Exception("error") def failing_function_listener_1(new): exceptions_from.append(1) raise Exception("error") def failing_function_listener_2(name, new): exceptions_from.append(2) raise Exception("error") def failing_function_listener_3(obj, name, new): exceptions_from.append(3) raise Exception("error") def failing_function_listener_4(obj, name, old, new): exceptions_from.append(4) raise Exception("error") class TestExtendedNotifiers(unittest.TestCase): #### 'TestCase' protocol ################################################## def setUp(self): self.exceptions = [] trait_notifiers.push_exception_handler(self._handle_exception) def tearDown(self): trait_notifiers.pop_exception_handler() #### Private protocol ##################################################### def _handle_exception(self, obj, name, old, new): self.exceptions.append((obj, name, old, new)) #### Tests ################################################################ def test_extended_notifiers_methods(self): obj = ExtendedNotifiers(ok=2) obj.ok = 3 self.assertEqual(len(obj.rebind_calls_0), 2) expected_1 = [2, 3] self.assertEqual(expected_1, obj.rebind_calls_1) expected_2 = [("ok", 2), ("ok", 3)] self.assertEqual(expected_2, obj.rebind_calls_2) expected_3 = [(obj, "ok", 2), (obj, "ok", 3)] self.assertEqual(expected_3, obj.rebind_calls_3) expected_4 = [(obj, "ok", 0, 2), (obj, "ok", 2, 3)] self.assertEqual(expected_4, obj.rebind_calls_4) def test_extended_notifiers_methods_failing(self): obj = ExtendedNotifiers() obj.fail = 1 self.assertCountEqual([0, 1, 2, 3, 4], obj.exceptions_from) self.assertEqual([(obj, "fail", 0, 1)] * 5, self.exceptions) def test_extended_notifiers_functions(self): calls_0.clear() calls_1.clear() calls_2.clear() calls_3.clear() calls_4.clear() obj = ExtendedNotifiers() obj._on_trait_change(function_listener_0, "ok", dispatch="extended") obj._on_trait_change(function_listener_1, "ok", dispatch="extended") obj._on_trait_change(function_listener_2, "ok", dispatch="extended") obj._on_trait_change(function_listener_3, "ok", dispatch="extended") obj._on_trait_change(function_listener_4, "ok", dispatch="extended") obj.ok = 2 obj.ok = 3 expected_0 = [True, True] self.assertEqual(expected_0, calls_0) expected_1 = [2, 3] self.assertEqual(expected_1, calls_1) expected_2 = [("ok", 2), ("ok", 3)] self.assertEqual(expected_2, calls_2) expected_3 = [(obj, "ok", 2), (obj, "ok", 3)] self.assertEqual(expected_3, calls_3) expected_4 = [(obj, "ok", 0, 2), (obj, "ok", 2, 3)] self.assertEqual(expected_4, calls_4) def test_extended_notifiers_functions_failing(self): obj = ExtendedNotifiers() exceptions_from.clear() obj._on_trait_change( failing_function_listener_0, "fail", dispatch="extended" ) obj._on_trait_change( failing_function_listener_1, "fail", dispatch="extended" ) obj._on_trait_change( failing_function_listener_2, "fail", dispatch="extended" ) obj._on_trait_change( failing_function_listener_3, "fail", dispatch="extended" ) obj._on_trait_change( failing_function_listener_4, "fail", dispatch="extended" ) obj.fail = 1 self.assertCountEqual([0, 1, 2, 3, 4], obj.exceptions_from) # 10 failures: 5 are from the internal extended listeners, see # test_extended_notifiers_methods_failing self.assertEqual([(obj, "fail", 0, 1)] * 10, self.exceptions) traits-6.3.2/traits/tests/test_extended_trait_change.py000066400000000000000000001040501414270267200234260ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Unit test case for testing HasTraits 'on_trait_change' support. """ import unittest from traits.api import ( Any, Dict, HasTraits, Instance, Int, List, Property, TraitDictEvent, TraitDictObject, TraitError, TraitListEvent, TraitListObject, Undefined, cached_property, on_trait_change, pop_exception_handler, push_exception_handler, ) class ArgCheckBase(HasTraits): value = Int(0) int1 = Int(0, test=True) int2 = Int(0) int3 = Int(0, test=True) tint1 = Int(0) tint2 = Int(0, test=True) tint3 = Int(0) calls = Int(0) tc = Any class ArgCheckList(ArgCheckBase): value = List(Int, [0, 1, 2]) class ArgCheckDict(ArgCheckBase): value = Dict(Int, Int, {0: 0, 1: 1, 2: 2}) class ArgCheckSimple(ArgCheckBase): def arg_check0(self): self.calls += 1 def arg_check1(self, new): self.calls += 1 self.tc.assertEqual(new, self.value) def arg_check2(self, name, new): self.calls += 1 self.tc.assertEqual(name, "value") self.tc.assertEqual(new, self.value) def arg_check3(self, object, name, new): self.calls += 1 self.tc.assertIs(object, self) self.tc.assertEqual(name, "value") self.tc.assertEqual(new, self.value) def arg_check4(self, object, name, old, new): self.calls += 1 self.tc.assertIs(object, self) self.tc.assertEqual(name, "value") self.tc.assertEqual(old, (self.value - 1)) self.tc.assertEqual(new, self.value) class ArgCheckDecorator(ArgCheckBase): @on_trait_change("value") def arg_check0(self): self.calls += 1 @on_trait_change("value") def arg_check1(self, new): self.calls += 1 self.tc.assertEqual(new, self.value) @on_trait_change("value") def arg_check2(self, name, new): self.calls += 1 self.tc.assertEqual(name, "value") self.tc.assertEqual(new, self.value) @on_trait_change("value") def arg_check3(self, object, name, new): self.calls += 1 self.tc.assertIs(object, self) self.tc.assertEqual(name, "value") self.tc.assertEqual(new, self.value) @on_trait_change("value") def arg_check4(self, object, name, old, new): self.calls += 1 self.tc.assertIs(object, self) self.tc.assertEqual(name, "value") self.tc.assertEqual(old, (self.value - 1)) self.tc.assertEqual(new, self.value) class ArgCheckDecoratorTrailingComma(ArgCheckDecorator): @on_trait_change("int1, int2,") def arg_check(self, object, name, old, new): pass class BaseInstance(HasTraits): #: An instance with a value trait we want to listen to. ref = Instance(HasTraits) calls = Dict({x: 0 for x in range(5)}) exp_object = Any exp_name = Any dst_name = Any exp_old = Any exp_new = Any dst_new = Any tc = Any class InstanceValueListener(BaseInstance): @on_trait_change("ref.value") def arg_check0(self): self.calls[0] += 1 @on_trait_change("ref.value") def arg_check1(self, new): self.calls[1] += 1 self.tc.assertEqual(new, self.dst_new) @on_trait_change("ref.value") def arg_check2(self, name, new): self.calls[2] += 1 self.tc.assertEqual(name, self.dst_name) self.tc.assertEqual(new, self.dst_new) @on_trait_change("ref.value") def arg_check3(self, object, name, new): self.calls[3] += 1 self.tc.assertIs(object, self.exp_object) self.tc.assertEqual(name, self.exp_name) self.tc.assertEqual(new, self.exp_new) @on_trait_change("ref.value") def arg_check4(self, object, name, old, new): self.calls[4] += 1 self.tc.assertIs(object, self.exp_object) self.tc.assertEqual(name, self.exp_name) self.tc.assertEqual(old, self.exp_old) self.tc.assertEqual(new, self.exp_new) class InstanceSimpleValue(InstanceValueListener): #: An instance with a simple value trait we want to listen to. ref = Instance(ArgCheckBase, ()) class InstanceListValue(InstanceValueListener): #: An instance with a list value trait we want to listen to. ref = Instance(ArgCheckList, ()) class InstanceDictValue(InstanceValueListener): ref = Instance(ArgCheckDict, ()) class InstanceValueListListener(BaseInstance): #: An instance with a list value trait we want to listen to. ref = Instance(ArgCheckList, ()) @on_trait_change("ref.value[]") def arg_check0(self): self.calls[0] += 1 @on_trait_change("ref.value[]") def arg_check1(self, new): self.calls[1] += 1 self.tc.assertEqual(new, self.dst_new) @on_trait_change("ref.value[]") def arg_check2(self, name, new): self.calls[2] += 1 self.tc.assertEqual(name, self.dst_name) self.tc.assertEqual(new, self.dst_new) @on_trait_change("ref.value[]") def arg_check3(self, object, name, new): self.calls[3] += 1 self.tc.assertIs(object, self.exp_object) self.tc.assertEqual(name, self.exp_name) self.tc.assertEqual(new, self.exp_new) @on_trait_change("ref.value[]") def arg_check4(self, object, name, old, new): self.calls[4] += 1 self.tc.assertIs(object, self.exp_object) self.tc.assertEqual(name, self.exp_name) self.tc.assertEqual(old, self.exp_old) self.tc.assertEqual(new, self.exp_new) class List1(HasTraits): refs = List(ArgCheckBase) calls = Dict({0: 0, 3: 0, 4: 0}) exp_object = Any exp_name = Any type_old = Any exp_old = Any type_new = Any exp_new = Any tc = Any @on_trait_change("refs.value") def arg_check0(self): self.calls[0] += 1 @on_trait_change("refs.value") def arg_check3(self, object, name, new): self.calls[3] += 1 self.tc.assertIs(object, self.exp_object) self.tc.assertEqual(name, self.exp_name) if self.type_new is None: self.tc.assertEqual(new, self.exp_new) else: self.tc.assertIsInstance(new, self.type_new) @on_trait_change("refs.value") def arg_check4(self, object, name, old, new): self.calls[4] += 1 self.tc.assertIs(object, self.exp_object) self.tc.assertEqual(name, self.exp_name) if self.type_old is None: self.tc.assertEqual(old, self.exp_old) else: self.tc.assertIsInstance(old, self.type_old) if self.type_new is None: self.tc.assertEqual(new, self.exp_new) else: self.tc.assertIsInstance(new, self.type_new) class List2(HasTraits): refs = List(ArgCheckBase) calls = Int(0) exp_new = Any tc = Any @on_trait_change("refs.value") def arg_check1(self, new): self.calls += 1 self.tc.assertEqual(new, self.exp_new) class List3(HasTraits): refs = List(ArgCheckBase) calls = Int(0) exp_name = Any exp_new = Any tc = Any @on_trait_change("refs.value") def arg_check2(self, name, new): self.calls += 1 self.tc.assertEqual(name, self.exp_name) self.tc.assertEqual(new, self.exp_new) class Dict1(List1): refs = Dict(Int, ArgCheckBase) class Dict2(HasTraits): refs = Dict(Int, ArgCheckBase) calls = Int(0) exp_new = Any tc = Any @on_trait_change("refs.value") def arg_check1(self, new): self.calls += 1 self.tc.assertEqual(new, self.exp_new) class Dict3(HasTraits): refs = Dict(Int, ArgCheckBase) calls = Int(0) exp_name = Any exp_new = Any tc = Any @on_trait_change("refs.value") def arg_check2(self, name, new): self.calls += 1 self.tc.assertEqual(name, self.exp_name) self.tc.assertEqual(new, self.exp_new) class Complex(HasTraits): int1 = Int(0, test=True) int2 = Int(0) int3 = Int(0, test=True) tint1 = Int(0) tint2 = Int(0, test=True) tint3 = Int(0) ref = Instance(ArgCheckBase, ()) calls = Int(0) exp_object = Any exp_name = Any dst_name = Any exp_old = Any exp_new = Any dst_new = Any tc = Any def arg_check0(self): self.calls += 1 def arg_check1(self, new): self.calls += 1 self.tc.assertEqual(new, self.exp_new) def arg_check2(self, name, new): self.calls += 1 self.tc.assertEqual(name, self.exp_name) self.tc.assertEqual(new, self.exp_new) def arg_check3(self, object, name, new): self.calls += 1 self.tc.assertIs(object, self.exp_object) self.tc.assertEqual(name, self.exp_name) self.tc.assertEqual(new, self.exp_new) def arg_check4(self, object, name, old, new): self.calls += 1 self.tc.assertIs(object, self.exp_object) self.tc.assertEqual(name, self.exp_name) self.tc.assertEqual(old, self.exp_old) self.tc.assertEqual(new, self.exp_new) class Link(HasTraits): next = Any prev = Any value = Int(0) class LinkTest(HasTraits): head = Instance(Link) calls = Int(0) exp_object = Any exp_name = Any dst_name = Any exp_old = Any exp_new = Any dst_new = Any tc = Any def arg_check0(self): self.calls += 1 def arg_check1(self, new): self.calls += 1 self.tc.assertEqual(new, self.exp_new) def arg_check2(self, name, new): self.calls += 1 self.tc.assertEqual(name, self.exp_name) self.tc.assertEqual(new, self.exp_new) def arg_check3(self, object, name, new): self.calls += 1 self.tc.assertIs(object, self.exp_object) self.tc.assertEqual(name, self.exp_name) self.tc.assertEqual(new, self.exp_new) def arg_check4(self, object, name, old, new): self.calls += 1 self.tc.assertIs(object, self.exp_object) self.tc.assertEqual(name, self.exp_name) self.tc.assertEqual(old, self.exp_old) self.tc.assertEqual(new, self.exp_new) class PropertyDependsOn(HasTraits): sum = Property(depends_on="ref.[int1,int2,int3]") ref = Instance(ArgCheckBase, ()) pcalls = Int(0) calls = Int(0) exp_old = Any exp_new = Any tc = Any @cached_property def _get_sum(self): self.pcalls += 1 r = self.ref return r.int1 + r.int2 + r.int3 def _sum_changed(self, old, new): self.calls += 1 self.tc.assertEqual(old, self.exp_old) self.tc.assertEqual(new, self.exp_new) class OnTraitChangeTest(unittest.TestCase): def setUp(self): def ignore(*args): pass push_exception_handler(handler=ignore, reraise_exceptions=True) def tearDown(self): pop_exception_handler() def test_arg_check_simple(self): ac = ArgCheckSimple(tc=self) ac.on_trait_change(ac.arg_check0, "value") ac.on_trait_change(ac.arg_check1, "value") ac.on_trait_change(ac.arg_check2, "value") ac.on_trait_change(ac.arg_check3, "value") ac.on_trait_change(ac.arg_check4, "value") for i in range(3): ac.value += 1 self.assertEqual(ac.calls, (3 * 5)) ac.on_trait_change(ac.arg_check0, "value", remove=True) ac.on_trait_change(ac.arg_check1, "value", remove=True) ac.on_trait_change(ac.arg_check2, "value", remove=True) ac.on_trait_change(ac.arg_check3, "value", remove=True) ac.on_trait_change(ac.arg_check4, "value", remove=True) for i in range(3): ac.value += 1 self.assertEqual(ac.calls, (3 * 5)) self.assertEqual(ac.value, (2 * 3)) def test_arg_check_trailing_comma(self): ac = ArgCheckSimple(tc=self) with self.assertRaises(TraitError): ac.on_trait_change(ac.arg_check0, "int1, int2,") def test_arg_check_decorator(self): ac = ArgCheckDecorator(tc=self) for i in range(3): ac.value += 1 self.assertEqual(ac.calls, (3 * 5)) self.assertEqual(ac.value, 3) def test_arg_check_decorator_trailing_comma(self): with self.assertRaises(TraitError): ArgCheckDecoratorTrailingComma(tc=self) def test_instance_simple_value(self): inst = InstanceSimpleValue(tc=self) for i in range(3): inst.trait_set( exp_object=inst.ref, exp_name="value", dst_name="value", exp_old=i, exp_new=(i + 1), dst_new=(i + 1), ) inst.ref.value = i + 1 self.assertEqual(inst.calls, {x: 3 for x in range(5)}) self.assertEqual(inst.ref.value, 3) inst.reset_traits(['calls']) ref = ArgCheckBase() inst.trait_set( exp_object=inst, exp_name="ref", dst_name="value", exp_old=inst.ref, exp_new=ref, dst_new=0, ) inst.ref = ref self.assertEqual(inst.calls, {x: 1 for x in range(5)}) self.assertEqual(inst.ref.value, 0) inst.reset_traits(['calls']) for i in range(3): inst.trait_set( exp_object=inst.ref, exp_name="value", dst_name="value", exp_old=i, exp_new=(i + 1), dst_new=(i + 1), ) inst.ref.value = i + 1 self.assertEqual(inst.calls, {x: 3 for x in range(5)}) self.assertEqual(inst.ref.value, 3) def test_instance_list_value(self): inst = InstanceListValue(tc=self) inst.trait_set( exp_object=inst.ref, exp_name="value", dst_name="value", exp_old=[0, 1, 2], exp_new=[0, 1, 2, 3], dst_new=[0, 1, 2, 3], ) inst.ref.value = [0, 1, 2, 3] self.assertEqual(inst.calls, {x: 1 for x in range(5)}) self.assertEqual(inst.ref.value, [0, 1, 2, 3]) inst.reset_traits(['calls']) ref = ArgCheckList() inst.trait_set( exp_object=inst, exp_name="ref", dst_name="value", exp_old=inst.ref, exp_new=ref, dst_new=[0, 1, 2], ) inst.ref = ref self.assertEqual(inst.calls, {x: 1 for x in range(5)}) self.assertEqual(inst.ref.value, [0, 1, 2]) inst.reset_traits(['calls']) inst.trait_set( exp_object=inst.ref, exp_name="value", dst_name="value", exp_old=[0, 1, 2], exp_new=[0, 1, 2, 3], dst_new=[0, 1, 2, 3], ) with self.assertRaises( AssertionError, msg="Behavior of a bug (#537) is not reproduced."): # Expected failure, see enthought/traits#537 # InstanceValueListener.arg_check1 receives a TraitListEvent # as `new` instead of the expected `[0, 1, 2, 3]` inst.ref.value.append(3) # Expected failure # See enthought/traits#537 with self.assertRaises( AssertionError, msg="Behavior of a bug (#537) is not reproduced."): # Handlers with arguments are unexpectedly called, but one of the # handlers fails, leading to the rest of the handlers # not to be called. Actual behavior depends on dictionary ordering # (Python <3.6) or the order of handlers defined in # InstanceValueListener (Python >= 3.6) self.assertEqual(inst.calls, {0: 1, 1: 0, 2: 0, 3: 0, 4: 0}) self.assertEqual(inst.ref.value, [0, 1, 2, 3]) def test_instance_dict_value(self): inst = InstanceDictValue(tc=self) inst.trait_set( exp_object=inst.ref, exp_name="value", dst_name="value", exp_old={0: 0, 1: 1, 2: 2}, exp_new={0: 0, 1: 1, 2: 2, 3: 3}, dst_new={0: 0, 1: 1, 2: 2, 3: 3}, ) inst.ref.value = {0: 0, 1: 1, 2: 2, 3: 3} self.assertEqual(inst.calls, {x: 1 for x in range(5)}) self.assertEqual(inst.ref.value, {0: 0, 1: 1, 2: 2, 3: 3}) inst.reset_traits(['calls']) ref = ArgCheckDict() inst.trait_set( exp_object=inst, exp_name="ref", dst_name="value", exp_old=inst.ref, exp_new=ref, dst_new={0: 0, 1: 1, 2: 2}, ) inst.ref = ref self.assertEqual(inst.calls, {x: 1 for x in range(5)}) self.assertEqual(inst.ref.value, {0: 0, 1: 1, 2: 2}) inst.reset_traits(['calls']) inst.trait_set( exp_object=inst.ref, exp_name="value", dst_name="value", exp_old={0: 0, 1: 1, 2: 2}, exp_new={0: 0, 1: 1, 2: 2, 3: 3}, dst_new={0: 0, 1: 1, 2: 2, 3: 3}, ) with self.assertRaises( AssertionError, msg="Behavior of a bug (#537) is not reproduced."): # Expected failure, see enthought/traits#537 # InstanceValueListener.arg_check1 receives a TraitDictEvent # as `new` instead of the expected `{0: 0, 1: 1, 2: 2, 3: 3}` inst.ref.value[3] = 3 # Expected failure # See enthought/traits#537 with self.assertRaises( AssertionError, msg="Behavior of a bug (#537) is not reproduced."): # Handlers with arguments are unexpectedly called, but one of the # handlers fails, leading to the rest of the handlers # not to be called. Actual behavior depends on dictionary ordering # (Python <3.6) or the order of handlers defined in # InstanceValueListener (Python >= 3.6) self.assertEqual(inst.calls, {0: 1, 1: 0, 2: 0, 3: 0, 4: 0}) self.assertEqual(inst.ref.value, {0: 0, 1: 1, 2: 2, 3: 3}) def test_instance_value_list_listener(self): inst = InstanceValueListListener(tc=self) inst.trait_set( exp_object=inst.ref, exp_name="value", dst_name="value", exp_old=[0, 1, 2], exp_new=[0, 1, 2, 3], dst_new=[0, 1, 2, 3], ) inst.ref.value = [0, 1, 2, 3] self.assertEqual(inst.calls, {x: 1 for x in range(5)}) self.assertEqual(inst.ref.value, [0, 1, 2, 3]) inst.reset_traits(['calls']) ref = ArgCheckList() inst.trait_set( exp_object=inst, exp_name="ref", dst_name="value", exp_old=inst.ref, exp_new=ref, dst_new=[0, 1, 2], ) inst.ref = ref self.assertEqual(inst.calls, {x: 1 for x in range(5)}) self.assertEqual(inst.ref.value, [0, 1, 2]) inst.reset_traits(['calls']) inst.trait_set( exp_object=inst.ref, exp_name="value_items", dst_name="value_items", exp_old=[], exp_new=[3], dst_new=[3], ) inst.ref.value.append(3) self.assertEqual( inst.calls, {x: 1 for x in range(5)} ) self.assertEqual(inst.ref.value, [0, 1, 2, 3]) inst.reset_traits(['calls']) inst.trait_set( exp_object=inst.ref, exp_name="value_items", dst_name="value_items", exp_old=[2], exp_new=[], dst_new=[], ) inst.ref.value.pop(2) self.assertEqual( inst.calls, {x: 1 for x in range(5)} ) self.assertEqual(inst.ref.value, [0, 1, 3]) inst.reset_traits(['calls']) inst.trait_set( exp_object=inst.ref, exp_name="value_items", dst_name="value_items", exp_old=[1], exp_new=[1, 2], dst_new=[1, 2], ) inst.ref.value[1:2] = [1, 2] self.assertEqual( inst.calls, {x: 1 for x in range(5)} ) self.assertEqual(inst.ref.value, [0, 1, 2, 3]) def test_list1(self): l1 = List1(tc=self) for i in range(3): ac = ArgCheckBase() l1.trait_set( exp_object=l1, exp_name="refs_items", type_old=None, exp_old=Undefined, type_new=TraitListEvent, ) l1.refs.append(ac) # Behavior of an existing bug. # The expected value should be {0: 3, 3: 3, 4: 3} # See enthought/traits#538 self.assertEqual( l1.calls, {0: 3, 3: 0, 4: 0}, "Behavior of a bug (#538) is not reproduced." ) for i in range(3): self.assertEqual(l1.refs[i].value, 0) l1.reset_traits(['calls']) refs = [ArgCheckBase(), ArgCheckBase(), ArgCheckBase()] l1.trait_set( exp_object=l1, exp_name="refs", type_old=None, exp_old=l1.refs, type_new=TraitListObject, ) l1.refs = refs self.assertEqual(l1.calls, {0: 1, 3: 1, 4: 1}) for i in range(3): self.assertEqual(l1.refs[i].value, 0) l1.reset_traits(['calls']) for i in range(3): for j in range(3): l1.trait_set( exp_object=l1.refs[j], exp_name="value", type_old=None, exp_old=i, type_new=None, exp_new=(i + 1), ) l1.refs[j].value = i + 1 self.assertEqual(l1.calls, {0: 9, 3: 9, 4: 9}) for i in range(3): self.assertEqual(l1.refs[i].value, 3) def test_list2(self): self.check_list(List2(tc=self)) def test_list3(self): self.check_list(List3(tc=self)) def test_dict1(self): d1 = Dict1(tc=self) for i in range(3): ac = ArgCheckBase() d1.trait_set( exp_object=d1, exp_name="refs_items", type_old=None, exp_old=Undefined, type_new=TraitDictEvent, ) d1.refs[i] = ac # Behavior of an existing bug. # The expected value should be {0: 3, 3: 3, 4: 3} # See enthought/traits#538 self.assertEqual( d1.calls, {0: 3, 3: 0, 4: 0}, "Behavior of a bug (#538) is not reproduced." ) for i in range(3): self.assertEqual(d1.refs[i].value, 0) d1.reset_traits(['calls']) refs = {0: ArgCheckBase(), 1: ArgCheckBase(), 2: ArgCheckBase()} d1.trait_set( exp_object=d1, exp_name="refs", type_old=None, exp_old=d1.refs, type_new=TraitDictObject, ) d1.refs = refs self.assertEqual(d1.calls, {0: 1, 3: 1, 4: 1}) for i in range(3): self.assertEqual(d1.refs[i].value, 0) d1.reset_traits(['calls']) for i in range(3): for j in range(3): d1.trait_set( exp_object=d1.refs[j], exp_name="value", type_old=None, exp_old=i, type_new=None, exp_new=(i + 1), ) d1.refs[j].value = i + 1 self.assertEqual(d1.calls, {0: 9, 3: 9, 4: 9}) for i in range(3): self.assertEqual(d1.refs[i].value, 3) def test_dict2(self): self.check_dict(Dict2(tc=self)) def test_dict3(self): self.check_dict(Dict3(tc=self)) def test_pattern_list1(self): c = Complex(tc=self) self.check_complex( c, c, "int1, int2, int3", ["int1", "int2", "int3"], ["tint1", "tint2", "tint3"], ) def test_pattern_list2(self): c = Complex(tc=self) self.check_complex( c, c, ["int1", "int2", "int3"], ["int1", "int2", "int3"], ["tint1", "tint2", "tint3"], ) def test_pattern_list3(self): c = Complex(tc=self) self.check_complex( c, c.ref, "ref.[int1, int2, int3]", ["int1", "int2", "int3"], ["tint1", "tint2", "tint3"], ) def test_pattern_list4(self): c = Complex(tc=self) handlers = [c.arg_check0, c.arg_check3, c.arg_check4] n = len(handlers) pattern = "ref.[int1,int2,int3]" self.multi_register(c, handlers, pattern) r0 = c.ref r1 = ArgCheckBase() c.trait_set(exp_object=c, exp_name="ref", exp_old=r0, exp_new=r1) c.ref = r1 c.trait_set(exp_old=r1, exp_new=r0) c.ref = r0 self.assertEqual(c.calls, 2 * n) self.multi_register(c, handlers, pattern, remove=True) c.ref = r1 c.ref = r0 self.assertEqual(c.calls, 2 * n) def test_pattern_list5(self): c = Complex(tc=self) c.on_trait_change(c.arg_check1, "ref.[int1,int2,int3]") self.assertRaises(TraitError, c.trait_set, ref=ArgCheckBase()) def test_pattern_list6(self): c = Complex(tc=self) c.on_trait_change(c.arg_check2, "ref.[int1,int2,int3]") self.assertRaises(TraitError, c.trait_set, ref=ArgCheckBase()) def test_pattern_list7(self): c = Complex(tc=self) self.check_complex( c, c, "+test", ["int1", "int3", "tint2"], ["int2", "tint1", "tint3"], ) def test_pattern_list8(self): c = Complex(tc=self) self.check_complex( c, c, "int+test", ["int1", "int3"], ["int2", "tint1", "tint2", "tint3"], ) def test_pattern_list9(self): c = Complex(tc=self) self.check_complex( c, c, "int-test", ["int2"], ["int1", "int3", "tint4", "tint5", "tint6"], ) def test_pattern_list10(self): c = Complex(tc=self) self.check_complex( c, c, "int+", ["int1", "int2", "int3"], ["tint1", "tint2", "tint3"] ) def test_pattern_list11(self): c = Complex(tc=self) self.check_complex( c, c, "int-", ["int1", "int2", "int3"], ["tint1", "tint2", "tint3"] ) def test_pattern_list12(self): c = Complex(tc=self) self.check_complex( c, c, "int+test,tint-test", ["int1", "int3", "tint1", "tint3"], ["int2", "tint2"], ) def test_pattern_list13(self): c = Complex(tc=self) self.check_complex( c, c.ref, "ref.[int+test,tint-test]", ["int1", "int3", "tint1", "tint3"], ["int2", "tint2"], ) def test_cycle1(self): lt = LinkTest(tc=self, head=self.build_list()) handlers = [ lt.arg_check0, lt.arg_check1, lt.arg_check2, lt.arg_check3, lt.arg_check4, ] nh = len(handlers) self.multi_register(lt, handlers, "head.next*.value") cur = lt.head for i in range(4): lt.trait_set( exp_object=cur, exp_name="value", exp_old=10 * i, exp_new=(10 * i) + 1, ) cur.value = (10 * i) + 1 cur = cur.next self.assertEqual(lt.calls, 4 * nh) self.multi_register(lt, handlers, "head.next*.value", remove=True) cur = lt.head for i in range(4): cur.value = (10 * i) + 2 cur = cur.next self.assertEqual(lt.calls, 4 * nh) def test_cycle2(self): lt = LinkTest(tc=self, head=self.build_list()) handlers = [ lt.arg_check0, lt.arg_check1, lt.arg_check2, lt.arg_check3, lt.arg_check4, ] nh = len(handlers) self.multi_register(lt, handlers, "head.[next,prev]*.value") cur = lt.head for i in range(4): lt.trait_set( exp_object=cur, exp_name="value", exp_old=10 * i, exp_new=(10 * i) + 1, ) cur.value = (10 * i) + 1 cur = cur.next self.assertEqual(lt.calls, 4 * nh) self.multi_register( lt, handlers, "head.[next,prev]*.value", remove=True ) cur = lt.head for i in range(4): cur.value = (10 * i) + 2 cur = cur.next self.assertEqual(lt.calls, 4 * nh) def test_cycle3(self): lt = LinkTest(tc=self, head=self.build_list()) handlers = [lt.arg_check0, lt.arg_check3, lt.arg_check4] nh = len(handlers) self.multi_register(lt, handlers, "head.next*.value") link = self.new_link(lt, lt.head, 1) self.assertEqual(lt.calls, nh) link = self.new_link(lt, link, 2) self.assertEqual(lt.calls, 2 * nh) self.multi_register(lt, handlers, "head.next*.value", remove=True) link = self.new_link(lt, link, 3) self.assertEqual(lt.calls, 2 * nh) def test_property(self): pdo = PropertyDependsOn(tc=self) sum = pdo.sum self.assertEqual(sum, 0) for n in ["int1", "int2", "int3"]: for i in range(3): pdo.trait_set(exp_old=sum, exp_new=sum + 1) setattr(pdo.ref, n, i + 1) sum += 1 self.assertEqual(pdo.pcalls, (3 * 3) + 1) self.assertEqual(pdo.calls, 3 * 3) for i in range(10): pdo.sum self.assertEqual(pdo.pcalls, (3 * 3) + 1) pdo.trait_set(exp_old=sum, exp_new=60) old_ref = pdo.ref pdo.ref = ArgCheckBase(int1=10, int2=20, int3=30) self.assertEqual(pdo.pcalls, (3 * 3) + 2) self.assertEqual(pdo.calls, (3 * 3) + 1) sum = 60 for n in ["int1", "int2", "int3"]: for i in range(3): pdo.trait_set(exp_old=sum, exp_new=sum + 1) setattr(pdo.ref, n, getattr(pdo.ref, n) + 1) sum += 1 self.assertEqual(pdo.pcalls, (2 * 3 * 3) + 2) self.assertEqual(pdo.calls, (2 * 3 * 3) + 1) for n in ["int1", "int2", "int3"]: for i in range(3): setattr(old_ref, n, getattr(old_ref, n) + 1) self.assertEqual(pdo.pcalls, (2 * 3 * 3) + 2) self.assertEqual(pdo.calls, (2 * 3 * 3) + 1) self.assertEqual(pdo.sum, sum) self.assertEqual(pdo.pcalls, (2 * 3 * 3) + 2) def check_list(self, l): for i in range(3): ac = ArgCheckBase() self.assertRaises(TraitError, l.refs.append, ac) self.assertEqual(l.calls, 0) for i in range(3): self.assertEqual(l.refs[i].value, 0) refs = [ArgCheckBase(), ArgCheckBase(), ArgCheckBase()] self.assertRaises(TraitError, l.trait_set, refs=refs) self.assertEqual(l.calls, 0) for i in range(3): self.assertEqual(l.refs[i].value, 0) for i in range(3): for j in range(3): l.exp_new = i + 1 l.refs[j].value = i + 1 self.assertEqual(l.calls, 0) for i in range(3): self.assertEqual(l.refs[i].value, 3) def check_dict(self, d): for i in range(3): ac = ArgCheckBase() self.assertRaises(TraitError, d.refs.setdefault, i, ac) self.assertEqual(d.calls, 0) for i in range(3): self.assertEqual(d.refs[i].value, 0) refs = {0: ArgCheckBase(), 1: ArgCheckBase(), 2: ArgCheckBase()} self.assertRaises(TraitError, d.trait_set, refs=refs) self.assertEqual(d.calls, 0) for i in range(3): self.assertEqual(d.refs[i].value, 0) for i in range(3): for j in range(3): d.exp_new = i + 1 d.refs[j].value = i + 1 self.assertEqual(d.calls, 0) for i in range(3): self.assertEqual(d.refs[i].value, 3) def check_complex(self, c, r, pattern, names, other=[]): handlers = [ c.arg_check0, c.arg_check1, c.arg_check2, c.arg_check3, c.arg_check4, ] nh = len(handlers) nn = len(names) self.multi_register(c, handlers, pattern) for i in range(3): for n in names: c.trait_set( exp_object=r, exp_name=n, exp_old=i, exp_new=(i + 1) ) setattr(r, n, i + 1) for n in other: c.trait_set( exp_object=r, exp_name=n, exp_old=i, exp_new=(i + 1) ) setattr(r, n, i + 1) self.assertEqual(c.calls, 3 * nn * nh) self.multi_register(c, handlers, pattern, remove=True) for i in range(3): for n in names: setattr(r, n, i + 1) for n in other: setattr(r, n, i + 1) self.assertEqual(c.calls, 3 * nn * nh) def multi_register(self, object, handlers, pattern, remove=False): for handler in handlers: object.on_trait_change(handler, pattern, remove=remove) def build_list(self): l1 = Link(value=00) l2 = Link(value=10) l3 = Link(value=20) l4 = Link(value=30) l1.trait_set(next=l2, prev=l4) l2.trait_set(next=l3, prev=l1) l3.trait_set(next=l4, prev=l2) l4.trait_set(next=l1, prev=l3) return l1 def new_link(self, lt, cur, value): link = Link(value=value, next=cur.next, prev=cur) cur.next.prev = link lt.trait_set( exp_object=cur, exp_name="next", exp_old=cur.next, exp_new=link ) cur.next = link return link traits-6.3.2/traits/tests/test_file.py000066400000000000000000000057531414270267200200470ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import os from pathlib import Path import unittest from traits.api import File, HasTraits, TraitError from traits.testing.optional_dependencies import requires_traitsui class ExampleModel(HasTraits): file_name = File(exists=True) new_file_name = File(exists=False) class FastExampleModel(HasTraits): file_name = File() class FileTestCase(unittest.TestCase): def test_valid_file(self): example_model = ExampleModel(file_name=__file__) example_model.file_name = os.path.__file__ def test_valid_pathlike_file(self): ExampleModel(file_name=Path(__file__)) def test_invalid_file(self): example_model = ExampleModel(file_name=__file__) with self.assertRaises(TraitError): example_model.file_name = "not_valid_path!#!#!#" def test_invalid_pathlike_file(self): example_model = ExampleModel(file_name=__file__) with self.assertRaises(TraitError): example_model.file_name = Path("not_valid_path!#!#!#") def test_directory(self): example_model = ExampleModel(file_name=__file__) with self.assertRaises(TraitError): example_model.file_name = os.path.dirname(__file__) def test_pathlike_directory(self): example_model = ExampleModel(file_name=__file__) with self.assertRaises(TraitError): example_model.file_name = Path(os.path.dirname(__file__)) def test_invalid_type(self): example_model = ExampleModel(file_name=__file__) with self.assertRaises(TraitError): example_model.file_name = 11 def test_fast(self): example_model = FastExampleModel(file_name=__file__) example_model.path = "." def test_info_text(self): example_model = ExampleModel() with self.assertRaises(TraitError) as exc_cm: example_model.file_name = 47 self.assertIn("a string or os.PathLike object", str(exc_cm.exception)) self.assertIn("referring to an existing file", str(exc_cm.exception)) with self.assertRaises(TraitError) as exc_cm: example_model.new_file_name = 47 self.assertIn("a string or os.PathLike object", str(exc_cm.exception)) self.assertNotIn("exist", str(exc_cm.exception)) class TestCreateEditor(unittest.TestCase): @requires_traitsui def test_exists_controls_editor_dialog_style(self): x = File(exists=True) editor = x.create_editor() self.assertEqual(editor.dialog_style, "open") x = File(exists=False) editor = x.create_editor() self.assertEqual(editor.dialog_style, "save") traits-6.3.2/traits/tests/test_float.py000066400000000000000000000117631414270267200202330ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the Float trait type. """ import unittest from traits.api import BaseFloat, Either, Float, HasTraits, Str, TraitError from traits.testing.optional_dependencies import numpy, requires_numpy class MyFloat(object): def __init__(self, value): self._value = value def __float__(self): return self._value class InheritsFromFloat(float): pass class BadFloat(object): def __float__(self): raise ZeroDivisionError class FloatModel(HasTraits): value = Float # Assignment to the `Either` trait exercises a different C code path (see # validate_trait_complex in ctraits.c). value_or_none = Either(None, Float) float_or_text = Either(Float, Str) class BaseFloatModel(HasTraits): value = BaseFloat value_or_none = Either(None, BaseFloat) float_or_text = Either(Float, Str) class CommonFloatTests(object): """ Common tests for Float and BaseFloat """ def test_default(self): a = self.test_class() self.assertEqual(a.value, 0.0) def test_accepts_float(self): a = self.test_class() a.value = 5.6 self.assertIs(type(a.value), float) self.assertEqual(a.value, 5.6) a.value_or_none = 5.6 self.assertIs(type(a.value_or_none), float) self.assertEqual(a.value_or_none, 5.6) def test_accepts_float_subclass(self): a = self.test_class() a.value = InheritsFromFloat(37.0) self.assertIs(type(a.value), float) self.assertEqual(a.value, 37.0) a.value_or_none = InheritsFromFloat(37.0) self.assertIs(type(a.value), float) self.assertEqual(a.value, 37.0) def test_accepts_int(self): a = self.test_class() a.value = 2 self.assertIs(type(a.value), float) self.assertEqual(a.value, 2.0) a.value_or_none = 2 self.assertIs(type(a.value_or_none), float) self.assertEqual(a.value_or_none, 2.0) def test_accepts_float_like(self): a = self.test_class() a.value = MyFloat(1729.0) self.assertIs(type(a.value), float) self.assertEqual(a.value, 1729.0) a.value = MyFloat(594.0) self.assertIs(type(a.value), float) self.assertEqual(a.value, 594.0) def test_rejects_string(self): a = self.test_class() with self.assertRaises(TraitError): a.value = "2.3" with self.assertRaises(TraitError): a.value_or_none = "2.3" def test_bad_float_exceptions_propagated(self): a = self.test_class() with self.assertRaises(ZeroDivisionError): a.value = BadFloat() def test_compound_trait_float_conversion_fail(self): # Check that a failure to convert to float doesn't terminate # an assignment to a compound trait. a = self.test_class() a.float_or_text = "not a float" self.assertEqual(a.float_or_text, "not a float") def test_accepts_small_integer(self): a = self.test_class() a.value = 2 self.assertIs(type(a.value), float) self.assertEqual(a.value, 2.0) a.value_or_none = 2 self.assertIs(type(a.value_or_none), float) self.assertEqual(a.value_or_none, 2.0) def test_accepts_large_integer(self): a = self.test_class() a.value = 2 ** 64 self.assertIs(type(a.value), float) self.assertEqual(a.value, 2 ** 64) a.value_or_none = 2 ** 64 self.assertIs(type(a.value_or_none), float) self.assertEqual(a.value_or_none, 2 ** 64) @requires_numpy def test_accepts_numpy_floats(self): test_values = [ numpy.float64(2.3), numpy.float32(3.7), numpy.float16(1.28), ] a = self.test_class() for test_value in test_values: a.value = test_value self.assertIs(type(a.value), float) self.assertEqual(a.value, test_value) a.value_or_none = test_value self.assertIs(type(a.value_or_none), float) self.assertEqual(a.value_or_none, test_value) class TestFloat(unittest.TestCase, CommonFloatTests): def setUp(self): self.test_class = FloatModel def test_exceptions_propagate_in_compound_trait(self): # This test doesn't currently pass for BaseFloat, which is why it's not # in the common tests. That's probably a bug. a = self.test_class() with self.assertRaises(ZeroDivisionError): a.value_or_none = BadFloat() class TestBaseFloat(unittest.TestCase, CommonFloatTests): def setUp(self): self.test_class = BaseFloatModel traits-6.3.2/traits/tests/test_float_range.py000066400000000000000000000222671414270267200214100ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the Range trait with value type float. """ import unittest from traits.api import ( BaseRange, Either, HasTraits, Instance, Range, TraitError, ) from traits.testing.optional_dependencies import numpy, requires_numpy class Impossible(object): """ Type that never gets instantiated. """ def __init__(self): raise TypeError("Cannot instantiate this class") def ModelFactory(name, RangeFactory): """ Helper function to create various similar model classes. Parameters ---------- name : str Name to give the created class. RangeFactory : callable(*range_args, **range_kwargs) -> TraitType Callable with the same signature as Range; this will be used to create the model traits. Returns ------- HasTraits subclass Subclass containing various Range-like traits, for testing. """ class ModelWithRanges(HasTraits): """ Model containing various Range-like traits. """ # Simple floating-point range trait. percentage = RangeFactory(0.0, 100.0) # Traits that exercise the various possiblities for inclusion # or exclusion of the endpoints. open_closed = RangeFactory(0.0, 100.0, exclude_low=True) closed_open = RangeFactory(0.0, 100.0, exclude_high=True) open = RangeFactory(0.0, 100.0, exclude_low=True, exclude_high=True) closed = RangeFactory(0.0, 100.0) # Traits for one-sided intervals steam_temperature = RangeFactory(low=100.0) ice_temperature = Range(high=0.0) ModelWithRanges.__name__ = name return ModelWithRanges # A trait type that has a fast validator but doesn't accept any values. impossible = Instance(Impossible, allow_none=False) def RangeCompound(*args, **kwargs): """ Compound trait including a Range. """ return Either(impossible, Range(*args, **kwargs)) def BaseRangeCompound(*args, **kwargs): """ Compound trait including a BaseRange. """ return Either(impossible, BaseRange(*args, **kwargs)) ModelWithRange = ModelFactory("ModelWithRange", RangeFactory=Range) ModelWithBaseRange = ModelFactory("ModelWithBaseRange", RangeFactory=BaseRange) ModelWithRangeCompound = ModelFactory( "ModelWithRangeCompound", RangeFactory=RangeCompound, ) ModelWithBaseRangeCompound = ModelFactory( "ModelWithBaseRangeCompound", RangeFactory=BaseRangeCompound, ) class InheritsFromFloat(float): """ Object that's float-like by virtue of inheriting from float. """ pass class FloatLike(object): """ Object that's float-like by virtue of providing a __float__ method. """ def __init__(self, value): self._value = value def __float__(self): return self._value class BadFloatLike(object): """ Object whose __float__ method raises something other than TypeError. """ def __float__(self): raise ZeroDivisionError("bogus error") class CommonRangeTests(object): def test_accepts_float(self): self.model.percentage = 35.0 self.assertIs(type(self.model.percentage), float) self.assertEqual(self.model.percentage, 35.0) with self.assertRaises(TraitError): self.model.percentage = -0.5 with self.assertRaises(TraitError): self.model.percentage = 100.5 def test_accepts_int(self): self.model.percentage = 35 self.assertIs(type(self.model.percentage), float) self.assertEqual(self.model.percentage, 35.0) with self.assertRaises(TraitError): self.model.percentage = -1 with self.assertRaises(TraitError): self.model.percentage = 101 def test_accepts_bool(self): self.model.percentage = False self.assertIs(type(self.model.percentage), float) self.assertEqual(self.model.percentage, 0.0) self.model.percentage = True self.assertIs(type(self.model.percentage), float) self.assertEqual(self.model.percentage, 1.0) def test_rejects_bad_types(self): # A selection of things that don't count as float-like. non_floats = [ "not a number", "\N{GREEK CAPITAL LETTER SIGMA}", b"not a number", "3.5", "3", 3 + 4j, 0j, [1.2], (1.2,), None, ] for non_float in non_floats: with self.assertRaises(TraitError): self.model.percentage = non_float @requires_numpy def test_accepts_numpy_types(self): numpy_values = [ numpy.uint8(25), numpy.uint16(25), numpy.uint32(25), numpy.uint64(25), numpy.int8(25), numpy.int16(25), numpy.int32(25), numpy.int64(25), numpy.float16(25), numpy.float32(25), numpy.float64(25), ] for numpy_value in numpy_values: self.model.percentage = numpy_value self.assertIs(type(self.model.percentage), float) self.assertEqual(self.model.percentage, 25.0) def test_accepts_float_subclass(self): self.model.percentage = InheritsFromFloat(44.0) self.assertIs(type(self.model.percentage), float) self.assertEqual(self.model.percentage, 44.0) with self.assertRaises(TraitError): self.model.percentage = InheritsFromFloat(-0.5) with self.assertRaises(TraitError): self.model.percentage = InheritsFromFloat(100.5) def test_accepts_float_like(self): self.model.percentage = FloatLike(35.0) self.assertIs(type(self.model.percentage), float) self.assertEqual(self.model.percentage, 35.0) with self.assertRaises(TraitError): self.model.percentage = FloatLike(-0.5) with self.assertRaises(TraitError): self.model.percentage = FloatLike(100.5) def test_bad_float_like(self): with self.assertRaises(ZeroDivisionError): self.model.percentage = BadFloatLike() def test_endpoints(self): # point within the interior of the range self.model.open = self.model.closed = 50.0 self.model.open_closed = self.model.closed_open = 50.0 self.assertEqual(self.model.open, 50.0) self.assertEqual(self.model.closed, 50.0) self.assertEqual(self.model.open_closed, 50.0) self.assertEqual(self.model.closed_open, 50.0) # low endpoint self.model.closed = self.model.closed_open = 0.0 self.assertEqual(self.model.closed, 0.0) self.assertEqual(self.model.closed_open, 0.0) with self.assertRaises(TraitError): self.model.open = 0.0 with self.assertRaises(TraitError): self.model.open_closed = 0.0 # high endpoint self.model.closed = self.model.open_closed = 100.0 self.assertEqual(self.model.closed, 100.0) self.assertEqual(self.model.open_closed, 100.0) with self.assertRaises(TraitError): self.model.open = 100.0 with self.assertRaises(TraitError): self.model.closed_open = 100.0 def test_half_infinite(self): ice_temperatures = [-273.15, -273.0, -100.0, -1.0, -0.1, -0.001] water_temperatures = [0.001, 0.1, 1.0, 50.0, 99.0, 99.9, 99.999] steam_temperatures = [100.001, 100.1, 101.0, 1000.0, 1e100] for temperature in steam_temperatures: self.model.steam_temperature = temperature self.assertEqual(self.model.steam_temperature, temperature) for temperature in ice_temperatures + water_temperatures: self.model.steam_temperature = 1729.0 with self.assertRaises(TraitError): self.model.steam_temperature = temperature self.assertEqual(self.model.steam_temperature, 1729.0) for temperature in ice_temperatures: self.model.ice_temperature = temperature self.assertEqual(self.model.ice_temperature, temperature) for temperature in water_temperatures + steam_temperatures: self.model.ice_temperature = -1729.0 with self.assertRaises(TraitError): self.model.ice_temperature = temperature self.assertEqual(self.model.ice_temperature, -1729.0) class TestFloatRange(CommonRangeTests, unittest.TestCase): def setUp(self): self.model = ModelWithRange() class TestFloatBaseRange(CommonRangeTests, unittest.TestCase): def setUp(self): self.model = ModelWithBaseRange() class TestFloatRangeCompound(CommonRangeTests, unittest.TestCase): def setUp(self): self.model = ModelWithRangeCompound() class TestFloatBaseRangeCompound(CommonRangeTests, unittest.TestCase): def setUp(self): self.model = ModelWithBaseRangeCompound() traits-6.3.2/traits/tests/test_get_traits.py000066400000000000000000000060411414270267200212640ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import ( HasTraits, Int, List, Str, TraitError, ) class Foo(HasTraits): num = Int bar = Str class Bar(HasTraits): # Default is visible. PubT1 = Str # Change to invisible. PubT2 = Str(visible=False) # New behaviour makes private traits invisible. PrivT1 = Str(private=True) # Force visibility of a private trait. PrivT2 = Str(private=True, visible=True) class FooBar(HasTraits): num = Int baz = "non-trait class attribute" class GetTraitTestCase(unittest.TestCase): def test_trait_set_bad(self): b = Foo(num=23) # This should fail before and after #234. with self.assertRaises(TraitError): b.num = "first" self.assertEqual(b.num, 23) def test_trait_set_replaced(self): b = Foo() # Overriding the trait with a new type should work. b.add_trait("num", Str()) b.num = "first" self.assertEqual(b.num, "first") def test_trait_set_replaced_and_check(self): b = Foo() b.add_trait("num", Str()) b.num = "first" self.assertEqual(b.num, "first") # Check that the "traits" call picks up the new instance trait. (See # #234.) self.assertEqual(b.trait("num"), b.traits()["num"]) def test_trait_names_returned_by_visible_traits(self): b = Bar() self.assertEqual( sorted(b.visible_traits()), sorted(["PubT1", "PrivT2"]) ) def test_dir(self): b = FooBar() names = dir(b) self.assertIn("baz", names) self.assertIn("num", names) self.assertIn("edit_traits", names) # Issue 925: _notifiers not shown in dir() self.assertIn("_notifiers", names) # Ensure no duplicates self.assertEqual(len(set(names)), len(names)) def test_trait_name_with_list_items(self): # Dynamically added a List trait causes an "_items" to be added, but # that should not be reported by HasTraits.traits class Base(HasTraits): pass a = Base() # This adds an instance trait for "pins_items" as well. a.add_trait("pins", List()) self.assertIn("pins", a.traits()) self.assertNotIn("pins_items", a.traits()) def test_trait_name_with_items(self): # Dynamically added traits with name "*_items" is also skipped. class Base(HasTraits): pass a = Base() a.add_trait("good_items", Str()) # If enthought/traits#1329 is fixed, then the following assertion # should fail. self.assertNotIn("good_items", a.traits()) traits-6.3.2/traits/tests/test_has_required_traits.py000066400000000000000000000026731414270267200231670ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import Int, Float, String, HasRequiredTraits, TraitError class TestHasRequiredTraits(unittest.TestCase): def test_trait_value_assignment(self): test_instance = RequiredTest(i_trait=4, f_trait=2.2, s_trait="test") self.assertEqual(test_instance.i_trait, 4) self.assertEqual(test_instance.f_trait, 2.2) self.assertEqual(test_instance.s_trait, "test") self.assertEqual(test_instance.non_req_trait, 4.4) self.assertEqual(test_instance.normal_trait, 42.0) def test_missing_required_trait(self): with self.assertRaises(TraitError) as exc: RequiredTest(i_trait=3) self.assertEqual( exc.exception.args[0], "The following required traits were not " "provided: f_trait, s_trait.", ) class RequiredTest(HasRequiredTraits): i_trait = Int(required=True) f_trait = Float(required=True) s_trait = String(required=True) non_req_trait = Float(4.4, required=False) normal_trait = Float(42.0) traits-6.3.2/traits/tests/test_has_traits.py000066400000000000000000000654441414270267200212740ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import copy import pickle import unittest from traits.has_traits import ( update_traits_class_dict, on_trait_change, BaseTraits, ClassTraits, PrefixTraits, ListenerTraits, InstanceTraits, HasTraits, observe, ObserverTraits, SingletonHasTraits, SingletonHasStrictTraits, SingletonHasPrivateTraits, MetaHasTraits, ) from traits.ctrait import CTrait from traits.observation.api import ( compile_str, compile_expr, NotifierNotFound, trait, ) from traits.observation.exception_handling import ( pop_exception_handler, push_exception_handler, ) from traits.traits import ForwardProperty, generic_trait from traits.trait_types import Event, Float, Instance, Int, List, Map, Str from traits.trait_errors import TraitError def _dummy_getter(self): pass def _dummy_setter(self, value): pass def _dummy_validator(self, value): pass class TestMetaHasTraits(unittest.TestCase): def test_add_listener_and_remove_listener_deprecated(self): def listener(cls): pass with self.assertWarnsRegex( DeprecationWarning, "add_listener is deprecated" ): MetaHasTraits.add_listener(listener) with self.assertWarnsRegex( DeprecationWarning, "remove_listener is deprecated" ): MetaHasTraits.remove_listener(listener) class TestCreateTraitsMetaDict(unittest.TestCase): def test_class_attributes(self): # Given class_name = "MyClass" bases = (object,) class_dict = {"attr": "something"} # When update_traits_class_dict(class_name, bases, class_dict) # Then; Check that the original Python-level class attributes are still # present in the class dictionary. self.assertEqual(class_dict["attr"], "something") # Other traits dictionaries should be empty. for kind in (BaseTraits, ClassTraits, ListenerTraits, InstanceTraits): self.assertEqual(class_dict[kind], {}) def test_forward_property(self): # Given class_name = "MyClass" bases = (object,) class_dict = { "attr": "something", "my_property": ForwardProperty({}), "_get_my_property": _dummy_getter, "_set_my_property": _dummy_setter, "_validate_my_property": _dummy_validator, } # When update_traits_class_dict(class_name, bases, class_dict) # Then self.assertEqual(class_dict[ListenerTraits], {}) self.assertEqual(class_dict[InstanceTraits], {}) # Both ClassTraits and BaseTraits should contain a single trait (the # property we created) self.assertEqual(len(class_dict[BaseTraits]), 1) self.assertEqual(len(class_dict[ClassTraits]), 1) self.assertIs( class_dict[BaseTraits]["my_property"], class_dict[ClassTraits]["my_property"], ) # The class_dict should still have the entry for `attr`, but not # `my_property`. self.assertEqual(class_dict["attr"], "something") self.assertNotIn("my_property", class_dict) def test_standard_trait(self): # Given class_name = "MyClass" bases = (object,) class_dict = {"attr": "something", "my_int": Int} # When update_traits_class_dict(class_name, bases, class_dict) # Then self.assertEqual(class_dict[ListenerTraits], {}) self.assertEqual(class_dict[InstanceTraits], {}) # Both ClassTraits and BaseTraits should contain a single trait (the # Int trait) self.assertEqual(len(class_dict[BaseTraits]), 1) self.assertEqual(len(class_dict[ClassTraits]), 1) self.assertIs( class_dict[BaseTraits]["my_int"], class_dict[ClassTraits]["my_int"] ) # The class_dict should still have the entry for `attr`, but not # `my_int`. self.assertEqual(class_dict["attr"], "something") self.assertNotIn("my_int", class_dict) def test_prefix_trait(self): # Given class_name = "MyClass" bases = (object,) class_dict = {"attr": "something", "my_int_": Int} # prefix trait # When update_traits_class_dict(class_name, bases, class_dict) # Then for kind in (BaseTraits, ClassTraits, ListenerTraits, InstanceTraits): self.assertEqual(class_dict[kind], {}) self.assertIn("my_int", class_dict[PrefixTraits]) # The class_dict should still have the entry for `attr`, but not # `my_int`. self.assertEqual(class_dict["attr"], "something") self.assertNotIn("my_int", class_dict) def test_listener_trait(self): # Given @on_trait_change("something") def listener(self): pass class_name = "MyClass" bases = (object,) class_dict = {"attr": "something", "my_listener": listener} # When update_traits_class_dict(class_name, bases, class_dict) # Then self.assertEqual(class_dict[BaseTraits], {}) self.assertEqual(class_dict[ClassTraits], {}) self.assertEqual(class_dict[InstanceTraits], {}) self.assertEqual( class_dict[ListenerTraits], { "my_listener": ( "method", { "pattern": "something", "post_init": False, "dispatch": "same", }, ) }, ) def test_observe_trait(self): # Given @observe(trait("value"), post_init=True, dispatch="ui") @observe("name") def handler(self, event): pass class_name = "MyClass" bases = (object,) class_dict = {"attr": "something", "my_listener": handler} # When update_traits_class_dict(class_name, bases, class_dict) # Then self.assertEqual( class_dict[ObserverTraits], { "my_listener": [ { "graphs": compile_str("name"), "post_init": False, "dispatch": "same", "handler_getter": getattr, }, { "graphs": compile_expr(trait("value")), "post_init": True, "dispatch": "ui", "handler_getter": getattr, }, ], }, ) def test_python_property(self): # Given class_name = "MyClass" bases = (object,) class_dict = { "attr": "something", "my_property": property(_dummy_getter), } # When update_traits_class_dict(class_name, bases, class_dict) # Then self.assertEqual(class_dict[BaseTraits], {}) self.assertEqual(class_dict[InstanceTraits], {}) self.assertEqual(class_dict[ListenerTraits], {}) self.assertIs(class_dict[ClassTraits]["my_property"], generic_trait) def test_complex_baseclass(self): # Given class Base(HasTraits): x = Int class_name = "MyClass" bases = (Base,) class_dict = {"attr": "something", "my_trait": Float()} # When update_traits_class_dict(class_name, bases, class_dict) # Then self.assertEqual(class_dict[InstanceTraits], {}) self.assertEqual(class_dict[ListenerTraits], {}) self.assertIs( class_dict[BaseTraits]["x"], class_dict[ClassTraits]["x"] ) self.assertIs( class_dict[BaseTraits]["my_trait"], class_dict[ClassTraits]["my_trait"], ) class TestHasTraits(unittest.TestCase): def test__class_traits(self): # Exercise the _class_traits() private introspection method. class Base(HasTraits): pin = Int a = Base() a_class_traits = a._class_traits() self.assertIsInstance(a_class_traits, dict) self.assertIn("pin", a_class_traits) self.assertIsInstance(a_class_traits["pin"], CTrait) b = Base() self.assertIs(b._class_traits(), a_class_traits) def test__instance_traits(self): # Exercise the _instance_traits() private introspection method. class Base(HasTraits): pin = Int a = Base() a_instance_traits = a._instance_traits() self.assertIsInstance(a_instance_traits, dict) # A second call should return the same dictionary. self.assertIs(a._instance_traits(), a_instance_traits) # A different instance should have its own instance traits dict. b = Base() self.assertIsNot(b._instance_traits(), a_instance_traits) def test__trait_notifications_enabled(self): class Base(HasTraits): foo = Int(0) foo_notify_count = Int(0) def _foo_changed(self): self.foo_notify_count += 1 a = Base() # Default state is that notifications are enabled. self.assertTrue(a._trait_notifications_enabled()) # Changing foo increments the count. old_count = a.foo_notify_count a.foo += 1 self.assertEqual(a.foo_notify_count, old_count + 1) # After disabling notifications, count is not increased. a._trait_change_notify(False) self.assertFalse(a._trait_notifications_enabled()) old_count = a.foo_notify_count a.foo += 1 self.assertEqual(a.foo_notify_count, old_count) # After re-enabling notifications, count is increased. a._trait_change_notify(True) self.assertTrue(a._trait_notifications_enabled()) old_count = a.foo_notify_count a.foo += 1 self.assertEqual(a.foo_notify_count, old_count + 1) def test__trait_notifications_vetoed(self): class SomeEvent(HasTraits): event_id = Int() class Target(HasTraits): event = Event(Instance(SomeEvent)) event_count = Int(0) def _event_fired(self): self.event_count += 1 target = Target() event = SomeEvent(event_id=1234) # Default state is not vetoed. self.assertFalse(event._trait_notifications_vetoed()) # Firing the event increments the count. old_count = target.event_count target.event = event self.assertEqual(target.event_count, old_count + 1) # Now veto the event. Firing the event won't affect the count. event._trait_veto_notify(True) self.assertTrue(event._trait_notifications_vetoed()) old_count = target.event_count target.event = event self.assertEqual(target.event_count, old_count) # Unveto the event. event._trait_veto_notify(False) self.assertFalse(event._trait_notifications_vetoed()) old_count = target.event_count target.event = event self.assertEqual(target.event_count, old_count + 1) def test__object_notifiers_vetoed(self): class SomeEvent(HasTraits): event_id = Int() class Target(HasTraits): event = Event(Instance(SomeEvent)) event_count = Int(0) target = Target() event = SomeEvent(event_id=9) def object_handler(object, name, old, new): if name == "event": object.event_count += 1 target.on_trait_change(object_handler, name="anytrait") # Default state is not vetoed. self.assertFalse(event._trait_notifications_vetoed()) # Firing the event increments the count. old_count = target.event_count target.event = event self.assertEqual(target.event_count, old_count + 1) # Now veto the event. Firing the event won't affect the count. event._trait_veto_notify(True) self.assertTrue(event._trait_notifications_vetoed()) old_count = target.event_count target.event = event self.assertEqual(target.event_count, old_count) # Unveto the event. event._trait_veto_notify(False) self.assertFalse(event._trait_notifications_vetoed()) old_count = target.event_count target.event = event self.assertEqual(target.event_count, old_count + 1) def test_traits_inited(self): foo = HasTraits() self.assertTrue(foo.traits_inited()) def test__trait_set_inited(self): foo = HasTraits.__new__(HasTraits) self.assertFalse(foo.traits_inited()) foo._trait_set_inited() self.assertTrue(foo.traits_inited()) def test_generic_getattr_exception(self): # Regression test for enthought/traits#946. class PropertyLike: """ Data descriptor giving a property-like object that produces successive reciprocals on __get__. This means that it raises on first access, but not on subsequent accesses. """ def __init__(self): self.n = 0 def __get__(self, obj, type=None): old_n = self.n self.n += 1 return 1 / old_n # Need a __set__ method to make this a data descriptor. def __set__(self, obj, value): raise AttributeError("Read-only descriptor") class A(HasTraits): fruit = PropertyLike() banana_ = Int(1729) a = A() # The exception raised on the first attribute access should be # propagated. with self.assertRaises(ZeroDivisionError): a.fruit # Exercise the code path where the PyObject_GenericGetAttr call raises # AttributeError. In this case, we catch the error but the prefix trait # machinery raises a new AttributeError. with self.assertRaises(AttributeError): a.veg # Exercise the case where the prefix traits machinery goes on to # produce a valid result. self.assertEqual(a.banananana, 1729) def test_deepcopy_memoization(self): class A(HasTraits): x = Int() y = Str() a = A() objs = [a, a] objs_copy = copy.deepcopy(objs) self.assertIsNot(objs_copy[0], objs[0]) self.assertIs(objs_copy[0], objs_copy[1]) def test_add_class_trait(self): # Testing basic usage. class A(HasTraits): pass A.add_class_trait("y", Str()) a = A() self.assertEqual(a.y, "") def test_add_class_trait_affects_existing_instances(self): class A(HasTraits): pass a = A() A.add_class_trait("y", Str()) self.assertEqual(a.y, "") def test_add_class_trait_affects_subclasses(self): class A(HasTraits): pass class B(A): pass class C(B): pass class D(B): pass A.add_class_trait("y", Str()) self.assertEqual(A().y, "") self.assertEqual(B().y, "") self.assertEqual(C().y, "") self.assertEqual(D().y, "") def test_add_class_trait_has_items_and_subclasses(self): # Regression test for enthought/traits#1460 class A(HasTraits): pass class B(A): pass class C(B): pass # Code branch for traits with items. A.add_class_trait("x", List(Int)) self.assertEqual(A().x, []) self.assertEqual(B().x, []) self.assertEqual(C().x, []) # Exercise the code branch for mapped traits. A.add_class_trait("y", Map({"yes": 1, "no": 0}, default_value="no")) self.assertEqual(A().y, "no") self.assertEqual(B().y, "no") self.assertEqual(C().y, "no") def test_add_class_trait_add_prefix_traits(self): class A(HasTraits): pass A.add_class_trait("abc_", Str()) A.add_class_trait("abc_def_", Int()) a = A() self.assertEqual(a.abc_def_g, 0) self.assertEqual(a.abc_z, "") def test_add_class_trait_when_trait_already_exists(self): class A(HasTraits): foo = Int() with self.assertRaises(TraitError): A.add_class_trait("foo", List()) self.assertEqual(A().foo, 0) with self.assertRaises(AttributeError): A().foo_items def test_add_class_trait_when_trait_already_exists_in_subclass(self): class A(HasTraits): pass class B(A): foo = Int() A.add_class_trait("foo", Str()) self.assertEqual(A().foo, "") self.assertEqual(B().foo, 0) def test_traits_method_with_dunder_metadata(self): # Regression test for enthought/envisage#430 class A(HasTraits): foo = Int(__extension_point__=True) bar = Int(__extension_point__=False) baz = Int() a = A(foo=3, bar=4, baz=5) self.assertEqual( a.traits(__extension_point__=True), {"foo": a.trait("foo")}, ) self.assertEqual( A.class_traits(__extension_point__=True), {"foo": A.class_traits()["foo"]}, ) def test_decorated_changed_method(self): # xref: enthought/traits#527 # Traits should ignore the _changed magic naming. events = [] class A(HasTraits): foo = Int() @on_trait_change("foo") def _foo_changed(self, obj, name, old, new): events.append((obj, name, old, new)) a = A() a.foo = 23 self.assertEqual( events, [(a, "foo", 0, 23)], ) def test_observed_changed_method(self): events = [] class A(HasTraits): foo = Int() @observe("foo") def _foo_changed(self, event): events.append(event) a = A() a.foo = 23 self.assertEqual(len(events), 1) event = events[0] self.assertEqual(event.object, a) self.assertEqual(event.name, "foo") self.assertEqual(event.old, 0) self.assertEqual(event.new, 23) def test_decorated_changed_method_subclass(self): # xref: enthought/traits#527 # Traits should ignore the _changed magic naming. events = [] class A(HasTraits): foo = Int() @on_trait_change("foo") def _foo_changed(self, obj, name, old, new): events.append((obj, name, old, new)) class B(A): pass a = B() a.foo = 23 self.assertEqual( events, [(a, "foo", 0, 23)], ) class TestObjectNotifiers(unittest.TestCase): """ Test calling object notifiers. """ def test_notifiers_empty(self): class Foo(HasTraits): x = Int() foo = Foo(x=1) self.assertEqual(foo._notifiers(True), []) def test_notifiers_on_object(self): class Foo(HasTraits): x = Int() foo = Foo(x=1) self.assertEqual(foo._notifiers(True), []) # when def handler(): pass foo.on_trait_change(handler, name="anytrait") # then notifiers = foo._notifiers(True) self.assertEqual(len(notifiers), 1) onotifier, = notifiers self.assertEqual(onotifier.handler, handler) class TestCallNotifiers(unittest.TestCase): def test_trait_and_object_notifiers_called(self): side_effects = [] class Foo(HasTraits): x = Int() y = Int() def _x_changed(self): side_effects.append("x") def object_handler(): side_effects.append("object") foo = Foo() foo.on_trait_change(object_handler, name="anytrait") # when side_effects.clear() foo.x = 3 # then self.assertEqual(side_effects, ["x", "object"]) # when side_effects.clear() foo.y = 4 # then self.assertEqual(side_effects, ["object"]) def test_trait_notifier_modify_object_notifier(self): # Test when a trait notifier has a side effect of adding # an object notifier side_effects = [] def object_handler1(): side_effects.append("object1") def object_handler2(): side_effects.append("object2") class Foo(HasTraits): x = Int() y = Int() def _x_changed(self): side_effects.append("x") # add the second object notifier self.on_trait_change(object_handler2, name="anytrait") # Add an object handler so that the list is created for mutation. foo = Foo() foo.on_trait_change(object_handler1, name="anytrait") # when side_effects.clear() foo.x = 1 # then # the second object notifier is not called. self.assertEqual(side_effects, ["x", "object1"]) # But the object notifier is added and will be used the next time # when side_effects.clear() foo.y = 2 # then # the second object notifier is called. self.assertEqual(side_effects, ["object1", "object2"]) class TestDeprecatedHasTraits(unittest.TestCase): def test_deprecated(self): class TestSingletonHasTraits(SingletonHasTraits): pass class TestSingletonHasStrictTraits(SingletonHasStrictTraits): pass class TestSingletonHasPrivateTraits(SingletonHasPrivateTraits): pass with self.assertWarns(DeprecationWarning): TestSingletonHasTraits() with self.assertWarns(DeprecationWarning): TestSingletonHasStrictTraits() with self.assertWarns(DeprecationWarning): TestSingletonHasPrivateTraits() class MappedWithDefault(HasTraits): married = Map({"yes": 1, "yeah": 1, "no": 0, "nah": 0}) default_calls = Int(0) def _married_default(self): self.default_calls += 1 return "yes" class TestHasTraitsPickling(unittest.TestCase): def test_pickle_mapped_default_method(self): person = MappedWithDefault() # Sanity check self.assertEqual(person.default_calls, 0) reconstituted = pickle.loads(pickle.dumps(person)) self.assertEqual(reconstituted.married_, 1) self.assertEqual(reconstituted.married, "yes") self.assertEqual(reconstituted.default_calls, 1) class Person(HasTraits): age = Int() class PersonWithObserve(Person): events = List() @observe(trait("age")) def handler(self, event): self.events.append(event) class TestHasTraitsObserveHook(unittest.TestCase): """ Test observe decorator and the observe method. """ def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def test_overloaded_signature_expression(self): # Test the overloaded signature for expression expressions = [ trait("age"), "age", [trait("age")], ["age"], ] for expression in expressions: class NewPerson(Person): events = List() @observe(expression) def handler(self, event): self.events.append(event) person = NewPerson() person.age += 1 self.assertEqual(len(person.events), 1) def test_observe_method_remove(self): events = [] person = Person() person.observe(events.append, "age") # sanity check person.age += 1 self.assertEqual(len(events), 1) # when person.observe(events.append, "age", remove=True) # then person.age += 1 self.assertEqual(len(events), 1) # unchanged def test_observe_method_remove_nonexistent_handler(self): events = [] person = Person() with self.assertRaises(NotifierNotFound): person.observe(events.append, "age", remove=True) def test_observe_dispatch_ui(self): # Test to ensure "ui" is one of the allowed value # Not testing the actual effect as it requires GUI event loop # as well as assumption on the local thread identity while running # the test. person = Person() person.observe(repr, trait("age"), dispatch="ui") def test_inherit_observer_from_superclass(self): # Test observers can be inherited class BaseClass(HasTraits): events = List() @observe("value") def handler(self, event): self.events.append(event) class SubClass(BaseClass): value = Int() instance = SubClass() instance.value += 1 self.assertEqual(len(instance.events), 1) def test_observer_overridden(self): # The handler is overriden, no change event should be registered. class BaseClass(HasTraits): events = List() @observe("value") def handler(self, event): self.events.append(event) class SubclassOverriden(BaseClass): value = Int() handler = None instance = SubclassOverriden() instance.value += 1 self.assertEqual(len(instance.events), 0) def test_observe_post_init(self): class PersonWithPostInt(Person): events = List() @observe("age", post_init=True) def handler(self, event): self.events.append(event) person = PersonWithPostInt(age=10) self.assertEqual(len(person.events), 0) person.age += 1 self.assertEqual(len(person.events), 1) def test_observe_pickability(self): # Test an HasTraits with observe can be pickled. person = PersonWithObserve() for protocol in range(pickle.HIGHEST_PROTOCOL + 1): serialized = pickle.dumps(person, protocol=protocol) deserialized = pickle.loads(serialized) deserialized.age += 1 self.assertEqual(len(deserialized.events), 1) def test_observe_deepcopy(self): # Test an HasTraits with observe can be deepcopied. person = PersonWithObserve() copied = copy.deepcopy(person) copied.age += 1 self.assertEqual(len(copied.events), 1) self.assertEqual(len(person.events), 0) traits-6.3.2/traits/tests/test_historical_unpickling.py000066400000000000000000000036531414270267200235110ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for unpicking of pickles created using previous versions of Traits. """ import pathlib import pickle import unittest from traits.testing.optional_dependencies import ( pkg_resources, requires_pkg_resources, ) def find_pickles(): """ Iterate over the pickle files in the test_data directory. Skip files that correspond to a protocol not supported with the current version of Python. Yields paths to pickle files. """ pickle_directory = pathlib.Path( pkg_resources.resource_filename( "traits.tests", "test-data/historical-pickles", ) ) for pickle_path in pickle_directory.glob("*.pkl"): header, _, protocol, _ = pickle_path.name.split("-", maxsplit=3) if header != "hipt": # Skip pickle files that don't follow the naming convention. continue if not protocol.startswith("p"): raise RuntimeError("Can't interpret protocol: {}".format(protocol)) protocol = int(protocol[1:]) if protocol > pickle.HIGHEST_PROTOCOL: # Protocol not understood by current Python; skip. continue yield pickle_path class TestHistoricalPickles(unittest.TestCase): @requires_pkg_resources def test_unpickling_historical_pickles(self): # Just test that the pickle can be unpickled. for pickle_path in find_pickles(): with self.subTest(filename=pickle_path.name): with pickle_path.open("rb") as f: pickle.load(f) traits-6.3.2/traits/tests/test_instance.py000066400000000000000000000045451414270267200207320ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the Instance and BaseInstance trait types. """ import unittest from traits.api import BaseInstance, HasStrictTraits, Instance, TraitError #: Define a new "trait type" using BaseInstance. This is similar to the #: way that Datetime and Time are defined. Slice = BaseInstance(slice) class HasSlices(HasStrictTraits): my_slice = Instance(slice) also_my_slice = Slice() none_explicitly_allowed = Instance(slice, allow_none=True) also_allow_none = Slice(allow_none=True) disallow_none = Instance(slice, allow_none=False) also_disallow_none = Slice(allow_none=False) class TestInstance(unittest.TestCase): def test_explicitly_prohibit_none(self): obj = HasSlices(disallow_none=slice(2, 5)) self.assertIsNotNone(obj.disallow_none) with self.assertRaises(TraitError): obj.disallow_none = None self.assertIsNotNone(obj.disallow_none) obj = HasSlices(also_disallow_none=slice(2, 5)) self.assertIsNotNone(obj.also_disallow_none) with self.assertRaises(TraitError): obj.also_disallow_none = None self.assertIsNotNone(obj.also_disallow_none) def test_explicitly_allow_none(self): obj = HasSlices(none_explicitly_allowed=slice(2, 5)) self.assertIsNotNone(obj.none_explicitly_allowed) obj.none_explicitly_allowed = None self.assertIsNone(obj.none_explicitly_allowed) obj = HasSlices(also_allow_none=slice(2, 5)) self.assertIsNotNone(obj.also_allow_none) obj.also_allow_none = None self.assertIsNone(obj.also_allow_none) def test_allow_none_permitted_by_default(self): obj = HasSlices(my_slice=slice(2, 5)) self.assertIsNotNone(obj.my_slice) obj.my_slice = None self.assertIsNone(obj.my_slice) obj = HasSlices(also_my_slice=slice(2, 5)) self.assertIsNotNone(obj.also_my_slice) obj.my_slice = None self.assertIsNone(obj.my_slice) traits-6.3.2/traits/tests/test_int_range_long.py000066400000000000000000000020261414270267200221030ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import HasTraits, Int, Range, TraitError class A(HasTraits): i = Int r = Range(2, 9223372036854775807) class TraitIntRange(unittest.TestCase): def test_int(self): "Test it is legal to set an Int trait to any integer value" a = A() a.i = 1 a.i = 10**20 def test_range(self): "Test a range trait with large integers being set to an int value" a = A() a.r = 256 a.r = 20 self.assertRaises(TraitError, a.trait_set, r=1) self.assertRaises( TraitError, a.trait_set, r=9223372036854775808 ) traits-6.3.2/traits/tests/test_integer.py000066400000000000000000000065301414270267200205570ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the Int trait type. """ import decimal import sys import unittest from traits.api import Either, HasTraits, Int, CInt, TraitError from traits.testing.optional_dependencies import numpy, requires_numpy class A(HasTraits): integral = Int convertible = CInt convertible_or_none = Either(None, CInt) class IntegerLike(object): def __index__(self): return 42 class Truncatable(object): def __int__(self): return 42 class TestInt(unittest.TestCase): def test_default(self): a = A() self.assertEqual(a.integral, 0) self.assertIs(type(a.integral), int) def test_accepts_int(self): a = A() a.integral = 23 self.assertEqual(a.integral, 23) self.assertIs(type(a.integral), int) def test_accepts_large_integer(self): size_limit = sys.maxsize a = A() a.integral = size_limit self.assertEqual(a.integral, size_limit) self.assertIs(type(a.integral), int) a.integral = size_limit + 1 self.assertEqual(a.integral, size_limit + 1) self.assertIs(type(a.integral), int) a.integral = 2**2048 + 1 self.assertEqual(a.integral, 2**2048 + 1) self.assertIs(type(a.integral), int) def test_accepts_bool(self): a = A() a.integral = True self.assertEqual(a.integral, 1) self.assertIs(type(a.integral), int) def test_respects_dunder_index(self): a = A() a.integral = IntegerLike() self.assertEqual(a.integral, 42) self.assertIs(type(a.integral), int) def test_rejects_dunder_int(self): a = A() with self.assertRaises(TraitError): a.integral = Truncatable() def test_rejects_floating_point_types(self): a = A() with self.assertRaises(TraitError): a.integral = 23.0 with self.assertRaises(TraitError): a.integral = decimal.Decimal(23) def test_rejects_string(self): a = A() with self.assertRaises(TraitError): a.integral = "23" @requires_numpy def test_numpy_types(self): a = A() a.integral = numpy.int32(23) self.assertEqual(a.integral, 23) self.assertIs(type(a.integral), int) a.integral = numpy.uint64(2 ** 63 + 2) self.assertEqual(a.integral, 2 ** 63 + 2) self.assertIs(type(a.integral), int) with self.assertRaises(TraitError): a.integral = numpy.float32(4.0) with self.assertRaises(TraitError): a.integral = numpy.float64(4.0) def test_cint_conversion_of_subclasses(self): # Regression test for enthought/traits#646 a = A() a.convertible = True self.assertIs(type(a.convertible), int) self.assertEqual(a.convertible, 1) a.convertible_or_none = True self.assertIs(type(a.convertible_or_none), int) self.assertEqual(a.convertible_or_none, 1) traits-6.3.2/traits/tests/test_integer_range.py000066400000000000000000000222641414270267200217350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the Range trait with value type int. """ import unittest from traits.api import ( BaseRange, Either, HasTraits, Instance, Range, TraitError, ) from traits.testing.optional_dependencies import numpy, requires_numpy def ModelFactory(name, RangeFactory): """ Helper function to create various similar model classes. Parameters ---------- name : str Name to give the created class. RangeFactory : callable(*range_args, **range_kwargs) -> TraitType Callable with the same signature as Range; this will be used to create the model traits. Returns ------- HasTraits subclass Subclass containing various Range-like traits, for testing. """ class ModelWithRanges(HasTraits): """ Model containing various Range-like traits. """ # Simple integer range trait. percentage = RangeFactory(0, 100) # Traits that exercise the various possiblities for inclusion # or exclusion of the endpoints. open_closed = RangeFactory(0, 100, exclude_low=True) closed_open = RangeFactory(0, 100, exclude_high=True) open = RangeFactory(0, 100, exclude_low=True, exclude_high=True) closed = RangeFactory(0, 100) # Traits for one-sided intervals steam_temperature = RangeFactory(low=100) ice_temperature = RangeFactory(high=0) ModelWithRanges.__name__ = name return ModelWithRanges class Impossible(object): """ Type that never gets instantiated. """ def __init__(self): raise TypeError("Cannot instantiate this class") # A trait type that has a fast validator but doesn't accept any values. impossible = Instance(Impossible, allow_none=False) def RangeCompound(*args, **kwargs): """ Compound trait including a Range. """ return Either(impossible, Range(*args, **kwargs)) def BaseRangeCompound(*args, **kwargs): """ Compound trait including a BaseRange. """ return Either(impossible, BaseRange(*args, **kwargs)) ModelWithRange = ModelFactory("ModelWithRange", RangeFactory=Range) ModelWithBaseRange = ModelFactory("ModelWithBaseRange", RangeFactory=BaseRange) ModelWithRangeCompound = ModelFactory( "ModelWithRangeCompound", RangeFactory=RangeCompound ) ModelWithBaseRangeCompound = ModelFactory( "ModelWithBaseRangeCompound", RangeFactory=BaseRangeCompound, ) class InheritsFromInt(int): """ Object that's integer-like by virtue of inheriting from int. """ pass class IntLike(object): """ Object that's integer-like by virtue of providing an __index__ method. """ def __init__(self, value): self._value = value def __index__(self): return self._value class BadIntLike(object): """ Object whose __index__ method raises something other than TypeError. """ def __index__(self): raise ZeroDivisionError("bogus error") class CommonRangeTests(object): def test_accepts_int(self): self.model.percentage = 35 self.assertIs(type(self.model.percentage), int) self.assertEqual(self.model.percentage, 35) with self.assertRaises(TraitError): self.model.percentage = -1 with self.assertRaises(TraitError): self.model.percentage = 101 def test_accepts_bool(self): self.model.percentage = False self.assertIs(type(self.model.percentage), int) self.assertEqual(self.model.percentage, 0) self.model.percentage = True self.assertIs(type(self.model.percentage), int) self.assertEqual(self.model.percentage, 1) def test_rejects_bad_types(self): # A selection of things that don't count as integer-like. non_integers = [ "not a number", "\N{GREEK CAPITAL LETTER SIGMA}", b"not a number", "3.5", "3", 3 + 4j, 0j, [1.2], (1.2,), 0.0, -27.8, 35.0, None, ] for non_integer in non_integers: self.model.percentage = 73 with self.assertRaises(TraitError): self.model.percentage = non_integer self.assertEqual(self.model.percentage, 73) @requires_numpy def test_accepts_numpy_types(self): numpy_values = [ numpy.uint8(25), numpy.uint16(25), numpy.uint32(25), numpy.uint64(25), numpy.int8(25), numpy.int16(25), numpy.int32(25), numpy.int64(25), ] for numpy_value in numpy_values: self.model.percentage = numpy_value self.assertIs(type(self.model.percentage), int) self.assertEqual(self.model.percentage, 25) @requires_numpy def test_rejects_numpy_types(self): numpy_values = [ numpy.float16(25), numpy.float32(25), numpy.float64(25), ] for numpy_value in numpy_values: self.model.percentage = 88 with self.assertRaises(TraitError): self.model.percentage = numpy_value self.assertEqual(self.model.percentage, 88) def test_accepts_int_subclass(self): self.model.percentage = InheritsFromInt(44) self.assertIs(type(self.model.percentage), int) self.assertEqual(self.model.percentage, 44) with self.assertRaises(TraitError): self.model.percentage = InheritsFromInt(-1) with self.assertRaises(TraitError): self.model.percentage = InheritsFromInt(101) def test_accepts_int_like(self): self.model.percentage = IntLike(35) self.assertIs(type(self.model.percentage), int) self.assertEqual(self.model.percentage, 35) with self.assertRaises(TraitError): self.model.percentage = IntLike(-1) with self.assertRaises(TraitError): self.model.percentage = IntLike(101) def test_bad_int_like(self): # Check that the exception is propagated as expected. with self.assertRaises(ZeroDivisionError): self.model.percentage = BadIntLike() def test_endpoints(self): # point within the interior of the range self.model.open = self.model.closed = 50 self.model.open_closed = self.model.closed_open = 50 self.assertEqual(self.model.open, 50) self.assertEqual(self.model.closed, 50) self.assertEqual(self.model.open_closed, 50) self.assertEqual(self.model.closed_open, 50) # low endpoint self.model.closed = self.model.closed_open = 0 self.assertEqual(self.model.closed, 0) self.assertEqual(self.model.closed_open, 0) with self.assertRaises(TraitError): self.model.open = 0 with self.assertRaises(TraitError): self.model.open_closed = 0 # high endpoint self.model.closed = self.model.open_closed = 100 self.assertEqual(self.model.closed, 100) self.assertEqual(self.model.open_closed, 100) with self.assertRaises(TraitError): self.model.open = 100 with self.assertRaises(TraitError): self.model.closed_open = 100 def test_half_infinite(self): ice_temperatures = [-273, -100, -1] water_temperatures = [1, 50, 99] steam_temperatures = [101, 1000, 10 ** 100, 10 ** 1000] for temperature in steam_temperatures: self.model.steam_temperature = temperature self.assertEqual(self.model.steam_temperature, temperature) for temperature in ice_temperatures + water_temperatures: self.model.steam_temperature = 1729 with self.assertRaises(TraitError): self.model.steam_temperature = temperature self.assertEqual(self.model.steam_temperature, 1729) for temperature in ice_temperatures: self.model.ice_temperature = temperature self.assertEqual(self.model.ice_temperature, temperature) for temperature in water_temperatures + steam_temperatures: self.model.ice_temperature = -1729 with self.assertRaises(TraitError): self.model.ice_temperature = temperature self.assertEqual(self.model.ice_temperature, -1729) class TestIntRange(CommonRangeTests, unittest.TestCase): def setUp(self): self.model = ModelWithRange() class TestIntBaseRange(CommonRangeTests, unittest.TestCase): def setUp(self): self.model = ModelWithBaseRange() class TestIntRangeCompound(CommonRangeTests, unittest.TestCase): def setUp(self): self.model = ModelWithRangeCompound() class TestIntBaseRangeCompound(CommonRangeTests, unittest.TestCase): def setUp(self): self.model = ModelWithBaseRangeCompound() traits-6.3.2/traits/tests/test_interface_checker.py000066400000000000000000000264421414270267200225520ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests to help find out if we can do type-safe casting. """ # Standard library imports. import unittest import warnings # Enthought library imports. from traits.adaptation.api import reset_global_adaptation_manager from traits.api import ( Adapter, HasTraits, Instance, Int, Interface, provides, register_factory, ) # Local imports. from traits.interface_checker import InterfaceError, check_implements # Make sure implicit interface checking is turned off, so that we can make the # checks explicitly: from traits import has_traits class InterfaceCheckerTestCase(unittest.TestCase): """ Tests to help find out if we can do type-safe casting. """ ########################################################################### # 'TestCase' interface. ########################################################################### def setUp(self): """ Prepares the test fixture before each test method is called. """ # Make sure implicit interface checking is turned off, so that we can # make the checks explicitly: self._old_check_interfaces = has_traits.CHECK_INTERFACES has_traits.CHECK_INTERFACES = 0 reset_global_adaptation_manager() def tearDown(self): has_traits.CHECK_INTERFACES = self._old_check_interfaces ########################################################################### # Tests. ########################################################################### def test_non_traits_class(self): """ non-traits class """ class IFoo(Interface): def foo(self): pass # A class that *does* implement the interface. @provides(IFoo) class Foo(object): def foo(self): pass # The checker will raise an exception if the class does not implement # the interface. check_implements(Foo, IFoo, 2) def test_single_interface(self): """ single interface """ class IFoo(Interface): x = Int # A class that *does* implement the interface. @provides(IFoo) class Foo(HasTraits): x = Int # The checker will raise an exception if the class does not implement # the interface. check_implements(Foo, IFoo, 2) def test_single_interface_with_invalid_method_signature(self): """ single interface with invalid method signature """ class IFoo(Interface): def foo(self): pass # A class that does *not* implement the interface. @provides(IFoo) class Foo(HasTraits): # Extra argument! def foo(self, x): pass self.assertRaises(InterfaceError, check_implements, Foo, IFoo, 2) def test_single_interface_with_missing_trait(self): """ single interface with missing trait """ class IFoo(Interface): x = Int # A class that does *not* implement the interface. @provides(IFoo) class Foo(HasTraits): pass self.assertRaises(InterfaceError, check_implements, Foo, IFoo, 2) def test_single_interface_with_missing_method(self): """ single interface with missing method """ class IFoo(Interface): def method(self): pass # A class that does *not* implement the interface. @provides(IFoo) class Foo(HasTraits): pass self.assertRaises(InterfaceError, check_implements, Foo, IFoo, 2) def test_multiple_interfaces(self): """ multiple interfaces """ class IFoo(Interface): x = Int class IBar(Interface): y = Int class IBaz(Interface): z = Int # A class that *does* implement the interface. @provides(IFoo, IBar, IBaz) class Foo(HasTraits): x = Int y = Int z = Int # The checker will raise an exception if the class does not implement # the interface. check_implements(Foo, [IFoo, IBar, IBaz], 2) def test_multiple_interfaces_with_invalid_method_signature(self): """ multiple interfaces with invalid method signature """ class IFoo(Interface): def foo(self): pass class IBar(Interface): def bar(self): pass class IBaz(Interface): def baz(self): pass # A class that does *not* implement the interface. @provides(IFoo, IBar, IBaz) class Foo(HasTraits): def foo(self): pass def bar(self): pass # Extra argument! def baz(self, x): pass self.assertRaises( InterfaceError, check_implements, Foo, [IFoo, IBar, IBaz], 2 ) def test_multiple_interfaces_with_missing_trait(self): """ multiple interfaces with missing trait """ class IFoo(Interface): x = Int class IBar(Interface): y = Int class IBaz(Interface): z = Int # A class that does *not* implement the interface. @provides(IFoo, IBar, IBaz) class Foo(HasTraits): x = Int y = Int self.assertRaises( InterfaceError, check_implements, Foo, [IFoo, IBar, IBaz], 2 ) def test_multiple_interfaces_with_missing_method(self): """ multiple interfaces with missing method """ class IFoo(Interface): def foo(self): pass class IBar(Interface): def bar(self): pass class IBaz(Interface): def baz(self): pass # A class that does *not* implement the interface. @provides(IFoo, IBar, IBaz) class Foo(HasTraits): def foo(self): pass def bar(self): pass self.assertRaises( InterfaceError, check_implements, Foo, [IFoo, IBar, IBaz], 2 ) def test_inherited_interfaces(self): """ inherited interfaces """ class IFoo(Interface): x = Int class IBar(IFoo): y = Int class IBaz(IBar): z = Int # A class that *does* implement the interface. @provides(IBaz) class Foo(HasTraits): x = Int y = Int z = Int # The checker will raise an exception if the class does not implement # the interface. check_implements(Foo, IBaz, 2) def test_inherited_interfaces_with_invalid_method_signature(self): """ inherited with invalid method signature """ class IFoo(Interface): def foo(self): pass class IBar(IFoo): def bar(self): pass class IBaz(IBar): def baz(self): pass # A class that does *not* implement the interface. @provides(IBaz) class Foo(HasTraits): def foo(self): pass def bar(self): pass # Extra argument! def baz(self, x): pass self.assertRaises(InterfaceError, check_implements, Foo, IBaz, 2) def test_inherited_interfaces_with_missing_trait(self): """ inherited interfaces with missing trait """ class IFoo(Interface): x = Int class IBar(IFoo): y = Int class IBaz(IBar): z = Int # A class that does *not* implement the interface. @provides(IBaz) class Foo(HasTraits): x = Int y = Int self.assertRaises(InterfaceError, check_implements, Foo, IBaz, 2) def test_inherited_interfaces_with_missing_method(self): """ inherited interfaces with missing method """ class IFoo(Interface): def foo(self): pass class IBar(IFoo): def bar(self): pass class IBaz(IBar): def baz(self): pass # A class that does *not* implement the interface. @provides(IBaz) class Foo(HasTraits): def foo(self): pass def bar(self): pass self.assertRaises(InterfaceError, check_implements, Foo, IBaz, 2) def test_subclasses_with_wrong_signature_methods(self): """ Subclasses with incorrect method signatures """ class IFoo(Interface): def foo(self, argument): pass @provides(IFoo) class Foo(HasTraits): def foo(self, argument): pass class Bar(Foo): def foo(self): pass self.assertRaises(InterfaceError, check_implements, Bar, IFoo, 2) # Make sure interfaces and adaptation etc still work with the 'HasTraits' # version of 'Interface'! def test_instance(self): """ instance """ class IFoo(Interface): pass @provides(IFoo) class Foo(HasTraits): pass class Bar(HasTraits): foo = Instance(IFoo) Bar(foo=Foo()) def test_callable(self): """ callable """ class IFoo(Interface): pass @provides(IFoo) class Foo(HasTraits): pass f = Foo() # Adaptation via direct instantiation of interfaces is deprecated, so # catch the warning to keep the test run output clean. with warnings.catch_warnings(record=True) as warn_msgs: warnings.simplefilter("always", DeprecationWarning) self.assertEqual(f, IFoo(f)) self.assertEqual(len(warn_msgs), 1) warn_msg = warn_msgs[0] self.assertIn( 'use "adapt(adaptee, protocol)" instead', str(warn_msg.message)) self.assertIn("test_interface_checker", warn_msg.filename) def test_adaptation(self): """ adaptation """ class IFoo(Interface): pass class Foo(HasTraits): pass @provides(IFoo) class FooToIFooAdapter(Adapter): pass register_factory(FooToIFooAdapter, Foo, IFoo) f = Foo() # Make sure adaptation works. Adaptation via direct instantiation of # Interface classes is deprecated, so suppress the warning. with warnings.catch_warnings(record=True) as warn_msgs: warnings.simplefilter("always", DeprecationWarning) i_foo = IFoo(f) self.assertNotEqual(None, i_foo) self.assertEqual(FooToIFooAdapter, type(i_foo)) self.assertEqual(len(warn_msgs), 1) warn_msg = warn_msgs[0] self.assertIn( 'use "adapt(adaptee, protocol)" instead', str(warn_msg.message)) self.assertIn("test_interface_checker", warn_msg.filename) traits-6.3.2/traits/tests/test_interfaces.py000066400000000000000000000315601414270267200212460ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Unit test case for testing interfaces and adaptation. """ import contextlib import logging import unittest from traits import has_traits from traits.api import ( HasTraits, Adapter, AdaptsTo, Instance, Int, Interface, List, provides, register_factory, Supports, TraitError, ) from traits.adaptation.api import reset_global_adaptation_manager from traits.interface_checker import InterfaceError class IFoo(Interface): def get_foo(self): """ Returns the current foo. """ class IFooPlus(IFoo): def get_foo_plus(self): """ Returns even more foo. """ class IAverage(Interface): def get_average(self): """ Returns the average value for the object. """ class IList(Interface): def get_list(self): """ Returns the list value for the object. """ class Sample(HasTraits): s1 = Int(1, sample=True) s2 = Int(2, sample=True) s3 = Int(3, sample=True) i1 = Int(4) i2 = Int(5) i3 = Int(6) @provides(IList) class SampleList(HasTraits): """SampleList docstring.""" data = List(Int, [10, 20, 30]) def get_list(self): return self.data @provides(IList, IAverage) class SampleAverage(HasTraits): data = List(Int, [100, 200, 300]) def get_list(self): return self.data def get_average(self): value = self.get_list() if len(value) == 0: return 0.0 average = 0.0 for item in value: average += item return average / len(value) class UndeclaredAverageProvider(HasTraits): """ Class that conforms to the IAverage interface, but doesn't declare that it does so. """ def get_average(self): return 5.6 class SampleBad(HasTraits): pass class TraitsHolder(HasTraits): a_no = Instance(IAverage, adapt="no") a_yes = Instance(IAverage, adapt="yes") a_default = Instance(IAverage, adapt="default") list_adapted_to = Supports(IList) foo_adapted_to = Supports(IFoo) foo_plus_adapted_to = Supports(IFooPlus) list_adapts_to = AdaptsTo(IList) foo_adapts_to = AdaptsTo(IFoo) foo_plus_adapts_to = AdaptsTo(IFooPlus) class SampleListAdapter(Adapter): def get_list(self): obj = self.adaptee return [getattr(obj, name) for name in obj.trait_names(sample=True)] class ListAverageAdapter(Adapter): def get_average(self): value = self.adaptee.get_list() if len(value) == 0: return 0.0 average = 0.0 for item in value: average += item return average / len(value) class SampleFooAdapter(HasTraits): object = Instance(Sample) def __init__(self, object): self.object = object def get_foo(self): object = self.object return object.s1 + object.s2 + object.s3 class FooPlusAdapter(object): def __init__(self, obj): self.obj = obj def get_foo(self): return self.obj.get_foo() def get_foo_plus(self): return self.obj.get_foo() + 1 class InterfacesTest(unittest.TestCase): #### 'TestCase' protocol ################################################## def setUp(self): reset_global_adaptation_manager() # Register adapters. register_factory(SampleListAdapter, Sample, IList) register_factory(ListAverageAdapter, IList, IAverage) register_factory(SampleFooAdapter, Sample, IFoo) register_factory(FooPlusAdapter, IFoo, IFooPlus) #### Tests ################################################################ def test_provides_none(self): @provides() class Test(HasTraits): pass def test_provides_one(self): @provides(IFoo) class Test(HasTraits): def get_foo(self): return "foo_and_only_foo" def get_average(self): return 42 test = Test() self.assertIsInstance(test, IFoo) self.assertNotIsInstance(test, IAverage) def test_provides_multi(self): @provides(IFoo, IAverage, IList) class Test(HasTraits): def get_foo(self): return "test_foo" def get_average(self): return 42 def get_list(self): return [42] test = Test() self.assertIsInstance(test, IFoo) self.assertIsInstance(test, IAverage) self.assertIsInstance(test, IList) def test_provides_extended(self): """ Ensure that subclasses of Interfaces imply the superinterface. """ @provides(IFooPlus) class Test(HasTraits): def get_foo(self): return "some_test_foo" def get_foo_plus(self): return "more_test_foo" test = Test() self.assertIsInstance(test, IFoo) self.assertIsInstance(test, IFooPlus) ta = TraitsHolder() ta.foo_adapted_to = test self.assertIs(ta.foo_adapted_to, test) def test_provides_bad(self): with self.assertRaises(Exception): @provides(Sample) class Test(HasTraits): pass def test_provides_with_no_interface_check(self): class Test(HasTraits): # Deliberately _not_ implementing get_foo. This class # should not pass an IFoo interface check. pass provides_ifoo = provides(IFoo) with self.set_check_interfaces(0): # Simulate application of the decorator Test = provides_ifoo(Test) test = Test() self.assertIsInstance(test, IFoo) def test_provides_with_interface_check_warn(self): class Test(HasTraits): # Deliberately _not_ implementing get_foo. This class # should not pass an IFoo interface check. pass provides_ifoo = provides(IFoo) with self.set_check_interfaces(1): with self.assertWarns(DeprecationWarning) as warnings_cm: with self.assertLogs("traits", logging.WARNING): # Simulate application of the decorator Test = provides_ifoo(Test) test = Test() self.assertIsInstance(test, IFoo) self.assertIn( "the @provides decorator will not perform interface checks", str(warnings_cm.warning), ) # Check we used the appropriate stacklevel. _, _, this_module = __name__.rpartition(".") self.assertIn(this_module, warnings_cm.filename) def test_provides_with_interface_check_error(self): class Test(HasTraits): # Deliberately _not_ implementing get_foo. This class # should not pass an IFoo interface check. pass provides_ifoo = provides(IFoo) with self.set_check_interfaces(2): with self.assertWarns(DeprecationWarning) as warnings_cm: with self.assertRaises(InterfaceError): # Simulate application of the decorator Test = provides_ifoo(Test) test = Test() self.assertIsInstance(test, IFoo) self.assertIn( "the @provides decorator will not perform interface checks", str(warnings_cm.warning), ) # Check we used the appropriate stacklevel. _, _, this_module = __name__.rpartition(".") self.assertIn(this_module, warnings_cm.filename) def test_instance_adapt_no(self): ta = TraitsHolder() # Verify that SampleAverage() does not raise an error (it is an # instance of the IAverage interface). try: ta.a_no = SampleAverage() except TraitError: self.fail( "Setting instance of interface should not require " "adaptation" ) # These are not instances of the IAverage interface, and therefore # cannot be set to the trait. self.assertRaises(TraitError, ta.trait_set, a_no=SampleList()) self.assertRaises(TraitError, ta.trait_set, a_no=Sample()) self.assertRaises(TraitError, ta.trait_set, a_no=SampleBad()) def test_instance_adapt_yes(self): ta = TraitsHolder() ta.a_yes = SampleAverage() self.assertEqual(ta.a_yes.get_average(), 200.0) self.assertIsInstance(ta.a_yes, SampleAverage) self.assertFalse(hasattr(ta, "a_yes_")) ta.a_yes = SampleList() self.assertEqual(ta.a_yes.get_average(), 20.0) self.assertIsInstance(ta.a_yes, ListAverageAdapter) self.assertFalse(hasattr(ta, "a_yes_")) ta.a_yes = Sample() self.assertEqual(ta.a_yes.get_average(), 2.0) self.assertIsInstance(ta.a_yes, ListAverageAdapter) self.assertFalse(hasattr(ta, "a_yes_")) self.assertRaises(TraitError, ta.trait_set, a_yes=SampleBad()) def test_instance_adapt_default(self): ta = TraitsHolder() ta.a_default = SampleAverage() self.assertEqual(ta.a_default.get_average(), 200.0) self.assertIsInstance(ta.a_default, SampleAverage) self.assertFalse(hasattr(ta, "a_default_")) ta.a_default = SampleList() self.assertEqual(ta.a_default.get_average(), 20.0) self.assertIsInstance(ta.a_default, ListAverageAdapter) self.assertFalse(hasattr(ta, "a_default_")) ta.a_default = Sample() self.assertEqual(ta.a_default.get_average(), 2.0) self.assertIsInstance(ta.a_default, ListAverageAdapter) self.assertFalse(hasattr(ta, "a_default_")) ta.a_default = SampleBad() self.assertEqual(ta.a_default, None) self.assertFalse(hasattr(ta, "a_default_")) def test_adapted_to(self): ta = TraitsHolder() ta.list_adapted_to = object = Sample() result = ta.list_adapted_to.get_list() self.assertEqual(len(result), 3) for n in [1, 2, 3]: self.assertIn(n, result) self.assertIsInstance(ta.list_adapted_to, SampleListAdapter) self.assertEqual(ta.list_adapted_to_, object) ta.foo_adapted_to = object = Sample() self.assertEqual(ta.foo_adapted_to.get_foo(), 6) self.assertIsInstance(ta.foo_adapted_to, SampleFooAdapter) self.assertEqual(ta.foo_adapted_to_, object) ta.foo_plus_adapted_to = object = Sample(s1=5, s2=10, s3=15) self.assertEqual(ta.foo_plus_adapted_to.get_foo(), 30) self.assertEqual(ta.foo_plus_adapted_to.get_foo_plus(), 31) self.assertIsInstance(ta.foo_plus_adapted_to, FooPlusAdapter) self.assertEqual(ta.foo_plus_adapted_to_, object) def test_adapts_to(self): ta = TraitsHolder() ta.list_adapts_to = object = Sample() self.assertEqual(ta.list_adapts_to, object) result = ta.list_adapts_to_.get_list() self.assertEqual(len(result), 3) for n in [1, 2, 3]: self.assertIn(n, result) self.assertIsInstance(ta.list_adapts_to_, SampleListAdapter) ta.foo_adapts_to = object = Sample() self.assertEqual(ta.foo_adapts_to, object) self.assertEqual(ta.foo_adapts_to_.get_foo(), 6) self.assertIsInstance(ta.foo_adapts_to_, SampleFooAdapter) ta.foo_plus_adapts_to = object = Sample(s1=5, s2=10, s3=15) self.assertEqual(ta.foo_plus_adapts_to, object) self.assertEqual(ta.foo_plus_adapts_to_.get_foo(), 30) self.assertEqual(ta.foo_plus_adapts_to_.get_foo_plus(), 31) self.assertIsInstance(ta.foo_plus_adapts_to_, FooPlusAdapter) def test_decorated_class_name_and_docstring(self): self.assertEqual(SampleList.__name__, "SampleList") self.assertEqual(SampleList.__doc__, "SampleList docstring.") def test_instance_requires_provides(self): ta = TraitsHolder() provider = UndeclaredAverageProvider() with self.assertRaises(TraitError): ta.a_no = provider @contextlib.contextmanager def set_check_interfaces(self, check_interfaces_value): """ Context manager to temporarily set has_traits.CHECK_INTERFACES to the given value. Parameters ---------- check_interfaces_value : int One of 0 (don't check), 1 (check and log a warning on interface mismatch) or 2 (check and raise on interface mismatch). Returns ------- context manager """ old_check_interfaces = has_traits.CHECK_INTERFACES has_traits.CHECK_INTERFACES = check_interfaces_value try: yield finally: has_traits.CHECK_INTERFACES = old_check_interfaces traits-6.3.2/traits/tests/test_keyword_args.py000066400000000000000000000014601414270267200216170ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import HasTraits, Instance, Int class Bar(HasTraits): b = Int(3) class Foo(HasTraits): bar = Instance(Bar) class KeyWordArgsTest(unittest.TestCase): def test_using_kw(self): bar = Bar(b=5) foo = Foo(bar=bar) self.assertEqual(foo.bar.b, 5) def test_not_using_kw(self): foo = Foo() self.assertEqual(foo.bar, None) traits-6.3.2/traits/tests/test_list.py000066400000000000000000000250671414270267200201030ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import CList, HasTraits, Instance, Int, List, Str, TraitError class Foo(HasTraits): l = List(Str) class Bar(HasTraits): name = Str class Baz(HasTraits): bars = List(Bar) class BazRef(HasTraits): bars = List(Bar, copy="ref") class DeepBaz(HasTraits): baz = Instance(Baz) class DeepBazBazRef(HasTraits): baz = Instance(BazRef) class CFoo(HasTraits): ints = CList(Int) strs = CList(Str) class ListTestCase(unittest.TestCase): def test_initialized(self): f = Foo() self.assertNotEqual(f.l, None) self.assertEqual(len(f.l), 0) def test_initializer(self): f = Foo(l=["a", "list"]) self.assertNotEqual(f.l, None) self.assertEqual(f.l, ["a", "list"]) def test_type_check(self): f = Foo() f.l.append("string") self.assertRaises(TraitError, f.l.append, 123.456) def test_append(self): f = Foo() f.l.append("bar") self.assertEqual(f.l, ["bar"]) def test_remove(self): f = Foo() f.l.append("bar") f.l.remove("bar") self.assertEqual(f.l, []) def test_slice(self): f = Foo(l=["zero", "one", "two", "three"]) self.assertEqual(f.l[0], "zero") self.assertEqual(f.l[:0], []) self.assertEqual(f.l[:1], ["zero"]) self.assertEqual(f.l[0:1], ["zero"]) self.assertEqual(f.l[1:], ["one", "two", "three"]) self.assertEqual(f.l[-1], "three") self.assertEqual(f.l[-2], "two") self.assertEqual(f.l[:-1], ["zero", "one", "two"]) def test_slice_assignment(self): # Exhaustive testing. starts = stops = [None] + list(range(-10, 11)) steps = list(starts) steps.remove(0) test_slices = [ slice(start, stop, step) for start in starts for stop in stops for step in steps ] for test_slice in test_slices: f = Foo(l=["zero", "one", "two", "three", "four"]) plain_l = list(f.l) length = len(plain_l[test_slice]) replacements = list(map(str, range(length))) # Plain Python list and Traits list behaviour should match. plain_l[test_slice] = replacements f.l[test_slice] = replacements self.assertEqual( f.l, plain_l, "failed for slice {0!r}".format(test_slice) ) def test_slice_assignments_of_different_length(self): # Test slice assignments where rhs has a different length # to the slice. These should work only for slices of step 1. test_list = ["zero", "one", "two", "three"] f = Foo(l=test_list) f.l[1:3] = "01234" self.assertEqual(f.l, ["zero", "0", "1", "2", "3", "4", "three"]) f.l[4:] = [] self.assertEqual(f.l, ["zero", "0", "1", "2"]) f.l[:] = "abcde" self.assertEqual(f.l, ["a", "b", "c", "d", "e"]) f.l[:] = [] self.assertEqual(f.l, []) f = Foo(l=test_list) with self.assertRaises(ValueError): f.l[::2] = ["a", "b", "c"] self.assertEqual(f.l, test_list) with self.assertRaises(ValueError): f.l[::-1] = [] self.assertEqual(f.l, test_list) def test_slice_deletion_bad_length_computation(self): # Regression test for enthought/traits#283. class IHasConstrainedList(HasTraits): foo = List(Str, minlen=3) f = IHasConstrainedList(foo=["zero", "one", "two", "three"]) # We're deleting two items; this should raise. with self.assertRaises(TraitError): del f.foo[::3] def test_retrieve_reference(self): f = Foo(l=["initial", "value"]) l = f.l self.assertIs(l, f.l) # no copy on change behavior, l is always a reference l.append("change") self.assertEqual(f.l, ["initial", "value", "change"]) f.l.append("more change") self.assertEqual(l, ["initial", "value", "change", "more change"]) def test_assignment_makes_copy(self): f = Foo(l=["initial", "value"]) l = ["new"] f.l = l # same content self.assertEqual(l, f.l) # different objects self.assertIsNot(l, f.l) # which means behaviorally... l.append("l change") self.assertNotIn("l change", f.l) f.l.append("f.l change") self.assertNotIn("f.l change", l) def test_should_not_allow_none(self): f = Foo(l=["initial", "value"]) try: f.l = None self.fail("None assigned to List trait.") except TraitError: pass def test_clone(self): baz = Baz() for name in ["a", "b", "c", "d"]: baz.bars.append(Bar(name=name)) # Clone will clone baz, the bars list, and the objects in the list baz_copy = baz.clone_traits() self.assertIsNot(baz_copy, baz) self.assertIsNot(baz_copy.bars, baz.bars) self.assertEqual(len(baz_copy.bars), len(baz.bars)) for bar in baz.bars: self.assertNotIn(bar, baz_copy.bars) baz_bar_names = [bar.name for bar in baz.bars] baz_copy_bar_names = [bar.name for bar in baz_copy.bars] baz_bar_names.sort() baz_copy_bar_names.sort() self.assertEqual(baz_copy_bar_names, baz_bar_names) def test_clone_ref(self): baz = BazRef() for name in ["a", "b", "c", "d"]: baz.bars.append(Bar(name=name)) # Clone will clone baz, the bars list, but the objects in the list # will not be cloned because the copy metatrait of the List is 'ref' baz_copy = baz.clone_traits() self.assertIsNot(baz_copy, baz) self.assertIsNot(baz_copy.bars, baz.bars) self.assertEqual(len(baz_copy.bars), len(baz.bars)) for bar in baz.bars: self.assertIn(bar, baz_copy.bars) def test_clone_deep_baz(self): baz = Baz() for name in ["a", "b", "c", "d"]: baz.bars.append(Bar(name=name)) deep_baz = DeepBaz(baz=baz) # Clone will clone deep_baz, deep_baz.baz, the bars list, # and the objects in the list deep_baz_copy = deep_baz.clone_traits() self.assertIsNot(deep_baz_copy, deep_baz) self.assertIsNot(deep_baz_copy.baz, deep_baz.baz) baz_copy = deep_baz_copy.baz self.assertIsNot(baz_copy, baz) self.assertIsNot(baz_copy.bars, baz.bars) self.assertEqual(len(baz_copy.bars), len(baz.bars)) for bar in baz.bars: self.assertNotIn(bar, baz_copy.bars) baz_bar_names = [bar.name for bar in baz.bars] baz_copy_bar_names = [bar.name for bar in baz_copy.bars] baz_bar_names.sort() baz_copy_bar_names.sort() self.assertEqual(baz_copy_bar_names, baz_bar_names) def test_clone_deep_baz_ref(self): baz = BazRef() for name in ["a", "b", "c", "d"]: baz.bars.append(Bar(name=name)) deep_baz = DeepBazBazRef(baz=baz) deep_baz_copy = deep_baz.clone_traits() self.assertIsNot(deep_baz_copy, deep_baz) self.assertIsNot(deep_baz_copy.baz, deep_baz.baz) baz_copy = deep_baz_copy.baz self.assertIsNot(baz_copy, baz) self.assertIsNot(baz_copy.bars, baz.bars) self.assertEqual(len(baz_copy.bars), len(baz.bars)) for bar in baz.bars: self.assertIn(bar, baz_copy.bars) def test_coercion(self): f = CFoo() # Test coercion from basic built-in types f.ints = [1, 2, 3] desired = [1, 2, 3] self.assertEqual(f.ints, desired) f.ints = (1, 2, 3) self.assertEqual(f.ints, desired) f.strs = ("abc", "def", "ghi") self.assertEqual(f.strs, ["abc", "def", "ghi"]) f.strs = "abcdef" self.assertEqual(f.strs, list("abcdef")) try: from numpy import array except ImportError: pass else: f.ints = array([1, 2, 3]) self.assertEqual(f.ints, [1, 2, 3]) f.strs = array(("abc", "def", "ghi")) self.assertEqual(f.strs, ["abc", "def", "ghi"]) def test_extend(self): f = Foo() f.l = ["4", "5", "6"] f.l.extend(["1", "2", "3"]) self.assertEqual(f.l, ["4", "5", "6", "1", "2", "3"]) def test_iadd(self): f = Foo() f.l = ["4", "5", "6"] f.l += ["1", "2", "3"] self.assertEqual(f.l, ["4", "5", "6", "1", "2", "3"]) def test_imul(self): f = Foo() f.l = list("123") f.l *= 4 self.assertEqual(f.l, list("123123123123")) def test_sort_no_args(self): f = Foo() f.l = ["a", "c", "b", "d"] f.l.sort() self.assertEqual(f.l, ["a", "b", "c", "d"]) def test_sort_key(self): f = Foo() f.l = ["a", "c", "b", "d"] f.l.sort(key=lambda x: -ord(x)) self.assertEqual(f.l, ["d", "c", "b", "a"]) def test_sort_reverse(self): f = Foo() f.l = ["a", "c", "b", "d"] f.l.sort(reverse=True) self.assertEqual(f.l, ["d", "c", "b", "a"]) def test_sort_key_reverse(self): f = Foo() f.l = ["a", "c", "b", "d"] f.l.sort(key=lambda x: -ord(x), reverse=True) self.assertEqual(f.l, ["a", "b", "c", "d"]) def test_sort_cmp_error(self): f = Foo() f.l = ["a", "c", "b", "d"] with self.assertRaises(TypeError): f.l.sort(cmp=lambda x, y: ord(x) - ord(y)) def test_copy(self): f = Foo() f.l = ["a", "c", "b", "d"] l_copy = f.l.copy() self.assertEqual(f.l, l_copy) def test_copy_returns_list(self): f = Foo() f.l = ["a", "c", "b", "d"] l_copy = f.l.copy() self.assertEqual(type(l_copy), list) def test_clear(self): f = Foo() f.l = ["a", "c", "b", "d"] f.l.clear() self.assertEqual(len(f.l), 0) def test_clear_with_min_length(self): class FooMinLen(HasTraits): l = List(Str, minlen=1) f = FooMinLen() f.l = ["a", "c", "b", "d"] with self.assertRaises(TraitError): f.l.clear() traits-6.3.2/traits/tests/test_list_events.py000066400000000000000000000200721414270267200214560ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for List items_changed events. """ import unittest from traits.api import HasTraits, Int, List class MyClass(HasTraits): l = List(Int, [1, 2, 3]) l_events = List def _l_items_changed(self, event): self.l_events.append(event) class ListEventTestCase(unittest.TestCase): def test_initialization(self): # Just creating an instance of MyClass shouldn't cause # the items_changed handler to fire. foo = MyClass() self.assertEqual(foo.l, [1, 2, 3]) self.assertEqual(len(foo.l_events), 0) def test_append(self): foo = MyClass() foo.l.append(4) self.assertEqual(foo.l, [1, 2, 3, 4]) self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.added, [4]) self.assertEqual(event.removed, []) self.assertEqual(event.index, 3) def test_extend(self): foo = MyClass() foo.l.extend([4, 5, 6]) self.assertEqual(foo.l, [1, 2, 3, 4, 5, 6]) self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.added, [4, 5, 6]) self.assertEqual(event.removed, []) self.assertEqual(event.index, 3) def test_extend_via_inplace_addition(self): foo = MyClass() foo.l += [4, 5, 6] self.assertEqual(foo.l, [1, 2, 3, 4, 5, 6]) self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.added, [4, 5, 6]) self.assertEqual(event.removed, []) self.assertEqual(event.index, 3) def test_insert(self): foo = MyClass() foo.l.insert(1, 99) self.assertEqual(foo.l, [1, 99, 2, 3]) self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.added, [99]) self.assertEqual(event.removed, []) self.assertEqual(event.index, 1) def test_insert_with_negative_argument(self): foo = MyClass() foo.l.insert(-1, 99) self.assertEqual(foo.l, [1, 2, 99, 3]) self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.added, [99]) self.assertEqual(event.removed, []) self.assertEqual(event.index, 2) def test_insert_index_invariants(self): # Note that Python's list.insert allows indices outside # the range [-len(my_list), len(my_list)]. for index in range(-10, 10): foo = MyClass() foo.l.insert(index, 1729) self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.added, [1729]) self.assertEqual(event.removed, []) self.assertGreaterEqual(event.index, 0) self.assertEqual(foo.l[event.index], 1729) def test_pop_with_no_argument(self): foo = MyClass() item = foo.l.pop() self.assertEqual(item, 3) self.assertEqual(foo.l, [1, 2]) self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.added, []) self.assertEqual(event.removed, [3]) self.assertEqual(event.index, 2) def test_pop(self): foo = MyClass() item = foo.l.pop(0) self.assertEqual(item, 1) self.assertEqual(foo.l, [2, 3]) self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.added, []) self.assertEqual(event.removed, [1]) self.assertEqual(event.index, 0) def test_pop_with_negative_argument(self): foo = MyClass() item = foo.l.pop(-2) self.assertEqual(item, 2) self.assertEqual(foo.l, [1, 3]) self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.added, []) self.assertEqual(event.removed, [2]) self.assertEqual(event.index, 1) def test_pop_out_of_range(self): foo = MyClass() with self.assertRaises(IndexError): foo.l.pop(-4) with self.assertRaises(IndexError): foo.l.pop(3) self.assertEqual(foo.l, [1, 2, 3]) self.assertEqual(len(foo.l_events), 0) def test_remove(self): foo = MyClass() foo.l.remove(2) self.assertEqual(foo.l, [1, 3]) self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.added, []) self.assertEqual(event.removed, [2]) self.assertEqual(event.index, 1) def test_remove_item_not_present(self): foo = MyClass() with self.assertRaises(ValueError): foo.l.remove(1729) self.assertEqual(foo.l, [1, 2, 3]) self.assertEqual(len(foo.l_events), 0) def test_inplace_multiply(self): foo = MyClass() foo.l *= 2 self.assertEqual(foo.l, [1, 2, 3, 1, 2, 3]) self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.added, [1, 2, 3]) self.assertEqual(event.removed, []) self.assertEqual(event.index, 3) def test_inplace_multiply_by_zero(self): foo = MyClass() foo.l *= 0 self.assertEqual(foo.l, []) self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.added, []) self.assertEqual(event.removed, [1, 2, 3]) self.assertEqual(event.index, 0) def test_remove_empty_slices(self): # Test that no events are produced when no items are deleted foo = MyClass() # Delete no items and get no events del foo.l[3:] self.assertEqual(foo.l, [1, 2, 3]) self.assertEqual(len(foo.l_events), 0) # Delete all items and get an expected event del foo.l[:] self.assertEqual(foo.l, []) self.assertEqual(len(foo.l_events), 1) event, = foo.l_events self.assertEqual(event.added, []) self.assertEqual(event.removed, [1, 2, 3]) self.assertEqual(event.index, 0) # Delete no items and get no new events del foo.l[:] self.assertEqual(foo.l, []) self.assertEqual(len(foo.l_events), 1) def test_remove_empty_slices_steps(self): foo = MyClass() # Delete no items and get no events del foo.l[3::2] self.assertEqual(foo.l, [1, 2, 3]) self.assertEqual(len(foo.l_events), 0) def test_clear(self): foo = MyClass() foo.l.clear() self.assertEqual(len(foo.l_events), 1) event = foo.l_events[0] self.assertEqual(event.index, 0) self.assertEqual(event.removed, [1, 2, 3]) self.assertEqual(event.added, []) def test_clear_empty_list(self): foo = MyClass() foo.l = [] foo.l.clear() self.assertEqual(len(foo.l_events), 0) def test_delete_step_slice(self): foo = MyClass() foo.l = [0, 1, 2, 3, 4] del foo.l[0:5:2] self.assertEqual(len(foo.l_events), 1) event, = foo.l_events self.assertEqual(event.index, slice(0, 5, 2)) self.assertEqual(event.removed, [0, 2, 4]) self.assertEqual(event.added, []) def test_delete_step_slice_empty_list(self): foo = MyClass() foo.l = [] del foo.l[::-1] # No items deleted, so no event fired self.assertEqual(len(foo.l_events), 0) def test_assignment_step_slice(self): foo = MyClass() foo.l = [1, 2, 3] foo.l[::2] = [3, 4] self.assertEqual(len(foo.l_events), 1) event, = foo.l_events self.assertEqual(event.index, slice(0, 3, 2)) self.assertEqual(event.added, [3, 4]) self.assertEqual(event.removed, [1, 3]) traits-6.3.2/traits/tests/test_listeners.py000066400000000000000000000171711414270267200211350ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test the 'add_trait_listener', 'remove_trait_listener' interface to the HasTraits class. """ import contextlib import io import logging import sys import threading import time import unittest from traits.api import HasTraits, Str, Int, Float, Any, Event from traits.api import push_exception_handler, pop_exception_handler @contextlib.contextmanager def captured_stderr(): """ Return a context manager that directs all stderr output to a string. """ new_stderr = io.StringIO() original_stderr = sys.stderr sys.stderr = new_stderr try: yield new_stderr finally: sys.stderr = original_stderr class GenerateEvents(HasTraits): name = Str age = Int weight = Float events = {} # dict of events class ListenEvents(HasTraits): # 'GenerateEvents' event interface: # the events are stored in the dict 'events' def _name_changed(self, object, name, old, new): events["_name_changed"] = (name, old, new) def _age_changed(self, object, name, old, new): events["_age_changed"] = (name, old, new) def _weight_changed(self, object, name, old, new): events["_weight_changed"] = (name, old, new) def alt_name_changed(self, object, name, old, new): events["alt_name_changed"] = (name, old, new) def alt_weight_changed(self, object, name, old, new): events["alt_weight_changed"] = (name, old, new) class GenerateFailingEvents(HasTraits): name = Str def _name_changed(self): raise RuntimeError class TestListeners(unittest.TestCase): def test_listeners(self): global events # FIXME: comparing floats ge = GenerateEvents() le = ListenEvents() # Starting test: No Listeners ge.trait_set(name="Joe", age=22, weight=152.0) # Adding default listener ge.add_trait_listener(le) events = {} ge.trait_set(name="Mike", age=34, weight=178.0) self.assertEqual( events, { "_age_changed": ("age", 22, 34), "_weight_changed": ("weight", 152.0, 178.0), "_name_changed": ("name", "Joe", "Mike"), }, ) # Adding alternate listener ge.add_trait_listener(le, "alt") events = {} ge.trait_set(name="Gertrude", age=39, weight=108.0) self.assertEqual( events, { "_age_changed": ("age", 34, 39), "_name_changed": ("name", "Mike", "Gertrude"), "_weight_changed": ("weight", 178.0, 108.0), "alt_name_changed": ("name", "Mike", "Gertrude"), "alt_weight_changed": ("weight", 178.0, 108.0), }, ) # Removing default listener ge.remove_trait_listener(le) events = {} ge.trait_set(name="Sally", age=46, weight=118.0) self.assertEqual( events, { "alt_name_changed": ("name", "Gertrude", "Sally"), "alt_weight_changed": ("weight", 108.0, 118.0), }, ) # Removing alternate listener ge.remove_trait_listener(le, "alt") events = {} ge.trait_set(name="Ralph", age=29, weight=198.0) self.assertEqual(events, {}) def test_trait_exception_handler_can_access_exception(self): """ Tests if trait exception handlers can access the traceback of the exception. """ from traits import trait_notifiers def _handle_exception(obj, name, old, new): self.assertIsNotNone(sys.exc_info()[0]) ge = GenerateFailingEvents() try: trait_notifiers.push_exception_handler( _handle_exception, reraise_exceptions=False, main=True ) ge.trait_set(name="John Cleese") finally: trait_notifiers.pop_exception_handler() def test_exceptions_logged(self): # Check that default exception handling logs the exception. ge = GenerateFailingEvents() traits_logger = logging.getLogger("traits") with self.assertLogs( logger=traits_logger, level=logging.ERROR) as log_watcher: ge.name = "Terry Jones" self.assertEqual(len(log_watcher.records), 1) log_record = log_watcher.records[0] self.assertIn( "Exception occurred in traits notification handler", log_record.message, ) _, exc_value, exc_traceback = log_record.exc_info self.assertIsInstance(exc_value, RuntimeError) self.assertIsNotNone(exc_traceback) class A(HasTraits): exception = Any foo = Event def foo_changed_handler(self): pass def foo_writer(a, stop_event): while not stop_event.is_set(): try: a.foo = True except Exception as e: a.exception = e class TestRaceCondition(unittest.TestCase): def setUp(self): push_exception_handler( handler=lambda *args: None, reraise_exceptions=True, main=True ) def tearDown(self): pop_exception_handler() def test_listener_thread_safety(self): # Regression test for GitHub issue #56 a = A() stop_event = threading.Event() t = threading.Thread(target=foo_writer, args=(a, stop_event)) t.start() for _ in range(100): a.on_trait_change(a.foo_changed_handler, "foo") time.sleep(0.0001) # encourage thread-switch a.on_trait_change(a.foo_changed_handler, "foo", remove=True) stop_event.set() t.join() self.assertTrue(a.exception is None) def test_listener_deleted_race(self): # Regression test for exception that occurred when the listener_deleted # method is called after the dispose method on a # TraitsChangeNotifyWrapper. class SlowListener(HasTraits): def handle_age_change(self): time.sleep(1.0) def worker_thread(event_source, start_event): # Wait until the listener is set up on the main thread, then fire # the event. start_event.wait() event_source.age = 11 def main_thread(event_source, start_event): listener = SlowListener() event_source.on_trait_change(listener.handle_age_change, "age") start_event.set() # Allow time to make sure that we're in the middle of handling an # event. time.sleep(0.5) event_source.on_trait_change( listener.handle_age_change, "age", remove=True ) # Previously, a ValueError would be raised on the worker thread # during (normal refcount-based) garbage collection. That # ValueError is ignored by the Python system, so the only # visible effect is the output to stderr. with captured_stderr() as s: start_event = threading.Event() event_source = GenerateEvents(age=10) t = threading.Thread( target=worker_thread, args=(event_source, start_event) ) t.start() main_thread(event_source, start_event) t.join() self.assertNotIn("Exception", s.getvalue()) traits-6.3.2/traits/tests/test_long_traits.py000066400000000000000000000013751414270267200214510ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import ( BaseCInt, BaseCLong, BaseInt, BaseLong, CInt, CLong, Int, Long, ) class TestLong(unittest.TestCase): def test_aliases(self): self.assertIs(BaseLong, BaseInt) self.assertIs(Long, Int) self.assertIs(BaseCLong, BaseCInt) self.assertIs(CLong, CInt) traits-6.3.2/traits/tests/test_map.py000066400000000000000000000211401414270267200176710ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the Map handler. """ import pickle import unittest from traits.api import HasTraits, Int, List, Map, on_trait_change, TraitError class Preferences(HasTraits): """ Example class with a Map that records changes to that map. """ # Changes to primary trait of the mapped trait pair primary_changes = List() # Changes to the shadow trait of the mapped trait pair shadow_changes = List() color = Map({"red": 4, "green": 2, "yellow": 6}, default_value="yellow") @on_trait_change("color") def _record_primary_trait_change(self, obj, name, old, new): change = obj, name, old, new self.primary_changes.append(change) @on_trait_change("color_") def _record_shadow_trait_change(self, obj, name, old, new): change = obj, name, old, new self.shadow_changes.append(change) class TestMap(unittest.TestCase): def test_assignment(self): class Person(HasTraits): married = Map({"yes": 1, "yeah": 1, "no": 0, "nah": 0}) person = Person() person.married = "yes" self.assertEqual("yes", person.married) self.assertEqual(1, person.married_) person.married = "no" self.assertEqual("no", person.married) self.assertEqual(0, person.married_) with self.assertRaises(TraitError): person.married = "dont know" with self.assertRaises(TraitError): person.married = [] def test_no_default(self): mapping = {"yes": 1, "yeah": 1, "no": 0, "nah": 0} class Person(HasTraits): married = Map(mapping) p = Person() # Since we're using Python >= 3.6, we can rely on dictionaries # being ordered, and then the default is predictable. self.assertEqual(p.married, "yes") self.assertEqual(p.married_, 1) def test_no_default_reverse_access_order(self): mapping = {"yes": 1, "yeah": 1, "no": 0, "nah": 0} class Person(HasTraits): married = Map(mapping) p = Person() shadow_value = p.married_ primary_value = p.married # For Python >= 3.6, dictionary ordering and hence the default # value are predictable. self.assertEqual(primary_value, "yes") self.assertEqual(shadow_value, 1) def test_default(self): class Person(HasTraits): married = Map({"yes": 1, "yeah": 1, "no": 0, "nah": 0, None: 2}, default_value=None) p = Person() self.assertIsNone(p.married) self.assertEqual(p.married_, 2) def test_default_reverse_access_order(self): class Person(HasTraits): married = Map({"yes": 1, "yeah": 1, "no": 0, "nah": 0, None: 2}, default_value=None) p = Person() self.assertEqual(p.married_, 2) self.assertIsNone(p.married) def test_default_method(self): class Person(HasTraits): married = Map({"yes": 1, "yeah": 1, "no": 0, "nah": 0, None: 2}) default_calls = Int(0) def _married_default(self): self.default_calls += 1 return None p = Person() self.assertIsNone(p.married) self.assertEqual(p.married_, 2) self.assertEqual(p.default_calls, 1) # Check that the order doesn't matter p2 = Person() self.assertEqual(p2.married_, 2) self.assertIsNone(p2.married) self.assertEqual(p2.default_calls, 1) def test_default_static_override_static(self): class BasePerson(HasTraits): married = Map({"yes": 1, "yeah": 1, "no": 0, "nah": 0, None: 2}, default_value=None) class Person(BasePerson): married = "yes" p = Person() self.assertEqual(p.married, "yes") self.assertEqual(p.married_, 1) def test_default_static_override_method(self): class BasePerson(HasTraits): married = Map({"yes": 1, "yeah": 1, "no": 0, "nah": 0, None: 2}, default_value=None) class Person(BasePerson): default_calls = Int(0) def _married_default(self): self.default_calls += 1 return "yes" p = Person() self.assertEqual(p.married, "yes") self.assertEqual(p.married_, 1) self.assertEqual(p.default_calls, 1) def test_default_method_override_static(self): class BasePerson(HasTraits): married = Map({"yes": 1, "yeah": 1, "no": 0, "nah": 0, None: 2}) default_calls = Int(0) def _married_default(self): self.default_calls += 1 return None class Person(BasePerson): married = "yes" p = Person() self.assertEqual(p.married, "yes") self.assertEqual(p.married_, 1) self.assertEqual(p.default_calls, 0) def test_default_method_override_method(self): class BasePerson(HasTraits): married = Map({"yes": 1, "yeah": 1, "no": 0, "nah": 0, None: 2}) default_calls = Int(0) def _married_default(self): self.default_calls += 1 return None class Person(BasePerson): def _married_default(self): self.default_calls += 1 return "yes" p = Person() self.assertEqual(p.married, "yes") self.assertEqual(p.married_, 1) self.assertEqual(p.default_calls, 1) def test_empty_map(self): with self.assertRaises(ValueError): Map({}) def test_notification(self): preferences = Preferences() self.assertEqual(len(preferences.primary_changes), 0) self.assertEqual(len(preferences.shadow_changes), 0) preferences.color = "red" self.assertEqual(len(preferences.primary_changes), 1) self.assertEqual(len(preferences.shadow_changes), 1) preferences.color = "green" self.assertEqual(len(preferences.primary_changes), 2) self.assertEqual(len(preferences.shadow_changes), 2) with self.assertRaises(TraitError): preferences.color = "blue" self.assertEqual(len(preferences.primary_changes), 2) self.assertEqual(len(preferences.shadow_changes), 2) def test_notification_init_value(self): preferences = Preferences(color="green") self.assertEqual(len(preferences.primary_changes), 1) self.assertEqual(len(preferences.shadow_changes), 1) def test_notification_change_shadow_value(self): class PreferencesWithDynamicDefault(Preferences): def _color_default(self): return "yellow" preferences = PreferencesWithDynamicDefault() self.assertEqual(len(preferences.primary_changes), 0) self.assertEqual(len(preferences.shadow_changes), 0) # access the dynamic default of color_ should not trigger event # because the value has not changed. preferences.color_ self.assertEqual(len(preferences.primary_changes), 0) self.assertEqual(len(preferences.shadow_changes), 0) def test_pickle_roundtrip(self): class Person(HasTraits): married = Map({"yes": 1, "yeah": 1, "no": 0, "nah": 0}, default_value="yes") p = Person() married_trait = p.traits()["married"] reconstituted = pickle.loads(pickle.dumps(married_trait)) self.assertEqual(married_trait.validate(p, "married", "yes"), "yes") self.assertEqual(reconstituted.validate(p, "married", "yes"), "yes") with self.assertRaises(TraitError): reconstituted.validate(p, "married", "unknown") def test_pickle_shadow_trait(self): class Person(HasTraits): married = Map({"yes": 1, "yeah": 1, "no": 0, "nah": 0}, default_value="yes") p = Person() married_shadow_trait = p.trait("married_") reconstituted = pickle.loads(pickle.dumps(married_shadow_trait)) default_value_callable = reconstituted.default_value()[1] self.assertEqual(default_value_callable(p), 1) traits-6.3.2/traits/tests/test_new_notifiers.py000066400000000000000000000062431414270267200217760ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for dynamic notifiers with `dispatch='new'`. Dynamic notifiers created with the `dispatch='new'` option dispatch event notifications on a new thread. The class handling the dispatch, `NewTraitChangeNotifyWrapper`, is a subclass of `TraitChangeNotifyWrapper`. Most of the functionality of the class is thus already covered by the `TestDynamicNotifiers` test case, and we only need to test that the notification really occurs on a separate thread. """ import threading import unittest from unittest import mock from traits.api import Float, HasTraits, List from traits.testing.unittest_tools import UnittestTools # Timeout for blocking calls, in seconds. SAFETY_TIMEOUT = 10.0 class RememberThreads(object): """ Context manager that behaves like Thread, but remembers created threads so that they can be joined. """ def __init__(self): self._threads = [] def __call__(self, *args, **kwargs): thread = threading.Thread(*args, **kwargs) self._threads.append(thread) return thread def __enter__(self): return self def __exit__(self, *exc_args): threads = self._threads while threads: thread = threads.pop() # Don't wait forever, but raise if we failed to join. thread.join(timeout=SAFETY_TIMEOUT) if thread.is_alive(): raise RuntimeError("Failed to join thread") class Foo(HasTraits): foo = Float class Receiver(HasTraits): notifications = List() def notified(self): # Have we received any notifications? return bool(self.notifications) class TestNewNotifiers(UnittestTools, unittest.TestCase): """ Tests for dynamic notifiers with `dispatch='new'`. """ def test_notification_on_separate_thread(self): receiver = Receiver() def on_foo_notifications(obj, name, old, new): thread_id = threading.current_thread().ident event = (thread_id, obj, name, old, new) receiver.notifications.append(event) obj = Foo() obj.on_trait_change(on_foo_notifications, "foo", dispatch="new") with RememberThreads() as remember_threads: patcher = mock.patch( "traits.trait_notifiers.Thread", new=remember_threads ) with patcher: obj.foo = 3 self.assertEventuallyTrue( receiver, "notifications_items", Receiver.notified, timeout=SAFETY_TIMEOUT) notifications = receiver.notifications self.assertEqual(len(notifications), 1) self.assertEqual(notifications[0][1:], (obj, "foo", 0, 3)) this_thread_id = threading.current_thread().ident self.assertNotEqual(this_thread_id, notifications[0][0]) traits-6.3.2/traits/tests/test_none.py000066400000000000000000000017521414270267200200620ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import HasTraits, TraitError from traits.trait_types import _NoneTrait class A(HasTraits): none_atr = _NoneTrait(default_value=None) class TestCaseNoneTrait(unittest.TestCase): def test_none(self): obj = A() self.assertIsNone(obj.none_atr) def test_assign_non_none(self): with self.assertRaises(TraitError): A(none_atr=5) def test_default_value_not_none(self): with self.assertRaises(ValueError): class TestClass(HasTraits): none_trait = _NoneTrait(default_value=[]) traits-6.3.2/traits/tests/test_observe.py000066400000000000000000000624201414270267200205670ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Integration tests between HasTraits and observe. See tests in ``traits.observations`` for more targeted tests. """ import unittest from traits.api import ( Any, Bool, DelegatesTo, Dict, Event, HasTraits, Instance, Int, List, observe, Property, Set, Str, Undefined, ) from traits.observation.api import ( anytrait, pop_exception_handler, push_exception_handler, trait, ) class TestObserveDecorator(unittest.TestCase): """ General tests for the observe decorator. """ def test_warning_on_handler_with_bad_signature(self): message_regex = "should be callable with a single positional argument" with self.assertWarnsRegex(UserWarning, message_regex): class A(HasTraits): foo = Int() @observe("foo") def _do_something_when_foo_changes(self): pass with self.assertWarnsRegex(UserWarning, message_regex): class B(HasTraits): foo = Int() @observe("foo") def _do_something_when_foo_changes(self, **kwargs): pass def test_decorated_method_signatures(self): # Test different handler signatures for compatibility with # observe decorator. class A(HasTraits): foo = Int() call_count = Int(0) @observe("foo") def _the_usual_signature(self, event): self.call_count += 1 @observe("foo") def _method_with_extra_optional_args(self, event, frombicate=True): self.call_count += 1 @observe("foo") def _method_with_star_args(self, *args): self.call_count += 1 @observe("foo") def _method_with_alternative_name(self, foo_change_event): self.call_count += 1 @observe("foo") def _optional_second_argument(self, event=None): self.call_count += 1 a = A() self.assertEqual(a.call_count, 0) a.foo = 23 self.assertEqual(a.call_count, 5) class Student(HasTraits): """ Model for testing list + post_init (enthought/traits#275) """ graduate = Event() class Teacher(HasTraits): """ Model for testing list + post_init (enthought/traits#275) """ students = List(Instance(Student)) student_graduate_events = List() @observe( trait("students", notify=True) .list_items(notify=False) .trait("graduate"), post_init=True) def _student_graduate(self, event): self.student_graduate_events.append(event) class TestHasTraitsObservePostInit(unittest.TestCase): """ Test for enthought/traits#275 """ def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def test_observe_post_init_true(self): # Resolves enthought/traits#275 students = [Student() for _ in range(3)] teacher = Teacher(students=students) # No events as handler is created post-init self.assertEqual(len(teacher.student_graduate_events), 0) # when students[0].graduate = True # then self.assertEqual(len(teacher.student_graduate_events), 1) # Integration tests for default initializer ----------------------------------- class Record(HasTraits): number = Int(10) default_call_count = Int() number_change_events = List() clicked = Event() def _number_default(self): self.default_call_count += 1 return 99 @observe('number') def handle_number_change(self, event): self.number_change_events.append(event) class Album(HasTraits): records = List(Instance(Record)) records_default_call_count = Int() record_number_change_events = List() name_to_records = Dict(Str, Record) name_to_records_default_call_count = Int() name_to_records_clicked_events = List() def _records_default(self): self.records_default_call_count += 1 return [Record()] @observe(trait("records").list_items().trait("number")) def handle_record_number_changed(self, event): self.record_number_change_events.append(event) def _name_to_records_default(self): self.name_to_records_default_call_count += 1 return {"Record": Record()} @observe("name_to_records:items:clicked") def handle_event(self, event): self.name_to_records_clicked_events.append(event) class TestHasTraitsObserverDefaultHandler(unittest.TestCase): """ Test the behaviour with dynamic default handler + container. """ def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def test_default_not_called_if_init_contains_value(self): record = Record(number=123) # enthought/traits#94 self.assertEqual(record.default_call_count, 1) self.assertEqual(len(record.number_change_events), 1) event, = record.number_change_events self.assertEqual(event.object, record) self.assertEqual(event.name, "number") self.assertEqual(event.old, 99) self.assertEqual(event.new, 123) def test_observe_extended_trait_in_list(self): album = Album() # default is not called. self.assertEqual(album.records_default_call_count, 0) self.assertEqual(len(album.record_number_change_events), 0) # But the observers are hooked up # when album.records[0].number += 1 # then self.assertEqual(album.records_default_call_count, 1) self.assertEqual(len(album.record_number_change_events), 1) event, = album.record_number_change_events self.assertEqual(event.object, album.records[0]) self.assertEqual(event.name, "number") self.assertEqual(event.old, 99) self.assertEqual(event.new, 100) def test_observe_extended_trait_in_default_dict(self): # Test for enthought/traits#279 album = Album() self.assertEqual(album.name_to_records_default_call_count, 0) self.assertEqual(len(album.name_to_records_clicked_events), 0) # when album.name_to_records["Record"].clicked = True # then self.assertEqual(len(album.name_to_records_clicked_events), 1) # Integration tests for nested List and extended traits ----------------------- class SingleValue(HasTraits): value = Int() class ClassWithListOfInstance(HasTraits): list_of_instances = List(Instance(SingleValue)) class ClassWithListOfListOfInstance(HasTraits): list_of_list_of_instances = List(List(Instance(SingleValue))) class TestHasTraitsObserveListOfInstance(unittest.TestCase): def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def test_observe_instance_in_nested_list(self): container = ClassWithListOfListOfInstance() events = [] handler = events.append container.observe( expression=( trait("list_of_list_of_instances", notify=False) .list_items(notify=False) .list_items(notify=False) .trait("value") ), handler=handler, ) # sanity check single_value_instance = SingleValue() inner_list = [single_value_instance] container.list_of_list_of_instances.append(inner_list) self.assertEqual(len(events), 0) # when single_value_instance.value += 1 # then event, = events self.assertEqual(event.object, single_value_instance) self.assertEqual(event.name, "value") self.assertEqual(event.old, 0) self.assertEqual(event.new, 1) def test_nested_list_reassigned_value_compared_equally(self): container = ClassWithListOfListOfInstance() events = [] handler = events.append container.observe( expression=( trait("list_of_list_of_instances", notify=False) .list_items(notify=False) .list_items(notify=False) .trait("value") ), handler=handler, ) inner_list = [SingleValue()] container.list_of_list_of_instances = [inner_list] # sanity check self.assertEqual(len(events), 0) # assignment of a list that compares equally should be handled # correctly. # This relies on TraitList not trying to suppress notifications # when new values compared equally to old values. container.list_of_list_of_instances[0] = inner_list second_instance = SingleValue() container.list_of_list_of_instances[0].append(second_instance) self.assertEqual(len(events), 0) # when second_instance.value += 1 # then event, = events self.assertEqual(event.object, second_instance) self.assertEqual(event.name, "value") self.assertEqual(event.old, 0) self.assertEqual(event.new, 1) def test_duplicated_items_tracked(self): # test for enthought/traits#237 container = ClassWithListOfInstance() events = [] handler = events.append container.observe( expression=( trait("list_of_instances", notify=False) .list_items(notify=False) .trait("value") ), handler=handler, ) instance = SingleValue() # The item is repeated. container.list_of_instances.append(instance) container.list_of_instances.append(instance) self.assertEqual(len(events), 0) # when instance.value += 1 # then self.assertEqual(len(events), 1) events.clear() # when container.list_of_instances.pop() instance.value += 1 # then self.assertEqual(len(events), 1) events.clear() # when container.list_of_instances.pop() instance.value += 1 # then self.assertEqual(len(events), 0) # Integration tests for nested Dict and extended traits ----------------------- class ClassWithDictOfInstance(HasTraits): name_to_instance = Dict(Str, Instance(SingleValue)) class TestHasTraitsObserveDictOfInstance(unittest.TestCase): def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def test_observe_instance_in_dict(self): container = ClassWithDictOfInstance() events = [] handler = events.append container.observe( handler=handler, expression=( trait("name_to_instance", notify=False) .dict_items(notify=False) .trait("value") ), ) single_value_instance = SingleValue() container.name_to_instance = {"name": single_value_instance} # sanity check self.assertEqual(len(events), 0) # when single_value_instance.value += 1 # then event, = events self.assertEqual(event.object, single_value_instance) self.assertEqual(event.name, "value") self.assertEqual(event.old, 0) self.assertEqual(event.new, 1) # Integration tests for Set and extended traits ------------------------------ class ClassWithSetOfInstance(HasTraits): instances = Set(Instance(SingleValue)) instances_compat = Set(Instance(SingleValue)) class TestHasTraitsObserveSetOfInstance(unittest.TestCase): def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def test_observe_instance_in_set(self): container = ClassWithSetOfInstance() events = [] handler = events.append container.observe( handler=handler, expression=( trait("instances", notify=False) .set_items(notify=False) .trait("value") ), ) single_value_instance = SingleValue() container.instances = set([single_value_instance]) # sanity check self.assertEqual(len(events), 0) # when single_value_instance.value += 1 # then event, = events self.assertEqual(event.object, single_value_instance) self.assertEqual(event.name, "value") self.assertEqual(event.old, 0) self.assertEqual(event.new, 1) # Integration test for maintaining and differentiating observers -------------- class Potato(HasTraits): name = Str() class PotatoBag(HasTraits): potatos = List(Instance(Potato)) class Crate(HasTraits): potato_bags = List(PotatoBag) class TestHasTraitsObserverDifferentiateParent(unittest.TestCase): def test_shared_instance_but_different_target(self): # If the comparison of targets is removed from # TraitEventNotifier.equals, this test would fail. potato = Potato() potato_bag = PotatoBag(potatos=[potato]) crate1 = Crate(potato_bags=[potato_bag]) crate2 = Crate(potato_bags=[potato_bag]) # when events = [] handler = events.append crate1.observe( handler, "potato_bags:items:potatos:items:name", ) crate2.observe( handler, "potato_bags:items:potatos:items:name", ) potato.name = "King Edward" # then # there are two notifiers, because they are observed from different # objects. self.assertEqual(len(events), 2) def test_shared_instance_same_graph_different_target(self): crate1 = Crate() crate2 = Crate() # given events = [] handler = events.append crate1.observe(handler, "potato_bags:items:potatos:items:name") crate2.observe(handler, "potato_bags:items:potatos:items:name") new_potato = Potato() new_potato_bag = PotatoBag(potatos=[new_potato]) crate1.potato_bags = [new_potato_bag] crate2.potato_bags = [new_potato_bag] new_potato.name = "King Edward I" self.assertEqual(len(events), 2) events.clear() # when # remove the second observer crate2.observe( handler, "potato_bags:items:potatos:items:name", remove=True) new_potato.name = "King Edward II" # then self.assertEqual(len(events), 1) events.clear() # then # This check the observer is maintained. maris_piper = Potato() crate2.potato_bags[0].potatos.append(maris_piper) crate1.potato_bags = [] self.assertEqual(len(events), 0) # sanity check # this fails if targets were not compared. maris_piper.name = "Maris Piper" self.assertEqual(len(events), 0) # Integration test for the special event metadata ---------------------------- class FooWithEventMetadata(HasTraits): val = Str(event="the_trait") @observe("the_trait") def _handle_the_trait_changed(self, event): pass class TestSpecialEvent(unittest.TestCase): """ Test the 'event' metadata... won't work with ``observe``! """ def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def test_events(self): with self.assertRaises(ValueError) as exception_cm: # Attempt to attach the observer will fail because # the "the_trait" is not actually a trait on the object. FooWithEventMetadata() self.assertIn( "Trait named 'the_trait' not found", str(exception_cm.exception), ) # Integration test for when the observer is not appropriate for the data ------ class Person(HasTraits): name = Str() class Team(HasTraits): leader = Instance(Person) member_names = List(Str()) any_value = Any() class TestObserverError(unittest.TestCase): def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def test_trait_is_not_list(self): team = Team() # The `list_items` should not be used here. # Error is not emitted now as leader is not defined so there is no # way to check. team.observe(lambda e: None, trait("leader").list_items()) person = Person() with self.assertRaises(ValueError) as exception_cm: team.leader = person self.assertIn( "Expected a TraitList to be observed", str(exception_cm.exception), ) def test_items_on_a_list_not_observable_by_named_trait(self): # The member_names is a list of str, attempt to observe extended # trait on them should fail. team = Team() team.observe( lambda e: None, trait("member_names").list_items().trait("does_not_exist") ) with self.assertRaises(ValueError) as exception_cm: team.member_names = ["Paul"] self.assertEqual( str(exception_cm.exception), "Trait named 'does_not_exist' not found on 'Paul'." ) def test_extended_trait_on_any_value(self): team = Team() team.any_value = 123 with self.assertRaises(ValueError) as exception_cm: team.observe( lambda e: None, trait("any_value").trait("does_not_exist")) self.assertEqual( str(exception_cm.exception), "Trait named 'does_not_exist' not found on 123." ) def test_no_new_trait_added(self): # Test enthought/traits#447 can be avoided with observe team = Team() team.observe(lambda e: None, trait("leader").trait("does_not_exist")) with self.assertRaises(ValueError): team.leader = Person() self.assertNotIn("does_not_exist", team.leader.trait_names()) # Integration test with DelegateTo -------------------------------------------- class Dummy(HasTraits): x = Int(10) class Dummy2(HasTraits): y = Int(20) dummy = Instance(Dummy) class DelegateMess(HasTraits): dummy1 = Instance(Dummy, args=()) dummy2 = Instance(Dummy2) y = DelegatesTo("dummy2") handler_called = Bool(False) def _dummy2_default(self): # Create `self.dummy1` return Dummy2(dummy=self.dummy1) @observe("dummy1.x") def _on_dummy1_x(self, event): self.handler_called = True class TestDelegateToInteraction(unittest.TestCase): def test_delegate_initializer(self): mess = DelegateMess() self.assertFalse(mess.handler_called) mess.dummy1.x = 20 self.assertTrue(mess.handler_called) # Integration tests with on_trait_change and observe ------------------ # The legacy of on_trait_change means instance trait named with "_items" # suffix is handled differently in HasTraits. This tests the awkward # interaction that could arise while using on_trait_change together with # observe involving "*_items" class Application(HasTraits): pass class TestObserveItemsFromOnTraitChange(unittest.TestCase): def test_observe_event_with_undefined_name_suffix_items(self): # Regression test for the error resulting from trying (and failing) to # retrieve the CTrait for an instance trait with name "*_items" # via HasTraits.traits app = Application() def dummy_handler(): pass # on_trait_change does not check if the trait has been defined. # This has the side-effect of creating the CTrait for this trait name. app.on_trait_change(dummy_handler, "i_am_undefined_with_items") self.assertIsNotNone(app._trait("i_am_undefined_with_items", 0)) # Precondition for this test, i_am_undefined_with_items is still not # reported by HasTraits.traits method self.assertNotIn("i_am_undefined_with_items", app.traits()) events = [] # This works because the CTrait is created by on_trait_change app.observe(events.append, "i_am_undefined_with_items") # This should not fail. app.trait_property_changed("i_am_undefined_with_items", 1, 2) self.assertEqual(len(events), 1) # Integration tests for anytrait listener ------------------------------------- class HasVariousTraits(HasTraits): #: Function to call on any trait change. trait_change_callback = Any() foo = Int(16) bar = Str("off") updated = Event(Bool) @observe("*") def _record_trait_change(self, event): callback = self.trait_change_callback if callback is not None: callback(event) class UpdateListener(HasTraits): foo = Instance(HasVariousTraits) bar = Instance(HasVariousTraits) class TestObserveAnytrait(unittest.TestCase): def test_observe_method_anytrait(self): obj = HasVariousTraits() events = [] obj.observe(events.append, "*") obj.foo = 23 obj.bar = "on" self.assertEqual(len(events), 2) foo_event, bar_event = events self.assertEqual(foo_event.object, obj) self.assertEqual(foo_event.name, "foo") self.assertEqual(foo_event.old, 16) self.assertEqual(foo_event.new, 23) self.assertEqual(bar_event.object, obj) self.assertEqual(bar_event.name, "bar") self.assertEqual(bar_event.old, "off") self.assertEqual(bar_event.new, "on") def test_observe_decorator_anytrait(self): events = [] obj = HasVariousTraits(trait_change_callback=events.append) obj.foo = 23 obj.bar = "on" self.assertEqual(len(events), 3) callback_event, foo_event, bar_event = events self.assertEqual(callback_event.object, obj) self.assertEqual(callback_event.name, "trait_change_callback") self.assertIs(callback_event.old, None) self.assertEqual(callback_event.new, events.append) self.assertEqual(foo_event.object, obj) self.assertEqual(foo_event.name, "foo") self.assertEqual(foo_event.old, 16) self.assertEqual(foo_event.new, 23) self.assertEqual(bar_event.object, obj) self.assertEqual(bar_event.name, "bar") self.assertEqual(bar_event.old, "off") self.assertEqual(bar_event.new, "on") def test_anytrait_expression(self): obj = HasVariousTraits() events = [] obj.observe(events.append, anytrait()) obj.foo = 23 obj.bar = "on" self.assertEqual(len(events), 2) foo_event, bar_event = events self.assertEqual(foo_event.object, obj) self.assertEqual(foo_event.name, "foo") self.assertEqual(foo_event.old, 16) self.assertEqual(foo_event.new, 23) self.assertEqual(bar_event.object, obj) self.assertEqual(bar_event.name, "bar") self.assertEqual(bar_event.old, "off") self.assertEqual(bar_event.new, "on") def test_anytrait_method(self): foo = HasVariousTraits() bar = HasVariousTraits() obj = UpdateListener(foo=foo, bar=bar) events = [] obj.observe(events.append, trait("foo", notify=False).anytrait()) foo.updated = True bar.updated = True self.assertEqual(len(events), 1) foo_event, = events self.assertEqual(foo_event.object, foo) self.assertEqual(foo_event.name, "updated") self.assertEqual(foo_event.old, Undefined) self.assertEqual(foo_event.new, True) def test_anytrait_with_children(self): foo = HasVariousTraits() bar = HasVariousTraits() obj = UpdateListener(foo=foo, bar=bar) events = [] with self.assertRaises(ValueError): obj.observe(events.append, "*:updated") def test_anytrait_of_anytrait(self): foo = HasVariousTraits() bar = HasVariousTraits() obj = UpdateListener(foo=foo, bar=bar) events = [] with self.assertRaises(ValueError): obj.observe(events.append, "*:*") def test_anytrait_unobserve(self): obj = HasVariousTraits() events = [] obj.observe(events.append, "*") obj.foo = 23 obj.bar = "on" self.assertEqual(len(events), 2) obj.observe(events.append, "*", remove=True) obj.foo = 232 obj.bar = "mid" # No additional events. self.assertEqual(len(events), 2) def test_property_subclass_observe(self): # Regression test for enthought/traits#1586 class Base(HasTraits): bar = Int() foo = Property(Int(), observe="bar") def _get_foo(self): return self.bar class Derived(Base): pass events = [] obj = Derived(bar=3) obj.observe(events.append, "foo") # Changing bar should result in a single event. self.assertEqual(len(events), 0) obj.bar = 5 self.assertEqual(len(events), 1) traits-6.3.2/traits/tests/test_pickle_validated_dict.py000066400000000000000000000020071414270267200234040ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import pickle import unittest from traits.api import Dict, HasTraits, Int, List class C(HasTraits): # A dict trait containing a list trait a = Dict(Int, List(Int)) # And we must initialize it to something non-trivial def __init__(self): super().__init__() self.a = {1: [2, 3]} class PickleValidatedDictTestCase(unittest.TestCase): def test_pickle_validated_dict(self): # And we must unpickle one x = pickle.dumps(C()) try: pickle.loads(x) except AttributeError as e: self.fail("Unpickling raised an AttributeError: %s" % e) traits-6.3.2/traits/tests/test_prefix_list.py000066400000000000000000000117371414270267200214570ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the PrefixList handler. """ import pickle import unittest from traits.api import HasTraits, TraitError, PrefixList class TestPrefixList(unittest.TestCase): def test_assignment(self): class A(HasTraits): foo = PrefixList(["zero", "one", "two"], default_value="one") a = A() a.foo = 'z' self.assertEqual(a.foo, "zero") with self.assertRaises(TraitError) as exception_context: a.foo = '' self.assertIn( "The 'foo' trait of an A instance must be 'zero' or 'one' or 'two'" " (or any unique prefix), but a value of ''", str(exception_context.exception), ) def test_bad_types(self): class A(HasTraits): foo = PrefixList(["zero", "one", "two"], default_value="one") a = A() wrong_type = [[], (1, 2, 3), 1j, 2.3, 23, b"zero", None] for value in wrong_type: with self.subTest(value=value): with self.assertRaises(TraitError): a.foo = value def test_repeated_prefix(self): class A(HasTraits): foo = PrefixList(("abc1", "abc2")) a = A() a.foo = "abc1" self.assertEqual(a.foo, "abc1") with self.assertRaises(TraitError): a.foo = "abc" def test_default_default(self): class A(HasTraits): foo = PrefixList(["zero", "one", "two"], default_value="zero") a = A() self.assertEqual(a.foo, "zero") def test_explicit_default(self): class A(HasTraits): foo = PrefixList(["zero", "one", "two"], default_value="one") a = A() self.assertEqual(a.foo, "one") def test_default_subject_to_completion(self): class A(HasTraits): foo = PrefixList(["zero", "one", "two"], default_value="o") a = A() self.assertEqual(a.foo, "one") def test_default_subject_to_validation(self): with self.assertRaises(ValueError): class A(HasTraits): foo = PrefixList(["zero", "one", "two"], default_value="uno") def test_default_legal_but_not_unique_prefix(self): # Corner case to exercise internal logic: the default is not a unique # prefix, but it is one of the list of values, so it's legal. class A(HasTraits): foo = PrefixList(["live", "modal", "livemodal"], default="live") a = A() self.assertEqual(a.foo, "live") def test_default_value_cant_be_passed_by_position(self): with self.assertRaises(TypeError): PrefixList(["zero", "one", "two"], "one") def test_values_not_sequence(self): # Defining values with this signature is not supported with self.assertRaises(TypeError): PrefixList("zero", "one", "two") def test_values_not_all_iterables(self): # Make sure we don't confuse other sequence types, e.g. str with self.assertRaises(TypeError) as exception_context: PrefixList("zero") self.assertEqual( str(exception_context.exception), "values should be a collection of strings, not 'zero'" ) def test_values_is_empty(self): # it doesn't make sense to use a PrefixList with an empty list, so make # sure we raise a ValueError with self.assertRaises(ValueError): PrefixList([]) def test_values_is_empty_with_default_value(self): # Raise even if we give a default value. with self.assertRaises(ValueError): PrefixList([], default_value="one") def test_no_nested_exception(self): # Regression test for enthought/traits#1155 class A(HasTraits): foo = PrefixList(["zero", "one", "two"]) a = A() try: a.foo = "three" except TraitError as exc: self.assertIsNone(exc.__context__) self.assertIsNone(exc.__cause__) def test_pickle_roundtrip(self): class A(HasTraits): foo = PrefixList(["zero", "one", "two"], default_value="one") a = A() foo_trait = a.traits()["foo"] reconstituted = pickle.loads(pickle.dumps(foo_trait)) self.assertEqual( foo_trait.validate(a, "foo", "ze"), "zero", ) with self.assertRaises(TraitError): foo_trait.validate(a, "foo", "zero-knowledge") self.assertEqual( reconstituted.validate(a, "foo", "ze"), "zero", ) with self.assertRaises(TraitError): reconstituted.validate(a, "foo", "zero-knowledge") traits-6.3.2/traits/tests/test_prefix_map.py000066400000000000000000000173141414270267200212560ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the PrefixMap handler. """ import pickle import unittest from traits.api import HasTraits, Int, PrefixMap, TraitError class Person(HasTraits): married = PrefixMap({"yes": 1, "yeah": 1, "no": 0, "nah": 0}) class TestPrefixMap(unittest.TestCase): def test_assignment(self): person = Person() # Test prefix person.married = "yea" self.assertEqual("yeah", person.married) self.assertEqual(1, person.married_) person.married = "yes" self.assertEqual("yes", person.married) self.assertEqual(1, person.married_) person.married = "na" self.assertEqual("nah", person.married) self.assertEqual(0, person.married_) with self.assertRaises(TraitError): person.married = "unknown" # Test duplicate prefix with self.assertRaises(TraitError): person.married = "ye" def test_bad_types(self): person = Person() wrong_type = [[], (1, 2, 3), 1j, 2.3, 23, b"not a string", None] for value in wrong_type: with self.subTest(value=value): with self.assertRaises(TraitError): person.married = value def test_no_default(self): mapping = {"yes": 1, "yeah": 1, "no": 0, "nah": 0} class Person(HasTraits): married = PrefixMap(mapping) p = Person() # Since we're using Python >= 3.6, we can rely on dictionaries # being ordered, and then the default is predictable. self.assertEqual(p.married, "yes") self.assertEqual(p.married_, 1) def test_default(self): class Person(HasTraits): married = PrefixMap({"yes": 1, "yeah": 1, "no": 0, "nah": 0}, default_value="nah") p = Person() self.assertEqual(p.married, "nah") self.assertEqual(p.married_, 0) def test_default_keyword_only(self): with self.assertRaises(TypeError): PrefixMap({"yes": 1, "no": 0}, "yes") def test_default_method(self): class Person(HasTraits): married = PrefixMap({"yes": 1, "yeah": 1, "no": 0, "nah": 0}) default_calls = Int(0) def _married_default(self): self.default_calls += 1 return "nah" p = Person() self.assertEqual(p.married, "nah") self.assertEqual(p.married_, 0) self.assertEqual(p.default_calls, 1) # Check that the order doesn't matter p2 = Person() self.assertEqual(p2.married_, 0) self.assertEqual(p2.married, "nah") self.assertEqual(p2.default_calls, 1) def test_default_static_override_static(self): class BasePerson(HasTraits): married = PrefixMap({"yes": 1, "yeah": 1, "no": 0, "nah": 0}, default_value="nah") class Person(BasePerson): married = "yes" p = Person() self.assertEqual(p.married, "yes") self.assertEqual(p.married_, 1) def test_default_static_override_method(self): class BasePerson(HasTraits): married = PrefixMap({"yes": 1, "yeah": 1, "no": 0, "nah": 0}, default_value="nah") class Person(BasePerson): default_calls = Int(0) def _married_default(self): self.default_calls += 1 return "yes" p = Person() self.assertEqual(p.married, "yes") self.assertEqual(p.married_, 1) self.assertEqual(p.default_calls, 1) def test_default_method_override_static(self): class BasePerson(HasTraits): married = PrefixMap({"yes": 1, "yeah": 1, "no": 0, "nah": 0}) default_calls = Int(0) def _married_default(self): self.default_calls += 1 return "nah" class Person(BasePerson): married = "yes" p = Person() self.assertEqual(p.married, "yes") self.assertEqual(p.married_, 1) self.assertEqual(p.default_calls, 0) def test_default_method_override_method(self): class BasePerson(HasTraits): married = PrefixMap({"yes": 1, "yeah": 1, "no": 0, "nah": 0}) default_calls = Int(0) def _married_default(self): self.default_calls += 1 return "nah" class Person(BasePerson): def _married_default(self): self.default_calls += 1 return "yes" p = Person() self.assertEqual(p.married, "yes") self.assertEqual(p.married_, 1) self.assertEqual(p.default_calls, 1) def test_static_default_transformed(self): # Test the static default is transformed class Person(HasTraits): married = PrefixMap( {"yes": 1, "yeah": 1, "no": 0}, default_value="yea") p = Person() self.assertEqual(p.married, "yeah") self.assertEqual(p.married_, 1) # access mapped trait first is okay p = Person() self.assertEqual(p.married_, 1) self.assertEqual(p.married, "yeah") def test_static_default_validation_error(self): with self.assertRaises(ValueError): class Person(HasTraits): married = PrefixMap( {"yes": 1, "yeah": 1, "no": 0}, default_value="meh") def test_no_nested_exception(self): # Regression test for enthought/traits#1155 class A(HasTraits): washable = PrefixMap({"yes": 1, "no": 0}) a = A() try: a.washable = "affirmatron" except TraitError as exc: self.assertIsNone(exc.__context__) self.assertIsNone(exc.__cause__) def test_pickle_roundtrip(self): class Person(HasTraits): married = PrefixMap({"yes": 1, "yeah": 1, "no": 0, "nah": 0}, default_value="yea") p = Person() married_trait = p.traits()["married"] reconstituted = pickle.loads(pickle.dumps(married_trait)) self.assertEqual(married_trait.validate(p, "married", "yea"), "yeah") self.assertEqual(reconstituted.validate(p, "married", "yea"), "yeah") with self.assertRaises(TraitError): reconstituted.validate(p, "married", "uknown") with self.assertRaises(TraitError): reconstituted.validate(p, "married", "ye") def test_empty_map(self): with self.assertRaises(ValueError): PrefixMap({}) def test_pickle_shadow_trait(self): class Person(HasTraits): married = PrefixMap({"yes": 1, "yeah": 1, "no": 0, "nah": 0}, default_value="yeah") p = Person() married_shadow_trait = p.trait("married_") reconstituted = pickle.loads(pickle.dumps(married_shadow_trait)) default_value_callable = reconstituted.default_value()[1] self.assertEqual(default_value_callable(p), 1) def test_existence_of__map(self): # This test can be removed once Mayavi no longer depends on the # existence of the _map attribute. # xref: enthought/traits#1577 # xref: enthought/mayavi#1094 prefix_map = PrefixMap({"yes": 1, "yeah": 1, "no": 0, "nah": 0}) self.assertEqual(prefix_map._map["yes"], "yes") traits-6.3.2/traits/tests/test_property_delete.py000066400000000000000000000020531414270267200223240ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Unit tests to ensure that we can call reset_traits/delete on a property trait (regression tests for Github issue #67). """ import unittest from traits.api import Any, HasTraits, Int, Property, TraitError class E(HasTraits): a = Property(Any) b = Property(Int) class TestPropertyDelete(unittest.TestCase): def test_property_delete(self): e = E() with self.assertRaises(TraitError): del e.a with self.assertRaises(TraitError): del e.b def test_property_reset_traits(self): e = E() unresetable = e.reset_traits() self.assertCountEqual(unresetable, ["a", "b"]) traits-6.3.2/traits/tests/test_property_notifications.py000066400000000000000000000373121414270267200237410ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import io import pickle import unittest from unittest import mock import weakref from traits.api import ( Any, Bool, cached_property, HasTraits, Instance, Int, List, observe, on_trait_change, Property, Str, ) from traits.trait_base import Undefined from traits.observation.api import ( trait, pop_exception_handler, push_exception_handler, ) class Test(HasTraits): output_buffer = Any() def __value_get(self): return self.__dict__.get("_value", 0) def __value_set(self, value): old_value = self.__dict__.get("_value", 0) if value != old_value: self._value = value self.trait_property_changed("value", old_value, value) value = Property(__value_get, __value_set) class Test_1(Test): def _value_changed(self, value): self.output_buffer.write(value) class TestPropertyNotifications(unittest.TestCase): def test_property_notifications(self): output_buffer = io.StringIO() test_obj = Test_1(output_buffer=output_buffer) test_obj.value = "value_1" self.assertEqual(output_buffer.getvalue(), "value_1") test_obj.value = "value_2" self.assertEqual(output_buffer.getvalue(), "value_1value_2") # Integration test for Property notifications via 'observe' / 'depends_on' class PersonInfo(HasTraits): age = Int() gender = Str() class ClassWithInstanceDefaultInit(HasTraits): info_without_default = Instance(PersonInfo) list_of_infos = List(Instance(PersonInfo), comparison_mode=1) sample_info = Instance(PersonInfo) sample_info_default_computed = Bool() def _sample_info_default(self): self.sample_info_default_computed = True return PersonInfo(age=self.info_without_default.age) info_with_default = Instance(PersonInfo) info_with_default_computed = Bool() def _info_with_default_default(self): self.info_with_default_computed = True return PersonInfo(age=12) class ClassWithPropertyObservesDefault(ClassWithInstanceDefaultInit): """ Dummy class for testing property with an observer on an extended attribute. 'info_with_default has a default initializer. To be compared with the next class using depends_on """ extended_age = Property(observe="info_with_default.age") extended_age_n_calculations = Int() def _get_extended_age(self): self.extended_age_n_calculations += 1 return self.info_with_default.age class ClassWithPropertyDependsOnDefault(ClassWithInstanceDefaultInit): """ Dummy class for testing property with an observer on an extended attribute. 'info_with_default' has a default initializer. """ extended_age = Property(depends_on="info_with_default.age") extended_age_n_calculations = Int() def _get_extended_age(self): self.extended_age_n_calculations += 1 return self.info_with_default.age class ClassWithPropertyObservesInit(ClassWithInstanceDefaultInit): """ Dummy class for testing property with an observer on an extended attribute. sample_info has a default value depending on 'info_without_default'. The value of 'info_without_default' is provided by __init__. To be compared with the next class using depends_on. """ extended_age = Property(observe="sample_info.age") extended_age_n_calculations = Int() def _get_extended_age(self): self.extended_age_n_calculations += 1 return self.sample_info.age class ClassWithPropertyDependsOnInit(ClassWithInstanceDefaultInit): # This class cannot be instantiated. # enthought/traits#709 extended_age = Property(depends_on="sample_info.age") def _get_extended_age(self): return self.sample_info.age class ClassWithPropertyMultipleObserves(PersonInfo): """ Dummy class to test observing multiple values. """ computed_value = Property(observe=[trait("age"), trait("gender")]) computed_value_n_calculations = Int() def _get_computed_value(self): self.computed_value_n_calculations += 1 return len(self.gender) + self.age class ClassWithPropertyMultipleDependsOn(PersonInfo): """ Dummy class using 'depends_on', to be compared with the one above. """ computed_value = Property(depends_on=["age", "gender"]) computed_value_n_calculations = Int() def _get_computed_value(self): self.computed_value_n_calculations += 1 return len(self.gender) + self.age class ClassWithPropertyObservesItems(ClassWithInstanceDefaultInit): """ Dummy class to test property observing container items""" discounted = Property( Bool(), observe=trait("list_of_infos").list_items().trait("age")) discounted_n_calculations = Int() def _get_discounted(self): self.discounted_n_calculations += 1 return any(info.age > 70 for info in self.list_of_infos) class ClassWithPropertyDependsOnItems(ClassWithInstanceDefaultInit): """ Dummy class using depends_on to be compared with the one using observe.""" discounted = Property(Bool(), depends_on="list_of_infos.age") discounted_n_calculations = Int() def _get_discounted(self): self.discounted_n_calculations += 1 return any(info.age > 70 for info in self.list_of_infos) class ClassWithPropertyObservesWithCache(PersonInfo): discounted = Property(Bool(), observe="age") discounted_n_calculations = Int() @cached_property def _get_discounted(self): self.discounted_n_calculations += 1 return self.age > 10 class ClassWithPropertyObservesDecorated(PersonInfo): """ Dummy class to test property with observers setup at init time.""" discounted = Property(Bool(), observe="age") discounted_n_calculations = Int() def _get_discounted(self): self.discounted_n_calculations += 1 return self.age > 60 discounted_events = List() @observe("discounted") def discounted_updated(self, event): self.discounted_events.append(event) class ClassWithPropertyDependsOnDecorated(PersonInfo): """ Dummy class to test property with depends_on and on_trait_change setup at init time.""" discounted = Property(Bool(), depends_on="age") discounted_n_calculations = Int() def _get_discounted(self): self.discounted_n_calculations += 1 return self.age > 60 discounted_events = List() @on_trait_change("discounted") def discounted_updated(self, event): self.discounted_events.append(event) class ClassWithPropertyMissingGetter(PersonInfo): """ Dummy class to test property that does not have getter/setter. """ discounted = Property(Bool(), observe="age") class ClassWithPropertyTraitNotFound(HasTraits): """ Dummy class to test error, prevent issues like enthought/traits#447 """ person = Instance(PersonInfo) last_name = Property(observe="person.last_name") # last_name not defined class TestHasTraitsPropertyObserves(unittest.TestCase): """ Tests Property notifications using 'observe', and compared the behavior with 'depends_on' """ def setUp(self): push_exception_handler(reraise_exceptions=True) self.addCleanup(pop_exception_handler) def test_property_observe_extended_trait(self): instance_observe = ClassWithPropertyObservesDefault() handler_observe = mock.Mock() instance_observe.observe(handler_observe, "extended_age") # sanity check against depends_on instance_depends_on = ClassWithPropertyDependsOnDefault() handler_otc = mock.Mock() instance_depends_on.on_trait_change( get_otc_handler(handler_otc), "extended_age" ) instances = [instance_observe, instance_depends_on] handlers = [handler_observe, handler_otc] for instance, handler in zip(instances, handlers): with self.subTest(instance=instance, handler=handler): # when instance.info_with_default.age = 70 # then self.assertEqual(handler.call_count, 1) self.assertEqual(instance.extended_age_n_calculations, 1) def test_property_observe_does_not_fire_default(self): instance_observe = ClassWithPropertyObservesDefault() handler_observe = mock.Mock() instance_observe.observe(handler_observe, "extended_age") # compared with 'depends_on' instance_depends_on = ClassWithPropertyDependsOnDefault() instance_depends_on.on_trait_change( get_otc_handler(mock.Mock()), "extended_age") # then # they are different. See enthought/traits#481, #709 self.assertFalse(instance_observe.info_with_default_computed) self.assertTrue(instance_depends_on.info_with_default_computed) def test_property_multi_observe(self): instance_observe = ClassWithPropertyMultipleObserves() handler_observe = mock.Mock() instance_observe.observe(handler_observe, "computed_value") self.assertEqual(instance_observe.computed_value_n_calculations, 0) instance_depends_on = ClassWithPropertyMultipleDependsOn() instance_depends_on.on_trait_change( get_otc_handler(mock.Mock()), "computed_value") self.assertEqual(instance_depends_on.computed_value_n_calculations, 0) for instance in [instance_observe, instance_depends_on]: with self.subTest(instance=instance): # when instance.age = 1 # then self.assertEqual(instance.computed_value_n_calculations, 1) # when instance.gender = "male" # then self.assertEqual(instance.computed_value_n_calculations, 2) def test_property_observe_container(self): instance_observe = ClassWithPropertyObservesItems() handler_observe = mock.Mock() instance_observe.observe(handler_observe, "discounted") instance_depends_on = ClassWithPropertyDependsOnItems() instance_depends_on.on_trait_change( get_otc_handler(mock.Mock()), "discounted") for instance in [instance_observe, instance_depends_on]: with self.subTest(instance=instance): self.assertEqual(instance.discounted_n_calculations, 0) instance.list_of_infos.append(PersonInfo(age=30)) self.assertEqual(instance.discounted_n_calculations, 1) instance.list_of_infos[-1].age = 80 self.assertEqual(instance.discounted_n_calculations, 2) def test_property_old_value_uncached(self): instance = ClassWithPropertyMultipleObserves() handler = mock.Mock() instance.observe(handler, "computed_value") instance.age = 1 ((event, ), _), = handler.call_args_list self.assertIs(event.object, instance) self.assertEqual(event.name, "computed_value") self.assertIs(event.old, Undefined) # property is not cached self.assertIs(event.new, 1) handler.reset_mock() instance.gender = "male" ((event, ), _), = handler.call_args_list self.assertIs(event.object, instance) self.assertEqual(event.name, "computed_value") self.assertIs(event.old, Undefined) # property is not cached self.assertIs(event.new, 5) # len("male") + 1 def test_property_with_cache(self): instance = ClassWithPropertyObservesWithCache() handler = mock.Mock() instance.observe(handler, "discounted") instance.age = 1 (event, ), _ = handler.call_args_list[-1] self.assertIs(event.object, instance) self.assertEqual(event.name, "discounted") self.assertIs(event.old, Undefined) self.assertIs(event.new, False) handler.reset_mock() instance.age = 80 (event, ), _ = handler.call_args_list[-1] self.assertIs(event.object, instance) self.assertEqual(event.name, "discounted") self.assertIs(event.old, False) self.assertIs(event.new, True) def test_property_default_initializer_with_value_in_init(self): # With "depends_on", instantiation will fail. # enthought/traits#709 with self.assertRaises(AttributeError): ClassWithPropertyDependsOnInit( info_without_default=PersonInfo(age=30)) # With "observe", initialization works. instance = ClassWithPropertyObservesInit( info_without_default=PersonInfo(age=30) ) handler = mock.Mock() instance.observe(handler, "extended_age") self.assertFalse(instance.sample_info_default_computed) self.assertEqual(instance.sample_info.age, 30) self.assertEqual(instance.extended_age, 30) # not called because 'sample_info' is still the "default" value. self.assertEqual(handler.call_count, 0) # when instance.sample_info.age = 40 # then self.assertEqual(handler.call_count, 1) # sanity check this is consistent with when property is not defined. instance_no_property = ClassWithInstanceDefaultInit( info_without_default=PersonInfo(age=30) ) self.assertFalse(instance_no_property.sample_info_default_computed) self.assertEqual(instance_no_property.sample_info.age, 30) def test_property_decorated_observer(self): instance_observe = ClassWithPropertyObservesDecorated(age=30) instance_depends_on = ClassWithPropertyDependsOnDecorated(age=30) for instance in [instance_observe, instance_depends_on]: with self.subTest(instance=instance): self.assertEqual(len(instance.discounted_events), 1) def test_garbage_collectable(self): instance = ClassWithPropertyObservesDefault() instance_ref = weakref.ref(instance) del instance self.assertIsNone(instance_ref()) def test_property_with_no_getter(self): instance = ClassWithPropertyMissingGetter() try: instance.age += 1 except Exception: self.fail( "Having property with undefined getter/setter should not " "prevent the observed traits from being changed." ) def test_property_with_missing_dependent(self): # This will prevent incidents like the one in enthought/traits#447 instance = ClassWithPropertyTraitNotFound() with self.assertRaises(ValueError) as exception_context: instance.person = PersonInfo() self.assertIn( "Trait named 'last_name' not found", str(exception_context.exception), ) def test_pickle_has_traits_with_property_observe(self): instance = ClassWithPropertyMultipleObserves() for protocol in range(pickle.HIGHEST_PROTOCOL + 1): serialized = pickle.dumps(instance, protocol=protocol) deserialized = pickle.loads(serialized) handler = mock.Mock() deserialized.observe(handler, "computed_value") deserialized.age = 1 self.assertEqual(handler.call_count, 1) def get_otc_handler(mock_obj): """ Return a callable to be used with on_trait_change, which will inspect call signature. Parameters ---------- mock_obj : mock.Mock Mock object for tracking calls. """ def handler(): mock_obj() return handler traits-6.3.2/traits/tests/test_python_properties.py000066400000000000000000000026671414270267200227260ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for regular Python properties in a HasTraits subclass. """ import unittest from traits.api import HasTraits class Model(HasTraits): def __init__(self): super().__init__() self._value = 0 @property def read_only(self): return 1729 @property def value(self): return self._value @value.setter def value(self, new): self._value = new class TestPythonProperty(unittest.TestCase): def test_read_only_property(self): model = Model() self.assertEqual(model.read_only, 1729) with self.assertRaises(AttributeError): model.read_only = 2034 with self.assertRaises(AttributeError): del model.read_only def test_read_write_property(self): model = Model() self.assertEqual(model.value, 0) model.value = 23 self.assertEqual(model.value, 23) model.value = 77 self.assertEqual(model.value, 77) with self.assertRaises(AttributeError): del model.value traits-6.3.2/traits/tests/test_range.py000066400000000000000000000071451414270267200202210ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import HasTraits, Int, List, Range, Str, TraitError, Tuple class WithFloatRange(HasTraits): r = Range(0.0, 100.0) r_copied_on_change = Str _changed_handler_calls = Int def _r_changed(self, old, new): self._changed_handler_calls += 1 self.r_copied_on_change = str(self.r) if (self.r % 10) > 0: self.r += 10 - (self.r % 10) class WithLargeIntRange(HasTraits): r = Range(0, 1000) r_copied_on_change = Str _changed_handler_calls = Int def _r_changed(self, old, new): self._changed_handler_calls += 1 self.r_copied_on_change = str(self.r) if self.r > 100: self.r = 0 class WithDynamicRange(HasTraits): low = Int(0) high = Int(10) value = Int(3) r = Range(value="value", low="low", high="high", exclude_high=True) def _r_changed(self, old, new): self._changed_handler_calls += 1 class RangeTestCase(unittest.TestCase): def test_non_ui_events(self): obj = WithFloatRange() obj._changed_handler_calls = 0 obj.r = 10 self.assertEqual(1, obj._changed_handler_calls) obj._changed_handler_calls = 0 obj.r = 34.56 self.assertEqual(obj._changed_handler_calls, 2) self.assertEqual(obj.r, 40) def test_non_ui_int_events(self): # Even though the range is configured for 0..1000, the handler resets # the value to 0 when it exceeds 100. obj = WithLargeIntRange() obj._changed_handler_calls = 0 obj.r = 10 self.assertEqual(obj._changed_handler_calls, 1) self.assertEqual(obj.r, 10) obj.r = 100 self.assertEqual(obj._changed_handler_calls, 2) self.assertEqual(obj.r, 100) obj.r = 101 self.assertEqual(obj._changed_handler_calls, 4) self.assertEqual(obj.r, 0) def test_dynamic_events(self): obj = WithDynamicRange() obj._changed_handler_calls = 0 obj.r = 5 self.assertEqual(obj._changed_handler_calls, 1) self.assertEqual(obj.r, 5) with self.assertRaises(TraitError): obj.r = obj.high self.assertEqual(obj.r, 5) def test_dynamic_range_in_tuple(self): # Regression test for #1391 class HasRangeInTuple(HasTraits): low = Int() high = Int() hours_and_name = Tuple(Range(low="low", high="high"), Str) model = HasRangeInTuple(low=0, high=48) model.hours_and_name = (40, "fred") self.assertEqual(model.hours_and_name, (40, "fred")) with self.assertRaises(TraitError): # First argument out or range; should raise. model.hours_and_name = (50, "george") def test_dynamic_range_in_list(self): # Another regression test for #1391. class HasRangeInList(HasTraits): #: Valid digit range low = Int() high = Int() #: Sequence of digits digit_sequence = List(Range(low="low", high="high")) model = HasRangeInList(low=-1, high=1) model.digit_sequence = [-1, 0, 1, 1] with self.assertRaises(TraitError): model.digit_sequence = [-1, 0, 2, 1] traits-6.3.2/traits/tests/test_readonly.py000066400000000000000000000022451414270267200207360ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the ReadOnly trait type. """ import unittest from traits.api import ( HasTraits, ReadOnly, TraitError, ) class ObjectWithReadOnlyText(HasTraits): """ A dummy object that set the readonly trait in __init__ There exists such usage in TraitsUI. """ text = ReadOnly() def __init__(self, text, **traits): self.text = text super(ObjectWithReadOnlyText, self).__init__(**traits) class TestReadOnlyTrait(unittest.TestCase): """ Test ReadOnly TraitType. """ def test_set_readonly_trait_in_init(self): obj = ObjectWithReadOnlyText(text="ABC") self.assertEqual(obj.text, "ABC") with self.assertRaises(TraitError): obj.text = "XYZ" self.assertEqual(obj.text, "ABC") traits-6.3.2/traits/tests/test_regression.py000066400000000000000000000320571414270267200213050ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ General regression tests for a variety of bugs. """ import gc import sys import unittest from traits.constants import DefaultValue from traits.has_traits import ( HasStrictTraits, HasTraits, Property, on_trait_change, ) from traits.testing.optional_dependencies import numpy, requires_numpy from traits.trait_errors import TraitError from traits.trait_type import TraitType from traits.trait_types import ( Bool, DelegatesTo, Dict, Either, Instance, Int, List, Set, Str, Union, ) if numpy is not None: from traits.trait_numeric import Array class Dummy(HasTraits): x = Int(10) def _create_subclass(): class Subclass(HasTraits): pass return Subclass class Dummy2(HasTraits): y = Int(20) dummy = Instance(Dummy) class DelegateMess(HasTraits): dummy1 = Instance(Dummy, args=()) dummy2 = Instance(Dummy2) y = DelegatesTo("dummy2") handler_called = Bool(False) def _dummy2_default(self): # Create `self.dummy1` return Dummy2(dummy=self.dummy1) @on_trait_change("dummy1.x") def _on_dummy1_x(self): self.handler_called = True def _init_trait_listeners(self): """ Force the DelegatesTo listener to hook up first to exercise the worst case. """ for name in ["y", "_on_dummy1_x"]: data = self.__class__.__listener_traits__[name] getattr(self, "_init_trait_%s_listener" % data[0])(name, *data) class DelegateLeak(HasTraits): visible = Property(Bool, depends_on="can_enable") can_enable = DelegatesTo("flag", prefix="x") flag = Instance(Dummy, kw={"x": 42}) class Presenter(HasTraits): obj = Instance(Dummy) y = Property(Int(), depends_on="obj.x") def _get_y(self): return self.obj.x class ListUpdatesTest(HasTraits): a = List b = List events_received = Int(0) @on_trait_change("a[], b[]") def _receive_events(self): self.events_received += 1 class SimpleProperty(HasTraits): x = Int y = Property(Int, depends_on="x") def _get_y(self): return self.x + 1 class ExtendedListenerInList(HasTraits): # Used in regression test for enthought/traits#403. dummy = Instance(Dummy) changed = Bool(False) @on_trait_change(["dummy:x"]) def set_changed(self): self.changed = True class RaisingValidator(TraitType): """ Trait type whose ``validate`` method raises an inappropriate exception. Used for testing propagation of that exception. """ info_text = "bogus" #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait: default_value = None def validate(self, object, name, value): raise ZeroDivisionError("Just testing") class TestRegression(unittest.TestCase): def test_default_value_for_no_cache(self): """ Make sure that CTrait.default_value_for() does not cache the result. """ dummy = Dummy() # Nothing in the __dict__ yet. self.assertEqual(dummy.__dict__, {}) ctrait = dummy.trait("x") default = ctrait.default_value_for(dummy, "x") self.assertEqual(default, 10) self.assertEqual(dummy.__dict__, {}) def test_default_value_for_property(self): """ Don't segfault when calling default_value_for on a Property trait. """ # Regression test for enthought/traits#336. y_trait = SimpleProperty.class_traits()["y"] simple_property = SimpleProperty() self.assertIsNone(y_trait.default_value_for(simple_property, "y")) def test_subclasses_weakref(self): """ Make sure that dynamically created subclasses are not held strongly by HasTraits. """ previous_subclasses = HasTraits.__subclasses__() _create_subclass() _create_subclass() _create_subclass() _create_subclass() gc.collect() # In Python < 3.6, we can end up seeing the same subclasses but in # a different order, so use assertCountEqual rather than assertEqual. # Ref: enthought/traits#1282. self.assertCountEqual(previous_subclasses, HasTraits.__subclasses__()) def test_leaked_property_tuple(self): """ the property ctrait constructor shouldn't leak a tuple. """ class A(HasTraits): prop = Property() a = A() self.assertEqual(sys.getrefcount(a.trait("prop").property_fields), 1) def test_delegate_initializer(self): mess = DelegateMess() self.assertFalse(mess.handler_called) mess.dummy1.x = 20 self.assertTrue(mess.handler_called) def test_no_leaking_notifiers(self): """ Extended trait change notifications should not leaf TraitChangeNotifyWrappers. """ dummy = Dummy() ctrait = dummy._trait("x", 2) self.assertEqual(len(ctrait._notifiers(True)), 0) presenter = Presenter(obj=dummy) self.assertEqual(len(ctrait._notifiers(True)), 1) del presenter self.assertEqual(len(ctrait._notifiers(True)), 0) def test_init_list_depends(self): """ Using two lists with bracket notation in extended name notation should not raise an error. """ list_test = ListUpdatesTest() # Updates to list items and the list trait itself should be counted. list_test.a.append(0) list_test.b = [1, 2, 3] list_test.b[0] = 0 self.assertEqual(list_test.events_received, 3) def test_has_traits_notifiers_refleak(self): # Regression test for issue described in # https://github.com/enthought/traits/pull/248 warmup = 5 cycles = 10 counts = [] def handler(): pass def f(): obj = HasTraits() obj.on_trait_change(handler) # Warmup. for _ in range(cycles): f() gc.collect() counts.append(len(gc.get_objects())) # All the counts beyond the warmup period should be the same. self.assertEqual(counts[warmup:-1], counts[warmup + 1:]) def test_delegation_refleak(self): warmup = 5 cycles = 10 counts = [] for _ in range(cycles): DelegateLeak() gc.collect() counts.append(len(gc.get_objects())) # All the counts should be the same. self.assertEqual(counts[warmup:-1], counts[warmup + 1:]) @requires_numpy def test_exception_from_numpy_comparison_ignored(self): # Regression test for enthought/traits#376. class MultiArrayDataSource(HasTraits): data = Either(None, Array) b = MultiArrayDataSource(data=numpy.array([1, 2])) # noqa: F841 # The following line was necessary to trigger the bug: the previous # line set a Python exception, but didn't return the correct result to # the CPython interpreter, so the exception wasn't triggered until # later. round(3.14159, 2) def test_on_trait_change_with_list_of_extended_names(self): # Regression test for enthought/traits#403 dummy = Dummy(x=10) model = ExtendedListenerInList(dummy=dummy) self.assertFalse(model.changed) dummy.x = 11 self.assertTrue(model.changed) def test_set_disallowed_exception(self): # Regression test for enthought/traits#415 class StrictDummy(HasStrictTraits): foo = Int with self.assertRaises(TraitError): StrictDummy(forbidden=53) # This is the case that used to fail on Python 2. with self.assertRaises(TraitError): StrictDummy(**{"forbidden": 53}) a = StrictDummy() with self.assertRaises(TraitError): setattr(a, "forbidden", 53) def test_validate_exception_propagates(self): class A(HasTraits): foo = RaisingValidator() bar = Either(None, RaisingValidator()) a = A() with self.assertRaises(ZeroDivisionError): a.foo = "foo" with self.assertRaises(ZeroDivisionError): a.bar = "foo" class NestedContainerClass(HasTraits): # Used in regression test for changes to nested containers # Nested list list_of_list = List(List) # enthought/traits#281 dict_of_list = Dict(Str, List(Str)) # Similar to enthought/traits#281 dict_of_union_none_or_list = Dict(Str, Union(List(), None)) # Nested dict # enthought/traits#25 list_of_dict = List(Dict) dict_of_dict = Dict(Str, Dict) dict_of_union_none_or_dict = Dict(Str, Union(Dict(), None)) # Nested set list_of_set = List(Set) dict_of_set = Dict(Str, Set) dict_of_union_none_or_set = Dict(Str, Union(Set(), None)) class TestRegressionNestedContainerEvent(unittest.TestCase): """ Regression tests for enthought/traits#281 and enthought/traits#25 """ def setUp(self): self.events = [] def change_handler(*args): self.events.append(args) self.change_handler = change_handler def test_modify_list_in_dict(self): # Regression test for enthought/traits#281 instance = NestedContainerClass(dict_of_list={"name": []}) try: instance.dict_of_list["name"].append("word") except Exception: self.fail("Mutating a nested list should not fail.") def test_modify_list_in_dict_wrapped_in_union(self): instance = NestedContainerClass( dict_of_union_none_or_list={"name": []}, ) try: instance.dict_of_union_none_or_list["name"].append("word") except Exception: self.fail("Mutating a nested list should not fail.") def test_modify_list_in_list_no_events(self): instance = NestedContainerClass(list_of_list=[[]]) instance.on_trait_change(self.change_handler, "list_of_list_items") instance.list_of_list[0].append(1) self.assertEqual(len(self.events), 0, "Expected no events.") def test_modify_dict_in_list(self): instance = NestedContainerClass(list_of_dict=[{}]) try: instance.list_of_dict[0]["key"] = 1 except Exception: self.fail("Mutating a nested dict should not fail.") def test_modify_dict_in_list_with_new_value(self): instance = NestedContainerClass(list_of_dict=[{}]) instance.list_of_dict.append(dict()) try: instance.list_of_dict[-1]["key"] = 1 except Exception: self.fail("Mutating a nested dict should not fail.") def test_modify_dict_in_dict_no_events(self): # Related to enthought/traits#25 instance = NestedContainerClass(dict_of_dict={"1": {"2": 2}}) instance.on_trait_change(self.change_handler, "dict_of_dict_items") instance.dict_of_dict["1"]["3"] = 3 self.assertEqual(len(self.events), 0, "Expected no events.") def test_modify_dict_in_union_in_dict_no_events(self): instance = NestedContainerClass( dict_of_union_none_or_dict={"1": {"2": 2}}, ) instance.on_trait_change( self.change_handler, "dict_of_union_none_or_dict_items") instance.dict_of_union_none_or_dict["1"]["3"] = 3 self.assertEqual(len(self.events), 0, "Expected no events.") def test_modify_set_in_list(self): instance = NestedContainerClass(list_of_set=[set()]) try: instance.list_of_set[0].add(1) except Exception: self.fail("Mutating a nested set should not fail.") def test_modify_set_in_list_with_new_value(self): instance = NestedContainerClass(list_of_set=[]) instance.list_of_set.append(set()) try: instance.list_of_set[0].add(1) except Exception: self.fail("Mutating a nested set should not fail.") def test_modify_set_in_dict(self): instance = NestedContainerClass(dict_of_set={"1": set()}) try: instance.dict_of_set["1"].add(1) except Exception: self.fail("Mutating a nested set should not fail.") def test_modify_set_in_union_in_dict(self): instance = NestedContainerClass( dict_of_union_none_or_set={"1": set()} ) try: instance.dict_of_union_none_or_set["1"].add(1) except Exception: self.fail("Mutating a nested set should not fail.") def test_modify_nested_set_no_events(self): instance = NestedContainerClass(list_of_set=[set()]) instance.on_trait_change( self.change_handler, "list_of_set_items") instance.list_of_set[0].add(1) self.assertEqual(len(self.events), 0, "Expected no events.") traits-6.3.2/traits/tests/test_rich_compare.py000066400000000000000000000206371414270267200215610ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest import warnings from traits.api import ( Any, cached_property, ComparisonMode, HasTraits, Property, Str, ) class IdentityCompare(HasTraits): bar = Any(comparison_mode=ComparisonMode.identity) class RichCompare(HasTraits): bar = Any(comparison_mode=ComparisonMode.equality) class RichCompareTests: def bar_changed(self, object, trait, old, new): self.changed_object = object self.changed_trait = trait self.changed_old = old self.changed_new = new self.changed_count += 1 def reset_change_tracker(self): self.changed_object = None self.changed_trait = None self.changed_old = None self.changed_new = None self.changed_count = 0 def check_tracker(self, object, trait, old, new, count): self.assertEqual(count, self.changed_count) self.assertIs(object, self.changed_object) self.assertEqual(trait, self.changed_trait) self.assertIs(old, self.changed_old) self.assertIs(new, self.changed_new) def test_id_first_assignment(self): ic = IdentityCompare() ic.on_trait_change(self.bar_changed, "bar") self.reset_change_tracker() default_value = ic.bar ic.bar = self.a self.check_tracker(ic, "bar", default_value, self.a, 1) def test_rich_first_assignment(self): rich = RichCompare() rich.on_trait_change(self.bar_changed, "bar") self.reset_change_tracker() default_value = rich.bar rich.bar = self.a self.check_tracker(rich, "bar", default_value, self.a, 1) def test_id_same_object(self): ic = IdentityCompare() ic.on_trait_change(self.bar_changed, "bar") self.reset_change_tracker() default_value = ic.bar ic.bar = self.a self.check_tracker(ic, "bar", default_value, self.a, 1) ic.bar = self.a self.check_tracker(ic, "bar", default_value, self.a, 1) def test_rich_same_object(self): rich = RichCompare() rich.on_trait_change(self.bar_changed, "bar") self.reset_change_tracker() default_value = rich.bar rich.bar = self.a self.check_tracker(rich, "bar", default_value, self.a, 1) rich.bar = self.a self.check_tracker(rich, "bar", default_value, self.a, 1) def test_id_different_object(self): ic = IdentityCompare() ic.on_trait_change(self.bar_changed, "bar") self.reset_change_tracker() default_value = ic.bar ic.bar = self.a self.check_tracker(ic, "bar", default_value, self.a, 1) ic.bar = self.different_from_a self.check_tracker(ic, "bar", self.a, self.different_from_a, 2) def test_rich_different_object(self): rich = RichCompare() rich.on_trait_change(self.bar_changed, "bar") self.reset_change_tracker() default_value = rich.bar rich.bar = self.a self.check_tracker(rich, "bar", default_value, self.a, 1) rich.bar = self.different_from_a self.check_tracker(rich, "bar", self.a, self.different_from_a, 2) def test_id_different_object_same_as(self): ic = IdentityCompare() ic.on_trait_change(self.bar_changed, "bar") self.reset_change_tracker() default_value = ic.bar ic.bar = self.a self.check_tracker(ic, "bar", default_value, self.a, 1) ic.bar = self.same_as_a self.check_tracker(ic, "bar", self.a, self.same_as_a, 2) def test_rich_different_object_same_as(self): rich = RichCompare() rich.on_trait_change(self.bar_changed, "bar") self.reset_change_tracker() default_value = rich.bar rich.bar = self.a self.check_tracker(rich, "bar", default_value, self.a, 1) # Values of a and same_as_a are the same and should therefore not # be considered a change. rich.bar = self.same_as_a self.check_tracker(rich, "bar", default_value, self.a, 1) class Foo(HasTraits): name = Str def __ne__(self, other): # Traits uses != to do the rich compare. The default implementation # of __ne__ is to compare the object identities. return self.name != other.name def __eq__(self, other): # Not required, but a good idea to make __eq__ and __ne__ compatible return self.name == other.name class RichCompareHasTraitsTestCase(unittest.TestCase, RichCompareTests): def setUp(self): self.a = Foo(name="a") self.same_as_a = Foo(name="a") self.different_from_a = Foo(name="not a") def test_assumptions(self): self.assertIsNot(self.a, self.same_as_a) self.assertIsNot(self.a, self.different_from_a) self.assertEqual(self.a.name, self.same_as_a.name) self.assertNotEqual(self.a.name, self.different_from_a.name) class OldRichCompareTestCase(unittest.TestCase): def test_rich_compare_false(self): with warnings.catch_warnings(record=True) as warn_msgs: warnings.simplefilter("always", DeprecationWarning) class OldRichCompare(HasTraits): bar = Any(rich_compare=False) # Check for a DeprecationWarning. self.assertEqual(len(warn_msgs), 1) warn_msg = warn_msgs[0] self.assertIs(warn_msg.category, DeprecationWarning) self.assertIn( "'rich_compare' metadata has been deprecated", str(warn_msg.message) ) _, _, this_module = __name__.rpartition(".") self.assertIn(this_module, warn_msg.filename) # Behaviour matches comparison_mode=ComparisonMode.identity. old_compare = OldRichCompare() events = [] old_compare.on_trait_change(lambda: events.append(None), "bar") some_list = [1, 2, 3] self.assertEqual(len(events), 0) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = [1, 2, 3] self.assertEqual(len(events), 2) old_compare.bar = [4, 5, 6] self.assertEqual(len(events), 3) def test_rich_compare_true(self): with warnings.catch_warnings(record=True) as warn_msgs: warnings.simplefilter("always", DeprecationWarning) class OldRichCompare(HasTraits): bar = Any(rich_compare=True) # Check for a DeprecationWarning. self.assertEqual(len(warn_msgs), 1) warn_msg = warn_msgs[0] self.assertIs(warn_msg.category, DeprecationWarning) self.assertIn( "'rich_compare' metadata has been deprecated", str(warn_msg.message) ) _, _, this_module = __name__.rpartition(".") self.assertIn(this_module, warn_msg.filename) # Behaviour matches comparison_mode=ComparisonMode.identity. old_compare = OldRichCompare() events = [] old_compare.on_trait_change(lambda: events.append(None), "bar") some_list = [1, 2, 3] self.assertEqual(len(events), 0) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = [1, 2, 3] self.assertEqual(len(events), 1) old_compare.bar = [4, 5, 6] self.assertEqual(len(events), 2) def test_rich_compare_with_cached_property(self): # Even though the property is cached such that old value equals new # value, its change event is tied to the dependent. class Model(HasTraits): value = Property(depends_on="name") name = Str(comparison_mode=ComparisonMode.none) @cached_property def _get_value(self): return self.trait_names instance = Model() events = [] instance.on_trait_change(lambda: events.append(None), "value") instance.name = "A" events.clear() # when instance.name = "A" # then self.assertEqual(len(events), 1) traits-6.3.2/traits/tests/test_special_event_handlers.py000066400000000000000000000023621414270267200236220ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import Any, HasStrictTraits, Str class TestSpecialEvent(unittest.TestCase): """ Test demonstrating special change events using the 'event' metadata. """ def setUp(self): self.change_events = [] self.foo = Foo(test=self) def test_events(self): self.foo.val = "CHANGE" values = ["CHANGE"] self.assertEqual(self.change_events, values) def test_instance_events(self): foo = self.foo foo.add_trait("val2", Str(event="the_trait")) foo.val2 = "CHANGE2" values = ["CHANGE2"] self.assertEqual(self.change_events, values) class Foo(HasStrictTraits): val = Str(event="the_trait") test = Any(None) def _the_trait_changed(self, new): if self.test is not None: self.test.change_events.append(new) traits-6.3.2/traits/tests/test_static_notifiers.py000066400000000000000000000075151414270267200224770ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the static notifiers. """ import unittest from traits import trait_notifiers from traits.api import Float, HasTraits, List calls_0 = [] class StaticNotifiers0(HasTraits): ok = Float def _ok_changed(): calls_0.append(True) fail = Float def _fail_changed(): raise Exception("error") class StaticNotifiers1(HasTraits): ok = Float def _ok_changed(self): if not hasattr(self, "calls"): self.calls = [] self.calls.append(True) fail = Float def _fail_changed(self): raise Exception("error") class StaticNotifiers2(HasTraits): ok = Float def _ok_changed(self, new): if not hasattr(self, "calls"): self.calls = [] self.calls.append(new) fail = Float def _fail_changed(self, new): raise Exception("error") class StaticNotifiers3(HasTraits): ok = Float def _ok_changed(self, old, new): if not hasattr(self, "calls"): self.calls = [] self.calls.append((old, new)) fail = Float def _fail_changed(self, old, new): raise Exception("error") class StaticNotifiers4(HasTraits): ok = Float def _ok_changed(self, name, old, new): if not hasattr(self, "calls"): self.calls = [] self.calls.append((name, old, new)) fail = Float def _fail_changed(self, name, old, new): raise Exception("error") class _LeadingUnderscore(HasTraits): _ok = Float() calls = List() def __ok_changed(self, name, old, new): self.calls.append((name, old, new)) class TestNotifiers(unittest.TestCase): """ Tests for the static notifiers, and the "anytrait" static notifiers. """ def setUp(self): self.exceptions = [] trait_notifiers.push_exception_handler(self._handle_exception) def tearDown(self): trait_notifiers.pop_exception_handler() def _handle_exception(self, obj, name, old, new): self.exceptions.append((obj, name, old, new)) def test_static_notifiers_0(self): calls_0.clear() obj = StaticNotifiers0(ok=2) obj.ok = 3 self.assertEqual(len(calls_0), 2) obj.fail = 1 self.assertEqual(self.exceptions, [(obj, "fail", 0, 1)]) def test_static_notifiers_1(self): obj = StaticNotifiers1(ok=2) obj.ok = 3 self.assertEqual(len(obj.calls), 2) obj.fail = 1 self.assertEqual(self.exceptions, [(obj, "fail", 0, 1)]) def test_static_notifiers_2(self): obj = StaticNotifiers2(ok=2) obj.ok = 3 self.assertEqual(obj.calls, [2, 3]) obj.fail = 1 self.assertEqual(self.exceptions, [(obj, "fail", 0, 1)]) def test_static_notifiers_3(self): obj = StaticNotifiers3(ok=2) obj.ok = 3 self.assertEqual(obj.calls, [(0, 2), (2, 3)]) obj.fail = 1 self.assertEqual(self.exceptions, [(obj, "fail", 0, 1)]) def test_static_notifiers_4(self): obj = StaticNotifiers4(ok=2) obj.ok = 3 self.assertEqual(obj.calls, [("ok", 0, 2), ("ok", 2, 3)]) obj.fail = 1 self.assertEqual(self.exceptions, [(obj, "fail", 0, 1)]) def test_leading_underscore(self): """ Test the name-mangling for the double-underscored change handlers. """ obj = _LeadingUnderscore(_ok=2.0) obj._ok = 3.0 self.assertEqual(obj.calls, [("_ok", 0.0, 2.0), ("_ok", 2.0, 3.0)]) traits-6.3.2/traits/tests/test_str_handler.py000066400000000000000000000035001414270267200214210ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import HasTraits, Trait, TraitError, TraitHandler from traits.trait_base import strx # Validation via function def validator(object, name, value): if isinstance(value, str): # arbitrary rule for testing if value.find("fail") < 0: return value else: raise TraitError else: raise TraitError # Validation via Handler class MyHandler(TraitHandler): def validate(self, object, name, value): try: value = strx(value) if value.find("fail") < 0: return value except: pass self.error(object, name, value) def info(self): msg = "a string not containing the character sequence 'fail'" return msg class Foo(HasTraits): s = Trait("", validator) class Bar(HasTraits): s = Trait("", MyHandler()) class StrHandlerCase(unittest.TestCase): def test_validator_function(self): f = Foo() self.assertEqual(f.s, "") f.s = "ok" self.assertEqual(f.s, "ok") self.assertRaises(TraitError, setattr, f, "s", "should fail.") self.assertEqual(f.s, "ok") def test_validator_handler(self): b = Bar() self.assertEqual(b.s, "") b.s = "ok" self.assertEqual(b.s, "ok") self.assertRaises(TraitError, setattr, b, "s", "should fail.") self.assertEqual(b.s, "ok") traits-6.3.2/traits/tests/test_string.py000066400000000000000000000016321414270267200204260ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the String trait type. """ import unittest from traits.api import HasTraits, String from traits.testing.optional_dependencies import numpy, requires_numpy class A(HasTraits): string = String class TestString(unittest.TestCase): @requires_numpy def test_accepts_numpy_string(self): numpy_string = numpy.str_("this is a numpy string!") a = A() a.string = numpy_string self.assertEqual(a.string, numpy_string) self.assertIs(type(a.string), str) traits-6.3.2/traits/tests/test_sync_traits.py000066400000000000000000000116731414270267200214700ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test that the `sync_trait` member function of `HasTraits` instances functions correctly. """ import unittest from traits.api import ( HasTraits, Int, List, push_exception_handler, pop_exception_handler, ) from traits.testing.unittest_tools import UnittestTools class A(HasTraits): t = Int l = List(Int) class B(HasTraits): t = Int u = Int l = List(Int) class TestSyncTraits(unittest.TestCase, UnittestTools): def setUp(self): push_exception_handler(lambda *args: None, reraise_exceptions=True) def tearDown(self): pop_exception_handler() def test_mutual_sync(self): """ Test that two traits can be mutually synchronized. """ a = A() b = B() a.sync_trait("t", b) b.t = 10 self.assertEqual(a.t, b.t) a.t = 20 self.assertEqual(b.t, a.t) # Check that we can remove the synchronization a.sync_trait("t", b, remove=True) with self.assertTraitDoesNotChange(a, "t"): b.t = 5 with self.assertTraitDoesNotChange(b, "t"): a.t = 7 def test_sync_alias(self): """ Test synchronization of a trait with an aliased trait. """ a = A() b = B() a.sync_trait("t", b, "u") with self.assertTraitDoesNotChange(b, "t"): a.t = 5 self.assertEqual(a.t, b.u) b.u = 7 self.assertEqual(a.t, b.u) def test_one_way_sync(self): """ Test one-way synchronization of two traits. """ a = A(t=3) b = B(t=4) a.sync_trait("t", b, mutual=False) self.assertEqual(b.t, 3) a.t = 5 self.assertEqual(b.t, a.t) with self.assertTraitDoesNotChange(a, "t"): b.t = 7 # Remove synchronization a.sync_trait("t", b, remove=True) with self.assertTraitDoesNotChange(b, "t"): a.t = 12 def test_sync_lists(self): """ Test synchronization of list traits. """ a = A() b = B() a.sync_trait("l", b) # Change entire list. a.l = [1, 2, 3] self.assertEqual(a.l, b.l) b.l = [4, 5] self.assertEqual(a.l, b.l) # Change list items. a.l = [7, 8, 9] with self.assertTraitChanges(b, "l_items"): a.l[-1] = 20 self.assertEqual(b.l, [7, 8, 20]) # Remove synchronization a.sync_trait("l", b, remove=True) with self.assertTraitDoesNotChange(a, "l"): b.l = [7, 8] def test_sync_lists_partial_slice(self): """ Test synchronization of list traits when there is a partial slice. Regression test for enthought/traits#540 """ a = A() b = B() a.sync_trait("l", b) # Change entire list. a.l = [1, 2, 3] self.assertEqual(a.l, b.l) b.l = [4, 5] self.assertEqual(a.l, b.l) # Change list items with an empty slice. with self.assertTraitChanges(b, "l_items"): a.l[:] = [7] self.assertEqual(b.l, [7]) # Change list items with a partial slice. with self.assertTraitChanges(b, "l_items"): a.l[:0] = [6] self.assertEqual(b.l, [6, 7]) def test_sync_delete(self): """ Test that deleting a synchronized trait works. """ a = A() b = B() a.sync_trait("t", b) a.t = 5 del a try: # Updating `b.t` should not raise an exception due to remaining # listeners. b.t = 7 except Exception: self.fail("Unexpected exception while setting sync trait.") def test_sync_delete_one_way(self): """ Test that deleting a one-way synchronized trait works. (Regression test for #131). """ a = A() b = B() a.sync_trait("t", b, mutual=False) del b try: a.t = 42 except Exception: self.fail("Unexpected exception while setting sync trait.") def test_sync_ref_cycle(self): """ Regression test for #69. """ a = A() b = B() change_counter = [0] def _handle_change(): change_counter[0] += 1 b.on_trait_change(_handle_change, "t") a.sync_trait("t", b) a.t = 17 self.assertEqual(change_counter, [1]) # Delete b and check that no more changes to b.t are recorded. del b a.t = 42 self.assertEqual(change_counter, [1]) traits-6.3.2/traits/tests/test_target.py000066400000000000000000000040051414270267200204030ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test whether HasTraits objects with cycles can be garbage collected. """ # Standard library imports import unittest # Enthought library imports from traits.api import HasTraits, Instance, Int class TestCase(unittest.TestCase): """ Tests the 'target' argument for on_traits_change. """ def test_simple(self): """ Tests a simple dynamic trait change handler. """ class Test(HasTraits): i = Int # Create objects obj = Test() target = HasTraits() # Set up to count changes in i self.count = 0 def count_notifies(): self.count += 1 obj.on_trait_change(count_notifies, "i", target=target) # Change the trait obj.i = 10 # Delete the target and change it again del target obj.i = 0 # The count should be 1 self.assertEqual(self.count, 1) def test_extended(self): """ Tests a dynamic trait change handler using extended names. """ class Child(HasTraits): i = Int class Parent(HasTraits): child = Instance(Child) # Create objects parent = Parent(child=Child()) target = HasTraits() # Set up to count changes in i self.count = 0 def count_notifies(): self.count += 1 parent.on_trait_change(count_notifies, "child:i", target=target) # Change the trait parent.child.i = 10 # Delete the target and change it again del target parent.child.i = 0 # The count should be 1 self.assertEqual(self.count, 1) traits-6.3.2/traits/tests/test_time.py000066400000000000000000000070051414270267200200560ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the Time trait type. """ import datetime import unittest from traits.testing.optional_dependencies import requires_traitsui, traitsui from traits.api import HasStrictTraits, Time, TraitError #: Unix epoch UNIX_EPOCH = datetime.time(12, 30) #: Windows NT epoch NT_EPOCH = datetime.time(18, 30) class HasTimeTraits(HasStrictTraits): #: Simple case - no default, no parameters, no metadata simple_time = Time() #: Time with default epoch = Time(UNIX_EPOCH) #: Time with default provided via keyword. alternative_epoch = Time(default_value=NT_EPOCH) #: None prohibited none_prohibited = Time(allow_none=False) #: None allowed none_allowed = Time(allow_none=True) class TestTime(unittest.TestCase): def test_default(self): obj = HasTimeTraits() self.assertEqual(obj.simple_time, None) self.assertEqual(obj.epoch, UNIX_EPOCH) self.assertEqual(obj.alternative_epoch, NT_EPOCH) def test_assign_time(self): # By default, datetime instances are permitted. test_time = datetime.time(6, 3, 35) obj = HasTimeTraits() obj.simple_time = test_time self.assertEqual(obj.simple_time, test_time) def test_assign_non_time(self): obj = HasTimeTraits() with self.assertRaises(TraitError) as exception_context: obj.simple_time = "12:00:00" message = str(exception_context.exception) self.assertIn("must be a time or None, but", message) def test_assign_datetime(self): obj = HasTimeTraits() with self.assertRaises(TraitError) as exception_context: obj.simple_time = datetime.datetime(1975, 2, 13) message = str(exception_context.exception) self.assertIn("must be a time or None, but", message) self.assertIsNone(obj.simple_time) def test_assign_none_with_allow_none_not_given(self): obj = HasTimeTraits(simple_time=UNIX_EPOCH) self.assertIsNotNone(obj.simple_time) with self.assertWarns(DeprecationWarning) as warnings_cm: obj.simple_time = None self.assertIsNone(obj.simple_time) _, _, this_module = __name__.rpartition(".") self.assertIn(this_module, warnings_cm.filename) self.assertIn( "None will no longer be accepted", str(warnings_cm.warning), ) def test_assign_none_with_allow_none_false(self): obj = HasTimeTraits(none_prohibited=UNIX_EPOCH) with self.assertRaises(TraitError) as exception_context: obj.none_prohibited = None message = str(exception_context.exception) self.assertIn("must be a time, but", message) def test_assign_none_with_allow_none_true(self): obj = HasTimeTraits(none_allowed=UNIX_EPOCH) self.assertIsNotNone(obj.none_allowed) obj.none_allowed = None self.assertIsNone(obj.none_allowed) @requires_traitsui def test_get_editor(self): obj = HasTimeTraits() trait = obj.base_trait("epoch") editor_factory = trait.get_editor() self.assertIsInstance(editor_factory, traitsui.api.TimeEditor) traits-6.3.2/traits/tests/test_trait_base.py000066400000000000000000000033661414270267200212430ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import collections import enum import unittest from traits.trait_base import safe_contains class Lights(enum.Enum): red = "red" blue = "blue" green = "green" class MoreLights(enum.Enum): amber = 1 aquamarine = 2 azure = 3 class RaisingContainer(collections.abc.Sequence): def __len__(self): return 15 def __getitem__(self, index): if not 0 <= index < 15: raise IndexError("Index out of range") return 1729 def __contains__(self, value): if value != 1729: raise TypeError("My contents are my own private business!") return True class TestTraitBase(unittest.TestCase): def test_safe_contains(self): self.assertFalse(safe_contains(1, Lights)) self.assertFalse(safe_contains(MoreLights.amber, Lights)) self.assertTrue(safe_contains(Lights.red, Lights)) lights_list = list(Lights) self.assertFalse(safe_contains(1, lights_list)) self.assertFalse(safe_contains(MoreLights.amber, lights_list)) self.assertTrue(safe_contains(Lights.red, lights_list)) unfriendly_container = RaisingContainer() self.assertFalse(safe_contains(1, unfriendly_container)) self.assertTrue(safe_contains(1729, unfriendly_container)) self.assertFalse(safe_contains(Lights.green, unfriendly_container)) traits-6.3.2/traits/tests/test_trait_change_event_tracer.py000066400000000000000000000125641414270267200243170ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the trait change event tracer. """ import unittest from traits import trait_notifiers from traits.api import Float, HasTraits, on_trait_change class FuzException(Exception): pass class Foo(HasTraits): """ Test traits class with static and dynamic listeners. Changing `baz` triggers a dynamic listeners that modifies `bar`, which triggers one dynamic and one static listeners. """ bar = Float baz = Float fuz = Float def _bar_changed(self): pass @on_trait_change("bar") def _on_bar_change_notification(self): pass @on_trait_change("baz") def _on_baz_change_notification(self): self.bar += 1 @on_trait_change("fuz") def _on_fuz_change_notification(self): self.bar += 1 raise FuzException("method") class TestChangeEventTracers(unittest.TestCase): #### 'TestCase' protocol ################################################## def setUp(self): self.pre_change_events = [] self.post_change_events = [] self.exceptions = [] trait_notifiers.push_exception_handler( lambda obj, name, old, new: None ) def tearDown(self): trait_notifiers.pop_exception_handler() #### Private protocol ##################################################### def _collect_pre_notification_events(self, *args): self.pre_change_events.append(args) def _collect_post_notification_events(self, *args, **kwargs): self.post_change_events.append(args) self.exceptions.extend(kwargs.values()) #### Tests ################################################################ def test_change_event_hooks(self): # Create the test object and a function listener. foo = Foo() def _on_foo_baz_changed(obj, name, old, new): pass foo.on_trait_change(_on_foo_baz_changed, "baz") # Set the event tracer and trigger a cascade of change events. pre_tracer = self._collect_pre_notification_events post_tracer = self._collect_post_notification_events with trait_notifiers.change_event_tracers(pre_tracer, post_tracer): foo.baz = 3 self.assertEqual(len(self.pre_change_events), 4) self.assertEqual(len(self.post_change_events), 4) expected_pre_events = [ (foo, "baz", 0.0, 3.0, foo._on_baz_change_notification), (foo, "bar", 0.0, 1.0, foo._bar_changed.__func__), (foo, "bar", 0.0, 1.0, foo._on_bar_change_notification), (foo, "baz", 0.0, 3.0, _on_foo_baz_changed), ] self.assertEqual(self.pre_change_events, expected_pre_events) expected_post_events = [ (foo, "bar", 0.0, 1.0, foo._bar_changed.__func__), (foo, "bar", 0.0, 1.0, foo._on_bar_change_notification), (foo, "baz", 0.0, 3.0, foo._on_baz_change_notification), (foo, "baz", 0.0, 3.0, _on_foo_baz_changed), ] self.assertEqual(self.post_change_events, expected_post_events) self.assertEqual(self.exceptions, [None] * 4) # Check that the tracers are no longer active. foo.baz = 23 self.assertEqual(len(self.pre_change_events), 4) self.assertEqual(len(self.post_change_events), 4) def test_change_event_hooks_after_exception(self): # Create the test object and a function listener. foo = Foo() def _on_foo_fuz_changed(obj, name, old, new): raise FuzException("function") foo.on_trait_change(_on_foo_fuz_changed, "fuz") # Set the event tracer and trigger a cascade of change events. pre_tracer = self._collect_pre_notification_events post_tracer = self._collect_post_notification_events with trait_notifiers.change_event_tracers(pre_tracer, post_tracer): foo.fuz = 3 self.assertEqual(len(self.pre_change_events), 4) self.assertEqual(len(self.post_change_events), 4) expected_pre_events = [ (foo, "fuz", 0.0, 3.0, foo._on_fuz_change_notification), (foo, "bar", 0.0, 1.0, foo._bar_changed.__func__), (foo, "bar", 0.0, 1.0, foo._on_bar_change_notification), (foo, "fuz", 0.0, 3.0, _on_foo_fuz_changed), ] self.assertEqual(self.pre_change_events, expected_pre_events) expected_post_events = [ (foo, "bar", 0.0, 1.0, foo._bar_changed.__func__), (foo, "bar", 0.0, 1.0, foo._on_bar_change_notification), (foo, "fuz", 0.0, 3.0, foo._on_fuz_change_notification), (foo, "fuz", 0.0, 3.0, _on_foo_fuz_changed), ] self.assertEqual(self.post_change_events, expected_post_events) self.assertEqual(self.exceptions[:2], [None, None]) self.assertIsInstance(self.exceptions[2], FuzException) self.assertEqual(self.exceptions[2].args, ("method",)) self.assertIsInstance(self.exceptions[3], FuzException) self.assertEqual(self.exceptions[3].args, ("function",)) traits-6.3.2/traits/tests/test_trait_converters.py000066400000000000000000000154021414270267200225150ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from contextlib import contextmanager import unittest from traits.ctrait import CTrait from traits.trait_converters import ( as_ctrait, check_trait, trait_cast, trait_for, trait_from, ) from traits.trait_factory import TraitFactory from traits.trait_handlers import TraitCastType, TraitInstance from traits.api import Any, Int @contextmanager def reset_trait_factory(): from traits import trait_factory old_tfi = trait_factory._trait_factory_instances.copy() try: yield finally: trait_factory._trait_factory_instances = old_tfi class TestTraitCast(unittest.TestCase): def test_trait_cast_ctrait(self): ct = Int().as_ctrait() result = trait_cast(ct) self.assertIs(result, ct) def test_trait_cast_trait_type_class(self): result = trait_cast(Int) self.assertIsInstance(result, CTrait) self.assertIsInstance(result.handler, Int) def test_trait_cast_trait_type_instance(self): trait = Int() result = trait_cast(trait) self.assertIsInstance(result, CTrait) self.assertIs(result.handler, trait) def test_trait_cast_trait_factory(self): int_trait_factory = TraitFactory(lambda: Int().as_ctrait()) with reset_trait_factory(): result = trait_cast(int_trait_factory) ct = int_trait_factory.as_ctrait() self.assertIsInstance(result, CTrait) self.assertIs(result, ct) def test_trait_cast_none(self): result = trait_cast(None) self.assertIsNone(result) def test_trait_cast_other(self): result = trait_cast(1) self.assertIsNone(result) class TestTraitFrom(unittest.TestCase): def test_trait_from_ctrait(self): ct = Int().as_ctrait() result = trait_from(ct) self.assertIs(result, ct) def test_trait_from_trait_type_class(self): result = trait_from(Int) self.assertIsInstance(result, CTrait) self.assertIsInstance(result.handler, Int) def test_trait_from_trait_type_instance(self): trait = Int() result = trait_from(trait) self.assertIsInstance(result, CTrait) self.assertIs(result.handler, trait) def test_trait_from_trait_factory(self): int_trait_factory = TraitFactory(lambda: Int().as_ctrait()) with reset_trait_factory(): result = trait_from(int_trait_factory) ct = int_trait_factory.as_ctrait() self.assertIsInstance(result, CTrait) self.assertIs(result, ct) def test_trait_from_none(self): result = trait_from(None) self.assertIsInstance(result, CTrait) self.assertIsInstance(result.handler, Any) def test_trait_from_other(self): result = trait_from(1) self.assertIsInstance(result, CTrait) self.assertIsInstance(result.handler, TraitCastType) self.assertEqual(result.handler.aType, int) class TestCheckTrait(unittest.TestCase): def test_check_trait_ctrait(self): ct = Int().as_ctrait() result = check_trait(ct) self.assertIs(result, ct) def test_check_trait_trait_type_class(self): result = check_trait(Int) self.assertIsInstance(result, CTrait) self.assertIsInstance(result.handler, Int) def test_check_trait_trait_type_instance(self): trait = Int() result = check_trait(trait) self.assertIsInstance(result, CTrait) self.assertIs(result.handler, trait) def test_check_trait_trait_factory(self): int_trait_factory = TraitFactory(lambda: Int().as_ctrait()) with reset_trait_factory(): result = check_trait(int_trait_factory) ct = int_trait_factory.as_ctrait() self.assertIsInstance(result, CTrait) self.assertIs(result, ct) def test_check_trait_none(self): result = check_trait(None) self.assertIsNone(result) def test_check_trait_other(self): result = check_trait(1) self.assertEqual(result, 1) class TestTraitFor(unittest.TestCase): def test_trait_for_ctrait(self): ct = Int().as_ctrait() result = trait_for(ct) self.assertIs(result, ct) def test_trait_for_trait_type_class(self): result = trait_for(Int) self.assertIsInstance(result, CTrait) self.assertIsInstance(result.handler, Int) def test_trait_for_trait_type_instance(self): trait = Int() result = trait_for(trait) self.assertIsInstance(result, CTrait) self.assertIs(result.handler, trait) def test_trait_for_trait_factory(self): int_trait_factory = TraitFactory(lambda: Int().as_ctrait()) with reset_trait_factory(): result = trait_for(int_trait_factory) ct = int_trait_factory.as_ctrait() self.assertIsInstance(result, CTrait) self.assertIs(result, ct) def test_trait_for_none(self): result = trait_for(None) self.assertIsInstance(result, CTrait) self.assertIsInstance(result.handler, TraitInstance) self.assertEqual(result.handler.aClass, type(None)) def test_trait_for_other(self): result = trait_for(1) self.assertIsInstance(result, CTrait) self.assertIsInstance(result.handler, TraitCastType) self.assertEqual(result.handler.aType, int) class TestAsCtrait(unittest.TestCase): def test_as_ctrait_from_ctrait(self): ct = Int().as_ctrait() result = as_ctrait(ct) self.assertIs(result, ct) def test_as_ctrait_from_class(self): result = as_ctrait(Int) self.assertIsInstance(result, CTrait) self.assertIsInstance(result.handler, Int) def test_as_ctrait_from_instance(self): trait = Int() result = as_ctrait(trait) self.assertIsInstance(result, CTrait) self.assertIs(result.handler, trait) def test_as_ctrait_from_trait_factory(self): int_trait_factory = TraitFactory(lambda: Int().as_ctrait()) with reset_trait_factory(): result = as_ctrait(int_trait_factory) ct = int_trait_factory.as_ctrait() self.assertIsInstance(result, CTrait) self.assertIs(result, ct) def test_as_ctrait_raise_exception(self): with self.assertRaises(TypeError): as_ctrait(1) with self.assertRaises(TypeError): as_ctrait(int) traits-6.3.2/traits/tests/test_trait_cycle.py000066400000000000000000000076021414270267200214250ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test whether HasTraits objects with cycles can be garbage collected. """ import gc import time import unittest # Enthought library imports from traits.api import HasTraits, Any, DelegatesTo, Instance, Int class TestCase(unittest.TestCase): def _simple_cycle_helper(self, foo_class): """ Can the garbage collector clean up a cycle with traits objects? """ # Create two Foo objects that refer to each other. first = foo_class() second = foo_class(child=first) first.child = second # get their ids foo_ids = [id(first), id(second)] # delete the items so that they can be garbage collected del first, second # tell the garbage collector to pick up the litter. gc.collect() # Now grab all objects in the process and ask for their ids all_ids = [id(obj) for obj in gc.get_objects()] # Ensure that neither of the Foo object ids are in this list for foo_id in foo_ids: self.assertTrue(foo_id not in all_ids) def test_simple_cycle_oldstyle_class(self): """ Can the garbage collector clean up a cycle with old style class? """ class Foo: def __init__(self, child=None): self.child = child self._simple_cycle_helper(Foo) def test_simple_cycle_newstyle_class(self): """ Can the garbage collector clean up a cycle with new style class? """ class Foo(object): def __init__(self, child=None): self.child = child self._simple_cycle_helper(Foo) def test_simple_cycle_hastraits(self): """ Can the garbage collector clean up a cycle with traits objects? """ class Foo(HasTraits): child = Any self._simple_cycle_helper(Foo) def test_reference_to_trait_dict(self): """ Does a HasTraits object refer to its __dict__ object? This test may point to why the previous one fails. Even if it doesn't, the functionality is needed for detecting problems with memory in debug.memory_tracker """ class Foo(HasTraits): child = Any foo = Foo() # It seems like foo sometimes has not finished construction yet, so # the frame found by referrers is not _exactly_ the same as Foo(). For # more information, see the gc doc: http://docs.python.org/lib/module- # gc.html # # The documentation says that this (get_referrers) should be used for # no purpose other than debugging, so this is really not a good way to # test the code. time.sleep(0.1) referrers = gc.get_referrers(foo.__dict__) self.assertTrue(len(referrers) > 0) self.assertTrue(foo in referrers) def test_delegates_to(self): """ Tests if an object that delegates to another is freed. """ class Base(HasTraits): """ Object we are delegating to. """ i = Int class Delegates(HasTraits): """ Object that delegates. """ b = Instance(Base) i = DelegatesTo("b") # Make a pair of object b = Base() d = Delegates(b=b) # Delete d and thoroughly collect garbage del d for i in range(3): gc.collect(2) # See if we still have a Delegates ds = [obj for obj in gc.get_objects() if isinstance(obj, Delegates)] self.assertEqual(ds, []) traits-6.3.2/traits/tests/test_trait_default_initializer.py000066400000000000000000000027571414270267200243630ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.trait_types import Int from traits.has_traits import HasTraits class Foo(HasTraits): bar = Int def _bar_default(self): return 4 class TestTraitDefaultInitializer(unittest.TestCase): """ Test basic usage of the default method. """ def test_default_value(self): foo = Foo() self.assertEqual(foo.bar, 4) def test_default_value_override(self): foo = Foo(bar=3) self.assertEqual(foo.bar, 3) def test_reset_to_default(self): foo = Foo(bar=3) foo.reset_traits(traits=["bar"]) self.assertEqual(foo.bar, 4) def test_error_propagation_in_default_methods(self): class FooException(Foo): def _bar_default(self): 1 / 0 foo = FooException() self.assertRaises(ZeroDivisionError, lambda: foo.bar) class FooKeyError(Foo): def _bar_default(self): raise KeyError() # Check that KeyError is propagated (issue #70). foo = FooKeyError() self.assertRaises(KeyError, lambda: foo.bar) traits-6.3.2/traits/tests/test_trait_dict_list_set_event.py000066400000000000000000000045051414270267200243570ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test cases for TraitListEvent, TraitDictEvent, TraitSetEvent. """ import unittest from traits.api import ( Dict, HasTraits, List, on_trait_change, Set, TraitListEvent, TraitDictEvent, TraitSetEvent ) class Foo(HasTraits): alist = List([1, 2, 3]) adict = Dict({'red': 255, 'blue': 0, 'green': 127}) aset = Set({1, 2, 3}) @on_trait_change(["alist_items", "adict_items", "aset_items"]) def _receive_events(self, event): self.event = event class TestTraitEvent(unittest.TestCase): def setUp(self): self.foo = Foo() def test_list_repr(self): self.foo.alist[::2] = [4, 5] event = self.foo.event event_str = ("TraitListEvent(index=slice(0, 3, 2), " "removed=[1, 3], added=[4, 5])") self.assertEqual(repr(event), event_str) self.assertIsInstance(eval(repr(event)), TraitListEvent) def test_list_event_kwargs_only(self): with self.assertRaises(TypeError): TraitListEvent(slice(0, 3, 2), [1, 3], [4, 5]) def test_dict_event_kwargs_only(self): with self.assertRaises(TypeError): TraitDictEvent({}, {'black': 0}, {'blue': 2}) def test_dict_event_repr(self): self.foo.adict.update({'blue': 10, 'black': 0}) event = self.foo.event event_str = ("TraitDictEvent(removed={}, added={'black': 0}, " "changed={'blue': 0})") self.assertEqual(repr(event), event_str) self.assertIsInstance(eval(repr(event)), TraitDictEvent) def test_set_event_kwargs_only(self): with self.assertRaises(TypeError): TraitSetEvent({3}, {4}) def test_set_event_repr(self): self.foo.aset.symmetric_difference_update({3, 4}) event = self.foo.event event_str = "TraitSetEvent(removed={3}, added={4})" self.assertEqual(repr(event), event_str) self.assertIsInstance(eval(repr(event)), TraitSetEvent) traits-6.3.2/traits/tests/test_trait_dict_object.py000066400000000000000000000355701414270267200226040ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import copy import pickle import sys import unittest from unittest import mock from traits.api import HasTraits from traits.trait_dict_object import TraitDict, TraitDictEvent, TraitDictObject from traits.trait_errors import TraitError from traits.trait_types import Dict, Int, Str def str_validator(value): if type(value) is str: return value else: raise TraitError def int_validator(value): if type(value) is int: return value else: raise TraitError class TestTraitDict(unittest.TestCase): def setUp(self): self.added = None self.changed = None self.removed = None self.trait_dict = None def notification_handler(self, trait_dict, removed, added, changed): self.trait_list = trait_dict self.removed = removed self.added = added self.changed = changed def test_init(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator) self.assertEqual(td, {"a": 1, "b": 2}) self.assertEqual(td.notifiers, []) def test_init_iterable(self): td = TraitDict([("a", 1), ("b", 2)], key_validator=str_validator, value_validator=int_validator) self.assertEqual(td, {"a": 1, "b": 2}) self.assertEqual(td.notifiers, []) with self.assertRaises(ValueError): TraitDict(["a", "b"], key_validator=str_validator, value_validator=int_validator) def test_notification(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) td["c"] = 5 self.assertEqual(self.added, {"c": 5}) self.assertEqual(self.changed, {}) self.assertEqual(self.removed, {}) def test_deepcopy(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) td_copy = copy.deepcopy(td) self.assertEqual(td, td_copy) self.assertEqual(td_copy.notifiers, []) self.assertEqual(td_copy.value_validator, td.value_validator) self.assertEqual(td_copy.key_validator, td.key_validator) def test_setitem(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) td["a"] = 5 self.assertEqual(self.added, {}) self.assertEqual(self.changed, {"a": 1}) self.assertEqual(self.removed, {}) with self.assertRaises(TraitError): td[5] = "a" def test_delitem(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) del td["a"] self.assertEqual(self.added, {}) self.assertEqual(self.changed, {}) self.assertEqual(self.removed, {"a": 1}) def test_delitem_not_found(self): python_dict = dict() with self.assertRaises(KeyError) as python_e: del python_dict["x"] td = TraitDict() with self.assertRaises(KeyError) as trait_e: del td["x"] self.assertEqual( str(trait_e.exception), str(python_e.exception), ) if sys.version_info >= (3, 9): # The |= operation on dictionaries was introduced in Python 3.9 def test_ior(self): td = TraitDict( {"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler], ) td |= {"a": 3, "d": 5} self.assertEqual(td, {"a": 3, "b": 2, "d": 5}) self.assertEqual(self.added, {"d": 5}) self.assertEqual(self.changed, {"a": 1}) self.assertEqual(self.removed, {}) def test_ior_is_quiet_if_no_change(self): td = TraitDict( {"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler], ) td |= [] self.assertEqual(td, {"a": 1, "b": 2}) self.assertIsNone(self.added) self.assertIsNone(self.removed) self.assertIsNone(self.changed) else: # Python versions earlier than 3.9 should still raise TypeError. def test_ior(self): td = TraitDict( {"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler], ) with self.assertRaises(TypeError): td |= {"a": 3, "d": 5} def test_update(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) td.update({"a": 2, "b": 4, "c": 5}) self.assertEqual(self.added, {"c": 5}) self.assertEqual(self.changed, {"a": 1, "b": 2}) self.assertEqual(self.removed, {}) def test_update_iterable(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) td.update([("a", 2), ("b", 4), ("c", 5)]) self.assertEqual(self.added, {"c": 5}) self.assertEqual(self.changed, {"a": 1, "b": 2}) self.assertEqual(self.removed, {}) def test_update_with_transformation(self): td = TraitDict( {"1": 1, "2": 2}, key_validator=str, notifiers=[self.notification_handler], ) # when td.update({1: 2}) # then self.assertEqual(td, {"1": 2, "2": 2}) self.assertEqual(self.added, {}) self.assertEqual(self.changed, {"1": 1}) self.assertEqual(self.removed, {}) def test_update_with_empty_argument(self): td = TraitDict( {"1": 1, "2": 2}, key_validator=str, notifiers=[self.notification_handler], ) # neither of these should cause a notification to be emitted td.update([]) td.update({}) self.assertEqual(td, {"1": 1, "2": 2}) self.assertIsNone(self.added) self.assertIsNone(self.changed) self.assertIsNone(self.removed) def test_update_notifies_with_nonempty_argument(self): # Corner case: we don't want to get into the difficulties of # comparing values for equality, so we notify for a non-empty # argument even if the dictionary has not actually changed. td = TraitDict( {"1": 1, "2": 2}, key_validator=str, notifiers=[self.notification_handler], ) td.update({"1": 1}) self.assertEqual(td, {"1": 1, "2": 2}) self.assertEqual(self.added, {}) self.assertEqual(self.changed, {"1": 1}) self.assertEqual(self.removed, {}) def test_clear(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) td.clear() self.assertEqual(self.added, {}) self.assertEqual(self.changed, {}) self.assertEqual(self.removed, {"a": 1, "b": 2}) def test_clear_empty_dictionary(self): # Clearing an empty dictionary should not notify. td = TraitDict( {}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler], ) td.clear() self.assertIsNone(self.added) self.assertIsNone(self.changed) self.assertIsNone(self.removed) def test_invalid_key(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) with self.assertRaises(TraitError): td[3] = "3" def test_invalid_value(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) with self.assertRaises(TraitError): td["3"] = True def test_setdefault(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) result = td.setdefault("c", 3) self.assertEqual(result, 3) self.assertEqual(td.setdefault("a", 5), 1) def test_setdefault_with_casting(self): # If the validator does transformation, the containment # is checked before the transformation. This is more # consistent with the description of setdefault, which is # effectively a short-hand for ``__getitem__``, # followed by ``__setitem__`` (if get fails), followed by # another ``__getitem__``. # The notification should be factual about the actual # mutation on the dict. notifier = mock.Mock() td = TraitDict( key_validator=str, value_validator=str, notifiers=[notifier, self.notification_handler], ) td.setdefault(1, 2) self.assertEqual(td, {"1": "2"}) self.assertEqual(notifier.call_count, 1) self.assertEqual(self.removed, {}) self.assertEqual(self.added, {"1": "2"}) self.assertEqual(self.changed, {}) notifier.reset_mock() td.setdefault(1, 4) self.assertEqual(td, {"1": "4"}) self.assertEqual(notifier.call_count, 1) self.assertEqual(self.removed, {}) self.assertEqual(self.added, {}) self.assertEqual(self.changed, {"1": "2"}) def test_pop(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) td.pop("b", "X") self.assertEqual(self.removed, {"b": 2}) self.removed = None res = td.pop("x", "X") # Ensure no notification is fired. self.assertIsNone(self.removed) self.assertEqual(res, "X") def test_pop_key_error(self): python_dict = {} with self.assertRaises(KeyError) as python_e: python_dict.pop("a") td = TraitDict() with self.assertRaises(KeyError) as trait_e: td.pop("a") self.assertEqual( str(trait_e.exception), str(python_e.exception), ) def test_popitem(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) items_cpy = td.copy().items() itm = td.popitem() self.assertIn(itm, items_cpy) self.assertNotIn(itm, td.items()) td = TraitDict({}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) with self.assertRaises(KeyError): td.popitem() def test_pickle(self): td = TraitDict({"a": 1, "b": 2}, key_validator=str_validator, value_validator=int_validator, notifiers=[self.notification_handler]) for protocol in range(pickle.HIGHEST_PROTOCOL + 1): td_unpickled = pickle.loads(pickle.dumps(td, protocol=protocol)) self.assertIs(td_unpickled.key_validator, str_validator) self.assertIs(td_unpickled.value_validator, int_validator) self.assertEqual(td_unpickled.notifiers, []) class TestTraitDictObject(unittest.TestCase): """ Test TraitDictObject operations.""" class TestClass(HasTraits): dict_1 = Dict(Str) dict_2 = Dict(Int, Str) def test_trait_dict_object_validate_key(self): obj = TestTraitDictObject.TestClass() trait_dict_obj = TraitDictObject( trait=obj.trait('dict_1').trait_type, object=obj, name="a", value={}, ) # This is okay trait_dict_obj.key_validator("1") # This fails. with self.assertRaises(TraitError): trait_dict_obj.key_validator(1) def test_trait_dict_object_validate_value(self): obj = TestTraitDictObject.TestClass() trait_dict_obj = TraitDictObject( trait=obj.trait('dict_2').trait_type, object=obj, name="a", value={}, ) # This is okay trait_dict_obj.value_validator("1") # This fails. with self.assertRaises(TraitError): trait_dict_obj.value_validator(1) def test_trait_dict_object_pickle(self): obj = TestTraitDictObject.TestClass() trait_dict_obj = TraitDictObject( trait=obj.trait('dict_2').trait_type, object=obj, name="a", value={}, ) tdo_unpickled = pickle.loads(pickle.dumps(trait_dict_obj)) # Validation is disabled tdo_unpickled.value_validator("1") tdo_unpickled.value_validator(1) tdo_unpickled.value_validator(True) class TestTraitDictEvent(unittest.TestCase): def test_trait_dict_event_str_representation(self): """ Test string representation of the TraitDictEvent class. """ desired_repr = "TraitDictEvent(removed={}, added={}, changed={})" trait_dict_event = TraitDictEvent() self.assertEqual(desired_repr, str(trait_dict_event)) self.assertEqual(desired_repr, repr(trait_dict_event)) def test_trait_dict_event_subclass_str_representation(self): """ Test string representation of a subclass of the TraitDictEvent class. """ class DifferentName(TraitDictEvent): pass desired_repr = "DifferentName(removed={}, added={}, changed={})" differnt_name_subclass = DifferentName() self.assertEqual(desired_repr, str(differnt_name_subclass)) self.assertEqual(desired_repr, repr(differnt_name_subclass)) traits-6.3.2/traits/tests/test_trait_exceptions.py000066400000000000000000000017771414270267200225160ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import HasTraits, Int class A(HasTraits): x = Int(5) class TestGetAttr(unittest.TestCase): def setUp(self): self.a = A() def test_bad__getattribute__(self): # Argument to __getattribute__ must be a string self.assertEqual(self.a.__getattribute__("x"), 5) with self.assertRaises(TypeError) as e: self.a.__getattribute__(2) # Error message contains value and type of bad attribute name exception_msg = str(e.exception) self.assertIn("2", exception_msg) self.assertIn("int", exception_msg) traits-6.3.2/traits/tests/test_trait_get_set.py000066400000000000000000000044151414270267200217570ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test the 'trait_set', 'trait_get' interface to the HasTraits class. """ import unittest from traits.api import HasTraits, Str, Int from traits.testing.unittest_tools import UnittestTools class TraitsObject(HasTraits): string = Str integer = Int class TestTraitGet(UnittestTools, unittest.TestCase): def test_trait_set(self): obj = TraitsObject() obj.trait_set(string="foo") self.assertEqual(obj.string, "foo") self.assertEqual(obj.integer, 0) def test_trait_get(self): obj = TraitsObject() obj.trait_set(string="foo") values = obj.trait_get("string", "integer") self.assertEqual(values, {"string": "foo", "integer": 0}) def test_trait_set_deprecated(self): obj = TraitsObject() with self.assertNotDeprecated(): obj.trait_set(integer=1) with self.assertDeprecated(): obj.set(string="foo") self.assertEqual(obj.string, "foo") self.assertEqual(obj.integer, 1) def test_trait_get_deprecated(self): obj = TraitsObject() obj.string = "foo" obj.integer = 1 with self.assertNotDeprecated(): values = obj.trait_get("integer") self.assertEqual(values, {"integer": 1}) with self.assertDeprecated(): values = obj.get("string") self.assertEqual(values, {"string": "foo"}) def test_trait_set_quiet(self): obj = TraitsObject() obj.string = "foo" with self.assertTraitDoesNotChange(obj, "string"): obj.trait_set(trait_change_notify=False, string="bar") self.assertEqual(obj.string, "bar") def test_trait_setq(self): obj = TraitsObject() obj.string = "foo" with self.assertTraitDoesNotChange(obj, "string"): obj.trait_setq(string="bar") self.assertEqual(obj.string, "bar") traits-6.3.2/traits/tests/test_trait_list_dict.py000066400000000000000000000141531414270267200223030ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test the persistence behavior of TraitListObjects, TraitDictObjects and TraitSetObjects. """ import copy import pickle import unittest from traits.has_traits import HasTraits, on_trait_change from traits.trait_types import Dict, List, Set, Str, Int, Instance class A(HasTraits): alist = List(Int, list(range(5))) adict = Dict(Str, Int, dict(a=1, b=2)) aset = Set(Int, set(range(5))) events = List() @on_trait_change("alist_items,adict_items,aset_items") def _receive_events(self, object, name, old, new): self.events.append((name, new)) class B(HasTraits): dict = Dict(Str, Instance(A)) class TestTraitListDictSetPersistence(unittest.TestCase): def test_trait_list_object_persists(self): a = A() list = pickle.loads(pickle.dumps(a.alist)) self.assertIsNone(list.object()) list.append(10) self.assertEqual(len(a.events), 0) a.alist.append(20) self.assertEqual(len(a.events), 1) list2 = pickle.loads(pickle.dumps(list)) self.assertIsNone(list2.object()) def test_trait_dict_object_persists(self): a = A() dict = pickle.loads(pickle.dumps(a.adict)) self.assertIsNone(dict.object()) dict["key"] = 10 self.assertEqual(len(a.events), 0) a.adict["key"] = 10 self.assertEqual(len(a.events), 1) dict2 = pickle.loads(pickle.dumps(dict)) self.assertIsNone(dict2.object()) def test_trait_set_object_persists(self): a = A() set = pickle.loads(pickle.dumps(a.aset)) self.assertIsNone(set.object()) set.add(10) self.assertEqual(len(a.events), 0) a.aset.add(20) self.assertEqual(len(a.events), 1) set2 = pickle.loads(pickle.dumps(set)) self.assertIsNone(set2.object()) def test_trait_list_object_copies(self): a = A() list = copy.deepcopy(a.alist) self.assertIsNone(list.object()) list.append(10) self.assertEqual(len(a.events), 0) a.alist.append(20) self.assertEqual(len(a.events), 1) list2 = copy.deepcopy(list) list2.append(30) self.assertIsNone(list2.object()) def test_trait_dict_object_copies(self): a = A() dict = copy.deepcopy(a.adict) self.assertIsNone(dict.object()) dict["key"] = 10 self.assertEqual(len(a.events), 0) a.adict["key"] = 10 self.assertEqual(len(a.events), 1) dict2 = copy.deepcopy(dict) dict2["key2"] = 20 self.assertIsNone(dict2.object()) def test_trait_set_object_copies(self): a = A() set1 = copy.deepcopy(a.aset) self.assertIsNone(set1.object()) set1.add(10) self.assertEqual(len(a.events), 0) a.aset.add(20) self.assertEqual(len(a.events), 1) set2 = copy.deepcopy(set1) set2.add(30) self.assertIsNone(set2.object()) set3 = a.aset.copy() self.assertIs(type(set3), set) # Should not raise an AttributeError: set3.remove(20) def test_pickle_whole(self): a = A() pickle.loads(pickle.dumps(a)) b = B(dict=dict(a=a)) pickle.loads(pickle.dumps(b)) def test_trait_set_object_operations(self): # Regression test for update methods not coercing in the same way as # standard set objects (github issue #288) a = A() a.aset.update({10: "a"}) self.assertEqual(a.aset, set([0, 1, 2, 3, 4, 10])) a.aset.intersection_update({3: "b", 4: "b", 10: "a", 11: "b"}) self.assertEqual(a.aset, set([3, 4, 10])) a.aset.difference_update({10: "a", 11: "b"}) self.assertEqual(a.aset, set([3, 4])) a.aset.symmetric_difference_update({10: "a", 4: "b"}) self.assertEqual(a.aset, set([3, 10])) def test_trait_set_object_inplace(self): a = A() a.aset |= set([10]) self.assertEqual(a.aset, set([0, 1, 2, 3, 4, 10])) a.aset &= set([3, 4, 10, 11]) self.assertEqual(a.aset, set([3, 4, 10])) a.aset -= set([10, 11]) self.assertEqual(a.aset, set([3, 4])) a.aset ^= set([10, 4]) self.assertEqual(a.aset, set([3, 10])) def test_trait_list_default_kind(self): a = A() list_trait = a.traits()["alist"] self.assertEqual(list_trait.default_kind, "list") def test_trait_dict_default_kind(self): a = A() dict_trait = a.traits()["adict"] self.assertEqual(dict_trait.default_kind, "dict") def test_trait_set_default_kind(self): a = A() set_trait = a.traits()["aset"] self.assertEqual(set_trait.default_kind, "set") def test_trait_list_default(self): a = A() list_trait = a.traits()["alist"] self.assertEqual(list_trait.default, [0, 1, 2, 3, 4]) # The default property should have returned a copy, so # modifying it doesn't change the actual default. list_trait.default.append(5) self.assertEqual(a.alist, [0, 1, 2, 3, 4]) def test_trait_dict_default(self): a = A() dict_trait = a.traits()["adict"] self.assertEqual(dict_trait.default, {"a": 1, "b": 2}) # The default property should have returned a copy, so # modifying it doesn't change the actual default. dict_trait.default.pop("a") self.assertEqual(a.adict, {"a": 1, "b": 2}) def test_trait_set_default(self): a = A() set_trait = a.traits()["aset"] self.assertEqual(set_trait.default, {0, 1, 2, 3, 4}) # The default property should have returned a copy, so # modifying it doesn't change the actual default. set_trait.default.remove(2) self.assertEqual(a.aset, {0, 1, 2, 3, 4}) traits-6.3.2/traits/tests/test_trait_list_object.py000066400000000000000000001433071414270267200226320ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import copy import operator import pickle import unittest.mock from traits.api import HasTraits, Int, List from traits.testing.optional_dependencies import numpy, requires_numpy from traits.trait_base import _validate_everything from traits.trait_errors import TraitError from traits.trait_list_object import ( TraitList, TraitListEvent, TraitListObject, ) def int_item_validator(item): """ An item_validator for TraitList that checks that the item is an int or integer-like object (e.g., any object whose type provides __index__). Parameters ---------- item : object Proposed item to add to the list. Returns ------- validated_item : object Actual item to add to the list. Raises ------ TraitError If the item is not valid. """ try: return int(operator.index(item)) except TypeError: raise TraitError("Value {} is not a valid integer".format(item)) def list_item_validator(item): """ An item_validator for TraitList that checks that the item is a list. Parameters ---------- item : object Proposed item to add to the list. Returns ------- validated_item : object Actual item to add to the list. Raises ------ TraitError If the item is not valid. """ if isinstance(item, list): return item else: raise TraitError("Value {} is not a list instance".format(item)) class TestTraitListEvent(unittest.TestCase): def test_creation(self): event = TraitListEvent(index=2, removed=[3], added=[4]) self.assertEqual(event.index, 2) self.assertEqual(event.removed, [3]) self.assertEqual(event.added, [4]) event = TraitListEvent(index=2, removed=[3], added=[4]) self.assertEqual(event.index, 2) self.assertEqual(event.removed, [3]) self.assertEqual(event.added, [4]) def test_defaults(self): event = TraitListEvent() self.assertEqual(event.index, 0) self.assertEqual(event.removed, []) self.assertEqual(event.added, []) def test_trait_list_event_str_representation(self): """ Test string representation of the TraitListEvent class. """ desired_repr = "TraitListEvent(index=0, removed=[], added=[])" trait_list_event = TraitListEvent() self.assertEqual(desired_repr, str(trait_list_event)) self.assertEqual(desired_repr, repr(trait_list_event)) def test_trait_list_event_subclass_str_representation(self): """ Test string representation of a subclass of the TraitListEvent class. """ class DifferentName(TraitListEvent): pass desired_repr = "DifferentName(index=0, removed=[], added=[])" different_name_subclass = DifferentName() self.assertEqual(desired_repr, str(different_name_subclass)) self.assertEqual(desired_repr, repr(different_name_subclass)) class TestTraitList(unittest.TestCase): def setUp(self): self.index = None self.added = None self.removed = None self.trait_list = None def notification_handler(self, trait_list, index, removed, added): self.trait_list = trait_list self.index = index self.removed = removed self.added = added def test_init(self): tl = TraitList([1, 2, 3]) self.assertListEqual(tl, [1, 2, 3]) self.assertIs(tl.item_validator, _validate_everything) self.assertEqual(tl.notifiers, []) def test_init_no_value(self): tl = TraitList() self.assertEqual(tl, []) self.assertIs(tl.item_validator, _validate_everything) self.assertEqual(tl.notifiers, []) def test_init_iterable(self): tl = TraitList("abcde") self.assertListEqual(tl, ['a', 'b', 'c', 'd', 'e']) self.assertIs(tl.item_validator, _validate_everything) self.assertEqual(tl.notifiers, []) def test_init_iterable_without_length(self): tl = TraitList(x**2 for x in range(5)) self.assertEqual(tl, [0, 1, 4, 9, 16]) self.assertIs(tl.item_validator, _validate_everything) self.assertEqual(tl.notifiers, []) def test_init_validates(self): with self.assertRaises(TraitError): TraitList([1, 2.0, 3], item_validator=int_item_validator) def test_init_converts(self): tl = TraitList([True, False], item_validator=int_item_validator) self.assertEqual(tl, [1, 0]) self.assertTrue( all(type(item) is int for item in tl), msg="Non-integers found in int-only list", ) def test_validator(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator) self.assertListEqual(tl, [1, 2, 3]) self.assertEqual(tl.item_validator, int_item_validator) self.assertEqual(tl.notifiers, []) def test_notification(self): tl = TraitList([1, 2, 3], notifiers=[self.notification_handler]) self.assertListEqual(tl, [1, 2, 3]) self.assertIs(tl.item_validator, _validate_everything) self.assertEqual(tl.notifiers, [self.notification_handler]) tl[0] = 5 self.assertListEqual(tl, [5, 2, 3]) self.assertIs(self.trait_list, tl) self.assertEqual(self.index, 0) self.assertEqual(self.removed, [1]) self.assertEqual(self.added, [5]) def test_copy(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl_copy = copy.copy(tl) for itm, itm_cpy in zip(tl, tl_copy): self.assertEqual(itm_cpy, itm) self.assertEqual(tl_copy.notifiers, []) self.assertEqual(tl_copy.item_validator, tl.item_validator) def test_deepcopy(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl_copy = copy.deepcopy(tl) for itm, itm_cpy in zip(tl, tl_copy): self.assertEqual(itm_cpy, itm) self.assertEqual(tl_copy.notifiers, []) self.assertEqual(tl_copy.item_validator, tl.item_validator) def test_deepcopy_memoization(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) trait_lists_copy = copy.deepcopy([tl, tl]) self.assertIs(trait_lists_copy[0], trait_lists_copy[1]) def test_setitem(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl[1] = 5 self.assertEqual(self.index, 1) self.assertEqual(self.removed, [2]) self.assertEqual(self.added, [5]) tl[:] = [1, 2, 3, 4, 5] self.assertEqual(self.index, 0) self.assertEqual(self.removed, [1, 5, 3]) self.assertEqual(self.added, [1, 2, 3, 4, 5]) def test_setitem_converts(self): tl = TraitList([9, 8, 7], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl[1] = False self.assertEqual(tl, [9, 0, 7]) self.assertEqual(self.index, 1) self.assertEqual(self.removed, [8]) self.assertEqual(self.added, [0]) self.assertTrue( all(type(item) is int for item in tl), msg="Non-integers found in int-only list", ) self.assertTrue( all(type(item) is int for item in self.added), msg="Event contains non-integers for int-only list", ) tl[::2] = [True, True] self.assertEqual(tl, [1, 0, 1]) self.assertEqual(self.index, slice(0, 3, 2)) self.assertEqual(self.removed, [9, 7]) self.assertEqual(self.added, [1, 1]) self.assertTrue( all(type(item) is int for item in tl), msg="Non-integers found in int-only list", ) self.assertTrue( all(type(item) is int for item in self.added), msg="Event contains non-integers for int-only list", ) def test_setitem_no_structural_change(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl[3:] = [] self.assertEqual(tl, [1, 2, 3]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_setitem_no_item_change(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl[0] = 1 self.assertEqual(tl, [1, 2, 3]) self.assertEqual(self.index, 0) self.assertEqual(self.removed, [1]) self.assertEqual(self.added, [1]) def test_setitem_no_removed(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl[3:] = [4, 5, 6] self.assertEqual(tl, [1, 2, 3, 4, 5, 6]) self.assertEqual(self.index, 3) self.assertEqual(self.removed, []) self.assertEqual(self.added, [4, 5, 6]) def test_setitem_no_added(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl[1:2] = [] self.assertEqual(tl, [1, 3]) self.assertEqual(self.index, 1) self.assertEqual(self.removed, [2]) self.assertEqual(self.added, []) def test_setitem_iterable(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl[:] = (x**2 for x in range(4)) self.assertEqual(tl, [0, 1, 4, 9]) self.assertEqual(self.index, 0) self.assertEqual(self.removed, [1, 2, 3]) self.assertEqual(self.added, [0, 1, 4, 9]) def test_setitem_indexerror(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) with self.assertRaises(IndexError): tl[3] = 4 self.assertEqual(tl, [1, 2, 3]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_setitem_validation_error(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) with self.assertRaises(TraitError): tl[0] = 4.5 self.assertEqual(tl, [1, 2, 3]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) with self.assertRaises(TraitError): tl[0:2] = [1, "a string"] self.assertEqual(tl, [1, 2, 3]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) with self.assertRaises(TraitError): tl[2:0:-1] = [1, "a string"] self.assertEqual(tl, [1, 2, 3]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_setitem_negative_step(self): tl = TraitList([1, 2, 3, 4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl[::-2] = [10, 11, 12] self.assertEqual(tl, [12, 2, 11, 4, 10]) self.assertEqual(self.index, slice(0, 5, 2)) self.assertEqual(self.removed, [1, 3, 5]) self.assertEqual(self.added, [12, 11, 10]) def test_setitem_negative_one_step(self): tl = TraitList([1, 2, 3, 4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl[:1:-1] = [10, 11, 12] self.assertEqual(tl, [1, 2, 12, 11, 10]) self.assertEqual(self.index, 2) self.assertEqual(self.removed, [3, 4, 5]) self.assertEqual(self.added, [12, 11, 10]) def test_setitem_index_and_validation_error(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) # Assigning an invalid value to an invalid index: the # TraitError from the invalid value wins. with self.assertRaises(TraitError): tl[3] = 4.5 self.assertEqual(tl, [1, 2, 3]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) # Assigning to a slice with invalid r.h.s. length and # invalid contents: again, the TraitError wins. with self.assertRaises(TraitError): tl[::2] = [1, 2, 4.5] self.assertEqual(tl, [1, 2, 3]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_setitem_item_conversion(self): tl = TraitList([2, 3, 4], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl[0] = True self.assertEqual(tl, [1, 3, 4]) self.assertEqual(self.index, 0) self.assertEqual(self.removed, [2]) self.assertEqual(self.added, [1]) # Check that the True has been converted to an int. self.assertTrue( all(type(item) is int for item in tl), msg="Non-integers found in int-only list", ) self.assertTrue( all(type(item) is int for item in self.added), msg="Event contains non-integers for int-only list", ) def test_setitem_corner_case(self): # A peculiar-looking corner case where it's easy to get the # implementation wrong (and CPython did so in the distance past). tl = TraitList(range(7), notifiers=[self.notification_handler]) # Note: new items inserted at position 5, not position 2. tl[5:2] = [10, 11, 12] self.assertEqual(tl, [0, 1, 2, 3, 4, 10, 11, 12, 5, 6]) self.assertEqual(self.index, 5) self.assertEqual(self.removed, []) self.assertEqual(self.added, [10, 11, 12]) def test_setitem_slice_exhaustive(self): # Try all possible (slice, list_length) combinations. for test_slice in self.all_slices(max_index=7): for test_length in range(6): for replacement_length in range(6): with self.subTest( slice=test_slice, length=test_length, replacement=replacement_length, ): test_list = list(range(test_length)) replacement = list( range(-1, -1 - replacement_length, -1)) self.assertEqual(len(test_list), test_length) self.assertEqual(len(replacement), replacement_length) self.validate_event( test_list, lambda items: items.__setitem__( test_slice, replacement, ) ) def test_delitem(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) del tl[2] self.assertEqual(self.index, 2) self.assertEqual(self.removed, [3]) self.assertEqual(self.added, []) del tl[:] self.assertEqual(self.index, 0) self.assertEqual(self.removed, [1, 2]) self.assertEqual(self.added, []) with self.assertRaises(IndexError): del tl[0] def test_delitem_extended_slice_normalization(self): tl = TraitList([1, 2, 3, 4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) del tl[2:10:2] self.assertEqual(tl, [1, 2, 4]) self.assertEqual(self.index, slice(2, 5, 2)) self.assertEqual(self.removed, [3, 5]) self.assertEqual(self.added, []) def test_delitem_negative_step_normalization(self): tl = TraitList([1, 2, 3, 4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) # Same effect as del tl[2:5:2]. del tl[5:1:-2] self.assertEqual(tl, [1, 2, 4]) self.assertEqual(self.index, slice(2, 5, 2)) self.assertEqual(self.removed, [3, 5]) self.assertEqual(self.added, []) def test_delitem_negative_step(self): tl = TraitList([1, 2, 3, 4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) del tl[::-2] self.assertEqual(tl, [2, 4]) self.assertEqual(self.index, slice(0, 5, 2)) self.assertEqual(self.removed, [1, 3, 5]) self.assertEqual(self.added, []) def test_delitem_slice_exhaustive(self): # Try all possible (slice, list_length) combinations. for test_slice in self.all_slices(max_index=7): for test_length in range(11): with self.subTest(slice=test_slice, length=test_length): test_list = list(range(test_length)) self.validate_event( test_list, lambda items: items.__delitem__(test_slice) ) def test_delitem_nochange(self): tl = TraitList([1, 2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) del tl[3:] self.assertEqual(tl, [1, 2, 3]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_iadd(self): tl = TraitList([4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl += [6, 7] self.assertEqual(self.index, 2) self.assertEqual(self.removed, []) self.assertEqual(self.added, [6, 7]) def test_iadd_validates(self): tl = TraitList([4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) with self.assertRaises(TraitError): tl += [6, 7, 8.0] self.assertEqual(tl, [4, 5]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_iadd_converts(self): tl = TraitList([4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl += [True, True] self.assertEqual(tl, [4, 5, 1, 1]) self.assertEqual(self.index, 2) self.assertEqual(self.removed, []) self.assertEqual(self.added, [1, 1]) self.assertTrue( all(type(item) is int for item in tl), msg="Non-integers found in int-only list", ) self.assertTrue( all(type(item) is int for item in self.added), msg="Event contains non-integers for int-only list", ) def test_iadd_empty(self): tl = TraitList([4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl += [] self.assertEqual(tl, [4, 5]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_iadd_iterable(self): tl = TraitList([4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl += (x**2 for x in range(3)) self.assertEqual(tl, [4, 5, 0, 1, 4]) self.assertEqual(self.index, 2) self.assertEqual(self.removed, []) self.assertEqual(self.added, [0, 1, 4]) def test_imul(self): tl = TraitList([1, 2], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl *= 1 self.assertListEqual(tl, [1, 2]) self.assertEqual(self.index, None) self.assertEqual(self.removed, None) self.assertEqual(self.added, None) tl *= 2 self.assertEqual(self.index, 2) self.assertEqual(self.removed, []) self.assertEqual(self.added, [1, 2]) with self.assertRaises(TypeError): tl *= "5" with self.assertRaises(TypeError): tl *= 2.5 tl *= -1 self.assertEqual(self.index, 0) self.assertEqual(self.removed, [1, 2, 1, 2]) self.assertEqual(self.added, []) def test_imul_no_notification_for_empty_list(self): for multiplier in [-1, 0, 1, 2]: with self.subTest(multiplier=multiplier): tl = TraitList( [], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl *= multiplier self.assertEqual(tl, []) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) @requires_numpy def test_imul_integer_like(self): tl = TraitList([1, 2], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl *= numpy.int64(2) self.assertEqual(tl, [1, 2, 1, 2]) self.assertEqual(self.index, 2) self.assertEqual(self.removed, []) self.assertEqual(self.added, [1, 2]) tl *= numpy.int64(-1) self.assertEqual(tl, []) self.assertEqual(self.index, 0) self.assertEqual(self.removed, [1, 2, 1, 2]) self.assertEqual(self.added, []) def test_imul_does_not_revalidate(self): item_validator = unittest.mock.Mock(wraps=int_item_validator) tl = TraitList([1, 1], item_validator=item_validator) item_validator.reset_mock() tl *= 3 item_validator.assert_not_called() def test_append(self): tl = TraitList([1], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.append(2) self.assertEqual(self.index, 1) self.assertEqual(self.removed, []) self.assertEqual(self.added, [2]) def test_append_validates(self): tl = TraitList([1], item_validator=int_item_validator, notifiers=[self.notification_handler]) with self.assertRaises(TraitError): tl.append(1.0) self.assertEqual(tl, [1]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_append_converts(self): tl = TraitList([2], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.append(False) self.assertEqual(tl, [2, 0]) self.assertEqual(self.index, 1) self.assertEqual(self.removed, []) self.assertEqual(self.added, [0]) self.assertTrue( all(type(item) is int for item in tl), msg="Non-integers found in int-only list", ) self.assertTrue( all(type(item) is int for item in self.added), msg="Event contains non-integers for int-only list", ) def test_extend(self): tl = TraitList([1], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.extend([1, 2]) self.assertEqual(self.index, 1) self.assertEqual(self.removed, []) self.assertEqual(self.added, [1, 2]) def test_extend_validates(self): tl = TraitList([5], item_validator=int_item_validator, notifiers=[self.notification_handler]) with self.assertRaises(TraitError): tl.extend([2, 3, 4.0]) self.assertEqual(tl, [5]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_extend_converts(self): tl = TraitList([4], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.extend([False, True]) self.assertEqual(tl, [4, 0, 1]) self.assertEqual(self.index, 1) self.assertEqual(self.removed, []) self.assertEqual(self.added, [0, 1]) self.assertTrue( all(type(item) is int for item in tl), msg="Non-integers found in int-only list", ) self.assertTrue( all(type(item) is int for item in self.added), msg="Event contains non-integers for int-only list", ) def test_extend_empty(self): tl = TraitList([1], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.extend([]) self.assertEqual(tl, [1]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_extend_iterable(self): tl = TraitList([1], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.extend(x**2 for x in range(10, 13)) self.assertEqual(tl, [1, 100, 121, 144]) self.assertEqual(self.index, 1) self.assertEqual(self.removed, []) self.assertEqual(self.added, [100, 121, 144]) def test_insert(self): tl = TraitList([2], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.insert(0, 1) # [1,2] self.assertEqual(self.index, 0) self.assertEqual(self.removed, []) self.assertEqual(self.added, [1]) tl.insert(-1, 3) # [1,3,2] self.assertEqual(self.index, 1) self.assertEqual(self.removed, []) self.assertEqual(self.added, [3]) def test_insert_index_matches_python_interpretation(self): for insertion_index in range(-10, 10): with self.subTest(insertion_index=insertion_index): tl = TraitList([5, 6, 7]) pl = [5, 6, 7] tl.insert(insertion_index, 1729) pl.insert(insertion_index, 1729) self.assertEqual(tl, pl) def test_insert_validates(self): tl = TraitList([2], item_validator=int_item_validator, notifiers=[self.notification_handler]) with self.assertRaises(TraitError): tl.insert(0, 1.0) self.assertEqual(tl, [2]) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_insert_converts(self): tl = TraitList([2, 3], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.insert(1, True) self.assertEqual(tl, [2, 1, 3]) self.assertEqual(self.index, 1) self.assertEqual(self.removed, []) self.assertEqual(self.added, [1]) self.assertTrue( all(type(item) is int for item in tl), msg="Non-integers found in int-only list", ) self.assertTrue( all(type(item) is int for item in self.added), msg="Event contains non-integers for int-only list", ) def test_pop(self): tl = TraitList([1, 2, 3, 4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.pop() self.assertEqual(self.index, 4) self.assertEqual(self.removed, [5]) self.assertEqual(self.added, []) tl.pop(0) self.assertEqual(self.index, 0) self.assertEqual(self.removed, [1]) self.assertEqual(self.added, []) # tl is now [2,3,4] tl.pop(-2) self.assertEqual(self.index, 1) self.assertEqual(self.removed, [3]) self.assertEqual(self.added, []) def test_remove(self): tl = TraitList([1, 2, 3, 4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.remove(3) self.assertEqual(self.index, 2) self.assertEqual(self.removed, [3]) self.assertEqual(self.added, []) with self.assertRaises(ValueError): tl.remove(3) tl.remove(2.0) self.assertEqual(self.index, 1) self.assertEqual(self.removed, [2]) self.assertIsInstance(self.removed[0], int) self.assertEqual(self.added, []) def test_clear(self): tl = TraitList([1, 2, 3, 4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.clear() self.assertEqual(self.index, 0) self.assertEqual(self.removed, [1, 2, 3, 4, 5]) self.assertEqual(self.added, []) def test_clear_empty_list(self): tl = TraitList([], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.clear() self.assertEqual(tl, []) self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_sort(self): tl = TraitList([2, 3, 1, 4, 5, 0], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.sort() self.assertEqual(tl, [0, 1, 2, 3, 4, 5]) self.assertEqual(self.index, 0) self.assertEqual(self.removed, [2, 3, 1, 4, 5, 0]) self.assertEqual(self.added, [0, 1, 2, 3, 4, 5]) def test_sort_empty_list(self): tl = TraitList([], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.sort() self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_sort_already_sorted(self): tl = TraitList([10, 11, 12, 13, 14], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.sort() self.assertEqual(tl, [10, 11, 12, 13, 14]) self.assertEqual(self.index, 0) self.assertEqual(self.removed, [10, 11, 12, 13, 14]) self.assertEqual(self.added, [10, 11, 12, 13, 14]) def test_reverse(self): tl = TraitList([1, 2, 3, 4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.reverse() self.assertEqual(tl, [5, 4, 3, 2, 1]) self.assertEqual(self.index, 0) self.assertEqual(self.removed, [1, 2, 3, 4, 5]) self.assertEqual(self.added, [5, 4, 3, 2, 1]) def test_reverse_empty_list(self): tl = TraitList([], item_validator=int_item_validator, notifiers=[self.notification_handler]) tl.reverse() self.assertIsNone(self.index) self.assertIsNone(self.removed) self.assertIsNone(self.added) def test_reverse_single_notification(self): # Regression test for double notification. notifier = unittest.mock.Mock() tl = TraitList([1, 2, 3, 4, 5], notifiers=[notifier]) notifier.assert_not_called() tl.reverse() self.assertEqual(notifier.call_count, 1) def test_pickle(self): tl = TraitList([1, 2, 3, 4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) for protocol in range(pickle.HIGHEST_PROTOCOL + 1): serialized = pickle.dumps(tl, protocol=protocol) tl_unpickled = pickle.loads(serialized) self.assertIs(tl_unpickled.item_validator, tl.item_validator) self.assertEqual(tl_unpickled.notifiers, []) for i, j in zip(tl, tl_unpickled): self.assertIs(i, j) def test_invalid_entry(self): tl = TraitList([1, 2, 3, 4, 5], item_validator=int_item_validator, notifiers=[self.notification_handler]) with self.assertRaises(TraitError): tl.append("A") def test_list_of_lists(self): tl = TraitList([[1]], item_validator=list_item_validator, notifiers=[self.notification_handler]) tl.append([2]) # Helper functions for checking a generic operation on a list. def validate_event(self, original_list, operation): """ Validate the event arising from a particular TraitList operation. Given a test list and an operation to perform, perform that operation on both a plain Python list and the corresponding TraitList, then: - check that the resulting lists match - check that the event information generated (if any) is suitably normalized - check that the list operation can be reconstructed from the event information Parameters ---------- original_list : list List to use for testing. operation : callable Single-argument callable which accepts the list and performs the desired operation on it. Raises ------ self.failureException If any aspect of the behaviour is found to be incorrect. """ # List to collection notifications in. notifications = [] def notifier(trait_list, index, removed, added): notifications.append((index, removed, added)) # Apply the operation to both a plain Python list and a TraitList. python_list = original_list.copy() try: python_result = operation(python_list) except Exception as e: python_exception = e python_raised = True else: python_raised = False trait_list = TraitList(original_list, notifiers=[notifier]) try: trait_result = operation(trait_list) except Exception as e: trait_exception = e trait_raised = True else: trait_raised = False # Check side-effects, results, and exception types (if applicable). self.assertEqual(python_list, trait_list) self.assertEqual(python_raised, trait_raised) if python_raised: self.assertEqual(type(python_exception), type(trait_exception)) return self.assertEqual(python_result, trait_result) # Check the notification attributes. if notifications == []: # No notifications. The new list should match the original, # and there's nothing more to check. self.assertEqual(trait_list, original_list) return # Otherwise, expect exactly one notification. self.assertEqual(len(notifications), 1) index, removed, added = notifications[0] self.assertTrue( len(removed) > 0 or len(added) > 0, "a notification was generated, " "but no elements were added or removed" ) # Check normalization of the index. self.check_index_normalized(index, len(original_list)) # Check that we can reconstruct the list operation from the event. reconstructed = original_list.copy() if isinstance(index, slice): self.assertEqual(removed, reconstructed[index]) if added: reconstructed[index] = added else: del reconstructed[index] else: removed_slice = slice(index, index + len(removed)) self.assertEqual(removed, reconstructed[removed_slice]) reconstructed[removed_slice] = added self.assertEqual(reconstructed, trait_list) def check_index_normalized(self, index, length): if isinstance(index, slice): start, stop, step = index.start, index.stop, index.step self.assertIsNotNone(start) self.assertIsNotNone(stop) self.assertIsNotNone(step) # Check start and stop. self.assertTrue( 0 <= start < stop <= length, msg="start and stop of {} not normalized for length {}".format( index, length ) ) # Check step. This should always be > 1, since for step 1 # we can use a plain integer index instead. self.assertTrue(step > 1, msg="step should be greater than 1") # Check that the slice represents at least two elements # (otherwise we should have a plain integer index instead) self.assertTrue( start + step < stop, msg="slice represents fewer than 2 elements" ) # Check that the stop is the smallest possible out of all # equivalent stops. self.assertTrue( (stop - start) % step == 1, msg="stop not normalised with respect to step" ) else: self.assertTrue( 0 <= index <= length, msg="index {} is not normalized for length {}".format( index, length) ) def all_slices(self, max_index=10): """ Generate all slices with bounded start, stop and step. Parameters ---------- max_index : int Maximum permitted absolute value of start, stop and step. Yields ------ s : slice Slice whose components are all either None, or bounded in absolute value by max_index. """ valid_indices = [None] + list(range(-max_index, max_index + 1)) valid_steps = [step for step in valid_indices if step != 0] for start in valid_indices: for stop in valid_indices: for step in valid_steps: yield slice(start, stop, step) def squares(n): """ Generic iterable without a valid len, for testing purposes. Parameters ---------- n : int Limit for computation. Returns ------- squares : generator Generator yielding the first n squares. """ return (x * x for x in range(n)) class HasLengthConstrainedLists(HasTraits): """ Test class for testing list length validation. """ at_least_two = List(Int, [3, 4], minlen=2) at_most_five = List(Int, maxlen=5) unconstrained = List(Int) class TestTraitListObject(unittest.TestCase): def test_list_of_lists_pickle_with_notifier(self): class Foo: pass tl = TraitListObject( trait=List(), object=Foo(), name="foo", value=(), ) self.assertEqual( [tl.notifier], tl.notifiers ) serialized = pickle.dumps(tl) tl_deserialized = pickle.loads(serialized) self.assertEqual( [tl_deserialized.notifier], tl_deserialized.notifiers ) def test_init_too_small(self): with self.assertRaises(TraitError): HasLengthConstrainedLists(at_least_two=[1]) def test_init_too_large(self): with self.assertRaises(TraitError): HasLengthConstrainedLists(at_most_five=[1, 2, 3, 4, 5, 6]) def test_init_from_iterable(self): class Foo: pass tl = TraitListObject( trait=List(), object=Foo(), name="foo", value=squares(5), ) self.assertEqual(tl, list(squares(5))) def test_delitem(self): foo = HasLengthConstrainedLists(at_most_five=[1, 23]) del foo.at_most_five[1] self.assertEqual(foo.at_most_five, [1]) def test_delitem_single_too_small(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2]) with self.assertRaises(TraitError): del foo.at_least_two[0] self.assertEqual(foo.at_least_two, [1, 2]) def test_delitem_slice_too_small(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2]) with self.assertRaises(TraitError): del foo.at_least_two[:] self.assertEqual(foo.at_least_two, [1, 2]) def test_delitem_from_empty(self): foo = HasLengthConstrainedLists() with self.assertRaises(IndexError): del foo.unconstrained[0] def test_iadd(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2]) foo.at_most_five += [6, 7, 8] self.assertEqual(foo.at_most_five, [1, 2, 6, 7, 8]) def test_iadd_too_large(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2, 3, 4]) with self.assertRaises(TraitError): foo.at_most_five += [6, 7, 8] self.assertEqual(foo.at_most_five, [1, 2, 3, 4]) def test_iadd_from_iterable(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2]) foo.at_most_five += squares(3) self.assertEqual(foo.at_most_five, [1, 2, 0, 1, 4]) def test_imul(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 3]) foo.at_least_two *= 2 self.assertEqual(foo.at_least_two, [1, 2, 3, 1, 2, 3]) def test_imul_too_small(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 3, 4]) with self.assertRaises(TraitError): foo.at_least_two *= 0 self.assertEqual(foo.at_least_two, [1, 2, 3, 4]) def test_imul_too_large(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2, 3, 4]) with self.assertRaises(TraitError): foo.at_most_five *= 2 self.assertEqual(foo.at_most_five, [1, 2, 3, 4]) def test_imul_negative_multiplier(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2, 3, 4]) foo.at_most_five *= -10 self.assertEqual(foo.at_most_five, []) def test_setitem_index(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 3, 4]) foo.at_least_two[1] = 7 self.assertEqual(foo.at_least_two, [1, 7, 3, 4]) def test_setitem_slice(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 3, 4]) foo.at_least_two[1:] = [6, 7] self.assertEqual(foo.at_least_two, [1, 6, 7]) def test_setitem_extended_slice(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 3, 4]) foo.at_least_two[1::2] = [6, 7] self.assertEqual(foo.at_least_two, [1, 6, 3, 7]) def test_setitem_too_small(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 3, 4]) with self.assertRaises(TraitError): foo.at_least_two[1:] = [] self.assertEqual(foo.at_least_two, [1, 2, 3, 4]) def test_setitem_too_large(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2, 3, 4]) with self.assertRaises(TraitError): foo.at_most_five[2:] = [10, 11, 12, 13] self.assertEqual(foo.at_most_five, [1, 2, 3, 4]) def test_setitem_from_iterable(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2]) foo.at_most_five[:1] = squares(4) self.assertEqual(foo.at_most_five, [0, 1, 4, 9, 2]) def test_setitem_extended_slice_bad_length(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 3, 4]) with self.assertRaises(ValueError): foo.at_least_two[1::2] = squares(3) self.assertEqual(foo.at_least_two, [1, 2, 3, 4]) def test_setitem_item_validation_failure(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 3, 4]) with self.assertRaises(TraitError): foo.at_least_two[2:] = [5.0, 6.0] self.assertEqual(foo.at_least_two, [1, 2, 3, 4]) def test_setitem_stop_lt_start(self): # Regression test for enthought/traits#994. events = [] foo = HasLengthConstrainedLists(at_least_two=[1, 2, 3, 4]) foo.on_trait_change( lambda event: events.append(event), "at_least_two_items") # Note: items are inserted at position 4, not position 2. foo.at_least_two[4:2] = [5, 6, 7] self.assertEqual(len(events), 1) event = events[0] self.assertEqual(event.index, 4) self.assertEqual(event.removed, []) self.assertEqual(event.added, [5, 6, 7]) def test_append(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2, 3]) foo.at_most_five.append(6) self.assertEqual(foo.at_most_five, [1, 2, 3, 6]) def test_append_too_large(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2, 3, 4, 5]) with self.assertRaises(TraitError): foo.at_most_five.append(6) self.assertEqual(foo.at_most_five, [1, 2, 3, 4, 5]) def test_clear(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2, 3, 4]) foo.at_most_five.clear() self.assertEqual(foo.at_most_five, []) def test_clear_too_small(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 3, 4]) with self.assertRaises(TraitError): foo.at_least_two.clear() self.assertEqual(foo.at_least_two, [1, 2, 3, 4]) def test_extend(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 3, 4]) foo.at_least_two.extend([10, 11]) self.assertEqual(foo.at_least_two, [1, 2, 3, 4, 10, 11]) def test_extend_too_large(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2, 3, 4]) with self.assertRaises(TraitError): foo.at_most_five.extend([10, 11, 12]) self.assertEqual(foo.at_most_five, [1, 2, 3, 4]) def test_extend_from_iterable(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2]) foo.at_most_five.extend(squares(3)) self.assertEqual(foo.at_most_five, [1, 2, 0, 1, 4]) def test_insert(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 3, 4]) foo.at_least_two.insert(3, 16) self.assertEqual(foo.at_least_two, [1, 2, 3, 16, 4]) def test_insert_too_large(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2, 3, 4, 5]) with self.assertRaises(TraitError): foo.at_most_five.insert(3, 16) with self.assertRaises(TraitError): foo.at_most_five.insert(-10, 16) with self.assertRaises(TraitError): foo.at_most_five.insert(10, 16) self.assertEqual(foo.at_most_five, [1, 2, 3, 4, 5]) def test_pop(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 6]) foo.at_least_two.pop() self.assertEqual(foo.at_least_two, [1, 2]) def test_pop_too_small(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2]) with self.assertRaises(TraitError): foo.at_least_two.pop() with self.assertRaises(TraitError): foo.at_least_two.pop(0) # TraitError takes precedence over the IndexError for a bad index. with self.assertRaises(TraitError): foo.at_least_two.pop(10) self.assertEqual(foo.at_least_two, [1, 2]) def test_pop_from_empty(self): foo = HasLengthConstrainedLists() with self.assertRaises(IndexError): foo.unconstrained.pop() with self.assertRaises(IndexError): foo.unconstrained.pop(10) def test_remove(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2, 6, 4]) foo.at_least_two.remove(2) self.assertEqual(foo.at_least_two, [1, 6, 4]) def test_remove_too_small(self): foo = HasLengthConstrainedLists(at_least_two=[1, 2]) with self.assertRaises(TraitError): foo.at_least_two.remove(1) with self.assertRaises(TraitError): foo.at_least_two.remove(2.0) # TraitError from the length violation takes precedence over # the ValueError for the vad value. with self.assertRaises(TraitError): foo.at_least_two.remove(10) self.assertEqual(foo.at_least_two, [1, 2]) def test_remove_from_empty(self): foo = HasLengthConstrainedLists() with self.assertRaises(ValueError): foo.unconstrained.remove(35) def test_length_violation_error_message(self): # Regression test for enthought/traits#1170 foo = HasLengthConstrainedLists(at_least_two=[1, 2]) with self.assertRaises(TraitError) as exc_cm: foo.at_least_two.remove(1) exc_message = str(exc_cm.exception) self.assertIn("'at_least_two' trait", exc_message) self.assertIn("HasLengthConstrainedLists instance", exc_message) self.assertIn("an integer", exc_message) self.assertIn("at least 2 items", exc_message) def test_dead_object_reference(self): foo = HasLengthConstrainedLists(at_most_five=[1, 2, 3, 4]) list_object = foo.at_most_five del foo list_object.append(5) self.assertEqual(list_object, [1, 2, 3, 4, 5]) with self.assertRaises(TraitError): list_object.append(4) traits-6.3.2/traits/tests/test_trait_prefix_list.py000066400000000000000000000024731414270267200226570ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the TraitPrefixList handler. """ import pickle import unittest from traits.api import HasTraits, TraitError, TraitPrefixList, Trait class TestTraitPrefixList(unittest.TestCase): def test_pickle_roundtrip(self): with self.assertWarns(DeprecationWarning): class A(HasTraits): foo = Trait("one", TraitPrefixList("zero", "one", "two")) a = A() foo_trait = a.traits()["foo"] reconstituted = pickle.loads(pickle.dumps(foo_trait)) self.assertEqual( foo_trait.validate(a, "foo", "ze"), "zero", ) with self.assertRaises(TraitError): foo_trait.validate(a, "foo", "zero-knowledge") self.assertEqual( reconstituted.validate(a, "foo", "ze"), "zero", ) with self.assertRaises(TraitError): reconstituted.validate(a, "foo", "zero-knowledge") traits-6.3.2/traits/tests/test_trait_set_object.py000066400000000000000000000370121414270267200224450ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import pickle import unittest from unittest import mock from traits.api import HasTraits, Set, Str from traits.trait_base import _validate_everything from traits.trait_errors import TraitError from traits.trait_set_object import TraitSet, TraitSetEvent from traits.trait_types import _validate_int def int_validator(value): try: return _validate_int(value) except TypeError: raise TraitError("int_validator error") def string_validator(value): if isinstance(value, str): return value else: raise TraitError("string_validator error") class TestTraitSet(unittest.TestCase): def setUp(self): self.added = None self.removed = None self.validator_args = None self.trait_set = None def notification_handler(self, trait_set, removed, added): self.trait_set = trait_set self.removed = removed self.added = added def validator(self, added): self.validator_args = added return added def test_init(self): ts = TraitSet({1, 2, 3}) self.assertEqual(ts, {1, 2, 3}) self.assertIs(ts.item_validator, _validate_everything) self.assertEqual(ts.notifiers, []) def test_init_with_no_input(self): ts = TraitSet() self.assertEqual(ts, set()) self.assertIs(ts.item_validator, _validate_everything) self.assertEqual(ts.notifiers, []) def test_validator(self): ts = TraitSet({1, 2, 3}, item_validator=int_validator) self.assertEqual(ts, {1, 2, 3}) self.assertEqual(ts.item_validator, int_validator) self.assertEqual(ts.notifiers, []) def test_notification(self): ts = TraitSet({1, 2, 3}, item_validator=int_validator, notifiers=[self.notification_handler]) self.assertEqual(ts, {1, 2, 3}) self.assertEqual(ts.item_validator, int_validator) self.assertEqual(ts.notifiers, [self.notification_handler]) ts.add(5) self.assertEqual(ts, {1, 2, 3, 5}) self.assertIs(self.trait_set, ts) self.assertEqual(self.removed, set()) self.assertEqual(self.added, {5}) def test_add(self): ts = TraitSet({1, 2, 3}, item_validator=int_validator, notifiers=[self.notification_handler]) ts.add(5) self.assertEqual(ts, {1, 2, 3, 5}) self.assertEqual(self.removed, set()) self.assertEqual(self.added, {5}) ts = TraitSet({"one", "two", "three"}, item_validator=string_validator, notifiers=[self.notification_handler]) ts.add("four") self.assertEqual(ts, {"one", "two", "three", "four"}) self.assertEqual(self.removed, set()) self.assertEqual(self.added, {"four"}) def test_add_iterable(self): python_set = set() iterable = (i for i in range(4)) python_set.add(iterable) ts = TraitSet() ts.add(iterable) # iterable has not been exhausted next(iterable) self.assertEqual(ts, python_set) def test_add_unhashable(self): with self.assertRaises(TypeError) as python_e: set().add([]) with self.assertRaises(TypeError) as trait_e: TraitSet().add([]) self.assertEqual( str(trait_e.exception), str(python_e.exception), ) def test_add_no_notification_for_no_op(self): # Test adding an existing item triggers no notifications notifier = mock.Mock() ts = TraitSet({1, 2}, notifiers=[notifier]) # when ts.add(1) # then notifier.assert_not_called() def test_remove(self): ts = TraitSet({1, 2, 3}, item_validator=int_validator, notifiers=[self.notification_handler]) ts.remove(3) self.assertEqual(ts, {1, 2}) self.assertEqual(self.removed, {3}) self.assertEqual(self.added, set()) with self.assertRaises(KeyError): ts.remove(3) def test_remove_iterable(self): iterable = (i for i in range(4)) ts = TraitSet() ts.add(iterable) self.assertIn(iterable, ts) # when ts.remove(iterable) # then self.assertEqual(ts, set()) def test_remove_does_not_call_validator(self): # Test validator should not be called with removed # items ts = TraitSet(item_validator=self.validator) ts.add("123") value, = ts # when self.validator_args = None ts.remove(value) # then # validator is not called. self.assertIsNone(self.validator_args) def test_update_with_non_iterable(self): python_set = set() with self.assertRaises(TypeError) as python_exc: python_set.update(None) ts = TraitSet() with self.assertRaises(TypeError) as trait_exc: ts.update(None) self.assertEqual( str(trait_exc.exception), str(python_exc.exception), ) def test_update_varargs(self): ts = TraitSet(notifiers=[self.notification_handler]) ts.update({1, 2}, {3, 4}) self.assertEqual(self.added, {1, 2, 3, 4}) self.assertEqual(self.removed, set()) def test_update_with_nothing(self): notifier = mock.Mock() python_set = set() python_set.update() ts = TraitSet(notifiers=[notifier]) # when ts.update() # then notifier.assert_not_called() self.assertEqual(ts, python_set) def test_discard(self): ts = TraitSet({1, 2, 3}, item_validator=int_validator, notifiers=[self.notification_handler]) ts.discard(3) self.assertEqual(ts, {1, 2}) self.assertEqual(self.removed, {3}) self.assertEqual(self.added, set()) # No error is raised ts.discard(3) def test_pop(self): ts = TraitSet({1, 2, 3}, item_validator=int_validator, notifiers=[self.notification_handler]) val = ts.pop() self.assertIn(val, {1, 2, 3}) self.assertEqual(self.removed, {val}) self.assertEqual(self.added, set()) def test_clear(self): ts = TraitSet({1, 2, 3}, item_validator=int_validator, notifiers=[self.notification_handler]) ts.clear() self.assertEqual(self.removed, {1, 2, 3}) self.assertEqual(self.added, set()) def test_clear_no_notifications_if_already_empty(self): # test no notifications are emitted if the set is already # empty. notifier = mock.Mock() ts = TraitSet(notifiers=[notifier]) ts.clear() notifier.assert_not_called() def test_ior(self): ts = TraitSet({1, 2, 3}, item_validator=int_validator, notifiers=[self.notification_handler]) ts |= {4, 5} self.assertEqual(self.removed, set()) self.assertEqual(self.added, {4, 5}) ts2 = TraitSet({6, 7}, item_validator=int_validator, notifiers=[self.notification_handler]) ts |= ts2 self.assertEqual(self.removed, set()) self.assertEqual(self.added, {6, 7}) with self.assertRaises(TypeError): ts |= 8 def test_iand(self): ts = TraitSet({1, 2, 3}, item_validator=int_validator, notifiers=[self.notification_handler]) ts &= {1, 2, 3} # Event is not fired self.assertIsNone(self.removed) self.assertIsNone(self.added) ts &= {1, 2} self.assertEqual(self.removed, {3}) self.assertEqual(self.added, set()) with self.assertRaises(TypeError): ts &= [3] def test_iand_does_not_call_validator(self): # Nothing are added, validator should not be called. ts = TraitSet({1, 2, 3}, item_validator=self.validator) values = list(ts) python_set = set(ts) python_set &= set(values[:2]) # when self.validator_args = None ts &= set(values[:2]) # then self.assertEqual(ts, python_set) self.assertIsNone(self.validator_args) def test_intersection_update_with_no_arguments(self): python_set = set([1, 2, 3]) python_set.intersection_update() notifier = mock.Mock() ts = TraitSet([1, 2, 3], notifiers=[notifier]) ts.intersection_update() self.assertEqual(ts, python_set) notifier.assert_not_called def test_intersection_update_varargs(self): python_set = set([1, 2, 3]) python_set.intersection_update([2], [3]) ts = TraitSet([1, 2, 3]) ts.intersection_update([2], [3]) self.assertEqual(ts, python_set) def test_intersection_update_with_iterable(self): python_set = set([1, 2, 3]) python_set.intersection_update(i for i in [1, 2]) ts = TraitSet([1, 2, 3]) ts.intersection_update(i for i in [1, 2]) self.assertEqual(ts, python_set) def test_ixor(self): ts = TraitSet({1, 2, 3}, item_validator=int_validator, notifiers=[self.notification_handler]) ts ^= {1, 2, 3, 5} self.assertEqual(self.removed, {1, 2, 3}) self.assertEqual(self.added, {5}) self.assertEqual(ts, {5}) with self.assertRaises(TypeError): ts ^= [5] def test_ixor_no_nofications_for_no_change(self): notifier = mock.Mock() ts_1 = TraitSet([1, 2], notifiers=[notifier]) # when ts_1 ^= set() # then notifier.assert_not_called() def test_ixor_with_iterable_items(self): iterable = range(2) python_set = set([iterable]) python_set ^= set([iterable]) self.assertEqual(python_set, set()) ts = TraitSet([iterable], item_validator=self.validator) self.validator_args = None ts ^= {iterable} self.assertEqual(ts, set()) # No values are being added. self.assertIsNone(self.validator_args) def test_ixor_validator_args_with_added(self): # Check the values given to the validator # when symmetric_difference_update is called. validator = mock.Mock(wraps=str) ts = TraitSet( [1, 2, 3], item_validator=validator, notifiers=[self.notification_handler], ) self.assertEqual(ts, set(["1", "2", "3"])) validator.reset_mock() # when ts ^= set(["2", 3, 4]) # then validator_inputs = set( value for (value,), _ in validator.call_args_list) self.assertEqual(validator_inputs, set([3, 4])) self.assertEqual(ts, set(["1", "3", "4"])) self.assertEqual(self.added, set(["4"])) self.assertEqual(self.removed, set(["2"])) def test_isub(self): ts = TraitSet({1, 2, 3}, item_validator=int_validator, notifiers=[self.notification_handler]) ts -= {2, 3, 5} self.assertEqual(self.removed, {2, 3}) self.assertEqual(self.added, set()) self.assertEqual(ts, {1}) with self.assertRaises(TypeError): ts -= [4, 5] def test_isub_validator_not_called(self): # isub never needs to add items, validator should not # be called. ts = TraitSet({1, 2, 3}, item_validator=self.validator) values = set(ts) # when self.validator_args = None ts -= values # then # Validator should not be called self.assertIsNone(self.validator_args) def test_isub_with_no_intersection(self): python_set = set([3, 4, 5]) python_set -= set(i for i in range(2)) notifier = mock.Mock() ts = TraitSet((3, 4, 5), notifiers=[notifier]) # when ts -= set(i for i in range(2)) # then self.assertEqual(ts, python_set) notifier.assert_not_called() def test_difference_update_with_no_arguments(self): python_set = set([1, 2, 3]) python_set.difference_update() ts = TraitSet([1, 2, 3]) ts.difference_update() self.assertEqual(ts, python_set) def test_difference_update_varargs(self): ts = TraitSet([1, 2, 3], notifiers=[self.notification_handler]) ts.difference_update([2], [3]) self.assertEqual(self.removed, {2, 3}) def test_get_state(self): ts = TraitSet(notifiers=[self.notification_handler]) states = ts.__getstate__() self.assertNotIn("notifiers", states) def test_set_state_exclude_notifiers(self): ts = TraitSet(notifiers=[]) ts.__setstate__({"notifiers": [self.notification_handler]}) self.assertEqual(ts.notifiers, []) class Foo(HasTraits): values = Set() def notifier(removed, added): pass class TestTraitSetObject(unittest.TestCase): def test_get_state(self): foo = Foo(values={1, 2, 3}) self.assertEqual( foo.values.notifiers, [foo.values.notifier]) states = foo.values.__getstate__() self.assertNotIn("notifiers", states) def test_pickle_with_notifier(self): foo = Foo(values={1, 2, 3}) foo.values.notifiers.append(notifier) protocols = range(pickle.HIGHEST_PROTOCOL + 1) for protocol in protocols: with self.subTest(protocol=protocol): serialized = pickle.dumps( foo.values, protocol=protocol) deserialized = pickle.loads(serialized) # Transient notifiers are gone. self.assertEqual( deserialized.notifiers, [deserialized.notifier], ) def test_validation(self): class TestSet(HasTraits): letters = Set(Str()) TestSet(letters={"4"}) with self.assertRaises(TraitError): TestSet(letters={4}) def test_notification_silenced_if_has_items_if_false(self): class Foo(HasTraits): values = Set(items=False) foo = Foo(values=set()) # name_items is a on_trait_change feature # Setting items to False effectively switches it off notifier = mock.Mock() foo.on_trait_change(lambda: notifier(), "values_items") # when foo.values.add(1) # then notifier.assert_not_called() class TestTraitSetEvent(unittest.TestCase): def test_trait_set_event_str_representation(self): """ Test string representation of the TraitSetEvent class. """ desired_repr = "TraitSetEvent(removed=set(), added=set())" trait_set_event = TraitSetEvent() self.assertEqual(desired_repr, str(trait_set_event)) self.assertEqual(desired_repr, repr(trait_set_event)) def test_trait_set_event_subclass_str_representation(self): """ Test string representation of a subclass of the TraitSetEvent class. """ class DifferentName(TraitSetEvent): pass desired_repr = "DifferentName(removed=set(), added=set())" different_name_subclass = DifferentName() self.assertEqual(desired_repr, str(different_name_subclass)) self.assertEqual(desired_repr, repr(different_name_subclass)) traits-6.3.2/traits/tests/test_trait_types.py000066400000000000000000000116151414270267200214710ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Unit test case for testing trait types created by subclassing TraitType. """ import os import sys import tempfile import textwrap import shutil import subprocess import unittest from traits.api import ( DefaultValue, Float, Function, Method, NoDefaultSpecified, Symbol, TraitType, Undefined ) from traits.testing.optional_dependencies import requires_numpy class TraitTypesTest(unittest.TestCase): def test_traits_shared_transient(self): # Regression test for a bug in traits where the same _metadata # dictionary was shared between different trait types. class LazyProperty(TraitType): #: The default value type to use. default_value_type = DefaultValue.constant def get(self, obj, name): return 1729 self.assertFalse(Float().transient) LazyProperty().as_ctrait() self.assertFalse(Float().transient) @requires_numpy def test_numpy_validators_loaded_if_numpy_present(self): # If 'numpy' is available, the numpy validators should be loaded, # even if numpy is imported after traits. test_script = textwrap.dedent(""" from traits.trait_types import float_fast_validate import numpy if numpy.floating in float_fast_validate: print("Success") else: print("Failure") """) this_python = sys.executable tmpdir = tempfile.mkdtemp() try: tmpfile = os.path.join(tmpdir, "test_script.py") with open(tmpfile, "w", encoding="utf-8") as f: f.write(test_script) cmd = [this_python, tmpfile] output = subprocess.check_output(cmd).decode("utf-8") finally: shutil.rmtree(tmpdir) self.assertEqual(output.strip(), "Success") def test_default_value_in_init(self): class MyTraitType(TraitType): pass # Tests for the behaviour of the default_value argument # to TraitType.__init__. trait_type = MyTraitType(default_value=23) self.assertEqual( trait_type.get_default_value(), (DefaultValue.constant, 23), ) # An explicit default value of None should work as expected. trait_type = MyTraitType(default_value=None) self.assertEqual( trait_type.get_default_value(), (DefaultValue.constant, None), ) # If no default is given, get_default_value() returns a value # of Undefined. trait_type = MyTraitType() self.assertEqual( trait_type.get_default_value(), (DefaultValue.constant, Undefined), ) # Similarly, if NoDefaultSpecified is given, get_default_value() # is Undefined. trait_type = MyTraitType(default_value=NoDefaultSpecified) self.assertEqual( trait_type.get_default_value(), (DefaultValue.constant, Undefined), ) def test_disallowed_default_value(self): class MyTraitType(TraitType): default_value_type = DefaultValue.disallow trait_type = MyTraitType() self.assertEqual( trait_type.get_default_value(), (DefaultValue.disallow, Undefined) ) ctrait = trait_type.as_ctrait() self.assertEqual( ctrait.default_value(), (DefaultValue.disallow, Undefined), ) self.assertEqual(ctrait.default_kind, "invalid") self.assertEqual(ctrait.default, Undefined) with self.assertRaises(ValueError): ctrait.default_value_for(None, "") class TestDeprecatedTraitTypes(unittest.TestCase): def test_function_deprecated(self): def some_function(): pass with self.assertWarnsRegex(DeprecationWarning, "Function trait type"): Function() with self.assertWarnsRegex(DeprecationWarning, "Function trait type"): Function(some_function, washable=True) def test_method_deprecated(self): class A: def some_method(self): pass with self.assertWarnsRegex(DeprecationWarning, "Method trait type"): Method() with self.assertWarnsRegex(DeprecationWarning, "Method trait type"): Method(A().some_method, gluten_free=False) def test_symbol_deprecated(self): with self.assertWarnsRegex(DeprecationWarning, "Symbol trait type"): Symbol("random:random") traits-6.3.2/traits/tests/test_traits.py000066400000000000000000001025411414270267200204270ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! # Imports import unittest import warnings from traits.api import ( Any, Bytes, CBytes, CFloat, CInt, ComparisonMode, Color, Delegate, Float, Font, HasTraits, Instance, Int, List, Range, RGBColor, Str, This, Trait, TraitError, TraitList, TraitPrefixList, TraitPrefixMap, Tuple, pop_exception_handler, push_exception_handler, ) from traits.testing.optional_dependencies import requires_traitsui # Base unit test classes: class BaseTest(object): def assign(self, value): self.obj.value = value def coerce(self, value): return value def test_assignment(self): obj = self.obj # Validate default value value = self._default_value self.assertEqual(obj.value, value) # Validate all legal values for i, value in enumerate(self._good_values): obj.value = value self.assertEqual(obj.value, self.coerce(value)) # If there's a defined if i < len(self._mapped_values): self.assertEqual(obj.value_, self._mapped_values[i]) # Validate correct behavior for illegal values for value in self._bad_values: self.assertRaises(TraitError, self.assign, value) class test_base2(unittest.TestCase): def indexed_assign(self, list, index, value): list[index] = value def indexed_range_assign(self, list, index1, index2, value): list[index1:index2] = value def extended_slice_assign(self, list, index1, index2, step, value): list[index1:index2:step] = value # This avoids using a method name that contains 'test' so that this is not # called by the tester directly. def check_values( self, name, default_value, good_values, bad_values, actual_values=None, mapped_values=None, ): obj = self.obj # Make sure the default value is correct: value = default_value self.assertEqual(getattr(obj, name), value) # Iterate over all legal values being tested: if actual_values is None: actual_values = good_values i = 0 for value in good_values: setattr(obj, name, value) self.assertEqual(getattr(obj, name), actual_values[i]) if mapped_values is not None: self.assertEqual( getattr(obj, name + "_"), mapped_values[i] ) i += 1 # Iterate over all illegal values being tested: for value in bad_values: self.assertRaises(TraitError, setattr, obj, name, value) class AnyTrait(HasTraits): value = Any class AnyTraitTest(BaseTest, unittest.TestCase): def setUp(self): self.obj = AnyTrait() _default_value = None _good_values = [10.0, b"ten", "ten", [10], {"ten": 10}, (10,), None, 1j] _mapped_values = [] _bad_values = [] class CoercibleIntTrait(HasTraits): value = CInt(99) class IntTrait(HasTraits): value = Int(99) class CoercibleIntTest(AnyTraitTest): def setUp(self): self.obj = CoercibleIntTrait() _default_value = 99 _good_values = [ 10, -10, 10.1, -10.1, "10", "-10", b"10", b"-10", ] _bad_values = [ "10L", "-10L", "10.1", "-10.1", b"10L", b"-10L", b"10.1", b"-10.1", "ten", b"ten", [10], {"ten": 10}, (10,), None, 1j, ] def coerce(self, value): try: return int(value) except: return int(float(value)) class IntTest(AnyTraitTest): def setUp(self): self.obj = IntTrait() _default_value = 99 _good_values = [10, -10] _bad_values = [ "ten", b"ten", [10], {"ten": 10}, (10,), None, 1j, 10.1, -10.1, "10L", "-10L", "10.1", "-10.1", b"10L", b"-10L", b"10.1", b"-10.1", "10", "-10", b"10", b"-10", ] try: import numpy as np except ImportError: pass else: _good_values.extend( [ np.int64(10), np.int64(-10), np.int32(10), np.int32(-10), np.int_(10), np.int_(-10), ] ) def coerce(self, value): try: return int(value) except: return int(float(value)) class CoercibleFloatTrait(HasTraits): value = CFloat(99.0) class FloatTrait(HasTraits): value = Float(99.0) class CoercibleFloatTest(AnyTraitTest): def setUp(self): self.obj = CoercibleFloatTrait() _default_value = 99.0 _good_values = [ 10, -10, 10.1, -10.1, "10", "-10", "10.1", "-10.1", b"10", b"-10", b"10.1", b"-10.1", ] _bad_values = [ "10L", "-10L", b"10L", b"-10L", "ten", b"ten", [10], {"ten": 10}, (10,), None, 1j, ] def coerce(self, value): return float(value) class FloatTest(AnyTraitTest): def setUp(self): self.obj = FloatTrait() _default_value = 99.0 _good_values = [10, -10, 10.1, -10.1] _bad_values = [ "ten", b"ten", [10], {"ten": 10}, (10,), None, 1j, "10", "-10", "10L", "-10L", "10.1", "-10.1", b"10", b"-10", b"10L", b"-10L", b"10.1", b"-10.1", ] def coerce(self, value): return float(value) # Trait that can only have 'complex'(i.e. imaginary) values: class ImaginaryValueTrait(HasTraits): value = Trait(99.0 - 99.0j) class ImaginaryValueTest(AnyTraitTest): def setUp(self): self.obj = ImaginaryValueTrait() _default_value = 99.0 - 99.0j _good_values = [ 10, -10, 10.1, -10.1, "10", "-10", "10.1", "-10.1", 10j, 10 + 10j, 10 - 10j, 10.1j, 10.1 + 10.1j, 10.1 - 10.1j, "10j", "10+10j", "10-10j", ] _bad_values = [b"10L", "-10L", "ten", [10], {"ten": 10}, (10,), None] def coerce(self, value): return complex(value) class StringTrait(HasTraits): value = Trait("string") class StringTest(AnyTraitTest): def setUp(self): self.obj = StringTrait() _default_value = "string" _good_values = [ 10, -10, 10.1, -10.1, "10", "-10", "10L", "-10L", "10.1", "-10.1", "string", 1j, [10], ["ten"], {"ten": 10}, (10,), None, ] _bad_values = [] def coerce(self, value): return str(value) class BytesTrait(HasTraits): value = Bytes(b"bytes") class BytesTest(StringTest): def setUp(self): self.obj = BytesTrait() _default_value = b"bytes" _good_values = [b"", b"10", b"-10"] _bad_values = [ 10, -10, 10.1, [b""], [b"bytes"], [0], {b"ten": b"10"}, (b"",), None, True, "", "string", ] def coerce(self, value): return bytes(value) class CoercibleBytesTrait(HasTraits): value = CBytes(b"bytes") class CoercibleBytesTest(StringTest): def setUp(self): self.obj = CoercibleBytesTrait() _default_value = b"bytes" _good_values = [ b"", b"10", b"-10", 10, [10], (10,), set([10]), {10: "foo"}, True, ] _bad_values = [ "", "string", -10, 10.1, [b""], [b"bytes"], [-10], (-10,), {-10: "foo"}, set([-10]), [256], (256,), {256: "foo"}, set([256]), {b"ten": b"10"}, (b"",), None, ] def coerce(self, value): return bytes(value) class EnumTrait(HasTraits): value = Trait([1, "one", 2, "two", 3, "three", 4.4, "four.four"]) class EnumTest(AnyTraitTest): def setUp(self): self.obj = EnumTrait() _default_value = 1 _good_values = [1, "one", 2, "two", 3, "three", 4.4, "four.four"] _bad_values = [0, "zero", 4, None] class MappedTrait(HasTraits): value = Trait("one", {"one": 1, "two": 2, "three": 3}) class MappedTest(AnyTraitTest): def setUp(self): self.obj = MappedTrait() _default_value = "one" _good_values = ["one", "two", "three"] _mapped_values = [1, 2, 3] _bad_values = ["four", 1, 2, 3, [1], (1,), {1: 1}, None] # Suppress DeprecationWarning from TraitPrefixList instantiation. with warnings.catch_warnings(): warnings.filterwarnings(action="ignore", category=DeprecationWarning) class PrefixListTrait(HasTraits): value = Trait("one", TraitPrefixList("one", "two", "three")) class PrefixListTest(AnyTraitTest): def setUp(self): self.obj = PrefixListTrait() _default_value = "one" _good_values = [ "o", "on", "one", "tw", "two", "th", "thr", "thre", "three", ] _bad_values = ["t", "one ", " two", 1, None] def coerce(self, value): return {"o": "one", "on": "one", "tw": "two", "th": "three"}[value[:2]] # Suppress DeprecationWarning from TraitPrefixMap instantiation. with warnings.catch_warnings(): warnings.filterwarnings(action="ignore", category=DeprecationWarning) class PrefixMapTrait(HasTraits): value = Trait("one", TraitPrefixMap({"one": 1, "two": 2, "three": 3})) class PrefixMapTest(AnyTraitTest): def setUp(self): self.obj = PrefixMapTrait() _default_value = "one" _good_values = [ "o", "on", "one", "tw", "two", "th", "thr", "thre", "three", ] _mapped_values = [1, 1, 1, 2, 2, 3, 3, 3] _bad_values = ["t", "one ", " two", 1, None] def coerce(self, value): return {"o": "one", "on": "one", "tw": "two", "th": "three"}[value[:2]] # This test a combination of Trait, a default, a mapping and a function def str_cast_to_int(object, name, value): """ A function that validates the value is a str and then converts it to an int using its length. """ if not isinstance(value, str): raise TraitError("Not a string!") return len(value) class TraitWithMappingAndCallable(HasTraits): value = Trait( "white", {"white": 0, "red": 1, (0, 0, 0): 999}, str_cast_to_int, ) class TestTraitWithMappingAndCallable(unittest.TestCase): """ Test that demonstrates a usage of Trait where TraitMap is used but it cannot be replaced with Map. The callable causes the key value to be changed to match the mapped value. e.g. this would not work: value = Union( Map({"white": 0, "red": 1, (0,0,0): 999}), NewTraitType(), default_value="white", ) where NewTraitType is a subclass of TraitType with ``validate`` simply calls str_cast_to_int """ def test_trait_default(self): obj = TraitWithMappingAndCallable() # the value is not 'white' any more. self.assertEqual(obj.value, 5) self.assertEqual(obj.value_, 5) def test_trait_set_value_use_callable(self): obj = TraitWithMappingAndCallable(value="red") # The value is not 'red' any more. # the callable is used, not the mapping. self.assertEqual(obj.value, 3) self.assertEqual(obj.value_, 3) def test_trait_set_value_use_mapping(self): obj = TraitWithMappingAndCallable(value=(0, 0, 0)) # Now this uses the mapping, and the value is the original one. self.assertEqual(obj.value, (0, 0, 0)) self.assertEqual(obj.value_, 999) # Old style class version: class OTraitTest1: pass class OTraitTest2(OTraitTest1): pass class OTraitTest3(OTraitTest2): pass class OBadTraitTest: pass otrait_test1 = OTraitTest1() class OldInstanceTrait(HasTraits): value = Trait(otrait_test1) class OldInstanceTest(AnyTraitTest): def setUp(self): self.obj = OldInstanceTrait() _default_value = otrait_test1 _good_values = [ otrait_test1, OTraitTest1(), OTraitTest2(), OTraitTest3(), None, ] _bad_values = [ 0, 0.0, 0j, OTraitTest1, OTraitTest2, OBadTraitTest(), b"bytes", "string", [otrait_test1], (otrait_test1,), {"data": otrait_test1}, ] # New style class version: class NTraitTest1(object): pass class NTraitTest2(NTraitTest1): pass class NTraitTest3(NTraitTest2): pass class NBadTraitTest: pass ntrait_test1 = NTraitTest1() class NewInstanceTrait(HasTraits): value = Trait(ntrait_test1) class NewInstanceTest(AnyTraitTest): def setUp(self): self.obj = NewInstanceTrait() _default_value = ntrait_test1 _good_values = [ ntrait_test1, NTraitTest1(), NTraitTest2(), NTraitTest3(), None, ] _bad_values = [ 0, 0.0, 0j, NTraitTest1, NTraitTest2, NBadTraitTest(), b"bytes", "string", [ntrait_test1], (ntrait_test1,), {"data": ntrait_test1}, ] class FactoryClass(HasTraits): pass class ConsumerClass(HasTraits): x = Instance(FactoryClass, ()) class ConsumerSubclass(ConsumerClass): x = FactoryClass() embedded_instance_trait = Trait( "", Str, Instance("traits.has_traits.HasTraits") ) class Dummy(HasTraits): x = embedded_instance_trait xl = List(embedded_instance_trait) class RegressionTest(unittest.TestCase): """ Check that fixed bugs stay fixed. """ def test_factory_subclass_no_segfault(self): """ Test that we can provide an instance as a default in the definition of a subclass. """ # There used to be a bug where this would segfault. obj = ConsumerSubclass() obj.x def test_trait_compound_instance(self): """ Test that a deferred Instance() embedded in a TraitCompound handler and then a list will not replace the validate method for the outermost trait. """ # Pass through an instance in order to make the instance trait resolve # the class. d = Dummy() d.xl = [HasTraits()] d.x = "OK" # Trait(using a function) that must be an odd integer: def odd_integer(object, name, value): try: float(value) if (value % 2) == 1: return int(value) except: pass raise TraitError class OddIntegerTrait(HasTraits): value = Trait(99, odd_integer) class OddIntegerTest(AnyTraitTest): def setUp(self): self.obj = OddIntegerTrait() _default_value = 99 _good_values = [ 1, 3, 5, 7, 9, 999999999, 1.0, 3.0, 5.0, 7.0, 9.0, 999999999.0, -1, -3, -5, -7, -9, -999999999, -1.0, -3.0, -5.0, -7.0, -9.0, -999999999.0, ] _bad_values = [0, 2, -2, 1j, None, "1", [1], (1,), {1: 1}] class NotifierTraits(HasTraits): value1 = Int value2 = Int value1_count = Int value2_count = Int def _anytrait_changed(self, trait_name, old, new): if trait_name == "value1": self.value1_count += 1 elif trait_name == "value2": self.value2_count += 1 def _value1_changed(self, old, new): self.value1_count += 1 def _value2_changed(self, old, new): self.value2_count += 1 class NotifierTests(unittest.TestCase): def setUp(self): obj = self.obj = NotifierTraits() obj.value1 = 0 obj.value2 = 0 obj.value1_count = 0 obj.value2_count = 0 def tearDown(self): obj = self.obj obj.on_trait_change(self.on_value1_changed, "value1", remove=True) obj.on_trait_change(self.on_value2_changed, "value2", remove=True) obj.on_trait_change(self.on_anytrait_changed, remove=True) def on_anytrait_changed(self, object, trait_name, old, new): if trait_name == "value1": self.obj.value1_count += 1 elif trait_name == "value2": self.obj.value2_count += 1 def on_value1_changed(self): self.obj.value1_count += 1 def on_value2_changed(self): self.obj.value2_count += 1 def test_simple(self): obj = self.obj obj.value1 = 1 self.assertEqual(obj.value1_count, 2) self.assertEqual(obj.value2_count, 0) obj.value2 = 1 self.assertEqual(obj.value1_count, 2) self.assertEqual(obj.value2_count, 2) def test_complex(self): obj = self.obj obj.on_trait_change(self.on_value1_changed, "value1") obj.value1 = 1 self.assertEqual(obj.value1_count, 3) self.assertEqual(obj.value2_count, 0) obj.on_trait_change(self.on_value2_changed, "value2") obj.value2 = 1 self.assertEqual(obj.value1_count, 3) self.assertEqual(obj.value2_count, 3) obj.on_trait_change(self.on_anytrait_changed) obj.value1 = 2 self.assertEqual(obj.value1_count, 7) self.assertEqual(obj.value2_count, 3) obj.value1 = 2 self.assertEqual(obj.value1_count, 7) self.assertEqual(obj.value2_count, 3) obj.value2 = 2 self.assertEqual(obj.value1_count, 7) self.assertEqual(obj.value2_count, 7) obj.on_trait_change(self.on_value1_changed, "value1", remove=True) obj.value1 = 3 self.assertEqual(obj.value1_count, 10) self.assertEqual(obj.value2_count, 7) obj.on_trait_change(self.on_value2_changed, "value2", remove=True) obj.value2 = 3 self.assertEqual(obj.value1_count, 10) self.assertEqual(obj.value2_count, 10) obj.on_trait_change(self.on_anytrait_changed, remove=True) obj.value1 = 4 self.assertEqual(obj.value1_count, 12) self.assertEqual(obj.value2_count, 10) obj.value2 = 4 self.assertEqual(obj.value1_count, 12) self.assertEqual(obj.value2_count, 12) class RaisesArgumentlessRuntimeError(HasTraits): x = Int(0) def _x_changed(self): raise RuntimeError class TestRuntimeError(unittest.TestCase): def setUp(self): push_exception_handler(lambda *args: None, reraise_exceptions=True) def tearDown(self): pop_exception_handler() def test_runtime_error(self): f = RaisesArgumentlessRuntimeError() self.assertRaises(RuntimeError, setattr, f, "x", 5) class DelegatedFloatTrait(HasTraits): value = Trait(99.0) class DelegateTrait(HasTraits): value = Delegate("delegate") delegate = Trait(DelegatedFloatTrait()) class DelegateTrait2(DelegateTrait): delegate = Trait(DelegateTrait()) class DelegateTrait3(DelegateTrait): delegate = Trait(DelegateTrait2()) class DelegateTests(unittest.TestCase): def test_delegation(self): obj = DelegateTrait3() self.assertEqual(obj.value, 99.0) parent1 = obj.delegate parent2 = parent1.delegate parent3 = parent2.delegate parent3.value = 3.0 self.assertEqual(obj.value, 3.0) parent2.value = 2.0 self.assertEqual(obj.value, 2.0) self.assertEqual(parent3.value, 3.0) parent1.value = 1.0 self.assertEqual(obj.value, 1.0) self.assertEqual(parent2.value, 2.0) self.assertEqual(parent3.value, 3.0) obj.value = 0.0 self.assertEqual(obj.value, 0.0) self.assertEqual(parent1.value, 1.0) self.assertEqual(parent2.value, 2.0) self.assertEqual(parent3.value, 3.0) del obj.value self.assertEqual(obj.value, 1.0) del parent1.value self.assertEqual(obj.value, 2.0) self.assertEqual(parent1.value, 2.0) del parent2.value self.assertEqual(obj.value, 3.0) self.assertEqual(parent1.value, 3.0) self.assertEqual(parent2.value, 3.0) del parent3.value # Uncommenting the following line allows # the last assertions to pass. However, this # may not be intended behavior, so keeping # the line commented. # del parent2.value self.assertEqual(obj.value, 99.0) self.assertEqual(parent1.value, 99.0) self.assertEqual(parent2.value, 99.0) self.assertEqual(parent3.value, 99.0) # Complex(i.e. 'composite') Traits tests: # Make a TraitCompound handler that does not have a fast_validate so we can # check for a particular regression. slow = Trait(1, Range(1, 3), Range(-3, -1)) try: del slow.handler.fast_validate except AttributeError: pass # Suppress DeprecationWarnings from TraitPrefixList and TraitPrefixMap with warnings.catch_warnings(): warnings.filterwarnings(action="ignore", category=DeprecationWarning) class complex_value(HasTraits): num1 = Trait(1, Range(1, 5), Range(-5, -1)) num2 = Trait( 1, Range(1, 5), TraitPrefixList("one", "two", "three", "four", "five"), ) num3 = Trait( 1, Range(1, 5), TraitPrefixMap( {"one": 1, "two": 2, "three": 3, "four": 4, "five": 5} ), ) num4 = Trait(1, Trait(1, Tuple, slow), 10) num5 = Trait(1, 10, Trait(1, Tuple, slow)) class test_complex_value(test_base2): def setUp(self): self.obj = complex_value() def test_num1(self): self.check_values( "num1", 1, [1, 2, 3, 4, 5, -1, -2, -3, -4, -5], [ 0, 6, -6, "0", "6", "-6", 0.0, 6.0, -6.0, [1], (1,), {1: 1}, None, ], [1, 2, 3, 4, 5, -1, -2, -3, -4, -5], ) def test_enum_exceptions(self): """ Check that enumerated values can be combined with nested TraitCompound handlers. """ self.check_values( "num4", 1, [1, 2, 3, -3, -2, -1, 10, ()], [0, 4, 5, -5, -4, 11] ) self.check_values( "num5", 1, [1, 2, 3, -3, -2, -1, 10, ()], [0, 4, 5, -5, -4, 11] ) class test_list_value(test_base2): def setUp(self): with self.assertWarns(DeprecationWarning): class list_value(HasTraits): # Trait definitions: list1 = Trait([2], TraitList(Trait([1, 2, 3, 4]), maxlen=4)) list2 = Trait( [2], TraitList(Trait([1, 2, 3, 4]), minlen=1, maxlen=4) ) alist = List() self.obj = list_value() self.last_event = None def tearDown(self): del self.last_event def del_range(self, list, index1, index2): del list[index1:index2] def del_extended_slice(self, list, index1, index2, step): del list[index1:index2:step] def check_list(self, list): self.assertEqual(list, [2]) self.assertEqual(len(list), 1) list.append(3) self.assertEqual(len(list), 2) list[1] = 2 self.assertEqual(list[1], 2) self.assertEqual(len(list), 2) list[0] = 1 self.assertEqual(list[0], 1) self.assertEqual(len(list), 2) self.assertRaises(TraitError, self.indexed_assign, list, 0, 5) self.assertRaises(TraitError, list.append, 5) self.assertRaises(TraitError, list.extend, [1, 2, 3]) list.extend([3, 4]) self.assertEqual(list, [1, 2, 3, 4]) self.assertRaises(TraitError, list.append, 1) self.assertRaises( ValueError, self.extended_slice_assign, list, 0, 4, 2, [4, 5, 6] ) del list[1] self.assertEqual(list, [1, 3, 4]) del list[0] self.assertEqual(list, [3, 4]) list[:0] = [1, 2] self.assertEqual(list, [1, 2, 3, 4]) self.assertRaises( TraitError, self.indexed_range_assign, list, 0, 0, [1] ) del list[0:3] self.assertEqual(list, [4]) self.assertRaises( TraitError, self.indexed_range_assign, list, 0, 0, [4, 5] ) def test_list1(self): self.check_list(self.obj.list1) def test_list2(self): self.check_list(self.obj.list2) self.assertRaises(TraitError, self.del_range, self.obj.list2, 0, 1) self.assertRaises( TraitError, self.del_extended_slice, self.obj.list2, 4, -5, -1 ) def assertLastTraitListEventEqual(self, index, removed, added): self.assertEqual(self.last_event.index, index) self.assertEqual(self.last_event.removed, removed) self.assertEqual(self.last_event.added, added) def test_trait_list_event(self): """ Record TraitListEvent behavior. """ self.obj.alist = [1, 2, 3, 4] self.obj.on_trait_change(self._record_trait_list_event, "alist_items") del self.obj.alist[0] self.assertLastTraitListEventEqual(0, [1], []) self.obj.alist.append(5) self.assertLastTraitListEventEqual(3, [], [5]) self.obj.alist[0:2] = [6, 7] self.assertLastTraitListEventEqual(0, [2, 3], [6, 7]) self.obj.alist[:2] = [4, 5] self.assertLastTraitListEventEqual(0, [6, 7], [4, 5]) self.obj.alist[0:2:1] = [8, 9] self.assertLastTraitListEventEqual(0, [4, 5], [8, 9]) self.obj.alist[0:2:1] = [8, 9] # If list values stay the same, a new TraitListEvent will be generated. self.assertLastTraitListEventEqual(0, [8, 9], [8, 9]) old_event = self.last_event self.obj.alist[4:] = [] # If no structural change, NO new TraitListEvent will be generated. self.assertIs(self.last_event, old_event) self.obj.alist[0:4:2] = [10, 11] self.assertLastTraitListEventEqual( slice(0, 3, 2), [8, 4], [10, 11] ) del self.obj.alist[1:4:2] self.assertLastTraitListEventEqual(slice(1, 4, 2), [9, 5], []) self.obj.alist = [1, 2, 3, 4] del self.obj.alist[2:4] self.assertLastTraitListEventEqual(2, [3, 4], []) self.obj.alist[:0] = [5, 6, 7, 8] self.assertLastTraitListEventEqual(0, [], [5, 6, 7, 8]) del self.obj.alist[:2] self.assertLastTraitListEventEqual(0, [5, 6], []) del self.obj.alist[0:2] self.assertLastTraitListEventEqual(0, [7, 8], []) del self.obj.alist[:] self.assertLastTraitListEventEqual(0, [1, 2], []) def _record_trait_list_event(self, object, name, old, new): self.last_event = new class ThisDummy(HasTraits): allows_none = This() disallows_none = This(allow_none=False) class TestThis(unittest.TestCase): def test_this_none(self): d = ThisDummy() self.assertIsNone(d.allows_none) d.allows_none = None d.allows_none = ThisDummy() self.assertIsNotNone(d.allows_none) d.allows_none = None self.assertIsNone(d.allows_none) # Still starts out as None, unavoidably. self.assertIsNone(d.disallows_none) d.disallows_none = ThisDummy() self.assertIsNotNone(d.disallows_none) with self.assertRaises(TraitError): d.disallows_none = None self.assertIsNotNone(d.disallows_none) def test_this_other_class(self): d = ThisDummy() with self.assertRaises(TraitError): d.allows_none = object() self.assertIsNone(d.allows_none) class ComparisonModeTests(unittest.TestCase): def test_comparison_mode_none(self): class HasComparisonMode(HasTraits): bar = Trait(comparison_mode=ComparisonMode.none) old_compare = HasComparisonMode() events = [] old_compare.on_trait_change(lambda: events.append(None), "bar") some_list = [1, 2, 3] self.assertEqual(len(events), 0) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = some_list self.assertEqual(len(events), 2) old_compare.bar = [1, 2, 3] self.assertEqual(len(events), 3) old_compare.bar = [4, 5, 6] self.assertEqual(len(events), 4) def test_comparison_mode_identity(self): class HasComparisonMode(HasTraits): bar = Trait(comparison_mode=ComparisonMode.identity) old_compare = HasComparisonMode() events = [] old_compare.on_trait_change(lambda: events.append(None), "bar") some_list = [1, 2, 3] self.assertEqual(len(events), 0) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = [1, 2, 3] self.assertEqual(len(events), 2) old_compare.bar = [4, 5, 6] self.assertEqual(len(events), 3) def test_comparison_mode_equality(self): class HasComparisonMode(HasTraits): bar = Trait(comparison_mode=ComparisonMode.equality) old_compare = HasComparisonMode() events = [] old_compare.on_trait_change(lambda: events.append(None), "bar") some_list = [1, 2, 3] self.assertEqual(len(events), 0) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = [1, 2, 3] self.assertEqual(len(events), 1) old_compare.bar = [4, 5, 6] self.assertEqual(len(events), 2) def test_rich_compare_false(self): with warnings.catch_warnings(record=True) as warn_msgs: warnings.simplefilter("always", DeprecationWarning) class OldRichCompare(HasTraits): bar = Trait(rich_compare=False) # Check for a DeprecationWarning. self.assertEqual(len(warn_msgs), 1) warn_msg = warn_msgs[0] self.assertIs(warn_msg.category, DeprecationWarning) self.assertIn( "'rich_compare' metadata has been deprecated", str(warn_msg.message) ) _, _, this_module = __name__.rpartition(".") self.assertIn(this_module, warn_msg.filename) # Behaviour matches comparison_mode=ComparisonMode.identity. old_compare = OldRichCompare() events = [] old_compare.on_trait_change(lambda: events.append(None), "bar") some_list = [1, 2, 3] self.assertEqual(len(events), 0) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = [1, 2, 3] self.assertEqual(len(events), 2) old_compare.bar = [4, 5, 6] self.assertEqual(len(events), 3) def test_rich_compare_true(self): with warnings.catch_warnings(record=True) as warn_msgs: warnings.simplefilter("always", DeprecationWarning) class OldRichCompare(HasTraits): bar = Trait(rich_compare=True) # Check for a DeprecationWarning. self.assertEqual(len(warn_msgs), 1) warn_msg = warn_msgs[0] self.assertIs(warn_msg.category, DeprecationWarning) self.assertIn( "'rich_compare' metadata has been deprecated", str(warn_msg.message) ) _, _, this_module = __name__.rpartition(".") self.assertIn(this_module, warn_msg.filename) # Behaviour matches comparison_mode=ComparisonMode.identity. old_compare = OldRichCompare() events = [] old_compare.on_trait_change(lambda: events.append(None), "bar") some_list = [1, 2, 3] self.assertEqual(len(events), 0) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = some_list self.assertEqual(len(events), 1) old_compare.bar = [1, 2, 3] self.assertEqual(len(events), 1) old_compare.bar = [4, 5, 6] self.assertEqual(len(events), 2) @requires_traitsui class TestDeprecatedTraits(unittest.TestCase): def test_color_deprecated(self): with self.assertWarnsRegex(DeprecationWarning, "'Color' in 'traits'"): Color() def test_rgb_color_deprecated(self): with self.assertWarnsRegex(DeprecationWarning, "'RGBColor' in 'traits'"): RGBColor() def test_font_deprecated(self): with self.assertWarnsRegex(DeprecationWarning, "'Font' in 'traits'"): Font() traits-6.3.2/traits/tests/test_traits_listener.py000066400000000000000000000360311414270267200223340ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Unittest tests on ListenerParser, ListenerBase etc. See test_listeners for integration tests on the public API using these objects. """ from functools import partial import unittest from traits import traits_listener from traits.api import ( pop_exception_handler, push_exception_handler, TraitError, Undefined, ) def assert_listener_item_equal(test_case, item1, item2, msg=None): """ Assertion function for comparing two instances of ListenerItem. """ def get_msg(name, msg): return "{name} mismatched. {msg}".format( name=name, msg="" if msg is None else msg ) test_case.assertEqual( item1.name, item2.name, msg=get_msg("name", msg), ) test_case.assertEqual( item1.metadata_name, item2.metadata_name, msg=get_msg("metadata_name", msg), ) test_case.assertEqual( item1.metadata_defined, item2.metadata_defined, msg=get_msg("metadata_defined", msg), ) test_case.assertEqual( item1.is_anytrait, item2.is_anytrait, msg=get_msg("is_anytrait", msg), ) test_case.assertEqual( item1.dispatch, item2.dispatch, msg=get_msg("dispatch", msg), ) test_case.assertEqual( item1.notify, item2.notify, msg=get_msg("notify", msg), ) test_case.assertEqual( item1.is_list_handler, item2.is_list_handler, msg=get_msg("is_list_handler", msg), ) test_case.assertEqual( item1.type, item2.type, msg=get_msg("type", msg), ) if item1.next is item2.next: # avoid recursion pass else: test_case.assertEqual( item1.next, item2.next, msg=get_msg("next", msg), ) class TestListenerParser(unittest.TestCase): def setUp(self): push_exception_handler( handler=lambda *args: None, reraise_exceptions=True) self.addTypeEqualityFunc( traits_listener.ListenerItem, partial(assert_listener_item_equal, self) ) def tearDown(self): pop_exception_handler() def test_listener_parser_single_string(self): text = "some_trait_name" parser = traits_listener.ListenerParser(text=text) expected = traits_listener.ListenerItem( name="some_trait_name", metadata_name="", metadata_defined=True, is_anytrait=False, dispatch="", notify=True, is_list_handler=False, type=traits_listener.ANY_LISTENER, next=None, ) self.assertEqual(parser.listener, expected) def test_listener_parser_trait_of_trait_dot(self): text = "parent.child" parser = traits_listener.ListenerParser(text=text) # then common_traits = dict( metadata_name="", metadata_defined=True, is_anytrait=False, dispatch="", notify=True, is_list_handler=False, type=traits_listener.ANY_LISTENER, ) expected_child = traits_listener.ListenerItem( name="child", next=None, **common_traits ) expected_parent = traits_listener.ListenerItem( name="parent", next=expected_child, **common_traits ) self.assertEqual(parser.listener, expected_parent) def test_listener_parser_trait_of_trait_of_trait_mixed(self): text = "parent.child1:child2" parser = traits_listener.ListenerParser(text=text) # then common_traits = dict( metadata_name="", metadata_defined=True, is_anytrait=False, dispatch="", is_list_handler=False, type=traits_listener.ANY_LISTENER, ) expected_child2 = traits_listener.ListenerItem( name="child2", notify=True, next=None, **common_traits ) expected_child1 = traits_listener.ListenerItem( name="child1", notify=False, # ':' indicates no notifications next=expected_child2, **common_traits ) expected_parent = traits_listener.ListenerItem( name="parent", notify=True, next=expected_child1, **common_traits ) self.assertEqual(parser.listener, expected_parent) def test_parse_comma_separated_text(self): text = "child1, child2, child3" parser = traits_listener.ListenerParser(text=text) listener_group = parser.listener common_traits = dict( metadata_name="", metadata_defined=True, is_anytrait=False, dispatch="", notify=True, is_list_handler=False, type=traits_listener.ANY_LISTENER, next=None, ) expected_items = [ traits_listener.ListenerItem( name="child1", **common_traits, ), traits_listener.ListenerItem( name="child2", **common_traits, ), traits_listener.ListenerItem( name="child3", **common_traits, ), ] self.assertEqual(len(listener_group.items), len(expected_items)) for actual, expected in zip(listener_group.items, expected_items): self.assertEqual(actual, expected) def test_parse_comma_separated_text_trailing_comma(self): # Made illegal, see enthought/traits#406 text = "child1, child2, child3," with self.assertRaises(TraitError): traits_listener.ListenerParser(text=text) def test_parse_text_with_question_mark(self): text = "foo?.bar?" parser = traits_listener.ListenerParser(text=text) # parent listener = parser.listener self.assertEqual(listener.name, "foo?") # child listener = listener.next self.assertEqual(listener.name, "bar?") def test_parse_nested_empty_prefix_with_question_mark(self): text = "foo.?" with self.assertRaises(TraitError) as exception_context: traits_listener.ListenerParser(text=text) self.assertIn( "Expected non-empty name", str(exception_context.exception)) def test_parse_question_mark_only(self): text = "?" with self.assertRaises(TraitError) as exception_context: traits_listener.ListenerParser(text=text) self.assertIn( "Expected non-empty name", str(exception_context.exception)) def test_parse_with_asterisk(self): text = "prefix*" parser = traits_listener.ListenerParser(text=text) actual = parser.listener expected = traits_listener.ListenerItem( name="prefix", metadata_name="", metadata_defined=True, is_anytrait=False, dispatch="", notify=True, is_list_handler=False, type=traits_listener.ANY_LISTENER, # next is the ListenItem itself (so it is recursive) next=actual, ) self.assertEqual(actual, expected) def test_parse_text_with_metadata(self): text = "prefix+foo" parser = traits_listener.ListenerParser(text=text) expected = traits_listener.ListenerItem( name="prefix*", metadata_name="foo", metadata_defined=True, is_anytrait=False, dispatch="", notify=True, is_list_handler=False, type=traits_listener.ANY_LISTENER, next=None, ) self.assertEqual(parser.listener, expected) def test_parse_is_anytrait_plus(self): text = "+" parser = traits_listener.ListenerParser(text=text) expected = traits_listener.ListenerItem( name="*", metadata_name="", metadata_defined=True, is_anytrait=False, dispatch="", notify=True, is_list_handler=False, type=traits_listener.ANY_LISTENER, next=None, ) self.assertEqual(parser.listener, expected) def test_parse_is_anytrait_minus(self): text = "-" parser = traits_listener.ListenerParser(text=text) expected = traits_listener.ListenerItem( name="*", metadata_name="", metadata_defined=False, # the effect of '-' is_anytrait=True, # the effect of '-' dispatch="", notify=True, is_list_handler=False, type=traits_listener.ANY_LISTENER, next=None, ) self.assertEqual(parser.listener, expected) def test_parse_nested_exclude_empty_metadata_name(self): text = "foo-" parser = traits_listener.ListenerParser(text=text) expected = traits_listener.ListenerItem( name="foo*", metadata_name="", metadata_defined=False, # the effect of '-' is_anytrait=False, dispatch="", notify=True, is_list_handler=False, type=traits_listener.ANY_LISTENER, next=None, ) self.assertEqual(parser.listener, expected) def test_parse_exclude_metadata(self): text = "-foo" parser = traits_listener.ListenerParser(text=text) expected = traits_listener.ListenerItem( name="*", metadata_name="foo", metadata_defined=False, # the effect of '-' is_anytrait=False, dispatch="", notify=True, is_list_handler=False, type=traits_listener.ANY_LISTENER, next=None, ) self.assertEqual(parser.listener, expected) def test_parse_square_bracket(self): text = "[foo, bar]" parser = traits_listener.ListenerParser(text=text) listener_group = parser.listener # then common_traits = dict( metadata_name="", metadata_defined=True, is_anytrait=False, dispatch="", notify=True, is_list_handler=False, type=traits_listener.ANY_LISTENER, next=None, ) expected_items = [ traits_listener.ListenerItem( name="foo", **common_traits, ), traits_listener.ListenerItem( name="bar", **common_traits, ) ] self.assertEqual(len(listener_group.items), len(expected_items)) for actual, expected in zip(listener_group.items, expected_items): self.assertEqual(actual, expected) def test_parse_square_bracket_nested_attribute(self): text = "[foo, bar].baz" parser = traits_listener.ListenerParser(text=text) listener_group = parser.listener self.assertEqual(len(listener_group.items), 2) common_traits = dict( metadata_name="", metadata_defined=True, is_anytrait=False, dispatch="", notify=True, is_list_handler=False, type=traits_listener.ANY_LISTENER, ) child_listener = traits_listener.ListenerItem( name="baz", next=None, **common_traits, ) expected_items = [ traits_listener.ListenerItem( name="foo", next=child_listener, **common_traits, ), traits_listener.ListenerItem( name="bar", next=child_listener, **common_traits, ) ] self.assertEqual(len(listener_group.items), len(expected_items)) for actual, expected in zip(listener_group.items, expected_items): self.assertEqual(actual, expected) def test_parse_square_bracket_in_middle(self): text = "foo.[bar, baz]" parser = traits_listener.ListenerParser(text=text) actual_foo = parser.listener # next is a ListenerGroup, and is checked separately actual_next = actual_foo.next actual_foo.next = None common_traits = dict( metadata_name="", metadata_defined=True, is_anytrait=False, dispatch="", notify=True, is_list_handler=False, type=traits_listener.ANY_LISTENER, next=None ) expected_foo = traits_listener.ListenerItem( name="foo", **common_traits, ) self.assertEqual(actual_foo, expected_foo) # Next listener is a ListenerGroup expected_items = [ traits_listener.ListenerItem( name="bar", **common_traits, ), traits_listener.ListenerItem( name="baz", **common_traits, ), ] self.assertEqual(len(actual_next.items), len(expected_items)) for actual, expected in zip(actual_next.items, expected_items): self.assertEqual(actual, expected) def test_parse_is_list_handler(self): text = "foo[]" parser = traits_listener.ListenerParser(text=text) expected = traits_listener.ListenerItem( name="foo", metadata_name="", metadata_defined=True, is_anytrait=False, dispatch="", notify=True, is_list_handler=True, # the effect of '[]' type=traits_listener.ANY_LISTENER, next=None, ) self.assertEqual(parser.listener, expected) def test_listener_handler_for_method(self): class A: def __init__(self, value): self.value = value def square(self): return self.value * self.value a = A(7) listener_handler = traits_listener.ListenerHandler(a.square) handler = listener_handler() self.assertEqual(handler(), 49) # listener_handler does not keep the object 'a' alive del a, handler handler = listener_handler() self.assertEqual(handler, Undefined) def test_listener_handler_for_function(self): def square(value): return value * value listener_handler = traits_listener.ListenerHandler(square) handler = listener_handler() self.assertEqual(handler(9), 81) # listener_handler *does* keep the 'square' function alive del square, handler handler = listener_handler() self.assertEqual(handler(5), 25) traits-6.3.2/traits/tests/test_tuple.py000066400000000000000000000042431414270267200202520ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Unit tests for the Tuple trait type. """ import unittest from traits.api import ( BaseInt, Either, HasTraits, Int, List, Str, TraitError, Tuple) from traits.tests.tuple_test_mixin import TupleTestMixin class BadInt(BaseInt): """ Test class used to simulate a Tuple item with bad validation. """ # Describe the trait type info_text = 'a bad integer' def validate(self, object, name, value): # Simulate a coding error in the validation method return 1 / 0 class TupleTestCase(TupleTestMixin, unittest.TestCase): def setUp(self): self.trait = Tuple def test_unexpected_validation_exceptions_are_propagated(self): # Regression test for enthought/traits#1389. class A(HasTraits): foo = Tuple(BadInt(), BadInt()) bar = Either(Int, Tuple(BadInt(), BadInt())) a = A() with self.assertRaises(ZeroDivisionError): a.foo = (3, 5) with self.assertRaises(ZeroDivisionError): a.bar = (3, 5) def test_non_constant_defaults(self): class A(HasTraits): foo = Tuple(List(Int),) a = A() a.foo[0].append(35) self.assertEqual(a.foo[0], [35]) # The inner list should be being validated. with self.assertRaises(TraitError): a.foo[0].append(3.5) # The inner list should not be shared between instances. b = A() self.assertEqual(b.foo[0], []) def test_constant_defaults(self): # Exercise the code path where all child traits have a constant # default type. class A(HasTraits): foo = Tuple(Int, Tuple(Str, Int)) a = A() b = A() self.assertEqual(a.foo, (0, ("", 0))) self.assertIs(a.foo, b.foo) traits-6.3.2/traits/tests/test_type.py000066400000000000000000000035651414270267200201100ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import HasTraits, Subclass, TraitError, Type class BaseClass: pass class DerivedClass(BaseClass): pass class UnrelatedClass: """ Does not extend the BaseClass """ pass class ExampleTypeModel(HasTraits): _class = Type(klass=BaseClass) class ExampleSubclassModel(HasTraits): _class = Subclass(BaseClass) class TypeTestCase(unittest.TestCase): """ Tests the Type trait and its alias - the Subclass trait""" def test_type_base(self): model = ExampleTypeModel(_class=BaseClass) self.assertIsInstance(model._class(), BaseClass) def test_type_derived(self): model = ExampleTypeModel(_class=DerivedClass) self.assertIsInstance(model._class(), DerivedClass) def test_invalid_type(self): example_model = ExampleTypeModel() def assign_invalid(): example_model._class = UnrelatedClass self.assertRaises(TraitError, assign_invalid) def test_subclass_base(self): model = ExampleSubclassModel(_class=BaseClass) self.assertIsInstance(model._class(), BaseClass) def test_subclass_derived(self): model = ExampleSubclassModel(_class=DerivedClass) self.assertIsInstance(model._class(), DerivedClass) def test_invalid_subclass(self): example_model = ExampleSubclassModel() def assign_invalid(): example_model._class = UnrelatedClass self.assertRaises(TraitError, assign_invalid) traits-6.3.2/traits/tests/test_ui_notifiers.py000066400000000000000000000105041414270267200216150ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for dynamic notifiers with `dispatch='ui'`. Dynamic notifiers created with the `dispatch='ui'` option dispatch event notifications on the UI thread. The class handling the dispatch, `FastUITraitChangeNotifyWrapper`, is a subclass of `TraitChangeNotifyWrapper`. Most of the functionality of the class is thus already covered by the `TestDynamicNotifiers` test case, and we only need to test that the notification really occurs on the UI thread. At present, `dispatch='ui'` and `dispatch='fast_ui'` have the same effect. """ import threading import time import unittest # Preamble: Try importing Qt, and set QT_FOUND to True on success. try: from pyface.util.guisupport import get_app_qt4 # This import is necessary to set the `ui_handler` global variable in # `traits.trait_notifiers`, which is responsible for dispatching the events # to the UI thread. from traitsui.qt4 import toolkit # noqa: F401 qt4_app = get_app_qt4() except Exception: QT_FOUND = False else: QT_FOUND = True from traits import trait_notifiers from traits.api import Callable, Float, HasTraits, on_trait_change class CalledAsMethod(HasTraits): foo = Float class CalledAsDecorator(HasTraits): foo = Float callback = Callable @on_trait_change("foo", dispatch="ui") def on_foo_change(self, obj, name, old, new): self.callback(obj, name, old, new) class BaseTestUINotifiers(object): """ Tests for dynamic notifiers with `dispatch='ui'`. """ #### 'TestCase' protocol ################################################## def setUp(self): self.notifications = [] #### 'TestUINotifiers' protocol ########################################### def flush_event_loop(self): """ Post and process the Qt events. """ qt4_app.sendPostedEvents() qt4_app.processEvents() def on_foo_notifications(self, obj, name, old, new): thread_id = threading.current_thread().ident event = (thread_id, (obj, name, old, new)) self.notifications.append(event) #### Tests ################################################################ @unittest.skipIf( not QT_FOUND, "Qt event loop not found, UI dispatch not possible." ) def test_notification_from_main_thread(self): obj = self.obj_factory() obj.foo = 3 self.flush_event_loop() notifications = self.notifications self.assertEqual(len(notifications), 1) thread_id, event = notifications[0] self.assertEqual(event, (obj, "foo", 0, 3)) ui_thread = trait_notifiers.ui_thread self.assertEqual(thread_id, ui_thread) @unittest.skipIf( not QT_FOUND, "Qt event loop not found, UI dispatch not possible." ) def test_notification_from_separate_thread(self): obj = self.obj_factory() # Set obj.foo to 3 on a separate thread. def set_foo_to_3(obj): obj.foo = 3 threading.Thread(target=set_foo_to_3, args=(obj,)).start() # Wait for a while to make sure the function has finished. time.sleep(0.1) self.flush_event_loop() notifications = self.notifications self.assertEqual(len(notifications), 1) thread_id, event = notifications[0] self.assertEqual(event, (obj, "foo", 0, 3)) ui_thread = trait_notifiers.ui_thread self.assertEqual(thread_id, ui_thread) class TestMethodUINotifiers(BaseTestUINotifiers, unittest.TestCase): """ Tests for dynamic notifiers with `dispatch='ui'` set by method call. """ def obj_factory(self): obj = CalledAsMethod() obj.on_trait_change(self.on_foo_notifications, "foo", dispatch="ui") return obj class TestDecoratorUINotifiers(BaseTestUINotifiers, unittest.TestCase): """ Tests for dynamic notifiers with `dispatch='ui'` set by decorator. """ def obj_factory(self): return CalledAsDecorator(callback=self.on_foo_notifications) traits-6.3.2/traits/tests/test_undefined.py000066400000000000000000000033101414270267200210540ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import HasTraits, Str, Undefined, ReadOnly, Float class Foo(HasTraits): name = Str() original_name = ReadOnly bar = Str baz = Float def _name_changed(self): if self.original_name is Undefined: self.original_name = self.name class Bar(HasTraits): name = Str(Undefined) class UndefinedTestCase(unittest.TestCase): def test_initial_value(self): b = Bar() self.assertEqual(b.name, Undefined) def test_name_change(self): b = Bar() b.name = "first" self.assertEqual(b.name, "first") def test_read_only_write_once(self): f = Foo() self.assertEqual(f.name, "") self.assertIs(f.original_name, Undefined) f.name = "first" self.assertEqual(f.name, "first") self.assertEqual(f.original_name, "first") f.name = "second" self.assertEqual(f.name, "second") self.assertEqual(f.original_name, "first") def test_read_only_write_once_from_constructor(self): f = Foo(name="first") f.name = "first" self.assertEqual(f.name, "first") self.assertEqual(f.original_name, "first") f.name = "second" self.assertEqual(f.name, "second") self.assertEqual(f.original_name, "first") traits-6.3.2/traits/tests/test_unicode_traits.py000066400000000000000000000014361414270267200221360ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import ( BaseCStr, BaseCUnicode, BaseStr, BaseUnicode, CStr, CUnicode, Str, Unicode, ) class TestUnicodeTraits(unittest.TestCase): def test_aliases(self): self.assertIs(Unicode, Str) self.assertIs(CUnicode, CStr) self.assertIs(BaseUnicode, BaseStr) self.assertIs(BaseCUnicode, BaseCStr) traits-6.3.2/traits/tests/test_union.py000066400000000000000000000144121414270267200202500ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import ( Bytes, DefaultValue, Float, HasTraits, Instance, Int, List, Str, TraitError, TraitType, Type, Union) class CustomClass(HasTraits): value = Int class CustomStrType(TraitType): #: The default value type to use. default_value_type = DefaultValue.constant #: The default value. default_value = "a string value" def validate(self, obj, name, value): if not isinstance(value, Str): return value self.error(obj, name, value) class TestUnion(unittest.TestCase): def test_union_incompatible_trait(self): with self.assertRaises(ValueError) as exception_context: Union(Str(), "none") self.assertEqual( str(exception_context.exception), "Union trait declaration expects a trait type or an instance of " "trait type or None, but got 'none' instead" ) def test_list_trait_types(self): class TestClass(HasTraits): int_or_str_type = Union(Type, Int, Str) TestClass(int_or_str_type=3) TestClass(int_or_str_type="3.5") with self.assertRaises(TraitError): TestClass(int_or_str_type=3.5) with self.assertRaises(TraitError): TestClass(int_or_str_type=Int(3)) def test_malformed_declaration(self): with self.assertRaises(ValueError): class TestClass(HasTraits): a = Union(int, Float) TestClass(a=2.4) with self.assertRaises(ValueError): class TestClass(HasTraits): a = Union([1, 2], Float) TestClass(a=2.4) def test_list_trait_instances(self): class TestClass(HasTraits): float_or_str_obj = Union(Instance(Float), Instance(Str)) TestClass(float_or_str_obj=Float(3.5)) TestClass(float_or_str_obj=Str("3.5")) with self.assertRaises(TraitError): TestClass(float_or_str_obj=Float) with self.assertRaises(TraitError): TestClass(float_or_str_obj=3.5) def test_union_with_none(self): class TestClass(HasTraits): int_or_none = Union(None, Int) TestClass(int_or_none=None) def test_union_unspecified_arguments(self): class TestClass(HasTraits): none = Union() TestClass(none=None) def test_default_value(self): class TestClass(HasTraits): atr = Union(Int(3), Float(4.1), Str("Something")) self.assertEqual(TestClass().atr, 3) class TestClass(HasTraits): atr = Union( Int(3), Float(4.1), Str("Something"), default_value="XYZ", ) self.assertEqual(TestClass().atr, "XYZ") class TestClass(HasTraits): atr = Union() self.assertEqual(TestClass().atr, None) class TestClass(HasTraits): atr = Union(None) self.assertEqual(TestClass().atr, None) def test_default_raise_error(self): # If 'default' is defined, it could be caused by migration from # ``Either``. Raise an error to aid migrations from ``Either`` # to ``Union`` with self.assertRaises(ValueError) as exception_context: Union(Int(), Float(), default=1.0) self.assertEqual( str(exception_context.exception), "Union default value should be set via 'default_value', not " "'default'." ) def test_inner_traits(self): class TestClass(HasTraits): atr = Union(Float, Int, Str) obj = TestClass() t1, t2, t3 = obj.trait('atr').inner_traits self.assertEqual(type(t1.trait_type), Float) self.assertEqual(type(t2.trait_type), Int) self.assertEqual(type(t3.trait_type), Str) def test_union_user_defined_class(self): class TestClass(HasTraits): obj = Union(Instance(CustomClass), Int) TestClass(obj=CustomClass(value=5)) TestClass(obj=5) with self.assertRaises(TraitError): TestClass(obj=CustomClass) def test_union_user_defined_type(self): class TestClass(HasTraits): type_value = Union(CustomStrType, Int) TestClass(type_value="new string") def test_notification(self): class TestClass(HasTraits): union_attr = Union(Int) shadow_union_trait = None def _union_attr_changed(self, new): self.shadow_union_trait = new obj = TestClass(union_attr=-1) obj.union_attr = 1 self.assertEqual(obj.shadow_union_trait, 1) def test_extending_union_trait(self): class UnionAllowStr(Union): def validate(self, obj, name, value): if isinstance(value, str): return value return super().validate(obj, name, value) class TestClass(HasTraits): s = UnionAllowStr(Int, Float) TestClass(s="sdf") def test_list_inside_union_default(self): class HasUnionWithList(HasTraits): foo = Union(List(Int), Str) has_union = HasUnionWithList() value = has_union.foo self.assertIsInstance(value, list) with self.assertRaises(TraitError): value.append("not an integer") def test_constant_default(self): # Exercise the branch where the default is constant. class HasUnionWithList(HasTraits): foo = Union(Int(23), Float) nested = Union(Union(Str(), Bytes()), Union(Int(), Float(), None)) has_union = HasUnionWithList() value = has_union.foo self.assertEqual(value, 23) self.assertEqual( has_union.trait("foo").default_value(), (DefaultValue.constant, 23), ) self.assertEqual( has_union.trait("nested").default_value(), (DefaultValue.constant, ""), ) traits-6.3.2/traits/tests/test_uuid.py000066400000000000000000000017211414270267200200650ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test cases for UUID traits. """ import unittest import uuid from traits.api import HasTraits, TraitError, UUID class A(HasTraits): id = UUID class B(HasTraits): id = UUID(can_init=True) class TestUUID(unittest.TestCase): def test_bad_assignment(self): with self.assertRaises(TraitError): a = A() a.id = uuid.uuid4() def test_bad_init(self): with self.assertRaises(TraitError): A(id=uuid.uuid4()) def test_good_init(self): B(id=uuid.uuid4()) B(id=str(uuid.uuid4())) traits-6.3.2/traits/tests/test_validated_tuple.py000066400000000000000000000031001414270267200222560ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import HasStrictTraits, Int, TraitError from traits.tests.tuple_test_mixin import TupleTestMixin from traits.trait_types import ValidatedTuple class Simple(HasStrictTraits): scalar_range = ValidatedTuple( Int(0), Int(1), fvalidate=lambda x: x[0] < x[1] ) class ValidatedTupleTestCase(TupleTestMixin, unittest.TestCase): def setUp(self): self.trait = ValidatedTuple def test_initialization(self): simple = Simple() self.assertEqual(simple.scalar_range, (0, 1)) def test_custom_validation(self): simple = Simple() simple.scalar_range = (2, 5) self.assertEqual(simple.scalar_range, (2, 5)) with self.assertRaises(TraitError): simple.scalar_range = (5, 2) def test_error_during_custom_validation(self): def fvalidate(x): if x == (5, 2): raise RuntimeError() return True class Simple(HasStrictTraits): scalar_range = ValidatedTuple(Int(0), Int(1), fvalidate=fvalidate) simple = Simple() with self.assertRaises(RuntimeError): simple.scalar_range = (5, 2) traits-6.3.2/traits/tests/test_version.py000066400000000000000000000037411414270267200206100ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Tests for the traits.__version__ attribute and the traits.version module contents. """ import unittest from traits.testing.optional_dependencies import ( pkg_resources, requires_pkg_resources, ) import traits class TestVersion(unittest.TestCase): @requires_pkg_resources def test_dunder_version(self): self.assertIsInstance(traits.__version__, str) # Round-trip through parse_version; this verifies not only # that the version is valid, but also that it's properly normalised # according to the PEP 440 rules. parsed_version = pkg_resources.parse_version(traits.__version__) self.assertEqual(str(parsed_version), traits.__version__) @requires_pkg_resources def test_version_version(self): # Importing inside the test to ensure that we get a test error # in the case where the version module does not exist. from traits.version import version self.assertIsInstance(version, str) parsed_version = pkg_resources.parse_version(version) self.assertEqual(str(parsed_version), version) def test_version_git_revision(self): from traits.version import git_revision self.assertIsInstance(git_revision, str) # Check the form of the revision. Could use a regex, but that seems # like overkill. self.assertEqual(len(git_revision), 40) self.assertLessEqual(set(git_revision), set("0123456789abcdef")) def test_versions_match(self): import traits.version self.assertEqual(traits.version.version, traits.__version__) traits-6.3.2/traits/tests/test_view_elements.py000066400000000000000000000071011414270267200217630ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import unittest from traits.api import AbstractViewElement, HasTraits, Int, TraitError from traits.testing.optional_dependencies import requires_traitsui @requires_traitsui class TestViewElements(unittest.TestCase): def setUp(self): import traitsui.api self.toolkit = traitsui.api.toolkit() def tearDown(self): del self.toolkit def test_view_definition(self): from traitsui.api import View view = View('count') class Model(HasTraits): count = Int my_view = view view_elements = Model.class_trait_view_elements() self.assertEqual(view_elements.content, {'my_view': view}) def test_view_definition_twice(self): from traitsui.api import View view = View('count') class Model(HasTraits): count = Int my_view = view view_elements = Model.class_trait_view_elements() view_elements2 = Model.class_trait_view_elements() self.assertEqual(view_elements.content, {'my_view': view}) self.assertIs(view_elements, view_elements2) def test_view_elements_parents(self): from traitsui.api import View class Model(HasTraits): count = Int my_view = View('count') class ModelSubclass(Model): total = Int my_view = View('count', 'total') view_elements = ModelSubclass.class_trait_view_elements() parent_view_elements = Model.class_trait_view_elements() self.assertEqual(view_elements.parents[0], parent_view_elements) def test_instance_view_definition(self): from traitsui.api import View view = View('count') class Model(HasTraits): count = Int my_view = view m = Model() view_elements = m.trait_view_elements() self.assertEqual(view_elements.content, {'my_view': view}) def test_trait_views(self): from traitsui.api import View view = View('count') class Model(HasTraits): count = Int my_view = view m = Model() views = m.trait_views() self.assertEqual(views, ['my_view']) def test_included_names(self): from traitsui.api import Group, Item, View item = Item('count', id='item_with_id') group = Group(item) view = View(Item('count')) class Model(HasTraits): count = Int my_group = group my_view = view view_elements = Model.class_trait_view_elements() self.assertEqual( view_elements.content, {'my_view': view, 'my_group': group, 'item_with_id': item} ) def test_duplicate_names(self): from traitsui.api import Group, Item, View class Model(HasTraits): count = Int includable = Group(Item('count', id='name_conflict')) name_conflict = View(Item('count')) with self.assertRaises(TraitError): Model.class_trait_view_elements() def test_view_element_superclass(self): from traitsui.api import ViewElement self.assertIsInstance(ViewElement(), AbstractViewElement) traits-6.3.2/traits/tests/test_weak_ref.py000066400000000000000000000036041414270267200207040ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Test cases for weakref (WeakRef) traits. """ import contextlib import gc import unittest from traits.has_traits import HasTraits from traits.trait_types import Str, WeakRef from traits.testing.unittest_tools import UnittestTools class Eggs(HasTraits): name = Str class Spam(HasTraits): eggs = WeakRef(Eggs) @contextlib.contextmanager def restore_gc_state(): """Ensure that gc state is restored on exit of the with statement.""" originally_enabled = gc.isenabled() try: yield finally: if originally_enabled: gc.enable() else: gc.disable() class TestWeakRef(UnittestTools, unittest.TestCase): """ Test cases for weakref (WeakRef) traits. """ def test_set_and_get(self): eggs = Eggs(name="platypus") spam = Spam() self.assertIsNone(spam.eggs) spam.eggs = eggs self.assertIs(spam.eggs, eggs) del eggs self.assertIsNone(spam.eggs) def test_target_freed_notification(self): eggs = Eggs(name="duck") spam = Spam(eggs=eggs) # Removal of the last reference to 'eggs' should trigger notification. with self.assertTraitChanges(spam, "eggs"): del eggs def test_weakref_trait_doesnt_leak_cycles(self): eggs = Eggs(name="ostrich") with restore_gc_state(): gc.disable() gc.collect() spam = Spam(eggs=eggs) del spam self.assertEqual(gc.collect(), 0) traits-6.3.2/traits/tests/tuple_test_mixin.py000066400000000000000000000052021414270267200214520ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from traits.api import HasTraits, TraitError from traits.testing.unittest_tools import UnittestTools VALUES = ("value1", 33, None) class TupleTestMixin(UnittestTools): """ A mixin class for testing tuple like traits. TestCases should set the self.trait attribute during setUp for the tests to run. """ def test_default_values(self): # Check that the default values for t1 and t2 are correctly # derived from the VALUES tuple. dummy = self._create_class() self.assertEqual(dummy.t1, VALUES) self.assertEqual(dummy.t2, VALUES) def test_simple_assignment(self): # Check that we can assign different values of the correct type. dummy = self._create_class() with self.assertTraitChanges(dummy, "t1"): dummy.t1 = ("other value 1", 77, None) with self.assertTraitChanges(dummy, "t2"): dummy.t2 = ("other value 2", 99, None) def test_invalid_assignment_length(self): # Check that assigning a tuple of incorrect length # raises a TraitError. self._assign_invalid_values_length(("str", 44)) self._assign_invalid_values_length(("str", 33, None, [])) def test_type_checking(self): # Test that type checking is done for the 't1' attribute. dummy = self._create_class() other_tuple = ("other value", 75, True) with self.assertRaises(TraitError): dummy.t1 = other_tuple self.assertEqual(dummy.t1, VALUES) # Test that no type checking is done for the 't2' attribute. try: dummy.t2 = other_tuple except TraitError: self.fail("Unexpected TraitError when assigning to tuple.") self.assertEqual(dummy.t2, other_tuple) def _assign_invalid_values_length(self, values): dummy = self._create_class() with self.assertRaises(TraitError): dummy.t1 = values self.assertEqual(dummy.t1, VALUES) with self.assertRaises(TraitError): dummy.t2 = values self.assertEqual(dummy.t2, VALUES) def _create_class(self): trait = self.trait class Dummy(HasTraits): t1 = trait(VALUES) t2 = trait(*VALUES) return Dummy() traits-6.3.2/traits/trait_base.py000066400000000000000000000237271414270267200170450ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Defines common, low-level capabilities needed by the Traits package. """ import enum import os import sys from os import getcwd from os.path import dirname, exists, join from weakref import ref from .etsconfig.api import ETSConfig # backwards compatibility: trait_base used to provide a patched enumerate enumerate = enumerate # Constants SequenceTypes = (list, tuple) ComplexTypes = (float, int) RangeTypes = (int, float) TypeTypes = ( str, int, float, complex, list, tuple, dict, bool, ) TraitNotifier = "__trait_notifier__" # The standard Traits property cache prefix: TraitsCache = "_traits_cache_" # Singleton 'Uninitialized' object: Uninitialized = None class _Uninitialized(object): """ The singleton value of this class represents the uninitialized state of a trait and is specified as the 'old' value in the trait change notification that occurs when the value of a trait is read before being set. """ def __new__(cls): if Uninitialized is not None: return Uninitialized else: self = object.__new__(cls) return self def __repr__(self): return "" def __reduce_ex__(self, protocol): return (_Uninitialized, ()) #: When the first reference to a trait is a 'get' reference, the default value #: of the trait is implicitly assigned and returned as the value of the trait. #: Because of this implicit assignment, a trait change notification is #: generated with the Uninitialized object as the 'old' value of the trait, and #: the default trait value as the 'new' value. This allows other parts of the #: traits package to recognize the assignment as the implicit default value #: assignment, and treat it specially. Uninitialized = _Uninitialized() Undefined = None class _Undefined(object): """ Singleton 'Undefined' object (used as undefined trait name and/or value). """ def __new__(cls): if Undefined is not None: return Undefined else: self = object.__new__(cls) return self def __repr__(self): return "" def __reduce_ex__(self, protocol): return (_Undefined, ()) def __eq__(self, other): return type(self) is type(other) def __hash__(self): return hash(type(self)) def __ne__(self, other): return type(self) is not type(other) #: Singleton object that indicates that a trait attribute has not yet had a #: value set (i.e., its value is undefined). This object is used instead of #: None, because None often has other meanings, such as that a value is not #: used. When a trait attribute is first assigned a value, and its associated #: trait notification handlers are called, Undefined is passed as the *old* #: parameter, to indicate that the attribute previously had no value. Undefined = _Undefined() class Missing(object): """ Singleton 'Missing' object (used as missing method argument marker). """ def __repr__(self): return "" #: Singleton object that indicates that a method argument is missing from a #: type-checked method signature. Missing = Missing() class Self(object): """ Singleton 'Self' object (used as object reference to current 'object'). """ def __repr__(self): return "" #: Singleton object that references the current 'object'. Self = Self() def strx(arg): """ Wraps the built-in str() function to raise a TypeError if the argument is not of a type in StringTypes. """ if isinstance(arg, StringTypes): return str(arg) raise TypeError # Constants StringTypes = (str, int, float, complex) # Default item validator for TraitDict, TraitList and TraitSet. def _validate_everything(item): """ Item validator which accepts any item and returns it unaltered. """ return item def safe_contains(value, container): """ Perform "in" containment check, allowing for TypeErrors. This is required because in some circumstances ``x in y`` can raise a TypeError. In these cases we make the (reasonable) assumption that the value is _not_ contained in the container. """ # Do a LBYL check for Enums, to avoid the DeprecationWarning issued # by Python 3.7. Ref: enthought/traits#853. if isinstance(container, enum.EnumMeta): if not isinstance(value, enum.Enum): return False try: return value in container except TypeError: return False def class_of(object): """ Returns a string containing the class name of an object with the correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image', 'a PlotValue'). """ if isinstance(object, str): return add_article(object) return add_article(object.__class__.__name__) def add_article(name): """ Returns a string containing the correct indefinite article ('a' or 'an') prefixed to the specified string. """ if name[:1].lower() in "aeiou": return "an " + name return "a " + name def user_name_for(name): """ Returns a "user-friendly" version of a string, with the first letter capitalized and with underscore characters replaced by spaces. For example, ``user_name_for('user_name_for')`` returns ``'User name for'``. """ name = name.replace("_", " ") result = "" last_lower = False for c in name: if c.isupper() and last_lower: result += " " last_lower = c.islower() result += c return result.capitalize() _traits_home = None def traits_home(): """ Gets the path to the Traits home directory. """ global _traits_home if _traits_home is None: _traits_home = verify_path(join(ETSConfig.application_data, "traits")) return _traits_home def verify_path(path): """ Verify that a specified path exists, and try to create it if it does not exist. """ if not exists(path): try: os.mkdir(path) except: pass return path def get_module_name(level=2): """ Returns the name of the module that the caller's caller is located in. """ return sys._getframe(level).f_globals.get("__name__", "__main__") def get_resource_path(level=2): """Returns a resource path calculated from the caller's stack. """ module = sys._getframe(level).f_globals.get("__name__", "__main__") path = None if module != "__main__": # Return the path to the module: try: path = dirname(getattr(sys.modules.get(module), "__file__")) except: # Apparently 'module' is not a registered module...treat it like # '__main__': pass if path is None: # '__main__' is not a real module, so we need a work around: for path in [dirname(sys.argv[0]), getcwd()]: if exists(path): break # Handle application bundlers. Since the python source files may be placed # in a zip file and therefore won't be directly accessable using standard # open/read commands, the app bundlers will look for resources (i.e. data # files, images, etc.) in specific locations. For py2app, this is in the # [myapp].app/Contents/Resources directory. For py2exe, this is the same # directory as the [myapp].exe executable file generated by py2exe. For # pyinstaller, the attribute sys._MEIPASS is set to this directory. frozen = getattr(sys, "frozen", False) if frozen: if hasattr(sys, "_MEIPASS"): root = sys._MEIPASS elif frozen == "macosx_app": root = os.environ["RESOURCEPATH"] elif frozen in ("dll", "windows_exe", "console_exe"): root = os.path.dirname(sys.executable) else: # Unknown app bundler, but try anyway root = os.path.dirname(sys.executable) if ".zip/" in path: zippath, image_path = path.split(".zip/") path = os.path.join(root, image_path) return path def xgetattr(object, xname, default=Undefined): """ Returns the value of an extended object attribute name of the form: name[.name2[.name3...]]. """ names = xname.split(".") for name in names[:-1]: if default is Undefined: object = getattr(object, name) else: object = getattr(object, name, None) if object is None: return default if default is Undefined: return getattr(object, names[-1]) return getattr(object, names[-1], default) def xsetattr(object, xname, value): """ Sets the value of an extended object attribute name of the form: name[.name2[.name3...]]. """ names = xname.split(".") for name in names[:-1]: object = getattr(object, name) setattr(object, names[-1], value) # Helpers for weak references. def _make_value_freed_callback(object_ref, name): def _value_freed(value_ref): object = object_ref() if object is not None: object.trait_property_changed(name, Undefined, None) return _value_freed class HandleWeakRef(object): def __init__(self, object, name, value): object_ref = ref(object) _value_freed = _make_value_freed_callback(object_ref, name) self.object = object_ref self.name = name self.value = ref(value, _value_freed) def is_none(value): return value is None def not_none(value): return value is not None def not_false(value): return value is not False def not_event(value): return value != "event" def is_str(value): return isinstance(value, str) traits-6.3.2/traits/trait_converters.py000066400000000000000000000104151414270267200203130ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Utility routines that convert objects to CTrait instances Most of these functions depend on objects having an informal ``as_ctrait`` interface if they know how to turn themselves into a CTrait instance. We need to special-case ``TraitType`` subclasses so that we can use them in trait definitions without needing to call them, eg.:: x = Float rather than:: x = Float() To handle this, there is another informal interface with the deliberately unwieldy classmethod name ``instantiate_and_get_ctrait``. """ from functools import partial from .constants import DefaultValue def trait_cast(obj): """ Convert to a CTrait if the object knows how, else return None. """ try: return as_ctrait(obj) except TypeError: return None def as_ctrait(obj): """ Convert to CTrait if the object knows how, else raise TraitError. Parameters ---------- obj An object that supports conversion to `CTrait`. Refer documentation for when the object supports this conversion. Returns ------- ctrait.CTrait A CTrait object. Raises ------ TypeError If the object does not support conversion to CTrait. """ if isinstance(obj, type) and hasattr(obj, 'instantiate_and_get_ctrait'): return obj.instantiate_and_get_ctrait() elif not isinstance(obj, type) and hasattr(obj, 'as_ctrait'): return obj.as_ctrait() else: raise TypeError( "Object {!r} does not support conversion to CTrait".format(obj)) def check_trait(trait): """ Returns either the original value or a valid CTrait if the value can be converted to a CTrait. """ try: return as_ctrait(trait) except TypeError: return trait #: alias for check_trait try_trait_cast = check_trait def trait_from(obj): """ Returns a trait derived from its input. """ from .trait_types import Any from .traits import Trait # special-case None if obj is None: return Any().as_ctrait() try: return as_ctrait(obj) except TypeError: return Trait(obj) def trait_for(trait): """ Returns the trait corresponding to a specified value. """ # XXX this is the same as trait_from except that None is treated # differently and returns Trait(None) (which is the same as # Instance(NoneType)) from .traits import Trait try: return as_ctrait(trait) except TypeError: return Trait(trait) def _mapped_trait_default(trait, name, instance): """ Callable providing default for a shadow trait of a mapped trait pair. Parameters ---------- trait : CTrait The principal trait of the mapped trait pair. name : str The name of the trait on the relevant HasTraits object. instance : HasTraits The HasTraits object on which the mapped trait lives. Returns ------- default : object The default value for the shadow trait. """ value = getattr(instance, name) return trait.handler.mapped_value(value) def mapped_trait_for(trait, name): """ Returns the 'mapped trait' definition for a mapped trait, the default value of which is a callable that maps the value of the original trait. Parameters ---------- trait : ctrait.CTrait A trait for which the 'mapped trait' definition is being created. name : str The name of the trait for which the 'mapped trait' definition is being created. Returns ------- trait_types.Any A definition of the 'mapped trait' """ from .trait_types import Any mapped_trait = Any( is_base=False, transient=True, editable=False ).as_ctrait() mapped_trait.set_default_value( DefaultValue.callable, partial(_mapped_trait_default, trait, name) ) return mapped_trait traits-6.3.2/traits/trait_dict_object.py000066400000000000000000000425121414270267200203750ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import copy import sys from weakref import ref from traits.observation.i_observable import IObservable from traits.trait_base import Undefined, _validate_everything from traits.trait_errors import TraitError class TraitDictEvent(object): """ An object reporting in-place changes to a traits dict. Parameters ---------- removed : dict, optional Old keys and values that were just removed. added : dict, optional New keys and values that were just added. changed : dict, optional Updated keys and their previous values. Attributes ---------- removed : dict Old keys and values that were just removed. added : dict New keys and values that were just added. changed : dict Updated keys and their previous values. """ def __init__(self, *, removed=None, added=None, changed=None): if removed is None: removed = {} self.removed = removed if added is None: added = {} self.added = added if changed is None: changed = {} self.changed = changed def __repr__(self): return ( f"{self.__class__.__name__}(" f"removed={self.removed!r}, " f"added={self.added!r}, " f"changed={self.changed!r})" ) @IObservable.register class TraitDict(dict): """ A subclass of dict that validates keys and values and notifies listeners of any change. Parameters ---------- value : dict or iterable, optional The initial dict or an iterable containing key-value pairs. key_validator : callable, optional Called to validate a key in the dict. The callable must accept a single key and return a validated key or raise a TraitError If not provided, all keys are considered valid. value_validator : callable, optional Called to validate a value in the dict. The callable must accept a single value and return a validated value or raise a TraitError If not provided, all values are considered valid. notifiers : list, optional A list of callables with the signature:: notifier(trait_dict, removed, added, changed) Where: 'removed' is a dict of key-values that are no longer in the dictionary. 'added' is a dict of new key-values that have been added. 'changed' is a dict with old values previously associated with the key. Attributes ---------- key_validator : callable Called to validate a key in the dict. The callable must accept a single key and return a validated key or raise a TraitError value_validator : callable Called to validate a value in the dict. The callable must accept a single value and return a validated value or raise a TraitError notifiers : list A list of callables with the signature:: notifier(trait_dict, removed, added, changed) Where: 'removed' is a dict of key-values that are no longer in the dictionary. 'added' is a dict of new key-values that have been added. 'changed' is a dict with old values previously associated with the key. """ def __new__(cls, *args, **kwargs): self = super().__new__(cls) self.key_validator = _validate_everything self.value_validator = _validate_everything self.notifiers = [] return self def __init__(self, value=None, *, key_validator=None, value_validator=None, notifiers=None): if key_validator is not None: self.key_validator = key_validator if value_validator is not None: self.value_validator = value_validator if notifiers is None: notifiers = [] self.notifiers = notifiers if value is None: value = {} items = value.items() if hasattr(value, 'keys') else value value = {self.key_validator(key): self.value_validator(value) for key, value in items} super().__init__(value) def notify(self, removed, added, changed): """ Call all notifiers. This simply calls all notifiers provided by the class, if any. The notifiers are expected to have the signature:: notifier(trait_dict, removed, added, changed) Any return values are ignored. """ for notifier in self.notifiers: notifier(self, removed, added, changed) # -- dict interface ------------------------------------------------------- def __setitem__(self, key, value): """ Set a value for the key, implements self[key] = value. Parameters ---------- key : A hashable object. The key for the value. value : any The value to set for the corresponding key. """ removed = {} validated_key = self.key_validator(key) validated_value = self.value_validator(value) if validated_key in self: changed = {validated_key: self[validated_key]} added = {} else: changed = {} added = {validated_key: validated_value} super().__setitem__(validated_key, validated_value) self.notify(removed=removed, added=added, changed=changed) def __delitem__(self, key): """ Delete the item from the dict indicated by the key. Parameters ---------- key : A hashable object. The key to be deleted. Raises ------ KeyError If the key is not found. """ removed = {key: self[key]} if key in self else {} super().__delitem__(key) self.notify(removed=removed, added={}, changed={}) if sys.version_info >= (3, 9): def __ior__(self, other): """ Update self with the contents of other. Parameters ---------- other : mapping or iterable of (key, value) pairs Values to be added to this dictionary. """ validated_dict = {} added = {} changed = {} items = other.items() if hasattr(other, 'keys') else other for key, value in items: validated_key = self.key_validator(key) validated_value = self.value_validator(value) if validated_key in self: changed[validated_key] = self[validated_key] else: added[validated_key] = validated_value validated_dict[validated_key] = validated_value retval = super().__ior__(validated_dict) if added or changed: self.notify(removed={}, added=added, changed=changed) return retval def clear(self): """ Remove all items from the dict. """ was_empty = (self == {}) removed = self.copy() super().clear() if not was_empty: self.notify(removed=removed, added={}, changed={}) def update(self, other): """ Update the values in the dict by the new dict or an iterable of key-value pairs. Parameters ---------- other : dict or iterable The dict from which values will be updated into this dict. """ validated_dict = {} added = {} changed = {} items = other.items() if hasattr(other, 'keys') else other for key, value in items: validated_key = self.key_validator(key) validated_value = self.value_validator(value) if validated_key in self: changed[validated_key] = self[validated_key] else: added[validated_key] = validated_value validated_dict[validated_key] = validated_value super().update(validated_dict) if added or changed: self.notify(removed={}, added=added, changed=changed) def setdefault(self, key, value=None): """ Returns the value if key is present in the dict, else creates the key-value pair and returns the value. Parameters ---------- key : A hashable object. Key to the item. """ if key in self: return self[key] validated_key = self.key_validator(key) validated_value = self.value_validator(value) if validated_key in self: changed = {validated_key: self[validated_key]} added = {} else: changed = {} added = {validated_key: validated_value} super().__setitem__(validated_key, validated_value) self.notify(removed={}, added=added, changed=changed) return validated_value def pop(self, key, value=Undefined): """ Remove specified key and return the corresponding value. If key is not found, the default value is returned if given, otherwise KeyError is raised. Parameters ---------- key : A hashable object. Key to the dict item. value : any Value to return if key is absent. """ should_notify = (value is Undefined or key in self) if value is Undefined: removed = super().pop(key) else: removed = super().pop(key, value) if should_notify: self.notify( removed={key: removed}, added={}, changed={} ) return removed def popitem(self): """ Remove and return some (key, value) pair as a tuple. Raise KeyError if dict is empty. Returns ------- key_value : tuple Some 2-tuple from the dict. Raises ------ KeyError If the dict is empty """ item = super().popitem() self.notify(removed=dict([item]), added={}, changed={}) return item # -- pickle and copy support ---------------------------------------------- def __getstate__(self): """ Get the state of the object for serialization. Notifiers are transient and should not be serialized. """ result = self.__dict__.copy() # notifiers are transient and should not be serialized del result["notifiers"] return result def __setstate__(self, state): """ Restore the state of the object after serialization. Notifiers are transient and are restored to the empty list. """ state['notifiers'] = [] self.__dict__.update(state) def __deepcopy__(self, memo): """ Perform a deepcopy operation. Notifiers are transient and should not be copied. """ result = TraitDict( dict(copy.deepcopy(x, memo) for x in self.items()), key_validator=copy.deepcopy(self.key_validator, memo), value_validator=copy.deepcopy(self.value_validator, memo), notifiers=[] ) return result # -- Implement IObservable ------------------------------------------------ def _notifiers(self, force_create): """ Return a list of callables where each callable is a notifier. The list is expected to be mutated for contributing or removing notifiers from the object. Parameters ---------- force_create: boolean Not used here. """ return self.notifiers class TraitDictObject(TraitDict): """ A subclass of TraitDict that fires trait events when mutated. This is for backward compatibility with Traits 6.0 and lower. This is used by the Dict trait type, and all values set into a Dict trait will be copied into a new TraitDictObject instance. Mutation of the TraitDictObject will fire a "name_items" event with appropriate added, changed and removed values. Parameters ---------- trait : CTrait instance The CTrait instance associated with the attribute that this dict has been set to. object : HasTraits instance The HasTraits instance that the dict has been set as an attribute for. name : str The name of the attribute on the object. value : dict The dict of values to initialize the TraitDictObject with. Attributes ---------- trait : CTrait instance The CTrait instance associated with the attribute that this dict has been set to. object : weak reference to a HasTraits instance A weak reference to a HasTraits instance that the dict has been set as an attribute for. name : str The name of the attribute on the object. name_items : str The name of the items event trait that the trait dict will fire when mutated. """ def __init__(self, trait, object, name, value): self.trait = trait self.object = ref(object) self.name = name self.name_items = None if trait.has_items: self.name_items = name + "_items" super().__init__(value, key_validator=self._key_validator, value_validator=self._value_validator, notifiers=[self.notifier]) def _key_validator(self, key): """ Calls the trait's key_trait.handler.validate. Parameters ---------- key : A hashable object. The key to validate. Returns ------- validated_key : A hashable object. The validated key. Raises ------ TraitError If the validation fails. """ trait = getattr(self, 'trait', None) object = getattr(self, 'object', lambda: None)() # Deserialized TraitDictObjects without 'trait' and 'object' set # will not validate its keys if trait is None or object is None: return key validate = trait.key_trait.handler.validate if validate is None: return key try: return validate(object, self.name, key) except TraitError as excep: excep.set_prefix("Each key of the") raise excep def _value_validator(self, value): """ Calls the trait's value_handler.validate Parameters ---------- value : any The value to validate. Returns ------- validated_value : any The validated value. Raises ------ TraitError If the validation fails. """ trait = getattr(self, 'trait', None) object = getattr(self, 'object', lambda: None)() # Deserialized TraitDictObjects without 'trait' and 'object' set # will not validate its values if trait is None or object is None: return value validate = trait.value_handler.validate if validate is None: return value try: return validate(object, self.name, value) except TraitError as excep: excep.set_prefix("Each value of the") raise excep def notifier(self, trait_dict, removed, added, changed): """ Fire the TraitDictEvent with the provided parameters. Parameters ---------- trait_dict : dict The complete dictionary. removed : dict Dict of removed items. added : dict Dict of added items. changed : dict Dict of changed items. """ if self.name_items is None: return object = self.object() if object is None: return if getattr(object, self.name) is not self: # Workaround having this dict inside another container which # also uses the name_items trait for notification. # See enthought/traits#25 return event = TraitDictEvent(removed=removed, added=added, changed=changed) items_event = self.trait.items_event() object.trait_items_event(self.name_items, event, items_event) # -- pickle and copy support ---------------------------------------------- def __getstate__(self): """ Get the state of the object for serialization. Object and trait should not be serialized. """ result = super().__getstate__() del result["object"] del result["trait"] return result def __setstate__(self, state): """ Restore the state of the object after serialization. """ state.setdefault("name", "") state["notifiers"] = [self.notifier] state["object"] = lambda: None state['trait'] = None self.__dict__.update(state) def __deepcopy__(self, memo): """ Perform a deepcopy operation.. Object is a weakref and should not be copied. """ result = TraitDictObject( self.trait, lambda: None, self.name, dict(copy.deepcopy(x, memo) for x in self.items()), ) return result traits-6.3.2/traits/trait_errors.py000066400000000000000000000061761414270267200174460ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Defines the standard exceptions raised by the Traits package. """ from .trait_base import class_of def repr_type(obj): """ Return a string representation of a value and its type for readable error messages. """ the_type = type(obj) msg = "%r %r" % (obj, the_type) return msg class TraitError(Exception): def __init__(self, args=None, name=None, info=None, value=None): if name is None: # If the given args is not a tuple then assume that the user # intended it to be the single item in a one-element tuple. if not isinstance(args, tuple): args = (args,) self.args = args else: # Save the information, in case the 'args' object is not the # correct one, and we need to regenerate the message later: self.name = name self.info = info self.value = value self.desc = None self.prefix = "The" self.set_desc(None, args) def set_desc(self, desc, object=None): if hasattr(self, "desc"): if desc is not None: self.desc = desc if object is not None: self.object = object self.set_args() def set_prefix(self, prefix): if hasattr(self, "prefix"): self.prefix = prefix self.set_args() def set_args(self): if self.desc is None: extra = "" else: extra = " specifies %s and" % self.desc obj = getattr(self, "object", None) # Note: self.args must be a tuple so be sure to leave the trailing # commas. if obj is not None: self.args = ( ( "%s '%s' trait of %s instance%s must be %s, " "but a value of %s was specified." % ( self.prefix, self.name, class_of(obj), extra, self.info, repr_type(self.value), ) ), ) else: self.args = ( ( "%s '%s' trait%s must be %s, but a value of %s was " "specified." % ( self.prefix, self.name, extra, self.info, repr_type(self.value), ) ), ) class TraitNotificationError(Exception): pass class DelegationError(TraitError): def __init__(self, args): # .args must be a tuple. self.args = (args,) traits-6.3.2/traits/trait_factory.py000066400000000000000000000043101414270267200175650ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Defines the TraitFactory class and related objects. A TraitFactory is a class which allows deferred, but cached, creation of CTrait instances. The TraitFactory API provides the ``as_ctrait`` method so that the trait conversion functions can generate CTrait instances in a standard way. """ from .trait_errors import TraitError _trait_factory_instances = {} class TraitFactory(object): """ A factory class that allows deferred creation of traits Traits created by TraitFactory instances are cached, and the cached trait is returned by all subsequent calls to the same TraitFactory instance. """ def __init__(self, maker_function=None): if maker_function is not None: self.maker_function = maker_function self.__doc__ = maker_function.__doc__ def __call__(self, *args, **metadata): """ Creates a CTrait instance. """ return self.maker_function(*args, **metadata) def as_ctrait(self): """ Get the CTrait instance from the factory. """ return trait_factory(self) class TraitImportError(TraitFactory): """ TraitFactory subclass that always fails when creating a CTrait This class is designed for uses such as deferring import problems until encountering code that actually tries to use the unimportable trait. """ def __init__(self, message): self.message = message def __call__(self, *args, **metadata): """ Raises an TraitError with the message as is payload. """ raise TraitError(self.message) def trait_factory(trait): """ Returns a trait created from a TraitFactory instance """ global _trait_factory_instances tid = id(trait) if tid not in _trait_factory_instances: _trait_factory_instances[tid] = trait() return _trait_factory_instances[tid] traits-6.3.2/traits/trait_handler.py000066400000000000000000000056531414270267200175460ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Defines the TraitHandler class. A trait handler mediates the assignment of values to object traits. It verifies (via its validate() method) that a specified value is consistent with the object trait, and generates a TraitError exception if it is not consistent. """ from .base_trait_handler import BaseTraitHandler from .trait_base import class_of from .trait_errors import TraitError class TraitHandler(BaseTraitHandler): """ The task of this class and its subclasses is to verify the correctness of values assigned to object trait attributes. This class is an alternative to trait validator functions. A trait handler has several advantages over a trait validator function, due to being an object: * Trait handlers have constructors and state. Therefore, you can use them to create *parametrized types*. * Trait handlers can have multiple methods, whereas validator functions can have only one callable interface. This feature allows more flexibility in their implementation, and allows them to handle a wider range of cases, such as interactions with other components. The only method of TraitHandler that *must* be implemented by subclasses is validate(). """ def validate(self, object, name, value): """ Verifies whether a new value assigned to a trait attribute is valid. This method *must* be implemented by subclasses of TraitHandler. It is called whenever a new value is assigned to a trait attribute defined using this trait handler. If the value received by validate() is not valid for the trait attribute, the method must called the predefined error() method to raise a TraitError exception Parameters ---------- object : HasTraits instance The object whose attribute is being assigned. name : str The name of the attribute being assigned. value : any The proposed new value for the attribute. Returns ------- any If the new value is valid, this method must return either the original value passed to it, or an alternate value to be assigned in place of the original value. Whatever value this method returns is the actual value assigned to *object.name*. """ raise TraitError( "The '%s' trait of %s instance has an unknown type. " "Contact the developer to correct the problem." % (name, class_of(object)) ) traits-6.3.2/traits/trait_handlers.py000066400000000000000000001233721414270267200177300ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Defines a standard set of TraitHandler subclasses. A trait handler mediates the assignment of values to object traits. It verifies (via its validate() method) that a specified value is consistent with the object trait, and generates a TraitError exception if it is not consistent. """ from importlib import import_module import sys from types import FunctionType, MethodType from .constants import DefaultValue, ValidateTrait from .trait_base import ( SequenceTypes, TypeTypes, class_of, ) from .trait_base import RangeTypes # noqa: F401, used by TraitsUI from .trait_errors import TraitError from .trait_dict_object import TraitDictEvent, TraitDictObject from .trait_converters import trait_from from .trait_handler import TraitHandler from .trait_list_object import TraitListEvent, TraitListObject from .util.deprecated import deprecated # Constants CallableTypes = (FunctionType, MethodType) # Mapping of coercable types. CoercableTypes = { float: (ValidateTrait.coerce, float, int), complex: (ValidateTrait.coerce, complex, float, int), } _WARNING_FORMAT_STR = ("'{handler}' trait handler has been deprecated. " "Use {replacement} instead.") # Private functions def _undefined_get(object, name): raise TraitError( ( "The '%s' trait of %s instance is a property that has " "no 'get' or 'set' method" ) % (name, class_of(object)) ) def _undefined_set(object, name, value): _undefined_get(object, name) class TraitCoerceType(TraitHandler): """Ensures that a value assigned to a trait attribute is of a specified Python type, or can be coerced to the specified type. TraitCoerceType is the underlying handler for the predefined traits and factories for Python simple types. The TraitCoerceType class is also an example of a parametrized type, because the single TraitCoerceType class allows creating instances that check for totally different sets of values. For example:: class Person(HasTraits): name = Trait('', TraitCoerceType('')) weight = Trait(0.0, TraitCoerceType(float)) In this example, the **name** attribute must be of type ``str`` (string), while the **weight** attribute must be of type ``float``, although both are based on instances of the TraitCoerceType class. Note that this example is essentially the same as writing:: class Person(HasTraits): name = Trait('') weight = Trait(0.0) This simpler form is automatically changed by the Trait() function into the first form, based on TraitCoerceType instances, when the trait attributes are defined. For attributes based on TraitCoerceType instances, if a value that is assigned is not of the type defined for the trait, a TraitError exception is raised. However, in certain cases, if the value can be coerced to the required type, then the coerced value is assigned to the attribute. Only *widening* coercions are allowed, to avoid any possible loss of precision. The following table lists the allowed coercions. ============ ================= Trait Type Coercible Types ============ ================= complex float, int float int ============ ================= Parameters ---------- aType : type or object Either a Python type or a Python value. If this is an object, it is mapped to its corresponding type. For example, the string 'cat' is automatically mapped to ``str``. Attributes ---------- aType : type A Python type to coerce values to. """ def __init__(self, aType): if not isinstance(aType, type): aType = type(aType) self.aType = aType try: self.fast_validate = CoercableTypes[aType] except: self.fast_validate = (ValidateTrait.coerce, aType) def validate(self, object, name, value): fv = self.fast_validate tv = type(value) # If the value is already the desired type, then return it: if tv is fv[1]: return value # Else see if it is one of the coercable types: for typei in fv[2:]: if tv is typei: # Return the coerced value: return fv[1](value) # Otherwise, raise an exception: self.error(object, name, value) def info(self): return "a value of %s" % str(self.aType)[1:-1] def get_editor(self, trait): # Make the special case of a 'bool' type use the boolean editor: if self.aType is bool: if self.editor is None: from traitsui.api import BooleanEditor self.editor = BooleanEditor() return self.editor # Otherwise, map all other types to a text editor: auto_set = trait.auto_set if auto_set is None: auto_set = True from traitsui.api import TextEditor return TextEditor( auto_set=auto_set, enter_set=trait.enter_set or False, evaluate=self.fast_validate[1], ) class TraitCastType(TraitCoerceType): """Ensures that a value assigned to a trait attribute is of a specified Python type, or can be cast to the specified type. This class is similar to TraitCoerceType, but uses casting rather than coercion. Values are cast by calling the type with the value to be assigned as an argument. When casting is performed, the result of the cast is the value assigned to the trait attribute. Any trait that uses a TraitCastType instance in its definition ensures that its value is of the type associated with the TraitCastType instance. For example:: class Person(HasTraits): name = Trait('', TraitCastType('')) weight = Trait(0.0, TraitCastType(float)) In this example, the **name** trait must be of type ``str`` (string), while the **weight** trait must be of type ``float``. Note that this example is essentially the same as writing:: class Person(HasTraits): name = CStr weight = CFloat To understand the difference between TraitCoerceType and TraitCastType (and also between Float and CFloat), consider the following example:: >>> class Person(HasTraits): ... weight = Float ... cweight = CFloat ... >>> bill = Person() >>> bill.weight = 180 # OK, coerced to 180.0 >>> bill.cweight = 180 # OK, cast to 180.0 >>> bill.weight = '180' # Error, invalid coercion >>> bill.cweight = '180' # OK, cast to float('180') Parameters ---------- aType : type Either a Python type or a Python value. If this is an object, it is mapped to its corresponding type. For example, the string 'cat' is automatically mapped to ``str``. Attributes ---------- aType : type A Python type to cast values to. """ def __init__(self, aType): if not isinstance(aType, type): aType = type(aType) self.aType = aType self.fast_validate = (ValidateTrait.cast, aType) def validate(self, object, name, value): # If the value is already the desired type, then return it: if type(value) is self.aType: return value # Else try to cast it to the specified type: try: return self.aType(value) except: self.error(object, name, value) class TraitInstance(TraitHandler): """Ensures that trait attribute values belong to a specified Python type. Any trait that uses a TraitInstance handler ensures that its values belong to the specified type or class (or one of its subclasses). For example:: class Employee(HasTraits): manager = Trait(None, TraitInstance(Employee, True)) This example defines a class Employee, which has a **manager** trait attribute, which accepts either None or an instance of Employee as its value. TraitInstance ensures that assigned values are exactly of the type specified (i.e., no coercion is performed). Parameters ---------- aClass : type, object or str A Python type or a string that identifies the type, or an object. If this is an object, it is mapped to the class it is an instance of. If this is a str, it is either the name of a class in the module identified by the module parameter, or an identifier of the form "*module_name*[.*module_name*....].*class_name*". allow_none : bool Flag indicating whether None is accepted as a valid value. module : str The name of the module that the class belongs to. This is ignored if the type is provided directly, or the str value is an identifier with '.'s in it. Attributes ---------- aClass : type or str A Python type, or a string which identifies the type. If this is a str, it is either the name of a class in the module identified by the module attribute, or an identifier of the form "*module_name*[.*module_name*....].*class_name*". A string value will be replaced by the actual type object the first time the trait is used to validate an object. module : str The name of the module that the class belongs to. This is ignored if the type is provided directly, or the str value is an identifier with '.'s in it. """ def __init__(self, aClass, allow_none=True, module=""): self._allow_none = allow_none self.module = module if isinstance(aClass, str): self.aClass = aClass else: if not isinstance(aClass, type): aClass = aClass.__class__ self.aClass = aClass self.set_fast_validate() def allow_none(self): """ Whether or not None is permitted as a valid value. Returns ------- bool Whether or not None is a valid value. """ self._allow_none = True if hasattr(self, "fast_validate"): self.set_fast_validate() def set_fast_validate(self): fast_validate = [ValidateTrait.instance, self.aClass] if self._allow_none: fast_validate = [ValidateTrait.instance, None, self.aClass] if self.aClass in TypeTypes: fast_validate[0] = ValidateTrait.type self.fast_validate = tuple(fast_validate) def validate(self, object, name, value): if value is None: if self._allow_none: return value else: self.error(object, name, value) if isinstance(self.aClass, str): self.resolve_class(object, name, value) if isinstance(value, self.aClass): return value self.error(object, name, value) def info(self): aClass = self.aClass if type(aClass) is not str: aClass = aClass.__name__ result = class_of(aClass) if self._allow_none: return result + " or None" return result def resolve_class(self, object, name, value): aClass = self.validate_class(self.find_class(self.aClass)) if aClass is None: self.error(object, name, value) self.aClass = aClass # fixme: The following is quite ugly, because it wants to try and fix # the trait referencing this handler to use the 'fast path' now that # the actual class has been resolved. The problem is finding the trait, # especially in the case of List(Instance('foo')), where the # object.base_trait(...) value is the List trait, not the Instance # trait, so we need to check for this and pull out the List # 'item_trait'. Obviously this does not extend well to other traits # containing nested trait references (Dict?)... self.set_fast_validate() trait = object.base_trait(name) handler = trait.handler if (handler is not self) and hasattr(handler, "item_trait"): trait = handler.item_trait trait.set_validate(self.fast_validate) def find_class(self, klass): module = self.module col = klass.rfind(".") if col >= 0: module = klass[:col] klass = klass[col + 1:] theClass = getattr(sys.modules.get(module), klass, None) if (theClass is None) and (col >= 0): try: mod = import_module(module) theClass = getattr(mod, klass, None) except Exception: pass return theClass def validate_class(self, aClass): return aClass def create_default_value(self, *args, **kw): aClass = args[0] if isinstance(aClass, str): aClass = self.validate_class(self.find_class(aClass)) if aClass is None: raise TraitError("Unable to locate class: " + args[0]) return aClass(*args[1:], **kw) def get_editor(self, trait): if self.editor is None: from traitsui.api import InstanceEditor self.editor = InstanceEditor( label=trait.label or "", view=trait.view or "", kind=trait.kind or "live", ) return self.editor class TraitFunction(TraitHandler): """Ensures that assigned trait attribute values are acceptable to a specified validator function. TraitFunction is the underlying handler for the predefined trait **Function**, and for the use of function references as arguments to the Trait() function. The signature of the function must be of the form *function*(*object*, *name*, *value*). The function must verify that *value* is a legal value for the *name* trait attribute of *object*. If it is, the value returned by the function is the actual value assigned to the trait attribute. If it is not, the function must raise a TraitError exception. Parameters ---------- aFunc : function A function to validate trait attribute values. Attributes ---------- aFunc : function A function to validate trait attribute values. """ def __init__(self, aFunc): if not isinstance(aFunc, CallableTypes): raise TraitError("Argument must be callable.") self.aFunc = aFunc self.fast_validate = (ValidateTrait.function, aFunc) def validate(self, object, name, value): try: return self.aFunc(object, name, value) except TraitError: self.error(object, name, value) def info(self): try: return self.aFunc.info except: if self.aFunc.__doc__: return self.aFunc.__doc__ return "a legal value" class TraitEnum(TraitHandler): """ Ensures that a value assigned to a trait attribute is a member of a specified list of values. TraitEnum is the underlying handler for the forms of the Trait() function that take a list of possible values The list of legal values can be provided as a list or tuple of values. That is, ``TraitEnum([1, 2, 3])``, ``TraitEnum((1, 2, 3))`` and ``TraitEnum(1, 2, 3)`` are equivalent. For example:: class Flower(HasTraits): color = Trait('white', TraitEnum(['white', 'yellow', 'red'])) kind = Trait('annual', TraitEnum('annual', 'perennial')) This example defines a Flower class, which has a **color** trait attribute, which can have as its value, one of the three strings, 'white', 'yellow', or 'red', and a **kind** trait attribute, which can have as its value, either of the strings 'annual' or 'perennial'. This is equivalent to the following class definition:: class Flower(HasTraits): color = Trait(['white', 'yellow', 'red']) kind = Trait('annual', 'perennial') The Trait() function automatically maps traits of the form shown in this example to the form shown in the preceding example whenever it encounters them in a trait definition. Parameters ---------- *values Either all legal values for the enumeration, or a single list or tuple of the legal values. Attributes ---------- values : tuple Enumeration of all legal values for a trait. """ def __init__(self, *values): if (len(values) == 1) and (type(values[0]) in SequenceTypes): values = values[0] self.values = tuple(values) self.fast_validate = (ValidateTrait.enum, self.values) def validate(self, object, name, value): if value in self.values: return value self.error(object, name, value) def info(self): return " or ".join([repr(x) for x in self.values]) def get_editor(self, trait): from traitsui.api import EnumEditor return EnumEditor( values=self, cols=trait.cols or 3, evaluate=trait.evaluate, mode=trait.mode or "radio", ) class TraitPrefixList(TraitHandler): r"""Ensures that a value assigned to a trait attribute is a member of a list of specified string values, or is a unique prefix of one of those values. TraitPrefixList is a variation on TraitEnum. The values that can be assigned to a trait attribute defined using a TraitPrefixList handler is the set of all strings supplied to the TraitPrefixList constructor, as well as any unique prefix of those strings. That is, if the set of strings supplied to the constructor is described by [*s*\ :sub:`1`\ , *s*\ :sub:`2`\ , ..., *s*\ :sub:`n`\ ], then the string *v* is a valid value for the trait if *v* == *s*\ :sub:`i[:j]` for one and only one pair of values (i, j). If *v* is a valid value, then the actual value assigned to the trait attribute is the corresponding *s*\ :sub:`i` value that *v* matched. As with TraitEnum, the list of legal values can be provided as a list or tuple of values. That is, ``TraitPrefixList(['one', 'two', 'three'])`` and ``TraitPrefixList('one', 'two', 'three')`` are equivalent. Example ------- :: class Person(HasTraits): married = Trait('no', TraitPrefixList('yes', 'no') The Person class has a **married** trait that accepts any of the strings 'y', 'ye', 'yes', 'n', or 'no' as valid values. However, the actual values assigned as the value of the trait attribute are limited to either 'yes' or 'no'. That is, if the value 'y' is assigned to the **married** attribute, the actual value assigned will be 'yes'. Note that the algorithm used by TraitPrefixList in determining whether a string is a valid value is fairly efficient in terms of both time and space, and is not based on a brute force set of comparisons. Parameters ---------- *values Either all legal string values for the enumeration, or a single list or tuple of legal string values. Attributes ---------- values : tuple of strings Enumeration of all legal values for a trait. """ @deprecated(_WARNING_FORMAT_STR.format( handler="TraitPrefixList", replacement="PrefixList")) def __init__(self, *values): if (len(values) == 1) and (type(values[0]) in SequenceTypes): values = values[0] self.values = values[:] self.values_ = values_ = {} for key in values: values_[key] = key self.fast_validate = (ValidateTrait.prefix_map, values_, self.validate) def validate(self, object, name, value): try: if value not in self.values_: match = None n = len(value) for key in self.values: if value == key[:n]: if match is not None: match = None break match = key if match is None: self.error(object, name, value) self.values_[value] = match return self.values_[value] except: self.error(object, name, value) def info(self): return ( " or ".join([repr(x) for x in self.values]) + " (or any unique prefix)" ) def get_editor(self, trait): from traitsui.api import EnumEditor return EnumEditor(values=self, cols=trait.cols or 3) def __getstate__(self): result = self.__dict__.copy() if "fast_validate" in result: del result["fast_validate"] return result class TraitMap(TraitHandler): """ Checks that the value assigned to a trait attribute is a key of a specified dictionary, and also assigns the dictionary value corresponding to that key to a *shadow* attribute. A trait attribute that uses a TraitMap handler is called *mapped* trait attribute. In practice, this means that the resulting object actually contains two attributes: one whose value is a key of the TraitMap dictionary, and the other whose value is the corresponding value of the TraitMap dictionary. The name of the shadow attribute is simply the base attribute name with an underscore ('_') appended. Mapped trait attributes can be used to allow a variety of user-friendly input values to be mapped to a set of internal, program-friendly values. Example ------- The following example defines a ``Person`` class:: >>> class Person(HasTraits): ... married = Trait('yes', TraitMap({'yes': 1, 'no': 0 }) ... >>> bob = Person() >>> print bob.married yes >>> print bob.married_ 1 In this example, the default value of the ``married`` attribute of the Person class is 'yes'. Because this attribute is defined using TraitPrefixList, instances of Person have another attribute, ``married_``, whose default value is 1, the dictionary value corresponding to the key 'yes'. Parameters ---------- map : dict A dictionary whose keys are valid values for the trait attribute, and whose corresponding values are the values for the shadow trait attribute. Attributes ---------- map : dict A dictionary whose keys are valid values for the trait attribute, and whose corresponding values are the values for the shadow trait attribute. """ is_mapped = True def __init__(self, map): self.map = map self.fast_validate = (ValidateTrait.map, map) def validate(self, object, name, value): try: if value in self.map: return value except: pass self.error(object, name, value) def mapped_value(self, value): """ Get the mapped value for a value. """ return self.map[value] def post_setattr(self, object, name, value): try: setattr(object, name + "_", self.mapped_value(value)) except: # We don't need a fancy error message, because this exception # should always be caught by a TraitCompound handler: raise TraitError("Unmappable") def info(self): keys = sorted(repr(x) for x in self.map.keys()) return " or ".join(keys) def get_editor(self, trait): from traitsui.api import EnumEditor return EnumEditor(values=self, cols=trait.cols or 3) class TraitPrefixMap(TraitMap): """A cross between the TraitPrefixList and TraitMap classes. Like TraitMap, TraitPrefixMap is created using a dictionary, but in this case, the keys of the dictionary must be strings. Like TraitPrefixList, a string *v* is a valid value for the trait attribute if it is a prefix of one and only one key *k* in the dictionary. The actual values assigned to the trait attribute is *k*, and its corresponding mapped attribute is *map*[*k*]. Example ------- :: mapping = {'true': 1, 'yes': 1, 'false': 0, 'no': 0 } boolean_map = Trait('true', TraitPrefixMap(mapping)) This example defines a Boolean trait that accepts any prefix of 'true', 'yes', 'false', or 'no', and maps them to 1 or 0. Parameters ---------- map : dict A dictionary whose keys are strings that are valid values for the trait attribute, and whose corresponding values are the values for the shadow trait attribute. Attributes ---------- map : dict A dictionary whose keys are strings that are valid values for the trait attribute, and whose corresponding values are the values for the shadow trait attribute. """ @deprecated(_WARNING_FORMAT_STR.format( handler="TraitPrefixMap", replacement="PrefixMap")) def __init__(self, map): self.map = map self._map = _map = {} for key in map.keys(): _map[key] = key self.fast_validate = (ValidateTrait.prefix_map, _map, self.validate) def validate(self, object, name, value): try: if value not in self._map: match = None n = len(value) for key in self.map.keys(): if value == key[:n]: if match is not None: match = None break match = key if match is None: self.error(object, name, value) self._map[value] = match return self._map[value] except: self.error(object, name, value) def info(self): return super().info() + " (or any unique prefix)" class TraitCompound(TraitHandler): """ Provides a logical-OR combination of other trait handlers. This class provides a means of creating complex trait definitions by combining several simpler trait definitions. TraitCompound is the underlying handler for the general forms of the Trait() function. A value is a valid value for a trait attribute based on a TraitCompound instance if the value is valid for at least one of the TraitHandler or trait objects supplied to the constructor. In addition, if at least one of the TraitHandler or trait objects is mapped (e.g., based on a TraitMap or TraitPrefixMap instance), then the TraitCompound is also mapped. In this case, any non-mapped traits or trait handlers use identity mapping. Parameters ---------- *handlers Either all TraitHandlers or trait objects to be combined, or a single list or tuple of TraitHandlers or trait objects. Attributes ---------- handlers : list or tuple A list or tuple of TraitHandler or trait objects to be combined. """ def __init__(self, *handlers): if (len(handlers) == 1) and (type(handlers[0]) in SequenceTypes): handlers = handlers[0] self.handlers = handlers self.set_validate() def set_validate(self): self.is_mapped = False self.has_items = False self.reversable = True post_setattrs = [] mapped_handlers = [] validates = [] fast_validates = [] slow_validates = [] for handler in self.handlers: fv = getattr(handler, "fast_validate", None) if fv is not None: validates.append(handler.validate) if fv[0] == ValidateTrait.complex: # If this is a nested complex fast validator, expand its # contents and adds its list to our list: fast_validates.extend(fv[1]) else: # Else just add the entire validator to the list: fast_validates.append(fv) else: slow_validates.append(handler.validate) post_setattr = getattr(handler, "post_setattr", None) if post_setattr is not None: post_setattrs.append(post_setattr) if handler.is_mapped: self.is_mapped = True mapped_handlers.append(handler) else: self.reversable = False if handler.has_items: self.has_items = True self.validates = validates self.slow_validates = slow_validates if self.is_mapped: self.mapped_handlers = mapped_handlers elif hasattr(self, "mapped_handlers"): del self.mapped_handlers # If there are any fast validators, then we create a 'complex' fast # validator that composites them: if len(fast_validates) > 0: # If there are any 'slow' validators, add a special handler at # the end of the fast validator list to handle them: if len(slow_validates) > 0: fast_validates.append((ValidateTrait.slow, self)) # Create the 'complex' fast validator: self.fast_validate = (ValidateTrait.complex, tuple(fast_validates)) elif hasattr(self, "fast_validate"): del self.fast_validate if len(post_setattrs) > 0: self.post_setattrs = post_setattrs self.post_setattr = self._post_setattr elif hasattr(self, "post_setattr"): del self.post_setattr def validate(self, object, name, value): for validate in self.validates: try: return validate(object, name, value) except TraitError: pass return self.slow_validate(object, name, value) def slow_validate(self, object, name, value): for validate in self.slow_validates: try: return validate(object, name, value) except TraitError: pass self.error(object, name, value) def full_info(self, object, name, value): return " or ".join( [x.full_info(object, name, value) for x in self.handlers] ) def info(self): return " or ".join([x.info() for x in self.handlers]) def mapped_value(self, value): for handler in self.mapped_handlers: try: return handler.mapped_value(value) except: pass return value def _post_setattr(self, object, name, value): for post_setattr in self.post_setattrs: try: post_setattr(object, name, value) return except TraitError: pass setattr(object, name + "_", value) def get_editor(self, trait): from traitsui.api import TextEditor, CompoundEditor the_editors = [x.get_editor(trait) for x in self.handlers] text_editor = TextEditor() count = 0 editors = [] for editor in the_editors: if isinstance(text_editor, editor.__class__): count += 1 if count > 1: continue editors.append(editor) return CompoundEditor(editors=editors) def items_event(self): return items_event() class TraitTuple(TraitHandler): r""" Ensures that values assigned to a trait attribute are tuples of a specified length, with elements that are of specified types. TraitTuple is the underlying handler for the predefined trait **Tuple**, and the trait factory Tuple(). Example ------- The following example defines a ``Card`` class:: rank = Range(1, 13) suit = Trait('Hearts', 'Diamonds', 'Spades', 'Clubs') class Card(HasTraits): value = Trait(TraitTuple(rank, suit)) The Card class has a **value** trait attribute, which must be a tuple of two elments. The first element must be an integer in the range from 1 to 13, and the second element must be one of the four strings, 'Hearts', 'Diamonds', 'Spades', or 'Clubs'. Parameters ---------- *args The traits, each *trait*\ :sub:`i` specifies the type that the *i*\ th element of a tuple must be. Each *trait*\ :sub:`i` must be either a trait, or a value that can be converted to a trait using the trait_from() function. The resulting trait handler accepts values that are tuples of the same length as *args*, and whose *i*\ th element is of the type specified by *trait*\ :sub:`i`. Parameters ---------- types : tuple of CTrait instances The traits to use for each item in a validated tuple. """ @deprecated(_WARNING_FORMAT_STR.format( handler="TraitTuple", replacement="Tuple")) def __init__(self, *args): self.types = tuple([trait_from(arg) for arg in args]) self.fast_validate = (ValidateTrait.tuple, self.types) def validate(self, object, name, value): try: if isinstance(value, tuple): types = self.types if len(value) == len(types): values = [] for i, type in enumerate(types): values.append( type.handler.validate(object, name, value[i]) ) return tuple(values) except: pass self.error(object, name, value) def full_info(self, object, name, value): return "a tuple of the form: (%s)" % ( ", ".join( [ self._trait_info(type, object, name, value) for type in self.types ] ) ) def _trait_info(self, type, object, name, value): handler = type.handler if handler is None: return "any value" return handler.full_info(object, name, value) def get_editor(self, trait): from traitsui.api import TupleEditor return TupleEditor( types=self.types, labels=trait.labels or [], cols=trait.cols or 1 ) class TraitList(TraitHandler): """ Ensures that a value assigned to a trait attribute is a list containing elements of a specified type, and that the length of the list is also within a specified range. TraitList also makes sure that any changes made to the list after it is assigned to the trait attribute do not violate the list's type and length constraints. TraitList is the underlying handler for the predefined list-based traits. Example ------- :: class Card(HasTraits): pass class Hand(HasTraits): cards = Trait([], TraitList(Trait(Card), maxlen=52)) This example defines a Hand class, which has a **cards** trait attribute, which is a list of Card objects and can have from 0 to 52 items in the list. Parameters ---------- trait : Trait The type of items the list can contain. If this is None or omitted, then no type checking is performed on any items in the list; otherwise, this must be either a trait, or a value that can be converted to a trait using the trait_from() function. minlen : int The minimum length of the list. maxlen : int The maximum length of the list. has_items : bool Flag indicating whether the list contains elements. Attributes ---------- item_trait : CTrait or None The type of items the list can contain. If None, no type checking is performed on the items of the list. minlen : int The minimum length of the list. maxlen : int The maximum length of the list. has_items : bool Flag indicating whether the list contains elements. """ info_trait = None default_value_type = DefaultValue.trait_list_object _items_event = None @deprecated(_WARNING_FORMAT_STR.format( handler="TraitList", replacement="List")) def __init__( self, trait=None, minlen=0, maxlen=sys.maxsize, has_items=True ): self.item_trait = trait_from(trait) self.minlen = max(0, minlen) self.maxlen = max(minlen, maxlen) self.has_items = has_items def clone(self): return TraitList( self.item_trait, self.minlen, self.maxlen, self.has_items ) def validate(self, object, name, value): if isinstance(value, list) and ( self.minlen <= len(value) <= self.maxlen ): return TraitListObject(self, object, name, value) self.error(object, name, value) def full_info(self, object, name, value): if self.minlen == 0: if self.maxlen == sys.maxsize: size = "items" else: size = "at most %d items" % self.maxlen else: if self.maxlen == sys.maxsize: size = "at least %d items" % self.minlen else: size = "from %s to %s items" % (self.minlen, self.maxlen) handler = self.item_trait.handler if handler is None: info = "" else: info = " which are %s" % handler.full_info(object, name, value) return "a list of %s%s" % (size, info) def get_editor(self, trait): from traits.editor_factories import list_editor return list_editor(trait, self) def items_event(self): return items_event() def items_event(): from .trait_types import Event if TraitList._items_event is None: TraitList._items_event = Event( TraitListEvent, is_base=False ).as_ctrait() return TraitList._items_event class TraitDict(TraitHandler): """ Ensures that values assigned to a trait attribute are dictionaries whose keys and values are of specified types. TraitDict also makes sure that any changes to keys or values made that are made after the dictionary is assigned to the trait attribute satisfy the type constraints. TraitDict is the underlying handler for the dictionary-based predefined traits, and the Dict() trait factory. Example ------- :: class WorkoutClass(HasTraits): member_weights = Trait({}, TraitDict(str, float)) This example defines a WorkoutClass class containing a *member_weights* trait attribute whose value must be a dictionary containing keys that are strings (i.e., the members' names) and whose associated values must be floats (i.e., their most recently recorded weight). Parameters ---------- key_trait : trait The type for the dictionary keys. If this is None or omitted, the keys in the dictionary can be of any type. Otherwise, this must be either a trait, or a value that can be converted to a trait using the trait_from() function. In this case, all dictionary keys are checked to ensure that they are of the type specified. value_trait : trait The type for the dictionary values. If this is None or omitted, the values in the dictionary can be of any type. Otherwise, this must be either a trait, or a value that can be converted to a trait using the trait_from() function. In this case, all dictionary values are checked to ensure that they are of the type specified. has_items : bool Flag indicating whether the dictionary contains entries. Attributes ---------- key_trait : CTrait or TraitHandler or None The type for the dictionary keys. If this is None then the keys are not validated. value_trait : CTrait or TraitHandler or None The type for the dictionary values. If this is None then the values are not validated. value_handler : BaseTraitHandler or None The trait handler for the dictionary values. has_items : bool Flag indicating whether the dictionary contains entries. """ info_trait = None default_value_type = DefaultValue.trait_list_object _items_event = None @deprecated(_WARNING_FORMAT_STR.format( handler="TraitDict", replacement="Dict")) def __init__(self, key_trait=None, value_trait=None, has_items=True): self.key_trait = trait_from(key_trait) self.value_trait = trait_from(value_trait) self.has_items = has_items handler = self.value_trait.handler if handler.has_items: handler = handler.clone() handler.has_items = False self.value_handler = handler def clone(self): return TraitDict(self.key_trait, self.value_trait, self.has_items) def validate(self, object, name, value): if isinstance(value, dict): return TraitDictObject(self, object, name, value) self.error(object, name, value) def full_info(self, object, name, value): extra = "" handler = self.key_trait.handler if handler is not None: extra = " with keys which are %s" % handler.full_info( object, name, value ) handler = self.value_handler if handler is not None: if extra == "": extra = " with" else: extra += " and" extra += " values which are %s" % handler.full_info( object, name, value ) return "a dictionary%s" % extra def get_editor(self, trait): if self.editor is None: from traitsui.api import TextEditor self.editor = TextEditor(evaluate=eval) return self.editor def items_event(self): from .trait_types import Event if TraitDict._items_event is None: TraitDict._items_event = Event( TraitDictEvent, is_base=False ).as_ctrait() return TraitDict._items_event traits-6.3.2/traits/trait_list_object.py000066400000000000000000000653571414270267200204410ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import copy import operator from weakref import ref from traits.observation.i_observable import IObservable from traits.trait_base import class_of, Undefined, _validate_everything from traits.trait_errors import TraitError class TraitListEvent(object): """ An object reporting in-place changes to a trait list. Parameters ---------- index : int or slice, optional An index or slice indicating the location of the changes to the trait list. The default is 0. added : list, optional The list of values added to the trait list. removed : list, optional The list of values removed from the list. Attributes ---------- index : int or slice An index or slice indicating the location of the changes to the list. added : list The list of values added to the list. If nothing was added this is an empty list. removed : list The list of values removed from the list. If nothing was removed this is an empty list. """ def __init__(self, *, index=0, removed=None, added=None): self.index = index if removed is None: removed = [] self.removed = removed if added is None: added = [] self.added = added def __repr__(self): return ( f"{self.__class__.__name__}(" f"index={self.index!r}, " f"removed={self.removed!r}, " f"added={self.added!r})" ) def _normalize_slice_or_index(index, length): """ Normalize a slice or index for use with __delitem__ or __setitem__. For slices with positive step, returns a slice that's equivalent for the purposes of __delitem__ and __setitem__ operations. For slices with negative step, a normalized slice representing the reverse of the given slice is returned: note that in this case, the matching *added* and *removed* lists will need to be reversed. Slices with a step of 1 or -1 are normalized to a single integer index, referring to the position of the first element referenced by the slice. Similarly, slices that refer to only a single element of the corresponding list (for example, a slice of `[1::10]` applied to a list of length 5) are normalized to the index that refers to that same element. Empty slices are also normalized to a single index. Note that in the case of an empty slice, the corresponding __delitem__ or __setitem__ operation does not cause any list change, so does not issue a notification. So the normalized index in this case is unused in current code. A normalized slice will have 0 <= start < stop <= length and a step >= 2. It should further satisfy start + step < stop. The stop will always be one larger than the last element referenced by the slice. For a plain integer index, it's assumed -length <= index < length on input (but this is not explicitly checked). A normalized output index will satisfy 0 <= index <= length. Parameters ---------- index : slice or integer The slice to normalize length : int The length of the list to which the slice will be applied. Returns ------- reversed : bool True if the returned slice is in the opposite direction to the original, else False. normalized_index : slice or integer An equivalent (or reversed equivalent) normalized slice or index. """ if not isinstance(index, slice): index = operator.index(index) return False, index + length if index < 0 else index start, stop, step = index.indices(length) reversed = step < 0 if reversed: start, stop, step = ( min(stop - step + (start - stop) % step, length), start + 1, -step, ) # Reduce stop so that equivalent slices give identical normalized # slices (e.g., del x[3:7:2] is equivalent to del x[3:6:2]). stop -= (stop - start - 1) % step # For a step of 1, a single item, or an empty slice, return a simple index. if step == 1 or stop - start <= step: return reversed, start else: return reversed, slice(start, stop, step) def _removed_items(items, index, return_for_invalid_index): """ Return removed items for a given list and index, suppressing IndexError. This is used by the __setitem__ and __delitem__ implementations to get the "removed" part of the event. Note that this deliberately suppresses any IndexError arising from an out-of-range integer index. A suitable IndexError will be re-raised when the actual __delitem__ or __setitem__ operation is performed. Parameters ---------- items : list The list being operated on. index : integer or slice Index of items to remove or replace. return_for_invalid_index : any Object to return for an invalid index. Returns ------- removed_items : list List containing the removed items. """ if isinstance(index, slice): return items[index] else: try: return [items[index]] except IndexError: return return_for_invalid_index @IObservable.register class TraitList(list): """ A subclass of list that validates and notifies listeners of changes. Parameters ---------- value : iterable Iterable providing the items for the list item_validator : callable, optional Called to validate and/or transform items added to the list. The callable should accept a single item from the list and return the transformed item, raising TraitError for invalid items. If not given, no item validation is performed. notifiers : list of callable, optional A list of callables with the signature:: notifier(trait_list, index, removed, added) If this argument is not given, the list of notifiers is initially empty. Attributes ---------- item_validator : callable Called to validate and/or transform items added to the list. The callable should accept a single item from the list and return the transformed item, raising TraitError for invalid items. notifiers : list of callable A list of callables with the signature:: notifier(trait_list, index, removed, added) """ def __new__(cls, *args, **kwargs): # We need a __new__ in addition to __init__ in order to properly # support unpickling: the 'append' or 'extend' methods may be # called during unpickling, triggering item validation. self = super().__new__(cls) self.item_validator = _validate_everything self.notifiers = [] return self def __init__(self, iterable=(), *, item_validator=None, notifiers=None): if item_validator is not None: self.item_validator = item_validator super().__init__(self.item_validator(item) for item in iterable) if notifiers is not None: self.notifiers = list(notifiers) def notify(self, index, removed, added): """ Call all notifiers. This simply calls all notifiers provided by the class, if any. The notifiers are expected to have the signature:: notifier(trait_list, index, removed, added) Any return values are ignored. Parameters ---------- index : int or slice The indices being modified by the operation. removed : list The items to be removed. added : list The items being added to the list. """ for notifier in self.notifiers: notifier(self, index, removed, added) # -- list interface ------------------------------------------------------- def __delitem__(self, key): """ Delete self[key]. Parameters ---------- key : integer or slice Index of the element(s) to be deleted. Raises ------ IndexError If key is an integer index and is out of range. """ original_length = len(self) removed = _removed_items(self, key, return_for_invalid_index=None) super().__delitem__(key) if removed: reversed, normalized_key = _normalize_slice_or_index( key, original_length) if reversed: removed = removed[::-1] self.notify(normalized_key, removed, []) def __iadd__(self, value): """ Implement self += value. Parameters ---------- value : iterable The items to be added. Returns ------- self : TraitList The modified list. """ original_length = len(self) added = [self.item_validator(item) for item in value] extended = super().__iadd__(added) if added: self.notify(original_length, [], added) return extended def __imul__(self, value): """ Implement self *= value. Parameters ---------- value : integer The multiplier. Returns ------- self : TraitList The modified list. """ if value < 1: removed = self.copy() multiplied = super().__imul__(value) if removed: self.notify(0, removed, []) else: original_length = len(self) multiplied = super().__imul__(value) added = self[original_length:] if added: self.notify(original_length, [], added) return multiplied def __setitem__(self, key, value): """ Set self[key] to value. Parameters ---------- key : integer or slice Index of the element(s) to be replaced. value : iterable Replacement values. Raises ------ IndexError If key is an integer index and is out of range. ValueError If key is an extended slice (that is, it's a slice whose step is not 1 and not None) and the number of replacement elements doesn't match the number of removed elements. """ original_length = len(self) removed = _removed_items(self, key, return_for_invalid_index=None) if isinstance(key, slice): value = [self.item_validator(item) for item in value] added = value else: value = self.item_validator(value) added = [value] super().__setitem__(key, value) if added or removed: reversed, normalized_key = _normalize_slice_or_index( key, original_length) if reversed: added = added[::-1] removed = removed[::-1] self.notify(normalized_key, removed, added) def append(self, object): """ Append object to the end of the list. Parameters ---------- object : any The object to append. """ original_length = len(self) super().append(self.item_validator(object)) self.notify(original_length, [], self[original_length:]) def clear(self): """ Remove all items from list. """ removed = self.copy() super().clear() if removed: self.notify(0, removed, []) def extend(self, iterable): """ Extend list by appending elements from the iterable. Parameters ---------- iterable : iterable The elements to append. """ original_length = len(self) added = [self.item_validator(item) for item in iterable] super().extend(added) if added: self.notify(original_length, [], added) def insert(self, index, object): """ Insert object before index. Parameters ---------- index : integer The position at which to insert. object : object The object to insert. """ # For insert, *any* index is valid! if index < 0: normalized_index = max(index + len(self), 0) else: normalized_index = min(index, len(self)) object = self.item_validator(object) super().insert(index, self.item_validator(object)) self.notify(normalized_index, [], [object]) def pop(self, index=-1): """ Remove and return item at index (default last). Parameters ---------- index : int, optional Index at which to remove item. If not given, the last item of the list is removed. Returns ------- item : object The removed item. Raises ------ IndexError If list is empty or index is out of range. """ # We don't need to worry about indices < -len(self) or >= len(self): # for those, the pop call will raise anyway. normalized_index = index + len(self) if index < 0 else index item = super().pop(index) self.notify(normalized_index, [item], []) return item def remove(self, value): """ Remove first occurrence of value. Notes ----- The value is not validated or converted before removal. Parameters ---------- value : object Value to be removed. Raises ------ ValueError If the value is not present. """ # Suppress ValueError. If the index call fails because the item is not # in the list, remove should also fail, and we want to allow the remove # error to propagate. try: index = self.index(value) except ValueError: pass else: removed = [self[index]] super().remove(value) self.notify(index, removed, []) def reverse(self): """ Reverse the items in the list in place. """ removed = self.copy() super().reverse() if removed: self.notify(0, removed, self.copy()) def sort(self, *, key=None, reverse=False): """ Sort the list in ascending order and return None. The sort is in-place (i.e. the list itself is modified) and stable (i.e. the order of two equal elements is maintained). If a key function is given, apply it once to each list item and sort them, ascending or descending, according to their function values. The reverse flag can be set to sort in descending order. Parameters ---------- key : callable Custom function that accepts a single item from the list and returns the key to be used in comparisons. reverse : bool If true, the resulting list will be sorted in descending order. """ removed = self.copy() super().sort(key=key, reverse=reverse) if removed: self.notify(0, removed, self.copy()) # -- pickle and copy support ---------------------------------------------- def __deepcopy__(self, memo): """ Perform a deepcopy operation. Notifiers are transient and should not be copied. """ return type(self)( [copy.deepcopy(x, memo) for x in self], item_validator=copy.deepcopy(self.item_validator, memo), ) def __getstate__(self): """ Get the state of the object for serialization. Notifiers are transient and should not be serialized. """ result = self.__dict__.copy() result.pop("notifiers", None) return result def __setstate__(self, state): """ Restore the state of the object after serialization. Notifiers are transient and are restored to the empty list. """ state["notifiers"] = [] self.__dict__.update(state) # -- Implement IObservable ------------------------------------------------ def _notifiers(self, force_create): """ Return a list of callables where each callable is a notifier. The list is expected to be mutated for contributing or removing notifiers from the object. Parameters ---------- force_create: boolean It is added for compatibility with CTrait. Not used here. """ return self.notifiers class TraitListObject(TraitList): """ A specialization of TraitList with a default validator and notifier which provide bug-for-bug compatibility with the TraitListObject from Traits versions before 6.0. Parameters ---------- trait : CTrait The trait that the list has been assigned to. object : HasTraits The object the list belongs to. name : str The name of the trait on the object. value : iterable The initial value of the list. Attributes ---------- trait : CTrait The trait that the list has been assigned to. object : HasTraits The object the list belongs to. name : str The name of the trait on the object. value : iterable The initial value of the list. """ def __init__(self, trait, object, name, value): self.trait = trait self.object = ref(object) self.name = name self.name_items = None if trait.has_items: self.name_items = name + "_items" # Convert to an explicit list so that we can validate the length. value = list(value) self._validate_length(len(value)) super().__init__( value, item_validator=self._item_validator, notifiers=[self.notifier], ) def notifier(self, trait_list, index, removed, added): """ Converts and consolidates the parameters to a TraitListEvent and then fires the event. Parameters ---------- trait_list : list The list index : int or slice Index or slice that was modified removed : list Values that were removed added : list Values that were added """ is_trait_none = self.trait is None is_name_items_none = self.name_items is None if not hasattr(self, "trait") or is_trait_none or is_name_items_none: return object = self.object() if object is None: return if getattr(object, self.name) is not self: # Workaround having this list inside another container which # also uses the name_items trait for notification. # See enthought/traits#25, enthought/traits#281 return event = TraitListEvent(index=index, removed=removed, added=added) items_event = self.trait.items_event() object.trait_items_event(self.name_items, event, items_event) # -- list interface ------------------------------------------------------- def __delitem__(self, key): """ Delete self[key]. Parameters ---------- key : integer or slice Index of the element(s) to be deleted. Raises ------ IndexError If key is an integer index and is out of range. """ removed_count = len(self[key]) if isinstance(key, slice) else 1 self._validate_length(max(len(self) - removed_count, 0)) super().__delitem__(key) def __iadd__(self, value): """ Implement self += value. Parameters ---------- value : iterable The items to be added. Returns ------- self : TraitList The modified list. """ # Convert input to a concrete list for length-checking purposes. value = list(value) self._validate_length(len(self) + len(value)) return super().__iadd__(value) def __imul__(self, value): """ Implement self *= value. Parameters ---------- value : integer The multiplier. Returns ------- self : TraitList The modified list. """ self._validate_length(max(0, len(self) * value)) return super().__imul__(value) def __setitem__(self, key, value): """ Set self[key] to value. Parameters ---------- key : integer or slice Index of the element(s) to be replaced. value : iterable Replacement values. Raises ------ IndexError If key is an integer index and is out of range. ValueError If key is an extended slice (that is, it's a slice whose step is not 1 and not None) and the number of replacement elements doesn't match the number of removed elements. """ if isinstance(key, slice): value = list(value) if key.step is None or key.step == 1: self._validate_length(len(self) - len(self[key]) + len(value)) else: # No length change possible, so no need to validate length. But # for backwards compatibility we simulate Python's complaint # about any length difference before validating items. if len(value) != len(self[key]): raise ValueError( "attempt to assign sequence of size {} " "to extended slice of size {}".format( len(value), len(self[key]) ) ) super().__setitem__(key, value) def append(self, object): """ Append object to the end of the list. Parameters ---------- object : any The object to append. """ self._validate_length(len(self) + 1) super().append(object) def clear(self): """ Remove all items from list. """ self._validate_length(0) super().clear() def extend(self, iterable): """ Extend list by appending elements from the iterable. Parameters ---------- iterable : iterable The elements to append. """ # Convert input to a concrete list for length-checking purposes. items = list(iterable) self._validate_length(len(self) + len(items)) super().extend(items) def insert(self, index, object): """ Insert object before index. Parameters ---------- index : integer The position at which to insert. object : object The object to insert. """ self._validate_length(len(self) + 1) super().insert(index, object) def pop(self, index=-1): """ Remove and return item at index (default last). Parameters ---------- index : int, optional Index at which to remove item. If not given, the last item of the list is removed. Returns ------- item : object The removed item. Raises ------ IndexError If list is empty or index is out of range. """ self._validate_length(max(len(self) - 1, 0)) return super().pop(index) def remove(self, value): """ Remove first occurrence of value. Notes ----- The value is not validated or converted before removal. Parameters ---------- value : object Value to be removed. Raises ------ ValueError If the value is not present. """ self._validate_length(max(len(self) - 1, 0)) super().remove(value) # -- pickle and copy support ---------------------------------------------- def __deepcopy__(self, memo): """ Perform a deepcopy operation. Notifiers are transient and should not be copied. """ return TraitListObject( self.trait, lambda: None, self.name, [copy.deepcopy(x, memo) for x in self], ) def __getstate__(self): """ Get the state of the object for serialization. Notifiers are transient and should not be serialized. """ result = super().__getstate__() result.pop("object", None) result.pop("trait", None) return result def __setstate__(self, state): """ Restore the state of the object after serialization. Notifiers are transient and are restored to the empty list. """ name = state.setdefault("name", "") state["notifiers"] = [self.notifier] object = state.pop("object", None) if object is not None: state["object"] = ref(object) trait = self.object()._trait(name, 0) if trait is not None: state["trait"] = trait.handler else: state["object"] = lambda: None state["trait"] = None self.__dict__.update(state) # -- private methods ------------------------------------------------------ def _item_validator(self, value): """ Validate an item that's being added to the list. """ object = self.object() if object is None: return value trait_validator = self.trait.item_trait.handler.validate if trait_validator is None: return value try: return trait_validator(object, self.name, value) except TraitError as excp: excp.set_prefix("Each element of the") raise def _validate_length(self, new_length): """ Validate the new length for a proposed operation. Parameters ---------- new_length : int New length of the list. Raises ------ TraitError If the proposed new length would violate the length constraints of the list. """ trait = getattr(self, "trait", None) if trait is None: return if not trait.minlen <= new_length <= trait.maxlen: raise TraitError( "The '%s' trait of %s instance must be %s, " "but you attempted to change its length to %d %s." % ( self.name, class_of(self.object()), self.trait.full_info(self.object(), self.name, Undefined), new_length, "element" if new_length == 1 else "elements", ) ) traits-6.3.2/traits/trait_notifiers.py000066400000000000000000000606121414270267200201270ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Classes that implement and support the Traits change notification mechanism """ import contextlib import logging import threading from threading import local as thread_local from threading import Thread import traceback from types import MethodType import weakref import sys from .constants import ComparisonMode, TraitKind from .trait_base import Uninitialized from .trait_errors import TraitNotificationError # Global Data # The thread ID for the user interface thread ui_thread = -1 # The handler for notifications that must be run on the UI thread ui_handler = None def set_ui_handler(handler): """ Sets up the user interface thread handler. """ global ui_handler, ui_thread ui_handler = handler ui_thread = threading.current_thread().ident def ui_dispatch(handler, *args, **kw): if threading.current_thread().ident == ui_thread: handler(*args, **kw) else: ui_handler(handler, *args, **kw) class NotificationExceptionHandlerState(object): def __init__(self, handler, reraise_exceptions, locked): self.handler = handler self.reraise_exceptions = reraise_exceptions self.locked = locked class NotificationExceptionHandler(object): def __init__(self): self.traits_logger = None self.main_thread = None self.thread_local = thread_local() # -- Private Methods ------------------------------------------------------ def _push_handler( self, handler=None, reraise_exceptions=False, main=False, locked=False ): """ Pushes a new traits notification exception handler onto the stack, making it the new exception handler. Returns a NotificationExceptionHandlerState object describing the previous exception handler. Parameters ---------- handler : handler The new exception handler, which should be a callable or None. If None (the default), then the default traits notification exception handler is used. If *handler* is not None, then it must be a callable which can accept four arguments: object, trait_name, old_value, new_value. reraise_exceptions : bool Indicates whether exceptions should be reraised after the exception handler has executed. If True, exceptions will be re-raised after the specified handler has been executed. The default value is False. main : bool Indicates whether the caller represents the main application thread. If True, then the caller's exception handler is made the default handler for any other threads that are created. Note that a thread can explicitly set its own exception handler if desired. The *main* flag is provided to make it easier to set a global application policy without having to explicitly set it for each thread. The default value is False. locked : bool Indicates whether further changes to the Traits notification exception handler state should be allowed. If True, then any subsequent calls to _push_handler() or _pop_handler() for that thread will raise a TraitNotificationError. The default value is False. """ handlers = self._get_handlers() self._check_lock(handlers) if handler is None: handler = self._log_exception handlers.append( NotificationExceptionHandlerState( handler, reraise_exceptions, locked ) ) if main: self.main_thread = handlers return handlers[-2] def _pop_handler(self): """ Pops the traits notification exception handler stack, restoring the exception handler in effect prior to the most recent _push_handler() call. If the stack is empty or locked, a TraitNotificationError exception is raised. Note that each thread has its own independent stack. See the description of the _push_handler() method for more information on this. """ handlers = self._get_handlers() self._check_lock(handlers) if len(handlers) > 1: handlers.pop() else: raise TraitNotificationError( "Attempted to pop an empty traits notification exception " "handler stack." ) def _handle_exception(self, object, trait_name, old, new): """ Handles a traits notification exception using the handler defined by the topmost stack entry for the corresponding thread. """ excp_class, excp = sys.exc_info()[:2] handler_info = self._get_handlers()[-1] handler_info.handler(object, trait_name, old, new) if handler_info.reraise_exceptions or isinstance( excp, TraitNotificationError ): raise excp def _get_handlers(self): """ Returns the handler stack associated with the currently executing thread. """ thread_local = self.thread_local if isinstance(thread_local, dict): id = threading.current_thread().ident handlers = thread_local.get(id) else: handlers = getattr(thread_local, "handlers", None) if handlers is None: if self.main_thread is not None: handler = self.main_thread[-1] else: handler = NotificationExceptionHandlerState( self._log_exception, False, False ) handlers = [handler] if isinstance(thread_local, dict): thread_local[id] = handlers else: thread_local.handlers = handlers return handlers def _check_lock(self, handlers): """ Raises an exception if the specified handler stack is locked. """ if handlers[-1].locked: raise TraitNotificationError( "The traits notification exception handler is locked. " "No changes are allowed." ) def _log_exception(self, object, trait_name, old, new): """ Logs any exceptions generated in a trait notification handler. This method defines the default notification exception handling behavior of traits. However, it can be completely overridden by pushing a new handler using the '_push_handler' method. """ # When the stack depth is too great, the logger can't always log the # message. Make sure that it goes to the console at a minimum: excp_class, excp = sys.exc_info()[:2] if ( (excp_class is RuntimeError) and (len(excp.args) > 0) and (excp.args[0] == "maximum recursion depth exceeded") ): sys.__stderr__.write( "Exception occurred in traits notification " "handler for object: %s, trait: %s, old value: %s, " "new value: %s.\n%s\n" % ( object, trait_name, old, new, "".join(traceback.format_exception(*sys.exc_info())), ) ) logger = self.traits_logger if logger is None: self.traits_logger = logger = logging.getLogger("traits") try: logger.exception( "Exception occurred in traits notification handler for " "object: %s, trait: %s, old value: %s, new value: %s" % (object, trait_name, old, new) ) except Exception: # Ignore anything we can't log the above way: pass # Traits global notification exception handler notification_exception_handler = NotificationExceptionHandler() push_exception_handler = notification_exception_handler._push_handler pop_exception_handler = notification_exception_handler._pop_handler handle_exception = notification_exception_handler._handle_exception # Traits global notification event tracer _pre_change_event_tracer = None _post_change_event_tracer = None def set_change_event_tracers(pre_tracer=None, post_tracer=None): """ Set the global trait change event tracers. The global tracers are called whenever a trait change event is dispatched. There are two tracers: `pre_tracer` is called before the notification is sent; `post_tracer` is called after the notification is sent, even if the notification failed with an exception (in which case the `post_tracer` is called with a reference to the exception, then the exception is sent to the `notification_exception_handler`). The tracers should be a callable taking 5 arguments: :: tracer(obj, trait_name, old, new, handler) `obj` is the source object, on which trait `trait_name` was changed from value `old` to value `new`. `handler` is the function or method that will be notified of the change. The post-notification tracer also has a keyword argument, `exception`, that is `None` if no exception has been raised, and the a reference to the raise exception otherwise. :: post_tracer(obj, trait_name, old, new, handler, exception=None) Note that for static trait change listeners, `handler` is not a method, but rather the function before class creation, since this is the way Traits works at the moment. """ global _pre_change_event_tracer global _post_change_event_tracer _pre_change_event_tracer = pre_tracer _post_change_event_tracer = post_tracer def get_change_event_tracers(): """ Get the currently active global trait change event tracers. """ return _pre_change_event_tracer, _post_change_event_tracer def clear_change_event_tracers(): """ Clear the global trait change event tracer. """ global _pre_change_event_tracer global _post_change_event_tracer _pre_change_event_tracer = None _post_change_event_tracer = None @contextlib.contextmanager def change_event_tracers(pre_tracer, post_tracer): """ Context manager to temporarily change the global event tracers. """ old_pre_tracer, old_post_tracer = get_change_event_tracers() set_change_event_tracers(pre_tracer, post_tracer) try: yield finally: set_change_event_tracers(old_pre_tracer, old_post_tracer) class AbstractStaticChangeNotifyWrapper(object): """ Concrete implementation must define the 'argument_transforms' class argument, a dictionary mapping the number of arguments in the event handler to a function that takes the arguments (obj, trait_name, old, new) and returns the arguments tuple for the actual handler. """ arguments_transforms = {} def __init__(self, handler): arg_count = handler.__code__.co_argcount if arg_count > 4: raise TraitNotificationError( ( "Invalid number of arguments for the static anytrait " "change notification handler: %s. A maximum of 4 " "arguments is allowed, but %s were specified." ) % (handler.__name__, arg_count) ) self.argument_transform = self.argument_transforms[arg_count] self.handler = handler def __call__(self, object, trait_name, old, new): """ Dispatch to the appropriate handler method. """ if _change_accepted(object, trait_name, old, new): # Extract the arguments needed from the handler. args = self.argument_transform(object, trait_name, old, new) # Send a description of the change event to the event tracer. if _pre_change_event_tracer is not None: _pre_change_event_tracer( object, trait_name, old, new, self.handler ) try: # Call the handler. self.handler(*args) except Exception as e: if _post_change_event_tracer is not None: _post_change_event_tracer( object, trait_name, old, new, self.handler, exception=e ) handle_exception(object, trait_name, old, new) else: if _post_change_event_tracer is not None: _post_change_event_tracer( object, trait_name, old, new, self.handler, exception=None, ) def equals(self, handler): return False class StaticAnytraitChangeNotifyWrapper(AbstractStaticChangeNotifyWrapper): # The wrapper is called with the full set of argument, and we need to # create a tuple with the arguments that need to be sent to the event # handler, depending on the number of those. argument_transforms = { 0: lambda obj, name, old, new: (), 1: lambda obj, name, old, new: (obj,), 2: lambda obj, name, old, new: (obj, name), 3: lambda obj, name, old, new: (obj, name, new), 4: lambda obj, name, old, new: (obj, name, old, new), } class StaticTraitChangeNotifyWrapper(AbstractStaticChangeNotifyWrapper): # The wrapper is called with the full set of argument, and we need to # create a tuple with the arguments that need to be sent to the event # handler, depending on the number of those. argument_transforms = { 0: lambda obj, name, old, new: (), 1: lambda obj, name, old, new: (obj,), 2: lambda obj, name, old, new: (obj, new), 3: lambda obj, name, old, new: (obj, old, new), 4: lambda obj, name, old, new: (obj, name, old, new), } class TraitChangeNotifyWrapper(object): """ Dynamic change notify wrapper. This class is in charge to dispatch trait change events to dynamic listener, typically created using the `on_trait_change` method, or the decorator with the same name. """ # The wrapper is called with the full set of argument, and we need to # create a tuple with the arguments that need to be sent to the event # handler, depending on the number of those. argument_transforms = { 0: lambda obj, name, old, new: (), 1: lambda obj, name, old, new: (new,), 2: lambda obj, name, old, new: (name, new), 3: lambda obj, name, old, new: (obj, name, new), 4: lambda obj, name, old, new: (obj, name, old, new), } def __init__(self, handler, owner, target=None): self.init(handler, owner, target) def init(self, handler, owner, target=None): # If target is not None and handler is a function then the handler # will be removed when target is deleted. if type(handler) is MethodType: func = handler.__func__ object = handler.__self__ if object is not None: self.object = weakref.ref(object, self.listener_deleted) self.name = handler.__name__ self.owner = owner arg_count = func.__code__.co_argcount - 1 if arg_count > 4: raise TraitNotificationError( ( "Invalid number of arguments for the dynamic " "trait change notification handler: %s. A maximum " "of 4 arguments is allowed, but %s were specified." ) % (func.__name__, arg_count) ) # We use the unbound method here to prevent cyclic garbage # (issue #100). self.notify_listener = type(self)._notify_method_listener self.argument_transform = self.argument_transforms[arg_count] return arg_count elif target is not None: # Set up so the handler will be removed when the target is deleted. self.object = weakref.ref(target, self.listener_deleted) self.owner = owner arg_count = handler.__code__.co_argcount if arg_count > 4: raise TraitNotificationError( ( "Invalid number of arguments for the dynamic trait change " "notification handler: %s. A maximum of 4 arguments is " "allowed, but %s were specified." ) % (handler.__name__, arg_count) ) self.name = None self.handler = handler # We use the unbound method here to prevent cyclic garbage # (issue #100). self.notify_listener = type(self)._notify_function_listener self.argument_transform = self.argument_transforms[arg_count] return arg_count def __call__(self, object, trait_name, old, new): """ Dispatch to the appropriate method. We do explicit dispatch instead of assigning to the .__call__ instance attribute to avoid reference cycles. """ # `notify_listener` is either the *unbound* # `_notify_method_listener` or `_notify_function_listener` to # prevent cyclic garbage (issue #100). self.notify_listener(self, object, trait_name, old, new) def dispatch(self, handler, *args): """ Dispatch the event to the listener. This method is normally the only one that needs to be overridden in a subclass to implement the subclass's dispatch mechanism. """ handler(*args) def equals(self, handler): if handler is self: return True if (type(handler) is MethodType) and (handler.__self__ is not None): return (handler.__name__ == self.name) and ( handler.__self__ is self.object() ) return (self.name is None) and (handler == self.handler) def listener_deleted(self, ref): # In multithreaded situations, it's possible for this method to # be called after, or concurrently with, the dispose method. # Don't raise in that case. try: self.owner.remove(self) except ValueError: pass self.object = self.owner = None def dispose(self): self.object = None def _dispatch_change_event(self, object, trait_name, old, new, handler): """ Prepare and dispatch a trait change event to a listener. """ # Extract the arguments needed from the handler. args = self.argument_transform(object, trait_name, old, new) # Send a description of the event to the change event tracer. if _pre_change_event_tracer is not None: _pre_change_event_tracer(object, trait_name, old, new, handler) # Dispatch the event to the listener. try: self.dispatch(handler, *args) except Exception as e: if _post_change_event_tracer is not None: _post_change_event_tracer( object, trait_name, old, new, handler, exception=e ) # This call needs to be made inside the `except` block in case # the handler wants to re-raise the exception. handle_exception(object, trait_name, old, new) else: if _post_change_event_tracer is not None: _post_change_event_tracer( object, trait_name, old, new, handler, exception=None ) def _notify_method_listener(self, object, trait_name, old, new): """ Dispatch a trait change event to a method listener. """ obj_weak_ref = self.object if (obj_weak_ref is not None and _change_accepted(object, trait_name, old, new)): # We make sure to hold a reference to the object before invoking # `getattr` so that the listener does not disappear in a # multi-threaded case. obj = obj_weak_ref() if obj is not None: # Dynamically resolve the listener by name. listener = getattr(obj, self.name) self._dispatch_change_event( object, trait_name, old, new, listener ) def _notify_function_listener(self, object, trait_name, old, new): """ Dispatch a trait change event to a function listener. """ if _change_accepted(object, trait_name, old, new): self._dispatch_change_event( object, trait_name, old, new, self.handler ) class ExtendedTraitChangeNotifyWrapper(TraitChangeNotifyWrapper): """ Change notify wrapper for "extended" trait change events.. The "extended notifiers" are set up internally when using extended traits, to add/remove traits listeners when one of the intermediate traits changes. For example, in a listener for the extended trait `a.b`, we need to add/remove listeners to `a:b` when `a` changes. """ def _dispatch_change_event(self, object, trait_name, old, new, handler): """ Prepare and dispatch a trait change event to a listener. """ # Extract the arguments needed from the handler. args = self.argument_transform(object, trait_name, old, new) # Dispatch the event to the listener. try: self.dispatch(handler, *args) except Exception: handle_exception(object, trait_name, old, new) def _notify_method_listener(self, object, trait_name, old, new): """ Dispatch a trait change event to a method listener. """ obj_weak_ref = self.object if obj_weak_ref is not None: # We make sure to hold a reference to the object before invoking # `getattr` so that the listener does not disappear in a # multi-threaded case. obj = obj_weak_ref() if obj is not None: # Dynamically resolve the listener by name. listener = getattr(obj, self.name) self._dispatch_change_event( object, trait_name, old, new, listener ) def _notify_function_listener(self, object, trait_name, old, new): """ Dispatch a trait change event to a function listener. """ self._dispatch_change_event(object, trait_name, old, new, self.handler) class FastUITraitChangeNotifyWrapper(TraitChangeNotifyWrapper): """ Dynamic change notify wrapper, dispatching on the UI thread. This class is in charge to dispatch trait change events to dynamic listener, typically created using the `on_trait_change` method and the `dispatch` parameter set to 'ui' or 'fast_ui'. """ def dispatch(self, handler, *args): if threading.current_thread().ident == ui_thread: handler(*args) else: ui_handler(handler, *args) class NewTraitChangeNotifyWrapper(TraitChangeNotifyWrapper): """ Dynamic change notify wrapper, dispatching on a new thread. This class is in charge to dispatch trait change events to dynamic listener, typically created using the `on_trait_change` method and the `dispatch` parameter set to 'new'. """ def dispatch(self, handler, *args): Thread(target=handler, args=args).start() def _change_accepted(object, name, old, new): """ Return true if notifications should be emitted for the change. Parameters ---------- object : HasTraits The object on which the trait is changed. name : str The name of the trait changed. old : any The old value new : any The new value Returns ------- accepted : bool Whether the event should be emitted. """ if old is Uninitialized: return False trait = object._trait(name, 2) if (trait.type == TraitKind.trait.name and trait.comparison_mode == ComparisonMode.equality): try: return bool(old != new) except Exception: # Maybe do something else about the exception # enthought/traits#1230 pass return True traits-6.3.2/traits/trait_numeric.py000066400000000000000000000350351414270267200175700ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Trait definitions related to the numpy library. """ import warnings from .constants import ComparisonMode, DefaultValue from .trait_base import SequenceTypes from .trait_errors import TraitError from .trait_type import TraitType from .trait_types import Str, Any, Int as TInt, Float as TFloat # Deferred imports from numpy: ndarray = None asarray = None def dtype2trait(dtype): """ Get the corresponding trait for a numpy dtype. """ import numpy if dtype.char in numpy.typecodes["Float"]: return TFloat elif dtype.char in numpy.typecodes["AllInteger"]: return TInt elif dtype.char[0] == "S": return Str else: return Any class AbstractArray(TraitType): """ Abstract base class for defining numpy-based arrays. """ def __init__( self, dtype=None, shape=None, value=None, coerce=False, typecode=None, *, casting="unsafe", **metadata ): global ndarray, asarray try: import numpy except ImportError: raise TraitError( "Using Array or CArray trait types requires the " "numpy package to be installed." ) from numpy import asarray, ndarray # Mark this as being an 'array' trait: metadata["array"] = True # Normally use object identity to detect array values changing: metadata.setdefault("comparison_mode", ComparisonMode.identity) if typecode is not None: warnings.warn( "typecode is a deprecated argument; use dtype " "instead", DeprecationWarning, ) if (dtype is not None) and (dtype != typecode): raise TraitError( "Inconsistent usage of the dtype and " "typecode arguments; use dtype alone." ) else: dtype = typecode if dtype is not None: try: # Convert the argument into an actual numpy dtype object: dtype = numpy.dtype(dtype) except TypeError: raise TraitError( "could not convert %r to a numpy dtype" % dtype ) if shape is not None: if isinstance(shape, SequenceTypes): for item in shape: if ( (item is None) or (type(item) is int) or ( isinstance(item, SequenceTypes) and (len(item) == 2) and (type(item[0]) is int) and (item[0] >= 0) and ( (item[1] is None) or ( (type(item[1]) is int) and (item[0] <= item[1]) ) ) ) ): continue raise TraitError("shape should be a list or tuple") else: raise TraitError("shape should be a list or tuple") if value is None: value = self._default_for_dtype_and_shape(dtype, shape) self.dtype = dtype self.shape = shape self.coerce = coerce self.casting = casting super().__init__(value, **metadata) def validate(self, object, name, value): """ Validates that the value is a valid array. """ try: # Make sure the value is an array: if not isinstance(value, ndarray): if not isinstance(value, SequenceTypes): self.error(object, name, value) if self.dtype is not None: value = asarray(value, self.dtype) else: value = asarray(value) # Make sure the array is of the right type: if (self.dtype is not None) and (value.dtype != self.dtype): value = value.astype(self.dtype, casting=self.casting) # If no shape requirements, then return the value: trait_shape = self.shape if trait_shape is None: return value # Else make sure that the value's shape is compatible: value_shape = value.shape if len(trait_shape) == len(value_shape): for i, dim in enumerate(value_shape): item = trait_shape[i] if item is not None: if type(item) is int: if dim != item: break elif (dim < item[0]) or ( (item[1] is not None) and (dim > item[1]) ): break else: return value except: pass self.error(object, name, value) def info(self): """ Returns descriptive information about the trait. """ dtype = shape = "" if self.shape is not None: shape = [] for item in self.shape: if item is None: item = "*" elif type(item) is not int: if item[1] is None: item = "%d.." % item[0] else: item = "%d..%d" % item shape.append(item) shape = " with shape %s" % (tuple(shape),) if self.dtype is not None: # FIXME: restore nicer descriptions of dtypes. dtype = " of %s values" % self.dtype return "an array%s%s" % (dtype, shape) def create_editor(self): """ Returns the default UI editor for the trait. """ editor = None auto_set = False if self.auto_set is None: auto_set = True enter_set = self.enter_set or False if self.shape is not None and len(self.shape) == 2: from traitsui.api import ArrayEditor editor = ArrayEditor(auto_set=auto_set, enter_set=enter_set) else: from traitsui.api import TupleEditor if self.dtype is None: types = Any else: types = dtype2trait(self.dtype) editor = TupleEditor( types=types, labels=self.labels or [], cols=self.cols or 1, auto_set=auto_set, enter_set=enter_set, ) return editor # -- Private Methods ------------------------------------------------------ def get_default_value(self): """ Returns the default value constructor for the type (called from the trait factory. """ return ( DefaultValue.callable_and_args, ( self.copy_default_value, (self.validate(None, None, self.default_value),), None, ), ) def copy_default_value(self, value): """ Returns a copy of the default value (called from the C code on first reference to a trait with no current value). """ return value.copy() def _default_for_dtype_and_shape(self, dtype, shape): """ Invent a suitable default value for a given dtype and shape. """ from numpy import zeros if dtype is None: # Compatibility with the default of Traits 2.0 dt = int else: dt = dtype if shape is None: value = zeros((0,), dt) else: size = [] for item in shape: if item is None: item = 1 elif type(item) in SequenceTypes: # Given a (minimum-allowed-length, maximum-allowed_length) # pair for a particular axis, use the minimum. item = item[0] size.append(item) value = zeros(size, dt) return value class Array(AbstractArray): """ A trait type whose value must be a NumPy array. An Array trait allows only upcasting of assigned values that are already numpy arrays. It automatically casts tuples and lists of the right shape to the specified *dtype* (just like numpy's **array** does). The default value is either the *value* argument or ``zeros(min(shape))``, where ``min(shape)`` refers to the minimum shape allowed by the array. If *shape* is not specified, the minimum shape is (0,). Parameters ---------- dtype : a numpy dtype (e.g., int32) The type of elements in the array; if omitted, no type-checking is performed on assigned values. shape : a tuple Describes the required shape of any assigned value. Wildcards and ranges are allowed. The value None within the *shape* tuple means that the corresponding dimension is not checked. (For example, ``shape=(None,3)`` means that the first dimension can be any size, but the second must be 3.) A two-element tuple within the *shape* tuple means that the dimension must be in the specified range. The second element can be None to indicate that there is no upper bound. (For example, ``shape=((3,5),(2,None))`` means that the first dimension must be in the range 3 to 5 (inclusive), and the second dimension must be at least 2.) value : numpy array A default value for the array. casting : str Casting rule for the array's dtype. If ``dtype`` is set, a value can only be assigned if it passes the casting rule. Values can be: - "no": No casting is allowed - "equiv": Only byte-order changes are allowed - "safe": Only allow casting that fully preserves values (e.g. "float32" to "float64") - "same-kind": Only safe casts or casts within a kind (e.g. "float64" to "float32") are allowed - "unsafe": Any casting is allowed Default is "unsafe". """ def __init__( self, dtype=None, shape=None, value=None, typecode=None, *, casting="unsafe", **metadata ): super().__init__( dtype, shape, value, False, typecode=typecode, casting=casting, **metadata ) class CArray(AbstractArray): """ A coercing trait type whose value is a NumPy array. The trait returned by CArray() is similar to that returned by Array(), except that it allows both upcasting and downcasting of assigned values that are already numpy arrays. It automatically casts tuples and lists of the right shape to the specified *dtype* (just like numpy's **array** does). The default value is either the *value* argument or ``zeros(min(shape))``, where ``min(shape)`` refers to the minimum shape allowed by the array. If *shape* is not specified, the minimum shape is (0,). Parameters ---------- dtype : a numpy dtype (e.g., int32) The type of elements in the array. shape : a tuple Describes the required shape of any assigned value. Wildcards and ranges are allowed. The value None within the *shape* tuple means that the corresponding dimension is not checked. (For example, ``shape=(None,3)`` means that the first dimension can be any size, but the second must be 3.) A two-element tuple within the *shape* tuple means that the dimension must be in the specified range. The second element can be None to indicate that there is no upper bound. (For example, ``shape=((3,5),(2,None))`` means that the first dimension must be in the range 3 to 5 (inclusive), and the second dimension must be at least 2.) value : numpy array A default value for the array. casting : str Casting rule for the array's dtype. If ``dtype`` is set, a value can only be assigned if it passes the casting rule. Values can be: - "no": No casting is allowed - "equiv": Only byte-order changes are allowed - "safe": Only allow casting that fully preserves values (e.g. "float32" to "float64") - "same-kind": Only safe casts or casts within a kind (e.g. "float64" to "float32") are allowed - "unsafe": Any casting is allowed Default is "unsafe". """ def __init__( self, dtype=None, shape=None, value=None, typecode=None, *, casting="unsafe", **metadata ): super().__init__( dtype, shape, value, True, typecode=typecode, casting=casting, **metadata ) class ArrayOrNone(CArray): """ A coercing trait whose value may be either a NumPy array or None. This trait is designed to avoid the comparison issues with numpy arrays that can arise from the use of constructs like Either(None, Array). The default value is None. """ def __init__(self, *args, **metadata): # Normally use object identity to detect array values changing: metadata.setdefault("comparison_mode", ComparisonMode.identity) super().__init__(*args, **metadata) def validate(self, object, name, value): if value is None: return value return super().validate(object, name, value) def get_default_value(self): dv = self.default_value if dv is None: return (DefaultValue.constant, dv) else: return ( DefaultValue.callable_and_args, ( self.copy_default_value, (self.validate(None, None, dv),), None, ), ) def _default_for_dtype_and_shape(self, dtype, shape): # For ArrayOrNone, if no default is explicitly specified, we # always default to `None`. return None traits-6.3.2/traits/trait_set_object.py000066400000000000000000000402311414270267200202410ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import copy import copyreg from itertools import chain from weakref import ref from traits.observation.i_observable import IObservable from traits.trait_base import _validate_everything from traits.trait_errors import TraitError class TraitSetEvent(object): """ An object reporting in-place changes to a traits sets. Parameters ---------- removed : set, optional Old values that were removed from the set. added : set, optional New values added to the set. Attributes ---------- removed : set Old values that were removed from the set. added : set New values added to the set. """ def __init__(self, *, removed=None, added=None): if removed is None: removed = set() self.removed = removed if added is None: added = set() self.added = added def __repr__(self): return ( f"{self.__class__.__name__}(" f"removed={self.removed!r}, " f"added={self.added!r})" ) @IObservable.register class TraitSet(set): """ A subclass of set that validates and notifies listeners of changes. Parameters ---------- value : iterable, optional Iterable providing the items for the set. item_validator : callable, optional Called to validate and/or transform items added to the set. The callable should accept a single item and return the transformed item, raising TraitError for invalid items. If not given, no item validation is performed. notifiers : list of callable, optional A list of callables with the signature:: notifier(trait_set, removed, added) Where 'added' is a set containing new values that have been added. And 'removed' is a set containing old values that have been removed. If this argument is not given, the list of notifiers is initially empty. Attributes ---------- item_validator : callable Called to validate and/or transform items added to the set. The callable should accept a single item and return the transformed item, raising TraitError for invalid items. notifiers : list of callable A list of callables with the signature:: notifier(trait_set, removed, added) where 'added' is a set containing new values that have been added and 'removed' is a set containing old values that have been removed. """ def __new__(cls, *args, **kwargs): self = super().__new__(cls) self.item_validator = _validate_everything self.notifiers = [] return self def __init__(self, value=(), *, item_validator=None, notifiers=None): if item_validator is not None: self.item_validator = item_validator super().__init__(self.item_validator(item) for item in value) if notifiers is not None: self.notifiers = notifiers def notify(self, removed, added): """ Call all notifiers. This simply calls all notifiers provided by the class, if any. The notifiers are expected to have the signature:: notifier(trait_set, removed, added) Any return values are ignored. Any exceptions raised are not handled. Notifiers are therefore expected not to raise any exceptions under normal use. Parameters ---------- removed : set The items that have been removed. added : set The new items that have been added to the set. """ for notifier in self.notifiers: notifier(self, removed, added) # -- set interface ------------------------------------------------------- def __iand__(self, value): """ Return self &= value. Parameters ---------- value : set or frozenset A value. Returns ------- self : TraitSet The updated set. """ old_set = self.copy() retval = super().__iand__(value) removed = old_set.difference(self) if len(removed) > 0: self.notify(removed, set()) return retval def __ior__(self, value): """ Return self |= value. Parameters ---------- value : set or frozenset A value. Returns ------- self : TraitSet The updated set. """ old_set = self.copy() # Validate each item in value, only if value is a set or frozenset. # We do not want to convert any other iterable type to a set # so that super().__ior__ raises the appropriate error message # for all other iterables. if isinstance(value, (set, frozenset)): value = {self.item_validator(item) for item in value} retval = super().__ior__(value) added = self.difference(old_set) if len(added) > 0: self.notify(set(), added) return retval def __isub__(self, value): """ Return self-=value. Parameters ---------- value : set or frozenset A value. Returns ------- self : TraitSet The updated set. """ old_set = self.copy() retval = super().__isub__(value) removed = old_set.difference(self) if len(removed) > 0: self.notify(removed, set()) return retval def __ixor__(self, value): """ Return self ^= value. Parameters ---------- value : set or frozenset A value. Returns ------- self : TraitSet The updated set. """ removed = set() added = set() # Validate each item in value, only if value is a set or frozenset. # We do not want to convert any other iterable type to a set # so that super().__ixor__ raises the appropriate error message # for all other iterables. if isinstance(value, (set, frozenset)): values = set(value) removed = self.intersection(values) raw_added = values.difference(removed) validated_added = {self.item_validator(item) for item in raw_added} added = validated_added.difference(self) value = added | removed retval = super().__ixor__(value) if removed or added: self.notify(removed, added) return retval def add(self, value): """ Add an element to a set. This has no effect if the element is already present. Parameters ---------- value : any The value to add to the set. """ value = self.item_validator(value) value_in_self = value in self super().add(value) if not value_in_self: self.notify(set(), {value}) def clear(self): """ Remove all elements from this set. """ removed = set(self) super().clear() if removed: self.notify(removed, set()) def discard(self, value): """ Remove an element from the set if it is a member. If the element is not a member, do nothing. Parameters ---------- value : any An item in the set """ value_in_self = value in self super().discard(value) if value_in_self: self.notify({value}, set()) def difference_update(self, *args): """ Remove all elements of another set from this set. Parameters ---------- args : iterables The other iterables. """ old_set = self.copy() super().difference_update(*args) removed = old_set.difference(self) if len(removed) > 0: self.notify(removed, set()) def intersection_update(self, *args): """ Update the set with the intersection of itself and another set. Parameters ---------- args : iterables The other iterables. """ old_set = self.copy() super().intersection_update(*args) removed = old_set.difference(self) if len(removed) > 0: self.notify(removed, set()) def pop(self): """ Remove and return an arbitrary set element. Raises KeyError if the set is empty. Returns ------- item : any An element from the set. Raises ------ KeyError If the set is empty. """ removed = super().pop() self.notify({removed}, set()) return removed def remove(self, value): """ Remove an element that is a member of the set. If the element is not a member, raise a KeyError. Parameters ---------- value : any An element in the set Raises ------ KeyError If the value is not found in the set. """ super().remove(value) self.notify({value}, set()) def symmetric_difference_update(self, value): """ Update the set with the symmetric difference of itself and another. Parameters ---------- value : iterable """ values = set(value) removed = self.intersection(values) raw_result = values.difference(removed) validated_result = {self.item_validator(item) for item in raw_result} added = validated_result.difference(self) super().symmetric_difference_update(removed | added) if removed or added: self.notify(removed, added) def update(self, *args): """ Update the set with the union of itself and others. Parameters ---------- args : iterables The other iterables. """ validated_values = {self.item_validator(item) for item in chain.from_iterable(args)} added = validated_values.difference(self) super().update(added) if len(added) > 0: self.notify(set(), added) # -- pickle and copy support ---------------------------------------------- def __deepcopy__(self, memo): """ Perform a deepcopy operation. Notifiers are transient and should not be copied. """ # notifiers are transient and should not be copied result = TraitSet( [copy.deepcopy(x, memo) for x in self], item_validator=copy.deepcopy(self.validator, memo), notifiers=[], ) return result def __getstate__(self): """ Get the state of the object for serialization. Notifiers are transient and should not be serialized. """ result = self.__dict__.copy() # notifiers are transient and should not be serialized del result["notifiers"] return result def __setstate__(self, state): """ Restore the state of the object after serialization. Notifiers are transient and are restored to the empty list. """ state['notifiers'] = [] self.__dict__.update(state) # -- Implement IObservable ------------------------------------------------ def _notifiers(self, force_create): """ Return a list of callables where each callable is a notifier. The list is expected to be mutated for contributing or removing notifiers from the object. Parameters ---------- force_create: boolean Not used here. """ return self.notifiers class TraitSetObject(TraitSet): """ A specialization of TraitSet with a default validator and notifier for compatibility with Traits versions before 6.0. Parameters ---------- trait : CTrait The trait that the set has been assigned to. object : HasTraits The object the set belongs to. name : str The name of the trait on the object. value : iterable The initial value of the set. Attributes ---------- trait : CTrait The trait that the set has been assigned to. object : HasTraits The object the set belongs to. name : str The name of the trait on the object. value : iterable The initial value of the set. """ def __init__(self, trait, object, name, value): self.trait = trait self.object = ref(object) self.name = name self.name_items = None if trait.has_items: self.name_items = name + "_items" super().__init__(value, item_validator=self._validator, notifiers=[self.notifier]) def _validator(self, value): """ Validates the value by calling the inner trait's validate method. Parameters ---------- value : any The value to be validated. Returns ------- value : any The validated value. Raises ------ TraitError On validation failure for the inner trait. """ object_ref = getattr(self, 'object', None) trait = getattr(self, 'trait', None) if object_ref is None or trait is None: return value object = object_ref() # validate the new value(s) validate = trait.item_trait.handler.validate if validate is None: return value try: return validate(object, self.name, value) except TraitError as excp: excp.set_prefix("Each element of the") raise excp def notifier(self, trait_set, removed, added): """ Converts and consolidates the parameters to a TraitSetEvent and then fires the event. Parameters ---------- trait_set : set The complete set removed : set Set of values that were removed. added : set Set of values that were added. """ if self.name_items is None: return object = self.object() if object is None: return if getattr(object, self.name) is not self: # Workaround having this set inside another container which # also uses the name_items trait for notification. # Similar to enthought/traits#25 return event = TraitSetEvent(removed=removed, added=added) items_event = self.trait.items_event() object.trait_items_event(self.name_items, event, items_event) # -- pickle and copy support ---------------------------------------------- def __deepcopy__(self, memo): """ Perform a deepcopy operation. Notifiers are transient and should not be copied. """ result = TraitSetObject( self.trait, lambda: None, self.name, {copy.deepcopy(x, memo) for x in self}, ) return result def __getstate__(self): """ Get the state of the object for serialization. Notifiers are transient and should not be serialized. """ result = super().__getstate__() del result["object"] del result["trait"] return result def __setstate__(self, state): """ Restore the state of the object after serialization. Notifiers are transient and are restored to the empty list. """ state.setdefault("name", "") state["notifiers"] = [self.notifier] state["object"] = lambda: None state["trait"] = None self.__dict__.update(state) def __reduce_ex__(self, protocol=None): """ Overridden to make sure we call our custom __getstate__. """ return ( copyreg._reconstructor, (type(self), set, list(self)), self.__getstate__(), ) traits-6.3.2/traits/trait_type.py000066400000000000000000000420311414270267200171010ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Defines the TraitType class. The ``TraitType`` class a trait handler that is the base class for modern traits, and provides a richer API than the old-style traits derived from ``TraitHandler``. """ import warnings from .base_trait_handler import BaseTraitHandler from .constants import ComparisonMode, DefaultValue, TraitKind from .trait_base import Missing, Self, TraitsCache, Undefined, class_of from .trait_dict_object import TraitDictObject from .trait_errors import TraitError from .trait_list_object import TraitListObject from .trait_set_object import TraitSetObject #: Mapping from trait metadata 'type' to CTrait 'type': trait_types = {"python": 1, "event": 2} def _infer_default_value_type(default_value): """ Figure out the default value type given a default value. """ if default_value is Missing: return DefaultValue.missing elif default_value is Self: return DefaultValue.object elif isinstance(default_value, TraitListObject): return DefaultValue.trait_list_object elif isinstance(default_value, TraitDictObject): return DefaultValue.trait_dict_object elif isinstance(default_value, TraitSetObject): return DefaultValue.trait_set_object elif isinstance(default_value, list): return DefaultValue.list_copy elif isinstance(default_value, dict): return DefaultValue.dict_copy else: return DefaultValue.constant def _write_only(object, name): """ Raise a trait error for a write-only trait. """ raise TraitError( "The '%s' trait of %s instance is 'write only'." % (name, class_of(object)) ) def _read_only(object, name, value): """ Raise a trait error for a read-only trait. """ raise TraitError( "The '%s' trait of %s instance is 'read only'." % (name, class_of(object)) ) class _NoDefaultSpecifiedType(object): """ An instance of this class is used to provide the singleton object ``NoDefaultSpecified`` for use in the TraitType constructor. """ #: Singleton object that can be passed for the ``default_value`` argument #: in the :class:`TraitType` constructor, to indicate that no default value #: was specified. NoDefaultSpecified = _NoDefaultSpecifiedType() class TraitType(BaseTraitHandler): """ Base class for new trait types. This class enables you to define new traits using a class-based approach, instead of by calling the Trait() factory function with an instance of a TraitHandler derived object. When subclassing this class, you can implement one or more of the method signatures below. Note that these methods are defined only as comments, because the absence of method definitions in the subclass definition implicitly provides information about how the trait should operate. The optional methods are as follows: ``get(self, object, name)`` This is the getter method of a trait that behaves like a property. If neither this method nor the ``set()`` method is defined, the value of the trait is handled like a normal object attribute. If this method is not defined, but the ``set()`` method is defined, the trait behaves like a write-only property. This method should return the value of the ``name`` property for the ``object`` object. Parameters object : any The object that the property applies to. name : str The name of the property on ``object``. ``set(self, object, name, value)`` This is the setter method of a trait that behaves like a property. If neither this method nor the ``get()`` method is implemented, the trait behaves like a normal trait attribute. If this method is not defined, but the ``get()`` method is defined, the trait behaves like a read-only property. This method does not need to return a value, but it should raise a ``TraitError`` exception if the specified ``value`` is not valid and cannot be coerced or adapted to a valid value. Parameters object : any The object that the property applies to. name : str The name of the property on ``object``. value : any The value being assigned as the value of the property. ``validate(self, object, name, value)`` This method validates, coerces, or adapts the specified ``value`` as the value of the ``name`` trait of the ``object`` object. This method is called when a value is assigned to an object trait that is based on this subclass of ``TraitType`` and the class does not contain a definition for either the get() or set() methods. This method must return the original ``value`` or any suitably coerced or adapted value that is a legal value for the trait. If ``value`` is not a legal value for the trait, and cannot be coerced or adapted to a legal value, the method should either raise a ``TraitError`` or call the ``error`` method to raise the ``TraitError`` on its behalf. ``is_valid_for(self, value)`` As an alternative to implementing the ``validate`` method, you can instead implement the ``is_valid_for`` method, which receives only the ``value`` being assigned. It should return ``True`` if the value is valid, and ``False`` otherwise. ``value_for ( self, value )`` As another alternative to implementing the ``validate`` method, you can instead implement the ``value_for`` method, which receives only the ``value`` being assigned. It should return the validated form of ``value`` if it is valid, or raise a ``TraitError`` if the value is not valid. ``post_setattr(self, object, name, value)`` This method allows the trait to do additional processing after ``value`` has been successfully assigned to the ``name`` trait of the ``object`` object. For most traits there is no additional processing that needs to be done, and this method need not be defined. It is normally used for creating "shadow" (i.e., "mapped" traits), but other uses may arise as well. This method does not need to return a value, and should normally not raise any exceptions. """ #: The default value for the trait type. default_value = Undefined #: The metadata for the trait. metadata = {} def __init__(self, default_value=NoDefaultSpecified, **metadata): """ TraitType initializer This is the only method normally called directly by client code. It defines the trait. The default implementation accepts an optional, unvalidated default value, and caller-supplied trait metadata. Override this method whenever a different method signature or a validated default value is needed. """ if default_value is not NoDefaultSpecified: self.default_value = default_value if len(metadata) > 0: if len(self.metadata) > 0: self._metadata = self.metadata.copy() self._metadata.update(metadata) else: self._metadata = metadata # By default, private traits are not visible. if ( self._metadata.get("private") and self._metadata.get("visible") is None ): self._metadata["visible"] = False else: self._metadata = self.metadata.copy() self.init() def init(self): """ Allows the trait to perform any additional initialization needed. """ pass def get_default_value(self): r""" Get information about the default value. The default implementation analyzes the value of the trait's ``default_value`` attribute and determines an appropriate ``default_value_type`` for the ``default_value``. If you need to override this method to provide a different result tuple, the following values are valid values for ``default_value_type``: - 0, 1: The ``default_value`` item of the tuple is the default value. - 2: The object containing the trait is the default value. - 3: A new copy of the list specified by ``default_value`` is the default value. - 4: A new copy of the dictionary specified by ``default_value`` is the default value. - 5: A new instance of TraitListObject constructed using the ``default_value`` list is the default value. - 6: A new instance of TraitDictObject constructed using the ``default_value`` dictionary is the default value. - 7: ``default_value`` is a tuple of the form: ``(callable, args, kw)``, where ``callable`` is a callable, ``args`` is a tuple, and ``kw`` is either a dictionary or None. The default value is the result obtained by invoking ``callable(\*args, \*\*kw)``. - 8: ``default_value`` is a callable. The default value is the result obtained by invoking ``default_value(object)``, where ``object`` is the object containing the trait. If the trait has a ``validate()`` method, the ``validate()`` method is also called to validate the result. - 9: A new instance of ``TraitSetObject`` constructed using the ``default_value`` set is the default value. Returns ------- default_value_type, default_value : int, any The default value information, consisting of an integer, giving the type of default value, and the corresponding default value as described above. """ dv = self.default_value dvt = self.default_value_type if dvt < 0: dvt = _infer_default_value_type(dv) self.default_value_type = dvt return (dvt, dv) def clone(self, default_value=NoDefaultSpecified, **metadata): """ Copy, optionally modifying default value and metadata. Clones the contents of this object into a new instance of the same class, and then modifies the cloned copy using the specified ``default_value`` and ``metadata``. Returns the cloned object as the result. Note that subclasses can change the signature of this method if needed, but should always call the 'super' method if possible. Parameters ---------- default_value : any The new default value for the trait. **metadata : dict A dictionary of metadata names and corresponding values as arbitrary keyword arguments. Returns ------- clone : TraitType Clone of self. """ if "parent" not in metadata: metadata["parent"] = self new = self.__class__.__new__(self.__class__) new_dict = new.__dict__ new_dict.update(self.__dict__) if "editor" in new_dict: del new_dict["editor"] if "_metadata" in new_dict: new._metadata = new._metadata.copy() else: new._metadata = {} new._metadata.update(metadata) if default_value is not NoDefaultSpecified: new.default_value = default_value if self.validate is not None: try: new.default_value = self.validate( None, None, default_value ) except Exception: pass return new def get_value(self, object, name, trait=None): """ Returns the current value of a property-based trait. """ cname = TraitsCache + name value = object.__dict__.get(cname, Undefined) if value is Undefined: if trait is None: trait = object.trait(name) object.__dict__[cname] = value = trait.default_value_for( object, name ) return value def set_value(self, object, name, value): """ Sets the cached value of a property-based trait and fires the appropriate trait change event. """ cname = TraitsCache + name old = object.__dict__.get(cname, Undefined) if value != old: object.__dict__[cname] = value object.trait_property_changed(name, old, value) # -- Private Methods ------------------------------------------------------ def __call__(self, *args, **kw): """ Allows a derivative trait to be defined from this one. """ return self.clone(*args, **kw).as_ctrait() def _is_valid_for(self, object, name, value): """ Handles a simplified validator that only returns whether or not the original value is valid. """ if self.is_valid_for(value): return value self.error(object, name, value) def _value_for(self, object, name, value): """ Handles a simplified validator that only receives the value argument. """ try: return self.value_for(value) except TraitError: self.error(object, name, value) def as_ctrait(self): """ Returns a CTrait corresponding to the trait defined by this class. """ from .traits import CTrait metadata = getattr(self, "_metadata", {}) getter = getattr(self, "get", None) setter = getattr(self, "set", None) if (getter is not None) or (setter is not None): if getter is None: getter = _write_only metadata.setdefault("transient", True) elif setter is None: setter = _read_only metadata.setdefault("transient", True) trait = CTrait(TraitKind.property) validate = getattr(self, "validate", None) trait.property_fields = (getter, setter, validate) metadata.setdefault("type", "property") else: type = getattr(self, "ctrait_type", None) if type is None: type = trait_types.get(metadata.get("type"), 0) trait = CTrait(type) validate = getattr(self, "fast_validate", None) if validate is None: validate = getattr(self, "validate", None) if validate is None: validate = getattr(self, "is_valid_for", None) if validate is not None: validate = self._is_valid_for else: validate = getattr(self, "value_for", None) if validate is not None: validate = self._value_for if validate is not None: trait.set_validate(validate) post_setattr = getattr(self, "post_setattr", None) if post_setattr is not None: trait.post_setattr = post_setattr trait.is_mapped = self.is_mapped # Note: The use of 'rich_compare' metadata is deprecated; use # 'comparison_mode' metadata instead. Ref: enthought/traits#602. rich_compare = metadata.get("rich_compare") if rich_compare is not None: warnings.warn( "The 'rich_compare' metadata has been deprecated. Please " "use the 'comparison_mode' metadata instead. In a future " "release, rich_compare will have no effect.", DeprecationWarning, stacklevel=6, ) if rich_compare: trait.comparison_mode = ComparisonMode.equality else: trait.comparison_mode = ComparisonMode.identity comparison_mode = metadata.pop("comparison_mode", None) if comparison_mode is not None: trait.comparison_mode = comparison_mode metadata.setdefault("type", "trait") trait.set_default_value(*self.get_default_value()) trait.handler = self trait.__dict__ = metadata.copy() return trait @classmethod def instantiate_and_get_ctrait(cls): """ Instantiate the class an return a CTrait instance This is primarily to allow traits to be defined within classes without having to explicitly call them. """ return cls().as_ctrait() def __getattr__(self, name): if (name[:2] == "__") and (name[-2:] == "__"): raise AttributeError( "'%s' object has no attribute '%s'" % (self.__class__.__name__, name) ) return getattr(self, "_metadata", {}).get(name, None) traits-6.3.2/traits/trait_types.py000066400000000000000000004676221414270267200173050ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Core Trait definitions. """ import collections.abc import datetime from importlib import import_module import operator from os import fspath from os.path import isfile, isdir import re import sys from types import FunctionType, MethodType, ModuleType import uuid import warnings from .constants import DefaultValue, TraitKind, ValidateTrait from .trait_base import ( strx, get_module_name, HandleWeakRef, class_of, RangeTypes, safe_contains, SequenceTypes, TypeTypes, Undefined, TraitsCache, xgetattr, ) from .trait_converters import trait_from, trait_cast from .trait_dict_object import TraitDictEvent, TraitDictObject from .trait_errors import TraitError from .trait_list_object import TraitListEvent, TraitListObject from .trait_set_object import TraitSetEvent, TraitSetObject from .trait_type import ( NoDefaultSpecified, TraitType, ) from .traits import ( Trait, _TraitMaker, ) from .util.deprecated import deprecated from .util.import_symbol import import_symbol # TraitsUI integration imports from .editor_factories import ( code_editor, html_editor, password_editor, shell_editor, date_editor, datetime_editor, time_editor, list_editor, ) # Constants SetTypes = SequenceTypes + (set,) # Numeric type fast validator definitions # A few words about the next block of code: # The coerce validator is a generic validator for possibly coercible types # (see validate_trait_coerce_type in ctraits.c). # # The tuples below are of the form # (ValidateTrait.coerce, type1, [type2, type3, ...], # [None, ctype1, [ctype2, ...]]) # # 'type1' corresponds to the main type for the trait # 'None' acts as the separator between 'types' and 'ctypes' (coercible types) # # The validation passes if: # 1) The trait value type is (a subtype of) one of 'type1', 'type2', ... # in which case the value is returned as-is # or # 2) The trait value type is (a subtype of) one of 'ctype1', 'ctype2', ... # in which case the value is returned coerced to trait type using # 'return type1(value') try: # The numpy enhanced definitions: from numpy import integer, floating, complexfloating, bool_ int_fast_validate = (ValidateTrait.coerce, int, integer) float_fast_validate = ( ValidateTrait.coerce, float, floating, None, int, integer, ) complex_fast_validate = ( ValidateTrait.coerce, complex, complexfloating, None, float, floating, int, integer, ) bool_fast_validate = (ValidateTrait.coerce, bool, None, bool_) # Tuple or single type suitable for an isinstance check. _BOOL_TYPES = (bool, bool_) except ImportError: # The standard python definitions (without numpy): int_fast_validate = (ValidateTrait.coerce, int) float_fast_validate = (ValidateTrait.coerce, float, None, int) complex_fast_validate = (ValidateTrait.coerce, complex, None, float, int) bool_fast_validate = (ValidateTrait.coerce, bool) # Tuple or single type suitable for an isinstance check. _BOOL_TYPES = bool def default_text_editor(trait, type=None): """ Return a default text editor for a trait. Parameters ---------- trait : TraitType The trait we are constructing the editor for. type : callable, optional A callable (usually a Python type) to use to evaluate the text content of the editor and return the correct type of value for the trait. Returns ------- TextEditor A TraitsUI TextEditor instance for the trait. """ auto_set = trait.auto_set if auto_set is None: auto_set = True enter_set = trait.enter_set or False from traitsui.api import TextEditor if type is None: return TextEditor(auto_set=auto_set, enter_set=enter_set) return TextEditor(auto_set=auto_set, enter_set=enter_set, evaluate=type) # Generic validators def _validate_int(value): """ Convert an integer-like Python object to an int, or raise TypeError. """ if type(value) is int: return value else: return int(operator.index(value)) def _validate_float(value): """ Convert an arbitrary Python object to a float, or raise TypeError. """ if type(value) is float: # fast path for common case return value try: nb_float = type(value).__float__ except AttributeError: raise TypeError( "Object of type {!r} not convertible to float".format(type(value)) ) return nb_float(value) # Trait Types class Any(TraitType): """ A trait type whose value can be anything. Parameters ---------- default_value : object, optional The default value for the trait. If this is an instance of either :class:`list` or :class:`dict` then a copy of the default value is made for each instance. Otherwise, the default is shared between all instances. .. deprecated:: 6.3.0 In a future version of Traits, a ``list`` or ``dict`` default value will no longer be copied. If you need a per-instance default, use a ``_trait_name_default`` method to supply that default. factory : callable, optional A callable, that when called with *args* and *kw*, returns the default value for the trait. args : tuple, optional Positional arguments (if any) for generating the default value. kw : dictionary, optional Keyword arguments (if any) for generating the default value. **metadata Metadata for the trait. """ #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait: default_value = None #: A description of the type of value this trait accepts: info_text = "any value" def __init__( self, default_value=NoDefaultSpecified, *, factory=None, args=(), kw={}, **metadata ): if isinstance(default_value, list): warnings.warn( ( "In the future, a default value of type 'list' in an Any " "trait will be shared between all instances. To keep the " "current semantics, replace `Any([])` with " "`Any(factory=list)` or `Any([1, 2, 3])` (for example) " "with `Any(factory=list, args=([1, 2, 3],))`." ), DeprecationWarning, stacklevel=2, ) self.default_value_type = DefaultValue.list_copy elif isinstance(default_value, dict): warnings.warn( ( "In the future, a default value of type 'dict' in an Any " "trait will be shared between all instances. To keep the " "current semantics, replace `Any({})` with " "`Any(factory=dict)` or `Any({1: 2})` (for example) " "with `Any(factory=dict, args=({1: 2},))`." ), DeprecationWarning, stacklevel=2, ) self.default_value_type = DefaultValue.dict_copy # Sanity check the parameters if default_value is not NoDefaultSpecified and factory is not None: raise TypeError( "ambiguous defaults: both a default value and a default " "value factory are specified" ) if factory is not None: self.default_value_type = DefaultValue.callable_and_args default_value = (factory, args, kw) super().__init__(default_value, **metadata) class BaseInt(TraitType): """ A trait type whose value must be an int. Values which support the Python index protocol will validate and will be converted to the corresponding int value. """ #: The function to use for evaluating strings to this type: evaluate = int #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait: default_value = 0 #: A description of the type of value this trait accepts: info_text = "an integer" def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. """ try: return _validate_int(value) except TypeError: self.error(object, name, value) def create_editor(self): """ Returns the default traits UI editor for this type of trait. """ return default_text_editor(self, int) class Int(BaseInt): """ A fast-validating trait type whose value must be an integer. Values which support the Python index protocol will validate and will be converted to the corresponding int value. """ #: The C-level fast validator to use: fast_validate = (ValidateTrait.int,) class BaseFloat(TraitType): """ A trait type whose value must be a float. Values which support automatic conversion to floats via the Python __float__ method will validate and will be converted to the corresponding float value. """ #: The function to use for evaluating strings to this type: evaluate = float #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait: default_value = 0.0 #: A description of the type of value this trait accepts: info_text = "a float" def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ try: return _validate_float(value) except TypeError: self.error(object, name, value) def create_editor(self): """ Returns the default traits UI editor for this type of trait. """ return default_text_editor(self, float) class Float(BaseFloat): """ A fast-validating trait type whose value must be a float. Values which support automatic conversion to floats via the Python __float__ method will validate and will be converted to the corresponding float value. """ #: The C-level fast validator to use: fast_validate = (ValidateTrait.float,) class BaseComplex(TraitType): """ A trait type whose value must be a complex number. Integers and floating-point numbers will be converted to the corresponding complex value. """ #: The function to use for evaluating strings to this type: evaluate = complex #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait: default_value = 0.0 + 0.0j #: A description of the type of value this trait accepts: info_text = "a complex number" def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ if isinstance(value, complex): return value if isinstance(value, (float, int)): return complex(value) self.error(object, name, value) def create_editor(self): """ Returns the default traits UI editor for this type of trait. """ return default_text_editor(self, complex) class Complex(BaseComplex): """ A fast-validating trait type whose value must be a complex number. Integers and floating-point numbers will be converted to the corresponding complex value. """ #: The C-level fast validator to use: fast_validate = complex_fast_validate class BaseStr(TraitType): """ A trait type whose value must be a string. """ #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait: default_value = "" #: A description of the type of value this trait accepts: info_text = "a string" def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ if isinstance(value, str): return value self.error(object, name, value) def create_editor(self): """ Returns the default traits UI editor for this type of trait. """ from .editor_factories import multi_line_text_editor auto_set = self.auto_set if auto_set is None: auto_set = True enter_set = self.enter_set or False return multi_line_text_editor(auto_set, enter_set) class Str(BaseStr): """ A fast-validating trait type whose value must be a string. """ #: The C-level fast validator to use: fast_validate = (ValidateTrait.coerce, str) class Title(Str): """ A Str trait which by default uses a TraitsUI TitleEditor. """ def create_editor(self): """ Returns the default traits UI editor to use for a trait. """ from traitsui.api import TitleEditor if hasattr(self, "allow_selection"): return TitleEditor(allow_selection=self.allow_selection) else: return TitleEditor() class BaseBytes(TraitType): """ A trait type whose value must be a bytestring. """ #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait: default_value = b"" #: A description of the type of value this trait accepts: info_text = "a bytes string" #: An encoding to use with TraitsUI editors encoding = None def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ if isinstance(value, bytes): return value self.error(object, name, value) def create_editor(self): """ Returns the default traits UI editor for this type of trait. """ from .traits import bytes_editor auto_set = self.auto_set if auto_set is None: auto_set = True enter_set = self.enter_set or False return bytes_editor(auto_set, enter_set, self.encoding) class Bytes(BaseBytes): """ A fast-validating trait type whose value must be a bytestring. """ #: The C-level fast validator to use: fast_validate = (ValidateTrait.coerce, bytes) class BaseBool(TraitType): """ A trait type whose value must be a bool. """ #: The function to use for evaluating strings to this type: evaluate = bool #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait: default_value = False #: A description of the type of value this trait accepts: info_text = "a boolean" def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ if isinstance(value, _BOOL_TYPES): return bool(value) self.error(object, name, value) def create_editor(self): """ Returns the default traits UI editor for this type of trait. """ from traitsui.api import BooleanEditor return BooleanEditor() class Bool(BaseBool): """ A fast-validating trait type whose value must be a bool. """ #: The C-level fast validator to use: fast_validate = bool_fast_validate class BaseCInt(BaseInt): """ A coercing trait type whose value is an integer. """ #: The function to use for evaluating strings to this type: evaluate = int def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ try: return int(value) except (ValueError, TypeError): self.error(object, name, value) class CInt(BaseCInt): """ A fast-validating, coercing trait type whose value is an int. """ #: The C-level fast validator to use: fast_validate = (ValidateTrait.cast, int) class BaseCFloat(BaseFloat): """ A coercing trait type whose value is a float. """ #: The function to use for evaluating strings to this type: evaluate = float def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ try: return float(value) except (ValueError, TypeError): self.error(object, name, value) class CFloat(BaseCFloat): """ A fast-validating, coercing trait type whose value is a float. """ #: The C-level fast validator to use: fast_validate = (ValidateTrait.cast, float) class BaseCComplex(BaseComplex): """ A coercing trait type whose value is a complex number. """ #: The function to use for evaluating strings to this type: evaluate = complex def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ try: return complex(value) except (ValueError, TypeError): self.error(object, name, value) class CComplex(BaseCComplex): """ A fast-validating, coercing trait type whose value is a complex number. """ #: The C-level fast validator to use: fast_validate = (ValidateTrait.cast, complex) class BaseCStr(BaseStr): """ A coercing trait type whose value is a string. """ def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ try: return str(value) except: self.error(object, name, value) class CStr(BaseCStr): """ A fast-validating, coercing trait type whose value is a string. """ #: The C-level fast validator to use: fast_validate = (ValidateTrait.cast, str) class BaseCBytes(BaseBytes): """ A coercing trait type whose value is a bytestring. """ def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ try: return bytes(value) except: self.error(object, name, value) class CBytes(BaseCBytes): """ A fast-validating, coercing trait type whose value is a bytestring. """ #: The C-level fast validator to use: fast_validate = (ValidateTrait.cast, bytes) class BaseCBool(BaseBool): """ A coercing trait type whose value is a bool. """ #: The function to use for evaluating strings to this type: evaluate = bool def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ try: return bool(value) except: self.error(object, name, value) class CBool(BaseCBool): """ A fast-validating, coercing trait type whose value is a bool. """ #: The C-level fast validator to use: fast_validate = (ValidateTrait.cast, bool) class String(TraitType): """ A trait type whose value must be a string with optional constraints. The value is a string whose length is in a specified range, and which optionally matches a specified regular expression. Parameters ---------- value : str The default value for the string. minlen : integer The minimum length allowed for the string. maxlen : integer The maximum length allowed for the string. regex : str A Python regular expression that the string must match. **metadata The trait metadata for the trait. Attributes ---------- minlen : integer The minimum length allowed for the string. maxlen : integer The maximum length allowed for the string. regex : str A Python regular expression that the string must match. """ #: The default value type to use. default_value_type = DefaultValue.constant def __init__( self, value="", minlen=0, maxlen=sys.maxsize, regex="", **metadata ): super().__init__(value, **metadata) self.minlen = max(0, minlen) self.maxlen = max(self.minlen, maxlen) self.regex = regex self._init() def _init(self): """ Completes initialization of the trait at construction or unpickling time. """ self._validate = "validate_all" if self.regex != "": self.match = re.compile(self.regex).match if (self.minlen == 0) and (self.maxlen == sys.maxsize): self._validate = "validate_regex" elif (self.minlen == 0) and (self.maxlen == sys.maxsize): self._validate = "validate_str" else: self._validate = "validate_len" def validate(self, object, name, value): """ Validates that the value is a valid string. """ return getattr(self, self._validate)(object, name, value) def validate_all(self, object, name, value): """ Validates that the value is a valid string in the specified length range which matches the specified regular expression. """ try: value = strx(value) if (self.minlen <= len(value) <= self.maxlen) and ( self.match(value) is not None ): return value except: pass self.error(object, name, value) def validate_str(self, object, name, value): """ Validates that the value is a valid string. """ try: return strx(value) except: pass self.error(object, name, value) def validate_len(self, object, name, value): """ Validates that the value is a valid string in the specified length range. """ try: value = strx(value) if self.minlen <= len(value) <= self.maxlen: return value except: pass self.error(object, name, value) def validate_regex(self, object, name, value): """ Validates that the value is a valid string which matches the specified regular expression. """ try: value = strx(value) if self.match(value) is not None: return value except: pass self.error(object, name, value) def info(self): """ Returns a description of the trait. """ msg = "" if (self.minlen != 0) and (self.maxlen != sys.maxsize): msg = " between %d and %d characters long" % ( self.minlen, self.maxlen, ) elif self.maxlen != sys.maxsize: msg = " <= %d characters long" % self.maxlen elif self.minlen != 0: msg = " >= %d characters long" % self.minlen if self.regex != "": if msg != "": msg += " and" msg += " matching the pattern '%s'" % self.regex return "a string" + msg def create_editor(self): """ Returns the default traits UI editor for this type of trait. """ return default_text_editor(self) def __getstate__(self): """ Returns the current state of the trait. """ result = self.__dict__.copy() for name in ["validate", "match"]: if name in result: del result[name] return result def __setstate__(self, state): """ Sets the current state of the trait. """ self.__dict__.update(state) self._init() class Regex(String): """ A trait type whose value must match a regular expression. Parameters ---------- value : str The default value of the trait. regex : str The regular expression that the trait value must match. **metadata Trait metadata. """ def __init__(self, value="", regex=".*", **metadata): super().__init__(value=value, regex=regex, **metadata) class Code(String): """ A trait type whose value holds a string of source code. Validation does not perform any sort of syntax checking. The default TraitsUI editor is a CodeEditor. """ #: The standard metadata for the trait: metadata = {"editor": code_editor} class HTML(String): """ A trait type whose value holds an HTML string. The validation of the value does not enforce HTML syntax. The default TraitsUI editor is an HTMLEditor. """ #: The standard metadata for the trait: metadata = {"editor": html_editor} class Password(String): """ A trait type whose value holds a password string. The default TraitsUI editor is an PasswordEditor, which obscures text entered by the user. """ #: The standard metadata for the trait: metadata = {"editor": password_editor} class BaseCallable(TraitType): """ A trait type whose value must be a Python callable. """ #: The standard metadata for the trait: metadata = {"copy": "ref"} #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait: default_value = None #: A description of the type of value this trait accepts: info_text = "a callable value" def validate(self, object, name, value): """ Validates that the value is a Python callable. """ if (value is None) or callable(value): return value self.error(object, name, value) class Callable(BaseCallable): """ A fast-validating trait type whose value must be a Python callable. """ def __init__(self, value=None, allow_none=True, **metadata): self.fast_validate = (ValidateTrait.callable, allow_none) default_value = metadata.pop("default_value", value) super().__init__(default_value, **metadata) class BaseType(TraitType): """ A trait type whose value must be an instance of a Python type. This is an abstract class and should not be directly instantiated. """ #: The default value type to use. default_value_type = DefaultValue.constant def validate(self, object, name, value): """ Validates that the value is a Python callable. """ if isinstance(value, self.fast_validate[1:]): return value self.error(object, name, value) class This(BaseType): """ A trait type whose value must be an instance of the defining class. """ #: The default value type to use. default_value_type = DefaultValue.constant #: The C-level fast validator to use: fast_validate = (ValidateTrait.self_type,) #: A description of the type of value this trait accepts: info_text = "an instance of the same type as the receiver" def __init__(self, value=None, allow_none=True, **metadata): super().__init__(value, **metadata) if allow_none: self.fast_validate = (ValidateTrait.self_type, None) self.validate = self.validate_none self.info = self.info_none def validate(self, object, name, value): if isinstance(value, object.__class__): return value self.error(object, name, value) def validate_none(self, object, name, value): if isinstance(value, object.__class__) or (value is None): return value self.error(object, name, value) def info(self): return "an instance of the same type as the receiver" def info_none(self): return "an instance of the same type as the receiver or None" class self(This): """ A trait type whose default value is the object containing the trait. The trait can be assigned to, but any new value must be an instance of the defining class. """ #: The default value type to use (i.e. 'self'): default_value_type = DefaultValue.object class Function(TraitType): """ A trait type whose value must be a function. .. deprecated:: 6.2.0 This trait type explicitly checks for an instance of ``types.FunctionType``. For the majority of use cases, the more general ``Callable`` trait type should be used instead. If an instance specifically of ``types.FunctionType`` really is needed, one can use ``Instance(types.FunctionType)``. """ #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait type. default_value = Undefined @deprecated("Function trait type has been deprecated. Use 'Callable' or " "'Instance(types.FunctionType)' instead") def __init__(self, default_value=NoDefaultSpecified, **metadata): super().__init__(default_value=default_value, **metadata) #: The C-level fast validator to use: fast_validate = (ValidateTrait.coerce, FunctionType) #: A description of the type of value this trait accepts: info_text = "a function" class Method(TraitType): """ A trait type whose value must be a method. .. deprecated:: 6.2.0 This trait type explicitly checks for an instance of ``types.MethodType``. For the majority of use cases, the more general ``Callable`` trait type should be used instead. If an instance specifically of ``types.MethodType`` really is needed, one can use ``Instance(types.MethodType)``. """ #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait type. default_value = Undefined @deprecated("Method trait type has been deprecated. Use 'Callable' or " "'Instance(types.MethodType)' instead") def __init__(self, default_value=NoDefaultSpecified, **metadata): super().__init__(default_value=default_value, **metadata) #: The C-level fast validator to use: fast_validate = (ValidateTrait.coerce, MethodType) #: A description of the type of value this trait accepts: info_text = "a method" class Module(TraitType): """ A trait type whose value must be a module. """ #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait type. default_value = Undefined #: The C-level fast validator to use: fast_validate = (ValidateTrait.coerce, ModuleType) #: A description of the type of value this trait accepts: info_text = "a module" class Python(TraitType): """ A trait type that behaves as a standard Python attribute. This trait type allows any value to be assigned, and raises an ValueError if an attempt is made to get the value before one has been assigned. It has no default value. This trait is most often used in conjunction with wildcard naming. See the *Traits User Manual* for details on wildcards. """ #: The standard metadata for the trait: metadata = {"type": "python"} #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait: default_value = Undefined class ReadOnly(TraitType): """ A trait type that is write-once, and then read-only. The initial value of the attribute is the special, singleton object Undefined. The trait allows any value to be assigned to the attribute if the current value is the Undefined object. Once any other value is assigned, no further assignment is allowed. Normally, the initial assignment to the attribute is performed in the class constructor, based on information passed to the constructor. If the read-only value is known in advance of run time, use Constant instead of ReadOnly to define the trait. """ # Defines the CTrait type to use for this trait: ctrait_type = TraitKind.read_only #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait: default_value = Undefined # Create a singleton instance as the trait: ReadOnly = ReadOnly() class Disallow(TraitType): """ A trait that prevents any value from being assigned or read. Any attempt to get or set the value of the trait attribute raises an exception. This trait is most often used in conjunction with wildcard naming, for example, to catch spelling mistakes in attribute names. See the *Traits User Manual* for details on wildcards. """ #: Defines the CTrait type to use for this trait: ctrait_type = TraitKind.disallow #: The default value type to use. default_value_type = DefaultValue.constant # Create a singleton instance as the trait: Disallow = Disallow() class Constant(TraitType): """ A trait type whose value is a constant. Traits of this type are very space efficient (and fast) because *value* is not stored in each instance using the trait, but only in the trait object itself. Parameters ---------- value : any The constant value for the trait. **metadata Trait metadata for the trait. """ #: The default value type to use. default_value_type = DefaultValue.constant #: Defines the CTrait type to use for this trait: ctrait_type = TraitKind.constant #: The standard metadata for the trait: metadata = {"type": "constant", "transient": True} class Delegate(TraitType): """ A trait type whose value is delegated to a trait on another object. This is a base class that shouldn't be used directly, rather use one of the subclasses DelegatesTo or PrototypesFrom, depending on desired behaviour. An object containing a delegator trait attribute must contain a second attribute that references the object containing the delegate trait attribute. The name of this second attribute is passed as the *delegate* argument. The following rules govern the application of the prefix parameter: * If *prefix* is empty or omitted, the delegation is to an attribute of the delegate object with the same name as the delegator attribute. * If *prefix* is a valid Python attribute name, then the delegation is to an attribute whose name is the value of *prefix*. * If *prefix* ends with an asterisk ('*') and is longer than one character, then the delegation is to an attribute whose name is the value of *prefix*, minus the trailing asterisk, prepended to the delegator attribute name. * If *prefix* is equal to a single asterisk, the delegation is to an attribute whose name is the value of the delegator object's __prefix__ attribute prepended to delegator attribute name. Parameters ---------- delegate : str The name of the trait that holds the HasTraits instance that the value is delegated to. prefix : str The name of the trait on the delegate that holds the delegated value. If empty, then the name of this trait will be used. modify : bool Whether modifications of this trait are applied to the delegated object. This differentiates the behaviour of DelegatesTo and PrototypedFrom. listenable : bool Whether changes to the delegated trait will fire listeners to this trait. Attributes ---------- delegate : str The name of the trait that holds the HasTraits instance that the value is delegated to. prefix : str The name of the trait on the delegate that holds the delegated value. If empty, then the name of this trait will be used. prefix_type : int An integer giving the type of prefix being used. modify : bool Whether modifications of this trait are applied to the delegated object. This differentiates the behaviour of DelegatesTo and PrototypedFrom. """ #: Defines the CTrait type to use for this trait: ctrait_type = TraitKind.delegate #: The default value type to use. default_value_type = DefaultValue.constant #: The standard metadata for the trait: metadata = {"type": "delegate", "transient": False} def __init__( self, delegate, prefix="", modify=False, listenable=True, **metadata ): """ Creates a Delegate trait. """ if prefix == "": prefix_type = 0 elif prefix[-1:] != "*": prefix_type = 1 else: prefix = prefix[:-1] if prefix != "": prefix_type = 2 else: prefix_type = 3 metadata["_delegate"] = delegate metadata["_prefix"] = prefix metadata["_listenable"] = listenable super().__init__(**metadata) self.delegate = delegate self.prefix = prefix self.prefix_type = prefix_type self.modify = modify def as_ctrait(self): """ Returns a CTrait corresponding to the trait defined by this class. """ trait = super().as_ctrait() trait.delegate( self.delegate, self.prefix, self.prefix_type, self.modify ) return trait class DelegatesTo(Delegate): """ A trait type that matches the 'delegate' design pattern. This defines a trait whose value and definition is "delegated" to another trait on a different object. An object containing a delegator trait attribute must contain a second attribute that references the object containing the delegate trait attribute. The name of this second attribute is passed as the *delegate* argument to the DelegatesTo() function. The following rules govern the application of the prefix parameter: * If *prefix* is empty or omitted, the delegation is to an attribute of the delegate object with the same name as the delegator attribute. * If *prefix* is a valid Python attribute name, then the delegation is to an attribute whose name is the value of *prefix*. * If *prefix* ends with an asterisk ('*') and is longer than one character, then the delegation is to an attribute whose name is the value of *prefix*, minus the trailing asterisk, prepended to the delegator attribute name. * If *prefix* is equal to a single asterisk, the delegation is to an attribute whose name is the value of the delegator object's __prefix__ attribute prepended to delegator attribute name. Note that any changes to the delegator attribute are actually applied to the corresponding attribute on the delegate object. The original object containing the delegator trait is not modified. Parameters ---------- delegate : str Name of the attribute on the current object which references the object that is the trait's delegate. prefix : str A prefix or substitution applied to the original attribute when looking up the delegated attribute. listenable : bool Indicates whether a listener can be attached to this attribute such that changes to the delegated attribute will trigger it. **metadata Trait metadata for the trait. """ def __init__(self, delegate, prefix="", listenable=True, **metadata): super().__init__( delegate, prefix=prefix, modify=True, listenable=listenable, **metadata ) class PrototypedFrom(Delegate): """ A trait type that matches the 'prototype' design pattern. This defines a trait whose default value and definition is "prototyped" from another trait on a different object. An object containing a prototyped trait attribute must contain a second attribute that references the object containing the prototype trait attribute. The name of this second attribute is passed as the *prototype* argument to the PrototypedFrom() function. The following rules govern the application of the prefix parameter: * If *prefix* is empty or omitted, the prototype delegation is to an attribute of the prototype object with the same name as the prototyped attribute. * If *prefix* is a valid Python attribute name, then the prototype delegation is to an attribute whose name is the value of *prefix*. * If *prefix* ends with an asterisk ('*') and is longer than one character, then the prototype delegation is to an attribute whose name is the value of *prefix*, minus the trailing asterisk, prepended to the prototyped attribute name. * If *prefix* is equal to a single asterisk, the prototype delegation is to an attribute whose name is the value of the prototype object's __prefix__ attribute prepended to the prototyped attribute name. Note that any changes to the prototyped attribute are made to the original object, not the prototype object. The prototype object is only used to define to trait type and default value. Parameters ---------- prototype : str Name of the attribute on the current object which references the object that is the trait's prototype. prefix : str A prefix or substitution applied to the original attribute when looking up the prototyped attribute. listenable : bool Indicates whether a listener can be attached to this attribute such that changes to the corresponding attribute on the prototype object will trigger it. **metadata Trait metadata for the trait. """ def __init__(self, prototype, prefix="", listenable=True, **metadata): super().__init__( prototype, prefix=prefix, modify=False, listenable=listenable, **metadata ) class Expression(TraitType): """ A trait type whose value must be a valid Python expression. The compiled form of a valid expression is stored as the mapped value of the trait. """ #: The default value type to use. default_value_type = DefaultValue.constant #: The default value for the trait: default_value = "0" #: A description of the type of value this trait accepts: info_text = "a valid Python expression" #: Indicate that this is a mapped trait: is_mapped = True def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. """ try: return compile(value, "", "eval") except: self.error(object, name, value) def post_setattr(self, object, name, value): """ Performs additional post-assignment processing. """ object.__dict__[name + "_"] = value def mapped_value(self, value): """ Returns the 'mapped' value for the specified **value**. """ return compile(value, "", "eval") def as_ctrait(self): """ Returns a CTrait corresponding to the trait defined by this class. """ # Tell the C code that 'setattr' should store the original, unadapted # value passed to it: ctrait = super().as_ctrait() ctrait.setattr_original_value = True return ctrait class PythonValue(Any): """ A trait type whose value can be of any type. The default editor is a ShellEditor. """ #: The standard metadata for the trait: metadata = {"editor": shell_editor} class BaseFile(BaseStr): """ A trait type whose value must be a file path string. This will accept both strings and os.pathlib Path objects, converting the latter to the corresponding string value. Parameters ---------- value : str The default value for the trait. filter : str A wildcard string to filter filenames in the file dialog box used by the attribute trait editor. auto_set : bool Indicates whether the file editor updates the trait value after every key stroke. entries : int A hint to the TraitsUI editor about how many values to display in the editor. exists : bool Indicates whether the trait value must be an existing file or not. Attributes ---------- filter : str A wildcard string to filter filenames in the file dialog box used by the attribute trait editor. auto_set : bool Indicates whether the file editor updates the trait value after every key stroke. entries : int A hint to the TraitsUI editor about how many values to display in the editor. exists : bool Indicates whether the trait value must be an existing file or not. """ def __init__( self, value="", filter=None, auto_set=False, entries=0, exists=False, **metadata ): self.filter = filter self.auto_set = auto_set self.entries = entries self.exists = exists super().__init__(value, **metadata) def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ try: # If value is of type os.PathLike, get the path representation # The path representation could be either a str or bytes type # If fspath returns bytes, further validation will fail. value = fspath(value) except TypeError: pass validated_value = super().validate(object, name, value) if not self.exists: return validated_value elif isfile(value): return validated_value self.error(object, name, value) def info(self): """ Return a description of the type of value this trait accepts. """ description = "a string or os.PathLike object" if self.exists: description += " referring to an existing file" return description def create_editor(self): from traitsui.editors.file_editor import FileEditor editor = FileEditor( filter=self.filter or [], auto_set=self.auto_set, entries=self.entries, dialog_style="open" if self.exists else "save", ) return editor class File(BaseFile): """ A fast-validating trait type whose value must be a file path string. This will accept both strings and os.pathlib Path objects, converting the latter to the corresponding string value. Parameters ---------- value : str The default value for the trait. filter : str A wildcard string to filter filenames in the file dialog box used by the attribute trait editor. auto_set : bool Indicates whether the file editor updates the trait value after every key stroke. entries : int A hint to the TraitsUI editor about how many values to display in the editor. exists : bool Indicates whether the trait value must be an existing file or not. Attributes ---------- filter : str A wildcard string to filter filenames in the file dialog box used by the attribute trait editor. auto_set : bool Indicates whether the file editor updates the trait value after every key stroke. entries : int A hint to the TraitsUI editor about how many values to display in the editor. exists : bool Indicates whether the trait value must be an existing file or not. """ def __init__( self, value="", filter=None, auto_set=False, entries=0, exists=False, **metadata ): super().__init__( value, filter, auto_set, entries, exists, **metadata ) class BaseDirectory(BaseStr): """ A trait type whose value must be a directory path string. This also accepts objects implementing the :class:`os.PathLike` interface, converting them to the corresponding string. Parameters ---------- value : str The default value for the trait. auto_set : bool Indicates whether the directory editor updates the trait value after every key stroke. entries : int A hint to the TraitsUI editor about how many values to display in the editor. exists : bool Indicates whether the trait value must be an existing directory or not. Attributes ---------- auto_set : bool Indicates whether the directory editor updates the trait value after every key stroke. entries : int A hint to the TraitsUI editor about how many values to display in the editor. exists : bool Indicates whether the trait value must be an existing directory or not. """ def __init__( self, value="", auto_set=False, entries=0, exists=False, **metadata ): self.entries = entries self.auto_set = auto_set self.exists = exists super().__init__(value, **metadata) def validate(self, object, name, value): """ Validates that a specified value is valid for this trait. Note: The 'fast validator' version performs this check in C. """ try: value = fspath(value) except TypeError: pass validated_value = super().validate( object, name, value ) if not self.exists: return validated_value elif isdir(value): return validated_value self.error(object, name, value) def info(self): """ Return a description of the type of value this trait accepts. """ description = "a string or os.PathLike object" if self.exists: description += " referring to an existing directory" return description def create_editor(self): from traitsui.editors.directory_editor import DirectoryEditor editor = DirectoryEditor(auto_set=self.auto_set, entries=self.entries) return editor class Directory(BaseDirectory): """ A fast-validating trait type whose value is a directory path string. This also accepts objects implementing the :class:`os.PathLike` interface, converting them to the corresponding string. Parameters ---------- value : str The default value for the trait. auto_set : bool Indicates whether the directory editor updates the trait value after every key stroke. entries : int A hint to the TraitsUI editor about how many values to display in the editor. exists : bool Indicates whether the trait value must be an existing directory or not. Attributes ---------- auto_set : bool Indicates whether the directory editor updates the trait value after every key stroke. entries : int A hint to the TraitsUI editor about how many values to display in the editor. exists : bool Indicates whether the trait value must be an existing directory or not. """ def __init__( self, value="", auto_set=False, entries=0, exists=False, **metadata ): # Fast validation is disabled (Github issue #877). super().__init__( value, auto_set, entries, exists, **metadata ) class BaseRange(TraitType): """ A trait type whose numeric value lies inside a range. The value held will be either an integer or a float, which type is determined by whether the *low*, *high* and *value* arguments are integers or floats. The *low*, *high*, and *value* arguments must be of the same type (integer or float), except in the case where either *low* or *high* is a string (i.e. extended trait name). If *value* is None or omitted, the default value is *low*, unless *low* is None or omitted, in which case the default value is *high*. Parameters ---------- low : integer, float or string (i.e. extended trait name) The low end of the range. high : integer, float or string (i.e. extended trait name) The high end of the range. value : integer, float or string (i.e. extended trait name) The default value of the trait. exclude_low : bool Indicates whether the low end of the range is exclusive. exclude_high : bool Indicates whether the high end of the range is exclusive. """ #: The default value type to use. default_value_type = DefaultValue.constant def __init__( self, low=None, high=None, value=None, exclude_low=False, exclude_high=False, **metadata ): if value is None: if low is not None: value = low else: value = high super().__init__(value, **metadata) vtype = type(high) if (low is not None) and ( not issubclass(vtype, (float, str)) ): vtype = type(low) is_static = not issubclass(vtype, str) if is_static and (vtype not in RangeTypes): raise TraitError( "Range can only be use for int or float " "values, but a value of type %s was specified." % vtype ) self._low_name = self._high_name = "" self._vtype = Undefined kind = None if vtype is float: self._validate = "float_validate" kind = ValidateTrait.float_range self._type_desc = "a floating point number" if low is not None: low = float(low) if high is not None: high = float(high) elif vtype is int: self._validate = "int_validate" self._type_desc = "an integer" if low is not None: low = int(low) if high is not None: high = int(high) else: self.get, self.set, self.validate = ( self._get, self._set, self._validate) self._vtype = None self._type_desc = "a number" if isinstance(high, str): self._high_name = high = "object." + high else: self._vtype = type(high) high = compile(str(high), "", "eval") if isinstance(low, str): self._low_name = low = "object." + low else: self._vtype = type(low) low = compile(str(low), "", "eval") if isinstance(value, str): value = "object." + value self._value = compile(str(value), "", "eval") self.default_value_type = DefaultValue.callable self.default_value = self._get_default_value exclude_mask = 0 if exclude_low: exclude_mask |= 1 if exclude_high: exclude_mask |= 2 if is_static and kind is not None: self.init_fast_validate(kind, low, high, exclude_mask) #: Assign type-corrected arguments to handler attributes: self._low = low self._high = high self._exclude_low = exclude_low self._exclude_high = exclude_high def init_fast_validate(self, *args): """ Does nothing for the BaseRange class. Used in the Range class to set up the fast validator. """ pass def validate(self, object, name, value): """ Validate that the value is in the specified range. """ return getattr(self, self._validate)(object, name, value) def float_validate(self, object, name, value): """ Validate that the value is a float value in the specified range. """ # Convert to exact type float, re-raising a TypeError as a TraitError # and letting other errors propagate. Keep original value for # error-reporting purposes. original_value = value try: value = _validate_float(value) except TypeError: self.error(object, name, original_value) if ( ( (self._low is None) or (self._exclude_low and (self._low < value)) or ((not self._exclude_low) and (self._low <= value)) ) and ( (self._high is None) or (self._exclude_high and (self._high > value)) or ((not self._exclude_high) and (self._high >= value)) ) ): return value self.error(object, name, original_value) def int_validate(self, object, name, value): """ Validate that the value is an int value in the specified range. """ # Convert to exact type float, re-raising a TypeError as a TraitError # and letting other errors propagate. Keep original value for # error-reporting purposes. original_value = value try: value = _validate_int(value) except TypeError: self.error(object, name, original_value) if ( ( (self._low is None) or (self._exclude_low and (self._low < value)) or ((not self._exclude_low) and (self._low <= value)) ) and ( (self._high is None) or (self._exclude_high and (self._high > value)) or ((not self._exclude_high) and (self._high >= value)) ) ): return value self.error(object, name, original_value) def _get_default_value(self, object): """ Returns the default value of the range. """ return eval(self._value) def _get(self, object, name, trait): """ Returns the current value of a dynamic range trait. """ cname = "_traits_cache_" + name value = object.__dict__.get(cname, Undefined) if value is Undefined: object.__dict__[cname] = value = eval(self._value) low = eval(self._low) high = eval(self._high) if (low is not None) and (value < low): value = low elif (high is not None) and (value > high): value = high return self._typed_value(value, low, high) def _set(self, object, name, value): """ Sets the current value of a dynamic range trait. """ value = self._validate(object, name, value) self._set_value(object, name, value) def _validate(self, object, name, value): """ Validate a value for a dynamic range trait. """ if not isinstance(value, str): try: low = eval(self._low) high = eval(self._high) if (low is None) and (high is None): if isinstance(value, RangeTypes): return value else: new_value = self._typed_value(value, low, high) if ( (low is None) or (self._exclude_low and (low < new_value)) or ((not self._exclude_low) and (low <= new_value)) ) and ( (high is None) or (self._exclude_high and (high > new_value)) or ((not self._exclude_high) and (high >= new_value)) ): return new_value except: pass self.error(object, name, value) def _typed_value(self, value, low, high): """ Returns the specified value with the correct type for the current dynamic range. """ vtype = self._vtype if vtype is None: if low is not None: vtype = type(low) elif high is not None: vtype = type(high) else: vtype = lambda x: x return vtype(value) def _set_value(self, object, name, value): """ Sets the specified value as the value of the dynamic range. """ cname = "_traits_cache_" + name old = object.__dict__.get(cname, Undefined) if old is Undefined: old = eval(self._value) object.__dict__[cname] = value if value != old: object.trait_property_changed(name, old, value) def full_info(self, object, name, value): """ Returns a description of the trait. """ if self._vtype is not Undefined: low = eval(self._low) high = eval(self._high) low, high = ( self._typed_value(low, low, high), self._typed_value(high, low, high), ) else: low = self._low high = self._high if low is None: if high is None: return self._type_desc return "%s <%s %s" % ( self._type_desc, "="[self._exclude_high:], high, ) elif high is None: return "%s >%s %s" % ( self._type_desc, "="[self._exclude_low:], low, ) return "%s <%s %s <%s %s" % ( low, "="[self._exclude_low:], self._type_desc, "="[self._exclude_high:], high, ) def create_editor(self): """ Returns the default UI editor for the trait. """ # fixme: Needs to support a dynamic range editor. auto_set = self.auto_set if auto_set is None: auto_set = True from traitsui.api import RangeEditor return RangeEditor( self, mode=self.mode or "auto", cols=self.cols or 3, auto_set=auto_set, enter_set=self.enter_set or False, low_label=self.low or "", high_label=self.high or "", low_name=self._low_name, high_name=self._high_name, ) class Range(BaseRange): """ A fast-validating trait type whose numeric value lies inside a range. """ def init_fast_validate(self, *args): """ Set up the C-level fast validator. """ self.fast_validate = args class BaseEnum(TraitType): """ A trait type whose value is an element of a finite collection. This trait type can be either *static*, with the collection of valid values specified directly in the constructor, or *dynamic*, with the collection provided by the value of another trait attribute. For both static and dynamic enumerations, a default value can be provided as a positional argument. If no default is provided, the default is the first item (in iteration order) of the underlying collection. Notes ----- 1. If the enumeration is based on an unordered collection like a ``set``, and no explicit default is given, the default used will effectively be arbitrary (the first element of the set in iteration order). It's recommended that a default be given explicitly in this case. 2. Instances of ``str``, ``bytes`` and ``bytearray`` are not treated as collections for the purposes of this trait type, both for pragmatic reasons (it's more likely that a user wants to use a string as an element in a collection than as a collection in its own right), and because the behavior of the ``in`` operator for those types does not express the usual membership semantics (for example, ``"bc" in "abc"`` is ``True``). Parameters ---------- *args The enumeration of all valid values for the trait. For a static enumeration trait (where the *values* keyword argument is not given) the supported signatures for ``args`` are as follows: (collection,) A nonempty collection of valid values. The default is the first element of the collection, in iteration order. (default, collection) The default value, followed by a nonempty collection of valid values. The default should be an element of the collection, but this is not checked. (item1, item2, ..., itemn) One or more items giving the valid values for the collection. The default is *item1*. For a dynamic enumeration trait, where the *values* keyword argument is given, the supported signatures for ``args`` are: () No arguments given. In this case the default is the first item of the collection, in iteration order. (default,) The default value for the collection. For the static case, the ambiguity in the signatures is resolved as follows: if ``args`` has length ``1`` or ``2``, ``args[-1]`` can be iterated over, and ``args[-1]`` is not an instance of ``str``, ``bytes`` or ``bytearray``, then ``args[-1]`` is assumed to give the collection of values. Otherwise, all elements of ``args`` are assumed to be items in the collection. Thus the first two signatures are safe from ambiguity, and it's recommended to use one of these two signatures in preference to the third form. values : str, optional The name of a trait holding the valid values. If given, this is a dynamic enumeration, otherwise it's a static numeration. **metadata Metadata for the trait. Attributes ---------- values : tuple or None For a static enumeration, this is a tuple holding the valid values. For a dynamic enumeration, this is None. name : str or None For a dynamic enumeration, this is the name of a trait holding the collection of valid values. For a static enumeration, this is None. """ #: The default value type to use. default_value_type = DefaultValue.constant def __init__(self, *args, values=None, **metadata): self.name = values nargs = len(args) if self.name is not None: # Dynamic enumeration self.values = None self.get, self.set, self.validate = ( self._get, self._set, self._validate) if nargs == 0: super().__init__(**metadata) elif nargs == 1: default_value = args[0] super().__init__(default_value, **metadata) else: raise TraitError( "Incorrect number of arguments specified " "when using the 'values' keyword" ) else: # Static enumeration if nargs == 0: raise TraitError("Enum trait requires at least 1 argument") # If we have either 1 or 2 arguments and the last argument is a # collection, then that collection provides the values of the # enumeration. Otherwise, args itself is the collection. have_collection_arg = ( nargs <= 2 and not isinstance(args[-1], (str, bytes, bytearray)) and isinstance(args[-1], collections.abc.Iterable) ) self.values = tuple(args[-1]) if have_collection_arg else args if not self.values: raise TraitError("Enum collection should be nonempty") # In the two-argument collection case, the first argument is # the default. Otherwise, we take the first element of self.values. if have_collection_arg and nargs == 2: default_value = args[0] else: default_value = self.values[0] self.init_fast_validate(ValidateTrait.enum, self.values) super().__init__(default_value, **metadata) def init_fast_validate(self, *args): """ Does nothing for the BaseEnum class. Used in the Enum class to set up the fast validator. """ pass def validate(self, object, name, value): """ Validates that the value is one of the enumerated set of valid values. """ if value in self.values: return value self.error(object, name, value) def full_info(self, object, name, value): """ Returns a description of the trait. """ if self.name is None: values = self.values else: values = xgetattr(object, self.name) return " or ".join([repr(x) for x in values]) def create_editor(self): """ Returns the default UI editor for the trait. """ from traitsui.api import EnumEditor if self.name is None: values = self.values name = "" else: values = None name = self.name editor = EnumEditor( name=name, cols=self.cols or 3, evaluate=self.evaluate, format_func=self.format_func, mode=self.mode if self.mode else "radio", ) # Workaround enthought/traitsui#782 if values is not None: editor.values = values return editor def _get(self, object, name, trait): """ Returns the current value of a dynamic enum trait. """ value = self.get_value(object, name, trait) values = xgetattr(object, self.name) if not safe_contains(value, values): value = next(iter(values), None) return value def _set(self, object, name, value): """ Sets the current value of a dynamic enum trait. """ value = self._validate(object, name, value) self.set_value(object, name, value) def _validate(self, object, name, value): """ Validate a value for a dynamic enum trait. """ if safe_contains(value, xgetattr(object, self.name)): return value else: self.error(object, name, value) class Enum(BaseEnum): """ A fast-validating trait type whose value is an element of a finite collection. This trait type can be either *static*, with the collection of valid values specified directly in the constructor, or *dynamic*, with the collection provided by the value of another trait attribute. For both static and dynamic enumerations, a default value can be provided as a positional argument. If no default is provided, the default is the first item (in iteration order) of the underlying collection. Notes ----- 1. If the enumeration is based on an unordered collection like a ``set``, and no explicit default is given, the default used will effectively be arbitrary (the first element of the set in iteration order). It's recommended that a default be given explicitly in this case. 2. Instances of ``str``, ``bytes`` and ``bytearray`` are not treated as collections for the purposes of this trait type, both for pragmatic reasons (it's more likely that a user wants to use a string as an element in a collection than as a collection in its own right), and because the behavior of the ``in`` operator for those types does not express the usual membership semantics (for example, ``"bc" in "abc"`` is ``True``). Parameters ---------- *args The enumeration of all valid values for the trait. For a static enumeration trait (where the *values* keyword argument is not given) the supported signatures for ``args`` are as follows: (collection,) A nonempty collection of valid values. The default is the first element of the collection, in iteration order. (default, collection) The default value, followed by a nonempty collection of valid values. The default should be an element of the collection, but this is not checked. (item1, item2, ..., itemn) One or more items giving the valid values for the collection. The default is *item1*. For a dynamic enumeration trait, where the *values* keyword argument is given, the supported signatures for ``args`` are: () No arguments given. In this case the default is the first item of the collection, in iteration order. (default,) The default value for the collection. For the static case, the ambiguity in the signatures is resolved as follows: if ``args`` has length ``1`` or ``2``, ``args[-1]`` can be iterated over, and ``args[-1]`` is not an instance of ``str``, ``bytes`` or ``bytearray``, then ``args[-1]`` is assumed to give the collection of values. Otherwise, all elements of ``args`` are assumed to be items in the collection. Thus the first two signatures are safe from ambiguity, and it's recommended to use one of these two signatures in preference to the third form. values : str, optional The name of a trait holding the valid values. If given, this is a dynamic enumeration, otherwise it's a static numeration. **metadata Metadata for the trait. Attributes ---------- values : tuple or None For a static enumeration, this is a tuple holding the valid values. For a dynamic enumeration, this is None. name : str or None For a dynamic enumeration, this is the name of a trait holding the collection of valid values. For a static enumeration, this is None. """ def init_fast_validate(self, *args): """ Set up C-level fast validation. """ self.fast_validate = args class BaseTuple(TraitType): """ A trait type holding a tuple with typed elements. The default value is determined as follows: 1. If no arguments are specified, the default value is (). 2. If a tuple is specified as the first argument, it is the default value. 3. If a tuple is not specified as the first argument, the default value is a tuple whose length is the length of the argument list, and whose values are the default values for the corresponding trait types. Example for case #2:: mytuple = Tuple(('Fred', 'Betty', 5)) The trait's value must be a 3-element tuple whose first and second elements are strings, and whose third element is an integer. The default value is ``('Fred', 'Betty', 5)``. Example for case #3:: mytuple = Tuple('Fred', 'Betty', 5) The trait's value must be a 3-element tuple whose first and second elements are strings, and whose third element is an integer. The default value is ``('','',0)``. Parameters ---------- *types Definition of the default and allowed tuples. If the first item of *types* is a tuple, it is used as the default value. The remaining argument list is used to form a tuple that constrains the values assigned to the returned trait. The trait's value must be a tuple of the same length as the remaining argument list, whose elements must match the types specified by the corresponding items of the remaining argument list. **metadata Trait metadata for the trait. Attributes ---------- types : tuple The tuple of traits specifying the type of each element in order. no_type_check : bool Flag to indicate whether validation should check the type of each element. """ #: The default value type to use. default_value_type = DefaultValue.constant def __init__(self, *types, **metadata): if len(types) == 0: self.init_fast_validate(ValidateTrait.coerce, tuple, None, list) super().__init__((), **metadata) return default_value = None if isinstance(types[0], tuple): default_value, types = types[0], types[1:] if len(types) == 0: types = [Trait(element) for element in default_value] self.types = tuple(trait_from(type) for type in types) self.init_fast_validate(ValidateTrait.tuple, self.types) if default_value is None: # Optimisation: if all child traits have a constant default value, # we can use a constant default value too. Otherwise the default # needs to be computed dynamically. child_defaults = [] child_default_types = [] for child_trait in self.types: child_default_type, child_default = child_trait.default_value() child_default_types.append(child_default_type) child_defaults.append(child_default) constant_default = all( dvt == DefaultValue.constant for dvt in child_default_types ) if constant_default: default_value = tuple(child_defaults) else: self.default_value_type = DefaultValue.callable default_value = self._get_default_value super().__init__(default_value, **metadata) def _get_default_value(self, object): # Dynamic default, used when at least one of the child traits requires # a dynamic default. return tuple( inner_trait.default_value_for(object, "") for inner_trait in self.types ) def init_fast_validate(self, *args): """ Saves the validation parameters. """ self.no_type_check = args[0] == ValidateTrait.coerce def validate(self, object, name, value): """ Validates that the value is a valid tuple. """ if self.no_type_check: if isinstance(value, tuple): return value if isinstance(value, list): return tuple(value) self.error(object, name, value) try: if isinstance(value, list): value = tuple(value) if isinstance(value, tuple): types = self.types if len(value) == len(types): values = [] for i, type in enumerate(types): values.append(type.validate(object, name, value[i])) return tuple(values) except: pass self.error(object, name, value) def full_info(self, object, name, value): """ Returns a description of the trait. """ if self.no_type_check: return "a tuple" return "a tuple of the form: (%s)" % ( ", ".join( [type.full_info(object, name, value) for type in self.types] ) ) def create_editor(self): """ Returns the default UI editor for the trait. """ from traitsui.api import TupleEditor auto_set = self.auto_set if auto_set is None: auto_set = True enter_set = self.enter_set or False return TupleEditor( types=self.types, labels=self.labels or [], cols=self.cols or 1, auto_set=auto_set, enter_set=enter_set, ) class Tuple(BaseTuple): """ A fast-validating trait type holding a tuple with typed elements. """ def init_fast_validate(self, *args): """ Set up the C-level fast validator. """ super().init_fast_validate(*args) self.fast_validate = args class ValidatedTuple(BaseTuple): """ A trait type holding a tuple with customized validation. Parameters ---------- *types Definition of the default and allowed tuples. (see :class:`~.BaseTuple` for more details) fvalidate : callable, optional A callable to provide the additional custom validation for the tuple. The callable will be passed the tuple value and should return True or False. fvalidate_info : string, optional A string describing the custom validation to use for the error messages. **metadata Trait metadata for the trait. Example ------- The definition:: value_range = ValidatedTuple( Int(0), Int(1), fvalidate=lambda x: x[0] < x[1]) will accept only tuples ``(a, b)`` containing two integers that satisfy ``a < b``. """ def __init__(self, *types, **metadata): metadata.setdefault("fvalidate", None) metadata.setdefault("fvalidate_info", "") super().__init__(*types, **metadata) def validate(self, object, name, value): """ Validates that the value is a valid tuple. """ values = super().validate(object, name, value) # Exceptions in the fvalidate function will not result in a TraitError # but will be allowed to propagate up the frame stacks. if self.fvalidate is None or self.fvalidate(values): return values else: self.error(object, name, value) def full_info(self, object, name, value): """ Returns a description of the trait. """ message = "a tuple of the form: ({0}) that passes custom validation{1}" types_info = ", ".join( [type_.full_info(object, name, value) for type_ in self.types] ) if self.fvalidate_info is not None: fvalidate_info = ": {0}".format(self.fvalidate_info) else: fvalidate_info = "" return message.format(types_info, fvalidate_info) class List(TraitType): """ A trait type for a list of values of the specified type. The length of the list assigned to the trait must be such that:: minlen <= len(list) <= maxlen Note that this trait type creates copies of values on assignment, rather than assigning the exact instance. For example, consider:: >>> class A(HasTraits): ... x = List() ... >>> b = [1, 2, 3] >>> a = A(x=b) >>> a.x [1, 2, 3] >>> b.append(4) >>> a.x [1, 2, 3] Parameters ---------- trait : a trait or value that can be converted using trait_from() The type of item that the list contains. If not specified, the list can contain items of any type. value : list Default value for the list. minlen : integer The minimum length of a list that can be assigned to the trait. maxlen : integer The maximum length of a list that can be assigned to the trait. items : bool Whether there is a corresponding `_items` trait. **metadata Trait metadata for the trait. Attributes ---------- item_trait : trait The type of item that the list contains. minlen : integer The minimum length of a list that can be assigned to the trait. maxlen : integer The maximum length of a list that can be assigned to the trait. has_items : bool Whether there is a corresponding `_items` trait. """ info_trait = None default_value_type = DefaultValue.trait_list_object _items_event = None def __init__( self, trait=None, value=None, minlen=0, maxlen=sys.maxsize, items=True, **metadata ): metadata.setdefault("copy", "deep") if isinstance(trait, SequenceTypes): trait, value = value, list(trait) if value is None: value = [] self.item_trait = trait_from(trait) self.minlen = max(0, minlen) self.maxlen = max(minlen, maxlen) self.has_items = items if self.item_trait.instance_handler == "_instance_changed_handler": metadata.setdefault("instance_handler", "_list_changed_handler") super().__init__(value, **metadata) def validate(self, object, name, value): """ Validates that the values is a valid list. .. note:: `object` can be None when validating a default value (see e.g. :meth:`~traits.trait_handlers.TraitType.clone`) """ if isinstance(value, list) and ( self.minlen <= len(value) <= self.maxlen ): if object is None: return value return TraitListObject(self, object, name, value) self.error(object, name, value) def full_info(self, object, name, value): """ Returns a description of the trait. """ if self.minlen == 0: if self.maxlen == sys.maxsize: size = "items" else: size = "at most %d items" % self.maxlen else: if self.maxlen == sys.maxsize: size = "at least %d items" % self.minlen else: size = "from %s to %s items" % (self.minlen, self.maxlen) return "a list of %s which are %s" % ( size, self.item_trait.full_info(object, name, value), ) def create_editor(self): """ Returns the default UI editor for the trait. """ return list_editor(self, self) def inner_traits(self): """ Returns the *inner trait* (or traits) for this trait. """ return (self.item_trait,) # -- Private Methods ------------------------------------------------------ def items_event(self): cls = self.__class__ if cls._items_event is None: cls._items_event = Event( TraitListEvent, is_base=False ).as_ctrait() return cls._items_event class CList(List): """ A coercing trait type for a list of values of the specified type. """ def validate(self, object, name, value): """ Validates that the values is a valid list. """ if not isinstance(value, list): try: # Should work for all iterables as well as strings (which do # not define an __iter__ method) value = list(value) except (ValueError, TypeError): value = [value] return super().validate(object, name, value) def full_info(self, object, name, value): """ Returns a description of the trait. """ return "%s or %s" % ( self.item_trait.full_info(object, name, value), super().full_info(object, name, value), ) class PrefixList(TraitType): r"""Ensures that a value assigned to the attribute is a member of a list of specified string values, or is a unique prefix of one of those values. The values that can be assigned to a trait attribute of type PrefixList type is the set of all strings supplied to the PrefixList constructor, as well as any unique prefix of those strings. That is, if the set of strings supplied to the constructor is described by [*s*\ :sub:`1`\ , *s*\ :sub:`2`\ , ..., *s*\ :sub:`n`\ ], then the string *v* is a valid value for the trait if *v* == *s*\ :sub:`i[:j]` for one and only one pair of values (i, j). If *v* is a valid value, then the actual value assigned to the trait attribute is the corresponding *s*\ :sub:`i` value that *v* matched. The legal values can be provided as an iterable of values. Example ------- :: class Person(HasTraits): married = PrefixList(['yes', 'no']) The Person class has a **married** trait that accepts any of the strings 'y', 'ye', 'yes', 'n', or 'no' as valid values. However, the actual values assigned as the value of the trait attribute are limited to either 'yes' or 'no'. That is, if the value 'y' is assigned to the **married** attribute, the actual value assigned will be 'yes'. Parameters ---------- values A list or other iterable of legal string values for this trait. Attributes ---------- values : list of str The list of legal values for this trait. """ #: The default value type to use. default_value_type = DefaultValue.constant def __init__(self, values, *, default_value=None, **metadata): # Avoid confusion from treating a string-like object as an iterable. if isinstance(values, (str, bytes, bytearray)): raise TypeError( "values should be a collection of strings, " f"not {values!r}" ) values = list(values) if not values: raise ValueError("values must be nonempty") self.values = values # Use a set for faster lookup in the common case that the value # to be validated is one of the elements of 'values' (rather than # a strict prefix). self._values_as_set = frozenset(values) if default_value is not None: default_value = self._complete_value(default_value) else: default_value = self.values[0] super().__init__(default_value, **metadata) def _complete_value(self, value): """ Validate and complete a given value. Parameters ---------- value : str Value to be validated. Returns ------- completion : str Equal to *value*, if *value* is already a member of self.values. Otherwise, the unique member of self.values for which *value* is a prefix. Raises ------ ValueError If value is not in self.values, and is not a prefix of any element of self.values, or is a prefix of multiple elements of self.values. """ if value in self._values_as_set: return value matches = [key for key in self.values if key.startswith(value)] if len(matches) == 1: return matches[0] raise ValueError( f"{value!r} is neither a member nor a unique prefix of a member " f"of {self.values}" ) def validate(self, object, name, value): if isinstance(value, str): try: return self._complete_value(value) except ValueError: pass self.error(object, name, value) def info(self): return ( " or ".join(repr(x) for x in self.values) + " (or any unique prefix)" ) class Set(TraitType): """ A trait type for a set of values of the specified type. Note that this trait type creates copies of values on assignment, rather than assigning the exact instance. For example, consider:: >>> class A(HasTraits): ... x = Set() ... >>> b = set() >>> a = A(x=b) >>> a.x TraitSetObject() >>> b.add(1) >>> a.x TraitSetObject() Parameters ---------- trait : a trait or value that can be converted using trait_from() The type of item that the set contains. If not specified, the set can contain items of any type. value : set Default value for the set. items : bool Whether there is a corresponding `_items` trait. **metadata Trait metadata for the trait. Attributes ---------- item_trait : a trait or value that can be converted to a trait The type of item that the set contains. If not specified, the set can contain items of any type. has_items : bool Whether there is a corresponding `_items` trait. """ info_trait = None default_value_type = DefaultValue.trait_set_object _items_event = None def __init__(self, trait=None, value=None, items=True, **metadata): metadata.setdefault("copy", "deep") if isinstance(trait, SetTypes): trait, value = value, set(trait) if value is None: value = set() self.item_trait = trait_from(trait) self.has_items = items super().__init__(value, **metadata) def validate(self, object, name, value): """ Validates that the values is a valid set. .. note:: `object` can be None when validating a default value (see e.g. :meth:`~traits.trait_handlers.TraitType.clone`) """ if isinstance(value, set): if object is None: return value return TraitSetObject(self, object, name, value) self.error(object, name, value) def full_info(self, object, name, value): """ Returns a description of the trait. """ return "a set of %s" % self.item_trait.full_info(object, name, value) def create_editor(self): """ Returns the default UI editor for the trait. """ from traitsui.api import TextEditor return TextEditor(evaluate=eval) def inner_traits(self): """ Returns the *inner trait* (or traits) for this trait. """ return (self.item_trait,) # -- Private Methods ------------------------------------------------------ def items_event(self): if self.__class__._items_event is None: self.__class__._items_event = Event( TraitSetEvent, is_base=False ).as_ctrait() return self.__class__._items_event class CSet(Set): """ A coercing trait type for a set of values of the specified type. """ def validate(self, object, name, value): """ Validates that the values is a valid list. """ if not isinstance(value, set): try: # Should work for all iterables as well as strings (which do # not define an __iter__ method) value = set(value) except (ValueError, TypeError): value = set([value]) return super().validate(object, name, value) def full_info(self, object, name, value): """ Returns a description of the trait. """ return "%s or %s" % ( self.item_trait.full_info(object, name, value), super().full_info(object, name, value), ) class Dict(TraitType): """ A trait type for a dictionary with specified key and value types. Note that this trait type creates copies of values on assignment, rather than assigning the exact instance. For example, consider:: >>> class A(HasTraits): ... x = Dict() ... >>> b = {} >>> a = A(x=b) >>> a.x {} >>> b['one'] = 1 >>> a.x {} Parameters ---------- key_trait : a trait or value that can be converted using trait_from() The trait type for keys in the dictionary; if not specified, any values can be used as keys. value_trait : a trait or value that can be converted using trait_from() The trait type for values in the dictionary; if not specified, any values can be used as dictionary values. value : dict The default value for the returned trait. items : bool Indicates whether the value contains items. Attributes ---------- key_trait : a trait The trait type for keys in the dictionary; if not specified, any values can be used as keys. value_trait : a trait The trait type for values in the dictionary; if not specified, any values can be used as dictionary values. value_trait_handler : TraitHandler The TraitHandler for the value_trait. has_items : bool Indicates whether the value contains items. """ info_trait = None default_value_type = DefaultValue.trait_dict_object _items_event = None def __init__( self, key_trait=None, value_trait=None, value=None, items=True, **metadata ): if isinstance(key_trait, dict): key_trait, value_trait, value = value_trait, value, key_trait if value is None: value = {} self.key_trait = trait_from(key_trait) self.value_trait = trait_from(value_trait) self.has_items = items handler = self.value_trait.handler if (handler is not None) and handler.has_items: handler = handler.clone() handler.has_items = False self.value_handler = handler super().__init__(value, **metadata) def validate(self, object, name, value): """ Validates that the value is a valid dictionary. Note ---- `object` can be None when validating a default value (see e.g. :meth:`~traits.trait_handlers.TraitType.clone`) """ if isinstance(value, dict): if object is None: return value return TraitDictObject(self, object, name, value) self.error(object, name, value) def full_info(self, object, name, value): """ Returns a description of the trait. """ return ( "a dictionary with keys which are %s and with values which " "are %s" ) % ( self.key_trait.full_info(object, name, value), self.value_trait.full_info(object, name, value), ) def create_editor(self): """ Returns the default UI editor for the trait. """ from traitsui.api import TextEditor return TextEditor(evaluate=eval) def inner_traits(self): """ Returns the *inner trait* (or traits) for this trait. """ return (self.key_trait, self.value_trait) # -- Private Methods ------------------------------------------------------ def items_event(self): cls = self.__class__ if cls._items_event is None: cls._items_event = Event(TraitDictEvent, is_base=False).as_ctrait() return cls._items_event #: Allowed values and mappings for the 'adapt' keyword. #: #: - 'no': Adaptation is not allowed. #: - 'yes': Adaptation is allowed. If adaptation fails, an #: exception should be raised. #: - 'default': Adaptation is allowed. If adaptation fails, the #: default value for the trait should be used. AdaptMap = {"no": 0, "yes": 1, "default": 2} class Map(TraitType): """ Checks that the value assigned to a trait attribute is a key of a specified dictionary, and also assigns the dictionary value corresponding to that key to a *shadow* attribute. A trait attribute of type Map is called a *mapped* trait attribute. In practice, this means that the resulting object actually contains two attributes: one whose value is a key of the Map dictionary, and the other whose value is the corresponding value of the Map dictionary. The name of the shadow attribute is simply the base attribute name with an underscore ('_') appended. Mapped trait attributes can be used to allow a variety of user-friendly input values to be mapped to a set of internal, program-friendly values. Example ------- The following example defines a ``Person`` class:: >>> class Person(HasTraits): ... married = Map({'yes': 1, 'no': 0 }, default_value="yes") ... >>> bob = Person() >>> print(bob.married) yes >>> print(bob.married_) 1 In this example, the default value of the ``married`` attribute of the Person class is 'yes'. Because this attribute is defined using Map, instances of Person have another attribute, ``married_``, whose default value is 1, the dictionary value corresponding to the key 'yes'. Parameters ---------- map : dict A dictionary whose keys are valid values for the trait attribute, and whose corresponding values are the values for the shadow trait attribute. default_value : object, optional The default value for the trait. If given, this should be a key from the mapping. If not given, the first key from the mapping (in normal dictionary iteration order) will be used as the default. Attributes ---------- map : dict A dictionary whose keys are valid values for the trait attribute, and whose corresponding values are the values for the shadow trait attribute. """ #: The default value type to use. default_value_type = DefaultValue.constant is_mapped = True def __init__(self, map, **metadata): self.map = map self.fast_validate = (ValidateTrait.map, map) try: default_value = metadata.pop("default_value") except KeyError: if len(self.map) > 0: default_value = next(iter(self.map)) else: raise ValueError( "The dictionary of valid values can not be empty." ) from None super().__init__(default_value, **metadata) def validate(self, object, name, value): try: if value in self.map: return value except TypeError: pass self.error(object, name, value) def mapped_value(self, value): """ Get the mapped value for a value. """ return self.map[value] def post_setattr(self, object, name, value): setattr(object, name + "_", self.mapped_value(value)) def info(self): keys = sorted(repr(x) for x in self.map.keys()) return " or ".join(keys) def get_editor(self, trait): from traitsui.api import EnumEditor return EnumEditor(values=self, cols=trait.cols or 3) class PrefixMap(TraitType): """ A cross between the PrefixList and Map classes. Like Map, PrefixMap is created using a dictionary, but in this case, the keys of the dictionary must be strings. Like PrefixList, a string *v* is a valid value for the trait attribute if it is a prefix of one and only one key *k* in the dictionary. The actual values assigned to the trait attribute is *k*, and its corresponding mapped attribute is *map*[*k*]. Example ------- :: mapping = {'true': 1, 'yes': 1, 'false': 0, 'no': 0 } boolean_map = PrefixMap(mapping) This example defines a Boolean trait that accepts any prefix of 'true', 'yes', 'false', or 'no', and maps them to 1 or 0. Parameters ---------- map : dict A dictionary whose keys are strings that are valid values for the trait attribute, and whose corresponding values are the values for the shadow trait attribute. default_value : object, optional The default value for the trait. If given, this should be either a key from the mapping or a unique prefix of a key from the mapping. If not given, the first key from the mapping (in normal dictionary iteration order) will be used as the default. Attributes ---------- map : dict A dictionary whose keys are strings that are valid values for the trait attribute, and whose corresponding values are the values for the shadow trait attribute. """ #: The default value type to use. default_value_type = DefaultValue.constant is_mapped = True def __init__(self, map, *, default_value=None, **metadata): map = dict(map) if not map: raise ValueError("map must be nonempty") self.map = map # Provide backwards compatibility for Mayavi, which currently # subclasses PrefixMap and depends on the existence of the _map # attribute. This attribute can be removed as soon as RevPrefixMap in # Mayavi has been fixed. # xref: enthought/traits#1577 # xref: enthought/mayavi#1094 self._map = {value: value for value in map} if default_value is not None: default_value = self._complete_value(default_value) else: default_value = next(iter(self.map)) super().__init__(default_value, **metadata) def _complete_value(self, value): """ Validate and complete a given value. Parameters ---------- value : str Value to be validated. Returns ------- completion : str Equal to *value*, if *value* is already a member of self.map. Otherwise, the unique member of self.values for which *value* is a prefix. Raises ------ ValueError If value is not in self.map, and is not a prefix of any element of self.map, or is a prefix of multiple elements of self.map. """ if value in self.map: return value matches = [key for key in self.map if key.startswith(value)] if len(matches) == 1: return matches[0] raise ValueError( f"{value!r} is neither a member nor a unique prefix of a member " f"of {list(self.map)}" ) def validate(self, object, name, value): if isinstance(value, str): try: return self._complete_value(value) except ValueError: pass self.error(object, name, value) def mapped_value(self, value): """ Get the mapped value for a value. """ return self.map[value] def post_setattr(self, object, name, value): setattr(object, name + "_", self.mapped_value(value)) def info(self): return ( " or ".join(repr(x) for x in self.map) + " (or any unique prefix)" ) def get_editor(self, trait): from traitsui.api import EnumEditor return EnumEditor(values=self, cols=trait.cols or 3) class BaseClass(TraitType): """ A base trait type for trait types which have an associated class. Traits sometimes need to be able to access classes which have not yet been defined, or which are from a module that we want to defer importing from. To support this, classes can be determined dynamically by specifying a string name for the class (e.g. ``'package1.package2.module.class'``). This base class provides the machinery for this sort of deferred access to classes. Any subclass must define instances with 'klass' and 'module' attributes that contain the string name of the class (or actual class object) and the module name that contained the original trait definition (used for resolving local class names (e.g. 'LocalClass')). This is an abstract class that only provides helper methods used to resolve the class name into an actual class object. Attributes ---------- klass : type or str The class object or a string that refers to it. module : str The name of the module that contains the class. """ #: The default value type to use. default_value_type = DefaultValue.constant def resolve_class(self, object, name, value): """ Resolve the class object as part of validation. This is called when the ``klass`` attribute is a string and sets the ``klass`` attribute to the actual klass object as a side-effect. If the class cannot be resolved, it will call validate_failed(). """ klass = self.validate_class(self.find_class(self.klass)) if klass is None: self.validate_failed(object, name, value) self.klass = klass def validate_class(self, klass): """ Validate a class object. """ return klass def find_class(self, klass): """ Given a string describing a class, get the class object. """ module = self.module col = klass.rfind(".") if col >= 0: module = klass[:col] klass = klass[col + 1:] theClass = getattr(sys.modules.get(module), klass, None) if (theClass is None) and (col >= 0): try: mod = import_module(module) theClass = getattr(mod, klass, None) except Exception: pass return theClass def validate_failed(self, object, name, value): """ Raise a TraitError if the class could not be resolved. """ self.error(object, name, value) class BaseInstance(BaseClass): """ A trait type whose value is an instance of a class or its subclasses. The default value is **None** if *klass* is an instance or if it is a class and *args* and *kw* are not specified. Otherwise, the default value is the instance obtained by calling ``klass(*args, **kw)``. Note that the constructor call is performed each time a default value is assigned, so each default value assigned is a unique instance. Parameters ---------- klass : class, str or instance The object that forms the basis for the trait; if it is an instance, then trait values must be instances of the same class or a subclass. This object is not the default value, even if it is an instance. If the provided value is a string, it is expected to be a reference to a class that will be resolved at run-time. factory : callable A callable, typically a class, that when called with *args* and *kw*, returns the default value for the trait. If not specified, or *None*, *klass* is used as the factory. args : tuple Positional arguments for generating the default value. kw : dictionary Keyword arguments for generating the default value. allow_none : bool Indicates whether None is allowed as a value. adapt : str A string specifying how adaptation should be applied. The possible values are: - 'no': Adaptation is not allowed. - 'yes': Adaptation is allowed. If adaptation fails, an exception should be raised. - 'default': Adaptation is allowed. If adaptation fails, the default value for the trait should be used. Attributes ---------- factory : callable A callable, typically a class, that when called with *args* and *kw*, returns the default value for the trait. If not specified, or *None*, *klass* is used as the factory. args : tuple Positional arguments for generating the default value. kw : dictionary Keyword arguments for generating the default value. allow_none : bool Indicates whether None is allowed as a value. adapt : str A string specifying how adaptation should be applied. The possible values are: - 'no': Adaptation is not allowed. - 'yes': Adaptation is allowed. If adaptation fails, an exception should be raised. - 'default': Adaptation is allowed. If adaptation fails, the default value for the trait should be used. """ #: Default adaptation behavior. adapt_default = "no" def __init__( self, klass=None, factory=None, args=None, kw=None, allow_none=True, adapt=None, module=None, **metadata ): if klass is None: raise TraitError( "A %s trait must have a class specified." % self.__class__.__name__ ) metadata.setdefault("copy", "deep") metadata.setdefault("instance_handler", "_instance_changed_handler") adapt = adapt or self.adapt_default if adapt not in AdaptMap: raise TraitError("'adapt' must be 'yes', 'no' or 'default'.") if isinstance(factory, tuple): if args is None: args, factory = factory, klass elif isinstance(args, dict): factory, args, kw = klass, factory, args elif (kw is None) and isinstance(factory, dict): kw, factory = factory, klass elif ((args is not None) or (kw is not None)) and (factory is None): factory = klass self._allow_none = allow_none self.adapt = AdaptMap[adapt] self.module = module or get_module_name() if isinstance(klass, str): self.klass = klass else: if not isinstance(klass, type): klass = klass.__class__ self.klass = klass self.init_fast_validate() value = factory if factory is not None: if args is None: args = () if kw is None: if isinstance(args, dict): kw = args args = () else: kw = {} elif not isinstance(kw, dict): raise TraitError("The 'kw' argument must be a dictionary.") if (not callable(factory)) and ( not isinstance(factory, str) ): if (len(args) > 0) or (len(kw) > 0): raise TraitError("'factory' must be callable") else: self.default_value_type = DefaultValue.callable_and_args value = (self.create_default_value, (factory, *args), kw) self.default_value = value super().__init__(value, **metadata) def validate(self, object, name, value): """ Validates that the value is a valid object instance. """ from traits.adaptation.api import adapt if value is None: if self._allow_none: return value self.validate_failed(object, name, value) if isinstance(self.klass, str): self.resolve_class(object, name, value) # Adaptation mode 0: do a simple isinstance check. if self.adapt == 0: if isinstance(value, self.klass): return value else: self.validate_failed(object, name, value) # Try adaptation; return adapted value on success. result = adapt(value, self.klass, None) if result is not None: return result # Adaptation failed. Move on to an isinstance check. if isinstance(value, self.klass): return value # Adaptation and isinstance both failed. In mode 1, fail. # Otherwise, return the default. if self.adapt == 1: self.validate_failed(object, name, value) else: result = self.default_value if self.default_value_type == DefaultValue.callable_and_args: return result[0](*result[1], **result[2]) else: return result def info(self): """ Returns a description of the trait. """ klass = self.klass if not isinstance(klass, str): klass = klass.__name__ if self.adapt == 0: result = class_of(klass) else: result = ( "an implementor of, or can be adapted to implement, %s" % klass ) if self._allow_none: return result + " or None" return result def clone(self, default_value=NoDefaultSpecified, **metadata): """ Copy, optionally modifying default value and metadata. """ # We extend the base class method in order to ensure that "allow_none" # is handled in the same way that it's handled in the initializer. allow_none = metadata.pop("allow_none", None) clone_of_self = super().clone(default_value=default_value, **metadata) if allow_none is not None: clone_of_self._allow_none = allow_none return clone_of_self def create_editor(self): """ Returns the default traits UI editor for this type of trait. """ from traitsui.api import InstanceEditor return InstanceEditor( label=self.label or "", view=self.view or "", kind=self.kind or "live", ) # -- Private Methods ------------------------------------------------------ def create_default_value(self, *args, **kw): klass = args[0] if isinstance(klass, str): klass = self.validate_class(self.find_class(klass)) if klass is None: raise TraitError("Unable to locate class: " + args[0]) return klass(*args[1:], **kw) #: fixme: Do we still need this method using the new style?... def allow_none(self): self._allow_none = True self.init_fast_validate() def init_fast_validate(self): """ Does nothing for the BaseInstance' class. Used by the 'Instance', 'Supports' and 'AdaptsTo' classes to set up the C-level fast validator. """ pass def resolve_class(self, object, name, value): super().resolve_class(object, name, value) # fixme: The following is quite ugly, because it wants to try and fix # the trait referencing this handler to use the 'fast path' now that # the actual class has been resolved. The problem is finding the trait, # especially in the case of List(Instance('foo')), where the # object.base_trait(...) value is the List trait, not the Instance # trait, so we need to check for this and pull out the List # 'item_trait'. Obviously this does not extend well to other traits # containing nested trait references (Dict?)... self.init_fast_validate() trait = object.base_trait(name) handler = trait.handler if handler is not self: set_validate = getattr(handler, "set_validate", None) if set_validate is not None: # The outer trait is a TraitCompound. Recompute its # fast_validate table now that we have updated ours. # FIXME: there are probably still issues if the TraitCompound # is further nested. set_validate() else: item_trait = getattr(handler, "item_trait", None) if item_trait is not None and item_trait.handler is self: # The outer trait is a List trait. trait = item_trait handler = self else: return if handler.fast_validate is not None: trait.set_validate(handler.fast_validate) class Instance(BaseInstance): """ A fast-validated trait type whose value is an instance of a class. """ def init_fast_validate(self): """ Sets up the C-level fast validator. """ if self.adapt == 0: fast_validate = [ValidateTrait.instance, self.klass] if self._allow_none: fast_validate = [ValidateTrait.instance, None, self.klass] else: fast_validate = [ValidateTrait.instance, self.klass] if self.klass in TypeTypes: fast_validate[0] = ValidateTrait.type self.fast_validate = tuple(fast_validate) else: self.fast_validate = ( ValidateTrait.adapt, self.klass, self.adapt, self._allow_none) class Supports(Instance): """ A trait type whose value is adapted to a specified protocol. In other words, the value of the trait directly provide, or can be adapted to, the given protocol (Interface or type). The value of the trait after assignment is the possibly adapted value (i.e., it is the original assigned value if that provides the protocol, or is an adapter otherwise). The original, unadapted value is stored in a "shadow" attribute with the same name followed by an underscore (e.g., ``foo`` and ``foo_``). """ adapt_default = "yes" def post_setattr(self, object, name, value): """ Performs additional post-assignment processing. """ # Save the original, unadapted value in the mapped trait: object.__dict__[name + "_"] = value def as_ctrait(self): """ Returns a CTrait corresponding to the trait defined by this class. """ return self.modify_ctrait(super().as_ctrait()) def modify_ctrait(self, ctrait): # Tell the C code that the 'post_setattr' method wants the original, # unadapted value passed to 'setattr': ctrait.post_setattr_original_value = True return ctrait class AdaptsTo(Supports): """ A trait type whose value must support a specified protocol. In other words, the value of the trait directly provide, or can be adapted to, the given protocol (Interface or type). The value of the trait after assignment is the original, unadapted value. A possibly adapted value is stored in a "shadow" attribute with the same name followed by an underscore (e.g., ``foo`` and ``foo_``). """ def modify_ctrait(self, ctrait): # Tell the C code that 'setattr' should store the original, unadapted # value passed to it: ctrait.setattr_original_value = True return ctrait class Type(BaseClass): """ A trait type whose value must be a subclass of a specified class. Parameters ---------- value : class or None The default value of the trait. klass : class, str or None The class that trait values must be subclasses of. If None, then the default value is used instead. If both are None, then the ``object`` type is used. If it is a string, the first time that the validate method is called, the class will be imported and the value replaced with the class object. allow_none : bool Indicates whether None is allowed as an assignable value. Even if **False**, the default *value* may be **None**. **metadata Trait metadata for the trait. Attributes ---------- klass : class or str The class that trait values must be subclasses of. If this is a string, the first time that the validate method is called, the class will be imported and the value replaced with the class object. module : str The name of the module where local class names (ie. class names with no module components) are presumed to be importable from. This is the caller's caller's module, as determined by the ``get_module_method``. """ def __init__(self, value=None, klass=None, allow_none=True, **metadata): if value is None: if klass is None: klass = object elif klass is None: klass = value if isinstance(klass, str): self.validate = self.resolve elif not isinstance(klass, type): raise TraitError("A Type trait must specify a class.") self.klass = klass self._allow_none = allow_none self.module = get_module_name() super().__init__(value, **metadata) def validate(self, object, name, value): """ Validates that the value is a valid object instance. """ try: if issubclass(value, self.klass): return value except: if (value is None) and (self._allow_none): return value self.error(object, name, value) def resolve(self, object, name, value): """ Resolves a class originally specified as a string into an actual class, then resets the trait so that future calls will be handled by the normal validate method. """ if isinstance(self.klass, str): self.resolve_class(object, name, value) del self.validate return self.validate(object, name, value) def info(self): """ Returns a description of the trait. """ klass = self.klass if not isinstance(klass, str): klass = klass.__name__ result = "a subclass of " + klass if self._allow_none: return result + " or None" return result def get_default_value(self): """ Returns a tuple of the form: ( default_value_type, default_value ) which describes the default value for this trait. """ if not isinstance(self.default_value, str): return super().get_default_value() return ( DefaultValue.callable_and_args, (self.resolve_default_value, (), None), ) def resolve_default_value(self): """ Resolves a class name into a class so that it can be used to return the class as the default value of the trait. """ if isinstance(self.klass, str): try: self.resolve_class(None, None, None) del self.validate except: raise TraitError( "Could not resolve %s into a valid class" % self.klass ) return self.klass #: An alias for the Type trait Subclass = Type class Event(TraitType): """ A trait type that holds no value but can be set and listened to. Event traits are write-only traits. They do not hold any value, but they can be assigned to, and listeners to the trait will be notified of the assignment. Since no value is held, trait change functions that ask for the ``old`` value of the trait will be given the Undefined special value. Event traits can be given an optional trait type that is used to validate values assigned to the trait. If the assigned value does not validate, then a TraitError will occur. Parameters ---------- trait : a trait The type of value that can be assigned to the event. """ #: The default value type to use. default_value_type = DefaultValue.constant def __init__(self, trait=None, **metadata): metadata["type"] = "event" metadata["transient"] = True super().__init__(**metadata) self.trait = None if trait is not None: self.trait = trait_from(trait) validate = self.trait.get_validate() if validate is not None: self.fast_validate = validate def full_info(self, object, name, value): """ Returns a description of the trait. """ trait = self.trait if trait is None: return "any value" return trait.full_info(object, name, value) class Button(Event): """ An Event trait type whose UI editor is a button. Parameters ---------- label : str The label for the button. image : pyface.ImageResource An image to display on the button. style : 'button', 'radio', 'toolbar' or 'checkbox' The style of button to display. values_trait : str For a "button" or "toolbar" style, the name of an enum trait whose values will populate a drop-down menu on the button. The selected value will replace the label on the button. orientation : 'horizontal' or 'vertical' The orientation of the label relative to the image. width_padding : integer between 0 and 31 Extra padding (in pixels) added to the left and right sides of the button. height_padding : integer between 0 and 31 Extra padding (in pixels) added to the top and bottom of the button. view : traitsui View, optional An optional View to display when the button is clicked. **metadata Trait metadata for the trait. Attributes ---------- label : str The label for the button. image : pyface.ImageResource An image to display on the button. style : 'button', 'radio', 'toolbar' or 'checkbox' The style of button to display. values_trait : str For a "button" or "toolbar" style, the name of an enum trait whose values will populate a drop-down menu on the button. The selected value will replace the label on the button. orientation : 'horizontal' or 'vertical' The orientation of the label relative to the image. width_padding : integer between 0 and 31 Extra padding (in pixels) added to the left and right sides of the button. height_padding : integer between 0 and 31 Extra padding (in pixels) added to the top and bottom of the button. view : traitsui View, optional An optional View to display when the button is clicked. """ def __init__( self, label="", image=None, values_trait=None, style="button", orientation="vertical", width_padding=7, height_padding=5, view=None, **metadata ): self.label = label self.values_trait = values_trait self.image = image self.style = style self.orientation = orientation self.width_padding = width_padding self.height_padding = height_padding self.view = view super().__init__(**metadata) def create_editor(self): from traitsui.api import ButtonEditor editor = ButtonEditor( label=self.label, values_trait=self.values_trait, image=self.image, style=self.style, orientation=self.orientation, width_padding=self.width_padding, height_padding=self.height_padding, view=self.view, ) return editor class ToolbarButton(Button): """ A Button trait type whose UI editor is a toolbar button. This is just a Button trait with different defaults to style it like a toolbar button. Parameters ---------- label : str The label for the button. image : pyface.ImageResource An image to display on the button. style : 'button', 'radio', 'toolbar' or 'checkbox' The style of button to display. orientation : 'horizontal' or 'vertical' The orientation of the label relative to the image. width_padding : integer between 0 and 31 Extra padding (in pixels) added to the left and right sides of the button. height_padding : integer between 0 and 31 Extra padding (in pixels) added to the top and bottom of the button. **metadata Trait metadata for the trait. Attributes ---------- label : str The label for the button. image : pyface.ImageResource An image to display on the button. style : 'button', 'radio', 'toolbar' or 'checkbox' The style of button to display. values_trait : str For a "button" or "toolbar" style, the name of an enum trait whose values will populate a drop-down menu on the button. The selected value will replace the label on the button. orientation : 'horizontal' or 'vertical' The orientation of the label relative to the image. width_padding : integer between 0 and 31 Extra padding (in pixels) added to the left and right sides of the button. height_padding : integer between 0 and 31 Extra padding (in pixels) added to the top and bottom of the button. view : traitsui View, optional An optional View to display when the button is clicked. """ def __init__( self, label="", image=None, style="toolbar", orientation="vertical", width_padding=2, height_padding=2, **metadata ): super().__init__( label, image=image, style=style, orientation=orientation, width_padding=width_padding, height_padding=height_padding, **metadata ) class Either(TraitType): """ A trait type whose value can be any of of a specified list of traits. Parameters ---------- *traits Arguments that define allowable trait values. **metadata Trait metadata for the trait. Attributes ---------- trait_maker : TraitHandler A TraitHandler generated by _TraitMaker from the arguments. """ def __init__(self, *traits, **metadata): self.trait_maker = _TraitMaker( metadata.pop("default", None), *traits, **metadata ) def as_ctrait(self): """ Returns a CTrait corresponding to the trait defined by this class. """ return self.trait_maker.as_ctrait() class _NoneTrait(TraitType): """ Defines a trait that only accepts the None value This is primarily used for supporting ``Union``. """ info_text = "None" default_value = None default_value_type = DefaultValue.constant def __init__(self, **metadata): default_value = metadata.pop("default_value", None) if default_value is not None: raise ValueError("Cannot set default value {} " "for _NoneTrait".format(default_value)) super().__init__(**metadata) def validate(self, obj, name, value): if value is None: return value self.error(obj, name, value) class Union(TraitType): """ Defines a trait whose value can be any of of a specified list of trait types or list of trait type instances or None If the default value is not defined on Union, the default value from the first trait will be used. """ #: The default value type to use. default_value_type = DefaultValue.constant def __init__(self, *traits, **metadata): self.list_ctrait_instances = [] if not traits: traits = (_NoneTrait,) for trait in traits: if trait is None: trait = _NoneTrait ctrait_instance = trait_cast(trait) if ctrait_instance is None: raise ValueError("Union trait declaration expects a trait " "type or an instance of trait type or None," " but got {!r} instead".format(trait)) self.list_ctrait_instances.append(ctrait_instance) # ``Either`` uses 'default' for defining static default values. # Raise if 'default' is found in order to help code migrate to Union if "default" in metadata: raise ValueError( "Union default value should be set via 'default_value', not " "'default'." ) if 'default_value' in metadata: default_value = metadata.pop("default_value") else: first_default_value_type, first_default_value = ( self.list_ctrait_instances[0].default_value()) if first_default_value_type == DefaultValue.constant: default_value = first_default_value else: self.default_value_type = DefaultValue.callable default_value = self._get_default_value super().__init__(default_value, **metadata) def _get_default_value(self, object): return self.list_ctrait_instances[0].default_value_for( object, "") def validate(self, obj, name, value): """ Return the value by the first trait in the list that can validate the assigned value, raise an error if none of them can. """ for trait_type_instance in self.list_ctrait_instances: try: return trait_type_instance.validate(obj, name, value) except TraitError: pass self.error(obj, name, value) def info(self): return " or ".join([ctrait.info() for ctrait in self.list_ctrait_instances]) def inner_traits(self): return tuple(self.list_ctrait_instances) def get_editor(self, trait): from traitsui.api import TextEditor, CompoundEditor the_editors = [x.get_editor() for x in self.list_ctrait_instances] text_editor = TextEditor() count = 0 editors = [] for editor in the_editors: if isinstance(text_editor, editor.__class__): count += 1 if count > 1: continue editors.append(editor) return CompoundEditor(editors=editors) # ------------------------------------------------------------------------------- # 'Symbol' trait: # ------------------------------------------------------------------------------- class Symbol(TraitType): """ A property trait type that refers to a Python object by name. The value set to the trait must be a value of the form ``'[package.package...package.]module[:symbol[([arg1,...,argn])]]'`` which is imported and evaluated to get underlying value. The value returned by the trait is the actual object that this string refers to. The value is cached, so any calls are only evaluated once. .. deprecated:: 6.3.0 This trait type is deprecated, and will be removed in a future version of Traits. """ @deprecated("The Symbol trait type has been deprecated.") def __init__(self, default_value=NoDefaultSpecified, **metadata): super().__init__(default_value=default_value, **metadata) #: A description of the type of value this trait accepts: info_text = ( "an object or a string of the form " "'[package.package...package.]module[:symbol[([arg1,...,argn])]]' " "specifying where to locate the object" ) def get(self, object, name): value = object.__dict__.get(name, Undefined) if value is Undefined: cache = TraitsCache + name ref = object.__dict__.get(cache) if ref is None: object.__dict__[cache] = ref = object.trait( name ).default_value_for(object, name) if isinstance(ref, str): object.__dict__[name] = value = self._resolve(ref) return value def set(self, object, name, value): dict = object.__dict__ old = dict.get(name, Undefined) if isinstance(value, str): dict.pop(name, None) dict[TraitsCache + name] = value object.trait_property_changed(name, old) else: dict[name] = value object.trait_property_changed(name, old, value) def _resolve(self, ref): try: elements = ref.split("(", 1) symbol = import_symbol(elements[0]) if len(elements) == 1: return symbol args = eval("(" + elements[1]) if not isinstance(args, tuple): args = (args,) return symbol(*args) except Exception: raise TraitError( "Could not resolve '%s' into a valid symbol." % ref ) class UUID(TraitType): """ A read-only trait type whose value is a globally unique UUID (type 4). Parameters ---------- can_init : bool Whether the value can be set during object instantiation. Otherwise the UUID is generated automatically. Example ------- Passing `can_init=True` allows the UUID value to be set during object instantiation, e.g.:: class A(HasTraits): id = UUID class B(HasTraits): id = UUID(can_init=True) # TraitError! A(id=uuid.uuid4()) # Okay! B(id=uuid.uuid4()) Note however that in both cases, the UUID trait is set automatically to a `uuid.UUID` instance (assuming none is provided during initialization in the latter case). """ #: A description of the type of value this trait accepts: info_text = "a read-only UUID" def __init__(self, can_init=False, **metadata): super().__init__(None, **metadata) self.can_init = can_init def validate(self, object, name, value): """ Raises an error, since no values can be assigned to the trait. """ if not self.can_init: raise TraitError( "The '%s' trait of %s instance is a read-only " "UUID." % (name, class_of(object)) ) if object.traits_inited(): msg = ("Initializable UUID trait is read-only " "after initialization") raise TraitError(msg) if isinstance(value, uuid.UUID): return value try: # Construct the UUID from a string return uuid.UUID(value) except ValueError: msg = ("The '{}' trait of '{}' expects an RFC 4122-compatible " "UUID value, but '{}' was given") raise TraitError(msg.format(name, type(object).__name__, value)) def get_default_value(self): """ Return a Traits default value tuple for the trait. This uses the _create_uuid method to generate the default value. """ return ( DefaultValue.callable_and_args, (self._create_uuid, (), None), ) # -- Private Methods --------------------------------------------------- def _create_uuid(self): return uuid.uuid4() class WeakRef(Instance): """ A trait type holding a weak reference to an instance of a class. Only a weak reference is maintained to any object assigned to a WeakRef trait. If no other references exist to the assigned value, the value may be garbage collected, in which case the value of the trait becomes None. In all other cases, the value returned by the trait is the original object. Parameters ---------- klass : class, str or instance The object that forms the basis for the trait. If *klass* is omitted, then values must be an instance of HasTraits. If a string, the value will be resolved to a class object at runtime. allow_none : boolean Indicates whether None can be _assigned_. The trait attribute may give a None value if the object referred to has been garbage collected even if allow_none is False. adapt : str How to use the adaptation infrastructure when setting the value. """ def __init__( self, klass="traits.has_traits.HasTraits", allow_none=False, adapt="yes", **metadata ): metadata.setdefault("copy", "ref") super().__init__( klass, allow_none=allow_none, adapt=adapt, module=get_module_name(), **metadata ) def get(self, object, name): value = getattr(object, name + "_", None) if value is not None: return value.value() return None def set(self, object, name, value): old = self.get(object, name) if value is None: object.__dict__[name + "_"] = None else: object.__dict__[name + "_"] = HandleWeakRef(object, name, value) if value is not old: object.trait_property_changed(name, old, value) def resolve_class(self, object, name, value): # fixme: We have to override this method to prevent the 'fast validate' # from being set up, since the trait using this is a 'property' style # trait which is not currently compatible with the 'fast_validate' # style (causes internal Python SystemError messages). klass = self.find_class(self.klass) if klass is None: self.validate_failed(object, name, value) self.klass = klass class Date(TraitType): """ A trait type whose value must be a date. The value must be an instance of :class:`datetime.date`. Note that :class:`datetime.datetime` is a subclass of :class:`datetime.date`, so by default instances of :class:`datetime.datetime` are also permitted. Use ``Date(allow_datetime=False)`` to exclude this possibility. .. deprecated:: 6.3.0 In the future, :class:`datetime.datetime` instances will not be valid values for this trait type unless "allow_datetime=True" is explicitly given. .. deprecated:: 6.3.0 In the future, ``None`` will not be a valid value for this trait type unless "allow_none=True" is explicitly given. Parameters ---------- default_value : datetime.date, optional The default value for this trait. If no default is provided, the default is ``None``. allow_datetime : bool, optional If ``False``, instances of ``datetime.datetime`` are not valid values for this Trait. If ``True``, ``datetime.datetime`` instances are explicitly permitted. If this argument is not given, ``datetime.datetime`` instances will be accepted, but a ``DeprecationWarning`` will be issued; in some future version of Traits, ``datetime.datetime`` instances will not be permitted. allow_none : bool, optional If ``False``, it's not permitted to assign ``None`` to this trait. If ``True``, ``None`` instances are permitted. If this argument is not given, ``None`` instances will be accepted but a ``DeprecationWarning`` will be issued; in some future verison of Traits, ``None`` may no longer be permitted. **metadata: dict Additional metadata. """ #: The default value type to use. default_value_type = DefaultValue.constant def __init__( self, default_value=None, *, allow_datetime=None, allow_none=None, **metadata, ): super().__init__(default_value, **metadata) self.allow_datetime = allow_datetime self.allow_none = allow_none def validate(self, object, name, value): """ Check that the given value is valid date for this trait. """ if value is None: if self.allow_none: return value elif self.allow_none is None: warnings.warn( ( "In the future, None will no longer be accepted by " "this trait type. To allow None and silence this " "warning, use Date(allow_none=True)." ), DeprecationWarning, stacklevel=2, ) return value elif isinstance(value, datetime.datetime): if self.allow_datetime: return value elif self.allow_datetime is None: warnings.warn( ( "In the future, datetime.datetime instances will no " "longer be accepted by this trait type. To accept " "datetimes and silence this warning, use " "Date(allow_datetime=True) or " "Union(Datetime(), Date())." ), DeprecationWarning, stacklevel=2, ) return value elif isinstance(value, datetime.date): return value self.error(object, name, value) def info(self): """ Return text description of this trait. """ if self.allow_datetime or self.allow_datetime is None: datetime_qualifier = "" else: datetime_qualifier = " non-datetime" if self.allow_none or self.allow_none is None: none_qualifier = " or None" else: none_qualifier = "" return f"a{datetime_qualifier} date{none_qualifier}" def create_editor(self): """ Create default editor factory for this trait. """ return date_editor() class Datetime(TraitType): """ A trait type whose value must be a datetime. The value must be an instance of :class:`datetime.datetime`. .. deprecated:: 6.3.0 In the future, ``None`` will not be a valid value for this trait type unless "allow_none=True" is explicitly given. Parameters ---------- default_value : datetime.datetime, optional The default value for this trait. If no default is provided, the default is ``None``. allow_none : bool, optional If ``False``, it's not permitted to assign ``None`` to this trait. If ``True``, ``None`` instances are permitted. If this argument is not given, ``None`` instances will be accepted but a ``DeprecationWarning`` will be issued; in some future verison of Traits, ``None`` may no longer be permitted. **metadata: dict Additional metadata. """ #: The default value type to use. default_value_type = DefaultValue.constant def __init__( self, default_value=None, *, allow_none=None, **metadata, ): super().__init__(default_value, **metadata) self.allow_none = allow_none def validate(self, object, name, value): """ Check that the given value is valid datetime for this trait. """ if value is None: if self.allow_none: return value elif self.allow_none is None: warnings.warn( ( "In the future, None will no longer be accepted by " "this trait type. To allow None and silence this " "warning, use Datetime(allow_none=True)." ), DeprecationWarning, stacklevel=2, ) return value elif isinstance(value, datetime.datetime): return value self.error(object, name, value) def info(self): """ Return text description of this trait. """ if self.allow_none or self.allow_none is None: none_qualifier = " or None" else: none_qualifier = "" return f"a datetime{none_qualifier}" def create_editor(self): """ Create default editor factory for this trait. """ return datetime_editor() class Time(TraitType): """ A trait type whose value must be a time. The value must be an instance of :class:`datetime.time`. .. deprecated:: 6.3.0 In the future, ``None`` will not be a valid value for this trait type unless "allow_none=True" is explicitly given. Parameters ---------- default_value : datetime.time, optional The default value for this trait. If no default is provided, the default is ``None``. allow_none : bool, optional If ``False``, it's not permitted to assign ``None`` to this trait. If ``True``, ``None`` instances are permitted. If this argument is not given, ``None`` instances will be accepted but a ``DeprecationWarning`` will be issued; in some future verison of Traits, ``None`` may no longer be permitted. **metadata: dict Additional metadata. """ #: The default value type to use. default_value_type = DefaultValue.constant def __init__( self, default_value=None, *, allow_none=None, **metadata, ): super().__init__(default_value, **metadata) self.allow_none = allow_none def validate(self, object, name, value): """ Check that the given value is valid time for this trait. """ if value is None: if self.allow_none: return value elif self.allow_none is None: warnings.warn( ( "In the future, None will no longer be accepted by " "this trait type. To allow None and silence this " "warning, use Time(allow_none=True)." ), DeprecationWarning, stacklevel=2, ) return value elif isinstance(value, datetime.time): return value self.error(object, name, value) def info(self): """ Return text description of this trait. """ if self.allow_none or self.allow_none is None: none_qualifier = " or None" else: none_qualifier = "" return f"a time{none_qualifier}" def create_editor(self): """ Create default editor factory for this trait. """ return time_editor() # Predefined, reusable trait instances # Everything from this point onwards is deprecated, and has a simple # drop-in replacement. #: A trait whose value must support a specified protocol. This is #: an alias for :class:`Supports`. Use ``Supports`` instead. AdaptedTo = Supports #: A trait whose value must be a (Unicode) string. This is an alias for #: :class:`BaseStr`. Use ``BaseStr`` instead. BaseUnicode = BaseStr #: A trait whose value must be a (Unicode) string, using a C-level #: fast validator. This is an alias for :class:`Str`. Use ``Str`` instead. Unicode = Str #: A trait whose value must be a (Unicode) string and which supports #: coercions of non-string values to string. This is #: an alias for :class:`BaseCStr`. Use ``BaseCStr`` instead. BaseCUnicode = BaseCStr #: A trait whose value must be a (Unicode) string and which supports #: coercions of non-string values to string, using a C-level fast validator. #: This is an alias for :class:`CStr`. Use ``CStr`` instead. CUnicode = CStr #: A trait whose value must be an integer. This is an alias for #: :class:`BaseInt`. Use ``BaseInt`` instead. BaseLong = BaseInt #: A trait whose value must be an integer, using a C-level fast validator. #: This is an alias for :class:`Int`. Use ``Int`` instead. Long = Int #: A trait whose value must be an integer and which supports coercions #: of non-integer values to integer. This is an alias for #: :class:`BaseCInt`. Use ``BaseCInt`` instead. BaseCLong = BaseCInt #: A trait whose value must be an integer and which supports coercions #: of non-integer values to integer, using a C-level fast validator. #: This is an alias for :class:`CInt`. Use ``CInt`` instead. CLong = CInt #: Synonym for Bool; default value is ``False``. This trait type is #: deprecated. Use ``Bool(False)`` or ``Bool()`` instead. false = Bool #: Boolean values only; default value is ``True``. This trait type is #: deprecated. Use ``Bool(True)`` instead. true = Bool(True) #: Allows any value to be assigned; no type-checking is performed. #: Default value is ``Undefined``. This trait type is deprecated. Use #: ``Any(Undefined)`` instead. undefined = Any(Undefined) # -- List Traits -------------------------------------------------------------- #: List of integer values; default value is ``[]``. This trait type is #: deprecated. Use ``List(Int)`` instead. ListInt = List(int) #: List of float values; default value is ``[]``. This trait type is #: deprecated. Use ``List(Float)`` instead. ListFloat = List(float) #: List of string values; default value is ``[]``. This trait type is #: deprecated. Use ``List(Str)`` instead. ListStr = List(str) #: List of string values; default value is ``[]``. This trait type is #: deprecated. Use ``List(Str)`` instead. ListUnicode = List(str) #: List of complex values; default value is ``[]``. This trait type is #: deprecated. Use ``List(Complex)`` instead. ListComplex = List(complex) #: List of Boolean values; default value is ``[]``. This trait type is #: deprecated. Use ``List(Bool)`` instead. ListBool = List(bool) #: List of function values; default value is ``[]``. This trait type is #: deprecated. Use ``List(Instance(types.FunctionType, allow_none=False))`` #: instead. ListFunction = List(FunctionType) #: List of method values; default value is ``[]``. This trait type is #: deprecated. Use ``List(Instance(types.MethodType, allow_none=False))`` #: instead. ListMethod = List(MethodType) #: List of container type values; default value is ``[]``. This trait type is #: deprecated. Use ``List(This(allow_none=False))`` instead. ListThis = List(This(allow_none=False)) # -- Dictionary Traits -------------------------------------------------------- #: Only a dictionary with strings as keys can be assigned; only string keys #: can be inserted. The default value is {}. This trait type is deprecated. Use #: ``Dict(Str, Any)`` instead. DictStrAny = Dict(str, Any) #: Only a dictionary mapping strings to strings can be assigned; only string #: keys with string values can be inserted. The default value is {}. This trait #: type is deprecated. Use ``Dict(Str, Str)`` instead. DictStrStr = Dict(str, str) #: Only a dictionary mapping strings to integers can be assigned; only string #: keys with integer values can be inserted. The default value is {}. This #: trait type is deprecated. Use ``Dict(Str, Int)`` instead. DictStrInt = Dict(str, int) #: Only a dictionary mapping strings to floats can be assigned; only string #: keys with float values can be inserted. The default value is {}. This trait #: type is deprecated. Use ``Dict(Str, Float)`` instead. DictStrFloat = Dict(str, float) #: Only a dictionary mapping strings to booleans can be assigned; only string #: keys with boolean values can be inserted. The default value is {}. This #: trait type is deprecated. Use ``Dict(Str, Bool)`` instead. DictStrBool = Dict(str, bool) #: Only a dictionary mapping strings to lists can be assigned; only string keys #: with list values can be inserted. The default value is {}. This trait type #: is deprecated. Use ``Dict(Str, List)`` instead. DictStrList = Dict(str, list) traits-6.3.2/traits/traits.py000066400000000000000000000640771414270267200162410ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Defines the 'core' traits for the Traits package. A trait is a type definition that can be used for normal Python object attributes, giving the attributes some additional characteristics: Initialization: Traits have predefined values that do not need to be explicitly initialized in the class constructor or elsewhere. Validation: Trait attributes have flexible, type-checked values. Delegation: Trait attributes' values can be delegated to other objects. Notification: Trait attributes can automatically notify interested parties when their values change. Visualization: Trait attributes can automatically construct (automatic or programmer-defined) user interfaces that allow their values to be edited or displayed) .. note:: 'trait' is a synonym for 'property', but is used instead of the word 'property' to differentiate it from the Python language 'property' feature. """ from types import FunctionType, MethodType import warnings from .constants import ( ComparisonMode, DefaultValue, TraitKind, ) from .ctrait import CTrait from .trait_errors import TraitError from .trait_base import ( SequenceTypes, TypeTypes, add_article, ) from .trait_converters import ( trait_cast, check_trait as try_trait_cast, ) from .trait_handler import TraitHandler from .trait_type import ( _infer_default_value_type, _read_only, _write_only, ) from .trait_handlers import ( TraitInstance, TraitFunction, TraitCoerceType, TraitCastType, TraitEnum, TraitCompound, TraitMap, _undefined_get, _undefined_set, ) from .trait_factory import ( TraitFactory, ) from .util.deprecated import deprecated # Constants NoneType = type(None) # Python 3's types does not include NoneType ConstantTypes = (NoneType, int, float, complex, str) PythonTypes = ( str, int, float, complex, list, tuple, dict, FunctionType, MethodType, type, NoneType, ) CallableTypes = (FunctionType, MethodType) TraitTypes = (TraitHandler, CTrait) DefaultValues = { str: "", int: 0, float: 0.0, complex: 0j, list: [], tuple: (), dict: {}, bool: False, } # This function is needed when unpickling historical pickles (pickles # created on versions of Traits prior to 6.0). It can be removed when # there's no longer any need to support pickles generated on older # versions of Traits. def __newobj__(cls, *args): """ Unpickles new-style objects. """ return cls.__new__(cls, *args) # --- 'instance' traits ------------------------------------------------------- class _InstanceArgs(object): def __init__(self, factory, args, kw): self.args = (factory,) + args self.kw = kw # --- 'creates a run-time default value' -------------------------------------- class Default(object): """ Generates a value the first time it is accessed. A Default object can be used anywhere a default trait value would normally be specified, to generate a default value dynamically. """ def __init__(self, func=None, args=(), kw=None): self.default_value = (func, args, kw) def Trait(*value_type, **metadata): """ Creates a trait definition. This function accepts a variety of forms of parameter lists: +-------------------+---------------+-------------------------------------+ | Format | Example | Description | +===================+===============+=====================================+ | Trait(*default*) | Trait(150.0) | The type of the trait is inferred | | | | from the type of the default value, | | | | which must be in *ConstantTypes*. | +-------------------+---------------+-------------------------------------+ | Trait(*default*, | Trait(None, | The trait accepts any of the | | *other1*, | 0, 1, 2, | enumerated values, with the first | | *other2*, ...) | 'many') | value being the default value. The | | | | values must be of types in | | | | *ConstantTypes*, but they need not | | | | be of the same type. The *default* | | | | value is not valid for assignment | | | | unless it is repeated later in the | | | | list. | +-------------------+---------------+-------------------------------------+ | Trait([*default*, | Trait([None, | Similar to the previous format, but | | *other1*, | 0, 1, 2, | takes an explicit list or a list | | *other2*, ...]) | 'many']) | variable. | +-------------------+---------------+-------------------------------------+ | Trait(*type*) | Trait(Int) | The *type* parameter must be a name | | | | of a Python type (see | | | | *PythonTypes*). Assigned values | | | | must be of exactly the specified | | | | type; no casting or coercion is | | | | performed. The default value is the | | | | appropriate form of zero, False, | | | | or emtpy string, set or sequence. | +-------------------+---------------+-------------------------------------+ | Trait(*class*) |:: | Values must be instances of *class* | | | | or of a subclass of *class*. The | | | class MyClass:| default value is None, but None | | | pass | cannot be assigned as a value. | | | foo = Trait( | | | | MyClass) | | +-------------------+---------------+-------------------------------------+ | Trait(None, |:: | Similar to the previous format, but | | *class*) | | None *can* be assigned as a value. | | | class MyClass:| | | | pass | | | | foo = Trait( | | | | None, MyClass)| | +-------------------+---------------+-------------------------------------+ | Trait(*instance*) |:: | Values must be instances of the | | | | same class as *instance*, or of a | | | class MyClass:| subclass of that class. The | | | pass | specified instance is the default | | | i = MyClass() | value. | | | foo = | | | | Trait(i) | | +-------------------+---------------+-------------------------------------+ | Trait(*handler*) | Trait( | Assignment to this trait is | | | TraitEnum ) | validated by an object derived from | | | | **traits.TraitHandler**. | +-------------------+---------------+-------------------------------------+ | Trait(*default*, | Trait(0.0, 0.0| This is the most general form of | | { *type* | | 'stuff', | the function. The notation: | | *constant* | | TupleType) | ``{...|...|...}+`` means a list of | | *dict* | *class* || | one or more of any of the items | | *function* | | | listed between the braces. Thus, the| | *handler* | | | most general form of the function | | *trait* }+ ) | | consists of a default value, | | | | followed by one or more of several | | | | possible items. A trait defined by | | | | multiple items is called a | | | | "compound" trait. | +-------------------+---------------+-------------------------------------+ All forms of the Trait function accept both predefined and arbitrary keyword arguments. The value of each keyword argument becomes bound to the resulting trait object as the value of an attribute having the same name as the keyword. This feature lets you associate metadata with a trait. The following predefined keywords are accepted: desc : str Describes the intended meaning of the trait. It is used in exception messages and fly-over help in user interfaces. label : str Provides a human-readable name for the trait. It is used to label user interface editors for traits. editor : traits.api.Editor Instance of a subclass Editor object to use when creating a user interface editor for the trait. See the "Traits UI User Guide" for more information on trait editors. comparison_mode : int Indicates when trait change notifications should be generated based upon the result of comparing the old and new values of a trait assignment. Possible values come from the ``ComparisonMode`` enum: * 0 (none): The values are not compared and a trait change notification is generated on each assignment. * 1 (identity): A trait change notification is generated if the old and new values are not the same object. * 2 (equality): A trait change notification is generated if the old and new values are not equal using Python's standard equality testing. This is the default. """ return _TraitMaker(*value_type, **metadata).as_ctrait() class _TraitMaker(object): # Ctrait type map for special trait types: type_map = {"event": TraitKind.event, "constant": TraitKind.constant} def __init__(self, *value_type, **metadata): metadata.setdefault("type", "trait") self.define(*value_type, **metadata) def define(self, *value_type, **metadata): """ Define the trait. """ default_value_type = DefaultValue.unspecified default_value = handler = clone = None if len(value_type) > 0: default_value = value_type[0] value_type = value_type[1:] if (len(value_type) == 0) and ( type(default_value) in SequenceTypes ): default_value, value_type = default_value[0], default_value if len(value_type) == 0: default_value = try_trait_cast(default_value) if default_value in PythonTypes: handler = TraitCoerceType(default_value) default_value = DefaultValues.get(default_value) elif isinstance(default_value, CTrait): clone = default_value default_value_type, default_value = clone.default_value() metadata["type"] = clone.type elif isinstance(default_value, TraitHandler): handler = default_value default_value = None else: typeValue = type(default_value) if typeValue in TypeTypes: handler = TraitCastType(typeValue) else: metadata.setdefault( "instance_handler", "_instance_changed_handler" ) handler = TraitInstance(default_value) if default_value is handler.aClass: default_value = DefaultValues.get(default_value) else: enum = [] other = [] map = {} self.do_list(value_type, enum, map, other) if ((len(enum) == 1) and (enum[0] is None)) and ( (len(other) == 1) and isinstance(other[0], TraitInstance) ): enum = [] other[0].allow_none() metadata.setdefault( "instance_handler", "_instance_changed_handler" ) if len(enum) > 0: if ((len(map) + len(other)) == 0) and ( default_value not in enum ): enum.insert(0, default_value) other.append(TraitEnum(enum)) if len(map) > 0: other.append(TraitMap(map)) if len(other) == 0: handler = TraitHandler() elif len(other) == 1: handler = other[0] if isinstance(handler, CTrait): clone, handler = handler, None metadata["type"] = clone.type elif isinstance(handler, TraitInstance): metadata.setdefault( "instance_handler", "_instance_changed_handler" ) if default_value is None: handler.allow_none() elif isinstance(default_value, _InstanceArgs): default_value_type = ( DefaultValue.callable_and_args ) default_value = ( handler.create_default_value, default_value.args, default_value.kw, ) elif (len(enum) == 0) and (len(map) == 0): aClass = handler.aClass typeValue = type(default_value) if typeValue is dict: default_value_type = ( DefaultValue.callable_and_args ) default_value = (aClass, (), default_value) elif not isinstance(default_value, aClass): if typeValue is not tuple: default_value = (default_value,) default_value_type = ( DefaultValue.callable_and_args ) default_value = (aClass, default_value, None) else: for i, item in enumerate(other): if isinstance(item, CTrait): if item.type != "trait": raise TraitError( "Cannot create a complex " "trait containing %s trait." % add_article(item.type) ) handler = item.handler if handler is None: break other[i] = handler else: handler = TraitCompound(other) # Save the results: self.handler = handler self.clone = clone if default_value_type < 0: if isinstance(default_value, Default): default_value_type = DefaultValue.callable_and_args default_value = default_value.default_value else: if (handler is None) and (clone is not None): handler = clone.handler if handler is not None: default_value_type = handler.default_value_type if default_value_type < 0: try: default_value = handler.validate( None, "", default_value ) except: pass if default_value_type < 0: default_value_type = _infer_default_value_type( default_value ) self.default_value_type = default_value_type self.default_value = default_value self.metadata = metadata.copy() def do_list(self, list, enum, map, other): """ Determine the correct TraitHandler for each item in a list. """ for item in list: if item in PythonTypes: other.append(TraitCoerceType(item)) else: item = try_trait_cast(item) typeItem = type(item) if typeItem in ConstantTypes: enum.append(item) elif typeItem in SequenceTypes: self.do_list(item, enum, map, other) elif typeItem is dict: map.update(item) elif typeItem in CallableTypes: other.append(TraitFunction(item)) elif isinstance(item, TraitTypes): other.append(item) else: other.append(TraitInstance(item)) def as_ctrait(self): """ Return a properly initialized 'CTrait' instance. """ metadata = self.metadata trait = CTrait( self.type_map.get(metadata.get("type"), TraitKind.trait)) clone = self.clone if clone is not None: trait.clone(clone) if clone.__dict__ is not None: trait.__dict__ = clone.__dict__.copy() trait.set_default_value(self.default_value_type, self.default_value) handler = self.handler if handler is not None: trait.handler = handler validate = getattr(handler, "fast_validate", None) if validate is None: validate = handler.validate trait.set_validate(validate) post_setattr = getattr(handler, "post_setattr", None) if post_setattr is not None: trait.post_setattr = post_setattr trait.is_mapped = handler.is_mapped rich_compare = metadata.get("rich_compare") if rich_compare is not None: # Ref: enthought/traits#602 warnings.warn( "The 'rich_compare' metadata has been deprecated. Please " "use the 'comparison_mode' metadata instead. In a future " "release, rich_compare will have no effect.", DeprecationWarning, stacklevel=4, ) if rich_compare: trait.comparison_mode = ComparisonMode.equality else: trait.comparison_mode = ComparisonMode.identity comparison_mode = metadata.pop("comparison_mode", None) if comparison_mode is not None: trait.comparison_mode = comparison_mode if len(metadata) > 0: if trait.__dict__ is None: trait.__dict__ = metadata else: trait.__dict__.update(metadata) return trait def Property( fget=None, fset=None, fvalidate=None, force=False, handler=None, trait=None, **metadata ): """ Returns a trait whose value is a Python property. If no getter, setter or validate functions are specified (and **force** is not True), it is assumed that they are defined elsewhere on the class whose attribute this trait is assigned to. For example:: class Bar(HasTraits): # A float traits Property that should be always positive. foo = Property(Float) # Shadow trait attribute _foo = Float def _set_foo(self,x): self._foo = x def _validate_foo(self, x): if x <= 0: raise TraitError( 'foo property should be a positive number') return x def _get_foo(self): return self._foo You can use the **observe** metadata attribute to indicate that the property depends on the value of another trait. The value of **observe** follows the same signature as the **expression** parameter in ``HasTraits.observe``. The property will fire a trait change notification if any of the traits specified by **observe** change. For example:: class Wheel(Part): axle = Instance(Axle) position = Property(observe='axle.chassis.position') For details of the extended trait name syntax, refer to the observe() method of the HasTraits class. Parameters ---------- fget : function The "getter" function for the property. fset : function The "setter" function for the property. fvalidate : function The validation function for the property. The method should return the value to set or raise TraitError if the new value is not valid. force : bool Indicates whether to use only the function definitions specified by **fget** and **fset**, and not look elsewhere on the class. handler : function A trait handler function for the trait. trait : Trait or value A trait definition or a value that can be converted to a trait that constrains the values of the property trait. """ metadata["type"] = "property" # If no parameters specified, must be a forward reference (if not forced): if (not force) and (fset is None): sum = ( (fget is not None) + (fvalidate is not None) + (trait is not None) ) if sum <= 1: if sum == 0: return ForwardProperty(metadata) handler = None if fget is not None: trait = fget if trait is not None: trait = trait_cast(trait) if trait is not None: fvalidate = handler = trait.handler if fvalidate is not None: fvalidate = handler.validate if (fvalidate is not None) or (trait is not None): if "editor" not in metadata: if (trait is not None) and (trait.editor is not None): metadata["editor"] = trait.editor return ForwardProperty(metadata, fvalidate, handler) if fget is None: metadata["transient"] = True if fset is None: fget = _undefined_get fset = _undefined_set else: fget = _write_only elif fset is None: fset = _read_only metadata["transient"] = True if trait is not None: trait = trait_cast(trait) handler = trait.handler if (fvalidate is None) and (handler is not None): fvalidate = handler.validate if ("editor" not in metadata) and (trait.editor is not None): metadata["editor"] = trait.editor metadata.setdefault("depends_on", getattr(fget, "depends_on", None)) if getattr(fget, "cached_property", False): metadata.setdefault("cached", True) trait = CTrait(TraitKind.property) trait.__dict__ = metadata.copy() trait.property_fields = (fget, fset, fvalidate) trait.handler = handler return trait Property = TraitFactory(Property) class ForwardProperty(object): """ Used to implement Property traits where accessor functions are defined implicitly on the class. """ def __init__(self, metadata, validate=None, handler=None): self.metadata = metadata.copy() self.validate = validate self.handler = handler # Predefined, reusable trait instances # Generic trait with 'object' behavior: generic_trait = CTrait(TraitKind.generic) # User interface related color and font traits @deprecated("'Color' in 'traits' package has been deprecated. " "Use 'Color' from 'traitsui' package instead.") def Color(*args, **metadata): """ Returns a trait whose value must be a GUI toolkit-specific color. .. deprecated:: 6.1.0 ``Color`` trait in this package will be removed in the future. It is replaced by ``Color`` trait in TraitsUI package. """ from traitsui.toolkit_traits import ColorTrait return ColorTrait(*args, **metadata) Color = TraitFactory(Color) @deprecated("'RGBColor' in 'traits' package has been deprecated. " "Use 'RGBColor' from 'traitsui' package instead.") def RGBColor(*args, **metadata): """ Returns a trait whose value must be a GUI toolkit-specific RGB-based color. .. deprecated:: 6.1.0 ``RGBColor`` trait in this package will be removed in the future. It is replaced by ``RGBColor`` trait in TraitsUI package. """ from traitsui.toolkit_traits import RGBColorTrait return RGBColorTrait(*args, **metadata) RGBColor = TraitFactory(RGBColor) @deprecated("'Font' in 'traits' package has been deprecated. " "Use 'Font' from 'traitsui' package instead.") def Font(*args, **metadata): """ Returns a trait whose value must be a GUI toolkit-specific font. .. deprecated:: 6.1.0 ``Font`` trait in this package will be removed in the future. It is replaced by ``Font`` trait in TraitsUI package. """ from traitsui.toolkit_traits import FontTrait return FontTrait(*args, **metadata) Font = TraitFactory(Font) traits-6.3.2/traits/traits_listener.py000066400000000000000000001243641414270267200201420ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Defines classes used to implement and manage various trait listener patterns. """ import re import string import weakref from string import whitespace from types import MethodType from .constants import DefaultValue from .trait_base import Undefined, Uninitialized from .trait_errors import TraitError from .trait_notifiers import TraitChangeNotifyWrapper from .util.weakiddict import WeakIDKeyDict # Constants # The name of the dictionary used to store active listeners TraitsListener = "__traits_listener__" # End of String marker EOS = "\0" # Types of traits that can be listened to ANYTRAIT_LISTENER = "_register_anytrait" SIMPLE_LISTENER = "_register_simple" LIST_LISTENER = "_register_list" DICT_LISTENER = "_register_dict" SET_LISTENER = "_register_set" # Mapping from trait default value types to listener types type_map = { DefaultValue.trait_list_object: LIST_LISTENER, DefaultValue.trait_dict_object: DICT_LISTENER, DefaultValue.trait_set_object: SET_LISTENER, } # Listener types: ANY_LISTENER = 0 SRC_LISTENER = 1 DST_LISTENER = 2 ListenerType = { 0: ANY_LISTENER, 1: DST_LISTENER, 2: DST_LISTENER, 3: SRC_LISTENER, 4: SRC_LISTENER, } # Invalid destination ( object, name ) reference marker (i.e. ambiguous): INVALID_DESTINATION = (None, None) # Regular expressions used by the parser: simple_pat = re.compile(r"^([a-zA-Z_]\w*)(\.|:)([a-zA-Z_]\w*)$") name_pat = re.compile(r"([a-zA-Z_]\w*)\s*(.*)") # Characters valid in a traits name: name_chars = string.ascii_letters + string.digits + "_" # Utility functions def indent(text, first_line=True, n=1, width=4): """ Indent lines of text. Parameters ---------- text : str The text to indent. first_line : bool, optional If False, then the first line will not be indented (default: True). n : int, optional The level of indentation (default: 1). width : int, optional The number of spaces in each level of indentation (default: 4). Returns ------- indented : str """ lines = text.split("\n") if not first_line: first = lines[0] lines = lines[1:] spaces = " " * (width * n) lines2 = [spaces + x for x in lines] if not first_line: lines2.insert(0, first) indented = "\n".join(lines2) return indented # Metadata filters def is_not_none(value): return value is not None def is_none(value): return value is None def not_event(value): return value != "event" class ListenerBase: """ Abstract base class for both ListenerItem and ListenerGroup. """ def set_notify(self, notify): """ Set notify state on this listener. Parameters ---------- notify : bool True if this listener should notify, else False. """ raise NotImplementedError def set_next(self, next): """ Set the child listener for this listener. Parameters ---------- next : ListenerBase The next level (if any) of ListenerBase object to be called when any of our listened to traits is changed: """ raise NotImplementedError def register(self, new): """ Registers new listeners. """ raise NotImplementedError def unregister(self, old): """ Unregisters any existing listeners. """ raise NotImplementedError def handle(self, object, name, old, new): """ Handles a trait change for a simple trait. """ raise NotImplementedError def handle_list(self, object, name, old, new): """ Handles a trait change for a list trait. """ raise NotImplementedError def handle_list_items(self, object, name, old, new): """ Handles a trait change for a list traits items. """ raise NotImplementedError def handle_dict(self, object, name, old, new): """ Handles a trait change for a dictionary trait. """ raise NotImplementedError def handle_dict_items(self, object, name, old, new): """ Handles a trait change for a dictionary traits items. """ raise NotImplementedError class ListenerItem(ListenerBase): """ Listener description for a single item. Parameters ---------- name : str The name of the trait to listen to. metadata_name : str, optional The name of any metadata that must be present (or not present). metadata_defined : bool, optional True if the specified metadata needs to be defined; False if the specified metadata needs to be not defined. handler : ListenerHandler, optional Zero-argument callable that returns the actual handler when called (or Undefined if that handler is no longer available). wrapped_handler_ref : weakref.ref, optional Weak reference to a ListenerNotifyWrapper wrapping the actual handler. dispatch : str The dispatch mechanism to use when invoking the handler. priority : bool, optional True if the handler goes at the beginning of the notification handlers list, else False. next : ListenerBase or None, optional The next level (if any) of ListenerBase object to be called when any of this object's listened-to traits is changed. The default is None. type : int The type of handler being used. One of ANY_LISTENER, SRC_LISTENER, DST_LISTENER. notify : bool, optional True if changes to this item should generate a notification to the handler; False otherwise. The default is True. deferred : bool, optional True if registering listeners for items reachable from this listener item should be deferred until the associated trait is first read or set. is_anytrait : bool, optional True if this is an "anytrait" change listener. False if it creates explicit listeners for each individual trait. is_list_handler : bool, optional True if the associated handler is a special list handler that handles both "foo" and "foo_items" events. False otherwise. """ def __init__( self, *, name, metadata_name="", metadata_defined=True, handler=None, wrapped_handler_ref=None, dispatch, priority=False, next=None, type, notify=True, deferred=False, is_anytrait=False, is_list_handler=False, ): self.name = name self.notify = notify self.handler = handler self.wrapped_handler_ref = wrapped_handler_ref self.dispatch = dispatch self.priority = priority self.deferred = deferred self.type = type self.next = next self.metadata_name = metadata_name self.metadata_defined = metadata_defined self.is_anytrait = is_anytrait self.is_list_handler = is_list_handler self.active = WeakIDKeyDict() self._metadata = None # -- 'ListenerBase' Class Method Implementations -------------------------- def __repr__(self, seen=None): """Returns a string representation of the object. Since the object graph may have cycles, we extend the basic __repr__ API to include a set of objects we've already seen while constructing a string representation. When this method tries to get the repr of a ListenerItem or ListenerGroup, we will use the extended API and build up the set of seen objects. The repr of a seen object will just be ''. """ if seen is None: seen = set() seen.add(self) next_repr = "None" next = self.next if next is not None: if next in seen: next_repr = "" else: next_repr = next.__repr__(seen) return """%s( name = %r, metadata_name = %r, metadata_defined = %r, is_anytrait = %r, dispatch = %r, notify = %r, is_list_handler = %r, type = %r, next = %s, )""" % ( self.__class__.__name__, self.name, self.metadata_name, self.metadata_defined, self.is_anytrait, self.dispatch, self.notify, self.is_list_handler, self.type, indent(next_repr, False), ) def set_notify(self, notify): """ Set notify state on this listener. Parameters ---------- notify : bool True if this listener should notify, else False. """ self.notify = notify def set_next(self, next): """ Set the child listener for this one. Parameters ---------- next : ListenerBase The next level (if any) of ListenerBase object to be called when any of our listened to traits is changed: """ self.next = next def register(self, new): """ Registers new listeners. """ # Make sure we actually have an object to set listeners on and that it # has not already been registered (cycle breaking): if (new is None) or (new is Undefined) or (new in self.active): return INVALID_DESTINATION # Create a dictionary of {name: trait_values} that match the object's # definition for the 'new' object: name = self.name last = name[-1:] if last == "*": # Handle the special case of an 'anytrait' change listener: if self.is_anytrait: try: self.active[new] = [("", ANYTRAIT_LISTENER)] return self._register_anytrait(new, "", False) except TypeError: # This error can occur if 'new' is a list or other object # for which a weakref cannot be created as the dictionary # key for 'self.active': return INVALID_DESTINATION # Handle trait matching based on a common name prefix and/or # matching trait metadata: metadata = self._metadata if metadata is None: self._metadata = metadata = {"type": not_event} if self.metadata_name != "": if self.metadata_defined: metadata[self.metadata_name] = is_not_none else: metadata[self.metadata_name] = is_none # Get all object traits with matching metadata: names = new.trait_names(**metadata) # If a name prefix was specified, filter out only the names that # start with the specified prefix: name = name[:-1] if name != "": n = len(name) names = [aname for aname in names if name == aname[:n]] # Create the dictionary of selected traits: bt = new.base_trait traits = dict([(name, bt(name)) for name in names]) # Handle any new traits added dynamically to the object: new.on_trait_change(self._new_trait_added, "trait_added") else: # Determine if the trait is optional or not: optional = last == "?" if optional: name = name[:-1] # Else, no wildcard matching, just get the specified trait: trait = new.base_trait(name) # Try to get the object trait: if trait is None: # Raise an error if trait is not defined and not optional: # fixme: Properties which are lists don't implement the # '..._items' sub-trait, which can cause a failure here when # used with an editor that sets up listeners on the items... if not optional: raise TraitError( "'%s' object has no '%s' trait" % (new.__class__.__name__, name) ) # Otherwise, just skip it: traits = {} else: # Create a result dictionary containing just the single trait: traits = {name: trait} # For each item, determine its type (simple, list, dict): self.active[new] = active = [] for name, trait in traits.items(): # Determine whether the trait type is simple, list, set or # dictionary: type = SIMPLE_LISTENER handler = trait.handler if handler is not None: type = type_map.get( handler.default_value_type, SIMPLE_LISTENER ) # Add the name and type to the list of traits being registered: active.append((name, type)) # Set up the appropriate trait listeners on the object for the # current trait: value = getattr(self, type)(new, name, False) if len(traits) == 1: return value return INVALID_DESTINATION def unregister(self, old): """ Unregisters any existing listeners. """ if old is not None and old is not Uninitialized: try: active = self.active.pop(old, None) if active is not None: for name, type in active: getattr(self, type)(old, name, True) except TypeError: # An error can occur if 'old' is a list or other object for # which a weakref cannot be created and used an a key for # 'self.active': pass def handle_simple(self, object, name, old, new): """ Handles a trait change for an intermediate link trait. """ self.next.unregister(old) self.next.register(new) def handle_dst(self, object, name, old, new): """ Handles a trait change for an intermediate link trait when the notification is for the final destination trait. """ self.next.unregister(old) object, name = self.next.register(new) if old is not Uninitialized: if object is None: raise TraitError( "on_trait_change handler signature is " "incompatible with a change to an intermediate trait" ) wh = self.wrapped_handler_ref() if wh is not None: wh(object, name, old, getattr(object, name, Undefined)) def handle_list(self, object, name, old, new): """ Handles a trait change for a list (or set) trait. """ if old is not None and old is not Uninitialized: unregister = self.next.unregister for obj in old: unregister(obj) register = self.next.register for obj in new: register(obj) def handle_list_items(self, object, name, old, new): """ Handles a trait change for items of a list (or set) trait. """ self.handle_list(object, name, new.removed, new.added) def handle_list_items_special(self, object, name, old, new): """ Handles a trait change for items of a list (or set) trait with notification. """ wh = self.wrapped_handler_ref() if wh is not None: wh(object, name, new.removed, new.added) def handle_dict(self, object, name, old, new): """ Handles a trait change for a dictionary trait. """ if old is not Uninitialized: unregister = self.next.unregister for obj in old.values(): unregister(obj) register = self.next.register for obj in new.values(): register(obj) def handle_dict_items(self, object, name, old, new): """ Handles a trait change for items of a dictionary trait. """ self.handle_dict(object, name, new.removed, new.added) if len(new.changed) > 0: # If 'name' refers to the '_items' trait, then remove the '_items' # suffix to get the actual dictionary trait. # # fixme: Is there ever a case where 'name' *won't* refer to the # '_items' trait? if name.endswith("_items"): name = name[: -len("_items")] dict = getattr(object, name) unregister = self.next.unregister register = self.next.register for key, obj in new.changed.items(): unregister(obj) register(dict[key]) def handle_error(self, obj, name, old, new): """ Handles an invalid intermediate trait change to a handler that must be applied to the final destination object.trait. """ if old is not None and old is not Uninitialized: raise TraitError( "on_trait_change handler signature is " "incompatible with a change to an intermediate trait" ) # -- Private Methods ------------------------------------------------------ def _register_anytrait(self, object, name, remove): """ Registers any 'anytrait' listener. """ handler = self.handler() if handler is not Undefined: object._on_trait_change( handler, remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) return (object, name) def _register_simple(self, object, name, remove): """ Registers a handler for a simple trait. """ next = self.next if next is None: handler = self.handler() if handler is not Undefined: object._on_trait_change( handler, name, remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) return (object, name) tl_handler = self.handle_simple if self.notify: if self.type == DST_LISTENER: if self.dispatch != "same": raise TraitError( "Trait notification dispatch type '%s' " "is not compatible with handler signature and " "extended trait name notification style" % self.dispatch ) tl_handler = self.handle_dst else: handler = self.handler() if handler is not Undefined: object._on_trait_change( handler, name, remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) object._on_trait_change( tl_handler, name, remove=remove, dispatch="extended", priority=self.priority, target=self._get_target(), ) if remove: return next.unregister(getattr(object, name)) if not self.deferred or name in object.__dict__: # Sometimes, the trait may already be assigned. This can happen # when there are chains of dynamic initializers and 'delegate' # notifications. If 'trait_a' and 'trait_b' have dynamic # initializers and 'trait_a's initializer creates 'trait_b', *and* # we have a DelegatesTo trait that delegates to 'trait_a', then the # listener that implements the delegate will create 'trait_a' and # thus 'trait_b'. If we are creating an extended trait change # listener on 'trait_b.something', and the 'trait_a' delegate # listeners just happen to get hooked up before this one, then # 'trait_b' will have been initialized already, and the # registration that we are deferring will never happen. return next.register(getattr(object, name)) return (object, name) def _register_list(self, object, name, remove): """ Registers a handler for a list trait. """ next = self.next if next is None: handler = self.handler() if handler is not Undefined: object._on_trait_change( handler, name, remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) if self.is_list_handler: object._on_trait_change( self.handle_list_items_special, name + "_items", remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) elif self.type == ANY_LISTENER: object._on_trait_change( handler, name + "_items", remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) return (object, name) tl_handler = self.handle_list tl_handler_items = self.handle_list_items if self.notify: if self.type == DST_LISTENER: tl_handler = tl_handler_items = self.handle_error else: handler = self.handler() if handler is not Undefined: object._on_trait_change( handler, name, remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) if self.is_list_handler: object._on_trait_change( self.handle_list_items_special, name + "_items", remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) elif self.type == ANY_LISTENER: object._on_trait_change( handler, name + "_items", remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) object._on_trait_change( tl_handler, name, remove=remove, dispatch="extended", priority=self.priority, target=self._get_target(), ) object._on_trait_change( tl_handler_items, name + "_items", remove=remove, dispatch="extended", priority=self.priority, target=self._get_target(), ) if remove: handler = next.unregister elif self.deferred: return INVALID_DESTINATION else: handler = next.register for obj in getattr(object, name): handler(obj) return INVALID_DESTINATION # Handle 'sets' the same as 'lists': # Note: Currently the behavior of sets is almost identical to that of # lists, so we are able to share the same code for both. This includes some # 'duck typing' that occurs with the TraitListEvent and TraitSetEvent, that # define 'removed' and 'added' attributes that behave similarly enough # (from the point of view of this module) that they can be treated as # equivalent. If the behavior of sets ever diverges from that of lists, # then this code may need to be changed. _register_set = _register_list def _register_dict(self, object, name, remove): """ Registers a handler for a dictionary trait. """ next = self.next if next is None: handler = self.handler() if handler is not Undefined: object._on_trait_change( handler, name, remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) if self.type == ANY_LISTENER: object._on_trait_change( handler, name + "_items", remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) return (object, name) tl_handler = self.handle_dict tl_handler_items = self.handle_dict_items if self.notify: if self.type == DST_LISTENER: tl_handler = tl_handler_items = self.handle_error else: handler = self.handler() if handler is not Undefined: object._on_trait_change( handler, name, remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) if self.type == ANY_LISTENER: object._on_trait_change( handler, name + "_items", remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) object._on_trait_change( tl_handler, name, remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) object._on_trait_change( tl_handler_items, name + "_items", remove=remove, dispatch=self.dispatch, priority=self.priority, target=self._get_target(), ) if remove: handler = next.unregister elif self.deferred: return INVALID_DESTINATION else: handler = next.register for obj in getattr(object, name).values(): handler(obj) return INVALID_DESTINATION def _new_trait_added(self, object, name, new_trait): """ Handles new traits being added to an object being monitored. """ # Set if the new trait matches our prefix and metadata: if new_trait.startswith(self.name[:-1]): trait = object.base_trait(new_trait) for meta_name, meta_eval in self._metadata.items(): if not meta_eval(getattr(trait, meta_name)): return # Determine whether the trait type is simple, list, set or # dictionary: type = SIMPLE_LISTENER handler = trait.handler if handler is not None: type = type_map.get(handler.default_value_, SIMPLE_LISTENER) # Add the name and type to the list of traits being registered: self.active[object].append((new_trait, type)) # Set up the appropriate trait listeners on the object for the # new trait: getattr(self, type)(object, new_trait, False) def _get_target(self): """ Get the target object from the ListenerNotifyWrapper. """ target = None lnw = self.wrapped_handler_ref() if lnw is not None: target_ref = getattr(lnw, "object", None) if target_ref is not None: target = target_ref() return target class ListenerGroup(ListenerBase): """ Listener description for a collection of items. The ListenerParser produces a ListenerGroup rather than a ListenerItem when parsing strings like ``[abc,def]``. Parameters ---------- items : list List of ListenerItem objects representing the components of the group. """ # -- 'ListenerBase' Class Method Implementations -------------------------- def __init__(self, *, items): self.items = items self.next = None def __repr__(self, seen=None): """Returns a string representation of the object. Since the object graph may have cycles, we extend the basic __repr__ API to include a set of objects we've already seen while constructing a string representation. When this method tries to get the repr of a ListenerItem or ListenerGroup, we will use the extended API and build up the set of seen objects. The repr of a seen object will just be ''. """ if seen is None: seen = set() seen.add(self) lines = ["%s(items = [" % self.__class__.__name__] for item in self.items: lines.extend(indent(item.__repr__(seen), True).split("\n")) lines[-1] += "," lines.append("])") return "\n".join(lines) def set_notify(self, notify): """ Set notify state on this listener. Parameters ---------- notify : bool True if this listener should notify, else False. """ for item in self.items: item.set_notify(notify) def set_next(self, next): """ Set the child listener for this one. Parameters ---------- next : ListenerBase The next level (if any) of ListenerBase object to be called when any of our listened to traits is changed: """ for item in self.items: item.set_next(next) self.next = next if self.items else None def register(self, new): """ Registers new listeners. """ for item in self.items: item.register(new) return INVALID_DESTINATION def unregister(self, old): """ Unregisters any existing listeners. """ for item in self.items: item.unregister(old) class ListenerParser: # -- Property Implementations --------------------------------------------- @property def next(self): """The next character from the string being parsed.""" index = self.index self.index += 1 if index >= self.len_text: return EOS return self.text[index] @property def backspace(self): """Backspaces to the last character processed.""" self.index = max(0, self.index - 1) @property def skip_ws(self): """The next non-whitespace character.""" while True: c = self.next if c not in whitespace: return c @property def name(self): """The next Python attribute name within the string.""" match = name_pat.match(self.text, self.index - 1) if match is None: return "" self.index = match.start(2) return match.group(1) # -- object Method Overrides ---------------------------------------------- def __init__( self, text, *, handler=None, wrapped_handler_ref=None, dispatch="", priority=False, deferred=False, handler_type=ANY_LISTENER, ): #: The text being parsed. self.text = text #: The length of the string being parsed. self.len_text = len(self.text) #: The current parse index within the string. self.index = 0 #: The handler to be called when any listened-to trait is changed. self.handler = handler #: A weakref 'wrapped' version of 'handler'. self.wrapped_handler_ref = wrapped_handler_ref #: The dispatch mechanism to use when invoking the handler. self.dispatch = dispatch #: Does the handler go at the beginning (True) or end (False) of the #: notification handlers list? self.priority = priority #: The parsed listener. self.listener = self.parse(deferred, handler_type) # -- Private Methods ------------------------------------------------------ def parse(self, deferred, handler_type): """ Parses the text and returns the appropriate collection of ListenerBase objects described by the text. Parameters ---------- deferred : bool Should registering listeners for items reachable from this listener item be deferred until the associated trait is first read or set? handler_type : int The type of handler being used; one of {ANY_LISTENER, SRC_LISTENER, DST_LISTENER}. """ # Try a simple case of 'name1.name2'. The simplest case of a single # Python name never triggers this parser, so we don't try to make that # a shortcut too. Whitespace should already have been stripped from the # start and end. if self.text.strip().endswith(","): self.error("Error parsing name. Trailing ',' is not allowed") # TODO: The use of regexes should be used throughout all of the parsing # functions to speed up all aspects of parsing. match = simple_pat.match(self.text) if match is not None: return ListenerItem( name=match.group(1), notify=match.group(2) == ".", next=ListenerItem( name=match.group(3), handler=self.handler, wrapped_handler_ref=self.wrapped_handler_ref, dispatch=self.dispatch, priority=self.priority, # Bug-for-bug compatibility with old behaviour: don't # propagate the 'deferred' or 'handler_type' values for the # child item. Ref: enthought/traits#537. deferred=False, type=ANY_LISTENER, ), handler=self.handler, wrapped_handler_ref=self.wrapped_handler_ref, dispatch=self.dispatch, priority=self.priority, deferred=deferred, type=handler_type, ) return self.parse_group( terminator=EOS, deferred=deferred, handler_type=handler_type, ) def parse_group(self, *, terminator, deferred, handler_type): """ Parses the contents of a group. Parameters ---------- terminator : str or EOS Character on which to halt parsing of this item. deferred : bool Should registering listeners for items reachable from this listener item be deferred until the associated trait is first read or set? handler_type : int The type of handler being used; one of {ANY_LISTENER, SRC_LISTENER, DST_LISTENER}. """ items = [] while True: items.append( self.parse_item( terminator=terminator, deferred=deferred, handler_type=handler_type, ) ) c = self.skip_ws if c == terminator: break if c != ",": if terminator == EOS: self.error("Expected ',' or end of string") else: self.error("Expected ',' or '%s'" % terminator) if len(items) == 1: return items[0] return ListenerGroup(items=items) def parse_item(self, *, terminator, deferred, handler_type): """ Parses a single, complete listener item or group string. Parameters ---------- terminator : str or EOS Character on which to halt parsing of this item. deferred : bool Should registering listeners for items reachable from this listener item be deferred until the associated trait is first read or set? handler_type : int The type of handler being used; one of {ANY_LISTENER, SRC_LISTENER, DST_LISTENER}. """ c = self.skip_ws if c == "[": result = self.parse_group( terminator="]", deferred=deferred, handler_type=handler_type, ) c = self.skip_ws else: name = self.name if name != "": c = self.next result = ListenerItem( name=name, handler=self.handler, wrapped_handler_ref=self.wrapped_handler_ref, dispatch=self.dispatch, priority=self.priority, deferred=deferred, type=handler_type, ) if c in "+-": result.name += "*" result.metadata_defined = c == "+" cn = self.skip_ws result.metadata_name = metadata = self.name if metadata != "": cn = self.skip_ws result.is_anytrait = ( (c == "-") and (name == "") and (metadata == "") ) c = cn if result.is_anytrait and ( not ( (c == terminator) or ((c == ",") and (terminator == "]")) ) ): self.error("Expected end of name") elif c == "?": if len(name) == 0: self.error("Expected non-empty name preceding '?'") result.name += "?" c = self.skip_ws cycle = c == "*" if cycle: c = self.skip_ws if c in ".:": result.set_notify(c == ".") # Bug-for-bug compatibility with old behaviour: don't propagate the # 'deferred' or 'handler_type' values for the child item. # Ref: enthought/traits#537. next = self.parse_item( terminator=terminator, deferred=False, handler_type=ANY_LISTENER, ) if cycle: last = result while last.next is not None: last = last.next lg = ListenerGroup(items=[next, result]) last.set_next(lg) result = lg else: result.set_next(next) return result if c == "[": is_closing_bracket = self.skip_ws == "]" next_char = self.skip_ws item_complete = next_char == terminator or next_char == "," if is_closing_bracket and item_complete: self.backspace result.is_list_handler = True else: self.error("Expected '[]' at the end of an item") else: self.backspace if cycle: result.set_next(result) return result def parse_metadata(self, item): """ Parses the metadata portion of a listener item. """ self.skip_ws item.metadata_name = name = self.name if name == "": self.backspace def error(self, msg): """ Raises a syntax error. """ raise TraitError( "%s at column %d of '%s'" % (msg, self.index, self.text) ) class ListenerNotifyWrapper(TraitChangeNotifyWrapper): # -- TraitChangeNotifyWrapper Method Overrides ---------------------------- def __init__(self, handler, owner, id, listener, target=None): self.type = ListenerType.get( self.init(handler, weakref.ref(owner, self.owner_deleted), target) ) self.id = id self.listener = listener def listener_deleted(self, ref): owner = self.owner() if owner is not None: dict = owner.__dict__.get(TraitsListener) listeners = dict.get(self.id) listeners.remove(self) if len(listeners) == 0: del dict[self.id] if len(dict) == 0: del owner.__dict__[TraitsListener] # fixme: Is the following line necessary, since all registered # notifiers should be getting the same 'listener_deleted' call: self.listener.unregister(owner) self.object = self.owner = self.listener = None def owner_deleted(self, ref): self.object = self.owner = None class ListenerHandler(object): """ Wrapper for trait change handlers that avoids strong references to methods. For a bound method handler, this wrapper prevents us from holding a strong reference to the object bound to that bound method. For other callable handlers, we do keep a strong reference to the handler. When called with no arguments, this object returns either the actual handler, or Undefined if the handler no longer exists because the object it was bound to has been garbage collected. Parameters ---------- handler : callable Object to be called when the relevant trait or traits change. """ def __init__(self, handler): if isinstance(handler, MethodType): self.handler_ref = weakref.WeakMethod(handler) else: self.handler = handler def __call__(self): result = getattr(self, "handler", None) if result is not None: return result else: handler = self.handler_ref() return Undefined if handler is None else handler traits-6.3.2/traits/util/000077500000000000000000000000001414270267200153205ustar00rootroot00000000000000traits-6.3.2/traits/util/__init__.py000066400000000000000000000007201414270267200174300ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Utility functions, part of the Traits project. """ traits-6.3.2/traits/util/_traitsui_helpers.py000066400000000000000000000022531414270267200214210ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Functions to help removing TraitsUI being a dependency of Traits. Used internally by traits only. """ # All imports of TraitsUI should be delayed. def check_traitsui_major_version(major): """ Raise RuntimeError if TraitsUI major version is less than the required value. Used internally in traits only. Parameters ---------- major : int Required TraitsUI major version. Raises ------ RuntimeError """ from traitsui import __version__ as traitsui_version actual_major, _ = traitsui_version.split(".", 1) actual_major = int(actual_major) if actual_major < major: raise RuntimeError( "TraitsUI {} or higher is required. Got version {!r}".format( major, traitsui_version) ) traits-6.3.2/traits/util/api.py000066400000000000000000000010141414270267200164370ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! from .deprecated import deprecated from .event_tracer import record_events from .import_symbol import import_symbol traits-6.3.2/traits/util/async_trait_wait.py000066400000000000000000000046221414270267200212420ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import threading def wait_for_condition(condition, obj, trait, timeout=None): """ Wait until the given condition is true, re-evaluating on trait change. This is intended for use in multithreading situations where traits can be modified from a different thread than the calling thread. Wait until `condition` is satisfied. Raise a RuntimeError if `condition` is not satisfied within the given timeout. `condition` is a callback function that will be called with `obj` as its single argument. It should return a boolean indicating whether the condition is satisfied or not. `timeout` gives the maximum time in seconds to wait for the condition to become true. The default value of `None` indicates no timeout. (obj, trait) give an object and trait to listen to for indication of a possible change: whenever the trait changes, the condition is re-evaluated. The condition will also be evaluated on entering this function. Note that in cases of unusual timing it's possible for the condition to be evaluated one more time *after* the ``wait_for_condition`` call has returned. """ condition_satisfied = threading.Event() def handler(): if condition(obj): condition_satisfied.set() obj.on_trait_change(handler, trait) try: if condition(obj): # Catch case where the condition was satisfied before # the on_trait_change handler was active. pass elif timeout is None: # Allow a Ctrl-C to interrupt. The 0.05 value matches # what's used by the standard library's Condition.wait. while not condition_satisfied.is_set(): condition_satisfied.wait(timeout=0.05) else: condition_satisfied.wait(timeout=timeout) if not condition_satisfied.is_set(): raise RuntimeError("Timed out waiting for condition.") finally: obj.on_trait_change(handler, trait, remove=True) traits-6.3.2/traits/util/camel_case.py000066400000000000000000000045061414270267200177530ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Defines utility functions for operating on camel case names. """ # Standard library imports. import functools import re ############################################################################### # Classes ############################################################################### class CamelCaseToPython: """ Simple functor class to convert names from camel case to idiomatic Python variable names. For example:: >>> camel2python = CamelCaseToPython >>> camel2python('XMLActor2DToSGML') 'xml_actor2d_to_sgml' """ def __init__(self): self.patn = re.compile(r"([A-Z0-9]+)([a-z0-9]*)") self.nd_patn = re.compile(r"(\D[123])_D") def __call__(self, name): ret = self.patn.sub(self._repl, name) ret = self.nd_patn.sub(r"\1d", ret) if ret[0] == "_": ret = ret[1:] return ret.lower() def _repl(self, m): g1 = m.group(1) g2 = m.group(2) if len(g1) > 1: if g2: return "_" + g1[:-1] + "_" + g1[-1] + g2 else: return "_" + g1 else: return "_" + g1 + g2 ############################################################################### # Functions ############################################################################### # Instantiate a converter. camel_case_to_python = CamelCaseToPython() def camel_case_to_words(s): """ Convert a camel case string into words separated by spaces. For example:: >>> camel_case_to_words('CamelCase') 'Camel Case' """ def add_space_between_words(s, c): # We detect a word boundary if the character we are looking at is # upper case, but the character preceding it is lower case. if len(s) > 0 and s[-1].islower() and c.isupper(): return s + " " + c return s + c return functools.reduce(add_space_between_words, s, "") traits-6.3.2/traits/util/clean_strings.py000066400000000000000000000077451414270267200205420ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Provides functions that mange strings to avoid characters that would be problematic in certain situations. """ # Standard library imports. import copy import datetime import keyword import re import unicodedata import warnings def clean_filename(name, replace_empty=""): """ Make a user-supplied string safe for filename use. Returns an ASCII-encodable string based on the input string that's safe for use as a component of a filename or URL. The returned value is a string containing only lowercase ASCII letters, digits, and the characters '-' and '_'. This does not give a faithful representation of the original string: different input strings can result in the same output string. .. deprecated:: 6.3.0 This function will be removed in a future version of Traits. Parameters ---------- name : str The string to be made safe. replace_empty : str, optional The return value to be used in the event that the sanitised string ends up being empty. No validation is done on this input - it's up to the user to ensure that the default is itself safe. The default is to return the empty string. Returns ------- safe_string : str A filename-safe version of string. """ warnings.warn( "clean_filename is deprecated and will eventually be removed", DeprecationWarning, stacklevel=2, ) # Code is based on Django's slugify utility. # https://docs.djangoproject.com/en/1.9/_modules/django/utils/text/#slugify name = ( unicodedata.normalize('NFKD', name) .encode('ascii', 'ignore') .decode('ascii') ) name = re.sub(r'[^\w\s-]', '', name).strip().lower() safe_name = re.sub(r'[-\s]+', '-', name) if safe_name == "": return replace_empty return safe_name def clean_timestamp(dt=None, microseconds=False): """ Return a timestamp that has been cleansed of characters that might cause problems in filenames, namely colons. If no datetime object is provided, then uses the current time. The timestamp is in ISO-8601 format with the following exceptions: * Colons ':' are replaced by underscores '_'. * Microseconds are not displayed if the 'microseconds' parameter is False. .. deprecated:: 6.3.0 This function will be removed in a future version of Traits. Parameters ---------- dt : None or datetime.datetime If None, then the current time is used. microseconds : bool Display microseconds or not. Returns ------- A string timestamp. """ warnings.warn( "clean_timestamp is deprecated and will eventually be removed", DeprecationWarning, stacklevel=2, ) if dt is None: dt = datetime.datetime.now() else: # Operate on a copy. dt = copy.copy(dt) if not microseconds: # The microseconds are largely uninformative but annoying. dt = dt.replace(microsecond=0) stamp = dt.isoformat().replace(":", "_") return stamp def python_name(name): """ Attempt to make a valid Python identifier out of a name. """ if len(name) > 0: # Replace spaces with underscores. name = name.replace(" ", "_").lower() # If the name is a Python keyword then prefix it with an # underscore. if keyword.iskeyword(name): name = "_" + name # If the name starts with a digit then prefix it with an # underscore. if name[0].isdigit(): name = "_" + name return name traits-6.3.2/traits/util/deprecated.py000066400000000000000000000017621414270267200200000ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ A decorator for marking methods/functions as deprecated. """ # Standard library imports. import functools import warnings def deprecated(message): """ A factory for decorators for marking methods/functions as deprecated. """ def decorator(fn): """ A decorator for marking methods/functions as deprecated. """ @functools.wraps(fn) def wrapper(*args, **kw): """ The method/function wrapper. """ warnings.warn(message, DeprecationWarning, stacklevel=2) return fn(*args, **kw) return wrapper return decorator traits-6.3.2/traits/util/event_tracer.py000066400000000000000000000251451414270267200203620ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Record trait change events in single and multi-threaded environments. """ import inspect import os import threading from contextlib import contextmanager from datetime import datetime from traits import trait_notifiers CHANGEMSG = ( "{time} {direction:-{direction}{length}} {name!r} changed from " "{old!r} to {new!r} in {class_name!r}\n" ) CALLINGMSG = "{time} {action:>{gap}}: {handler!r} in {source}\n" EXITMSG = ( "{time} {direction:-{direction}{length}} " "EXIT: {handler!r}{exception}\n" ) SPACES_TO_ALIGN_WITH_CHANGE_MESSAGE = 9 class SentinelRecord(object): """ Sentinel record to separate groups of chained change event dispatches. """ __slots__ = () def __str__(self): return "\n" class ChangeMessageRecord(object): """ Message record for a change event dispatch. """ __slots__ = ("time", "indent", "name", "old", "new", "class_name") def __init__(self, time, indent, name, old, new, class_name): #: Time stamp in UTC. self.time = time #: Depth level in a chain of trait change dispatches. self.indent = indent #: The name of the trait that changed self.name = name #: The old value. self.old = old #: The new value. self.new = new #: The name of the class that the trait change took place. self.class_name = class_name def __str__(self): length = self.indent * 2 return CHANGEMSG.format( time=self.time, direction=">", name=self.name, old=self.old, new=self.new, class_name=self.class_name, length=length, ) class CallingMessageRecord(object): """ Message record for a change handler call. """ __slots__ = ("time", "indent", "handler", "source") def __init__(self, time, indent, handler, source): #: Time stamp in UTC. self.time = time #: Depth level of the call in a chain of trait change dispatches. self.indent = indent #: The traits change handler that is called. self.handler = handler #: The source file where the handler was defined. self.source = source def __str__(self): gap = self.indent * 2 + SPACES_TO_ALIGN_WITH_CHANGE_MESSAGE return CALLINGMSG.format( time=self.time, action="CALLING", handler=self.handler, source=self.source, gap=gap, ) class ExitMessageRecord(object): """ Message record for returning from a change event dispatch. """ __slots__ = ("time", "indent", "handler", "exception") def __init__(self, time, indent, handler, exception): #: Time stamp in UTC. self.time = time #: Depth level of the exit in a chain of trait change dispatch. self.indent = indent #: The traits change handler that is called. self.handler = handler #: The exception type (if one took place) self.exception = exception def __str__(self): length = self.indent * 2 return EXITMSG.format( time=self.time, direction="<", handler=self.handler, exception=self.exception, length=length, ) class RecordContainer(object): """ A simple record container. This class is commonly used to hold records from a single thread. """ def __init__(self): self._records = [] def record(self, record): """ Add the record into the container. """ self._records.append(record) def save_to_file(self, filename): """ Save the records into a file. """ with open(filename, "w", encoding="utf-8") as fh: for record in self._records: fh.write(str(record)) class MultiThreadRecordContainer(object): """ A container of record containers that are used by separate threads. Each record container is mapped to a thread name id. When a RecordContainer does not exist for a specific thread a new empty RecordContainer will be created on request. """ def __init__(self): self._creation_lock = threading.Lock() self._record_containers = {} def get_change_event_collector(self, thread_name): """ Return the dedicated RecordContainer for the thread. If no RecordContainer is found for `thread_name` then a new RecordContainer is created. """ with self._creation_lock: container = self._record_containers.get(thread_name) if container is None: container = RecordContainer() self._record_containers[thread_name] = container return container def save_to_directory(self, directory_name): """ Save records files into the directory. Each RecordContainer will dump its records on a separate file named .trace. """ with self._creation_lock: containers = self._record_containers for thread_name, container in containers.items(): filename = os.path.join( directory_name, "{0}.trace".format(thread_name) ) container.save_to_file(filename) class ChangeEventRecorder(object): """ A single thread trait change event recorder. Parameters ---------- container : MultiThreadRecordContainer A container to store the records for each trait change. Attributes ---------- container : MultiThreadRecordContainer A container to store the records for each trait change. indent : int Indentation level when reporting chained events. """ def __init__(self, container): self.indent = 1 self.container = container def pre_tracer(self, obj, name, old, new, handler): """ Record a string representation of the trait change dispatch """ indent = self.indent time = datetime.utcnow().isoformat(" ") container = self.container container.record( ChangeMessageRecord( time=time, indent=indent, name=name, old=old, new=new, class_name=obj.__class__.__name__, ) ) container.record( CallingMessageRecord( time=time, indent=indent, handler=handler.__name__, source=inspect.getsourcefile(handler), ) ) self.indent += 1 def post_tracer(self, obj, name, old, new, handler, exception=None): """ Record a string representation of the trait change return """ time = datetime.utcnow().isoformat(" ") self.indent -= 1 indent = self.indent if exception: exception_msg = " [EXCEPTION: {}]".format(exception) else: exception_msg = "" container = self.container container.record( ExitMessageRecord( time=time, indent=indent, handler=handler.__name__, exception=exception_msg, ) ) if indent == 1: container.record(SentinelRecord()) class MultiThreadChangeEventRecorder(object): """ A thread aware trait change recorder. The class manages multiple ChangeEventRecorders which record trait change events for each thread in a separate file. Parameters ---------- container : MultiThreadChangeEventRecorder The container of RecordContainers to keep the trait change records for each thread. Attributes ---------- container : MultiThreadChangeEventRecorder The container of RecordContainers to keep the trait change records for each thread. tracers : dict Mapping from threads to ChangeEventRecorder instances. """ def __init__(self, container): self.tracers = {} self._tracer_lock = threading.Lock() self.container = container def close(self): """ Close and stop all logging. """ with self._tracer_lock: self.tracers = {} def pre_tracer(self, obj, name, old, new, handler): """ The traits pre event tracer. This method should be set as the global pre event tracer for traits. """ tracer = self._get_tracer() tracer.pre_tracer(obj, name, old, new, handler) def post_tracer(self, obj, name, old, new, handler, exception=None): """ The traits post event tracer. This method should be set as the global post event tracer for traits. """ tracer = self._get_tracer() tracer.post_tracer(obj, name, old, new, handler, exception=exception) def _get_tracer(self): with self._tracer_lock: thread = threading.current_thread().name if thread not in self.tracers: container = self.container thread_container = container.get_change_event_collector(thread) tracer = ChangeEventRecorder(thread_container) self.tracers[thread] = tracer return tracer else: return self.tracers[thread] @contextmanager def record_events(): """ Multi-threaded trait change event tracer. Example ------- This will install a tracer that will record all events that occur from setting of some_trait on the my_model instance:: >>> from trace_recorder import record_events >>> with record_events() as change_event_container: ... my_model.some_trait = True >>> change_event_container.save_to_directory('C:\\dev\\trace') The results will be stored in one file per running thread in the directory 'C:\\dev\\trace'. The files are named after the thread being traced. """ container = MultiThreadRecordContainer() recorder = MultiThreadChangeEventRecorder(container=container) trait_notifiers.set_change_event_tracers( pre_tracer=recorder.pre_tracer, post_tracer=recorder.post_tracer ) try: yield container finally: trait_notifiers.clear_change_event_tracers() recorder.close() traits-6.3.2/traits/util/home_directory.py000066400000000000000000000022501414270267200207050ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! import os def get_home_directory(): """ Determine the user's home directory.""" # 'HOME' should work on most Unixes, and 'USERPROFILE' works on at # least Windows XP ;^) # # FIXME: Is this really better than the following?? # path = os.path.expanduser('~') # The above seems to work on both Windows and Unixes though the docs # indicate it might not work as well on Macs. for name in ["HOME", "USERPROFILE"]: if name in os.environ: # Make sure that the path ends with a path separator. path = os.environ[name] if path[-1] != os.path.sep: path += os.path.sep break # If all else fails, the current directory will do. else: path = "" return path traits-6.3.2/traits/util/import_symbol.py000066400000000000000000000026071414270267200205760ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ A function to import symbols. """ from importlib import import_module from traits.trait_base import xgetattr def import_symbol(symbol_path): """ Import the symbol defined by the specified symbol path. Examples -------- import_symbol('tarfile:TarFile') -> TarFile import_symbol('tarfile:TarFile.open') -> TarFile.open To allow compatibility with old-school traits symbol names we also allow all-dotted paths, but in this case you can only import top-level names from the module. import_symbol('tarfile.TarFile') -> TarFile """ if ":" in symbol_path: module_name, symbol_name = symbol_path.split(":") module = import_module(module_name) symbol = xgetattr(module, symbol_name) else: components = symbol_path.split(".") module_name = ".".join(components[:-1]) symbol_name = components[-1] module = import_module(module_name) symbol = getattr(module, symbol_name) return symbol traits-6.3.2/traits/util/resource.py000066400000000000000000000164151414270267200175300ustar00rootroot00000000000000# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX # All rights reserved. # # This software is provided without warranty under the terms of the BSD # license included in LICENSE.txt and may be redistributed only under # the conditions described in the aforementioned license. The license # is also available online at http://www.enthought.com/licenses/BSD.txt # # Thanks for using Enthought open source! """ Utility functions for managing and finding resources (e.g. images, files). get_path : Returns the absolute path of a class or instance create_unique_name : Creates a name with a given prefix that is not in a given list of existing names. The separator between the prefix and the rest of the name can also be specified (default is a '_') find_resource: Given a setuptools project specification string ('MyProject>=2.1') and a partial path leading from the projects base directory to the desired resource, will return either an opened file object or, if specified, a full path to the resource. """ # Standard library imports. import inspect import os import sys import sysconfig import warnings def get_path(path): """ Returns an absolute path for the specified path. 'path' can be a string, class or instance. """ if type(path) is not str: # Is this a class or an instance? if inspect.isclass(path): klass = path else: klass = path.__class__ # Get the name of the module that the class was loaded from. module_name = klass.__module__ # Look the module up. module = sys.modules[module_name] if module_name == "__main__": dirs = [os.path.dirname(sys.argv[0]), os.getcwd()] for d in dirs: if os.path.exists(d): path = d break else: # Get the path to the module. path = os.path.dirname(module.__file__) return path def create_unique_name(prefix, names, separator="_"): """ Creates a name starting with 'prefix' that is not in 'names'. """ i = 1 name = prefix while name in names: name = prefix + separator + str(i) i += 1 return name def find_resource(project, resource_path, alt_path=None, return_path=False): """ Returns a file object or file path pointing to the desired resource. This function will find a desired resource file and return an opened file object. The main method of finding the resource uses the pkg_resources resource_stream method, which searches your working set for the installed project specified and appends the resource_path given to the project path, leading it to the file. If setuptools is not installed or it cannot find/open the resource, find_resource will use the sys.path[0] to find the resource if alt_path is defined. .. deprecated:: 6.3.0 Parameters ---------- project : str The name of the project to look for the resource in. Can be the name or a requirement string. Ex: 'MyProject', 'MyProject>1.0', 'MyProject==1.1' resource_path : str The path to the file from inside the package. If the file desired is MyProject/data/image.jpg, resource_path would be 'data/image.jpg'. alt_path : str The path to the resource relative to the location of the application's top-level script (the one with __main__). If this function is called in code/scripts/myscript.py and the resource is code/data/image.jpg, the alt_path would be '../data/image.jpg'. This path is only used if the resource cannot be found using setuptools. return_path : bool Determines whether the function should return a file object or a full path to the resource. Returns ------- file : file object or file path A file object containing the resource. If return_path is True, 'file' will be the full path to the resource. If the file is not found or cannot be opened, None is returned. """ warnings.warn( "find_resource is deprecated. Use importlib.resources instead.", DeprecationWarning, stacklevel=2, ) try: # Get the image using the pkg_resources resource_stream module, which # will find the file by getting the Chaco install path and appending # the image path. This method works in all cases as long as setuptools # is installed. If setuptools isn't installed, the backup sys.path[0] # method is used. from pkg_resources import resource_stream, working_set, Requirement # Get a requirement for the project requirement = Requirement.parse(project) if return_path: dist = working_set.find(requirement) full_path = os.path.join(dist.location, resource_path) # If the path exists, return it if os.path.exists(full_path): return full_path else: raise else: return resource_stream(requirement, resource_path) except: # Setuptools was either not installed, or it failed to find the file. # First check to see if the package was installed using egginst by # looking for the file at: site-packages\\resource_path full_path = os.path.join(sysconfig.get_path('purelib'), resource_path) if os.path.exists(full_path): if return_path: return full_path else: return open(full_path, "rb") # Get the image using sys.path[0], which is the directory that the # running script lives in. The path to the file is then constructed by # navigating from the script's location. This method only works if this # script is called directly from the command line using # 'python %SOMEPATH%/