pax_global_header00006660000000000000000000000064150725416350014522gustar00rootroot0000000000000052 comment=7d044102103f8a6c4847d57b3273540e2c2cb293 spyder-line-profiler-0.4.2/000077500000000000000000000000001507254163500156005ustar00rootroot00000000000000spyder-line-profiler-0.4.2/.github/000077500000000000000000000000001507254163500171405ustar00rootroot00000000000000spyder-line-profiler-0.4.2/.github/FUNDING.yml000066400000000000000000000000301507254163500207460ustar00rootroot00000000000000open_collective: spyder spyder-line-profiler-0.4.2/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000010361507254163500227410ustar00rootroot00000000000000## Description of Changes ### Affirmation By submitting this Pull Request or typing my (user)name below, I affirm the [Developer Certificate of Origin](https://developercertificate.org) with respect to all commits and content included in this PR, and understand I am releasing the same under Spyder's MIT (Expat) license. I certify the above statement is true and correct: spyder-line-profiler-0.4.2/.github/scripts/000077500000000000000000000000001507254163500206275ustar00rootroot00000000000000spyder-line-profiler-0.4.2/.github/scripts/generate-without-spyder.py000066400000000000000000000012201507254163500257730ustar00rootroot00000000000000#!/usr/bin/env python # # Copyright (c) Spyder Project Contributors # Licensed under the terms of the MIT License # (see LICENSE.txt for details) """Script to generate requirements/without-spyder.txt""" import re from pathlib import Path rootdir = Path(__file__).parents[2] input_filename = rootdir / 'requirements' / 'conda.txt' output_filename = rootdir / 'requirements' / 'without-spyder.txt' with open(input_filename) as infile: with open(output_filename, 'w') as outfile: for line in infile: package_name = re.match('[-a-z0-9_]*', line).group(0) if package_name != 'spyder': outfile.write(line) spyder-line-profiler-0.4.2/.github/workflows/000077500000000000000000000000001507254163500211755ustar00rootroot00000000000000spyder-line-profiler-0.4.2/.github/workflows/run-tests.yml000066400000000000000000000076511507254163500236750ustar00rootroot00000000000000name: Run tests on: push: branches: - master pull_request: branches: - master jobs: main: strategy: fail-fast: false matrix: OS: ['ubuntu', 'macos', 'windows'] PYTHON_VERSION: ['3.10', '3.11', '3.12'] SPYDER_SOURCE: ['conda', 'git'] exclude: - OS: ['macos', 'windows'] PYTHON_VERSION: ['3.11'] name: ${{ matrix.OS }} py${{ matrix.PYTHON_VERSION }} spyder-from-${{ matrix.SPYDER_SOURCE }} runs-on: ${{ matrix.OS }}-latest env: CI: True PYTHON_VERSION: ${{ matrix.PYTHON_VERSION }} steps: - name: Checkout branch uses: actions/checkout@v4 with: path: 'spyder-line-profiler' - name: Install System Packages if: matrix.OS == 'ubuntu' run: | sudo apt-get update --fix-missing sudo apt-get install -qq pyqt5-dev-tools libxcb-xinerama0 xterm --fix-missing - name: Install Conda uses: conda-incubator/setup-miniconda@v3 with: miniforge-version: latest auto-update-conda: true conda-remove-defaults: "true" python-version: ${{ matrix.PYTHON_VERSION }} - name: Checkout Spyder from git if: matrix.SPYDER_SOURCE == 'git' uses: actions/checkout@v4 with: repository: 'spyder-ide/spyder' path: 'spyder' - name: Install Spyder's dependencies (main) if: matrix.SPYDER_SOURCE == 'git' shell: bash -l {0} run: conda env update --file spyder/requirements/main.yml - name: Install Spyder's dependencies (Linux) if: matrix.SPYDER_SOURCE == 'git' && matrix.OS == 'ubuntu' shell: bash -l {0} run: conda env update --file spyder/requirements/linux.yml - name: Install Spyder's dependencies (Mac / Windows) if: matrix.SPYDER_SOURCE == 'git' && matrix.OS != 'ubuntu' shell: bash -l {0} run: conda env update --file spyder/requirements/${{ matrix.OS }}.yml - name: Install Spyder from source if: matrix.SPYDER_SOURCE == 'git' shell: bash -l {0} run: pip install --no-deps spyder - name: Install plugin dependencies (without Spyder) if: matrix.SPYDER_SOURCE == 'git' shell: bash -l {0} run: | python spyder-line-profiler/.github/scripts/generate-without-spyder.py conda install --file spyder-line-profiler/requirements/without-spyder.txt -y - name: Install plugin dependencies if: matrix.SPYDER_SOURCE == 'conda' shell: bash -l {0} run: conda install --file spyder-line-profiler/requirements/conda.txt -y - name: Install test dependencies shell: bash -l {0} run: | conda install nomkl -y -q conda install --file spyder-line-profiler/requirements/tests.txt -y - name: Install plugin shell: bash -l {0} run: pip install --no-deps spyder-line-profiler - name: Show environment information shell: bash -l {0} run: | conda info conda list - name: Run tests (Linux) if: matrix.OS == 'ubuntu' uses: nick-fields/retry@v3 with: timeout_minutes: 10 max_attempts: 3 shell: bash command: | . ~/.profile xvfb-run --auto-servernum pytest spyder-line-profiler/spyder_line_profiler -vv - name: Run tests (MacOS) if: matrix.OS == 'macos' uses: nick-fields/retry@v3 with: timeout_minutes: 10 max_attempts: 3 shell: bash command: | . ~/.profile pytest spyder-line-profiler/spyder_line_profiler -x -vv - name: Run tests (Windows) if: matrix.OS == 'windows' uses: nick-fields/retry@v3 with: timeout_minutes: 10 max_attempts: 3 command: pytest spyder-line-profiler/spyder_line_profiler -x -vv spyder-line-profiler-0.4.2/.gitignore000066400000000000000000000005241507254163500175710ustar00rootroot00000000000000*.py[cod] # C extensions *.so # Packages *.egg *.egg-info dist build eggs parts bin var sdist develop-eggs .installed.cfg lib lib64 __pycache__ # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox nosetests.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject # Linux files .directoryspyder-line-profiler-0.4.2/AUTHORS.md000066400000000000000000000005461507254163500172540ustar00rootroot00000000000000# Authors ## Original author * Joseph Martinot-Lagarde ([@Nodd](http://github.com/Nodd)) ## Current maintainers * Jitse Niesen ([@jitseniesen](https://github.com/jitseniesen)) * The [Spyder Development Team](https://github.com/spyder-ide) * The [spyder-line-profiler Contributors](https://github.com/spyder-ide/spyder-line-profiler/graphs/contributors) spyder-line-profiler-0.4.2/CHANGELOG.md000066400000000000000000000233251507254163500174160ustar00rootroot00000000000000# History of changes ## Version 0.4.2 (2025/10/11) This version fixes a bug and makes the plugin compatible with Spyder 6.1. ### Bug fix * Fix shortcut to run profiler ([PR 100](https://github.com/spyder-ide/spyder-line-profiler/pull/100) by [@rear1019](https://github.com/rear1019)) ### Maintenance * Define run configuration options to make plugin compatible with Spyder 6.1 ([Issue 101](https://github.com/spyder-ide/spyder-line-profiler/issues/101), [Issue 104](https://github.com/spyder-ide/spyder-line-profiler/issues/104), ([PR 105](https://github.com/spyder-ide/spyder-line-profiler/pull/105)) * Drop Python 3.8 and Python 3.9 ([PR 102](https://github.com/spyder-ide/spyder-line-profiler/pull/102)) ## Version 0.4.1 (2025/03/10) This release contains some bug fixes. Thanks to [@rear1019](https://github.com/rear1019) who contributed all the changes except for the last PR. ### Bug fixes * Fix go-to-line when clicking entries ([PR 94](https://github.com/spyder-ide/spyder-line-profiler/pull/94)) * Fix setting of working directory ([Issue 85](https://github.com/spyder-ide/spyder-line-profiler/issues/85), [PR 96](https://github.com/spyder-ide/spyder-line-profiler/pull/96)) * Consistently use UTF-8 encoding even if the system default is different ([PR 99](https://github.com/spyder-ide/spyder-line-profiler/pull/99)) * Fix runtime dependency check ([PR 95](https://github.com/spyder-ide/spyder-line-profiler/pull/95)) ### Maintenance * Remove QTextCodec for better compatibility with Qt 6 ([Issue 98](https://github.com/spyder-ide/spyder-line-profiler/issues/98), [PR 99](https://github.com/spyder-ide/spyder-line-profiler/pull/99)) * Fix GitHub automatic testing ([PR 97](https://github.com/spyder-ide/spyder-line-profiler/pull/97)) ## Version 0.4.0 (2024/09/03) This release updates the plugin to be used with Spyder 6 and fixes a bug. ### Bug fix * Allow Python code to have non-ASCII characters ([Issue 90](https://github.com/spyder-ide/spyder-line-profiler/issues/90), [PR 92](https://github.com/spyder-ide/spyder-line-profiler/pull/92)) ### Maintenance * Make plugin compatible with Spyder 6 ([Issue 86](https://github.com/spyder-ide/spyder-line-profiler/issues/86), [Issue 91](https://github.com/spyder-ide/spyder-line-profiler/issues/91), [PR 87](https://github.com/spyder-ide/spyder-line-profiler/pull/87), [PR 93](https://github.com/spyder-ide/spyder-line-profiler/pull/93)) * Thanks to [Reinert Huseby Karlsen](https://github.com/rhkarls) and [Simon Kern](https://github.com/skjerns) for help with this! ## Version 0.3.2 (2023/06/24) This version contains some bug fixes and is compatible with Spyder 5.4. ### Bug fixes * Use Python interpreter/environment from Preferences ([Issue 67](https://github.com/spyder-ide/spyder-line-profiler/issues/67), [Issue 5](https://github.com/spyder-ide/spyder-line-profiler/issues/5), [PR 78](https://github.com/spyder-ide/spyder-line-profiler/pull/78)) * Adapt colors to Spyder's palette ([Issue 50](https://github.com/spyder-ide/spyder-line-profiler/issues/50), [PR 82](https://github.com/spyder-ide/spyder-line-profiler/pull/82)) * Update LICENSE.txt to match individual file copyright statements ([Issue 74](https://github.com/spyder-ide/spyder-line-profiler/issues/74), [PR 79](https://github.com/spyder-ide/spyder-line-profiler/pull/79)) * Update description on PyPI ([Issue 73](https://github.com/spyder-ide/spyder-line-profiler/issues/73), [PR 83](https://github.com/spyder-ide/spyder-line-profiler/pull/83)) ### Maintenance * Updates for Spyder 5.4 ([Issue 80](https://github.com/spyder-ide/spyder-line-profiler/issues/80), [Issue 72](https://github.com/spyder-ide/spyder-line-profiler/issues/72), [PR 77](https://github.com/spyder-ide/spyder-line-profiler/pull/77), [PR 84](https://github.com/spyder-ide/spyder-line-profiler/pull/84)) * Remove last bits of Python 2 support ([PR 68](https://github.com/spyder-ide/spyder-line-profiler/pull/68)) * Update test for line_profiler 4.x ([Issue 75](https://github.com/spyder-ide/spyder-line-profiler/issues/75), [PR 68](https://github.com/spyder-ide/spyder-line-profiler/pull/68)) * Update GitHub test action ([PR 76](https://github.com/spyder-ide/spyder-line-profiler/pull/76)) ## Version 0.3.1 (2022/08/07) This version fixes a compatibility issue with Spyder 5.3.2 ([Issue 65](https://github.com/spyder-ide/spyder-line-profiler/issues/65), [PR 66](https://github.com/spyder-ide/spyder-line-profiler/pull/66)). ## Version 0.3.0 (2022/06/03) This version is compatible with Spyder 5.2 and 5.3. ### Issues Closed * [Issue 54](https://github.com/spyder-ide/spyder-line-profiler/issues/54) - How to proceed with spyder 5 compatibility ([PR 56](https://github.com/spyder-ide/spyder-line-profiler/pull/56) by [@skjerns](https://github.com/skjerns)) * [Issue 52](https://github.com/spyder-ide/spyder-line-profiler/issues/52) - Spyder 5 compatibility ([PR 56](https://github.com/spyder-ide/spyder-line-profiler/pull/56) by [@skjerns](https://github.com/skjerns)) * [Issue 48](https://github.com/spyder-ide/spyder-line-profiler/issues/48) - Correctly register shortcuts * [Issue 27](https://github.com/spyder-ide/spyder-line-profiler/issues/27) - saving profiling results * [Issue 25](https://github.com/spyder-ide/spyder-line-profiler/issues/25) - Text box for file to be profiled accept directories In this release 5 issues were closed. ### Pull Requests Merged * [PR 62](https://github.com/spyder-ide/spyder-line-profiler/pull/62) - PR: Update `README.md`, `CONTRIBUTING.md`, screenshot and add `RELEASE.md`, by [@dalthviz](https://github.com/dalthviz) * [PR 61](https://github.com/spyder-ide/spyder-line-profiler/pull/61) - PR: Add default config and change plugin icon, by [@dalthviz](https://github.com/dalthviz) * [PR 60](https://github.com/spyder-ide/spyder-line-profiler/pull/60) - PR: Remove outdated `conda.recipe` directory, by [@dalthviz](https://github.com/dalthviz) * [PR 56](https://github.com/spyder-ide/spyder-line-profiler/pull/56) - PR: Switch to new API for Spyder 5, by [@skjerns](https://github.com/skjerns) ([54](https://github.com/spyder-ide/spyder-line-profiler/issues/54), [53](https://github.com/spyder-ide/spyder-line-profiler/issues/53), [52](https://github.com/spyder-ide/spyder-line-profiler/issues/52)) In this release 4 pull requests were closed. ## Version 0.2.1 (2020/04/28) This release fixes some compatibility issues with Spyder 4.1 and some other bugs. ### Issues Closed * [Issue 44](https://github.com/spyder-ide/spyder-line-profiler/issues/44) - TextEditor initializer receives unexpected argument size ([PR 46](https://github.com/spyder-ide/spyder-line-profiler/pull/46)) * [Issue 41](https://github.com/spyder-ide/spyder-line-profiler/issues/41) - Move CI to github actions ([PR 45](https://github.com/spyder-ide/spyder-line-profiler/pull/45)) * [Issue 39](https://github.com/spyder-ide/spyder-line-profiler/issues/39) - Crash from opening options ([PR 40](https://github.com/spyder-ide/spyder-line-profiler/pull/40)) * [Issue 35](https://github.com/spyder-ide/spyder-line-profiler/issues/35) - Opening editor from line profiler output is broken ([PR 47](https://github.com/spyder-ide/spyder-line-profiler/pull/47)) In this release 4 issues were closed. ### Pull Requests Merged * [PR 47](https://github.com/spyder-ide/spyder-line-profiler/pull/47) - PR: Fix opening editor from profiler widget ([35](https://github.com/spyder-ide/spyder-line-profiler/issues/35)) * [PR 46](https://github.com/spyder-ide/spyder-line-profiler/pull/46) - PR: Fix initialization of TextEditor ([44](https://github.com/spyder-ide/spyder-line-profiler/issues/44)) * [PR 45](https://github.com/spyder-ide/spyder-line-profiler/pull/45) - PR: Move CI to GitHub Actions ([41](https://github.com/spyder-ide/spyder-line-profiler/issues/41)) * [PR 43](https://github.com/spyder-ide/spyder-line-profiler/pull/43) - PR: Fix invalid escape sequence in regex string * [PR 40](https://github.com/spyder-ide/spyder-line-profiler/pull/40) - PR: Add CONF_DEFAULTS ([39](https://github.com/spyder-ide/spyder-line-profiler/issues/39)) In this release 5 pull requests were closed. ## Version 0.2.0 (2019/12/18) This release updates the plugin to be used with Spyder 4 and fixes some bugs. ### Issues Closed * [Issue 33](https://github.com/spyder-ide/spyder-line-profiler/issues/33) - Sorting by time / % not working correctly ([PR 38](https://github.com/spyder-ide/spyder-line-profiler/pull/38)) * [Issue 26](https://github.com/spyder-ide/spyder-line-profiler/issues/26) - Update plugin to Spyder v4 ([PR 36](https://github.com/spyder-ide/spyder-line-profiler/pull/36)) In this release 2 issues were closed. ### Pull Requests Merged * [PR 38](https://github.com/spyder-ide/spyder-line-profiler/pull/38) - PR: Add natural sort for columns ([33](https://github.com/spyder-ide/spyder-line-profiler/issues/33)) * [PR 36](https://github.com/spyder-ide/spyder-line-profiler/pull/36) - PR: Compatibility changes for Spyder 4 ([26](https://github.com/spyder-ide/spyder-line-profiler/issues/26)) * [PR 31](https://github.com/spyder-ide/spyder-line-profiler/pull/31) - PR: Fix continuous integration services * [PR 30](https://github.com/spyder-ide/spyder-line-profiler/pull/30) - PR: "Profile by line" Button Behavior * [PR 24](https://github.com/spyder-ide/spyder-line-profiler/pull/24) - Update readme: Plugin can now be installed using conda or pip * [PR 23](https://github.com/spyder-ide/spyder-line-profiler/pull/23) - Add conda recipe ([15](https://github.com/spyder-ide/spyder-line-profiler/issues/15)) In this release 6 pull requests were closed. ## Version 0.1.1 (2017/03/26) This version improves the packaging. The code itself was not changed. ### Pull Requests Merged * [PR 22](https://github.com/spyder-ide/spyder-line-profiler/pull/22) - Install tests alongside package In this release 1 pull request was closed. ## Version 0.1.0 (2017/03/22) Initial release. spyder-line-profiler-0.4.2/CONTRIBUTING.md000066400000000000000000000044711507254163500200370ustar00rootroot00000000000000# Contributing to the Spyder line profiler plugin :+1::tada: First off, thanks for taking the time to contribute to the Spyder Line Profiler plugin! :tada::+1: ## General guidelines for contributing The Spyder line profiler plugin is developed as part of the wider Spyder project. In general, the guidelines for contributing to Spyder also apply here. Specifically, all contributors are expected to abide by [Spyder's Code of Conduct](https://github.com/spyder-ide/spyder/blob/master/CODE_OF_CONDUCT.md). There are many ways to contribute and all are valued and welcome. You can help other users, write documentation, spread the word, submit helpful issues on the [issue tracker](https://github.com/spyder-ide/spyder-line-profiler/issues) with problems you encounter or ways to improve the plugin, test the development version, or submit a pull request on GitHub. The rest of this document explains how to set up a development environment. ## Setting up a development environment This section explains how to set up a conda environment to run and work on the development version of the Spyder line profiler plugin. ### Creating a conda environment This creates a new conda environment with the name `spyderlp-dev`. ```bash $ conda create -n spyderlp-dev -c conda-forge python=3.9 $ conda activate spyderlp-dev ``` ### Cloning the repository This creates a new directory `spyder-line-profiler` with the source code of the Spyder line profiler plugin. ```bash $ git clone https://github.com/spyder-ide/spyder-line-profiler.git $ cd spyder-line-profiler ``` ### Installing dependencies This installs Spyder, line_profiler and all other plugin dependencies into the conda environment previously created, using the conda-forge channel. ```bash $ conda install -c conda-forge --file requirements/conda.txt ``` ### Installing the plugin This installs the Spyder line profiler plugin so that Spyder will use it. ```bash $ pip install --no-deps -e . ``` ### Running Spyder You are done! You can run Spyder as normal and it should load the line profiler plugin. ```bash $ spyder ``` ### Running Tests This command installs the test dependencies into your conda environment, using the conda-forge channel. ```bash $ conda install -c conda-forge --file requirements/tests.txt ``` You can now run the tests with a simple ```bash $ pytest ``` spyder-line-profiler-0.4.2/LICENSE.txt000066400000000000000000000021061507254163500174220ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2013 Spyder Project Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. spyder-line-profiler-0.4.2/MANIFEST.in000066400000000000000000000001241507254163500173330ustar00rootroot00000000000000include CHANGELOG.md LICENSE.txt README.md recursive-include spyder_line_profiler * spyder-line-profiler-0.4.2/README.md000077500000000000000000000064131507254163500170660ustar00rootroot00000000000000# Spyder line profiler plugin ## Project details ![license](https://img.shields.io/pypi/l/spyder-line-profiler.svg) [![conda version](https://img.shields.io/conda/v/conda-forge/spyder-line-profiler.svg)](https://www.anaconda.com/download/) [![download count](https://img.shields.io/conda/d/conda-forge/spyder-line-profiler.svg)](https://www.anaconda.com/download/) [![pypi version](https://img.shields.io/pypi/v/spyder-line-profiler.svg)](https://pypi.python.org/pypi/spyder-line-profiler) [![Join the chat at https://gitter.im/spyder-ide/public](https://badges.gitter.im/spyder-ide/spyder.svg)](https://gitter.im/spyder-ide/public) [![OpenCollective Backers](https://opencollective.com/spyder/backers/badge.svg?color=blue)](#backers) [![OpenCollective Sponsors](https://opencollective.com/spyder/sponsors/badge.svg?color=blue)](#sponsors) ## Build status [![Windows status](https://github.com/spyder-ide/spyder-line-profiler/workflows/Windows%20tests/badge.svg)](https://github.com/spyder-ide/spyder-line-profiler/actions?query=workflow%3A%22Windows+tests%22) [![Linux status](https://github.com/spyder-ide/spyder-line-profiler/workflows/Linux%20tests/badge.svg)](https://github.com/spyder-ide/spyder-line-profiler/actions?query=workflow%3A%22Linux+tests%22) [![MacOS status](https://github.com/spyder-ide/spyder-line-profiler/workflows/Macos%20tests/badge.svg)](https://github.com/spyder-ide/spyder-line-profiler/actions?query=workflow%3A%22Macos+tests%22) [![codecov](https://codecov.io/gh/spyder-ide/spyder-line-profiler/branch/master/graph/badge.svg)](https://codecov.io/gh/spyder-ide/spyder-line-profiler/branch/master) ## Description This is a plugin to run the Python [line_profiler](https://pypi.python.org/pypi/line_profiler) from within the Python IDE [Spyder](https://github.com/spyder-ide/spyder). The code is an adaptation of the profiler plugin integrated in Spyder. ## Installation To install this plugin, you can use either ``pip`` or ``conda`` package managers, as follows: Using conda (the recommended way!): ``` conda install spyder-line-profiler -c conda-forge ``` Using pip: ``` pip install spyder-line-profiler ``` ## Usage Add a `@profile` decorator to the functions that you wish to profile then Shift+F10 (line profiler default) to run the profiler on the current script, or go to `Run > Run line profiler`. The results will be shown in a dockwidget, grouped by function. Lines with a stronger color take more time to run. ## Screenshot ![Screenshot of spyder-line-profiler plugin showing profiler results](./img_src/screenshot_profiler.png) ## Contributing Everyone is welcome to contribute! ## Sponsors Spyder and its subprojects are funded thanks to the generous support of [![Quansight](https://static.wixstatic.com/media/095d2c_2508c560e87d436ea00357abc404cf1d~mv2.png/v1/crop/x_0,y_9,w_915,h_329/fill/w_380,h_128,al_c,usm_0.66_1.00_0.01/095d2c_2508c560e87d436ea00357abc404cf1d~mv2.png)](https://www.quansight.com/)[![Numfocus](https://i2.wp.com/numfocus.org/wp-content/uploads/2017/07/NumFocus_LRG.png?fit=320%2C148&ssl=1)](https://numfocus.org/) and the donations we have received from our users around the world through [Open Collective](https://opencollective.com/spyder/): [![Sponsors](https://opencollective.com/spyder/sponsors.svg)](https://opencollective.com/spyder#support) spyder-line-profiler-0.4.2/RELEASE.md000066400000000000000000000044331507254163500172060ustar00rootroot00000000000000# Release Follow these steps to release a new version of spyder-line-profiler. In the commands below, replace `X.Y.Z` with the release version when needed. **Note**: We use `pip` instead of `conda` here even on Conda installs, to ensure we always get the latest upstream versions of the build dependencies. ## PyPI and GitHub You will need to have a local clone of the repo. The following steps supose a repo setup from a fork with and `upstream` remote pointing to the main `spyder-line-profiler` repo * Close [milestone on Github](https://github.com/spyder-ide/spyder-line-profiler/milestones) * Update local repo ```bash git restore . && git switch master && git pull upstream master ``` * Clean local repo ```bash git clean -xfdi ``` * Install/upgrade Loghub ```bash pip install --upgrade loghub ``` * Update `CHANGELOG.md` with Loghub: `loghub spyder-ide/spyder-line-profiler --milestone vX.Y.Z` * git add and git commit with "Update Changelog" * Update `__version__` in `__init__.py` (set release version, remove `dev0`) * Create release commit ```bash git commit -am "Release X.Y.Z" ``` * Update the packaging stack ```bash python -m pip install --upgrade pip pip install --upgrade --upgrade-strategy eager build setuptools twine wheel ``` * Build source distribution and wheel ```bash python -bb -X dev -W error -m build ``` * Check distribution archives ```bash twine check --strict dist/* ``` * Upload distribution packages to PyPI ```bash twine upload dist/* ``` * Create release tag ```bash git tag -a vX.Y.Z -m "Release X.Y.Z" ``` * Update `__version__` in `__init__.py` (add `.dev0` and increment minor) * Create `Back to work` commit ```bash git commit -am "Back to work" ``` * Push new release commits and tags to `master` ```bash git push upstream master --follow-tags ``` * Create a [GitHub release](https://github.com/spyder-ide/spyder-line-profiler/releases) from the tag ## Conda-Forge To release a new version of `spyder-line-profiler` on Conda-Forge: * After the release on PyPI, an automatic PR in the [Conda-Forge feedstock repo for spyder-line-profiler](https://github.com/conda-forge/spyder-line-profiler-feedstock/pulls) should open. Merging this PR will update the respective Conda-Forge package.spyder-line-profiler-0.4.2/codecov.yml000066400000000000000000000004311507254163500177430ustar00rootroot00000000000000# See https://docs.codecov.io/docs/codecovyml-reference coverage: status: project: default: threshold: 5% # allow for 5% decrease in total coverage patch: default: target: 50% # require 50% of diff to be covered comment: layout: "files" spyder-line-profiler-0.4.2/img_src/000077500000000000000000000000001507254163500172235ustar00rootroot00000000000000spyder-line-profiler-0.4.2/img_src/screenshot_profiler.png000066400000000000000000002067631507254163500240260ustar00rootroot00000000000000‰PNG  IHDRß©ÚûÍÒsBITÛáOà pHYsÄÄ•+ IDATxœìÝgXWà³½R·Ð«ET±`±Ä^¢ÆÏMb‹5š¨±$šÄhl±%ö{�¬¨ˆ ‚€iÒYXØÞ¿£+.,,EXÍ}~,³3wÎÜ�ræÎ�œ]«v€ ‚ b2ð-‚ ‚ È{Pv‚ ‚ ˆiAÙ ‚ ‚ ¦e'‚ ‚˜”� ‚ bZˆºOV,®�­#‘DjÁhA�O˜T* +‹ rZ:ÄÔá°;Š½ÚøIeÒ¼,•RÙÒ!!‚ +_ÿÀĸhCßÒh KÇÊšóòÅÓæŒ ùèÀŠÅ•ɤ¹Yi- ‚ ò)“JÅÒ<±F­²bqËKy-bºð`cëX�—ÕÒ‘ ‚ ÿ ¥%Å6vŽ-bÒð@$‘ÐA¤y¨TJ"õqDjƒîÙAAÄ´ ìAAÓÒÙ —þãb8 ¤ï–ß×6a� ¶wÇæA� ˜ðôÑ}¾mZƒ ,K@Gÿsÿ ¿|¦�·ç¥SGÚx{À²Åóþ7al F…ipõbª®xº oA\.gßÎ-á—Ï|>zøêe‹¿; L`h˜f«Ï‰Ÿ�ºvîø•³ÿ8:Øß¾zNoî&²¢6­�t•@�¦õ¡²“ß/Ôí5„BÑæ»ëœ$¤wðÚUK�)<)5õÌ…Ëõ Éøò›SÖ¥ Íœ6eëÎÝ¡CF'§¾ÚsàhQqIÃÊ1ÍêÕÙwðXAQQËÆ0fø�Ä—É¡CFŸyĺGi4©LvþÒ•:G ˆŠ6êøÜÜüÜÜüú†a|ù‘@P©ÕÕ‡7lYšjî`kËÍÎÉÅ>_¾v£Á%›fõê\�¸Ýâ‘ØÙpcâ°ÏÑõ?¦âp8<§Vk‚¢ŸÆhµÚFúá¿Jª46›%‘Jˉ%g/êïFbâ˜á™,"�Ð<û„�ÚÒïæ�1�Ç€B¡œûÝòÇOcZ0<•¬‘)Z0€ORÙÉôÉ_ bnn^PP¸uçìloè °žÝ»––•‡öíÅç—.ÿy�»¶Sÿ7^«ÕnÞö×­{‘a!}úôê¡V©GýìùþÃÿœ9º/8l¬^¶X(¹89²Ù,¡P¸bíz¯p8\—€Ž;vïwt°?ðן»öîŸ>y"‡ßºcwqIÉ÷ æ°X¬ ÿ^ÃNž„ôÚwþ÷?Ò¨Ôå‹çtòÇãðù…E³ü ‘JØ,ëù³¾îØ¡=‘@ŒŒŠ^³ncÕòkœäÒ©#—®\ìÒ‰N£'¾LþcëN­Fsù̱y‹—§¥g€…¹ù¥S‡GN˜ZZVÜ#èÛÓ-ÌÌ®ÜW�Âô)„ö¡�)‘Q�7oû[*“aËrøŸ“a!}32³Vý²¾z ë–E7r¿Þ=™LæÙ —�Ÿ>o¨d½BªÇ¯T*õæþû¦msg}Õ³[WµZ}ífÄžGUjõ?þ²´0ß¾ñ7•J 6ç«9 ’S_U-¼¿ÞS&Žã°Ù)©ië6þ™_X„Íñô…Ëýzõ Óèc'M¯oõ*•ÊõkWÅÆ½8qæ<6—Ã{¶ÁA¥³³�Û¼}÷ó· VíkˆÞ}òÌù .�é ê…Ë×Nž½ˆ•ܯwO~Y¹oï3þ�Š~ºxþŸÖ^eåå{ ¿uÏÃÝuóïk--ÌÏ?‘Édô4²ê¬—-ž—›_xäŸS†~V&ƒ¾tñü.;—ðoÞºÛ'¸ûÔs«ÿ¬¿¯YA"‘°-üaUÖëœê U}ÝžùÕd›³nÍ ¥R±ïðñ¯ÝÔ+ÖȔޚý Û'@M›¶ ‡ýíŒé4*õüñ"±ôÓgU�c½¶5ÛJ“13·dqmõ–òŠ„•‚F–~ÚøëÈN²ss§Ï^(¨¨пߚ•KGŒŸ,“É k—€Õ¿nøcëÎo¦MÞ°vŽ�GN˜Ò¹c‡ß/¼÷0êFÄ�.�:dçæùçp9ìªevï8}öü²rÁœÓ¾žÞؘºò?5Lol„vmÛÌœ»X Úu?¯˜4aì¾CÇÂoßÚËNBûÇÆ%”–•ÛÚØü´lÉ’??�{1qüèÖ^žØäÓ&Olïë3mÖ±D²|É‚o¾œ´eçn`2è eⴙƴÃ3t˜òÍ\6ËúøÁÝ÷"*YOõøõæþÝÜÙö¶6ã¦|M£R7­[SQ!üçô¹ Sg\¿pb΢¥¯sràÒ©#zÅtôÿvÆôï–­NÏÌ=bè/«—M�1;kïä×þ«9‹T*Uê÷ê�ˆ)?Çö˜î®Îv6¶‘Qцª·Æ0ê[½:�:øÏœ¿$!ée÷®]–-™?jÂTøuõòÔ´WÃÇO¶°°Øº~MN~~äÃÇ5NÞ³{Дo¾--+Ÿøù¨ÕK¿›µàû7ž­��ÞÁãF�˜·xy�÷ù˗,X¼ü§_6la0Ocã°vÄÕËëkia¾uÃÚ?þÜyçÞ_ŸÖ¿¯Y9qÚ,~iôêÑmúì¼>‡#�üýÖmü ¬u«Ù°gû¦§1±Ýºv¡PÈÿ8€½�Æ'$ZZZ¬_»jìÈ¡GOœc¶µ€Žþ³þð<>Á·Më�¿ý4jâ—"‘¸Î5¤êÍdеZí´Ùó--ÌüµõUzVlü lÚy‹—¯Y·‘@ Ú½ýÁ£Ç‹–­òií½ù÷Ÿòò ’S_Í_²üÏ?~1~*8:ØÞ³½¾?ëÜY_ñ„!c'š››o]¿Ffà÷ûkNÚƒÍÈÐBUßÛlüsW� .+~þ=19¥Æb�ßAU]“Ãúõ©ZHõmgÛ_{CûôÆÒ—êŒÜÖj©É¦"¬Ðfl®½nŸWÐøÔðxüoÿLyÿ<ª*™¤’6_vŒN­v[rävéÙ‡Zu ´k’I$ ™¬7�@ 4[b‰ä‹©3k!¯ °^ÖÑï$âöýÒ²rµZsåZ¸H,vuv†§¦¥ßºs_¥R]�¸mÃåþ½ï�\®x�Ãálm¸µ—y=âvY¹¢?óöj… ì޵ˣ·�À8n÷þ# …âAT´Z¥9wùJ¹@PXÄ{þ"Á³•{Õ¢T*•••…‹““V«MIKW*•­Ü\Ü]]6oÿ[,‘¨Tª¸IzåWŸáôùË*µZ­Öœ<{1¬oo¸z#"´o/<ú÷»~ úw{ö<îiÌs•Z}ôø±øÍnzø��;÷,-+—ÉäûëÛ»§.Èc'΀1íðjµk/á—–¥gdzx¸×^rUÕã×›{ÿ�Þí?$Šx%üƒÇŽìß·Îx`ÄÐA§Ï_N}•®VkNž¹Àa³ìí°¯N�»¨T*±åj@õ>ˆŠ¶µábkÔ€Ð~·îE*•JCÕ[KÆW¯NâË”„¤—ðøé3[.‡Éd¸»:{{µÚþ÷>¹\Á㕜>©_¯šëÂoß+-+€“ç.µóõa³¬õ*¤HŸÓç/eçäÊdòmííÈd2êŒ*¤wpjZzÄíûjµ&>áåÓØ¸n��±¯nܺË+ác‹ÙÎ×'ûu–Ô¸ndçäî=tô·Õ?N?võ¯°3ÈìœÜ˜¸x•ZÍ/-;uö¢_»¶XÉÆlkiéX{IbrJÖëÜ À€ªaúiªnÑpâÌTT^ ¿Ú¯60%-kŽmåæjkÃÙ{ð¨J¥z‘˜t3ânXˆQëgUÕVè×»çÞCÿÈdr¯äì…º¯/ײP†ÖíZ¿ƒÃk²¡MÛ#·5#«¢‘Š s‹ r@ Z­¶¸ §¸0·©JŽ‘Äa³F TãߺŸ~ìÜÉ¿©æe$<•dóU˜ûö™TOûºÇþä¨Õ𨸄Zþ°�˜ñêh; é3vä06ËZ£Q³Y, slxYÙ›ö+¹L.–Hu×dr9�J«½ÌŠÊÊ7ÓÊåTÚ›‘ƒºtÞ´}öY¯ÀÒÒ7¹¶L&§Ñß+üÒÕ›,ëן–Ѩԫ×Ãÿ>p˜Ëáðù¥ …þ’®üꓨÕ(”¿]´2ÛRÒÒ+…¢€Ž~…Ån®N÷F›Í*,*ÆÆT©ÕÅ%< R)–æ«–.Òh4€‰HÄÒ±D‚-Ëêe‹ÃBúÀÁ£'ÿިƚ‘ÊdXSÈå :•f¨ä•?,Ò+­züUçN£R™ zQÑ›çFòØl6Á–ËmßÖgpX?Ý–µe^~`§õ ®^•J~çþ€Ð¾ï?Ö¯÷ª_ת^Ca”– t X/•o×@µZ£V«é4š­� ‰H<¶ÿÍH$‘2³² M^VþfY”J¥H$f³¬±ªÐU›e]Xü&òÒ²r¥RÉe³ª¶7ÔÈÆÖÆ§µ÷ÉCoƨTjÚ«Œ7…T©ên��±£¾¡uC£Ñ\ ¿=ë«©÷=ÎÉÍæ²¶²üvæt_Ÿ6d"‘D&a_À¸m ;—xIyÇšU5lCkHÕ-Z¡Pˆ%’7¥•–y¶rÓUö�Ãfñù¥º¦ø‚b^k/�Ú««ºê?«F­¡Óè¼’7½‹KŒíñ]ãBZ·kaüª–5¹ÆM»Fnk͆_R¨R«p -/«ßÁ©NSÿ7¾moCßÖØÆÜ ¨vîÛf”�yX´ï&˜|ç°&ÔÜWvÏŸ=cÞ’ôŒL8ux¯ñíçZM=~KK [[n²áf:C”Jåîý‡wï?ìää°é·ŸS_e¼ÎÍe³Y$©êÉAÕò«Orë^$ØÙÚ¾LN{;»Rþ›ƒÁµáa!} ‹ŠïÞ„]ÒâóK}ªlV–V “É++…?¬þ%#Cÿ…º•sõ¯Vÿº¡¾ h¨äê¥Õ¿nîR™L,‘ØÚr±#�­—Ï7jOÁ+)¹qçÔ¹ngÐÞˆê�X»rÙ³Ø8•FŸð T¯¡0ì›jÛç•”ˆ%’ñSg`GúÚÙÛÚ`˜ º¹S—”è‚á—–Ù½mA´¶²$‘H<~iÝ1ðJbââXYýZx·œA��W­]µ®u‹çÎŽzò, ƒ¿vX³Ç쯿”Ieÿ›>K&“÷ï×{ìÈauÆS}yÀÁÎönäÃ÷®é§ÑÛ¢Éd²µ•%¶îÙÛÛ½ËkßVY ¿”ÍféúÆÚÛpKJê®±:I¤R‰TÂåp°3"ÇИz?»¡Õ¾úº]û~ÎÈ@mG±êÛNí{W#·µæ$(kà�€µ°²´ðiíeèÛ¢â¬ì{ ²<‡Wù é?•š€X"ù|Ò×µŒPPX¿»&븲#—+róò ¨K€“c=Z«Ê';#GîÖ% úYŒ1=�üýœœp8\e…P¥R*ÕªŒ¬×™Ù¯ÌþšN£‰Dÿömõʯ> VÔ„1#­,-ÍÍͦL~÷>6ðzÄ�àn]õ¹vó6änäÃÀNìl ¤w°®Uÿüå«óg}Íår€Í²êMÄÈ’kŒ¿ªð[w¿ž2‰Édpج)ã?¿~Çȹñù(ŸÖ^8ŽA§÷ î�µ UÕàê}™’&WÈæÍþæzøm¬A»–ê­3ŒÆÈÈzý:'÷ÛÓè4:�wuvªåœ¬_ïàÖ^DaÆô©/“«¶!anÞ¾3zøgÎNŽT*eÎŒi?©³ánݽïçÛ6´_/"�@"‘üÛ·µµ±Ñ‡Ëå0´Œ·k\7Búû¶õ^³nÓÆ­;Wþ°�A§“ÁÈÉË—Éä yØgêS7àèàðÙÀþ>´_/{ûÇOÞ»9¢ÆŸFo‹Öh4ßL›L"‘<Ü]‡…ܺ£¿~fdeóøS'M ‰¾>mBûõ¾yÛ¨õ³N·ï>˜>y•Jár9£†64ZEe�@Ðõ�«q¡j\·ËËŽwŒFî jW}Û)lm8Ä·] :øµ3bh-ãCMÛÚÇ®{P—ZΖD=iÎ`t´ %ï@DæÌ�’”¼  ©Õš‰/kù«¾«¬]m'WoDÞ½½°ˆ÷*3 kA1Òåë7]¹4üÒéGÑOwìÞ_ûÈÝ;ß}øÈøÂulí¸?|7×ÚÊB"‘]»y+òác­V»tåÚßÎ8w|?p¢¢ã^$U-¿ú$Øð›·ïþýç–æ÷<:tì$6�_Z–”œêæêûö>…Â"Þo·®[³²RXù*=Kwv¸÷àÑ)ÇíÚ²ÞÒœÏ/½tåFÔ“g X¢êŒ,¹Æø«Úö×þs¾>ux�Z­¹~ûäÙ ÆÌýɳçÛví]ºh®½½­X,�‰‹¿óþ©3¼ÿóÕ«zàêÍÛ³¦OYöÓ/Ø¿†ª×˜0C«Õþ°ò—ogN;ud…BÉÉÉÛsH¿ƒ°Î¿7ÂçÏžáÑÊ5%íU�ía·îDÚr8[ׯ¡Óè1q/~Y¿Å˜ÊÊó–üøíÌé‹çÎVk4)©¯þغCoœî]»DE¿ûõ«¯é™YßÍ�õÃʵb‰$âîýžÝ».˜3cíúM{ùñû…½{v‰%ÏãºÖ'{~üô™;ßù³¿.áó—®\#Šª~[ãO£·EK¤²Ì¬ì 'i4šGOTЋZ­ùaåÏ‹ç;vþDyYù[vbgÿ�·uמeßÍ¿|êhq ?üÖ½®]:Õ8šL&?ôÏ©C»·‰Ä™ó¾«q¡j\·?µhÎŒEófíÚ»ÿÜÅ«zŹƒª}ªo;Ïbãó ‹®ž;.‘J†�›âãíÕ§W�Óç/£·­}ìzvïZË·š¥Û¯q|VÁ–‹Š¼&höû5ù•œ]«v¾þ�‰qð·´árÿ9°«ßàQ5~K àÿ=}lìä¯ôözMŘò/�:²héêWÕ¿úaÑÜÊJáÎ=>DlM¥–ø?´FV/v•aúì2Ʀ´zÙâä´W'Ï•Û5¹ ¿¬ºtåz䣿ÛóÖ#(pÉŠŸ�ŸDo•Àn— 2úƒÅh¬±#‡µóm³âçu-H=ÔwÓ6…mÍÈJcŽ;'ïîÚ¹æD***{ �=&§y0üÜÈöÖå×c[ðj‰D"TkQV(šúô²h ïç[[[`^Aa½:Æ6ÇÓØZ¹¹¾í�Y�“¹ïб”š4²|.—Ó¯WÏ©3ç5yTŸŒÆT/…B=ü³ ÿ^kò¨>Uqñ‰ÏbMýùcz‹®G{ •’‘‘åäh?vÔ°¿öléˆZÆ'¶­Mþú[w7C—w³sr++…Í�8>K¯ßý«™)›íF,°{vš°Àž�Œ9lÒ„±¿oÞfhAE噋ÿ~¸\þôÉ_Lø|Ô?'Ïb·¨ 5jpõtôß°vUL\üõ·}z#¸GЂÙïuÈâ—•5{acÊܹùw;Û÷n�ß¾»…›Ð =#Τ|è-º^è4Ú/«–ZZZŠÅ¢¯…ß¾ûàC¬*ðaÖÀ¦Ò´Ûš)�Éä‰/k~Æ òÉhŽ+;‚ ÈD3\ÙAþ ð •Ši´ºŸ… ‚ �G£3¤’ºodCþËð VZ± > AAš•Ê +Z: Ĥá ¨ ÇÒšccëD$’Z:Aä“E£3¬X{g7^Ó=Õù$áìZµÃ>Y±86v(AAA>©D,V4á w�OÕ»ìAAÄ4åãÀAAe'‚ ‚˜”� ‚ bZPv‚ ‚ ˆiAÙ ‚ ‚ ¦e'‚ ‚˜”� ‚ bZPv‚ ‚ ˆiAÙ ‚ ‚ ¦e'‚ ‚˜”� ‚ bZPv‚ ‚ ˆiAÙ ‚ ‚ ¦e'‚ ‚˜”� ‚ bZPv‚ ‚ ˆiAÙ ‚ ‚ ¦e'‚ ‚˜”� ‚ bZPv‚ ‚ ˆi!¶t‚ ‚|Ü<‰D"à ‹æÎ´±á@qqÉÆ?w©5j¥R©Vkê[ ήU»zM`ii�Çáª)ThµÚúθ1p8\`@G …\uàóø„J¡¨9Ã@Aþãª5Z­@PѲñ´”Áa!;·ü^ãW³æåFD} ¬_v²sËïƒÃBôvã•ðë;ãÆ˜1mÒœÓ**„U~5gÑË”Ôæ ùÏâr9¿­^îìä¸÷ÐÑ6^ž¯Ò3��:; ¤ï€Ð¾ó¿ÿ‘ËaŸ9º/8lX“ÏÂÐÈËÏËÍ/<òÏ©ê_9:ØøëÏÐ!£ÃÞ›=ñ *Ú˜‘'Ž=aìH­�šÐ€y!ÈÇhëúµÃ‡ Ôý«T©~ݰeÿáã͆›«³³£Cõáñ‰/›-[²´´è@£R±ñø7ýF$éÓØ¸J¡°¾-(õ»²Ó¹£ÿôÙ cžÇWXÞì©¢“£Ã©³—~^·±™ç‹|bŽìÙîÑÊ•1±qü¹SPQiÌ„c†I|™tôÄ™‹ÿbÃ��\2¿µ—gn~á†-Ûã^$V/üËÿ�3b(™Bºqw㟻Tju-"Hí:úWýwó¶¿§L'—+Ž�4x.ÑäœìÃ/�*-+¯:�Çs9ì´ôÌ/¾œÙ<ÍAÅØ‘Ãúw×~7òQïžÝÆŽVß”úe'8N$[[Y-_2ŸF£VýêßkáGOœ©Wi�diiqòÐng§÷ÆG�ŸN›µ 9Ã@>j¿lØrýæ-[îš•Kgýå/¶è¾"Ø¡«:;nL|ö9úi¬Þ·R™ìü¥+� ¬öY艉‹¯}„�Íf‰%’r� ÓêÕ³ —»fÅÒ5ë7E?�Y0û›Ÿ–/™µà{½Iæ|ó%‡Ã1aг£ãæßÊÌΉ��Çã×ýüãã'1 ¾_Ú{ÃÚU#&L‰ÞKÚúõ 5|ÈœÅË„•Â�¿ý…Bqúü忉ÁƆ+•Ê{¬:ÐÜŒ™ðäž—‡û™£{ÇM™QPXÔ<ÁT§ÕjOœ½xûþƒ¨'1õš°!½b'ŒÙÊÝ56î½­·R(44þÒ¶µ—-—óÅÔ™ï‡�ºž õ ÕjTju^Aaø­»¡ýzÀ¥SGN_¸Ü¯W:�>vÒôñcFŒ1”A§ÅĽذy» ¢rùâù݃;wê0iüh°°°ØwðXÕË.U¯ì`¥õîÞÍÌŒ™˜œüëú-Ø‘¸Op÷Y_iafvåFx»¶>zP Í»LsøŸ“ýz÷d2™g/\>~úßÿ¸F ¨*nFÜ< $6þEko;Û=ŽHe²s¯~>rx¯AW®Gx¸»öêÑmßá`pXÈ…¯eddÀ¡NÌþjê¾CÇ ØD«òß’›_ðÅ—³Nú;)9Í:¸8; íÓü›tp8ܸQÃ8öµ›·ë5aC²"‘ýìûk8l–�­�n¸¯OëôÌ,™LÞ€2‡Ç+UªØø3&ÓÃ݇À¹³C{ßÌ×9Æ5Ñ#ШԠÀ€ÜÜ|ìßN~í¿š³H¥R…ô7zļÅË‹x¼Î]¾dÁâå?ý²a ƒÁx‡5�¬^¶¸öÂÛù´ùfî"صu}ÿ~½¯Þ¼egË]ñâŽOL7jDk/O½Ij™“A€)ßÌe³¬�Ü}/òQAQ±îÛYÓ§ãñx‹Ýø21%üÒ5¿oÂápý7­ûùiìsCcòJJnDÜ9uîbÕ�>­½}Úxëþµ²´ª>á/+—î9xìFÄmµZóâ¹úÝ´šwm!2™¼²RøÃê_°®ï�fàIYÙ¯»vÆ>³¬­,-Ì3³³«ŽP\R"‘J<ÜܰÆ'Ow׬ìר„Nö Y.W€G+·¨§úÇŒÌìœVî®w#b#K¤R¹B^c�bŒ•K©TïºuÓhT±Åsº~óŽCÇN@RrÚùãZ*Œ&Ѩ'ÙK¥Ò%?þ¬ûÛþ×¾¦ «vA…^·’u›¶í>p¶ìØýë[›' ä“wóö�ÑÃ?svr¤R)sfL{øøI}Njt7òaçN:úµ'ðãG�033k|™˜¾Á=¬,-µZm™@ Õhªî4õœ¿|õ‹ÏGù´öÂáp :½op<7òa`§Žv¶Ò;˜Í²®>!ƒÎÈÈÌV«56\n¯îAÕG(lm8DA7£ù³¾ær9ÀfYu ¨}"îD¶ñöêÕ£�FûfÚ¤ø„¤Â"÷ éjµæfÄÝ©“Æ›››ù´ö í×çÊõHIM/(*š6é *•2d`ËÚúþÃÇàáî:mÒ›G°\½1ü³�®ÎN,k«IãÇü{=¢–Äß.ZÖ®K/Ýß�ðúõýlZº+•-ÐóR¡PÔ8�HjP×L~ç>¶ë1c2£ï^«úUsÞ2ý´gÿ¡Øç˧�`]^NÞƒ]èA�Æ»u'Ò–ÃÙº~ �F�‰{ñËú-uOc„‚¢âµ¿oZ¶d¾9“yåFxzf¦BYÃVÝþ~¾ çΤP(åeåk×o®¨¬43cÖ8æ“gÏ·íÚ»tÑ\{{[±X'òaaï·�[×­YY)¬|•ž•œúªú„¿oÙþÓòÅ%¥eeeå�žè7NÀ³Øøü¢«çŽK¤’áã¦ì=xtÊÄq»¶¬·´0çóK/]¹UÓT:EÅÅ+×®›7û.›÷"qõ¯°áº^±°í¯}KÍ»xâ°X"ù{ïA¬ÍC£Ñ,]õË�Kæß}*¯ pñ�? …"x¿WlÄíû.ŽŽý¹�D"Þ¼uïÐÑXá5ˆ ÆØ¹y�Zó®�#™L®eämÉ‚Ù"±X$/Y0»ùç¾eÇ©TF"“t]ÝUJÕ™ —7þöSâË”ú–Vï'Ùëtôkw¾Ú¥µr�À?¨_M£@™‰O |VvÎÖ�{–~7׆ËŸN=uÝßÄdøÏü3sÞb¬ï-‚ ‘˧�´÷õ©ñ«�#&4ÏÅæ—Ovqvªñ[� b—3kïºÞ´¦Oþ¢ƒÿ›¼‚€Çw èȲ¶ºqçëo¿«W9 ¿<–˜œzñßëU*4ÍÅ+×\`ƒý¹kO¿Þ=q8Ü´Éx%üb^É£èg(5ALYP—€Øøj•zÒ„±‚ AN^~KG„ H½}3wqP—Nº§¶ë5ÛÃN***ƒÃ†7ϼŒñ(úY»¶m°«9j�&êÉ3•Rõ÷þ#õ-§ám'‚4Ø’ù³CúôÒjµ™Ù¯7lÙž™�ÓÒ!‚˜”� ‚ bZuÏ‚ ‚ H“CÙ ‚ ‚ ¦e'‚ ‚˜”� ‚ bZPv‚ ‚ ˆiAÙ ‚ ‚ ¦e'‚ ‚˜”� ‚ bZPv‚ ‚ ˆiAÙ ‚ ‚ ¦e'‚ ‚˜–*ï(v Ây‡Õ¼å‚AAä?©"JÒ´Iÿbÿ½} `È2¨(„„³ «lÉàAù²pĹt—@íåÅ@0³¶× RáéPÉ[::AAþ{ä•PüˆDƒ ‚<"à¼Ã´÷6€¯`KG×(‰qÑ-µ-8ë–ò\d#}Ô5óQ� ˆIIŒ‹®÷4™¡×BÈ~Œ š£ :‚ ‚´0Y%Öÿݳƒ ‚ ˆiAÙ ‚ ‚ ¦e'‚ ‚˜–¦ÉN|¼Ü7þô]“Õ"¾ÿvj¯nÍ9G¿gÓ*[.»ÉKöñrÿaÞ—�,ÄÑÞæçïg„& ©‘Úûx­[1¯úðzÕá’o¿lÛºU##™9ulPgÿFÒxnåA>jhÅ@>%ĺGy_Xïnݺø¯Z¿³êÀBÿÜ•ˆ¦‹ `ӚŠWlhªÒª‡=|`_o—ß·€ð»�‹Jø@"w®_¾ü×m<~Y“Ì÷ûo§z¸9W¾qç¡ãç®U EM2—ªÆ ;}éf# É+(.(*éÓ= â~ý{\¿µ}ÝR ™ ©,;·àÌ¥ðÜ‚¢FV•F£ÕÕáÈÏB¬-Í÷=Wã˜�Ú·Áã!)%£‘s¼týî‚ÿ{úí‹‘‹Výc†ögY[Ê g{ …rë~ô­È7çß^­\FîggÉ¥·#ߊ4¸!¹9;f¾Î׈Ãázv;< ´@¥’DÇ5U‚òý·SÇ$Ü{ôlѬI°hÖ$•Jó :öæ�GãGìЮ ‰D”H¥¯Ý�ªçaI­VcgÙj�F«Õ*U*l8�€ÿkÃÊëvñøc†ö·47S(•þme2ùÉK7x%e“Ʊã²3^çî9rN(…L>°O‡ö­©Jæë¼cg¯”–UèÍο�wrZ–®Z~\øu\BJkOWwW§â’²½GÏ:ÙÛØ—Á >‰M8zæªV«%àñ5.cZF¶µ•…ƒ7¯ ¸Á«ÑjÕj� Bxû~t€_[Ks¦D*¯q)~\øuJz–«£�…¹Ùå›÷žÄ&êðYÿ`*…ûâå‘Sÿª5ÿ׆+Öíp´³éÔ �Çÿ²l.üôÇ.…B©›ÐŒA÷puÜsä öo{¯ £†ß}<0¤•LºóðÙÍ;�&}>ÔÇ˽´\pàÄŬ×ùàíá6vh(›e…Å%¿o;€ÕjRj¦»Ö ËN¸,ëÜüBÈÉ+íÕ ¼Z¹8Øqÿ9wµÆñ›yåA>vº-¢ˆÇÇÖóÈDZþ¾­tZZF6¶Õ€qûaËjôÐPWg‰˜_X¼mïq‰Tæho;nD˜“½­D*{ô$îê­HµZC¥�·ý¶ôÄùk�ÛÓéA…pßñ‹ååc†öwr°9¸ï€~= ‹w8‰Ãႃ:õíÙÅÚÒœWRvúrxÊ«,0pÈðk«·Q3éôÿ�ùÌÕÙ�Ç *„{ŽœÉ+ä5s #�dÍâÚ9ºàÀÉ¥U_^Vbhä¦ÉNôøùxý¾ý@vN>—mµjñ¬¤ÔŒ"ßÑŽ;ï«/ö;—”jñžÿÍÄJ¡øi\’Þ´ßNïéîB&ÕýÌ£¯ aƒúðx?r�J»q÷QÓF¾qçá�ë—oÜy»²Ó½K‡VnÎ+Öm—Heæf &�Þ´³Óéоõ�.üsöj×Ní'�šž•³ûð™J¡xÎôqƒCƒOœ¿SÆ¥’)¿mÙ'’H‡ôï5gÚ„5ÿּ߯àâhóâeÕ!=;î:x²°¸d¨Á³¿—žùúç�1´æNKJÉŒMHîàWã2*”ª~™³£mc² �€ïܱ�D*«Š¿úßHCKоíïÛö•W«—`ianoËY¹n‡“¾hÖ¤î]üï?~×ò,>ÉÙÉÎP#°“£­B¡(¼{¢�¥¹¹µ•Å�¿nã°¬˜7­�—ûé‹7w>3d@ïIc‡þ´aL?ìÒÍ{¢Ÿx7gGÝ´yEÅ]Ú5¬ò Šôé†Çã[{¸ä“ɤ #í:x²‘IvS­<È'†ee)W(Ù¼‡L".�ÿ¶Õ³¦RÈ‹fMŠKLýñ·m ¥ÒÕÉA£ÑÐiÔ…3ÿwû~ô–¿�rXVs¿úB¥Ñ\‹ˆÄ&iåæüû¶ýj�fÒçCF î·÷è¹Ó—nzº9W½²Ó«[§°>Ýwî?™WXÜ®�çœ/?_µþ¯ÒrÔtȨ¾QݧB(únõ&�FÃe³d2Y3Ö%Òlí�Y\;x··Ã98¹Q¨´¢‚œÇÿ ÷ì¼LËÈÎÉ¿¼¨¸ÄÅÑúô蟛�¬Ñh ‹ù·îGvªa/¿mïñ¹ËÖ•–Wüºe�n ‘@1¨ï¨!!Xj<~Ô��áƒú�î¹iËem^³X÷Ú;¨ÎIT*�Jvr°#•BqA±Á,¯‘^eä<�KRªTž<'“ˆÇòøe2¹üñ³nÎö`aÆ ðk{ôì¿B‘Z­¾xýËÊÂÑÞF¯:�*“¾wEìþã˜×y… ¥êÑÓ8ËêÔ¥p‰TÆã—'¥f¸:Û×¾Œ2™œA§5f¹&�²ñ§ï¶ý¶ÔÛÃu×ÁSf z-KScjjµæôÅ2¹¼¤´üyBª«‹ƒñ10h4‰ì½:Qk4ç®DÈäŠÜ‚¢¬œ¼ŒìÜÔŒl¥JõàqŒƒ-‡D$€R­¶µa[YY¨Õšô¬]!“Ê™ ­“/ÓR3_/ùvŠg+—3—ÃG ê÷èi~îW–̙ڻ{ûe7Õʃ|bdrÅ­ûÑ Pª’S3±­Æ˜ý°_[o<žpêâM©L®Vk2²ser…[o…Bq%"R¥Ró¯ÝzØ3°ƒn’›wa 3ñ‰inÎ5ož!Á�—oÞÍ-(Òjµ/^¦¥f¼îè×ûªÆC†•ZmeafgÀâ~…Ét¯AŒáà܊ű…÷OÄ´€cqlí�Ükœäƒ´�ˆ«tÔR(•T*ØÖVNŽvk—Î~3c Ëš«³²4§S)Eo“$qì°°ž�õN1µZí€>Ý4Ú©‹7t�Þµ()-Û¸ëˆîß°>Ýjܪzò<Ñœ9vh¨ —•šž}örÄJP**ßœÙc øºƒ´\¡ RÞÔ,øf¢n•JeaÆÔ+G"•QiäªCoKV(”*•Zôö§Q(ØïRË2R©±DÚ˜å:s)<þeªT*Ç~ V.Nµ,…À@jB‘H×E.WXV[ðZˆ¥R:õ½:ŠDjõ»Òtó•Ë•8ŽJ!+UªûO íµráשìAôók·`ãPiQ#êäâµ;¯Ý7g7gûSo,ž3õæ�/Ó²V.ü&=+·-UMµò Ÿ±D¢Ûg*”J+ 30n?̲¶äóËôšÖ¬¬Ìùe]�üÒ2kËw/´ŠßôpT*•ØZWÛÚjØ€>ƒúõÀþ%“)ºµ½ÆC†ž³—#>ëßkÖÔÏ©TÊó/Ïþ{K"EÍ' �&—Iô‡âp@g0jœäƒd'5â—WðËÊ�œ¾RË8!½ºìÛƒD"‰„?V/Â:²XYš‰„è˜5NB$¬¬Ìy%ußb£Vk«6ïËd5ôºÕTK€nÞ�ºy7ŠN£Ž:eüðª-:Í©T € ;UTÖvÆ�“_doíWɆ–‘L"rØÖ9y�º¬#‘É*…ï:f×¾ZhÄÃ)rò‹Éd²•¥yÕ_¿NE%9ƒÃáÜ�ç}óE^AqBò+p´µÉÍkì�G$"ñ‹Qƒv9£Õj�í¹)¯^+ʬÜ|gû&¸ŽV�‘+ò_`Ì~¸´LÀfYáp¸ª'„åå•l«wÙ,«²º6( ¼·UòË*.^¿ýô¹þÕ|ÃÓ¿7¹X"=yáúÉ ×ÙÖ–_O3(¤ç™ËáÆ…´´ôTý®„ujЕ�ˆDÝoT!÷> ìØ®“Ÿ�@ ðvÜêwKFÜ{¼hÕ‰)é‡N\ÂRà•”:qéÀ‰‹5þ:qɘÔÄHjµZ,‘êàÕÊÅÙÁ�ÇË ©T¦Ñ6ä>Ò&!¨ÆÄ¿œ4vˆµ¥ÐiT¬&õF‹KHiãéŽÃáŒ/ÙÐ2zy¸– *ó ›ò`iäR4@…PÄaYÕ¸*ŠDâŒìÜ6^nÆ—F à»øÑiT­V[)©Õj]Ë��—{lbj#£6¨Ï“牅Å|(æ—99ØàñxG;nqÝÇ®çÃU;Ò²ˆD‚n?Lhºýp|R*hµc‡†R)ßÊʼnJ!Ç%¥R(¤}º{@ß×>¯ŠJ‘� K÷ïíÈèáûº:Ùãp82‰èÕʅ˶ªmò÷7êNíÛ°¬,@(–*•J�ºÅöÆHóhHÛ‰½ gçúåºO^¼Q`Dßéœü­{�Ðçc>ÃápE<þÕˆ5D$´ñt;rêr}Ov›Ê¹#&ŽùŒB&Ýyð4¯¨ø‹Ñ½X–æJ•:'¿èЉKÍ�ÎÁ‡7{²“!‘JSÓ³ãRôÆI~•%“ËÛxº½4ú¦bssf�ËØ½‹ÿ­Èè&¼mcÌR4@tlbÇö>›×,Æáp‹Wo’¿;zÄýè�àÀGOêq£Mç¾£‡õ'‰,üÞã—©`oñ¶¶xö¼Þ'U¹:;x»»üöç~ìßÎ\7r‡KJËÌÈÎmLɵø@ÕŽ´¬õ«ê>Ç%¦þuèT�“³–Éì:úù°°ýzHe²GOãoÜ~Xû¼nÜ~4eÜО�s ŠþØqèÎçJ¥jò¸alk •R••[pòBmOfÒÛ¨]œìÇcШr…*)åÕÕ[5>�O ήU;ܰMÚ‹ àcsz ¾üÝtÞ;ïãå>t`ïu[÷7¦G;î7“ǬÞð—Úð Šé,²1–|ûå•ð{�| ÛŒÉc^$§Õ™å|\5£ç£A“’§ÿ+W&“æf¥é —JÅÒ<±F­²bqËKõ{¯~�§±!‚ ‚€�­cA^–¡oKKŠmì«GÙ ‚ ‚ O ’HU/èèQ©”D"‰€×ÆÁ{Wvªw¯Õ í× ~ën‚kÌ´õUË"|³n)ÿÁE6ÒG]3uð‚˜”:ïÐÁ¨«�†ÚNA1-¨W,‚ Ÿ¦ÀŽí¢c k§v�c �Ö½‹?ÇÚ‡ƒ·�¼zë�V ƒC{^»õPïá~<?4¬×ƒèçü²šßÖœ|¼ÜílØ·"ŸTØÊÅp�‘�Wçäv\¶�—û­OêAš�Ée'íÛxÚÙ°)d²L.ÏÊ)x•õæNh;¶¯w+•ZZ.ˆMH‘Êä-'‚ ¦ŒJ!cY•B–ËkH/t>‰Ã>|ÒóI\ïíû°·U¢ÑhîGÅT}�T R(•*•~ø¹£Rdá!H˜\v’_\’ž�«R©™ Z—¾•"qqI)�F ðó‰MHá•”µ÷ñìԾ̓·;A�êÌ™ŒÊJÑ›�È!l¹,O7g2™TÄãǾ}üHÏ@‰H!“<‰Óµ�àp¸v­=¸k­V«R©ãS+„5¿v‘€Çé|ýÎ#Y•´)¸kÇÌ×ùy…Å–æfí}<Édh!;¯ =+l9î.Že‚ s&“É e¾ÎÏxý®QD¡P*ÞïuО˲VkÔ^î.ý\$®ö†Ø÷µñtsv°Åáp/Ó2sòß¼êÒÁŽëíîB TjÕó„TA¥Á‰€£��›³}ò«,_o*™\TRú,þ%‰HÚóê­ …ºøñø™9ùµ/‚˜\vRúvSI@¥V3é´b[® B˜_È€¤ÔŒ}»3è4q#^d� ȧŠ@ÀøµeÒi ¥’öÆ>y�£:+KóÛŸ�H¤�]¸lk¬e%"2ÂzUӖ˲¶4¿ùD«ÕÚÙ°m¹,CÙ‰Z£I¤L]&WP(d•R¥ÖhÌt¡HL àƒÚ'¦¤çÓ¨”>Ý;‹Ä’"^©F£eYY¤fd'¥fš›1ûtëô:¿P×^¢R©•JUÕYD={Ñ-À¯˜_jäR3t©L~ãnËÊ¢G¿L&WX˜3;øzGF?¯¨ÙpXÝ»ø]¿UËÛ-„b±…³µ§Û㘑XRûëHk_"1¹ìÚxº¹9;�ID±D–WÄs3†îåï2¹B.W0t”� R�Z­‰ŽMðó‰KJU©Ô~>q‰©ª†¾Ò6#;O£ÑÊå �PÄ ÓjS©T14[.�_VXÌÇÞAmˆH$1c2$RY¿ž]R^eç䉡HÌaYiµÚÜ‚b�ÊäyÅv\v¯dr�_•BШ¡èMsHQ ¿‘/¸Vk4¯ó  ´¼B,•±¬-ó yNö¶üR¶ï-.)•Ë\–U!Ïàr)•*"‰˜–ñk§©ó¢µ,‚4SvÒ§gwgGCßî;t¬ê¿¯²r²s ¬­,¬-ͱTšH Tíh¢T©H$SÌ«1$Û{�Hħ& ë«Õhkk à— â’Ò\íü}½¢ÄÔtA…Áë •"1“AÃãÙ™Ùy¶\VyE¥X"ÓhµT*¥j'\¹BaeiŽ}®Ú:¢ÕÞ…£ÑhÕê “ËuÉ„B¡$“H@&Ù,K]�@ “I‹ÀKŒ·|-K„ ÍtŒ¿ùÐøç�¨Tj•J�_Èc[Yzº9¥¤g«Ôj"áÝ£ZHD¢^3&‚ †Ë¶nåêhaÆ ìØ�Ça²ròy�k]0F~!/¿�‡Çã=\»ø·½yﱡ1+…"G; 3³Ø„dÛšee�]’Éää*¯I#“HÍsÀ{3%“°>"R™¼ˆWú,þe½ŠRk4UÿÕ‚Þ&.€N,#™úóN°¦ÔJ¡ØÜŒ� ¡�É2©Î^‚ü7ñøe™Ùyi™¯£c2³óÒ2^GÇ&4CjâêdßÚÃ4� ²æ':B±„É  x‰TV\RêdoƒÝ_S*¨À„ïñ IDATãñŽv\ Q)N¶X»P©ÕLð8\Õ³»‘ID{XY˜Ó©T~¹ò‹JlØÖfL:Lÿ¶µ·�Ô†J­RªÌt0c2t{r©�i¥±ÞÕÉ¡°¸D¥R³­-�mã“Ò ¿ˆ×ÚÓÕÞ†Ã+-óñrã— P§A a[[b]7tšP[owg; �I�|5Zm!�—˜ZÈãû·õ îªÑhTjuíMB‘„É §¤g@¯ÔÛÃU(€J¥Žzö¢½�gkO7­F›˜’Þàç©d¼Îëèë=¤°B¡|™–YK=àñ8A…�mméãå†ÇãŸ'¦`÷`W Eq/Óºøûâñx­V›–ùkS©¯ɯü}½¥R™H"å•”áð¦~VŒ˜œ]«v¸a›´Ö>^ó<É�Çvðµ¶4'b©4;·@×áÜΆݮµ•BAÏ;AA��…¯`íïÇÐËIL«íD£ÑDż¨ñ«:ûÀ#‚ òi@-l‚ ‚˜”� ‚ bZPv‚ ‚ ˆiAÙ ‚ ‚ ¦Å´zÅ"‚´”^];ó˰»|›Ð�þÁxN«�V[Q)LJÍ(3úiªzBƒÃï×pïƒ Û:¨³ß…kwV¬‡›“ok¨òàù؄݋?4W'{WG»û�c5oìè«Õ“ç‰!Á�ù…¼äWY�ýÛJ$Ò¤´LÝT–æf½‚:]ºy¯O÷€´Ìœ¼úÜ7n¨?aÃö ¿÷¸Î'q4rEjZ&—�´oãigæ�É2¹<+§àUVP)d_o+ s …|ãÎ#t;1‚ MîybªRõABýði<¿L@ ¼Ü�;¶»vûa ¡Q)2¹Æ¯Ê•÷£b!¿´¼E^üN§Q}½[Ý�ŠÑTÉ�T*5öÀY•R…ý""±Dï%GtU$‘Ôù*Ÿêj©F¤ñ+R2¹ì$¿¸$=;W¥R3´.|+Eââ’R-@qIYzVn�À- ‚ ¦ŽJ!‡õîݱ]k 3¦R¥ºq7 tš¿¯7ƒFÅãñY¹©o›I:øzÛrÙ$"1-óuÕ¶kKóöm<‰D"à  ¨äåÛsw;®·» �@P©UÏR•ß§S•Z­ÎÉ/òöp%“IZ�vphÏ«·`Ï7ëàWÄãgæä“ɤAýzľH¶·å0h´ ¡(æE²V«e[[vð%’ˆûv€"ÿyb*0ôž�p8™LÒ�ò:Øq�l±åMÏÊuq°•ÊOž'€…9³]k*•‚HÍx]gIHpà‹¤4G{;6O¸óè™P$6T½ ÙÏÇ {,¿T�˜šŽ½êÈß×[.W(”*O7'"‘�”𙕓�•ïÝÊ%¯ˆ§÷ìo¥R…½ Y©Ra/-‰%\¶5�É$2‰$Kh4Šn*�Ú+¨#�FŠÄOã_b�’³a[·õnE"ÕMRjö@ CÕh�ïàëͲ²Àápe‚ÊØ„,0G;7gûäWYþ¾ÞT2¹¨äÍóþ�¯^:�Ü5üþc‰T† éÔ1¯°$#;�õñt³³å€D"‹™†µyôíÑ95=;¿¨¼Ü�-ÍÍžÄ%Õ¼�—»“½�R©ÊÎ-x·D ¯qE€~=º¼Î/dYYR)$¬AK&WTŸ×‡`rÙIéÛ#Š$ R«™tZ1€\®ÈÊÉ'M.ZAL�L®P«Õ�ýÛ&§eóËt/yiׯ£R(zø$ŽN£†ô ,æ•b‰ÅóÄT€ÔNíÛè•ã×Ö+%=»°˜�ÇãýÛz1è4±DjaÎìàëý¼¢RdÃauïâwýN”Úˆ 7g¡P¬P( íÍ´-0è´Ç1 x<¾¯®\–U1¿Œ_&ˆŠyÑ-ÀO¯ÝE$–\»ý�A§…öêZµ–•åµÛ»th˲²xð$î³Ð`2‰¨Öh‚:µOIÏÎÎ- Ó¨½»E’òŠÚ.3 E’öm½²s â“Òt/Ð1T½|½årÅ­È'8®[g¿Ön‰)é ‰Ýœ**E·±‰)…Å|;n§ö>W""µZ­¡j4ÄÝÅÁŒA�¸ 8\¯ ŽnÎöéY¹ ‹-̘­=ÝÇ$ˆÄl‰¼ñÕ+‘ÊŠJJ]�챔׌A77cæ>KwWG.ÇúÞ£¥JÕÖÛ½³Û»�žmUlkK7'û[žÈä ì o–È@á5®H ­ Û:êÙ �VØÁ·•‹cÕëk”)ïÛxº¹9;�ID±D–WÔÀwL ò_¦T©xü²b~èÚÿŸÆ½Ä>K¤2‘XÂdÐjoöP©Ô¶\‰TV)Ç&¤`�ìmù¥‚ŠJ—”Êå .˪�WÛ³"ƒÚkµ@$ò Š=‹¯3xìœ[£ÑEbúûW4Œ¡ÕjE"±Z­–Ëb‰T­Ñ¨T*2™Ì Óx„÷I÷Ž´æ¬mhÎÍ¿ÜÅFY�¿Xœ0 b̈‚ š[¤¥57h‘Jm6[ÜÝܤ­ò®Rk|é™ÜB­ÖdvtïwCsK€¯×=iCôFcYems‹tØ ¸c§Îéõ†N»ÑžËe•ƒý¼UjMþåÒ! "BJì´ËA÷Úc4™êÅ~Þ¢Ú†«w÷TTÕ1h´Œaƒ(ŠJ¥9{¡ýÆœ’òê�qQ>Ï`04µH\8Ž"Z±´µº®qTÚ“ÉTRQc6›É7‰½Â;}#Ù»çÈK$ä²YÒÖ¶ØÈÐ3y…4*5:<¸¡¹ÅqcoÅ;4ŽÜ­Øq¾±£3(]¿:Ó½c1 KIŠåó\qWkµUµ åUuäK“&Œ²Í¹óÀq4%Aä¶– Èsx[ï�-2,ˆÅdÜÙ=›˜r1ÏÑòw2�1‰s��X,–ìÜŽw—‘œdõ:A¤§”TTß“6¤¬²ÖÁ$’;‡Í ö÷Éê�u𜟳Ï;AAîT­® ¨lp|4Ö­{jnk 1é)I—K+•wedvCÎ5v‚ ‚ÜUªë«ëû»ýàBa‰ub%r=4v‚ ‚ ˆsAÑ ‚ ‚ ÎE'‚ ‚8§›wîí)dÐé:½¾²¦¡´²<î¡�î®.‚hn‘\.#÷#@AäÎãtÑI}sKYU­ÉdærXÉI± •º¹EÊb2jêÏ·á8>0.*~@øÍ.#� ‚ ÈíÂ颩¬}Ñ@•Lf3—Íj¾²c'©¬ª6úÊv‹‚ ‚Üyœ.:€èðàà_:�ªÖèêš:îÔÀç¹*•ê~©‚ ‚ } �¢“Qéi~¾ö^]½v½íÓÒÊšªÚ¾»ŸçÚa¹z‘À=ÀÇëØ©s½UQAAú[E'G2³º¾G�Éd6™Ìõ�b¡;/<Ø¿¨¬ŠL¸» NŒ9uþâݹæ1‚ ‚Ü%œýŽb›E>¸»¥ Œ;“Wh�˜‚ ‚ Èɹ¢ÇBƒüÙ,&�Fóñôðój‘¶€»›ëÐ�qy‹¥­m†á7ÚjAA�Û—sÍŠ% Ü£BqWkµ—J*È»u‚ü½itZòÀX2›Ùlþoÿñ~­)‚ ‚ ½Å¹¢‹Å’�›}úù‹Åç/÷}}Aé{è ‚ ‚ ÎE'‚ ‚8§¸²C ìï* ‚ Ò“ —\º},;AAĹ èA�þÁb°?{zéÎå»÷¬Ø¿ù“-=^~ò€”cßgv=ÿO¯ý<÷¾y=^�¾ñÞœ÷_œü¢õ©› oñmÿ|ç¶¥;ÞxìM&�Ù�us€Å`mühÓôÑÓmÝ\x›—lM‹ï¯Z!ÎÀ)®ìØzqÊK#ÒÝ]øR…tÛñ­ü""=új€W V\üzË×u͵7[ò##¹/ub°wè¾Ó{–¯_F& \¯Í|c@P4�ë>õýGÄ­-d:‹Á^8uaZÜp Pþ;ù߯;~&¢çZéÈœ{çLΘB§Óž9ðÕ¦¯Ìs‡ þ¢€·+Ò?ª®¥nå?+òË.@RøÀyç…ùG´*e3_ýSÿìé¥iñÃÉÇZ½öÞWÇõM+nQ§mì Ó޲wàð¸´ç&¿èáæq¡<Ù_ŸµÈ[ú´=]@Åñç'/:`¨ÀMP×R¿f×êÌ í·Í§Æ¦Îð?_I›äϽk÷žÚsýác‡Œ›3aŽ·À§QÚôÙŸK.Uömõ»cDbF gà´¦ªu7½s…B¹áŸdaÅÅg¿\Ðõ2—­ÿ\­SÝlMìéJ {ÊȤ‘Q�QO|6ך²èÑW-„eú‡SéTúg –ξwö/;~é›ÊDD*5ÊIƒãl8†GF/œ¼�Ëâvx©M)_¹ñËwf¿?ëã™F“±×jŠ85§‹NŽ�?¼ùÈ&•Vå'ò_òÔ§•�U§ ³e Ù×ÿ®l�5Q)ø´1Óß›ýÁ‚/žºÙ’%mÒ?výžž8Ò6ÑBX² ³7úçë—¾±Mî‘ç}>�/™Å¢1?v¹¬M²ùèæ[lZWŒtÏÓ_þþe•Fñù³_>~ïœ?vÿn›£`KžþôtaÎë?¼6vȸ¥Ï|>탩*­JkÔîÈÚÁã¸=^óa£´yx|ÚâyÍýtN­¸Æ…íòñü%ßþûõîS»“—.X^\]TÙXi{lò€”&¿°|ÃòŠBO¾H¡VôW+ºHà*Xýö&�AÅië?ü*Ê}÷ DD¾0e¡;ÇÝD˜weïÜtèò�Wg¼.SÈTjÅŒq�±ìUÛ~Ü‘¹Í^ùþ¢€ï^ùžBÁx\·ŒÒoXŸ×g¾™—ÆarÖXoý‹ãqݶ-ýïó¿>‘8ÒGèSR[òùºÏ,„ÅA£6}²yö'³ÞœõN¨oˆV¯�òÞ#à+ô}mæë>B_œ‚ý—µcíÞµŽ —¶àáç°Ü¢3<�Üâ³[Žm€{Þ3ëÞ9 C§×|±aYQMû" {êþ§ßý»íyAù…“OjõZ­^›uáDbDÒ ;áz#“FNΘRP‘æî'òßrä_²&Ž�M_VWzÃèdö½³GùçðÆq)ã¯õäÅ“sî�{êÿ;¾Õ6ýåG_™4jÒÛÞTC�Û‘Ó]ÙÉ//h”6*5ÊFI½N§õóð€yËåê¢6¥\ª�6IÉÄ›uü±YJí53p[•­;2·•Ö•tÈ<Ÿßw¯Öè4Û3·µ*eÃÒ ¨êò�3û[›®/Ób6ŒƒÑp»ü ±×F[�v”½Ç ]T]|$÷°J«úeÇ/ña ^|¯~h˜Cz£þ«M+/WÉU­;Oî¬o©‹ ˆ¡›�ŠSwŸÚe2›Î�m”6zv8vÞÄù¿îø%+ÿ„\ÕZ\SÜ(mì�Ü©B:éíÛ¹úlñ™Io?8éíÉЄÅ`-]°ü¿;ûdæë?,š5fVjl*yHuSõèAc„ÄÎYòø„WÇí<±ÃAùµâšIo?øüŠgºXŸ/6,›ôöƒÇòŽÚ&šÌf …âãá÷ÎÏo=½|þà¨Áƒ¢;n”Þ¨ÿpÞGíÿóþ7î{ôý)dú S–וMû`ês+Ÿ›5~vT@¤ƒÂ4Æ;sÞÿé?ÎúxÆ…²¼ä)ä�Šp¿ˆ7{ó³?—<öÑô_ÿûuùó+4Y~d`”ÐÝãxÞ1ÛÊl>º™Œp ž�~±¢ ‹]qMXÌ1!±çKνñãëïýúîó“_d3XÝ(§Skv¯y~Ås‡Ï¶—áÀÙýc‡Œí�¨Ñ©eÊÖžªâÌœnìæÝ?RÚC\ŽK£´éPî!2‘Ídoøp#ƒÎdÒ¿lÿ©·ë€aÛ§�ÞA8†_‘¥Ç{ïÌÚI>.«+óä{±,�^k›¡¶¥N{%¥¬¶,Ø;Äq™s&Ì›3a^½¤vÝÞu¹Åg{©æ=¨+mì´£ìè\V_J&JÚ$r•<Ø;¤IÖI$ç$x\w¡oeC9T5U�½|澡wŸÚ�–èÊá”_óMƒcx„¸×}ó’­8†Ë;ºê?ê�ú~ªû-‰ �³–}§÷€¸µå@îÁá é'/žµN%t<³|9yÈÁFÏÚwjŒ†ÊÆJ��ãÌj­êô¥œÓ—r€€ö¡ÊÅ«? ‹[›k[êüDÖa�ë ÷‹ åDA>wø©Û¬1CÆæå–Õ•À©Âl¹²upô�¬üW\]ÔéoŒ‚½6óu £’—È»AÚ&;St*êËÀÃ]TÝTÝiÎØà¸%O ,Ëb±,xèY˜ùÑt�®››¶^(Ë8n2_ýàýeÇ/}v‰ é_}�ŒJO ð³;à±îÌ5ÑÆß6ü—µ#6$6&p€õ�­Õkç-�Ësq¿/eù'Ú«N^<ùè=�^ª*dÒ�¤?Œc8�J3z=:aÒYš+×àÕZ0¯�NØt–ÆæÒ¸R§â8ü5³ýÄv¹ªU«×¥Å¥.î‹g¾xºzïu¥��v”½ÙLVK«Øš®Ö¨XÌû Øã¨8õƒ'>Ø{jwyC±çôžW§¿öêŒ×Í󲿖JRÛü7!Žáiq©Ï, DZ¥Ï,›}ïì_ÿûµŸªK®¹Í/c¹ªÕGC>&¢ARß�*·È:…0[pÊ › ‚(ª-ê�7cìcn³Ùì#ðÆ(Wù\_8�ëªÐ\½0g}ߺr\E Úôñ¿äS�åÎå‘�ù\žT)»¾2 ãý¹¸°]^ýîån�›ÚNıX,ö8»XY@^pyaʲºÒNgGÝI[ Žán^‡7\¡U±lbq¾›�| nm9~!ó³?—\ˆu�¦Ãy—=·\ÜÚòáêú`з7P(°Ó:änàtóNlQ¼:Je1ضa½A¥U-ýë³GÞ™4cñ4£ÉXT}¹WOgUÙXâJ>õ m–5uÂ*+ý<|­—œCýB++ºX¸Édį½båœºÒÆN;ÊÞ�Õ�•a>í™ù®|7®[×;­/áþÞÜiTÚâß?´Žfû„Ô4Wç\:e¶˜‹kŠ/”æ ŠºföC›R.SÈn—)ÏŽ–à>fðXðp�4öà¹Cý]©[âÊq¥Óè—*/À°˜TOÄd²ä/«+eÒ™ƒ"@Züp^{tr,ïhjl*9åÈÃ]ôñüOx\7ò%™R.páw(ç…) uÝÒuŸ^š|øÄâÍK¶Ò¨´žh_/¸ ͳBÝf›øäýOýöÖêþªÒ—œkÞ ‹ÁºØýY³TZUBXâ½)¾Þ´F$dÈÕòªÆJ7ŽëÓ-¨—ÔwcÒÇ1 Ç1§àtÝb1“_t�üC¥át:�NþôñB¡jK 8}ôô7W½ÑÓmíÜÞœ½/L~ñȹCJ�ò±±�í¾2:úÔOíÍÙW+®)©.n”6ιï‰?÷ü1zо«€¼öŒQ0*•Jè Ðit‹Åb2›4FFbƹ’sF“15>mxüð—¾^Ø7 ¹öÚ˜žæJÞ5ÐiGÙ;ðйÃsî{"=aDnÑ™ùI¦l�÷Ùœ[hÇU-ò–oüjá×-­âÓ—rÖí_÷äÄù�-u—«;^"itšW¼ùØ›½6»0» ,ŸŒ:+êËWnürñ¼Oè4ºÉlüçàF¹ªýk»°"ÿ©ž¢QiÖË7lëþÔûõÝöÏÿ#S$mR²E ePÄ ?ö¬é½9òßoþ¶+Ù=mָǀËâ&…œ9nÖ©ÂS¶ƒC añ—ª m'�€ ›+tóèÙ #ΉâGyh%±}‘ã|cGgP\�¹•c­+ÙÓiô%O}8€Ig6É·ŸØ±ùÈ&3x,¹–ƒF«.¨(XµcU7Ö;™{ß¼'î{ÂúôŸÃÜútX¯i«ã4zí°˜ÔEÓ_¸ñkšk~ýïòK®oÌ�0÷‘‘SèTÚ�³¿þg%ùÓgïŠý¬~ŸœmàøÖ¬·"ü#ë%õ+6Ù:Ô7 IDAT~I.鑞ôÍKW?ŠkŠŸ^>ŸAc|ùüŠP¿0*N­m®Y·ïÏ£ç�öYCnE§mœ>zúȤQ ¾lŸ'ØiGuz �K{~òBžÇ…ò Ëþú̺°�ó¹{üûÉ57O®úßm€qCÆ=~ïl‘»§R­Ø�³gÍ®ÕAØö§¾<õå{�1š ‡rÿ´íÇÛâ"rC?¾ºjë±­Ïp�£`¾¿nÍî5‡Î¼a�á~Ÿ?»lÆâiÎÿù鵟÷žÞ»íøÿú»"H÷‘+ÙÇ&¦\ÌËq�­C2&q®èAä.÷öãïª4Šï¶|àøë›¿=¹tn]K½ãC2G>õàSO|6÷†#"3ÇÌ4šŒÿý·çêÛ+RcS_~ô•ÇÐjl·¹[‰NœzÞ ‚ ÈÝæïëÇlühÓÒ§—~ûï77 MàXÞÑ¢ê¢ÝxaÜ 78hÂãº-šþÚ’?— Ðänæ\óNAîrUMU7µ?iÉÚOz£2ýB®j#—ÙEîfN�`g¿Š ‚ HŸAWvAq.(:A¹9Ëÿfë{/>æa›âºdÆ7UÔ—s¾ãq:®Vr³’ÇùÈѬC¹í8Å•[/LX”�áÎH•’í§7oÌúËöÕ…_{8yêÂÕOÔ\¸Ù’Nž:aà!ž¡ûòv±ýS2Qà"xõÁw¢}ð8üGW<Тh_˜’Eç¼xß+©‘#(ÊÎÜm¿ü±ÏV»š�1ï‘”Gé4úÁüýßìúâúÅ”ü�o>ü^„Ot½´ö«]Ëó«ÎÀ¤ä)=ä'Phä»r·¯;¾†¬°ãþtZ�¶±ƒN;ÊÞ�iQéÏ�Eèê‘_�·|ÛÇ- §»£ØÊÃÍsí ÿ\®»øêÚÀÛÝç©1Ï'%±èÌ¢úËßí^Y).·Í�cÔç'¼œž*à ëeuù%óòÑþ©º³¢P(=û÷ûƺ—`÷»G;¤‡zFt’ÛŽ{“&º²Ü¨uHhJ„Oä{¿îv} kòŸÿõÉnŽ NÈéÆNŽzyͳ“¿˜ðñ¿ïN6#%<ÕúR„wT´oŒÎØÍå%JÉÚ£¿Ìßo›h±§J²>þ÷½™Ÿÿ¢·»ïœï§=óÓìÔˆá�¤<Ú½“Þ¬Q±c&¥L]ôç s¾›ã?+c^‡ ûxƲKµ…“–�ÿßé?�ñ%—É×ãçßÏüêáO·.~$åÑ{Û7UvПNË^muÚQö¹y½?åÓßý8ù‹ ReË»“?î‡VuÙ ¯–6[Ÿò¹‚Ò¦’WÖ<÷ø·S뤵ŸÏZI¡\³à/Ç1À>ù÷½é_MÚz꟦~ê/踉ñÝFà"8ðA–ß÷›y?ÿ÷ö¡µ/JæÆqwòGënÞ¸hÛsã_ƱöŸg1þq«žZ³æ…�ën~òžgÉæ2¹G>Êqc·/K½üñoNžêळ2æ¾òÀÉáö¾±gë{îMºÁÆæ§J²Õ:ul@üÀ�Á»Ïý×½–ú ·¾±gýË[x ­ ŠÜQœ.:)¨¹ÐØÚ Ô*dõ:½ÆOàO¦cìåûßøn÷Šnÿʼ|$«(S©SØ&¶ªe;Îlµý2 ¥E�Øxb]›ºµIÞ¸5gÓ}Ivï¤7k|âÄÿÎn«h*kQˆ×g®™�4±C†ß(wß5G~ÖèÕ;ÎlmUK‡GgÀêëΖ崪eùUç�]:2À?–Ìo¯?�™½6Úê´£ì8:nlqÃå#ªtªßþ˜äÅóuÁЈ4•v²è¸5¥°¶àï̵5’*©Rúûá_Dn^®Àö½Qÿõ®åEõ—äjÙ®sÛëeµ>Q}^qç"UJõ&ý‡S?[ŸùǃŸ�™¾²ýï÷ÕÞ4[,s¿Ÿ>ç»i>‘�¦Î Ó_šøú_™¿?ñýô'œ)tõðtóêÆIÿ:öǺãœ.Í~dù„G–OØ{~§ãürµ,.0áËKC¼ÂÄmí‹ÏHŸ³ó�öÿ¾}ÒÑ–¼µÒêG–O@'È�Çé®ìÀ÷<óÐà‡¹,×&yãá‚öEï<©ª¥âRÝž©víÏÓ@Q0Žá}°™V°(dWîòqYc©§›7‹ÎÖ®nAäR'­Õ´Ö|¿JqY¯Õñ¶¡Ö)O—ž:]š Wv’cÑ9iQO¯šm¶˜ÌÓö3[f¦ÏùûÄ:Ðê5£bÇ6Ë›+šË–m룡5 …’U”™yùˆ¸­™Š·ÿ�¹öï̵}Sqf}�ŒJO ðóµ÷êúŠköeØxâ¯�¹ÛbýãøÅj jàqøÓÒf=ׇ¿²K²M�y¹î"ƒÆœ4d Žá4œÖÑ “ÎÖèÛ÷ˆWë•À¢³l£6�­Ñ_ÝÓ\¥S²é×l*6wÔÓä\kÊõýéänØF°ÓQöd3X-mW·ºUkUl†£�ØúËã#ž8véH½¬®ÓW=Ü<_šøÆ·{VZK§¨8õý)ï=¿³¢¹¼Ó wˆâÆK¶)\£`K[a `ܺØ×Ç›ß�>|öâiK9 ö¹Û×ùµþØ ‚ȼ|ÎUœéís!Èm§�¢“#™YV²g¦_óTkPk ê#mÍq�‰3Òÿãèo ƽ¸éäú6uko×Óêǽ_?ï¢ßŸß¨7éö_Ø#tu{¾ËMÑ4l‡|Ìa¸€u$€¤1hØŒ«“0¸L±¢ÙúôÑÔ™÷ÄŒyi̓éê2×÷gï¶á–9n#©Ó޲w F¯eÛl Ëaq5z 8A`F̘ù«ëôU�‹`åìïÿÍ^¸`§pŒúÁÔOÕzõ7»¾ìÍjÞNlÿ @¦”š-æ—×<ÛÐÚqõU©RúÞ¯~ØóU GÐÇÓ—ÕKk÷åí2[À(í—¿­ï·^5#}Îcé×l@XÑ\¶põÓ}pjq*ÎxeÇŠ/w_2dhø°9#ç“Æ\2óËuÇ~ßœýwï�Z¥SYxg¦Ï-ª+ì½sÙªW„x…‘¿¨B½ÂšÛmN ª¥Â—ïÇ 1ôF=™çtÙIò¥ÉC§MJžúÒïÏÈTÒN ·ö§“sÐF«N;ÊÞ�Õ-ÖéÀ|®À�Í«Wôi“º >0ÑÃUô÷+Û€IcÐpƦWw>ºâ~àqø+æü°/׿';ÏãþÞ”�éTú{¿n¶˜ú´Þ·³Å”Utlúðǿ޹œbòÐéF³aûé- cùãß.Ùü^‹¢¥NZת’ 5¨Õzu�(¸µR óŠ8”¿Ïñ)4z•'Ï‹gå2¹ ­Âqþë¡+;Br®è„EgMøÐÉâL•N™4p|âÄov-€§~z¿ò fýË[—oûø\ÅÙ›-Ǩ8†áŽQp:•n¶XÈÏq:•NÃé@£ÒèT:ù{Ë_HP…ZžW˜UtòÈŒásýñ\›FN§ÒͳÙb¶×ŸNÎ^‚†z†mÍÙv:ÊÞ�‡ Î9?=zäÙòÓOŽ^PP�ç„“NìÍ.iß ûÁ!““‚-þçmpc»­œûý©Ò“›²6Щt0š�AX{£`o?ò!ŸÃ÷ï×0 fýßïÏÆ8«•ÿ-[xß«ë^Ú ”7—’z£~ïù�_ÌþŽÀ(”Ó¥Ù¯D!?ìùjÑýo5µ55ÈêN—�Ä1^šøzFÌ=À¤1¿œó½…0ï=¿ë—ßÀÑÂÃcã'ìxû Þ =X°ÿû=+{»E_?±*À#ˆàÙúÆøyÿwûòv÷öy¤·9ÅÅÌôößút*ýãéË¢ýb™4f“¼á¿³Û® ÙýîÑ7×½Ô�õNæŒzjîÈùÖ§›NnXµïè°ŠÑ}ŸŽÒ4C#Ò=ðŸ+¨•TÿvhU–Í=½mÎÈ'N™F§Rm—ñØýîÑÅ›Þ&§øƒÞ˜ô^„OT½¬î«�ËÈ%=Ö¿´Õ‡u\äTIÖÛëu¥?�S§mœ–úXFÌèç~m¿ËºÓŽêô@ ×;¹÷WQ~õùeÿûĺ°�sš–úXrø0r½“±ñÞ™¼ØöÕ?Ï-n¸lí WѦW¯¹õ§}ßþsr}_VAäzºLtw�bçŠNA¹3ÜJtâtë� ‚ r—CÑ ‚ ‚ ÎÅ)fÅ’ƒ?‚ ‚ €ÆNAq6(:Aäö°ô£wÃC;îipûzröÌ][6ß·}Ú”I^ºÃZŠ ÝàWvl½òÂ3ÇñÝÝ%ÒÖ­ÛÿûëŸ-úç¯ßYó|ÿÓêõ›¶ôÈé„þ›‹^Œ‰Žtçñš6[Ü"é‘bożÇgL}øA:ƒ¶ÿàÑß®2™;.\àï÷Þ/GE„×Ö7~ñõ÷yùÈf±ÞZ´0=m¨J­^ûׯÍÛo°3™“°×F[�¶×Þ�é©) Ÿ{Z$äå.Y¾²Eâ췉ݰ&Þ;fÖô)Þž^­&+ûôÊï~Òêúb9ã^B¡Pn¸ÁgXhHïÞ—å�Vÿ¹aõŸ¾ülñõ/u»¥rÇpº±“ÃÇ2Ÿ{ù͉S{ÿ“¥Ó¦<œš2„Lo‘H3î�DþÛ¸å=u:‹År2çìû/ë©oÑèQ#&Ozà…×ß™1wAlÌ€9³¦wÈ€aØç¿wñRñ„‡glÙ¾ã‹%r¹¾ðÌ<ÁÃ3ç¾ûÑÒgŸž;0!¾¯›tóìµÑV§íµw §HôÉûoÿ´zíÄ)�I¤Ò�Þ}£Zu3ºÒÅ%eï|øÙƒÓfák^^žóæt¾¾Ó;:cÕ×Ë%&ü³ö—ÿmþè�öÿ”ðÐпZ¶éÏßþýkõ}ãÇ�‰4m×– ~>Þß­øt×– ÖüD¦�>lýï?YË<¾o{hp üÌý;ü|¼W}ýÅ�ÿnÿçO2Ãúßš1õáåŸ|ðë+ùîK¡€ï¸’o.zqþÜYÓ&?ô߿ڵeÒ÷‘écFŽX÷Û�ÿ®ûíÏ_¿‹Ž '1 {å…g6­ýuã?ÿúýа� 2}ݯßß3b8ùøñ™�~¶ø]g´×R¹Û8]tr¡àRCS³R©ªohÔj´~¾>Ö— W˜Í�ï‚Ö ²Vùÿvì*.s–=]'޳mçžòòJq‹dí†�÷ß;¦C†¨È0_o¯_׬Sk4[·ï–µ¶f fï@ÇÆ�µzíz¹¼-ÿbáþƒG'^W ²×F[�¶×Þ�cïq¹¸ôБã*•zÕo$ÆÇz{‰ú¡a]Ö•(«¨ª¬®Q(”�MâV™Üß×»_ªÚmUUua¡!OÌžþÚ{�}`Êâ¥_‹ÉüòÓö<òèìù/,zûÅóDG€Ñhœ8y¦Ñh|ñÕw'Nž9ó‰Ž —He:½á“Þ^»a㸇�4½}ç‹Ù4,yð;‹?}êùE²Vù£?xƒJÖÔŽ»gdlLôÌy FOœ¼}çˆ }ûõ…/]1õñù?ýöçWË>a0è�6tHì€èóž™>÷™?7lJ–Ò�n¹Ù–"È�Êé¢xê‰Ç÷lý{çæ ŒrðÈ12‘çæºyýïÖü´ðÙ§Ø,gÜ`¶G„”–µoSZVéåéÉf±l3ÖÔ5XÇðKË*‚ƒíèéáÁf±KÊÛÓKÊ+ÉÌNÎ^muÚ^{––·oÛ+‘ÊZåm!AA}Ð�nëJÀÐäA»¶l8¼kKZjò¦-;ú¶Ž·J­Vq9ìµë7ÕÖÖ€Åb€�‰ñ,kû®½Ð,>zbܨ‘Ý.ÿÔéÜS§s ‚ '8|œ¼XTRêíã帕Z-ò—­øV©TY+9nÌȳ¹ÈwÔÉœ3­ryòà� Ñè|}¼î™îêê’y2gíúºWsA Ïæ�ŒJO ð³»ÿÜêµ×¬º½~ã–í»öÆÅDÇFGª5�µÊÞûäóʪj¡@ðâ‚ùï¼ñÒ{-íõJ÷“E6Ôj5°XL�öê6Ål&K£Q[Ÿ*Õj‹eï@6›u{ºJ­â°¯‰uœ“½6Úê¼½vd³˜bñÕEj•šÅfö^ýo]WzrÏçÏyú?ßq÷d45wÜÆÙÉ@ÀåâÛDW›õ¿¿×�Oi4zΙÜn–O—KJ®O'ß-`¶ä¾9ŽK©¯oP©¯Ù‰ÓÍÅeð k%™L–»›äæ]øòë¸oÜ[‹•”~·ê·¢g”E�ÛNE'G2³º¾ ¾F«Ñh5‡Ä-‰q1�OŸúÛÚõRYëñÙP[×ðùŠoW¯úšF£�Æ^¬q?Ñê´vûȇíöš©Ž�–;:Á…Ãiji±w ƒN6‡­P(€Ëáª5ZpzöÚh«ÓöÚ;P£Õq8W¿Ý9\ŽVãÔH»Ò`4%R™D*ã¹¹¾ûæ+Ï¿òVÖ±g ×ü‹[$2©ìáOtñp‹Ù‚cò1�N§R¯ù@3 ·^C½¡ãçLs‹ä؉ì�—®¸>óÁ£Ç=N§Ó§M™ôÙâ÷™9Ì o¥æÞ?Ä8ã•�«(oïŽC¯&“£P°+Iw˜ŠªšÐ+“éÂBƒ›š›mN ²ªÚßׇ¼ÎM橬ª¶w`sK‹F« &ÓÃC‚ÈÌNÎ^muÚ^{VVU‡…´w‚€ïÎss­¨ªêývt_WzÀ(¾×ý¥ÜŽ.^¾ Êø1£€Á ¿þÒ ‰ñ1ÖWÕjM ¿/°Y,:�Íb‰HäA^ê;:£o¨qàHfÖð¡)Aþ y|¶ø]ž›+Lzà¾'ç<ƒ¡¨¸”±X,&3mØÐ®œâú–"ÈÝÆ¹¢“9mòC¾Þ^®®.ÃS'Ž“{.LŒ ãr9!A¯¾ôÜé³çõúøUD¢Óét è4Z¿ìÞpÒý‚ü|÷Ù3¦îÜ{�L_ðäœ?(*.khjzröcL&ã� ã|þñ¬Sö4›-û}bö WW—QcG�Úu¥@gf¯�I qS¯Lcì´½öÇ`òCÃB‚¸\NLtäü'f�ͽé]»��^oxí��&Ý?aóúßÿZ½JoÐ_,,²¾úÛÚ¿^{ù¹ƒ;7¯ýå;/O(-/ßwàð¯?¬\±ô#.‡Ó*o£ÜðbÍ-+/¯\þÕ÷K>|çßu¿}½ì““9gäm 8~âddxØ¿ë~[ÿûOO?1ëÃ%ËÉü¬ß8jÄðïW.}ï­EYÙ§p €q£GîÚ²a×– Ƀ’ž~bÖ®-~úæK-E�»�SìQlE§Ó?ÿø½˜¨H&“ÑØÔü¿�{þÙ¼ îŸ0nî¬éžBy›"ç̹ïY-—·u£&�Ê>¼Ûöé艓; Wô±'gÏœúȃ4uÿ¡c+¾ù‘œÁwx÷Öwzêt.ø¿÷ÆË‘áau �Ë¿ººF§²Y¬·_}ixjŠZ£ùcÝß·Ëz'�¶ñ±G'�Ê>ÿùWÈ<�¶×^礧¦¼ôü3"¡ /ÿâ’å_9ÃÂ6ŽuÚ�èÈðßW}“qï$ƒÁðü3OŽ»'ƒïΓÉZ�Ÿ<µê×µ­æ†Å"‚ô±îíQì\Ñ ‚ ‚ w’îE'ÎueAAE'‚ ‚8� ‚ â\Pt‚ ‚ ˆsqº=йK¸r9~>ž—J*\¹ÏÂ’ {9Ó’=ø< ®,j²ûÐ �;/&*ôàñÎ'Üy ùÆ$lÛsäë™1t`³DVTVu‹å\ÏÍ…›Éå²(MbÉÙ —Èô”¤Ø¢òª6…ªÇÏØiáÞ"¡ƒnì“&Œ:pìT÷–‹¤RñAñ„înŒb2™÷9é8ÿØ)®mlö€½ÿÓè(¯ª»þ¥Þ{—ö§‹Nâ£Ã½=… :]§×WÖ4”VÖ�é =.*ÌK$ 44‰Ï9.A'çêÂU(ÕíTj9³Nç‘î“~:¯P,‘u¥|™\q<»› áÛ:±Øh2Ýz9× òSª5ÇsÎY,׬#çêÒqKêÔ«…÷ O.{ÿ±S]ùob1ŒÞ\×ÊÞÿi�puáØûKé½wiqºè¤¾¹¥¬ªÖd2s9¬ä¤X…JÝÜ"€¡cUjíÑ“¹&“ÉåºÝä¹í¸¹rjë›Éu Ý\�°QaA�~Þ†•UUÖÔ—ÃNOI¢P(t:Ívì„Á Œ‹b³˜kSªÎ9þ@OŠ�ô iTjIEµí¯Ò_¯ˆ�@‚  ¨¼ª¾ÑQå9lVbl$‡ÅÄ0¬²¶¡¸¬ |½DñÂiTª…°ˆ„©PUÛp¹´ǰq#‡1ôáɉ a4šf¶ÿ ÷õE†â8n2›ÎËJ`2èãG¦ÌÌåæÂ5šLûŽfÛ«‰ƒÂ;íF{'µ‡N§ÅE…¹ó\q «o_*©°X:�vßèáçò/ûxypX¬6¥*7ÿ2¹ªï€ˆO£ÑTUÛà XF¡D‡{{y€F£»p©D­Ñ2ôQiCpÃ(ؘ) T©O\‰e¯'äóR’b©4ê„{Ò I,9±ØAP(”¨° _oF¡(TêsE†ëv6°²÷ê-ˆ9tâ4™íÁqGOžU¨Ô "€F£2t&“q¾ HÚÚFž4"40ÈÏ›B¡¨4ÚüÂ2"68^$à›-æˆ�@ÈÌ9Oîeï]êïãHŽ']*)KZÀÞI��ÓE'R™œ| Ò€Élæ²YÍž&ƒ‘™sžŒFu=·P,‚ }�Ïs  twsqárÈÕõ]±Åa³tzþ£Ù"!Ø øšú&³Ù¬RköÎâ°Yc3®Y9>"$@¥ÖdŸÍ€ÈÐ@ß­I,uPøù‹ÅŃâ£mé4ZbLäÞ£' #›Åâ8:‰‹S(UY§óØ,æ˜ô”f±T®PÖ7‰ë›Ä)㤭ò²ÊZkf³Å²çpÖƒã2NœÎ³½øâæÊMŠ�ÌÌ9ߦPyzÒ’öÉ6›Í:½Ál6IŒ¹\RÑ,‘Q(޶ø°W¸½n´wR{å'ÅDšÌæÃ'NS(ذAq¡�þ¥•5„… Ë?•[€aظŒ¡"�{³D&äó‚ý}�8­Ó¢Â‚T›ä'òà;™k4™b"C†$Æ=yV§7ì9œä'òÉÿVÇ$2yvn~êà„=‡³:¼Ôi„øúxzÏ>g0c#CÅEgçÚ=‹½ÿS{,‹Ÿ�çágôCh _lTè±ìsäï-9yÖ`0† wàxAÙgóS'4K¤®ìtú.幺$ÆF=™«T©E÷”Aqû��Òë öNꄜqVltxð}£‡ßwO(uMbàó\å UrRìýcÓG¦’W ¹=É䊜sr…òTnAι‚6¥êTnA7B0šÚy·H[6ËÑîÓ&“YàÎó¸cV\^í84±Çl1@ùysØ,�VwÉgò.W€F«S©5\Nw6ô÷ñ’HådHÑÜ"Õë "�;ù’ÑdKdÍ�ƒ9ÝÒi7:8éõ¨TÜÛSXZYc±f³¹²¶ÁÏGd}µ¦¾ ,‹R¥&÷N÷¸‹¥­äOÍ®Œ�øzyTÖ4�c]¥µ<7“ѽÆvªóðõªªk4�PZUë)Ш=ù“^,‘é hU(ÙWö!÷õUÕ6�ƒ4åÕµG³s»ñßêëåÑØ,QªÔ –¶ªÕZëÿ]§'uB}4v2*=-ÀÏ×Þ««×®·}ZZYSUÛÀwwãó\M&3°˜ oOaî…K§Ïøz ·ÿø)#l‚89�Nî–E§ÓneÛ,ëçAŽw-.«2›-1!\.»I,Í¿\Ú��³Ù’™s>,È?,8À`0•U×56;ÈÏç¹F„Ðh4ÂbápXއ7ì¡Ó¨BoüÈaäSÇétšõÕV¹¢eÚê´Ÿ´• Jêàò«”B¡ØŽ²X¯ ÙnM4ož �b?O:�&í¹=Šé{..¥ZC>p|;q7 ONtárȯIòîŒÂâòšú¦ªÚ†øèðبP P”jMÞ•û5:å%$ÅF�J%€ðÕë ‡³Î´)•Z�þžáÉAX,–‚¢2£Z�¾¬²6mH‚VgKd%åUÑáÁj�Fì𫢨¬21&")6J¯7œ:—¯TiJUÞ¥’äÄX Â(©¨îö¥íë ·—ófOšw©$>:|숂 Jõ…K%2‹¥­Õu�£Ò†˜L¦’гÙìøšWEUƒFË6ˆB¡¨Tš³ oØÒN)ÕšÚ†æÑéÉ„…Pk´GÞs^U×À`ÐG¦ƒÑx±¨¬glS¨jš3†Òètb‰Lo0:¾YQ]G§QG§'¡ÖêN�+°¾T^]706ò�q# 㥒ŠÚ†f{ïR¹By¡°$91Ã1£Ñ˜�›OΞqŒN£1=9›çV8×ņ¥$Åòy®8Ž«µÚªÚëäd!Ÿ—0 ‚Íf*Uš‚ËeÒVy7j‚ ‚ H_êÞÅÎ5vb±Xìݯ%‘É­÷‹#‚ rsöy'‚ ‚ÜmPt‚ ‚ ˆsAÑ ‚ ‚ ÎE'‚ ‚8� ‚ â\œëžˆ�÷ö2èt�^_YÓPZYQaAQáÁ¶Ùv:�V²GA�;’ÓE'õÍ-eUµ&“™Ëa%'Å*TêæiIEuIE ™!<8@$tG¡ ‚ ‚Ü©œ.:‘ÊÚ—YSiÀd6sÙ¬f‹…h_Ê×ß׳ôJ¤‚ ‚ È�Ç颈ð¥Ó¨j�®®IlûŸçÊb2ê¯MDAäNÒGÑɨô´?»;B­^»ÞöiieMUmßÝ�Ïs½º×3øy76K:$"‚ r'é£èäHfV×÷è1™Ì&“¹¾Q,tç…û•U‘é†ùy‰rÎ_ì¥J"‚ â œýŽb›e}ìãéa4™Z¤7ÞAA�Û—sE'8Ž…ù³YL:�æãéàçe‹úyÕÔ7õcõAéÎ5+– @$p� Äq\­Õ^*©°†#,&ÃCàžWXÒ¿5DA¤·9Wtb±X²só;}I«ÓoÛ{´o«ƒ ‚ H?p®+;‚ ‚ (:AAĹ èAAç‚¢AAœ‹sÍŠEä®âÎs=q:Ï6ÑÍ…›Éå²(MbÉÙ —ì.äó†§$AXSò Kªjìå ùƒâ£qk‘ÊsÎôHé N�ÄG‡{{ tºN¯¯¬i(­lßð/"$ $Ð�F£*•êüË¥2¹¢ë‰ È­«¨©§^·ˆQh�ŸR­9žsÎb!:=Ê–Ùlþoÿñ.žN,‘í9œì/pçÝt]éCN�Ô7·”UÕšLf.‡•œ«P©›[¤ž‚ˆÐÀ¬ÓJUX°ÊÀ¸=‡³ú»¦‚t_ Ÿ÷€ˆÇåm ëØ‰¯—(~@8�Jµ‘0ªj.—VÞlá†%ÅF ÜÝ(ŠL®8WPd6;Úœ‹Ïs��§R©@�†¦–K%dº›+7.*ŒÉdPŠË«mWƒôõò’{(ó´R¥¾Ùê!rCN�Herò�J&³™Ëf5pXÌ6…ªµMUu�Ñ!t:Í`0ökMé¾êºÆêºÆ@?oOkb}“¸¾Iœ20NÚ*/«¬ívá!�¾.öÁã9@¡d à㸴„˜ˆ¢²ªÆf †a‰16K­Ñâ86lP|QYUUm›Å™:X©Ò�ŸB`¶XôzƒÅbév%qÀ颈ð¥Ó¨j�®®I Í-Á¾în®m e�Ÿ·\®@¡ ‚ öTT×UÕ6XB*kã²ÙŽó›Lf_/‘F«S(Õç ŠÈD!ßÇ0r‹F««oûùˆ¬ÑI“XŠFp¤÷ôQt2*=-ÀÏ×Þ««×®·}ZZYSUÛÀwwãó\M&3è Æ&±$#uèõ†¬3y�„ È]ÇñIFYŸžÈ9/‘É™ FLd(—ò˜-,³¹Eê¸�3y…áÁɉ±T*^UÛPTVE�F¥Rññ#‡‘y0 Kd½ØAlôQtr$3ëÀ¡£]Ìl2™M&s}£XèÎ ö/*« òóõÊÌQ«µ>^Ó“fæ áA:�;(>Z¡T½p‰ ˆ„ávƒ¥tzCAQYAQ™ —�œ«Öhkê›´:½Þ`Üw4»×êŽ ˆ]Î¾Þ ‡Í7nc³D©ÒX¢®QL„»«KW A'Åd0ZÛA°YL‘P@¥:ú†ãxzJ‹ÉµF«×ÈôÖ6%�ÓbpOˆ‰°½ÓÇÓC0~ä0ò A�ç\óNp ò÷mln1™ÌB>/ÀÏëBa È䊰 ÿÊÚµFëãåA§Ñ”jMWA�n¢Óh£Ó“Çq£L¸' ŽŸ:§Öh{¤üËe•ƒý¼UjMþåÒ! "Bê›ZF 8ŽaŒ<é¡§ cu]cÚ� „X"«mh³Ùœ�›LD£XÒ*o³ž‚Šc,ó†£2‚t�sE'"�{Th Žãj­öRIy _Um›ÉžœH£Q5Ý™ …­®¿+‹ H7ŒFSJ»¾NšD&ït±“º†æº†fëÓ�3ÉöNZSßTsݲ+ЦPeæœïô�ú¦–ú=GºXOAn–sE'‹%;7ÿút‚ K* ¯,B€ ‚ È K"‚ â\Pt‚ ‚ ˆsAÑ ‚ ‚ ÎE'‚ ‚8çš‹ ÒSRÆ‘·ÿ w*×î}@iɉ|…Dû®È»� ˜86}Ï¡,½ÁpýQ†=8>ƒ\š¶Wj3D„x{ ež¶M ô ”WÕÝðpo‘p@DÈ¡§o˜AúŒÓE'ñÑáÞžB�®Óë+kJ+kÈôðà€�@_:�&n‘�¿Xl0¢…b±‹É “Q“A·.°Ö©¬+;$ß?&ýt^¡u¹zšÃ5Ü,Ëñì\…Ò)6(6�䦶\]8 ´2rÛrºè¤¾¹¥¬ªÖd2s9¬ä¤X…JÝÜ"õóö ö?yæ‚Z£MŒ�LŠ�Ì9±¿kŠ ˆórår Uûƒ[ˆ!¼D‚ðà:�Ö$–X7“žB£QtÚ‰ÓyÖ± …&òàa2™ó.·)U�–‰cØãFì=rRg6�:°¢º¾®±™çê? œN§Uu äîʾ^!�~2y›+—Ëå°*ªëË«¯Š Æ?؆ Ž øf‹9"$2sΫn´‚etxp€¯…B±.4¾Þ¢È�@ÇMfÓù‚b¹Bé ?oÏàŸË¥•‰±‘L:½©EzöÂ%•:qlúîC'ȽGR'4‰%5õŽ[„ N�H¯ü©«4`2›¹lV3€—HPSßDþ©•U�IO¦ÓihŸA®‡ãØà„.›e0=„|òA¯q\Ï�çz8ë4�F3¯¾Qìïã%‘ÊÛ*hn‘êõ‘À½Ql·]F£‰J£–”W“ã4Ä•I<ö8hrGùø{½)L“ª­­®ºÌ^æ>ŠNF¥§øùÚ{uõÚõ¶OK+kªjøîn|ž+J7‰%1‘¡5õ�­.24pïí:#rû¢Ñ¨ä§�FívhÖ)±„…p4 ‘Éó K‚ü¼c#ämª‹Åeò6»×A*5—ÃÂ0aEU�—HÐÚ¦Pkt‚`2¶“põƒ;Ï•|l;:B@�«Õ±X€[uÐéõÖ`Â`0Òi4 Ó¨BÏ:D„ã8�NsPù3²U®èâI´¹ó ˆÌvsã‰L½¨¬Êb±È�Ï8±Rª5\Ëd2k´ºæ©¿�gm£¤ò6 Ãü¼Eu�b“áïëuº»w˜Ìf.‡ …‚a˜ã$:�êãéÑÐÜâîæÊf2%­r¨ojIONtᲕ* ‹Éˆ‹ Ë»Tr³þL&³Éhrá°õzƒ —ãêÂé^s�Ûš‡Ð›'ò¼>�ë.ˆ¼:=Ĺ¢Ç‚ü}›[L&³�Ï ðóºPXt�Ãf©Ô.;)6ª¤¢ÆÁÌ,AîrB>�œºa}Ѓb"C|½€A§¥$ÅZ¢Q,É»XÜ(–$ÆDŒ1Ôb±˜ÌfÇCJ•†Ëa•U@“X¤TªÀd2gŸÍ�LXˆ‹EeÝž`W^]706ò�q# 㥒 ý€ay›RÈç ˆÆ0ìüÅ"òl…R•w©$91Ã0‚ J*ª»w/BþåÒÄØH­V§ÒhÅ-2 †V½ëP0 yA§œJÅ(�¿(Þ¡q”‡VÛ9.zìè JׯÎtïX ÃR’bù]«Ó“·ð!‚ rÇC#l‚ ‚8� ‚ â\Pt‚ ‚ ˆsAÑ ‚ ‚ ÎŹfÅ"‚ô—Œ¡›%2ò.ßôÀ¸…B`!ˆ6…²°¸\ÖåÕT;;"åÀñNîðò‡ IضçH÷Š ö�� ›…çÏY7ìmAþ>A~ÞÇO�³\©@ÊÀX‚€Óç/Ž‘Rß(¾\ZÙ^ÉÈP B"“Ÿ¸²¹th _§û(aåÁñ#ÏäÖ7Šû¦-�’[T^ÕvÝ‚7½ôg�·H8 "äЉΗauLÈç Š�Þw4»g«t³œ4:a1cF¤´ÊÖ÷Ÿ·§062”ÅdJ[åç ŠúfýDù?{ç×ÔÕð“½Øì½7¢8PA\u¯ªuV­³vX[G«ÖÑ::ì°Ãªu·u[·²ˆ ÊÞ;�ABvnò~¸Ó�PFÚ÷ü|¸œ{Æóœ{ÎÍsÆ=äÿ‡¬¼B…RÙq¼®“úèi3—�Ãá|<\ô ¾ž”ú ™PÈ$‘¨÷—/¸›–ù:6sxš—moB¥�ƒ|=SÒ2UZ¶‘R‰ Î*JÍ))¯.)¯örwv°eÞ}øD; sš U�j•J­T*½ë/Vïqs=úìþ«˜¨uà£í¢‚J!G†<É-`7qC¼#Büû¤#A �dqôðA ÷ÒûûYš›)”Jt H£R‚|i2‹-¯®+|1MäkÇbðø¢²Jí¹+‹o<0 ®¡éyQîhÏòõpÅápJD™•[Èô§£ ‚ Uµ ¾^nD"A­R¿?ôZâ}ô|³A‘¡ ìæ²ªZ"‘0.nÈ“œ|;&�Bi¶fæä«Õj†�Õ€ð <?6v0 �Ýœ•W0£Q‡Ç`0D"A3þv´g¹8Ú¡ú–”W»:ÚIdrôÌYK ³`?/2™„ °´²Ã ’‘1rž99ØÚÛ2pX\òƒÇÂV‘¡ê%‘ˆ¡>èÏs3‡ŸWX‚º: ò•Éär…ÒÛÝ�Ç=+,+qz¯¯§kMõ¨A¡P¢çm*”JßË퉎 aÑmâãá ¸—ž¥�›R‰(þé÷ØÅÑÎÇÃõQXPZa|Z�Ç…ùÙXYÈdòŠšú@�«‰÷D"!ØÏËÚʇÅÖ6°Ÿ•©Tj;jx4‰D¦R© %zF—ž 4À@ àÉ$"™LÊÊ-àðZÐø!~$"±U$áµ,Ìhé�#ìïíîâh‡Á`ž•¡Ï‹Å†ùÒ­-1 —/x’[€V5‡‹ñ·¶²�ÊäF=ö&¦h�Ø2é ¦žÝlǤ£!Žv,~‹mFÏ KÇĦQ)"x˜=чT&G¤X`~QYc3Wãä%ØßK lMÍȦRÈ#‡hdsPÃ"+¯€Âˆ�|B} J*ê›±XlX úÚ±´0 ò½—žÕ"hµeÒG…ÞHNëÌéÕ8ÎÝÅQ(Éå ^ÿ»W­RhTÊÃÌ\,;jØ@ݺ±™ÛÌå§eæ Š Õ™wi‰¯'¥Ò¨”øaµ3¡[[]OJ� ¤[[ÞÏÈC$à•*:"¤ ¤¢¢ºŽJ!)lóZŒ-3 [Å!�>ÕuOŸièªÞð _™Lžx/ƒÁ êêçåžWP¶ŠÜ][­I÷É M|,ãho›öX÷Œ+…R‰š5rEÇÖIÚãœA‘¡�Íœö+;¹\¡=F$Â}o¤<�ËT 9ÀÇøuâéêD¥�î¦c°˜èˆ�›Âð@_%‚$ÝÏÀ`°ÑÁž®ÎÅåUˆJu=)uâ¨a÷3²µWvºôì*•ÊÉÁ6éþ#™\îéêäçy'í 4À›Ëäæ—Ð¨”˜�ý8"lF£J¤²›)itkË!Qaìf®T&÷pu4§Qî¦ fXt?w‡’òj€·‡ ‘H¸•’†Á`ô 6žsï`r»bq8\�ŸgN~±v …9Mó°¥2¹L&GýG@ ˆ^J%»™ÛØÌè0À£ìçÏ Ëb‰´U$6£QŒg¢T"Žv,K 3µZý$·9;Ø5søè©±‰#“ÉYtkãùDG†Œ��™0*†L">xü´CáÑa®J¥¶Š¨Ô„l�Z­nm!"“É[EbD¥R*•D"‘ac�Ãb+ªëb‰´¶�íäÀB“0èÖG ÓüiÕ€R.W””Wëøök_½X,ÖŽÅ(.¯V«Õ*•ª¬¢ÆžE‘ B!“²ó å Ðzæf4ÃkiÑ‘¿¨´²´¢ð$· ¡éµÆñwÓŸhO¥ *D ÔnNö4*E,‘vèà�acUÛЄ¨TJ%‚Ö�ÇÙÛ2ŠË«T*5‚ åÕušjì.ØÍ\ÔU5O ¤R(/„±F݈ĒÆ&N‡™ *UeM=€ÃkI¤t+@YeÍýGÙ*µZ¥Rq¸-fTªFÓšz¶J­FTª^ÛrdœÞ˜;ibsfN›äâäh(¡£'5×¾ž®u M:ó"xN{£‰B©„Ž.!ˆqxí6ŸÚXYøx¸µJE£Q4ƒxC<Ê~æíî„Çã*ªë J*Ôj5‘€gЭF�Fãàp8"‘`<Ÿ´Ç9¼a|Ì€Æ&NgöÌi†ûj5è@D >ÿÔju›U� †HÀãñ8�äX,Vã·ÙȾ“öÕ¨7œB&P=©\N"½Üi!KÚïé!‰r…R¥Rë„k,¡×÷§¦ü粂¨î¥gy¹9{¹»Èåò‚’Êšzcn˜4îššGÀã3(25³0L·û}{)¶Z�ÅbxƒÅh„K¤føS”ÊdCP.W n¨É$R ¯§�¢BT Ycå�ˆDÍR(zu§Ž!zã7>;7/;·Sn6ÍhT;frêc�p%‚àq8Í¿<¾Ãé>òŽêŸÃ}’™›�Næ�: Ã¤2ynAInA‰¹5*tk«WÈG/*•ª�Ýìíá‚fîéæÜáw¼2…‚HÀ£s¯ƒAе~,£=Žm�µ¥ETx ‹ðBAŒ[H\^‹ƒ= ‹Åàp8W'{4P¥R×54ùxº¢Æ¥§›“‡ëË•�0xrò‹#‚ý�ìm[šºFšÑ]SX,†ß"dØXø¸c±Ø¬¼Ô¼Î/)ðvwu²o‰sò‹û‡øx¸•U—U÷ ¡�‰,•Ê*jêР4�ˆDñe#·c1̨¯%È×óQö3ïïí^רdDžWcïŒz+6/>n˜Û‰)Ý[¼¼Ü�í˜tíóN‚ý¼È$<ï�@þ„ú ÈÎ+ìkA:†E· ôIÐw¢ZïèëAÀ²Ÿý ê 6àèã«÷nmQ! /ûeÅ¢6‰iÍ�hƒž½£ù·¾±¹¾Ñ$>†@ H·PTV;¸Iyµi.Ö[˜ÓE†¢[Lœl mîÜœœlS3²±8¬“QRQÝqš3¦k�@ ä¿�X"Í-(‰ ñ×>ÉÞtE•5õC„«Õj¡Hœ•[ЇÂÔÔ7²ÖñêT*v3¯ºÎ$¾ûí9 u�@ �>£²¦=–Ã4É/.Gýô9J%’‘õ¬¯¥è=:k�ÜN¼Ó£r@ � ˜ÖÅ�@ ÿzë$(Àÿû½;ûZŠŽY±dÁ›Ó'·g1wo^êd&8vûæõ·.�þb릉ãFõÅV4üéhM IDAT̉CAþ~Ý%*Ä8Ý[ÛcFÆîÛ½£»r{îÿvHtÇ”µgãº÷æÍ™ L@—È~açO¹}ù¬¿¯÷ß§�ûûzk‹×·¬\ºèÝK^9¹ö‹Âú;‹Å<ôӾۗϾ9}òÖ�ëÞš9 ˜@x5z­>ç¾9íúù?®ž;åäè�tí¼Né&ÒPM‡½u²|ÉüãžE¯©ʶMŸ$_»pùÌ‰é“Æë�ÿö¼Ù×Ïÿ‘xõì'¬ÖœÛóÁêeÿx9ÿ8{qî›Óµ�vF [¿Ý “™DEôsrp7uöÆ­;óžç_ºr½«bÄÆ ùbë&“qá�ß5�6ÖVWΞìðTï×aäð˜[6tožþø½“ï”?ŽüâîêòÊ}öɇÚo�CGNÖ5täÙµÓú>+,<{ñrWEê‰ú|}^M—ndÅâ…ßýt ~ÂôüÂâß~?Ñðª0ôB�x:Ó{š“'ä=Ï�Ÿ0ý¯³¯ßN|œÕ±ó C¼f÷ì^¿ÇѨÔÅ æÎy{ÅÓæðùüý¿Ò‰póvJÆ£'¯Sн«ó#^mt^t}ο{W¬³“ƒ‹“S拎±zÙÛL&}Êœ….NNßîþ¼¬¢êÉÓx¿Œ3mò„Õë6 ¯¿Ü¶`î,ÔÅOÒ�{�½(‰\œwmû¬¬¢êAú#Àž�›«ªj.[#‘HÝ^¯ÿðù-…Å%#†¹‘�¤.‘J/ü}µ“™ØÙÙÖÖÖ¡4Ê*ªÊ*:8쨓DˆL”Ù£§JGˆLKÔsùÁÎÖ–L"•WvO]tž ^:¯ouumuumWeèÃúàq8¥>Ç"¯¦Kw•°³cUTµ}fyùúÍWιzDgÄ0DgZ`OKboËÊ|š‹^§wý7ƒÁ`±Qu{÷ì!:ßã UƒAK$<>Ð*Ÿ»¤ûÚÏÌ~u ï?IÖ �Jsuu,(,ѸTÀ`0~>Þ5uuBa«¡T‹çÏ™{þÙŽÝ+–,9"¦¾�ýÙ¶/ÑnÖ¾O²rŒÒy³°˜Œ³'ÅŒžøûôñ3/<ÈÜÜ,/?ÿ‹=û´[ù¤7Æ,{>‘HD§=(JÞó‚�6nÕÎ �Ã-Y8wLü‘t/íá·?ü*‘vì "z@ÿ”;©€% ÞzcÌH ‹ººúï~ú mݸN,;;;YZ˜µ´·ïù–ÍnB¥ýûê�QT 5ïyþWßý¤P(\]œ7~´ÆÃÍM¥RÝ{�¾cÏ7 Ùoÿ�ÃxnÇ– ¡A�x<þY~áîo¿¯o`w¦J)dò¦uïGF„a1ØÚú†U¬_±t“Áܵý3…B~èØ7n%êÍ0x`䃇™€aC-Y8×ÁÞV üqæâéó—Ç�:x ‡Ë‹�ÖÜÌÙ´mWXpà¢y³Õjõ·?ü’xçÞè‘#F ‚(‘©Ʀ?ÎÚõõ÷gNú|çÞ¼ü‚­× [[]�� ºP(ülÇ´f4úv¦…�;&>öýO>ÕÛlÂ’sâcGXZš•WT¯Ý°¥E Ðäß¾ZÄqûç¢V©.Ÿ=ùÞºME%¥K ‹¿O›:g‡Ë‹ýîò%–ææWoÞ6ÞŠP]Ž�úkôÈØÒ²ò-;÷´oH]4‘ã†533;wñòg. qFÅ _8w“Á((,Úõõ÷µõºszÛ[ûÒgϘ2}ÊD•’™�³÷Ûù-‚S¿ÿbeiñã×_*• “Á\ºúƒüÂx;×[:Úï↠¡R¨3ç/Ñî퟈^ñöìØò$;çϳm:ûí‡#ÇÿJº{ßÕÅù³O>tws~šû¼‘Ý$–H ‰Ñ™êÕ i�Ç�Ž>´™Ãõñö"àq{÷ý„þÂY[Y­}wyDx¨L.;sþòÉÓçôæ3qÜè‘#bø|�‹‹#‹ùöÇYOsÛWHTdø»ËÛÛÛ•WTîÝ÷SQIé¦uïŽÐ?"|þìéKKËCGNꔢW´Ë¸¹º8ØÛmؼ£¨¤TÓ=õ¶ºµkVØ2™¶ °|ñ‚� €Õk78;9®ÿp�—‡›B©¸s?íÛ•Ëå�ék†ôí°…èôè¿Î^ˆŽêO¥‘/^¾þ×¹¶×HÜð¡Í\^�¿ïÙ‹WÒÒ­{u€Ÿ—Ç;xìäíÄ;^nßîÞaei�¾½q8¼™-vÜTí¢7®{¯º¶þø©Ó†º��ºaÝûQý›šo%¦Œˆ¼hùšö�u÷öÏZЇ뷔WVéUJ§m;:Øé¼èŒ´ÀÞ¡ƒ•2™´zÙ’Ù3¦âpX‹™6iü‡ï.×øtn�—§ÇÄq£ç/]?aú{od7;B�J!;;:Nžµpçžo×}°röô)+ÞÿdþÒ•ÇŽB׌�ãíî^Q]ƒ^Û2™T µ¨´ ý·¨´ÜÝÍU'¾‡›KqI[„â’r;[[�"KÍ»~þ�+gOa°˜„ä;€À¿â’ò/·}šxõìï¿|¬ÉgôÈû~ümì”Yx<áÐOû22³FOz3-ãñÊw©�Šªj//7ãø/[³v΢eÎŽ£â†kߺtõÆoGN¤¦¥O™½hÊìE?ø½}òÅ æ†,^ùÁ”9 )ʲ·çëDÈ/*:ÿ÷U�Pøã‹äx.",ôáãL@Euõ’UŽš8ãÏó—¶oÞ ñ5tpôÖ�{æ/}7ýQæÖ ½”6ÐÅšuó—®´±¶š?g&`å’…÷>5iæÓß:ù ÍÏÇ«©™ÃåñwSN{ëíñ3ÞjljZ÷þêNVéÄ7FI¤‰3ç�™2k÷7ß+”Н¿ÿ¹©¹iýgÛ§Ì^tåú-#9Gèÿ = –H6oß?aÆÆ­_,]87пíàÂ�Q‘�žd�žôæÝé{w|æäè0uÎÂ]_ÿñ«ñxüÍ„ää;÷�ýyfÊìEí{ìà�¶~±w΢å¹Ï ÞY0·½¾�oáz›Í;‹æõ ]ùÁ'ñf~ýýOè åšüÛW‹Þç¢D�ÛI)câcÑ»ñ#bždçr¸<;[ÛÏ7~¼çÛÇM�Ý"øùxoEf4*‰Dš»xÅÖ/ö¶o{: ®F.[³|ÍGoÏËÁÎÙ/ìÝåK>ÿâ«1“gÞ˜±sëF½«'zÛ›vé#‡ÇÌš>eíúÍ“g-PÈ›>þ0gÑrakëêµÐÂåñt²5RzDhÈÒÕkß\°hõC¹½x×n&Œ‰�Þõps±·µ»—–ŽÅbwmÛ”š–>z⛜¹0nTœq1ºT½"ÂÃ.^¹1oÉÊ~9´ñã÷ÑÀ/¶njæp'Ï^ðΚuãÇÅ<ÐPòÈ~a®\[¸lÍžoöïúüS³no5bËbíÚöÙ¯‡��™ôæÍÛÉßìÚF!“wîÝ—–ñø—ÃÇЪ¾{_�[AC2 2hû®¯§ÍYT\Z´º§ÞV÷㯇\œ'Žà?e¸m»¾Q©T91vʬùKWûz{Íœ:͹3}Í�¾Æ�v�6£QÕjõâUï¯xïãYÓ'÷ Ѥ½~3áÍïœÿûê®í›ó ‹ÆN�½sïwë?|×ß×»¤¬âý�7ñ[h�­üàã�Uo÷Y³r)‹›0sî‡6�5ÂPÚO>Û®P(ЂÊ+«ô*Õ¾mÑõ X'.wóöÝQaï­x‡B&/_¼0vø�O·ïjd\ÐU!J"‰äíåŽÇãëØlÃ1 æÀáãr¹ü~Z:¢T�¿|•Çç×7°³rr½==:”ÞÜÜLòÂá•Jˆ_8Ø*j¥QuM( ™"·E‰D …Œþ{òÏs –¯ÙòÅžûiéh[cÈ ‰É÷ÆN™séÊõ=;¶XYZ ‘oÜN*.-•H¥ÉwïóxüÄä»J¥òFB’¯·—‘KÄf43ã�>I‰ JIœåãíÕa è0yÂØŸ~;Âáò¤RÙ¡#'c‡Õ‰PßÀ~ü$[*•%&ßEC‚ƒ**«Z[E€„¤».ATW¯ßn‰Ü\œÑ8·“îp¸<À_çÿ `ÐÛP�¹pY‰ ¢úëܥѱà Déä`Ïb2•Jåóü6߃F¡+eJ¹v3A,‘ÈdòCGO†j3^¥J¥ÒÚÚÒÕÙY­V•´wðm(g"‘àÿ8+ð(3«¼²J¥Rå'߻ԧ°¨DSœ-‹õë¡£2™ü~Z:ƒ±³e¯ð Iè;+íác_O}AWZ¸Þf3qÜè~>ÔÐØˆŠ-–ˆÿQŸª¥ýs¹v3!>vê“l̨¸ë·#b=ÎÊ~”™¥D�œE{„ñVtòϳ s®eD…øš9Ü’Ò2//À”‰ãÎ\¸\X\‚ ª¿Î^d2ŽöíÓjošÒG�qæÂßUÕR©ì‡_‰`Ö‘7y㥟>I¡P ziz„¡ŽÜ^¼ûiév¶,´¿Œ‰�K¼sO¡Px{z0lèÇÿ8£D�G™Yé�³:£óÕ«!ïyAî³ç€‡�Û±˜ff47_Ï=$“ÉÙì¦3þަûÐPTRŠÎäå”WVGˆÔ©�1ƒ³sòî§¥+äì¥+"‘¨dx‡R‘áfb »©US»{êmu2™|ë{W/[¼íÓOöí?ÐÐØ¨¨ªÎÌ~ªD�f÷ô¹KšÎÞ™¾fH_C�F»Gþ<{Ào\¿�7 ,(*A'›=ÝÝìl™�œP*•9yÏn%¤ŒÛa�é ·ûÄ zðè)©TÆf7�»ØÙýz•êÒÏt_Ññ¾“fgÖ�ëÞ_yòðÏùEź ý%3DYEÕ¿\¶h�««Óƒ´Gû~ú•kØÃ“H,Ñ,=He2§-¦T*£´³-Ú#¶j¢‰Å•F„3šY{O�©„F¥¢×4 yáJ,‹%âDvSXpà¼Y3=)•ËË*ªÐ…˜‹W®ÏŸófpPÀ½Ô‡Î‹a™T*årÛ®eR…B1RT µUdp9 ¥¥EØ–›\ÎbÒ;¬mÈd’•¥Å– kÑ¥. Àðx,kÈ:Ê ý5oôÈ3§NbÐmT*„A§[¾°Æ4ÃP…BÑÚ*bÐmÐu..¿-œËåÒ6€ïöX¾xÁ‘_¿çñùÇNžFk/:ªÿ7?þ Àá°KÎ64šJ¡ªÕ**…B ÐßTãUú÷µ[t:ý‹Ï7RÈäk7nÿúû1ù‡R†rŽ y^P„º¿ ð÷Y¶h¾‹³#ƒ133;Ï»òBø—Åé4H ¹ƒFØ"h;ÙZ&“‘_ÌÃiô]iáí›�X"±°0¯­«Ó)T“¿¡jiÿ\ ŠJÂÖÈ~¡uõ�înÎwSÓ ½¾¡Í_šA›ØÀp+ˆÄbT—­×�9päÄ_¿>ª·f$R©R©|Q9r*™°c±BÞ§‰F·±Z²à-�ÜÚ··V‘XS:€A·©ol[¹ãpy …‚Å /*½¦¶h­Û­a¨#ëí·“�ýõð±Ñq÷|±ÀdÐØMšÅÙººz#bp¸|m;�àE D‚ T ÅÎÖ–€ÇŸ<ÜÖñBYy…¡äÚ/g�Ë´i{çh*„Á°ihxéT¯¾�Í¢wü^2"G«ª5ÝÓÈ»« ¨¤ª¦Ö–ż•”Œ¦²±¶zwÅ’ "O 4‹ƒ�ék†ômÛ@ ÑîÑr¹\3Äår¸Þžîm¹½x�0ôæfÎËçÞÈöóéò8³}÷¡R(T •ÝÔfF46u֞ЫÔÓÜç�ÿ™î+:µ+V,‘ìܳoØ�Aw.)-œ>vP3ï�Î+ÌhT s3Í›ËÞÎ� q°·ç4sMÍœí»¿Á`0‘ý¾ٵíÑ“,D¥²³c¡Ëÿcâc£"û­|=�ÏgÐm.Ÿ9ÑÉÏ" Å�ÃÇ>æììøÍ—Û ‹KïÜSi�0 å_­R)•È ¨ÈôÇ™èKÊŒFãp¹è®õ.½S"ÂB��1Œ E¨T*ˆÀãñÑýËFrŽÐ_³ÓžF¥•–U ˆÊ–Å68ºó¥sù|gG= zÑÖ·Kèm6_»¹zÙ"[ ‹ÅúùxQ)TíüõV Ð÷\7’c 7jäõ[‰hHʽÔýíí#‡ÇhPºÚŠ:Ï…Ë×ÞzsZ€Ÿƒ¡Q©±1CÐY µ7 ·’’§OïâìD&“V/_œú0£Ã‰“N–®Ý# ud½â=/(’É¥ï­Zvãvº4S\Z& G�8ÚÛ Õ¥JxeJË++«ªß]¾˜J¡b±X7ç@ý¾aNŽŽãÇŽÂá°ñqÃfdêDH¹÷ <$xðÀ(<7uÒ8ssóÇ™ÙÝ%ƒv÷ÔÛêœV-]ôù_}þÅW³¦OA'!Ìh´ªšZ©TF"'uñ×ĸ¾z�N�V©TË/ ^noŒ©Y"×Ò½¼‘ݼhþ<à7\3ëóš$¥Ü_²`™Lb±˜Ó&¿a(Z‹ ‡Ã±˜ #JémÛ¾èFÄ Ö¬dÅ ª÷ºéþ/Š)òÚ5Ë�íårevNî¾ã§/üýù¦�Oú™Çã=ÉÎ�ìÖ-eUU×T×ÖF„‡>~’ øá—CÖ¾wéÏc"±ø×ƒGÐIº�õœS=t HBÒ]W'§_¾ßK ào%Þ9zâO¢R èñö¼9d2©¾¡ñ×ÃÇ®ÝJð[úùÚ5+?]÷ayeÕºO·ò[:å Ro XYZøûú|ºíËnQÜ�œX8wÖÏûöXYZ47sþ¾z3-㱑øƒF¥¥·E()-»v3áØ�ëØÅeå%/ö®Ü¼ýþªå^žnEÅÚÃÜ[I)¿~ÿ••¥Å�ûŽžü ôáš$‰ÇåíØóm‹@0h@ÿ”ÔhüË×n÷�?öÛÿ~ÚÃÎëegÏZÿÑkK±XzýV"º¾vì�ÓkW/_ûÞÊŸÖ›³«‹3¢Tj&~wïûñóMëš8\.—÷ÀhµèpùÆ­/6o¸ý÷™é�ŒLÐÖ·Kèm6~?þ΢y¾ßkfN+«¨Z»a‹vþz«è{.€f÷Y~¡»›Ë“ß)Ô7°¿üú»]Û7 „‚â’rÍè°«­¨ód<ÎúáçƒÖ®qp°‰$™ÙO“ÿ9xE1ÔÞ4$&ß³c2¿Û³�J¡ffçìܳ¯»J×îzŸˆñ®ÝJZ¹dáÆÏÛ‡T©T¶ìܸÓ&r¸¼ä”û]ª„WF­V¯ß¼óÝ‹Oÿ�D"UUÕüvô¸¡È= zÕ;MÍÍ6ooÿ%fCcㆭ;V½³øóO?.¯¬Z»a³žùæW’A§{¶ou™O¶lüèÔésE%€ýoÙøÑ‚wÖüväø§Ÿ|8|è V‘8+;w`W¬gãúê}4:=Z,‘–•W\üó¨J¥úýÄŸízAÕúÍÛÖ½·êú…?y\ÞWû~ÒìÀ{M¾ûù·�½ùô‰Æ¦æÛ‰wFEè�&•ÊŽž:}ôÀ�x<~Å{éUJoÛîðEN¡PP·6¢ú Äö×ÝÆÞ33éõ¥»7ß^#$(pÉ‚9kÖmêkA:`ùâ-�æ»JaïÎ-_½qïAº‘8[7®Ë/*þëìE�ð¿O_»akqi©‘´8öÊ™“3,5òýyÏ1{Æ“ñÝO¿uo¶çNý¾iëNô�©COëÛ™ü�<—õkן~Óóµ—é`¨½õö#â¡« KV½Ö±�½ÉÄq£‡D@¿×í}z¨{áôÕéqè·¾ñ¦÷˜Œ�eæÔIÁAþŸmÛÕׂtŠ °GýsxµE…€¼ì—�µIþݧ±ròž™¾iøå�þ̓}KöÓ¼ÇOzð s3³CGOö‰ihllJ¤;SýšXZXX[Y6ØâÞÓú¾Nþ,3nØÐE+Þëv©þK¼r� ‘ˆÓ'�¿Øõã›ÿoé‰îÙíôíL'G™TZZîìä0sÚ¤_ék‰z“¶NV.]£rç^Ú¾Ÿ:{î;¤C ÓÔ]ð[g/]éÑ"Œ�t÷~÷fèãå¹ÿ›]�½Äç·è�ÐÓú¾rþK¼5çÍi§þ:‡~¢1Ä«õˆÈ~a{wlÉÌ~zãÅžž×!fHô«ÞÑiæò–®z­ém½ïÒ²vß ô&ÝÞ={‚¾}ƒé@¥PvnÙ`ee%µ^¹~;)å~O4ÝÆúàþotW¼¿ý¢»×è�•�ø¸a`n'¦ô\�@L�W[Ùù×{„@ òäWv HßâåîlÏb¨ÔjA²ó ¥2y7fŽÇã"BÖ–,F©Dn$¿ü2bØÀ~�ÍÜ­ó�|=Ý<\ xü³¢ÒÒŠšn�˜ &j�PȤ‘1x|ÁýŒl€•¥yX€zX5—×’“_ÜúâÄzÒCøy¹áñøûÙjµÚÊÂ|@xÐÝô¬nôÜë`Ë47£ÞºóPñâ( Yy…:�…¥…¥Ñ‘!ÝU:1eLÔ: ðá¿8Ó “ÉŸ>/I$X ÆËÝ%2Ä?%ÍÔ7{C ÿjH$¢‹‘ùôùÀˆ`¢Hdr[¦ —/7$óésOW"�P×Д“_Œš,#cä<+rr°µ·eà°¸ä�…­",ãïínoLjÅÒ§Ï‹Db ™D1¸?‡Åb°#c„­"t(äkÇbðø¢²Ê‚Nœ­ìhÏòõpÅápJD™•[È;L�@LS´Nl™t SÏn¶{áhF"•I¤2ôZ,–ÐíúN:äÿ{£¶žäû$'ƒÁ �Žxœ“oeaÆá¶6VÉ©�ðxüˆA‘~KM]#@Ø* ô©¨®{ú¬yq¶¦‡›‹isçA¦B© ôõè˜òà±T&¿ž”êéæÄbؤ=ÎÑ.7+¯€ÂˆÿÎiiaä{/=«EÐjˤŽ ½‘œ†¼pq�@þ½˜Ü®Xä癓¯ë¦�Ã��<>~hH€wQYUŸÈ�üÿ`ia&’H€ˆ%R¯E¨T*ñxz·¼ºN¥RË劆&æ͛ŒR©”Ë%åÕˆÖAþŽvÌòª:t™¦¸¬ÚÊÒœB&u—�ÎvÍ~‹ ÐØÄ‘Éä,ºuwe�@ú�^š;1t°‹“£¡»‡ŽžÔ\ûzºÖ54µw/¬D�¤û�H$¢«“]‹NÞB = ™HÄ`0¨ÓWk+ ¾@H&‘$’¶)LÙ‹í± …ÒŒFÕ¤âñu½=�I$Md¹B¡V©H$¢f*ô5!ð ºÕèám^“p8‘Hè–œ!HßÒKÖIò½ÔΜwÜÎ'r IDATbF£:Ø1“Sõ;õ�Éå2¹¼°´rÔ°�7’(•pþé)•J.WPÈd ãì`[×ÐdË´),m;¿‹@  �€—k9mïþP*“i,�Áb»Ë4H¤²6çñÓN¹ç„@ ÿ"Lke‡nmI!“F 86v°Ÿ—Ýúå¨H<O$ÀÒƒH$R,Ãå·D†—U9Ú±ø-Bͤ¦«“€€ÇÛ1éìf]ÂÚÔ64¹»8¢KB>.;¬û>K®mh²eؘ›Q2)*,Î�@ ÿ LkWlM=»�ÍA¯=\6VÙ϶L™\.l‰„@‘HŒ®…C �¢™×âhÏz’[Ðö/—�Ãá4w%RÙˆÁ‘D¡¾±¹¾±ÙH>e5$aXtƒim?~úÌHd;=<È@ÀãÕ@íîâ(“É“R9Ù³‚ý½Ñpºµ¥�‡k«H|/=K lÍ~^„ÅbÕjuQY¥\®0’?ù·`ZÖ ‚ šýö ¥R­V£Ã,,äK£P”Â嵤eæö©˜ÈŸÆ&Ž·‡‹«“}eM=‹ ðñ‹%eUµèÝêºÆ’òj�$™9ùíóQ©ÕÏŠÊž•µ¿UZQ£s®Z›s=)µ}ÌšzvM=[¯œµõìZ· ȿӲN´))¯Ö¼þŒ¼› HñðqN ¯§Ë;•JUSÏ®¬©y¯ÛŽdƒ@ =˜®u�@ú%‚<}^Ô×R@ �ÿG u�@º€B©¼x=¹¯¥€@ ÿqLë›�@ h�@ 1-àÊé?/7•¢÷«míYÞd2Q…¨ J*J+kŒÇïi"Büå En~I‡1÷mæò5ÇÍA �¾ÅD­ ™42f�/@Ý–j ðqwu¼—žÅáòûJ6bˆ@�âòêò÷-ŽvLk+‹äû�:93'?nHT}c³ UÔÓ‚A �1Që$4À‡ß¢ëLÇÊÒÜÚÒ: …@zs3jDH‘€‰%"ñËó--Ì‚ý¼Èd€ÂÒʪÚ@�Ÿ§³ƒ‰D ðq÷ór<ÉÉo4|Œ,‰DììG¥�±l‹°5+·@¡Tðø7â‡^K¼�ª6(2´�Ý\VUèƒÃbÍÍhR©LÐ*r°cVT×—V踢 ƒñ÷ñ((®ÐvI7$ª²¶žnmE&Ôj�‘•'}qp­T&¯¬©÷óvËÈúÇyqD"a\Ü�§ÏŠLÄä‚@þO0Å}'¶L:ƒ©gÿãJ êïÝÞw1é!Â}›8Ü[wfæäÛ±èh ‡�Ž©©g'ÜMO}ô4ÈÏËÚÒ�WPz=)U©P¦f<½ž”z=)Õˆiðñpi‰ïeܾû°E ¤ÛX‰¬V©)dÒ݇O˜ k‰TöôY‘›“½qá­-Í)dR}cÓ?òj[†Í£¬¼;iOd2¹§«“öݪºF{Sã‡Y“F&“ÃAÒ˘œu‚Ãá‚ü<Û[!nÎB‘˜ÛÎ*é °X ÝÚ�‘Êä Mm.&6Ö8,¶¢º –HkØN¬WÈ_©DèÖVLº5‹-,­Ô¸°Ð‹Z­n´ªÕj¹\!l)J¡ƒy_k+ _€´óJXSÏV©Õ¾@H¥R´o „­‚XY˜kÊŠëI©h=@ �^£—VvF ìâähèî¡£'5×¾ž®u Mgc($ÑÛÝ9%-³E„@ Zàñx€ÁÈåJô_…\�#“D�ÇiÜsb±Xã^ QXR� ª@33j›““_lÜEŽAjµATjµƒÁÏŸL$Êôe¨T¶i¤V«Ûg!‘ÉÈ$R§•€@ =E/Y'É÷Ro'¦tÍŒFu°c&§>Ö òõ,©¨†þ½ �^C©PˆD‚L.�Ém¿Ù©L&WÜLI{ÍüUjuQYeQY%‘H ô òõ|’[ j€Æòèp‚ÄX/a0¯–�t/¦µ²C·¶¤�I£† ;ØÏË�nm…Ñ6V~^îcc��ŒÃá†yº9u˜yeTj5�/pq°Ш&Ý çµÎ¶èC·¶z…üûûÙ2é¹\Ñ*j›+U*¥BiN£ÌÍhæ´W–_*““ˆ„®¦"‰R©L;„H Œ�ê �@z Óúf§¦ž­Y~öpudØXed?$?x¬ÑŒ>ðI^Á«M&C �Γ•Wâïâd/¶ÖÔ5¢Ó'‚¤eæ„ø{û{»«Õêzv3�ßò ™WT×…ø{ùybF(gç¢á9ùÅaA¾‰´U,a7q1ØWAqy‚Û~ë‰!,ÌÍp8¯åŸ›Û0€B!ãñ¦õª„@þó˜V—CD³7^¡TªÕj™LÐYÓ‘+”ÒÙ7y5BQûeV@‹ õ^z–Þ$Wîu2s._ w'YUmCû-¨¹mǩݾ›Ž^\OJ5ž?_ ”Heö¶ÌšúFM`’ÖÙ'EeU:I\lëÙÍ:ï¹\ý A ½�iY'Ú””W—”ë9Ïàò­»½/ 15ìY ÍwÎÚTT×óZjµ:¿¨Üßǽ¾±©3Ó'dÑÕÉÞ�Õ�@zÓµN Äõìf�S‘t¨m`Û±è¾�9É>"Ä¿¤¢ �˜Ð:�@ ÿY:t ¤!õÑÓ•�t “°Nà7|�üÇ@Ïx5Lë‹b�@ “˜;�@ �n„L&�=y‡Ãâqøø 3´o͘2‹Ãýuöb·ŠÁ`ÞY4otü2™œû,×WßóøÐ•:òŠ˜èÜ ‹ÅL¼vîû¯v¢ÿz{znØOûv÷ ùó请/ŸÙº±í¡x{zìÿv×_Ç~;sâàØÑ#5ñƒüíÿöäï¿üuì·eoÏG­™˜!Ñ'ÿ¬‰sçæEOwW#…~ýåÖ±ñ±K½uåÜÉ+çNº8wç‘ÓcFŽøóÜ6»I¡PüzðèÐA©j7æ�ü_aŠÖÉ �ý DÂýuÂå/èÆ£Ø¸<þÅ¿¯•”vµW7zä¥+7JKËÙMÍGOýõƘ‘:|}½ímûý¸H,¹pé—Ç‹m(!‡?üÐÑS|~KNÞóÛ wÆ·ËÐ1¤£6zõ5”0>6&¿°81ù^k«èçƒGÃB‚ìí^Å­n¯Ñ™¨Ô*M§P«_}÷YŸPQQííéñöüÙë>Ý?aÆç_~ �É{wn¾•�òæü¥«?ÜøîòÅþþ>hü�Þ_qääŸo-Z>oÉ*&ƒngË|…B×nØš™•óÛï'ÇO{kü´·ªªkŒDž7gÆíËg´ÿ~þn¯‘ø®.ÎmG4qy|©TêêbÐõ)1ŽÉí;!‘ˆï._¼nÓ¶˜ÁµÃ­,-Μ<$—+Ò329)–ˆûJÂÅÃÍåòÕ›èuqI¹�-‹J¡ˆ%­®Õ5u©TÇÃÍÕPB+K *…Z\Z††––M;ª÷”yU éøÏ8zô5”ÐÝÍES Í.�ßâîæZßÀî e^‰ÎÔ``TÄ¥ÓÇš9Ük7Îÿ}õße ˆD"�zôäéêêZ€J¥„‡S(”KWoÙìä”û£F ËÏ/ˆÅ’¸1 �M¥å;ö|Û ?uæø©3��O¡P¤rÙÚ÷VŒˆ2~Ú[R©ŒL&÷œxÈ›^²NF ìâdpqøè)Íõ¹³’ï¦ÖÔÖiGàòxŸmß]^QÉ ÓW/_¼ñã5Ÿ~¾«Åí;(dŠHÜf‹´ŠZ YÛ:¡’É"ñKËL(j¥Q(†R¨€XÔ_$Ѩ”ÞPãõ0¤£6zõ5X9 [ëØ.Q«ˆjÚõЙxš“·qKiS3ÇÇËó£÷V¨�úü¥«½+æk�~j˜_X¤hinN¥RÎÿñ;ú/�@ÈxÔvÚýgÛwÍ�5cçÖ 4õÒ•‡Žž45w‰„L$eçäI$R™B–¾°/!HWé%ë$ù^êíÄCw5ç�¸8;Å:©în2—w÷~ º¦n÷×?üù[� P(t3ú÷#‘J4„Í €¾é4ˆ¥Rõåb¶9ͬ±©ÉPB‘ Ò¨�@£Ñ4¿è¦Œ!µÑ«¯ÁÊ‘H¨´—á43šØ´ë¡35 ÙhRS[Çd2âc‡ÿ»¬Z�MÍwêìEícr8¼ïöønÿ7ç/·mª®­¿~3A…¨pض·‘Hì^_}óæÌ˜?{¦vHIYÅŠ÷ nZ*+¯ôps=wéJbò=;[™D¬¬2¶r�@Œ`ZûN‚YLƹS¿_9wòí³ÃB‚.�>¦G©T`1,ö¿y€[YE•§‡;zíåéÖÐÈÖž8”UT:9:�HDMœ²ŠJC ›šÄ±§»îãá^QQÙ+z¼†tüg=úJX^Qååá†Òm¬­,-ÊM»:SÚ( î¿Ð#žå fôȉ¸î½Ua!�èõOûö [ÕÔÖqy| VÙM,Ý|7¬3k["±ÈÅÑ€Çã�O%?u&~ í?#¦ àÚÍ„7§Ob±˜D"qù’ÉwRu:/é<¦e�ÜLLžþÖÛ –®^°tõŸg.å=/\´l ²_˜¯·—™ÍÃÍeí{+3g¡¾‹»"‘H$�H$vW¶¯Æõ[‰“Ç�usq¦ÛXÏ›=ãê�4|Ùâùè÷……%u �oÏŸC&“&ŒE·±¹—úÐPBQÝN¸óöüÙæ~Þñqï¼ÈД1¤cxhðŒ)Ð8zõ5”0!ù®¿¯Ï°!ÑT å�ÅóŸæ>3åM'À°",&ãÝKð8 nÄP'G�Ú/,dÞœ÷RÓûZên@&“¯Ûøù¤ñcΜv“1ïq¦€^Eü}½ý¼oø˜)r¹Ý}ianÖØÔ|íÆíc§N›Ú> òº½,(lÀÑÇWoœÚ¢B@^öËñj“˜®u�@ äßËëX'¦µ²�@ ­�@ ¦…IœÆö:N–!�üÇ€s'�@L h�@ 1-Lbe§=2idÌ_p?# !‘ˆÁ~^v,:˜ºö“Ü‚¾•�@ Ha¢ÖIh€¿E¨2°_P«H’ò S©Tšëó&�@ ä¿�)®ìØ2é ¦^Ëm›-“N&‘²ò ZEb©LÞÄáõ¡x�@z“›;ÁápA~ž3símš@+ ¾ 5*<ˆacÕ*’ä”4sù}($�@ �ž£—¬“C»89º{èèI͵¯§k]C“Ž+] ™doËÈ|ú<#뙋£ÝÀ~Á·î>Ôñn �@ ä¿A/Y'É÷R�œd¯ÁŒFu°c&§>Ö GD(U×5*ªë|<\èV–ÚK?�@þ3˜ÖÊÝÚ’B&�6€ÃaqXÜèáÑ7SÒZ„"ºµU_K�@ ¤70-뤦žÝÀæ ×®Ž «Œìg€ºÆ¦ _O'Ûºz¶“ƒ-‘@àtŸ�b�@ &…iY'‚ ‚^+”JµZ-“Ér¹âá“ÜПð _a«8-3n:�@ 俊iY'Ú””W—”Wkþmæòïgô¡<�@zS<ï�@ Èÿ3Ð:�@ bZ˜ÄÊÎpÜ×"@ éNR@î+§…s'�@L h�@ �¾�H!Íß¾`ó¥­[¯n[ÿç†nÏß'Ê÷ˤÝ��¿rÿª¸ñÝ.FïðæÆYãWNÐ 8)úókÛûDžNB$?>µ>ffŒv ÍÊlýéMî!n}$Ä$0‰•�öX²¬><²¶êyÕ¡�~Ä-ˆ¹`¤æ®Z­Þ9m‡ˆßÚ¥<£'Šiën—uëɹ½gÑ@¯~^Ãßáèã„(‘Âô‚+û/K„m‡èÇ΋4e�DÈNȺôý%¢ê&å: ÃrÎÌéOwôqâÔr.î»P‘SðóŒ_oïíÐÊkýjîíøa#ÃãæÅYÛÛðx§¿ü«:¿ªwyôꨃފ2”0`�ÿ¸•,–å9åçöœniôª>]A§ñH„ù;Ø{Ú)¤æš¦›o¦è$!QHS>œê?8P&’&ŸHL»”Ö‚w™ ˜ ¦ sÏœ]R‘´«i1ŒZ­6§êYåO«öw>Ïs{Ͼ‚$†èŒ„ÝEpL°“¯ÓwKöiBhVf‘c#‡ÎÚ;hãèã(J¸õ\ãѰ8¬“¯ó„UÈ4²Î-¿õâ·çg¬ŸõÍ‚¯” e�I 1iLÔ:™¸zbmQ�æß”IwþHF¯‡ÍîÕÏ««¦ @À$¹ó�=.V¶VOndžÝ}†@&NÿxúøÕÏ|ù dDHôäA×”Ä ¿|{Äܸģ·_O§NÑa¹,fÞ¶ùE…¿r8,>|ÁŽ…»ç|)m•Êeòô+é4KZô”AÚñ}¢|ǯîësUϪ¬X–b�¸´xM é¨GoEJhŲšõÙ[g÷œ.zT4aÕÄ77Í>ðÁ¯}¥]‡è4~D‰Üù#…]ÉV*”^^s?Ÿ÷åÌ�:Ïqì²q–LË=sv1œoï~»±¢±ìiY¯ ÞÌéæk¼O$°xÜÚcë å ¨5æäë4~Õš%M¥R?º–qÿÌ=4É”§ ¹B‰P2lÖp"•xý×ké?4”?Ù¹lßr C³¤mˆý¤Cy¦~4Í?:€L#§ü‘¢éq4KÚ¦óŸ�Ý}&hX��=½¶¸öìîÓj•AƒÃœnþɾ]øõ´�gÚ{ØÉ¤ò]3wèô)k§ÚØÓ±XLÆÕŒ¤ã‰Æ3ä?vÙƒ)É,¶dX–<)yp!2@*’Z0,ö¯ø]|12‡Ñ½<¹™ PÊ•� 66Æ#KEÒ¢ŒÂ¢ŒBx!à©m'Q ƒÏæ7×43œši�ö™;x9b0˜çò9)OG/ƒÆ V’Y‚>åÂô‚V¾Ð+Ò;?õ9À5е¶°º‡V@„\añãb@Ci=À’iÉ®bë�éè6wÛ<‘BR«Tc—Ž|5o�LüНÍòœŠq+Æãp8Í‛oÜ :L:‰Bzù¼ºôwf™°š·+É.&SÉö½ìÀÙ³«žqÃ£ÔØTçþΦV¦À2ÕŸ¶q:ƒÅÀŸâqxLfË‹4u]ðšÐµ$²Ö]Öo„i¨'“ÊÜ·&€û;tÿ²ö*¢IÚu‚&F>{—Ž?v×ßÖÍ>dÓ›‘’ÞÃû<½ý´ÕßµD"#b"�€H’\*—J¥�ºtœ±uæÅ�òSóIÈ¿|ûôv˜¯Ç¦D%ÕñêMüäƒG)[H]¾ÃçO¸ý´²°¢(ã»”í;cè�Ý}ܘ†zøµgŒ€ID"‘ˆa‰B’ËäR‰n>ñ òÊOÉ'0�‰žéߌª…ÔÕѦ‡­¹­9~׀ʆR—0)*yÈ ?—�.Ù ÙÃæÏOÉÓÂI'êN~K}JÉ IDATKCsÃü´|�CßQ}�,� R @©5dRYbij!3|K7•Yöðu;±îX{ÖäÔ×Õ_{tÌâ±¾3†J$²›näµê棻šX™b Ö^X7þ½þô¶êwq—Îß�A“ÉdýÇõç±y»çíú€z¼Á­¬‰=;oç|n73>#*$Êoö°êâªÂ…*ã× ê/ÿy)`U`}�èEÜ‹‚”<�Ë 4§äò®KS7L'SHR‰464†ÏåãI^¦æ›3‚D&)O=Y{a=�H  eýå p`žҼ2 ÃìzÙE�üxwê†ÿïjK¢ œäå3mÐ4[7ûAÁ>/½P²én]˜þRyÒ Ð™t=#Vãc!Ÿ#ÌÜ®æÿ‡wøîy6;"2hÊ ‰Xzÿ½¶+ïGÑe€³ÿ2ÿ�3ÐjlŸ¶é�hוA�/\ÌéèÀÕ“V‡¬‘Š%W÷„µd´8õnŠË@—óG†ÿÝÌU•˜31mTÌ�ˆÁbŒ_1ñÌ–Ô5ù’¡Þ ‚ ˆ)/(¯øqg9ó1 Ó.ø\>¾Ì.ò%ÓŠÞ‰±ü=&œ#‚ ò P»>Nó´ëŽbAAÔ;Ay?Ûƒ¿¾¸bå�µ&öoí±`bk:~K�æËcÝÏušÏA>­¸²ó.¦©Þ죋JÒ‹Î}w éìéæß›¦G¯Ê«¸³÷VÉó¢÷=fÏ }\G¹Û˜¦ÝJ¾ý[8hÕËÆ}º§™£¹L"Í}”½÷¶°¶aåæ_yõœØ‡D%¥G¤E±;Š›Í× “шƘ9Z°‹ª#þ¼Q”ôÜÆ÷é>ÚM¿£‘°F�žwò¾0 …Nñûn´�§£ˆ_wò^âåÖl ¨y*ëØˆÊ†R—ÐÞÓaÐ7Ãt�™¯’ om¿Â«ÔƵ±Ço ²ótÄ‹ëD�Ú�?& ž³¹Œt£êR+sËÏ­<©¼‚0�H¼x˜m{†¡.»¨úÁ‘˜ì{íPz-†aXÛ®Ixá‡Xv}u£p;³÷=”�»ý«ä—â[Šº$íUÈâ#rÑ6ZÚ;²txYÖ›õ.mÜíݧ{žûîdEvYŸ)ýÇo Úðçû~Üð*y�ÆØ{;+ê™é¥ÝLºùëU2�<ü‡1>K†ßØN>]Ý&ô ýþT}�p¯SÜ¿øðèÝ6©ZÓšÍ#`þ›'å?ʹ°ú´³_· [‚LÝ[Ïê2cöß©È.3°2òßP[Y“z# ¼ù2�™¦î5ìh°cJU^EaR�*ò!ÔÕQ9ŽÊ†R—�iʽ>àæö+ù�s‡,ñ½vüÙm¿B›ˆØu#íf(ŸÞžs[õ²¹¼ölM)×ÄάQ‡•@"`þóÅšR®�§ãØ �ÎÙÏ.lå²@Ÿ†‘î‚3K�ÌÜ7ü‡q&¶&b¡øßI»€®ÏðYìס‹‘LÌŠyqw$Þ˜];ú,FÖ¡ˆ„̨ôûG¢år9U—¶äê÷�ÿ£Ž+€€íÁ¹q™Ï.©íß»åÙoª'‘Düúâ ˆ=p6Ík¾Ïåu¡­î�t2š²{FÀè,��>[ZwÑBÚØ;±íï@¤sdØô³ÃCXæúåYe¥éÅ�ž8pŽM�^÷ö ÇÍÊŠ}{ÚP”¶”Sþøxz>ÞsÎ`ü±ËˆîIáO+sÊàÑ©{Þ |5Ó;i6_3's–¹þý£1â:QRXBï€~öÓn&ß;…G°ù™1/Ì»vL½‘D ºú¹^^{®ŽÃ/âðÓ#Ò\Gv×þÞ‰º:*ÇQÙPê:éZšQ’õbF-ýV¯«¦Td“Ie�–É¢ëÑ{Nè{bþö«j(Hh¼vª¤^¹ûþ8åÚ³>“Ü;8šá½~O\/³!àÞ¡¨‚Ç¹Š©y~+GŠêDGgí#�¿Ní3É=þÌCð]1âáјìûY$ ièŠQL3½Vœ�NÜ—KÁ¢«ååu¡­.y¿`Ï~ÁÊ!•¹åg–©]ü—]XõÏÄ]–sN.nu¦¢…´®wB¢’}í{ù§³v߬ܒû¢‡ïÎåYeÝÆ¸•¦¿oפ%,ºZVæ5lnlm’Þ°ðbEv¹ž‹B§h`#Àfó5¶6a¿ªVüÒ*Ï.3¶6U>†aæ.–©×“€iªG¦SËsÊ‘]G¹}ì*|¸fëjJ]BC“Šœ†�ux•¼:ŽÀØÚT;{'fz ˜éÅ)ªŽ;qÿåÓ<0±3ÖÔ¹ŽîÙcLϺšº„sq‰—Õî« £Ï`Y(Nã/™ˆ/Ì”“Ÿа“™Nµ÷t:±à L*“Ie‰W܃=ðÞ‰˜/rôqá–ÕVæ–ÝÜ~EÅë3¹ßÉ€¦GŸ¾o®\&¯Ì+?÷Ý©ø�ûñ!÷5PÑrê�øxyZu´T÷,÷hžâqÿé3ï¾`½µ JG�û 3ø³1 °ùçW…´y ;÷µí:¬{È’£ø¿dE±�m=_d:Y½“fó%Ó("¥hëùÂF›Š ˜í�¤\{ø(‘ˆ_¯ˆLmr2-ÑlAMC©KH¡Sxeo&šÔó„dòÇ+«%]y*àðÄB‰Ý‡€íSN~}¤"»”i¢§k¤Ð(ÿýelc2é÷`Ϋêü'yï&'�ˆ£×�O»™T‘‹z' —Cif±r�IÅØ„_&ãWÍ0&7ìáruóžS=Æn  2(ÉáϽû±ç™=9÷älÌ88ÿòºPíì+#H;ÒPï$*ö~+ÙBÃH¦A'#ÇÁ]�ÏÛß(B¯€~N>.Ggïãqœ9OÚ9íÈÌ}m8|bÙÃjôOþ—×…*ÆÃÅB‘â‘Ê €¸N»·7›¯X(¢(m°NeÐjËkÿö êßep׳Ë�ãWðn …AÖÔá‘뽃õáš®£RœÆ ¥.¡¨NDÑ}Ó¿¡êÒÄM¼šï+/>Pý²Ò¢›•ã .Ù¥‘ðG¢Åu¢’çE™16îöïöNDÂØ EQäî›/¸–jt�Œ_Å“Ieg—ç–pÅäWñ¢÷ÞŽÞ{Û°³‘ÿϓدØÏo%ɤ �<Žò)ôñ¼ï•ù\iו�ŽÝ­˜&zóO/2�D$“žûößI»MlM²dVT@zdêàÅ~fNæ c¶ÌÂ¥“ÿÆ€ðÍ—‹RÞìZ™_algŠOU1±3­)ãj`à¤%ùVæWX’¨$I½�£øJë5±ŸÛø>g¿=ίnؼ´¶¼F\WobcŠÏ51±3­Îÿ~U7QGå8ï6”º„Õy6îöxB†!ƒÎÒ©Ôúv�I$ Å…¹&ˆ„QëÆÉÄËëÎiìæ²OŽL*˾ŸÙoªGÄŸ7@½ûIÅ’ÄË $*)`Ç´k›/ò*k9¯Ø‚j>&—€¸®¾ž_oÔÙDÀæZ›Úux‘Út"�PÏL�H&ʤ2ª. ÿUð^ЕÁiWï$="%÷a&þ¸‡ŸNnÖW7ž€âôâÞ“ú']~Â-á8xw¡1iÕ•ï{p|?q‰B¯=wèb1á— Û¿_+N-$QHr¹ìM»•ìóͰŒ¨´úZa¿`�Ô›ÍϽoêò8wpÚívaUYF ·”3`¦wÜñØ.C\†º9÷3 Ç¸Þý‚=BWž¬ã µ“IeéiýgzUl,×·0èâë¶¶õóõ4F];ºu6±1}vé1¨i(u _D=ï?ÓÛ~ ÓË„<Ϲ>EÉ/µp �D%9z;¿|–'Ií<í=Ï.? ìªâç¯Ìò¾»/ÒØÆÄÁ»KØús Ôñã8]ÝKëB ŒðúÕoï i£ˆ?®Y:|îÉÅr¹¼2·<âÏ ©—¤ÝLœôû49†A~|NzdC/$ú·ýVŽä–Õp‹ªóâ³ ø~;Âq�3�häI;§É¥²Ô[ɱÿF@Fô g¿n‹¯|/ŠÒï¤Eí¹Ýl‘ŽÏ;ð!5š¼ë+ÃÎÆø~¯ÐÝ}‘i·“›K‡ ÚN+ö(”{¼Øgr›~vøz'8ÏÇy¨+�Iç–râŽÅfD?ßb ˜åí1Ó[ñï“и˜"†­ÓMi¢¨ò"fxõ èG"Ò#Ó"ÿÔàz'ªò]v}õ•�ðá"C+ãá?Œ1s0ç³ÿÛu_Òcî©ÅúŠƒäÆe]úñ,Pè”aß�±õp Dq'b?•õNTÖ±ÏäþNÞΧ^¯ë ²¡T&{O‡Á‹‡ë3_%ÜÚ^[ÑøRQ»#QI�Ûƒ�í͈$"»°2îäý̘tü)¦©Þ°Uc;vëįæÅŸ~�|õ)(µÓDoAè2åCÅì‹Àç4 ‚´£óØhíÅÚÛ;AAäÓõ!½´’=‚ ‚ ÚõNAÑ.Z1+öö ½‹€ ‚ ˆ¶@c'‚ ‚hÔ;AäÓð˦µvví]Š63gFpø…�˜[a“Ç7zê3«)‚´‚–öNLMM"¯_üë÷_!Ó§^:sôÎõKÛ~^§§Çl«ŒŒŒ ÛºáÚÅ�w®›š·Õa?Ä쯦^¿x:âÚùV,!‰ïF°êÔñß=¿ÇÜ ;yxŸ[wצêÐé›Öþpçú¥«çNø�ÑP>˜º:*SY_u ½<ÜÏ�<}óòŸ;¶ši¢¦Ù5bhÈÑ}Q7._»òÓªåtMó…lC†5ÇÁÎöã\“ÇÁ>2& øq³wŸjuMD;Id±°þÝp‘P(•JU&ÑÒÞÉÊ%‹22ß,ëç;hrà„ïÚ86pš¨^üã÷ß¶UFr™ìþ£'ëÞÞVü@¾>ÞãÇ.]õSð¬E®.]gMŸÒ(�@Øöóº´ç£&L½veÇ– ººŒ&.Y8ÇÄÄhb𬵛¶}½`VÏÝ5]¥÷§®ŽÊTÖW]B3SÓŸ×ÿ¸ïб1�Óªªª6®]ݵz-i�ŒÌìµ~ñŸüÕ¢eß›w0›3sZ»µÕü|ýýçŽ^n=ÎÛÿßÕójxQììþ·kûÙãÏ�<4røP<�L&‡_±´0ÿkçÖð !§ŽìÃý8yxŸâ˜1·Âìl:€‘‘áÝÛW,-Ìÿþó·ÛWÎ]>{�pòð¾)“&lßüþ÷Ç¿{~722lº�«W.�7kúäÿ«çNF\»à?vî;ØûÄÁ¿CONÁËB¿!ƒ]]œƒç,::àJø p´·ûqÕ²Ÿ·í újÞ¾ƒÇÿؾ™J¥€gÿ¾®]�ƒç,œ:ká‰�Ð�Ü[Ñ,ï[SÑ~üÚq½�Ïáp*Ê¥’†Ý¯DB!�Ëá”—Örصµ*ïÖºÞ •JYºhî®=oýbÀÞ.&�@°±î¬ÑbiŠ­µUVv.þ8+;¯ƒ™™�þv„Î…¯Šë„Â×qrm­;«Khfb¢C×ÉÊiÏÈɳþÚM]ߎ£¢¾êÚXwÎÊiŠ«¬ªfs¸6ÖÖ¨H«µ¤ ¿ÞáB"¯]ðôèzáŠfËø¡ø|ƒ¡sìThaaÈd2èéÖ�N§‡]» eååQÑ÷†ù nÝñy|Þ£ø„¸ø¹\Žqç.>’ü"3Ë¢Csáþºó¯ÚZž¢�Æ~’�„ŸQ=fs8ýúô¾@hiÑaÈ`/==fìƒGÇN�m]Éä3SZüRßФ²¬¤ ëEqNVQfFQfFi^navfQa®…•MyIứ4qGqEyUP€¿UGKu;¥x t�/hØ{™Çç�NÔ½ÙKL‡Fç+ ‚Õòù :]]Bºü†p>ŸÇÐy«¯£�ÔÕQ™Êúªm:­¼üÍÆL|_GG«gi´¤ áYòÌK¬:Z2¨¬¬ù͵Šä�ž‘©Èb2utèO7lV@&Sâ'´òøryzfæ»áøÙ2™œ@P1¯«ÑAŠŠŠùü·¶C×c2ûôî¡($�F7`±àibÒïþ=vÔ°V.ËÈÌÚóÏÁ™Ú2(‹ íëyòc#3ãN„׃ D"‘L$Q(´4¥Ub•i¢w’˜’š˜ÒÔÞžŠ™fV�:ä5cþ7�"ÜŒ¸cjfüû¯?Ó¨ÔsÃêëEå•ï½ à'¡NXÇÐÑÁë2PW'TŽ Ö1tÞLA`2eêR)ÐaèÔÔÔƒ¡Ë¼÷¦©š§®ŽÊTÖWmãÔ uo¾Ýº �@Z¬%-b±¸ªªºªªZŸ¥·ö‡‹W¬Ñ`Û†H$Vþ·¬¢²ªªzâÔÙ-L.“ʈ„†Ï …B"½õ�&µÁ¾â�Jå•1÷nÞ¶óÝÈ‘Ñw#£ïR(”É�ã·n\< ¤2�Øð‰üIü<@���]UÁ®ª ˆR™êi°�hו·n.¦&ÆBކ_™3sª[w×°Ð —Ë��<<{L@p³d‘HÔhp峑›ÿR1™ÎÞΦ´¬Lyàró :ZZà×¹ñ8¹ùê–UTêv66x¸£­u~~�FêñAÔÕñí8*ê«.a^~�½mC#è³ôòòó?~=Z¯%-ð6̼™‹Ÿ„´ôtÀ°áC}€J¥¬úv‰[wų|¾Àª“%èÐé ÊÊ+MMMtè:àç;H.—k �Q±÷öw·¶ê¦¦&[7®Å§Áù�5wæ4‰D/2²ðÁ!(/¯´éltÍs@ÿ–dñnMäóЮ h[ïäVdTà´Ù3ç/ž9ñ™s—SŸgÌ^¸˜L]ggG]]FWg§5ß{âth}}ü*ÂQ( ™ d2¹Ý?nÜŽ?f¤µU'#Cƒ¯¦Nºv3_8w¦U§Ž�‘‘]\Z:gÆ4�:väp#CÃØûqêJ¥²ÿ"¢ç̘ª§ÇìÚÅÑÏ×'üõµ™º:öìÑmÒëiŒ*ë«.aDT¬³“ã �:tú‚¹3’RÒJJËÛ±‚ÍRWSã¥_Ï#‰0Ñ´�­5þ¦˜7{ú“„¤ö.u¨¯­úi“ÿ˜‘çN>yèŸzQ}JÚ Å³��ü~ù7ÿ…Ÿ?º�E3ÈÊɹýß�ýÿûcç¶Mº ›ÃÅš»XóárròvìÚ»yÃO¡'îÚ¾ùá£Çn ÄÞ{àè`zâàÉÃûæÏž¾qKÃnçÇN�ì=pïÛÖ­Yyÿa‘@€a¾ƒÃ/„„_éÛ»çüÙÓÃ/„ü³û÷&jŠ _MìQÜ|!Tôï×{Ù÷?€©©É®í›;YZ°9Ü‹WÂ�Ÿ mÃIî\Wþwèè€FÃ6gFð¤‰ãÈdÒíȘ�»ÿÆgðE^¿¸vãÖ¸øèlÕiíêåNö¯ŠK~Ûµ719µ‰„:túšï¾èáÎŽž8}!,¼«Ör*ë0dÐÀy‹WàqTÖW]ãxy¸/[¼ÐÔØ(19uëŽ]åÚ~ePeEœ�ý³{ðˆñ"‘hñ¹~CèWW³ï>ˆÛwà˜ NÐìaA4¦ußÓxŸD{{'‚ ‚|º½{'U‹j¾ž!›ý"ù­`ÿ?äa+µb@AA>WB¡€¥o¬r,‚ÃV1å´mÞ ‚ ‚ Ÿ™W¹U•¥�/õ`PUQZô2We­;ÑÄ<{AAÚIiÑK‘PhÞÑúõмøe»ZõÀ  ±AA4 ºª¼° @ /,Èi¢kZ2v‚ ‚ Èg¯†S•W/”ÉA(T±óŸ2Ô;AADCuÍôKpèÊ‚ ‚ ÚõNAÑ.¨w‚ ‚ ˆvA½AA´ €û XÛ»$‚ ‚|Ùô;§z'åXçíë� ‚ ò±èYÈË3ï�ÈŸ_ƒÎîÐu$ÐôÚ»\‚ ‚|yô;�U?¬g¤_ÌÜ®ŽY»ƒê  ‚ ¢qœByyÞ5åÞ ‚ È'J÷‡ˆö.‚æð¶mï" ÈG‡îÙAAD» •쑦¸º¹k,¯ÔÄGÎñ³×.MªáLñì¾@ŸÓ;å‹}‘& Þ ‚ Ÿ¼Ow·w4ç~{A4]ÙAAD» Þ ‚ ‚ ÚõNAÑ.¨w‚|Dý{w_¾`z»dm ¯÷ÏŽuMDðrïµxΔw÷þ´Ì¶³æ6vÐpvêÌœ†ÿËdèü±yÕêŸw±95#»á>=»wùu÷aEˆ�öÇÏßoÝu°°¸´é´�ðÌ団T nݺ,ž=Y9dÛîC¹¯>j¦nÃ÷ ;Zt€Z¾ #3/äâõZ¾ é$F†¬-k–~½zK«3�<~ÄPï7÷˜\¼—�R'¶ú€M[9wÒÝÇÉO’3!¥åB‘èCŽI§R6¯œ r¹œ[Ëššyãn¼\.oIÚQƒÜÃ"î§fæÀ­ØÇl.ïCJ¢’¢…EbI5›“šžu=â^³¯,‚h-Ô;A´W\Bò„Q¾¦Æ†å•ÕxHßž®%e•ÍvMˆDB½HóàÉÇ.a5‡»î—½Š%RéÇË‹H$H¥²�GÏ\‰KH22`-˜1)`ìУg®´Q›—�|üìUü±T&“Éš/gª¬âTVq>ü8Ûö�âÔð¬ÌÍæ�*«â$¤¾é ©šJ°˜å¯s�OJßL›8²²O’ŽŸ½B§ÑÌÍŒýGúü¸|Þ–?ö ê>VðC´ðDE¾d¨w‚´ "�0nÄàþ}ºSH¤Ä´Ì3—nÖ¿ýSudž•÷â\ºØÓ¨Ôœ‚Â� ×%’f¾Ë¹5¼ô¬Ü}{„݈ÂCôíþàIbSãAc-ÍM¥Ré³”g.ÝK$xQ÷âûôèJ¥Rwþsì—Ÿ–á?÷{vë2n„�±¡>_ ø/:.2¶aq"‘0{ÊøžÝ»°¹5§Î_ËÌ)hT÷^ÝFùy°ôò ‹N„†WT±E�ËåxÖÊíðÓòyR"bb¶jñ¬Œœü°Qó¦O ëÍLŒ :�/8ræ ›ÍUNH£R&ùwsq’Êdq�ÃnEK¥2/÷^}ܺrjyv�-£î=޾ÿäÝFn'26¾ÙK2©TV^ÉŽšÒ¯WãÕ¢ý÷2Ð�F¥ddçŸ:­–/XsòX‹¦r¹<)5óÈ™ËÍær™L¹­fNW^Y}#òžr¦.#xÂÈ.Ö"‰äÎÝø[ÑÀÍÕ)pŒŸžž®H$ÿ/&ú~k:�½]{¹:8ë—̸—�ÚÝцF£¾,.={-ï*õìê0Ô³7‹É(,)?#¦JÕˆ L&—Jey¯Jr ‹-ÌŒ ŠXËgÞyð´§«ciEÕù1c}=\l¤2YBJÆ­ØÇR™lÕü) Ú¢à±xƒ¥ËØsübaI…òaUf�—³G[*…²ýß�fëˆÉåR©ŒÇdå¾üë@Èæ5‹yö½ êÏä¡Þî#|ÊdòÛQ÷#î>€‘¾M� ��½4*e϶¿Y½U,‘X˜™ÌžêßÁÌ8;¯°šÍÖ‹Î]¹ ½»;Oã§Õ⯠6IDATË ?ˆfgmþßÝäç™*? Zq¢"_2Ô;AÚÆØáƒím¬~Ùu°®¾~Öÿñ#}ΆÝjÇκӎ=GäßÌéëuõVt³‡½ÿ81p´ß•›Ñr¹ÜÔØÀº£å?‡Cutha7£³s tuu–Ì�êëí~óNÃNvÖÛþ:$•ÊôYLÅAêëEŽŸ/)¯ìÜÑ|Å¢¯r_¾Ê+('»c¡WŽ…^éÕÃyñœ)?nÙ­üCÓÙÁvÒ¸a yU\6īߢ™“¶ì:ÐìH¾T&;xêâšesÓ3sº;;�ɤðÛ1øS=\œ¶ü±Ÿ[Ëîã1/xÂoÿ;ªœ0`ŒŸ±¡þú_÷R©”oçOã ênG?gGÛ?ö�8rÃ0ÿ>*Y9N³Mª@¥P\�íËÊ«”ûº¹øyØõï‰*6wFÐØYSý÷<ý¿Ãg¶¬YºfsÚ"‹gON~žµcïQ�ÐɲCËslÖ׳‚ ‹Øü'C—±bÁ´²ÊªÄÔŒÙSÇÿµ?$§ P‡N3Ðo›�À¬-Íöœ¸‹§û÷rqx’’á`Ýq¬¯Çás׋˫<{»~5aØî£Ô½ÜzL+s³çY@£RÈdÒ΃g1 ›8ÌËP_oûþÓT ynÐh~�0&>é·g6-Ÿ½/äjyÖ/™ÑèhMdmoe±÷ø¥– œ4"‰Sžg9ÚZÝPs&ã%773Y³ùO3£ï¾™YXT–‘“¯òh†}3'èþ£Ä[Ñíl:-Ÿ?-úÁ02dÍ¿çÀ鬼—~Þý;w2Çã«û4h݉Š|™Ð¬XäýôíÙm׿Uøßæ—(½=z_ �äÖòD"ñÕ[ѽÝ\ÞM{çÞc|H?òn¼{O×–d—”’A§Sím­ ŸÏ3s¸µ¼’²ÊŒì<©LÆ­áEÞ}ä`k¥ˆûH"‘6úRyž™[\V!—Ëó ‹Ÿ&§;Ø4Ä/-¯zŸ$“ÉžKÏÄÈ Qñ õYŠÖصy•B€’²Ê«·¢¿ž4ÂwàÁ“—#Ø�Ÿ¥qkyx!í¬;±ôt•åÞ»Û¥ëwuB6§æZÄÝ}ºãáù…%/²ò@.—«kdå8-iÕ©FîÜôýŸ[V“Äó×ÞÚ¡¦_¯îwîÅ—”UŠDâsa·»wuÔ¡Ó%—Ȥ&Æ,=©Tšÿ²¨%9ÂÛgS—ñn‹&V;œÿO$–°ÙÜ;÷âû¸¹€L*íhi¦C§ ê„E%å-Ì®i÷ž¤Èd2™L–™÷ÊÒÌôìz/!åUi…L&‹}œ¬ÏÔ5RÕZ>+pÓ·³~X85=§àqò <0êQ"Èåòž.7bÕ ë95¼È ½»9¶¤0Md}ïIŠDÚø|n!·íÔ�Ɇ]¾~G"‘•”?ˆOì×Kí[²“e†ŽÎ­è‡2™,+§ åE6Þ«»szf^FN¾L&»óP ¨ÃÃÛêDE¾dhìy?‰i/BÃnã�tÚ†U_…Bf2tæL/—Ëä™Hx÷çþÝ ÜÚZ–ÒØFÄÉ“Ä4�>=²r ú÷î~éZ$è1“Æ ³í܉L$�È$å .Üó ­­,'Œô135Â0L‡N‹º÷¯Vº¶RÍæèë½U$C};ëNž}»+BXL†b ŽÃ­Ýö×!Å¿"±ððIòÄ1CS3Ê**ÏÖðÊ&‘HB¡¾SQZ*…B§Q«Ù Sªª¹,–^£5ÑÈ*kÝ„°QñÏRù¡ô�‰2ú,ÝÊ×ÅàÖò$©>‹Ùè"]èå[F Y÷Ý‚ZÿFĽ¸„ä–dª|æðTÍÖ42Ð'‰›V�ÿK$’ŠJÊ`c†yŽõ{ùªäÜ•Ûù…ÅïSWÕø‚†A2‘DÊb’@ŸÅ´îØ¡o7'E¦.½òí«op(ôZ·VP'T|¿Ö‹Ä"‘(2�Jaskñp6§–¥« -ÐDÖ5¼ÖOkÕg1ù‚:Ps&skùb‰D1m¶ªšÓ¨wþÖ¡ô˜Üžbª�⢤¾ž^5§á±\.g×ÔB›ž¨È— õN�÷#‰wèHÄ ÓD"1_P÷ÏÑÐWÅeM¤56ÒÇj›r_ˆ7ëÁã¤å §=~–ªËÐILÍ€À1CE"Ѧßÿ‰Äùz½¹Dåo²E3ÃnÆz¨×㤴9'¿�[ß1yìãg©ø´J:�VZQ%‰)d’W VŒ ÓhE%e2™ÌPŸÕËõÍ/Ô¦FúôÀ0¬O3SãÔôìF5îãace�a�Jíݣ뻣A†‘I$Å¡oO[kËÃ!—O_¸>'x¼â«½�›KçŽæDaâè¡Ùy…�~GÆ?M?ÂG‡N3`1GùzÅ©ú®jI# øgÉ>ûš™S(äÀ±~ÉÏ3uBž@@$s>z÷èÊÔeÈåò_.“·bV„JE¥¥å•Aãü¨T*†aæfÆ6�-)rï])²D"å êd-¾+ŠD ’H BótŸ¥ rw³27Å0ŒJ!wïb׊¹ÏÒ2Gxõ£S),&Ãw@¯§©Y-IÕ&Y€ÈDC‡î`Óié¼`©T†ß¶¦îL–Ëåþ#}ˆD¢E“�ýÜ'¦ÀË¢R›Îø5JÅMà…Åe|~ÝðÁ‚ƒ­•k;<üirzWG[';k�0lÐ:®�ù족¤m\¹=ÚÏkõâYº nMMìÃg©/²ʼn–òÃÒ9L]�g)é×ÿ‹mùÁ>I?rÈÃ' WÂnFÍž:¾W7ç:a}fv¾k‡¦“Ÿ8>úD·–[ËKV*UZFN{›à€‘lNÍßGÎ6º÷òyFî¹+·g�512EÙyO“ß j¨Ïú{ÇZÅ¿ûŽ�ËÍ/ ž8êÂúúlji=\�¦N‰ßÕr?>qò„‘�,L ‹ž¼ØèP¡W"¦N¾åÇ%R©,.!9ânÜ»iI# '‰Ï õY+M£Q©/²óñ›�E"ñõˆ{ë¿[H"wì9ì`ÛyêÄ‘2¹¦†wôL˜ÊË4­ —Ëÿ>:iœßÖŸ–PÈä²òʰ[Ñ`ƒ=úÌ %å-¿ù9pä À‘ƒðÇOÓ²2r^6?3ïUø�‡�£éë ëÅÙ/‹R2rß· WïÄùûyþ°(X&“%¤fÞ}Ü¢k^m’5xôéáѧ‡X"©fsRžgí?~?¥Õ�ÉÂzQiyåŽÿ[!“É®EÞÇg„då¾|šœ¾þ»…ÜšÚg¯ï—–Édÿ �9Ù´ŸWVná“Äç‰*«9GN‡Íœ2Ž¡CÿìUq™D*�œ¨Èg3·k|?!‚(´á.í;6¬Üs ¤‰¥Jð]Ô?§}á•Í›>1¿°8"FEŸããi—&Õp¦xvž~c5“�6¸ÿßUh×wÊ7³'?ÏÌitk7�@ø}Ów¿í=RRV©.¡:ø‹ˆ ÊЕ¤)’×ÓýwÊ»/"‚(Cc'‚|0 ûìW ýêˆ 84+A�ÏÁ—ðµý%ÔAp¤ÏõNAA>QÿÝ9c°9€Ë£IEND®B`‚spyder-line-profiler-0.4.2/requirements/000077500000000000000000000000001507254163500203235ustar00rootroot00000000000000spyder-line-profiler-0.4.2/requirements/conda.txt000066400000000000000000000000371507254163500221500ustar00rootroot00000000000000line_profiler spyder>=6.1,<6.2 spyder-line-profiler-0.4.2/requirements/tests.txt000066400000000000000000000000211507254163500222170ustar00rootroot00000000000000pytest pytest-qt spyder-line-profiler-0.4.2/setup.py000066400000000000000000000065751507254163500173270ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # ----------------------------------------------------------------------------- # Copyright (c) 2015- Spyder Project Contributors # # Released under the terms of the MIT License # (see LICENSE.txt in the project root directory for details) # ----------------------------------------------------------------------------- """ Setup script for spyder_line_profiler """ from setuptools import setup, find_packages import os import os.path as osp def get_version(): """Get version from source file""" import codecs with codecs.open("spyder_line_profiler/__init__.py", encoding="utf-8") as f: lines = f.read().splitlines() for l in lines: if "__version__" in l: version = l.split("=")[1].strip() version = version.replace("'", '').replace('"', '') return version def get_package_data(name, extlist): """Return data files for package *name* with extensions in *extlist*""" flist = [] # Workaround to replace os.path.relpath (not available until Python 2.6): offset = len(name) + len(os.pathsep) for dirpath, _dirnames, filenames in os.walk(name): for fname in filenames: if not fname.startswith('.') and osp.splitext(fname)[1] in extlist: flist.append(osp.join(dirpath, fname)[offset:]) return flist # Requirements REQUIREMENTS = ['line_profiler', 'qtawesome', 'spyder>=6.1,<6.2'] EXTLIST = ['.jpg', '.png', '.json', '.mo', '.ini'] LIBNAME = 'spyder_line_profiler' LONG_DESCRIPTION = """ This is a plugin for the Spyder IDE that integrates the Python line profiler. It allows you to see the time spent in every line. Usage ----- Add a ``@profile`` decorator to the functions that you wish to profile then press Shift+F10 (line profiler default) to run the profiler on the current script, or go to ``Run > Run line profiler``. The results will be shown in a dockwidget, grouped by function. Lines with a stronger color take more time to run. .. image: https://raw.githubusercontent.com/spyder-ide/spyder-line-profiler/master/img_src/screenshot_profiler.png """ setup( name=LIBNAME, version=get_version(), packages=find_packages(), package_data={LIBNAME: get_package_data(LIBNAME, EXTLIST)}, keywords=["Qt PyQt5 PySide2 spyder plugins spyplugins line_profiler profiler"], install_requires=REQUIREMENTS, url='https://github.com/spyder-ide/spyder-line-profiler', license='MIT', python_requires='>= 3.10', entry_points={ "spyder.plugins": [ "spyder_line_profiler = spyder_line_profiler.spyder.plugin:SpyderLineProfiler" ], }, author="Spyder Project Contributors", description='Plugin for the Spyder IDE that integrates the Python line profiler.', long_description=LONG_DESCRIPTION, classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: X11 Applications :: Qt', 'Environment :: Win32 (MS Windows)', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Topic :: Software Development', 'Topic :: Text Editors :: Integrated Development Environments (IDE)']) spyder-line-profiler-0.4.2/spyder_line_profiler/000077500000000000000000000000001507254163500220175ustar00rootroot00000000000000spyder-line-profiler-0.4.2/spyder_line_profiler/__init__.py000066400000000000000000000006201507254163500241260ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # ----------------------------------------------------------------------------- # Copyright (c) 2013- Spyder Project Contributors # # Released under the terms of the MIT License # (see LICENSE.txt in the project root directory for details) # ----------------------------------------------------------------------------- """ Spyder Line Profiler. """ __version__ = "0.4.2" spyder-line-profiler-0.4.2/spyder_line_profiler/example/000077500000000000000000000000001507254163500234525ustar00rootroot00000000000000spyder-line-profiler-0.4.2/spyder_line_profiler/example/__init__.py000066400000000000000000000000001507254163500255510ustar00rootroot00000000000000spyder-line-profiler-0.4.2/spyder_line_profiler/example/profiling_test_script.py000066400000000000000000000023341507254163500304420ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # # ----------------------------------------------------------------------------- # Copyright (c) 2013- Spyder Project Contributors # # Released under the terms of the MIT License # (see LICENSE.txt in the project root directory for details) # ----------------------------------------------------------------------------- from __future__ import ( print_function, division, unicode_literals, absolute_import) import subdir.profiling_test_script2 as script2 @profile def fact(n): result = 1 for i in range(2, n // 4): result *= i result = 1 # This is a comment for i in range(2, n // 16): result *= i result = 1 if False: # This won't be run raise RuntimeError("What are you doing here ???") for i in range(2, n + 1): result *= i return result # This is after the end of the function. if False: # This won't be run raise RuntimeError("It's getting bad.") @profile def sum_(n): result = 0 for i in range(1, n + 1): result += i return result if __name__ == "__main__": print(fact(120)) print(sum_(120)) print(script2.fact2(120)) print(script2.sum2(120)) spyder-line-profiler-0.4.2/spyder_line_profiler/example/subdir/000077500000000000000000000000001507254163500247425ustar00rootroot00000000000000spyder-line-profiler-0.4.2/spyder_line_profiler/example/subdir/__init__.py000066400000000000000000000000001507254163500270410ustar00rootroot00000000000000spyder-line-profiler-0.4.2/spyder_line_profiler/example/subdir/profiling_test_script2.py000066400000000000000000000013441507254163500320140ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # # ----------------------------------------------------------------------------- # Copyright (c) 2013- Spyder Project Contributors # # Released under the terms of the MIT License # (see LICENSE.txt in the project root directory for details) # ----------------------------------------------------------------------------- from __future__ import ( print_function, division, unicode_literals, absolute_import) @profile def fact2(n): result = 1 for i in range(2, n + 1): result *= i * 2 return result def sum2(n): result = 0 for i in range(1, n + 1): result += i * 2 return result if __name__ == "__main__": print(fact2(120)) print(sum2(120)) spyder-line-profiler-0.4.2/spyder_line_profiler/spyder/000077500000000000000000000000001507254163500233255ustar00rootroot00000000000000spyder-line-profiler-0.4.2/spyder_line_profiler/spyder/__init__.py000066400000000000000000000005731507254163500254430ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # ----------------------------------------------------------------------------- # Copyright (c) 2013- Spyder Project Contributors # # Released under the terms of the MIT License # (see LICENSE.txt in the project root directory for details) # -----------------------------------------------------------------------------""" """ Spyder Line Profiler """ spyder-line-profiler-0.4.2/spyder_line_profiler/spyder/config.py000066400000000000000000000021161507254163500251440ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # ----------------------------------------------------------------------------- # Copyright (c) 2022- Spyder Project Contributors # # Released under the terms of the MIT License # (see LICENSE.txt in the project root directory for details) # ----------------------------------------------------------------------------- """Spyder line-profiler default configuration.""" CONF_SECTION = 'spyder_line_profiler' CONF_DEFAULTS = [ (CONF_SECTION, { 'use_colors': True, } ), ('shortcuts', { 'spyder_line_profiler/Run file in spyder_line_profiler': 'Shift+F10', } ) ] # IMPORTANT NOTES: # 1. If you want to *change* the default value of a current option, you need to # do a MINOR update in config version, e.g. from 1.0.0 to 1.1.0 # 2. If you want to *remove* options that are no longer needed in our codebase, # or if you want to *rename* options, then you need to do a MAJOR update in # version, e.g. from 1.0.0 to 2.0.0 # 3. You don't need to touch this value if you're just adding a new option CONF_VERSION = '2.0.0' spyder-line-profiler-0.4.2/spyder_line_profiler/spyder/confpage.py000066400000000000000000000044071507254163500254660ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # ----------------------------------------------------------------------------- # Copyright (c) 2013- Spyder Project Contributors # # Released under the terms of the MIT License # (see LICENSE.txt in the project root directory for details) # ----------------------------------------------------------------------------- """ Spyder Line Profiler 5 Preferences Page. """ # Third party imports from qtpy.QtCore import Qt from qtpy.QtWidgets import QGroupBox, QLabel, QVBoxLayout from spyder.api.preferences import PluginConfigPage from spyder.api.translations import get_translation # Local imports from .widgets import SpyderLineProfilerWidget # Localization _ = get_translation("spyder_line_profiler.spyder") class SpyderLineProfilerConfigPage(PluginConfigPage): # --- PluginConfigPage API # ------------------------------------------------------------------------ def setup_page(self): settings_group = QGroupBox(_("Settings")) use_color_box = self.create_checkbox( _("Use deterministic colors to differentiate functions"), 'use_colors', default=True) results_group = QGroupBox(_("Results")) results_label1 = QLabel(_("Line profiler plugin results " "(the output of kernprof.py)\n" "are stored here:")) results_label1.setWordWrap(True) # Warning: do not try to regroup the following QLabel contents with # widgets above -- this string was isolated here in a single QLabel # on purpose: to fix Issue 863 of Profiler plugin results_label2 = QLabel(SpyderLineProfilerWidget.DATAPATH) results_label2.setTextInteractionFlags(Qt.TextSelectableByMouse) results_label2.setWordWrap(True) settings_layout = QVBoxLayout() settings_layout.addWidget(use_color_box) settings_group.setLayout(settings_layout) results_layout = QVBoxLayout() results_layout.addWidget(results_label1) results_layout.addWidget(results_label2) results_group.setLayout(results_layout) vlayout = QVBoxLayout() vlayout.addWidget(settings_group) vlayout.addWidget(results_group) vlayout.addStretch(1) self.setLayout(vlayout)spyder-line-profiler-0.4.2/spyder_line_profiler/spyder/plugin.py000066400000000000000000000127561507254163500252100ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # ----------------------------------------------------------------------------- # Copyright (c) 2013- Spyder Project Contributors # # Released under the terms of the MIT License # (see LICENSE.txt in the project root directory for details) # ----------------------------------------------------------------------------- """ Spyder Line Profiler Plugin. """ # Third-party imports import qtawesome as qta from qtpy.QtCore import Qt, Signal # Spyder imports from spyder.api.plugins import Plugins, SpyderDockablePlugin from spyder.api.translations import get_translation from spyder.api.plugin_registration.decorators import ( on_plugin_available, on_plugin_teardown) from spyder.plugins.mainmenu.api import ApplicationMenus, RunMenuSections from spyder.plugins.run.api import RunContext, RunExecutor, run_execute from spyder.utils.icon_manager import ima # Local imports from spyder_line_profiler.spyder.config import ( CONF_SECTION, CONF_DEFAULTS, CONF_VERSION) from spyder_line_profiler.spyder.confpage import SpyderLineProfilerConfigPage from spyder_line_profiler.spyder.widgets import ( SpyderLineProfilerWidget, is_lineprofiler_installed) from spyder_line_profiler.spyder.run_conf import LineProfilerConfigurationGroup # Localization _ = get_translation("spyder_line_profiler.spyder") class SpyderLineProfiler(SpyderDockablePlugin, RunExecutor): """ Spyder Line Profiler plugin for Spyder 5. """ NAME = "spyder_line_profiler" REQUIRES = [Plugins.Preferences, Plugins.Editor, Plugins.Run] OPTIONAL = [] TABIFY = [Plugins.Help] WIDGET_CLASS = SpyderLineProfilerWidget CONF_SECTION = CONF_SECTION CONF_DEFAULTS = CONF_DEFAULTS CONF_VERSION = CONF_VERSION CONF_WIDGET_CLASS = SpyderLineProfilerConfigPage CONF_FILE = True # --- Signals sig_finished = Signal() """This signal is emitted to inform the profile profiling has finished.""" # --- SpyderDockablePlugin API # ------------------------------------------------------------------------ @staticmethod def get_name(): return _("Line Profiler") @staticmethod def get_description(): return _("Line profiler display for Spyder") @classmethod def get_icon(cls): return qta.icon('mdi.speedometer', color=ima.MAIN_FG_COLOR) def on_initialize(self): self.widget = self.get_widget() self.widget.sig_finished.connect(self.sig_finished) self.executor_configuration = [ { 'input_extension': 'py', 'context': { 'name': 'File' }, 'output_formats': [], 'configuration_widget': LineProfilerConfigurationGroup, 'requires_cwd': True, 'priority': 7 } ] @on_plugin_available(plugin=Plugins.Run) def on_run_available(self): run = self.get_plugin(Plugins.Run) run.register_executor_configuration(self, self.executor_configuration) if is_lineprofiler_installed(): run.create_run_in_executor_button( RunContext.File, self.NAME, text=_('Run line profiler'), tip=_('Run line profiler'), icon=self.get_icon(), shortcut_context='spyder_line_profiler', register_shortcut=True, add_to_menu={ "menu": ApplicationMenus.Run, "section": RunMenuSections.RunInExecutors }, shortcut_widget_context=Qt.ApplicationShortcut, ) @on_plugin_available(plugin=Plugins.Editor) def on_editor_available(self): widget = self.get_widget() editor = self.get_plugin(Plugins.Editor) widget.sig_edit_goto_requested.connect(editor.load) @on_plugin_available(plugin=Plugins.Preferences) def on_preferences_available(self): preferences = self.get_plugin(Plugins.Preferences) preferences.register_plugin_preferences(self) @on_plugin_teardown(plugin=Plugins.Run) def on_run_teardown(self): run = self.get_plugin(Plugins.Run) run.deregister_executor_configuration( self, self.executor_configuration) run.destroy_run_in_executor_button( RunContext.File, self.NAME) @on_plugin_teardown(plugin=Plugins.Preferences) def on_preferences_teardown(self): preferences = self.get_plugin(Plugins.Preferences) preferences.deregister_plugin_preferences(self) @on_plugin_teardown(plugin=Plugins.Editor) def on_editor_teardown(self): widget = self.get_widget() editor = self.get_plugin(Plugins.Editor) widget.sig_edit_goto_requested.disconnect(editor.load) def check_compatibility(self): valid = True message = "" # Note: Remember to use _("") to localize the string return valid, message def on_close(self, cancellable=True): return True # --- Public API # ------------------------------------------------------------------------ @run_execute(context=RunContext.File) def run_file(self, input, conf): self.switch_to_plugin() exec_params = conf['params'] cwd_opts = exec_params['working_dir'] params = exec_params['executor_params'] run_input = input['run_input'] filename = run_input['path'] wdir = cwd_opts['path'] args = params['args'] self.get_widget().analyze(filename, wdir=wdir, args=args) spyder-line-profiler-0.4.2/spyder_line_profiler/spyder/run_conf.py000066400000000000000000000037201507254163500255120ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright © Spyder Project Contributors # Licensed under the terms of the MIT License # (see spyder/__init__.py for details) """Line profiler run executor configurations.""" # Third-party imports from qtpy.QtWidgets import ( QGroupBox, QVBoxLayout, QGridLayout, QCheckBox, QLineEdit) # Local imports from spyder.api.translations import _ from spyder.plugins.run.api import ( RunExecutorConfigurationGroup, Context, RunConfigurationMetadata) class LineProfilerConfigurationGroup(RunExecutorConfigurationGroup): """Run configuration options for line profiler.""" def __init__(self, parent, context: Context, input_extension: str, input_metadata: RunConfigurationMetadata): super().__init__(parent, context, input_extension, input_metadata) self.dir = None # --- General settings ---- common_group = QGroupBox(_("File settings")) common_layout = QGridLayout(common_group) self.clo_cb = QCheckBox(_("Command line options:")) common_layout.addWidget(self.clo_cb, 0, 0) self.clo_edit = QLineEdit(self) self.clo_edit.setMinimumWidth(300) self.clo_cb.toggled.connect(self.clo_edit.setEnabled) self.clo_edit.setEnabled(False) common_layout.addWidget(self.clo_edit, 0, 1) layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(common_group) layout.addStretch(100) @staticmethod def get_default_configuration() -> dict: return { 'args_enabled': False, 'args': '' } def set_configuration(self, config: dict): args_enabled = config['args_enabled'] args = config['args'] self.clo_cb.setChecked(args_enabled) self.clo_edit.setText(args) def get_configuration(self) -> dict: return { 'args_enabled': self.clo_cb.isChecked(), 'args': self.clo_edit.text(), } spyder-line-profiler-0.4.2/spyder_line_profiler/spyder/widgets.py000066400000000000000000000707261507254163500253610ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # ----------------------------------------------------------------------------- # Copyright (c) 2013- Spyder Project Contributors # # Released under the terms of the MIT License # (see LICENSE.txt in the project root directory for details) # ----------------------------------------------------------------------------- """ Spyder Line Profiler Main Widget. """ # Standard library imports import inspect import linecache import logging import os import os.path as osp import pickle import re import time from datetime import datetime # Third party imports from qtpy.QtGui import QBrush, QColor, QFont from qtpy.QtCore import (QByteArray, QProcess, Qt, QProcessEnvironment, Signal, QTimer) from qtpy.QtWidgets import (QMessageBox, QVBoxLayout, QLabel, QTreeWidget, QTreeWidgetItem, QApplication) from qtpy.compat import getopenfilename, getsavefilename # Spyder imports from spyder.api.config.decorators import on_conf_change from spyder.api.translations import get_translation from spyder.api.widgets.main_widget import PluginMainWidget from spyder.config.base import get_conf_path from spyder.plugins.variableexplorer.widgets.texteditor import TextEditor from spyder.utils import programs from spyder.utils.misc import getcwd_or_home from spyder.utils.palette import SpyderPalette from spyder.widgets.comboboxes import PythonModulesComboBox # Local imports from spyder_line_profiler.spyder.config import CONF_SECTION # Localization and logging _ = get_translation("spyder") logger = logging.getLogger(__name__) COL_NO = 0 COL_HITS = 1 COL_TIME = 2 COL_PERHIT = 3 COL_PERCENT = 4 COL_LINE = 5 COL_POS = 0 # Position is not displayed but set as Qt.UserRole CODE_NOT_RUN_COLOR = QBrush(QColor.fromRgb(128, 128, 128, 200)) # Cycle to use when coloring lines from different functions COLOR_CYCLE = [ SpyderPalette.GROUP_1, SpyderPalette.GROUP_4, SpyderPalette.GROUP_10, SpyderPalette.GROUP_12, SpyderPalette.GROUP_2, SpyderPalette.GROUP_8, SpyderPalette.GROUP_6] WEBSITE_URL = 'http://pythonhosted.org/line_profiler/' def is_lineprofiler_installed(): """ Check if the program and the library for line_profiler is installed. """ return (programs.is_module_installed('line_profiler') and programs.is_module_installed('kernprof')) class TreeWidgetItem(QTreeWidgetItem): """ An extension of QTreeWidgetItem that replaces the sorting behaviour such that the sorting is not purely by ASCII index but by natural sorting, e.g. multi-digit numbers sorted based on their value instead of individual digits. Taken from https://stackoverflow.com/questions/21030719/sort-a-pyside-qtgui- qtreewidget-by-an-alpha-numeric-column/ """ def __lt__(self, other): """ Compare a widget text entry to another entry. """ column = self.treeWidget().sortColumn() key1 = self.text(column) key2 = other.text(column) return self.natural_sort_key(key1) < self.natural_sort_key(key2) @staticmethod def natural_sort_key(key): """ Natural sorting for both numbers and strings containing numbers. """ regex = r'(\d*\.\d+|\d+)' parts = re.split(regex, key) return tuple((e if i % 2 == 0 else float(e)) for i, e in enumerate(parts)) class SpyderLineProfilerWidgetActions: # Triggers Browse = 'browse_action' Clear = 'clear_action' Collapse = 'collapse_action' Expand = 'expand_action' LoadData = 'load_data_action' Run = 'run_action' SaveData = 'save_data_action' ShowOutput = 'show_output_action' Stop = 'stop_action' class SpyderLineProfilerWidgetMainToolbarSections: Main = 'main_section' ExpandCollaps = 'expand_collaps_section' ShowOutput = 'show_output_section' class SpyderLineProfilerWidgetToolbars: Information = 'information_toolbar' class SpyderLineProfilerWidgetMainToolbarItems: FileCombo = 'file_combo' class SpyderLineProfilerWidgetInformationToolbarSections: Main = 'main_section' class SpyderLineProfilerWidgetInformationToolbarItems: Stretcher1 = 'stretcher_1' Stretcher2 = 'stretcher_2' DateLabel = 'date_label' class SpyderLineProfilerWidget(PluginMainWidget): # PluginMainWidget class constants CONF_SECTION = CONF_SECTION DATAPATH = get_conf_path('lineprofiler.results') VERSION = '0.0.1' redirect_stdio = Signal(bool) sig_finished = Signal() # Signals sig_edit_goto_requested = Signal(str, int, str) """ This signal will request to open a file in a given row and column using a code editor. Parameters ---------- path: str Path to file. row: int Cursor starting row position. word: str Word to select on given row. """ def __init__(self, name=None, plugin=None, parent=None): super().__init__(name, plugin, parent) self.setWindowTitle("Line profiler") # Attributes self._last_wdir = None self._last_args = None self.pythonpath = None self.error_output = None self.output = None self.use_colors = True self.process = None self.started_time = None # Widgets self.filecombo = PythonModulesComboBox( self, id_=SpyderLineProfilerWidgetMainToolbarItems.FileCombo) self.datatree = LineProfilerDataTree(self) self.datelabel = QLabel(self) self.datelabel.ID = SpyderLineProfilerWidgetInformationToolbarItems.DateLabel self.datelabel.setText(_('Please select a file to profile, with ' 'added @profile decorators for functions')) self.timer = QTimer(self) layout = QVBoxLayout() layout.addWidget(self.datatree) self.setLayout(layout) # Signals self.datatree.sig_edit_goto_requested.connect( self.sig_edit_goto_requested) # --- PluginMainWidget API # ------------------------------------------------------------------------ def get_title(self): return _("Line Profiler") def get_focus_widget(self): pass def setup(self): self.start_action = self.create_action( SpyderLineProfilerWidgetActions.Run, text=_("Profile by line"), tip=_("Run line profiler"), icon=self.create_icon('run'), triggered=self.start, ) self.stop_action = self.create_action( SpyderLineProfilerWidgetActions.Stop, text=_("Stop"), tip=_("Stop current profiling"), icon=self.create_icon('stop'), triggered=self.kill_if_running, ) self.browse_action = self.create_action( SpyderLineProfilerWidgetActions.Browse, text=_("Open Script"), tip=_('Select Python script'), icon=self.create_icon('fileopen'), triggered=self.select_file, ) self.log_action = self.create_action( SpyderLineProfilerWidgetActions.ShowOutput, text=_("Show Result"), tip=_("Show program's output"), icon=self.create_icon('log'), triggered=self.show_log, ) self.collapse_action = self.create_action( SpyderLineProfilerWidgetActions.Collapse, text=_("Collaps"), tip=_('Collapse all'), icon=self.create_icon('collapse'), triggered=lambda dD=-1: self.datatree.collapseAll(), ) self.expand_action = self.create_action( SpyderLineProfilerWidgetActions.Expand, text=_("Expand"), tip=_('Expand all'), icon=self.create_icon('expand'), triggered=lambda dD=-1: self.datatree.expandAll(), ) self.save_action = self.create_action( SpyderLineProfilerWidgetActions.SaveData, text=_("Save data"), tip=_('Save line profiling data'), icon=self.create_icon('filesave'), triggered=self.save_data, ) self.clear_action = self.create_action( SpyderLineProfilerWidgetActions.Clear, text=_("Clear output"), tip=_('Clear'), icon=self.create_icon('editdelete'), triggered=self.clear_data, ) self.set_running_state(False) self.start_action.setEnabled(False) self.clear_action.setEnabled(False) self.log_action.setEnabled(False) self.save_action.setEnabled(False) # Main Toolbar toolbar = self.get_main_toolbar() for item in [self.filecombo, self.browse_action, self.start_action, self.stop_action]: self.add_item_to_toolbar( item, toolbar=toolbar, section=SpyderLineProfilerWidgetMainToolbarSections.Main, ) # Secondary Toolbar secondary_toolbar = self.create_toolbar( SpyderLineProfilerWidgetToolbars.Information) for item in [self.collapse_action, self.expand_action, self.create_stretcher( id_=SpyderLineProfilerWidgetInformationToolbarItems.Stretcher1), self.datelabel, self.create_stretcher( id_=SpyderLineProfilerWidgetInformationToolbarItems.Stretcher2), self.log_action, self.save_action, self.clear_action]: self.add_item_to_toolbar( item, toolbar=secondary_toolbar, section=SpyderLineProfilerWidgetInformationToolbarSections.Main, ) if not is_lineprofiler_installed(): for widget in (self.datatree, self.filecombo, self.log_action, self.start_action, self.stop_action, self.browse_action, self.collapse_action, self.expand_action): widget.setDisabled(True) text = _( 'Please install the line_profiler module' ) % WEBSITE_URL self.datelabel.setText(text) self.datelabel.setOpenExternalLinks(True) else: pass def analyze(self, filename=None, wdir=None, args=None, use_colors=True): self.use_colors = use_colors if not is_lineprofiler_installed(): return self.kill_if_running() #index, _data = self.get_data(filename) # FIXME: storing data is not implemented yet if filename is not None: filename = osp.abspath(str(filename)) index = self.filecombo.findText(filename) if index == -1: self.filecombo.addItem(filename) self.filecombo.setCurrentIndex(self.filecombo.count()-1) else: self.filecombo.setCurrentIndex(index) self.filecombo.selected() if self.filecombo.is_valid(): filename = str(self.filecombo.currentText()) if wdir is None: wdir = osp.dirname(filename) self.start(wdir, args) def select_file(self): self.redirect_stdio.emit(False) pwd = getcwd_or_home() filename, _selfilter = getopenfilename( self, _("Select Python script"), pwd, _("Python scripts")+" (*.py ; *.pyw)") self.redirect_stdio.emit(False) if filename: self.analyze(filename) def show_log(self): if self.output: editor = TextEditor(self.output, title=_("Line profiler output"), readonly=True, parent=self) # Call .show() to dynamically resize editor; # see spyder-ide/spyder#12202 editor.show() editor.exec_() def show_errorlog(self): if self.error_output: editor = TextEditor(self.error_output, title=_("Line profiler output"), readonly=True, parent=self) self.datelabel.setText(_('Profiling did not complete (error)')) # Call .show() to dynamically resize editor; # see spyder-ide/spyder#12202 editor.show() editor.exec_() def update_timer(self): elapsed = str(datetime.now() - self.started_time).split(".")[0] self.datelabel.setText(_(f'Profiling, please wait... elapsed: {elapsed}')) def start(self, wdir=None, args=None): filename = str(self.filecombo.currentText()) if wdir in [None, False]: wdir = self._last_wdir if wdir in [None, False]: wdir = osp.dirname(filename) if args is None: args = self._last_args if args is None: args = [] self._last_wdir = wdir self._last_args = args self.datelabel.setText(_('Profiling starting up, please wait...')) self.started_time = datetime.now() self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.SeparateChannels) self.process.setWorkingDirectory(wdir) self.process.readyReadStandardOutput.connect(self.read_output) self.process.readyReadStandardError.connect( lambda: self.read_output(error=True)) self.process.finished.connect(self.finished) proc_env = QProcessEnvironment() for k, v in os.environ.items(): proc_env.insert(k, v) proc_env.remove('PYTHONPATH') if self.pythonpath is not None: logger.debug(f"Pass Pythonpath {self.pythonpath} to process") proc_env.insert('PYTHONPATH', os.pathsep.join(self.pythonpath)) self.process.setProcessEnvironment(proc_env) self.clear_data() self.error_output = '' # Use UTF-8 mode so that profiler writes its output to DATAPATH using # UTF-8 encoding, instead of the ANSI code page on Windows. # See issue spyder-ide/spyder-line-profiler#90 # # UTF-8 mode also changes the encoding of stdin/stdout/stdout which must # be taken into account when using stdandard I/O. p_args = ['-X', 'utf8', '-m', 'kernprof', '-lvb', '-o', self.DATAPATH] if os.name == 'nt': # On Windows, one has to replace backslashes by slashes to avoid # confusion with escape characters (otherwise, for example, '\t' # will be interpreted as a tabulation): p_args.append(osp.normpath(filename).replace(os.sep, '/')) else: p_args.append(filename) if args: p_args.extend(programs.shell_split(args)) executable = self.get_conf('executable', section='main_interpreter') if executable.endswith('spyder.exe'): # py2exe distribution executable = 'python.exe' logger.debug(f'Starting process with {executable=} and {p_args=}') self.process.start(executable, p_args) running = self.process.waitForStarted() self.set_running_state(running) self.timer.timeout.connect(self.update_timer) self.timer.start(1000) if not running: QMessageBox.critical(self, _("Error"), _("Process failed to start")) def set_running_state(self, state=True): self.start_action.setEnabled(not state) self.stop_action.setEnabled(state) def read_output(self, error=False): if error: self.process.setReadChannel(QProcess.StandardError) else: self.process.setReadChannel(QProcess.StandardOutput) qba = QByteArray() while self.process.bytesAvailable(): if error: qba += self.process.readAllStandardError() else: qba += self.process.readAllStandardOutput() # encoding: Python process is started with UTF-8 mode text = str(qba.data(), encoding="utf-8") if error: self.error_output += text else: self.output += text def finished(self): self.timer.stop() self.set_running_state(False) self.output = self.error_output + self.output if not self.output == 'aborted': elapsed = str(datetime.now() - self.started_time).split(".")[0] self.show_data(justanalyzed=True) self.datelabel.setText(_(f'Profiling finished after {elapsed}')) self.show_errorlog() # If errors occurred, show them. self.sig_finished.emit() def kill_if_running(self): self.datelabel.setText(_('Profiling aborted.')) if self.process is not None: if self.process.state() == QProcess.Running: self.process.kill() self.output = 'aborted' self.process.waitForFinished() @on_conf_change(section='pythonpath_manager', option='spyder_pythonpath') def _update_pythonpath(self, value): self.pythonpath = value def clear_data(self): self.datatree.clear() self.clear_action.setEnabled(False) self.log_action.setEnabled(False) self.save_action.setEnabled(False) self.output = '' def show_data(self, justanalyzed=False): if not justanalyzed: self.clear_data() output_exists = self.output is not None and len(self.output) > 0 self.clear_action.setEnabled(output_exists) self.log_action.setEnabled(output_exists) self.save_action.setEnabled(output_exists) self.kill_if_running() filename = str(self.filecombo.currentText()) if not filename: return self.datatree.load_data(self.DATAPATH) QApplication.processEvents() self.datatree.show_tree() text_style = "%s " date_text = text_style % time.strftime("%d %b %Y %H:%M", time.localtime()) self.datelabel.setText(date_text) def save_data(self): """Save data.""" if not self.output: self.datelabel.setText(_("Nothing to save")) return title = _("Save line profiler result") curr_filename = self.filecombo.currentText() filename, _selfilter = getsavefilename( self, title, f'{curr_filename}_lineprof.txt', _("LineProfiler result") + " (*.txt)", ) if filename: with open(filename, 'w') as f: # for some weird reason, everything is double spaced on Win results = self.output results = results.replace('\r', '') f.write(results) self.datelabel.setText(_(f"Saved results to {filename}")) def update_actions(self): pass class LineProfilerDataTree(QTreeWidget): """ Convenience tree widget (with built-in model) to store and view line profiler data. """ sig_edit_goto_requested = Signal(str, int, str) def __init__(self, parent=None): QTreeWidget.__init__(self, parent) self.header_list = [ _('Line #'), _('Hits'), _('Time (ms)'), _('Per hit (ms)'), _('% Time'), _('Line contents')] self.stats = None # To be filled by self.load_data() self.max_time = 0 # To be filled by self.load_data() self.header().setDefaultAlignment(Qt.AlignCenter) self.setColumnCount(len(self.header_list)) self.setHeaderLabels(self.header_list) self.clear() self.itemClicked.connect(self.on_item_clicked) def show_tree(self): """Populate the tree with line profiler data and display it.""" self.clear() # Clear before re-populating self.setItemsExpandable(True) self.setSortingEnabled(False) self.populate_tree() self.expandAll() for col in range(self.columnCount()-1): self.resizeColumnToContents(col) if self.topLevelItemCount() > 1: self.collapseAll() self.setSortingEnabled(True) self.sortItems(COL_POS, Qt.AscendingOrder) def load_data(self, profdatafile): """Load line profiler data saved by kernprof module""" # lstats has the following layout : # lstats.timings = # {(filename1, line_no1, function_name1): # [(line_no1, hits1, total_time1), # (line_no2, hits2, total_time2)], # (filename2, line_no2, function_name2): # [(line_no1, hits1, total_time1), # (line_no2, hits2, total_time2), # (line_no3, hits3, total_time3)]} # lstats.unit = time_factor with open(profdatafile, 'rb') as fid: lstats = pickle.load(fid) # First pass to group by filename self.stats = dict() linecache.checkcache() for func_info, stats in lstats.timings.items(): # func_info is a tuple containing (filename, line, function anme) filename, start_line_no = func_info[:2] # Read code start_line_no -= 1 # include the @profile decorator all_lines = linecache.getlines(filename) block_lines = inspect.getblock(all_lines[start_line_no:]) # Loop on each line of code func_stats = [] func_total_time = 0.0 next_stat_line = 0 for line_no, code_line in enumerate(block_lines): line_no += start_line_no + 1 # Lines start at 1 code_line = code_line.rstrip('\n') if (next_stat_line >= len(stats) or line_no != stats[next_stat_line][0]): # Line didn't run hits, line_total_time, time_per_hit = None, None, None else: # Compute line times hits, line_total_time = stats[next_stat_line][1:] line_total_time *= lstats.unit time_per_hit = line_total_time / hits func_total_time += line_total_time next_stat_line += 1 func_stats.append( [line_no, code_line, line_total_time, time_per_hit, hits]) # Compute percent time for line in func_stats: line_total_time = line[2] if line_total_time is None: line.append(None) else: line.append(line_total_time / func_total_time) # Fill dict self.stats[func_info] = [func_stats, func_total_time] def fill_item(self, item, filename, line_no, code, time, percent, perhit, hits): item.setData(COL_POS, Qt.UserRole, (osp.normpath(filename), line_no)) item.setData(COL_NO, Qt.DisplayRole, line_no) item.setData(COL_LINE, Qt.DisplayRole, code) if percent is None: percent = '' else: percent = '%.1f' % (100 * percent) item.setData(COL_PERCENT, Qt.DisplayRole, percent) item.setTextAlignment(COL_PERCENT, Qt.AlignCenter) if time is None: time = '' else: time = '%.3f' % (time * 1e3) item.setData(COL_TIME, Qt.DisplayRole, time) item.setTextAlignment(COL_TIME, Qt.AlignCenter) if perhit is None: perhit = '' else: perhit = '%.3f' % (perhit * 1e3) item.setData(COL_PERHIT, Qt.DisplayRole, perhit) item.setTextAlignment(COL_PERHIT, Qt.AlignCenter) if hits is None: hits = '' else: hits = '%d' % hits item.setData(COL_HITS, Qt.DisplayRole, hits) item.setTextAlignment(COL_HITS, Qt.AlignCenter) def populate_tree(self): """Create each item (and associated data) in the tree""" if not self.stats: warn_item = TreeWidgetItem(self) warn_item.setData( 0, Qt.DisplayRole, _('No timings to display. ' 'Did you forget to add @profile decorators ?') .format(url=WEBSITE_URL)) warn_item.setFirstColumnSpanned(True) warn_item.setTextAlignment(0, Qt.AlignCenter) font = warn_item.font(0) font.setStyle(QFont.StyleItalic) warn_item.setFont(0, font) return try: monospace_font = self.window().editor.get_plugin_font() except AttributeError: # If run standalone for testing monospace_font = QFont("Courier New") monospace_font.setPointSize(10) for func_index, stat_item in enumerate(self.stats.items()): # Function name and position func_info, func_data = stat_item filename, start_line_no, func_name = func_info func_stats, func_total_time = func_data func_item = TreeWidgetItem(self) func_item.setData( 0, Qt.DisplayRole, _('{func_name} ({time_ms:.3f}ms) in file "{filename}", ' 'line {line_no}').format( filename=filename, line_no=start_line_no, func_name=func_name, time_ms=func_total_time * 1e3)) func_item.setFirstColumnSpanned(True) func_item.setData(COL_POS, Qt.UserRole, (osp.normpath(filename), start_line_no)) # For sorting by time func_item.setData(COL_TIME, Qt.DisplayRole, func_total_time * 1e3) func_item.setData(COL_PERCENT, Qt.DisplayRole, func_total_time * 1e3) if self.parent().use_colors: color_index = func_index % len(COLOR_CYCLE) else: color_index = 0 func_color = COLOR_CYCLE[color_index] # Lines of code for line_info in func_stats: line_item = TreeWidgetItem(func_item) (line_no, code_line, line_total_time, time_per_hit, hits, percent) = line_info self.fill_item( line_item, filename, line_no, code_line, line_total_time, percent, time_per_hit, hits) # Color background if line_total_time is not None: alpha = percent color = QColor(func_color) color.setAlphaF(alpha) # Returns None color = QBrush(color) for col in range(self.columnCount()): line_item.setBackground(col, color) else: for col in range(self.columnCount()): line_item.setForeground(col, CODE_NOT_RUN_COLOR) # Monospace font for code line_item.setFont(COL_LINE, monospace_font) def on_item_clicked(self, item): data = item.data(COL_POS, Qt.UserRole) if data is None or len(data) < 2: return filename, line_no = data self.sig_edit_goto_requested.emit(filename, line_no, '') # ============================================================================= # Tests # ============================================================================= profile = lambda x: x # dummy profile wrapper to make script load externally @profile def primes(n): """ Simple test function Taken from http://www.huyng.com/posts/python-performance-analysis/ """ if n==2: return [2] elif n<2: return [] s=list(range(3,n+1,2)) mroot = n ** 0.5 half=(n+1)//2-1 i=0 m=3 while m <= mroot: if s[i]: j=(m*m-3)//2 s[j]=0 while j= 900 # time (ms) assert float(top.child(2).data(2, Qt.DisplayRole)) <= 1200 assert float(top.child(3).data(2, Qt.DisplayRole)) <= 100 assert float(top.child(4).data(2, Qt.DisplayRole)) <= 100 assert float(top.child(5).data(2, Qt.DisplayRole)) <= 100