pax_global_header00006660000000000000000000000064143456523600014522gustar00rootroot0000000000000052 comment=67b6c68ea49753d5c0b7afc591e9204de64fbace metakernel-0.29.4/000077500000000000000000000000001434565236000137455ustar00rootroot00000000000000metakernel-0.29.4/.coveragerc000066400000000000000000000002251434565236000160650ustar00rootroot00000000000000# Configuration for coverage.py [run] branch = True omit = */setup.py [report] exclude_lines = def __repr__ if __name__ == .__main__.: metakernel-0.29.4/.github/000077500000000000000000000000001434565236000153055ustar00rootroot00000000000000metakernel-0.29.4/.github/dependabot.yml000066400000000000000000000003331434565236000201340ustar00rootroot00000000000000version: 2 updates: # Set update schedule for GitHub Actions - package-ecosystem: "github-actions" directory: "/" schedule: # Check for updates to GitHub Actions every weekday interval: "weekly" metakernel-0.29.4/.github/workflows/000077500000000000000000000000001434565236000173425ustar00rootroot00000000000000metakernel-0.29.4/.github/workflows/check-release.yml000066400000000000000000000012211434565236000225540ustar00rootroot00000000000000name: Check Release on: push: branches: ["main"] pull_request: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true jobs: check_release: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Install Dependencies run: | pip install -e . - name: Check Release uses: jupyter-server/jupyter_releaser/.github/actions/check-release@v2 with: token: ${{ secrets.GITHUB_TOKEN }} metakernel-0.29.4/.github/workflows/enforce-label.yml000066400000000000000000000004241434565236000225630ustar00rootroot00000000000000name: Enforce PR label on: pull_request: types: [labeled, unlabeled, opened, edited, synchronize] jobs: enforce-label: runs-on: ubuntu-latest steps: - name: enforce-triage-label uses: jupyterlab/maintainer-tools/.github/actions/enforce-label@v1 metakernel-0.29.4/.github/workflows/tests.yml000066400000000000000000000043221434565236000212300ustar00rootroot00000000000000name: Tests on: push: branches: ["main"] pull_request: schedule: - cron: "0 0 * * *" concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true jobs: test: name: Test runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] python-version: [3.7, 3.8, 3.9, "3.10", "3.11"] env: OS: ${{ matrix.os }} steps: - name: Checkout uses: actions/checkout@v3 - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - name: Install dependencies run: | pip install coveralls make install - name: Run the tests run: | make docs make help make cover test_miniumum_versions: name: Test Minimum Versions timeout-minutes: 20 runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Base Setup uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 with: python_version: "3.7" - name: Install normally run: make install - name: Install minimum versions uses: jupyterlab/maintainer-tools/.github/actions/install-minimums@v1 - name: Run the unit tests run: make test make_sdist: name: Make SDist runs-on: ubuntu-latest timeout-minutes: 20 steps: - uses: actions/checkout@v3 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - uses: jupyterlab/maintainer-tools/.github/actions/make-sdist@v1 test_sdist: runs-on: ubuntu-latest needs: [make_sdist] name: Install from SDist and Test timeout-minutes: 20 steps: - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - uses: jupyterlab/maintainer-tools/.github/actions/test-sdist@v1 link_check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1 - uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1 with: ignore_links: "http://some/file/from/* http://path/to/some/*" metakernel-0.29.4/.gitignore000066400000000000000000000002061434565236000157330ustar00rootroot00000000000000*.pyc **/*.egg-info/ **/build/ **/dist/ MANIFEST docs/_build/ examples/.ipynb_checkpoints examples/temp.txt *~ .*.swp *,cover .cover* metakernel-0.29.4/CHANGELOG.md000066400000000000000000000416751434565236000155730ustar00rootroot00000000000000# Changelog Entries ## 0.29.4 ([Full Changelog](https://github.com/Calysto/metakernel/compare/v0.29.3...5ec51d6828bf079b7ee2007f6351f4321434b49e)) ### Maintenance and upkeep improvements - Add back magics tests [#261](https://github.com/Calysto/metakernel/pull/261) ([@ellert](https://github.com/ellert)) - Update tests for widgets 8 [#260](https://github.com/Calysto/metakernel/pull/260) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/Calysto/metakernel/graphs/contributors?from=2022-12-01&to=2022-12-12&type=c)) [@blink1073](https://github.com/search?q=repo%3ACalysto%2Fmetakernel+involves%3Ablink1073+updated%3A2022-12-01..2022-12-12&type=Issues) | [@ellert](https://github.com/search?q=repo%3ACalysto%2Fmetakernel+involves%3Aellert+updated%3A2022-12-01..2022-12-12&type=Issues) ## 0.29.3 ([Full Changelog](https://github.com/Calysto/metakernel/compare/v0.29.2...758c19d08fc74daff077b242c0fae30f82313479)) ### Maintenance and upkeep improvements - Bump actions/checkout from 2 to 3 [#258](https://github.com/Calysto/metakernel/pull/258) ([@dependabot](https://github.com/dependabot)) - Maintenance cleanup [#257](https://github.com/Calysto/metakernel/pull/257) ([@blink1073](https://github.com/blink1073)) - Use hatch for example projects [#256](https://github.com/Calysto/metakernel/pull/256) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/Calysto/metakernel/graphs/contributors?from=2022-08-08&to=2022-12-01&type=c)) [@blink1073](https://github.com/search?q=repo%3ACalysto%2Fmetakernel+involves%3Ablink1073+updated%3A2022-08-08..2022-12-01&type=Issues) | [@dependabot](https://github.com/search?q=repo%3ACalysto%2Fmetakernel+involves%3Adependabot+updated%3A2022-08-08..2022-12-01&type=Issues) ## 0.29.2 ([Full Changelog](https://github.com/Calysto/metakernel/compare/v0.29.1...dbe3fc91a87bca68412faf640b58778204102b29)) ### Bugs fixed - Restore versions of metakernel-echo and metakernel-python [#252](https://github.com/Calysto/metakernel/pull/252) ([@ellert](https://github.com/ellert)) ### Maintenance and upkeep improvements - Switch to hatch backend [#254](https://github.com/Calysto/metakernel/pull/254) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/Calysto/metakernel/graphs/contributors?from=2022-08-01&to=2022-08-08&type=c)) [@blink1073](https://github.com/search?q=repo%3ACalysto%2Fmetakernel+involves%3Ablink1073+updated%3A2022-08-01..2022-08-08&type=Issues) | [@ellert](https://github.com/search?q=repo%3ACalysto%2Fmetakernel+involves%3Aellert+updated%3A2022-08-01..2022-08-08&type=Issues) ## 0.29.1 ([Full Changelog](https://github.com/Calysto/metakernel/compare/v0.29.0...68b0da7ad71de8e9802c9ab573344a3ea0a1a832)) ### Bugs fixed - Strip paste-bracketing control characters [#250](https://github.com/Calysto/metakernel/pull/250) ([@anewusername](https://github.com/anewusername)) ### Maintenance and upkeep improvements - Address deprecation warnings [#249](https://github.com/Calysto/metakernel/pull/249) ([@ellert](https://github.com/ellert)) - Switch to flit build backend [#246](https://github.com/Calysto/metakernel/pull/246) ([@blink1073](https://github.com/blink1073)) ### Documentation improvements - Correct spelling mistakes [#248](https://github.com/Calysto/metakernel/pull/248) ([@EdwardBetts](https://github.com/EdwardBetts)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/Calysto/metakernel/graphs/contributors?from=2022-03-29&to=2022-08-01&type=c)) [@anewusername](https://github.com/search?q=repo%3ACalysto%2Fmetakernel+involves%3Aanewusername+updated%3A2022-03-29..2022-08-01&type=Issues) | [@blink1073](https://github.com/search?q=repo%3ACalysto%2Fmetakernel+involves%3Ablink1073+updated%3A2022-03-29..2022-08-01&type=Issues) | [@EdwardBetts](https://github.com/search?q=repo%3ACalysto%2Fmetakernel+involves%3AEdwardBetts+updated%3A2022-03-29..2022-08-01&type=Issues) | [@ellert](https://github.com/search?q=repo%3ACalysto%2Fmetakernel+involves%3Aellert+updated%3A2022-03-29..2022-08-01&type=Issues) ## 0.29.0 ([Full Changelog](https://github.com/Calysto/metakernel/compare/v0.28.2...a339b3976ede13e5813f1f078acc031d6999f412)) ### Maintenance and upkeep improvements - Clean up testing and add more CI [#244](https://github.com/Calysto/metakernel/pull/244) ([@blink1073](https://github.com/blink1073)) - Fix macos tests [#243](https://github.com/Calysto/metakernel/pull/243) ([@blink1073](https://github.com/blink1073)) - Clean up CI and bump supported pythons [#242](https://github.com/Calysto/metakernel/pull/242) ([@blink1073](https://github.com/blink1073)) ### Contributors to this release ([GitHub contributors page for this release](https://github.com/Calysto/metakernel/graphs/contributors?from=2021-12-02&to=2022-03-29&type=c)) [@blink1073](https://github.com/search?q=repo%3ACalysto%2Fmetakernel+involves%3Ablink1073+updated%3A2021-12-02..2022-03-29&type=Issues) ## 0.28.2 - Test with jupyter_kernel_test [#238](https://github.com/Calysto/metakernel/pull/238) ([@blink1073](https://github.com/blink1073)) ## 0.28.1 - Fix trove classifier [#236](https://github.com/Calysto/metakernel/pull/236) ([@blink1073](https://github.com/blink1073)) ## 0.28.0 *Note* This was not uploaded to PyPI because it had an incorrect trove classifier - Add support for jupyter releaser [#234](https://github.com/Calysto/metakernel/pull/234) ([@blink1073](https://github.com/blink1073)) - Modernize build and test [#233](https://github.com/Calysto/metakernel/pull/233) ([@blink1073](https://github.com/blink1073)) - Fix Iframe display issue [#231](https://github.com/Calysto/metakernel/pull/231) ([@cathalmccabe](https://github.com/cathalmccabe)) - Add a blockly magic instead of a jigsaw magic [#229](https://github.com/Calysto/metakernel/pull/229) ([@ChrisJaunes](https://github.com/ChrisJaunes)) ## 0.27.5 - Escape backslashes in strings [#226](https://github.com/Calysto/metakernel/pull/226) ([@ellert](https://github.com/ellert)) - Add missing dollar signs to %latex examples and tests [#225](https://github.com/Calysto/metakernel/pull/225) ([@ellert](https://github.com/ellert)) - Support older jedi versions [#224](https://github.com/Calysto/metakernel/pull/224) ([@ellert](https://github.com/ellert)) ## 0.27.4 - Add support for `SOURCE_DATE_EPOCH` [#223](https://github.com/Calysto/metakernel/pull/223) ([@jnahmias](https://github.com/jnahmias)) ## 0.27.3 - Fix warnings when running tests under python 3.9 [#222](https://github.com/Calysto/metakernel/pull/222) ([@jnahmias](https://github.com/jnahmias)) ## 0.27.2 - Use `TERM=dumb` for bash `REPLWrapper` [#221](https://github.com/Calysto/metakernel/pull/221) ([@jnahmias](https://github.com/jnahmias)) - Use `tempfile` instead of writing to `cwd` [#220](https://github.com/Calysto/metakernel/pull/220) ([@jnahmias](https://github.com/jnahmias)) ## 0.27.0 - More `py2` removal [#219](https://github.com/Calysto/metakernel/pull/219) ([@blink1073](https://github.com/blink1073)) - Remove `py2` [#218](https://github.com/Calysto/metakernel/pull/218) ([@joequant](https://github.com/joequant)) - Monkey patch display to output to kernel [#216](https://github.com/Calysto/metakernel/pull/216) ([@joequant](https://github.com/joequant)) - Fix warnings [#215](https://github.com/Calysto/metakernel/pull/215) ([@joequant](https://github.com/joequant)) ## 0.26.1 - Dev/fix `retval` in `exec` [#214](https://github.com/Calysto/metakernel/pull/214) ([@joequant](https://github.com/joequant)) ## 0.26.0 - Combine `exec`/`eval` evaluators [#213](https://github.com/Calysto/metakernel/pull/213) ([@joequant](https://github.com/joequant)) - Dev/fix `voila` [#212](https://github.com/Calysto/metakernel/pull/212) ([@joequant](https://github.com/joequant)) - Add `Error_display` method to `_metakernel.py` [#205](https://github.com/Calysto/metakernel/pull/205) ([@jld23](https://github.com/jld23)) ## 0.25.0 - Fix python evals #208 [#210](https://github.com/Calysto/metakernel/pull/210) ([@joequant](https://github.com/joequant)) - Fix `ipywidgets` display [#209](https://github.com/Calysto/metakernel/pull/209) ([@joequant](https://github.com/joequant)) ## v0.24.4 - Remove undefined line in expect stdin #203 [#204](https://github.com/Calysto/metakernel/pull/204) ([@dekuenstle](https://github.com/dekuenstle)) - Add `portalocker` and `ipyparallel` as optional dependencies [#202](https://github.com/Calysto/metakernel/pull/202) ([@mdeff](https://github.com/mdeff)) ## v0.24.3 - Update `activity_magic.py` [#197](https://github.com/Calysto/metakernel/pull/197) ([@dovfields](https://github.com/dovfields)) ## v0.24.2 - Fix `TypeError` [#192](https://github.com/Calysto/metakernel/pull/192) ([@ellert](https://github.com/ellert)) ## v0.24.1 - Delay creating wrapper until we need to execute [#190](https://github.com/Calysto/metakernel/pull/190) ([@blink1073](https://github.com/blink1073)) ## v0.24.0 - Add the full license [#189](https://github.com/Calysto/metakernel/pull/189) ([@toddrme2178](https://github.com/toddrme2178)) - Clean up stream/line handling for process kernels [#188](https://github.com/Calysto/metakernel/pull/188) ([@blink1073](https://github.com/blink1073)) - Remove local bash kernel and point to `calysto_bash` [#186](https://github.com/Calysto/metakernel/pull/186) ([@blink1073](https://github.com/blink1073)) ## v0.23.0 - Clean up configurability handling and docs [#184](https://github.com/Calysto/metakernel/pull/184) ([@blink1073](https://github.com/blink1073)) ## v0.22.0 - Add settings handling [#182](https://github.com/Calysto/metakernel/pull/182) ([@blink1073](https://github.com/blink1073)) ## v0.21.3 - Switch to powershell on windows [#181](https://github.com/Calysto/metakernel/pull/181) ([@blink1073](https://github.com/blink1073)) ## v0.21.2 - Clean up `replwrap` prompt handling [#180](https://github.com/Calysto/metakernel/pull/180) ([@blink1073](https://github.com/blink1073)) ## v0.21.1 - Avoid double printing output in process kernels [#179](https://github.com/Calysto/metakernel/pull/179) ([@blink1073](https://github.com/blink1073)) ## v0.21.0 - Carriage Return Handling for `ProcessKernel` [#178](https://github.com/Calysto/metakernel/pull/178) ([@blink1073](https://github.com/blink1073)) - Fix handling metadata in `_formatter` [#174](https://github.com/Calysto/metakernel/pull/174) ([@ccordoba12](https://github.com/ccordoba12)) - Fix for Python 2 compatibility [#173](https://github.com/Calysto/metakernel/pull/173) ([@ccordoba12](https://github.com/ccordoba12)) - Allow to redefine default MetaKernel magics with custom ones [#172](https://github.com/Calysto/metakernel/pull/172) ([@ccordoba12](https://github.com/ccordoba12)) - Don't rely on `'python'` in path during testing [#169](https://github.com/Calysto/metakernel/pull/169) ([@ellert](https://github.com/ellert)) - Include `LICENSE.txt` file in wheels [#168](https://github.com/Calysto/metakernel/pull/168) ([@toddrme2178](https://github.com/toddrme2178)) ## v0.20.13 - Fix display of output in Bash kernel [#160](https://github.com/Calysto/metakernel/pull/160) ([@ellert](https://github.com/ellert)) - Use `sys.executable` when creating `kernel.json` [#159](https://github.com/Calysto/metakernel/pull/159) ([@ellert](https://github.com/ellert)) ## v0.20.12 - Expose the prompt change cmd [#157](https://github.com/Calysto/metakernel/pull/157) ([@blink1073](https://github.com/blink1073)) ## v0.20.11 - Replwrap fixes [#156](https://github.com/Calysto/metakernel/pull/156) ([@blink1073](https://github.com/blink1073)) ## v0.20.10 - Clean up handling of command and args [#155](https://github.com/Calysto/metakernel/pull/155) ([@blink1073](https://github.com/blink1073)) ## v0.20.9 - Allow a list to be passed as the command [#154](https://github.com/Calysto/metakernel/pull/154) ([@blink1073](https://github.com/blink1073)) ## v0.20.8 - Fix handling of fallback images [#153](https://github.com/Calysto/metakernel/pull/153) ([@blink1073](https://github.com/blink1073)) ## v0.20.6 - Get kernel images from package if possible [#152](https://github.com/Calysto/metakernel/pull/152) ([@blink1073](https://github.com/blink1073)) - Version 0.20.5 [#151](https://github.com/Calysto/metakernel/pull/151) ([@dsblank](https://github.com/dsblank)) ## v0.20.1 - Adding call to close on child pty [#141](https://github.com/Calysto/metakernel/pull/141) ([@Daniel-V1](https://github.com/Daniel-V1)) ## v0.20.0 - Mark tests that use the network [#139](https://github.com/Calysto/metakernel/pull/139) ([@QuLogic](https://github.com/QuLogic)) - Restore Jedi 0.9 compatibility [#138](https://github.com/Calysto/metakernel/pull/138) ([@QuLogic](https://github.com/QuLogic)) - Update versions of MetaKernel kernels. [#137](https://github.com/Calysto/metakernel/pull/137) ([@QuLogic](https://github.com/QuLogic)) - Remove shell ambiguity [#134](https://github.com/Calysto/metakernel/pull/134) ([@blink1073](https://github.com/blink1073)) ## v0.19.0 - Require ipykernel [#132](https://github.com/Calysto/metakernel/pull/132) ([@blink1073](https://github.com/blink1073)) - Make help logic more robust [#131](https://github.com/Calysto/metakernel/pull/131) ([@blink1073](https://github.com/blink1073)) - Update for jedi 0.10 [#129](https://github.com/Calysto/metakernel/pull/129) ([@blink1073](https://github.com/blink1073)) - Clean up kernel magic [#128](https://github.com/Calysto/metakernel/pull/128) ([@blink1073](https://github.com/blink1073)) ## v0.18.2 - Use clrf for end of line response from process [#124](https://github.com/Calysto/metakernel/pull/124) ([@blink1073](https://github.com/blink1073)) ## v0.18.1 - Fix shell magic on Windows [#123](https://github.com/Calysto/metakernel/pull/123) ([@blink1073](https://github.com/blink1073)) ## v0.18.0 - Replwrap cleanup [#122](https://github.com/Calysto/metakernel/pull/122) ([@blink1073](https://github.com/blink1073)) ## v0.17.0 - Added support for better error handling to metakernel [#121](https://github.com/Calysto/metakernel/pull/121) ([@mariusvniekerk](https://github.com/mariusvniekerk)) ## v0.16.0 - Add support for stdin requests and clean up replwrap [#120](https://github.com/Calysto/metakernel/pull/120) ([@blink1073](https://github.com/blink1073)) - Improvements to bash handling from bash_kernel [#119](https://github.com/Calysto/metakernel/pull/119) ([@blink1073](https://github.com/blink1073)) - Clean up plot magic handling and add width/height options [#118](https://github.com/Calysto/metakernel/pull/118) ([@blink1073](https://github.com/blink1073)) - Use pexpect and clean up handling of replwrap [#117](https://github.com/Calysto/metakernel/pull/117) ([@blink1073](https://github.com/blink1073)) ## v0.15.1 - Better handling of ipywidgets import [#114](https://github.com/Calysto/metakernel/pull/114) ([@blink1073](https://github.com/blink1073)) - Expose path escaper. [#110](https://github.com/Calysto/metakernel/pull/110) ([@anntzer](https://github.com/anntzer)) - Remove workaround [#109](https://github.com/Calysto/metakernel/pull/109) ([@dsblank](https://github.com/dsblank)) - Save history as JSON, to handle multiline entries. [#105](https://github.com/Calysto/metakernel/pull/105) ([@anntzer](https://github.com/anntzer)) ## v0.13.1 - Fix kernelspec install. [#98](https://github.com/Calysto/metakernel/pull/98) ([@anntzer](https://github.com/anntzer)) - New kernelspec install. [#97](https://github.com/Calysto/metakernel/pull/97) ([@anntzer](https://github.com/anntzer)) ## v0.12.1 - Remove redundant if statement. [#89](https://github.com/Calysto/metakernel/pull/89) ([@bsvh](https://github.com/bsvh)) - wrap output in TextOutput in ProcessMetaKernel [#88](https://github.com/Calysto/metakernel/pull/88) ([@minrk](https://github.com/minrk)) - Allow long running tasks to print [#86](https://github.com/Calysto/metakernel/pull/86) ([@blink1073](https://github.com/blink1073)) - Fix import from ipywidgets [#85](https://github.com/Calysto/metakernel/pull/85) ([@has2k1](https://github.com/has2k1)) ## v0.11.7 - still timeout=None seems to be ignored [#84](https://github.com/Calysto/metakernel/pull/84) ([@schlichtanders](https://github.com/schlichtanders)) ## v0.11.6 - bug fixed timeout=None [#83](https://github.com/Calysto/metakernel/pull/83) ([@schlichtanders](https://github.com/schlichtanders)) - Fix intermittent failing "ls" test [#82](https://github.com/Calysto/metakernel/pull/82) ([@blink1073](https://github.com/blink1073)) - Fix handling of multiple commands [#81](https://github.com/Calysto/metakernel/pull/81) ([@blink1073](https://github.com/blink1073)) ## v0.11.5 - Fix handling of multiple commands [#81](https://github.com/Calysto/metakernel/pull/81) ([@blink1073](https://github.com/blink1073)) - Make widgets optional [#77](https://github.com/Calysto/metakernel/pull/77) ([@blink1073](https://github.com/blink1073)) - Jupyter 4 test [#75](https://github.com/Calysto/metakernel/pull/75) ([@blink1073](https://github.com/blink1073)) metakernel-0.29.4/CONTRIBUTORS.rst000066400000000000000000000003601434565236000164330ustar00rootroot00000000000000 Development Leads ```````````````````````````````` - Doug Blank - Steven Silvester Patches and Suggestions ``````````````````````` - Daniel Mendler @minad - Thomas Kluyver @takluyver metakernel-0.29.4/LICENSE.txt000066400000000000000000000030361434565236000155720ustar00rootroot00000000000000Copyright (c) 2014-2019, IPython Kernel Development Team and Metakernel Development Team All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Metakernel nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. metakernel-0.29.4/Makefile000066400000000000000000000017071434565236000154120ustar00rootroot00000000000000# Note: This is meant for Metakernel developer use only .PHONY: all clean test test_warn cover release help all: install install: clean pip install --upgrade --upgrade-strategy eager -e .[parallel,activity,test] pip install ./metakernel_python python -m metakernel_python install --user pip install ./metakernel_echo python -m metakernel_echo install --user clean: rm -rf build dist /usr/bin/find . -name "*.pyc" -o -name "*.py,cover"| xargs rm -f test: clean ipcluster start -n=3 & python -m pytest -W default || python -m pytest -W default --lf ipcluster stop python metakernel_python/test_metakernel_python.py make clean cover: clean ipcluster start -n=3 & python -m pytest --cov=metakernel || python -m pytest --lf --cov=metakernel ipcluster stop python metakernel_python/test_metakernel_python.py coverage annotate docs: clean pip install -r docs/requirements.txt make -C docs html SPHINXOPTS="-W" help: python docs/generate_help.py metakernel-0.29.4/README.rst000066400000000000000000000144671434565236000154500ustar00rootroot00000000000000A Jupyter kernel base class in Python which includes core magic functions (including help, command and file path completion, parallel and distributed processing, downloads, and much more). .. image:: https://badge.fury.io/py/metakernel.png/ :target: http://badge.fury.io/py/metakernel .. image:: https://coveralls.io/repos/Calysto/metakernel/badge.png?branch=main :target: https://coveralls.io/r/Calysto/metakernel .. image:: https://travis-ci.org/Calysto/metakernel.svg :target: https://travis-ci.org/Calysto/metakernel .. image:: https://anaconda.org/conda-forge/metakernel/badges/version.svg :target: https://anaconda.org/conda-forge/metakernel .. image:: https://anaconda.org/conda-forge/metakernel/badges/downloads.svg :target: https://anaconda.org/conda-forge/metakernel See Jupyter's docs on `wrapper kernels `_. Additional magics can be installed within the new kernel package under a `magics` subpackage. Features ------------- - Basic set of line and cell magics for all kernels. - Python magic for accessing python interpreter. - Run kernels in parallel. - Shell magics. - Classroom management magics. - Tab completion for magics and file paths. - Help for magics using ? or Shift+Tab. - Plot magic for setting default plot behavior. Kernels based on Metakernel --------------------------- - matlab_kernel, https://github.com/Calysto/matlab_kernel - octave_kernel, https://github.com/Calysto/octave_kernel - calysto_scheme, https://github.com/Calysto/calysto_scheme - calysto_processing, https://github.com/Calysto/calysto_processing - java9_kernel, https://github.com/Bachmann1234/java9_kernel - xonsh_kernel, https://github.com/Calysto/xonsh_kernel - calysto_hy, https://github.com/Calysto/calysto_hy - gnuplot_kernel, https://github.com/has2k1/gnuplot_kernel - spylon_kernel, https://github.com/mariusvniekerk/spylon-kernel - wolfram_kernel, https://github.com/mmatera/iwolfram - sas_kernel, https://github.com/sassoftware/sas_kernel - pysysh_kernel, https://github.com/Jaesin/psysh_kernel - calysto_bash, https://github.com/Calysto/calysto_bash ... and many others. Installation ---------------- You can install Metakernel through ``pip``: .. code::bash pip install metakernel --upgrade Installing `metakernel` from the `conda-forge` channel can be achieved by adding `conda-forge` to your channels with: .. code::bash conda config --add channels conda-forge Once the `conda-forge` channel has been enabled, `metakernel` can be installed with: .. code::bash conda install metakernel It is possible to list all of the versions of `metakernel` available on your platform with: .. code::bash conda search metakernel --channel conda-forge Use MetaKernel Magics in IPython -------------------------------- Although MetaKernel is a system for building new kernels, you can use a subset of the magics in the IPython kernel. .. code:: python from metakernel import register_ipython_magics register_ipython_magics() Put the following in your (or a system-wide) ``ipython_config.py`` file: .. code:: python # /etc/ipython/ipython_config.py c = get_config() startup = [ 'from metakernel import register_ipython_magics', 'register_ipython_magics()', ] c.InteractiveShellApp.exec_lines = startup Use MetaKernel Languages in Parallel To use a MetaKernel language in parallel, do the following: 1. Make sure that the Python module `ipyparallel` is installed. In the shell, type: .. code:: bash pip install ipyparallel 2. To enable the extension in the notebook, in the shell, type: .. code:: bash ipcluster nbextension enable 3. To start up a cluster, with 10 nodes, on a local IP address, in the shell, type: .. code:: bash ipcluster start --n=10 --ip=192.168.1.108 4. Initialize the code to use the 10 nodes, inside the notebook from a host kernel ``MODULE`` and ``CLASSNAME`` (can be any metakernel kernel): .. code:: bash %parallel MODULE CLASSNAME For example: .. code:: bash %parallel calysto_scheme CalystoScheme 5. Run code in parallel, inside the notebook, type: Execute a single line, in parallel: .. code:: bash %px (+ 1 1) Or execute the entire cell, in parallel: .. code:: bash %%px (* cluster_rank cluster_rank) Results come back in a Python list (Scheme vector), in ``cluster_rank`` order. (This will be a JSON representation in the future). Therefore, the above would produce the result: .. code:: bash #10(0 1 4 9 16 25 36 49 64 81) You can get the results back in any of the parallel magics (``%px``, ``%%px``, or ``%pmap``) in the host kernel by accessing the variable ``_`` (single underscore), or by using the ``--set_variable VARIABLE`` flag, like so: .. code:: bash %%px --set_variable results (* cluster_rank cluster_rank) Then, in the next cell, you can access ``results``. Notice that you can use the variable ``cluster_rank`` to partition parts of a problem so that each node is working on something different. In the examples above, use ``-e`` to evaluate the code in the host kernel as well. Note that ``cluster_rank`` is not defined on the host machine, and that this assumes the host kernel is the same as the parallel machines. Configuration ------------- ``Metakernel`` subclasses can be configured by the user. The configuration file name is determined by the ``app_name`` property of the subclass. For example, in the ``Octave`` kernel, it is ``octave_kernel``. The user of the kernel can add an ``octave_kernel_config.py`` file to their ``jupyter`` config path. The base ``MetaKernel`` class offers ``plot_settings`` as a configurable trait. Subclasses can define other traits that they wish to make configurable. As an example: .. code:: bash cat ~/.jupyter/octave_kernel_config.py # use Qt as the default backend for plots c.OctaveKernel.plot_settings = dict(backend='qt') Documentation ----------------------- Example notebooks can be viewed here_. Documentation is available online_. Magics have interactive help_ (and online). For version information, see the Changelog_. .. _here: http://nbviewer.ipython.org/github/Calysto/metakernel/tree/main/examples/ .. _help: https://github.com/Calysto/metakernel/blob/main/metakernel/magics/README.md .. _online: http://Calysto.github.io/metakernel/ .. _Changelog: https://github.com/Calysto/metakernel/blob/main/CHANGELOG.md metakernel-0.29.4/RELEASE.md000066400000000000000000000015171434565236000153530ustar00rootroot00000000000000# Making a Jupyter Server Release ## Using `jupyter_releaser` The recommended way to make a release is to use [`jupyter_releaser`](https://github.com/jupyter-server/jupyter_releaser#checklist-for-adoption). ## Manual Release To create a manual release, perform the following steps: ### Set up ```bash pip install tbump twine build git pull origin $(git branch --show-current) git clean -dffx ``` ### Update the version and apply the tag ```bash echo "Enter new version" read script_version tbump ${script_version} ``` ### Build the artifacts ```bash rm -rf dist python -m build . ``` ### Update the version back to dev ```bash echo "Enter dev version" read dev_version tbump ${dev_version} --no-tag git push origin $(git branch --show-current) ``` ### Publish the artifacts to pypi ```bash twine check dist/* twine upload dist/* ``` metakernel-0.29.4/conftest.py000066400000000000000000000000631434565236000161430ustar00rootroot00000000000000import os os.environ['JUPYTER_PLATFORM_DIRS'] = '1'metakernel-0.29.4/docs/000077500000000000000000000000001434565236000146755ustar00rootroot00000000000000metakernel-0.29.4/docs/Makefile000066400000000000000000000126641434565236000163460ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Jedi.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Jedi.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/Jedi" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Jedi" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." metakernel-0.29.4/docs/_templates/000077500000000000000000000000001434565236000170325ustar00rootroot00000000000000metakernel-0.29.4/docs/_templates/layout.html000066400000000000000000000007541434565236000212430ustar00rootroot00000000000000{% extends '!layout.html' %} {# Add github banner (from: https://github.com/blog/273-github-ribbons). #} {% block header %} {{ super() }} {% if pagename == "index" %} Fork me on GitHub {% endif %} {% endblock %} metakernel-0.29.4/docs/conf.py000066400000000000000000000222401434565236000161740ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Jupyter Kernel documentation build configuration file, created by # sphinx-quickstart on Wed Dec 26 00:11:34 2012. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os, datetime, time today_date = datetime.datetime.utcfromtimestamp( int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) ) # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['myst_parser','sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.todo', 'sphinx.ext.intersphinx', 'sphinx.ext.inheritance_diagram', 'numpydoc'] myst_enable_extensions = ["html_image"] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = ['.rst', '.ipynb'] # The encoding of source files. source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = 'Metakernel' copyright = f'2014 - {today_date.year}, Metakernel contributors' import metakernel # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = metakernel.__version__ # The full version, including alpha/beta/rc tags. release = metakernel.__version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. import sphinx_bootstrap_theme html_theme = 'bootstrap' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} html_theme_options = { #'navbar_class': 'navbar-inverse', #'navbar_sidebarrel': False, 'bootswatch_theme': 'cosmo', 'bootstrap_version': '3', } # Add any paths that contain custom themes here, relative to this directory. html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". #html_static_path = ['source/static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. html_sidebars = { '**': [ 'localtoc.html', ] } # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'Metakerneldoc' #html_style = 'default.css' # Force usage of default template on RTD # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'Metakernel.tex', u'Metakernel Documentation', u'Metakernel contributors', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'Jupyter Kernel', u'Jupyter Kernel Documentation', [u'Jupyter Kernel contributors'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'Jupyter Kernel', u'Jupyter Kernel Documentation', u'Jupyter Kernel contributors', 'Jupyter Kernel', 'Jupyter Kernel Tools', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # -- Options for todo module --------------------------------------------------- todo_include_todos = False # -- Options for autodoc module ------------------------------------------------ autoclass_content = 'both' autodoc_member_order = 'bysource' autodoc_default_flags = [] #autodoc_default_flags = ['members', 'undoc-members'] # ----------------------------------------------------------------------------- # Numpy extensions # ----------------------------------------------------------------------------- numpydoc_show_class_members = False # ----------------------------------------------------------------------------- # intersphinx # ----------------------------------------------------------------------------- _python_doc_base = 'http://docs.python.org/2.7' intersphinx_mapping = { _python_doc_base: None, } metakernel-0.29.4/docs/generate_help.py000066400000000000000000000017061434565236000200550ustar00rootroot00000000000000from __future__ import print_function import sys from metakernel_python import MetaKernelPython kernel = MetaKernelPython() path = "metakernel/magics/README.md" with open(path) as fid: prev = fid.read() print("Generating README.md...") prefix = kernel.magic_prefixes['magic'] text = "# Line Magics\n\n" for magic in sorted(kernel.line_magics.keys()): text += "## `" + prefix + magic + "`\n\n" text += kernel.get_help_on(prefix + magic) + "\n\n" text += "# Cell Magics\n\n" for magic in sorted(kernel.cell_magics.keys()): text += "## `" + prefix + prefix + magic + "`\n\n" text += kernel.get_help_on(prefix + prefix + magic) + "\n\n" # Fix for "Title underline too short". text = text.replace('-------', '--------') with open(path, 'w') as fid: fid.write(text) print("done!") if text != prev: print('Readme changed, please commit the changes') print('If this is on CI, run `make help` locally to regenerate') sys.exit(1) metakernel-0.29.4/docs/index.rst000066400000000000000000000010371434565236000165370ustar00rootroot00000000000000 .. include:: ../README.rst :end-before: Installation .. toctree:: :hidden: :maxdepth: 1 source/installation source/api source/info `API Reference `_ ------------------------------------------------ Documentation for the functions included in Jupyter Kernel. `Installation `_ ------------------------------------------------ How to install Jupyter Kernel. `Information `_ ----------------------------------------- Other information about Jupyter Kernel. metakernel-0.29.4/docs/make.bat000066400000000000000000000056171434565236000163130ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation set SPHINXBUILD=sphinx-build set ALLSPHINXOPTS=-d _build/doctrees %SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (_build\*) do rmdir /q /s %%i del /q /s _build\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% _build/html echo. echo.Build finished. The HTML pages are in _build/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% _build/dirhtml echo. echo.Build finished. The HTML pages are in _build/dirhtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% _build/pickle echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% _build/json echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% _build/htmlhelp echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in _build/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% _build/qthelp echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in _build/qthelp, like this: echo.^> qcollectiongenerator _build\qthelp\oct2py.qhcp echo.To view the help file: echo.^> assistant -collectionFile _build\qthelp\oct2py.ghc goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% _build/latex echo. echo.Build finished; the LaTeX files are in _build/latex. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% _build/changes echo. echo.The overview file is in _build/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% _build/linkcheck echo. echo.Link check complete; look for any errors in the above output ^ or in _build/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% _build/doctest echo. echo.Testing of doctests in the sources finished, look at the ^ results in _build/doctest/output.txt. goto end ) :end metakernel-0.29.4/docs/requirements.txt000066400000000000000000000002361434565236000201620ustar00rootroot00000000000000metakernel IPython pypandoc sphinx_rtd_theme nbsphinx jupyter_sphinx sphinxcontrib-napoleon recommonmark requests sphinx_bootstrap_theme numpydoc myst-parser metakernel-0.29.4/docs/source/000077500000000000000000000000001434565236000161755ustar00rootroot00000000000000metakernel-0.29.4/docs/source/README.md000077700000000000000000000000001434565236000247462../../metakernel/magics/README.mdustar00rootroot00000000000000metakernel-0.29.4/docs/source/api.rst000066400000000000000000000003121434565236000174740ustar00rootroot00000000000000******************** API Reference ******************** Metakernel ============= .. module:: metakernel .. autoclass:: MetaKernel :members: .. autoclass:: Magic :members: .. autofunction:: option metakernel-0.29.4/docs/source/info.rst000066400000000000000000000002011434565236000176530ustar00rootroot00000000000000 ****************** Information ****************** .. toctree:: :maxdepth: 2 :caption: Contents: :numbered: README metakernel-0.29.4/docs/source/installation.rst000066400000000000000000000001661434565236000214330ustar00rootroot00000000000000Installation ************************ You can install metakernel through `pip`: `pip install metakernel --upgrade` metakernel-0.29.4/examples/000077500000000000000000000000001434565236000155635ustar00rootroot00000000000000metakernel-0.29.4/examples/Calysto Processing.ipynb000066400000000000000000001452551434565236000223550ustar00rootroot00000000000000{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Calysto Processing\n", "\n", "This notebook shows Calysto Processing, a MetaKernel-based Jupyter language.\n", "\n", "To see this notebook with included Javascript parts, please use this URL:\n", "\n", "http://nbviewer.ipython.org/github/Calysto/metakernel/blob/main/examples/Calysto%20Processing.ipynb\n", "\n", "To run Calysto Processing yourself, you will need:\n", "\n", "* IPython/Jupyter\n", "* MetaKernel\n", "* Calysto\n", "* Calysto Processing\n", "\n", "You can run any Processing sketch as a cell in a notebook:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " var component = document.getElementById(\"sketch_1\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"state_1\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"controls_div_1\");\n", " if (component != undefined)\n", " component.remove();\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " // FIXME: Stop all previously running versions (?)\n", " var processingInstance = Processing.getInstanceById(\"canvas_1\");\n", " if (processingInstance != undefined && processingInstance.isRunning())\n", " processingInstance.noLoop();\n", " });\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " Sketch #1:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #1 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "line(10, 10, 90, 90);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calysto Processing has full error checking and messages. It shows the line both in red, and highlights in yellow the offending line:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ " Line +---------------------------------------------------------------------------\n", " 1: -> | line(10, 10, 90, h);\n", " +---------------------------------------------------------------------------\n", "\n", "Compile error in line 1: Cannot find anything named “hâ€\n" ] }, { "data": { "text/html": [ "\n", "\n", "\n", "\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "line(10, 10, 90, h);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Processing sketches that use setup and draw can be stepped one call at a time. Simply Pause the sketch, and press the setup() or draw() buttons. Press on the Run button to resume:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " var component = document.getElementById(\"sketch_3\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"state_3\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"controls_div_3\");\n", " if (component != undefined)\n", " component.remove();\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " // FIXME: Stop all previously running versions (?)\n", " var processingInstance = Processing.getInstanceById(\"canvas_3\");\n", " if (processingInstance != undefined && processingInstance.isRunning())\n", " processingInstance.noLoop();\n", " });\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " Sketch #3:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #3 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "void setup() {\n", " background(255);\n", "}\n", "\n", "void draw() {\n", " ellipse(mouseX, mouseY, 5, 5);\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are a number of additional support tools for Java and Processing in Calysto Processing, including the online tutor:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%tutor\n", "\n", "public class YourClassNameHere {\n", " public static void main(String[] args) {\n", " for (int i=0; i < 10; i++) {\n", " System.out.println(\"i: \" + i);\n", " }\n", " }\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And drag-and-drop Processing code generator, called Jigsaw:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " if (document.jigsaw_register_workspace === undefined) {\n", "\n", " document.jigsaw_workspaces = {};\n", "\n", " document.jigsaw_register_workspace = function(workspace_filename, workspace, xml_init) {\n", " workspace.element = document.element;\n", " document.jigsaw_workspaces[workspace_filename] = workspace;\n", "\n", " try {\n", " $([window.parent.IPython.events]).on('notebook_saved.Notebook', function() { \n", " try {\n", " document.jigsaw_save_workspace(workspace_filename); \n", " } catch(err) {\n", " // ignore failure, might not exist\n", " }\n", " });\n", " } catch (err) {\n", " // rendering for display\n", " }\n", " \n", " var xml = document.jigsaw_loadXMLDoc(workspace_filename);\n", " if (xml === null) {\n", " xml = xml_init;\n", " if (xml === null) {\n", " xml = Blockly.Xml.textToDom('');\n", " }\n", " } else {\n", " xml = xml.children[0]; // document\n", " }\n", " Blockly.Xml.domToWorkspace(workspace, xml);\n", " };\n", "\n", " document.jigsaw_handle_output = function(workspace_filename, out) {\n", " var workspace = document.jigsaw_workspaces[workspace_filename];\n", " //var output_area = workspace.element.output_area;\n", " var cell_index = document.jigsaw_get_cell(workspace.element);\n", " var cell = IPython.notebook.get_cell(cell_index);\n", " var res = null;\n", " var data = null;\n", " document.cell = cell;\n", " document.out = out;\n", " if (out.msg_type == \"stream\") {\n", " res = out.content.text;\n", " //document.getElementById('code_output').value += res.toString();\n", " } else if (out.msg_type === \"pyout\") {\n", " // if output is a python object\n", " res = out.content.data[\"text/plain\"];\n", " //document.getElementById('code_output').value += res.toString(); \n", " } else if (out.msg_type == \"pyerr\") {\n", " // if output is a python error\n", " res = out.content.data[\"text/plain\"];\n", " //document.getElementById('code_output').value += res.toString();\n", " } else if (out.msg_type == \"execute_result\") {\n", " var str = out.content.data[\"text/plain\"];\n", " res = str;\n", " if (res.indexOf(\"u\") == 0)\n", " res = res.substring(2, res.length - 1) + \"\\n\";\n", " if (res) {\n", " //document.getElementById('code_output').value += res.toString();\n", " }\n", " } else if (out.msg_type == \"error\") {\n", " res = out.content.ename + \": \" + out.content.evalue + \"\\n\";\n", " // FIXME: out.traceback is Array of terminal color-coded [-codes\n", " } else {\n", " // if output is something we haven't thought of\n", " res = out.toString();\n", " //document.getElementById('code_output').value += res.toString();\n", " }\n", " if (res) {\n", " cell.output_area.append_output({output_type: \"stream\", text: res.toString(), name: \"output\"});\n", " }\n", " };\n", " \n", " document.jigsaw_generate = function(workspace_filename, language, insert_code) {\n", " var workspace = document.jigsaw_workspaces[workspace_filename];\n", " var callbacks = { 'iopub' : {'output' : function(out) { document.jigsaw_handle_output(workspace_filename, out); }}};\n", " var code = Blockly[language].workspaceToCode(workspace);\n", " if (insert_code == 1) {\n", " var cell_index = document.jigsaw_get_cell(workspace.element);\n", " var cell = IPython.notebook.insert_cell_at_index(0, cell_index + 1);\n", " cell.set_text(code);\n", " } else {\n", " window.parent.IPython.notebook.kernel.execute(code,\n", " callbacks,\n", " {silent: false});\n", " }\n", " };\n", " \n", " document.jigsaw_save_workspace = function(workspace_filename) {\n", " var workspace = document.jigsaw_workspaces[workspace_filename];\n", " var xml = Blockly.Xml.workspaceToDom(workspace);\n", " document.xml = xml;\n", " if (xml !== undefined) {\n", " console.log(xml);\n", " //xml.style = \"display: none\";\n", " //xml.id = \"workspace\";\n", " var xml_text = Blockly.Xml.domToText(xml)\n", " IPython.notebook.kernel.execute('%%file ' + workspace_filename + '\\n' + xml_text);\n", " }\n", " };\n", " \n", " document.jigsaw_loadXMLDoc = function(filename) {\n", " var xhttp = new XMLHttpRequest();\n", " xhttp.open(\"GET\", filename, false);\n", " xhttp.send();\n", " return xhttp.responseXML;\n", " };\n", " }\n", "\n", " document.jigsaw_get_cell = function (element) {\n", " // FIXME: brittle and ugly:\n", " var mydiv = element[0].parentNode.parentNode.parentNode.parentNode;\n", " var cells = IPython.notebook.get_cells();\n", " for (var i = 0; i < cells.length; i++) {\n", " if (mydiv === cells[i].element[0]) {\n", " return i;\n", " }\n", " }\n", " return null;\n", " };\n", "\n", " document.jigsaw_clear_output = function (workspace_filename) {\n", " var workspace = document.jigsaw_workspaces[workspace_filename];\n", " var cell_index = document.jigsaw_get_cell(workspace.element);\n", " var cell = IPython.notebook.get_cell(cell_index);\n", " // FIXME: brittle and ugly:\n", " cell.element[0].children[2].children[1].children[2].children[1].children[0].innerHTML = \"\"\n", " cell.output_area.outputs[2].text = \"\"\n", " };\n", "\n", " try {\n", " document.element = element;\n", " } catch (err) {\n", " // rendering\n", " }\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%jigsaw Processing --workspace processing1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Clicking on \"Generate Processing Code\" created the following cell (except for a type that we added):" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " var component = document.getElementById(\"sketch_7\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"state_7\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"controls_div_7\");\n", " if (component != undefined)\n", " component.remove();\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " // FIXME: Stop all previously running versions (?)\n", " var processingInstance = Processing.getInstanceById(\"canvas_7\");\n", " if (processingInstance != undefined && processingInstance.isRunning())\n", " processingInstance.noLoop();\n", " });\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " Sketch #7:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #7 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "\n", "\n", "void draw() {\n", " for (int i = 1; i<=10; i++) {\n", " ellipse((30 * i), 10, 20, 20);\n", " }\n", "}\n", "\n", "void setup() {\n", " size(600, 40);\n", "}\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Try it out!" ] } ], "metadata": { "kernelspec": { "display_name": "Calysto Processing", "language": "java", "name": "calysto_processing" }, "language_info": { "codemirror_mode": { "name": "text/x-java", "version": 2 }, "file_extension": ".java", "mimetype": "text/x-java", "name": "java" } }, "nbformat": 4, "nbformat_minor": 0 } metakernel-0.29.4/examples/Jigsaw in IPython.ipynb000066400000000000000000000511361434565236000220220ustar00rootroot00000000000000{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Jigsaw in IPython\n", "\n", "This notebook demonstrates using the %jigsaw magic in IPython.\n", "\n", "Dependencies:\n", "\n", "1. system running IPython or Jupyter\n", "2. [metakernel](https://github.com/Calysto/metakernel)\n", "\n", "## Overview\n", "\n", "Jigsaw is a combination of Google's Blockly drag-and-drop interface in the browser with Python. With Jigsaw, you can:\n", "\n", "* do many Python tasks in the block-only view\n", "* have access to predefined Python variables\n", "* create functions and variables in Jigsaw, but use them in Python cells\n", "\n", "To use in IPython, you need to add the metakernel magics for IPython:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from metakernel import register_ipython_magics\n", "register_ipython_magics()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, let's define some Python things:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x = 42" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def myfunc(a, b):\n", " return a + b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, we create a Jigsaw workspace named \"workspace1\". This will create two files in this subdirectory:\n", "\n", "1. workspace1.html\n", "2. workspace1.xml\n", "\n", "Once you have the Jigsaw workspace showing, then you can start dragging blocks around:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " if (document.jigsaw_register_workspace === undefined) {\n", "\n", " document.jigsaw_workspaces = {};\n", "\n", " document.jigsaw_register_workspace = function(workspace_filename, workspace, xml_init) {\n", " workspace.element = document.element;\n", " document.jigsaw_workspaces[workspace_filename] = workspace;\n", "\n", " try {\n", " $([window.parent.IPython.events]).on('notebook_saved.Notebook', function() { \n", " try {\n", " document.jigsaw_save_workspace(workspace_filename); \n", " } catch(err) {\n", " // ignore failure, might not exist\n", " }\n", " });\n", " } catch (err) {\n", " // rendering for display\n", " }\n", " \n", " var xml = document.jigsaw_loadXMLDoc(workspace_filename);\n", " if (xml === null) {\n", " xml = xml_init;\n", " if (xml === null) {\n", " xml = Blockly.Xml.textToDom('');\n", " }\n", " } else {\n", " xml = xml.children[0]; // document\n", " }\n", " Blockly.Xml.domToWorkspace(workspace, xml);\n", " };\n", "\n", " document.jigsaw_handle_output = function(workspace_filename, out) {\n", " var workspace = document.jigsaw_workspaces[workspace_filename];\n", " //var output_area = workspace.element.output_area;\n", " var cell_index = document.jigsaw_get_cell(workspace.element);\n", " var cell = IPython.notebook.get_cell(cell_index);\n", " var res = null;\n", " var data = null;\n", " document.cell = cell;\n", " document.out = out;\n", " if (out.msg_type == \"stream\") {\n", " res = out.content.text;\n", " //document.getElementById('code_output').value += res.toString();\n", " } else if (out.msg_type === \"pyout\") {\n", " // if output is a python object\n", " res = out.content.data[\"text/plain\"];\n", " //document.getElementById('code_output').value += res.toString(); \n", " } else if (out.msg_type == \"pyerr\") {\n", " // if output is a python error\n", " res = out.content.data[\"text/plain\"];\n", " //document.getElementById('code_output').value += res.toString();\n", " } else if (out.msg_type == \"execute_result\") {\n", " var str = out.content.data[\"text/plain\"];\n", " res = str;\n", " if (res.indexOf(\"u\") == 0)\n", " res = res.substring(2, res.length - 1) + \"\\n\";\n", " if (res) {\n", " //document.getElementById('code_output').value += res.toString();\n", " }\n", " } else if (out.msg_type == \"error\") {\n", " res = out.content.ename + \": \" + out.content.evalue + \"\\n\";\n", " // FIXME: out.traceback is Array of terminal color-coded [-codes\n", " } else {\n", " // if output is something we haven't thought of\n", " res = out.toString();\n", " //document.getElementById('code_output').value += res.toString();\n", " }\n", " if (res) {\n", " cell.output_area.append_output({output_type: \"stream\", text: res.toString(), name: \"output\"});\n", " }\n", " };\n", " \n", " document.jigsaw_generate = function(workspace_filename, language, insert_code) {\n", " var workspace = document.jigsaw_workspaces[workspace_filename];\n", " var callbacks = { 'iopub' : {'output' : function(out) { document.jigsaw_handle_output(workspace_filename, out); }}};\n", " var code = Blockly[language].workspaceToCode(workspace);\n", " if (insert_code == 1) {\n", " var cell_index = document.jigsaw_get_cell(workspace.element);\n", " var cell = IPython.notebook.insert_cell_at_index(0, cell_index + 1);\n", " cell.set_text(code);\n", " } else {\n", " window.parent.IPython.notebook.kernel.execute(code,\n", " callbacks,\n", " {silent: false});\n", " }\n", " };\n", " \n", " document.jigsaw_save_workspace = function(workspace_filename) {\n", " var workspace = document.jigsaw_workspaces[workspace_filename];\n", " var xml = Blockly.Xml.workspaceToDom(workspace);\n", " document.xml = xml;\n", " if (xml !== undefined) {\n", " console.log(xml);\n", " //xml.style = \"display: none\";\n", " //xml.id = \"workspace\";\n", " var xml_text = Blockly.Xml.domToText(xml)\n", " IPython.notebook.kernel.execute('%%file ' + workspace_filename + '\\n' + xml_text);\n", " }\n", " };\n", " \n", " document.jigsaw_loadXMLDoc = function(filename) {\n", " var xhttp = new XMLHttpRequest();\n", " xhttp.open(\"GET\", filename, false);\n", " xhttp.send();\n", " return xhttp.responseXML;\n", " };\n", " }\n", "\n", " document.jigsaw_get_cell = function (element) {\n", " // FIXME: brittle and ugly:\n", " var mydiv = element[0].parentNode.parentNode.parentNode.parentNode;\n", " var cells = IPython.notebook.get_cells();\n", " for (var i = 0; i < cells.length; i++) {\n", " if (mydiv === cells[i].element[0]) {\n", " return i;\n", " }\n", " }\n", " return null;\n", " };\n", "\n", " document.jigsaw_clear_output = function (workspace_filename) {\n", " var workspace = document.jigsaw_workspaces[workspace_filename];\n", " var cell_index = document.jigsaw_get_cell(workspace.element);\n", " var cell = IPython.notebook.get_cell(cell_index);\n", " // FIXME: brittle and ugly:\n", " cell.element[0].children[2].children[1].children[2].children[1].children[0].innerHTML = \"\"\n", " cell.output_area.outputs[2].text = \"\"\n", " };\n", "\n", " try {\n", " document.element = element;\n", " } catch (err) {\n", " // rendering\n", " }\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "output", "output_type": "stream", "text": [ "42\n" ] } ], "source": [ "%jigsaw Python --workspace workspace1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "In the above example, I pulled a print block from the Text category on the left, and a variable block from the Variables category. Snapping them together forms a valid program. I then clicked on the \"Run\" button to run the code. x got its value from the Python cell above.\n", "\n", "Let's create another workspace:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " if (document.jigsaw_register_workspace === undefined) {\n", "\n", " document.jigsaw_workspaces = {};\n", "\n", " document.jigsaw_register_workspace = function(workspace_filename, workspace, xml_init) {\n", " workspace.element = document.element;\n", " document.jigsaw_workspaces[workspace_filename] = workspace;\n", "\n", " try {\n", " $([window.parent.IPython.events]).on('notebook_saved.Notebook', function() { \n", " try {\n", " document.jigsaw_save_workspace(workspace_filename); \n", " } catch(err) {\n", " // ignore failure, might not exist\n", " }\n", " });\n", " } catch (err) {\n", " // rendering for display\n", " }\n", " \n", " var xml = document.jigsaw_loadXMLDoc(workspace_filename);\n", " if (xml === null) {\n", " xml = xml_init;\n", " if (xml === null) {\n", " xml = Blockly.Xml.textToDom('');\n", " }\n", " } else {\n", " xml = xml.children[0]; // document\n", " }\n", " Blockly.Xml.domToWorkspace(workspace, xml);\n", " };\n", "\n", " document.jigsaw_handle_output = function(workspace_filename, out) {\n", " var workspace = document.jigsaw_workspaces[workspace_filename];\n", " //var output_area = workspace.element.output_area;\n", " var cell_index = document.jigsaw_get_cell(workspace.element);\n", " var cell = IPython.notebook.get_cell(cell_index);\n", " var res = null;\n", " var data = null;\n", " document.cell = cell;\n", " document.out = out;\n", " if (out.msg_type == \"stream\") {\n", " res = out.content.text;\n", " //document.getElementById('code_output').value += res.toString();\n", " } else if (out.msg_type === \"pyout\") {\n", " // if output is a python object\n", " res = out.content.data[\"text/plain\"];\n", " //document.getElementById('code_output').value += res.toString(); \n", " } else if (out.msg_type == \"pyerr\") {\n", " // if output is a python error\n", " res = out.content.data[\"text/plain\"];\n", " //document.getElementById('code_output').value += res.toString();\n", " } else if (out.msg_type == \"execute_result\") {\n", " var str = out.content.data[\"text/plain\"];\n", " res = str;\n", " if (res.indexOf(\"u\") == 0)\n", " res = res.substring(2, res.length - 1) + \"\\n\";\n", " if (res) {\n", " //document.getElementById('code_output').value += res.toString();\n", " }\n", " } else if (out.msg_type == \"error\") {\n", " res = out.content.ename + \": \" + out.content.evalue + \"\\n\";\n", " // FIXME: out.traceback is Array of terminal color-coded [-codes\n", " } else {\n", " // if output is something we haven't thought of\n", " res = out.toString();\n", " //document.getElementById('code_output').value += res.toString();\n", " }\n", " if (res) {\n", " cell.output_area.append_output({output_type: \"stream\", text: res.toString(), name: \"output\"});\n", " }\n", " };\n", " \n", " document.jigsaw_generate = function(workspace_filename, language, insert_code) {\n", " var workspace = document.jigsaw_workspaces[workspace_filename];\n", " var callbacks = { 'iopub' : {'output' : function(out) { document.jigsaw_handle_output(workspace_filename, out); }}};\n", " var code = Blockly[language].workspaceToCode(workspace);\n", " if (insert_code == 1) {\n", " var cell_index = document.jigsaw_get_cell(workspace.element);\n", " var cell = IPython.notebook.insert_cell_at_index(0, cell_index + 1);\n", " cell.set_text(code);\n", " } else {\n", " window.parent.IPython.notebook.kernel.execute(code,\n", " callbacks,\n", " {silent: false});\n", " }\n", " };\n", " \n", " document.jigsaw_save_workspace = function(workspace_filename) {\n", " var workspace = document.jigsaw_workspaces[workspace_filename];\n", " var xml = Blockly.Xml.workspaceToDom(workspace);\n", " document.xml = xml;\n", " if (xml !== undefined) {\n", " console.log(xml);\n", " //xml.style = \"display: none\";\n", " //xml.id = \"workspace\";\n", " var xml_text = Blockly.Xml.domToText(xml)\n", " IPython.notebook.kernel.execute('%%file ' + workspace_filename + '\\n' + xml_text);\n", " }\n", " };\n", " \n", " document.jigsaw_loadXMLDoc = function(filename) {\n", " var xhttp = new XMLHttpRequest();\n", " xhttp.open(\"GET\", filename, false);\n", " xhttp.send();\n", " return xhttp.responseXML;\n", " };\n", " }\n", "\n", " document.jigsaw_get_cell = function (element) {\n", " // FIXME: brittle and ugly:\n", " var mydiv = element[0].parentNode.parentNode.parentNode.parentNode;\n", " var cells = IPython.notebook.get_cells();\n", " for (var i = 0; i < cells.length; i++) {\n", " if (mydiv === cells[i].element[0]) {\n", " return i;\n", " }\n", " }\n", " return null;\n", " };\n", "\n", " document.jigsaw_clear_output = function (workspace_filename) {\n", " var workspace = document.jigsaw_workspaces[workspace_filename];\n", " var cell_index = document.jigsaw_get_cell(workspace.element);\n", " var cell = IPython.notebook.get_cell(cell_index);\n", " // FIXME: brittle and ugly:\n", " cell.element[0].children[2].children[1].children[2].children[1].children[0].innerHTML = \"\"\n", " cell.output_area.outputs[2].text = \"\"\n", " };\n", "\n", " try {\n", " document.element = element;\n", " } catch (err) {\n", " // rendering\n", " }\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "output", "output_type": "stream", "text": [ "11\n" ] } ], "source": [ "%jigsaw Python --workspace workspace2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "In the above example, I dragged the following blocks:\n", " \n", "1. print from Text\n", "2. expression from Python\n", "3. set ... to from Variables\n", "4. sqrt(2) from Math\n", "\n", "I had to click on the set block and create a new variable named \"sqrt_two\". I also had to click on the math constant block to change pi to sqrt(2).\n", "\n", "If you click on the \"Generate Python Code\" it will create a new cell below:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import math\n", "\n", "\n", "print((myfunc(5, 6)))\n", "sqrt_two = math.sqrt(2)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you enter the variable named \"sqrt_two\" in the following cell and run it, you get as output the result from running the Jigsaw blocks:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "1.4142135623730951" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sqrt_two" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Try it out!" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.4.0" } }, "nbformat": 4, "nbformat_minor": 0 } metakernel-0.29.4/examples/Mandelbrot.ipynb000066400000000000000000000354671434565236000207340ustar00rootroot00000000000000{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Parallel Processing with Metakernel\n", "\n", "Metakernel uses the `ipyparallel` system for running code in parallel. This notebook demonstrates the process using the kernel Calysto Scheme. However, other Metakernel-based kernels may also work. The kernel needs to be able to return values, and implement kernel.set_variable() and kernel.env.\n", "\n", "Before opening a notebook, you should run the following command. This example starts 10 nodes in the cluster:\n", "\n", "```shell\n", "ipcluster start -n 10 --ip=10.0.0.190\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We then initiate the parallel communication using the `%parallel` line magic. In this example, the 10 distributed kernels will be the same type of kernel as the host kernel, namely Calysto Scheme. We call %parallel with the name of the module and the name of the class of the kernel:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "got unknown result: 834e76c8-bee8d3c516994eed98c32d1c\n" ] } ], "source": [ "%parallel calysto_scheme CalystoScheme" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To see if everything is working, we can \"parallel execute\" using the %%px cell magic:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "#10(0 1 4 9 16 25 36 49 64 81)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%px\n", "\n", "(* cluster_rank cluster_rank)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we don't want to return the results, but rather save them in a variable, use the `--set_variable` flag followed by the name of the variable. That sets the variable in the host kernel:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "%%px --set_variable results\n", "\n", "(* cluster_rank cluster_rank)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And we then have access to it:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "#10(0 1 4 9 16 25 36 49 64 81)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, we use the Metakernel `%%%` triple magic to initiate \"sticky magics\". This means that the `%%px` magic will be active for the following cells, until we turn it off. So, all of the next few cells will be sent to all of the cluster kernels. The `-e` means to also evaluate the cell in the host kernel as well:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "px added to session magics.\n", "\n" ] }, { "data": { "text/plain": [ "#10(10 10 10 10 10 10 10 10 10 10)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%%px -e\n", "\n", "cluster_size" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, we define some useful Scheme code for creating a `for` syntax:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "(define-syntax for\n", " [(for ?exp times do . ?bodies)\n", " (for-repeat ?exp (lambda () . ?bodies))]\n", " [(for ?var in ?exp do . ?bodies)\n", " (for-iterate1 ?exp (lambda (?var) . ?bodies))]\n", " [(for ?var at (?i) in ?exp do . ?bodies)\n", " (for-iterate2 0 ?exp (lambda (?var ?i) . ?bodies))]\n", " [(for ?var at (?i ?j . ?rest) in ?exp do . ?bodies)\n", " (for ?var at (?i) in ?exp do\n", " (for ?var at (?j . ?rest) in ?var do . ?bodies))])\n", "\n", "(define for-repeat\n", " (lambda (n f)\n", " (if (< n 1)\n", " 'done\n", " (begin\n", " (f)\n", " (for-repeat (- n 1) f)))))\n", "\n", "(define for-iterate1\n", " (lambda (values f)\n", " (if (null? values)\n", " 'done\n", " (begin\n", " (f (car values))\n", " (for-iterate1 (cdr values) f)))))\n", "\n", "(define for-iterate2\n", " (lambda (i values f)\n", " (if (null? values)\n", " 'done\n", " (begin\n", " (f (car values) i)\n", " (for-iterate2 (+ i 1) (cdr values) f)))))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's solve a problem in parallel! For this example, we will compute the Mandelbrot set:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "(define MAX 255)\n", "(define n 30)\n", "(define xc -0.5)\n", "(define yc 0)\n", "(define size 2)\n", "\n", "(define mandelbrot\n", " (lambda (z0 limit)\n", " (let loop ((z z0)\n", " (t 0))\n", " (if (> (abs z) 2.0)\n", " t\n", " (if (> t limit)\n", " limit\n", " (loop (+ (* z z) z0) (+ t 1)))))))\n", "\n", "(define alphabet \"@MHWRmEBSQKUGgqyp$8XDPFwdbkA&0ZTNhe9654YV*Cnsyza%3OLxo2JufIrc][vt}{71lji?|+)(=;-_!~:/,^.` \")\n", "\n", "(define ascii\n", " (lambda (i)\n", " (get-item alphabet (int (* (/ i 256) 90)))))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We need a data structure to store our results, a 2D matrix (vector of vectors):" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "(define matrix \n", " (list->vector \n", " (map list->vector \n", " (map range \n", " (map (lambda (v) n) \n", " (range n))))))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And an easy way to get/set the 2D location:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "(define mget\n", " (lambda (matrix x y)\n", " (vector-ref (vector-ref matrix x) y)))\n", "\n", "(define mset!\n", " (lambda (matrix x y value)\n", " (vector-set! (vector-ref matrix x) y value)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's get location (10, 10) from all of the matrices:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "#10(10 10 10 10 10 10 10 10 10 10)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(mget matrix 10 10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Good, they are all \"10\". Now let's set all of these locations to the string \"a\":" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "(mset! matrix 10 10 \"a\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And check:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "#10(\"a\" \"a\" \"a\" \"a\" \"a\" \"a\" \"a\" \"a\" \"a\" \"a\")" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(mget matrix 10 10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ok, good. everything is working. Let's now run some code just on the host. So, we remove the sticky magics:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "%%px removed from session magics.\n", "\n" ] } ], "source": [ "%%%px" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "How long does it take to compute a small picture of the Mandelbrot:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " ``````````````````.^^^```````\n", "```````````````````.^~..``````\n", "``````````````````.;/@^^``````\n", "````````````````...l@@@^.`````\n", "``````````````....^!@@@^....``\n", "`````````````.~^^-o/@@:,^^../`\n", "````````````..:@/@@@@@@@@/^/:.\n", "```````````..^/@@@@@@@@@@@2@,.\n", "````.````...~:@@@@@@@@@@@@@~^.\n", "```.^.......^;@@@@@@@@@@@@@@,^\n", "``..,^^/^^.^!@@@@@@@@@@@@@@@@~\n", "``..^-:!!!^^)@@@@@@@@@@@@@@@@^\n", "``..,;@@@@1/@@@@@@@@@@@@@@@@@=\n", "..^^~@@@@@@!@@@@@@@@@@@@@@@@@.\n", ".^!;@@@@@@@@@@@@@@@@@@@@@@@@^.\n", "@@@@@@@@@@@@@@@@@@@@@@@@@@@,..\n", ".^!;@@@@@@@@@@@@@@@@@@@@@@@@^.\n", "..^^~@@@@@@!@@@@@@@@@@@@@@@@@.\n", "``..,;@@@@1/@@@@@@@@@@@@@@@@@=\n", "``..^-:!!!^^)@@@@@@@@@@@@@@@@^\n", "``..,^^/^^.^!@@@@@@@@@@@@@@@@~\n", "```.^.......^;@@@@@@@@@@@@@@,^\n", "````.````...~:@@@@@@@@@@@@@~^.\n", "```````````..^/@@@@@@@@@@@2@,.\n", "````````````..:@/@@@@@@@@/^/:.\n", "`````````````.~^^-o/@@:,^^../`\n", "``````````````....^!@@@^....``\n", "````````````````...l@@@^.`````\n", "``````````````````.;/@^^``````\n", "```````````````````.^~..``````\n", "Time: 75.23063731193542 seconds.\n", "\n" ] }, { "data": { "text/plain": [ "done" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%time\n", "(for row in (range n) do\n", " (for col in (range n) do\n", " (let* ((x0 (+ (- xc (/ size 2)) (* size (/ col n))))\n", " (y0 (+ (- yc (/ size 2)) (* size (/ row n))))\n", " (z0 (complex x0 y0))\n", " (gray (- MAX (mandelbrot z0 MAX))))\n", " (printf \"~a\" (ascii gray))))\n", " (printf \"~%\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wow, that took 75 seconds on my computer. Note that this code could easily be parallelized by having each node in the cluster do a portion of the problem. \n", "\n", "Now, we execute the following cell on all nodes, but note that each node will do a different portion:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Time: 19.94576096534729 seconds.\n", "\n" ] } ], "source": [ "%%time\n", "%%px --set_variable results\n", "\n", "(define portion (int (/ n cluster_size)))\n", "\n", "(for col in (range n) do\n", " (for row in (range (* cluster_rank portion) \n", " (* (+ cluster_rank 1) portion)) do\n", " (let* ((x0 (+ (- xc (/ size 2)) (* size (/ col n))))\n", " (y0 (+ (- yc (/ size 2)) (* size (/ row n))))\n", " (z0 (complex x0 y0))\n", " (gray (- MAX (mandelbrot z0 MAX))))\n", " (mset! matrix col row (ascii gray))\n", " (printf \".\")))\n", " (printf \"\\n\"))\n", "\n", "matrix" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That went much faster, but not 10 times faster. Mostly because I really don't have 10 CPUs on my computer, so the nodes were being shared across fewer CPUs. There was also a little overhead time in collecting the results. But still, 20 seconds is much faster than 75 seconds." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Did the cluster produce the same results as a single computer?" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " ``````````````````.^^^```````\n", "```````````````````.^~..``````\n", "``````````````````.;/@^^``````\n", "````````````````...l@@@^.`````\n", "``````````````....^!@@@^....``\n", "`````````````.~^^-o/@@:,^^../`\n", "````````````..:@/@@@@@@@@/^/:.\n", "```````````..^/@@@@@@@@@@@2@,.\n", "````.````...~:@@@@@@@@@@@@@~^.\n", "```.^.......^;@@@@@@@@@@@@@@,^\n", "``..,^^/^^.^!@@@@@@@@@@@@@@@@~\n", "``..^-:!!!^^)@@@@@@@@@@@@@@@@^\n", "``..,;@@@@1/@@@@@@@@@@@@@@@@@=\n", "..^^~@@@@@@!@@@@@@@@@@@@@@@@@.\n", ".^!;@@@@@@@@@@@@@@@@@@@@@@@@^.\n", "@@@@@@@@@@@@@@@@@@@@@@@@@@@,..\n", ".^!;@@@@@@@@@@@@@@@@@@@@@@@@^.\n", "..^^~@@@@@@!@@@@@@@@@@@@@@@@@.\n", "``..,;@@@@1/@@@@@@@@@@@@@@@@@=\n", "``..^-:!!!^^)@@@@@@@@@@@@@@@@^\n", "``..,^^/^^.^!@@@@@@@@@@@@@@@@~\n", "```.^.......^;@@@@@@@@@@@@@@,^\n", "````.````...~:@@@@@@@@@@@@@~^.\n", "```````````..^/@@@@@@@@@@@2@,.\n", "````````````..:@/@@@@@@@@/^/:.\n", "`````````````.~^^-o/@@:,^^../`\n", "``````````````....^!@@@^....``\n", "````````````````...l@@@^.`````\n", "``````````````````.;/@^^``````\n", "```````````````````.^~..``````\n" ] }, { "data": { "text/plain": [ "done" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(define portion (int (/ n cluster_size)))\n", "\n", "(for row in (range n) do\n", " (for col in (range n) do\n", " (let ((vec (// row portion)))\n", " (printf \"~a\" (mget (vector-ref results vec) col row))))\n", " (printf \"\\n\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Great! " ] } ], "metadata": { "kernelspec": { "display_name": "Calysto Scheme 3", "language": "scheme", "name": "calysto_scheme" }, "language_info": { "codemirror_mode": { "name": "scheme" }, "mimetype": "text/x-scheme", "name": "scheme", "pygments_lexer": "scheme" } }, "nbformat": 4, "nbformat_minor": 2 } metakernel-0.29.4/examples/Processing Magic in IPython.ipynb000066400000000000000000000161071434565236000237120ustar00rootroot00000000000000{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Processing in IPython\n", "\n", "This notebook shows the ability to use the Processing library (based on Java). There is also a full [Processing kernel](https://github.com/Calysto/calysto_processing) that does a Java-compile (showing any errors) with additional benefits. This magic does no error checking.\n", "\n", "Requirements:\n", "\n", "* IPython/Jupyter notebook\n", "* [metakernel](https://github.com/Calysto/metakernel)\n", "* Internet connection\n", "\n", "First you need to install metakernel:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "! pip install metakernel --user" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, you should enable metakernel magics for IPython:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from metakernel import register_ipython_magics\n", "register_ipython_magics()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, you are ready to embed Processing sketches in your notebook. Try moving your mouse over the sketch:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%processing\n", "\n", "void draw() {\n", " background(128);\n", " ellipse(mouseX, mouseY, 10, 10);\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This example from https://processing.org/examples/clock.html :" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%processing\n", "\n", "int cx, cy;\n", "float secondsRadius;\n", "float minutesRadius;\n", "float hoursRadius;\n", "float clockDiameter;\n", "\n", "void setup() {\n", " size(640, 360);\n", " stroke(255);\n", " \n", " int radius = min(width, height) / 2;\n", " secondsRadius = radius * 0.72;\n", " minutesRadius = radius * 0.60;\n", " hoursRadius = radius * 0.50;\n", " clockDiameter = radius * 1.8;\n", " \n", " cx = width / 2;\n", " cy = height / 2;\n", "}\n", "\n", "void draw() {\n", " background(0);\n", " \n", " // Draw the clock background\n", " fill(80);\n", " noStroke();\n", " ellipse(cx, cy, clockDiameter, clockDiameter);\n", " \n", " // Angles for sin() and cos() start at 3 o'clock;\n", " // subtract HALF_PI to make them start at the top\n", " float s = map(second(), 0, 60, 0, TWO_PI) - HALF_PI;\n", " float m = map(minute() + norm(second(), 0, 60), 0, 60, 0, TWO_PI) - HALF_PI; \n", " float h = map(hour() + norm(minute(), 0, 60), 0, 24, 0, TWO_PI * 2) - HALF_PI;\n", " \n", " // Draw the hands of the clock\n", " stroke(255);\n", " strokeWeight(1);\n", " line(cx, cy, cx + cos(s) * secondsRadius, cy + sin(s) * secondsRadius);\n", " strokeWeight(2);\n", " line(cx, cy, cx + cos(m) * minutesRadius, cy + sin(m) * minutesRadius);\n", " strokeWeight(4);\n", " line(cx, cy, cx + cos(h) * hoursRadius, cy + sin(h) * hoursRadius);\n", " \n", " // Draw the minute ticks\n", " strokeWeight(2);\n", " beginShape(POINTS);\n", " for (int a = 0; a < 360; a+=6) {\n", " float angle = radians(a);\n", " float x = cx + cos(angle) * secondsRadius;\n", " float y = cy + sin(angle) * secondsRadius;\n", " vertex(x, y);\n", " }\n", " endShape();\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Try it out!" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.4.0" } }, "nbformat": 4, "nbformat_minor": 0 } metakernel-0.29.4/examples/SAS_metakernel_example.ipynb000066400000000000000000003542521434565236000232110ustar00rootroot00000000000000{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# SAS produceses two streams of output\n", "\n", "1. Log\n", "2. Listing\n", "\n", "The new method of `Error_display` allows SAS to return the error message with context and the listing output that might be related or unrelated to the code submitted.\n", "\n", "Prior to this method it wasn't possible to flag the cell as having an error and also display non-text objects.\n", "\n", "See the code examples of the four cases below:\n", "\n", "The data is shipped with every SAS installation.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## SAS code with no errors and no listing" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "SAS Connection established. Subprocess id is 90425\n", "\n", "\f", "7 The SAS System 12:47 Wednesday, August 19, 2020\n", "\n", "34 ods listing close;ods html5 (id=saspy_internal) file=_tomods1\n", "34 ! options(bitmap_mode='inline') device=svg style=HTMLBlue; ods graphics on /\n", "34 ! outputfmt=png;\n", "\u001b[34mNOTE: Writing HTML5(SASPY_INTERNAL) Body file: _TOMODS1\n", "\u001b[0m35 \n", "36 data class;\n", "37 set sashelp.class;\n", "38 id = _n_;\n", "39 run;\n", "\n", "\u001b[34mNOTE: There were 19 observations read from the data set SASHELP.CLASS.\n", "\u001b[0m\u001b[34mNOTE: The data set WORK.CLASS has 19 observations and 6 variables.\n", "\u001b[0m\u001b[34mNOTE: DATA statement used (Total process time):\n", " real time 0.02 seconds\n", " cpu time 0.01 seconds\n", " \n", "\n", "\u001b[0m40 /* proc print data=class;\n", "41 run;\n", "42 proc means data=class;\n", "43 run; */\n", "44 \n", "45 \n", "46 ods html5 (id=saspy_internal) close;ods listing;\n", "47 \n", "\f", "8 The SAS System 12:47 Wednesday, August 19, 2020\n", "\n", "48 \n" ] } ], "source": [ "data class;\n", " set sashelp.class;\n", " id = _n_;\n", "run;\n", "/* proc print data=class;\n", "run;\n", "proc means data=class;\n", "run; */" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## SAS code with no errors and listing" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "SAS Output\r\n", "\r\n", "\r\n", "\r\n", "
\r\n", "
\r\n", "

The SAS System

\r\n", "
\r\n", "
\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "
ObsNameSexAgeHeightWeightid
1AlfredM1469.0112.51
2AliceF1356.584.02
3BarbaraF1365.398.03
4CarolF1462.8102.54
5HenryM1463.5102.55
6JamesM1257.383.06
7JaneF1259.884.57
8JanetF1562.5112.58
9JeffreyM1362.584.09
10JohnM1259.099.510
11JoyceF1151.350.511
12JudyF1464.390.012
13LouiseF1256.377.013
14MaryF1566.5112.014
15PhilipM1672.0150.015
16RobertM1264.8128.016
17RonaldM1567.0133.017
18ThomasM1157.585.018
19WilliamM1566.5112.019
\r\n", "
\r\n", "
\r\n", "
\r\n", "
\r\n", "
\r\n", "

The SAS System

\r\n", "
\r\n", "
\r\n", "

The MEANS Procedure

\r\n", "
\r\n", "
\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "
VariableNMeanStd DevMinimumMaximum
\r\n", "
\r\n", "
Age
\r\n", "
Height
\r\n", "
Weight
\r\n", "
id
\r\n", "
\r\n", "
\r\n", "
\r\n", "
19
\r\n", "
19
\r\n", "
19
\r\n", "
19
\r\n", "
\r\n", "
\r\n", "
\r\n", "
13.3157895
\r\n", "
62.3368421
\r\n", "
100.0263158
\r\n", "
10.0000000
\r\n", "
\r\n", "
\r\n", "
\r\n", "
1.4926722
\r\n", "
5.1270752
\r\n", "
22.7739335
\r\n", "
5.6273143
\r\n", "
\r\n", "
\r\n", "
\r\n", "
11.0000000
\r\n", "
51.3000000
\r\n", "
50.5000000
\r\n", "
1.0000000
\r\n", "
\r\n", "
\r\n", "
\r\n", "
16.0000000
\r\n", "
72.0000000
\r\n", "
150.0000000
\r\n", "
19.0000000
\r\n", "
\r\n", "
\r\n", "
\r\n", "
\r\n", "\r\n", "\r\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "data class;\n", " set sashelp.class;\n", " id = _n_;\n", "run;\n", "proc print data=class;\n", "run;\n", "proc means data=class;\n", "run;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## SAS code with errors and no listing" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\f", "11 The SAS System 12:47 Wednesday, August 19, 2020\n", "\n", "68 ods listing close;ods html5 (id=saspy_internal) file=_tomods1\n", "68 ! options(bitmap_mode='inline') device=svg style=HTMLBlue; ods graphics on /\n", "68 ! outputfmt=png;\n", "\u001b[34mNOTE: Writing HTML5(SASPY_INTERNAL) Body file: _TOMODS1\n", "\u001b[0m69 \n", "70 data class;\n", "71 set sashelp.class;\n", "72 id = _n_;\n", "73 foo = bar;\n", "74 run;\n", "\n", "\u001b[34mNOTE: Variable bar is uninitialized.\n", "\u001b[0m\u001b[34mNOTE: There were 19 observations read from the data set SASHELP.CLASS.\n", "\u001b[0m\u001b[34mNOTE: The data set WORK.CLASS has 19 observations and 8 variables.\n", "\u001b[0m\u001b[34mNOTE: DATA statement used (Total process time):\n", " real time 0.01 seconds\n", " cpu time 0.01 seconds\n", " \n", "\n", "\u001b[0m75 /* proc print data=class;\n", "76 run;\n", "77 proc means data=class;\n", "78 run; */\n", "79 \n", "80 \n", "81 ods html5 (id=saspy_internal) close;ods listing;\n", "82 \n", "\f", "12 The SAS System 12:47 Wednesday, August 19, 2020\n", "\n", "83 \n" ] } ], "source": [ "data class;\n", " set sashelp.class;\n", " id = _n_;\n", " foo = bar;\n", "run;\n", "/* proc print data=class;\n", "run;\n", "proc means data=class;\n", "run; */" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## SAS code with errors and listing" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " \n", "\n", "94 proc means data=class;\n", "95 foo = bar;\n", " ___\n", " 180\n", "\u001b[1m\u001b[31mERROR 180-322: Statement is not valid or it is used out of proper order.\n", "\u001b[0m\u001b[0m96 run;\n", "\n", "\u001b[34mNOTE: The SAS System stopped processing this step because of errors.\n", "\u001b[0mNOTE: PROCEDURE MEANS used (Total process time):\n", " real time 0.00 seconds\n", "\n" ] }, { "data": { "text/plain": [ "None" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "SAS Output\r\n", "\r\n", "\r\n", "\r\n", "
\r\n", "
\r\n", "

The SAS System

\r\n", "
\r\n", "
\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "\r\n", "
ObsNameSexAgeHeightWeightid
1AlfredM1469.0112.51
2AliceF1356.584.02
3BarbaraF1365.398.03
4CarolF1462.8102.54
5HenryM1463.5102.55
6JamesM1257.383.06
7JaneF1259.884.57
8JanetF1562.5112.58
9JeffreyM1362.584.09
10JohnM1259.099.510
11JoyceF1151.350.511
12JudyF1464.390.012
13LouiseF1256.377.013
14MaryF1566.5112.014
15PhilipM1672.0150.015
16RobertM1264.8128.016
17RonaldM1567.0133.017
18ThomasM1157.585.018
19WilliamM1566.5112.019
\r\n", "
\r\n", "
\r\n", "\r\n", "\r\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stderr", "output_type": "stream", "text": [ "\u001b[0;31mERROR 180-322: Statement is not valid or it is used out of proper order.\n", "\u001b[0m" ] } ], "source": [ "data class;\n", " set sashelp.class;\n", " id = _n_;\n", "run;\n", "proc print data=class;\n", "run;\n", "proc means data=class;\n", " foo = bar;\n", "run;" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\f", "15 The SAS System 12:47 Wednesday, August 19, 2020\n", "\n", "104 ods listing close;ods html5 (id=saspy_internal) file=_tomods1\n", "104 ! options(bitmap_mode='inline') device=svg style=HTMLBlue; ods graphics on /\n", "104 ! outputfmt=png;\n", "\u001b[34mNOTE: Writing HTML5(SASPY_INTERNAL) Body file: _TOMODS1\n", "\u001b[0m105 \n", "\n", "\n", "106 proc means data=sashelp.class;\n", "107 var gender;\n", "\u001b[1m\u001b[31mERROR: Variable GENDER not found.\n", "\u001b[0m\u001b[0m108 run;\n", "\n", "\u001b[34mNOTE: The SAS System stopped processing this step because of errors.\n", "\u001b[0m\u001b[34mNOTE: PROCEDURE MEANS used (Total process time):\n", " real time 0.00 seconds\n", " cpu time 0.00 seconds\n", " \n", "\u001b[0m109 \n", "110 \n", "111 ods html5 (id=saspy_internal) close;ods listing;\n", "112 \n", "\f", "16 The SAS System 12:47 Wednesday, August 19, 2020\n", "\n", "113 \n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\u001b[0;31mERROR: Variable GENDER not found. None\n", "\u001b[0m" ] } ], "source": [ "proc means data=sashelp.class;\n", " var gender;\n", "run;" ] } ], "metadata": { "kernelspec": { "display_name": "SAS", "language": "sas", "name": "sas" }, "language_info": { "codemirror_mode": "sas", "file_extension": ".sas", "mimetype": "text/x-sas", "name": "sas" } }, "nbformat": 4, "nbformat_minor": 4 } metakernel-0.29.4/examples/Tutor Magic in IPython.ipynb000066400000000000000000000046441434565236000227160ustar00rootroot00000000000000{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutor Magic in IPython\n", "\n", "This notebook demonstrates the %%tutor magic as used in IPython notebook.\n", "\n", "First, you'll need the following installed:\n", "\n", "1. IPython/Jupyter\n", "2. [Metakernel](https://github.com/Calysto/metakernel)\n", "\n", "Next, you'll need to use the magics in IPython:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from metakernel import register_ipython_magics\n", "register_ipython_magics()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, put a %%tutor at the top of any cell with Python code, and watch the visualization:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%tutor\n", "\n", "mylist = []\n", "\n", "for i in range(10):\n", " mylist.append(i ** 2)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Try it out!" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.4.3" } }, "nbformat": 4, "nbformat_minor": 0 } metakernel-0.29.4/examples/echo_kernel.ipynb000066400000000000000000000132411434565236000211050ustar00rootroot00000000000000{ "metadata": { "kernelspec": { "codemirror_mode": "python", "display_name": "Echo", "language": "python", "name": "echo_kernel" }, "name": "", "signature": "sha256:3c92219980d36116204e8b00f5019c7bce7eeaf931e3047f17f280334b5d8e7f" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Echo Kernel: Simple Text Echo Wrapper Kernel" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Installation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Install the echo kernel by running `pip install .` from that directory.\n", "Then run `ipython notebook` from this directory.\n", "Select \"Echo\" from the top right dropdown list of kernels." ] }, { "cell_type": "code", "collapsed": false, "input": [ "Hello, world!" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 1, "text": [ "u'Hello, world!'" ] } ], "prompt_number": 1 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Magics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Like all of the Metakernels, the echo kernel comes with a base set of magics." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%magic" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Line magics:\n", " %cd PATH - change current directory of session\n", " %connect_info - show connection information\n", " %download URL [FILENAME] - download file from URL\n", " %html CODE - display code as HTML\n", " %install_magic URL - download and install magic from URL\n", " %javascript CODE - send code as JavaScript\n", " %latex TEXT - display text as LaTeX\n", " %lsmagic - list the current line and cell magics\n", " %magic - show installed magics\n", " %plot [options] backend - configure plotting for the session.\n", " %python CODE - evaluate code as Python\n", " %reload_magics - reload the magics from the installed files\n", " %shell COMMAND - run the line as a shell command\n", "\n", "Cell magics:\n", " %%file [--append|-a] FILENAME - write contents of cell to file\n", " %%html - display contents of cell as HTML\n", " %%javascript - send contents of cell as JavaScript\n", " %%latex - display contents of cell as LaTeX\n", " %%python - evaluate contents of cell as Python\n", " %%shell - run the contents of the cell as shell commands\n", " %%time - show time to run cell\n", "\n", "Shell shortcut:\n", " ! COMMAND ... - execute command in shell\n", "\n", "Any cell magic can be made persistent for rest of session by using %%% prefix.\n", "\n" ] } ] }, { "cell_type": "code", "collapsed": false, "input": [ "%python print('hello, world!')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "hello, world!\n" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can get help on a magic by typing `?`" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%%html?" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also get help by pressing `SHIFT+TAB` at the end of the word." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%lsmagic" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Code completion works for magics. Press tab below to see the completion (when not viewing through nbviewer)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%javas" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Completion also works for path names (local, absolute, or from the home `~` directory). Press `TAB` below for completion." ] }, { "cell_type": "code", "collapsed": false, "input": [ "echo_kernel.ip" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "%%file temp.txt\n", "This concludes our example.\n", "Goodbye, world!" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Created file 'temp.txt'.\n" ] } ], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] } metakernel-0.29.4/examples/processing1.html000066400000000000000000001143131434565236000207110ustar00rootroot00000000000000
metakernel-0.29.4/examples/processing1.xml000066400000000000000000000026521434565236000205470ustar00rootroot00000000000000setup60040drawi1101MULTIPLY30i102020metakernel-0.29.4/examples/workspace1.html000066400000000000000000000327571434565236000205460ustar00rootroot00000000000000
metakernel-0.29.4/examples/workspace1.png000066400000000000000000000660661434565236000203660ustar00rootroot00000000000000‰PNG  IHDRj¹p|PôsBITÛáOàtEXtSoftwaregnome-screenshotï¿> IDATxœìÝ{|›y}'ú¯®lI­Dr’±fRüÌäb‡.2dØ3šv¥e£¡§Q¶!ʶ'†e­¾Zì–bÓs°–¶Î«íØdù¼–(í§eGyˆ€nL;ÀØ3öÜìa2òä"9¶I–]ÏOâø˱%Yþ¼ÿàe?—Ÿ~ æÃ÷w“är9Øi±;; â#äñò€øy¯sïìÙ³ëʼn'òzÕG€ÝëÈ‘#ù¾²^õQ”o €afffo¡úy@|€< >@ ˆÄGÈâ#äñò€øy@|€<ÜÿГ““Û× "™LVì.@9Èd27oÞ Wœ&޳ûù-nw¢ÛÂqöÐ7 «(ƒSg˜úÆF [Ë»»AÄG£Íã³»»D)Í} yOÛ-&Žã8S£ýtï• °pO^éuÙMÇ™­În¿ÿt#géhÅàµ0æï¼ó$g¶:;ý‹Z€T2ÕÇßem P㱎ç,u4èïöîö{íF"þJ»ýøEÞ|´£Çª†/t·¶†‰jW¶"Lô:žñŒÖZÛïs×3DÔÜÒÈ9¬îá•ÍðCžžQec÷@¯Ý@DÔÔT²;#|K3ò#À(Ákabp8L&‡»·†³9Íö…à°’jmöú…›F뱆U›ñ$©Þa1ܽÂÔwø‡dG€-Rñ‘„OÄÖ.Iy¬žUÏóä‰Xãâ¥Õ «×®Ò áIiÐ#,l—Òˆ k`‰ø©%[Bòa>I,Ë2¬‘%âƒü¢%0ެÒ«g)ɇ¯•áÇ®\Áê€-Rñ‘ŒÖF=ûü÷r^Ðï%eƒÕÈmu4Xt34xad•VÎÚ ¤‘Á{[ˆOøZï`Oq€­Qð¥3Á˽ÞañÖd³75¸;¬VÝr³ÖÑTàBwÿ¨²±³­™%b퇽ÇûN¡ã¤UèéL®Ö8ÛÔæ6ºZ§ƒ­v³6<ØßÓ7©?|În,Ì—ƒÝ"òSzÍUìN”°ü´Ø=€mTðø¾Ô×uiÉía³­É`°õ´½g¼§ú“¤¬5[O>çnmsÛìxÎÐáñ¹÷“¶Îêènt{³ü¨†sú.º»zz[Gˆô&kÛ¹NVÎl•ÆG¦Ù;>±Þ†f×™æÕJ:üˆ?ªuzî;„‘öRÖ› DDœ{pÂ}ïa†³uxm[ÕkX¬Dö}¼Ð@û©AãáöV›IÏðSƒº/„knBUq#^|çÍÉÛ7fâ1"šŽñ÷}~1 SñlC3«ªÜž®]› ÿóÏ”̤·ï#¶Ü#²·>½$%mGÄG¶¥Ç×Ùíñö´^Œ‘¶¶ÑÚ~ÞílX>t ‹}çµ^¹5%¤S2ɽRRI~‹¥æ“Âׇ¾Ó`¬ûø£ïßê ¼ü£_Þ¾µ‰Ž—D")vŠfGÄG"¶ÁÑåst»;Äßÿ·_ŽÉ¥2"³c22)"ЧR™lfãM4Ur©ltêÍWnMýîSÝÂ2äµ™ð?½ôoâÏñ¤0›ˆmUËPÉD¨¢Ø(’acfçcg¯~G*‘ŠÙq6åñ¨³ã&„bsTª+4‰T²oè;OmQr¡èHD×ùÛ7"3Þf!é2Ú»übJPÌÜÚuó)t5¼‚Ùäß.Ø¡ËÇOƒo|ÿ—ÄrcD˜Ÿš»O=è~é™löÍÛ7«Uчu†-)C.+:¾5zðN–ˆ™[ìw¿ùáb÷¢Ð>qäG5O»PPˆeâŸ_š¼}C&‘¦³™·gB[;<›ˆEnƼ ¹Ó‹Ž@ˆåá‡oŽOÞ¾ADñ¤ðæí››ª^Ç–!˸è°Û >îx¯†Þùá[ã2‰4ž^Ÿ~'“Ínßgm® ‰¢#@9A|Üñþåç?–Keélf»³£(¯2$ŠŽåñqgû§(.²~óöÍdÇ+ËÕj™tÉÞ™l–OÌ‹?£èP6w°ÙùØ/gnI%’[ѹ¨/ð§/+C.$Åev\ÑÑ ˆ}¤êMñçPJýÊ|M(¥.n—J âãv镟J%’t6s#r»X}ËFV¯ËVÞ ‰UtüŒágŸÚóÚ²‹ãó5ß=õVB·µŸÅh*MÉm>.DãBtõÿ' *`|®8ÍÇë{Fl»noåíœ Ë¥2>>_Èaë•2Ùì[³·ŠØ­òŇ¿gª\勘*o}åà·¿}ûñ‹·ŸœÏ(ðSMemÃãÕ÷É•Šlj›¤“©Ù·nN¼† «Bõq§z5ôŽ8ëñVl®Ø})Ÿ©ùÙªÙqÁ§ö¼öíÔ×o4ŽÏïÛô§Ô6<^Ûðø¦_/ ¹R¡̨Ì85òÚÔÈòZ,€ôþ@Izé7‰(™Ní i…%ËTyóSºûç$ƒ"öŇ¿ÿÃÏÔÒUvÖ¼\qŽáRu1—~v\¬¶áñº˜‹Ý (9¥CCÞÓv‹‰ã8ÎÔh?Ý{%¸(ñ#¾v‡ÕÌqÇ5Úœþ‰;7…±N g>íóµ‰ïšm§{¯„î¾'/w;mœØªÍuïÅ.#¢íØ!¼ô)¶ú¯­…}sãjÏkŸ«ýA¾q°ñ=úÇŒù¾UtúÇŒµO=Qì^@i)™øò»¬Ïv 2ÖŽçÎ®ÃÆ zŽÛ\A""⯴َt ðæÖžsçÏuÛý­-ï½ ¹ÔÑ=eíŒ ¸Mãžãöö!žˆ„±nÇ©¾‰:×sçÏŸ?籆ú[#å £É8E…D±;²6Õû¾âøÂ7_øÆ§ó}[5ÍOe´}äw¿ønÝN¬”%–Z?ˆ™pÕZ·Må¾÷¼ëÁ?¢(jÍ1šMqe©Dæ> CÝH]Ûe¯‹cˆˆšZ¶–®Îî!뙦PoÇÅ)ýÑó]MâÍfK½ÓÒÚݰùî,ÃÑ>ÝÓëjb‰¨ÞÞÕ31üLŸÇïpÐèðÕµµ:[8"¢¦½¡g!ˆ)ÖWÝ*’Q*“)vG Goü¤û×ÞûŒÞ™ÞÊfë+V™ò8bß{øÉ¦×ÌFë»3¡5—„Õ>µ“ƬWª}êñÉÁÑb÷JEiT…‰Áá0™6î^ªãlN3E†ýA!8<8Eµ6Gý›˱ferda ZÙ`oXøw7ÃYõ4ãÉ`¶ÔѤÇns¶uû.MP“³Ãíh(‡•ß™\1W[ƒ¬êÀ»Zew õîÊ›+/¾9öð+/Ô}ëï?þê ªÞz{olnÍ]õ#›_mS vzÿ`k•F|$!ıµKb«g•Äó< Aˆ5²‹ † «g)Éówâ#£_v—!â#1õîovk¢±‹}§žmià,Îî{#w2…LND Ù6ä©­’¼þí_\}þWŸùçï”p‘ô ³ÊΔâ:˜¤ øÙ•÷~„ûŒ–¿<´f}‘Ý¿·d÷èÙ ¹RQ¹wÍ¡yØmJcðša ,?ÅÝK|˜O˲Ä">È/rø)ž”ìÝÐ ‡ßå§B¤äô Û`ïèµwèïîï;ÞÊ ù솂}»]+úÁ‹; ªë«ìn8së^ZºÔëï?þÔGQWÿöª-¼ú»nõÛÕ¿Ò W”ÆÿV@ (‘ê£ÑÚ¨§qßâUÑA¿o”” V#ch´ÔÑTÀ7vïfh°(I Ö…Áî¡ ƒ A…¿Ò?”¤{=+ŒuÚÌ®Ë<1†úf{G§ËDœ•ÃâØElÙ•¿ü0˜¤ úŽù{ÿt(8±Ù­—üøÏ®¼wö³”{ðN]y| د(/÷zCK*¬ÉfojpwX­»3ä>f­£©À…îþQecg[3KĺÚû_pØ·ËfÒ†G/ôx“¦“í6‘“ƒ­öÓA·­Ž&ý=ž@ÄÔÖn5ÃÚÌlÿ·³3|ÒZÇòSþžqª;¹xŽå®'5|Æö~JC”|å+ߺ4.3~Òüá<¤”Q2~kâú/žùÅ—bˇŸ+9úõ÷½ñoó¥ëì¯à‡>T-£düöÄõÿÇÕ®)ß÷•ÃÖƒD”y£ûâ·^J-ý¸øÏ¿ò­ïŒ“îïþð§Þõ0W¥VQ&öNøíŸ½~õùk¡E%A¦©åÿpQuï!óq¯™ˆè­«g¿øÿ ß¾R–\yq­YŒ7ƒú›A½ºj^gàuú¹X¤òfp½)yˆþèsÇN_š!"R¾ÿÏþ÷_>³¼:ž|ÙóYç×ß&"ÒþÚW¾óåO¢|ÅRðø¾Ô×uiÉía³­É`°õ´½g¼§ú“¤¬5[O>çnm7Êc›=þóõg¼Ý­“¤Ô›šu÷¶Úëï…@s[·y¸§íÔTR[g9ÚÝão2 ]¾sl—g óT’H[Ûhm?ïvÖ#=®ªR÷«_´XL‹ŽåSVÔ˜êjLuOýôê·þöÐê‹e{~Ýò;Ç÷Éï¾²ÇTÃnh®ûž?°|êfqSê‡ö½û¡}ïþõ›ÿú•}áÚö¯Zuâãúbs•±¹ÊàËËDóá/»mÃì%_üÚŸþë¡ç>¶x4\=û'bv$]ËWÝëgÇÄôw¾?1•ÇŸªñ£ï{æþÏQAã#ÓìŸXïC³ëL³k›l“ÓÓäô¬ù²ÑÚá²w¬v£ÙÝÛìΣŸ»–òáÏ|ìÝÅÞx땟†yRøàÁw?ZADUüÐï|.ó?xP9õæ*eÕU)÷=ò(²#äÓáaÚ #оò7ÿûÛCü¡jÿè>òkŸ>ù°šHõþ}¢éúÅ¡û”ÚC”~kò_ÿñõ·g©êуÒä­ûo–(«y´‚(úƹ~ûûÓwæ¢*T¿rØò›ÏèåDdxìC¦—Å!ïLøú«? §ÿ°ç§ßzs¦ìÎÛÑ6þÁ_üÇŸœü‡¢Øå?ý[{ã}€%¢èÏ<ݧˆˆ¨öðû²Y{߆¤{¹‡kßÚ`RÕ`ªF5òQ"Kg 4dÞ>·(;eg~ðÃç爈Hö®O?aXuT:ôúÀW†^zizæÚô/¿ÿÂw¿?»±}z2oö}ï[ Ù‘ˆR‰_þãÐÞ‘ø[ÂÛmÍÚÚ×Qøò—ü‹kâOš_yte‚‰_#¾‰K_®¶'+¼sw||Ãaió «múXTÚÆ?ø‹ßyyûÿýÌŸùÃDDôþÿü'Í+èm ©Ü÷ð(=@ÞaÁíñ•¥GQ’ëN@TT¯PN\of‰´ðN2½ÚõÌÝL)/À_ÏPj+¶ÝÙZÊ'ÛÚÖ.¾ðþ?ûkû¯äÛŒt/÷ðþõþUï3éPz€ü!>Â]ÉØÜš÷¡;ÁRV¥\> œL&6µŠ%*á“ ‹‹©ÿìW?ºPâ [(ìïþóï.ZT”|ñkôü;›jJµ·ñà*‹åe(=Àæ!>Â]²=*ÖÈ{Þ9šcÅé…åGÉsOÉÐwþü~’$"R7ÿ?í6=Qòê_ÿÉ…›iMº—3®(@ªPz€ÍC|„U‡¬¾ý‘¾æ=ÅŸfÞxcŶáåGgx s´Èíçÿè¯~œ$"Ò|âólÿØîN‚üùŸvù65„½¢‰Ò#<ÄG¸ç`ý‡Þ·r¤Sa|Æüøã¯¿.pŸV£PlÙ~ãóûòz^ɤêêƒM-#ÿíYžùI]ýæ&%®å®ÿû)""å¯þñ—?¦'ÒZþàKŸgžŽÿåç~¹‰F— •(=Àƒ)`|†N›9Žã8û@hÅÍßaâ8޳­ro%~¨÷´³sD "Æ:-g÷¯^TF*Þû¹O|ô}ªEWT¿òéÙ?.Ž\G_üÇÉbþ1ÏÇîL»¬Úw j;?¨ºf•5èJ&õä¡×~ã?}·é“#uï î3N½ÑôÉ‘ÿì•­ì~çÏÿôÅ$‘â_þÜ' âÕ=ýòç‰ ¨_ü»/õ_Ö|M‹ 2ÃA”àÁ£ú8ê ,/Ù„}ÃÉ 7 Œôy.!/n¥îîî/}ä“Î_ýÄg?rôoÛŨ‰n=ÿÃŒofÇ­’™‹òâ_¥Þú×G\õ[¿ÿ¥'t«¢˜—k‰êeW”LzY"Üg ÿûg¯<Ùôª’Y¾rHWÃä7~òÀ½ º1ðGõ3ñ ~èþ̾ÿÞÃÇþøËïäÏ¿Ò=0±ñTî’îåŒû‰ˆ” ïAéPÁãc­¥–Æ}Ëòc0àVÖÕàXGìÇ£?‡ˆHýèÃïýøcï·<üÐ`û¾û?ÿqzu¯­4ëg/-$'¥ÚPQõÈ=cÙUÚ¨yxúÎç0©§šþñßþ±ºjÍ£uö§ßýÔäƒõâ Ý_»*FVÓùê3-½ûÝý‡ïÿËÏü2ÿÿ&T{Q*Qz€-Pðøh´:Í4î L,º øFõV‡Ù°èš0áïtÙ-&Žã8Ž3[ícQÐk«?>H¾x¤ž³yïæP~È{ÚÞÈqg²ØÛ|å_›Ìd·¼˜ž»ùÝ/~ë_þaòíÐÝyÒ³soŽþKÛ·þ§ÿV‘³#Qbâo/û{7çîîi“ž'Õƒ3>_³òâ¾Ú0Ý-:¾û©7ïÛÈæ5㣔$÷}=øüŸÜ¶¦Çÿ«Û¾Ê&áûí_ýýÇïtø¿ÿÉ&†°¥{Mµ<¹éÒãF¾ì[¶a£½ÅÑH­¾À„“ãÄK~߸ÞÚnbFž ù]¶ÖAãÓížÓ&=…'ÞÎ nÕºŒöÞç™Ög:&¬=¾6³ÑHA"¢ÑŽS!ëÉÖž“,?èí¼Ðá ºaOSyÒå¶£ÑTlÂ?4áßÀ“ó×.|Ʒ¾è{iùÅlèÿëkßXï5aèò׆Öêÿ ï÷~áÝ@÷6n<¾èË.¹Õ5ü>ãôQWÅu5s3·69'ÓøLÿëϬÿÃõ½~tsÍ‹êšÍ×jÓ)ì÷ w<>c°8,ÊÖ —›#"šðMÖÚzêÙ…gø±!³´÷œqŠ ³©ÙÄ·xFÇCÔ`d\-KÄhk9ÎÈX…Q6ö ôÚ DD-fmîLMõå‰H&]s§oØ ñù}óYE¥tÉdGuU|ÑêUé üªñ‘¿1I¦e+{ÜA2ÉôüôÚGZÀ.S„¥3 k9Ú¤œô‹ƒÑ˜Ï?Uçp,Izls—Ïïurć&Ɔ®ø}½½ ‘À¯9bÇÙî }êŒJâCe>|­QVQ…âÁçþ}ûöãy=Œ¬²A¦Z;¿Öó3×6µåwÉØéý€­U”ŠÛt¬YyÜ?0ÑZÏùüS&—#[ô„¼ÜÓáñN&‰HYkjà˜õ ‰ »ú†×åëàžšWnµL¥L*݆y»ËxîS{^[V€\U")ï»Þ•2_Ô~Ù­u¶ï™zá5ý£«LhÜ)¦^x­Ø](¨l6›Ífs¹åóÄÒéôììììì¬N§Û»wo^m*ʨâSœmÃÙ¦cVí”ß7Æùa“úô߬ÂXóTßÁùÜóWF&&Æý¾v«a¶v«¨Va-íƒ ¥Ô_¿ÞtßÇ^ í?}í7’xdÕ»ëœU#Dç§F_ß|ÿŠjjôu!ºfa ,I¥R¹\®XA.—K$™L–ÍfWÞ]_±¿ÓV*Ò©3LƒÃª ¼¾¾ov.KÄN’ÖÖÖÚRo‹ŠÁáÀ’…­Œ’J`!pQíÓV‹«göT">nŸF_¿±f‚¼Sõ¼õkžÛ›Ïlr{©©^ ¿±µGÔBøàÔ ¯»Å·¬¹ðs.—[Y¤,{Å:´ipØôáKž€Ðà´,/,²&³ž"~OhlläÊ@·ÓÑ9JDBHC#«e)2ØçõùGÊ|†ãºêö " S¡a*ŠÝ—r08÷®¿žúH8µd/ ·ç«¾~£étð·Ö*:nÜäàèΪAN¾>98zÿçÊ×B4”H$Ùl6•J¥R©\.—N§AÈd2‰D"‘,~r7(ÚjP¦Þa«½Ðj:¶"=ÓÐáí:z¼­Ïö‘Roj¶·ûÛ&]ÏxFÇyª7SïrY‡»žŽ‘Ã&‹³Ý/ ¿õdÓW¿? —Éhu¯ ù-¾çþ;éì"?5TÍTJ“Dô– Ût¹qUS/¼~ííÚ§×îßËhJ4ô ÑxäÆôÔ ¯aÌ@"‘¤ÓéH$2??ŸL&Óét2™Ìf³Éd2•JÉår†a*++Õjµ\.'¢\.'¦Éò&Y',Ÿ={–ˆNœ8!þ:9ù€çjÀ}ÔÕÕåûÊw_ñÅwÞ$¢ëüí‘™mè¬ÂTyó‹/_:sëí½ßýæ‡7Þˆ\©¨ÜSr+¾æoóédGxâÈNè¹ç?ÝÊ>I:æy>Æb1±ú˜Éd …øs6›%"q¤ö.™¬T6ÔËd2W¯^=tèÐúÍÌÌ‘N§Ë«ñ¼Ñ'{ÿ/®_Kç2Ø=‰Tr6»ÿ;PÒÉc£Û’@!år¹T*5===77'V5R©”Ëåâê1J¦ÓéD"1??/–'‰„N§cî³YL9@|Üñ~ÞûãÿO!—?¢«‰ß ™–ƒúý]ÿÇï~ñâßKµâü (¤š‡§Ÿ¾Ø½€Í'2‘F£1 y-£duuµ¸ÑO$Yò¦²ÛÐ!£¬pûjÿ»³­:Nó3|alX6›K‰D«Õ.$¿ÅÄU5±XL„•[Š£ØjµZ*•ÎÏÏ‹I´,!>–ªâïN´}ò1óÜÛ7bá!2 °¾\.—Íf‰©T*­V»ìqHúí·ß~ë­·‚ÁàµkׂÁಀ(‘H¤R©¸‹x.—›Ÿ¿wøB™M…Äàuy:Ùò[Ÿxÿ‡¾~ùŸ_¾6Aa’H¥reÞ‡µ+*+TUÛ{ v&™¿=K™pãÕ³ôp±;[A<´Z<]F™LVQQ±¬ô(fÇéééX,&%‰ étº¦¦F­V/~X.—«TªÙÙYA’ɤ¸ò&“ɬZÎÜ¡Êç›À2ܾگþîÞœ»ýÁo¿üÖ·æò>“&•RóñJÙ|[öÐOÌEã³|nGó:—J™¸ðE …©TJ7àif‰ˆššÌ[‹§Ãç ¸82´tõ>~ÁÝmiåÝæ“Ïw4±Ddàjµ [ËqF„ÇBÙÈlÈò™éåN*•ær9†axžÇã±XlÙÎáâ‘Ö••• ´•Jåʲb6›_'¢ŠŠŠ…j%âã6 û'I{ØÞÄÞ½Â-Ö:OŸ8èâŒDlsGï±á#ý§Ü¤lììq×#,ÕâÙiÙŠs<³Y!:™Ž°Sˆ%ÆùùùD"Áó¼F£Y¶\F*•2 £T*ͬl$“ÉÄb±L&SQQ¡ÑÜ+¯”Ó×TBñQàƒ×ãX6ÍîÌh&z[=“ʺ:íhõ6úœ˜éX4ªŠ?ýíÿôãW_þ—«WVÞ=ôÄ“(:ÀŽ “ÉX–affFܲººú¾o‰ÛôˆÙqzzšˆ4N§[6'rûº]x%ÉÐØXKý£“lGËÝXÈu¶ž™2µu» c=.ϸþés¾ŽH‡µµ«ÕÛ8à°‘"KÀ¡'žÜÜžä%B"‘(•JN—N§c±Ø­[·ÒéôÂÚêU‹‘étzfffvv6“ɨÕj½^_N'\¯T:+¯™úÖÎÃúqÝÙî»|eèŠßÛæpöµŽ%â‡:]}“úÃÝ]̓­³Ëª÷´vDİF–h¤¿Ç70„ƒ@`óÄ-¾ ƒF£! ]¿~=‰ˆk±WJ§Ó<Ï߸qczz:Nk4½^¿r'È2SJјmöøÏ×wŸñvžº$RÖš­íç;œM,ñW:[/LéŸïelÝþ¡Sý­VWgk}z íR_ÇиÞÚÔÂÞïsÖ"•JÅ)“É"‘H$‰F£Z­–a¹\.“ÉÄeÚét:•J%‰D"‘J¥r¹\uuuuuõ‚ë2&Yµ+:{ö,8qBüurr²@Ú­êêêŠÝ º{˜5ÏóÑh4‹û„g2qƒñl6›J¥äry6›Íf³jµZ­VWUUÉåòÉŽ™LæêÕ«‡Zÿ±™™"Òéty5^JÕG€Ò H¨Óé´Zm4ŸŸO£I¥RÉdRÜ$RÜýQ¥RiµZ±0Yì^â#À*Ä­|¤RiuuµV«Íd2‚ ÌÍÍÍÏÏ«T*q}ŒøÀî Ž"ÄG€5‰!R"‘ˆXÇãqAÄC ×Ù?¼¼!>ÜÇBFó¢T*ÝÁQT:÷”¨…Ó«Åe×å½­ã}íê/°A‰D.—×ÔÔÔÔÔ»/E†ê#äñò€øy@|€< >@ …+NÇÙýüê7ר>"ܧ~¨÷´³ó¾Àö(™ê#k¶46Ö³ÌúO #}žKc«P(€RÙ÷‘ip{}ÅîÜO©T—^‡†zOÛMÇq\£ÕÙ>0ÆQÐk«?>H¾x¤ž³yƒDÂÄ@»Ãjæ8ŽãLûéÞ+¡â~ €rW*ñq± ×ù¬gØàôœ;þ|“›¸àv´_áÉhï}¾ÓL¤µö<¹×nä‡Úìî |£û¹óß<®ËJÏqgïD±»PÎJeðz~,0Nú£§¶†ˆšêØîˆ F®–%b´µgd„±ÁÑ™­Ž54Õë ½ÃFˆî3ƒ6«ã#[okTv\pØ&mk³Õbiptt¬òÃY,µ}Ü6{ÀjµZ››]Íï.ì\sssD$‘Hˆ(—ËI$™L¦T*år¹x1›Í¦îÊd2¹\N|Q|R¡PˆK¥¥8¢»MJ0>’Ñáõ³==^¿¿¿ëb?éÍG;z:lÆeEE¦©kà<×Ó7à¿à \ "eµµ³ÛÕġӰUUU­uK„ùùùx<.‚ ™L&›Íær91eJ$©T*—ˆQ*•jµº²²R¡P²óÅRŠñ‘ˆálî367 ¡‰‘Áþž¾ ­N£)àâ–?hhrv59»ˆŽ úz.x\nÓ`o3$lV*•ŠD"±Xl~~>™LJ$†a*++e2™\.'¢\.—Íf“Éd2™ŒF£¹\.ªÕjF£V«ÅgÊX ~½ ¯ÃÞCŸÝÀ¸&»»^;Úpjl,$GÄ(éΞáü•6›kØâ t50¬±¡ÅYo >Ӝ≠¹\N„™™™h4šL& …N§ë‹ ÃÈd2©T*jg2™t:-B2™!‹ÍÍÍÅãñD"Q]]Í0å¼£àñ1x¹×2,¾ÂšlöÅãÍF‹ÅØåq;Ûx—ͤ§©ÁþîaÒvÔ3D«e)2ØçõÙm›™¹xÁåbÝG-µ,?é?ã›"³Ëb,ôw€2Ífãñøôôt4•ËåUUUâ´8µQL ¤R©B¡P©T™L&“ÉD£Q±Z9==J¥öìÙSQQ±ì•-FÓé´\.¯¨¨ÉdÛúY‹<>†/õu]ZrE{Ølkª¿÷;ù|ç™v·»õb’HYkn>y®½µ‰%"¦Þå²w<#‡MƒÏ@¡«gÀ}ªˆ´uöÎoºH¯\.'†¿H$"µZ­R©\MŒD"‘Ëår¹\¡PTTTðȰB¡¨ªªªªª’J¥b³Ùlv {{óæÍuîÞºuk ?k-ˆ°{‰K­c±X6›eYV³^çyñáT*µÎ3âÔIµZ-.©I&“[X€œŸŸ_çn&“YÀî•N§£Ñh<—Ëåfý}¿³Ù,Ïó7oÞŒF£ëוJ¥F£‘Édñx<‹e2™­êð}“h"‘تÏZ â#ì^ÉdRÌ[æ¾[툥J± ¸~³‰D­VWTTd³ÙD"‘N§·²Óņø»W2™L¥R …BÜßq [·ò‘ËåâGlaËE‡ø»W<ããvœ4¨R©d2Y2™\Â⎃ø»—¸±Ã0kÍzÌ-²ð+e³Ùe·VR(J¥2›ÍÆb±íû …‡ø»W6›CÞF6ë‘,²‘çår¹R©$"A¶ ¯%£à‡”ŒL&#“Éd2Ù²E3¹\.™LŠ{î,Ô%‰X­L$<Ïçr9ñ-1PªTªeÕ,iXfKg`÷J§Óbp™l6;777??/‘HÄqj‰D"Gñtìt:-^‘H$R©4›Íêt:–eâãâp¹µÏ]ᯅà¯Óe·˜MÇq¦F«³Ý;Úà»C.g>=TV`(²•ûõˆ¡paœZ&“I¥RñÊÂ]©T*^'¢…[»A«¡ËmŽS'•u»Ã]od„àH`àB׳v¿×É1…í ìr⊙•ÕA‰D²¬J¥Z|1›ÍNOO'“ÉÊÊJñXÂ…[R©T¡P,¾"¦Iqà»Ì’eAãã„×yêâdݱs¾ŽfÃkg«£Û~¤¯Ëåµø]P@‰$N§Óée!O"‘(•Êe˱s¹Ïó‰„a­V»¬•g³ÙL&#N¯Ü¦þE¯ù¡žžqª=Öã^ÈŽDDÄ4´v·?ýt#Ëß“ yOÛ-w·í§{¯W­ÆüN«™ã8Ž3[ícü;A¯39}¾ÓVÇq–ÓWøU€ÝM&“¥Óéd2¹‘Õ-‹wêYÿÐBQ:çJ2LYÈ W}&†#Tk·¯¬02õÎ3gîþò»¬­j<Öñœ¥Ž¦ýÝžãƒÃÝ~¯Ý¸´½‘nû‘¾ñº§ÛzÚÍÚÈè@ÇýÌðØ7:X""Jvt›º;‚PwçÀb ÃÄãñD"!n¾ìîªs"¯¶^¿qñ¼™L¦V«·°ÏEWÀøš 56×ßÂPwg R×vÙ{g »©¥Ñhkéê첞iZôjp «o\k}Îw¦Å@DÔÔl1‘õxÇ€Óï¼4ͽ]vÃÊ ""•J¥P(2™Œ¸#ÏNRÈÎd2âé…[Õl)(ôÊëû¬™&‡ÃdrØ•(9›ÓL‘aÿ’l~Ì?JZ˱Eãàl“Óª§qÿèÝeܵf`âÇd2‹Å6x2õwáÛÌd2+çPît…‹ŒÑTKYu#?1!^B<[»$ö±zVI<¿dú¢ˆXÃ’çÖÈ ¡»ÀÊk¢l5¥RYQQ!“Éb±Øüüüú3%IeeeuuµJ¥Z¿N™Ëå¢Ñh<—Éd•••Ûq v0>rÖF-Mü+ò£0Öãlin<=$0¬%â§–DE>Ì'‰e—FE-Kć–FJ~‚'b ÈŒ°12™L£ÑTVVf³ÙH$²þé‚R©”eÙýû÷k4šõãc<F£¹\N­V«ÕêÅú”~¦Éå2ÑT_k÷ÐÒt8Òã:‡«!£µQOã¾Å3è÷’²ÁºdÒ$[o3Sd°Ñ’j~Ä7¦:« ³`cÄ zÄ„Fçææ’Éä:ÏËår†aÖ߈'™LÞ¾};‹) µZ½ì$Ã2PÐR*çêíµ»ûŸm´Ø¬–#ÃO .F´í½­õ 5¸;¬VÝr³ÖÑTàBwÿ¨²±³­™]2sÒhk?é=ÒwÊ~º­ÕnÖFÆý½]õG{\!¿ìpR©T­V ‚033377'‘HöìÙ³éÙŠ‚ ܾ};Êd2–e+++ˬôH?uÆhï ˜zÎø¾Á‹D¤Ô›šŽvžlu4Ý­l½moçoç©þ$)kÍ֓Ϲ[[ŒË›bܾç¹nOooëñ‘¶Îr´³ÓíÀ=‰D¢P(ª««3™ÌÜÜÜììl.—d^UÃl6›L&Å JDUUU,Ë–_鑈Ö;ÃûìÙ³DtâÄ ñ×ÉÉÉuj·ª««+vv©\.Ç ÕÕÕZ­V¥RÉd²ûæ?ñt™D"Áó¼x,MUU•N§cf˳ã+¯¼‹ÅÖyà±ÇcY6“É\½zõСCë·633CD:.¯>”Õ: €Í‘H$âfà‘H„çùD"¡V«5x˜µT*]–³Ù¬xüL2™äy>'“I™LVUUU]]­T*˯î(B| º› ¥R©R©ŒD"ñx\„x<®P(”J¥J¥’ËåbˆS£x&¡ ©T*QEE˲Z­¶Ì6z\ñà†aär¹J¥ŠD"óóóñx<‹Éd2¹\.ÆG©T*ÆÇT*•L&s¹œT*U©Tb©R©T–Ù.+•ù×È—¸$Ã0‰DB¬/&‰d2™H$ös¤¸ë¸øŸbî,nÏ cW|I€|) …B¡ÑhR©” ét:N/ÄG™L&“É …˜ËušãªÖ$î+®T*‹Ý‘RnûXÀ¶Bõ`u¹\.NG£Qq_žT*•Íf%I6›—cWVVVUUUVVŠ;þ»¿‚ø°ŠX,vóæÍX,&®³Ó¡øŸR©Tœ FÃá°\.gYvß¾}»dŒñàŽl6+•Jc±Ø­[·b±X&“—WkµZµZ½°J&“ɤÓéx<F#‘H.—»}û6Ïó:nß¾}2™,—Ë•q1ñà©T …Âáp:Îår:nïÞ½ …B\g½ð˜\.g¦²²R§Ó‰›‡ßºu+™L†ÃáX,V[[[YYYÆ 2ø¨R©¶¯E”Ëåˆèúõë·oß–H$•••555ëlå(‘HÄXÉ0ŒJ¥ŠF£×¯_O$×®]Û¿uuu¹&È<âc"‘ؾ~‘D"yçwÂá°D"©ªªª©©aF¼µ~ ï2w]¿~]„7nˆíˆ£á…úRnß`Ä1ë\.·wïÞ0 #Ö#éîr™µˆwŇ58rÉd®_¿FË/;â#@,»qã‰ÙQ.—ç;î,>œÍf+++÷ï߯T*3™Ì7Ä9”ÛÕï"A|€]M¬f³YµZ}àÀ‰D²é9‹R©4—ˉ R.— ‚ …Êoú#â#ì^¹\.ÎÏÏK¥Ò‡zH\^ý OLŸZ­V§ÓI$’ÙÙÙT*µuý- ˆ°{¥R©[·ne³YN·°VfK°,+“ÉR©T(ÚÂfKâ#ì^Éd2‘HH¥Òššš­Zæ"/U*•^¯W(ÑhtKš-ˆ°{Åb1"ª¬¬ÜÚóÅå2©T*•J•Y‚D|€Ýk~~^œª¸+ F“ÉdxžßŽö‹‡Àî•H$$‰F£Yy+ß w/¸–Ëå†çùx<þ€ý,)ˆ°{%“Iñë•·|ÉD¢R©¤R© ØTIA|€ÝNܯg±\.777F³ÙìFZH$z½¾¢¢bq â¡Ø‰$“Élew‹­Psù+.ÇY{'V¹'Œ´7®uo]Ý޳Ü5|Ðgã8«7¸z×üv޳t•Õÿ-€KŒ+ ¹\ŽçùT*%‚ É5ˆ·R©T,K&“k}J™øŠìL&“Ëåäò²š.XÀ{8‡ÓLa¿wdÉÒõP 0©·kfÅßù_»ÓÖhâ8Žã¸F«³órPV†N›8k÷@·£‘ã8³½wbéർÜ{Ún5‹oš,ö¶eî=m3sÇ™m®î»Í®ÀøÚójð#¾6»Eì›Ùêhó•Õ2|€]G¡Pd³ÙD"±òV.O«¶H$r¹Ü²ÂäNWÈ}V§E ô/Î\A¿w˜jíÎ;É ¯óHÇ@ÈÜÚsîüùs=m4ØÊå½7+r²Ïígíí.‡Õ¸¸qþJ»ý”gØ`ï:wþüùçºƉ‹]Îö+÷>k²ßÝnìxîÜs6æJß){Ûå•áj·é¸2»zÎ?×ee]GìíbCþVG‡Ÿ±ŠŸà6‡.v9]˜y ¥ª¢¢"›Í®º­·$O‹ßÓd*•ŠD"‰dñ’š2PÐRªÁrÒª¼Ô?j±‰CÕ>ï8™:w¦C†ÆÇÈô´ÇÛuçvSSíÄ𑋃¼‹»SÔíéqß ›÷š&†Ã†Æ“=®;÷šh´É=:šïε4µ x]CDÍÍ&Æz¤ßãkmq-™q9áë¸0¥?|nÀ#VC›šÌ[‹§Ãç ¸Œ—G’Êæ“­öf–ˆššêYƒ7¨ÅŠ€K£ÑD£ÑH$²ÿþ-Ÿ¡(.©Q(,ËnmËÅUØ‘x¶Áe¯½Ôï ÚìF"aÄ;0¥´¸êˆ›gÀFD ƒÁÉÉáË£a"cò^Fã,ÜjKe˜·×OD$„‚Á‰àää°‚ˆY´Í’Éa[x•©·[õýýÑkqsÁaÿ$iÛ›þ;fŒk§Ï?tqœ­I{)pÜæxÚji¶X,M6wÇVýÉ@1ˆÕÇD"‘H$¶°F(&Ñùùy¥R)“ÉÔjõVµ\ <‘“©w8êú=Þ@Ðî4ò#^Xk=i¹·hF˜ðwvt_ž""ÒÖš8Zz¥VÏ®±Ð:4ÔÛÑÕ‘R_×P¿|)Ž¡vц5ˆøO´èÓù O¹ølýÅeïÖNðÕ·ôøÏy{úýžKý"­é°»»ËQ¥ß;”x®`$¹yóæ#<"•nÁ¼¾l6+•Jc±X8N¥R:îÁÛ,)_ÄÙ]·Ï7ápMô"µWÃB©Ojw´^$kû¹^[S½!FÚ-ƒ“h6ès=ë5ëù¦ÓRod¢Ð€½ixñN|dQV“¢Ñ¸¤”̰–ˆŽ>×ã0.„Œcˆˆ16»<Í."~bh00ÐÛs±Ãɘ—.%€C©T †H$277Ç·¤L(–#‘1 £×ë¼Í’RÈ¥3"ƒõ˜U9é÷ ú“&§sQí.88¦:{›³¹ÞÀ á0Ýw~!?á%²´µÚŒby24[úÌ„ìÞR™ààà™¬æ¥%JCcc-MN²\ý]F~ÀÓuf (PÈïj4ÙÄÍÍY®Éæêj·j)<ÂìG€L­VWUUQ0L¥Rô`»|‹[HÎÎÎÎÌÌär9NWf»öPQ-d›OÚôG|Iec·mñòiCc½¶/0àñšO6…ਿ¿çBˆþ~ 5ZêhxÐÓ=À8L ?9ìëé $—¾ ´¶ööv:êiÌßíöLÖ;o7.m†©oí<ì?î±;ƒîcÖ:&2îïí¾8n8|’c‰5[9r{œ.r5ë)<>Ðs)¢µk(«É°»T*Ý¿,ajjêᇖÉd+7ßqØ:^¿~=“ɨÕê={öl®©RVŒ8ÌÔ;íµû¦´Ë÷ g›»½íí½]§Ž)kÍ6gÏåÓŽgýƒc¼Ó¸î1çôö„ÜÝ>÷³ˆô&‹­uà²ÐÑâ R“¸¸ÚÜî® ¸­ž©$éÍO·³Ë¹Jðc›=þóõÝg¼§.$‰”µfkûùgKDF{ï€ÐÝåím=!RêMMÇzzÝ-ùow%E¥RÆk×®ñ¬I"‘hµZ­V[쎔r®¬À–C|€< >@ ˆ‡BÆÇ‰^+·:Çe~»>T˜ð·;]þø[hÀÆqÖÞ‰íú4€rWð{”棭6néé‘Lmýòã$·L0Ðsam¸ûIz³Å"Ùíú4€rWðøh0;œÎíK‹÷Á6wy›‹ôÙå „æ>ò~;ÇYºÇ„»„±NËÝmaè´™³v_hwXÍÇqf«³Ó\x–„1§ËÖhZ|O:mnñLº›8“kHX>xòž¶[LÇq¦FûéÞ+ ò—g÷^öµÝ¹o¶¹º¯„ú:²pƒ3[mÞ¡m}() .îÿ–h²ïTOØÚî»råùs.ÃH«³G ‚ÂD¯ã™Öþ1£Ósîü¹—q¬¿ÕÖvYhè8w´–¨®íüå@gÃÒšgÈï²>Û5ÈX;ž;wþ¹3è9ns ï=1ÚÕê#{÷À•+Ï?gg®ôwù‚â›­Ž?cí:wþüùçÜæÐÅ.§k Då¯àƒ×á‹Ç[..¹bê¼âw7ôrí±ÞqäÛèêt ´xƒnÎÈyzF•ݽvQSS]Èî Œ-ÍF#CÄ8ÎhXÒ”0Ô݈Ե]öºÄ™˜M-F[KWg÷õLÓÉ‘&w¯GìšÑÝnó¹èãFfâòHRÙ|²ÕÞÌQSS=kðµNÁ;XÁã£ÖÒÞu´V¹è [oXóée8‹q¡‚ÈX">$ þ‘$Õ;, í0õþañÇ5j‚ÂÄàp˜L®Å«x8›ÓÜåö…¦z±¯&ó½&YŽ%"ËÙš´—Çmާ­–f‹ÅÒdswlô+ìll]£µe“Kg” ³ìE±âÇGxRôy­§B<‘±vÉ;¬žUÏ/LcdØåý?ÏÐÒã?çíéô{.õ{ˆ´¦Ãîî.GÑVL --æC[ÂêYJòá%¯Ž]¹2\{<™‹—SK>€óIbÙ ÄPÆØìòø£#—Ï÷´6N\ìpvŽ`øÊ_)ÅG-KšZXI#LF#yᬠJ¼7P=ák=~¼#°Îj£µQOã>ÿĽÌôûFIÙ`5Þ§ˆò»M6qù6Ë5Ù\]íV-…'7¾`Ç*øàõÚØz[£r0ÐÚÚÝqÔÌL z{ýÌclS›Ûèjuœ¶ÚÍÚð`Oߤþð9»‘(d`‰Æ|=^²ZíÍ÷‚!Óàî°Z=vgÈ}ÌZGS Ýý£ÊÆÎ¶æûU f+GnÓEî£f=…Çz.E´Öc ØÊ_ ÅG2Ø{zCoŸû)ë,ŽN¯£ÿˆ{#o2œÓwÙÐÝÕÓÛz@ ˆÄGÈâ#ä¡”N(¬uÎOY‹D"ÙŽžì ˆ°{! nBñQ¥Rm_? ,NÏÏÏ‹?¯_†”H$¹\NÌšZíÿßÞ‡GQåû?M  æÞ. ¤˜nå¡ÃOHrÙ”Õ€`DY5a‘€(à ›W08l d‰0¢ìH„8 0(²oB„è Ç$0Cž›îæš:¿?: ­I ¤“æýú£R]]õ­S§“§Ou›îóЩ#>:Ž{W@Uúõ×_ùå—¼¼<מaq¸Ô4­Q£FµjÝ¿7ðæ5¸ïüóŸÿÌÉÉB+zæJƒ!33SJxߎA€OÑ4ÍãRJ)åÏ?ÿìÊŽÅk*¹sWÖ,NÅ™²Ü ƒOFLâ#ð)iii7oÞ,((¿éÆêÛrí333333³¢m C:uTUµX,š¦ùØ;ÝÄGàkŠïtñ0øw‡Éò¶s%]5Üv˚ȧ²0€+®ÕªUËC@¼óQIÏ{pn¼# ÞÅè#ð)²ˆ¸ÇÑÍó΋ïÈñ½ÑGâ#ð)7Þùsß¼’wv× ÄGàSþïÿþÏh4Þ¼yÓ‹¡MÓ4£Ñøë¯¿ Fª9³Ù\PP išw‡ýüüüEñÖÑï)â#ð)f³ÙÛ%”Àè#@µV<ßÑ[¹Í}Â¥ïeGQ¥ñÑyêÍÏ­»Vr¥1 edtÜÄI1!·ÝÍ;¼ìͤ«q˦µV„óû]{¯2'žÚ­Þ³z@MTœØ~ýõWׇ‡Wñ¡k×®ícŸ^J•>š:ÄÆw°¸²¢ÓyõÇÉŸ­štøÎÝkY<=Ïy*iÞß?W%E€šÌ5ëñÚµk¹¹¹‡£Êœ”Òh4™L&ß»áºX•ÇGK‡¸ø8· ß5¾Ãè݉ËNÅÌlí›óK€7ÔªU«  À`0TÙdUË‹¼?²ªF>"ĵŸ~v^MŽkikÿ÷¼[æ~­•­Õk;–F‡ ; ĵϞ ±E¯¼RüèÊ×bÚÚl6[Ë1×~ïöDç÷É3⺶²Ùl6[«®ƒÞÜRüà•µÑ¶–q[þ¶ìµè¶-m6[˶1¯­<ìöTà|ïë^ª ïÇGç•ÓW„0(棺šnîN:pµè±¼ÃI»oDÇu¼lÇŒVB˜º&îøÛ²˜ÂÁËÓÓF¯¼Ùv\âÒÄ1æï?›6hÆa§k—§æÆô·êJËøÄ>ý(1¾åÕu“zÇÌ8Uœo˜4i·9.1ùïÛ<³CÞ3ã&ý €/*þÜ-Uþæµóê•+E£‡Î¼+?X53ég×ZJëø˜ /V­Ü}%zEquwÒ›Í&ƵVTa R…PLA6›E®”hl›¸eY´Y!ºµ§;N;²ûGgdˆreË̤˜º.]»°›Y!";vh)º[5mK\rÑûæmg.›æzªeÚ›ÉÉÃ'ïìÉ›çø *žƒè:s’wL*±ÆØìé¹Ë&µV„JÈ AÍVÍ[™üã x›ø1yåiÑjF´­‚]Ù¢[®“¹™Å(_ÍBä}Ÿ|Z˜žŽíxëCŸÔȸ®_¬K>}µ0>6kÕ²øQE RÅλwŽ zðJ€óùÁÎ*OϘàú·¢¨f[HˆÅíÃwl1ñmçMZ»öû¸IbíÊ;$v­ð†lE-÷S{œ7œB¨fµä¦UçÕâŒh.=ÐHzÀ÷x%Éùê c±*æÖºuóð=æ®±]£“מê*’6uÛA÷Ç+&Uˆ¯–˜ËèÌû1O‹Y!'paôñ^ðþ­3¥©GE\Kž7/ùZ@t\ë[ƒˆŠ±rÑO ‰n%nXåvwÞ©µ®‰f][V¯/1¨yª_|JH\LÐÓ§o4‹‹sû$HդВV®M>u››¤-ÑoŽjyc÷è˜×–%ÿýðß“WN4ø³kAg ªh%*©ÆG¡Ø¢» Ñ*Îý¦%$>¾kеÝó¦ÍXûãmF!•Ö“Öî˜;Ðòeㆠ6.ñ´yàŒÍÉ3#ù‚C€;eððöüòåË…#GŽtýøÓO?UMMÎïçF÷^iYzde·û+ð5kÖÌÛ%à \š“••õïÿûæÍ›U6Ñ`0Ô®]û¡‡2™Lš¦Ý‹/K<þüÿþïÿzØ yóæªª=z4**ÊóÞ®_¿.„ð÷÷×UC•ß:ãÑÕ¿¯ÜräÇ#Éë~j6*±ãý•j„ê×v'&Ížž»l\Ÿá PýT¯øh‰Yûo€ŠUÇ[gPm ñ:î&ŸÿÎkâ#ðY^ùúi¾ó ¦òÊ@ £5•Ïzñø,×·VýA…OA€o2 ƒ¡ê ]Áч>‰À—ykÑG@â#t!>@â#t >@â#t >@â#t >@â#t >@â#t >@â#t >ß$¥”Rzå¸ÅKŸD|¾Ì`0Tñá\G¬UËgS–Ïž€BÓ4¯®Š[•ˆÀ׸Þ8öóóÓ4­ŠG¥”®qÇ*>nU">_ãŠnÿñÿQ·nÝÛ¾‰|ç9ϵƒÁP«V­úõëÆ»²Ûj«¶· ¸Ë\Ñ­^½zÿüç? Ч$º“RºÞböóó»Ã#ºnÓ©]»v£Fj×öñ|åã§îg®±À¬¬,»Ý^v2¢+>ºF ïä(RÊ:uêüçþg`` kèÑ}ÿ®øR¦ô3(«^½zM›6õÊ¡ ÃkVCÌ}€ÄGè@|€ÄGè@|€ÄGè@|€ÄGè@|€ÄGè@|€ÄGè@|€ÄGè@|€ÄG€Ã`0xÞ N:÷ºâ#@ñ»ßýÎã~~~õêÕ»×5jŒFyx400° j >ÔF£Ñjµ–ûP½zõ<‡Ë»¥vwK`` ŸŸ_FFFAAAñʆ Z­V??¿*(€øPÃ4lذaÆ7nܸqㆢ(&“Éh4VÙщ5’Éd2™LU\æ>@FÔ`7oÞÌÊʲÛíÞ.î>×­0Uù®t%ÔTÿú׿ÒÓÓ½]Ü+7nÜÈÎζZ­Uóq<•Ç›×j¤œœ²#€ûAFFÆ¿þõ/oWQñ@”‘‘áí ŠT·ßxÄG5Ýn¿yó¦·«€*RPPpãÆ oWq ñ@Íó믿z»¨RÄGè (Š·K¸…ø æùÝï~çí JyåãÁ+B|PóøùùU·±€{§aÆÕêÓ‰j¤|°^½zÞ®î¹zõêY­VoWQñ@äççÒ¤I???o×÷„ŸŸ_“&Myä‘êö‹ŽoPƒ=øàƒ>øàÍ›7N§·k€»©víÚÕö=â#€Ïh4V«YAàÛˆÕˆ¦iÞ.ø‚‚‚‚{·sâc5räÈo—p:âc³fÍî]´0¨ ¸ó: ñ: ñ: ñ: ñ: ñ: ñ: ñ: ñ: ñ: ñ:Ôöv€÷ýôÓOGÕ4Í+G¯U«V›6mš5kV}JB£TCå^.ÄG@>|¸_¿~^,`ëÖ­¥þJy½$T1ú@5Tö¢p!>¢  @Ó4ƒÁ ¥ôʲ   lIRJoÕÃ’>ÀRJYö¢paî# ¤”B×»„ÞZ–åÝzXÒXº~3(‹ÑG@H)ÝÿZTý²lzÐ4Í5òäŪXÒîó¥ëÊbô¢èOE9ìg&‡©¥X#úMÞ‘^áSôÓW’Ëõ£ׯ}°ÙUQX¯Øù;Òíw±&}ìé»?ÑÑ$ö3ã‚K¶©9¬Kìâ×=>ëú™ÍŸ½.¥”é‹Û«aÓ¸çkOß½8¾W„Õ¬ªªܾßäÍ:s}G/Õ{@om¿¡T\ªýh|°Úå“L5TŠý‡óc»„YUUUÍÁ]bçï¾Ýaì»û™ÍývÛ¥Ìü¤‹<îh¹msýÌ'“vhkX—Øù;*Óð:;^™cõ¨òÝË_9@ÍF|„”Ò5ÒSÞR !Ô^‹wýõ¾þz÷ß6-Žkt|éà˜ù?Ø+~–îe©’n³}ú'ƒ}jÂŽÇ',Ù´cÇæOg=x6aðïŸý$ýnÕ£oùËŽa1 É™ù•~–«UßûtóæM›6mÞü銷žt~15zÐ'—*|–ýHB̰.Ø5MJáºëçb?úÖÓÆÌ¾ðPÜ{Ÿ$'o^1>,û£axvñöÊïÇUÛí®à÷ü#o=ýh̬ Öaó?ݱcÓ_'üWÖGÃþ³ä|¾&¥Ô~k ·Yæìÿ‡ß^’ýø¸÷6''oš?¨Ññ„˜ÇnμM›½Ê Ë*³Í/É£Ÿxb̧YOX¼iÇæOgÅ>taÖàßÿaòÏõd&‹Iø"ë·½Ý{T…[ÞÓß<@ÍÅ›×À­w Cé¥RŠºš‡††ÖsÍ©{üñÇÕ³-†®MN?á‘òŸ¥sYnUoŸ¾rø+_¨±;¾^Ð^-œãÿd¯~=Õ6Ýßž}¤ßâ6õî´ÝËÛ×\¦U…¨ÿÐï;w +lÕ'{=®kõÇ•~8¸±‡VrŸ—¦é8be–Îs ÃÞ?Û~ñ‘vUÕþÉ'Ô¶}Þž’ÜoKLãÊ_ÍßP›¾>æíáïŸmÿÁÑäÁV×}íŸ|2LiÓ;á/úmzVuo«»w­óŒ¶2ëÙ5GVD7vµOû'»D i;tBÂ^KžP*z®”B¤Û9–Ú&û³W†­u üäèâ^Eýyà³]bÚŽ<¾×™žx âª ÿñÛÎô¶­D|*Âè#àyôQ+žå¶^Q„päJMË?6¦…ÿSŸf®ÏÙíßtø×ùšfÿzÈà [º`Èû7hÐà‘§&l¹TáQÊþ•’¥è¶üa˲ãJ¯w¦·3¹¯7>þÎç‡ö¿û¸âZ“¹;apÛ¦ üýý›¶’°û)¥¦å7õ±‡£—,Óõÿ š>1ì¯EãjöôÍSz?ÖÄßß¿A‹Öuú¸ÎbÁ˜®ûû·¾çºöËžCžx¤qƒ üýé0ü£3×5ißÝbÄq‘½®[“Ǧ~—¯iöïÖŽ~êÑ& ø7~´ë˜µgò+i“%Ö¨j}!Ç ú·xýX~áúüï¦>æÿDâþ·Ûv[™-Žmá½%GJ!DÖW³cÚ4iÐÀÿá6C»îÚ>ÿü–©ÏµyØ¿Aƒ·¼`O¦ëìÎLy´iï¥KF?Õ¢Aÿ‡; ÿè|™ªò.Y›8pz_«{Uí§¯Ù¸fz;UÓ4iÿaó”˜âV_تš”9G— ëдpÏÇrEñÈhþ™OÇt}¬±¿ƒ&=5úÓï*ÅÔÕìÇ–®Í8½ŸÅm½©Ý´5×Lkg*Ü™k°§ožò\‡þþþ 4yä© k]£é™[žjÜæõ·‡·iìß íëGÝ[éú÷wæ57±W [=½Þ]óñš×ÂŒ÷¢â™„®JYêŒ.%¿ÿ•3bú´žf÷õÖïLjž·uΞëšfßó\ãÆ1{ŠZ/}É ›zæß»{·q\d¯ëþà£SÎØs¶D7~tÌÛcžzäá¦Mš>zëŒÖ>åÿÈëÇìE­1å±þšžÿCÉUÑu¹÷¿~€‰øÜf†Y©-ì™ßmyãNk¯¾Ö²ßÚ¡Îì­sŽwy÷Еk©Û8W»ÅÃ$±Ê—”yvçEÖ3Bu«Én·ÛíÒlU×ÏÇÞèþü:Ç€åûN¦Zó’\÷|Ÿ7ŽÙ]‡É;øçͧï»ríÇ}“êïüÓÈ•—¤”9{Æv¹3pÜÆC'Oî{·Köœ>ý—^(>‹Äì~Ë·o_ôZDÎÒ¡ÏÏÍê²(ådêÉ}P¶þiÄÊ Ré²!uQ„PlÿñÔ;aÊ¥µC»ÿñ\ؤí‡RO¦L ;÷Ç>CË;q!„p8\•çä\:¶ö>(‚ûµ·6œ½síY×Ä7ûÙ•[³#bût˜¶?å¥@öîÉ+Ûû©R ‘±~ÎÙöÓ¶ïÛ÷q¬úÕŒs¾³K™³gì3#×9{~°ïС”wÛ]žû|wÏ'î.ëì¹<Ö3X)¹ZèÒ%,Pñ°óKk‡öùïãaï¤:´q”².ñ\ѬdSèï·+Õ­[VPƒý»9}F®–:™z2eQÏÜUcÇ~æªM8/®úLŒÚ¸}û£BÝŽ`¿tð¢Sho-UL`û^훫ÒC/r{‘”s^ö _]Á½"K?`íÒÅ*.~uÁ.˼ …¢tÇ“R83Ö¯sŽJùþ§ŸO}ðøñ?>3vONÙƒºWi^ªGUà.ÿ®|ñÂÓ,1)…È^ÝÃPÈÚùå½õ_JZÿf˜R86Y8²R4çìÖˆKðkÓ^ 7e`»_u^<žUÞ8\¹¥\+Ë­Ê‘+„jV‹Æ·¾{#ÄR¬åØcvíúž¹«²;ÏMz­K˜Ålk7jÞŒvië¿ÉwUe0ãåvf£¦† !.¼œ¯¥6w«|!iáKílKXÏi‰ƒO,\ö]~ÑYÌÕ9*ªK˜Q³ô¹èÃ7;‡Z­¡=^ÕNdÏ´Ki”F!êÊ:u¤”?¬œ»×:1iÞ Á–о3¾TïÜ­¥G^¥"#©‡ÍUµÍÞãÕ­¢çÜÕ#ƒ¥´=órXö®•Çò¥”ùß­Ü•ñR‹”FMH¡FW‹ ¥Ë¢¤W{D„…õøÓ›=ÕŒãì2ó‹¹[s{.ZýfÐààˆ¾óVÍ‹ÈX5§(B˜12*P‘¦Ð^Ž^²—œ —“•+TÕX§‚žàÚùÂUÓz†ÙláýÞ]=/"cÕܯ®k?|–xP})iÞ€›-|À¼_µö «æîµNüðÝá6³5¬ßŒ…/Õß;÷³ô;ïù9Ù¹BUcÅ£æ…Ã|j{yƇ Gµ³YÌÖˆ~¯¾*²Ïf^q1qÆ‹QQ]ÚÝ÷™“•+꛽R<÷"YTU™¹ŽÜl§¨o6•Ù§b²¨"7;§Äøe‰³S¤"„"ŒF×+N ¥ÝÌy}-F)Õ¨ÿžÑÓ±3qO¦tÄ–x®ëõ^¢G•Û’÷òWP³1÷ðø )RJ!Ô‰ë'† göÅõ3'm/&®šÙ%Phš,g, D®oBh²0Hh®ÇUÒá(JN¥ŽRntÐ*ø,!£I"7+G“BJ©ØF®ÛÙ×)„ãòúqñ»¤Ôì—^t:3b››Ý÷z1KFI)D`¨ÉèªªŽ¢(Âa—öË/Š«'zY7¸?¡þe‡´•8 £µç‹ÏœØ•4#ñÜÅŒ‹i'N¦ ¥GQúR©i×/žÈi3ÛÎtÛ•züRþHKÝ­*…¹obÒËÍ뺶07¨¾ëZkÏ‘áÓ¦­>žß.âÄê½¹íft6KMÓ„,šE 5!D Íbt¥©ºZ7ÿòÁË"ø…SQ“šCÛYÛNdj]?™WûŠ"­ðª¹ª2š¬ªpæ:RSʹF×ÎCÕ¢ëÚÎêÜv<Ën<˜!šw6ºöf´uUW MÊœ Ç3DÚÌvæMqâ²]³Ö½³> ˜,ªpæÚíš4–û‰3Záó+®áåöϼh:¸mÙŸOœ¸˜v9õÜÉ aŽpµ­êC–â6t«P5׎lGU9*îEE7:¾ZDÉ=Ô1©ŠÈÈÊ‘Ò\rŸöÜËyB S‹2Ÿë?sE-%‹ª-|7\jšP¬ÅW_±DXÏÊowëó¢“*L“n=ªüÏî!A!>BÍ—e¿yBÓ„ŠÙªÈððp‹|2fàewò›ÿUOJ·ÑG) iwÎ93!„4¥¦IƒÁàv'lùßoQªžâ?ue·4…¶³ˆå»Žç<ßC5 Òh ·J) æãŠp Ê!ÌϯÝ2±y½[Ï­[ߢi©B!•¢j‹niRˆà±[V¾ôrëXuLšB(Æ¢³pžùtײßéÛ³]ßîcÿxuzôô¢9m¢(hRˆð9»—u~À­æºJ‰.lÕððÿ*>¢Ûùt~9Â9iõ‰,±z—³sbçM“·»‰ BB(FMÓdÑÞDÑØ–…m^gÕkÍoµU–Œ‰ ¥IDAT5äœøä³ڽУSçŸÕ|n\ÌrQ4j®(Š,ûŠ0uU–Ÿøæ’ ÿnëŸÚwÙûÁö"·¹ÅýäÖ”à¡bò¾™cmJ1û›o3DXç c‰= ©9‹^M…-¥išA )·¶‘v‡SHQrƒAÓŽâù—·zT¥^•Šñæ5pÛožp߯ÔZR?ýÞwùš¢ŽQg®Ýõhþ¥“Ù¢è^Î÷„ !„ŽRùªŒ!C_ w¦L›¶/»Äú̳'²…šV×nWS3êY­Ö  :çMŸ¹õ’CM–®AH)êZí"ã\¶©pû ñí»ç}uµÔYäÿàãTÛ[¾XöçWFôïª\ξUgQÍu¬a‘q"Ïlu½áõïL_~<§L«z<Ç€Ž#¢Ä·I듾‡FšÜŽRúAÜ÷f Š´Š´½g¯­Ï;ûm†P¦ýK^ÓÂeÝП±\ÝøÎÆKn믳ðÝ”TGP@}k;«HÛw.·hûœÔo¯(¶ðÀºÁQÁ"m_j~áúË'Ró„ЄP‚B,"ãDNÃÂV5çîšùfÒ‰¼»ÑZék¹ºaæú ·õ¹ß.š—’ê´oµUE5ä\øñ•ð÷wl^ðçW_ìÓ©¥HËB:‹Û§ÜãÖÑCMûཙnë3÷þåƒCi¢zèEòV/*"zŒí¡|;sú®l÷õ—ÖM|/U}敎BhF£p:sì®Gó3Nf ÷«_ü,ç•g3 ÿº7C ޲ëÔ"/«ð¹Z^ZÚU·Ü{Tå¯ â# „ǹ®Ço­1ENÝÇœöÁøåó5£9*TIýàÕÏžýfÃ[ã7\qŸûèvO·ôt”ŠFž*ØÞ2dÉ‚î΃Ú<7ýÃõ[wnÛ°hÒÀß·¶ÝòL‹¢™:¾>Ôœ:9vò†ã.Ý»hôø5'¤Íb,{¿³ëg-¨Ï+Ý•ýãG¿³ëØ…KçvM¼1Mµ5,}ªEWöí=–™Ÿsùøúéã_N‡Ý!¥VÇ¤Š«ç¶í=~Ñ2ü•ð¼ñq ÷ž»|áØúÉ£ßÚ~9Èf.¯U=œ£9¢“óË¿|)º‰T‹f©ŠHKÙùÕÙ¬Â+µ7Mš»¿ÞGýrü°™;Ï^¾|nç̸)'-Ï¿©º¶wß©kêZC^_0Ârhr‡§â®ßyðàÞõ GE?·æjTÂìîf- Ûë}Ô”ñqïì:wéÒÙ]ï ›|Òòü+‘&-¨ÏëÝÇ_}ðÂ…cۦǿ—æ:–1tÄ+áyG[ôÕÙKo˜ÿÖö ‹-ànô%t‚–CSžxrÔ¢ »¾ùæ« ‹âŸŽYs5*av··þVQ uLª*Òví»˜“ýÒÁÕãÇmÌNG9ý¶ÄÒ•° ²}XטII[÷<¸sý´A]‡¥(Ýg't2Uª•7÷QʀôW¶{"fò‡[¿úæàÞm _{ºÃ„ýæ¡KfuR5MS,Q6q轿l;vöìÞÇOJÉs]~iTUqõÜö}Ç.\wåÐ”Ñ ¿:{ñÜÞ…ñ“™Ÿ¥£IƒÃ-Îýyoç±³Çw-7ýdQÏ)Ñ£Êmç»öûð9ÄGàvßï"\s¥nQ;%Ìê®~?küÆËÒÜgÖâáÁ'§öïÖmÌÇrĬþEOÏ%w#=I_I–þÝÿåâáÁÙ)ó§Œ>fÂü}¹¡Ãç~èo ÌRJ5ê­ÏWŒ üö­>#» _#úÌß4¿“Z|œ’G•RJsŸÅŸÏï/¶éÓ1²Û˜}CVlJWJ…2fÉÔNÙ³ú´¶…t›bzeÍT›Hû6Û.¥2|HÈ+†ùKªÝ2tͦYrW ïÙ±Ï[©ÁS7}2ÂV~«z Fí¤ s÷¡­‹ïý ê?¢“òåÔ!ã·_”å4®”Rªæ¾¸¿Ø>¦[dd·)û̯¯ù|V”§/}Ô¨„Ï?ŸÕ?0uñ„áýû™°"-xÌŠýk†ÚO;7w_¼i~TÆüþ;ö/ã™×;©…{¯dS¸Ué>à±T·ó+¿%*añ˜ÐÔ)Cl!½ß::kÅs^jj¶§Æ‘RJs÷%_nJè$öÍ3¤ÿáSRr£¦®ùò¯}ÌRzèEî{,ÿe`î¾àË/QO¬˜2¤ÿ!SÖ¤Y^_±ÿËY…½VZ†,™ß_MÓ§[ï)_Z^ŸÕI-¼ànOJ!”¨þ¶ýºuì6|£ÒŦ·¢)• K:å®Þ§[ÿ¿œŒJ˜Úºð%Z¢GUò¢pñ4½cùòåBˆ‘#GVa=€,]º4::ºü¹U²Ü±cÇèÑ£K•Ô»wooÕS–YÛû·Ÿºmï[aõªE=ôê¾Ìû¼ØÖí'Þk­Ü­}&''—º(€ï¹~ýºÂßß_׳}JÌ¢óÖ²,ïÖãÅ¥#íЮmËßxûTȰ¸ÐºÞ¯‡>PC–¥gßùR2úT€;¯OŸ’S5˲éAóðYB¾¾t¤-ùÓ«W»½³z°Å»×…>P³–Åív·öé¾[%ÿüTÕ°¤ªaêºêÌÿ¸þyß¶A¡ûýüu1E¯ûŸhA£U‚ø!„VÑç>VÕ²T=²Hµ˜UÆ’>p_.«ê×PóѶmÛ””oýµ0 ‘‘‘¥VFFFîÚµ‹?`÷ ú@5d0Ú¶mëí*€jÊÓ°¸óÀ‡qç5î9â#t >@â#À}gÔ¨Q¿ù¹ÄG€û˨Q£’’’~óÓ‰÷‘;ÌŽ‚øpÿ¸óì(ˆ÷ ÷ìÈÜGxR*;2÷º‹ÙQ|ž{^¼ó¹µo»…ëËqÛÑÇçž{®jê@`Rz»ÔÌ}€ÄGè@|€ÄGè@|€ÄGè@|€ÄGè@|€ÄGè@|€ÄGè@|€ÄGè@|€ÄGè@|€ÄGè@|€•9ûc †Vï§®p¤§ÌŽíÔ¢q]ƒÁ`x EñëÏ;îQ¨6*§gǯÏ)±*3eJBŠ£Uìì•ëV.ˆm|8q`ä€õ™÷¢DT)åm7J?2r}§XÇœ9bÁÿœßT!™éŽÆM(ÜÂqx|‹¨ÄŠ€oªÄècæúø„œïÇ·¨ë¾¶î­ì(„¨Û"²©9é9¼ àÓnsöOºÇû ‘u=må8¿ÿ¼PZtjêq+Ôtµ=?ì8=;~}Ó„ó=žæ5ž_6>)ëáq =ð°j>Ïñ1}YüûŽøý±M=mä8<¥ï„#M>5Ûó%j>Oñ1sÛø„ó–­o%‡p!„Ñ“ãpxmetakernel-0.29.4/examples/workspace2.html000066400000000000000000000327571434565236000205470ustar00rootroot00000000000000
metakernel-0.29.4/examples/workspace2.png000066400000000000000000001115731434565236000203610ustar00rootroot00000000000000‰PNG  IHDRe±m$‰sBITÛáOàtEXtSoftwaregnome-screenshotï¿> IDATxœìÝ{\Tuþ?ðså2 ·¹ ÉàeÐbÈ ¸&j VŽÕBûU±-ñ[^Öò²»bûUÜ ü~7hK»j¶‚» úka+±RlMÔP*AH«3Üæœ3~ " 8¤ïçcûÈ9gÎ|˜f^¼?7›öövB!„Ò޵@!„BF5Ê‹„B!¤?” !„BH(/B!„þðú?¼wïÞ»ÓB!„b-/¾øb?G©¾H!„r_{æ™gú?á6õE‹þ#'!„Bù…jll¼í9T_$„B!ý¡¼H!„BúCy‘B!„ô‡ò"!„BéåEB!„ÒÊ‹„B!¤?” !„BH(/B!„þP^$„B!ý¡¼H!„Bú3 ý;•••P;ˆ—˵v!„r‹Å·=gpy‘Œ4???k7B!÷Ú?šB!„Ü)Ê‹„B!¤?” !„BH(/B!„þP^$„B!ý¡¼H!„BúCy‘B!„ô‡ò"!„BéÏÝÍ‹ÌɹL•©æë–&†ÉdQéªa¾,!„B¹Göw†„„‰½…Ön!„BȽçÞÈ‹>ʤT¥µA!„rOeãU9Éë£Âä2™L&‰Z¿ûd%ÓyŒ©<¹{2D.“Éá1‰™™ëCdañE néfŠ2ã;Δ)Âcâ3»\…B!„ Êhª/ª2ׄoÈBÈŠ¸ÃüQ••’˜´2;7139ÊМܵ2C£X·+\Âä¦%nØ ¼o½ Sº;zqRwøæ¤Í GmAJ|Ò¥JýN„øîÿH„B!¿x£'/29‰ñYZÿÍÇ’×È„⣌HˆOÌ 'T•š¡ö^}856P`NDˆ,:<6÷ÖËhr’vBÓwGI 4Ô_“•¯‰˜C‘B!dÐFM4Sš«†L¦XŸšºÙr_yˆrý÷c*%Æ(Cd–«*×ܼ#!„B¹Ñ”U™k—'d Ãã>ÜwàÃ8¥0;i¥rMz%@sr³ò™¸tbî}ö%Fù”¦lˆˆN¾™ü´Gâ«Â³ŠŠòÓcåÅI+£¶åh0E‰Ñk÷”ú¯ùðÀû’¢¤9)bâó)1B!„ ÏÚ èÄä$Ægiý7K^#@hDˆ2"!>1'üPÕ*ɲé ¡–ƒsÂcÂ6$Æe)S•b€ã¢]»×„ŠF%ì*Í]¼')sMz4 r«à¿yCL„ Bƒ%Ò]ÙB0€ÐZ?*!„BÈ/Ȩ©/2¥Ù¹jÈ£•²›1N¦ŒQ@››YÉTæfWÁ[|ó 4lÅ›ßÙ·,Ž ß8(”…‡HPU¤T沤(eÌæÄÔc9¥‰‹¾y*!„BéϨɋ`T@ìÝ-lj%b4 ˜Jûˆ»–…b‰¬FÓ‘…’G…€FË@›þÏÄ¡(ÊØ·vyD°,,&ñæàFB!„Ò¯QÓ-KÅ€¦JÜŒŒµ†…X,†ØGh*5]{‘M•ñ”¨U«ºÕT© I„ ŽŠÛFU”“ž’˜²gåYNj”ô®ýt¤‹£?}wùzc4´\›ÛÿÅb/®œ¾@ÈãùÓøÏÕ†ëC¾û#rúíÔy'“ÿjÅ6rokÕ6=¶>ÞÚ­ äž5jò"|ÂC${2R3K£×Üè’®ÌL-€ <ÜG(†ùcOVjQlÂ.iUvJ‹àðÎþ뜴lU„Ò’5'SrXGŠ™¢ø¨èLŸÄ¬Ýb¡4pNT L“;'¡²TÅ@J#ï®ýxö'U5àgÛ蘶þï"äò¼s:ó‘qò™~“ûˆêO¿?  ©U×j`‡Òèá Óëœ:êY¶¥¹ÞZÍ äf2Nýë€ï¤ýäY»-„܃¬‘+íNVu«í‰åʨÐàØ¸ð¬ IQ1ªØáþ¨ÊJKL)„Äož#Äk¶Ef®L‹Žbb×(åŽê‚´]IÙ¬|õ6¥°ôH³Ù¢ÖWÆ*ýQ–¹+)K+ß¼-\ ¡X©§¤ÅÆÄ«W‡û‹5UY)»Šá¿ºë8I2âê´M)ç¿áq¸f³¹¢¹¡©Mg2›xßúV­Ÿ³ô?W/}WYöBHøÀ –²¢ÑlºÖ¨jjÓµíà¬Q“Ûta‹—ÉÈhUµVl !÷°‹ÿ:0ûéhÊ‹„ŒkäEõ‘= GºÝâ©P†J¥ÊÝYŽ»ãßIŽ_›ÂBà­_ýa솀xNRæÀøw’7d°HäsV$îÞx3õ)6'*rwm^[Å:ú‡-KÜk9( NHÝ'NHJ_›ÂŽÞ!áÛÄÆR\¼k «>úS>íl®Wéš{wÓzIUéáè:Fä4ÀBcײbE“jàÙ”B!·º»yQ8'¹¸´¿¤sÖ¼3gMÅ¡1I¡1I}ÞÙ'-<Ããp+Uw-zOý\dÓå(džCeEB!dØÝyQ—]Ú[G4±²ŸëZضúÍð^¶k¡±ëíTV$„BFÂ=‘ɨtôr>׆Ө2"¥>K¡±ªY='÷'‰ßxñ“í\­ÝÒSKsCí•‹êò+Ön!÷/Ê‹d¤×Uͦa/.ŽBf³¹­QãÕ¢×Ú¢;V¹¸¶=ΰRÓÈ€ðø‚qÓÂ\¼|­ÝÒ;{'Wÿi³¥~WÎ~c´ÞBª„ÜÏFÏ~€ä^ØŒÃ5lq”Ó×Õ?ØÊ>Îå{êuãkjæ]”WVòL¦ÎL¬Ad6õsb]¾A!G?G©ç¸iaÖn!÷)Ê‹d¤ð8ÜVƒÁÚ­qlK«¡™&r°utî¼qœJvñ¢¸µÕòO#kp7ÞûOÅ/”Xê!ñoíVqñòK=¬Ý BîGÔMFénÕø²­‘O˹ 3“3ÕnëùèÔ¹3¿N,jB¦3¶2D[¦EÛíª&Ó#—.U9;/óL&…ÙÀl¢*ãmpü×E®)Ð|sôÿ’ëwã%L¸Ó«ú¼¤øÒr¯iˆ‚¶î}kÅÖióãûO¾xÔÿõ”Ã-Ã7uYŸú]no§NÞváãyâA?[™søÝ¿ξxMÍ¢±3¯ÿ]TˆÛãõGWF&V-y÷‹ßÝf3÷€)Ú$‰»Žò"¹Ï §†þ×J/žJ7Äßkàr8\.«×ÝzÔ»©É»©cK›úk?˜Ö¡·”Œ ¡½ÈJ\›¶åO]À—x¸ ….þn·½ËÈÐæmß’Qû·ðs}˜ÚÜr€€ß}(.Änݳ ]îÎß?{¨€÷ä Ù"T],Ìûòƒg³Ïýåï‰ò¸-|}íáy»B?Џ¿WÄÞÉeð „Ü)Ê‹ä^aªÉ8ûµú’^bÛ2²?[[·Í‚mÚAï…x2«¾Îùä{ޱ\sWŠ‹%Vêßdj³¯p~oʶ)‚Ûž>bt¹;3Æþñýy>7o+-¨Ds?ÉŒ ¹ã½SUY‰+•B4ýõ÷__6ALEú–—^É=·ýa;çI>¿Þøü¡Õûã÷FܤèûA…ŽwÚ BÈàÑøEr¯0·W\8ÃÂeéÛ:Â"¡oÔ–gû•±%ªÎIq€տ Ôfn?TqÇJfw·¾Èä¬Y~D (sÒ£¤Ýª2£Ã6ä²'ædöz¤)pÑ’±NS[yù‘¸›ºŽ_äOÜú¥œýqGæw’g/öëeÇÚªëJ¾ùáÛ£×|ñôDe˜å½&ü\òd4]IÝt®f°IÅA(ÄŽMä;L\¨óôòðCSsé…ËY‡J*Z,Gç½úÄ~€êÒ»±ßu¦,ÇÐÙ›_kÝÙį2¾7؆Îɽõü‰wº<ñìĉ~v| U¥þñ낯Ž^¿1ð’?qãS/Lã^zû«œ‡B—Ì—ØÁÔPX°çåjÃíšq£©“*æÍ÷ô“ €m½^Zs6£àtq[ç)¶²qODNš,w ˜ZU¥9—¾Ì¨Pu´¼×ñ‹|ßGáó}d~v|lkUqùéŒΗv¾Rü‰ëžza&÷ÒÛŸg`â“‘þ?àåo~øòhÍP¦@éßW<öáµùt§ã™7?NËʯӂ/?kÅÆu«vejN¿³óï9¥jŽ~Ó#×nÜ<ÇC0?í]øüÁ*AÐÛo)»u1³¹ñÏ<û¥ÞmÒ²ã›wt,&X¼I9´íÓ†-øs‚Þ>ö–²KùnûÃëΰã7þçï‹¥óãÛs_ÌÔ,øëÙÈøàï)Ù…U:\e!a‹×ÿn±¢{õ¹š—v(#-» ¬Á8øÏZö‹+î\cR—ý·ô2¸D>7£ë‡gå¥ZÀûaù¢2å'ŽÔ~ËV÷èeö\¼ïàâ'KC—†‹ ücî¯ãB¨ŒHÈhb¥úbArVe›TÙ©¹_V‹Éß“t¤èÞ_Ùï~äðÐŒèM“ÇIZ¯^û¹DÇórZ¹ð·«|ì»ŸÆ ˜ùÛ±N\[ûV};F9ÿ¹ÕãÇI ©nnfaëå>å· ¢—¸qXUNÙ¥âV`›>[þ㩚>®ÓC+@ÈåÙZÎ~Ì“¯*_XêççÅÕ–«KK[í&ÍŸñrâìiž04zïB9 H'-‰tëøP2î¿Vµ®>óÅ÷7";?Åš­Š)ž¦êÂk—JšyRÉôß.ؼqœK÷i®Î^1_b\Gè h8L[÷øŠ¥~~R\/W—«¯·Ø‘û?µõñÿz¨ãle¿üÚÌ™A.vÍåÅuåå­<©dÊâG6m(íkTßù‘­O½¼rü$?;cucyIãuƒwФ%¯)ŸTÜý^®ë£ó6oš<ÅÚêæ=ì¤ÅÒy/ÅxÚÞÑkPõe“ëvf\„Ïd™¿È ¾òí›ë^IÊJ[¾ôÏå4HÇËýEЖŸÛÿÊKÛ¿ÓNX¼b<À¦ä4t»¶ 帯Z4AþDäÒ§§KÀaÆÊ¥OGFä0ÊòÃk—þaÇ—Eð”ù¹° ¥§>Ûù›ß/貆•êä —ýiÇgçÊà;#dúŒñ(Ë?¶c]ôÊUtœUfO¶¢é‘“»Ö8ueßÕ|oQá;[VÍ3üÌù“­Z»óDQ·9]¢¹RXH‚åR芲Òâ¶¼²ü…߯Œ{?%§¶—Õ¶#v€îÛwzpøTiKÛÕC95SçÈíxÍ•§>*T ¹Ôd‘•&mƒÖ…ÍöãBU~(ñìyKO»½sèªyQÓÆ.yiRõ«EÕk.øÄgóJ÷1‹CÃÏ~õUè‘—fLÀPr!%£ûc©‹¸üÒljß]n[yÐ ›'ûM›±|öõ÷þݹwLSÃÙ¼C×Ûœ¥úê¶5ƒ' ||šúêC[³Ï«-ƒl'¯z|E˜Ýô%þ'¾¿¬‚í”ßN\ÿú軟Ô[^JžoàšW~FÈË|ëóÏñ}6ì)¹¬úßIÙ_uÔ)m'>;ïùÇ\¦¬œýDùW_”Þ€0&È¥!ûôÇÉ–j%ßÉ‚µ‹]ÄaNɨ9?ô­€ª² ýŸ~íÓø¦"åŘWJ?Ú^*Yûõ¶…2!€ÚÌ-«6e7fþ½`ëÈá±hIÐŽ„ÂÂC'*Eu~Ì©rg!Yî&/]ÂäU}vî|—ýnSGr0iŒ½òmÞøÈ¿½½.Ì ˜ŸÒW¾øA^ùáwržß7Gõ'¶l?VþŒµo}ø\ å×£òäϾrìTâḬ̂·¢Ü úîh! xxž¼k¿3S›[n÷áÎ<8xûÉü™Ú²ÚÒ㇎Ÿ<ýöqJÏA4Su¥€Ø±.åw¯¼™ã]v±ðÔñŒ”±Ÿl[èÓ­Ë[¤x"Ù…GŠ4áP!£‡5ê‹>á1 §f•v¹­2+µ@­èÚÍ”fƯ‰ “Ëd2™L¦Þ–^Ä@e²2pe6 Îx&P¦L¾Q©Ôä$¯ ‘Éd2yXÔæTª>þR±uÇ÷t„E-ß_øúk XìÓýëC}â½ïJ+4¥•—¿×÷Ù\ýCfGXÐVšQt€ÀÅËiôÝåyúG Ý©÷n¤4-M9åü¨üçtåÿ“QÈN¾ô`P䬧¸`«3Þ»|Knþò½KXÐVüáC×ﱯ®å½¦²C•”Õhª‹+ +ÌlÏÙÁ€AßÐÒàÚ.Êùü`Aúau¾ÀÑ Z«Û:s¿±âRFrÁ—ÿ¸p^ÕÛKhï>[˜J“Ï|u³S»íò'ÙÅ&À)t±W·ÚaÓ•É]Û†²Ã?\b8øKïèÕE¼n ‹„¾‹–È@0ýõXKXà¾dº#ÀÖ^S¤aKˆ€+éiW;¯R{üP!àþœb˜bûª×;Â"á„ÅëÃCY~GÝ®4kÿ)Þ´óFXà3gÝÖ0wo?×°[–]À'Ø·[“,“]ùÓ¯}ýíßüè迾¸°?v‘Pûí¦-é]?ºoK[¯Pv(áÍ|×ÈØ¿ž8öÕ•c>ݦ”UÇŸý°¨Ç_Zb?¹7À^9Sv_,öOÈ/†5¾3…’°˜”u Œ¥™©Å’ð讃eT™k”RJ½c’ö8°oW¼RœŸ»&>Ÿ|¢vŽWŽá»Û}ãÏ÷‚¸µÉlȆ]eÄEÇçÐçÍ/‘±ôÊÏÝjAæëgkô|}¤]û¤«+¯  d¤/®Ót M-z \û>î0ŠØøÐTSPÑ}O‹ú|… øNíìÕŸ·¤7¯ÉÏ.vZ ÞÏ饢V]RÐm:Yõ}ùu^^^]žCIyu—çl€Íh+/¯fçñkwD,vb\l  ¹ætfQNN½€AWú}+¿•oÞúø£>^NÀ\}ªèÄÑŸ/÷6O‰ççã%XõÙ =¶!×ÿøÚð|º&]CIåõ®¯¶¡µ±—ÏçÞzñ?«kùMì&¿éò®ìD®bLcùÔqT¬^àÔeº‘‡®žH¹¸Î[1y˜–ï…w«ó $ž®Æ24¢¡øø5A‹¦w . #õÛƒom›"ÊÊõ¼èÞ$·y¦íùtoò'[¹ˆ!ž°ð·_ðp%-åÇÁŒ¾° Õ`½ýÞ¿Vø8 àè¡X´é“·ç:Uÿú8«¾ûùnÞ®UÞÝ…!ý³Êz:BiXt˜`CzzéšX”¦§–y+wŠÓ;ÏÑå0²°m»Þ‰‘BçÈ5¹IÅ*ûˆ}dÞb@èè-“ùaù<„ìJß­”@„sâr³J™ÐÛ,ýJF¦Zß#蛚5 à pp°:§W´èZzÞµ·«ÝRb3ÁŇ^ð…ß?9Ž~|pÿrrïÛ8zÚñ€ŽçæÊŒ®É6µZÏŸû¢K×}'Cµ¦çîf¾—7ꎭj¶K/ö€›¡.?ð‘ûó«ü½¥ÅcÅcZ¯×üøÍ¥9Mm`®8”ý¥$ì‰ »1Aþù?º•úò÷e9‡Ë.«{Ë‹Nb-š['¬UšV¸óíìøÀ£­Íl÷UxL–muîìsÎÑMÔËLj ·»V,YèýÙÁªã‡ 6†Ù¢Ï—þK¢úY)fpD®=§U[R_G–ÓUéð}<û‰§l% ÀA,èq%ô€[ç ˜·Ìïãå…W0eÀ‹ € Wwk‰8xÙ"×o6”/g•n] p V§¦m¢ M¬³þ¢P¶,T°63½hCl )JͬòŽ27ó¢xNBêШJ+K+ËÊŠOfU>š>k†2åÍÞl©¿9*ꑾ·tk8‚[ªØpm˜ÚÁáwEço'Û\ZÚKøL­Å­]âßkªe’ ìš8QRyk}±× -bèvšéÖÐ scNÎÎ ?øOõS„zÊÜÇ8Û‘û?*÷Ÿ9?ïÝÄ•h©?‘ô¯³¾žŠ™~“#óñ¥’)ó%SæO<›x,£—ñ‹·u76Ì駿ūÇÜ~åDJþºàŠýYu€|Eøv©îc6•°ßè9¿AöŒ‹$"`´r–ª§nÒ­ŠÝ€½Še[Ÿak®1D¹•µÖ뇮˜#X™™^º!PV”šY%_£”E]Î`*íŠKJÎ.c¼åÁ²þ?!Óàè{‚PbÇë¸R{zf Å»‰'0¶·ÄÅÍZK¯°úçôÄ¢ÛNÅqœº<ÌЕ–ÛÉüÜ#_ (ßQÒã^vR[>Ð5ôñ$.ŽÐVÝlzͼƒk ú²œ¢²œ"¶’1S{ðÉÇÜíäSŸ—ï¿Û*jr*jr|[¯‡üæ-™ªðršùìøS[{^ߨ¬×b{± =±@‹^;jjôXðÛ „í…Ù *q"«‚ਚ)Â2Ýó˜F«|­Mä/`¨¬Ñ®]0?ȸïÉÓÃIô*m·Ä¦ù.-éH‰Ö/êçzôÏ4Té@â×í‚ý“>ì!øÇ5¶¾DÅ,ì;ª›>¢îѵ H¬µí!ÃÁl6›z[dÍ`0¨ÕêÖÖV‰D"Ll±±±áñ¬¹ÇŠÕÆü‹CW„;Ve¦iŠR³ÔòèpŸn‡™¢]1k÷äHc><|2¿´´8;3u[øme$÷^À¸îkçð=g{ÚÆŠòë£-/vàòðmí†ù²Ú’ê^]Ö¬ðÅó^}òO‰ËC:n‘øZЩ:˜ýñÛy—Xðf,_èÜó³ÅsüDI×sÆÌôsP^^ÝŒ¾ ¬/åü?íYò§Uc:´M}ýü¡sgU¸..œ|–'>ó¿{"B;Û`h«¾p9ýPµ€“øÖõöŒå•Õ, ÌœÚcI‡‰ó% å5×Gm^´¬&6?cÏÁsZ8„=7ý6Ÿa‘X@WÖm¢´®8{ëW»*ÂÆ(>R¨êv».÷oooOHØ‘£D>~Ôåݯa 3¾üöÈ?ævŸ¯Íüºrék IDATt4­@Pä”AD9ñø… P{&ãJ÷Ð{õÌñr@¸À¯[^djJÔ\e>Ta$¿d‡ßÎ z=¡/Ö ‹°æþ.ÂàèpGuVrêž,"¦G\„¦ » ŽÊÍ";&ÅVæfu[jG(Mg¹79Œ}lUÀåø8.³g(Ãì€Ö‹5# #{±Ã¶ÅÀáóG1¾ípa4V”d›Ñ£›fÞÌj|Û‰Kf= rõâ–—[†#:„®ž9É(/øG›ŒêŸ3’« €÷ÒYá¾ÝÃ’ÈÕ¾íä¸Lº|±`Ì(ïž)†Ð sCkçÀu ›ú„üæ3i0E @WQ΢ES ßAòijãn®¶ÈOyT u½/[ª³Né®,&ìqygd´õ_2+RÎtç3ª{í#%+¸€-<˜«‡ë¼ÕÁ·‹YB?×2þv¢²ããMWt$qËq}¿wëlѲ°ùooùWIçg¥êäûÛ³õ@Ъ9€@¾ @YNE×ÎkqðÒHW@wfKbg3À\=±eËÁ*À{É ‹3õE¹ßäþXÑßg±Û¬Í¿vêöǽYs#2j ’¶\x?ñ\X÷¿,ë5 ¦Ì†­e5Úo`ccÀl6w²fËÌŠqU­”d¤%e Bv…õü³[,WHPœ™´kÎz¥¿PUœ•²+¹£b@ˆÅÐfïINU†(ÃésåÞÂÚN›ñÜžÀëmpr#å¦êÃÙ§ŠG¤Ä¨[àgë06ê£%mªòÏ·æT*–rüêvŒøÂÞW…ne F“ÙÑn(ïRýù÷Îøo ›îå·$ÉçñòF•ëâéâꀽ´ïLNàHÎzRοÜsÉÒuÜxê\F¨rIÓ£/).ný®KO. ¹âå÷&VUhŒö.~^׿9“ÑÛä˜A6mß÷Åy÷%Ó\foýMPµZÕlâ9‰½¼ìø@Cö¹¬R3 9»çRÐk“¼§ÍŒÝó`U…¾ ‚Žë°u_î+ïmõAsÅ'ÙŸK<$ytkäÌjuu3}%c,ý쮋/ŽFÅ’…þŸ,¼-–ßþ-àùßsßyå[õñ„yÙ{åãELyi™ò'"Ä_ôÒ´n w¾^ðì+ÇN%®~øïò "¦¦$ïJ#à²`[l”'ˆ§,žÂ¼+'Š™Gnî-Tl~ciñºƒ…ÇæåìŸ1ÙW¨«È½xÃbÿ¶öf'µ*kç³»Jáªü4£ŸŸеyýêKÛsmŠ<ñîd…·HWœ[¬“_ع±G—·® «à‡<Hã‹È½ÄÆÆ¦½½Ýl6³,k0Ìf³Ñhd†Çãqo ooo·DÉÑÉšåMa`´Ò;-Eºâ–¸ap\r"·+yÃò=Häs¢¶en.[³8© Xƒ@)„kÖ„ç&d%ÅåGÊÃb¬Ñ|2RJ.¤~í23Ò\€,Û\\þÝá ûYañÕ\ùú Ûc‘c]\[''>zn=Ô?¾PXÝÖ6…eùv=û£[YCƒ®…5t´|H‘±¹òÿmͼùà¼PO/?‰ Ûz½°òTæ9Åmx¾“–ÿVªž=us½ýùä¼i‰3e^“–?[ùvòõŽ›«‹>>„Ù‘'¸óÁ6””þ!낦×y0ƒjFǃ¾ŸÙð¨"b¾§¯—Dæ€m(¹vñ›޲ÌF[éw»ÿG9y²ÜÅ;@˾‚Ù?ŸÈ¸Ôëüh04Nʬ~ôÁyó}d~™ z]ùùÊœÃ]÷¼-Í öNƒ78ž³¢ƒe:ÙŠ_ äåÏÙrôí€?œ_W|±A2~Öªÿ~aý„âß|yl.³å‹´Y);˜–S|*€‹/)ñ˜‘/Ün¦‹õ',Ûú„ ›¿?å§!Ôít¹_–'õ, S”òq1<”¯ÿº¿_“|½>ííí---uuujµša±X0ÞQ2œQ¾ôàªÇvul`%Y÷LJGóÚ0¢°eÿ9eç‰,T®ÕœLÜþ£bëÇóÑså—ì¯u‰|ÿÅ~–4oinP—_ŽG#dµ··ëõzµZ­Õjù|¾³³³£££exb×AŠf³Ù`0èõzFÓÚÚÚØØØÞÞîìì,Ú²¯#‰ê‹„ #ÚKÕ5%Õ{ºë]ëýÆ^ýU¨%,Z”ÕUY±y¤Wþs¼¥¹áöç ˜t‚Ì\ä 6~?¸f޼þ†Ršÿþö“ƒ{Äs¶Íx=j@‹JÞNýÑí;‹ý—¼þzßÙº¥¹áÒÉ/‡ãÁAf³Ù[ZZlmmÝÝÝÇŒãàà`é†î1£…Ãá…Bwww'''³ÙÜØØØØØ8 «ŒT_$£‡æè‘¿µv#î„ÆlÔ<híVô¦-ç›Í9ÖnÄèe4°—N~é>~ŠG@ —? Ö‹ÞòíÙ-w~»Füð¦oÏnüýâáZÂmᾓ û:h2°µ%EuW~4Òd2ºµ··3 ÓØØ¨×ë…B¡D"qrrê̈ýL¶µµ•H$\.·©©©©©ÉR•´ÊXƾP^$„ lUÑwUEßÙ;»ñøC[‹“Œ£ÁÐÒToíV2 F£Q«Õêt:gé†È9–sø|¾“““eŠLSS“@ ‰FÑPÊ‹„rEBÈ †––‡ãäääââÂð˜uKWµ­­­‹‹‹ÉdbF¯×ÛÚÚŽžEvFQ©“B!äÊ`0XÖYäóù–‹·žc6›ÛÚÚZZZz¡h‰Œöööf³Y§Ó1Ìͥ嬾 ÌhÉ­„B!¿Pííí–º ‡Ã±····ï¹C¬¥«º¹¹Ù’¹\®ƒƒƒ‹‹‹­m·½Áx<žƒƒCKK Ã0mmmwç[u¨ åEB!„!êÜÚ²} Ç …=Š‹F£±¹¹¹¡¡a˪Ý666 ØL&777».ÛƒÙØØ§×ëY–5\.×F)/r¿0›FjWCB!VazhÙ¾Å`0ðùü[ƒÃ0MMMmmmf³Ù²O´e;éææfK¾ì:šÃáðù|ËÎ<ÏrþÝý±z¢¼HFŠ«½£N¯/kÔÜÉElDw¾ ÛÒjd¬¹–•©àà"åð…¥Å­ØB!ÃK¥R™L¦öövKäp8=¾¶,cY–íÌ|–ÿ°±±±ta ¡ðæÚT666\.—Ëåêõúëׯ[þ›Ãát-CÞ}w1/2Eñá‹Sú\´Øó±¬5²!^[S”Ÿ•œ:\‹‘;3}þ'Ù_ç6ÝQ^d4:©‹À~ˆ¿$f³Y¯n4è­±eó-¦=ý\yñ÷ÙÇhÁaB¹w444ðx¼öövËK¶ëz‚¥7¹³¬Øãe#é×äp8–úbKK —Ë5™L@"‘ŒôÏÒ»˜…>Ê Û|:“Ÿœt¤Ê;rsÌ]ê¥!Cß)MÞ•‘¨†V’as"ñ€ÚÿÀ{ø¯Ãå‰S™+:~û` lK«^ÕØn6›Üá{ 8V®¦›t ½½}æä¥ÖméŸû´jM‚óÅzk7äžå%á‡=ìSý0ÀBcgYQhÃ[މRG#k0µZy{%º8ú™M&3Ã1´ y|¦µ•5š¬<`èžÔÔ"ИÇ=0Fä`{û³ õ,e¿ööv­V{ýúu£ÑØ£^Èáp,SX ƒ%#Zn·±±é<Ôõ|ƒÁ`4Åb±D"±Œelkk»k?Q¯FßøEM~j|Òî¬Ü*-Þ e̶¸˜`1UzLXl¶tÙÌ„P1&?^ùLŠjчʔ𵹲WʼWΊ ¤:J´Ôk´µwºú±Hêâèáæ]Ò²Ésj2sñ¶…Æ®eÅvp8\Ýõ&mm=Í5!qñûx*à%«¬ÖèôÌíï@é{}ãW_gÿåµgšâgí¶2 ,•¿öövÇçó-½Ï=Î …ÎÎÎ&“©kdäp8"‘H,ß:ÞÑh4àñxÀr}«×GÙzÝšœmÊgâ2TŠ5»öØ—.ÌJx&j[Ž€4*q×"Ǫ´ØÄ  9¹mMJ™÷²Ý þsvÞî(âKÝ £°xÑ©¯ÿTÎh[Ùš¦hµ§ÒqÛÒûxD³Ù¬½^¯««´sVBá 3Íê+•ÍU×),B õBÇãñL&Sש-–ý ÝÜÜìííy<—ËNNN‰ÄÞ޾ǞƒÁd2q¹\>ŸÏår{í³¾ûFW}±45.­J¹/=iŽBCReDR\jLÖ¤ »"sW¦Å&†mÐÄf¨å«Ç…ŠHeÞŽB@ì-“ùPZ¼™ƒºäZÿ…F*+B± K¤³¬¤£×ëu:H$걪"ŸÏwss‹Å«äXâ`â¢ÑhÔëõ–Mb„Ba×0zW¤[Œª¼X™›YÇȨPñ[„>aáþI{2s+×È|ñœ¸Ý+rŸIY AHü®Xêx¾¯èT­ËXÑfϺIŽû¿?Ñõ„®£Êk]‹•ZJ!ä¾ÃårÅb1Ã0F£Q§ÓõXU±s•ËúÞ–ˆyëEX–mmmmooï±IL¯'ßM£)/2šJ  ÍX˜Ñãˆw©†„ÄÁÑÑþ)IeT† uñòËÕµÐèñ“~‹Ë,-s³oÚÁÈáp8TV$„r÷Y&¯ØÚÚ666655Yú o=­¯¤hY‘§±±Q«Õ …B‘HÔµ¦Hy± ¡X*°ìÃ]Ñ=º•…ÒŽQ‰Léî IeÄmHI¡ÑŠ÷£ÎB£pìò6 åÕTV$„b|>_,·µµétºúúz'‰n{/Ë`G£ÑØÔÔ¤Õj¹\®““SçÎÑ£ÄhÊ‹†„x#¥ Lq#jrâ7¼S%ßœ+‚)Úµ&©X²h_jœ6.|C†äô5–>iŠ÷K¡q/(?ÖÅÏC(²³wßþlr;Œ¶¥¥QÛX^«¾2œ/Óè1Þ_â7ÖEä tu±¿ýÙ÷–5Ö7¶64¶äÿPŲw´Š!¿\666vvvnnn–=]êêêÌf³£££¥:Øëž~–r#Ã0 Z­€““““““Õ'¸ô0ªò¢0pC|dæÊ¤¨˜ÊØáþBmqæîÄŒbiäj™ÐäįÙS&‰Ü—0G*F|BfΆ¤ ‰!™qÁB¡ØG ä§ìJU‡…G…}áorŠìÇ/˜F1qx í…Žö.¾î“Ç]9~~ô}Ífss›^oëÔ"tò0µˆÍ=WÌa†þ?EÂsÆSLìA àyº;zº;Ž÷w˽Pq¥LmíbÇÁÁ¡½½]­V·´´ÔÕÕµ´´ˆÅb[[Û^ƒ3 :N«Õêõz‡ãäääâârëÔV7ªò" ž“”y 0ñäøµi, ðV„o;*†ædü†´*Iä8ËÔi©2>13gmʆøðÌ„P™râôÍGöÄåKÂC#蛟 OÀ§°8¢ì]Å“½øù)#kåõÒ˜ÍæjªåÉUü1­­†ÀÕÔȨ»¦Fs»YoâõÕc!ð_0ÉQD=}x³gú³SùµFk·…ëàr¹"‘ÈÆÆ¦±±±µµµ¹¹Y¯×ÛÛÛ …BgÙ`Ú²È"˲mmm–)2ÇÙÙÙÙÙÙ²@·µˆž¬•Å©¥¥½‘†Æ$…Æ$Ýr‡9I¹¥Ýn•Fì.輄ò,å;ÃÞLr¯óž@aq¤ í}C'—eX»!hnÓÌ&ÇÀ)®j]Uk3€®ýi{_¦a’¡c4h1sûʃ¡S}),ÄŒ‡}kê´Ô1Mî[–ÈÈçó5^¯gÆ`0Xö¶,©h2™Ìf³eohGGGË—Q1êÖë&d˜ð}ƒ¦oýïéòÛŒÿpŸ<îî´§7ڂï.ÿV3ø{2µß&myOÉ/f÷I€OÐ_÷Ê_¯;Ôbhc¤¾X¶Ûôù2¡ë7¶¾ \»æV­Ù†×ÜÞû>u/À_2¢-ì—¦èó-¿5K×ˡʣ|xþ³I]ÞLÅ©=ñë>³`üü°ñóÌ\õǸô|U×ûèr7>6÷Ü!¼oÏQ$ôó©M¢ ùEàp8¶¶¶nnnîîî+uÛØØXVÌ1–%Åb±‡‡‡‡‡‡““Óè¬,ZŒ²þhB†ß[ûôxg]Y¿g‰=ÜîR{z£9ýÇßì¼€ ¹ƒ¾'{ùßÿñ£:ÏçŸþV{W±¦¯Í!özÝ9Ödh—xh½e3q†'Ìáùðø3‡k£7ÔÔi †žµ1ëŽYÔZûò_ó Xp롊O7&払®è(}ªòÞüÍŸ¾¨à0cº‡PWQPœwðƒ¼Œ«¼µ\!ˆB¶nš17áµ-³þñá##ð«@…XBlll,ÐÀl6›L&K÷4Ã0"‘ÈÅÅ…ËåvöPÚ¤hAy‘Ü“x£k^ÙpûÅÔên¼^­€ý˜1úÚÚȳ“¹¶N;ò-&5)‰ï:<òÁ‹“;ò™îÔö„/ª za×¾e“-Ã-˜Úo¶ÿþµŒâ=÷*Ž®ë8S:ï›Ó—ìH|7Kñjøí×ü$w1P5ÜW%ä—§k´±±ikk3™L¶¶¶–å¸ûZŽñ.¨¯¯×jµ,ËJ¥·Ÿ(LýÑäþeF/K2Jžív>¿µ•êÍÃÚ–a¡:ýnR1ü¯î |šsŸ×²Õ;o„EBù[7>êTø¼øæÏïù£ŽúïØqøÿéuéBîO·&B+–Y–-**ºzõª%2ä.T_$£ŠÃ˜… œ ñq°ºæÒ«?>~éûæn_ÔöÞã–Ì4õgVUYóÍé‚£—õ°½:rµ@ä¿u›?Ú®%î<õýà¿Ù«Yû?Úsæ?…×t.B¦+W<æÑ­—MUþÎÁÔãåjƒ@"›ùÂV°¯ýêϼ—þóè‹Ò´¨Ç>.ŸñÚ[ëþºiïÉ2ƒÈêÓ]ûä³ë€Â?NÈÿüŸ÷d!(ÍéÕSÿ|P³õ¬ýp‹Ü±¾rëŸó0å/Ÿ¦D¹Þ8¯áèòßl̓`öÿÝ7ÃñÆ­Õ)+žÜqÍóù=ÿÜfé¹Ôý¾?%íÌ…Â: Œ¶xÙË‹å#èãá™ëe_ýÐÌö›l¸bˆǾŽ÷¢¿×‹ïæ³pnàü©-0éÕêï ŠåÔ¨‡²yk2º–¡æÅþ1¥§“ß=x:»¸B €ï*ẄŒŒY6óÛ¦!?mÿ”3e¬À% láê­Qì–ßlÍsþ:eLTX³§,hljßÕîHØsüë8vÚMºö·¬:@Áïž ÿòéî(WåŸf¸b±_ç#hà;[Îb–¢ÇJì1^ŠkºX.tÿ÷þÃ{²–½£tŭزӗÎ÷÷„s¥S'ÍÛ×;†ÒÁ’ -Kêp8+îm2™JJJZ[[oj”Éèáà¹ê…yaÎ@›®¼Rß§‡‹|ŠB0fÏîoO5[NâxNµU9Ö@[sI­o+öóñ[ºÔgfΉG¯·€­þ±ì¬nÌÌ +ü±¾¹­Z5øIšìÕ”ß?³£pð š>U ]UÑ…SÇÞ:uâì_RÞ²Ä0¥éëŸüà x͉tGeáÉþt6wz/cÁÔ'þïÙoÏj@WiôyéÉeœÂcçêá23r–§cÀœ¤-ôx^é–wôX±ò¹‘A®^a„häÈ+þéH‘6ꑎ¤¦)9VlÁ‰«ÌŒ;KíÙŒk€ËÌH_!¦$uåïßÊÓ|Ï éŠÙú‚³œÍ8ºìooý!¬×îI¡Û©Y}¹ïðíáå:˜°ôýz9M ݺÔß €QW^©7ðľî3¸Oriç'ß}¯ÜÃfs;Ža$&í2¥éû ùËg„¸BS[”wîëçþû} =;Nªøtåªwó €»bA„ê ŽÜœ]8£—¿¾ÙþûŸÒ€¶ÖèûÛ§Ÿ·É?r,O ×Ùx‹ÆËDÀ}šr ?>Ûãæ]}æýqß¼^š¨*Í­àîÛmÊŽÀ7rºëþÌ‚NÔ(£óæze'.¨ -8ñ0A)—ˆ"ýÔLñ‰ ZB>8»ÞZbJ¦yÝ¥Õ™ûÛ&f@ììîø½ú>¾3%ëÄ»Þù茱"@Wvîë7ÖþjÕî„}½wú†ékú‘ª`÷ò¯e\ƒdúËŸÔWXØ# ÇúwÉ¢â"!÷‘»[_dNÆ(VfîÊOWÞú¥ÅœŒ\YºìŸÙ Áý~ïhrvoÛ£ŠÙ×ÿiäÊ ¯¿[!Gâí3îÔÅvL Í9vª­MÕ†[Sùéì¤Ëw£´$ðRÌ‹VÌ‹ ©½•ö×W2*>ø×ŒÅ)Ë<Ü䮀¾¾¬íQ“QÕªïBÓzúFÌvI;Xr¬ ÖëH ÷™3<<¨”!¯ôBnÅ•çtàÏŒ ´Ì^v”º‹P¬«*ªgJºÿ"iK¯éˆ}û-ˆÚûŒøÓ¥Î£tØF.LmÕmàäáÀ¿ØÔí•æ:ø‰ Y=Øâ"‡c ÝÜÎåŒØßÉBŸÀù+篠«É=s`GâÅ¥© GŸúçbOI€+ŽéT×zñ†ü†I½N¥»µ.È”}íÙÄÓj‚–&}øbp¿‹5±jO¿²ØMœÚ¥ÄHÅEBî3£©¾(V„…„Šo“™ü=IGŠFdÇSbU³—?¹gë3›'vîÝkVWUú¬ l½D˜4*MW>ÍÓ©ûí'ÎJüÓ‰ÏÉ:R‹ ¸ƒ?‡´¹o¯˜ûä•'n~‘‹=¦F­ûÃ"õ¥:p›1Ý`s3.tÛ”WŸ(êãT/¿$‚ QÓÝ`ø!íÄá=$As}ÀkƈW…€†²[ÆV}í7‰§ÕðX´ín†Š*À÷õï¿)ôºYb¤â"!÷›Q”…Á±É©ïDˬÝb%­ÕM\ž è1ÅT‡Î÷%ÇW1Þ@[}q“h»pºLfnš?¦32Ú»¬{ÚÏK$rÒ]ï˜Kk4ð$¶·<Î@8z J_jï{Y]¾ŠUyé¹z€?!ÄC—­šÁ{îÕ-‡;ëlÚܽÿófé€C(4\U :øÅõUÝ"“P¾pª#t§ögVA ˜÷€%ÀùM•Å™ÇÔ€bá”κ¾tÖª¥.@cÆÆ7—v^¦áBRÂÿ‚ +n;ÛÂÞg¬e¢ô0{¾^æŠó?çI/==ÎóÆÅùnãV-ï °W‹¾©ÚÀ>§Ý~øû£ÅãQ§SŸÛóæé.Ó„òÒ u€@ä!„Ë_À·%ñó¢O¹¦`÷¦Kô ¡¬¡³ÿÙ5(È`‹ +ºuIW|ú»ÄÓZˆlûpç<ÏÛ&yMEn)€€Ù·›‘ŵ›8Õ‰ €ãDÅEBî7£h¾K÷þhUÎîø„ä¬b5 HüÃÂ×lŽ W&+ç$Èx&0C¾ídfŒ´4=>nwfn™x+£×ÿöî?.Š:ÿø{—Ý™vA5ëX½íD½;°º%ëV³¶_®]‰u‰e¢uRÝÉ]wpÕA×…Õ Õ wX—ØW3é—T Iùë[Š—‚É/–ÝÙeg¾ ?–_+*²«¼žûÙ™Ï|fàÕç×d¤$å9ào„ªOÊJ'Í6Œ‰~äwº†Zk£ƒ‚Æ„^:&€Èþå¶J鮣ÏmãþtøI×üò¥Ÿ¶mt¸TÜÄð@†ˆÿïyˉv""r57µiã–ýîÎ䶺—^ü¤â̞ûÄŸÞOzê eÅŸDO»2ZMÖÚᄄ:I¤þå#¿í\þ.ìæçÿ²÷îÇ6}úü¢¦ÆOÔXíúºŽ4ÁÔ:„ŤÙñ3u´ëHõ‹7ÜRûÀVýÿ•ÆÆŒg¨ÚùÁã³gO0üeãóq,±“LñÊí¸ˆèÊ›&u¶²“æÆoÚb#¢™ó§y,ÔÌÌLÿÛ£G]ýÅ'OÞðùËÓâ~Ì9Oüú»F"Ššÿ|ºùô úIMŒ‡¿ <çÆÅ¾_-ÿ{qcøŸîš|ÉÔY9W\y´ÖæRO¯fˆ¨ñÐKÿwæ]¸J–ˆ‚Y…­ƒÔÁì€îèàår¥üÌ;¬ÇßðÌŠ÷nùÇMß^7QMmµ¿>ÜH¤¹ú·ê\F}¬9ý©ÊGW½¾ûï·Þ²~ZÜD®íاk)XM¶AV²ñÄŒOŸV{6ù¦üÐØ•«×,žÈêç^¹iãñÝ• K'w}ÇZK^Í?HDÔöÁ3wNy¦_9꟯-ü«Çrìü‘8‰¦Ííû<˜°—èbƒ­Ç&ODã"ÀhãG틞j ’å”k“sÖ­_¿>7Y_µ!-)}‡•tæ¼Í™qDcîæíyfµl•9mƒ5>míúë×e©$gIrÞКwÀïØN¼œ÷þº/8Ú sYø¥jçÑÇÖ¾÷ü×ÝL8VþaZánjV„\ª7)<ÐÕܸë³ÒUy_ìN¶£ù–£GDÀ¨'¨¼Ñå4øS;™Ë¯ÞøÏûM?bk¾ÞõÁ绾¨e¦]½ðo/l^;÷’î½´?ÿã»Ï>põTîÔ¾Owï:Â̺7}ýÚÙ<ßeÍϬHŒ&rµ5Ö~×z­ŒÃý+f,µÚN6Twµh©¯œ/-–¢OŒëîYd~|Ó$""Š1õ™ïÀNJZ_Tð·ù‰ÓÂN~½{ǧ_ÿÀêgÝõpþÇ/ÿÑxš™]‚t—];C7´ÆEoŸö€ß¯–owÿéÅÒÍû:Ô—êÆMØÞXWºíã‡óvWœñÃ]$L€rŒÐFMyq9íͧj¬M?´œª„AÚ.eƒÿÂdõæÜ÷Ÿ^6ÚD¶¶òÓÏ?ûôëZ6æš{ÓÖ~ò—y=Ù;,>óå×þq×5ÓÔ§¾Þýŧǘ_Ìü¿\>h±ž.]˜ö›_F©‰œ­MµÛx"b'ݺ0Ѝê½j»örû ²ë^r9ýÿkjë”6ì>EÊŸ/p¨¾‚rMôµCk\t‡uÑÀWü¨}уõ@ÉA _¸2Ù4%¢„éÑ\v1ÏòDZ>’#b5‘z½Žå”V¶R\rjÒ-MOˆ ׿•ëhÐE!`d)ÏôûÀŸühË'm9Í^-G=\àmáDÅçªøÜûÉÚ¼>‰¹Ä°ð ÃÂÓÔ…xíª¿\»Ê£ÔÊÊ^;è¸Mœùïï›OSþÀÆ_›ùâµ™ý 4þmç¡þWÙocõ•æÿn~ð¬ê@D|éÐÂ1Q‡ËÛSøþ~¹NÖ¼Q\óÆYV®?5lk¤@ Ãôd\AíM»•ˆ”2ŠýÑXõxm͉¶Ö¶¾ §y «ûù¢g~¾è4u`.5.ý«qiÏþÀž^;L\ôþ‡ÂÅÞ±¶ðŽÞÛ.]xÿ5kÿ¬°øÐÂ'³DÄLyæÝÒþ­Šƒ±~ñ¦¥‰"ç/êÿ#°áC]êTSû«þÎ?ó"kŠg26$™Ž˜ ÆD£Á0=)#c€ýX½Á™¿!Íd.1†øøÄÄ”ŒÄ¯. Hp Æ?o°N|[;ßfgÕ‰uÞñmöö“gûü¾á£fƒj¾94õÞY7#mq9í¶¶“‚ÛEDãdâ,VhØ_qiÜTU êPUcŸ>ë“Mím6^ìWÿ7Ê]³lUÌgOmÎ/]øìP3_£þý™3øš?Ý;yø/êhuÓ°— à‡ZZZˆH&“‰¢HDr¹< €a…¢ó/ Ûív¹\N§³££Ãíîiw—Ëå …B©T*•Ê€€€³ 3’üôϹ.©ÀÂåæX,…Y› ‰(ßiaÞj8år9ÜN"RMS W("j–ͧH6ðôðòŠc×&h¥OëÒ…iË6%ç?µa¿áÁ)gto4|–¿¦JýËô®¹Ãèð‘Æ“h_„Ñ!$$d°·ìv»Ífs8N§“çy·Û-‚+©+Y*•J–e†  ƵɆ“ŸæE"VoJ[cJ#¾¡jOiqanþ†Ôd]LIJ¿)ڄ䬄ä,²Öì)+)ÎÏÝ“’Sš—ˆÄèk?ºú'‡>Øʵ֞ͣÍGFÓÑÚ㕇"ã|Ní{ùùÕ‡°cÌóL/9ý~þ¤nÿÿšŽÖž~¿ “Ÿüö˜*Ä|vÊ)'ÒˆÓ”‚ZÖù< @Ñz²™Â΋G«›*÷»r 'øù ;qÑ?.ŸûüÓkæþsÕiçµwk+êùϸ99Ï qÀíÐjj/«86Ì…\PG[[›Ífkoow¹\ …‚aµZ­P(d2™L&Ajwäy¾¹¹9  ­­-88X­Vûa[£æÅª‚$s.e”™µ¬VŸ`N‹ÕTN_~à@Oz"–ézžuÇ*SJ¹¡¨$k:Ëé¦ÏIŽÕÕ”Þ\XsÜJ„¼èk—L›ôïíRGŒ±54 nÿù~ü«oÛO¶LŒŸ2LÓlÜ#ïzä o~÷óÉè×ø6û±òýþ»¹ì|$ñw²ÚR‡Ó[KïWß?ÙÔ?sâ0uL³±¿ÛõáïαÝÍköß|†Ç¨ãŸßXzŽç@åÞãûþ¯Îé}¬'ÀÅK›ÍÖÒÒb³Ù\.W`` Çq èT*†aºûEQÁåru·>Úl6§Ói·ÛNgHHHww¶ŸðEmj¶ç4ôZ¹‹1™=»uƒ.+'-y•5ÅNÇK ³Ë)|~R,KÄsŽZKó ŠLñ&ƒ)ŽÝ´!%…K[hˆä¬G,kŠŽS\ŠakÀøÑ/¦+ÛÞt¬Î×uñ¦éhmÓÑÚ ±!Aa« òuu.|k»³µÝêÇMËçâhuÓÑꦱ¡Aa¡A¯EU~¨k=ÕÔŽ¤£™Ûínmm=yò¤Ãá`YV­V«ÕêÀÀ@)üõi5”:£U*•(ŠN§ÓjµJý×N§Óår…††2 #“yYYbDù"/6nÉÏê=V3?ΔÛó5«O)ZϦçd§nr1‘q‰ËÖ¥§&pDÄÆ¦¤˳Jr2öÌ)ÍÉ)ÎÕfå§-Ï'"Mt¼9scZ⢟øÑÕ?9¶û@ÐØÞfo?éïåi?Ùâs2àBq²©Cô ›(Š---MMMíííAAA¡¡¡ÁÁÁJåi–t•ÞU©TJ¥’çy…B!"ÂØ±cý'2ʺÇ]è•W^!¢¥K;8rä,Ÿ[Cíë* ¿þú/%Ëßó¯+pz'ZO*®Œë¸Dß~4 ‹v[“£½ùoOÞý“©—úº.ÃFÅÖÖÖúúzžçƒ‚‚ÆŽ+ C<£´'BGGÇÉ“'›››EQ S*•Ã+**úl‘²Ghh¨—£ün@%\|®Zanøßq_×༡½½½©©I ‹Z­V­VœiΓËå ÃŒ;v̘12™¬¹¹ÙjµºÝnïM{#yλ 1jÓßV¸ð1¸IÃív;˲cÇŽ :— ÎRdÔh4‚ ´´´8äE-Tê ;׬RO‰lå1Þ .Rãb{{»L&“Æ,z ‹¢(J“Z::¼Í c&,,L¥R¹\®ÖÖVhbô¯ÙÚpS©ƒnyìþoJv~ºÞân±ÈX…Bæå¼DD¨†É§î—à¿ ú€_Aáæy·@Ôárz}b$œ?Œpqq¹\mmm<ÏK«'zoYáÔ©S‡cüøñÞ;¬5ÍÉ“'ÛÚÚ¤Ey|;ñyFÔOŒWýxVÜ7ì:úÍ·ß•}}Úý™exðV¡<ë3¶8Úším‚(œu 0ÚŒlþföï3^;ö½ß­ þ†çyžçår¹Z­>íÜQG{{»÷öE"’Éd!!!ÒãaÚÛÛ5š"0ba¤©ÔA?¿íúŸßv=ýæÛÓîßRwr׫ïj”g¼˜v‡»£¡½Åáâ‰(âG:ÃÝ7«‚ñ¨h8=Up=°dŽÍæðu].ZÑ?çë* ‡ÃÑÑÑÁ²l``à‡-±s™a˜ÀÀ@‡ÃÁó|GG‡oˆ¼¾téO.Ên?ž÷îÓ¯Úªê‡ÞÐèÙ¬ø‹$“áî3}øŒvz)/JÏúÊþg41((¨¥¥Ez ËúòéÈ‹pP©ƒ~õÔÊowU~òüë§mhìÓ¬xË£‹Çé£F¤š0êð+îÒ+콡ÍŠ0†aYÖ{g´»_‡Øs­T*†‘8,U=kÈ‹p!ñÒЈfEð …BÑÿQ.ÒÔ—ËÕ§)QZ§½½]jeôLžƒEQ”Ëå …" @|]ÒÝqs°åx|»ø"ù"/6l_•´|Ó&Ú`NJ‹Õ±|Íž’â Y‹ŠKÒ-Éz„@ºËgÅ]>+Î×µ€Ñ«{ZtŸH'—ËÃÂÂ\.—çFAœNgGGGHHH`` ç!}–o”þ-Š¢ £./V$/ßt$zñº¢ŒÄ®æÄ¤äÔ¤ló‚ü¬”ƒ%‰.n·»££Cj;ìÞ(“ÉX–eÆsOA¤Çº¨T*µZíùÖ€‰P—ËÕ§dŸÙÓ[ËrsRäâÜ´Ä^}ÏìôÔìô›nŠç¬|ç–†²‚•fCŒ^¯×ÇÄ›Wæí¨á(ˆ?`ÉL6Æéõz½>Θ”^|ÀÚùNMI“\T´Ò£×ë +wX,àlÉd2—ËÅó¼÷…={¥¥&ÃîUu¼p:N§SÊ—ÃXç³0¢í‹|Uqy+EšÍýÛÙØä5kº¾h°¤SK(~qÆZC4/)ÌÎYRZžm)0ëz—·'Û¼ ÿ`ôM«rÓã4­•Ź9i7—ØXœ1]Z£ÈYš‘·0-3™ç£§ûrÙ"¸±,ër¹‡Ûíîÿ–îVCÏxò^¸´¸B¡ey±áx#Qüt×.g¾,;³¤5zÕö‚ξé„9ñ:Óœ¬Ìì2c¯I.5ÅYù5ƵEkæh‰ˆ 1d\R˜QœlIîL–qyYæ¡Ì£8S*•Ên·K£ûô>hèÏw‘VäEQ¥RùsU"×kô£Î”¾¬`AþróÊU©æ8MëAK^Ö¦ÆÈ…¹Iú¾*­8ŽãyÞjµžÊ:<à,9™L¦V«û¿u¦ëàxÎ’‘þ­P(ÔjµÕjåyþëyŽÎ’Óé”Ýÿ­s_G&“©T*¹\ît:ϱ¨s„¼pN¤et<‰¢ØÒÒÒÖÖFÈt^ IDAT&ÂPJÉdáááž%H˜–ÉdC,äüÁñ‹Ö)1z½1¯j€÷ø=éñƒ½çUU¶A¯7Ÿ~¢yM‘I¯7Ô \5‹Y¯7dðqc/\X¤FÄþM‰¢(Z­V—ËÅó<ÏóÎAHo¹\.›Íæ¥ÑçxÁöE.a™9¼dCQÑäŒØÞͶÖ=–FŠK3ëÏ´P66>ÞÀEçzGC#µö ‹\. •fO%íI]Ï}¶tëóG¼Œd4;=Ù½!ßRt -kºg³–å—´2ÆeFí—©3噆¯ŠC'…ÅŽŽ¥RÙç-Fsîó¦Ýn·(Šýû»GØÈ®§£OJŽ£FKÁ«çÖ†’ÂRg¸iq"'}mÝS”žlŠÑëõz½>Þ˜œ¹½Fê)æËVÆèÙÅÙIñz½>ΜWÕ»?š¯Ùž·ÒlŒ“ŽŒ1˜Wõ9UMyÞJSœ^¯×Ç™R²»ŠíǺ§hU’!n B¬{ŠV™ RÝâŒI« ʬ—=¥R)‚Ãáèÿ–x†,Áápˆ¢Ø?ŒŽ°^QgL60­%…ž!«ÆRPN‘æäÎ&Ǫ‚äÅ q©¹ëÖ¯_—»*žJ —§ôŒl<’ŸfáÌ™™é)IFgáÖéæå9åZsÖºõëׯÍNÒUmÊJNßÑs®#…iyñk×­Í4±;ò—›WmïŸö¬e馛âRr×­_—edK²˜Ó¥7XR“2,¬Q:CZ\æ¬ä”!Œž€‹Q``  >‚Ev†<•â£ËåjmmíßU=òFz~´Ö°Ì¨)ÝRXÚ0Ç$õ>W¤˜Ì¤Î! PÌM9Yo'$DV•/ØTZeMÑw¶?†/ÌÍMëJ—=EóUåÚøe™¹)ï%L§Ê„´ÊÒ>±k¼d̪â‚=KD‰‰1¬qAaNQ꜔^£&«Š26Ÿ¿®8GjïLHˆÓšæäd%—¤èª¶ïq2‰ËR͉%$ÄrÚ‚ ¦ÉŒNjµº­­­µµuüøñÃ>ÊPš£T*ƒƒƒ‡·ä35âëépÓSÌ‘[ JkLf¿§ ø8cHën)ÔšrŠMDÄ[kjjjjŽ)ß^ÙH¤sö„2½A?ÐüvzZ…ˆˆo¨©ª©ª9r¤ÜREÄz,q“dê>”5à K*R<‹«)·!Í|s×]®Î`ŒÎÉ·”פèõ¦Í–’%¦¤›Œ†DƒÁ`JË®O.4Rû¢Ãáp8ž«áœ#)z¶··3 0àúŽ#iä×_dc“’¢ s JjÌÉ:ëžK£Æ¸ÌÐ3Ó…¯²dfdo(?ND¤‰Œ›®§ÞdÔ„sƒ|h eyYy%[‰ˆ žÛwþŒ6Òc Ëé´DÖ+‘ÇÙ­5V¢ÖM‹b7õ96²ÊÊSìœ\˺‚Üüâ’œ-…9Dš˜ùiÙYI±˜  0 Iìkmm­««›8q¢\> #ýAËå6›­±±Ñår…††ž{™çÈëuëÍ)ñ9iEEUI)Uù%­‘I)Ó»óø²ô¤ÔMdL_—gJˆÕ²DüžtCé‘![S”²(§2fqîÆdC¬Žc‰ŠÍ åž+.Z[=¡ u:γ–ÓrD´pmn’®wdµz–ˆX]bJNb ‘µª¬´¤8/wSF2SÚ{Â7Œ ÃhµÚÖÖÖ––»Ý>,ÇRãbkk+±,~îež£žï"Ñ™#–¢²’ÂRgLr²Gë\Miy#E›W%'ÆjY""¾ª¤¼‘ˆN;FÐZe©$2¬J5M×I {JôÞ§Êr g~KMiéqŠ1Æõn„ÔÆÇGÒñÊ#œ>¶‹ÎZœ“µ¦¸†§KJ|ŒIZUœÓ'˜R²Òj<Ò€Œ£TpppHHÕÔÔ¸\.:·åµ¥¥››››ššDQ U(|ÿ4>ßÔ€K\f _P”‘édâ³Mž“œµñ±šü’✂¸eñ:¾¦ÒR˜»¡†ˆxëé"§3DSyiNv1›ÃZ”åæ–8{ÙZ’šš——™K,Ùi9G¢¯7ëzÃÆ¦fη,É1'פ-6F³­-yÙ›jç/ÓsÄÅõ”–“œBi ã©ñ`qî–VqñtŽ`T’ËåãÇ·Ùl<Ï?~<***  ÿ ÞC!õD·µµ8qÂív‡……]QÃËG‰•M6GnÊ?®é»H7—˜]žž‘—µ|gJÎݾ²8i‘¥ô€5YçµÏWŸ\Û–]”¶hQxŒÁ”Z¼Ï˜“v°´†¤)Ðqéi‘%iÆœãN »)}cVòIḴ¬Í^S¹|ƒ“ˆ‰Œ3¦¯ÏHNàˆHgÎ+æ³³ òR—´1á1 ‹sóÒæœù:ãpÑP©T:îØ±cV«õøñããÇgF„þ å F …ÝaQ†a&L˜à‹D$óÞdúÊ+¯ÑÒ¥K¥/Ê@B8{ÑÑѾ®œ†††ÚÚZ"R«ÕÒXÆî 5`p”Vêîž%ÓÔÔT__ßÑÑ!…EµZ=ì‹}¶HÙÃû¬¿­4QµZ-566ÚíöãLJ‡‡÷_ Ç3v7@Úl6i’µ\.W©TãÇ?añ¬!/œ+éAÒZ­V¡P466:Ž'N¨Tª°°0•J¥P( …þº#  Ò¢Ü2™, @­VO˜0eYi,£O¯©ò"À0"chhhPPPCCCkkk[[Ïón·[£ÑHm2™LJŠv»Ýf³IOpéèèP©TááááááÒþ y`¸Hm‡,Ëêt:‡ÃÑØØØÖÖ&Š¢Õjmnn–ËåÝ‹¢(J¡Pjz;v¬V«íΈ~ yà|&M‹¢ØÖÖfµZív;Ïó‚ H\”J%˲AAAÇ ãƒÏäE€óE&“i4Fã늜ÿjíƒ¼Þ /€7È‹à ò"x3Ây±*ϨXÒvëù:)_eION±4H_5›ôzc^Õù:ÀÅÅëé0q SMúÞOSd#cû>^qØÔ”än(å¦w)<Î`àuÜù:ÀÅÅyQ—”œ|þâáip‰Y‰>:7À…Ç¿Æ/Z-f½Þ}€ïÚÀÈ4tõUóe+ãôÆìíÅéIÆ8½^¯3&gZjº÷%þ€%3Åãù_¶2nN΢ʴ}LJß·?º¡¬`¥Ù£×ëõ1ñæ•y;º ´nOÒëÍÛ‹Vu¾gJÉÞÑÐ]×=ÝoèãŒI« ÊÎ[‡:€ù"/òÖ†šÞøÓ%9’¿<·Ñ˜^´cÇæu)Ú=…©É¹Ròã«ò’nN-< KÎY·~]nŠî@aªiÕv~zFñº…‘DÑ«Öo/ɜ޻U³Á’b\”UÊ3Ö®[¿6ÃÄ–æ,1¥×ôìQ™•ZDæìâ;6¯5³;ò—¤ÕHG¦&eXXcÖºõëׯM‹kØ”•œRÜ@_ôG7nZ2gS¯-1™;,Iº!¹8/WêÌÖ¥d¦ÏÉ)-­IÓë¬e9¹•L|vqžYKD”Ý`N.-ÙÃÏIÔéX"N«×ë´½Šâ˲3KZ£Wm/H‘FS&̉יædef—×$tpŒIËË‘ª¦KK7Yl²°&éØªí{œLâ²Ts"GD ±œ¶ F3äØ pÁðE^ÔÒ³F2[¸Xí {÷¡7èºÛ9-Gdmà‰ø*Ë'Å&ºËac3,åÒ?iõã«JË)&ÅsêÞ”—•Vn©áb¥ºÆÄõÉé9"¾•'âô¦Í–’%¦¤›Œ†DƒÁ`JËê%\H|‘¹èx㜳œï°lŸ¥6=k«•møÍzæ¬DºÈ^ÇpáCVk÷PD–ë[Oé|Ú9¹–u¹ùÅ%…9[ sˆ41óÓ²³’|6à<ñ¯ù.Ï^]kÃÐf‘pá9­½=°cÇžšÁ»ˆY©yòx¯X­Nâ¸!äNV—˜’STRYµgûúÜUóuU›2’3÷ G.6~–5QÃñîé/|UIeëPŽcõÆé í).íé{®*J]²$£ÄË1>œYªzB^¥¨’˜éFÝiš ,)ñ1&i’5§O0¥d¥5Ôxdèw.¾èkŠgJKRS³3ƱÇK ò,C `\ª´¸’¬Ô¤•5©æ8Mcianþ‘ðùëÌ:¢-Gt (·€ŒFsbOd§§eKRsÌÉ i‹Ñt¼dCva%Ÿ¹*ñtí‹Ú8£žÒr’S(ma\85,ÎÝÒª1.žŽeÀàbã_y‘´æÜ¼†Œœ‚ü´åÄD’2 ’ ¤ åHVŸ\´]›•›—º¤•(<Ƹj]fJ"GDZÃÊ…1©6dUdãž§3å•hò2×d./tg\¶6-uÎfjëÌyÅ|vVt6&<&aqn^Úœ!OÛ¸PÈDQôòö+¯¼BDK—.•¾“Ëå^á¹·;z/Á³Añ|´qž)´/ô»ÐyÎjÞ ïžFãí‹È‹=d|Õ¶çÙ>Äù×çò"@—ËÅ0ŒÓéôaJa˜ŽŽBû"€¿Ñjµn·[ß6ì°,뫳÷¼ÐC«Õúº ½ }À¿tYôUPó4éa‘F:/ò{Ò 64öÞÈ„Ç$˜’W¥™cO×èj-ËKÏoH΢Î Óxs¡6wO±‰;oõ€Ñ¦;¢uttH«vð© …ÏèîÃí‹ÃâƒN ‡<ßPUjÙT˜Vv/)JÒy;Žß“Ÿ³åÀüä©$ŒVÒÈÅÆÆÆ––‡Ã1béME†a"##5?L‹î拼¨3$§${$ÔcŠayInÞsÖtØ £›\.w»Ý2™lÄZGò\gÄ/Z;¹„ù±DGŽó –ä}LÊkϛֲ•qú¸•›×šb—”5nZ«7Ôt¿[°Ò¯×ëõ1óª¢ò,™ÉÆ8½^¯×Ǔҋ»ß¬)2éc’‹·ç­4ÅÇèõú˜xóÊ‚2C`Ô󇫸 ¿È‹|Me ‘&<œÕ–5Î’üÒ†®÷¬eù%­á¦ä9‹ò6gÆiŒ¹›·ç™;›'+3–8ãSs׿fšµ6e$e–ñR‘{²Í7§ÖĤä®[¿.7%¦aCÚÍæÌ=Ý¡ÐYš–V¢MÎµìØ¾1Ë`Ý’•œ¶‰zë~ÖËhæ‹þh¾¡¦¦«}·ÖT•få§ÈÅÉÓYb§§˜#·”Ô˜’tDÔP’_êŒ^•<åHɱšH½^Ç’ ™øÜâ<“–ˆhNU&f”—Tñ ±lMqVþAqmÑš9Z"¢„DC —f'[ººÂã³ò2¤CuéË’2Ë~Núà—G(nÔ_<’¿(1¿×&ú¦ì¼´é,±±IIÑ…9–ª¤=UY *).Ó¤¤(½)®{$m´Ž¡²+YX*IsÓâÄž”¸„dcø– –ʆμÓý.ËErTÚÊß5À…Ï'‰Í›3}‘ÃoÊÌ4…KÿfYN«Õy¬‰£7§Äç¤HN£¢‚ƒŒ!×8è´i–p1¾•'â´\ï]ußÐ µ}›À“O¢›ÿ4+vóE^ÔN7Ì™ãeå­q±‘Yn)Úc$Ëq1ÛpÆË¬³ލª¡×xDÞZe%ÒiYC´/Jüb¾K_\â2Sx£%'ÇÒnJžÞÓLÈ2CËz\¬)ŽZK =æY[÷•6R´1Æ¿žñàïü2/›lŽl­¬lNNöX‘‘ÓpÔZš_PdÙsš©Ì:Sú²˜Ö’åæ•y–e;,«’mjŒ\˜™4ØHHæEbõ&c$Q\²çL66%ÅÙX’“‘YTušvFvzZÑæì…ºƒy©K-IÍ­Ô.ÌÜhÉJÀ³ÎŒÌ{ù+¯¼BDK—.•¾´/Ày¼A^oÀäEðy¼A^oÀäEðy¼A^oÀäEðy¼A^€(Š¢(úä¼Ý¯~y`P2™l„O'Q.÷£æGUð7‚ øät#|^ïz‘ú‚AáöEQ¥–Å>¯wÈ‹½HY-88X¥R¶_øÜƒT‚L&“Ëå!!! à K±ÃHáë ø)«FDDüðÃn·»{X¡'Q¥^ €s<£4·F¡PŒ7N¡ð»xæwðRk_]]Ýnï? PÊ‹R»à¹œEE¥R©V«#""¤ÆEÏò¥Ÿ{$=È‹ƒ ¼ì²Ë|rj™LæÛ˜Ø ãÀäEðy¼A^-Ïâ(äE€Ñbܸqgqò"Àh1vìØ³hbD^E.¿üò1cÆœÑ!X` Ðëõv»½©©iˆ‡ /Œ:RÇôPR#ú£ÀäEðy¼A^oÀäEðy¼A^oÀäEðy¼A^oÀäEðFáë À0p:uuuv»ÝׯŒ3vìX_Wä|A^¸àxÅ=€WQ~ö³ŸEGGìo#ßC^XYYÙí·ßîà ¼õÖ[}²Â®]»|[%a¸üÐ[o½…¼£ò"ÀÀÜn·(о­@ÿ-¾­Œ0Ü~¨ÿ7`4@^” ¾íüêS±‹?tÌá÷Àè|©_?þó]&‚Ï_ý³VxÅ=€W€Ñy`PRß߯¶ÊßOå4 Çõ¼Fͼ=íÝÿ ¼ÿY½öÿ³$ÂiŽjúâ••·]=I«Ñh8.jʼ{WoþÞ6Lõ9óWÛ÷%ÿy÷CÞßV™:©÷§>åºÅ/í8åõ¨S•ÿóÅ)·[¿ñ*ÍÔ?{>®×ö¿÷_J¹q†.œã8þªÛ¿ñ íŒJhzwž&jqé™Öí,îû÷%/.›73J«Ñh¸IWß–ößoíÒ»ö²ezîºÿüp>¾×¶ƒ›W/ž=EÇqœ&\ÝâÕïÿpš£ì%·‡‡ßVbÝ?¼v7ie™mÀÏ­òµ´…WO —îçÙ÷®Þ<”ï¯ýï¿¶ùû³½–ž;jà}Fê×€A^˜÷ÖQ¤›þ±½´ôÓO?--Ý^²ñÉ»×.2ÿýÿÚO{ìùj[:V´ðÊ_>º…ÿéÃ/m´XÞüÏ_çGì}bÑÏóMLÝ–%æ'¶Ô9ÎèzCnZýŸ7ßܸqã›oþçŸO\ïØò˜iQÑ÷ƒÕ¾û ó’uß:ˆA$"‘†ÿZÚË7ýdÁÓßE-Y½~óæ7ÿùÈ•uë–übÁÚÿkz9RÝÄó}8v?qÓOÌûnbòßÿc±l|õá©õëî»fþKß9ºK;›:œæµiû#¿øù¢ÔýìáÕonÞ¼ñ¹¤ˆÝO,øù¢7Ox?¶çZ¹®ºÍ)×übEQÝOþÇFË›ÿùkòÄCO/úÙ/û¬É{}Nl^²à KíÙý$zÞQh_èñ‹ƒêІbßWA "V«Ÿ:uªªsߟΜ©ùæŠ{6l9úðä|ÔY½z» ´ç±uKVl YünéêkB¤Ý¯ºþÆÛçqñsŸxú‹Û^ú™jxês¯Bçg5xû~ª"5óºë¯ìüT¯¿q&³;î·ë>­½+jÜ€GuŸD¥‹Ò¿‡ï*ìß³+‡ò)ŒBh_˜èÝû°*"G‹(ŠöÝ+®3Õvno¶ÜvÙ}ŸÚEÑþéÝ—]qßÚçî6\v…ñÑ⣧=ÉЪômqÞ—ìOýùj®W•~úÔ»»>yö§¬ôeíOÞYXXXØeñw?ùTAû7M»ìæµkW¯ »ÌpߺoíÒþö£Åݳ ~‚t…ÏuVX´[üØ‚î îôÞþ{mQuÄÂ?ßåY««ÿüÚ_ûóUÜà…‹¢Ø¼{í}†Ë:Kþ²¥çÚ†òQôúL†vœ¶ª$‰äµö£Å-0\6á ã£EÒ'R[lœÿè“÷ÅO ‹ïù6ˆ¢(6úüVëäÔ´#<6FÜøìkÿ~måT¶«Ìþw‘Çw›øÆ‹G·<ÿ?óϽʣ>•6ÙúÖ34‹¢ýƒ&,ø «2Gצ=öMSﯹøæ ÓV<¹ÂxÅe—M¸lZÏ=n(é~ZwÔþmï;j0çó€ŸB^˜(µ òJD$öli?ñuñÿ¸•ºñ¶(©e‚¨ç]éï‹ÔÆ×¿õÌ—×åì¬nÜÿÎ]|áCŸä,ýÿ,I¬OíÞ­‡hê¼™\Ïv»½½½Ý.juFEAhßýǹ¿Úà¸ë•+öí|í^qÚH‰ÞIDATïnùãn»T[ëçÙ:ùÏU7T}œÆmýÝÒ‚£‚ 4ðÐÜ¥[#Rÿ»³¢âãg¯«{æ–;Ö~×}¹õ·¿üöÛ/¬œÙ´öž_e×]·æ½¯öõÑ¿îbßúÝýë¾Ùë^ß·f&qw½}xÏSS™ï×ß3÷·û¦®zg×þŠ÷2¦îûí-÷×ö¿"í©æÍÍß±þ·ùœ&ÝvuÔä;ïT¿µè›vAE¡ý›‚·êgÞ{³!ã“÷î ©ÏVT¿};'ŠDÕ¯?³÷ªôw>þø_‹¹3ïÿÛ×í¢Ø\òà­K7ðó^øh×®mÏ^u,ûWsû¢]EA$ëçÙ2)ããšÆÃ¥…lýÝÒ‚ïû|¶µ{÷Yiê z¦÷vnÆìÙS#XAhúà¡[—npÌ{ñã;ß“ —>Õ£E÷Üò§/§>µmçÎ7–±r÷uÝG‹î™ûÛ}SÓÞÞ¹ï«mŰÜu{÷Yiê¼Ilïíš™×]7Eˈ¢Øy×^û7ÏܲtÝõÊΊ}_m{a^KáCm’êFü¡ÂMôÀo¿ñì²XÆãÎÿþ³C<7ó*]Ÿúh¯šwõdÎÛ]Ô=Û=îÞï>vî÷€£¹®…8ŽQzu'z«ƒ8eYÖËk˜5yâ8ÝŒÛV.žJõ{ë÷óÌU™‹¯¾zö,½Ê³Lk} …D öùx¹‹<~F¨ÿ¨J{s=O!ZM¿2™‰!ÔR×2àO‰DĈ ‘JT*©sä({UföíU‚ ¹:#kžcëšê„®ÿ‡ëslÿ;j€Ÿ}äE•0~``=-̉¸r__5•øúC¯g¥½A¿^S˜u]‰¢ÐÙŽ#Š¢´cg;ˆ R4›¤ílÏ`4 ‘Ã!¢8ÀYúÇÏ6§>¯,Ç5×µˆ+£_úúÖÛx"DZ×SSÞ#Û~v˜ç«ïáYâ”CµÂ,Q$ÒNѰR­†eÉáÚîã¦?{^T÷ØÏ|]y–ÅöºQ$"•vÊŒݳˆ<¯W;û™|Ú¿*êè_ïñ³sgk¥?ìÝ'‘>O–éžx|ü÷¾ð^±vÊL-ÿÞ{‡ì³gz| TýÆâeoÏÌλjÐÂY"ÞÑó)Û5vp(…Wƒí齪¿™Ô붨͟¯úåüÓUwÞ0{ö¯õ›ˆý©ó_îþDX–àNeu³§°¯T|~Lœ1Ùc³ãÐ I©ûnÍÏ<è]ÔçãîóÁ³“n˜B¿ÿ¸¢î7½ÿ‡ê?ßYMSgëØþ%ð(ïQ¶ÃÁ{|„= •ïúíóà Ð 00ÑûøEÑsü"—ðØs÷èö¿¸,g¯]aˆøfGçH¬c_ÖSç¸1‘¤¿J]åto|”¤/{²S~ýà ~[FƇµ}Æ´UÔ‰¢ÈDN×QþcŒN§‹ŒŒÔ阽kÒ³Þ:Ö.RcL÷QRò˜ÈQT½¯–ëÜ_'|–³*磺>Wa¯xáßû'ý±Ø²öɇ–þjnŒ²º¾ç“¡Î6&2VGÕÍc#¥³‡7oÍJÏÿ²e€ñ‹¢8è5j¯½í|ùõ—wÒì_Ïê©)ö|†"‘H½J#A`u³¢èðÇ{›»¶7ïÛYÍêgh»Ú{OÅ>çebî¾M×ðFÖëÇ<¶7¾&gÛ~‡N«‰Lˆ¢ÃímêÚ¿eïÎjV?#œÑÏšD‡>ÚkïÜ~ìË}V"Q”º):ª®h ïüTÇ6mÍÊxùËæá¸bï¹U×ðFÖG=¶7}¶&gÛ~Gd8ÛóY V‡¦Ï×ü»zÆs–âçŸ|ðž[gÇ ‡ê‰D{׈½Ï«™¾ôîð Ïn­óØ^÷QÖ ;S”ÚË]Ô5ûÆã>ñ,Y7÷¡¹ìάŒ­µžÛ½¾êÙýÜ­]."ËïhqHïÚVÔ“ØùùxÖVä«+öÕu–P»÷£jV?+’e"k}ç±bów‡ºëàqG özïø+äE€‰‚Œa"êµ%äªÇþv‹¶ê¥Ô—¿s*|Övÿ‹Y…ŸíÛ·óõ?§þ·†ºÆ/ö-“ú”s¶ã!ò×kŸ›ËÿwQ¼qqFþoo{ëõ5¿Oúù´%ïðSn½%’¡ÙÞ£Ýÿ‡%i¯ï>\½ïÃ5)¿ö•¨ìní}^(ê–粟<’’µµâpõÞ­KþðßÃ\´¶ïUhtUüQE½£éèî7äÅâyÞ.ĆpÔ°ÿOvgŸºô¡Öÿ._òâ‡{®x#-åñwj¢ôá_ï ×¨IX:›ßö×mtÃ=ñš®ÑlK‡ßÛöñ¾ÚÎ}»q…ð9¿½•ÛöpòSÛö=ºwÛSK~ÿ•îWÍÒôW*H×<ÀyUSyî~Ý®?üâúe/¾±í³Ï>|ãÅå7™_k˜õäßæ„SÄ Þ½ÿð’¬­{««÷mÍJþÃWº_=˜BQ·<:—ÿïé…Ÿ>\ñVFÊß«¤s©bï{p†õ¿)Ék>ÞWýÝî×ÿ°üñwŽENŠŽ{€‰ýíó÷ëvýÞ`\¾æõ­;w~üúše¦¯5Ìzâ™"ºJ¯«á8:¼í£ïš-ÕŸ¦>ü_+ñŽîûVø¼! O'!aÎï?Ö>úÚ»O'hº?à^í‘4Ày¹YO¼ûîÓwDìñ‘%wÜq÷#¯š´âÕO^»[ÏŠ‚ ¹võ»/ÝA﬘?çRá³8A´s_zsõ¬êÕw þ^}ë£×rçÒÝóÚ›O_Ûòê’9ñ‰·<¾oÒcoþçþèaº4 O¼ûîÓwh÷½ôÈ} ,zäÕÓV¼úÉk÷D3Ý-Çâàu`f=ñÒŠ)ûÿcz|×”§_½[kÝ¿¯NèªÇÿ·w?¡qTqÀg ˜R°˜CÀ‚—+²é¥{$b"=d‹Ð¤¥lSjñz1 µÔžj±ZH=´¶Í©éEsðÏ R ¥šcÄC·§n.[Òt“¼M%ÝÙv?ŸÃ#ì<6¿Ì¾É|yó»ÁïÝÑwföÂX6ºúùÑá\îàháNωó³_½µ#8Š’•Qtýâƒïü\ßéÙÙ3Ãm¿NÊ ~{³óøÔÜ쩽m÷þŠá3_äÚ G{Gg;ŸÊ¶U®¦¶®CÃ]·¦8ùçÝ$‰¢–žÜ‹Wõîí=ô}Knꇙ§–“–®÷¾ËÞ9p°7÷Éo=c'^m¹7¿¸zD™_„5¾=ýìÙ³Q>|¸^õ@£L’$ŽãTÚ+W®ŒŒŒT•400V=Ðþûãþ=Ÿv]ºúQWKCÔc 4z[º´ÿå:/þrúµ§·ê=/_¾\õ¡ÀãîöíÛQmß¾=ÐÇ~X_²²²j½=’uk«JªH½ªú·woþtíúõ>þ½kä³—îíhN¿*c ÑÛÊ ÜÒkyí‡Í@^„õ¥~cØ(+¤RLê–n¿ÿîµ¶Þ“ßèlž“` l•-;ðÝ_oÆq¼…×r½þý@c±ßÖW¹1l¼ù‘·qW•T¹í¥[•ÖhòVd¤9™_„õe2™™™™´î qwwwW½ØÝÝ](Ü®š„1Ѐâ8Îd2iW)¨1»n4Àl3û£= D^ D^ D^hFù|~“=åE€¦“Ïç'''7ÙY^h.#y ©VäIEND®B`‚metakernel-0.29.4/examples/workspace2.xml000066400000000000000000000006041434565236000203650ustar00rootroot00000000000000myfunc(5, 6)sqrt_twoSQRT2metakernel-0.29.4/metakernel/000077500000000000000000000000001434565236000160745ustar00rootroot00000000000000metakernel-0.29.4/metakernel/__init__.py000066400000000000000000000010711434565236000202040ustar00rootroot00000000000000"""A Jupyter kernel base class in Python which includes core magic functions (including help, command and file path completion, parallel and distributed processing, downloads, and much more).""" from ._metakernel import ( ExceptionWrapper, MetaKernel, IPythonKernel, register_ipython_magics, get_metakernel, MetaKernelApp) from . import pexpect from .replwrap import REPLWrapper, u from .process_metakernel import ProcessMetaKernel from .magic import Magic, option from .parser import Parser __all__ = ['Magic', 'MetaKernel', 'option'] __version__ = '0.29.4' metakernel-0.29.4/metakernel/_metakernel.py000066400000000000000000001057461434565236000207510ustar00rootroot00000000000000from __future__ import print_function import base64 import codecs import glob import importlib import inspect import json import logging import os import pkgutil import subprocess from subprocess import CalledProcessError import sys import warnings from collections import OrderedDict warnings.filterwarnings('ignore', module='IPython.html.widgets') from jupyter_core.paths import jupyter_config_path, jupyter_config_dir from IPython.paths import get_ipython_dir from ipykernel.kernelapp import IPKernelApp from ipykernel.kernelbase import Kernel from ipykernel.comm import CommManager from traitlets.config import Application from traitlets import Dict, Unicode PY3 = sys.version_info[0] == 3 try: from ipywidgets.widgets.widget import Widget except ImportError: Widget = None try: from IPython.utils.PyColorize import NeutralColors RED = NeutralColors.colors["header"] NORMAL = NeutralColors.colors["normal"] except: from IPython.core.excolors import TermColors RED = TermColors.Red NORMAL = TermColors.Normal from IPython.core.formatters import IPythonDisplayFormatter from IPython.display import HTML from IPython.display import publish_display_data from IPython.utils.tempdir import TemporaryDirectory from .config import get_history_file, get_local_magics_dir from .parser import Parser class ExceptionWrapper(object): """ Utility wrapper that we can use to get the kernel to respond properly for errors. When the return value of your execute is an instance of this, an error will be thrown similar to Ipykernel """ def __init__(self, ename, evalue, traceback): self.ename = ename self.evalue = evalue self.traceback = traceback def __repr__(self): return '{}: {}\n{}'.format(self.ename, self.evalue, self.traceback) def lazy_import_handle_comm_opened(*args, **kwargs): if Widget is None: return Widget.handle_comm_opened(*args, **kwargs) def get_metakernel(): """ Get the MetaKernel instance. """ return MetaKernel.meta_kernel class MetaKernel(Kernel): """The base MetaKernel class.""" app_name = 'metakernel' identifier_regex = r'[^\d\W][\w\.]*' func_call_regex = r'([^\d\W][\w\.]*)\([^\)\()]*\Z' magic_prefixes = dict(magic='%', shell='!', help='?') help_suffix = '?' help_links = [ { 'text': "MetaKernel Magics", 'url': "https://metakernel.readthedocs.io/en/latest/source/README.html", }, ] language_info = { # 'mimetype': 'text/x-python', # 'name': 'python', # ------ If different from 'language': # 'codemirror_mode': { # "version": 2, # "name": "ipython" # } # 'pygments_lexer': 'language', # 'version' : "x.y.z", # 'file_extension': '.py', 'help_links': help_links, } plot_settings = Dict(dict(backend='inline')).tag(config=True) meta_kernel = None @classmethod def run_as_main(cls, *args, **kwargs): """Launch or install a metakernel. Modules implementing a metakernel subclass can use the following lines: if __name__ == '__main__': MetaKernelSubclass.run_as_main() """ kwargs['app_name'] = cls.app_name MetaKernelApp.launch_instance(kernel_class=cls, *args, **kwargs) def __init__(self, *args, **kwargs): super(MetaKernel, self).__init__(*args, **kwargs) if MetaKernel.meta_kernel is None: MetaKernel.meta_kernel = self if self.log is None: # This occurs if we call as a stand-alone kernel # (eg, not as a process) # FIXME: take care of input/output, eg StringIO # make work without a session self.log = logging.Logger(".metakernel") else: # Write has already been set try: sys.stdout.write = self.Write except: pass # Can't change stdout self.redirect_to_log = False self.shell = None self.sticky_magics = OrderedDict() self._i = None self._ii = None self._iii = None self._ = None self.__ = None self.___ = None self.max_hist_cache = 1000 self.hist_cache = [] kwargs = {'parent': self, 'kernel': self} if not PY3: kwargs['shell'] = None self.comm_manager = CommManager(**kwargs) self.comm_manager.register_target('ipython.widget', lazy_import_handle_comm_opened) self.hist_file = get_history_file(self) self.parser = Parser(self.identifier_regex, self.func_call_regex, self.magic_prefixes, self.help_suffix) comm_msg_types = ['comm_open', 'comm_msg', 'comm_close'] for msg_type in comm_msg_types: self.shell_handlers[msg_type] = getattr(self.comm_manager, msg_type) self._ipy_formatter = IPythonDisplayFormatter() self.env = {} self.reload_magics() # provide a way to get the current instance self.set_variable("kernel", self) # Run command line filenames, if given: if self.parent is not None and self.parent.extra_args: level = self.log.level self.log.setLevel("INFO") self.redirect_to_log = True self.Write("Executing files...") for filename in self.parent.extra_args: self.Write(" %s..." % filename) try: self.do_execute_file(filename) except Exception as exc: self.log.info(" %s" % (exc,)) self.Write("Executing files: done!") self.log.setLevel(level) self.redirect_to_log = False def makeSubkernel(self, kernel): """ Run this method in an IPython kernel to set this kernel's input/output settings. """ from IPython import get_ipython from IPython.display import display shell = get_ipython() if shell: # we are running under an IPython kernel self.session = shell.kernel.session self.Display = display self.send_response = self._send_shell_response else: self.session = kernel.session self.send_response = kernel.send_response self.Display = kernel.Display ##################################### # Methods which provide kernel - specific behavior def set_variable(self, name, value): """ Set a variable to a Python-typed value. """ pass def get_variable(self, name): """ Lookup a variable name and return a Python-typed value. """ pass def repr(self, item): """The repr of the kernel.""" return repr(item) def get_usage(self): """Get the usage statement for the kernel.""" return "This is a usage statement." def get_kernel_help_on(self, info, level=0, none_on_fail=False): """Get help on an object. Called by the help magic.""" if none_on_fail: return None else: return "Sorry, no help is available on '%s'." % info['code'] def handle_plot_settings(self): """Handle the current plot settings""" pass def get_local_magics_dir(self): """ Returns the path to local magics dir (eg ~/.ipython/metakernel/magics) """ base = get_ipython_dir() return os.path.join(base, 'metakernel', 'magics') def get_completions(self, info): """ Get completions from kernel based on info dict. """ return [] def do_execute_direct(self, code, silent=False): """ Execute code in the kernel language. """ pass def do_execute_file(self, filename): """ Default code for running a file. Just opens the file, and sends the text to do_execute_direct. """ with open(filename) as f: return self.do_execute_direct("".join(f.readlines())) def do_execute_meta(self, code): """ Execute meta code in the kernel. This uses the execute infrastructure but allows JavaScript to talk directly to the kernel bypassing normal processing. When responding to the %%debug magic, the step and reset meta commands can answer with a string in the format: "highlight: [start_line, start_col, end_line, end_col]" for highlighting expressions in the frontend. """ if code == "reset": raise Exception("This kernel does not implement this meta command") elif code == "stop": raise Exception("This kernel does not implement this meta command") elif code == "step": raise Exception("This kernel does not implement this meta command") elif code.startswith("inspect "): raise Exception("This kernel does not implement this meta command") else: raise Exception("Unknown meta command: '%s'" % code) def initialize_debug(self, code): """ This function is used with the %%debug magic for highlighting lines of code, and for initializing debug functions. Return the empty string if highlighting is not supported. """ #return "highlight: [%s, %s, %s, %s]" % (line1, col1, line2, col2) return "" def do_function_direct(self, function_name, arg): """ Call a function in the kernel language with args (as a single item). """ f = self.do_execute_direct(function_name) return f(arg) def restart_kernel(self): """Restart the kernel""" pass ############################################ # Implement base class methods def do_execute(self, code, silent=False, store_history=True, user_expressions=None, allow_stdin=False): """Handle code execution. https://jupyter-client.readthedocs.io/en/stable/messaging.html#execute """ # Set the ability for the kernel to get standard-in: self._allow_stdin = allow_stdin # Create a default response: self.kernel_resp = { 'status': 'ok', # The base class increments the execution count 'execution_count': self.execution_count, 'payload': [], 'user_expressions': {}, } # TODO: remove this when IPython fixes this # This happens at startup when the language is set to python if '_usage.page_guiref' in code: return self.kernel_resp if code and store_history: self.hist_cache.append(code.strip()) if not code.strip(): return self.kernel_resp info = self.parse_code(code) self.payload = [] retval = None if info['magic'] and info['magic']['name'] == 'help': if info['magic']['type'] == 'line': level = 0 else: level = 1 text = self.get_help_on(code, level) if text: content = { "start_line_number": 0, "source": "page", } if isinstance(text, dict): content["data"] = text ## {mime-type: ..., mime-type:...} self.log.debug(str(text)) else: content["data"] = {"text/plain": text} self.log.debug(text) self.payload = [content] elif info['magic'] or self.sticky_magics: retval = None if self.sticky_magics: magics, code = _split_magics_code(code, self.magic_prefixes) code = magics + self._get_sticky_magics() + code stack = [] # Handle magics: magic = None prefixes = ((self.magic_prefixes['shell'], self.magic_prefixes['magic'])) while code.startswith(prefixes): magic = self.get_magic(code) if magic is not None: stack.append(magic) code = str(magic.get_code()) # signal to exit, maybe error or no block if not magic.evaluate: break else: break # Execute code, if any: if ((magic is None or magic.evaluate) and code.strip() != ""): if code.startswith("~~META~~:"): retval = self.do_execute_meta(code[9:].strip()) else: retval = self.do_execute_direct(code) # Post-process magics: for magic in reversed(stack): retval = magic.post_process(retval) else: if code.startswith("~~META~~:"): retval = self.do_execute_meta(code[9:].strip()) else: retval = self.do_execute_direct(code) self.post_execute(retval, code, silent) if 'payload' in self.kernel_resp: self.kernel_resp['payload'] = self.payload return self.kernel_resp def post_execute(self, retval, code, silent): """Post-execution actions Handle special kernel variables and display response if not silent. """ # Handle in's self.set_variable("_iii", self._iii) self.set_variable("_ii", self._ii) self.set_variable("_i", code) self.set_variable("_i" + str(self.execution_count), code) self._iii = self._ii self._ii = code if (retval is not None): # -------------------------------------- # Handle out's (only when non-null) self.set_variable("___", self.___) self.set_variable("__", self.__) self.set_variable("_", retval) self.set_variable("_" + str(self.execution_count), retval) self.___ = self.__ self.__ = retval self.log.debug(retval) if isinstance(retval, ExceptionWrapper): self.kernel_resp['status'] = 'error' content = { 'traceback': retval.traceback, 'evalue': retval.evalue, 'ename': retval.ename, } self.kernel_resp.update(content) if not silent: self.send_response(self.iopub_socket, 'error', content) else: try: data = _formatter(retval, self.repr) except Exception as e: self.Error(e) return content = { 'execution_count': self.execution_count, 'data': data[0], 'metadata': data[1], } if not silent: if Widget and isinstance(retval, Widget): self.Display(retval) return self.send_response(self.iopub_socket, 'execute_result', content) def do_history(self, hist_access_type, output, raw, session=None, start=None, stop=None, n=None, pattern=None, unique=False): """ Access history at startup. https://jupyter-client.readthedocs.io/en/stable/messaging.html#history """ with open(self.hist_file) as fid: self.hist_cache = json.loads(fid.read() or "[]") return {'status': 'ok', 'history': [(None, None, h) for h in self.hist_cache]} def do_shutdown(self, restart): """ Shut down the app gracefully, saving history. https://jupyter-client.readthedocs.io/en/stable/messaging.html#kernel-shutdown """ if self.hist_file: with open(self.hist_file, "w") as fid: json.dump(self.hist_cache[-self.max_hist_cache:], fid) if restart: self.Print("Restarting kernel...") self.restart_kernel() self.reload_magics() self.Print("Done!") return {'status': 'ok', 'restart': restart} def do_is_complete(self, code): """ Given code as string, returns dictionary with 'status' representing whether code is ready to evaluate. Possible values for status are: 'complete' - ready to evaluate 'incomplete' - not yet ready 'invalid' - invalid code 'unknown' - unknown; the default unless overridden Optionally, if 'status' is 'incomplete', you may indicate an indentation string. Example: return {'status' : 'incomplete', 'indent': ' ' * 4} https://jupyter-client.readthedocs.io/en/stable/messaging.html#code-completeness """ if code.startswith(self.magic_prefixes['magic']): ## force requirement to end with an empty line if code.endswith("\n"): return {'status' : 'complete'} else: return {'status' : 'incomplete'} # otherwise, how to know is complete? elif code.endswith("\n"): return {'status' : 'complete'} else: return {'status' : 'incomplete'} def do_complete(self, code, cursor_pos): """Handle code completion for the kernel. https://jupyter-client.readthedocs.io/en/stable/messaging.html#completion """ info = self.parse_code(code, 0, cursor_pos) content = { 'matches': [], 'cursor_start': info['start'], 'cursor_end': info['end'], 'status': 'ok', 'metadata': {} } matches = info['path_matches'] if info['magic']: # if the last line contains another magic, use that line_info = self.parse_code(info['line']) if line_info['magic']: info = line_info if info['magic']['type'] == 'line': magics = self.line_magics else: magics = self.cell_magics if info['magic']['name'] in magics: magic = magics[info['magic']['name']] info = info['magic'] if info['type'] == 'cell' and info['code']: info = self.parse_code(info['code']) else: info = self.parse_code(info['args']) matches.extend(magic.get_completions(info)) elif not info['magic']['code'] and not info['magic']['args']: matches = [] for name in magics.keys(): if name.startswith(info['magic']['name']): pre = info['magic']['prefix'] matches.append(pre + name) info['start'] -= len(pre) info['full_obj'] = pre + info['full_obj'] info['obj'] = pre + info['obj'] else: matches.extend(self.get_completions(info)) if info['full_obj'] and len(info['full_obj']) > len(info['obj']): new_list = [m for m in matches if m.startswith(info['full_obj'])] if new_list: content['cursor_end'] = (content['cursor_end'] + len(info['full_obj']) - len(info['obj'])) matches = new_list content["matches"] = sorted(matches) return content def do_inspect(self, code, cursor_pos, detail_level=0, omit_sections=()): """Object introspection. https://jupyter-client.readthedocs.io/en/stable/messaging.html#introspection """ if cursor_pos > len(code): return content = {'status': 'aborted', 'data': {}, 'found': False, 'metadata': {}} docstring = self.get_help_on(code, detail_level, none_on_fail=True, cursor_pos=cursor_pos) if docstring: content["status"] = "ok" content["found"] = True if isinstance(docstring, dict): ## {"text/plain": ..., mime-type: ...} content["data"] = docstring self.log.debug(str(docstring)) else: content["data"] = {"text/plain": docstring} self.log.debug(docstring) return content def clear_output(self, wait=False): """Clear the output of the kernel.""" self.send_response(self.iopub_socket, 'clear_output', {'wait': wait}) def Display(self, *objects, **kwargs): """Display one or more objects using rich display. Supports a `clear_output` keyword argument that clears the output before displaying. See https://ipython.readthedocs.io/en/stable/config/integrating.html?highlight=display#rich-display """ if kwargs.get('clear_output'): self.clear_output(wait=True) for item in objects: if Widget and isinstance(item, Widget): self.log.debug('Display Widget') data = { 'text/plain': repr(item), 'application/vnd.jupyter.widget-view+json': { 'version_major': 2, 'version_minor': 0, 'model_id': item._model_id } } content = { 'data': data, 'metadata': {} } self.send_response( self.iopub_socket, 'display_data', content ) else: self.log.debug('Display Data') try: data = _formatter(item, self.repr) except Exception as e: self.Error(e) return content = { 'data': data[0], 'metadata': data[1] } self.send_response( self.iopub_socket, 'display_data', content ) def Print(self, *objects, **kwargs): """Print `objects` to the iopub stream, separated by `sep` and followed by `end`. Items can be strings or `Widget` instances. """ for item in objects: if Widget and isinstance(item, Widget): self.Display(item) objects = [i for i in objects if not (Widget and isinstance(i, Widget))] message = format_message(*objects, **kwargs) stream_content = { 'name': 'stdout', 'text': message} self.log.debug('Print: %s' % message.rstrip()) if self.redirect_to_log: self.log.info(message.rstrip()) else: self.send_response(self.iopub_socket, 'stream', stream_content) def Write(self, message): """Write message directly to the iopub stdout with no added end character.""" stream_content = { 'name': 'stdout', 'text': message} self.log.debug('Write: %s' % message) if self.redirect_to_log: self.log.info(message) else: self.send_response(self.iopub_socket, 'stream', stream_content) def Error(self, *objects, **kwargs): """Print `objects` to stdout, separated by `sep` and followed by `end`. Objects are cast to strings. """ message = format_message(*objects, **kwargs) self.log.debug('Error: %s' % message.rstrip()) stream_content = { 'name': 'stderr', 'text': RED + message + NORMAL } if self.redirect_to_log: self.log.info(message.rstrip()) else: self.send_response(self.iopub_socket, 'stream', stream_content) def Error_display(self, *objects, **kwargs): """Print `objects` to stdout is they area strings, separated by `sep` and followed by `end`. All other objects are rendered using the Display method Objects are cast to strings. """ msg = [] msg_dict = {} for item in objects: if not isinstance(item, str): self.log.debug('Item type:{}'.format(type(item)) ) self.Display(item) else: # msg is the error for str msg.append(item) for k,v in kwargs: if not isinstance(v, str): self.Display(k,v) else: msg_dict[k] = v message = format_message(' '.join(msg), **kwargs) if len(msg_dict.keys()) > 0: message = format_message(' '.join(msg), msg_dict) self.log.debug('Error: %s' % message.rstrip()) stream_content = { 'name': 'stderr', 'text': RED + message + NORMAL } if self.redirect_to_log: self.log.info(message.rstrip()) else: self.send_response(self.iopub_socket, 'stream', stream_content) ############################## # Private API and methods not likely to be overridden def reload_magics(self): """Reload all of the line and cell magics.""" self.line_magics = {} self.cell_magics = {} # get base magic files and those relative to the current class # directory magic_files = [] # Make a metakernel/magics if it doesn't exist: local_magics_dir = get_local_magics_dir() # Search all of the places there could be magics: try: paths = [os.path.join(os.path.dirname( os.path.abspath(inspect.getfile(self.__class__))), "magics")] except: paths = [] paths += [local_magics_dir, os.path.join(os.path.dirname(os.path.abspath(__file__)), "magics")] for magic_dir in paths: sys.path.append(magic_dir) magic_files.extend(glob.glob(os.path.join(magic_dir, "*.py"))) for magic in magic_files: basename = os.path.basename(magic) if basename == "__init__.py": continue try: module = __import__(os.path.splitext(basename)[0]) importlib.reload(module) module.register_magics(self) except Exception as e: self.log.error("Can't load '%s': error: %s" % (magic, e)) def register_magics(self, magic_klass): """Register magics for a given magic_klass.""" magic = magic_klass(self) line_magics = magic.get_magics('line') cell_magics = magic.get_magics('cell') for name in line_magics: self.line_magics[name] = magic for name in cell_magics: self.cell_magics[name] = magic def send_response(self, *args, **kwargs): ### if we are running via %parallel, we might not have a ### session if self.session: super(MetaKernel, self).send_response(*args, **kwargs) def call_magic(self, line): """ Given an line, such as "%download http://example.com/", parse and execute magic. """ return self.get_magic(line) def get_magic(self, text): ## FIXME: Bad name, use call_magic instead. # if first line matches a magic, # call magic.call_magic() and return magic object info = self.parse_code(text) magic = self.line_magics['magic'] return magic.get_magic(info) def get_magic_args(self, text): # if first line matches a magic, # call magic.call_magic() and return magic args info = self.parse_code(text) magic = self.line_magics['magic'] return magic.get_magic(info, get_args=True) def get_help_on(self, expr, level=0, none_on_fail=False, cursor_pos=-1): """Get help for an expression using the help magic.""" help_magic = self.line_magics['help'] return help_magic.get_help_on(expr, level, none_on_fail, cursor_pos) def parse_code(self, code, cursor_start=0, cursor_end=-1): """Parse code using our parser.""" return self.parser.parse_code(code, cursor_start, cursor_end) def _get_sticky_magics(self): retval = "" for key in self.sticky_magics: retval += (key + " " + self.sticky_magics[key] + "\n") return retval def _send_shell_response(self, socket, stream_type, content): publish_display_data({ 'text/plain': content['text'] }) class MetaKernelApp(IPKernelApp): """The MetaKernel launcher application.""" config_dir = Unicode() def _config_dir_default(self): return jupyter_config_dir() @property def config_file_paths(self): path = jupyter_config_path() if self.config_dir not in path: path.insert(0, self.config_dir) path.insert(0, os.getcwd()) return path @classmethod def launch_instance(cls, *args, **kwargs): cls.name = kwargs.pop('app_name', 'metakernel') super(MetaKernelApp, cls).launch_instance(*args, **kwargs) @property def subcommands(self): # Slightly awkward way to pass the actual kernel class to the install # subcommand. class KernelInstallerApp(Application): kernel_class = self.kernel_class def initialize(self, argv=None): self.argv = argv def start(self): kernel_spec = self.kernel_class().kernel_json with TemporaryDirectory() as td: dirname = os.path.join(td, kernel_spec['name']) os.mkdir(dirname) with open(os.path.join(dirname, 'kernel.json'), 'w') as f: json.dump(kernel_spec, f, sort_keys=True) filenames = ['logo-64x64.png', 'logo-32x32.png'] name = self.kernel_class.__module__ for filename in filenames: try: data = pkgutil.get_data(name.split('.')[0], 'images/' + filename) except (OSError, IOError): data = pkgutil.get_data('metakernel', 'images/' + filename) with open(os.path.join(dirname, filename), 'wb') as f: f.write(data) try: subprocess.check_call( [sys.executable, '-m', 'jupyter', 'kernelspec', 'install'] + self.argv + [dirname]) except CalledProcessError as exc: sys.exit(exc.returncode) return {'install': (KernelInstallerApp, 'Install this kernel')} def _split_magics_code(code, prefixes): lines = code.split("\n") ret_magics = [] ret_code = [] index = 0 shell = prefixes['shell'] magic = prefixes['magic'] while index < len(lines) and lines[index].startswith((shell, magic)): ret_magics.append(lines[index]) index += 1 while index < len(lines): ret_code.append(lines[index]) index += 1 ret_magics_str = "\n".join(ret_magics) if ret_magics_str: ret_magics_str += "\n" ret_code_str = "\n".join(ret_code) if ret_code_str: ret_code_str += "\n" return (ret_magics_str, ret_code_str) def _formatter(data, repr_func): reprs = {} reprs['text/plain'] = repr_func(data) lut = [("_repr_png_", "image/png"), ("_repr_jpeg_", "image/jpeg"), ("_repr_html_", "text/html"), ("_repr_markdown_", "text/markdown"), ("_repr_svg_", "image/svg+xml"), ("_repr_latex_", "text/latex"), ("_repr_json_", "application/json"), ("_repr_javascript_", "application/javascript"), ("_repr_pdf_", "application/pdf")] for (attr, mimetype) in lut: obj = getattr(data, attr, None) if obj: reprs[mimetype] = obj format_dict = {} metadata_dict = {} for (mimetype, value) in reprs.items(): metadata = None try: value = value() except Exception: pass if not value: continue if isinstance(value, tuple): metadata = value[1] value = value[0] if isinstance(value, bytes): try: value = value.decode('utf-8') except Exception: value = base64.encodestring(value) value = value.decode('utf-8') try: format_dict[mimetype] = str(value) except: format_dict[mimetype] = value if metadata is not None: metadata_dict[mimetype] = metadata return (format_dict, metadata_dict) def format_message(*objects, **kwargs): """ Format a message like print() does. """ objects = [str(i) for i in objects] sep = kwargs.get('sep', ' ') end = kwargs.get('end', '\n') return sep.join(objects) + end class IPythonKernel(MetaKernel): """ Class to make an IPython Kernel look like a MetaKernel Kernel. """ language_info = { 'mimetype': 'text/x-python', 'name': 'python', 'file_extension': '.py', } def __init__(self): from metakernel.magics.magic_magic import MagicMagic self.line_magics = {'magic': MagicMagic(self)} self.cell_magics = {} self.parser = Parser(self.identifier_regex, self.func_call_regex, self.magic_prefixes, self.help_suffix) self.shell = None def Display(self, *objects, **kwargs): """Display an object in the kernel, using `IPython.display`.""" from IPython.display import display return display(*objects, **kwargs) def Error(self, *objects, **kwargs): """Print `objects` to stderr, separated by `sep` and followed by `end`. """ sys.stderr.write(format_message(*objects, **kwargs)) def Print(self, *objects, **kwargs): """Print `objects` to stdout, separated by `sep` and followed by `end`. """ sys.stdout.write(format_message(*objects, **kwargs)) def register_ipython_magics(*magics): """ Loads all magics (or specified magics) that have a register_ipython_magics function defined. """ if magics: # filename is name of magic + "_magic.py" magics = [name + "_magic.py" for name in magics] local_magics_dir = get_local_magics_dir() # Search all of the places there could be magics: paths = [local_magics_dir, os.path.join(os.path.dirname(os.path.abspath(__file__)), "magics")] magic_files = [] for magic_dir in paths: sys.path.append(magic_dir) magic_files.extend(glob.glob(os.path.join(magic_dir, "*.py"))) for magic in magic_files: basename = os.path.basename(magic) if basename == "__init__.py": continue if len(magics) == 0 or basename in magics: module = __import__(os.path.splitext(basename)[0]) importlib.reload(module) if hasattr(module, "register_ipython_magics"): module.register_ipython_magics() metakernel-0.29.4/metakernel/config.py000066400000000000000000000016601434565236000177160ustar00rootroot00000000000000from IPython.paths import get_ipython_dir import os def get_history_file(kernel): """Gets the history file for the kernel. Histories are stored in ~/.ipython/metakernel/history """ base = get_ipython_dir() dname = os.path.join(base, 'metakernel', 'history') if not os.path.exists(dname): os.makedirs(dname) if hasattr(kernel, 'implementation'): fname = kernel.implementation.lower() else: fname = kernel.__class__.__name__ fname = fname.replace("Magic", '').lower() path = os.path.join(dname, fname + '.json') with open(path, 'a'): pass return path def get_local_magics_dir(): """ Ensures that there is a ~/.ipython/metakernel/magics directory, and returns the path to it. """ base = get_ipython_dir() dname = os.path.join(base, 'metakernel', 'magics') if not os.path.exists(dname): os.makedirs(dname) return dname metakernel-0.29.4/metakernel/display.py000066400000000000000000000007451434565236000201210ustar00rootroot00000000000000 from IPython.display import * ipdisplay = display ipclear_output = clear_output def display(*args, **kwargs): from . import get_metakernel kernel = get_metakernel() if kernel: kernel.Display(*args, **kwargs) else: ipdisplay(*args, **kwargs) def clear_output(*args, **kwargs): from . import get_metakernel kernel = get_metakernel() if kernel: kernel.clear_output(*args, **kwargs) else: ipclear_output(*args, **kwargs) metakernel-0.29.4/metakernel/images/000077500000000000000000000000001434565236000173415ustar00rootroot00000000000000metakernel-0.29.4/metakernel/images/dragon.py000066400000000000000000000042031434565236000211640ustar00rootroot00000000000000from Graphics import * from Myro import show # positive to left def dragon(arrow, level=4, size=200, direction=45): if level: arrow.rotate(direction) dragon(arrow, level-1, size/1.41421356237, 45) arrow.rotate(-direction * 2) dragon(arrow, level-1, size/1.41421356237, -45) arrow.rotate(direction) else: arrow.forward(size) def draw_dragon4(center, size, counts, colors, angle=0): for color, count in zip(colors, counts): if color is not None: arrow = Arrow(center) arrow.pen.color = Color(color) arrow.penDown() arrow.draw(win) arrow.rotate(angle + 45) dragon(arrow, count, size) arrow.penUp() arrow.undraw() angle += 90 def makePicture(size): global win size2 = size / 2 win = Window(size, size) bg = "white" win.setBackground(Color(bg)) win.Hide() blue = Color(36, 136, 192) yellow = Color(255, 199, 0) darkblue = Color(35, 115, 160) darkyellow = Color(211, 166, 0) angle = -90 # Shadow: if size > 128: scolor = darkblue yscolor = darkyellow draw_dragon4((size2 - 0, size2 + 2), size2, [16] * 4, [None, scolor, None, yscolor], angle) draw_dragon4((size2 + 2, size2 - 0), size2, [16] * 4, [None, scolor, None, yscolor], angle) draw_dragon4((size2 - 2, size2 + 0), size2, [16] * 4, [None, scolor, None, yscolor], angle) draw_dragon4((size2 + 0, size2 - 2), size2, [16] * 4, [None, scolor, None, yscolor], angle) draw_dragon4((size2, size2), size2, [16] * 4, [None, blue, None, None], angle) draw_dragon4((size2, size2), size2, [16] * 4, [None, None, None, yellow], angle) pic = Picture(win) pic.setTransparent(Color(bg)) #pic.flipHorizontal() #show(pic) pic.savePicture("logo-%dx%d.png" % (size, size)) return pic for size in [32, 64]: # 16, 32, 64, 128, 256, 512]: pic = makePicture(size) show(pic, "%sx%s" % (size, size)) #pic.savePicture("metakernel-logo-%sx%s.gif" % (size, size)) #pic.savePicture("metakernel-logo-%sx%s.jpg" % (size, size)) metakernel-0.29.4/metakernel/images/logo-32x32.png000066400000000000000000000027241434565236000215730ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ‹IDATX…­—]lUÇÓ¥-³[)EÝíJùC‹…BDÓU!ÑhILy0ø }0ò hˆQ ¡ò ¼ød$ÑhBI ºH¥ÐBÁjØ–.´Kkw§ ÎÀÔëÃí~Ñíî‚þ“›¹sæÜsþçž{ÎÍ „࿌þèß"1o½xS¤¿2ŠxHø;Äs-gÄúo.`X¶Øúý±õ‡«ôÇÌœkî—=îH\–®©„ “†–3z†ô Mºîr$Îÿ%aXv’ˆ"ÄR9Ž™"Ð3Dkç W"ñ ß§j*‡×Õ¡k*—SIÈ}û‚°lF-îäØ; 蚪¨äð¸œÊÆE^ ÓW"q+Ý–$3jÙ¬<Ð@{ó2¡kª°|ö4tM%Ð3L8f¢W”>üظØKc¥›îHœð$yO—o{e–²i‘€+‘8+´cX¶È»á˜)úc&Á¾(+f—£k*­,©rŽ™Ì›QÊñ,¹ß{º@蚃%UnZ;ñº4–×–3jÚä%0Õ©â?=€¿k0‘¿kÆJ7á˜IØ01,;¥¯©ŒZ6s+JYRåbïé^F-Ããìõ(à Ø¥?fæ>„ž!ì‹âïd~ÓÝ/Ëî$l˜Ég:Ú›—å&`X¶öEyÏiR5ÏÎ ØË0>·¢¯ËI÷`ó*J]S ëÁ¾¨Ø{ºw<‡™øpYë>‰PÝ4´œÉˆöË×ç`¤•åÜŠRö¯™ŸÑòèŽÄÅÎã$ë½±ÒÍö—Êioÿ”·=?Au ”ÔsóâÖþÒÌÒ§ªyÿ…š¤£îH\´v°i‘7ÃyAvžøC:Îí~Ùä Ç»Ýí½ Šëaà+Ʀ, pw¯.~+ÑaÙɦ”ŽœeèÇÂß5˜!ox\ðšúEV/8\`…À8€Ã9“çç¾9ÁV6ç箨-W>^> e·¼¶îd÷ê¥Ü+Ò±Š_d}Ï)~´w¥…Ú†~þ¸ºº K&o+Ö5UI4ô &¾ýAŠÓЬ‹ôp®ß€ê=ã |òy§ìh^Ý¿5/SŽmjH¶Q€Í¿nfÇ­7î8©š2 Œ|'Ÿvn£-'‰‚oÃ" ô,d9=Z\ÎáÎ!¦j* ^Ü:”¹@÷Áô º³æ>‰;p»Cð×Ñ ¬ç}Ë ßg4”Œ×²†îˆóõ‚]TÍ\ ZµTÔª¡¸®Ð¸²”áeŸÀ ÉùÂd¾F`Ga,&OýÂÁàýÏèÒiú÷éå(©Ï½$poD ºŒ6A¨î\H}õn—†­P*·Zµ4~»#%KGq´¡7Á3m>"Ð}ÐYe«ÁhË$‘ˆè~¹Þwv‰u :@«ÉIB±“#ÿ¿0}ƒ$¯û&%Q„J9ת%ódM7Áì#)íÄA©çpI'zSj]º§*¹œ¨è>iÀ8Þ2ߪ[1NÉmNÀêMÍKêA«‘à É÷’zy1Ý週(X!‘/*·;’}+$/Yà vTpë`ö<'ú¶ÃöØê\>3P„Uò­¸^2Ot5Õ­PRŸÒv¸Rs­&µKYúF¡}ÀŽ Î•¥¤e«`ÎÑTT7[cQèÿ$»•édúòlw6ÈN¨ºf¯ñ PÓ’©õD³‚w‡’qp¸d¯0ÚdΫ÷F„¸±gò¿ÛëÛ…ø!®} Äð9¿P'Ľ‘ú#N…¹ŒÅÏKç ØI!Ìkí\Á¿ðßrÊÔ´IEND®B`‚metakernel-0.29.4/metakernel/images/logo-512x512.png000066400000000000000000003206571434565236000217510ustar00rootroot00000000000000‰PNG  IHDRôxÔúsBIT|dˆ IDATxœìw˜SUúÇ¿'7=3“L¦7ŠH+""Tlذëö¢ûÛUw×µ¯®]ѵlqÝuuݵ#((¨H°*(½3½¤÷äæ¾¿?ÎM&™™„˜a çó<-¡7ñ(GG¿1µÍÎ .‹H€à°$‹K-ú;²¢Ð½³>Ç’MÕŒ: á˜rÖ‚s@!XAŠqL±Û¤Äùÿ7(è³§;ª!M…i¶ù@˜ùÅ6ºwöçcX¶…G-Èç#…·'¿<{;baPÀÄ"€V–ê¤n«Ž$°ý‚Ãá…ˆÎ{ê=ìiörÃ-évÕƒTÑ7¤•Y³äæ<£†Àµ†7%¿pÏ´“ inôÿøüµôòòÉ9ÿˆ£†ÏýëÍÜq±•fž–ˆE’£rÕ:XNÇyˆEEƱƒ‹Pœgîx`#¦‚ˆBD÷Îú³¾ÚžžíŸâ'`ÙÒ€R†òY¶%¿yñÇKÆãǧ>(ã?{ͺkæªôlÿ.µ¹“DC O#NZŒ7~uÞA;-AD$ ¿~¼ž‹­Õøi!þýÒýoK~'_à죫°µœÕÛë¹ñ×[?ÐÅ6w‚HäkÃCÓOA4?øc ýáaÅVɱžý"9 VP –cǾ‹‡æ}EWˆ¾ØÑ@à Giý¾–ý†æòq¹'[Ìs ªÀ앸àé÷1åñ9Åd¸B"­Þ^/£‚È r\å™ÑðLxBRÀ§»`¶Rþ”øxuåfÜ=íDºá…°nOþtÙÉô𼯠áßœOÇɬˆ¨†?e”O¾–ôh@w´9¿œ¿ÐHÓ ÉB8Ç›«·Òãó×bê1ƒ¡Ñ0,\¿÷L;‰~zºP  LD€@0@Y·§‰>ßÞ€ç–lâq°ü²ìkú’Ä2Àá¥6loð: sƒ.é0÷7gCQ€qƒ 3Ônò…¢¸ò…Å)Éä¿k³º pÚqC1ÿ›Ý€ÞDÃüC½÷?ÃKm˜8¼L8‚‡p‚Jƒ'H“žh´Ù³ý9ë C•öìnöñÈ€Îò;¹Žx@Ñ0š>×2²Cƒ‹+tÖãsPïr‡E«ï¹V{›HçŒEö¦<ÞÖH ò)gK.:v(ž»a²p ‘  @:küÉUÈõuÝ}9ë€x ÃKmiÆ@«ñ@j²Ýýï~Mžv#X\¡éý`¿ÆŸ|-|?r7X›UãêðrnüÍÖÖ¶Ì\p€3À£ ¾ÝyëvŠÑ’`@!`òÎ—Ûø SNÆmÈUhõ OÈÁ…‚º 9k½ZI‹MµN@§OÿvH:@gtFÔºüídƒ×ínRaÈjü¡Äh˜·Yu^ºÔfo3_N¨ÕcÕö:.glÉïp[&iù´‰1V³ï®Ù!œÁ€A$ ¤osÅŒ9ªÄ¯ËçjR6îäz{fÊL¹ˆ“´ìKÿ°Í1˜ÎÀËøé–ñ>ºãRVleÐáRü¶Çt€šH΀XÆm3¶Y«O¶ƒ5|¿LÇÐH`|yã/Þøû!i]zÂ01 è÷ˆ€@0¹ì„a€³Ž°ÈÛ„¼é™òøÿŒ @Žñu$ÐùкI]º—ˆÄ¢¼´pØÏË]| ÔÚšà7np!†æá¬áE\¯?äKV&Ìx RøtqyãN‘z âÇ@Ð (ñöÇP§$+-²B @ €TÚsØæ?À16^*7ÌœP`(Ì1‚\ ¼P¢Ngaà¡ôܧô€ågÞ^Ã=®@kß •ØÂÛ/ÁÏOrÖüŽýT"T? z@ŽêŒ%‹³·[–cE‚\f8Û1Ôïkñ…ºþ=AD8ÁE'iðоF5º‰Ñ7.‰ëªÃ‰C‹Ñâ’f¯<€å‚Œ'îsÀl¥`öŠŒÇ g-—ññ—¶«À§“4lÜàBØ-jAê1U'€ä¬QNR 0Æ ±‹mVË›òÀòËÁl%AÞ& Äßx¦Œ©áÁ€@,8»›½ôû7W@†„-~‰‡Õ%-˜%äi„AÒ "Çù{öž_.ˆx O\5WŒžÑú#1ºé•%8aH)þ±¶pñ˜µ˜'ñÅe”XÍhô†Àò+©çÒ™+&¬À~q¶0þ‚ƒˆ}…ˆ"rœ ‹Q¶Ô> •)õõТ<6÷Ö‹˜YâËþJr @,r7à”a¥XxÇ%|ã «ÌÌ×Ú¯ÜVç~™üÂ`DN{cб×ošÊ¬&ÏGˆ…Qžg¹êaÒßq)=ªºaO¿å—ch± =ý>%dƒ‚þŽp‚>ŒBD7þg Nô]8ýašüèlÜôß%Èä,\¿‡Ž¹ç l®sÒŸ?üšŽ¹ç ´øBO_wŽ©*À¼ß^„™¿9Ç.Âç;êñêg[øÎ©†4èößÂòŠc.`ÊÂïkðÚª-ØÞà¦M{f­ÜVGcï}#¹DðúSGb‘¥xë×çaέblUì9FÜ9s•zДyO´ÙlåÓ Z=þ·f¶Ô»ðþ×»ºý{‚Þ@,ú(²¢Ð3Wa鿀1Lzd6¢qŸn¬FµÓ*{1Öºxÿ½u»è¶·>ôgæó7Ã×{›qÚˆrª´ç°¹·^ð¢Tç Lƒÿ~¶IýÂXë:{¦KÍ€ï$]ëkÕ}ÙÛâÃÞþ `Ü•4ê¼¶j3Ž*·“Ù e¯ß4àG)רdž'j]~è$ b q=½ ˆ†º¿Í©9êrÁCÏ© ‡‘ ôA"šúä<ìnöòŒ|­äªã…l䬲G•Ûñß_œ ìß˾§ Ö X^ßÖ`ÌVL´ËXµµ ÿp †—ÚØÞMybNrΟüN@Ž€ÙÊøÒ=ÔíxÒ£ W=†çag“t`öФóÁ¬%i c˾‘O¾ðúMçâŸK¾ÇÊíõ<¯7ñmRÎGwAWR0íµ0þ‚ˆp‚>Æß>YOùè[Àl³Ø:܆ÕÜøÅÕ¥qZ}Æ0ùZ¸À˜º î¡Ög!äkû‰TÅ=V˜¡‘ w\$Æ.ÀW»Ò¡€¼M\ )áTÈQîlÈQ@‰cÞo/ÂÑ•Âø  " P è#(D´ts /Q~<šycIf¯³ªb;©kûÛ8VPÅÃå Yõ{ yy; ñ¶ÁG<–[f¯Àv'Þ¡„³Óc00{˜Á ÈQœ2¼ ˆ†’#aü ‘(ô"úõÿ–á“ï÷aê1mFÅÑ  (i£_f+å/ôf¨2|ÉÏÈÛ”¦Â—¦ê—ÝÆÂ€ÎÈçÑDAïH¶9Ñb|Ä­Õµksª\¯+Ä%x“šý!/ìéæRÁÉó`°7š@¼Ñ!àôQÂð÷#œþ0ÉŠ‡?ŒÑåöäµÛ\礊üxCÑvê“ek½‹J¬f£2ÊmpÇ}{ƒŒ1 +¶Bê°¢UßE8A/¢ÑOÿ½ª[øØ`‚>Ú×H ¿,§ ë1˜ÅÆG̉yþD’\GHz°\~<ò;³; =‰ÖÐÚŽ”d»!JVä#Ÿ#¹_ È wÊl¼zã¹=÷=‚nÇéÓøf&ÿ~üª‰tåøálÅ–ZúéK‹“ï/½ûrª*Èí’¡^¼±šnzeIòïå÷N§2›7½²K6U&(ÇË??›ú“ r‚^"!ò³z{=ÓÔÊxfk2;Æ?¹=À÷Ïfü4ãÙkÆ¿m;²¤·³»Œ?y›yAp…ÂÄ*‰DÄeö͈°?Âé“#æ÷F´zÜýÎjÜ÷î–ã|ºˆiI‹³ž˜ƒ¯v5v:fk½‹¢©ÇÐhqÎŒ¹xÿë]\B[«´z¬ÜV‡ë^X„¨¬ô›Ìz± @ è%v6zhêSó’ëà‡òª%†•8_E‘H ÔhP–gÂË??#JmÂø÷’÷‘FJFŠuõKØèMiy0ä¬â2–Þ}9ö øëÇëé¯ Ìi9*‰c0k±š‡^XËÓˆ1v̹õ¢~1 "A/Ñ¡šo¶l~A·ÀtF°¼b®ƒ >£'(£Ëó‘cÔ¡Þ ›_[N©5 }@$Æ?€¶«[2-eöÊd$ ÚáËx}Wn«ãÆh·b%Y€*õmÕÑØXëÄ/þó)âJß] @ è%†Û0õ˜Á˜0¤€‡ £A^øFг¤&ª×s×OÆØªB,ÙTƒsgÌÅyO½‡…ë÷à±ùkz©‘‚ýáô‡éë=Í8éÈr>õ¥3q%ËXn!ŸûÒßÏ)ð༯:<öÊmud1èøq%Æ£ É0®œp¥;íz 7aÅ–Z|¶µ¶»~j!¦‚^„´pîä§ÑòlÿC­Îw“PøÓJÈ å‚ü<7€åäããŠÐì â‰+O…Ũíó!ÝÃ…@$Fãî}“׬(Ôµå(ÈÝ€aŹ8gÌ äu¸pÜätÀÊmuôã?i7uÐ(èn\0n¦U…Ý-^Ü|θ>;  iðiêS󈘽¼½$n%΃Äÿ‚ƒC‰ƒ\u°›t(Ë·`c­ÌZÊ—# €i ‰ø÷¶ÀbÐáóû¯‚Ù œ€¾ÂgNo±'†s»´o¢Ät*‰œ‡?L'?0³]NAç¬ðå¸ Í —ž¼fRŸtÄ€@ÐK4z‚4éáYD°‚ʌƟ\u¼â],ÌÿOy¸%žÌöÇdnü ªZµK^‹¸ÌÕ‘>X¿;cfÁ¡çG“Fà “]…©Ël‘XB+iqæãsðÕÎ*È1²_Ÿ=–;ÛAw¬á« À˜f±á½¯wáìsûäêὄ٠Êpd‰Â‘»Ì`á¡iwC²T¯àÀ!w=X®Ì’`TV‹ e8§çE–ì•ø¾Ö…3"1°÷ñ‡ctþŸßãSùé+hÈÛÄÕ33‹p= {˜ÙfÉO&^÷ÂGxmÕz~ñnÄÍ)µ8Y¢ÊL¢ÖË+âùfX^ª>ÜñöÊ>—(ž$A/ÑàVRRJH?5ÑË+ä#½‰Ëß­C$pZ9ð`¶R¾tKù¥ÿ¶çßœÏ%‚%-ÞXW§¬ß}ˆ[,hKŽQÇ»r"¹ûiŸ±¼bþžéxg0Z’Õ&“û©NÀƒs¿ÄEy܉Sêqh´`3È•9¹åp§1’â€,`Ö,øv7~öÒâ>å@ è%†—ÚØË??Ï]s ÈÓò4ÚuMŠX§úÜ g (àN Ùºˆ¦½*¹ê@~(äk³mÊ#R=ÿFP=”(j¢šÒ&amúIGâþKÇa_óŸJj¥Ì`¹…`‰f©ÎàŒk'¡(Çr×ñXëçZ PÖ庼*g/鯰»Ù‹X¼ïL቞,ô"§ª`ÛÜ„(¯x)Ã-—xe6 êÝ âç#ÁAà A(Ì^sAM;åÈÒÌÛº§?L“™¨§#Kl˜ÿûi¤“4iò¾“GV`ÅÖZP<Äã¼.Vb>mêIßÈQŒ,ËÇ•ýP‘ŸƒZW]Ò€#áÉ¢Ùq™&ý»‰@îzµ¼{Ë0ê¤>“ ("A/3¼ÔÆn¿ðþGÊè”jR<rÕ¢4Ï 9®’–‹Øš¤£ÙšÕø'– ~ñ§«P˜kê3ðŒBD¬ßƒ¨ÌGÛ;ݸé•%DbôÇÙŸ'·[±µ—žp‹ŠÌåH¨ÝÚÿýÁr [ë[#kᘌJ›…OÄø”ùš³FÚ˜—™Ë ¦>9áX¼ÏLˆe€AaÕöz²´¸âŸKùG‰s}ÿh\Á…ÀІôvSâ23 ½üDœtD Ž(²  ‡ÙÛì¥óŸ~Q|… w„u(m>ù€:uÃòŠö?òÏ9jÀríIyß„ä/4ZµP“F»Ø"·ç‚¿Þp:CŸèC" ôN^ÆÂÑ8 J·œ{, b°=ûáPúÞ*¢…¼<£Û^ç—mŹ3æaý¾–._o(J+·ÕìmñѦZgÖc,Ú°—ˆ@±¸BŸn¬>¬.¼Ó¦)3æò‘¿Á$l¥¤ãÚûŒµ)j¥êHºƒ3þÏùHhû<Ò&iÓ%…;iüÉÝrTƒÕȺ±ìžé}Êø"@ èSL8²”ýïÆsiD© E¹&V˜k¤ûßý×ýcF—Û±¹ÎÉ3Œ f·)­@‰ ûI­DX§®ÚE»þ7þ'ýémÄÂ/O¼Çåg?üÃ%ÔQÑ¡æ~I¯¯Ú‚óÇ AµÃ‡ïkxಓé†SGõÃÑSxBQÚçðñytRøJ­®UèGo³–‚\õªj&7a,·äs€<]VïKÀ,ù %ž~_i$0{%h»æ`0[i2‚pÜÐ2Täçô)ãˆ) Ï²vw]óüBu©šÄ—5é ­Z’އ<‡„D¨ù¡épÝ)#;õ ¯uùiÊs!+à×.J&”ÍûÍThpT…=y¬ýëcZµ½žOýD‚ 7áÙ+O„Y¯Å”1U}Ê€t'N˜Æ¨__D ûŸuTþùã³ Ñô-㈀@Ð'©qú“Æ?‘íO~w ¿3mt*èaÂ> äÃÕ'ÀµFvjo(Jg>6 Xa–vÝ.ýûG€Å_p]0n0»ëÕ´j{=¿Æ¦\>ú•t€V?-ܯӋŽJÏÝ0¹Ï’î Æ¥j0t°L³ßòªµ$ZÖÓŽÚ'? r‚>GÓOg<önšñ4þüu÷rÖ"±‘œÙ«—‘¯%)žB †ý•dÒ—"ó×Éù8º²\qJ§Â¸ÞP”&<ø7þÜøm®›šI~ËkËð‡·VÒ쯶ó¹m“î6Xør6Þ_‚¸àÛÝX´aïÀ;ñÆV²WŸ È‘öëú»ïÓÁÖ×Ù¶õ9ÒûôÁ–ã6婵|© Ö€ß½¹ÿX¼¡O^³~ìj “¿ÛÇ_¤$#õä¬å¹>ŸoͤAnüGjÙw`™Ð}rÔÆžõO _¿Ý² —0 3®žÔé9Ü/v6¨IlæÌçIÒr/G1oÝNn02µ‘´< 3B+iðÖçÛèÚSF ¨ °£ÑMwÎ\ŧ¶r Ó? û:Uð‡œµ€Þò9jÙŸŽË€FÓÚ§¶ÐV$Ä£iŽ;y›ñÌ¢oPbµÐô“†õ©k&"A¡Æé§Ÿ½´˜|U~´‡ ,3[¹zA¥:šOù¾6#!¦3€YKx‚UÛ‡êÁŽšú,Çf±ñßH„á%6€\x짩Ͷ)£¯¸ €xèT-«; 0¨õn1ê°îákñÜõ[ºå EéÚ,Âò-µøó_ó7£A®%às€üÎôRÏ©¢´VŸ‹EÚIÍ>W¥i‡¥+Ùõw*í9lÙ=ÓùùJL¿¨0k Ñp†½UÚõé(¿a?¿Ò¶M=ÿÝÔ§uF°;/H”Úþ¼"€1üîÅúN1)1 ô2ëö4ÑÕWþ¬%ØÓÒ è `¦7&Z=/B” ,§t!_v¥G52ˆÄ2oÓO©´ç°·}>]óüB³L5Òöåäzcç$Ç0 *ÈÁ>‡jŒuYöMDÛº£O,`m– ’« ÂÂ?\“N›Ö§ö9|4gíNÄä8®?uÊm³×ì "žf/~þñ4ÝË‚^$1òãeMW] Äc8yX)¾ÜÙÈņº»O‡¼ ¿?;} îžvbòºÉq…FÝùZÚ¦ËïŽOWÿ}aò½KN8O^=©Ûá½D;@“™.3ÚñQ(Lñ6óhƒÙ ò¶ÀjÖaÕ}WÁ¨“X,®Ð½³Vcd™O,Û û9 –WÈCØq¥V3cÔâóû¯‚I¯eŠºwöjŒ,ËÇ£Kv©}:–[ÄÕÿâ1TÚsPã pq¡ý9kú›Ô„Ò ^³AË#ÿïëÜX¾Ç€ñj”ŠŒ_M‹ÙêÑì I:PÀ…J{>¾ã2赚n»î"@ è%òŒêƒ†z¶<(¹ÀÌyÜø{aÔj9 ò6ãŒÑøâOW蓘;!¤aO^3‰åuü¡ ct™ äiSd,¹ûr4x‚¨¨ç#¯Ì” ò6¡ÀÂzÈçÀ'ûeË IDAT™4þî`d¿£#“^uöð@мÍ|Á^ Y!œýÄÜä\²7%"ž9ç EûýˆŽtÙ_àõÕ[°|Š1'KZò“Ñ0ò4ð$ʼ"§ É>}æè ¬yð˜ô<Ԯр=~ÕDf5é“}úè už>Ãâ».CÓ€ºÕø“»ämyš0Ñ.ãÅŸœ¯¸fƒ–íjòÐYÏÁß?Ù€åM 0ÛxAª‚J@Òâ…[Ñ X˜­`¹…¨qúqç;+Wº¯³ @ è%<þ"5¼m=ún€Y‹y“Þh Çd<}Ýi˜<ªË6×àÇÊmutâýo'3˧Ÿt$.?qÞúõy˜ùëó1eL–Üu9Êl‰¹Í”AHØßímîI˜­ŒÏ›òI ‡?Œ§¯; SŽªÂì5;ðîÚ˜³v'xÿÛX»»)ëÃÖRWlhR¥=q sì\C@ÒâÝõuØçðaùæZ8üa:þ¾·ð«ÿ.Á–zpß[xqé÷ýÚ X±µß×8øa2'#–W̯ŸÎè ˆÄâxêÚI8ÜüãÇgB'µ%_zÂ0\9~8ÞøÕT¼õëópö˜*,¾ë2Tæ'»·O3[)Oª±jk & +ƒ=ÇÈàö·Wª[Q»äDf¯äS‘`ë›Æ0k æ½?{iq·9b @ èEVn«£@DƯßú‚¿Á4=*ïK®:@ŽbÆ5§â9_"$Së’'' . ?96³!c˜±Þ 6ìÃ# ¾æ™ó±Ï_臣Pd/-߈}Î@kIÕÐ_óÐ5ÈÏÒæ¾èo†`DÆÊº(²HRRö:ã~îz Á»·\ˆcª @´8™hôéÃõ{ð肯ùŠ‹h¨µTôÁü&µŒôG·_Ša%V¶Ïá£ß¾¾þaoÔ…Àó|Lm4Háï§æ"ÈQ«£Ëó1ëæ  “4 "A/2iD9[³»‘4RÏjûËQ@ŽáÈRî|{Bq®RÇ,6^d¥`ª N¼ÿm¼´lcÆ‘A™ÍÂŽRÄGf±p¿5þˆEÆøa%Üøë \µÏ˜ÃG\ƒ°j'Þÿ6æ®Û™ñ|Œ*Ëg:‰O«ô´ñ)@4 ³^‡ûç|}® Xá >"Öêy‚ÙŠ“î¿÷U¿Ý­ØZ‹÷ÖíÂ'Ûš–ŒÜ¹Ô²O5É1 ÅðRF•çã¦W–bô¯aÔ¯aG£»Ó¿¿Äjf'+åÎßAò9@®z£&iüçÞz!†•ðÒ¿{c6T·`wDEÒs‡±­ñ¸Ó“jüIy`Ôk°¹Î‰£ï~½["Âz‘¹kwÒWlJÏPn‹m I†}èH(e¿¨kË« ,¨uúùµürþ™Ù–\öÔåÓO,X›Qhf[ƒ›nxá#ui[æåjÉuï¤!o×ÛÜ“„ý o3NZŒ¯v6¦e˜³ÜÂ䵨ÜÌe’okeÆé€¯v6ÒïßüŒ'f1þpñ±ÛÏzö@ G ´ÀžcàcâüÌÉëÉ,ù€ÿ}¶ÿêGÓ§ª`¿<óhî wF÷BŽ‚\u¨²[0ï·¡ÚáÇ’MÕÐJ —ÿõl©suê÷ïlôÐÕÏ/L¿/:`}šåð™%®F’~ùŸ%ØÝì%xñ§SPiÏá:ñ.T•d°üJ„c S+·Õáö·W"*xpá½Äö7ÝþöJ@Ûôi‚häiÝ o—8íj]‘H‡5ª~„¢q>Âé0z¨¾§Õ#•±¹.½n}TŽÓ~!9Δƒ.ä ó¶;jú–lpÈÇ×Û3 Öínâ×LŽŒ†hõˆÅãØÖ>ªt#tÝ ‹x¦Y&ã/Gùh0yšx6W¯¡áçT#¡ÔfFÓß±*c*Z=ö9|ØTëìN@(&Ó¢ {y_Ù_Ù]õ¾€$áÙ&ã/Š þü˜µ²½ ¬h0‚2ÃEϼo÷6gýýq…hêSó²ßDíût¦k¨FXѰ¢ÁhÆpÎŒ¹ØÑà¦]Mžp(é²_»ŽˆøŠ¡¢ÁüØÖ¼ÿõ.œ=cÎG„ ôùuÝ·’y…}»t+¦=3?- %’ݲ=o"0‹]I1îÄûŽ\0Eƒ`öJ.gd;”x˜ç—ã¶YkpÁŸßK‹tjg–óAan¬™½BR—W~PØf+³W Þ/gÿN%Î3Çó˱x—?;¿_$nØ×‚}ŸöO1ޤ¨T õ­”ûâŠç?ÆêíõÐèô€ÞŒD^Ë/$~øâÇœØ_ŸÎouzIÅÛ 1‘ßÉóHR´;˜­ ´øÁ¿>ÆŒëø{[úŽ!_võA"PЖªt¨7å¢ÎÀ3lu€p‚^BÒ´¿ýøè°–Wœò¡ú¿:ÐNÚ4iÇHDÍ0nw ƒ%)§Zçááïp,=Tyú(u~4QEГÞfs[euÕÑTI5”AOr¿Þ¢ÊAUŽëàü§,=kòª¿7å9«a •võ¡¬†tÛ#ÇÞnyYޤVòµtj !Ë)HÅx\ubj{Ôjv­’’ÓÎoÓ>G÷¯LènNVÊþþÃ3ø(;õ71 XAUr Ðñ}!G#|î½e_ë~ö £ Î{꽌K$5Œaʘ*þG4Ã}aÌI‰Jð>m7©¹ AOò~J\ë´ök$0{%šýa|»¯§Ž(ãÇO½L¹€ÎÙ ` ¬ ö%Û˜h˱ã½u»ðøü5ï›á½D¾ÅÀÖºãR|tû% W-gÝkù1 ±?wJ¼ëÓ#’Ž™H#Û÷iøõmô3oÓ‡8oì`v˹ã¸$oŠ%o3ï7Éùª}’–'¦¦LPÀ‚ߟw\FYgÆÀþùã³°èöKù³V¶u S¯a±AiíÓ†ÖÊ,·°]2/ù~vú<2ýµš¤ß@"ÁÌS‰cÛ+ÛU %5ᇓFgÝ·#„ ô"ù+È1µ& e˜ Ÿˆ…qé Ãø:Ã~¢&ª1{%×,Ï)èx»Hpá¼±ƒñ»óŽKûHÒ06¸0§Yª>ÀRV)¯# èÆé#+°­ÁÍŸ´Y¬zƒÌZ VP fÊÍ\s!äÂ>ühÒh´-ÃkÐJ¬Òžƒ’<P†óôa?.B0"Óúêfüà_‹Û »Ü{ñx<úþWü­¢!=׈Xäm3åâÞ)#à †q˹Çftâ QË)σĀ8 Â…ã†Âf1àÕ[øÜ¨©–¯ û@A/`0ã¹ËÇ¡ÖÀgñ!‘㴻Ƀ‹ž]ÀÕ’5@œxÒØO'ÁÚÝØPÝ¢jÎwS‘§ G5˜) ÏGE¾7Ÿ;®]ºþ€BD/.ýþðk>ºWs¨£ßx{‡ ìO&»Všƒó´¸áÔQ8{LU§~?¨ÆåÙñ>­Ó0Ĉ0õ˜Á¨²çà¥åy[:Y¥“< <ƒ?%:AÎ ïzýRxidZ­gUˆDñ·žŽ\cçªW&SAÁlвQev€\qÒ‘øèŽKRðÐô øá¤QíwèÊ:â΢Ѩ¡T_ºÏ/Þ€¿|ümÆÍ% c•ù98st%Ìz +ï»V£Ç*„3†œPÕëê²·¾‚F f¯³äã·³¿ÁS¬ÃÌ/·üiÎ4{ÍŠÅúÙK‹iíî&2h%6´ØŠÊ| Ž©²cÙ=ÓR0eLj]~hTqºäÙè¡:,¯0[ñiu/.ý·½ñY|OO£aŒ .P…rÚöwI—–˜„1žÓáiDuCž»ar§¿º;«ÌÏÅ”1U0i%,¿÷ å1¦¢¾p¡¨œÜ°ó?DÛª0™ø{%W:Ì’oÐq5 ×±ˆ9ëa3ëñß_žÃºjüúÁˆL‰m #‹AÇ`Õözº{æ*Ô^ØÇUÏ•ëzòµa?þ|í$\z°¬—¸B•ã0éµìë½ÍtÕß> +¶bg“‡Ò|žýÌ•ÍÙ×'IHÎÎüÍùøè»½øÏòMÐÖ°yÆ “4,"ÇIÃt’†}üÝ>ú¿ÿ- /±a{£›‡­% w½º´¬‡ÆbêÔÃu§ŒÄCÓ'ôS/ X´a/ýæÕe ßM Çd˜ôZ¶¡º….ÿË€#K¬<T#å—óBYæ¼ýj¯…'™¦n§Äùþ¶’®õUÉbÐaå}WtyäŸ@8A?"‰Ñ¸{ßäÃkIÇYÑÝy›HÏÝ0;´S˜ä¼­Vf±ƒ¼|¾[oæ…ÙÖ~ t?!QŽ·Êžƒj§,§$G€pÌZ z0ù;nþ~ýß—ª}:Ÿß:˜1ämÌyéS=‘ZÆ[˜„“ÊŒ°› xâê‰lüáý†X\¡›_]†ÅkÔO†Qt4 èUÇ I%iÐp« %çSÆÿÙë'cÚq3þ›jtñ³óÓ“£ähëü¦éÑyïž$aüÏ; 7ìMÏiHùÔ¼áõ_MELVð“’žð—zºë|¤žã”ëIôà›Î:¦_ÿÉH€Êo·›Ï‡ÛÞü ¾Ý|þï§at¹ý ó–z]ôôû}£O‡¼­RÄ*]¹?;B8A?@!¢ËžûküA”!iˆ‡í`9ù H?¸rì4ùšùÒ@ÍV>× à‡“FáþKOîÔÃek½‹.lû  pãÁТ\ìnöfMhäPi·pÉ×ýÔ8hä(oŸ¤3åòå¢3 é †•âõ_MÆ?Á¢ {I!Âîf/~5åhcq…èÇÅV˜ôÝ3òßÞà¦óÿü—êî ¯ˆxr§%Ÿ«*q ÀõGâÁËlz§‹bÄ 7Ð0ƶԫšîÚ ÕÑÂ~@‰ƒ V3Œå¬bAäw€y[@7F–åck=/XÓ•‘E‹/DöÄd¥ïHþväsð1Ö@“ÊpZˆ¸!¶W W·í¡$¿äWz¹Ãñƒ|Täç ÖåP#ÿTÎ;¸Ýo’4ŒÝ:õØnû‡?LEyêꂾЧSŒ?L¹ÉH^àÕ[qâÐ:H€p‚~@\!Ê5êáFÀˆ@ŒñʀƔR¢Æœ¤V83æ‚.H:= Uh(%rÀKž2°¼"Ps[ë]¸ãÂPf³t9ìåøáüTeÁ·.ýK娓ÙÞ»=jöw©J™2᷊´€+ý|„ýÝ>ßÏò+¸š¡Ù½¨uùñÔ5“PãòHã(Ø\ç¤iÏÌÇe Ñ-MŠÃÝ[}ZÍù!o˜Áœìƒ,¯äåe†"ºäø#ºtÍ… ô$ c‹ïºŒÞûz›¿ŠÞ„ý`Æj‰§0©ÒŒå{|[kqú‡dÿìô1×ü·eõö:úá¿>4f}µ¿—U‰S™Ï}wîçõ]Ú Æ…™ä?§mWa$·W§Vc‘äR5fêÜšñ.Ñtô”1UÈË {+ÈÎ;èG/~ h$Ì]·“¿©È\»_Qxò_o5Ngèvñ(¡ ôlf»aâ(ä´|$’%¼La^üåˆbkë¶t¸æ:áÙë'wÚøoØ×¿VÏ«²Yl¼&}AèÍ=Ÿ}¨‰Ë\‚· Šë¶g[‚)Gy¶AßO ÝöA7@ n>gœ0þÈwÕ-tÃ??B\£Sût>ïÇUÜYÖ3çÓ*´úôi½HˆpîуÐÕÑ? ’‚~GÓOg<ö.¯vV8€ºÆXUKÌÿ/½ûrTÚsqåß?Ä·{›a.(AHcâÞÄ…TÔlÿ§¯;­Ó³ý=)\Ú’Ï+ÂKr©ß¯¦ƒÛÎ?^ÿ`s“.}n7þùeèOÂU‰ëëÔcqó9][ê) âFhW“Wýc¯‹¨ÕêˆËxóWS1~X)xþÐò-5øpýÌÙPÇç®ãË£aüjÊXÜvþqzpÄâ ¾ó5 ¬hpOþDA*ªD34ÿ—(%«7Ñ.>î•W1SGþ ãðü¡3FW2­¤¢!üôô£0´0ˆ†ñìõ“;müþ4.XP$ÐZP­yÊ‘e@4„KŽ?·_x<à½u»(‘Ũ® hÚæmôa/CÜr7ðœ“Tâ1^>¼e/¨e~sÆ(|óȵ]6þ€ˆýw0B{[|7¨ílò^Ò ª ·ÃA"pÆèJ•ã´vw&/ëÒCƒô«ÿ.ÁâÕ\oÞ`¹zv­» „Ìíüß_ŒEöàùÅ¿<óh¼¸ô{”Ù,X~ïthXWÄê_ˆ@¿{c|»;))Ü}šü V¥¡[/9jƒ)½t·* à€Fþ „ ºhw³ç>9/s3X^Â_&‘·qÎуðÉ÷ûø4€0æÀŒ¾lÎ9zP¿,Üö:¼8û‰¹¼Oë͇&á/‘ÈKƒ¯áh”ëNØË0°JBýÏ”—lS"ìÿêç`âðò¾Æb @ èŒ-Ú°²¢®ULì ¸€HÓŽŠùßìæ+/òÔåA`¶"¤È¸í­Ï`1è°ê¾+)Ǩa?0öÉwÕ¼Og3þÝÙ§ã1nÈÕ)0€¥6ìmñ!¢*J€e÷NDzMµx`î 0ºÜŽ÷~wõAGyD€@ èûd==³èkµ°Oã òÕàF‹|ŽŽ·tž z0¸0¯½ñZkÓ«úH ¿{cE/4´ÿñ¯¥ßÓŒÖfkfã %û4‚n®ïp0H:0‹*4¥3:#¶5xPœg†Vâ×ðçgŒAe~»áÔ‘ì¾KÇ'w}xú„n™âS Ót*c:ù\›>èHɪŸ/Ø?pó¥zеQ4yC\ÉQêHš@-Õ`.i‡Õ¤Ãmç/¦2й>æKmÍyüZÂ_óAˆ;©f+k½ŽräjÀÅy˜ÿûi0h¥´k¦¨»»ò;D@ ñXúß ¬ ’?“F_Øžƒé |€%MþØNžÑvZõŒ'°™ò°pOÿ[¹·¾¾üP6·_ÑaÏlÛ§% ¬ ‚ÏÛÕ>}°6XÒLâh `ù¥ØÕäŵÏ/B,®¤Ð5Œ±îLî€@ è4:IÃ^úÙŒ(µryÔD5ºTR+ªÒ±…:.ìªk]Ã.è<©5Ôsªx›ÕsZß~{õD£Q@©-Céh´’†½ò‹s0<[Ÿ–tH¸ ¤*jW¬oíÓ‘à}7Ë/…ý骞Z 3`Cu ¾ÙÓ|@Çí,Â]âŒÑ•ì½ßMã¡~WOŒÊ„úÙž&ÈYf°¤3ÁÀxþ…ÁÂÏinælõ„±ª´÷  ñà´‘ål~§û47Ö»ÝjŸ6óÌÓð)€”ºäw±0¼|Æ+éÑЙpA—ÑIöôµ“ø©ÉhëHˆäwAî½ø$ÜxæÑbf?h% {öúÉüL}ÚÛD‚¸ø¸#à „y6Ûºµ,§`üiÎp#=š¤'– ‚â’†1›ÅHßU·à¹¥[yØ9èáóþqˆqò°Rž±n¶r£%8xR§XR_§@òÁžcÄ §Ž:D ëÿL;n(³™ ´vw#ž_±=½O+2 bü%xÿ›]jŸî!ý I ÈQÔ8ý°™ =óAD!¢f_ˆ “ÉŽfõ‚=Aêèõ¡¦+íhô‰ˆk6ôb›S¿{íE[¯E‹/Dq…èôQ쪓Gðyý gUÉ‹ Eƒ˜qõ©8¬šU¥r¡ ›‘£\Q®h0Šó­}çkX¿¯å€úXWúG“7”ìÓMÞÞëÓ©ß½¿v„b2yC¼O;üa’ã 6²œ]?qT²OOSÅût$ˆG®8—œpßYÉÞ§ÉÝÐ>7 .sÉß¶S AÈÓrÖ€\õ˜÷›s1çÖ qte˜>(DtÓ+Kqʃï`k½‹N{x6Ž¿ï-dr®ßC§>< ï}½‹þüá×têóðÍÞæCþðyçËítêóðéÆjúãìÏéÔ‡gas³ÃvìlòЩÏÂoßXŽ•ÛêhÒóðŸå›y›7Õ:iÒóðÀÜ/éãï÷Ѥ‡gaÖWÛ;lG(*Ó©ω÷¿m nšðà;¸þ…Eˆ+DÅy&öòÏÏÆ€:…Ý3í$œ7v0 kv7Xr™S”¤=‡V¯V´¶rÝüí“õ]>Ì»kvФ‡gaц½ôм¯hÒó°±ÖÑaÿØÓ⥉½ƒÿûßR|±£&>4 /.ýþ÷é-õ.šøÐ,Ü3k5-Ý\Cš…™_në¸OÇd:ãÑwqü}oa{ƒ›N~`&®~~!ä¸BÅy&öÊ/ÎÁïÏ;ÿúÉYì—ŒÇùc‡à³?Çš]M&©t9Ö~Õf+MÎç'‘´`fkû<³•ÿ—9[UØãÓ6B@Ðg…n~u9—7ÕH|yc>¼mÊlfä[k¿õù6ºïÝÏ[·„ǦŸŒÓGU Äj>$óž/-ÛHO,XÛ®¿á47¸(­_íl¤½ø1bÄR¶Õ¢ÒfÄÛ¿>¥‡¨Í+¶ÖÑOÿý  Ñ¶d§Q„§®”Ö§?L?zñcl®w`|4¯þÖ%w_ŽŠüH­Uðм¯èÕ•›Û,€ZÔ&­¦¹ çˆ†@žFœ>ª/ÿüìN÷­ÿ¬ØD½¿¦]ÿx8qhIZÿX·§™~üâÇÉ”v½mF->üÃÅ(Î;4}zõözúÑ‹ƒXz¿[‘þäÌ´v¸‚aúé¿?Åw5¤÷i‹ïº •ùh%MrûGß_C¯¬ØÔæ|¤öé2þY¨e@Ä—eêÔP~Ðçh$×rHl«Êû>~ÕD\9~ø!9gÂô "ºøÙØRç³z3ÈUf-4Xü „ÃXqï(³YØÌ/¶Ñ½³?çR´yE o3˜V˜­i c˾ö"A0k @Ks3~qÆÜyщ,“iüý3’ã`öJ@#\µ`ù¼ì²»G–äaÞ­Á¨×²î8- IDAT»f®¢Ùkv¨‰—6^(Èlô&µO—&³øÉ§ŽøIá#zR0²ÔŽ­ .@’0œ?¦ç=w¿³ …4Z¼ü“Ó1¸0C óÙ "A¯£Ñïßø,­W[ÈYÄe0O^3 ·¿½2iüÛmësaàÝ[.ĸA=J{çËítϬÕIãß®jÑøçOÎÂͯ.C R²ÐGq9)3úÇKÆãǧî‘6oªuÒÅ©ʶ¨F¹â¼õù6l¬srÃÝAÂá(8~H1ÆQ‚.ùîàÒ]‚.0c. i¹Z]n!?Y5pF—Û;ÕŸÞ]³ƒîœ¹*iüÛ}WZŸ>¿{ã3„â¬];¾±Âû€».:??cLôé-õ.šöÌû )CŸ–#I­„§OÀܵ;ñí¾>¸ÐµO°Kôé±U…˜<²_¼!iü;¹x_­`ÑkQ‘oÁ¶7.ï{×E'²½->šòÄœä~SÕï@€ ×™õÕvºûÕ:’¥/—“á:VPÕñƒnPÐ HZÌýõ¹ÐJ¬ÓÀÎ’¼yÛ„ñÒÚìw? ‘ ƒ‚˜+Üñ8á茸ï±8ªÜŽ“ŽèÞ5Àq…hä¯"«äi,ÂC‘:#& µc嶺¬2¾Ô²Ðê ‘£PˆQ”>„ßÉGœJœgŽÇ"<4­‘9Šçt&¦3¨Sý¨Úá£3ŸÃç©í•Ÿºº’y:ÀŠòû°£)%rT:#þpÎQ8~pq·¯kïTŸN8:#&aÇŠ­uYTrT«ç2 €;À‚@Ž~¨y/ä¬â1¼ø“³0´ØŠ¡E­#ü:w€ì# 3…¿•8Xn!˜­/¬Þƒkÿ±ÿýls·µyS­“¾ØÑ°ÿ •8˜µÌVŠo¹bµ“šMÁ`³•¬%Éý‡%Îï {% Ç Õhø5PGþ5þ ×ï!oXMdË6(T°ÂA`ùåð&òÞ²öé0[)^Y[‹ë^X„—–mì¶>½¥ÞEŸïH¨ î§Íy¼O¯kèDŸÖ›Àle­Žì~²ýS¡€›;C)5X>×úÿÝ›Ÿ!ÞæXå6 3ê$ÖÆ:‚^B!¢ÛÞü ó¿Ù±Uê¨?qSFƒ|þ.%ê'@<óVÒµÎI'¶M©æ‹q§"ÇÐQÑ”®3{ͺkæ*€^«A4®p'€i@®údö5€ôi„£ –l%wCúHYgH†#[|9mäðó>-wÁ˜fcs“¦=30¶ªª[x;Lyíï­åÉ@DõZ’}Ú &I€±U)±µOÒ§ç¹FY"\Ì’"â¹@VµR#Ó€Ù+hÙ‹óžzß?~uRŸH„€à#+ M{f>¶7¸S.6T;’%1ÉQd1“Lh4<G«ÎX¾´: Ãî/†•ܼô}ï~No}¾ç(Ä"ˆÊ27¢ÎZÞŽòZÛ¬åÎJ$ÀC¨†Ìr¸LÒìlòT{`Á7»é·o¬àb¦áÆ_oæS$`lŸo‘l‡VŠi¹sã¨á#›ülÂ' 0˜ÕkˆôRµ‚žGÃ…`ÐIaíœñ`Îôúê­É>Šª}Zrc9Yú´¤4ZP$„ü€Þ˜qS&iAö9|]úI±hÃ^úÍ«ËxŸÖHÜøëM z³Êò2IR§HxŸÖå ´îÑå>ÝÑóˆ¼Íž¾î4´5þ¡˜LßîmF\!œ<¬:uõÁæ:'Y :ìsø0iDy8 ÂR"ºõµåØÞànMø3XT©BzÀ”]·œ%ªÌ‘DÃox>Äý—ŽÇÙcªêšµf7þ©y ê(ñ<>bÒeyê­IDj C"ß Æ Áý—ž|0MÆÆZGÒø'#$Awk;ÔSæF«Uýö׿ĿÖ".K«7'΂î†Ð¾~\õÐ1`îmÃf6tzäÿúê­é}:äã÷Ÿbd9»Q×:Ù§ƒ Ÿç=]>¡3MËÈæ:gÒøwا÷×OSs‡:Ó§óŠøóEo´Ú—úu 5ŠßFÕ/Wè¼'ßC­Ë^jÃû¿›F»šW|[ç¤Å÷¼Òý9ÊýÖ¶b\xÔüfù'EånŸ÷G[Ur”6yï€ù,ïkÎ5ïf™ÚHÔ¼ŠaùÏwÙùÀ¯­€¾Ó²˜ân„°á¬Yãpë Ÿ"uÛ¦?Û®’X;È´ $ßÅ-“!&åG°tÆ(<{ÍɰšôŠМß=‹‹X…·keˆ‚ G9Dá4yB8÷·äNá(Ì6ügÍf<ñÑ·½ºc× ý¥½lS;š=…023]äàÆå_á/+¿ÂŠõ»IVˆ.ù×›ôÒ;ÈŒÐ)÷¼LÉ aÐñc’X]ûàœ!éxWc¶á¿_ÕcÙÇßá¶—><øÎFºö‰H!¢kþ÷uE6Ø«çŸôˆkÙ¾A a°0ÏZ˜þwå±S"L©*Á–:'¼!¶éµ;;½Ñf§²ûñŽ:pº ŽÏÙlÃs›[ðô§ßá·/| xôýMtÍÿÞ#U„º"ÜêWmZJ¶é;cBè OÈÛŒ;kñ›3f'úüòØ»ðÕ6äiƒÐX'$­KAØŠ‹ ·¾ð)žüxK¯=ÈZ @C¿â™O·Ò[ßìÁên£äkm«3÷âéѾ¬Þ€ëwF”ذ»Ù I|{çÅDötûæÚVºaÙìr…6€Ü Ù5zãœýN àÆõ'“A‡?¼Äˆê2G‚¸ææ³;” ö#tÑ+1mD9–mv³@ŒÅžÂà×08AÎ: Æó?=¿»o¤Ù4|w×%Úô–:']¿l j¼axõŽ>·i\ ¿ W(ŠóÍøírF—:°£‰múýÿw†äe=go(B?ð&¦*Çã] o „%?…Á?Ð×øÛ%G㤩#D0£ÿ®ùÞP|¼‡½crar° ªP©%GjÞ á›?]“¾çZ ¡ßññ¶zºø•€¤çh·“¾þž þæ› ð…b\3 yH01¬c|‰·žqfu ¼•šxÓÿ@ñ…vÄzíœUµµ)UÅØ°·…ÇŽêÜ‚d/EÃ8v´3G”áŠc;žó~ì_ =-^ÀZ ã=@j#ÜÁÛtØÏü€‚ ¯ãK,ø¿ÓÇQc+³ÚGLVhâ/‡B€((ïÓÔ:y›‡/Á×{š‹Â`j³éX'Œv`JU ~¼pJ‡6}Â/ÒŽ&wߎãí&È×Ê‘cp˜u[lÅÏMÃìê ?ð&}¼­N]Cr¸Þ¤€Zk`Ñ Ì[‰‘¥vTÙpáQã{h% ýŠzw€nXö;ÿŠìÎ?>A‹”n‹ËÄÿÜqCØùÛK£Â^Ê©I½¢ [Ꜹà+°nWû©Ó¨¬ÐÕÿ}—¿£4»óOý ´ÿžÎÎYuþKfT³ó·Øy‘3å±â )"¿«7×áÎ××á/+¿ÊÁÿëªówdwþÉç©J¼j¸ˆ;ÿyㇰ󷗲p­$ɦ+°¥Î‰Kþõ&>ßÑЮ}Äd…~öøûìüí¥ÙQ²MtצUç¿dFu›óÏ/Jµé¼B¼¹©÷¼ñîzý‹¬6ýèû›ØùÇŸ‹ö &÷ι»ùE|Í"¸=^¬ÝÙ€¼µ>Á}øÅ¢iÔ,_N– ò ŒÄðÖ7{ñð»ßàÖ>Á²ÛŸtØUh€†~C«/Dsÿ,ê½aNû·×RCrÖ‚Ü<¤Fuâ9A–¡Ä0¬(Ÿål ÊSÛuiÂ@BàÑ÷7!Ë$Þ]ôÏ•xû›½µ³´z›AÞ&ß rÕsotŽ O  ÂaÅ‹ë¶[jOqÊ9³Îøý«¾F|žy2þ³f3ÝõÚºŽÊk”®z¯è¹î€†>‚ú\@ŽbD‰ l©erXòÜŒvlú_ïll—Lz郫°rÃîÌç"ù+½-l×¾ÖîÛ´·ûQj³°M›ó;µé­ÞЮM?þá·LÈM.’‘lÓ~g7 éÙ a/ÅGÛê1ëÖ§á „iX‘ ev s.rÝØ-€$ñ&¯°ØpóóãçO¼ßí @ 4ô óÔ]F†OÞfSDÉpPÀ©ÖÈr#ú§Âbƒ(¿ª˜• ±~}ÉìvG0é—#è‹«‡e+©F‚,{Z2‚ÿ×fÏa?@ DÉØlj^îè‚¿ÏbÇa7/ÿßK•X-ÉWÙÿ]k¿‹¡7°&@_Á4ô Úž‹ðGâÏC›ŽE6]ë‹aò¯G:1PQ:ñÑ GÙ>baõß9ÚG$x.vµNßÉs!JFV»yþ•F l“ ïÀ¦.– ׹ϿŸ¥©ÉÛm³Lyör£2®ùß{øá#o£Ñd•ÀdŒót²˜@­5VÎÂê`‘&³ ¯~¹³Û™-ÐÐohñ©©¹$Ã'¿+å=Â^Ò&Ρç€A¯Wßòué{„½T¸p†U§/5¤#ixÍ·N^àþýÞ7mçG x€>N™¦©™- É[¡ ëHzugCJ×R§¦¼Ä1¶¹Ô…V§fH¹­$ÿEÜ-ò‹!ðÇWÖ"’”½ˆ ‹X-jÐ%ÇxPLÊ1†ªÇ( Ú¾àÅSÀAòsÑRos6›V˰ÕÃïý×ê )o‰¨N´íÙJ³é¤ç"Ó¦©k©u£5aÓÛ=ª#N¶éäT=@$ò !p×këR²»š=³9¾‘ˆe>…q›.B¦M§®5}&íQêóc4CÅÇÛêÑâ "ßdP•“66VK g „€(¬\)ÑxwÀÍÏÜ­î-ÐÐo(±YÄê_-Å×jÝÇb&i‹@ŠÊ™ºã®Ò8ÙÕX¤CH O£zŒŽ.yw$IJ«áç…†§Dý­žÂŒ ¿·µ¦$Gõü#ê÷9k3‘ÒÞ?×¶ß}Å1“ÅÏ9 ¿]4Q=F 2vŒéX„S§ÎZhäà†ölº©ËÏEúÝ|ò'‹pûÙGar~”áëܦ-3ów¶îëM;°éÌ [òK—/˜$î8wîá4EîXi0>y4½Ô£såöìÈÙ úËmbò°"Þ‘F‚Å·9 DQlÃŽF7 fQÚ!™§—W±pÖѽ@1ç†Sf¤¼n1èÅY‡…I/ñn«ƒ…$¾oØÛ„ýØLDÙhÉÀª{h[ƒ‹à©O¾£V_ˆ†Û„Å K´ÄÜÉÑ@,‚ »?9n*Lq‚RöÃö‘!¬vG9>¬ ⲇVánµy{£›V¬ßMðáÖ:úrwY z1¶¢•+‹ào/àÀEŽá' §bÆ(u\h_3ê…Žõà ‡âü¿¯Ä)w¿Œ¨¬P0Òv/êÝzaív€#ËD¹Ã DøvÑtLQĸxÎ!XÍQºß‰3KgŽÁ‰w½¸â˜Éxð(£1ÚÙèÁÄ¡E¢Æé§+]͵­8jl%â‰O, ¸AD}ZS§¦]€ ·_ˆÅ÷¾ŒÝÍ^œ1³Ë×nüå¢ùXÝ^ßfÓAHŽeïÅïÄmzýíâ쿽Ž-uNœ6}4^þràžóçáô£3lú·Ë?Å“oHB@€(©…‡míÇ 9ky”y2A0b5Ä¢¡¹+c‘‰°;;ÿ8´@CNˆ) zï+ØZïâV»xûÙ†[OšY&\:w„à"寮¥‡Þý†kÚ±(×Í6 ÀmKgá„ÉÃQ”oðÅ®F:çþ7¸>h03ÑÇ ÖÜcQnM²—öÝ ûAž&Ì®®À'Ûë9ª7r¾Ñ‚‡.™‡«11ÔÊÐ1|Î@„WУN;´rûŸ$©i¿> ZPÓn³APLN:=`4ãÑ‹D“7ˆ¥3«'qùÃoÑ{ßÖ$î™ï§ªü&ìe}*w¬¡Ÿ ÚôÕåøt{CªMÌÿ¾tòÍÌY& ‰ÑÂ?¾€&o°´cÓBµé¾ ÄѦyŸo2À‰¥=[<|áhñ…pæác'ñÃGÞ¦w6íëÀ¦;P< Pï™!/ì‚URðïƒC‡—tûFh€†.C!¢Ÿ?ñ>^ÿjÏ7sÊB:ÌQ‚®fL©*Æ ?]Œ•vãêÿ¾«Ša¨Ž;èᇒÔ¼’>¼ålDeóo{ŽScñá@ñ÷ÜWÛ—ä´päiœ±øpk][ËMÚwÇIQ½hŽŸ\…3ï{›ëœLø3˜˜•WVK>ÿ¾€¹ê1¼Ð‚HLA½'È ³ÎÀÁ“:ø'Y^øîóçŠûÞüŠî{óë¤Ú#á Ÿw”I—¶#iˆAîFÕù×wjÓ÷\0':þs%¾ØÕÔ6  ~΃^ ú r äªÇ»zÀžVïÚãA‹º{ŽË Ÿ:}þ|á|ñÏ·7Ð=o|‘ÊSˆ?‹±0 tÝ"ä$´×6½â†Ó1¦¼@ 4ô-"ºòÑÕX½i«Xµ#‰KÞ–DFàü#ÇaÙÇߥ:ÿô÷«i¾)U%ذ·™ÙþÝiõë)b³zàTxòB™†øÎ†çcO«¿Íéö3¨e Ä`3á G¹-¬4bœ$ QÐØþ8bQ³: êĦ÷$jåcÊØÖàIÌèoÄmº0ß §_mql§ &>Î<| žÿ|Ûþgû÷¨y7g#eµ{@ŽâÁï‹c'Vu+ÐH€:ÈŠbõ&U$‹>$‰Y·ùEøx+·³ˆŽv ’a+A(.öµœ(Yå”`ò05Péhá“t\û4˜°§Å§î,öóV 7ŠðŽ=[ QÒñÎÉbWyBsþ2ˆ@îz[1&%lº•xÐ flkp«ÏñþqþÂjôF8}!¶Û,-°lÓVÀbÇóŸoã×tçï¬åÙö2ˆÂ! Q +Y8Á:Wh€†¡Ñ["›€º«ŒC­¼s°Ø±Ë·G50mG°C8*s>vÕÅ&ùaÏuPw!é8ÅhÊÃwÛkmç‘Ê|ùÅüT²ÃM®ƒ¦]¾D\4Á/èà<„ÅÎ",jà’‚~æàfEhè3(DtôíÏ£Î凰—ba´ø=…CA'ÈçìPV N+êô g=󲱆™Ehl¥ü-ꀚ~†¢¨ß]Ä5Fs>DGiE!ñ€oˆ”Ä ’~‡¤ƒ(¬P2ѱð ÂQR bñ¡BP(23Çm%„›ò:óIØt3(ìäïCH:>Õ™w¨·éhˆmº›ª¡ƒ­—‘ ÈïÄ1†áÆ4 ó.O#jH‡B¼óîómml€S‡ÉÓ¼²ÕçÒß›ü÷ÎË{{¤´¥»rJl`°å;»Éèî}Ñ08AÔxk6}@"ÞðÈŽÃüC†jJ€z†›žþ0Óù©Vggò{sy ÷çÛ\sìÊy „…èúB tÿ¾hœHκi6}`B-÷ìhʽlz^- ¡$_­¯e™´¥áÀ¹ê!Ly©½ÝJŒË6…Ùu 9ÆLôôaF7(f¡¡ƒ ÑÈÛ’‘Rg¾†è‘ªy[Ú˜üm¯‚ZjTñ›ƒKÐ‰Ü FKª‡"³_ƒˆ:…Â6ô€¢¡žÙtÀ ŠE2Z¦ÛUŒEA•ç éqÇÒ¨*²aVuyέ€Z@Cš}L2±ZTv­ª¤¥áÀƒ(¨Ý,‡¤‡°«5ãî:}—"ùV@è_rÙ@€Á aÎgѤÙ"¿˜I²ê(êî@ØŠµà¤W¹†îi8pYñY åL"N&;J:æ2¹ê² ï ’"¿8ó¹P AÜMXmë$ˆÂ!LÈŒÚ^Ô8Ø“c@4o(Ú-çh€†vpǹspçys±p¸•É@¾î/N8ÔQ¤ämN ô¢áŽû°»rèhDÍ&Ô¦þ‡ƒØ}æû$³6µ¦_¹ç×CQ] ÄÂöOOÿ~‡ûT1ÿ IDAT¢¨ÂdIm4Ä=)sÄ"‰lB ä ëé=”ÒÍ)Ç%… ¾I-€¤N?¼è¨Cð½y4%@ ½‹zw€æþþÙTi^ Èïä–Ëø¤4R0cTÖíll[•XVÅÇì&Sq (1XzXM4û#ì¤$bÕÂéŽB‘1²Ä޽­^ÈÔë!©Œ÷™ë!/ÈïVÉr È˜?~(ÞßR£ÞC¯}°(>¶gÓ³ÇTà“mõmA¬"sšÞ”ƒMƒÔ±½ê?•LzìV#š|=´éHï¸(2æ‚¶Ôª÷PˆðÚu§á¶—>ÃÇ[ëÔï8aâPܼäpTäõh ƒ–Ðzw€ßó2;ÿ¦d€¥¿4ô+D^¡ª GüG’°ng#f®àô¨C©ÍÂ;‘\ÒÇB°t+‘º ¢2Jm–„þ_æÒÀIÇ­¡Š¬²ñ%ìjöbÆÈ²¤ë!³u®ÏÙ¦:2Jûý-58qʈÄ5.µYØ1†n°ƒ• HØ´ðɶzÌ[É×X‘Qf·°.‰º{îâ‘U›V°M‡eBQž¹›®íäXi0ZÔ6ã¶{øÁ–Z,š¿‡ †äaD± ýðx̪.WK 3G•õØùZ@C;øÁ¿ß¦w7ïãyÕé‚3*È©F©±êûI}z¤€ZkT’ïøYD%Œ{/˜‡pLƯžù0Z9 Ë¡ý. h Iµì…^øä–spåc«±vgc‡¶u wx2ÿ^ˆ†A®z”ÚÌXyãœt÷Khð¨ýö)©i5‹Òѱ[öAØŠYš¸@×/NœŽ)UÅøþÃo±4wGº ˆ@­ûXÍPeÅ“«ˆ†pïó@\·ìvºñ{ÑU\ p²M¨e/t‚ðÑ-çàO¼¶Öu˦ÉYË$Üø`&UTlñ´QøÍÒ#`6èa6èÀÂl-¾ d…zÅùZ@C;0èT³è 8¦<GD~¡ºÃÑ: B>nyLr8¢ 0˜pí“`ÕÆ=üZzª4àa-!L•f„£1…péCobíÎÆÄH×d§ñÀË"‘DCÌHÃ`‚p”¢ÉÂÕÿ} î߇´º4¹ê™ü• áJ)Ñ{)`ÊßW~‰×¾Þ•ø¾Ä" –½^‡OÈ—˜J‡(¨ f\ûäX¹q7¿–^ÒŠùztŠS¯£åIಇVᣭuœÂϰ馎m:æR«u¼dóêW;ñÔ'ß%œ?è$!ÊìVÑ[ÎÐ íàÌÃdž糑§13¯+ª½ó6½j“é$ ;3Ò]õ)/Çç¬Þ´gÏË»×`“ÚdÌy ÖìA€(¬äk2ùÊ`‚°•à›}­8nÒp”ÛLNHØËØ9ù]½ö3÷;„Q4 ô¦j¸­y|´µ5^%Ö¤~´ ’¯a(MŠ:“•»,Ò?g/t<ÿù6üè˜)Ü¢–L Ô!ò Õº¶Ò[¿tÿÃbƒ0ÛÚ±ižoðæ†=8ÿÈqÜv™,3n´[Ç6]PÉë_ò½Ð³MoªiÅ1†a¨ÃÂ64gAØK¹e/[‡‡ÞÄ ÎÚ”{!ò £w¿þ>ÜZ×§)z-Ðã&U‰Ï{Æ© u8I¬ ˜u –= ¿³G=Íú ñá/I O@ î»xn?û( /¶ñ‚öóÎ>ÆŽ]tLX…•©R¤€|­(°šð»3gã‘Ëk«™Æ"ªãwrÍ<ïÀ›è&І¦fEä((àÁÈ;n¼ùlÎ8k9¸;,9PPû`4…ó*VÜp:;~g a·®‡PˆðNôáËŠ_.žÉA€³J«ÚÃ~ íþ;‚z=ªM¯¸~ .;Û›Sl:Çk- ø:ËŠ‚1åâ£[ÎáL@²M£;6ÍÏa0ÚM½‚ ²âøÉÃÅÝçσQ¯ã2·ºË O#Œ: kw6°ðK‘Ö.8˜!l%€pãSkà EHˆßœ1§6óЉCŠÔYó9N["¯Áh ÷¼ñ% Üa¿?s6F•Ø¡3š9ä3€P $`±£ÁÀÖlŒ)/+n8c+ 0¢Ä†ÙÕ¼CÍVÈ«ÐðÀê ØÙä!¸lþDœ|èH”;¬¬(g0s©å „­tøõ³Áé“ÿïôY8{ÖXÌ7†vϦ! ò “üéÕu€2»E<{Íɘ8´“‡cÞø!m™€\`²F3Vm܃·õm·ŒÖ ¡SDe…&Üô?Åù&´øB掫Äe &âò‡Þâ.€NÒhújjRØJR_¸>™, ð{uz¢`ZeæW—☠Ã0¥ª8…hä „iæ-O±älñð´c´@Xì),(2;I‚N§Çå‡A(à §‹A/–¯ÛN7,[Ã5éÁ:½-ètº ­ò6s,mž=…|Œ&®Ÿ? žnºål¶ƒöž‹p 302QtÉŒj5¶²Ï? •4äˆok´øÞ—¹æ_8äj„:€£µ0š3Suúäªã^r!0<_;›=윉½?w&î~ý ìlò°C£(·[ð—sgÃlз»óO‡¢€ÎúÛ«X¿·…ÅÐ+®>f<~õÌǼÃQ‚KfǤ¡…8yÚHÄwþGýîfûV)à°ö'æÎ)0 É„;åkªÈ8tˆ Æ•ã¾7¿æ²ŽûüoZ8«g>&#íßVoÚKW<²š!é7/š€W¾Ü‰¯v7q=_ŽÂh4à?ß›8Š£' p÷ë_Ы7 j)à„MnÓC'v6ª6 tÜwö üeåWØÑèNØtI¾÷?ÔîÎ?Š:ïoà‹]ê1b¨°[pÝ “pò5ªMs@páaU˜6¼‹‘‘öo›ktê½/§ã{³F`O³«7íã6DEt,™QÝ%ç†&2ñc¬ÝQ¿¿P¶7¸qÆÌêÄâòìg[©ºÌƒN×eçŸþuÏ~¶ËmpX˜0¤H@³7Hkw6ÂŽ&vþÉŸ{é‹tÝ“pû ½OñÞòx:˜¼Í€Åeó'âÈ1_Yˆ¡…¬¢µ£ÉM5­~Ô¹ü]Þù§c[ƒ‹š¼Aìmñá¬Yc >Æ+_î¤Ñev4y‚)Î|¡(yßkØÞäe]†d2Û µìm³iÈÛ‚!…y¸ï⣱£Ñ¥íØ´¢ËÎ?å»ôÜç[1²Ô‹AÉÃø¹hõ…è³ Fb]Þù§£Ñ¤/w7Šbñ´Q …¿w6ï£r»Û]ýîü-ÐÐÔºüd31ýæ'¢tdŸ}yš ŒfÀlK¨Åee/ËQfë:ʹ'§GÞÛÄ]É,ùHYòƒ ó‚ZkXñ°›þÞ¼ ø¿ÓfAˆN&hèZ @C‡Ø×ê£ù·=‡#~û4¿ÔÚÔ¡Vy7!ì¥\[ĦÄl‚d¢è ‰ÁB]ä$•ТTRÏQ4¬MÝ,‹"¿¼· ¿Yþé~ôKlñà÷r ÀJ€…CÔÉuþ,Ÿ 0ç³rºälÑP@gÀ‰w¾ˆÝÍÞý~­±h:fŽ*ãkš"CláŽ\'×툢¡ªM'M3´Ø!lÅxìƒÍø¿ç>Ú'w€@ 4dÅ»é„;—’Y]Ó$¨e//€}-$¢c­,J¾ÎëÆŠM܉к/Án?X Š«2’¨‹ÿ¬Ñ™ЂÑ£1rúÃ)«Õ¢¨¬7éuGvìÄaâîóç‘@jg§‚ "¿žÆu!ík1êQœoÎøL³7HÞP„¢²’¸¦ ¹ajõ…zý:[ zñèÇ#ߤçìX2&Î.í=ÀÀ6¦³a›>¢:Sw$Q £fo0åš6yƒ•r{ߦ3®RC—±¯ÕGçÜÿþŠyÆ;yÔ1®Ñ(äë[¶4 „8ldŠòÌø¦¦¥Ã·“¯:I`W‹ˆÆxûAd Æ×pjU ŽŸœš²Fc4ÿ¶çàôsŸò“?^D³ªËÅÆ}-´ä/¯&Þ÷ÅïÏ'»¥ýÖÀîbÉŒj!„ ëžü€Ë<¤Îp7å }úôé}^æÜuÞ|ä› )×kÕÆ=ôãÇÞŒ¯,Ä‹?_L:IàÊGßÁêMÜ"ö‡³¤s׫×ÙbЋw~½”®ø÷j|¹§Ü®#E(Ñ›_ÕˆE€H“†㤩©¿!ÑqZÎüçG'М±•bSM+öçWï[û»ó¨ÀÚ~kàÁ†Aò´ièOìkõÑ w¾¨¶ú©ÃF„h›£mè½V¿äTjBŽ3¹ê1¬(OüøDÜwñŒ«P‡Ä¨;Zr7$ØÍÔºc]æ€?㮄ƒÝùê´±R¬ßÛŒ«ÿûnâå`4FûZ}p"ì$.øç ¼¸nmªiUO $œsÿ¨uùz}×túa£Å}/h"pùbj{ 7âêÿ¾‹Íµ­‰ëÕì Ò‡ßÕò5¶Ô¹pÙC«°½ÑÍÎ_’I‡ÿ{öc<òÞ¦^¿Î…V³øï•' ÒnmËØIªfÃ`”Ö!ìeø¦¦?ztuâå`4F5­~4x‚ê¨k.ý×›xú“ïhsmšMÿí ìiÙÿeš¨!?ø÷Ûôîæ}ìðû0%K­5ªºY¸mÈŒÎÈ1LZ„§®Z«‘·²B´µÁ…Å÷¼ è <5MH,5K2.›7¿÷ `¶±þ÷Á µ‹ÔÄÂXþ³Å˜RU,œ-üãrxBÑ”ÁMäªçà*Mš—š÷¤à‹ßŸÞÌÔ¹ü´àÏCè½®’¤ßÝ@îz5¶þðxè$!~÷úÓ«k™ÈfWå`cU%X"VMo“·yñ³Å5ÇOëÕÝé}+¿¢ûV} ˜ósÜ÷ç5Ír䪢a<{Íɘ>¢T8!ZtçKhñ‡Sm:A N³é–=€¢`íïÎÃÁž Ð22 —Ôg¢ƒCaµCØK!ò R¸¦'G1¦Ü3fŒ†Õ¨k¾«¥U÷NblyŽS Ä¢xèò…°$@Žá­›ÎÀô‘jK RYÙ^\õ ¦Ý ¦Ý8v\¶Üy ¦T‹`4ÆÎ?áE2ia,°’VŽk<œû÷7àé¥ú©7¡y·=…ˆµôsEØjÉœßN¾–Luµ¾Dȧ^ç] w=^¾öÔ„óû›½ìüˆäQÀz#;~)u†€°fþºòk<ýéw½öུn;ÿôóè"Èݘ©Ù‹$:tú än³é¹£ŠðícúˆRŒÆèä»_æù$é6ßÀ´gÓ’„sï®@ø Þk€† \päxÀHänè}ÿ8Û_ 4†æá‘‡m .üáåÏñ˧?¤ï=¸ ?~ìlªi%$ÄcW7®?ÇL&>¾å¼ûë3QUlqíí™ÃÔ–¡ ‡wU„:#žëêW7:Iˆ`4F;Ü(µçñ‚(é2™ìLK–ùÕ l%ØZïÂO­éñÙyCÚÛêãóÐXn5W§mÊL– '$ìe@4Òeµ#ÆV`|E!t’ö¶‚e–%Kc§1ñ…­˜KWI¶b@oÀÿ=û1¶Ö»z옾ÞÓL’”tWÎϱ(¬Ì”Ö!ò 8ƒ×Oe„D)„«Ÿ½NÁhŒv5yP`UWÑŽM;ÊÙF’;‚t[)¶7ºqí“ôËùTh% íŒЩ÷¾ŒWS˜}Iø‹AîL^‚õ{šÙ1-Üög´BàïçÍ‚$ŽŸ<ŠIp¹Š+Yœ™¬‰óyaívQ]Žc& Ãô¥°õ\bëÀÈ+äë·i£—=´ ¬Þ@:Iˆû/9’$T›ÎñØù…œ4ç&+d˜yËS]w€hÈÀ{ßòRÑA¹ ì¬4FÞæn¥ÚYW  ÃJÔ¿Žvã’‘_ ˜¬¸óµux뛽)j¼÷·£cPË>vfŠœQì g`d}}Q8„ëùF î|mVmÜCGßþvo!ÜÅUõ< *Ñâcé}¯ãn¦§>ù°ØÚ8.̾N´,n‚zŒ:P8}ñK«}Ç䀫Oæô+LyG¦cUw6³—ÎÀ»£4ç!u˜6Ü©‘nz#"l®íÚµâÏÎÇiÓG±£H¾Ç3ÑáüQXÉÁh2qYH€ÎO0‚‡/_(1îHþœÙÆŽ¤³±Ò]„(JÏšè €N§üà8¶­t–¿)ˆ„²;H½‘;Òš•ç\<òþ&(]dm­(o\:‹‚œ5™çögOßÌ\R e‹Ðè à†Sfwj éIŸæX{S#í‹ I?º%6 ö4{Y¾Z§çì˜NÏçQ’š6ïJ ÔZƒJ‡oÞ´$çQ´omÜKW>¶šÅ³„Ä× äÏ] XŽ‚Zk1ºÔŽ×®? $~ö¿÷赯w±-ÉÑÄï}Ø…‹€œµSÎc³Aõ{›Õóˆè®M·An^2 —ÎpPµ@CV4{ƒ4ç÷ÏBjß„ IDATVˆÛ¶„Ä»65«—ÅÂÝj9JGGÌüpäiÄ‚ ÃðàeǶ;[]VˆN¾û%lotÃ\PаA]œ xûAž&5¶m­;p¿Šø¢–Œ“¦ŽÀëw'½"T! ºÐ6÷í_.ň[N &è×Ï~„g?Ûšt‚ËB92ù©e Ä°ææ³Qá°Šw€æüþÙÔ7õÃ}N×%˜5ºŸíH+¯̹;ÈämÁy³Çá¶³ŽÌÙ1m­w1÷"FK›´wW¡îø¯ø&Bqâ¢ðü5'á­{ðÏÕ@jë]¾A‡*¹¢²ÂÎ"µS§ßgnôàûbaµ ¦-¤à´é£pܤ^K=ˆ •4ôQY¡óÿ±ÍÞ³›³8ò¶$úy;žÚœÒkoùúýYGâôÃFwÙùŸöçWRYà:}YË”w`;ÿžÂ`Jª ®“®ÛŽ›žþ°×S‡’q÷ùóT± &î:mQ&ž¹ú¤¶”/)˜PY˜ž=k¬øþ‚‰\BHëz,ö2•ë ¿Ö§þù|¾£¡×¯õŒQeâÅŸ/n#G’‚%6\wòaâW§Îä×§6*áüÀ “ÄG·œƒ|³ž»úi`¯Bo‚È/ ’/¹×/ûŠÒ-êà …VÐÐ#¼öÕ.úÙãï±#;Õ4ĵ÷yxGÜYÓ´a?×!Uå´kZgä(nZ<?è¶ÂSÉ6a+ÆÇÛêqóóƒèàÈh€†aj÷þ1B%нŒàr"³C ûy;Ñš*S ‹=é½ÌüþÑ1“±òÆ%9§ýo{é3Œ(á6°8»yP,P :=DAȦñn±F+ÿð[¼6˜iàè Ãăß?VUyL²?Iá(c›ìN~?BäñÜ…&¾€(¬D$&cé__ÛïŽÉ¤×‰7n8G©`BhòÌuZc¯Í]è+èô•™s Ì6ÀdÅSŸ|‡•vgÿü-ÐÐ#å›Åú?\ˆΟjÞñI®ª;ò41ë¸#YT‰³·Õ×åÖœW¿Ü™¨ùÃbÇç;x€ ˆ»1Il¿Agà>ïäÝiÈD8{ÖX;q`°îX%~z¡ªVKóŠh¨­¿¥€{ "¿8C¾š\u€ç®9y@¤¦-½øÛ% `1è8°Š¸S#àæ ^–Rà€‚Nß¾M‡X2£š Ð =†Õ¤S«JeÑžS'Ôº“«¹G­Tû“Ö³¤^oò4‘þ|á|;±kŒóM5­ôó'ÞOþD~QÛ¸O{ÿû@mõëoè6îkA¬•ßrÁOO˜–” h€âªç®~Òè¨eÏÀ)c8,&ñÙoÏÅœ1 w#ÈÛÂdÝÁH ŒCµé͵­ʦûZ ¡WP”oïýú,”Ù­8cR)×^]õœ&TdN½Ë1Ý^ÏA™)·‰¢ y_£•ÇU›¾íÌÙ(±[1wܘ lÓ_ín"›ÅˆîƒÖùÚ4@ ªËÔx­^ps7PÕâzþÜ“«Žª$½°—ÂíiÂ?ÞZëwsº4Íù“§‘Ó÷i¢/ Ä"@À•’vvV´[±~7F•:°nW#/vÉÎ_m¹Žò샙|­D o@T€\õx`õF<}õI ç‡,@Ò5€xþ³mø®ÞÅmÉ¿;¹ëyìmÑ)ò4zCŠÃŽrÄÜ øÇÛ_cg“G}-íú€Ë.|£ÈÜea/©äT‘W"—»ñÎæ}¸lÞÄÄuÖIB,š:°h¢²ÂÎ"Ãù“§‰³ØtbÖªm ì¥ °jãŒ-/À§Ûëí„ ( ¬ö²¬|Ö  4›®¹êðÀ;ñÌÕ''œ?LQ:àmº? •4púC«I] ™ FIHÌ>7ZÙHmæßÝÞeQ8„SŒ!_Û‹¦<G9V¬ß™£Ê`úÿìu˜çÕ·ïG,­–™×cLap¨;ŒMRJ1…·¤}ß¶)¦ýJBʘ6I“4 3£Ã`'f{™wµ’V ó|<•´Þ5ÆÎÜ×å+íh43šsž¿c4¨Â¦Œh› ;OÒ`²(ƒ?ÖŸU-JjÀbçwO®áœƒf)gÆŸÑ`0&|Cáj¥kÌ®H7š•ÍtŒú8ì{·3ŠìS¡ÁKœÇE‡Áq¥J—ÄdFW%ŠÂbyß+Jj”‘Éü.Ì6DE¯·#Q-ªI-‹ÔûŠÊ'ï0å ª–#ã»Î °ó£{_ã–—6îS×Ùl4ˆG®> «É ®iÖ=]½ý{º´V9ÍY÷t5XüöÉ5œwÈlÕ"˜¹ƒA]GÏ ÄÂyvœø.Læ ÷´ QÙLÏX€#pÞà¾uOï t@g¿à¸ùMâÖ+NáÏ=R ¹z² |^´8r´G=Ø'‘™¢¢)GdH&‚=_åÑc‘ì$©ÆÝŠÌÙ±:råJ!eL®>ý 5:7àÎj”¡qµ¢$ .JksW®!Hsž…Ó:½úÞFĵçÁM•Y£§!ñ]˜­“~Ç¢¼>·'=è$?z¾ÊkñÜ6²XDé("áXå|Qå°:s/hVì$³kËÄ]ÿsºªªÏœ­‘º§'¹{þbÊ„aÿÚ)Ë”1ß…Ñœ­W1¥ø9ážûAj¬Z:ƒbÛ¾uOï t@g¿áÐYµ"V…UH‰Œçï%V}ïGÌ®-†°íÚŽx"AfV—²bn‹›«Ä_: +q5/a¸3Õ.8í–²„Þúg_DM‰]ÜxÙ1âóZŒô»Õ¾Gº àAØ&y@&Š"/?váûBs~º¸ëVqîÁ³Õ¬‰äõûÓm“ÔâòS^d圃gQ[ê~ýlšÊì‰ï°Cí[¦/ZöC,Ê©KÚ˜]»û;UvóÊÅ]ÿsV¡¥¯Çhêz™®3ô‚çòcP[ê?½è(ñ•S–*' óž¶O_ÉS&¢€Ÿ9~Ñ>yOïnt@g¿â¸ùMâÊS–0£\=˜¥,µš5¼dåÂfVoØ!µ¸íb4#ÊêØ6ìá#¿ €å­Õâ®/Ÿž‡l7U¸t|tzûv”‚µˆ?<ý.¼Ý.¾vê2ñ¥—¨}Kæ §Ji$V™SE”7€0°êºûö¹@ƒñÓ‹ŽR݉ëQSbW)‘éHŒˆÊ&ÆüV\ûâš”³jJÅí_85-0#5µ ž(˜´=¬Eà(ãáw:øí“k¶¿ýû”%-ÕâÞ¯®J]«Q@4<ýtš½lNþúì:îyc«øâÊ%âªÓ–§¾Ã–Êbõ·²ƒ÷ô™7Ü;Þ'ïé݉Þ ³_ÒãòÉ{ßÜÆ ¯Mçm&ˆÇ¸ú´ƒøùCo¨áöº¤–[<¦Åó¯Ü£áT‘’ëÇp×ÿœÎÍ•©•‡/•ž`„côŸüªûÈ9)R£":F©ÝÌ=_]…ÝlJíیȇ×tð­;WçˆÍ¨}Èl™bPF1){ës!ƒ^¾wÎa\vÔ¼}zµ$%ÒŽò§gÞå¦'ÖäˆÍä½ýz‡ à÷Ÿ8•Ý㡈ýÞíDâ2[@iÂ>²Ðb  (0„Å@R)sŸ¾Ö㡈ô‡b}í ÇiÂtÈíÝÓH*".œV÷_yFÖ=í Eåck»øúí/ìÐ=Ðúæ‡pù± öéë¼;лtÞw¬ëuɧ×÷ð…•‹ÅcïvI(Ê9ÏÊûÇŒÄäO|ƒ«N]Îx(Âߟ_Ï×O?ˆ¦ §˜[_.‰Ç¸ê´åhšäúGÞâ܃g1§>vÍô} ìWºîÉ¢Âä.üc©Ê¢¦Jîþòªœ°£Óf}n¿úä<5 Òç‹-ÛXÅ"j•)5$ðíËŽáô%3rö]b·ˆAOPí{âèÛXéÊ©†_fYMߘ±hm¼ƒÏ|âÊKjò^ko÷]R‹‡(k»TŒ¬ÿ™tT¯ÀQuĨŽmû»4Y+(nuÊ2>ÿ¡ÅûEXºØfCÉû.O§…ô»T efw@<ª®GâžþßÍYËgåý{ñ%ïé æ*AzÕ*?Ã!—!VMÌkß¿˜ò"ë>wz@ç}Åú>—<ãúû8eq«j£îýê*6Vfý#1yÑM³®×Åœº2¥°|ùä¥|éDez\>ÙTá×Þûšüûóë¨tÚõUk—Ñ’hË ù”¡(U•ÊI’=Æ9NÀp' ¹ó‹§±¬­ºàCgCÿ˜\uÝ}¹Ó “û°g?0EQe+Ï_s~Ö*i"¿j­üÅCoæ®zndÀ«šŒÙõ—Šæm¥¨æ8f|èéœ}{»ï’]/œ@iË…xºî`þ¹Ã­U{ìáênÿ‡ìyùã”4Ÿ‡·û.\0ŽÁäÌ:ŽÈøf¹éxÅ}ïÈ£yxüœÔïåø¨ÒY˜h@F»A‹ó³‹æÜŽ'À ' OýŽxÃñÇJŽvÙž½bMŒ(6 ¼xÍûüÊ"[Ýò”Ÿß«R`ùþ.&ÞÓA/Òç¢ÄnáÅï\0é=ýçgÞ“?yàõ<÷´G T*­Í–QëƒX„O³ÿ;óàýê:ïJt@ç}ÃoµË¯Üò\BÏ¡¼x«jÙûÉYK0 ‘Џ|!yÔï$ªIDQ…Z} ÂQÂ5+çÐ;æãë§„Ñ –g—üîùêÖA•C„ F8+Ué-JkT…±ÔT+™0`0™X\kº‡‰Ç%¢¤ â1J¯·)çÄhN<$óËM´”ZøÌñ²¸¹r»G×vÉ/üãiå8JÁâ*½ÃcŒŒÕÃÎ`Äj±pμ2<þ?¹è(–ÂÊ$—þîQùÊÖ%‰,6›•3g—pÇ«›H–6Ò`éãÃMSÙD,µ´Ÿ†Ñ1‹šÅ?Äh.o]-G6ü‚’"0pû ª!(žû#Šjß#‘€ÞW>%Ƕý…r'Ä4@MxPrÀ5”4Ÿ—Šø—OŸ„Å åN‡Mðfì8~»õ,f3ËZpç+›½ë• 5ZKL,­+â¤[8i 1ïõŽÊ³nx ½$3KŒÈpmö¶Ø1™LÓhňä‡çAå~fü“<½®G~ú¯Ofü]À #ƒ£n†Çƒ`/AMX,VΞ[‚Çâg=¥{ú“~B>»¡7ýwaµpú¬bî~m  Š«A‹Qé0sƼJêJ‹ø¤öŸÝÐy_Zùg®ˆÃ” HÒ£ÿÊÉKùä± ¹à×±aÀV}‹EUë ½€›Õ%uÜBþwÕôV2©H@‚/¬\Ìg_Än]ÅrÛc4VAy¢Y ‡a3Ûú¢LÅÌ=»ÿÀt½p>%EÐ’ˆh{üPš˜^»¾ âqh;îaœõ§ì¶‡mrå_愦ĢÚ뇒Äq¬ëTÒî3O| “µŠM€Å $‚:Þ”$8à ÂXÉÅÌ?毜yà yÓÒ³/÷BªŠíS>—AO@žö‹{ñÓ½þ¯ÿàb^Þ2Ào~&õÚŠ¹ üíÓ'î÷) È`ýO?­«7òÃ{^M½öñóùöY‡Nëz¤" >{ü"¾xÒ>ñÇÇy½}(õú}_=ƒûýµÞYt@g¯³®×%ϼáþ¼áð$ɰ,€ÓjÁ‰&Нòä½Ã©>ðµðø»]Ó«öE‘î>°«ÏLÌ ?tV-ËZª1 |õ”e`ë G^÷ð› ‚Ï`VÁßTÙÐ?&ozb ñ¸Æ—NZÂüõàúãÓïÊ_w€Ÿ^|Ô¤!ÒBüê±wd(£w̧¤gW_€·çZjÓ1¯ºÏÑ’¦³ñöÜ“eü'ò^GZ fáÅ1„0îò‡îض¿ÉÞW.§¼ ¨<'Ãh© qeÿ‰lêH¢!à€3¶á•u|ç®—)²™9ùÀÖ¬‚¿©2è ÈÜó*&£à¼ƒgs̼FðÈšNùäºnü¡(מÄ~ö/Ä–A·¼á‘·‘Ròù•‹YÔ¤þ.þòì{rÀ ßãçç>z‡îé?<ý®2ä ðÓ‹ŽÆf6Š`4&¯¾íêËŠ¨/-Ò þ¦ˆîèìD&m IDATU¢qM¾Ó5ÂÅ7=œ3z6¥Õ^ŽLªî ¢ª%ÿ¶ 50asR¡y)Çb*úð‰â$QZ“StõB<Êãß8‡Õ%ûàÃEJ-fÝv°pFþ­Ü>õ@C iG3>ð•%P_`ÀÞ†.h©…Q øpê–Ý€£êð]v}¤‘Ck¿ÇðºÿGm9Th›ßЭuÐç² †±Z`Ncþm7÷¨F8 ѲK°W,§jÞ•ûàwª£³sè::{u½.9ÿÿäéõ=ê…Ì*ß !xQZ£ò©ÅUjÕŸYy=až(*KÈ‹Ú$Š»’‘‚h~)ÑF3X‹²åuIÈÍœøÓ»iöîc^³”]/œOûG©ÿ͸t¾`ö–%E0«ìVpD^À’ÈŽhÄ&h+ͨW©ƒ™ y™m”ñ]r}ƶý]¾w»•°w=f³:ðhEßõ`·@kµ Ã[2n¥‰çØ\£Ru콕·®"âkßǾSGwtö kºGTØÁžZ«^ ùUUïX22Aðcâê]ÓžÁ„ÈO¶æV \"m Ýýª¢ß;ÄöÅ•jõ?Q;>Q'°yÐç]ïW4Ùûʧñvÿ—ÐØ›L*鿹F½Ð;A³%³z!)¤88cã°¹".‰5ãR'-è®èlSaÿO øŸ D26[ûr€äq ê(|AuÜíý*­‘I¦"l2*ŒºL¬Î]@g³zË€üÈïMåü¥{@I¸•Ô( «sri^a@T5)űHhò­Z\¥¤vÉÞ)ô??àp€Ï¯\œSŒÆäù¿zƒ8­fþù¹“0 âÝžQù±?]꿵K~bêEùxûrdýÏ(wBc5lìòR[© 7÷@[:—|øƒPdS-½*’ÑP n VÝöŠC0Y§7ªYGg@¯ÐÙ£l·à/ŸòÞŽl“oÛé¼/߮ݷ\q2‡ÍªK¹[Wo”ß¹ëåÔv'ØÊ//;†Ó¯»­CéèÄ/>|4gT¸¯|×"e﫟el럲ªýã ¹?çC“éˆÀdÛö»TÝ@ݲ먚÷µ:?wÇ?eÏêfUûO瘧Š/ƒà¨ZAÛ O ½@ç‡îèì1\¾<ô{·ç— Ýcý óß/ŸÎâæ*á†å¥¿}‰ =ê WºåÒ=ˆ`¶Ø‰W!Hß(„||ä¨y|÷œÃv»±Zû=9ôî÷©)W«øÝÅ€KÆâ0ï¬nLަ>7ÿàÓ²ý©R+øÝ…×}£ª¦aÆIo`-Á8õ¶?ý½@gQlOäY5mïÈT‰®äH'ÒÕÃß/?†§þï\7W‰`4&½ö.6ö±É%&LªNÁlC”T#%D‹Ê‘‰‚EQ\6'ÿ|qCjàÉîÄZ2P•@H¥ê*`Ã½Í ¼u•2.ýÃÏK€xÔ#Ccoo÷œ-ų€Ü:ƒ]Íp"õ1§ Ú;ˆÍÎG‹+¹YÿгRUH©~ÖÑÙÑ=F ùdϨàO¶ì½/±8ÔX])!£Än¡¥²X„cq¹© ò|B>§ßgu ÊjèÒÖLWÕÁU·½ÀcïvíVã¢ÅU·ƒÙ¦rÛ¾ Êûïjf&²8U ‰…‘ ×!µˆìxúDÚŸ8×–?Êw׳å‘eG_™ôœã5±13Äß7ÍÁrSaV¢=ÐlRã¢þN´¨—ÑM¿’íOGÏK—ѳúc´?y£›~¥;:û-z @gâ„e·ËÇ9¿zHÍ ·Ø³µ½ßg$Ãþ¿ûøñœ¸¨E£1yÜîbÔV³òMœl A£®<›ÙH[ÕîÓð='ÃÏãÛôm"1˜Õ¦éî´x¯]uØÊ—{‡ ü!eÐÍ&h<þU„0c+_ZðœCîµR‹ûè{æHbqh¨L«ýí6u«ˆCÙŒân¿™¢Ä1ƒ*&,Yø+le‹)ª9VOèìwè]:{”2‡UÜôĉ¦Í1yµÿÞ S-ƒš¦"RcvmÇÍWݛ܌úBjnÀ4?ÁqÐ☠’ò¿?½è(¹»º¬Å³iòXLÆÉ«ýw[zA Ö’y„ÝoÓV¯ hßÔUªbÂmÏE ¥ñÐ?ÉòYŸÊ{ÎÖ’yl~pÑ(̬WUü»‹ÞeüKš/ÀÝ~sJðÈíS¿/sÂp÷µ´¿1DYÛe²éˆêN€Î~…žÐÙ£üúñwäßž[—­Ë?‘Hé#vC¾=w€FSBP*o0±eÐÃE¿y˜@$&7W‰ë/]¡ÆëN7}a/›“˜DíÛhæ·¿Èž~w—‡ábÁ>¹ñÞVLF˜;I½å¶>%$ì·ôîØgméUû°—/'âYG[2þ ZðR1UÐûê§ {7䜳Ԣ²ýÉc‰ú·)aŸÆ¿o†T¶€ŽüÛlÞ¥mPT·o÷Yj‡eNõ RºîŽáîø—.ÕÙ¯Ð=Ƙ?,ùèÛª  ñùã.ähê¿ŸŠ„ï.DzGÔıŠFDe¢¼ž5Ý£¬üÉéqùä×ny^Cæ¨WP†&#…HQÙ¬þU4‚ÍÉÏ|ƒ<¿~—×–ß#eŒŠ’œqõ)¶öÕ¢Œè†®ÂÛMF²×Þd4t½ŽÝ–6þ±˜ÁaSZ±@/‘ÕYç~ÀÈjÖÂz½#ª°q<¨´ ÛvÌGϰ²YÀ?ðCa©c‹Y¥MÊœ`²Vãîø§îèì7è)=FÞz“‰½ùR¦Äz¤w»¹$<RCd†÷MDY-CîA¾”œî–oQB,H°& UÂLK+Š«Àï}§Í¼ËÒ ,èd%>¥EªxO“°¾ÌÛNµß¾¼*K ±¡‹´ *‹bÈØ‡ÃšÖòßüÂJÂQ˜súzi-™§ÎÙû8šxSz Цžìm'~^!¬æ´ÆÀÆî즔‰û0Ò铞×OI¤„,k»LOèìóè=F…Ó&.9b.ÕE–T>\º&ÄíÅéŸã*d\ZY˱>å0ìfDE#28®¦&1ÛÀ^ÌÚžQ¾¸r±4áØEYJW„ ”Û›mg¥ª1È|_qŒ|ãöî’fiëÅh%§jÂߨ7{›då¾A(G!U¡|o@IèN…Êõߤ‘FÔ Ýã‡ö áùÌA>I)_³#Ÿ°W„¹¨cÅÉDc*Dß58ù>4M¥¤Ìu ‘¹X\9Ãnµ¯‰ûH¦ ÝRi-ž;µÒÑyŸ£;:{”œw¸¸ç+«¾Q⟬.±"ô{‘#«c§”ü¦ƒ¨hÌN=„ýôrÔ ̬)ãÂÃæ¤€O¥.ÆúÔÈakž9»I¬DY¶Êô ‚ç/ŸZ9­9ô“aqÎ / c*;š÷:”ø½@&%SA £¹‚­}Ð?ªäv§‹Ñ ªöÛû•4pkmámM‰Å~,”ö F‡8`Õ&*|‹M=*Ü_HòÒ CnXß•^ÕO“Qixü°¡[ *„9ñyÑàKèè¼ÏÐ=Nm©Cœ|`+ ³Ïñ´jô A$È™ËgŽÅÁ^ ޽Ø1`-ƒ‘7õñµ[ŸãŽW6³¤¥J9ã#j.A,’3Åp*‹€ç6ìZÃ" QÚzq: pž2'úùCJ_ß^q±ÈXªhpºí‚B(õ¾òbõß&ÙÇæˆDaÎéë°8³¥‘…Á"ìa0«ÖPcÆ>’Ç\íÇ4 EÕ+Bn§}zÇ Êa©*…Ùd/N¤{HEFšº’¦³õð¿Î~® ³×øöVK›ÙÄ?ÞDj1x¥5*ü pðŒZ^oT:ŽÒ½}¸i#o4«ÑÅ/‹‘…M•¼1D‹EUq µ,Ó³FI}€—¿{á.‹$ {7Èî/Âb†Ë:Tq[mtôƒf¤Ålš¼c`W°¹G…Òý…ZâQ·ì|ætœµGãtýŒÁ1õ¾¶:•ΈDÁ\ÔJ,ÐÉìÆì©„»šî!!pÖHÛñéÆ_g¿Aèì0¡hzî{æÏùˆÄâRJU"–ÜöÚóg,›¡tòf×–ªpx$ÀM;«)q{îá.€¼½ª‚¿¼QR(*G”ÕˆÄy­Ï,ª@”Öª|þŒ¿Aú\Hï a~sÙ ¾ê¬Æ_J)‰ÝxHN^ÚGJÖ6ù³µdž˜}ê;"&ª_ß\‡?¤ZíUÇ0ûô÷¦}9v„-½PQ¢Bîþ¡çxëê¬ãÌüÙh.3O|Q¬ulëOˆóXØÒ Ѹ…9§®%êïv¯ñïUE’³ÀQ±”­*3UGg_Fwtvˆu½.¹èÿþųzåcïvÉEÿ÷/6¸ó>ƒ‘˜<òwòõÛ_ Ïí—‹þï_üëEÕ¾¤¥J\rÄ\®:m9÷í ŽšSÏ)‹[ùÂ?žÁ•dKUäGw çkWa/Q!ô`F%Ù†¨hPíÓ,NÅU©‚Áw;û9xF sêÊòÿ®çÏeóC ˆ‡Gä¦ûgÓýâÅr¼Ýÿ•ëîpö¼'‡Þý¾\w‡ƒXxX4q3¶²ÅÌ:åuf|èYìËñ?ÇØ–?Ù!{¯Z§3%škTÑ`U){ofdÃ/{ÖÉÈøf¹îîŽ[¤è¹îGªE°bögqTÉŒ=Íì“_ÇV¶sQ }o~ÈÎ íŽc®*Uµ v+ĺNÐõîö›wýéèìô€Î´y«sX^ø›‡ˆ´‚Ï·/´›Ù˜z,{aù™¿>Åà %6³‘PL)yçG—Rd5e½ëyKþö‰5 v“‘`4¦ÂêŽ2dÀ½—§J¤ß“«a ©ë0ݰ¿«âQþø‰8aasã¯ÉÞ—?ÉXûß„±÷#%Ì=³sQ ™&ÐÝùoÙóÒ‡1µjUáßxä7®Êšxß,;žZI<Ø•µm©SåÚ bò‚¸eS¢ í˜è~åcÈÈhÖq7_@ãáÿÈ:f-æ“]/^ˆ¿ÿaU>b´ƒÄb†‡ ÓÏiÚ}ÇÜ5¤œŒ–£ï¤¤ù|= ³Ï£;:ÓâÕ­ƒò’ß=¢zãËTÈ^DI ‡–ÇyeS77ö$ŽœS/‚‘˜\vÍmÄ4© w8€ô»•M*ìç+'/å‹'.ŸùëSò©uÝ©œ¿íVb;€ô ªÊü=Ô°;~7ĉbGÝ(ùÍGãØyyWþ›\HØ»ž–Z%Z³µO«BÐï­Ã^q­ÇÞÄȆëåÀ[WRR-5°¹JPS=ÑSq÷<ÌœU°Ï»ÜtßÌTοo‚aæîPÕü»Óø‡£*`.šIÄ· ‹hJ ǫ̂‡¾àR\oÓrô]”4Ÿ+¤‘î®E‹º™Ý¨¶ëV=úÃn%ß»;?(Í€h æžÕ…Ù‘ÏaÓÑÙ·Ð)³®×%Ϻñ~¤Qÿ%Ý ÜýåU\{﫼Ñ9Œ(­sBÚM¦+ÿåp' ùÎÙ‡á„ùÕcogKgl›õó>Œtdu YÍÜý•Ó™Y]šqrRö¾úiƶþ…Æ*UYjUŸ”ÕÝÐ¥VêÅ«(Ÿñqº^8?eü'’,b˜}Ê[t>wDº˜Y?y›Ýî †mý`qÎ!va”£ÌjÈòøÕqÌXù,#ë~Нÿ!Zj 8Ñe™y=vÕí14¦œ¦‰?ëÆ_gDwt¦„'‘]s¢ªÀd™ ésÁÄ‚úÖõº”8Ž9o•ªlpƒÍ©rãû1r¬auª®©©iƒñ(w|éT–·Ö€á÷®•ƒk®¡º j JÜÐ¥Œ_r"±Í¢¢ùèO@Èx\ýwaÛn8¹í0P½ýR*ñƒ€ŽÃëW!w‹ ÌÇâz–¦êlaž]M÷rP’­‡Á°r6Beügô2öÊÃt㯳߰ïÆSuöëû\ÒŸ”A›Äa”±¨ª„¯l¢ËXåjñükšÅ©hb(šT…‰æßv!àV×/ÙÒ( ˆòz0šùÄŸ cÄ#}ýJkÉ| ­<—‹YõÚ'WüÑI“#1êŸß¢ ýö–Ï?ìQ!ûù­jůMr¡¨’ü= ŒaÕ¥ÙÍ·‡&Õç9íÊø;ë>Äx ½ò׿Îþ†> @gRÖõºä™7Ü€Ùd 'o•Þ!DI:朩ï‹$ªâãÊ2IÿX"´Ÿx† ©a:žXbÉ•ŒáÆcÈиªØŸp”A<Žô ¨´(' ¢‘Àhßù!Ž({ƒÒ– ³Þ6T+÷ÌÕïÌ„˜`I‘ºl™úõÝCÙ9üƒˆ¸¢ã°ª<úŽ(èí3'‡&•Q·˜s¹&£ÎRÄF€´Ã0ê§M 2Ú•$• ˪® âï¤õ˜{±•/ÓÃþ:û%º Sßn—_þ×sª_‹ÅÁlCº¾“U½Íʇ} ¨!1Ež¡ÉÂ>!”œ®Ïr,ö'ò ùøÑœkYà܄Ӟ®;0$Âõ[ûT®Vž’‹L¬fØÔ­.s¡´€ÉF«ÒØ7›Tˆ}o`0€Ý¨êÌ&•Â(Dr"Ÿ?¤¶ÇÓ3v)áDa¤¸ñLÝðëì·è€N^ÖõºRÆ?Yð'ÇG•Kv±iÞÔT¿ñ‘ÉsûRKÕ HŸKE öájÿér\Ñ£,pn¢¥F­è‡ÆTáŸÙ¤ræÛ)‹¨.S+f?ÑB7É(KÆ$¼¾Q%…»7pXÕyI`Àõ…·Õ´Œ‰|ÃÐT_xÛ%W&[mÇ?¾û>HGç}€^¨“C*ìo*Pí¯³KHV|•Eûy Äûˆî¡„r¹RD¬.SŽ“^í¯óABèäpý#oì9øÝMد†e"5Uiœ W c4B…Åͧªÿ´×Œ¿/˜ˆÎx`òHÂTÈ·Ôà½øäéRõ¾ 9‹Cç ªþæ:fŸøˆnüu>|pâ¬::»ò©AY/JÕû› cRçƒ?6\Ä Çé—§§(¼Ó„"J”g"Cn5ÒwgSûÉ$®©ºmŸg&v«*ø›Õ®;-ª=xÕGb´T öÊžÕ—I-ÐC¤:û-º “ÃWN^ À¼„4½ëSSðt&E”ÖBØŸí$eŒÇ H¿nsÒŸÁkž¥ôÆ—1P+Òm}{ö˜«‰€uªm/°ãZë”08–~ÍfQÝ [÷ðyfR•1X29b¸åè;pTŽ·û¿l~h![Z„»ãÞüêÞ9H=€^ “—¸&åáß¿1¥¹ú÷:Hß(Âh$sÊŒ¸Çý y`s‚ÁˆÅbáãËë¸ùùu„¢ÂYŒG©.¶ñ©ÃZ°™ œÑô]/^€ÙÄQçsy¡Âñš± ¼{ 6‹*>(ã_S®Zâ¦C߈jÏ€Ïx~Ï6âáQªËÔªßl‚Oº¨oo“TTF+B ÓP•pX¤—®ú*Ñà ‡þƒÑ¡§tö+ô€N^þüì{ŒùÃà()lü3£Ð0Û¾Q¤ÏŦža†<Î9x–šôðqGyûÚK8iQsb‚—á¡!–µVsѲRz_û4&£Rò+dü“+ÕX]¥éPæTáýa7ŒŽŽr¯ÁYw"¡ˆÛ7ªœƒ™®g2¥÷ázxx”²¶ËÔgyUÅ<®¢{“¸¦ þ¤±{å!-Lkº6sav“úÙ2òkÜ·°ñžFôt€Îþ†ÐÉá¦'ÖÈy+[—"á€**GJ ¢!DÙnìÏz#G»Uñ_\M.$4Îâ–*N]ÜJ×è8לu(“QÄâšüὯÒRYŒÍlâ¢eÅl¸§“qòñÖ^ˆiÐ\ ÝÃ*w9ºwGèTzNFƒÒvƒÑ^OióyhZ˜àÈËD†»ó6LÆ\ãß1 ´ ùÇFìR¶öB}%„#08æFˆÂ×TÓ”6Cm9¸Çßeóƒ ä¬S^×Ó:ûz @'‡áqŸµ&µV'V°ƒÒ°7Sr¾Ymn‘@Îöû+¢¤ZoÆÌá¬{ ß»ûþöܺ‚æ=T•p¦ 7ÜíËÞ¦©ZÆÙTn=)‰»#!z€º e¬3?«¤ÚêÁ×s± ò42‹÷*ŠÕ(âBÝB(q×xZMH õ¾òIJ[. ÏíhªVŽÂd3 vmõêzV—)%DC†)Ÿxý«ËÔñ[Íïý5aïzÜíÿÚý©£³Ð®¿tŸ:n!§Ïtª¿îÁÜ&Djmés}ð:Œ&%[Ïî㉈Ȧw¾w`-](ZVÜCõòÐ5¨ àD”)Õ«IeX7w+Ú¿mz³s[ñì%ÀömfæI«ó¶šM“)rÚ•º`xÂ-`Mœ‡­ü ªæ_¥Z3Œä <´nÌk*ÿ¶ôªÈȨ'{ÛÌÈ@²EÓhÑ buöô€Nv³Iü廙¹âïOKéO<¥¥–WžWúÆ’ïW‰9Js¶Û¯1OH’Ç"ÈñæÖ—ó£ Ž˜ô­%Mg‰°ç=Ù“šXÌù·‹Å•Q5Ùjˆ††Wþvƒ*&èéoîM˜{Ú{˜Í¢eÅݲëùsØÜ£ŒŸÅ¬Ža~ëäûž(þã ª®gýÉT/ø†ˆ‡†åPû?ð‡Ô¹Å5õ¾š.XЪòü^?Ì*0RÔ,€¢ê£÷ȱéèìnô€NA~qÉÑÛ)¹\ ¤—HÒ3‘«–ΠcÄ« ?hÆ?& ¢¸Šýc\ýï¶»¹µt¡¨9ð@öê4Y|‰©A?kÂ`Iµ îjhƒÐØôÀhÑqYÒt¶˜}ê;„£ÊHBÊPwæ M†Ó®Ò¾þGz÷‡ ñð¿‹š¿‹?DjÿnŸ*Ü“$ë ªË&7þí‚sÏîÁdoÐóÿ:ûz@§ E³xé»ʧÞëá›ÿY_š•ÜmЫŠþ"AN[ÒÆo·«*øí ú !uËZ¦6k·fÑ5ÂQy¨4˜Šéxñ(BepB%©+ÌeÄ#.¤aa[ZÁnW©@£öH„I-Åme‹ÅœÓÞ“FkCk¾ƒkëŸ&ÜWˆdhßV¶M‹Hÿà³”`P>9â=Áö®c$íý*øÕ°ì·ÈØ^î_ÔÑÙ…èI±›MâÔ%­”;,öóù•‹UÁ[$ÈV.ás',RÆ÷ÃA6‘ r´'çe9>‚ôOxQCŽv§þ2§‚¯¹€ËŽš7eSí¬?YhZ_Pÿê…ßÂ㣣…Öc@jÊŠNf´bq%nãŸ`§Ü>Øœ{*lè³±¶Ó̆.¸só!Ì^µ™¶ãCcêS¬¥ „&Þ]wƒÑºœqÃíý¹õ‘˜:Žõjõlmû?æžÝCIÓYBʸlü(üCÏ`³î=ã?F½ª°ñ€&ðµÿ‚MÌ!èzcÚ½Óñ¨Gú‡ž‘_» ¹×LºñÞû$H)µˆï{HïÕÖÙ-è::S"ɧÞëáô¥mbÐ?}ð î{s‡Íªã•­éÉZ ðfµÅíÓ½ê|ÊëÀ˜Iw?Lé.ˆäëÀ䚳åc+æïÐ:Ý×ÿ¨´•ˆÉÞ \›n’}o|P«ç{ ­µ*WÞ=Í5¹ïkÊø¶ÔdçÔ\*š0«AÕ$¹ì髨6öqÿÐIœ{ð,~vñÑ9ÇÝ1â•+r7ßÿ.žÿ6fCºdSª¬¯ËøÚÃÑ´ÓѲ➔ñúÚÙüÀu B½o{#ßt ¨z†¶žÀYû¡)·ñˆ[n¸§Ñpðoé{ýóÌ9}Ö’Ü{dà­+åȆë)kûÿ6Ã/ÒpÈ礼ý9=õ ³KÑióÅ›Ÿ‘¬é‹#Ýògq¨(€ÔTUüĸ}9Ö ±¨2ö•‰„q<ªº¤kQÊ >½|õ”e|aåâ~XG_‘[;³ LFT_~,žðI:šL·³õ «¿0»AIó‚ª#ˆÄÔû’¹ïÕ#‹øøsW×Xœ»¸ž“lå„ÍxqsŸüØO·zƣ̯àþãþPNE². ºTIèt ªœ~ãa¦|æ'…”qÙñôIŸ¢­ŠÞÇ+ÿ|ô*冃KÅœ+¦ôýFÝróó2€Í¢ -&å€5ÿÂ`ÂV–¾W:Ÿ]%Çû¤Ø‘Hý!)[zs Å §éN€€ *Š IDATÎ.Cwt¦Åÿ»ÿuù—gßKü•©7B€Å7ØKòv ì3hq%î£ÅP5â’Š"V“‘~OÕ4&¸ý‹§Ð=êãªÛžOl YóãKqXL;ýŽºåÆ{[0›ÒÕþ½#é•rÿ¨³IÒÞŸÜ“ü“.ª9ŽÀð3H©¾¢Ú¥¿ ¨æ8þrû7¸©ýÃhÖDqñ˜Jé`/Á®…Œp`S%ÿýò*:G½¬üÉÝ`4#*T•œEWb1D‰ ÷`@ãþÏ/§4øƒo#•¢°8ç0û´w‹ˆ…‡å†ÿÖlWùðýˆÛ§«²¥éð¿3•*ŒxÄ-7Ü]ƒ(óZÔ;úFU›$¨èH8 -+élÑ÷úÒµù÷ÔU¨EnŸr6¯`xÄEYÛe4ñOÝ ÐÙ%ìÃOj=ÍÏ|#aüËÓV‡2þ ^ÛÆ?äS!vÔ°Bã“n.]‰8s,¢Fïî #¢¬Nýl2ƒÑŒ+NØxeY[«œØTÉÙÍ¿¼ìX’Ýäß9ûÐÝfü!;LžiüfÔ«€Õ¬¢ø‡žÁäh”SPÒ|m-寭!j)CsÖ—µ²·«žÀ`D…õ×öŒòÃ{_É1þ¢X}xD3×QÍÈù^G弫©]ò¤TŸW»ôg)ã`²V‹9§¯#Ï_ð~`S#ŠÅÕÏ ¢=Ã`+[2uãõÈ÷µ` ÊÜæô;2¾·ä\‡®çÏ¡÷ÕOJ׿ßS_™žVXæL+#†ƒªÈÂÝñ/¼Ýwé«6]‚Þ 3%ܰüÃÓïªØåîlõ z‘Áq0[‘£]ªý°¼p–í›SýWÓÀV´Ó‡ ½ƒÙzZœ~WN›™—¾s!£“QÜO_Ú&N:°E˜†]²2ótþ€ÒiœJϰJ´Õ¥_ÛÔ¬Úˆ¹¨ 3߸ýf@ Š $Ý&åÄÙ‹éQŽ—°M2Ð`«“@4À?ž_ÏYË¿ÌÂyj„n¦ñТ^¹õÑC0r[î<>(æäÁ]ÍÆîô¨bMSi•õª¦¢´õ"𼕩ö_øž@‹ŽSR”]o‘‰Å¤Ò3¡Œmý+&£š¡«YýsØ@íŒmý‹,ŸõI= ³Sèírý#oÉ'ÞëVÿ“¹öÐvÁhº‰ŒˆŠFe ÌÉ$qâCó¤«DI5¢¨<±*ð{©ål?5Dö¾ FDy¾pŒ³ox€è =³Ñ v…ñºe×óçJ-–˜Å0=Dîå9 I‰÷lz`.w¼ø¿jmî'~‡Â ®Q9/öl¿)_U¨‚ϲF~tßkœð“ÿ"…9Çø«ƒ4a0ÌU! G•FÿÞ¤¾Riþ·Õ 4 Ö’ùÄ5(i:›æ#o#[48?ñ¨Gv=ŽŒ…U—Hæ&Nr,+VȳsgLÜ6Y·ÑXc¯ŸN﫟Ò#:;îèLʯGþö‰5üïí/ÒTáTínþ±t!ܮƚ±ìM´V eˆR…w™˜1Ò¸zbÎ,5¦©V=ÿ1û)"Êá *þKb4ƒÍɶaw½ºe‡ö;Éb1oÏÝxºï`l\nç`Z¨ UÊØ»¼^¯„gFä[÷ná†GÞbN] U£Ôr¿C“%%óª¶C™HÁH÷€sœI": ÞJ0à ò».£Cpf;ÖŠCÙÔ®Y¨)W+í‰3ö$%‰Ž‰xbØ‚ÉVÍüsGhYñ_¦öoò8¼=÷0øÎ7UÈ©šþÑìí3WûqMýa7y%˜Ë2¢#I™ekÉüiŸŽÎDô€NA.ºéaùF{bäo,Bˇ(®BÇ‘Áñt®|w‘¨'pˆ8#Ã‰× =‡ÕC;×TêÀbG”ÖîøG—OÚ ù 8Îù‡ÌæÒ#çålÿû§ÖÊÖÊbF|!>’èýwÂòÏϼG‰ÝÂ1ó™W_ž÷àƒ®×äÖGÅl‚¦Zè^‡Ýª¤z×u¦×l‰­t¡<ÝÞÊŸQ†Ú`dó€;ñ}†‘£Ýªc£#˜mk‘jo´9S?‡¨²æ6Wפ4 ;­Ç=(7ÝÓBGÚ e C5‘°æ} %•ð%1Z«1Z+§Xíß#7ÞÛ‚Ñ i©…þ‘1Œ&Õ¹¹WÛdêFƒÚvÄ£þÍœdT²É˜POŒŒ²ôÚèì-ô.¼üúñwä/}eªâ J¯¸wÕàh8Ý2˜ñ³t@4Ä??w&ƒÿö@ ª[sßð ýcœ¶¤‡ÞéØiã_UgçÅk. ¶4=öß/o’ßþÏêÔvß<ã.?v8é§÷ÈmÃiéä®<3Ç P+ÿ¹E9M*Èœ4† ÚÆŠvbDîGžû:«½‡¦sþ™ßaæ5ÌGÖw“ñ¾‰„Hï0'ØÂ//;&U1Z< ;žZI`$}ÝÌF˜»‡ºbñìDÉë=6®º-Êg}ŠÆCÿÈÔWþÇõ¼ÃŒzµ¯¸¦Œ:@0œ=V9Pºà/-<¢½_Ý3>ô E5Çê5:;…žÐÉẇߔ¿|ôm•[/ÊX’e€]aüCãªÚ?àAŽªŸÃþ”ñÿöY‡pÄìzqÈÌZñï/œÊI‹šÛîÆz‘þ1Z«Šw«ñRçÿʶt§ÁïŸZ+mf#öÒJ•¾°—ðãû_cåO̪Kš,¬ºî>YÓ™ò¸£Á^µj$ÈÜæt†9SjwgŒ?Àų_Ì.øËü·§ÕùûBÆ?L¨"J~þᣧdüAEÊg}gÝIT”—PæT‰)ŒÝA,® ý6÷ªý¶>èPmw½#`.j²ñ×¢^¹á®*"žw˜×’þîŒOÖíHؾñ/Ÿù ŠªWl§::ÛAOèä0Jä¾wg?¿Ô”Â^U‹2ø±Ô•±i@Oýá'ð¡…Í"×dLÓ8xFXÒR%çãŸÈèKZªx§köó™ã±ra3þæá(üËC$ :´8ÍüãcG2³jé pél[1¢¸a)V§tŒxéÔŠÁQª ÁŠÊ‘c}|ñægxàÊ3å¼úra0ªzmábqU3°Á?¼Gòßþ“¡¸ðö–ñn"Öªt+'(-Ï`" 2¹ ”ã#ˆÊ&äøÇýø.®ûð ¹b®–ã Fd‰Ý"¤DúÃQœ6sjgCk¿'‡Þý>+4LîÎǰ[]³|’ĵåÙÆ4ÛúTÍD8¢®•ÉVÃxpˆñ`vŸ<ê‘Fsé¤@mH©Z'wÇ|†$ÝCª°¡ \F3›ZĬSÞ£=qœ%ê˜#ni´”é‘)¡Gtrpû°&%ä¢áI¶ÞA„AaÀX¡ÚÌ&ÎX6ƒãç7ñÙ¿=Eï˜Ož}ãœø“» FcÒl4ˆ;¿t'ØÊ¿¿p*×]²‚¯˜Ï×O?HlJ„Ú˧ÈNn±8ÔS=°ŸQ(eü_Ù: Œ?¨Iñ´,®pV€£éÉ>åò†T$`Cÿ˜ŒU^føØä’ÛÅd„Šbxqhw¶ƒÑœðñ¥–w^C¤¸™UŽ[±iKoƒas"]Û/òå jûÒZ\¾ŸøÓãhRÊ¿=¿N.¿æ66 ¸åU·=ÏÒoߊË’±Ð z÷û€*œîÀê2µrŸX0Ø\]Cª¦`2f4@±]õÛ›M Ñxøß)n8 wû͸;nÅÓùo¹þ?eFVOêžiQuÝ2[ývö;ÌG}¥2þV3ÄúþHØ»žñÞˆ…‡åúÿ”ÑýÒ%„=ïÉõw•3²áz=¯«3%ôBѸüí“kèõñЦ1dЋ¨Ü‰áóÛ#FºûYÒRÅÂÆJn]½Q9Hµ:ðà•gÐRYŒÝ\XhçoÏ­“µ¥þç?oA$€p”‚m’åï¾QŽsÁ¡³ù%¾w÷+Òˆðd—Ÿ@TSÅrB€iB¬7äKè¤9™Þ¸åŠ“9xF-ÁÁG‰G½Œ½yB¨4@>}ÿéà Bû€àn×å´,ù2×>¶ Bãy%š‹M~n¨ý8¥7× ÿŠ ¡Dey$€w% üÔÖ r¸€+O]Îu¿©"HɈŒ0pógV2“Çuÿ›¶§±ƒ€h|zšíjàQMyváà†.uý¦š:ÙØ­†æ#n¡{õ¥ **Œ_>÷jª~‹É"¡±·d`d5®5_Àa…Pt÷ŒkNÒ9¨ ÆCþÈÈÆˆùÖgs\ƒùç¹0Zòêè$ѼŒ‡"rù5·!1(ã¿ã›I£8¿¡‚õ}.ÕÓo+Fºz”Ñ2hãúúLʶ¼#%ò„ÿ÷_º]ã*ï=™€M!âQ¤;!lo4B4Ì…‡ÎáÇ™Zù_ú»GUuü4» ¤ß 7 +X׫”ݸòLÊÌÈú_PZ´ãÆsOÚN‡Â`v΢íäw8øû÷ÇÔ0£„ƒ"ü#üdæwh²ph«‹Á1U„6£í˜Ï/7_F("é¶”˜ìÜÆG äã¨9 ¼¸¹ì%gr¬O9bÖ"qŽòùâO`5i2Ó·ýfà ÀИ2Ö“š‹à¨8„€ë5Öt]™3W%q²}v ‚£úHÃ/a·ªAI=êý²¹úÇ0Ú÷ÍGÞJië‡ þx:ÿ-»_ú0Ûî5þR*'GÌԢ)Ye_EDæ4ª¡O#¨šwuË~®;:ÑÆCù±?<Κ¢¬6we›@ú\©©™?O‡¤ñ?ùÀV]Û©öaÏ•C“®^ˆG©rÚxú[çåD¤D~ïî—¹å¥g%Ø ¬üƒÞÄïÒ?¦Šô& =Cdjü_yêr®øÐàÆGß–¿yüô<„霯g0#5!0É/|‹E•½8ª*ÉËœ0惲¢üþØúN•Ojÿ·Ç窷?M¼¸^I6gðËæÏrRëÆš@6öš1¢üpëÕ¼i8Y©NvN ãæò™Ü÷æ¶”ñÏÙ.ñ]—›Ýüçð¯Ð:ÍZÍA {Òç.%”6_€§ûÎÔ6h®M÷ôÂãWyu{åáG_Nÿ‰Œx”A˜yâK8ªŽÈ¹òáä¶'Vl×ø»Uú"QBHÓ-ðLÿ¸4`uÎ&ØÄŒz•˜È»íê¿uË~AÕ¼+u'@'/z €NWÞúXØ‹f(c6Ãø2‡5¶ç£ˆsÚÌ\ãŸÄlˆb³€Ñ(¦fücJ™æ¾7·©ëVÈ4Á`d,^‰%ŸÕÚÁ”«s\Ø%Eà龓ŠÙW0ó¤W+ƒÊïOÆØ¸2êFG_ÆhÈoüAEUÊÈjñaïú¬û.•ÛžXÑPØø‡"Êp»}ªFa[ßöJ+óïcc·ªñ°µßD[]~ãŸÄf°g!÷}•§“ÝÐɡҙx‚NÔkÍ$!+¬Eª¸,¾Ê«‰H©†Ì”70%ÀyŠÔR¢¢ QÑÄ©×ÝÇÊDa`ò×3ªK¶» )™Û²:ÕמïüâQù³"ÂQŽRžx¯›Þó*k»GÁlÉvޤ†íÉUÊË$àdVjB”7Ð\Tx€‘Ë«ÍmVs…žäý£Ê &±Y ¥:}¹i Íïa<ª¾ãÅÏ?ÂwÖ1õ»HL Ín„µªóB>åìe"5u$F"«)Š¢²™šzõeÙßÓ¶þôJ;ãAÈ;j©Q+}×–ßá…)™ G•ñd|œÛ¯®çüVåLÖ…‰ªÔÈœ&p½õq6?¸ «0P˜Ôuœ,:6­µjјÚ6>Íf•Qoú8Œ15¥¨ÐqGcªÀqv#Xý²åá%za N^t@'‡9µ*¬]iWKDéså<ØS½å‰þpS²ý;EŽOÐ<͇©©r¾xFLÔT?_¶5HåÛ2µƒžlãd5«×ëJÎK4”#œÚ‡1wÙ”š"˜pJ¤w(Ë™Eå`srëê\vÔ—Ú{™S­²d0}.6'XìYòÁ)%AëÄ*>™}} ¥Ï0©äíîâ,gff½:¯B’ÇÅvU¿±;Ûok©‡\›n¢bÎŒ«hI«Y9 [úÒNÀŒ<¥ÉßµO¸þué¶ÂxP^emc¶«ÉFÑD¬½?{õ•i-€äwÖ”ÃÚ72µ6ÐÆªŒÕ¾TëO|5½ÙÍ&˜ „ƸºIÂÞuÛÿº “ÃåÇ.\y&ǵ•¨‡}Ð †¡à„uªwš‘®^¤{Q(_aT¸YºzUúd|‰Ï GÓi‡e­ÕâÑ«Ïægç’>ŽBǬv¢Ví#]ÈÑDæA£I>f: RB$€Ådä܃gqé‘s xi#'ÇGU•ý$©á¬È)ty |æÙϱ¡kò‚ûdG_×ÒŠŸ¸íœ¦´ñNRÞÌÌðKÌÖ^ÅfV×KCpņŸsêk§'TO©ÅO]E®ZTºUÕB$Bü„ý“×z˜¬HWOâš¾ú‚UYÃÆ|€˜\ò¸Ì©Vî™ç «Ô€½â`ê—ßHqã™ »³[ÇÔ{ó ì à´©ĦžÉóòIß”zÍ`tˆ9glbæ©kÙÜ­ö1Yà,y #þb¶ôªÅtÇHYLêX<~uLÖö˜LóÄBƒ…7ÒùÀ¢;:y™W_.¨-Ë~øO$Ez™QSB8¢²i‡TEy=¢¤a+RÆ·À>¤{4áTÊÖ¬Gç¬ÚRa·˜Ò+÷¢@ÒÝRcikµ K;Ë·ß. ‚¦‰Å9÷—rËK9uq›r†;•V~h¼`ÍÄdÈH‘P)±xáÐpÿ¨Êó—µ]¨Sõv9ªŒÃåõÿàçó~@›£;õ; Á–@%774}>ç½Þ,2¾ÀõKÿ€Á݃îPç(e~U@)UmCr:cY]AGHz‡ùêÚoóÔàá¼×ïµCï°2lÓe<¨©¸áT„Á"Z¹WÔ.þCc¨}w¨ëV¨. ¤Zë”cQQ\xË ®q¨˜s³?“õ;ƒÑ!,Ι¬µD¢…Wô£^UPÒ|±@/Fƒ ëO“Q9{³•ÃÒV %NŒ‰®8„¦#þ5ýÒÙïÑ‚\~ìñ©ãT¨8’—c½©â9eŒãôŒúЈªf¦_Þ„2(Iƒ?IU}²ŠüÆKáà5y?hYkµ¸ñÒc8°F¿IïpB®6aü£a–·Õðvç° a焯ó`u¨EaP‘³•‡×t°¸¹ `2«ßE‚žž²(­¥=Ü@Ìq8  Er"\ÿ¨2κ•¸;n¥Ì¹}ãjµÙT õ–!ìVøTÍŸ0‹(_*»–ŠÈ6ê¬ÃÜØt†á¬IuÁ°*84™ìœxÁ“4V”ª_˜,©(MîIˆtmƒµ(ošÔwAØÏ'ŽYÌG/ùRªº{ù2|AÕê7jÊ”z÷‡ø‡ž‘Õ ¿)Êg~)ÁnQ‘“¾QµÚžH2T.„Ê›çÃíSï·8gÒpðMä+Ã4böéïb²Õ}VjÀÑÆ„Ï56®¾G[Ù¼ÝwQdÛ1ãÙmŽ…Z5©ÒIqMÐvÂã“êè|pÑÛu¶‹'‘}ç¶a—Y5Å\¾bßúÏj°8¥;©`3 Ò= ŒJ,Ì÷Ï\βÖj4V|¨‡"ò·O¬åOÏ®Ë:f¤Æ —ÃWoyN…ú+š¦vÑÒ;œ-ˆp«ÞþÐ ìWõ j¬³J\°¼ŽZ†é|fe*Œœv©]òcßù&X8cj×”ÑP©ê‚Ûú4LFµêH ¬j Ê‹A̸‘Kî,¢ÃcF”Öeç$Güò¢C)¶šY1·–Àð ´?y|ŽQ”R߉i`8‘‘‰'>Û™,å4üÐûÊ'娶¿RQ¢Î}gp«VÀb8ÝN4ØKÕܯ¼ï´x@FÆ·²í‘ÅH@bÀ(4âTÌùA×[G_aVÃÔfì(ºÔ¸áHéŘŠfQ½ð[ŒvÝ ÐÉBèl—R‡E|óŒC@j<|ÕY¬Z:¤ÆmWœB‰=±rÏ\í@Kàö6§ÒÛ/oà»÷¼Æ™7ÜϘ?\Ð{-¶YÄI¶€Ô¸ñ²c¸î’ 5Ž›ßD4žçø¶wÌÉz‚Ìí’“whþ€P<  qý%+8ãÅÂZ¶Mƒ²¶K™}ÚZâÔ/¿êùß²»¢Û9d£Aå—#9b»EcVCáªu£A…—kËaëº_ÑáI¬ä'«îŸ"ÂbC”Ö"Jkùò­/qùŸŸ`ë£E-Ã'¦?„PxpBw€Ñƒ*¼Ý3è£|ö§SÆßÝy«ÛöW@ í,fÐõà[so~±­‘ýo~Eº;n‘R‹È®Γ‘ÕÿŸ½ó£¼öÿ÷Ù^¥Uï’%wã‚ Ý„ÞK „Ü ¤÷ÀMB’Ü$„n InÚBB.¡B·1Æw«kÕv¥í}wæýýq¶K«.!Ëóy‹ÕìhvfvÎyOù.ˆ¦17CÔ×Bk=K/j‡$æê żR’¾/cÕ L‡† ª§°Æž€sï°o¹zvþÂP˜0ÙÃ]ÑÌ: ‹Ä%~É/ŸÂÆE•xà`<䣼ºe1ê)Â]8ößy ÔãLŸóGbܬ£cþÖƒoàñwÚ%&†ªîWiÀÃãGâQÊ[íó Œ Tå?™Ï‘LG|õ¬5¸áœµéÏ!Ç}\P›‘?Ü%Ðÿ<·o½:Á‰Ú2ZÝ/g|.çTàV_AãvSøCd\Çãy¼u-¾yà6rzd‰ªø…â“„u\Æ»?¼½†E<»yë³k ÓPn;E4N*‡¥ÖL¸ êy—0–oBÓ/3€ÔøDm ÜoŸhœŒ·Íœ‰~L—ö~jE\tÖ›ð÷> ç¾;ú’ãÞXyULÐ0Y qÆT`‚†ùzŸäݯ]Ѓˆç}è4ÔùÐÚGâ,-Å\>J_Ø9í$)(¤P¦*L‹^Àd_rî©N-²go¼„ßòÐÊ O%>)HæNdÔ çÉ™2þ§ýèô¹ƒ`æRðä`f­º€0ON¾µvÔÏ6ªšàh„ý—À¥ÌZ5Ö4•à‚µM¸rcK΃YP[ÒÿŸ=ÙÍTu[rqß÷° {Æ6Þécc£‹Ü˜ ãÆ­‘玞I8Ž%`Ñk +ZÍêO~˜w¿q%Z{“>Ù£_öh̯bÈ{œÓª^«ÓðêP‡ì([ñíôÊß¾å?Pdšþ,…B¤\MûÖk ´¡ª„Ò^×6Ô—Sª gËÇP²ôëÜXv2€áƒ¿äýï~ F=`3vçû°™É9Ù×Eí}³eü¬¹šÉ9§ GŠ 0mÞiwà‘í­c)ž) ‹G Ï—O‘ˆe ¹LùûD Ü3€eUEø¿/“3^¶œƒßúÈ–¤ñ/t&j1LîŸijh…;C+Û1Ñ›Á‡{Y‚?¼áu#ãÂu|¬!GéÏ"ǹý­kÁPWFFr4‚‘L;[8:v®9Éô¹g¿ïÆíŸÃ}Á&§tœKöuN]OÎÁ]½Ð‰Àæ[®@…ÕþÜ–º+XËy»xë³kI6Ÿh¥×±äÂClèÀ]|`ç7’Fu"œ6þ`,?-õ«Y¡s€t¬õ…·û!TØ(Çпz-uìí|¾žÇÑtæ«r)ãŸÒШ3×è' ƒé‰QW{ nj‡,?æû(_õ]eõ¯0% 0-¶w ò«ûܸƟ{úAf°ÒÜ€1¦ rψÑj=è¢3S Íž‡Œ×o½•E† =оrß+ü¹Ý]ÉjÿŠOîsdTExÐ JÄëßùHÁ!GÀ¹Ä;^<á¡·ÐT]Øpô QO}U à a(T)Ód9³žœ€åƒq >»ý»èŠÔÓ5B['Uû‡ÀÌ%àa? Åéz&E¥¿áSW:êçxvó@ÿsb”.¿¢†Š=‡ÝÍUº Ä­9Æ?u†z·}îö{PS:²pp:¤Œ¿Æ´±ÀaT•dŒ>{;é_µqböiUûO„HŒ„‡4j:¦^'9": éÊN¢3ßPŒ¿Â¨(…iQœ²DcÑqÏU‘ÇÂÉv¼ÂÏ#îsÒÊÜRJ)Îa5háõ9°¼Ú†|é˜uš ­ü½á(†IÕ¶ Ž´MxÈCŽMV­SiñàÓz ÷霂‘ÆDÞÎ9 ¯è=Ê™¯h÷PñŸjŒo¸Ý ,¯'%¹ µ®„Ó³?8üUt…kÁ¬e¹Æ?ìODÇO „¼TRZî²²„ÅE8<è€^­Â ·V¤ IDAT\ª"cÁk¨+ZÍtE«G¼^²ä+ßã:ü;¸ÛïÍ’kü£1À>TXë<ú†)\¿¼èôÒ=Tè dNZ‹knw1L^òw²tÐgsèzjŒð;á *+…ñùàŸŠ G4­ƒ^úA•Õ÷7d‡W“!1X“a²¥Ü|¹Ûšl¤4'¨ ­Øo ­e)<þÜ~­†jÚF‘.˜•Å™<½N: £È˜ŸnX¦€±ÜHÊ{ÙÃz<“›€qô¿ûÄél&Œ?—cœË±œƒ`Læsw* Úzs[–i¾›,Ù¾jj̲}(9Ñ9rûü¹ 0EXF;ÿ3Áh×ÐRs1*Vß®…qQ…isåÆÅ,“hØÌX“Ã>@–påÆ* ‹ ÷—sˆE`ÔªqÒ’‰%Q9¿ä—Oáé÷:IV¸¤>-öÊ«(']2AáŸÙ$Oy»û.ã‰.QظyO7_~Óß°ü¦¿á/[Qºä$˜ _Ûq.{çÏÿD*: 1/Æ—ŒO!Íø›Þù zÂÕ¨9þôº#X~ÓßpÖOG­Í”tì43ÁÝL$M„¢A® zÑ8 ú ßû {ÔÂÛý .GùágV`ßC&ÈqDCõPû`k/¥7&Ò11ñµî-¯§úбZ0ƒQjA\Þ@iˆ2kẙÀ™¼Æe+n‚¨-QŒ¿Â„P…áÜÕ ìÒõ‹E©òôx437ì¸ðñ–âÇ=‰ýî§Óë,³„ádh™sða;ÔðúmWL8ìÿ­ßÀþ>¨dÁ³Õ&Ó*0[Í8{ù``¶@qÎÏž€+I¯lã’Ìïü×Ðz’ágOïÀ_ÙqÃkxÇ»fu&½»?ÓŠxÈNs–\xUë½mý‘aŠQûÆíŸÃ£§à[‡~„^ÍExþýn¤Ö¯vWÇ7W’CÇe AB÷ùÓ ³£*Ùé>lä^¿mìœÿD‘Þ¿ãz0F+íž7?OÇßxØõâVúŒ g4%ˆÆ)À@…rÓjªÊÔ_,)\à €ŒuÒOZT=3E‰’œrÓ¼€&(º€Òe_GÅšŸ(Æ_aÂ(] 3Ê+ûí<Mà†‡Þbœrù±N_^‹?}úŒôê@¿›Ë2ÇÅ¿yž Œ” ¶±D :•€Í“Èß¿å ÿÞcoz3˜išú¯sM<îÀ -U¸÷sgA{øíÃüÛm´†ôÈ]tSUQ $µ6µ‰÷°Ãшÿ]{êuvÄâ@ãé/ÀTyVzβ¿÷)x{C|àïøŸƒÇË®S°¡Ñ‰7|'Ñ®Þd«f–‚º“QŒ¿Â¤P" 3ʦåµÌޱ0Ö7–áÒõÍ@,„O¶"Çø4qP«) %ðýË?Ä#Њ [¾{å¤VMeÉøª4ÊÄ—y÷÷PhÝ3€—n¾ÇžÊVÞ çÞ; 16bÉEm[&[AAq ]C~þÆ¡>|ïŸ;H<¨¨2ÇpÎ+bapï Žo®Ä=Ÿ= •À^ÜÛÿpÏ¿sÂþ%•øØñKpùká EÑRA2Â’Ìù'þ¸[[û霌§Â8%8¸³ jQ€^£‚/§hBjê¡Jƒ‡>· Áh§,­žarþ-ï{ç+32Õo!‘J}¤T Mz*4ŒK ÆM¨:îÏ0×\Aœ˜`–ÂÑÉ<}:*(LZÄ÷{ Ä1•Ódå²ç„h()„”qº76W@£¢•Ú¾d18yå=$[/Øvl;ø×7.æËªŠY$žÀ»j7TÍ Z9î@¥Õ‰Ëpú#`Å5ä|…4é!IýãË@,‚ÿ:g-ÿÊYkÆ=ñ¡¡·ÌŒ\îBÁáIÿ†ÁÛõ̆L‡ƒÓCJޱD‡ÞüDµK/µsAeRœ…QQj_ˆŸôÇÇ5þÜÝ—.¤ãî)ªÃL­Bë‚Hùvµ¿ya¾õÀ›¾rÖvÊÒj äb“µ§I} Ö¦÷á/žÄæ=ÝܨU³o¾ øÈ¾þ€»9¸$‘ñ·Õf"/Ù“c˜ùü{8<à7ôXû¡¿BWt ìΑ"FG#N/éûkÍ-#Œ?@ÆTɧº÷¾õš¹?P…#% ° x§ÃA?ŒÞæî>@­É `sìÿÆB@,”ã ð ½Ó ›IÇ‹Z¼~°Œ¦&kÒO"FRËšÓœ1 Ö夸»_¼÷eŒ®a??sŒÚÞ·?‹ˆç}Ô”f†Ý4ð†±£+2àð¾ Eöƨÿ¯²@y È,/bZ+v~“—¯þ¾’PPXøÂÉ%b¶!Ë›OÀ V’.NÁìÇa!ñ¢™$¥«Ÿu\ÌXf,Ÿ_Ùƒ½öd}~'ƒJCýõcEDuz…ÞwR‚ùŠ_?ƒÆ2K²—?_¥QH¶úM f´†¢Lë`vJ%ïœ2‰š,åøÖ#Ûð…{þ=f$@[D’Ä‘¼Ó¡USK\l.Ù|A¯!ÙßJ`R׋Îu¾¾M,µ–Ѓ:ðsØ·üÇœ¯Â‘â(,.Y¿ÍV\»¡ŽÔë|Nðd¨?M¶çd B^ÊÍ{sÅmfAf)÷å¾n(ÏìêÄO>zb²VÀ‘³ Ó›I(©@Ñ.3Sø?âÏ{âÂå=ÎZUO">Ù³´FŒŠ§BjÂbÊðÇ#4o!äù9³ÏÒY)·.Ñ/]ú5V½án {i(O •H•ý=Ž‚o]pdw2¤fô88Ð6Šÿ–,ŠÅi–JW`R§ÂQ’PXèÕ*öü7/Åoâü}ôbvþ9Y`Ñ©á º“*S7YÔÚ‘­wž~@–pѺ&„ãŽ[TííƒI'€Ñê>ì+C{Ùò˜ˆûœXZUŒr‹jQD¹Å‡Ï âià2‰ÿdé L YJ:8eTè(™H˨ËDã ¸ìá²B,ÐŽªc &¨—£¼Ç Иš¡/Ù×ðÛàœV»)!œ¥cŸŽ‹À(ß/0à@7P?FÃHJþYmX ŠH 3ŠÒ¨° Çü¤< _8•µ’ÆDF ô@<îÄ1µ6ô à‰HÉþö0–l Ìæ’cáŸï¶ç¼ÆŒE-˜Ü;8"upÒ’*¼y¨?kÇÍH˜nM„,Qþ?õï¨$ƒ»zaÑŠxî›—À{í›3‚D–ÚËPwÒƒè÷kpþmúõâ¦káî¸/gW)! £pŒRù?ç3è¢ÂÁŠ5?AÙŠ›”ü¿Â@aÁŽ'ømoE‰É€{ÞLjÕ30cx`Q@,!M¼]pàÃ=`+¸” ÕqÈ‹"ƒõåÅx(€ƒ'â`æI6ÄGà!˜ÞJûˆ€D K«ŠàŒŠpE`¢Š:õ³,'%(!'ð›kOÃFý3àRrïÏ!G Qý.‚eK¿ õЯF!I4ï^¥¯†ÑdƒAÞª PôFÇá&ã/hJ°ì²0¦R…(€Â‚å¶G¶òÞ:‹^™s"q¬«/Ã?óa÷ÝIe¯´áƒ>LjÍÓèsBø)aVR7¦úޘģàž~Jd­îSEc†ègîêM~Fޝ×Ü‹SôÁ #éÞ¾åö«l€-kzžÝIýï+çôH"1AÜ\ ô†ÖÀ=¸ Íç¼½m½â(ä *,Xn½ä8\rì"<{ã%xî›—âìcê±³Û‰ëï{•6È6¬ùƒs*æTè3c1E,òR“B­ VpOî>Ò†Ž?3+®¢VFMªmt‘Ìèb°È!pxHÙ.EmPd:ç VóHG§!ãì8ÞÿîxD ó¥PaÁ¢W«Ø/>~ à@Ÿ›ïìt‚ˆ­­I+Â9­†‘òàÔ2Œc>†"°i*÷Qw@häëÅÕ“š6YQˆrKKK)óÈkçÓkiôn¾’}MEfÅPXðô{‚ü»ž¤*õ’:*º yÀŠªÀƒ@ŠƒYÊÆßÑl"ø*Ž!þ3a4ZífbßSà,Ëó8¶2Ó»¦å£kÕ#_ŽÎ¢¿é0˜ìî¬X}û{ ó% ° é÷ùå¿zšŒj•­ÑÓ„=$…xfÈøg÷½SááÛfý~D¿ü™ûq#Êh„<ãïÛŸÜ·œ G €EÄ‹~‚Žþ1Þ¸‘e` yɃÀ?2(“ƒÝ™ù¹wœËâðdD‘²·MO <÷]èŠ×)ù…(…ÍuØ §? f«™z1Ýà®ÞŒªž,åŽÓÍßÖ? $¢4¾WTeÚçîsReþpO2 2†ˆȈ3ú±X¡–DY¢QÇ¢HUÿ‰( %"¸®ú·`à(žå†ƒùD8 t ’€Qç SŠ£m}t)÷’ã`#P3èüaÀ壨IʹP‰düëNz@1þ Q" ’~O¿´·‡Ksa\q0½™¢ j9cI s¬¸šFóÆc€üÁuâ°â*šš7P ƒ•Ô’äo"^p;@, f.¡ó!ç8M#Šø >\ò:T"P”çuŒ¿Ò=Rñ…€EÕ$å+sª{(tÉ9'ƒ¿¨ (6‘OlŒÓÓ~—Ô‘&´HH™•¿µþ*Åø+Dqýž ?åöGðù{þšb²4< ½³ «RúdÏZ²ÐͦO×’}øÙ¤S¢ωpÏÜÅÆÓÇ¡N¦Z‚¹L+÷ѶÈ ?JŒ8fiD}Áùkq×'®Àâ AÌ8d§ÕmŠÆJZ;ÆÏ,qTgêR§8˜ –Ï eÆh{€VñÀE —øC@_ž“TŸ•í›ËQ,½¸ -ç½§¬üÆEq»ºü”Û¡¢:[÷Ó„ºXÜe;Ì=°äÜÅ%:p—Ü?&j’’¸2øPwR hrJ3£Ðýpø°=3Îw4’‹Üç¤s:V´#ùÙÛ^œ²´ši-‹Yã¦ç‹­}äpCÉáŒåÔÇŸ#RÅþxõPt@,ðV§M3öÐ$í·RªkBP›¡+Z£…qQ…C¿'È?òëg’Õþµ`Örj¥+®¢@­i† þ²â·ÙBZ±0¸›–×â¿ÎY—eG‰÷&%q­zMrR§ãëÊ|9>lGu‘O}í"Jp¹àÐ!îs‰~{í&œ¾¢v¤ñÏ~_$„<¸rãb|éŒÕé— ¥'²%@fìëövPœj<²ÃûÙ?;Ü€'”óß°µ|~Ä4ÃìmCª0”„êB<1vê µd†–sß…¨)VŒ¿Â„X _9…£TØ?eüS¤¦áåÿ<¸«/-¢Ã]vê§—âà^,z5~ÿ‰ÓqÜ¢ öÛë6–'WÌž*¼¨HNŠÃ¢Ó Óé§aDÓìùó˜}ÎôÄCîîOWÿs7IóþãKçby½ð­Ë§5“Æ.zÀݽÉ}8€hß¾hÎYÝÀþð‰3púòZ”5”¥LD ÷¡¹ÂŠ]y"Ë•YÐX–²ú„ 2@«Ô* †8¦8”p¾ ÉÀ¡ÊÁ#ô38=”Þ0×\„òUßc¶%_eåÇ|œg&¶“ƒ ÉTÁ™›ž‡Þ¶5~øE@ÜpŠt%³4©jÿ¦3^VÂþ “B‘VX<·»‹å¾W­qV{ú¹«—ÆÚÆB€‡V% —0œ¶¼¿¹æ44ÝõH\âß|à <»»+³:f Ez ~võÉøì_^D5u)ÌÖ1ûœ´ªD2ÔYÇQm5à¾/œÆRKÎ1¿¼¯_ýûk9Û‚süò?OÅ…k›ÒÛrÞç à´;ƒ^-"—Îqù†üä£'AEcÉßûïzíbhÕÀâÚüߎ?Dµ…F]îë7MÉ›å,Ϙè¦4†ÃC™ÊH!È([y+*VßžstRÂÏ÷?l¡ð½ ‡,…Á /= §> QcKo/KaîÜó} ï¿3  s†æ³¶@_ú!Åø+L % ° p£ôCöD;yŒÜôIIô’œ.C4.á„–*4”šÑï ‰c[ÛÿèÝÏòp<Áuj‘}êÔç¸ÿ‹çà?à\>êl£´ JãTØO嘵F0k˜¹PQù³›Vœ£Ø¨…ÓÆ 7Ä/üÅ“¼{ØÏuj‘ß\ pŽëÏ^‹go¼à¿½nSŽñhœBu‘ ç¯iD…E×n½µÅFœµªw^5ºñODy×kÓÏ… bÔQñ\4ïT‰"­†?Hê+h†AC% 1/ÌkÝGÞ.ǸsßOxßö/rUfV½ánÈX|á5] AmCã¦çsŒ?¢ž5^™õ§<††MÏ@æ@˹;ã¯0%”€Â‚ —øÇ÷66Wá/»†¨g]Tç Ø™i¸³ ÇÓ߸—þò)Ä%å>Ry¹õâãðÉSW°ÔñéÔ∟ò¯wøp ‚'ö»ÆÀ#YÒÇ퀜À‹7_Žo?ô&¶·Óœ€2³NÇ6–㡯œ7æ1º_“$hU"‹&$®Åaˆz÷ò¨ï|‡ 9°9µ“ ÚôQ¸¼±27p ›¢%–Âï a ã›*ÏDqËÐóÆ­u¢Þ}€æ³ß‚¾äxÐê^õ àœË10A[ð\g¶ÍýYAa²(€Â‚âº?næoê›õT¤8¸«Õ6ú\Ar6,e4¼GTƒ‹ñÙcKñNû þü™3`Ñi >¤ÜvˆßúðÖYO@- ˆËÌZI“¥8˜µK @Šã×ל†EåÖ5,‰È ?ðx%T"°¬~rï „o€iÔ"Ú“q¿ .Qj¥^ùX‚áÔ”ÎäQO §‡dxe§ è|f9%]ƒ@©•j¢%ÿž¡zã®ð 8 †gvuòëÿöêØÆ?Íô½ÇÂS«º…Á½×TŽ÷ºˆC¤"¾d+]Jq\@Ø«^ƒ7¾{%ôê‘3ÙÛ½üœŸ=1¾ñ—⤈¥Ãø“…ÛÁäÖ6”ag÷˜µ‚„‹€ôq R ’‹túÿýíËQ_bžQãÔ¿ã>|èר*™ü*½£Ÿ ë²Ñ—ðð¶ôÿOŹ˜inª°6|Þ®Àl’ýúÑx¦°­T-u—£þäG'@aÎQj›÷t'¿a ã÷’\oțѪŸ ±p²’Ÿc{Ç â\HîTv–ÜpRYÏŽc}q)·‰«{ØŸ4þªÂÆ?YYÏ=@ÄOÿNÖi—¥äÊ_‚Õ Áή!ú{ê¬Øyò¸åô!2ükgLjcž.¦êsq´ðGàK®ðË(e Qáám(^ôiÔp?L•gA’>؉àôLÔÂÛõ˜ôãä9✠}=!îUVb sŽâ(,*¬É‰wÒr¶>'éhöCú¶à>üC4Q0%ØÃÇØ‡,™KÁl5øÝ‹{pæOG8žH?èËÌúôv…ÙA…‡E•Q˜‚´1÷‚™l`ÅUð„âxá郉(EPʰ£Ç…å7ý ÝÃþ1N‰È ïzå|¨D ¡2÷wí}€o Ãí ‘XPK I䙀%µä¸Ûÿ‚¨ÿ›a³äN ŒÄ¨½n.eú +‹Å €R…$`iP] ´=·©Â@…¹Bqý ÊZbEs- ³ÕP—€ÁJÿf¯Ö'0Ý.³FšãìƒYËIWTáõö!ôºØcÏDú<ÉãË6ÆI}Ì>*¨íPTgBÿ)' ì›Ø1UZ½_¥À2Q„ü}è-éÊ«ôyþµ³cBgý½þü)‚)'À±ç‡ÐÛ6Àå': UåÏ… ä @™$§µY—ÖåÏÝ~q-¥,lfñ¸Zÿ‰¨Sqæ e Â‚à’õ‹ç6“ŸúÛ[4Æ`Í݈åù»r‚Ò‚âÈ’õÑÈßíƒ ”Çk[’”y¾7—[ÙÃ_=Ÿ‡c \ûÿ^M¾Gw‚§’Z$b`ú $ÒsöÁhj¡ËNõcìƒ1je‹I37P©xÑ'˜œðñþ7 p>Q¸SñDª.¥bÀ|RþPÝÉ£}ó‰èèGs5€º „h©ŽQËb(:Ræ8û˜2‰¥@aîP" †K×73w J´²^@£>J?iqÕ "õÈOµ†T52þæ’Ñ·‹Gxëʰ¡©<çWëÊX…ÕÞ¦ @<Ä£XUW IJážR» +©£È‚c<ì‡(0|ü„%Sø;…)Yr=«Xó¸À!;µîè̆Üùh䯵;)Ì^{âýÐÙ’ Ag;m}ÀÁÚ¿ÓÔÍbCÈh„£Ôޏ´Ž”ýªKPp²ÃMé€òc¾Q[ªx s†Ò °à¸ñÿ^çOìhGiy9†¹Æ­1]™ÞêF<»»Й¦fü'J< î@͈Í7]•(Œú€hÛa~ËÃ[ Òê YH„‡\äTÄ#àžA4WXÑáðBÕ³ª|¸%lùî•(·fÅ(¹Ûïå½Û> `LΨ.¡ýdHUÓ7Ÿý6ô%Ç1.ÇxÛ³ëñíKM#†(PšA3ÏbžƒnrPJ—~ •ÇÞ¥…9Eq$o· ònüà_»hõ PÕ{<‚ËÖ7ãñmÉêûIêÐN†hˆ4÷ñL4*,­*<¨eŸ‹Ç%—ÿv3éés9}Ì+jlØ×ë°²ÆÙ;fY¢9¢ _?s9ŽkªÀq‹*fÍ0Åü‡¹,…Ñúìš)µð%$ÒÛ´åXrqÑÀ|ö'x÷ë—A¯šg×Ošƒ.Àâ  ñ¬íЛ jK'@aÎPR ’ÍäÜÆ#¸t}3.^·ˆGðK7⦠×ÓF³ìüòx˜ÂíÅÕ¸ò÷/â‚_<‰ý}®‚tyµq ƒNÅpû'ñ>ÔR‰G¯¿`V5M" f.+ªÄ}Û{põïžÃ£Û[gíDiÌ‹Y,Ð0äÍBŠ%(5ßûïöû:=æo:ó-,½¸ ‚h`ááí¼ûuh”Ý 0‰%¨hpyйù8ì¬RÌ­¬ÈæŒySP˜9®;y9[^eãÇ-¢Fì}h 66W°H\â5Å&ôz‚´ÒUà3SVM€L•jÖ|+—ÇšúRöÔ×/âµ6Ì: k®°òcÊ! Œ}ú´•ü/¯î¥Ê}½ÜÓVT5£Ç !ýãŸ*=æ IDATî4*±ÐÖ3‚¥ö2V{Â}ܾõZØY` hª"}ÿº2À’4èÅf ù»üS™¡->LÔ±X K174jZU»|TS`6þÛ$uYå éá>ªyîµ(,(”€ÂQI$.ñV‡—þòi€ d¬µ³g)¸gˆGð÷/œƒµTN9Ì;à ò“øu.h³;ë ä‚\ö\öÚYM÷ïø*>t7ŠM@U)À9C—CƒP8Æ8+)—Ïìeàœ¡éŒW jl,<¼·½°qÞ‡ý q ›ÒË.w@¥-SÒ s‚’P8*†;þ¹à "À™0þÙ"=Y?sÿàçWŸ<-ãϼ×E?ŒeüsŽc¿À1#â‚\uü|õ¬µS;ØIRµþ7¬ö„ûàPˆ‡¤nÂÊ«¢0×^ŽŽ~ŠîI ¸åËh9o7KMÌ“%ÒT½Ärâdw†€HŸ;}.]ß<­‡û^ÞÃôÔvÀ`-lüca:.ƒ=à~çèÛ%á®^ ì'M„a;µEFCàþa4WXqû'Œ:Õo¶(j¼†ÕÑQSŒÚþ&¨Y݉ÀXv tÅk¡+:EM׿¼ÏX¾‰•­¼ÁUÕOI¦‚Â@˜êÚûÆÞ¾­Úàð8cˆÝ@kr݃A£Ö^R+lüðKЯSŒ¿Âœ¢¤Ž:½!~Ò¦þÿ’ºQ·áþaêÉWë’ê|¬´Ú ó‘”7§5LZ Q’ݽóª“ð‘ãZ¦õp—9çK¾y€1ºâQ’;6ZÁnZÑë->l3XÀÃ~@JÀ¨U!Mà¸rãbÜqʼn„#C™Ægœw¿~9, >K{?ž ¢Áòâñ÷q ¨(¦¾ü„D³š ”X´õÑâHŒœQ1ßh8ÜTío1Ь€Ô#—%›ÏÞ}ÉÆ#â<+,,”€ÂQG<ÛÍ6æ‰XÎ6Lk+ª$Éßd„€!ù¾|±QV\•Ԡ¿Wb¦Œ?P ’?Úqت™ŽË–*ÎÛ 3—ƒDŒÆ±²Ö†sŽiÀ®)=ÿ¤úà¢r+ößyÍŒÆùêùXÛPîéO 僘–ýM© ®¯ÐÒ1»ûF¦0rRä<ôåóp÷µ›æ4ì?hÍKØâ "©û_Q x‚@¬€ÈbŠTƒ†œt”BRü!’òÍO+dwpN黓†u ænk̺˜r$,Õ`åUQ%ì¯ð¢´N¡wñDÈŽX¨µ'ÜA40Y óÞ·> µ¾¢®e+nšô—Y–BܾõZ¨ uPjQºì ®ܹ÷€1TóCh­+ŽŠE"êä}o‚Ú KÍE°Ô]Á Ðÿw·ß Îã¨Zÿk¨õ5“>>û?¹Ïþä¸×ÿ{ „ðÔ»à‹ ÷¢×T'ŸýÉ…³Qàð¸û€1l#O®ÊË,PPý›*kÊØƒ_>/ýÖ}䌖ŽH!“PlЀ·w'_}ûŪ=èT8eŨ…ì[þjcT”¯úÞ”îéÞ·> µ¡*]J—‹@Äýwìù˜ BÙÊÛ +Z=é}‡]ïpç¾;.¡bÍÐZ–3Üý‡±ü4¯âÐkhØŽÛO+pÍ82Ã)’Ý0”ž€.û k H29‚ÚOÀO€þf!R…€‚Ê&hŽŠï´ÂüEq&@Ľ“ìüFúÿ;#ƒh<ýyîÜóx»L¿Î‘—.»qR_êÁ]·À×óhÖ>ÔÜÖò´=¿!ýš¯ç1,>/?œûÖkèàé¸õ'?Ìå§£ó•óÒÛ_FËùïóÉ8‰È ï~ýÒôÿ‡†·¡åÜwqËÆƒ8Nz»"ëñ¤#ùËh(ÝÀ]½€Ç‹7_w0‚+ól®áÍÞ6Yð÷ÓŒË7L¯à¯¢ÀØ=Ÿ9“òÏ/æù‰ij h„0¢!Ü}í&œ´¤ 'ÿ°Áh*• €f¨i¹{–éi|Ñös ×,Ç)ÙçÞÛóîi-/[qó¤>‹c÷÷àí~(óSñ’¥×£õ¹u闼ݣå¼]|2N—c¼íùãÒÿï³?ŽÅìã‰p?œ{oO¿n¬8ÁÁ—sVü}ùùüh ÐhÈ%ò‡2+z‡›òôåÇü7ÊVÞ†Ö§W ê?”3£ ´ õ·÷ëj,:k †üƒïê,ÀÌè¤ þZÎÝ ]ñì·U*(Œ‡R8C~Á¡^¨<ÿâƒÐ¨(Ô'C€mѵ0…D,†$N/`ª:›ž÷Ë-KAnßzÔ:Lû‹EOÐÌs•¾k5Lü]€Sq44œúÌ5.ÈG"êà}o‚€5ö$)_ˆ ZóR˜ zù€þaÓ|îè‹÷|øìOpŸý1¨BoA'† PN8!ÅÍŸ†Öÿx<»´˜ø0¾ÖõðHâøëçÏÂI‹«@r½Ï¿ß»_ÞO¢9!ý+@$€+7.Æ?zâ¬_£]N¾µµw½¸/S¨¨5à@4„Ïœ¶7_´€?ãÿóÜ{èvñjwçèC‘6€UUnœUüÔ"`d.À¶è“0‡þh4 Y&ch¬Ø„¦¿<¡{º÷­OA­³Áè¿Ñh )yOë*a±ÕÃ$½ Î)¤‰õ'? KÝåãî;ìÚÎû~ U¬ &¾`$¥–º+`ŠýRÜ•þ~*˜Ê6¢˜mC"!A’iÆ€(ˆP× ùq%ÚNKƒ†œÀX~šÎx…ç|ï&hŒ ;®Ç°Vý•ÅÀ€ àLƒ¥—ô@¥+gàé¸s.!¸÷SeÀ¢Ü¿?DŸ·îÄÀÚpõ‚ü+y(À ìü:ptšÌœo€æweÅ@YÖÄÙ=ì*×ý cEd)Ä>Q)æAU =„Rô“ÂÙÊÆÜ÷¶ÓÃnñù{\: uòƒOÔ‚Ë14VæN|ëvÐŒøì kIZí€,¡åü=c¦<åö·>1Bg>!ÑŠÌlj²f¹|´Z|ÆyþÔýŸØ|óåh,µäì?MðÕ·Þ8wužÛM½ù³¹ò w0ÊûÞ€ó×4â™]€»¯Ý„sW7Œ8Žÿøýó|qä·¸¢ò©÷t8 t Ðý\–5¶65¬¦bÍ1V$€îé:H1*m@iÞ÷bØ7òžN¯ˆÏÛ5f: 4´•·o>Œþ½P©€¦ÊÌkþÝ7…&ðê«h%ß5¨tHD(q_²ôTûK±@טš8öü€;Þÿ*8Œz÷BW¼‹Î|‚ʘsìa÷»¼í9’›¶Ô}$áSVþ ó Å(€æûÍX†ò¢ÜV¢”i¬Ì̲œ€µw¦sŸ¹pîéü;ì[©95¥,;Ä8à¢ùá‹òZÒNÀûÒ¹Ï#Î{ïÀàîï üiKMnµÛ€ç¶wYêi—öB¥¯q>¸ã{ÌHïZ¹ò«p°›æÌguy´ŠTU^‰e§?4êyÞßçâ›÷ôàú³×°—ööpO(:c“ag—“ooÄçN_Åþùn;תÄQ?x}ƒ¼ç錥,³Y‚²Lãs*}–bqvX|ôšÎ½]¢gËÕ(²¨jä÷"©Ò—vÎ:ëªQ÷Ýöüq»v Ö¼Ñ¾6K®#‰‘“¾¨jdî_æÁ ƒ=Ô*ØpÚSðv?OÇ_Q±úv€‰ÜõmÔŸò,µ—°T$ dé ÕV 캕kïaüSx:îã‚Ú Kíe̹÷vn®¾@)øS˜w(5£0tà.>°ó(µR«0²‚X%KêF*Å“#èE]ä¸ êÌêQ–B¼õÙµ@‡%u ã`ldQ¥€|RÝk¢Ê )îå¢ÚzD?PQ'o}fݬž1YYDU_>ò|pNr&ê ¨L#·ÏþOÞýú¥9}á£Ó¥õö©Jm[ÉÒä54#¿ânyµ-¯¦›ãŒ•uØuX×PÆÖ5xþ%Ç.*x®Ã¿å}ï|6 Cu }àüÖ6A ùõùµ…±ä=­ÒWCŠy¸¨)ʹ§Ûž[wcq-ƒ(pŒö•Íx÷´ 2ø¾„]ïð¶އ^#cU½6Ú>×’#˜NC¯ç·€ÜïlêLjw/<…F î¾ Í"ˆzßG¬h5טšX废§ßW½áî‘;΢¨éÚô_)[yÛý=UX¸(€<¤˜‹ï´¢PXØ£Á0…Q5¦f¤&œU¬ùÊV|›òƒãö­×¢È”x2QìNZ™2Q.Ñx´#=àÜ{;Üý”Q«Ödèè9%né¥v¨õ5Œóßû€zÔñxDã@[/ ꪓ\›µájÔx?Æ.»Ÿ¿Hq/ßÿHÑÔîéÐÙ¨MMˆ:嫾‹òc¾ÏÀÛõïÙrõ¨Ñ•ñè¢ }Ae€œ Åìt@ÛóxصÍÕ¹‰™Âé¥ü¿¥æøzÿ ³¢ƒnú}E10ZŒ¡ÁèX}ÊVÞrD^…B(:yˆk9÷]Ê3#ï™QOùäX  ‚@« Á]·À¹ç‡ ™ÓÒe_‡'@i‚ÉP[F}ÊŒGÀ@+›Öç×#4¼íˆõàÊVÞ ký•pzoprïmJ†vS+‰‘±‚#Qme-çíšÚ=­£I,ÐQ óìØó î¾€µác¬lÅMðÉ N†šÒd¼KF Ú^8¡¡­ y\­e):FF+¦KÊø›Ê?œcü2ü)‡”Ewß ß3GäõWP(„’çÎý?[ 5Q\~ä¬hÝÀàûßE,ØÎËWߎ¡wA-æIM„x‚B±Ëê2áÕÃöÚ_øZÎ}ëŠ×q«“¨w¼ÝC«™üìö`˜”n³W´»;qøéåXz©{:­(WÑm"8=¹õÞÐÓñWD¼{Ñ|ÎÛüÈ‹p>tà.“¿ïZ¥g§ÃÀ±÷Äm¼jÝ]pî»*1· v"$$2ìKë3Ž\koí›ODóÙoóX°QßAX¹52ÓÅá¦ê|µ 8þ AÈÿ|Ô*JèµÔ»t¼Êå§a×_Aat”@RÌ o×…‘F©ÇAƒ< ŽÒ-»©¢˜žîö{áHæuyáÌ„DÅhþ1f͸ü”Ïέ¶ÔЃ±mó‡õî;âV'AÇ«r•Ò*à:Ð=¶r›ËO½ØÙ4UjèØ|†þ*Ýæ•Í ›tÜ OPž9%Ù V­VîwÐûöç1þˆ½ù…÷ÁÓñWˆBîç(µ”¯\—M$F÷´-ë<–‘“ëízƒ»n[ð$ïé2´…öÑ=§o®¦}µ¿t*†ýP”WÉï P±âT‰'軳´nlÑ€ #—ÔQTȵýt¼´I‰(, QSÄ–]ÚÑÐDF(‘ù]]9= \£¿W¯¥v¤ÖÞÜQ¢•6jms·ß‹²•·¦Û”R¨D2^݃#uÄST“¡ìÉzcTè9‚ÃϬ—cGԃɶøK¬êØÿËGí)t2¸©1©£QWNÎPöµÐ¨€æ 샾ôdê¡¶ÍÅdp 9rjÓÞ!jKQl&#ènû\‡7õý ª­lÙeƒ‹G8Vµed³Ï6: ¿ö¾ÜkQQLîŽûP¶â¹çT%’1ï$Çx4*Šé{‘ý>ÆÈ839‚ó Xê®@÷@nЍÈDï›l:#EMVý$“‘O9ßù2Â¥ÖŒ“‹ÒA¨´%Sûà óŒ£ÚðÙŸàQßz+m8e)ÌCÃo£tùÍHHôà‹ÆÉ8=ô€ª,0‰ '`Y}îªÆ¢£ÆŠM(ª¿ –ÚËà ’1OH@<ÁÐ=Hm†ù+©lªJFZu Ðz´aÓ3óVZ4uòààËÜ×ó(ç\JŸëààËÜ\} ¥'`ØGÆ<b †þazPµB«/y-R«Ù’¥_CÙÊÛÀ™ @89µÍ¤ë™ßR˜(Ð5ÌŽ0Db€Ç謫P´è“S9 s‚¿÷Éä=½%}ž¹å¡¡-([‘¼§ûéDbT‹ÂA÷V!t:Ù×Â!ÀXz¬ WÁZw|IÇ6uOw ¥EcðUÚF^‹®Aª¶([qÊVÞ AS »#3¦7¥ë˜ßR8Ô"9w}Ãu+E’JCD}¦ÿ‡æGm €«õ¼oûçÓÿ¿è¬7¹¡äCh{n=¢¾ýQS AmÁa{Wz»± ôx_ÁágWН§óoÉ• =«'›ϼ˜¯³[¤¸—x,ãµË7¡ñÃ/òãUtüûŒôëEM×b¨ã¾dq$}ªé|¢Á]ßNÿ¬+Ùˆ¶Þ·Óÿ¯žÎ]ÏDLïÈf”èQЦ3_ãÆ²“ÑöÜD¼{$Û&õ58loKo7¥{:yã‡ÞDë³kP·„·ëÿà˺§ÍúÑß>œûî„sßSÕ9èLJD£·÷M…k&Mä þ¸(õP¹öN5]7?o…IrT¶úìOpÆTp¿s¢qz˜„¢€mñ—)„ÄÀ½à Õg:¨´¥PI}à\†FM¡æ±¢£Ñ5@+#´’ð­eâ‘A˜ÔnÄâ]¨)üyo'EV^´óæá”ˆ:yÔó>†÷~’w Dð•¡µ'Þǧ".Z­(µÖ"NUNÄ%ªÞoª?O›ó7“õ#ÉÇãô¯ÚØ!1‘¡é|¾aR ¬Þp7l‹¿uônûw·ß3B_"¥•ÐR“q*eNçC%Ó¸§Zg/R²Á%–É;Ù¤$š³µ!Z{)m‘Ÿ^›mœúî›4݈w/ª×ß °©LzäG`‰ÂB横ð÷>É=ó “U‘̨۟yM¨X’3+©`³qÊ/ ,+‘Âï+„QGN@ÿ0ಿŠÊµ?™WÆ\æí›O@ŸÙÈüʨ£U}4¯Ø±®œªí}“ÔÈF%ÒJÓÈ}}i==vÇê² ƒ–œ—ès„À˜ •ë~ÎæÓCÜß÷ w·ß`d±]Ó(÷´À’ê‡rnëd±YèÚæVhš,f=åû³Iu¼¸ü£¿g¶0é)Ê`³‘C_ëðïájýä÷ã鼟·>»²âï}‹÷¼ùQ^¨›$hç+çQï^t¾ÎbÛX ·=¿‰¨‡ŸY…ŽOE"܇ჿšÎÇPP•£"àï}’w½vIŽÚבFï­;cq€ Åàú¥¨^7t¶õóÆøƒËüÀUHD#ªÆ¢q Њ3$¬‚¡ü4Toø æÛÊ¿ëÕ Žè{úH#=¸èÜw'<Øg`ç|èÀ/Pd¢ƒö>êöQ«¿ñ:È êO~€ÀÂÃÛyÛ ¡Q‘³Ó1¨Z<85×ÂÛû"õ&4ÆÆys*Ù—c¼íù ˆzßO ‰¤¦ß¥0Už‰úSÿ A4Ì›B``3ï|ùl˜ô4)ñH$•ËΦáÔ'a®¹hÞœg.ÇxÛ Ç#êy§çž@&ê“ýóTŒ¿·ëÿxÏ–Ãj¢è@FM2z×ÖGÑ.SÅ¨Þø´=DÙæš‘uNOfFÁ²ËPiËæÍ½¨pärT¤˜ †®h-8/,´s$ ­)¥U_hðEx´ RÌ5o¼8µžÊ²ã“Ðߟoè4ôn¬dh¬¤‚´®×.†cÏ÷çÍyf‚zÛzp>½”‰B†A7ÕÖtÒv'ÕÙ¤Œ݉ÿ˜°ñ÷÷þ‹÷lù8̆Œñ2Æ  Á—pè©0É%u£9¦Ò‚„‡·CNæÍ½¨pärT8¾žÇàéü,Æ\)Ô”\étŠ¡æŠ'ÒzëÅf2JõäzÞ¼ ²šÎÛ6ŸhΛÙÞ?L×ùN4N õ€IÏaÒ“³e6Ž÷ÿþÞ§æÁyü½OÁÝö˜ ¹]©{z¦‡ç ÂÀŠJôøB€±ì û2+kÃÕ2þQß®1Ñüⱞ-rr–EJÜ«ê%@׳º„ŽÏsè§Ø÷°Ja Ât9*KÝå°µ|¾`n±J$ï¼½ozUþsA]U]g‡¦Mz ¥¾ˆÖ§W‚K‘øÀXóÙoƒ Z´õåÖ8W•Ѓ´äì|A«&ãß5˜û@N9]¯]h-ËXËy;ÔjO$¨`¾c1-Õ#‹S«9±aÄ{( Ãy~:†ÎÿpÁ–¯éP½ánfª:}Ã#ïiQ$q…É“ ·kP²ô6Qã?´ÿgܾõ?¡UžŽ¿ '¬kêw4yϘì’RƨàïP9oÙ-Ãù¤丯ðF à¨(Ì sûÖëàéü{úážhÅg1|°G6d™¦¢É‚K.8•¾*çAÕ·ý‹ÜÕú¿€Êu?Gé²o0):Ì÷?–Q@Z|þ^h­+f¼ (èxw¾|6D…$gV8‹kÆï|dÈK«²Òe_Gåº_䜯”èQŠe—õC¥«dî¶?óÞ·? °6| u'þ³ÑI`ë“ÜÓqoÎ=]W>5ii…©ü¹ZÿÀû¶!-Æ4è¦{¾ÔJóJ­¤+QˆÎ*šõ©ý±¦tôíBQrô%BÓ¯ÎÛù GGI …ÀjO¸EGBÊèrõ:ÌB*!9´†'|8ðDuÎ4ÀD¨—{ºþQ$Ã;°óF î¾…GmR³E íù 9ߘq/ÐX~*k9ogú}÷Wp_Ï£¨.lɱ”ôp¾4ïa;µœ·º¢cfðSȼóåsxqÁ¬FSm˜©6¬ ãÞñÒéШseuSÛ›3sorú£¾ä84Ÿ½ 3yÇøûžæ]¯^­fæ", Y´vÐE’œ¥£q þ”Ç`©½lBŸ^йøþGKF|¯fˆ´@´j üÄ—&ÂX~Ú½B sÅQˆxvñî×.è§Ð7Ý뤡>ÙH2Ñ|¶ÙÄî @{;Éø¯¸ÒŸ6þ}oŽûzM¥¨´ÑŠ$?/Ü\CcoÛ_8QïÞò9ï~ý ^„ LÞøGcdDó+Ù‡¼SŸ?ÂQ`°§ƒÎuņ¿`åU1¨´e,hã/€æ2d³(Y?ý¹­É•]xx;(-03žwÔ»—w½z!€)ÞÓC~ÎF’TÙèi IDATý¹u I¦û~I]¦ÐSÐ×"J¦Š3 Çýܹ÷öœñÕ£3768£h_SàØz:^Ú„àà¿9¸ÛïåôÝå|èÀ/Ù`… sÔ8QßÎå8´jZ‡c“ׯ-£B°ì¦(Ðß>‡i„ú 20œ«Aebvíà` z-µöR@ŠJ…"íÎÌk£U#—Ã8üÌ*pž˜æÃƒó°{'ÀDè“ýô‡ì™±ÅA«!cÙÚ›« _j¥ýå¬ÙB¯ÍL}ä0×\&¨Y,ÐιFE×?žÈíÎШ¨Â»×™ëÄ›é?wÛ_ànûË´/ê;˜¾§S+ÙáIÖ…Õ”’Ì¿§[ªÉ9©±ñÈ–*¶[|ÞN˜«ÏÇðáߢõ¹cÑúüz îþv~cÌ}‰j+Ì5A’3’Þ‡zfþ˜Ë‹2?'’é •®®Ö?òÞmŸÄágVÁþÖ'0°óFzªàs)˜¬p¤rT¤"ž]¼õÙµS û‡" •9N˜1äÓ!u¤'ãÀCƒÃj$ôÙ"΄øbÅðFl(Yr=J–^O+ÿdÁ_vØ¢¤¦Æ•­¼æê ª-S.ÄyÏ›WÁÛýð”ÂþžE(0lDÐÛ  ™õ€ XZ7ù#› Þ 9X‚  ?¸2thØô Ôúj–*øËûO„`„ ­®x=*×þñp/ŠÿS ¶G½{ùágVM)ìŽÒ_”d ’0Áé×#¡{ºÊpÆÐëä0ëI¶v!s°‡8µ±‰`J‹2NT‰ï—c(]ñm0&Ž~¸Ìc6ú׈9U–YLyu&u Ê7!èxÅ& £ÈY©ð†Ô(Yõc5]«(*ŒÉÐü6}˜@½gSñu8È@Ò{ýü°6| Þ®’áhÚ©I?3ÇZð88I‡nnpž‘55ô¤–¦ À—2?νwÀ¹÷Àâó÷ðÉ;Œ‰šbŒÝÆT·?5INÐЗŸŠÎÿÏÞ{‡IrUçÃï­êœ{¦§'ç™ÝÙ]å´Ê9g‚2 ˜`†ÆÆ6c°-lŸ@d’PBÊa•Vqãäzf:çîªûýqº:N÷NOÚÝzŸgžíép»êÜ{Î=÷=ï™}6ûœè/°P²92€ƒ™Gé>3Ø\+±%…|óîÆÈ“—"sO£yçOª>q_Í88§ö×ôÚ0€0ìmïE`ü äÙô¡ˆk›ƒSäüÍ — :ûZ2A«3#¦ÓÞéo`Ú‡ô—è¹z_*àà˜Ùýy0Íuå+ŠÒÒêíwjœ¿£óá¹£ ­¹"]ìv¤°ï/aî­¯bë “\c¨WƒKâ˜ÈÀbÿm|f÷çWÔ«||.'m«×ÒD3Öœ.Åpp.#Ü®¦Âîak‘Zše™Æˆö¶÷¡õœ_3.'ùà#' :˜mZ öŽÒâ—L§ÝDûù÷ÁÚ|CU‹‡,EùÀƒ}bèm©N_A’éìßn¦…9%ÑxŒÎS ³v#›Edþ9X@û:öP4 ìfZ´IK÷¯ÂXs ŒýŠO¼øAØÍ9·åbj²JŠö„? ˜\g¢ë²£v.ÞÁÿæÓ¯~ªÀ ,㺶ŒåÛô)¥c$üo£³éè ¶¿Á¾‰À^´7,ÄÏ,æ2M§ý5½Ÿ*¸GœK|äç!¶°«âµš^¤#‚ÞZOl¦œ°Ïr1•Ñ0ÑÛ¶!Ü©ƒsšÏ`mºí<¨*–Ä1ÁˆÌ=Égvfc¡óOK…çáKÁã'‡ÐÝD?-uTâó¾ KÓUÐÛ·#Üw¡ó„×–D5ã¥cˆ®F:ÆhugÒ}ãwa~ÿwøèS—#<ˆŽ†Bçï ÑXÊAѨwÒwëj¢”²^Œ={cuÄ@.ó¡GOG*:îæB翬Üö8-Ñ¢Üì¢qt6RŠ]§b¾×áìú("óÏA¯+uþ“ókW\—JS Õ^Oãèh¶¶Zzôt„¦æ/~F}¡óçüжä ÒQNo }¿–:ú¾Ñ…—0ùâ-¨f?ñ<ͧ_ý̆Ò3íCc>@AMOsΦj€˜÷uXê/Áq2âþ·Ñ\WèБBÕÁÍŠÁ)deÁã½`Bù ž(Ð5h©#žÌä®åtÑ…]„òÎÖK×Ûí Ri8Fó«Ì,’m6¹9E’‚åŽúdNf{= Æž½A%ªXÇD`pžˆš4"í€*‘Êê촨擹ê´`.ìÿ.8§\w±³·[ˆ¦Ô¯uv" æ§øjh,so~#‰ï/ÐN+-@‘¢Þê aéþíJ0ððq˘À\[ÿ@©ìi­v0åš1iDZ„‹«)” `ôé« 5·#™*•¸5èòGV­†Ô ‹¯ãÖ6úÛØ3×@Ô9Hs°LY¥qÔØp嘃à´R á»/ÞŒåÇIJ®§(Pad¦ük›Î­ËN»ÉÅþÛ eLñ½°›…àÆV¼¬kÉ·Ôa3{\Lz´™)(vX€Äàáý9|ƒ?Ê=A.Õ/Ö_°[(àsZs½H£¥w¹rÍ £5VÀ,N+o ´ZF(°³š‡ô$BS¿ÃÔK·.ïƒTS8&QWö½g2±¬p‰u;hÒÇÊ8&Æ(’.fW»ìä<ƒ¿AÛy÷"+ $ÌÆêYÙå h¼Ï9V·3Ó¼dün´žó+"”Þ͇ÑPúº|(ÕÅ —r–œz`ÙãtvŒ5ï¼¾±àóaЕ¶ÙÍG³‹œ}±S³däƒ]Û¾u+¦JW:]ĬmnI*^XÍ™q4œò}z7Žöp;è5á2Át4.,šéþÆ~…tbaYcu¶íÝ ™ûÇ 3 n'Ùs%GCiSc#›MýíçÝ·´MÖΦÌyrÔ§`ht–îËDÑÜÉo³¬8k¥+û˜¨¯emçÝ[çÇ0>G×´8c\â=æ¢]Lj‹±ägIêñYŽplé`OɾIMAc)}’ŠcÇ ÈI¶Š9g‘ôf«›¢å傃J}Ò’ˆ-×Bkjaóûþ‘Ͻõ5XŒ”ÎÖki§××¶n_² œ¸`Á~¦Óÿ‡Éé ï R‡HËDØ«µ­o†"li¼\ŠCNG‘î¤lfrÀ‘µk®¶ c`ŠRĽW喙ú"ãýtBd<›ÆÅ€–*™èœ“žEJÒ ÷Ú~è,laÿ?óÙ7¿³‘2Oz-7ë)x³Ñ80N;|æk¥ “¬JàÕïÀ`?®à>åKlWR„·Hèj¬ž748Eö.lt7*ù˜œ§ŒMË™wÀÑùa•  ¢ÇTr×ßÖƒóÜÖM¯¥sÙjM#Ó€Ñu&:/}Œ‰,<ó(}úÊ‚ç¹ì¹Zòõ@(JÍFòáèü0ü#ÿ[ðX½³z9:K ~Ç…ÀÒxeÕ‹‡oøg|êåÂÔc³«°}ír ”)v^ú,Ìuç1.'øÐ£;÷¿•}ŽF¤ãasZCÓ…ZC=À¤c¹-˜VC㨆ӟLƒ“€ÆÜ‰ž«÷BU]k)éãïk,åR +)SŒ%hGjpžŽ®Ëžt,<û8}êò‚ç­„H{¤"•ÎÛ-˹RÛbdÅÌ…ÿÊgßø‹‚rc_(gïŠó·4\†ÈÜãhu¯¬Iþ˜+UdÿY?‡£ãCªóWQ‚c¢ 0¢®†õ½{ŽGæžB*6 Ï; YòVœüKA›á¤¢“àrL4iLÐÛú`#¨5’H1ï`­¡Õ(Ç ’ÌMó#ÿ Ac†Íæ@¤óʽWB¶¹Ì2ÓÒÅpv}„‰:;×Yº°pà{ðü¼bôrPœºœô8t–NZ3êÄ×–’ЉÄÔׯc ¹s\`Â3‡”'¢Þ°ét šÌ8Š;¿U‚NC¶” €ËI@¬®¦TÔ9ÙÖ§xxöQH <{¾9婺ìL§¥ï•Œ ƒó4t´6èmÛ ‚p™¦Àpt‰åU—šÿ2ϵ wmû ´æò)=Wߟ3¥“2Æw¿2§:ž¤)’‚Ï>žm/½Ú1Wrþ¡( 3wÀÚtíÊ>HÅQc.ѧ¯âá™ß££¨È¤óäŽ"¶ùÈ -œ̼M;ï„ÞÖ A4±Èüó|äç1`GÇÆŒ_–IȤ¡¦pW=ë¥sÚjÇOR‰’Ìi‘qz't–nkÏXÕî¡’hMÿí&óÃHœÒþi™œcÝ™@kh€±æ4ƹÄ9‰ÀÞ‚æ+ëy?G䧈Ó04XÍK—cU¸‡x ’ @Û€– ÎÜ Qk_ÕµîFœ¼¿¤Ã¥/D»ÁÎÆÂçÌ’qÀ؇æ³~ ½­‚hb±ÅWøÐc;Çu®fT›Ó ¹ìÀdü<øgžÃÖëG¡5·³dd”kt5´6–ìå:[YÜ÷üý)g×­ð ÿÐ~á#Œýü#ÿ‹–º!p­OÒÐÑÌD·`q®ÅY<G7Ž `9´žõ èm}˜ð¾jlY :iÑ'TÜ—uþ\Nñù=ß̦}¦ª“¾])Ž.æ|…©é†Àe«žoÐ,-Ñûq.­Úù€Þ¾ƒ5Ÿñ#$’T -­ÀäB!qÎl €FÊŒƒq9ëüw ì@¥W_ç ³Úün†‘ªBÑê«=Úܽ…ˆÎ®‰ó€æ?ƒÞ¾ƒdˆó²>N+SÅ„±ÎºÎñ$ŠÍf?çiîÙû`Œ²“kÕ½`s¡É•ëê'Ÿ@BNÉð0ïÿ]'ÜׄÐôC|àáã0úÔåà\âçɬí¼{ÑqÑchÞy;k8å_¡·oÇØÓW!;"ªVŽ|90èr›3úés2mÁU¨ÈÇ1räbâŽræg1æ&SJ&AïFÏ5{¡Ñ¹Xta~ül˜ôD&ÖFñk-’訢(ç†îã¾÷ñ»¦;Ïž¿ãžwþ¶ KžÂa`¬Ì¤È6œü]¸ú¾Ä8—øØSW 2÷DYÑ–€$Q…ÀZ`ÿ qv”¦Ö5»ÖRÒÏ÷ÿÆYbÓ ‡ÁlÈe$‰²HLë@ïuÐè\,æ}=z:Œzº'À‘cÓ‡Ó ä°]}_ÄÂÁƒN”–3Â\: ™áèìÛ³²Ár:̇ÿp>þ7 ËtduâÉêùGÕ@™_Ö¦«Ñ~ÁCj@EŽù ê€±g®A:|2§ ZúíàrÓ¯|1SfÅî«öBké€ šŒ>}%ÏŸyý‹ÙfF’Lì÷éÝŸEÔó„ÌŽÓÞõiÔ÷7PdLWÓÏáHÁ¼Ÿêèe9Ó_BZÏù5ìmï[ó뜊ŒóÑg®B:´/kÓîS AÐcò¥CŒ„º¯Ú­¥3{¿Çž½‡¦~·ªsê£ ±$qô¶ˆöB§¡ì•Ì©t°½žª@Fgý8t_¹ ÀÀƒ[‘ŠŽ’J¨Žþ®l(Ff)³^ÈVvÈzô^{:s‡¨(À1} @géf]—¾)sš–£ã$Ôtœu\ô8Ò-Ö¢¡¹Àù@ûù÷Ãè<cs嵎dˆ¥±•:rA¤Ø$FŸ¼éäšG‡µ[ÿ‚5Ÿñ#¤%rþÖæë ·mCÇ…¿‡Þ~<$™®¿¹á2äk˜'²¶sï!ž‚§Ò'¹¨sÖLÈ@;ê‰Þÿè/×ü:kÍm¥6í<ŽÎ[Xç%OC’2AŸÎUàü íÜ»a¬9ãžëpy$#™"çÏD âÁÔí1Ã2:!•@"°“/¼#O\„Tt 9-€|^ÑZ9ÿ©…œÐ×èlî¨f`’*LT篢Ô @¤¤ 3¤¤CCv¤ãs\И&”ìŠý£¿ä“»>´¡„´µÆä<9ˆìQGšhlè{×̺dÒ‰yÎ P#Fø\NrYŠKq70‘SA~à¾&@Ž ¯­P5?¿,êH†"»ÜÕHÄ2€Ò³¡(ÐræÏáè\ûR-)à‚h„” t†“ œih{_|ãwñ‰Þ¿¢^GÂ1šF=ÖŸŒ˜ïŠÙ¾½£D¾LêOAÌûúº¯ “ó™žI Þ)úW€´¬Gç%OÂä:[uþ*–„šȃ¨s2&èX¾ó¡ž  [ÊFãG¨Ýò9L-J¤ZMTæÓ?yøÆ¶\ô4á.”ÇÄ7¨" :ÿ<î%ÏM?Ì5Æ$ƒaoÿ ].sßðíÐYº 14@oß^õuæ\âþáŸBkj…Öܽm+€TdŒ'C¨Ýú,ü7 Læ* <~J»®W]õZÂi-UBTŽ`ZÎúEéчå±» j-0Õ—#EúÞäRÒ‡dxÎî?ÁJl:æ}s9¹”Ms{Û˜¸³ÞŒÒÊ‘Yµ²ÒG tZ 4"UpØÌåÛnk2iø=W#æª„Ö ¢€ çƒCkjS¿ŠCbÃÿÈ|ò¥dÿßvÞ}ÜÖrùÃyˆywgï»qŠkŒMU1烟€dx(÷ïöp)áÅУ§e‹y_GÓiÿÁ«Y0½|øñ³ þßpò÷ØÂþïòÙ7ÿ2û¸­õ½˜ž¸'ûÆ(…¨+³HÉÐih±K†G KQÚ\óòˆçi>öÌ5Ùÿ§ó¼vËçØÔ«Ÿ„oè'ÙÇ{¯ÞË« ¦v}þ±;sïqÍ®1¸qðwÙÇŒµ§#¶øjA#•ÍX¡@á/¤¢Eá|øÑˆödé{×,—Ó þþäìcÑÅ—Ñ|ƪ³éà>ôèéÙÿÇ}oòÆSoc ¾Ïgßøböq{ÛM˜¿;ûÆ€Tªúv¶G¬Æ\™/ñ»4*ïÓˆD\«jŠ¥Ê1ÓR†¤¨kÀ–ËwAÔ9Tç¯bYØÐ#ÿØ\c¨‡ÃBõÞV0þÜ{öznqŸ §•¢j¸¯qß›ËJ‡ÊR”ûG~[ÓpXòÞã·nD_†ÍÑ’—ñüß‹åv.ìâéÄlöz˜2ï±pàûxh×™Ûá°AÈd‚÷@oÛ ƒ­öÌ8Õ›ýHc”Îär‹oË>š~˜ƒ‰°Yt0ê(­=³ûó~ìLnt§•ØÐz-0ðð„¦XÖuæ\⾡ŸpƒóD8­äÐõZ`à¡>,¼ öú3`5Ñõ{_…¨sBoß›‰lIŽü#€r¨w’½Î½õÿŽÍp€lÚ7|¬Á™oÓ÷6 2÷$l5Y›ö ýCîÄrm:æ}§ØMY›^ìÿ <¸•ëÌY›6€ÀøÝÐY{a°uÃa¡Î…“+S†ÞôÈÏ0ªŸ…N“sÔkåü'çéøH’©gCö÷ibûw\ô¨šöWQ6¬ `r×-Ü?ú‹V¬"øÒÝTØëÀ8E¶}7N¡R&@–"üà½ÍRlïøü÷…B¡ ocÎî¡ùŒ¡Ò®)0z'ŸØõG%¶Jg¸âF?#3¤“¾­m}›Ò¬)únœz¡ó_‘Ž{à>þïÀ˜Èæ÷~‹Ï½ýõ!˜Y$þCq£¥ùIïÕ{+p.ñÁ‡G"¸¿D"u`’ì _Ð&§óW‹1W‚µÙ0³H»Ätও¡oþ(Œ5§Âä:‹ÉR„¼¯Rr=Í…ÞŒSf&? ï Q)˜£ã´œu*ÚôÄ=|âù›J`-iLålzk«*t81½@NÞa¡6Ûù«¶ÆÐ€®Ë_„ÎÜÉ8OsÆ4j bYØ7ž{‚ûG€ï|(šå EýêûÚr™eW´¦^ºRŠ^ì)ê5ß×Fr~ó’ ¾¡Ÿ`ò¥[QNàTJ,ð‰]€ÒøÅýç›\ÄêÎGg#±ég}åF{dC¯%e8˜óÊHÇfQÂ?0ÆD–õó¹·¿€ôd9÷ºÆZº&¾¢xoK.ì+{ç÷~ ‰à~¥Ò¾J5_2Õl €q3ר×9€y9^ïì°·¾&×Y ¦_ù¤$•5Ì/aÓ2/œGN+1Ïý£?ÇÄ DY›NøÄó7 g’ýjmÀËØôÜ&µé£56ªÌqX(ëõ'|¢Ö&ê½éø,ßw—ÁÉû;‘TÅæÀº‹ýÿÁSáa¸ÝupZi¡)NÕ¶ÕÓN=UT2£dò¹ d)ÊgvŽë­hªepÙsJvùèl¤ÞöùpXèóü#w@JE ´ÿbÿm¨m<n'툊Ç\“!så3ç•Ïãr¡ƒÜLpdvðzÛV¸Oø& 8y?Mý®ú¸ì”².Ö0o¨!Ç\,†¤œÍ‡çž,ù,Î%>ûÆ—¸ 5£É¥G•îyqçÂ¥œ½AGËĦ„FÌe«Zμc#SlZgnD“K„ËN™¤b›îj,í=`7“MÆ )á-ù¼˜÷5¾xðßPÛt&ÜŽ¥mZ™ŸK¶@Že®b㑟Je:jœ§ÁX»éèæÞþ:9à Œ?w#¸œTƒ‡Äº„çžà£O^Z §¿\Ìùh÷ci¼RbœËè¸à¡luÀÄ ïãñ»Ñê¦Å¯ôOÐÈà<}=´¦4ïü ƤÄßÿÛ:ˆ"¥òvH2¥yEÈh©ƺ³ÑzöÿAÙù<¸µ$e¼(©isýEHE'À=Úι+{àÙó÷ÜóÎ7àvPyÜÑŸôX‹€´¶ '¶æëLîú0÷þ|Eâú')Sepž ¡}-ZÎú9ƤT€ï¿ÇQÒ@Åæ„²~1Q&'ÐÓLÙ7_¦[å„Åõh>ãÇptÞ¢¨(‹uæp>þÜ»œ¼¯¤=ér 4äQ 5·£û²]ÐY*2Æûì…FHaKKuEPÉT¦c_ÞW¯Ýò94žúoó ý„O½òñ‚¦5G3”†!ùPšðÀÜ[_ãóûþõNJ]WƒÑÙÂN@Ž %ý|ðáã '¦ÐÓR}ã¢Í¥!­±]W¼ ­±™¥¢|àÁ>ˆ,ŠÞ–RÁ£JPÔói€5½ŸBÓi?À˜R}³™+U䜿©î\ÄžG[}.Ë–_!°g„þm;ï^ØZnTƒKbÝ‘¼þJR⌑Ãén¢:uÃûšè<™‰4´õ_÷¹ð}Eènbèh '¿ØÚ€s&ÒŒ:VT’Fη§™¡»‰®ùì_ÆØ3×r+¾ÎÊ{ÛÍÀ–"R*œ€ðÌï9c˜ÆŽ\cš£ Ä—èiÎh/$§pð¾ÄýosÆ4`¢œWo{B¦Ã\WeÛZêïÀ¡ÿ^‹6}´!%‘ó—d@géBtþùIâb’¦(þ‘ŸAJ¬}OGÖ5Ï>ÿذ Sš’LlæhלžWï¤saƒŽŒ>s5¦_ýSHI?kÈ™+ð…PP¾†gˆTcÔó¬ºYc-îÇô«ŸÂä®AJwJÃ3¥dÅÍIÆ<@} `ÐqõtÍ]v 4ýæÞú*Ÿ{ûëÐiéñ|ôOV.½ó…ˆ¬Öê¦ón½.G }ú*̾ù$CpÙ «7"ñ£SmÎãÒ2¿tôÓÕLÁרÓWcêµOAJzÑX[hÓþp©z`1†¦ÈŽMzdç[S- aê•aâ…÷CJµýGfK‰†*Ž<Ì.ÒÝÖÕa–ãdÄ“”mÝÖèR{°ÿ·u*1PÅ’X×ÀÒp)«?ñ޲ˆEv?c³å™ÜõNÀ -”ÏÔj2,èØBÓÁà< “ …ïá´ÒÂ:\aÁÜÚJä±|_­LïàÿÀÖò®ìÙx>ºéu›•x¶Dvç3ÞB_C ]“ù}ß³ó#H¦J¥L·´P9d1s\ÓJŽºmÊx IDAT¨8 ëÍ”kzÿ–úK0ï/$ž™ ôÙý“›—L¹ÜN²Íün†Z‘tÜyr ¡Éûa¬9Só…6í°c¯li¥@!ÿ^Ôd˜ý¾¡Ûam¾6[?žÎ:?^<ŠlúhD>×IºYJ6g¾hSbбL a4ÿÈÏ6`”*6Ö,HE'x:6Í9—²‘¦,ÅxM÷Çao{?æý…A€/D=¿ö¿mõ¥;–P”"_Ký%è¼ðQp®ÁÈlaz:?´øF_[®5kþ{€­õÝh9ëçˆÄ ƒ€dŠ>ÇqÍM†ðh,RwS24öö÷Ã}üß#) BQ:N©Äíh¬-m{šJSý»ÆØŒ–óo(i=Š’ÓÛŒz •Ðæ¦Ÿ|„cT~i®;í> δ™)ÜáE¥öZŒ­­¥÷B l-ïBËY¿@4^¤ÒdmeQ¤9;ã%îNq•S>”Ã.oÂ^å*ÖkBÌ—5»/@ÇÅO€ËI <´ ©È’É NÜ“MmJ2í¸klåÞui M•–š' |œÓ™3°½J¶s4AÎ^chD*F+¤¥þ„瞀(P´ÍA‹pÛ&Ÿ©Á(‰4i HÇg¶–w#8ùÛ‚{Xk+lH²Œ{€`Q›É}>bóÏf{)H2¥;Å£,X ÅÄ@08OBÒÿ&8VnÓ±ŒM úÜ=4»ÏGÄólÖ¦Rnܬ‚JÇ"ÆçrkÐØ\ù{'ÉD¤–ÅZô\ù&´¦• ¨¢«^^SÑ ÚŒôeÔó ÆžºÉÐ ¤èX¶¼,8q•ôÉ´ 1FeQÅ ñC¡»™"`­†ÞC#éÄ< yJé…Ý?Qáɤ§lC*6m&ÂÏ=sýEdú,Æ(ø8DQl&:†IÇg¡É\ïàäoai¼¢àz£¥š‡B››Ò”‘ÞC+±ù¡µôB–s WÀ£ ·¥À¦c3`¢%kÓ«Þ¦›NÇg¡ÕdÊ<=ÏÂTwnÁ=Œ'é(GÅæ@þ¤Rà68EÕù«(‡Ue¦_û ÷ü°@>4FghaémÉ5:™ðx‰AWÚy®Ìù(hèÎ묥ȯ¤L-S€ÓB8€ÎT'çqÌÖOœ ,rœ¢h3h5”n^)`Î[(g«È‹ejó~º&ùóâà81¿W«‘08EgÇʼPŽqD¸Õ”ªØ<88A\¸þ–†Ëàè¸`êÝVQˆgþ;÷ü@¡J•Ù@ª äœ?#±hWÙ0‘,}îæL×­ |‚C!•¦sXSÞ{8,D¢úôbÄ3r¿ù×C °V« K”¾GO¦DÐp v™‹•±éCqd…”Dqþ=´›)ÀR² *ŽN4ÖÐ}¶%îÃäKÁäË·î!©8±¢ ây† Z;Ìêzåñ‘cV`5‘³–[ݴ謦”®­/d-S ;©Î)2™ÕB«¡ê OaÚY‘G]ù˜7# :J/N¦ëäM­¢#\C 9¶éÅÜcJÆÈ"籄67}ÿüy¡ž&jГ\©MgæÅdѼpX€:{i•‹Š£¶LÅ@2AdA%y¨(EÕG‹ÿϼþ…‘¿T¨P¡BÅÆA9Ætt~-gÞ¡æ|T ê €Þ¶×kÈ߉U³+;RˆlËɎ䯕(ÿ©Ø\8ælú0êJT“,¸/‡XkóïEþë|!rþή[Ѳó§ËÿpÇ ª,WÀÚt ±ҮaG3’i"TÍzé{*}:4E?)éÐ*në‰IªûN¥=Žés2EßïhvQÚbsФ‹°^,) S|ìºTÙ¬«ï‹h;ï^uç¯âXQ Þ¾µŸÿ»l08E)§ÅÀêD~6<™Îiή`!@’¶å’t¦[£w!–¤Ej5:+EO¹Ž]—½“ëléÄ<NÜ ÏëŸÌ®/z-ý£€«ïËh8ùŸ™rEÞ&hèÿ³,Ëi¥ÀAoßÞ+ßêüU,+ÎÄýoñ¡Çv"›F£#­†C#.ÏaH2í$"EŠo'NÌzéck+àœ HK49kz?…¶óï@Nœ]aRÒ _˜œ¿£ýf,ýxô½‹øÖûüÜã#’S_ãJ`r_€Å`¨Ù‰î+^… ±°˜w7çRœ›êÎa:s'¢qº®m_F Bο÷Úƒ08NpäÔz«Xf}¤rÙ×–±iלݟ@ÛÈÙ´£ó™”ôÁ&§åèü0ƒ€ÆÒƒ¾wS$±MD+Âã'ŸbÓi 05\‚Å ·Ÿ„ž+^ƒ ±±¸ï .KQnrÅtÖ^Dä€]ÛþÁ9ÿÞköÃä:@Žß²9³¯²Ñ8`i¸,{;.|&×Ù,ŸåÉð×è똳û£¸ÞP»å³H¤Èù·{wžóÆj·~ž¥bÓX ZËè§`18:>„Þ«ÞV¿Šª±"e~YŠqÿèÙ6¥£³Ä$Î'’U‚(=-”"o«Ï4­@fš  àpq ºòš ‰" ¥dt]þüÃ?ƒwà¿ì…Ù}÷ìù;Ômÿ*¯?ñ™£ãCŒËinm¼c#ŒµgÀÙóq0Ð!Ågˆ aªÙµ¶cV1´{ˆ')X1Ö…½ÿˆƒ÷· õœ_ó‰Þµ½Wïáz[ëºôyÎy f÷…ÌXs*7:OÎÚ˘ ã h|´ÈXŽÖ¼G#ºòŽž4"à—<ÀØXìÿ·amº–Ͻýu¸ú¾ÈNþfoÿãr‚›ë/ÖÔ £ó8»?&h¡³t#B2Es~=lº>¯’AG6íìüc˜jÏÄüÞoáàï:ÐzÎ]|â…÷AkjEïµ¹Þº…u]ö"—ÓX.e¦ÚÓ¹Þ~ô¶>DÙ´7D™…µäŒØþUÒøB€”ô£yçOàyû}ú*´{7þ&À–놸ÎÒŶÞ8Áƒ÷¢¦ç¬¦çOy"Ô[ËK:óúþ½Ξ|ƒ?Fí–Ϫi+BÕGqÿ[|ð‘“VÝÕÏã£(_(êXܽìpBéÓ^Óûx~“žþÏAuÈú¦ÂÙõQ˜êÎ);ùd)ÊãÞ×1úÄy0èéì½Õ½~cžõÒ¹cMÏ'àütZbJ§%:÷Œ'®Ë^Áq<˜h(;îðìc|±ÿ?Á½ •¦{¤bócxšvÔµ[>‡ÅþÛ²6Á9Ù´¶þ¨íý³CÚtÌ»cOœ£žå¶u´i¥ ¥³çãð þ:Mn·mÐQæªëò× ³oƒ šÊÛôÌ£Ü7r;$Ï]ënÓñ$­eûñÓ!¤££Ðe‚sH͘Ú/{L4BgéV·ŠÃ‚ª31"ܬälxd†Î™rìWCÍN L¾  8?2œ¿ÇOÎÞÞúx~›‰²‘LÚÜí¼‘ßbø·ÃÚt o¿àÁ%'± šX24Äe¾þÎ?§ó@cíðþzmn‘›ðÐg'SÀÀãg@Ô»±åÚ~.híKŽ[kjEhê‚÷P±¹1ï'çoo}ûoƒÕDløh‚H£õNÀ}Ãø,WðŽ _Ö¦SÑq.óõwþÑ8´Fç)Y篴‘Vl:•; L[ƒÞëú¹FW»´M[:»kÝmZ–©*JÐZ‘ŠM§¼ÙMθ'w½ú;É4ÐyñSÜ\¡¨ØpTÔ­?ñÛ°µÜ•›¬ääEŠT´ ÜAßÎ)(àL‡ƒãëÆX ?e(L®3˜ø læLBÐq…; 0‰jCÓaáÀ¿,9âÀø¯ùäËÉŠu,…dF ÄJÄ”©S&Z[|º¢ENùl–®m:îÁÈS—/ý^Áý|à¡í‡\(‡2| ÎÕÎrG:æ´“6Öœ†ÀÄo²Î vÁJÊ]àDEÏ<Š…ýÿ¼¤M'îá“/~ˆæE›NK”mˆ½¿•Ðd ™˜`BÌ÷zór6­Õ JI/ÆžºK­‰P?xpë¡m:OZxxºüó*apŠæ´FïOy³­Âë¥pƒFž¼éøœª´¡bÃQušzÁÉûa5ÑZ>*Õ´äTµ™I¼£ƒˆvB:>‹-×ì‡Ù} 'Ñ\WXź‘Jts>Z°L ºð+¿Èi5”ÊsZ­© ¾áŸLb.ÅùÄ cå4N NCœˆ Oa Ör è¸ÛÍ€Áq ÁYþù#ö° ˆð ý„s)^0îÙ7¾DïQ³äËÐXzàÀ8ý¨²ÁG.<> ¦à5æ} Œåœ14bÎ>4Æø†o/´i9ÉÇŸ¿©â¼Pxy”m@)ýåt\´™rJ}‰$]|E€dd¦´ÜÒ™Ñú—$ŠÖ¡P¥n;í–B lÂðL©f¹òÊ⟄<ó¹ó‡³ŠC>§&™±ieîÛ´IŸé 'ãÓšÛ³g‚ž5œü/à‰°o´0à-†˜¦ãs»ú¾È¶½×‡…½G¥Ý±bÓÑ{Ga™Z!Åïa6ÐϾQú¿’-+† Z[Áã&×YlÇûbHk{±w”‚bS™y‘  öQ9_k•6- týêtœˆTžÙkØÀÆ *Žy¬¸²»õìÿ£L@ô„‡C’—·c͇F$'•ŽÍ FWËúÞíÉ} &<¹²6¥‰ÆF¢ÞIg†]´”S›ñÒî¤á”÷3%á¨u0×¶¯ÒB™÷×üã’™EZh· ›…ÍL)Ôja7Sª·±–œrAS0B;)[ë{ÐqÑc%D#«Ûö•’lN>#!¶³¥á $ÃCÐk)Õ¬V$¹¨smt6RæMÙõcÎK%õ'þj·|nI›®;î¯!óB¾N±M{ƒ€£ó¤bS°™«w¤e¸:)Í_ɦCQ" Z›¯GçÅO–ü‰æÚú…’€%ߦ•yai¸ÉÈ(tšÌ¦¦Ê•R¯¥Ô~Ä=ÍK«ó§ÒÄ“`úl½a}:{TlV% Þòdx‰ð"³€È#UO˜HŒ&®¹þbt^ü€ˆç)>÷öß@Œï$ôözcíª†»æ˜óÃZoÛŠÞkTœ¼óû¾Íc‹¯Bº¥[3ýØT¾[|NËÊœÿr‰Ó"Ç!`Çûâ`‚¶|íôÜ|öõ?‡Mµ”:µ™)ЛRÒ·j]G¥ [®ªlÓû¿Ã£ó/@~F=‘X[êèÈh!kNGÌû*ì–•9ÿå"– £*Îv¼?&èÊŽ;ây†Ïìþ,„Ø;hr‘M+­zÇæAcƒ” nH¹àÀ?sýŪóW±¡XuÛ}ï]Æ%õÁ§ÈaXóRv’L …F¤4·ÐúU@t vëg!ˆ&¿›¿ð>è2Qô‘ oˆvíMµ@Ðög{v¡ãâ' –©­€Ttœ¼ŸÎTõ¶­HOýH <{¾ ·³rjvµ80NŠeÓdmZÎü_Ç—_|¸Ì÷üŠr”:k’¡A€½õ&Ônû†Û £èn*û*6 üaÚù7»€€åOò¼ŒÎ‹Ÿ„¨sT°éI~ð~ªÏÓÛú4žò¯¥æÞúê•ÐV‹¬M{Mõ=h9óœ'U¶é_k.Ø´­õݨÛþ5 =zÚºµ'€ÆPÛµ°5ßg÷ÇÔ @ņaMÄ]™h`M§ÿW¹HA³ ˜š/L Šáùô{Ï¿‚ºí_a‚hbr:ÌÇ_xJÍ-‡0t¸à0“Ó3ê6÷ŸˆywcñÀ÷*¾Fkjc '}Žö›Ñ{õ>ØÛnBÃ)ßGí–?c©(1²t:"å)$ĵFWé·Ö„÷½‰±g¯«ü&°®KŸƒÁq<º¯x Í;o‡Éu6w#4y/9¯r£˜ ¥bóÀž±iƒ<ÿ¸ï ,ìÿNÅ×hM-¬áäïÁÞvz¯Þ GûÍh8é;¨Ýú–ŠŒt‘¤Òªµ€RµÓîŽ#î#O]ZùL`]—>O6}ù«h9ë°Ô_‚Ös~Td„ƼÎ6ÝÑ@›£f›}S¯|\­P±¡X“ €ïÀùôkŸÓZxN78E@OS®µl*Mu·‚Ö‰-×CÔ:Xta÷þ„ø;0¥_@¯[ÏÃZaf‘vN§Þ†Ú-Ÿ]Q/KQ>³û Ðh´Ð-þs¾êz,T‹´”©á7¸Ñ÷®¹e9æ}?~À“Ù…1:_E)¸Û ÷LEe(ü›†“¿ Wß—VhÓ1>ûúŸC£³Bãùx|tž_­.À²?O&® µbû{XúäýÐðìù&×™Û<ð„ãä7VÐX-Œg ½Û£òTlVÔ ¨jz?ÍÁƒ|±ÿ6¤ÒTr$0 éüç1þÂMœžÙ@¥¸ÚÚÐqÑç`t eç?üøÙ`{û!?ꈃRjgv×Ô/‚hbM§ý€ï¿Ç.¯¯ór¥‰õ'VÞáå#2ÿ,ùÃÙôèè,²Â2“DØRÿÑe×k©¿dÅï!ˆFÖxÚøþ»màÒú:€¹Ðxò÷±Rçîãþš²¬1ÇýoóÑ'/ƒA—;ïïhÈ©Êõ4WVZS±2¤¥œM/§Ê&ß&¼UØtþë†26Ý}ånœ'¯Ü¦¹Ä'_¼\Š¢Å]¾ôn¾Ì8–B$žcîç¿©šÃÍ;ÿ¿UŸ¥/öÿÌ=…Z[yçŒæ4ƒK?'ÊüK¦s†@˜ˆ‡¶Öw£ýüÔ®~*6kšPàìþ8ÓšÛ¹ÎÒ 9ÊÌz®|GGy›Es‚`Y›öçÙtÏ'áìúèªÆœ¼ŸÏìþl¦òUGþpNŸÄj¢¹Vk[ú¹É4UpN×Õ¦ïè´RP`°ï@ÛÙ¿V¿Š Ǻ`i¸¼Ä˜™ c–†¥ÐÈRŒOîúV*˜16GN÷P%€s>rN‘ÎÔ*Ѽ!š¸n'MΔT¹ç@,A½ ƒtÞo¬=áÅW(;ÿÕ9ÐYºä—B*MãPé*ÜÁy?Ð×F¡4&¤ÒQÒ´ó_®óöpê£^^åQÅúÀã£l‹V“³é"9‰,üáÿbt–l¥XÁ1‘8Ù’/DNÕà<ßhç¿ZçPUPY"<‘¤qÌûik+Ø´'cÓ’ ˜ G*@ 4ï¼ή[×`Ì[9æ…#™*UB,ƼŸ*…¬&:&“y¦cçâ+°·­gýBuþ* Öü`¥D#ë½z/ Zh’ä1…Û3mxç|•ߣ³1—=Z$£ ú±Œp5'Å©¨Ü‰ZÚ.£¥¬ß®FúW‰òc‹¯¢ãÂÇÐsÕ[kâü€ ´ò‰zŠ€|¡Ò¼£þueÆ‘¯·P\¡¤é•þãr:Šž+_Gë9w-ßùûß⃃÷µ€1 ËVË”GU±rt4ä¢ÒGC‘—-¶i‡%Ç¿ÈÚ´Žl:-íÞÙ•±§•²7qßè¸è1ô\ùúš8YA}Ή|áÜœTЙ™[ŠBh~¿âï¨Ø´(Ms9î+^C>‡4I IDATë9w­‰ó9E¹zQCQæ¥Ý •,˜N›ËÄ)(žÍ®œ¢§²>ÕŸðh:íªóWqXqX€dh€ËRŒ§¢ã…ûIAƒ–³ïD"UØ–3‘¢]l5µñJ*qd†B** l\6Ff(åZÜ´(Êd77\´ª3ÿb¸ú¾Ä:/y¼á/02C‹_¹ãÅ §àÀàÉŠŽN”%FÐÚao»iYcNþ–>r ºÌõäitT¿<8Uy§¦bí¡ØÂØ¬€á™ÊåÞ$ ga8cÓšeÌvsýE«:ó/FíÖϳÎKžÐú5²éùCÛt"­Ã€bÓƬ¿b6½kw²ž+ß@ãùÏcpŠ2/•æmXöeZWÈ(¤ÞTd5½ŸfªóWq8±á@taïp öÝeÂÁûÛ‘ r˜}ãË|àÁ­özìÇ!Å-Ø7 ìɵ]î³ÇO»¤º CÍéˆÆËD”f5¹Î„­ù†’Æ9Åœ"µ±ž«Þcš5Ÿ¼f÷Œ šì8–úÎ2†fAcFË™?CŸóŠs‹sth=÷n$›.s6µ@öÞ|Æ¡³ö¬ù˜ Γ¸Œx’œ{9)ò mNZμ’Ìh.–¹Î ßÂÞþ8»n]ë!«PQ564H†¸”òSÚŒÑ.eà‘ãáû%OFF¡×Ò™v"¸:K'dNQ¾(Ð$ËOqËr®Ep8F;} w6îìºõ'ü=ë¼øièíÛ!s:Çrgvi  ˜Ðqñ¨éýsõ}LQW®±¹\uÀ`>3z wþÅpõ}‰Õô|°¦ÜáÈL.…«ì2z®|ÖæXë9¿êt¶Ì‘!§2lÿ†“þ¹*¶¿²óÏ'ü)òÄ:­Zê·Pœ @Î~8cÓÊÙ¸£ãfÔŸømÖqÉS08N—sǃSää%™8Ó£óÒgáìþSº;†%ʵÏåéY›¾âÕ5Ýù£vëçYMïgþKŒæuÌj…\õ&lÍ׳¶sÌ' ÎÎX† ©°ýëOøÖº*çkw²–3ï°Ì8ò»úMxhüͧÿf[oÀÀ:Ÿ“òÖ¨P”žopœˆÖ³~©¦ýUXS! Jð ßΧ^þ˜ô¹³G€Ä€’)ÚMº2,|E×[`À¶%4Ri:"°›iJRF[@CsmýNù×ìãrŠ'#£|hK6˜Zpõ5§¡ýÂG Ñ¹²ÏOǦùس7"x5צSÒCÇÅÃRɆLÞtlš<|<˜ä-‡ÌÌè¸è1˜\ggÇ‘ŠNòèüó˜}åƒÙÝŠr=Nþ>\}¾ì1=}5Í<‚ö†B g뇴D΢ĦE"¨Önù,O½-gÓ\â©ð(ì(Ú´Î~":.z ƒ»À>&_úc$Ÿ,±Ž ¥ñÊ ±éTt’üá<ðÄhn"æ:t\ôÌî rcŽMñØÂ.Ììº ))÷Ü”4œô]¸¶­Lœ¨ê1Ǧxxúxv¼dM§ÿ7jz>™‡” ðttÿ?œS¶N“¹?¶–ÑvÎÝ€°öY*V‚ Éļ»ùÔË`EŸØÛL;Êü³>£è¨/Ÿò—9ÐÙ@Uµ6Z(· •ìm7AkîÌïýÏ<Ê™ e:s 5;‘–€Þ«÷@’AïFç%Ï8ЛXMÏÇ‘–€ö „³ûcHK´;Ù(篌£nûW–€Î‹Ÿ„­åFÇ•o8€äXu¶-H¥ÉY´{R™´5Î@ÿ ç@{Ʀ]vºôö¶ %öÖ÷dmzaÿwyhæΘȴ–ëÎ%›¸úÈ\Ó:ÐuÙ Î ûptüRi í¼ß¢¦÷3H¥)‹´QÎ_GÍ–ÏRàqÑ£°·½) è¹ê­çZc3ÓY{‘’€šžO ýüû‘’(í¿QÎ_‡Þ¾)‰Ž`ZÎúRÐzÎ]ÎD­iL­d¦«EÏUo“ÈOóuh;÷7ªóWqDaÝ3±ÅW9ÓOIôÀlÌíöÌ™ö-€ùemÁ°Ì1ð—BVüãŒsŽéW)unm¾¡©ßúnœ†ÆØÈ¸œâRÒÁͤ¤Ÿ3Q—"Z éØ4×›XñïÜgsžŽÍBcl¬Ø˜EkjaÅ¿WƒØâ+|è±pÖŸ€fÓÛš&&³Â,W±¾˜Î´Ñm:í?Á4&L½ôQ€µùZ„¦gÓ\âRbC=“RΘ‚Ƽ®ö±È}6ç©Ø4´ÆæòcŽMqåïù¿o4ª‡” p&h!ˆ&–ŽÏrÞ­¦ýUqX× æÝ͇=m];Å)zåf÷ˆxžÍLé¹Å •Å€©ëë0Õ Kãê\&¸œäïk”œ¯¨†¦bí1磳f³ûBD÷ÖWQg/¯íŠ›Ü]CZ/¡ØúeyŽ(lQW)é-pþÅ(´éD‰¬¶ *T ëJŒxžáÓ¯}fC¡ó—dbùK+ì Œ¡°¥0;zä„n–cTÎf1C¿?á™GUz[(ýеº¶M/½­¤ßîñW–]Vqh„cÄþ¯Ö¦­&`èÑSš~X½*T¨¨ ë˜\gÁXs:¢‰\ >@Œ§ž.ÿÚJ°™€îf" šÓ»ä¶8/Õðîj¤ôtGîÅèÓW‚Ë)uÁ,ƒTt ÓQ;Â¥ôä»›èú·fÈæù-^C±Ò竨 ‹‘ºNXä—^Óâ{ Øt{=ìÁØ3×€ËIÕ¦U¨P±l¬]Àe^Ø*† :Öué³ÐYû08lý¹‚¥mZ… *–5 ¢ /ñ=¿±çW"ûo˺ŠÙ7¾Ì÷ÞeD2<­¹ Ã3¤h72CŽ¢±¶p—³$ÓÔÔg{;-–Í.ÚM-…9/9²úÿI=3­Aca§þ;KÅ}˜Y$‡T.ů4h5Ìû©e­[U \)ª`ÙÞ,2äÊØ´ÇG÷Æ}üß©6­B…Šª°z —ùࣧ"î{3ûPÓi?€µéjü]gîƒDô–^Äïd…L*yv3œ—šñÒbÚpÒ?õíËêB¹ È© ?p_ ät[[I9N)EHn8í7Ã?v'êªDðZCæå¹s^`>@åêvü•jÓ*T¨¨ « ³à£O]V ï;³H5øÐP+Àe“³ç‰ ÑÑÓcÔEKØ-Â/‘“i`˵ýÐY{°üÖBÇ6ät˜'ïÃìk ‹>˜ƒŽ*l-7"8yìf µL†ŠµÇ¬—ȰÉÐ{ÍL{Õ¦U¨P±|¬ØýFvñѧ.4¹r7Ö56r.f*Œe½°cЈ¹~Þx‚ØÕ­n ÿÁ-˜xñf¨¼õåAÐX˜£ýf0m üaÀµí/‘J“ó¯ÛñWpÿ·VÏåPQb `K ÐV <Ô‡ñçÞ…•Øtxî Îå€ÐÌ#¼Ò{$ÃÃ<<À ¶ø2—‹êR¡bcE)à‹¾‡Å}ß„ÌÉ™w6žçO/Sè,’ñ˜jí@u•#_!öŽmmÇÒ`LTwLË„’ pt|ˆ¥¢|î­¯Á?ú Xê/AxÚcZ¢zöÆ5Ô|PQ{GÉmW«qû?>ñâÍÐ[·ÀÚ||Îî¡ùŒ—¼G2<Ìûè4ï¼S/“<ñ¶÷ú!jíêÝHø¦ÓÊŠœ¾c BÇçäýÞš¯xæò‹–tMsžâÃ/}Œu•‹¿G¯#'®Ü$‚'PQo>¤ô{™Àt÷¿A ë‡U Öø€ÈYTÓ먭±š$UÀÙüa¤ õš×`­Ú/Œÿ çïxÐ{hÁó+åPI¢Õ¦»‚Ô"³Y¬\¥®’¦ÖV,|]ݦH»¦²¯é–{R(ìo­>¸´°ÿàOøäɯ-x~þ9”% ½ŽŠ8ÍѧO¹]W½·½NïõO¢ëÑ Ö ËvJ›>Èê/ý1fC€g"ó¼N¦°ðàØÙ»ñ–g­T´Ä®]_ÃÖ÷މ°ÿ ™8þE>þößbøå߇ÁÚE¥t2E«M©-óX;‡a yÏ¿¶´Z”TZþ9.·Cå”§öM­þþir®éôw¬>ï±õ½¾%‡ýµjÿ±ßýL¥ç€s`x‚¦ùçÐdÈÈ<Ǥ?<ÖõðQz&gº›Gb€š ˆî`°¢€iIã],qüŸ`°w€1Žú÷Á7_=úŸ½‚‡Ç~ªR –‚á¸+È Lùi¸ÒZ"§ Q4e±zœOOó T•áÄ u!ÌoA]ïèät§El¦Òs–t­¾þç|ªë^”ؽ Lξ*'Ík8>XX¼I'VÕy ç,ÛAË&–vÖL¥çÒ\Vh–¡@ (Vœ1­}÷7™µr'Q SLAÑZgòñ­^€´ê`h»öÍU1þ±™ßñ¡Ã·Ìý?ìBÝ%?âï|ãïüýÜó {àŽúÛ6Äoâøyxìר,Íü…cdœöÜã}:dŸÃìÇ> š.ÿ%˜d@ÿ³Wä8–ÙŸ?é§\yIÃmðýV3мÆÎÉZQ蚎%(ì¿TãïüÉœñ× þlæLÔD;Ÿù(±5é}1êówþ"Tx먻õ{~aü‚õÁiI+I?÷½<9sì0R*…†ë« Ï2_ ƦiZZ]%…%Ã1 ¡Š A,4ì{Žº÷®ÒÊ?Œp÷g¡D=0ê‰@28QuîßCéý$â ÔW±õ/áÚõ•u}ç |üíÏϵú­3!À;AÝ)…" õUÀtE×ù_BŶÏÌõ¢Oÿ"Ô™'QYJÕð¥6ÀlF¦ƒ­‰P?¬¦õ»òŸ¡ôJ]%]K¡(åþµkº~ÏÏPÒpûÿO¹ç¥»Ö\¢9#gs`ûíAH:Ûº¾ö‚ÍÄŠ‹•¤Ÿw>\€ç!TˇQ天eÕ§6þŠJmy©y#Nýa2§Â¦jÿ-õ”ç F½m|Z[Ô+pÔ½—©©pAiÓS1Õù¯|èð-˜x탨µyP_IðuU€š˜Òû§¨*UP_E·à Lžü*žŸ¯ë"¨TÔ€Ò(k…¢’bàÖ:ŸSÀP²Cãi÷÷!Tlû ãj‚s%Æ­U—±Æ÷B$ úcé.ÌÉøWlý4ê.þ!€õ;ä9¡jÿ­ ”J D½=ëš¾ò%”4ÜÎÔT˜/¥ÈŽsŠÉ¯u:Î3N’Ä63ÐýØ„|ÏÌ훚 f§BëõÔ–;¾7þ7Ô5hL.ïoµ6£¾y=Û%Vš{î=ÅöJ¬T­“ŠtKšµúrØ\`v¾ ƒ/Ü„Tt”Ÿ|¨ ƒ/Ü‚•8Jbšþö/Ð ØÎýü&0ÈÝrC½6tävø‡X·7¼Tl `0PÌ7_ýÏ% -}k+ÈJÉz;õ·ÂQw†ŽÜŠdÄÃûžÞƒîÇ·ƒ+1Î$k9xöškÑzÕËpï¾eí×®¯²xà8€\9êPtõ÷{­°[2×te:…f©Ü [õ°”ïÆÀó×#óñ“ÿãÂÐ 7Ÿ²Ò>èTH¡òµ™×ÐZK M. ÂÀ¯¯ç Ÿîù6?þsâ“Ü{ô~ü;”øäºýM‘e¯ñ”¤Ÿ{ŽÜ½ÁŠæZ=’É$TN‚ Ëîc2Pº Ë“+2¢×ÑóKE« —õ6HúR„}¿c@ç¡&0ž@Ð{‰Ð ¶¦Âs ÿ‚OwUͰIýî“Õ ¸Ó*jÙ¹p­U+ê]·ÅPu—þão³‘AÄü÷cÒO+ÓÕF»^XzÝÎUk#&O~’tj@>ì„Ѿ…[*÷²ÆË8[>gËGèqëÇY*>Í Ö&Œ{?ü‘3W‹²ÚhVR’ =K×ôÃõ`H!4ò’áè­M<_Å}Õ9_À Ë0ÑÿiL(°Údë.hû=Ýu/Fû$ û±mô]$ 6ûÌåq‘&Šƒe×x_ù>Óû¸+2-@K¥ÇK7ÎiU-]HÅ|0èèæ¡×Ñä¾íMËÛf,èL.(1šÒC‰z¼äX„£€gÒ sÅ%h¾âiœ*A¡$¦ù‰Ë!KÀ¶Æå}¿P”ò¡¦Òs›} Àòò¶Å„š ñã?w@b[ê×VÞwÀGÇÎ\¶ Ñé7PSN¢NEUd lƒ’ ¡ýÚ· JóÏ®GÛx"Ø»¢ë³XЮi½¥©È0]TØ=Láöp ðLYa.»ûŸ„”G˜s…ŸxÐ ž ¢¹f¡®Âjâ$ÅF›ë*„|O¡ÌNÚ ÝÃäˆ9í€'º~ßatÜÐ ƒ½cÝý&‚Ʋoë5»¾ Sé¹^¾ò_››ªócqr”˜ÖÊ÷ ‘¢v$­â·T9WíFi«¹ J̇º*ªjÖÉT ¥5ê%D{Ï]‡S¥dCkºü (*¦lÆf2}Ó ÿÖf¦¢9Íø€çÅ;Xgé5âýÏ„Ä8š]ùö1Xìx,Íø—4܉èô¨vfzß;êÈðtœ@2âA÷ç€+±EçèëŸä‰`/jÊóÿ©¬´Möù,zç®ékŠ Ã]Iו,¥¯i)}Mó0ÂãÏað¹kMp®pÏ‹w‚'ƒ¨¯ÊoüÇOqM/Íø—68Çø$*¤‹”ÿ0 ëÑ-" ËN¤âãˆÍ¾ƒ~ùm`±á·5Ò,žz¼/@’Íh»îLwÿ&O~ Æ%lW‚b*=¡Ñ§Pí¤ü»Æü`¿Q„FŸDÜÆ’mÓÑé×äJÐj79ˆ"ùî^±8r*¯=ãÀЋw Êÿ·¼êœÏ¯‹UçÅ÷#:uÕùexÇH¨'¥c‘{_*>rüt¦jø‡îG© ¨Ì’Î>C’DŽ@2:ŒD¸k3g²iîÓ=ÿΧº¾2{®xN6³Ôy01Kß+– „baîš.Ù‰Ðè/QUšÛwŸ}<#¹äÈØ³H»¡··ç¤ÆßúžQí¤âÔÅ™¤hÂLˆŽíJ¼¼“õÏÙþÀjÊÿùÈŒœs .+ÖÅoB ؈,;0Õu/€…7Ù`„òù…ðNn»–û5ê©k€«QŒ¼ú Lžü$FÝÙ ç"Ô£Ü^X% *p2è½Õ@÷ã; *‰>öÖç K¹ÆA3ü‰Ý4«SǨ’;»íª>Ý0þÎÖMw€Þâ@™ùÐ$cíV2¤Ë-0S9Ïö: ÜN¤Ð6$F)ö: çñís…ÚëFǶSn#¥¨B³‹«k e¼RBQrÛë«LE˜…¾‹QOߥÁEyö¡çỏK¶Ÿr‰TFö7˨).‡”BÛÐf $ lCQ©–d[ÐÿË8ñP¥ˆg‘e;®]_EiÓ‡à›Ê•µ[hhH§'ÿJ¢Õ DâiQ€Â›M. ä{–òÝŒ.tyr[ªhe=š–vuX2•ÒP¨oPûÌÙÐB¹RM±În¡ÙõAï!p¾øÝ_68YûuÇÀ%º‡3Fb[#…`MF šd/[´ImVÝ;‡r5ÖÒ©‰¡#·#<þ\Ñßð ¶V€*Ó]}lzaËf]–° 0‰ŽK"E­y§Bb™©rfÙŸóZ,‘9×Zo¿AGÇ>êGæ 3F—²ÎDoŒÆ†øµm ¹çX˜î9ÓØÌ™è‡¤æ^Ó0i#d3wM§pô‰œ×%™^Й©z³Ðï‘þ]d”¡±¥íwcº°P‹T,ö»ÐÈÖgÐÞÇy/S ¬)Ëv“™ûâïAgm€w"·Õj&H†¹P™]›{át1-Y}þ¿ éÀ3H¤€¾‘Ìë‘­FkæE’ –%2Ô=^ÚV¾'}íA~;l,ÙΚö?x’ô 20ÁK¨°º nÿoÐå¡©lά0m‰ØÒ›7O$É l­0—_T`犃ŠmŸam×ü û-èñÒHeM~>Ú¹Vtõè¦óæÌ#›‰QH['SÑØ€¯pŸ ç©ÌÅg©ÜËÚ®{Îwý=^j1-41rÒN Rä*{²åÙF¯ËËöxÓ*‡K¹¦yfùí¨¿µ]óLm/iÿ %üEµ:Ó×té (£hÛÜï¢À64™g%¾Ìb@°j¬Hê…1™µßÐÍGŽÞƒÁÿN?Iÿ”,óæŸHQ˜Ò`k†Ñ±:Sk¿¾“÷ÿê2ð§³õæ iÜ€ ŽvíôRDÉZu9Â/¢¾ª¸Œ?@õ5ò®é¾J—4x¦’‹GýmÌuþ—TrÚ&féuíw¡·6"îCË Œ?@Nº¶âwÚ ÿÙP¾åS(mþ°0þÁYä´fÔnÄÕúž¾ñÙß-X#tƒŸ/4Ô*ÌeŒGÛ‘‚õ{~ƒ­•Å'y÷cÛ “WG€¦{°Y€@(?ïk(i¸z³{É7®&9˜†èô«è}êb˜´úÏGË€¢î‹¿ïËwC¯£•öz¤Û ØLäŒUœ÷¯pÔÝ ½¥¾àr™ß" IDATñ:ü^Ħçά¨¹àÿÁ{ô#0¨Ng­žÈÔ’”]ð $½ 6×Uëê· l$N[Þ…1™1ɱà ‹Å8§›Õ|‚aZ}ôz¤˜­W¿Â ¶V¦¦B\Sã|u´Ý+J€š2 O½ñit>\®&y"ØÍ‡ßÂU%ÂÃãÏqï+[tv“ô \ç¥÷#è¢ç²^ŸÿZ ÷û¨˜jÈ…³íPwÉÙz3þ Ë™ëü/AQi¢£îf(*ÐråKЛÒÕ€Yßj±ãqº”X©ð°Í Œ¾vzž8¯`¹l,g÷MPT îâïÁ½û>( `w߯4¬Å>¯%Šl©|¿ý:Ñ®&x"ÔÇ_¸™«©OæÃ/ßÍ9W¸l,gå[þŠ 4í •;>E,•ûæ 8×úZŒTxØäÆŽ¾¿¾qÿñu6§Ðà\áÞß|þÁÃ]™Ví¥£ù«­cdnÛ¯? £c KÅ'xtòeø{ï…2ó4d‰þn5§»½Cʾ踡 ]vÌeÌõþ×]üý¡I®&øÐá[y Àd ÄÐT“žZ‰ø¦iT­¹ì´^ý*Ö£ñÏFIÌpÙàdçJÂÙPÊT%Â{?¶ê}¨ˆS2k9N»nv¼?yÊZ%>Å©V€sïÑb¦ï»© ©Ø8jÊ)båÈ•¤^OÌ]Ó7ö ë‘v¦Òó›}à¾è;p¶~Œ™ãA×ô{!YeI¶€+4º¨.g&X8Âuº¤ÙöÛüôŽuý»Ö+«æ€ª&xÏ£[  ªŒŠÄt&Py&Žÿô:êàHÙ¯…Îñn”6ÿ>´•ÿñì$`û2%x—J,AUýzK3‰ÉèW0\593wM'Sa™¢èU«{mGzwzÒ‹‚›¡·4lÜ߆@PĬª¤#/ßÙÍ=×rðô–:tjÊyïŽ;^OãûÝgøä‰/ÃU¶úƒ\‚êK¶T^Žðøs0¤…TjÑÓï´"%³sZ®ú †¿¡ÑÇÐPE:­ :2ôóÛã´"³l:nê‡ÁÚ´aor‘‰#¼ï™}¿vÌ€ÜãX"SK¢ šŠ%ÒµŽh>pr™8yíO0Ýý-Ô–gZP³÷a±ó¸EI‘Ñ\±‘‰#0èø\#ûøi*–¦ÒsÐrÕQ ¿ô½“H•vM'IYp5E$ž)(Œ'I¼ˆsªÉIªF´ßprCÿ.‚bgÕ€œ€ñ·þ{gËG$#C|ºû›`’anåŸýwqÿ1ÞýøN @û*#…cTù¬}Õlã?­Ò ¶$Ã}h«Å’ä‰ÒšŸòg*¢g‚düš†µrÙE&_â}Oï)lü“é¾|™ÄnF¦ wöÑP_ ŒN§[Ì*(R£¨À–›‡ ¼e3ü›ñÙÿF]eñUûŸ ®i]þ†6o ÅÄDðZjNí„Ãi©«¤ßDïŸ<¯·4,ú<¨J„w?¾[hü‡Æ©¬ J<ãT02E!z¥@›¢¢Rx_'ƒc}–nüCQÊûïhÊ@JŸHMÃ`½£]ÓõékZ_àšn¬¦Ô‡Ý˜Ò×´vΗ^ *Jèw$I™HXiã]°×\+ÂþAQTeO%w1UsïË@!` ‰­lX °0§™HR{ž¢’áÊ–,Í~/çô¹2ìÁÈ©enë*5 [¾vƒX 4ŽúÛXí…ßæ:s FÞ¸áI1gGkôóŽ¿¢P ¨Ñ@¹ê²ÇtæZ4^þø†Ê‡_þüƒ?…,qÿ1H ðq”¥UêŠIöw¥Ì¿¦“)ªàé!Kù®i¤•5»²®éµLhçPÒ—,ã ‚3AÑD4œÍw³êsÿþUìŸ"l4,_fx>)…Š’¶5`éPsžÑ¥…Ÿ·5Rø4¡©gK¡lžºw‚Š Ü»¿ cÉö w,kûƒšÀt¾g"Ϻ™ ƒÒ¦ßC4A«ÏŦ*d8Â1€IFX«ö/qO8ï}r7fû€ú*:w†ôÄÁ–Zú¼õ*ü“Î3×´”Žº¦N]6îŠå]Ó+%Ž9êo]ÛËfMŠWÿà¹ç¥ÈL*«v®~wÀ™¢w„*Ï[¯zæò 7œž—îâþÁŸ¢²¼ÕŽYDãTðUb¥ #S€³å¸wÿó{àž#wÀd p6ѽçœ?…ËØvëä’ÃþÞW>™ÞïÀ]Qx`uÉžW02•çÝå¡óßqc ¶æ yÍ ë™"uT>ôÂ-xA}ÕÊ‹ÿЉ“C´úÝzë8tÆÊ {3 zq%†ÿw@(JÆÜa¥• ÕuÍûŸžûî±™78ç*¼¿~7TN‘›™%•ëÑ~c7 ÖÆ%«éžoó‘Wÿevª!œ†'(£¨”ꉤÛ+ecw¿¢Kœ>ÞG`Ð/ßøûCTy<Ÿ¡1 ÅŸ>`dÞ@¢dŠŒûüÞÿé pb8ÖO#g¯xÛÞ7½¡?ØÝ7151`09/@IÃ턲ö?É1þMd²±ÿšwý+BQ@å:l½u|ÉÆŒö-(!8s¨œ"85edüMÎóç"?µïþ¬•{Y*æã!ß3ŸÒ65Eà<DÏ烩~”ûov-o+c3yÞì¨/­0]e+ßÃîaÀbÊͳ&Sät4TÓÔ?Ñ)ê6þÊ>Aï!n«¹LÒ#àyŽú÷åýî±™7¸¤³Ã`oc!ßÓÜ\váÃþ¢S¯ðÞ§v£ÄÙ€úÒ!„c”ã>s-Xš$qËç0|ô£H„zQuÎç1þöçÍW< kõþMóŠ"r8÷¼x'üC¬(ìÏy¦Ò^“ÍG F(?y:E`þ0õ_È 5kB+ŒÑjHS<ëô 7¢ýº·a°·‹ßtòÈÄaL¾ñq¨*ÍØhýÿÅ E»“!Ë¡ÆÇig˜œp“¨Þ÷(Él®ƒâ· Eã¨J”w>ìOÎ`KCfúRH¤h6zö3ƒµª…Ÿëy^‰NýtVòÈšLèlúf~47ï® §ÃûÊÇ¡&â&v–)i¼käš?B"EÅšc3¹ïÉRUª™ô“Ø?zf÷w£ ëjŽW4F±³ gzdMÖ[gYc)B@—¢Iä¸/þ>N½ïD) å«iMþùáûù´Öæþb–œ‚ÊŸCyÇŸ2Sé9¼ÿW—“ºV+Ó2æ–ÓÑì–LjA£ÛKF¤ýºw ébµ–‘t6ÖqSŸé½]]ô\UéâïUT:÷’lƒo:½náµ#XŠšN4C«ó@˜òð…Fž.FezúÜı@*6έU—±Ž{‘H‘s0>Cõó§§-…ŠtÝÀdçÿ]þ ÖÆJïœQ¬OO!RÕLQi$tFç»Àtfèe2þó‡ë–‡,­nÀj¢óUM·ÇJvl¹Ù½Ù-œgà,Q4m€óá\áï|{‚ÞCð=€*gþU]>´ý¦ýOÂæºŠ@"ÔÇýC÷CMþ’¡h©¡”Ár8>H7´í· éíâFV$¨© ÷ý( –˜¦¿ß4=ï*#5HÎôàjrÉí‚‚ÕAkL¦€ú=÷£¤ávˆFLàìQ´€Fpäq>øüõ°[¨€HCQ€¾Q{É^½Í¤#‰$µíUí} j*8gü³|þzy<§{ Šæh|áTµ­tJö¡lë_ÃTö®M¥ð·žyõ|ºç? é퀚‚ªDa.¿M—?V€1`GÓÙÞËÍC÷09aœSl?dƒ {ág‡¢KÌÇVs5l5× ¡•¼†,ÓtÀ¾‘Ü*}§ @º“ E^ãPÀHè'‹2;­Ræw4¹h›¡(ð†¥âRaü‹×®¯¢¤áv´_w í7œ„Ý}¢S¯ÂóâÐð M²Y°v´Ô£í°©é_#àyqÿ‰³½[Á¦¥èÆdÖxÙ£0:waЗë0F•Üó‡ÿh뉪s>Ÿ×ø€ÁÖÂ:nìY´; Ú€ùN€¶íöëOˆ°‘#él¬~ÏϘÞRÏÔD±™7!K@È÷@á’#…:ÁÚ"/Vg!ÿÁY£èSªšàÏ@tâŒé\½®ì Jš>Œ‘W>”€ªRØ¿òÂûatlƒ©ôœ%Ý]ÂãÏóþ_í‡AÇi¬©¨ÚýB£OaºçÛ022ÃÍW¿ÙT%VþëˆdÔË;®ƒ^¶4¶Ö¾ir"ªÎö^n‚`p °×^Æ÷šÁY¢è#’d`ÍžƒÕu%b šAÎd3œMDÇ ]H¦(7K ïR?PwE´mH²µ~‹¹/úOÄä¤ã¿ÎHF½¼ï©K —i:$@ÚZÛŸ«lõŒv´H+<ÌGöëóGLŸI²Ó_…±€tê+L'ü§Þ¶¦Û‘RÈáÈùl®Âø g™uÐà\áñÀ €s˜JvÌÝ@’‘!.élHF¼Ë2þÙ$Bý\68‘Œ ÂTzÞÜ6b³or±ôÂø¯3ºÛÆã“hÏÒ§_ z¼Íf ˆ‚ÓN5*‹12Iíˆ)…”&UµpÏüZ1ÚØåÒæßGÕŽÏ­Ý—+B8‚ ÁüV?ìB¼|EyË¥ÇKSʇGb¤<980—=kõ~VéOaé<V×*í{G¨N@ov#8Ž–Z ůÙ°~ß(0šîB衢Ŗƒ/À\önÖvÝ;Éy¥/zÒ£¸=ã”Jqÿ/(i¸ƒ5í6×p]9‚r&:=ôo0BŸi°w n÷}"ì/!ë® @ X ÿÐýÜóâûQbÍä¶×‚/`3Ój?‘83j`€µú ö=I—™©¦BÜ{ôcß?·ª–$²uÿC‡oAt¬áTÜá 2Ê:™Úð²÷C2Ö¢iÿÓ0•lÏÚç0ùžÂð‘[çê$F©º‹ˆÒæesΓ¡~t>Ò ‰œç@iÓ‡P·û»¢Ú_ (RD@°!P“¤å+e]ÑšxÓjRYJÚmn àjæŠK ³4BIø¡¦¢OæýÏ^Á¹ã’ÎÆÊ;þª 4í îÝ÷AUÖ«ŽÂho+†7?¤¾Ø-$c]W™i…,ßòI¨*`°6@MÌ óñÞ'/ä‰P?—tVf©¸**·m×þŽR{~6ÏøÓÞëmͰ»o‚d¨Ä–[<Õ°×^º‹¿/Œ¿@PĈ€`C *Þ÷Ô%°».GI🡶¶šòµûÌc”ón»þú~yT%½¥ÉÈšEP±õÓ  H€¤³-x<úúŸñTl–ðOÁ0X[M€“CäuÜØ ï+GxìY”ŠHF½°TîAËÁ#éý sIg]ðxq8W•$Ù̸ãL2ˆ°¿@Pä@°¡xî}Ž5(øË&‘º½T<—ŠŽÀ £ÔÃà­²«œ@¤âs¿ˆÆ}CÒ;òÙ¾û¸÷èGaÔ“ñ_Kyü.åü™lSchtc3ô}«‰äyH*zÔ]òß0::„60ÂlžùÐ‘Û ÿh0éq(Jùü劒¡7WìAlú èXmu”'×TõRΛô²±[oö€É¦5èäÝm…Q´¨H$©å.ž\¹¢¡fü-•{›<‚†êÌ÷O*41—Ñ7B¹“ŽûæÄ±ÁÆCÔ6Aï!>tä6Ø-ù8F•ð½^ÿ;<±üÏ Çhz ç@dâEÈ,‚Žz2þ@®š^2Eÿª‰ID¦Ž‚«‰o;êçÝm…A—ßø+ M»ì¥¶ºù㯗‚Öê—T© ÑÉ#hsç:?s£‘9Æ€Ù.Øg@°q€`C 3‘T]¡Â?Ï8UÛÛ­$Ù«°)´­ @eZù¯Ð祒ÄmwS_A÷ã;Á•ØœAÕIõ'U`?Ç賚\ÔB¸’}ôÕe@K  ÄÇÁyF°h>Ñiìhÿk8v¿‰P¿p‚ ˆp‚x° @nx\“ÿÕh¯£™ôU¥Ô- ËšO¿”évÚ6$‰ ª$宸'çm£¡(s±U&E"ØÈÔѹדQj°×Ëù·Ñè"i]“0§U µÖ¼éàÒö¹©†DÌFÚc™mLrß[îÈÈþÊGP$@ l<„°`CPÚô{Œ« ×›*á}ý£Ô²—MöÐ Ñ÷zÉ)Èv ‘3¸‡SO}oz Ïüa:‹ùá™%¼Ñ±•µ<ÌÕT}/_ r*´¹ ¶‘N3t{up˜SÇ€2û2÷9ý]jŒÆÉè/Š–ýç+;‚¢GDgËÝ,•˜ÆLˆÂïùzê}ÓJ·¹"š ã_W¹üÏ3)`3‘ñwçÑñ%hB É¹ –Ê=9¯Y*÷2½µ ‘ÕäÛçHŒŒµÉ¹ ©ÿBEƒùàØÖ@ÿ±Dá–Ùt„ÁÙú±å@ (z„ ØP”6ý+ix?@g"‹ìt:@«Ì/i¸ !ß3(µ­Ìø@s ý[]VØø÷Ž:sZ¯zL2,¨ª7:¶²Ú ¿åÌË£Sôo$ôûƒ­qÿ±¹vÁ• ýÙH3òÑé¡É–›=Ð[êD'€@°m€‚ IhìW<îÁãŸB(JÏi¾¥wavð'0耎úµÛ‡`„ ÷d p_þÈzŒY’»ó‰N½ÂÁ$Œ+ Ð3B [ÇßÁVu,•{„ l@D@°!±U`\UŠ% ·ÃQ+BQÀµë+¨¹àe}ß@„RíuÀÈó— ûñˆùßÉû©æò‹WˆÆ…K¨¹à^„c¤7Ðvõëk»³iÂ1ê\h©Ô‘o¢ï™½˜íÿX%Q(ذTlý439Ïã¶ê+¡±ga«>ÀT%Âu樱ѹ!9½^¼šd§´ö=YW¸jÏRq)k½ê(78¶@Ö—0SÉn©ÚÆt¬¼ãÏøT×½˜ Pá^ÿh& ±Z8¬™ÇÉdÒ •‡AQ#R‚M‰ªDx2Ô‡Þ'Î$Ѫ7Ûø­6>J?4]ñ lÕVRO†xç¡fèuÔ¯¿–³Ægñ jçÿAÕ9'ÒÁC¤›&1òê‚s*\ ã¯fuË©Y~µw’Œ¿{÷}§eü 0ü …ö~œÊ¿Ï·Ï3A2þΖ{Pµóó+ÛY@PÔ@°éà\áýÏìEdâE4׿Ÿ02ôV|TÔ—X‚*çS ÏîazÞ;Iÿ/ßúi8[>rZÆòä×øèo?…Š’üÆ?:‡ÉðOÌžZî¸ÛKû—R€Î!š5 /íp_ô1ÕO Ø ˆ€`Ó‘Œxxç/ ×[òtŒLñ`1S~Zoo$ÛS¨† Ê Œ¥5$Ù®ÆÀ9P{á ¬íã§eD9Wø±ŸêÀìÈÓÓœ‚ÊRÀ7C«ûŠÀU¶øû;=TK0¤–?&™ÁÕ(8œÍw“ñ—tÂø l:¸6ð&ë¹ø<»™ 쪀5!à鿘/Ö£“€–ZRå«)§÷Øj¯ç€û¢ïœ¶ñ§}eé}È¿ÏzÐVGòÃÕNz.[p¾¯_[NBGZPHU¢0Ø·Âî¾îÝÿ%Œ¿@°Á€`Óa°61×ù_‚¹æ6ø¦iÊÞàXî{ì–ÌcÍàN˜OÒd¾l é~šdЬ¬Ñ¾;îŒÁÙú±Õ1¢Lb-ÃTz.úF)åÐ?o?trÆàkû1ì#š å¾?û;jÎAÛµo¢qßÃ"ì/l„ Ø”Tlû «ÞõeLú—>8ž2¢{¸ðD¾Dz°ÁÖ &WÕˆZ*÷²¶kÞ@$Fµ jýЦ2}z¼”È7ï@«m°×^ÆtÂø ›á6-k+Këܲ1²‹ýº‡)ÔÞ~ýq4^ö€ÜÔAö{µ‚?÷Eÿ gëé‡ý…I¬IÛ¬Odí‡gœäë÷Ü÷îïBÒQ‹ƒ¬£~þX"óÞ™tôÃÙr7ßsH`!Š›žÉίs¾ Ñ“w#ž –=Wóxh¼ì1Øk¯cù- ý ¡ž/ÁaÆf¨…P–èý¥ÍFÝÅß_s#™8ÂCcÏ ÔýXMTñï´STÀÊ·| 5ïú:%1ÃÇÞü,R‘ØOÁ7EõN;ÍF0ØZÐq}§Èù › áB¾§ùÀ¯¯Øk¯Cpäq´ò7:¶åF5æÇ°Ñ{Ý7!è=@[ùôŒQ%1ÍO÷áÙgvf_€†ßOZíÎ3ÏÉÉm·ÝN¼°›ƒo×ïÄ Ú¦âi24»¶ësó»>C ÈŠJ~rëdE…OrBVTÒ7¶„óÇ8×ÿ²¢¢¥FÂT7ð€ ›¥Ot¢¥FÂÕ“ °K +*ž)¤±Ñ—¢Àsç×"äuq¢Às¬o)gX0~Rsrùc3ˆÏÉŠJDÁai¼æ36ØeE%C³k]Pò–!©édt!Ž ‡»tkš$µ ÈŠJÆÓh¯÷``r™ Í>Á’¢n{óÆ\T$©é¸~gÞhŸŠ§‰(ðèŸ\ÆT<Ÿ$ ÁëÂt< ŸèD(ÏtlÀÐì®Üž@ÃÏT<ƒ· ²¢ä¦VÒè=}—~õ¨ÔP›¢=èÁÔJ>ÉÉý°ï¸ù$©êU•áÆ˜ €jUJÓQ.ð8¼ç ·ëi©qÛo£ Šq’)M³½%“ºÏ®ANªˆ~¼DmY,t|[Q8Sñ4dE3Æe;¥éè“! <¾ÿó \¿#€ ÔtreøS,)„ƒM<4û-5’ÑŸ hhö M~L̰Òãò¼±òñÎíO-\x$5IµxYQ±dEEtl‰ì8 Œ.$È÷>ñ¥ŸóX-ÞûˆÚ0S×Rènöa`reÓ> ^ü’Ãy5…¯ )UGïé#y]ÜŽM TåÚ4.oÑÉ£»Ùèj¬ÚÔŠY;.xt½Tµ©ùÐä§ íAÊÿÒuĸ÷Á^EÈëâL@x.äuÆÌ|¢IMGK»@ú@î”t#òš~ɉˆ×ŵԸIGÐÃÝ“I~ßrÇÕ“‡!+*"Í~®«±šŒ.$°¤hE}ÁÕ×kèz¸ÉeÒôpW_?\HÙB„‚WkYtÈëBKd¨v1” ¼a³]UT`3k0G‹üþ)MG×KUU¹à“œ¸tëQQs8zл‹ ƒô\n?„R©´-Q Áë²x]ÑÉ££Þƒÿø^“A]ó‘Ê&E)MÇÔJ-5n\n?„Ë'êŒMä÷˜S¥'{óL“aæ9Ì•¦P•«äæ›xÀÍ3MžYCߘŒŽàœn¬ÆèBbÛqÞ/ Æ"#Í~ø$'i©qãÕkíÏì7äuq7Ï4yŠiOK» Í [4@x®¥Æ³Í>œ?àÊ<ú'­‹iðºŒ$¨=è1Ú¯¾~~kéÛôpËOWÐqàŽEƒº^ªÂ‡g_µô y]œOrrã‹3.x|pöÕ¢ –¶&CIM'²¢¢rÃ3Oà“œ¸»˜@¹À£7녯ߙ‡_èâÝkøÛoÌ`ßò?¯Ä8è ÞÍ!3N>_þFÿÃû©F¤A…ˆ³T;Šªstl‰dÙ!dEE{½AÏ–•#[04»FXVgŽéíA–7Ï4åìQ‹Ü }¸ö§@r\ƒÑ.Ôþ@‹þž])‹ÛJ…§Vr¬Îì;‚ +*ÞxSñ4•øjàMö9ÿ°‘ôDN(zˆ]´s‰°Å Í®‘”ªchö ¼. å¨Ú§4Óñ4þuøCœ:´NZ}pìû:í eÃ¥žÖÇs3-plîÈv[©ðfT–¤ßû„EÚè€;Õ¹Ž)§°¿ 8NÍg‡°% ˜i¨œTÑRã†_rØÝÅ’šŽc2Ö?ß0Là»_û5Ny€Öíƒûf¨Í93¹¦j¯Å¨Ch¸ÔJçl@o×\>Qg¨~W#MX® Ï}RšŸè„î{·¿Ò¨Ø÷„ý5DG¢À£¬þ=àåqÕr§»¡™qj6fˆ­v,Ýž0ØRãæD'O·Qo¿~'FòSÕ¤¦ãßgƒ¸1&£ÿX~Ï¿‹+7©ˆ¦chv -bÏ­'¼^¤à’/lû°­(š-q¾ Tå2ª± )MÇ@6G8ÿÉw:¨XîÕüé7ÀÜ¿m=s”ZŒ@ì($ÚZf<]VT2µ’¶ÔîË‘f¢Ùj­¬V+i®øa×ïñ—•óø–ûÔÖ‹E3g¨¾mÛ9AÚ•×ãYAXÂTJÓqþx€]PŒêQRÓÑôãPUN†]ÔÙ-ý¨8EiqÒ”%2_PûSà«ÿÿ¡ÍÿÖWVT":i@öÕ·‚Ž ‡‡ú_Ïþ Ø.p}¢ÐîÛÓ€ä¡a(@C؈mÅO!3N ÅÐåSá¯[FEæ)öí¬ŒÅ]=yØÈοFÐRµ ßçÿ ¬‚Y_õêêí3ã@e( /vÚ›B6ÿ¤ïò;ÐϧÝô{ú)ÙÿA+íó •»ý­~VÐÿÝÿùŒÅ·éý‰&b<·ø6½fsæÏï+=÷—øl®¯ ÷fIKY¸ÐgÆ f:sá+k¿û^†ÃáF~ó¦g/Ö'rÄg5ZHrÄ6úü³Aàñ5@l#Fr´ClíÌ‹13±¥àQgÎÑ ¢ìÌñ¿÷ù‹À½Rœ°z{#´åÁœÞ\˜;K…µfvNƒÍÒa-Fð°.H¨-\K[…Z .JeNkK¡²›žèROnl=û×ÅŸØJâj4wŸÍýd4@£/ ‘§uºÆ{tÁþ·s“›[ÑIãq]”Có3ºàº¾â³ µ@õEúÌ+1u}´äU.¾y€šRr„Þ7Ó_–3ì9è šnÞû:õú3C}€ '´¥ýòªÅ¨Š?ê¤^\l£vZ Ú<ÝÌÃ6àé ûñµ­i-£ÂŒðnk9m &!XÒ…äóîê Àò»¥G0Wp=M3ɇٜ*»·g6Å ¶ß±Áž$GèBŠ%ËïZSTæÙu™‰°l(ÖÍ;r¯Å ˜}ÉÓÁÂñÄÖÂçYÅhÕ|¶ÔÍ6/ÔRu­8UzÖÊn*Üûa‚± êc2㱋Å+<68»R Xê±nÐ!Ñ“Õb´H‘îHA?†ü¸_¶†G3Ø«.ÆríÛ¬¯ÅöT¬á¨#ÚP²Ü>JU›©`E ,¶æóì0Æ4;Gmžr‹¥*$Æ16ÛÜv`M†˜3ºÎ96¶x!@ão1°Tu5J7þb'&óom>»™ µÔãSg¸g°F69ËÏ­­¾®•^ïæ ¶QIVFX¿­Yš™TióÔ$J™Î.¡xA¤²;WqÝ.N‚ò!8TdëZŒ`#AÕ»½.…Õ¨íDg+À—¹¬B#88ÜIJy‡D_sÇ.æ„Âì_PÚ[ªÎ¸‹Ø½ªðF¢0·Ø¶¦±L•‘ç²y`7@‹$¹kÞM…RÑiÍ7x·ý•Þ?vVXKV‰Ó÷ù♵š;ÑD«Åùí{üÙµÿ2ãùÛkßcü¯õ·‰¶IIEND®B`‚metakernel-0.29.4/metakernel/magic.py000066400000000000000000000223471434565236000175360ustar00rootroot00000000000000import traceback import optparse import inspect import sys import os import shlex from ast import literal_eval as safe_eval try: _maxsize = sys.maxint except: # python3 _maxsize = sys.maxsize PY3 = sys.version_info[0] == 3 class MagicOptionParser(optparse.OptionParser): def error(self, msg): raise Exception('Magic Parse error: "%s"' % msg) def exit(self, status=0, msg=None): if msg: sys.stderr.write(msg) raise Exception(msg) ## FIXME: override help to also stop processing ## currently --help gives syntax error class Magic(object): """ Base class to define magics for MetaKernel based kernels. Users can redefine the default magics provided by Metakernel by creating a module with the exact same name as the Metakernel magic. For example, you can override %matplotlib in your kernel by writing a new magic inside magics/matplotlib_magic.py """ def __init__(self, kernel): self.kernel = kernel self.evaluate = True self.code = '' def get_args(self, mtype, name, code, args) : self.code = code old_args = args mtype = mtype.replace('sticky', 'cell') func = getattr(self, mtype + '_' + name) try: args, kwargs = _parse_args(func, args, usage=self.get_help(mtype, name)) except Exception as e: self.kernel.Error(str(e)) return self arg_spec = inspect.getfullargspec(func) if PY3 \ else inspect.getargspec(func) fargs = arg_spec.args if fargs[0] == 'self': fargs = fargs[1:] fargs = [f for f in fargs if not f in kwargs.keys()] if len(args) > len(fargs) and not arg_spec.varargs: extra = ' '.join(str(s) for s in (args[len(fargs) - 1:])) args = args[:len(fargs) - 1] + [extra] return (args, kwargs, old_args) def call_magic(self, mtype, name, code, args): self.code = code old_args = args mtype = mtype.replace('sticky', 'cell') func = getattr(self, mtype + '_' + name) try: args, kwargs = _parse_args(func, args, usage=self.get_help(mtype, name)) except Exception as e: self.kernel.Error(str(e)) return self arg_spec = inspect.getfullargspec(func) if PY3 \ else inspect.getargspec(func) fargs = arg_spec.args if fargs[0] == 'self': fargs = fargs[1:] fargs = [f for f in fargs if not f in kwargs.keys()] if len(args) > len(fargs) and not arg_spec.varargs: extra = ' '.join(str(s) for s in (args[len(fargs) - 1:])) args = args[:len(fargs) - 1] + [extra] try: try: func(*args, **kwargs) except TypeError: func(old_args) except Exception as exc: msg = "Error in calling magic '%s' on %s:\n %s\n args: %s\n kwargs: %s" % ( name, mtype, str(exc), args, kwargs) self.kernel.Error(msg) self.kernel.Error(traceback.format_exc()) self.kernel.Error(self.get_help(mtype, name)) # return dummy magic to end processing: return Magic(self.kernel) return self def get_help(self, mtype, name, level=0): if hasattr(self, mtype + '_' + name): func = getattr(self, mtype + '_' + name) if level == 0: if func.__doc__: return _trim(func.__doc__) else: return "No help available for magic '%s' for %ss." % (name, mtype) else: filename = inspect.getfile(func) if filename and os.path.exists(filename): with open(filename) as f: return f.read() else: return "No help available for magic '%s' for %ss." % (name, mtype) else: return "No such magic '%s' for %ss." % (name, mtype) def get_help_on(self, info, level=0): return "Sorry, no help is available on '%s'." % info['code'] def get_completions(self, info): """ Get completions based on info dict from magic. """ return [] def get_magics(self, mtype): magics = [] for name in dir(self): if name.startswith(mtype + '_'): magics.append(name.replace(mtype + '_', '')) return magics def get_code(self): return self.code def post_process(self, retval): return retval def option(*args, **kwargs): """Return decorator that adds a magic option to a function. """ def decorator(func): help_text = "" if not getattr(func, 'has_options', False): func.has_options = True func.options = [] help_text += 'Options:\n-------\n' try: option = optparse.Option(*args, **kwargs) except optparse.OptionError: help_text += args[0] + "\n" else: help_text += _format_option(option) + "\n" func.options.append(option) if func.__doc__: func.__doc__ += _indent(func.__doc__, help_text) else: func.__doc__ = help_text return func return decorator def _parse_args(func, args, usage=None): """Parse the arguments given to a magic function""" if isinstance(args, list): args = ' '.join(args) args = _split_args(args) kwargs = dict() if getattr(func, 'has_options', False): parser = MagicOptionParser(usage=usage, conflict_handler="resolve") parser.add_options(func.options) left = [] value = None if '--' in args: left = args[:args.index('--')] value, args = parser.parse_args(args[args.index('--') + 1:]) else: while args: try: value, args = parser.parse_args(args) except Exception: left.append(args.pop(0)) else: break args = left + args if value: kwargs = value.__dict__ new_args = [] for arg in args: try: new_args.append(safe_eval(arg)) except: new_args.append(arg) for (key, value) in kwargs.items(): try: kwargs[key] = safe_eval(value) except: pass return new_args, kwargs def _split_args(args): try: # do not use posix mode, to avoid eating quote characters args = shlex.split(args, posix=False) except: # parse error; let's pass args along rather than crashing args = args.split() new_args = [] temp = '' for arg in args: if arg.startswith('-'): new_args.append(arg) elif temp: arg = temp + ' ' + arg try: safe_eval(arg) except: temp = arg else: new_args.append(arg) temp = '' elif arg.startswith(('(', '[', '{')) or '(' in arg: try: safe_eval(arg) except: temp = arg else: new_args.append(arg) else: new_args.append(arg) if temp: new_args.append(temp) return new_args def _format_option(option): output = '' if option._short_opts: output = option._short_opts[0] + ' ' output += option.get_opt_string() + ' ' output += ' ' * (15 - len(output)) output += option.help + ' ' if not option.default == ('NO', 'DEFAULT'): output += '[default: %s]' % option.default return output def _trim(docstring, return_lines=False): """ Trim of unnecessary leading indentations. """ # from: http://legacy.python.org/dev/peps/pep-0257/ if not docstring: return '' # Convert tabs to spaces (following the normal Python rules) # and split into a list of lines: lines = docstring.expandtabs().splitlines() indent = _min_indent(lines) # Remove indentation (first line is special): trimmed = [lines[0].strip()] if indent < _maxsize: for line in lines[1:]: trimmed.append(line[indent:].rstrip()) # Strip off trailing and leading blank lines: while trimmed and not trimmed[-1]: trimmed.pop() while trimmed and not trimmed[0]: trimmed.pop(0) if return_lines: return trimmed else: # Return a single string: return '\n'.join(trimmed) def _min_indent(lines): """ Determine minimum indentation (first line doesn't count): """ indent = _maxsize for line in lines[1:]: stripped = line.lstrip() if stripped: indent = min(indent, len(line) - len(stripped)) return indent def _indent(docstring, text): """ Returns text indented at appropriate indententation level. """ if not docstring: return text lines = docstring.expandtabs().splitlines() indent = _min_indent(lines) if indent < _maxsize: newlines = _trim(text, return_lines=True) return "\n" + ("\n".join([(" " * indent) + line for line in newlines])) else: return "\n" + text metakernel-0.29.4/metakernel/magics/000077500000000000000000000000001434565236000173375ustar00rootroot00000000000000metakernel-0.29.4/metakernel/magics/README.md000066400000000000000000000445251434565236000206300ustar00rootroot00000000000000# Line Magics ## `%activity` %activity FILENAME - run a widget-based activity (poll, classroom response, clicker-like activity) This magic will load the JSON in the filename. Examples: %activity /home/teacher/activity1 %activity /home/teacher/activity1 new %activity /home/teacher/activity1 edit ## `%cd` %cd PATH - change current directory of session This line magic is used to change the directory of the notebook or console. Note that this is not the same directory as used by the %shell magics. Example: %cd .. ## `%connect_info` %connect_info - show connection information This line magic will show the connection information for this language kernel instance. This information is only necessary if you are interested in making additional connections to the running kernel. Example: %connect_info Paste the given JSON into a file, and connect with: $> ipython --existing or, if you are local, you can connect with just: $> ipython --existing %(key)s or even just: $> ipython --existing if this is the most recent Jupyter session you have started. ## `%conversation` %conversation ID - insert conversation by ID %%conversation ID - insert conversation by ID ## `%dot` %dot CODE - render code as Graphviz image This line magic will render the Graphiz CODE, and render it as an image. Example: %dot graph A { a->b }; ## `%download` %download URL [-f FILENAME] - download file from URL This line magic will download and save a file. By default it will use the same filename as the URL. You can give it another name using -f. Examples: %%download http://some/file/from/internet.txt -f myfile.txt %%download http://some/file/from/program.ss Options: -------- -f --filename use the provided name as filename [default: None] ## `%edit` %edit FILENAME - load code from filename into next cell for editing This line magic will open the file in the next cell, and allow you edit it. This is a shortcut for %load, and appending a "%%file" as first line. Example: %edit myprogram.ss ## `%get` %get VARIABLE - get a variable from the kernel in a Python-type. This line magic is used to get a variable. Examples: %get x ## `%help` This is MetaKernel Python. It implements a Python interpreter. ## `%html` %html CODE - display code as HTML This line magic will send the CODE to the browser as HTML. Example: %html This is underlined! ## `%include` %include FILENAME ... - include code from filename into this code This line magic will get the contents of a file and include it in this cell evaluation. You can have multiple %include's at the beginning of a cell, and they will be included in order. Examples: %include myprog.py %include myprog1.py myprog2.py ## `%install` %install PACKAGE - install package Example: %install calico-spell-check ## `%install_magic` %install_magic URL - download and install magic from URL This line magic will copy the file at the URL into your personal magic folder. Example: %install_magic http://path/to/some/magic.py ## `%javascript` %javascript CODE - send code as JavaScript This line magic will execute the CODE on the line as JavaScript in the browser. Example: %javascript console.log("Print in the browser console") ## `%jigsaw` %jigsaw LANGUAGE - show visual code editor/generator This line magic will allow visual code editing or generation. Examples: %jigsaw Processing %jigsaw Python %jigsaw Processing --workspace workspace1 --height 600 Options: -------- -h --height set height of iframe [default: 350] -w --workspace use the provided name as workspace filename [default: None] ## `%kernel` %kernel MODULE CLASS [-k NAME] - construct a kernel for sending code. This line magic will construct a kernel language so that you can communicate. Example: %kernel bash_kernel BashKernel -k bash Use `%kx` or `%%kx` to send code to the kernel. Also returns the kernel as output. Options: -------- -k --kernel_name kernel name given to use for execution [default: default] ## `%kx` %kx CODE [-k NAME] - send the code to the kernel. This line magic will send the CODE to the kernel for execution. Returns the result of the execution as output. Example: %kernel ls -al Use `%kernel MODULE CLASS [-k NAME]` to create a kernel. Options: -------- -k --kernel_name kernel name given to use for execution [default: None] ## `%latex` %latex TEXT - display text as LaTeX This line magic will display the TEXT on the line as LaTeX. Example: %latex $x_1 = \dfrac{a}{b}$ ## `%load` %load FILENAME - load code from filename into next cell This line magic will get the contents of a file and load it into the next cell. Example: %load myprog.py ## `%ls` %ls PATH - list files and directories under PATH This line magic is used to list the directory contents. Examples: %ls . %ls .. Options: -------- -r --recursive recursively descend into subdirectories [default: False] ## `%lsmagic` %lsmagic - list the current line and cell magics This line magic will list all of the available cell and line magics installed in the system and in your personal magic folder. Example: %lsmagic ## `%macro` %macro NAME - execute a macro %macro -l [all|learned|system] - list macros %macro [-s] [-d] NAME - show or delete a macro This line macro will execute, show, list, or delete the named macro. Examples: %macro renumber-cells %%macro test print "Ok!" %macro -l all %macro -d test Options: -------- -s --show show macro [default: False] -l --list list macros [default: False] -d --delete delete a named macro [default: False] ## `%magic` %magic - show installed magics This line magic shows all of the install magics, either from the system magic folder, or your own private magic folder. ## `%matplotlib` %matplotlib BACKEND - set the matplotlib backend to BACKEND This line magic will set (and reload) the items associated with the matplotlib backend. Also, monkeypatches the IPython.display.display to work with metakernel-based kernels. Example: %matplotlib notebook import matplotlib.pyplot as plt plt.plot([3, 8, 2, 5, 1]) plt.show() ## `%parallel` %parallel MODULE CLASS [-k NAME] [-i [...]] - construct an interface to the cluster. Example: %parallel bash_kernel BashKernel %parallel bash_kernel BashKernel -k bash %parallel bash_kernel BashKernel -i [0,2:5,9,...] cluster_size and cluster_rank variables are set upon initialization of the remote node (if the kernel supports %set). Use %px or %%px to send code to the cluster. Options: -------- -i --ids the machine ids to use from the cluster [default: None] -k --kernel_name arbitrary name given to reference kernel [default: default] ## `%plot` %plot [options] backend - configure plotting for the session. This line magic will configure the plot settings for this language. Examples: %plot qt --format=png %plot inline -w 640 Note: not all languages may support the %plot magic, and not all options may be supported. Options: -------- -h --height Plot height in pixels -w --width Plot width in pixels -r --resolution Resolution in pixels per inch -b --backend Backend selection [default: inline] -f --format Plot format (png, svg or jpg). -s --size Pixel size of plots, "width,height" ## `%pmap` %pmap FUNCTION [ARGS1,ARGS2,...] - ("parallel map") call a FUNCTION on args This line magic will apply a function name to all of the arguments given one at a time using a dynamic load balancing scheduler. Currently, the args are provided as a Python expression (with no spaces). You must first setup a cluster using the %parallel magic. Examples: %pmap function-name-in-language range(10) %pmap function-name-in-language [1,2,3,4] %pmap run_experiment range(1,100,5) %pmap run_experiment ["test1","test2","test3"] %pmap f [(1,4,7),(2,3,5),(7,2,2)] The function name must be a function that is available on all nodes in the cluster. For example, you could: %%px (define myfunc (lambda (n) (+ n 1))) to define myfunc on all machines (use %%px -e to also define it in the running notebook or console). Then you can apply it to a list of arguments: %%pmap myfunc range(100) The load balancer will run myfunc on the next available node in the cluster. Note: not all languages may support running a function via this magic. Options: -------- -s --set_variable set the variable with the parallel results rather than returning them [default: None] ## `%px` %px EXPRESSION - send EXPRESSION to the cluster. Example: %px sys.version %px -k scheme (define x 42) %px x %px cluster_rank cluster_size and cluster_rank variables are set upon initialization of the remote node (if the kernel supports %set). Use %parallel to initialize the cluster. Options: -------- -s --set_variable set the variable with the parallel results rather than returning them [default: None] -e --evaluate evaluate code in the current kernel, too. The current kernel should be of the same language as the cluster. [default: False] -k --kernel_name kernel name given to use for execution [default: None] ## `%python` %python CODE - evaluate code as Python This line magic will evaluate the CODE (either expression or statement) as Python code. Note that the version of Python is that of the notebook server. Examples: %python x = 42 %python import math %python x + math.pi ## `%reload_magics` %reload_magics - reload the magics from the installed files Example: %reload_magics This line magic will reload the magics installed in the system, and in your private magic folder. You only need to do this if you edit a magic file. It runs automatically if you install a new magic. ## `%restart` %restart - restart session This line magic will restart the connection to the language kernel. Example: %restart Note that you will lose all computed values. ## `%run` %run [--language LANG] FILENAME - run code in filename by kernel This magic will take the code in FILENAME and run it. The exact details of how the code runs are determined by your language. The --language LANG option will prefix the file contents with "%%LANG". You may also put information in the cell which will appear before the contents of the file. Examples: %run filename.ss %run -l python filename.py %kx calysto_scheme.kernel CalystoScheme %run --language kx filename.ss %run --language "kx default" filename.ss Note: not all languages may support %run. Options: -------- -l --language use the provided language name as kernel [default: None] ## `%scheme` %scheme CODE - evaluate code as Scheme This line magic will evaluate the CODE (either expression or statement) as Scheme code. Examples: %scheme (define x 42) %scheme (import "math") %scheme (+ x + math.pi) ## `%set` %set VARIABLE VALUE - set a variable in the kernel. This line magic is used to set a variable to a Python value. Examples: %set x 42 %set x [1, 2, 3] ## `%shell` %shell COMMAND - run the line as a shell command This line command will run the COMMAND in the bash shell. Examples: %shell ls -al %shell cd Note: this is a persistent connection to a shell. The working directory is synchronized to that of the notebook before and after each call. You can also use "!" instead of "%shell". # Cell Magics ## `%%activity` %%activity FILENAME - make an activity from a JSON structure This magic will construct a Python file from the cell's content, a JSON structure. Example: %%activity /home/teacher/activity1 {"activity": "poll", "instructors": ["teacher01"], "results_file": "/home/teacher/activity1.results", "items": [{"id": "...", "type": "multiple choice", "question": "...", "options": ["...", ...] }, ...] } In this example, users will load /home/teacher/activity1 ## `%%brain` %%brain - run a cell as brain control code for a calysto.simulation. Requires calysto. Examples: %%brain robot.forward(1) ## `%%conversation` %conversation ID - insert conversation by ID %%conversation ID - insert conversation by ID ## `%%debug` %%debug - step through the code expression by expression This cell magic will step through the code in the cell, if the kernel supports debugging. Example: %%debug (define x 1) ## `%%dot` %%dot - render contents of cell as Graphviz image This cell magic will send the cell to the browser as HTML. Example: %%dot graph A { a->b }; ## `%%file` %%file [--append|-a] FILENAME - write contents of cell to file This cell magic will create or append the cell contents into/onto a file. Example: %%file -a log.txt This will append this line onto the file "log.txt" Options: -------- -a --append append onto an existing file [default: False] ## `%%help` This is MetaKernel Python. It implements a Python interpreter. ## `%%html` %%html - display contents of cell as HTML This cell magic will send the cell to the browser as HTML. Example: %%html
Contents of div tag
## `%%javascript` %%javascript - send contents of cell as JavaScript This cell magic will execute the contents of the cell as JavaScript in the browser. Example: %%javascript element.html("Hello this is bold!") ## `%%kx` %%kx [-k NAME] - send the cell code to the kernel. This cell magic will send the cell to be evaluated by the kernel. The kernel must have been created use the %%kernel magic. Returns the result of the execution as output. Example: %%kernel bash ls -al Use `%kernel MODULE CLASS [-k NAME]` to create a kernel. Options: -------- -k --kernel_name kernel name given to use for execution [default: None] ## `%%latex` %%latex - display contents of cell as LaTeX This cell magic will display the TEXT in the cell as LaTeX. Example: %%latex $x_1 = \dfrac{a}{b}$ $x_2 = a^{n - 1}$ ## `%%macro` %%macro NAME - learn a new macro This cell macro will learn the macro in the cell. The cell contents are just commands (macros or code in the kernel language). Example: %%macro test print "Ok!" %macro test Ok! ## `%%pipe` %%pipe FUNCTION1 | FUNCTION2 ... The pipe cell will "pipe" the contents of a cell through a series of function calls. All of the functions must be defined in the language, and the kernel must support the `do_function_direct` method. Example: %%pipe f1 | f2 | f3 CELL CONTENTS is the same as issuing: f3(f2(f1("CELL CONTENTS"))) ## `%%processing` %%processing - run the cell in the language Processing This cell magic will execute the contents of the cell as a Processing program. This uses the Java-based Processing language. Example: %%processing setup() { } draw() { } ## `%%px` %%px - send cell to the cluster. Example: %%px (define x 42) Use %parallel to initialize the cluster. Options: -------- -s --set_variable set the variable with the parallel results rather than returning them [default: None] -e --evaluate evaluate code in the current kernel, too. The current kernel should be of the same language as the cluster. [default: False] -k --kernel_name kernel name given to use for execution [default: None] ## `%%python` %%python - evaluate contents of cell as Python This cell magic will evaluate the cell (either expression or statement) as Python code. Unlike IPython's Python, this does not return the last expression. To do that, you need to assign the last expression to the special variable "retval". The -e or --eval_output flag signals that the retval value expression will be used as code for the cell to be evaluated by the host language. Note that the version of Python is that of the notebook server. Examples: %%python x = 42 %%python import math retval = x + math.pi %%python -e retval = "'(this is code in the kernel language)" %%python -e "'(this is code in the kernel language)" Options: -------- -e --eval_output Use the retval value from the Python cell as code in the kernel language. [default: False] ## `%%scheme` %%scheme - evaluate contents of cell as Scheme This cell magic will evaluate the cell (either expression or statement) as Scheme code. The -e or --eval_output flag signals that the retval value expression will be used as code for the cell to be evaluated by the host language. Examples: %%scheme (define x 42) %%scheme (import "math") (define retval (+ x math.pi)) %%scheme -e (define retval "this = code") %%scheme -e "this = code" Options: -------- -e --eval_output Use the retval value from the Scheme cell as code in the kernel language. [default: False] ## `%%shell` %%shell - run the contents of the cell as shell commands This shell command will run the cell contents in the bash shell. Example: %%shell cd .. ls -al Note: this is a persistent connection to a shell. The working directory is synchronized to that of the notebook before and after each call. You can also use "!!" instead of "%%shell". ## `%%show` %%show [-o]- show cell contents or results in system pager This cell magic will put the contents or results of the cell into the system pager. Examples: %%show This information will appear in the pager. %%show --output retval = 54 * 54 Options: -------- -o --output rather than showing the contents, show the results [default: False] ## `%%time` %%time - show time to run cell Put this magic at the top of a cell and the amount of time taken to execute the code will be displayed before the output. Example: %%time [code for your language goes here!] This just reports real time taken to execute a program. This may fluctuate with number of users, system, load, etc. ## `%%tutor` %%tutor [--language=LANGUAGE] - show cell with Online Python Tutor. Defaults to use the language of the current kernel. 'python' is an alias for 'python3'. Examples: %%tutor -l python3 a = 1 b = 1 a + b [You will see an iframe with the pythontutor.com page including the code above.] %%tutor --language=java public class Test { public Test() { } public static void main(String[] args) { int x = 1; System.out.println("Hi"); } } Options: -------- -l --language Possible languages to be displayed within the iframe. Possible values are: python, python2, python3, java, javascript metakernel-0.29.4/metakernel/magics/__init__.py000066400000000000000000000000001434565236000214360ustar00rootroot00000000000000metakernel-0.29.4/metakernel/magics/activity_magic.py000066400000000000000000000311421434565236000227060ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. try: from ipywidgets import widgets except ImportError: widgets = None from metakernel import Magic, option import os import getpass import datetime def touch(fname, times=None): with open(fname, 'a'): os.utime(fname, times) class Activity(object): def __init__(self): self.questions = [] self.filename = None self.results_filename = None self.instructors = [] self.show_initial = True self.last_id = None def load(self, filename): if filename.startswith("~"): filename = os.path.expanduser(filename) filename = os.path.abspath(filename) self.filename = filename with open(self.filename) as fp: json_text = "".join(fp.readlines()) self.load_json(json_text) if self.results_filename is None: self.results_filename = filename + ".results" touch(self.results_filename) def load_json(self, json_text): # Allow use of widgets: if widgets is None: return json = eval(json_text.strip(), {key: getattr(widgets, key) for key in dir(widgets)}) if json.get("results_filename", None): self.results_filename = json["results_filename"] if json.get("instructors", []): for instructor in json["instructors"]: self.instructors.append(instructor) if json["activity"] == "poll": self.index = 0 for item in json["items"]: if item["type"] == "multiple choice": # FIXME: allow widgets; need to rewrite create/show: question = item["question"] #if isinstance(question, str): # question = widgets.HTML(question) options = item["options"] #for pos in range(len(options)): # option = options[pos] # if isinstance(option, str): # options[pos] = widgets.HTML(option) q = Question(item["id"], question, options) self.questions.append(q) else: raise Exception("not a valid question 'type': use ['multiple choice']") self.create_widget() self.use_question(self.index) else: raise Exception("not a valid 'activity': use ['poll']") def use_question(self, index): self.set_question(self.questions[index].question) self.set_id(self.questions[index].id) self.results_html.layout.visibility = "hidden" self.results_button.layout.visibility = "visible" if (getpass.getuser() in self.instructors) else "hidden" self.prev_button.disabled = index == 0 self.next_button.disabled = index == len(self.questions) - 1 for i in range(5): self.choice_row_list[i].layout.visibility = "hidden" self.buttons[i].layout.visibility = "hidden" for i in range(len(self.questions[index].options)): self.choice_widgets[i].value = self.questions[index].options[i] self.choice_row_list[i].layout.visibility = "visible" self.buttons[i].layout.visibility = "visible" def create_widget(self): self.id_widget = widgets.HTML("") self.question_widget = widgets.HTML("") self.choice_widgets = [] self.choice_row_list = [] for count in range(1, 5 + 1): self.choice_widgets.append(widgets.HTML("")) self.choice_row_list.append(widgets.HBox([widgets.HTML("%s)  " % count), self.choice_widgets[-1]])) self.buttons = [] for i in range(1, 5 + 1): button = widgets.Button(description = str(i)) button.on_click(self.handle_submit) button.layout.margin = "20px" self.buttons.append(button) self.respond_row_widgets = widgets.HBox([widgets.HTML("""

Respond: """)] + self.buttons) self.next_button = widgets.Button(description="Next") self.next_button.on_click(self.handle_next) self.results_button = widgets.Button(description="Results") self.results_button.on_click(self.handle_results) self.prev_button = widgets.Button(description="Previous") self.prev_button.on_click(self.handle_prev) self.results_html = widgets.HTML("") self.top_margin = widgets.HTML("") #self.top_margin.layout.height = "100px" right_stack = widgets.VBox([self.top_margin, self.results_html]) self.stack = widgets.VBox([self.id_widget, self.question_widget] + self.choice_row_list + [self.respond_row_widgets, widgets.HBox([self.prev_button, self.results_button, self.next_button])]) self.output = widgets.Output() self.top_level = widgets.VBox([widgets.HBox([self.stack, right_stack]), self.output]) def set_question(self, question): self.question_widget.value = "

%s

" % question def set_id(self, id): self.id_widget.value = "

Question ID: %s

" % id self.id = id def handle_results(self, sender): # write out when we show the Results: self.handle_submit(sender) if self.last_id == self.questions[self.index].id: self.show_initial = not self.show_initial else: self.show_initial = True self.last_id = self.questions[self.index].id data = {} with open(self.results_filename) as fp: line = fp.readline() while line: if "::" in line: id, user, time, choice = line.split("::") if self.questions[self.index].id == id: if choice.strip() != "Results": if self.show_initial: if user.strip() not in data: data[user.strip()] = choice.strip() else: # shows last data[user.strip()] = choice.strip() line = fp.readline() choices = {str(i): 0 for i in range(1, len(self.questions[self.index].options) + 1)} for datum in data.values(): if datum not in choices: choices[datum] = 0 choices[datum] += 1 barvalues = [int(value) for key,value in sorted(choices.items())] self.stack.layout.width = "55%" try: from calysto.graphics import BarChart barchart = BarChart(size=(300, 400), data=barvalues, labels=sorted(choices.keys())) self.results_html.value = str(barchart) self.results_html.layout.visibility = "visible" except: with self.output: print(sorted(choices.keys())) print(barvalues) def handle_submit(self, sender): import portalocker with portalocker.Lock(self.results_filename, "a+") as g: g.write("%s::%s::%s::%s\n" % (self.id, getpass.getuser(), datetime.datetime.today(), sender.description)) g.flush() os.fsync(g.fileno()) self.output.clear_output() with self.output: print("Received: " + sender.description) def handle_next(self, sender): if self.index < len(self.questions) - 1: self.index += 1 self.use_question(self.index) self.output.clear_output() def handle_prev(self, sender): if self.index > 0: self.index -= 1 self.use_question(self.index) self.output.clear_output() def render(self): from metakernel.display import display display(self.top_level) class Question(object): def __init__(self, id, question, options): self.id = id self.question = question self.options = options class ActivityMagic(Magic): def line_activity(self, filename, mode=None): """ %activity FILENAME - run a widget-based activity (poll, classroom response, clicker-like activity) This magic will load the JSON in the filename. Examples: %activity /home/teacher/activity1 %activity /home/teacher/activity1 new %activity /home/teacher/activity1 edit """ from IPython import get_ipython if mode == "new": text = ''' {"activity": "poll", "instructors": ["YOUR ID HERE"], "items": [ {"id": "1", "question": """When it comes to learning, metacognition (e.g., thinking about thinking) can be just as important as intelligence.""", "type": "multiple choice", "options": ["True", "False"] }, {"id": "2", "question": """What is the best way to learn from some text?""", "type": "multiple choice", "options": ["Read and reread the text.", "Explain key ideas of the text to yourself while reading.", "Underline key concepts.", "Use a highlighter"] }, {"id": "3", "question": """Intelligence is fixed at birth.""", "type": "multiple choice", "options": ["True", "False"] }, {"id": "4", "question": """You have a test coming up. What's the best way to review the material?""", "type": "multiple choice", "options": ["Circle key points in the textbook.", "Review relevant points of the lecture in audio format.", "Take an informal quiz based on the material."] }, {"id": "5", "question": """To which of the following should you not tailor your learning?""", "type": "multiple choice", "options": ["Learning styles (visual, audio, etc.)", "Previous knowledge", "Interests", "Ability"] }, {"id": "6", "question": """Learning should be spaced out over time.""", "type": "multiple choice", "options": ["True", "False"] }, {"id": "7", "question": """Right-brained people learn differently from left-brained people.""", "type": "multiple choice", "options": ["True", "False"] } ] }''' get_ipython().set_next_input(("%%%%activity %s\n\n" % filename) + text) return elif mode == "edit": text = "".join(open(filename, "r").readlines()) get_ipython().set_next_input(("%%%%activity %s\n\n" % filename) + text) else: activity = Activity() activity.load(filename) activity.render() def cell_activity(self, filename): """ %%activity FILENAME - make an activity from a JSON structure This magic will construct a Python file from the cell's content, a JSON structure. Example: %%activity /home/teacher/activity1 {"activity": "poll", "instructors": ["teacher01"], "results_file": "/home/teacher/activity1.results", "items": [{"id": "...", "type": "multiple choice", "question": "...", "options": ["...", ...] }, ...] } In this example, users will load /home/teacher/activity1 """ if filename.startswith("~"): filename = os.path.expanduser(filename) filename = os.path.abspath(filename) with open(filename, "w") as fp: fp.write(self.code) activity = Activity() activity.load(filename) # Make sure results file is writable: os.chmod(activity.results_filename, 0o777) # Ok, let's test it (MetaKernel): self.line_activity(filename) self.evaluate = False def register_magics(kernel): kernel.register_magics(ActivityMagic) def register_ipython_magics(): from metakernel import IPythonKernel from metakernel.utils import add_docs from IPython.core.magic import register_line_magic, register_cell_magic kernel = IPythonKernel() magic = ActivityMagic(kernel) # Make magics callable: kernel.line_magics["activity"] = magic kernel.cell_magics["activity"] = magic @register_line_magic @add_docs(magic.line_activity.__doc__) def activity(line): kernel.call_magic("%activity " + line) @register_cell_magic @add_docs(magic.cell_activity.__doc__) def activity(line, cell): magic.code = cell magic.cell_activity(line) metakernel-0.29.4/metakernel/magics/blockly_magic.py000066400000000000000000000102241434565236000225070ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. # @author ChrisJaunes from metakernel import Magic, option from IPython.display import IFrame, Javascript class BlocklyMagic(Magic): @option( '-o', '--page_from_origin', action='store', default=None, help='Load remote page about blockly' ) @option( '-l', '--page_from_local', action='store', default=None, help='Load local page about blockly' ) @option( '-t', '--template_data', action='store', default=None, help='generate page based on template and load, must be used with parameters(-o or -l)' ) @option( '-h', '--height', action='store', default=350, help='set height of iframe ' ) def line_blockly(self, page_from_origin=None, page_from_local=None, template_data=None, height=350): """ %blockly - show visual code This line magic will allow visual code editing If both -o and -l are provided, only -l is used Examples: %blockly --page_from_origin http://host[:port]/blockly_page.html %blockly --page_from_local blockly_page.html %blockly --page_from_origin http://host[:port]/blockly_template.html --template_data template_data %blockly --height 600 """ # Display iframe: script = """ if(document.receiveBlocklyPythonCode === undefined) { document.receiveBlocklyPythonCode = function ( event ) { IPython.notebook.insert_cell_above().set_text(event.data); } window.addEventListener("message", document.receiveBlocklyPythonCode, false) } """ #print(script) self.kernel.Display(Javascript(script)) if height is None: height = 350 if template_data is not None: if page_from_local is not None: with open(html_from_local, "rb") as fp: html_template = fp.read().decode("utf-8") elif page_from_origin is not None: try: import urllib.request urlopen = urllib.request.urlopen except: # python2 import urllib urlopen = urllib.urlopen page_template = urlopen(page_from_origin).read().decode("utf-8") else: raise ValueError("No -l or -o is provided") with open(template_data+'-toolbox.xml', "rb") as fp: blockly_toolbox = fp.read().decode("utf-8") html_template = html_template.replace("MY_BLOCKLY_TOOLBOX", blockly_toolbox) with open(template_data + '-workspace.xml', "rb") as fp: blockly_workspace = fp.read().decode("utf-8") html_template = html_template.replace("MY_BLOCKLY_WORKSPACE", blockly_workspace) with open(template_data + '-blocks.js', "rb") as fp: blockly_blocks = fp.read().decode("utf-8") html_template = html_template.replace("MY_BLOCKLY_BLOCKS_JS", blockly_blocks) with open(template_data + '.html', 'w') as fp: fp.write(html_template) page_from_local = template_data + '.html' if page_from_local is not None: self.kernel.Display(IFrame(page_from_local, width='100%', height=height)) elif page_from_origin is not None: self.kernel.Display(IFrame(page_from_origin, width='100%', height=height)) else: self.kernel.Display(IFrame("https://developers-dot-devsite-v2-prod.appspot.com/blockly/blockly-demo/blockly-demo", width='100%', height=height)) def register_magics(kernel): kernel.register_magics(Magic) def register_ipython_magics(): from metakernel import IPythonKernel from IPython.core.magic import register_line_magic kernel = IPythonKernel() magic = BlocklyMagic(kernel) # Make magics callable: kernel.line_magics["blockly"] = magic @register_line_magic def blockly(line): """ Use the blockly code visualizer and generator. """ kernel.call_magic("%blockly " + line) metakernel-0.29.4/metakernel/magics/brain_magic.py000066400000000000000000000021351434565236000221450ustar00rootroot00000000000000from metakernel import Magic, option from IPython.display import IFrame class BrainMagic(Magic): def cell_brain(self): """ %%brain - run a cell as brain control code for a calysto.simulation. Requires calysto. Examples: %%brain robot.forward(1) """ text = self.code pre_code = """ from calysto.simulation import * robot = get_robot() def brain(): """ post_code = """robot.brain = brain""" new_code = (" ".join(line + "\n" for line in text.split("\n"))) self.code = pre_code + new_code + post_code def register_magics(kernel): kernel.register_magics(BrainMagic) def register_ipython_magics(): from metakernel import IPythonKernel from IPython.core.magic import register_cell_magic kernel = IPythonKernel() magic = BrainMagic(kernel) @register_cell_magic def brain(line, cell): from IPython import get_ipython ipkernel = get_ipython() magic.code = cell magic.cell_brain() ipkernel.kernel.do_execute(magic.code, silent=True) metakernel-0.29.4/metakernel/magics/cd_magic.py000066400000000000000000000015121434565236000214360ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic import os class CDMagic(Magic): def line_cd(self, path='.'): """ %cd PATH - change current directory of session This line magic is used to change the directory of the notebook or console. Note that this is not the same directory as used by the %shell magics. Example: %cd .. """ path = os.path.expanduser(path) try: os.chdir(path) retval = os.path.abspath(path) except Exception as e: self.kernel.Error(str(e)) retval = None if retval: self.kernel.Print(retval) def register_magics(kernel): kernel.register_magics(CDMagic) metakernel-0.29.4/metakernel/magics/connect_info_magic.py000066400000000000000000000041411434565236000235150ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic import json class ConnectInfoMagic(Magic): def line_connect_info(self, dummy=None): """ %connect_info - show connection information This line magic will show the connection information for this language kernel instance. This information is only necessary if you are interested in making additional connections to the running kernel. Example: %connect_info Paste the given JSON into a file, and connect with: $> ipython --existing or, if you are local, you can connect with just: $> ipython --existing %(key)s or even just: $> ipython --existing if this is the most recent Jupyter session you have started. """ connection_file = self.kernel.config["IPKernelApp"]["connection_file"] try: config = json.loads(open(connection_file).read()) except: config = {"stdin_port": "UNKNOWN", "shell_port": "UNKNOWN", "iopub_port": "UNKNOWN", "hb_port": "UNKNOWN", "ip": "UNKNOWN", "key": "UNKNOWN", "signature_scheme": "UNKNOWN", "transport": "UNKNOWN" } retval = """{ "stdin_port": %(stdin_port)s, "shell_port": %(shell_port)s, "iopub_port": %(iopub_port)s, "hb_port": %(hb_port)s, "ip": "%(ip)s", "key": "%(key)s", "signature_scheme": "%(signature_scheme)s", "transport": "%(transport)s" } Paste the above JSON into a file, and connect with: $> ipython --existing or, if you are local, you can connect with just: $> ipython --existing %(key)s or even just: $> ipython --existing if this is the most recent Jupyter session you have started. """ % config self.kernel.Print(retval) def register_magics(kernel): kernel.register_magics(ConnectInfoMagic) metakernel-0.29.4/metakernel/magics/conversation_magic.py000066400000000000000000000030071434565236000235630ustar00rootroot00000000000000""" Magics to have disqus conversation in the notebook. """ from metakernel import Magic from IPython.display import HTML class ConversationMagic(Magic): def cell_conversation(self, id): """ %conversation ID - insert conversation by ID %%conversation ID - insert conversation by ID """ html = """
""" % id self.kernel.Display(HTML(html)) def line_conversation(self, id): """ %conversation ID - insert conversation by ID %%conversation ID - insert conversation by ID """ self.cell_conversation(id) self.evaluate = False def register_magics(kernel): kernel.register_magics(ConversationMagic) def register_ipython_magics(): from metakernel import IPythonKernel from IPython.core.magic import register_line_magic, register_cell_magic kernel = IPythonKernel() magic = ConversationMagic(kernel) @register_line_magic def conversation(id): magic.line_conversation(id) @register_cell_magic def conversation(id, cell): magic.code = cell magic.cell_conversation(id) metakernel-0.29.4/metakernel/magics/debug_magic.py000066400000000000000000000156471434565236000221540ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic from IPython.display import HTML, Javascript class DebugMagic(Magic): def cell_debug(self, dummy): """ %%debug - step through the code expression by expression This cell magic will step through the code in the cell, if the kernel supports debugging. Example: %%debug (define x 1) """ html_code = """

Speed: Inspect:
""" import time html = HTML(html_code) self.kernel.Display(html) time.sleep(.1) data = self.kernel.initialize_debug("\n" + self.code) ## add a line so line numbers will be correct time.sleep(.1) if data.startswith("highlight: "): self.kernel.Display(Javascript("highlight(cell, %s);" % data[11:])) time.sleep(.1) self.evaluate = False def register_magics(kernel): kernel.register_magics(DebugMagic) metakernel-0.29.4/metakernel/magics/dot_magic.py000066400000000000000000000034351434565236000216440ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic from IPython.display import HTML class DotMagic(Magic): def line_dot(self, code): """ %dot CODE - render code as Graphviz image This line magic will render the Graphiz CODE, and render it as an image. Example: %dot graph A { a->b }; """ try: import pydot except: raise Exception("You need to install pydot") graph = pydot.graph_from_dot_data(str(code)) svg = graph.create_svg() if hasattr(svg, "decode"): svg = svg.decode("utf-8") html = HTML(svg) self.kernel.Display(html) def cell_dot(self): """ %%dot - render contents of cell as Graphviz image This cell magic will send the cell to the browser as HTML. Example: %%dot graph A { a->b }; """ try: import pydot except: raise Exception("You need to install pydot") graph = pydot.graph_from_dot_data(str(self.code)) svg = graph.create_svg() if hasattr(svg, "decode"): svg = svg.decode("utf-8") html = HTML(svg) self.kernel.Display(html) self.evaluate = False def register_magics(kernel): kernel.register_magics(DotMagic) def register_ipython_magics(): from metakernel import IPythonKernel from IPython.core.magic import register_cell_magic kernel = IPythonKernel() magic = DotMagic(kernel) @register_cell_magic def dot(line, cell): """ %%dot - evaluate cell contents as a dot diagram. """ magic.code = cell magic.cell_dot() metakernel-0.29.4/metakernel/magics/download_magic.py000066400000000000000000000046141434565236000226650ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option import urllib try: import urlparse except ImportError: from urllib import parse as urlparse import os try: urllib.URLopener def download(url, filename): opener = urllib.URLopener() opener.retrieve(url, filename) except: # python3 import urllib.request def download(url, filename): g = urllib.request.urlopen(url) with open(filename, 'wb') as f: f.write(g.read()) class DownloadMagic(Magic): @option( '-f', '--filename', action='store', default=None, help='use the provided name as filename' ) def line_download(self, url, filename=None): """ %download URL [-f FILENAME] - download file from URL This line magic will download and save a file. By default it will use the same filename as the URL. You can give it another name using -f. Examples: %%download http://some/file/from/internet.txt -f myfile.txt %%download http://some/file/from/program.ss """ if filename is None: if url.count(" ") == 1: url, filename = url.split(" ") elif url.count(" ") == 0: parts = urlparse.urlsplit(url) #('http', 'example.com', '/somefile.zip', '', '') path = parts[2] filename = os.path.basename(path) else: raise Exception("invalid arguments to %%download: '%s'" % url) basename, extname = os.path.splitext(filename) if extname == '': filename += ".html" filename = filename.replace("~", "") filename = filename.replace("%20", "_") try: download(url, filename) self.kernel.Print("Downloaded '%s'." % filename) except Exception as e: self.kernel.Error(str(e)) def register_magics(kernel): kernel.register_magics(DownloadMagic) def register_ipython_magics(): from metakernel import IPythonKernel from IPython.core.magic import register_line_magic kernel = IPythonKernel() magic = DownloadMagic(kernel) # Make magics callable: kernel.line_magics["download"] = magic @register_line_magic def download(line): kernel.call_magic("%download " + line) metakernel-0.29.4/metakernel/magics/edit_magic.py000066400000000000000000000017141434565236000220010ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option import os class EditMagic(Magic): def line_edit(self, filename): """ %edit FILENAME - load code from filename into next cell for editing This line magic will open the file in the next cell, and allow you edit it. This is a shortcut for %load, and appending a "%%file" as first line. Example: %edit myprogram.ss """ orig_filename = filename if filename.startswith("~"): filename = os.path.expanduser(filename) filename = os.path.abspath(filename) with open(filename) as f: text = f.read() self.kernel.payload.append({"source": "set_next_input", "text": "%%file " + orig_filename + "\n" + text}) def register_magics(kernel): kernel.register_magics(EditMagic) metakernel-0.29.4/metakernel/magics/file_magic.py000066400000000000000000000034261434565236000217750ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option import os import errno class FileMagic(Magic): @option( '-a', '--append', action='store_true', default=False, help='append onto an existing file' ) def cell_file(self, filename, append=False): """ %%file [--append|-a] FILENAME - write contents of cell to file This cell magic will create or append the cell contents into/onto a file. Example: %%file -a log.txt This will append this line onto the file "log.txt" """ if filename.startswith("~"): filename = os.path.expanduser(filename) filename = os.path.abspath(filename) # Create the path of the file if dirs don't exist: path = os.path.dirname(os.path.abspath(filename)) try: os.makedirs(path) except OSError as exc: # Python >2.5 if exc.errno == errno.EEXIST and os.path.isdir(path): pass else: raise # Create or append to file: if not append: message = "Created file '%s'." % filename if os.path.isfile(self.code): message = "Overwrote file '%s'." % filename else: message = "Appended on file '%s'." % filename try: if append: fp = open(filename, "a") else: fp = open(filename, "w") fp.write(self.code) fp.close() self.kernel.Print(message) except Exception as e: self.kernel.Error(str(e)) self.evaluate = False def register_magics(kernel): kernel.register_magics(FileMagic) metakernel-0.29.4/metakernel/magics/get_magic.py000066400000000000000000000010701434565236000216260ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic class GetMagic(Magic): def line_get(self, variable): """ %get VARIABLE - get a variable from the kernel in a Python-type. This line magic is used to get a variable. Examples: %get x """ self.retval = self.kernel.get_variable(variable) def post_process(self, retval): return self.retval def register_magics(kernel): kernel.register_magics(GetMagic) metakernel-0.29.4/metakernel/magics/help_magic.py000066400000000000000000000102571434565236000220060ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic class HelpMagic(Magic): def help_strings(self): suffixes = [ "item{0}{0} - get detailed, technical information on item", "item{0} - get help on item", ] prefixes = [ "{0}{0}item - get detailed, technical information on item", "{0}item - get help on item", ] strings = [] if self.kernel.help_suffix: strings += [s.format(self.kernel.help_suffix['help']) for s in suffixes] if 'help' in self.kernel.magic_prefixes: strings += [p.format(self.kernel.magic_prefixes['help']) for p in prefixes] return sorted(strings) def line_help(self, text): """ %help TEXT - get help on the given text This line magic shows the help for TEXT. Shows the help in the system pager that opens at bottom of screen. Example: %help dir """ return self.get_help_on(text, 0, False) def cell_help(self, text): """ %%help TEXT - get detailed help on the given text This line magic looks like a cell magic, but it really gets more detailed help on TEXT. Shows the help in the system pager that opens at bottom of screen. Example: %%help dir """ return self.get_help_on(text, 1, False) def get_help_on(self, text, level, none_on_fail=False, cursor_pos=-1): """ Examples ======== All of the following give help on np.ones using the %python magic: %help %python np.ones %python np.ones? To get help on a magic itself, we would write one of the following: %python? %help %python ?%python """ text = self._prep_text(text) if not text: return self.kernel.get_usage() info = self.kernel.parse_code(text, cursor_end=cursor_pos) if info['magic']: minfo = info['magic'] errmsg = "No such %s magic '%s'" % (minfo['type'], minfo['name']) if minfo['type'] == 'line': magic = self.kernel.line_magics.get(minfo['name'], None) if minfo['args']: info = self.kernel.parse_code(minfo['args']) elif magic: return magic.get_help(minfo['type'], minfo['name'], level) else: magic = self.kernel.cell_magics.get(minfo['name'], None) if minfo['code']: info = self.kernel.parse_code(minfo['code']) elif minfo['args']: info = self.kernel.parse_code(minfo['args']) elif magic: return magic.get_help(minfo['type'], minfo['name'], level) else: return ("No such %s magic named '%s', so can't really help with that" % (minfo["type"], minfo["name"])) if magic: the_help = magic.get_help_on(info, level) self.kernel.log.error('got') self.kernel.log.error(the_help) return the_help elif not info['magic']['name']: return self.kernel.get_usage() else: return errmsg else: return self.kernel.get_kernel_help_on(info, level, none_on_fail) def _prep_text(self, text): text = text.strip() magic = self.kernel.magic_prefixes['magic'] prefix = self.kernel.magic_prefixes['help'] suffix = self.kernel.help_suffix text = text.replace('{0}{0}help'.format(magic), '') text = text.replace('{0}help'.format(magic), '') if prefix: while text.startswith(prefix): text = text[1:] if suffix: while text.endswith(suffix): text = text[:-1] return text def register_magics(kernel): kernel.register_magics(HelpMagic) metakernel-0.29.4/metakernel/magics/html_magic.py000066400000000000000000000016751434565236000220260ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic from IPython.display import HTML class HTMLMagic(Magic): def line_html(self, code): """ %html CODE - display code as HTML This line magic will send the CODE to the browser as HTML. Example: %html This is underlined! """ html = HTML(code) self.kernel.Display(html) def cell_html(self): """ %%html - display contents of cell as HTML This cell magic will send the cell to the browser as HTML. Example: %%html
Contents of div tag
""" html = HTML(self.code) self.kernel.Display(html) self.evaluate = False def register_magics(kernel): kernel.register_magics(HTMLMagic) metakernel-0.29.4/metakernel/magics/include_magic.py000066400000000000000000000031121434565236000224710ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option import os class IncludeMagic(Magic): def line_include(self, filenames): """ %include FILENAME ... - include code from filename into this code This line magic will get the contents of a file and include it in this cell evaluation. You can have multiple %include's at the beginning of a cell, and they will be included in order. Examples: %include myprog.py %include myprog1.py myprog2.py """ text = "" filenames = filenames.split() prefix = self.kernel.magic_prefixes['magic'] for filename in filenames: if filename.startswith("~"): filename = os.path.expanduser(filename) filename = os.path.abspath(filename) with open(filename) as f: text += f.read() + "\n" if self.code.lstrip().startswith(prefix): lines = self.code.lstrip().split("\n") new_lines = [] need_to_insert = True for line in lines: if need_to_insert and not line.startswith(prefix): new_lines.append(text) need_to_insert = False new_lines.append(line) if need_to_insert: new_lines.append(text) self.code = "\n".join(new_lines) else: self.code = text + self.code def register_magics(kernel): kernel.register_magics(IncludeMagic) metakernel-0.29.4/metakernel/magics/install_magic.py000066400000000000000000000045501434565236000225230ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option import os class InstallMagic(Magic): def line_install(self, package): """ %install PACKAGE - install package Example: %install calico-spell-check """ ## FIXME: get list of known extension names and locations from wiki if package == "calico-publish": self.kernel.do_execute("!ipython install-nbextension https://bitbucket.org/ipre/calico/raw/master/notebooks/nbextensions/calico-publish.js") elif package == "calico-spell-check": self.kernel.do_execute("!ipython install-nbextension https://bitbucket.org/ipre/calico/downloads/calico-spell-check-1.0.zip") elif package == "calico-cell-tools": self.kernel.do_execute("!ipython install-nbextension https://bitbucket.org/ipre/calico/downloads/calico-cell-tools-1.0.zip") elif package == "calico-document-tools": self.kernel.do_execute("!ipython install-nbextension https://bitbucket.org/ipre/calico/downloads/calico-document-tools-1.0.zip") self.enable_extension(package) # FIXME: related %config: ## // To turn off automatically creating closing parenthesis and bracket: ## IPython.CodeCell.options_default.cm_config["autoCloseBrackets"] = ""; def enable_extension(self, name): filename = "~/.ipython/profile_default/static/custom/custom.js" if filename.startswith("~"): filename = os.path.expanduser(filename) filename = os.path.abspath(filename) text = open(filename).read() if ('IPython.load_extensions("%s");' % name) in text: return if "// INSTALL MAGIC" not in text: text += """ require(["base/js/events"], function (events) { events.on("app_initialized.NotebookApp", function () { // INSTALL MAGIC // To turn off automatically creating closing parenthesis and bracket: IPython.CodeCell.options_default.cm_config["autoCloseBrackets"] = ""; }); }); """ text = text.replace(" // INSTALL MAGIC", ' IPython.load_extensions("%s");\n // INSTALL MAGIC' % name) with open(filename, "w") as fp: fp.write(text) def register_magics(kernel): kernel.register_magics(InstallMagic) metakernel-0.29.4/metakernel/magics/install_magic_magic.py000066400000000000000000000026441434565236000236650ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic import urllib try: import urlparse except ImportError: from urllib import parse as urlparse import os try: urllib.URLopener def download(url, filename): opener = urllib.URLopener() opener.retrieve(url, filename) except: # python3 def download(url, filename): g = urllib.request.urlopen(url) with open(filename, 'wb') as f: f.write(g.read()) class InstallMagicMagic(Magic): def line_install_magic(self, url): """ %install_magic URL - download and install magic from URL This line magic will copy the file at the URL into your personal magic folder. Example: %install_magic http://path/to/some/magic.py """ parts = urlparse.urlsplit(url) #('http', 'example.com', '/somefile.zip', '', '') path = parts[2] filename = os.path.basename(path) magic_filename = os.path.join(self.kernel.get_local_magics_dir(), filename) try: download(url, magic_filename) self.kernel.Print("Downloaded '%s'." % magic_filename) self.code = "%reload_magics\n" + self.code except Exception as e: self.kernel.Error(str(e)) def register_magics(kernel): kernel.register_magics(InstallMagicMagic) metakernel-0.29.4/metakernel/magics/javascript_magic.py000066400000000000000000000021241434565236000232160ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic from IPython.display import Javascript class JavascriptMagic(Magic): def line_javascript(self, code): """ %javascript CODE - send code as JavaScript This line magic will execute the CODE on the line as JavaScript in the browser. Example: %javascript console.log("Print in the browser console") """ jscode = Javascript(code) self.kernel.Display(jscode) def cell_javascript(self): """ %%javascript - send contents of cell as JavaScript This cell magic will execute the contents of the cell as JavaScript in the browser. Example: %%javascript element.html("Hello this is bold!") """ if self.code.strip(): jscode = Javascript(self.code) self.kernel.Display(jscode) self.evaluate = False def register_magics(kernel): kernel.register_magics(JavascriptMagic) metakernel-0.29.4/metakernel/magics/jigsaw_magic.py000066400000000000000000000202551434565236000223410ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option from IPython.display import IFrame, Javascript import string import random import os try: import urllib.request urlopen = urllib.request.urlopen except: # python2 import urllib urlopen = urllib.urlopen def download(url): g = urlopen(url) return g.read().decode("utf-8") class JigsawMagic(Magic): @option( '-w', '--workspace', action='store', default=None, help='use the provided name as workspace filename' ) @option( '-h', '--height', action='store', default=350, help='set height of iframe ' ) def line_jigsaw(self, language, workspace=None, height=350): """ %jigsaw LANGUAGE - show visual code editor/generator This line magic will allow visual code editing or generation. Examples: %jigsaw Processing %jigsaw Python %jigsaw Processing --workspace workspace1 --height 600 """ # Copy iframe html to here (must come from same domain): # Make up a random workspace name: if workspace is None: workspace = "jigsaw-workspace-" + (''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for i in range(6))) workspace_filename = workspace + ".xml" html_text = download("https://calysto.github.io/jigsaw/" + language + ".html") html_filename = workspace + ".html" html_text = html_text.replace("MYWORKSPACENAME", workspace_filename) with open(html_filename, "w") as fp: fp.write(html_text) # Display iframe: script = """ if (document.jigsaw_register_workspace === undefined) { document.jigsaw_workspaces = {}; document.jigsaw_register_workspace = function(workspace_filename, workspace, xml_init) { workspace.element = document.element; document.jigsaw_workspaces[workspace_filename] = workspace; try { $([window.parent.IPython.events]).on('notebook_saved.Notebook', function() { try { document.jigsaw_save_workspace(workspace_filename); } catch(err) { // ignore failure, might not exist } }); } catch (err) { // rendering for display } var xml = document.jigsaw_loadXMLDoc(workspace_filename); if (xml === null) { xml = xml_init; if (xml === null) { xml = Blockly.Xml.textToDom(''); } } else { xml = xml.children[0]; // document } Blockly.Xml.domToWorkspace(workspace, xml); }; document.jigsaw_handle_output = function(workspace_filename, out) { var workspace = document.jigsaw_workspaces[workspace_filename]; //var output_area = workspace.element.output_area; var cell_index = document.jigsaw_get_cell(workspace.element); var cell = IPython.notebook.get_cell(cell_index); var res = null; var data = null; document.cell = cell; document.out = out; if (out.msg_type == "stream") { res = out.content.text; //document.getElementById('code_output').value += res.toString(); } else if (out.msg_type === "pyout") { // if output is a python object res = out.content.data["text/plain"]; //document.getElementById('code_output').value += res.toString(); } else if (out.msg_type == "pyerr") { // if output is a python error res = out.content.data["text/plain"]; //document.getElementById('code_output').value += res.toString(); } else if (out.msg_type == "execute_result") { var str = out.content.data["text/plain"]; res = str; if (res.indexOf("u") == 0) res = res.substring(2, res.length - 1) + "\\n"; if (res) { //document.getElementById('code_output').value += res.toString(); } } else if (out.msg_type == "error") { res = out.content.ename + ": " + out.content.evalue + "\\n"; // FIXME: out.traceback is Array of terminal color-coded [-codes } else { // if output is something we haven't thought of res = out.toString(); //document.getElementById('code_output').value += res.toString(); } if (res) { cell.output_area.append_output({output_type: "stream", text: res.toString(), name: "output"}); } }; document.jigsaw_generate = function(workspace_filename, language, insert_code) { var workspace = document.jigsaw_workspaces[workspace_filename]; var callbacks = { 'iopub' : {'output' : function(out) { document.jigsaw_handle_output(workspace_filename, out); }}}; var code = Blockly[language].workspaceToCode(workspace); if (insert_code == 1) { var cell_index = document.jigsaw_get_cell(workspace.element); var cell = IPython.notebook.insert_cell_at_index(0, cell_index + 1); cell.set_text(code); } else { window.parent.IPython.notebook.kernel.execute(code, callbacks, {silent: false}); } }; document.jigsaw_save_workspace = function(workspace_filename) { var workspace = document.jigsaw_workspaces[workspace_filename]; var xml = Blockly.Xml.workspaceToDom(workspace); document.xml = xml; if (xml !== undefined) { console.log(xml); //xml.style = "display: none"; //xml.id = "workspace"; var xml_text = Blockly.Xml.domToText(xml) IPython.notebook.kernel.execute('%%file ' + workspace_filename + '\\n' + xml_text); } }; document.jigsaw_loadXMLDoc = function(filename) { var xhttp = new XMLHttpRequest(); xhttp.open("GET", filename, false); xhttp.send(); return xhttp.responseXML; }; } document.jigsaw_get_cell = function (element) { // FIXME: brittle and ugly: var mydiv = element[0].parentNode.parentNode.parentNode.parentNode; var cells = IPython.notebook.get_cells(); for (var i = 0; i < cells.length; i++) { if (mydiv === cells[i].element[0]) { return i; } } return null; }; document.jigsaw_clear_output = function (workspace_filename) { var workspace = document.jigsaw_workspaces[workspace_filename]; var cell_index = document.jigsaw_get_cell(workspace.element); var cell = IPython.notebook.get_cell(cell_index); // FIXME: brittle and ugly: cell.element[0].children[2].children[1].children[2].children[1].children[0].innerHTML = "" cell.output_area.outputs[2].text = "" }; try { document.element = element; } catch (err) { // rendering } """ script = script.replace("MYWORKSPACENAME", workspace_filename); self.kernel.Display(Javascript(script)) self.kernel.Display(IFrame(html_filename, width='100%', height=height)) def register_magics(kernel): kernel.register_magics(JigsawMagic) def register_ipython_magics(): from metakernel import IPythonKernel from IPython.core.magic import register_line_magic kernel = IPythonKernel() magic = JigsawMagic(kernel) # Make magics callable: kernel.line_magics["jigsaw"] = magic @register_line_magic def jigsaw(line): """ Use the Jigsaw code visualizer and generator. """ kernel.call_magic("%jigsaw " + line) metakernel-0.29.4/metakernel/magics/kernel_magic.py000066400000000000000000000074271434565236000223430ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option import importlib import logging class KernelMagic(Magic): kernels = {} kernel_name = None @option( '-k', '--kernel_name', action='store', default="default", help='kernel name given to use for execution' ) def line_kernel(self, module_name, class_name, kernel_name="default"): """ %kernel MODULE CLASS [-k NAME] - construct a kernel for sending code. This line magic will construct a kernel language so that you can communicate. Example: %kernel bash_kernel BashKernel -k bash Use `%kx` or `%%kx` to send code to the kernel. Also returns the kernel as output. """ self.kernel_name = kernel_name module = importlib.import_module(module_name) class_ = getattr(module, class_name) kernel = class_() self.kernel.makeSubkernel(self.kernel) kernel.makeSubkernel(self.kernel) self.kernels[kernel_name] = kernel self.kernels[kernel_name].kernel = self.kernel self.retval = self.kernels[kernel_name] @option( '-k', '--kernel_name', action='store', default=None, help='kernel name given to use for execution' ) def cell_kx(self, kernel_name=None): """ %%kx [-k NAME] - send the cell code to the kernel. This cell magic will send the cell to be evaluated by the kernel. The kernel must have been created use the %%kernel magic. Returns the result of the execution as output. Example: %%kernel bash ls -al Use `%kernel MODULE CLASS [-k NAME]` to create a kernel. """ if kernel_name is None: kernel_name = self.kernel_name self.retval = self.kernels[kernel_name].do_execute_direct(self.code) self.evaluate = False @option( '-k', '--kernel_name', action='store', default=None, help='kernel name given to use for execution' ) def line_kx(self, code, kernel_name=None): """ %kx CODE [-k NAME] - send the code to the kernel. This line magic will send the CODE to the kernel for execution. Returns the result of the execution as output. Example: %kernel ls -al Use `%kernel MODULE CLASS [-k NAME]` to create a kernel. """ if kernel_name is None: kernel_name = self.kernel_name # make sure the code is sent as a string for execution code = str(code) self.retval = self.kernels[kernel_name].do_execute_direct(code) def post_process(self, retval): return self.retval def register_magics(kernel): kernel.register_magics(KernelMagic) def register_ipython_magics(): from metakernel import IPythonKernel from IPython.core.magic import register_line_magic, register_cell_magic kernel = IPythonKernel() magic = KernelMagic(kernel) @register_line_magic def kernel(line): """ line is module_name, class_name[, kernel_name] """ if line.strip().count(" ") == 1: kernel_name = "default" module_name, class_name = [item.strip() for item in line.strip().split(" ", 1)] else: module_name, class_name, kernel_name = [item.strip() for item in line.strip().split(" ", 2)] magic.line_kernel(module_name, class_name, kernel_name) @register_cell_magic def kx(line, cell): """ line is kernel_name, or "default" """ if line.strip(): module_name = line.strip() else: module_name = "default" magic.code = cell magic.cell_kx(module_name) metakernel-0.29.4/metakernel/magics/latex_magic.py000066400000000000000000000016421434565236000221710ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic from IPython.display import Latex class LatexMagic(Magic): def line_latex(self, text): r""" %latex TEXT - display text as LaTeX This line magic will display the TEXT on the line as LaTeX. Example: %latex $x_1 = \dfrac{a}{b}$ """ latex = Latex(text) self.kernel.Display(latex) def cell_latex(self): r""" %%latex - display contents of cell as LaTeX This cell magic will display the TEXT in the cell as LaTeX. Example: %%latex $x_1 = \dfrac{a}{b}$ $x_2 = a^{n - 1}$ """ latex = Latex(self.code) self.kernel.Display(latex) self.evaluate = False def register_magics(kernel): kernel.register_magics(LatexMagic) metakernel-0.29.4/metakernel/magics/load_magic.py000066400000000000000000000014501434565236000217700ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option import os class LoadMagic(Magic): def line_load(self, filename): """ %load FILENAME - load code from filename into next cell This line magic will get the contents of a file and load it into the next cell. Example: %load myprog.py """ if filename.startswith("~"): filename = os.path.expanduser(filename) filename = os.path.abspath(filename) with open(filename) as f: self.kernel.payload.append({"source": "set_next_input", "text": f.read()}) def register_magics(kernel): kernel.register_magics(LoadMagic) metakernel-0.29.4/metakernel/magics/ls_magic.py000066400000000000000000000015011434565236000214640ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from IPython.display import FileLinks from metakernel import Magic, option import os class LSMagic(Magic): @option( "-r", "--recursive", action="store_true", default=False, help='recursively descend into subdirectories' ) def line_ls(self, path=".", recursive=False): """ %ls PATH - list files and directories under PATH This line magic is used to list the directory contents. Examples: %ls . %ls .. """ path = os.path.expanduser(path) self.retval = FileLinks(path, recursive=recursive) def post_process(self, retval): return self.retval def register_magics(kernel): kernel.register_magics(LSMagic) metakernel-0.29.4/metakernel/magics/lsmagic_magic.py000066400000000000000000000021451434565236000224720ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from IPython.core.magic import magic_escapes from metakernel import Magic import os class LSMagicMagic(Magic): def line_lsmagic(self): """ %lsmagic - list the current line and cell magics This line magic will list all of the available cell and line magics installed in the system and in your personal magic folder. Example: %lsmagic """ mesc = magic_escapes['line'] cesc = magic_escapes['cell'] line_magics = self.kernel.line_magics.keys() cell_magics = self.kernel.cell_magics.keys() mp = self.kernel.magic_prefixes['magic'] out = [ 'Available line magics:', ' '.join(sorted([(mp + lm) for lm in line_magics])), '', 'Available cell magics:', ' '.join(sorted([(mp + mp + cm) for cm in cell_magics])), ] self.kernel.Print('\n'.join(out)) def register_magics(kernel): kernel.register_magics(LSMagicMagic) metakernel-0.29.4/metakernel/magics/macro_magic.py000066400000000000000000000111361434565236000221540ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option import inspect import ast import os class MacroMagic(Magic): macros = {"renumber-cells": """%%javascript var cells = IPython.notebook.get_cells(); // We only keep the code cells. cells = cells.filter(function(c) { return c instanceof IPython.CodeCell; }) // We set the input prompt of all code cells. for (var i = 0; i < cells.length; i++) { cells[i].set_input_prompt(i + 1); } """} def __init__(self, *args, **kwargs): super(MacroMagic, self).__init__(*args, **kwargs) self._load_macros() @option( '-d', '--delete', action='store_true', default=False, help='delete a named macro' ) @option( '-l', '--list', action='store_true', default=False, help='list macros' ) @option( '-s', '--show', action='store_true', default=False, help='show macro' ) def line_macro(self, name, delete=False, list=False, show=False): """ %macro NAME - execute a macro %macro -l [all|learned|system] - list macros %macro [-s] [-d] NAME - show or delete a macro This line macro will execute, show, list, or delete the named macro. Examples: %macro renumber-cells %%macro test print "Ok!" %macro -l all %macro -d test """ if list: self._list_macros(name) elif show: retval = "%%%%macro %s\n" % name if name in self.macros: retval += self.macros[name] elif name in self.learned: retval += self.learned[name] self.kernel.Print(retval) elif name in self.learned: if delete: del self.learned[name] self._save_macros() else: self.code = self.code.strip() if self.code: self.code += "\n" self.code += self.learned[name] elif name in self.macros: if delete: raise Exception("Can't delete system macro") else: self.code = self.code.strip() if self.code: self.code += "\n" self.code += self.macros[name] elif name == "": self._list_macros() else: self._list_macros(retval="No such macro: '%s'\n\n" % name, error=True) self.evaluate = True def _list_macros(self, name="all", retval="", error=False): retval += "Available macros:\n" if name in ["all", "system"]: retval += " System:\n" for macro in sorted(self.macros.keys()): retval += " %s\n" % macro if name in ["all", "learned"]: retval += " Learned:\n" for macro in sorted(self.learned.keys()): retval += " %s\n" % macro if error: self.kernel.Error(retval) else: self.kernel.Print(retval) def _load_macros(self): self.learned = {} local_macros_dir = self.kernel.get_local_magics_dir() # Search all of the places there could be macros: files = [os.path.join(os.path.dirname(os.path.abspath(__file__)), "macros.json"), os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(self.__class__))), "macros.json"), os.path.join(local_macros_dir, "macros.json")] for macro_file in files: try: with open(macro_file) as mf: data = ast.literal_eval(mf.read()) except: continue self.learned.update(data) def _save_macros(self): local_macros_dir = self.kernel.get_local_magics_dir() filename = os.path.join(local_macros_dir, "macros.json") with open(filename, "w") as macros: macros.write(str(self.learned)) def cell_macro(self, name): """ %%macro NAME - learn a new macro This cell macro will learn the macro in the cell. The cell contents are just commands (macros or code in the kernel language). Example: %%macro test print "Ok!" %macro test Ok! """ self.learned[name] = self.code self._save_macros() self.evaluate = False def register_magics(kernel): kernel.register_magics(MacroMagic) metakernel-0.29.4/metakernel/magics/magic_magic.py000066400000000000000000000063121434565236000221330ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic class MagicMagic(Magic): def line_magic(self, line): """ %magic - show installed magics This line magic shows all of the install magics, either from the system magic folder, or your own private magic folder. """ line_magics = [] cell_magics = [] for (name, magic) in self.kernel.line_magics.items(): line_magics.append(magic.get_help('line', name).split("\n")[0]) for (name, magic) in self.kernel.cell_magics.items(): cell_magics.append(magic.get_help('cell', name).split("\n")[0]) prefixes = self.kernel.magic_prefixes line_magics = ("\n ".join(sorted(line_magics))) line_magics = line_magics.replace('%', prefixes['magic']) cell_magics = ("\n ".join(sorted(cell_magics))) cell_magics = cell_magics.replace('%', prefixes['magic']) self.kernel.Print("Line magics:") self.kernel.Print(" " + line_magics) self.kernel.Print("") self.kernel.Print("Cell magics:") self.kernel.Print(" " + cell_magics) self.kernel.Print("") self.kernel.Print("Shell shortcut:") self.kernel.Print(" %s COMMAND ... - execute command in shell" % prefixes['shell']) self.kernel.Print("") self.kernel.Print( "Any cell magic can be made persistent for rest of session by using {0}{0}{0} prefix.".format(prefixes['magic'])) self.kernel.Print("") self.kernel.Print("Help on items:") for string in self.kernel.line_magics['help'].help_strings(): self.kernel.Print(" " + string) self.kernel.Print("") def get_magic(self, info, get_args=False): if not info['magic']: return None minfo = info['magic'] name = minfo['name'] if minfo['type'] == 'sticky': sname = (self.kernel.magic_prefixes['magic'] * 2) + name if sname in self.kernel.sticky_magics: del self.kernel.sticky_magics[sname] self.kernel.Print("%s removed from session magics.\n" % sname) # dummy magic to eat this line and continue: return Magic(self.kernel) else: self.kernel.sticky_magics[sname] = minfo['args'] self.kernel.Print("%s added to session magics.\n" % name) cell_magics = self.kernel.cell_magics line_magics = self.kernel.line_magics if minfo['type'] in ['cell', 'sticky'] and name in cell_magics.keys(): magic = cell_magics[name] elif minfo['type'] == 'line' and name in line_magics.keys(): magic = line_magics[name] else: # FIXME: Raise an error return None if get_args: return magic.get_args(minfo['type'], minfo['name'], minfo['code'], minfo['args']) else: return magic.call_magic(minfo['type'], minfo['name'], minfo['code'], minfo['args']) def register_magics(kernel): kernel.register_magics(MagicMagic) metakernel-0.29.4/metakernel/magics/matplotlib_magic.py000066400000000000000000000025631434565236000232260ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option class MatplotlibMagic(Magic): """ Magic for using matplotlib with kernels other than ipython. """ def line_matplotlib(self, backend): """ %matplotlib BACKEND - set the matplotlib backend to BACKEND This line magic will set (and reload) the items associated with the matplotlib backend. Also, monkeypatches the IPython.display.display to work with metakernel-based kernels. Example: %matplotlib notebook import matplotlib.pyplot as plt plt.plot([3, 8, 2, 5, 1]) plt.show() """ import IPython.display import metakernel.display import imp # Monkeypatch IPython.display.display: IPython.display.display = metakernel.display.display import matplotlib imp.reload(matplotlib) if backend == "notebook": backend = "nbagg" matplotlib.use(backend) import matplotlib.backends.backend_nbagg imp.reload(matplotlib.backends.backend_nbagg) import matplotlib.backends.backend_webagg_core imp.reload(matplotlib.backends.backend_webagg_core) def register_magics(kernel): kernel.register_magics(MatplotlibMagic) metakernel-0.29.4/metakernel/magics/parallel_magic.py000066400000000000000000000255641434565236000226610ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option import logging import time class Slice(object): """Utility class for making slice ranges.""" def __getitem__(self, item): return item slicer = Slice() ## instance to parse slices class ParallelMagic(Magic): client = None view = None view_load_balanced = None module_name = None class_name = None kernel_name = None ids = None retval = None retry = False @option( '-k', '--kernel_name', action='store', default="default", help='arbitrary name given to reference kernel' ) @option( '-i', '--ids', action='store', default=None, help='the machine ids to use from the cluster' ) def line_parallel(self, module_name, class_name, kernel_name="default", ids=None): """ %parallel MODULE CLASS [-k NAME] [-i [...]] - construct an interface to the cluster. Example: %parallel bash_kernel BashKernel %parallel bash_kernel BashKernel -k bash %parallel bash_kernel BashKernel -i [0,2:5,9,...] cluster_size and cluster_rank variables are set upon initialization of the remote node (if the kernel supports %set). Use %px or %%px to send code to the cluster. """ from ipyparallel import Client count = 1 while count <= 5: try: self.client = Client() break except: print("Waiting on cluster to start...") time.sleep(2) count += 1 if count == 6: raise Exception("Cluster was not started.") if ids is None: count = 1 while count <= 5: try: self.view = self.client[:] break except: print("Waiting for engines...") time.sleep(2) count += 1 if count == 6: raise Exception("Engines were not started.") else: # ids[:] = slice(None, None, None) # ids[1:3] = slice(1, 3, None) # ids[1:3:1] = slice(1, 3, 1) # ids[1, 2, ...] = [1, 2, Ellipsis] # ids[1, 2:4, ...] = [1, slice(2, 4, None), Ellipsis] try: ids_slice = eval("slicer%s" % ids) # slicer[0,...,7] except: ids_slice = slicer[:] if isinstance(ids_slice, (slice, int)): count = 1 while count <= 5: try: self.view = self.client[ids_slice] break except: print("Waiting for engines...") time.sleep(2) count += 1 if count == 6: raise Exception("Engines were not started.") else: # tuple of indexes/slices # FIXME: if so, handle Ellipsis view = None for item in ids_slice: count = 1 while count <= 5: try: client = self.client[item] if view: ## FIXME: can't do this: view.append(client) else: view = client break except: print("Waiting on cluster to start...") time.sleep(2) count += 1 if count == 6: raise Exception("Cluster was not started.") self.view = view self.view_load_balanced = self.client.load_balanced_view() self.module_name = module_name self.class_name = class_name self.kernel_name = kernel_name self.view.execute(""" import os for key, value in %(env)s.items(): os.environ[key] = value try: kernels except: kernels = {} from %(module_name)s import %(class_name)s kernels['%(kernel_name)s'] = %(class_name)s() ## FIXME: kernels['%(kernel_name)s'].kernel = kernel """ % {"module_name": module_name, "class_name": class_name, "kernel_name": kernel_name, "env": str(self.kernel.env)}, block=True) self.view["kernels['%s'].set_variable(\"cluster_size\", %s)" % ( kernel_name, len(self.client))] self.client[:].scatter('cluster_rank', self.client.ids, flatten=True) self.view["kernels['%s'].set_variable(\"cluster_rank\", cluster_rank)" % ( kernel_name)] ## So that these are available in the host kernel: self.kernel.set_variable("cluster_size", len(self.client)) self.kernel.set_variable("cluster_rank", -1) self.retval = None @option( '-k', '--kernel_name', action='store', default=None, help='kernel name given to use for execution' ) @option( '-e', '--evaluate', action='store_true', default=False, help=('evaluate code in the current kernel, too. The current ' + 'kernel should be of the same language as the cluster.') ) @option( '-s', '--set_variable', action='store', default=None, help='set the variable with the parallel results rather than returning them' ) def line_px(self, expression, kernel_name=None, evaluate=False, set_variable=None): """ %px EXPRESSION - send EXPRESSION to the cluster. Example: %px sys.version %px -k scheme (define x 42) %px x %px cluster_rank cluster_size and cluster_rank variables are set upon initialization of the remote node (if the kernel supports %set). Use %parallel to initialize the cluster. """ results = None expression = str(expression) if kernel_name is None: kernel_name = self.kernel_name if self.retry: count = 1 while count <= 5: try: results = self.view["kernels['%s'].do_execute_direct(\"%s\")" % ( kernel_name, self._clean_code(expression))] break except: print("Waiting on cluster clients to start...") time.sleep(2) count += 1 if count == 6: raise Exception("Cluster clients have not started.") self.retry = False else: try: results = self.view["kernels['%s'].do_execute_direct(\"%s\")" % ( kernel_name, self._clean_code(expression))] except Exception as e: results = str(e) if set_variable is None: self.retval = results else: self.kernel.set_variable(set_variable, results) self.retval = None if evaluate: self.code = expression def _clean_code(self, expr): return expr.strip().replace('"', '\\"').replace("\n", "\\n") ## px --kernel NAME @option( '-k', '--kernel_name', action='store', default=None, help='kernel name given to use for execution' ) @option( '-e', '--evaluate', action='store_true', default=False, help=('evaluate code in the current kernel, too. The current ' + 'kernel should be of the same language as the cluster.') ) @option( '-s', '--set_variable', action='store', default=None, help='set the variable with the parallel results rather than returning them' ) def cell_px(self, kernel_name=None, evaluate=False, set_variable=None): """ %%px - send cell to the cluster. Example: %%px (define x 42) Use %parallel to initialize the cluster. """ if kernel_name is None: kernel_name = self.kernel_name results = self.view["kernels['%s'].do_execute_direct(\"%s\")" % ( kernel_name, self._clean_code(self.code))] if set_variable is None: self.retval = results else: self.kernel.set_variable(set_variable, results) self.retval = None self.evaluate = evaluate @option( '-s', '--set_variable', action='store', default=None, help='set the variable with the parallel results rather than returning them' ) def line_pmap(self, function_name, args, kernel_name=None, set_variable=None): """ %pmap FUNCTION [ARGS1,ARGS2,...] - ("parallel map") call a FUNCTION on args This line magic will apply a function name to all of the arguments given one at a time using a dynamic load balancing scheduler. Currently, the args are provided as a Python expression (with no spaces). You must first setup a cluster using the %parallel magic. Examples: %pmap function-name-in-language range(10) %pmap function-name-in-language [1,2,3,4] %pmap run_experiment range(1,100,5) %pmap run_experiment ["test1","test2","test3"] %pmap f [(1,4,7),(2,3,5),(7,2,2)] The function name must be a function that is available on all nodes in the cluster. For example, you could: %%px (define myfunc (lambda (n) (+ n 1))) to define myfunc on all machines (use %%px -e to also define it in the running notebook or console). Then you can apply it to a list of arguments: %%pmap myfunc range(100) The load balancer will run myfunc on the next available node in the cluster. Note: not all languages may support running a function via this magic. """ if kernel_name is None: kernel_name = self.kernel_name # To make sure we can find `kernels`: try: from ipyparallel.util import interactive except ImportError: from IPython.parallel.util import interactive f = interactive(lambda arg, kname=kernel_name, fname=function_name: \ kernels[kname].do_function_direct(fname, arg)) results = self.view_load_balanced.map_async(f, eval(args)) if set_variable is None: self.retval = results else: self.kernel.set_variable(set_variable, results) self.retval = None def post_process(self, retval): try: ## any will crash on numpy arrays if isinstance(self.retval, list) and not any(self.retval): return None except: pass return self.retval def register_magics(kernel): kernel.register_magics(ParallelMagic) metakernel-0.29.4/metakernel/magics/pipe_magic.py000066400000000000000000000031131434565236000220040ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option class PipeMagic(Magic): def __init__(self, *args, **kwargs): super(PipeMagic, self).__init__(*args, **kwargs) def cell_pipe(self, pipe_str): """ %%pipe FUNCTION1 | FUNCTION2 ... The pipe cell will "pipe" the contents of a cell through a series of function calls. All of the functions must be defined in the language, and the kernel must support the `do_function_direct` method. Example: %%pipe f1 | f2 | f3 CELL CONTENTS is the same as issuing: f3(f2(f1("CELL CONTENTS"))) """ functions = [function.strip() for function in pipe_str.split("|")] self.retval = self.code for function in functions: self.retval = self.kernel.do_function_direct(function, self.retval) self.evaluate = False def post_process(self, retval): return self.retval def register_magics(kernel): kernel.register_magics(PipeMagic) def register_ipython_magics(): from IPython.core.magic import register_cell_magic from IPython import get_ipython @register_cell_magic def pipe(line, cell): """ """ ip = get_ipython() functions = [function.strip() for function in line.split("|")] retval = cell for function in functions: f = eval(function, ip.ns_table["user_global"]) retval = f(retval) return retval metakernel-0.29.4/metakernel/magics/plot_magic.py000066400000000000000000000035111434565236000220270ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option class PlotMagic(Magic): @option( '-s', '--size', action='store', help='Pixel size of plots, "width,height"' ) @option( '-f', '--format', action='store', help='Plot format (png, svg or jpg).' ) @option( '-b', '--backend', action='store', default='inline', help='Backend selection' ) @option( '-r', '--resolution', action='store', help='Resolution in pixels per inch' ) @option( '-w', '--width', action='store', help='Plot width in pixels' ) @option( '-h', '--height', action='store', help='Plot height in pixels' ) def line_plot(self, *args, **kwargs): """ %plot [options] backend - configure plotting for the session. This line magic will configure the plot settings for this language. Examples: %plot qt --format=png %plot inline -w 640 Note: not all languages may support the %plot magic, and not all options may be supported. """ if args and not args[0].startswith('-'): kwargs['backend'] = args[0] if 'size' in kwargs and kwargs['size'] is not None: width, height = kwargs['size'] kwargs['width'] = int(width) kwargs['height'] = int(height) # Remove empty options so ".setdefault" will work. for key in ['resolution', 'format', 'size', 'width', 'height']: if key in kwargs and kwargs[key] is None: del kwargs[key] self.kernel.plot_settings = kwargs self.kernel.handle_plot_settings() def register_magics(kernel): kernel.register_magics(PlotMagic) metakernel-0.29.4/metakernel/magics/processing_magic.py000066400000000000000000000033331434565236000232270ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic from IPython.display import HTML class ProcessingMagic(Magic): canvas_id = 0 def cell_processing(self, dummy=None): """ %%processing - run the cell in the language Processing This cell magic will execute the contents of the cell as a Processing program. This uses the Java-based Processing language. Example: %%processing setup() { } draw() { } """ self.canvas_id += 1 """%%processing - run contents of cell as a Processing script""" repr_code = repr(self.code) if repr_code.startswith('u'): repr_code = repr_code[1:] env = {"code": repr_code, "id": self.canvas_id} code = """ """ % env html = HTML(code) self.kernel.Display(html) self.evaluate = False def register_magics(kernel): kernel.register_magics(ProcessingMagic) def register_ipython_magics(): from metakernel import IPythonKernel from IPython.core.magic import register_cell_magic kernel = IPythonKernel() magic = ProcessingMagic(kernel) @register_cell_magic def processing(line, cell): """ """ magic.code = cell magic.cell_processing() metakernel-0.29.4/metakernel/magics/python_magic.py000066400000000000000000000137701434565236000224020ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option, ExceptionWrapper import pydoc import sys import ast import jedi from jedi import Interpreter from jedi.api.helpers import get_on_completion_name from parso import split_lines def exec_then_eval(code, env): import traceback try: block = ast.parse(code, mode="exec") last = block.body.pop() if type(last) != ast.Expr: block.body.append(last) retval = exec(compile(block, "python cell", mode="exec"), env) else: exec(compile(block, "python cell", mode="exec"), env) retval = eval(compile(ast.Expression(last.value), "python cell", mode="eval"), env) if "retval" in env and env["retval"] is not None: return env['retval'] else: return retval except Exception as exc: ex_type, ex, tb = sys.exc_info() line1 = ["Traceback (most recent call last):"] line2 = ["%s: %s" % (ex.__class__.__name__, str(ex))] tb_format = line1 + [line.rstrip() for line in traceback.format_tb(tb)[1:]] + line2 return ExceptionWrapper(ex_type.__name__, repr(exc.args), tb_format) class PythonMagic(Magic): def __init__(self, kernel): super(PythonMagic, self).__init__(kernel) self.env = globals()['__builtins__'].copy() self.retval = None def line_python(self, *args): """ %python CODE - evaluate code as Python This line magic will evaluate the CODE (either expression or statement) as Python code. Note that the version of Python is that of the notebook server. Examples: %python x = 42 %python import math %python x + math.pi """ code = " ".join(args) self.retval = self.eval(code) self.env["retval"] = None def eval(self, code): import IPython.display import metakernel.display # monkey patch IPython.display.display # to redirect notebook display calls to kernel display IPython.display.display = metakernel.display.display if "__builtins__" not in self.env: ## __builtins__ get generated after an eval: eval("1", self.env) ## make 'kernel' and 'input' available: self.env["__builtins__"]["kernel"] = self.kernel self.env["__builtins__"]["input"] = self.kernel.raw_input self.env["input"] = self.kernel.raw_input return exec_then_eval(code.strip(), self.env) @option( "-e", "--eval_output", action="store_true", default=False, help="Use the retval value from the Python cell as code in the kernel language." ) def cell_python(self, eval_output=False): """ %%python - evaluate contents of cell as Python This cell magic will evaluate the cell (either expression or statement) as Python code. Unlike IPython's Python, this does not return the last expression. To do that, you need to assign the last expression to the special variable "retval". The -e or --eval_output flag signals that the retval value expression will be used as code for the cell to be evaluated by the host language. Note that the version of Python is that of the notebook server. Examples: %%python x = 42 %%python import math retval = x + math.pi %%python -e retval = "'(this is code in the kernel language)" %%python -e "'(this is code in the kernel language)" """ if self.code.strip(): if eval_output: retval = self.eval(self.code) self.code = str(self.env["retval"]) if ("retval" in self.env and self.env["retval"] != None) else retval self.retval = None self.env["retval"] = None self.evaluate = True else: self.retval = self.eval(self.code) self.env["retval"] = None self.evaluate = False def post_process(self, retval): if retval is not None: return retval else: return self.retval def get_completions(self, info): '''Get Python completions''' # https://github.com/davidhalter/jedi/blob/master/jedi/utils.py if jedi is None: return [] text = info['code'] position = (info['line_num'], info['column']) interpreter = Interpreter(text, [self.env]) lines = split_lines(text) name = get_on_completion_name( interpreter._module_node, lines, position ) before = text[:len(text) - len(name)] try: completions = interpreter.complete() except AttributeError: completions = interpreter.completions() completions = [before + c.name_with_symbols for c in completions] self.kernel.log.error(completions) return [c[info['start']:] for c in completions] def get_help_on(self, info, level=0, none_on_fail=False): """Implement basic help for functions""" if not info['code']: return None if none_on_fail else '' last = info['obj'] default = None if none_on_fail else ('No help available for "%s"' % last) parts = last.split('.') obj = self.env.get(parts[0], None) if not obj: return default for p in parts[1:]: obj = getattr(obj, p, None) if not obj: return default strhelp = pydoc.render_doc(obj, "Help on %s") if level == 0: return getattr(obj, '__doc__', strhelp) else: return strhelp def register_magics(kernel): kernel.register_magics(PythonMagic) metakernel-0.29.4/metakernel/magics/reload_magics_magic.py000066400000000000000000000013311434565236000236400ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic class ReloadMagicsMagic(Magic): def line_reload_magics(self): """ %reload_magics - reload the magics from the installed files Example: %reload_magics This line magic will reload the magics installed in the system, and in your private magic folder. You only need to do this if you edit a magic file. It runs automatically if you install a new magic. """ self.kernel.reload_magics() self.code = "%lsmagic\n" + self.code def register_magics(kernel): kernel.register_magics(ReloadMagicsMagic) metakernel-0.29.4/metakernel/magics/restart_magic.py000066400000000000000000000010331434565236000225320ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic class RestartMagic(Magic): def line_restart(self): """ %restart - restart session This line magic will restart the connection to the language kernel. Example: %restart Note that you will lose all computed values. """ self.kernel.do_shutdown(True) def register_magics(kernel): kernel.register_magics(RestartMagic) metakernel-0.29.4/metakernel/magics/run_magic.py000066400000000000000000000027621434565236000216640ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option import os class RunMagic(Magic): @option( '-l', '--language', action='store', default=None, help='use the provided language name as kernel' ) def line_run(self, filename, language=None): """ %run [--language LANG] FILENAME - run code in filename by kernel This magic will take the code in FILENAME and run it. The exact details of how the code runs are determined by your language. The --language LANG option will prefix the file contents with "%%LANG". You may also put information in the cell which will appear before the contents of the file. Examples: %run filename.ss %run -l python filename.py %kx calysto_scheme.kernel CalystoScheme %run --language kx filename.ss %run --language "kx default" filename.ss Note: not all languages may support %run. """ if filename.startswith("~"): filename = os.path.expanduser(filename) filename = os.path.abspath(filename) if language is None: self.kernel.do_execute_file(filename) else: self.code = "%%" + language + "\n" + self.code with open(filename) as f: self.code += "".join(f.readlines()) def register_magics(kernel): kernel.register_magics(RunMagic) metakernel-0.29.4/metakernel/magics/scheme_magic.py000066400000000000000000000052041434565236000223160ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option try: from calysto_scheme import scheme except: scheme = None class SchemeMagic(Magic): def __init__(self, kernel): super(SchemeMagic, self).__init__(kernel) self.retval = None def line_scheme(self, *args): """ %scheme CODE - evaluate code as Scheme This line magic will evaluate the CODE (either expression or statement) as Scheme code. Examples: %scheme (define x 42) %scheme (import "math") %scheme (+ x + math.pi) """ code = " ".join(args) self.retval = self.eval(code) def eval(self, code): if scheme: return scheme.execute_string_rm(code.strip()) else: raise Exception("calysto_scheme is required") @option( "-e", "--eval_output", action="store_true", default=False, help="Use the retval value from the Scheme cell as code in the kernel language." ) def cell_scheme(self, eval_output=False): """ %%scheme - evaluate contents of cell as Scheme This cell magic will evaluate the cell (either expression or statement) as Scheme code. The -e or --eval_output flag signals that the retval value expression will be used as code for the cell to be evaluated by the host language. Examples: %%scheme (define x 42) %%scheme (import "math") (define retval (+ x math.pi)) %%scheme -e (define retval "this = code") %%scheme -e "this = code" """ if self.code.strip(): if eval_output: self.code = self.eval(self.code) self.evaluate = True else: self.retval = self.eval(self.code) self.evaluate = False def post_process(self, retval): if retval is not None: return retval else: return self.retval def register_magics(kernel): kernel.register_magics(SchemeMagic) def register_ipython_magics(): from metakernel import IPythonKernel from IPython.core.magic import register_line_magic, register_cell_magic kernel = IPythonKernel() magic = SchemeMagic(kernel) @register_line_magic def scheme(line): magic.line_scheme(line) return magic.retval @register_cell_magic def scheme(line, cell): magic.code = cell magic.cell_scheme() return magic.retval metakernel-0.29.4/metakernel/magics/set_magic.py000066400000000000000000000012141434565236000216420ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic class SetMagic(Magic): def line_set(self, variable, value): """ %set VARIABLE VALUE - set a variable in the kernel. This line magic is used to set a variable to a Python value. Examples: %set x 42 %set x [1, 2, 3] """ value = self.kernel.do_execute_direct(value) self.kernel.set_variable(variable, value) def post_process(self, retval): return retval def register_magics(kernel): kernel.register_magics(SetMagic) metakernel-0.29.4/metakernel/magics/shell_magic.py000066400000000000000000000064721434565236000221710ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from __future__ import print_function from metakernel import Magic, pexpect from metakernel.replwrap import powershell, bash import os class ShellMagic(Magic): def __init__(self, kernel): super(ShellMagic, self).__init__(kernel) self.repl = None self.cmd = None self.start_process() def line_shell(self, *args): """ %shell COMMAND - run the line as a shell command This line command will run the COMMAND in the bash shell. Examples: %shell ls -al %shell cd Note: this is a persistent connection to a shell. The working directory is synchronized to that of the notebook before and after each call. You can also use "!" instead of "%shell". """ # get in sync with the cwd self.eval('cd "%s"' % os.getcwd().replace(os.path.sep, '/')) command = " ".join(args) self.eval(command, True) if self.cmd == 'cmd': cwd = self.eval('echo %cd%') else: cwd = self.eval('pwd') if os.path.exists(cwd): os.chdir(cwd) def eval(self, cmd, incremental=False): stream_handler = self.kernel.Print if incremental else None return self.repl.run_command(cmd, timeout=None, stream_handler=stream_handler) def start_process(self): if self.repl is not None: self.repl.child.terminate() if not self.cmd: if os.name == 'nt': self.cmd = 'powershell' self.repl = powershell() elif pexpect.which('bash'): self.cmd = 'bash' self.repl = bash() elif pexpect.which('sh'): self.cmd = 'sh' self.repl = bash(command='sh') else: msg = "The command was not found or was not executable: sh" raise Exception(msg) def cell_shell(self): """ %%shell - run the contents of the cell as shell commands This shell command will run the cell contents in the bash shell. Example: %%shell cd .. ls -al Note: this is a persistent connection to a shell. The working directory is synchronized to that of the notebook before and after each call. You can also use "!!" instead of "%%shell". """ self.line_shell(self.code) self.evaluate = False def get_completions(self, info): if self.cmd == 'cmd': return [] command = 'compgen -cdfa "%s"' % info['code'] completion_text = self.eval(command) return completion_text.split() def get_help_on(self, info, level=0): expr = info['code'].rstrip() if self.cmd == 'cmd': resp = self.eval('help %s' % expr) elif level == 0: resp = self.eval('%s --help' % expr) else: resp = self.eval('man %s' % expr) if resp and not ': command not found' in resp: return resp else: return "Sorry, no help is available on '%s'." % expr def register_magics(kernel): kernel.register_magics(ShellMagic) metakernel-0.29.4/metakernel/magics/show_magic.py000066400000000000000000000025751434565236000220420ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic, option import os class ShowMagic(Magic): @option( '-o', '--output', action='store_true', default=False, help='rather than showing the contents, show the results' ) def cell_show(self, output=False): """ %%show [-o]- show cell contents or results in system pager This cell magic will put the contents or results of the cell into the system pager. Examples: %%show This information will appear in the pager. %%show --output retval = 54 * 54 """ self.show_output = output if not output: # show contents self.kernel.payload = [{"data": {"text/plain": self.code}, "start_line_number": 0, "source": "page"}] self.evaluate = False else: self.evaluate = True def post_process(self, results): if self.show_output: self.kernel.payload = [{"data": {"text/plain": self.kernel.repr(results)}, "start_line_number": 0, "source": "page"}] return None def register_magics(kernel): kernel.register_magics(ShowMagic) metakernel-0.29.4/metakernel/magics/tests/000077500000000000000000000000001434565236000205015ustar00rootroot00000000000000metakernel-0.29.4/metakernel/magics/tests/__init__.py000066400000000000000000000000001434565236000226000ustar00rootroot00000000000000metakernel-0.29.4/metakernel/magics/tests/test_cd_magic.py000066400000000000000000000005151434565236000236410ustar00rootroot00000000000000 import os from metakernel.tests.utils import get_kernel, get_log_text, clear_log_text def test_cd_magic(): kernel = get_kernel() kernel.do_execute("%cd ~") assert os.getcwd() == os.path.expanduser('~'), os.getcwd() clear_log_text(kernel) kernel.do_execute('%cd') assert os.getcwd() in get_log_text(kernel) metakernel-0.29.4/metakernel/magics/tests/test_connect_info_magic.py000066400000000000000000000013171434565236000257200ustar00rootroot00000000000000 from metakernel.tests.utils import get_kernel, get_log_text def test_connect_info_magic(): kernel = get_kernel() kernel.do_execute("%connect_info") text = get_log_text(kernel) assert """{ "stdin_port": UNKNOWN, "shell_port": UNKNOWN, "iopub_port": UNKNOWN, "hb_port": UNKNOWN, "ip": "UNKNOWN", "key": "UNKNOWN", "signature_scheme": "UNKNOWN", "transport": "UNKNOWN" } Paste the above JSON into a file, and connect with: $> ipython --existing or, if you are local, you can connect with just: $> ipython --existing UNKNOWN or even just: $> ipython --existing if this is the most recent Jupyter session you have started. """.strip() in text, text metakernel-0.29.4/metakernel/magics/tests/test_debug_magic.py000066400000000000000000000002731434565236000243420ustar00rootroot00000000000000 import os from metakernel.tests.utils import get_kernel, EvalKernel def test_debug_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("""%%debug print('ok') """) metakernel-0.29.4/metakernel/magics/tests/test_download_magic.py000066400000000000000000000017501434565236000250640ustar00rootroot00000000000000 from metakernel.tests.utils import (get_kernel, get_log_text, clear_log_text, EvalKernel, has_network) import os import pytest @pytest.mark.skipif(not has_network(), reason='no network') def test_download_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("%download --filename TEST.txt https://raw.githubusercontent.com/calysto/metakernel/main/LICENSE.txt") text = get_log_text(kernel) assert "Downloaded 'TEST.txt'" in text, text assert os.path.isfile("TEST.txt"), "File does not exist: TEST.txt" clear_log_text(kernel) kernel.do_execute("%download https://raw.githubusercontent.com/calysto/metakernel/main/LICENSE.txt") text = get_log_text(kernel) assert "Downloaded 'LICENSE.txt'" in text, text assert os.path.isfile("LICENSE.txt"), "File does not exist: LICENSE.txt" def teardown(): for fname in ['TEST.txt', 'LICENSE.txt']: try: os.remove(fname) except: pass metakernel-0.29.4/metakernel/magics/tests/test_edit_magic.py000066400000000000000000000005541434565236000242030ustar00rootroot00000000000000 from metakernel.tests.utils import (get_kernel, get_log_text, clear_log_text, EvalKernel) def test_edit_magic(): kernel = get_kernel(EvalKernel) results = kernel.do_execute("%%edit %s" % __file__) text = results["payload"][0]["text"] assert text.startswith('%%file') assert 'def test_edit_magic' in text metakernel-0.29.4/metakernel/magics/tests/test_file_magic.py000066400000000000000000000021241434565236000241700ustar00rootroot00000000000000 import os from metakernel.tests.utils import get_kernel def test_file_magic(): kernel = get_kernel() kernel.do_execute("""%%file TEST.txt LINE1 LINE2 LINE3""", False) assert os.path.exists("TEST.txt") with open("TEST.txt") as fp: lines = fp.readlines() assert len(lines) == 3 assert lines[0] == "LINE1\n" assert lines[1] == "LINE2\n" assert lines[2] == "LINE3" kernel.do_execute("""%%file -a TEST.txt LINE4 LINE5 LINE6""", False) assert os.path.exists("TEST.txt") with open("TEST.txt") as fp: lines = fp.readlines() assert len(lines) == 6 assert lines[3] == "LINE4\n" assert lines[4] == "LINE5\n" assert lines[5] == "LINE6" kernel.do_execute("""%%file /tmp/tmp/TEST.txt TEST1 TEST2 TEST3""") with open("/tmp/tmp/TEST.txt") as fp: lines = fp.readlines() assert len(lines) == 3 assert lines[0] == "TEST1\n" assert lines[1] == "TEST2\n" assert lines[2] == "TEST3" def teardown(): import shutil shutil.rmtree("/tmp/tmp", ignore_errors=True) metakernel-0.29.4/metakernel/magics/tests/test_help_magic.py000066400000000000000000000017301434565236000242030ustar00rootroot00000000000000 from metakernel.tests.utils import get_kernel, get_log_text, clear_log_text def test_help_magic(): kernel = get_kernel() kernel.do_execute('?%magic', None) text = get_log_text(kernel) assert '%magic - show installed magics' in text, repr(text) kernel.do_execute('%lsmagic??', None) text = get_log_text(kernel) assert 'class LSMagicMagic' in text kernel.do_execute('?', None) text = get_log_text(kernel) assert 'This is a usage statement.' in text kernel.do_execute('?%', None) text = get_log_text(kernel) assert 'This is a usage statement.' in text kernel.do_execute('?%whatwhat', None) text = get_log_text(kernel) assert "No such line magic 'whatwhat'" in text clear_log_text(kernel) kernel.do_execute('%%help %magic', None) text = get_log_text(kernel) assert 'MagicMagic' in text kernel.do_execute('%%help\n%python', None) text = get_log_text(kernel) assert 'PythonMagic' in text metakernel-0.29.4/metakernel/magics/tests/test_html_magic.py000066400000000000000000000004671434565236000242250ustar00rootroot00000000000000 from metakernel.tests.utils import (get_kernel, get_log_text, clear_log_text, EvalKernel) def test_html_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("""%%html bold """) text = get_log_text(kernel) assert "Display Data" in text, text metakernel-0.29.4/metakernel/magics/tests/test_include_magic.py000066400000000000000000000014341434565236000246770ustar00rootroot00000000000000 from metakernel.tests.utils import get_kernel EXECUTION = "" def test_include_magic(): global EXECUTION kernel = get_kernel() def do_execute_direct(code): global EXECUTION EXECUTION = code kernel.do_execute_direct = do_execute_direct FILE = __file__ if FILE.endswith(".pyc"): FILE = FILE[:-1] kernel.do_execute("%%include %s" % FILE) assert "metakernel" in EXECUTION assert ("AND " + "THIS") not in EXECUTION EXECUTION = "" kernel.do_execute(("%%include %s\nAND" + " THIS") % FILE) assert "metakernel" in EXECUTION assert ("AND " + "THIS") in EXECUTION EXECUTION = "" kernel.do_execute("%%include '%s' '%s'" % (FILE, FILE)) assert "metakernel" in EXECUTION assert ("AND " + "THIS") not in EXECUTION metakernel-0.29.4/metakernel/magics/tests/test_install_magic_magic.py000066400000000000000000000015271434565236000260650ustar00rootroot00000000000000 from metakernel.tests.utils import (get_kernel, get_log_text, clear_log_text, EvalKernel, has_network) import re import os from metakernel.config import get_local_magics_dir import pytest filename = get_local_magics_dir() + os.sep + "cd_magic.py" @pytest.mark.skipif(not has_network(), reason='no network') def test_install_magic_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("%install_magic https://raw.githubusercontent.com/calysto/metakernel/main/metakernel/magics/cd_magic.py") text = get_log_text(kernel) assert re.match(".*Downloaded '.*ipython/metakernel/magics/cd_magic.py'", text, re.DOTALL | re.M), "Not downloaded" assert os.path.isfile(filename), ("File not found: %s" % filename) def teardown(): try: os.remove(filename) except OSError: pass metakernel-0.29.4/metakernel/magics/tests/test_javascript_magic.py000066400000000000000000000005351434565236000254230ustar00rootroot00000000000000 from metakernel.tests.utils import (get_kernel, get_log_text, clear_log_text, EvalKernel) def test_javascript_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("""%%javascript console.log("Hello from Javascript"); """) text = get_log_text(kernel) assert "Display Data" in text, text metakernel-0.29.4/metakernel/magics/tests/test_jigsaw_magic.py000066400000000000000000000011311434565236000245320ustar00rootroot00000000000000 from metakernel.tests.utils import (get_kernel, get_log_text, clear_log_text, EvalKernel, has_network) import os import pytest @pytest.mark.skipif(not has_network(), reason='no network') def test_jigsaw_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("%jigsaw Processing --workspace workspace1") text = get_log_text(kernel) assert os.path.isfile("workspace1.html"), "File does not exist: workspace1.html" def teardown(): for fname in ['workspace1.html']: try: os.remove(fname) except: pass metakernel-0.29.4/metakernel/magics/tests/test_kernel_magic.py000066400000000000000000000004201434565236000245260ustar00rootroot00000000000000 from metakernel.tests.utils import get_kernel, get_log_text, EvalKernel import os import time def test_kernel_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("%kx 42", False) results = get_log_text(kernel) assert "42" in results, results metakernel-0.29.4/metakernel/magics/tests/test_latex_magic.py000066400000000000000000000007441434565236000243740ustar00rootroot00000000000000 from metakernel.tests.utils import (get_kernel, get_log_text, clear_log_text) def test_latex_magic(): kernel = get_kernel() kernel.do_execute("%latex $x_1 = \\dfrac{a}{b}$") text = get_log_text(kernel) assert "Display Data" in text clear_log_text(kernel) kernel.do_execute("""%%latex $x_1 = \\dfrac{a}{b}$ $x_2 = a^{n - 1}$""") text = get_log_text(kernel) assert "Display Data" in text metakernel-0.29.4/metakernel/magics/tests/test_load_magic.py000066400000000000000000000003241434565236000241700ustar00rootroot00000000000000 from metakernel.tests.utils import get_kernel def test_load_magic(): kernel = get_kernel() ret = kernel.do_execute("%%load %s" % __file__) assert 'def test_load_magic' in ret['payload'][0]['text'] metakernel-0.29.4/metakernel/magics/tests/test_ls_magic.py000066400000000000000000000010041434565236000236630ustar00rootroot00000000000000 import os from metakernel.tests.utils import (get_kernel, get_log_text, clear_log_text) def test_ls_magic(): kernel = get_kernel() kernel.do_execute("%ls /tmp") text = get_log_text(kernel) ## FIXME: failing on Travis #assert '/tmp/' in text, text[:100] clear_log_text(kernel) kernel.do_execute("%ls /tmp --recursive") text = get_log_text(kernel) ## FIXME: failing on Travis #assert '/tmp' in text, text[:100] clear_log_text(kernel) metakernel-0.29.4/metakernel/magics/tests/test_lsmagic_magic.py000066400000000000000000000011051434565236000246660ustar00rootroot00000000000000 from metakernel.tests.utils import get_kernel, get_log_text def test_lsmagic_magic(): kernel = get_kernel() kernel.do_execute("%lsmagic") text = get_log_text(kernel) for item in "%cd %connect_info %download %edit %help %html %install_magic %javascript %kernel %kx %latex %load %lsmagic %magic %parallel %plot %pmap %px %python %reload_magics %restart %run %shell %macro %%debug %%file %%help %%html %%javascript %%kx %%latex %%processing %%px %%python %%shell %%show %%macro %%time".split(): assert item in text, ("lsmagic didn't list '%s'" % item) metakernel-0.29.4/metakernel/magics/tests/test_macro_magic.py000066400000000000000000000013431434565236000243540ustar00rootroot00000000000000 from metakernel.tests.utils import (get_kernel, get_log_text, EvalKernel, clear_log_text) def test_macro_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("""%%macro testme print("ok") """, False) kernel.do_execute("%macro testme", False) text = get_log_text(kernel) assert "ok" in text, text clear_log_text(kernel) kernel.do_execute("%macro -l learned", False) text = get_log_text(kernel) assert "testme" in text, text clear_log_text(kernel) kernel.do_execute("%macro -d testme", False) kernel.do_execute("%macro -l learned", False) text = get_log_text(kernel) assert "testme" not in text, text clear_log_text(kernel) metakernel-0.29.4/metakernel/magics/tests/test_magic_magic.py000066400000000000000000000003651434565236000243360ustar00rootroot00000000000000 from metakernel.tests.utils import get_kernel, get_log_text def test_magic_magic(): kernel = get_kernel() kernel.do_execute('%magic', None) text = get_log_text(kernel) assert '! COMMAND ... - execute command in shell' in text metakernel-0.29.4/metakernel/magics/tests/test_parallel_magic.py000066400000000000000000000016221434565236000250470ustar00rootroot00000000000000 from metakernel.tests.utils import get_kernel, get_log_text, EvalKernel import os import time import pytest try: import ipyparallel except ImportError: ipyparallel = None @pytest.mark.skipif(ipyparallel is None, reason="Requires ipyparallel") def test_parallel_magic(): kernel = get_kernel(EvalKernel) # start up an EvalKernel on each node: kernel.do_execute("%parallel metakernel_python MetaKernelPython", False) # Now, execute something on each one: kernel.do_execute("%px cluster_rank", False) results = get_log_text(kernel) assert "[0, 1, 2]" in results, results # Starting the cluster from here doesn't work with pytest # so we start `ipcluster` before we test. #def setup_func(): # ## start up a cluster in the background with three nodes: # os.system("ipcluster start --n=3 &") #def teardown(): # ## shutdown the cluster: # os.system("ipcluster stop") metakernel-0.29.4/metakernel/magics/tests/test_pipe_magic.py000066400000000000000000000022231434565236000242060ustar00rootroot00000000000000from metakernel.tests.utils import (get_kernel, get_log_text, EvalKernel, clear_log_text) def test_pipe_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute(""" def upper(text): return text.upper() def lower(text): return text.lower() def pl_word(word): if len(word) > 3: return word[1:] + word[0] + "ay" else: return word def piglatin(text): return " ".join([pl_word(word) for word in text.split(" ")]) """) kernel.do_execute("""%%pipe upper this is a test """) text = get_log_text(kernel) assert "THIS IS A TEST" in text, ("text: " + text) kernel.do_execute("""%%pipe upper | piglatin this is a test """) text = get_log_text(kernel) assert "HISTay IS A ESTTay" in text, ("text: " + text) kernel.do_execute("""%%pipe piglatin | upper this is a test """) text = get_log_text(kernel) assert "HISTAY IS A ESTTAY" in text, ("text: " + text) kernel.do_execute("""%%pipe piglatin | upper | lower this is a test """) text = get_log_text(kernel) assert "histay is a esttay" in text, ("text: " + text) clear_log_text(kernel) metakernel-0.29.4/metakernel/magics/tests/test_plot_magic.py000066400000000000000000000026761434565236000242430ustar00rootroot00000000000000 from metakernel.tests.utils import get_kernel def test_plot_magic_backend(): kernel = get_kernel() kernel.do_execute('%plot qt -f svg -s400,200', None) assert kernel.plot_settings['width'] == 400 assert kernel.plot_settings['height'] == 200 assert kernel.plot_settings['format'] == 'svg' assert kernel.plot_settings['backend'] == 'qt' def test_plot_magic_format(): kernel = get_kernel() kernel.do_execute('%plot qt -f svg -w 500 -h 400 -r 200') assert kernel.plot_settings['backend'] == 'qt', kernel.plot_settings assert kernel.plot_settings['format'] == 'svg', kernel.plot_settings assert kernel.plot_settings['width'] == 500, kernel.plot_settings assert kernel.plot_settings['height'] == 400, kernel.plot_settings assert kernel.plot_settings['resolution'] == 200, kernel.plot_settings def test_plot_magic_size(): kernel = get_kernel() kernel.do_execute('%plot qt4 -s 400,200') assert kernel.plot_settings['width'] == 400 assert kernel.plot_settings['height'] == 200 assert kernel.plot_settings['backend'] == 'qt4', kernel.plot_settings def test_plot_magic_all(): kernel = get_kernel() kernel.do_execute('%plot -b qt5 -f svg -s 400,200') assert kernel.plot_settings['width'] == 400 assert kernel.plot_settings['height'] == 200 assert kernel.plot_settings['format'] == 'svg', kernel.plot_settings assert kernel.plot_settings['backend'] == 'qt5', kernel.plot_settings metakernel-0.29.4/metakernel/magics/tests/test_processing_magic.py000066400000000000000000000005171434565236000254310ustar00rootroot00000000000000 from metakernel.tests.utils import (get_kernel, get_log_text, clear_log_text, EvalKernel) def test_processing_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("""%%processing setup() { } draw() { } """) text = get_log_text(kernel) assert "Display Data" in text, text metakernel-0.29.4/metakernel/magics/tests/test_python_magic.py000066400000000000000000000045631434565236000246030ustar00rootroot00000000000000import textwrap from metakernel.tests.utils import get_kernel, get_log_text, clear_log_text def test_python_magic(): kernel = get_kernel() text = '%python imp' comp = kernel.do_complete(text, len(text)) assert 'import' in comp['matches'] helpstr = kernel.get_help_on('%python bin') assert 'Return the binary representation of an integer' in helpstr, helpstr def test_python_magic2(): kernel = get_kernel() kernel.do_execute('%python retval = 1', None) assert '1' in get_log_text(kernel) kernel.do_execute(textwrap.dedent('''\ %%python def test(a): return a + 1 retval = test(2)'''), None) assert '3' in get_log_text(kernel) kernel.do_execute(textwrap.dedent('''\ %%python def test(a): return a + 1 test(2)'''), None) assert '3' in get_log_text(kernel) def test_python_magic3(): kernel = get_kernel() kernel.do_execute('%%python -e\n1 + 2', None) magic = kernel.get_magic('%%python') assert magic.retval is None kernel = get_kernel() kernel.do_execute('%%python\n1 + 2', None) magic = kernel.get_magic('%%python') assert magic.retval == 3 kernel = get_kernel() kernel.do_execute('%%python\n1 + 2\n2 + 3', None) magic = kernel.get_magic('%%python') assert magic.retval == 5 kernel = get_kernel() kernel.do_execute('%%python\nretval = 1 + 2\n2 + 3', None) magic = kernel.get_magic('%%python') assert magic.retval == 3 kernel = get_kernel() kernel.do_execute('%%python\nimport math', None) magic = kernel.get_magic('%%python') assert magic.retval == None def test_python_magic4(): kernel = get_kernel() kernel.do_execute('?%python', None) assert '%python CODE' in get_log_text(kernel) clear_log_text(kernel) ret = kernel.do_execute('?%python a', None) assert ret['payload'][0]['data']['text/plain'] == 'No help available for "a"' ret = kernel.do_execute('?%%python a.b', None) assert ret['payload'][0]['data']['text/plain'] == 'No help available for "a.b"' ret = kernel.do_execute('??%%python oct', None) assert 'Return the octal representation of an integer' in ret['payload'][0]['data']['text/plain'], ret['payload'][0]['data']['text/plain'] def test_python_magic5(): kernel = get_kernel() kernel.do_execute("%python print('hello')") assert 'hello' in get_log_text(kernel) metakernel-0.29.4/metakernel/magics/tests/test_reload_magics_magic.py000066400000000000000000000011201434565236000260350ustar00rootroot00000000000000 from metakernel.tests.utils import get_kernel, get_log_text def test_reload_magics_magic(): kernel = get_kernel() kernel.do_execute("%reload_magics") text = get_log_text(kernel) for item in "%cd %connect_info %download %edit %help %html %install_magic %javascript %kernel %kx %latex %load %lsmagic %magic %parallel %plot %pmap %px %python %reload_magics %restart %run %shell %macro %%debug %%file %%help %%html %%javascript %%kx %%latex %%processing %%px %%python %%shell %%show %%macro %%time".split(): assert item in text, ("load_magic didn't list '%s'" % item) metakernel-0.29.4/metakernel/magics/tests/test_restart_magic.py000066400000000000000000000004431434565236000247370ustar00rootroot00000000000000from metakernel.tests.utils import get_kernel, EvalKernel, get_log_text def test_restart_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute('a=1') kernel.do_execute("%restart") kernel.do_execute('a') text = get_log_text(kernel) assert 'NameError' in text metakernel-0.29.4/metakernel/magics/tests/test_run_magic.py000066400000000000000000000011301434565236000240510ustar00rootroot00000000000000 from metakernel.tests.utils import (get_kernel, EvalKernel, get_log_text, clear_log_text) def test_run_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("%%run %s" % __file__.replace(".pyc", ".py")) kernel.do_execute("TEST") text = get_log_text(kernel) assert '42' in text, "Didn't run this file" clear_log_text(kernel) kernel.do_execute("%%run --language python %s" % __file__.replace(".pyc", ".py")) kernel.do_execute("TEST") text = get_log_text(kernel) assert '42' in text, "Didn't run this file" TEST = 42 metakernel-0.29.4/metakernel/magics/tests/test_set_get_magic.py000066400000000000000000000014561434565236000247120ustar00rootroot00000000000000 import os import sys from metakernel.tests.utils import (get_kernel, get_log_text, clear_log_text, EvalKernel) def test_set_get_int_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("%set x 42") kernel.do_execute("%get x") text = get_log_text(kernel) assert "42" in text, text def test_set_get_list_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("%set variable [1., 2., 3., 4.]") kernel.do_execute("%get variable") text = get_log_text(kernel) assert "[1.0, 2.0, 3.0, 4.0]" in text, text def test_set_get_range_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("%set variable range(2)") kernel.do_execute("%get variable") text = get_log_text(kernel) assert "range(0, 2)" in text, text metakernel-0.29.4/metakernel/magics/tests/test_shell_magic.py000066400000000000000000000022171434565236000243630ustar00rootroot00000000000000 from metakernel.tests.utils import get_kernel, get_log_text # force locale to C to get consistent error messages import os os.environ["LC_ALL"] = "C" os.environ["LANG"] = "C" os.environ["LANGUAGE"] = "C" def test_shell_magic(): kernel = get_kernel() text = '%shell ech' comp = kernel.do_complete(text, len(text)) assert 'echo' in comp['matches'] helpstr = kernel.get_help_on('!cat') assert not 'Sorry, no help' in helpstr, helpstr helpstr = kernel.get_help_on('%%shell cat', level=1) assert not 'Sorry, no help' in helpstr helpstr = kernel.get_help_on('!lkjalskdfj') assert 'Sorry, no help' in helpstr def test_shell_magic2(): kernel = get_kernel() kernel.do_execute("!cat \"%s\"" % __file__, False) log_text = get_log_text(kernel) assert 'metakernel.py' in log_text kernel.do_execute('!!\necho "hello"\necho "goodbye"', None) log_text = get_log_text(kernel) assert '"hello"' in log_text assert '"goodbye"' in log_text def test_shell_magic3(): kernel = get_kernel() kernel.do_execute('!lalkjds') text = get_log_text(kernel) assert ': command not found' in text, text metakernel-0.29.4/metakernel/magics/tests/test_show_magic.py000066400000000000000000000011661434565236000242360ustar00rootroot00000000000000 from metakernel.tests.utils import (get_kernel, get_log_text, clear_log_text, EvalKernel) def test_show_magic(): kernel = get_kernel(EvalKernel) results = kernel.do_execute("""%%show Welcome to the big show! """) text = results["payload"][0]["data"]["text/plain"] assert "Welcome to the big show!" in text, text results = kernel.do_execute("""%%show --output # Welcome to the big show! retval = "This is a test" """) text = results["payload"][0]["data"]["text/plain"] assert "Welcome to the big show!" not in text, text assert "This is a test" in text, text metakernel-0.29.4/metakernel/magics/tests/test_time_magic.py000066400000000000000000000004701434565236000242110ustar00rootroot00000000000000 from metakernel.tests.utils import get_kernel, get_log_text, EvalKernel import re def test_time_magic(): kernel = get_kernel(EvalKernel) kernel.do_execute("""%%time x = 1 """) text = get_log_text(kernel) assert re.match(".*Time: .* seconds.", text, re.MULTILINE | re.DOTALL) != None, text metakernel-0.29.4/metakernel/magics/time_magic.py000066400000000000000000000016261434565236000220140ustar00rootroot00000000000000# Copyright (c) Metakernel Development Team. # Distributed under the terms of the Modified BSD License. from metakernel import Magic import time class TimeMagic(Magic): def cell_time(self): """ %%time - show time to run cell Put this magic at the top of a cell and the amount of time taken to execute the code will be displayed before the output. Example: %%time [code for your language goes here!] This just reports real time taken to execute a program. This may fluctuate with number of users, system, load, etc. """ self.start = time.time() def post_process(self, retval): if self.code.strip(): result = "Time: %s seconds.\n" % (time.time() - self.start) self.kernel.Print(result) return retval def register_magics(kernel): kernel.register_magics(TimeMagic) metakernel-0.29.4/metakernel/magics/tutor_magic.py000066400000000000000000000070341434565236000222320ustar00rootroot00000000000000""" ========== tutormagic ========== Magics to display pythontutor.com in the notebook. """ # Based on Kiko Correoso's IPython magic: # https://github.com/kikocorreoso/tutormagic # and Doug Blank's # http://jupyter.cs.brynmawr.edu/hub/dblank/public/Examples/Online%20Python%20Tutor.ipynb #----------------------------------------------------------------------------- # Copyright (C) 2015 Kiko Correoso and the pythontutor.com developers # # Distributed under the terms of the MIT License. The full license is in # the file LICENSE, distributed as part of this software. # # Contributors: # kikocorreoso #----------------------------------------------------------------------------- from metakernel import Magic, option from IPython.display import IFrame import sys if sys.version_info.major == 2 and sys.version_info.minor == 7: from urllib import quote elif sys.version_info.major == 3 and sys.version_info.minor >= 3: from urllib.parse import quote class TutorMagic(Magic): @option( '-l', '--language', action='store', nargs = 1, help=("Possible languages to be displayed within the iframe. " + "Possible values are: python, python2, python3, java, javascript") ) def cell_tutor(self, language=None): """ %%tutor [--language=LANGUAGE] - show cell with Online Python Tutor. Defaults to use the language of the current kernel. 'python' is an alias for 'python3'. Examples: %%tutor -l python3 a = 1 b = 1 a + b [You will see an iframe with the pythontutor.com page including the code above.] %%tutor --language=java public class Test { public Test() { } public static void main(String[] args) { int x = 1; System.out.println("Hi"); } } """ if language is None: language = self.kernel.language_info["name"] if language not in ['python', 'python2', 'python3', 'java', 'javascript']: raise ValueError("{} not supported. Only the following options are allowed: " "'python2', 'python3', 'java', 'javascript'".format(language)) url = "https://pythontutor.com/iframe-embed.html#code=" url += quote(self.code) url += "&origin=opt-frontend.js&cumulative=false&heapPrimitives=false" url += "&textReferences=false&" if language in ["python3", "python"]: url += "py=3&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400" elif language == "python2": url += "py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400" elif language == "java": url += "py=java&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400" elif language == "javascript": url += "py=js&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400" # Display the results in the output area self.kernel.Display(IFrame(url, height=500, width="100%")) self.evaluate = False def register_magics(kernel): kernel.register_magics(TutorMagic) def register_ipython_magics(): from metakernel import IPythonKernel from IPython.core.magic import register_cell_magic kernel = IPythonKernel() magic = TutorMagic(kernel) @register_cell_magic def tutor(line, cell): magic.code = cell magic.cell_tutor(language="python3") metakernel-0.29.4/metakernel/parser.py000066400000000000000000000255761434565236000177610ustar00rootroot00000000000000import re import os IDENTIFIER_REGEX = r'[^\d\W][\w\.]*' FUNC_CALL_REGEX = r'([^\d\W][\w\.]*)\([^\)\()]*\Z' MAGIC_PREFIXES = dict(magic='%', shell='!', help='?') HELP_SUFFIX = '?' class Parser(object): """Parse an input buffer using language-specific regexes.""" def __init__(self, identifier_regex=IDENTIFIER_REGEX, function_call_regex=FUNC_CALL_REGEX, magic_prefixes=MAGIC_PREFIXES, help_suffix=HELP_SUFFIX): """Set up the regexes and magic characters. Parameters ---------- identifier_regex : str Regex for a valid identifier in the desired language. function_call_regex : str Regex for a function call that we are in the midst of. magic_prefixes : dict Map of magic types to the prefix characters help_suffix : str Character to use for help suffix. """ self.func_call_regex = re.compile(function_call_regex + r'\Z', re.UNICODE) default_regex = r'[^\d\W][\w\.]*' self.id_regex = re.compile(r'(\{0}+{1}\Z|{2}\Z|\Z)'.format( magic_prefixes['magic'], default_regex, identifier_regex), re.UNICODE) self.magic_regex = '|'.join([default_regex, identifier_regex]) full_path_regex = r'([\w/\.~][^\'"]*)\Z' self.unquoted_path = re.compile(r'\A{0}| {0}'.format(full_path_regex), re.UNICODE) self.quoted_path = re.compile(r'[\'"]%s' % full_path_regex, re.UNICODE) single_path_regex = r'([\w/\.~][^ ]*)\Z' self.single_path = re.compile(single_path_regex, re.UNICODE) self.magic_prefixes = magic_prefixes self.help_suffix = help_suffix def parse_code(self, code, start=0, end=-1): """Parse an input buffer, extracting relevant information. Parameters ---------- code : str Input buffer. start : int, optional The start location in the buffer. end : int, optional The end location in the buffer. Returns ------- info : dict Metadata about the parsed buffer with the following items: magic : dict, Magic info, see `_parse_magic`. lines : int, Number of lines in code line_num : int, Current line Number line : str, Current line of text column : int, Index in current line of text obj : str, Matched object at the end of text full_obj : str, Obj plus valid text to the right of cursor help_obj : str, Full_obj or a function call. start : int, Start index in buffer. end: int, End index in buffer pre: str, Text before start mid : str, Text between start and end post : str, Text after end path_matches : list, File system path matches for text """ if end == -1: end = len(code) end = min(len(code), end) start = min(start, end) start = max(0, start) info = dict(code=code, magic=dict()) info['magic'] = self._parse_magic(code[:end]) info['lines'] = lines = code[:end].splitlines() info['line_num'] = line_num = len(lines) if info['line_num']: info['line'] = line = lines[-1] info['column'] = col = len(lines[-1]) else: info['line'] = line = '' info['column'] = col = 0 obj = re.search(self.id_regex, line).group() full_obj = obj if obj: full_line = code.splitlines()[line_num - 1] rest = full_line[col:] match = re.match(self.id_regex, rest) if match: full_obj = obj + match.group() func_call = re.search(self.func_call_regex, line) if func_call and not obj: info['help_obj'] = func_call.groups()[0] info['help_col'] = line.index(obj) + len(obj) info['help_pos'] = end - len(line) + col else: info['help_obj'] = full_obj info['help_col'] = col info['help_pos'] = end info['obj'] = obj info['full_obj'] = full_obj info['start'] = end - len(obj) info['end'] = end info['pre'] = code[:start] info['code'] = code[start: end] info['post'] = code[end:] info['path_matches'] = self._get_path_matches(info) return info def _parse_magic(self, code): """Find and parse magic calls in the buffer. Parameters ---------- code : str Input text. Notes ----- - The first magic must start at the beginning of the line. - Magics can be nested. - Magics return strings. - Magics in a cell block must start at the beginning of a line. - If no valid magic is found, the block will be considered code and handled by the kernel. - Help magic is special: -- It can be at the end of the line and takes precedence. -- No code is executed when a help magic is present. Examples -------- In [1]: ! ls -l # doctest: +SKIP In [2]: %time %python a = %paste # doctest: +SKIP Returns ------- info : dict Information about the magic with the following items: name : str, Name of magic type : str, Type of magic {'line', 'cell', 'sticky'} index : str, Index of end of magic in text rest : str, Text after index args : str, First line of "rest", the argument to the magic code : str, Rest of lines of "rest", the cell block for the magic arg_magic: dict, Information about a magic with an argument, can be nested code_magic: dict, Information about a magic within code, can be nested. """ info = {} code = code.lstrip() pre_magics = {} for (name, prefix) in self.magic_prefixes.items(): match = re.match(r'(\%s+)' % prefix, code, re.UNICODE) if match: pre_magics[name] = match.groups()[0] types = ['none', 'line', 'cell', 'sticky'] if 'help' in pre_magics: info['name'] = 'help' pre = pre_magics['help'] info['prefix'] = pre info['full_name'] = pre + 'help' info['type'] = types[len(pre)] info['index'] = code.index(pre) elif self.help_suffix and code.rstrip().endswith(self.help_suffix): info['name'] = 'help' regex = r'(\%s+)\Z' % self.help_suffix match = re.search(regex, code.strip(), re.UNICODE) suf = match.group() info['prefix'] = '' info['type'] = types[len(suf)] info['full_name'] = 'help' + suf info['index'] = len(code) - len(suf) elif 'magic' in pre_magics: pre = pre_magics['magic'] info['prefix'] = pre info['type'] = types[len(pre)] match = re.match(self.magic_regex, code[len(pre):]) if match: obj = match.group() else: obj = '' info['name'] = obj info['full_name'] = pre + obj info['index'] = code.index(pre + obj) + len(pre + obj) elif 'shell' in pre_magics: info['name'] = 'shell' pre = pre_magics['shell'] info['prefix'] = pre info['type'] = types[len(pre)] info['full_name'] = pre info['index'] = code.index(pre) + len(pre) else: return info info['rest'] = code[info['index']:].rstrip() if info['rest']: lines = info['rest'].splitlines() info['args'] = lines[0].strip() info['code'] = '\n'.join(lines[1:]) else: info['args'] = '' info['code'] = '' return info def _get_path_matches(self, info): """Get a list of matching file system paths. There are 3 types of matches: - start character and no quotes - quote mark followed by start character - single string of text with no spaces """ line = info['line'] obj = info['obj'] def get_regex_matches(regex): matches = [] path = re.findall(regex, line.replace(r'\ ', ' ')) if path: path = ''.join(path[0]) matches = _complete_path(path) if len(path) > len(obj) and not path == '.': matches = [m[len(path) - len(obj):] for m in matches] elif path == '.': matches = [m[1:] for m in matches if m.startswith('.')] return [m.strip() for m in matches if not m.strip() == obj] matches = get_regex_matches(self.unquoted_path) matches += get_regex_matches(self.single_path) matches = [self.escape_path(m) for m in matches] matches += get_regex_matches(self.quoted_path) if os.path.isdir(info['obj']): matches.append(info['obj'] + os.sep) return list(set(matches)) def escape_path(self, path): """Escape an unquoted path. Kernels may modify path escaping by overwriting this method in their own parser instance. """ if os.name == "nt": return '"{}"'.format(path) else: return path.replace(' ', r'\ ') def _listdir(root): "List directory 'root' appending the path separator to subdirs." res = [] root = os.path.expanduser(root) try: for name in os.listdir(root): path = os.path.join(root, name) if os.path.isdir(path): name += os.sep res.append(name) except: pass # no need to report invalid paths return res def _complete_path(path=None): """Perform completion of filesystem path. http://stackoverflow.com/questions/5637124/tab-completion-in-pythons-raw-input """ if not path or path == '.': return _listdir('.') dirname, rest = os.path.split(path) tmp = dirname if dirname else '.' res = [] for p in _listdir(tmp): try: if p.startswith(rest): res.append(os.path.join(dirname, p)) except UnicodeDecodeError: pass # directory name does not allow join in Python 2.7 # more than one match, or single match which does not exist (typo) if len(res) > 1 or not os.path.exists(path): return res # resolved to a single directory, so return list of files below it if os.path.isdir(path): return [os.path.join(path, p) for p in _listdir(path)] # exact file match terminates this completion return [path + ' '] metakernel-0.29.4/metakernel/pexpect.py000066400000000000000000000062321434565236000201210ustar00rootroot00000000000000# Convenience imports from pexpect from __future__ import absolute_import import os import shlex import signal from pexpect import is_executable_file, EOF, TIMEOUT, __file__ as PEXPECT_DIR try: from pexpect import spawn as pty_spawn import pty except ImportError: from pexpect.popen_spawn import PopenSpawn pty = None def spawn(command, args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None, cwd=None, env=None, ignore_sighup=True, echo=True, encoding='utf-8', **kwargs): '''This is the main entry point for Pexpect. Use this functio to start and control child applications. See https://github.com/pexpect/pexpect/blob/master/pexpect/pty_spawn.py for more information. ''' codec_errors = kwargs.get('codec_errors', kwargs.get('errors', 'strict')) if pty is None: command = shlex.split(command, posix=os.name == 'posix') command += args child = PopenSpawn(command, timeout=timeout, maxread=maxread, searchwindowsize=searchwindowsize, logfile=logfile, cwd=cwd, env=env, encoding=encoding, codec_errors=codec_errors) child.echo = echo else: try: # Signal handlers are inherited by forked processes, and we can't easily # reset it from the subprocess. Since kernelapp ignores SIGINT except in # message handlers, we need to temporarily reset the SIGINT handler here # so that the child and its children are interruptible. try: sig = signal.signal(signal.SIGINT, signal.SIG_DFL) except ValueError: # Only Main Thread can handle signals sig = None child = pty_spawn(command, args=args, timeout=timeout, maxread=maxread, searchwindowsize=searchwindowsize, logfile=logfile, cwd=cwd, env=env, encoding=encoding, codec_errors=codec_errors) finally: if sig: signal.signal(signal.SIGINT, sig) return child # For backwards compatibility spawnu = spawn def which(filename): '''This takes a given filename; tries to find it in the environment path; then checks if it is executable. This returns the full path to the filename if found and executable. Otherwise this returns None.''' # Special case where filename contains an explicit path. if os.path.dirname(filename) != '' and is_executable_file(filename): return filename if 'PATH' not in os.environ or os.environ['PATH'] == '': p = os.defpath else: p = os.environ['PATH'] pathlist = p.split(os.pathsep) for path in pathlist: ff = os.path.join(path, filename) if pty: if is_executable_file(ff): return ff else: pathext = os.environ.get('Pathext', '.exe;.com;.bat;.cmd') pathext = pathext.split(os.pathsep) + [''] for ext in pathext: if os.access(ff + ext, os.X_OK): return ff + ext return None metakernel-0.29.4/metakernel/process_metakernel.py000066400000000000000000000170031434565236000223340ustar00rootroot00000000000000from __future__ import absolute_import from . import MetaKernel from pexpect import EOF from .replwrap import REPLWrapper, bash from subprocess import check_output import re import sys __version__ = '0.0' version_pat = re.compile(r'version (\d+(\.\d+)+)') class TextOutput(object): """Wrapper for text output whose repr is the text itself. This avoids `repr(output)` adding quotation marks around already-rendered text. """ def __init__(self, output): self.output = output def __repr__(self): return self.output class ProcessMetaKernel(MetaKernel): implementation = 'process_kernel' implementation_version = __version__ language = 'process' language_info = { # 'mimetype': 'text/x-python', # 'language': 'python', # ------ If different from 'language': # 'codemirror_mode': 'language', # 'pygments_lexer': 'language', # 'file_extension': 'py', } @property def language_version(self): m = version_pat.search(self.banner) return m.group(1) _banner = "Process" @property def banner(self): return self._banner def __init__(self, *args, **kwargs): MetaKernel.__init__(self, *args, **kwargs) self.wrapper = None def do_execute_direct(self, code, silent=False): """Execute the code in the subprocess. """ if not self.wrapper: self.wrapper = self.makeWrapper() self.payload = [] wrapper = self.wrapper child = wrapper.child if not code.strip(): self.kernel_resp = { 'status': 'ok', 'execution_count': self.execution_count, 'payload': [], 'user_expressions': {}, } return interrupted = False output = '' error = None stream_handler = self.Write if not silent else None try: output = wrapper.run_command(code.rstrip(), timeout=None, stream_handler=stream_handler, stdin_handler=self.raw_input) except KeyboardInterrupt as e: interrupted = True output = wrapper.interrupt() except EOF: self.Print(child.before) self.do_shutdown(True) error = RuntimeError('End of File') tb = 'End of File' except Exception as e: ex_type, error, tb = sys.exc_info() self.Error(str(e)) if interrupted: self.kernel_resp = { 'status': 'abort', 'execution_count': self.execution_count, } exitcode, trace = self.check_exitcode() if exitcode: self.kernel_resp = { 'status': 'error', 'execution_count': self.execution_count, 'ename': '', 'evalue': str(exitcode), 'traceback': trace, } elif error: self.kernel_resp = { 'status': 'error', 'execution_count': self.execution_count, 'ename': '', 'evalue': str(error), 'traceback': str(tb), } else: self.kernel_resp = { 'status': 'ok', 'execution_count': self.execution_count, 'payload': [], 'user_expressions': {}, } if output: if stream_handler: stream_handler(output) else: return TextOutput(output) def check_exitcode(self): """ Return (1, ["trace"]) if error. """ return (0, None) def makeWrapper(self): """ In this method the REPLWrapper is created and returned. REPLWrapper takes the name of the executable, and arguments describing the executable prompt: return REPLWrapper('bash', orig_prompt, prompt_change, prompt_cmd=prompt_cmd, extra_init_cmd=extra_init_cmd) The parameters are: :param orig_prompt: What the original prompt is (or is forced to be by prompt_cmd). :param prompt_cmd: Used when the prompt is not printed by default (happens on Windows) to print something that we can search for. :param prompt_change: Used to set the PS1/PS2 equivalents to something that is easier to tell apart from everything else, make sure it is a string with {0} and {1} in it for the PS1/PS2 fill-ins. See `metakernel.replwrap.REPLWrapper` for more details. """ raise NotImplementedError def do_shutdown(self, restart): """ Shut down the app gracefully, saving history. """ try: self.wrapper.terminate() except Exception as e: self.Error(str(e)) super(ProcessMetaKernel, self).do_shutdown(restart) def restart_kernel(self): """Restart the kernel""" self.wrapper = self.makeWrapper() class DynamicKernel(ProcessMetaKernel): def __init__(self, executable, language, mimetype="text/plain", implementation="metakernel", file_extension='txt', orig_prompt=None, prompt_change=None, prompt_cmd=None, extra_init_cmd=None, stdin_prompt_regex=None): self.executable = executable self.orig_prompt = orig_prompt self.prompt_change = prompt_change self.prompt_cmd = prompt_cmd self.extra_init_cmd = extra_init_cmd self.stdin_prompt_regex = stdin_prompt_regex self.implementation = implementation self.language = language self.language_info['mimetype'] = mimetype self.language_info['language'] = language self.language_info['file_extension'] = file_extension super(DynamicKernel, self).__init__() def makeWrapper(self): return REPLWrapper(self.executable, self.orig_prompt, self.prompt_change, prompt_cmd=self.prompt_cmd, stdin_prompt_regex=self.stdin_prompt_regex, extra_init_cmd=self.extra_init_cmd) """ DynamicKernel(executable="bash", orig_prompt=re.compile('[$#]'), prompt_change=u"PS1='{0}' PS2='{1}' PROMPT_COMMAND=''", prompt_cmd=None, extra_init_cmd="export PAGER=cat", implementation="bash_kernel", language="bash", mimetype="text/x-bash", file_extension="sh") """ class BashKernel(ProcessMetaKernel): # Identifiers: implementation = 'bash_kernel' language = 'bash' language_info = { 'mimetype': 'text/x-bash', 'language': 'bash', # ------ If different from 'language': # 'codemirror_mode': 'language', # 'pygments_lexer': 'language', 'file_extension': 'sh', } _banner = None @property def banner(self): if self._banner is None: self._banner = check_output(['bash', '--version']).decode('utf-8') return self._banner def makeWrapper(self): return bash() if __name__ == '__main__': from IPython.kernel.zmq.kernelapp import IPKernelApp IPKernelApp.launch_instance(kernel_class=BashKernel) metakernel-0.29.4/metakernel/replwrap.py000066400000000000000000000310351434565236000203040ustar00rootroot00000000000000import errno import sys import re import signal import os import time import atexit from . import pexpect def u(s): return s basestring = str PEXPECT_PROMPT = u('PEXPECT_PROMPT>') PEXPECT_STDIN_PROMPT = u('PEXPECT_PROMPT+') PEXPECT_CONTINUATION_PROMPT = u('PEXPECT_PROMPT_') class REPLWrapper(object): """Wrapper for a REPL. All prompts are interpreted as regexes. If you have special characters in the prompt, use `re.escape` to escape the characters. :param cmd_or_spawn: This can either be an instance of :class:`pexpect.spawn` in which a REPL has already been started, or a str command to start a new REPL process. :param str prompt_regex: Regular expression representing process prompt, eg ">>>" in Python. :param str continuation_prompt_regex: Regular expression representing process continuation prompt, e.g. "..." in Python. :param str prompt_change_cmd: Optional kernel command that sets continuation-of-line-prompts, eg PS1 and PS2, such as "..." in Python. to something more unique. If this is ``None``, the prompt will not be changed. This will be formatted with the new and continuation prompts as positional parameters, so you can use ``{}`` style formatting to insert them into the command. :param str new_prompt_regex: The more unique prompt to expect after the change. :param str stdin_prompt_regex: The regex for a stdin prompt from the child process. The prompt itself will be sent to the `stdin_handler`, so any sentinel value inserted will have to be removed by the caller. :param str extra_init_cmd: Commands to do extra initialisation, such as disabling pagers. :param str prompt_emit_cmd: Optional kernel command that emits the prompt when one is not emitted by default (typically happens on Windows only) :param bool force_prompt_on_continuation: Whether to force a prompt when we need to interrupt a continuation prompt. :param bool echo: Whether the child should echo, or in the case of Windows, whether the child does echo. """ def __init__(self, cmd_or_spawn, prompt_regex, prompt_change_cmd, new_prompt_regex=PEXPECT_PROMPT, continuation_prompt_regex=PEXPECT_CONTINUATION_PROMPT, stdin_prompt_regex=PEXPECT_STDIN_PROMPT, extra_init_cmd=None, prompt_emit_cmd=None, force_prompt_on_continuation=False, echo=False): if isinstance(cmd_or_spawn, basestring): self.child = pexpect.spawnu(cmd_or_spawn, echo=echo, codec_errors="ignore", encoding="utf-8") else: self.child = cmd_or_spawn if self.child.echo and not echo: # Existing spawn instance has echo enabled, disable it # to prevent our input from being repeated to output. self.child.setecho(False) self.child.waitnoecho() # Convert all arguments to unicode. prompt_regex = u(prompt_regex) prompt_change_cmd = u(prompt_change_cmd) continuation_prompt_regex = u(continuation_prompt_regex) stdin_prompt_regex = u(stdin_prompt_regex) prompt_emit_cmd = u(prompt_emit_cmd) self.echo = echo self.prompt_emit_cmd = prompt_emit_cmd self._force_prompt_on_continuation = force_prompt_on_continuation if prompt_change_cmd is None: self.prompt_regex = u(prompt_regex) self.prompt_change_cmd = None else: self.set_prompt(prompt_regex, prompt_change_cmd.format(new_prompt_regex, continuation_prompt_regex)) self.prompt_regex = new_prompt_regex self.continuation_prompt_regex = continuation_prompt_regex self.stdin_prompt_regex = stdin_prompt_regex self._stream_handler = None self._stdin_handler = None self._line_handler = None self._expect_prompt() if extra_init_cmd is not None: self.run_command(extra_init_cmd) atexit.register(self.terminate) def sendline(self, line): self.child.sendline(u(line)) if self.echo: self.child.readline() def set_prompt(self, prompt_regex, prompt_change_cmd): self.child.expect(prompt_regex) self.sendline(prompt_change_cmd) self.prompt_change_cmd = prompt_change_cmd def _expect_prompt(self, timeout=None): """Expect a prompt from the child. """ expects = [self.prompt_regex, self.continuation_prompt_regex, self.stdin_prompt_regex] if self.prompt_emit_cmd: self.sendline(self.prompt_emit_cmd) if self._stream_handler: return self._expect_prompt_stream(expects, timeout) if self._line_handler: expects += [u(self.child.crlf)] while True: pos = self.child.expect(expects, timeout=timeout) # got a full prompt or continuation prompt. if pos in [0, 1]: return pos # got a stdin prompt if pos == 2: if not self._stdin_handler: raise ValueError('Stdin Requested but not stdin handler available') resp = self._stdin_handler(self.child.after) self.sendline(resp) # got a newline else: self._line_handler(self.child.before.rstrip()) def _expect_prompt_stream(self, expects, timeout=None): """Expect a prompt with streaming output. """ stream_handler = self._stream_handler stdin_handler = self._stdin_handler t0 = time.time() if timeout == -1: timeout = 30 elif timeout is None: timeout = 1e6 stream_timeout = 0.1 unhandled_cr = False # Wait for a prompt, handling carriage returns. while True: if time.time() - t0 > timeout: raise pexpect.TIMEOUT('Timed out') try: # Wait for a prompt. pos = self.child.expect(expects, timeout=stream_timeout) except pexpect.TIMEOUT: # Process any carriage returns in the stream. while 1: try: self.child.expect([u('\r')], timeout=0) if unhandled_cr: stream_handler('\r') stream_handler(self.child.before) unhandled_cr = True except pexpect.TIMEOUT: break continue # prompt or stdin request received, handle line. line = self.child.before # Handle cr state. if unhandled_cr: line = '\r' + line unhandled_cr = False # Handle stdin request. if pos == 2: if not stdin_handler: raise ValueError('Stdin Requested but no stdin handler available') resp = stdin_handler(line + self.child.after) self.sendline(resp) continue # prompt received, but partial line precedes it if len(line) != 0: stream_handler(line) # exit on prompt received. break return pos def run_command(self, command, timeout=None, stream_handler=None, line_handler=None, stdin_handler=None): """Send a command to the REPL, wait for and return output. :param str command: The command to send. Trailing newlines are not needed. This should be a complete block of input that will trigger execution; if a continuation prompt is found after sending input, :exc:`ValueError` will be raised. :param int timeout: How long to wait for the next prompt. -1 means the default from the :class:`pexpect.spawn` object (default 30 seconds). None means to wait indefinitely. :param func stream_handler - A function that accepts a string to print as a streaming output :param func line_handler - A function that accepts a string to print as a line output :param stdin_handler - A function that prompts the user for input and returns a response. """ # Split up multiline commands and feed them in bit-by-bit cmdlines = command.splitlines() # splitlines ignores trailing newlines - add it back in manually if command.endswith('\n'): cmdlines.append('') if not cmdlines: raise ValueError("No command was given") res = [] self._line_handler = line_handler self._stream_handler = stream_handler self._stdin_handler = stdin_handler self.sendline(cmdlines[0]) for line in cmdlines[1:]: if not self.prompt_emit_cmd: self._expect_prompt(timeout=timeout) res.append(strip_bracketing(self.child.before)) self.sendline(line) # Command was fully submitted, now wait for the next prompt if self._expect_prompt(timeout=timeout) == 1: # We got the continuation prompt - command was incomplete self.interrupt(continuation=True) raise ValueError("Continuation prompt found - input was incomplete:\n" + command) if self._stream_handler or self._line_handler: return u'' return u''.join(res + [strip_bracketing(self.child.before)]) def interrupt(self, continuation=False): """Interrupt the process and wait for a prompt. Returns ------- The value up to the prompt. """ if pexpect.pty: self.child.sendintr() else: self.child.kill(signal.SIGINT) if continuation and self._force_prompt_on_continuation: self.sendline(self.prompt_change_cmd or '') while 1: try: self._expect_prompt(timeout=-1) break except KeyboardInterrupt: pass return self.child.before def terminate(self): if pexpect.pty: self.child.close() return self.child.terminate() try: self.child.kill(signal.SIGTERM) except Exception as e: if e.errno != errno.EACCES: raise def python(command="python"): """Start a Python shell and return a :class:`REPLWrapper` object.""" if not pexpect.pty: raise OSError('Not supported on platform "%s"' % sys.platform) return REPLWrapper(command, u(">>> "), u("import sys; sys.ps1={0!r}; sys.ps2={1!r}")) def bash(command="bash", prompt_regex=re.compile('[$#]')): """Start a bash shell and return a :class:`REPLWrapper` object.""" # If the user runs 'env', the value of PS1 will be in the output. To avoid # replwrap seeing that as the next prompt, we'll embed the marker characters # for invisible characters in the prompt; these show up when inspecting the # environment variable, but not when bash displays the prompt. ps1 = PEXPECT_PROMPT[:5] + r'\[\]' + PEXPECT_PROMPT[5:] ps2 = PEXPECT_CONTINUATION_PROMPT[:5] + r'\[\]' + PEXPECT_CONTINUATION_PROMPT[5:] prompt_change_cmd = u"PS1='{0}' PS2='{1}' PROMPT_COMMAND=''".format(ps1, ps2) if os.name == 'nt': prompt_regex = u('__repl_ready__') prompt_emit_cmd = u('echo __repl_ready__') prompt_change_cmd = None else: prompt_emit_cmd = None extra_init_cmd = "export TERM=dumb PAGER=cat" # Make sure the bash shell has a valid ending character. bashrc = os.path.join(os.path.dirname(pexpect.PEXPECT_DIR), 'bashrc.sh') child = pexpect.spawn(command, ['--rcfile', bashrc], echo=False, encoding='utf-8') return REPLWrapper(child, prompt_regex, prompt_change_cmd, prompt_emit_cmd=prompt_emit_cmd, extra_init_cmd=extra_init_cmd) def powershell(command='powershell', prompt_regex='>'): """"Start a powershell and return a :class:`REPLWrapper` object.""" return REPLWrapper(command, prompt_regex, 'Function prompt {{ "{0}" }}', echo=True) def strip_bracketing(string, start='\x1b[?2004l', stop='\x1b[?2004h'): """Strip 'bracketed paste' control characters, if they are present""" if string.startswith(start) and string.endswith(stop): return string[len(start):-len(stop)] else: return string metakernel-0.29.4/metakernel/tests/000077500000000000000000000000001434565236000172365ustar00rootroot00000000000000metakernel-0.29.4/metakernel/tests/__init__.py000066400000000000000000000000001434565236000213350ustar00rootroot00000000000000metakernel-0.29.4/metakernel/tests/test_expect.py000066400000000000000000000112001434565236000221310ustar00rootroot00000000000000#!/usr/bin/env python ''' PEXPECT LICENSE This license is approved by the OSI and FSF as GPL-compatible. http://opensource.org/licenses/isc-license.txt Copyright (c) 2012, Noah Spurrier PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ''' import unittest import subprocess import sys import os from .. import pexpect # Many of these test cases blindly assume that sequential directory # listings of the /bin directory will yield the same results. # This may not be true, but seems adequate for testing now. # I should fix this at some point. FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)]) def hex_dump(src, length=16): result=[] for i in xrange(0, len(src), length): s = src[i:i+length] hexa = ' '.join(["%02X"%ord(x) for x in s]) printable = s.translate(FILTER) result.append("%04X %-*s %s\n" % (i, length*3, hexa, printable)) return ''.join(result) def hex_diff(left, right): diff = ['< %s\n> %s' % (_left, _right,) for _left, _right in zip( hex_dump(left).splitlines(), hex_dump(right).splitlines()) if _left != _right] return '\n' + '\n'.join(diff,) class ExpectTestCase (unittest.TestCase): def setUp(self): self.PYTHONBIN = sys.executable os.chdir(os.path.dirname(__file__)) def test_expect (self): the_old_way = subprocess.Popen(args=['ls', '-l', '/bin'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8') p = pexpect.spawn('ls -l /bin') the_new_way = '' while 1: i = p.expect ([u'\n', pexpect.EOF]) the_new_way = the_new_way + p.before if i == 1: break the_new_way = the_new_way.rstrip() the_new_way = the_new_way.replace('\r\n', '\n' ).replace('\r', '\n').replace('\n\n', '\n').rstrip() the_old_way = the_old_way.replace('\r\n', '\n' ).replace('\r', '\n').replace('\n\n', '\n').rstrip() assert the_old_way == the_new_way, hex_diff(the_old_way, the_new_way) def test_expect_exact (self): the_old_way = subprocess.Popen(args=['ls', '-l', '/bin'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8') p = pexpect.spawn('ls -l /bin') the_new_way = '' while 1: i = p.expect_exact ([u'\n', pexpect.EOF]) the_new_way = the_new_way + p.before if i == 1: break the_new_way = the_new_way.replace('\r\n', '\n' ).replace('\r', '\n').replace('\n\n', '\n').rstrip() the_old_way = the_old_way.replace('\r\n', '\n' ).replace('\r', '\n').replace('\n\n', '\n').rstrip() assert the_old_way == the_new_way, hex_diff(the_old_way, the_new_way) p = pexpect.spawn('echo hello.?world') i = p.expect_exact(u'.?') self.assertEqual(p.before, 'hello') self.assertEqual(p.after, '.?') def test_expect_eof (self): the_old_way = subprocess.Popen(args=['/bin/ls', '-l', '/bin'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8') p = pexpect.spawn('/bin/ls -l /bin') p.expect(pexpect.EOF) # This basically tells it to read everything. Same as pexpect.run() function. the_new_way = p.before the_new_way = the_new_way.replace('\r\n', '\n' ).replace('\r', '\n').replace('\n\n', '\n').rstrip() the_old_way = the_old_way.replace('\r\n', '\n' ).replace('\r', '\n').replace('\n\n', '\n').rstrip() assert the_old_way == the_new_way, hex_diff(the_old_way, the_new_way) def test_expect_timeout (self): p = pexpect.spawn('cat', timeout=5) p.expect(pexpect.TIMEOUT) # This tells it to wait for timeout. self.assertEqual(p.after, pexpect.TIMEOUT) if __name__ == '__main__': unittest.main() suite = unittest.TestLoader().loadTestsFromTestCase(ExpectTestCase) metakernel-0.29.4/metakernel/tests/test_magic.py000066400000000000000000000052231434565236000217310ustar00rootroot00000000000000from metakernel import Magic, option from metakernel.tests.utils import get_kernel, get_log_text class Dummy(Magic): @option( '-s', '--size', action='store', help='Pixel size of plots, "width,height"' ) def line_dummy(self, foo, size=None): """ %dummy [options] foo - Perform dummy operation on foo This is additional information on dummy. """ self.foo = foo self.size = size def cell_spam(self): """ %%spam - Cook some spam """ pass def line_eggs(self, style): """ %eggs STYLE - cook some eggs in the given style """ pass def test_get_magics(): kernel = get_kernel() d = Dummy(kernel) line = d.get_magics('line') cell = d.get_magics('cell') assert 'dummy' in line assert 'spam' in cell assert 'eggs' in line def test_get_help(): kernel = get_kernel() d = Dummy(kernel) dummy_help = d.get_help('line', 'dummy', 0) assert dummy_help.startswith("%dummy") assert " This is additional information on dummy" in d.line_dummy.__doc__, "Checking indents" assert "\nThis is additional information on dummy" in dummy_help, "Checking indent removal" dummy_help = d.get_help('line', 'dummy', 1) # will show this entire file, including this sentence assert "# will show this entire file, including this sentence" in \ dummy_help spam_help = d.get_help('cell', 'spam', 0) assert spam_help.startswith("%%spam"), spam_help spam_help = d.get_help('cell', 'spam', 1) assert "# will show this entire file, including this sentence" in \ spam_help def test_option(): kernel = get_kernel() d = Dummy(kernel) assert 'Options:' in d.line_dummy.__doc__ assert '--size' in d.line_dummy.__doc__ ret = d.call_magic('line', 'dummy', '', 'hey -s400,200') assert ret == d assert d.foo == 'hey', d.foo assert d.size == (400, 200) ret = d.call_magic('line', 'dummy', '', 'hey there') assert d.foo == 'hey there' ret = d.call_magic('line', 'dummy', '', 'range(1, 10)') # arg eval no longer evals Python raw code: assert d.foo == "range(1, 10)" ret = d.call_magic('line', 'dummy', '', '[1, 2, 3]') # arg eval does eval Python data structures: assert d.foo == [1, 2, 3] ret = d.call_magic('line', 'dummy', '', 'hey -l -s400,200') assert d.size == (400, 200) assert d.foo == "hey -l" ret = d.call_magic('line', 'dummy', '', 'hey -s -- -s400,200') assert d.size == (400, 200) assert d.foo == "hey -s" metakernel-0.29.4/metakernel/tests/test_metakernel.py000066400000000000000000000165711434565236000230100ustar00rootroot00000000000000import os import re import subprocess import pytest import tempfile from metakernel import MetaKernel from metakernel.tests.utils import (get_kernel, get_log_text, EvalKernel, clear_log_text) def test_magics(): kernel = get_kernel() for magic in ['cd', 'connect_info', 'download', 'html', 'install_magic', 'javascript', 'latex', 'lsmagic', 'magic', 'plot', 'reload_magics', 'shell']: msg = "magic '%s' is not in line_magics" % magic assert magic in kernel.line_magics, msg for magic in ['file', 'html', 'javascript', 'latex', 'shell', 'time']: assert magic in kernel.cell_magics with tempfile.NamedTemporaryFile() as ntf: kernel.get_magic('%%shell ls %s' % ntf.name) log_text = get_log_text(kernel) assert ntf.name in log_text def test_help(): kernel = get_kernel() resp = kernel.get_help_on('%shell', 0) assert 'run the line as a shell command' in resp resp = kernel.do_execute('%cd?', False) assert 'change current directory of session' in resp[ 'payload'][0]['data']['text/plain'] resp = kernel.get_help_on('what', 0) assert resp == "Sorry, no help is available on 'what'.", ("response was actually %s" % resp) def test_complete(): kernel = get_kernel() comp = kernel.do_complete('%connect_', len('%connect_')) assert comp['matches'] == ['%connect_info'], str(comp['matches']) comp = kernel.do_complete('%%fil', len('%%fil')) assert comp['matches'] == ['%%file'], str(comp['matches']) comp = kernel.do_complete('%%', len('%%')) assert '%%file' in comp['matches'] assert '%%html' in comp['matches'] def test_inspect(): kernel = get_kernel() kernel.do_inspect('%lsmagic', len('%lsmagic')) log_text = get_log_text(kernel) assert "list the current line and cell magics" in log_text kernel.do_inspect('%lsmagic ', len('%lsmagic') + 1) def test_path_complete(): kernel = get_kernel() comp = kernel.do_complete('~/.ipytho', len('~/.ipytho')) assert comp['matches'] == ['ipython/'] paths = [p for p in os.listdir(os.getcwd()) if not p.startswith('.') and not '-' in p] for path in paths: comp = kernel.do_complete(path, len(path) - 1) if os.path.isdir(path): path = path.split()[-1] assert path + os.sep in comp['matches'], ("'%s' not in '%s'" % (path + os.sep, comp['matches'])) else: path = path.split()[-1] assert path in comp['matches'], (comp['matches'], path) def test_ls_path_complete(): kernel = get_kernel() comp = kernel.do_complete('! ls ~/.ipytho', len('! ls ~/.ipytho')) assert comp['matches'] == ['ipython/'], comp def test_history(): kernel = get_kernel() kernel.do_execute('!ls', False) kernel.do_execute('%cd ~', False) kernel.do_shutdown(False) with open(kernel.hist_file, 'rb') as fid: text = fid.read().decode('utf-8', 'replace') assert '!ls' in text assert '%cd' in text kernel = get_kernel() kernel.do_history(None, None, None) assert '!ls' in ''.join(kernel.hist_cache) assert '%cd ~' def test_sticky_magics(): kernel = get_kernel() kernel.do_execute('%%%html\nhello', None) text = get_log_text(kernel) assert 'html added to session magics' in text kernel.do_execute('hello', None) kernel.do_execute('%%%html', None) text = get_log_text(kernel) assert text.count('Display Data') == 2 assert 'html removed from session magics' in text def test_shell_partial_quote(): kernel = get_kernel() kernel.do_execute('%cd "/home/', False) text = get_log_text(kernel) assert """No such file or directory: '"/home/'""" in text, text def test_other_kernels(): class SchemeKernel(MetaKernel): help_suffix = {} def do_execute_direct(self, code): return "OK" kernel = get_kernel(SchemeKernel) resp = kernel.do_execute('dir?', None) assert len(resp['payload']) == 0, "should handle this, rather than using help" resp = kernel.do_execute('?dir?', None) assert len(resp['payload']) == 1, "should use help" message = resp['payload'][0]['data']['text/plain'] assert "Sorry, no help is available on 'dir?'." == message, message content = kernel.do_inspect('dir', len('dir')) assert (content['status'] == 'aborted' and content['found'] == False), "do_inspect should abort, and be not found" content = kernel.do_inspect('len(dir', len('len(dir')) assert (content['status'] == 'aborted' and content['found'] == False), "do_inspect should abort, and be not found" content = kernel.do_inspect('(dir', len('(dir')) assert (content['status'] == 'aborted' and content['found'] == False), "do_inspect should abort, and be not found" # Now change it so that there is help available: kernel.get_kernel_help_on = lambda info, level=0, none_on_fail=False: \ "Help is available on '%s'." % info['obj'] content = kernel.do_inspect('dir', len('dir')) message = content["data"]["text/plain"] match = re.match("Help is available on '(.*)'", message) assert match.groups()[0] == "dir", message + " for 'dir'" content = kernel.do_inspect('len(dir', len('len(dir')) message = content["data"]["text/plain"] match = re.match("Help is available on '(.*)'", message) assert match.groups()[0] == "dir", message + " for 'dir'" content = kernel.do_inspect('(dir', len('(dir')) message = content["data"]["text/plain"] match = re.match("Help is available on '(.*)'", message) assert match.groups()[0] == "dir", message + " for 'dir'" def test_do_execute_meta(): kernel = get_kernel(EvalKernel) kernel.do_execute("~~META~~: reset") text = get_log_text(kernel) assert "RESET" in text, text clear_log_text(kernel) kernel.do_execute("~~META~~: stop") text = get_log_text(kernel) assert "STOP" in text, text clear_log_text(kernel) kernel.do_execute("~~META~~: step") text = get_log_text(kernel) assert "STEP" in text, text clear_log_text(kernel) kernel.do_execute("~~META~~: inspect something") text = get_log_text(kernel) assert "INSPECT" in text, text clear_log_text(kernel) def test_do_execute_meta2(): kernel = get_kernel() for code in ['reset, stop', 'step', 'inspect ', 'garbage']: with pytest.raises(Exception): kernel.do_execute("~~META~~: %s" % code) def test_misc(): class TestKernel(MetaKernel): def do_execute_file(self, filename): self.Print("This language does not support running files") def do_function_direct(self, f, arg): self.Print("%s(%s)" % (f, self.repr(arg))) def repr(self, arg): return "XXX" kernel = get_kernel(TestKernel) assert kernel.do_execute_direct('garbage') is None kernel.do_execute_file('hello.txt') assert "This language does not support" in get_log_text(kernel) clear_log_text(kernel) kernel.do_function_direct('hello', 'world') text = get_log_text(kernel) assert "hello(XXX)" in text, text kernel.restart_kernel() ret = kernel.do_is_complete('hello\n') assert ret == {'status': 'complete'} assert kernel.do_inspect('hello', 10) is None def teardown(): if os.path.exists("TEST.txt"): os.remove("TEST.txt") metakernel-0.29.4/metakernel/tests/test_parser.py000066400000000000000000000062141434565236000221460ustar00rootroot00000000000000 from metakernel import Parser import os def test_parser(): p = Parser() info = p.parse_code('import nump') assert info['help_obj'] == info['obj'] == 'nump' assert p.parse_code('%python impor', 0, 10)['magic']['name'] == 'python' assert p.parse_code('oct(a,')['help_obj'] == 'oct' assert p.parse_code('! ls')['magic']['name'] == 'shell' info = p.parse_code('%help %lsmagic', 0, 10) assert info['help_obj'] == '%lsmagic' assert info['obj'] == '%lsm' info = p.parse_code('%%python\nprint("hello, world!",') assert info['help_obj'] == 'print' info = p.parse_code('%lsmagic') assert info['help_obj'] == '%lsmagic' info = p.parse_code('%') assert info['magic']['type'] == 'line' def test_scheme_parser(): function_call_regex = r'\(([^\d\W][\w\.]*)[^\)\()]*\Z' p = Parser(function_call_regex=function_call_regex) info = p.parse_code('(oct a b ') assert info['help_obj'] == 'oct' def test_path_completions(): p = Parser() if not os.name == 'nt': code = '/usr/bi' assert 'bin/' in p.parse_code(code)['path_matches'] code = '~/.bashr' assert 'bashrc' in p.parse_code(code)['path_matches'] for f in os.listdir('.'): if f.startswith('.'): if os.path.isdir(f): assert f[1:] + os.sep in p.parse_code('.')['path_matches'], f else: assert f[1:] in p.parse_code('.')['path_matches'] def test_complete0(): p = Parser() info = p.parse_code('abcdefghijklmnop', 0, 4) assert info['obj'] == 'abcd', info def get_parser(): p = Parser() try: os.mkdir("/tmp/Test Dir") except OSError: pass # dir exists open("/tmp/Test Dir/test.txt", "w").close() return p def test_complete1(): p = get_parser() info = p.parse_code('/tmp/') assert "Test\\ Dir/" in info['path_matches'], info['path_matches'] def test_complete2(): p = get_parser() info = p.parse_code('open("/tmp/') assert "Test Dir/" in info['path_matches'], info def test_complete3(): p = get_parser() info = p.parse_code('/tmp/Test Dir/temp.txt', 0, 14) assert "test.txt" in info['path_matches'], info def test_complete4(): p = get_parser() info = p.parse_code('/tmp/Test Dir') assert 'Dir/test.txt' in info['path_matches'], info def test_complete5(): p = get_parser() info = p.parse_code('/tmp/Test Dir/') assert "test.txt" in info['path_matches'], info def test_complete6(): p = get_parser() info = p.parse_code('/tmp/Test') assert "Test\\ Dir/" in info['path_matches'], info['path_matches'] def test_complete7(): p = get_parser() info = p.parse_code('/tmp/Test Dir/test.txt') assert not info['path_matches'], info def test_complete8(): p = get_parser() info = p.parse_code('/tmp/Test Dir/', 0, 9) assert 'Test\\ Dir/' in info['path_matches'], info def test_complete9(): p = get_parser() info = p.parse_code('fluff\n/tmp/Test ') assert 'Dir/' in info['path_matches'], info def test_complete10(): p = get_parser() info = p.parse_code('/tmp/Test\\ Dir') assert 'Dir/test.txt' in info['path_matches'] metakernel-0.29.4/metakernel/tests/test_process_metakernel.py000077500000000000000000000015041434565236000245370ustar00rootroot00000000000000 from IPython.display import HTML from metakernel.tests.utils import get_kernel, get_log_text from metakernel.process_metakernel import BashKernel def test_process_metakernel(): kernel = get_kernel(BashKernel) kernel.do_execute("cat \"%s\"" % __file__, False) log_text = get_log_text(kernel) assert 'metakernel.py' in log_text, log_text kernel.do_execute('echo "hello"\necho "goodbye"', None) log_text = get_log_text(kernel) assert '"hello"' in log_text assert '"goodbye"' in log_text kernel.do_execute('lalkjds') text = get_log_text(kernel) assert ': command not found' in text, text html = HTML("some html") kernel.Display(html) kernel.do_execute(r'for i in {1..3};do echo -ne "$i\r"; sleep 1; done', None) text = get_log_text(kernel) assert r'1\r2\r3\r' in text metakernel-0.29.4/metakernel/tests/test_replwrap.py000066400000000000000000000066371434565236000225170ustar00rootroot00000000000000import platform import unittest import re import os import sys from metakernel import pexpect, replwrap from metakernel.tests.utils import get_log, get_log_text class REPLWrapTestCase(unittest.TestCase): def setUp(self): super(REPLWrapTestCase, self).setUp() self.save_ps1 = os.getenv('PS1', r'\$') self.save_ps2 = os.getenv('PS2', '>') os.putenv('PS1', r'\$') os.putenv('PS2', '>') def tearDown(self): super(REPLWrapTestCase, self).tearDown() os.putenv('PS1', self.save_ps1) os.putenv('PS2', self.save_ps2) def test_bash(self): bash = replwrap.bash() res = bash.run_command("time") assert 'real' in res, res # PAGER should be set to cat, otherwise man hangs res = bash.run_command('man sleep', timeout=2) assert 'SLEEP' in res, res # should handle CR by default cmd = r'for i in {1..3};do echo -ne "\r$i"; sleep 1; done' res = bash.run_command(cmd) assert '\r1\r2\r3' in res # should handle CRs in a stream res = bash.run_command(cmd, stream_handler=sys.stdout.write) assert res == '' # should handle lines with a line handler logger = get_log() res = bash.run_command('echo "1\n2\n3"', line_handler=logger.info) assert res == '' text = get_log_text(logger) assert '1\n2\n3' in text def test_multiline(self): bash = replwrap.bash() res = bash.run_command("echo '1 2\n3 4'") self.assertEqual(res.strip().splitlines(), ['1 2', '3 4']) # Should raise ValueError if input is incomplete try: bash.run_command("echo '5 6") except ValueError: pass else: assert False, "Didn't raise ValueError for incomplete input" # Check that the REPL was reset (SIGINT) after the incomplete input res = bash.run_command("echo '1 2\n3 4'") self.assertEqual(res.strip().splitlines(), ['1 2', '3 4']) def test_existing_spawn(self): child = pexpect.spawnu("bash", timeout=5, echo=False) repl = replwrap.REPLWrapper(child, re.compile('[$#]'), "PS1='{0}' PS2='{1}' " "PROMPT_COMMAND='' TERM='dumb'") res = repl.run_command("echo $HOME") assert res.startswith('/'), res def test_python(self): if platform.python_implementation() == 'PyPy': raise unittest.SkipTest("This test fails on PyPy because of REPL differences") if platform.system() == 'Darwin': raise unittest.SkipTest("This test fails on macOS because of REPL differences") p = replwrap.python(sys.executable) res = p.run_command('4+7') assert res.strip() == '11' res = p.run_command('for a in range(3): print(a)\n') assert res.strip().splitlines() == ['0', '1', '2'] def test_bracketed_paste(self): # Readline paste bracketing is easily toggled in bash, but can be harder elsewhere # This tests that run_command() still works with it enabled (the default for readline, # but overriden by bash and python) bash = replwrap.bash() bash.run_command("bind 'set enable-bracketed-paste on'") res = bash.run_command("echo '1 2\n3 4'") self.assertEqual(res.strip().splitlines(), ['1 2', '3 4']) if __name__ == '__main__': unittest.main() metakernel-0.29.4/metakernel/tests/utils.py000066400000000000000000000052171434565236000207550ustar00rootroot00000000000000from metakernel import MetaKernel try: from jupyter_client import session as ss except ImportError: from IPython.kernel.zmq import session as ss import zmq import logging try: from StringIO import StringIO except ImportError: from io import StringIO class EvalKernel(MetaKernel): implementation = 'Eval' implementation_version = '1.0' language = 'python' language_version = '0.1' banner = "Eval kernel - evaluates simple Python statements and expressions" def set_variable(self, name, value): """ Set a variable in the kernel language. """ python_magic = self.line_magics['python'] python_magic.env[name] = value def get_variable(self, name): """ Get a variable from the kernel language. """ python_magic = self.line_magics['python'] return python_magic.env[name] def do_execute_direct(self, code): python_magic = self.line_magics['python'] return python_magic.eval(code.strip()) def do_execute_meta(self, code): if code == "reset": return "RESET" elif code == "stop": return "STOP" elif code == "step": return "STEP" elif code.startswith("inspect "): return "INSPECT" else: raise Exception("Unknown meta command: '%s'" % code) def initialize_debug(self, code): return "highlight: [%s, %s, %s, %s]" % (0, 0, 1, 0) def has_network(): import requests try: _ = requests.head('http://google.com', timeout=3) return True except requests.ConnectionError: print("No internet connection available.") return False def get_log(): log = logging.getLogger('test') log.setLevel(logging.DEBUG) for hdlr in log.handlers: log.removeHandler(hdlr) hdlr = logging.StreamHandler(StringIO()) hdlr.setLevel(logging.DEBUG) log.addHandler(hdlr) return log def get_kernel(kernel_class=MetaKernel): context = zmq.Context.instance() iopub_socket = context.socket(zmq.PUB) kernel = kernel_class(session=ss.Session(), iopub_socket=iopub_socket, log=get_log()) return kernel def clear_log_text(obj): """Clear the log text from a kernel or a log object.""" if isinstance(obj, MetaKernel): log = obj.log else: log = obj log.handlers[0].stream.truncate(0) log.handlers[0].stream.seek(0) def get_log_text(obj): """Get the log text from a kernel or a log object.""" if isinstance(obj, MetaKernel): log = obj.log else: log = obj return log.handlers[0].stream.getvalue() metakernel-0.29.4/metakernel/utils/000077500000000000000000000000001434565236000172345ustar00rootroot00000000000000metakernel-0.29.4/metakernel/utils/__init__.py000066400000000000000000000001451434565236000213450ustar00rootroot00000000000000def add_docs(docs): def wrapper(f): f.__doc__ = docs return f return wrapper metakernel-0.29.4/metakernel_echo/000077500000000000000000000000001434565236000170725ustar00rootroot00000000000000metakernel-0.29.4/metakernel_echo/Makefile000066400000000000000000000001211434565236000205240ustar00rootroot00000000000000.PHONY: test test: pip install -e . ipython console --kernel=metakernel_echo metakernel-0.29.4/metakernel_echo/README.md000066400000000000000000000011441434565236000203510ustar00rootroot00000000000000**MetaKernel Echo** is a Jupyter kernel using MetaKernel magics, shell, help, and parallel processing tools. This code provides an example MetaKernel kernel. ## Install First, you need to install the metakernel_echo library and dependencies: ```shell pip install metakernel_echo --upgrade ``` Then, you need to install the metakernel echo kernel spec: ```shell python -m metakernel_echo install ``` ## Running You can then run the metakernel_echo kernel as a console, notebook, etc.: ```shell jupyter console --kernel=metakernel_echo ``` ## Dependencies 1. IPython 3 1. MetaKernel (installed with pip) metakernel-0.29.4/metakernel_echo/metakernel_echo.py000066400000000000000000000022441434565236000225730ustar00rootroot00000000000000"""A Echo kernel for Jupyter""" from metakernel import MetaKernel import sys __version__ = "0.19.1" class MetaKernelEcho(MetaKernel): implementation = 'MetaKernel Echo' implementation_version = '1.0' language = 'text' language_version = '0.1' banner = "MetaKernel Echo - as useful as a parrot" language_info = { 'mimetype': 'text/plain', 'name': 'text', # ------ If different from 'language': # 'codemirror_mode': { # "version": 2, # "name": "ipython" # } # 'pygments_lexer': 'language', # 'version' : "x.y.z", 'file_extension': '.txt', 'help_links': MetaKernel.help_links, } kernel_json = { 'argv': [ sys.executable, '-m', 'metakernel_echo', '-f', '{connection_file}'], 'display_name': 'MetaKernel Echo', 'language': 'echo', 'name': 'metakernel_echo' } def get_usage(self): return "This is the echo kernel." def do_execute_direct(self, code): return code.rstrip() def repr(self, data): return repr(data) if __name__ == '__main__': MetaKernelEcho.run_as_main() metakernel-0.29.4/metakernel_echo/pyproject.toml000066400000000000000000000013231434565236000220050ustar00rootroot00000000000000[build-system] requires = ["hatchling >=1.5"] build-backend = "hatchling.build" [project] name = "metakernel_echo" authors = [{name = "Douglas Blank", email = "doug.blank@gmail.com"}] classifiers = [ "Framework :: IPython", "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 2", "Topic :: System :: Shells", ] dependencies = ["metakernel"] dynamic = ["description", "version"] [project.readme] text = "A simple echo kernel for Jupyter/IPython, based on MetaKernel" content-type = "text/plain" [project.urls] Homepage = "https://github.com/calysto/metakernel/tree/main/metakernel_echo" [tool.hatch.version] path = "metakernel_echo.py" metakernel-0.29.4/metakernel_python/000077500000000000000000000000001434565236000174755ustar00rootroot00000000000000metakernel-0.29.4/metakernel_python/Makefile000066400000000000000000000001221434565236000211300ustar00rootroot00000000000000.PHONY: test test: pip install -e . ipython console --kernel=metakernel_python metakernel-0.29.4/metakernel_python/README.md000066400000000000000000000011731434565236000207560ustar00rootroot00000000000000**MetaKernel Python** is a Jupyter kernel using MetaKernel magics, shell, help, and parallel processing tools. This code provides the core of the Python magics for MetaKernel. ## Install First, you need to install the metakernel_python library and dependencies: ```shell pip install metakernel_python --upgrade ``` Then, you need to install the metakernel kernel spec: ```shell python -m metakernel_python install ``` ## Running You can then run the metakernel_python kernel as a console, notebook, etc.: ```shell jupyter console --kernel=metakernel_python ``` ## Dependencies 1. IPython 3 2. MetaKernel (installed with pip) metakernel-0.29.4/metakernel_python/metakernel_python.py000066400000000000000000000046711434565236000236070ustar00rootroot00000000000000"""A Python kernel for Jupyter.""" from IPython.core.inputtransformer2 import TransformerManager from metakernel import MetaKernel import sys __version__ = "0.19.1" class MetaKernelPython(MetaKernel): implementation = 'MetaKernel Python' implementation_version = '1.0' language = 'python' language_version = '0.1' banner = "MetaKernel Python - evaluates Python statements and expressions" language_info = { 'mimetype': 'text/x-python', 'name': 'python', # ------ If different from 'language': # 'codemirror_mode': { # "version": 2, # "name": "ipython" # } # 'pygments_lexer': 'language', # 'version' : "x.y.z", 'file_extension': '.py', 'help_links': MetaKernel.help_links, } kernel_json = { "argv": [ sys.executable, "-m", "metakernel_python", "-f", "{connection_file}"], "display_name": "MetaKernel Python", "language": "python", "name": "metakernel_python" } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.transformer_manager = TransformerManager() def get_usage(self): return ("This is MetaKernel Python. It implements a Python " + "interpreter.") def set_variable(self, name, value): """ Set a variable in the kernel language. """ python_magic = self.line_magics['python'] python_magic.env[name] = value def get_variable(self, name): """ Get a variable from the kernel language. """ python_magic = self.line_magics['python'] return python_magic.env.get(name, None) def do_execute_direct(self, code): python_magic = self.line_magics['python'] return python_magic.eval(code.strip()) def get_completions(self, info): python_magic = self.line_magics['python'] return python_magic.get_completions(info) def get_kernel_help_on(self, info, level=0, none_on_fail=False): python_magic = self.line_magics['python'] return python_magic.get_help_on(info, level, none_on_fail) def do_is_complete(self, code): status, indent_spaces = self.transformer_manager.check_complete(code) r = {'status': status} if status == 'incomplete': r['indent'] = ' ' * indent_spaces return r if __name__ == '__main__': MetaKernelPython.run_as_main() metakernel-0.29.4/metakernel_python/pyproject.toml000066400000000000000000000013351434565236000224130ustar00rootroot00000000000000[build-system] requires = ["hatchling >= 1.5"] build-backend = "hatchling.build" [project] name = "metakernel_python" authors = [{name = "Douglas Blank", email = "doug.blank@gmail.com"}] classifiers = [ "Framework :: IPython", "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 2", "Topic :: System :: Shells", ] dependencies = ["metakernel", "jedi"] dynamic = ["description", "version"] [project.readme] text = "A Python kernel for Jupyter/IPython, based on MetaKernel" content-type = "text/plain" [project.urls] Homepage = "https://github.com/calysto/metakernel/tree/main/metakernel_python" [tool.hatch.version] path = "metakernel_python.py" metakernel-0.29.4/metakernel_python/test_metakernel_python.py000066400000000000000000000071211434565236000246370ustar00rootroot00000000000000""" Test the metakernel_python kernel using jupyter_kernel_test with supported capabilities """ import unittest import jupyter_kernel_test as jkt class MetaKernelPythonTests(jkt.KernelTests): # REQUIRED # the kernel to be tested # this is the normally the name of the directory containing the # kernel.json file - you should be able to do # `jupyter console --kernel KERNEL_NAME` kernel_name = "metakernel_python" # Everything else is OPTIONAL # the name of the language the kernel executes # checked against language_info.name in kernel_info_reply language_name = "python" # the normal file extension (including the leading dot) for this language # checked against language_info.file_extension in kernel_info_reply file_extension = ".py" # code which should write the exact string `hello, world` to STDOUT code_hello_world = "print('hello, world')" # code which should cause (any) text to be written to STDERR code_stderr = "import sys; print('test', file=sys.stderr)" # samples for the autocompletion functionality # for each dictionary, `text` is the input to try and complete, and # `matches` the list of all complete matching strings which should be found completion_samples = [ { 'text': 'zi', 'matches': {'zip'}, }, ] # samples for testing code-completeness (used by console only) # these samples should respectively be unambigiously complete statements # (which should be executed on ), incomplete statements or code # which should be identified as invalid complete_code_samples = ['1', "print('hello, world')", "def f(x):\n return x*2\n\n\n"] incomplete_code_samples = ["print('''hello", "def f(x):\n x*2"] invalid_code_samples = ['import = 7q'] # code which should cause a help pager to be displayed (as of 4.1, this is # displayed by the notebook only as inline text, so it's probably more # useful for console clients) code_page_something = "zip?" # code which should generate a (user-level) error in the kernel, and send # a traceback to the client code_generate_error = "raise" # a statement or block of code which generates a result (which is shown # as Out[n] instead of just something printed to stdout) # running each `code` should cause `result` to be displayed (note that the # result here will always be a string representation of whatever the actual # result type is - be careful of string formatting) code_execute_result = [ {'code': "1+2+3", 'result': "6"}, {'code': "[n*n for n in range(1, 4)]", 'result': "[1, 4, 9]"} ] # code which generates some sort of rich output # for each `code` input a single rich display object with the specified # `mime` type should be sent to the frontend # note that this expects a `display_data` message rather than # `execute_result`; this test might be a little too inflexible in some cases code_display_data = [ {'code': "from IPython.display import HTML, display; display(HTML('test'))", 'mime': "text/html"}, {'code': "from IPython.display import Math, display; display(Math('\\frac{1}{2}'))", 'mime': "text/latex"} ] # test the support for object inspection # the sample should be a name about which the kernel can give some help # information (a built-in function is probably a good choice) # only the default inspection level (equivalent to ipython "obj?") # is currently tested code_inspect_sample = "zip" if __name__ == '__main__': unittest.main() metakernel-0.29.4/pyproject.toml000066400000000000000000000030311434565236000166560ustar00rootroot00000000000000[build-system] requires = ["hatchling >=1.5"] build-backend = "hatchling.build" [project] name = "metakernel" authors = [{name = "Metakernel Developers", email = "steven.silvester@ieee.org"}] classifiers = [ "License :: OSI Approved :: BSD License", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "Framework :: IPython", "Topic :: System :: Shells", ] urls = {Homepage = "https://github.com/Calysto/metakernel"} requires-python = ">=3.7" dependencies = [ "ipykernel >=5.5.6", "jupyter_core >=4.9.2", "pexpect >=4.8", "jedi >=0.18", ] dynamic = ["description", "version"] [project.readme] file = "README.rst" content-type = "text/x-rst" [project.optional-dependencies] test = [ "pytest", "pytest-cov", "requests", "jupyter_kernel_test", "pytest-timeout", ] activity = ["portalocker"] # activity magic parallel = ["ipyparallel"] # parallel magic [tool.hatch.version] path = "metakernel/__init__.py" [tool.hatch.build] exclude = [ "docs/", "examples", ] [tool.pytest.ini_options] addopts= "-raXs --durations 10 --color=yes --doctest-modules" testpaths = ["metakernel/tests", "metakernel/magics/tests"] timeout = 300 # Restore this setting to debug failures # timeout_method = "thread" filterwarnings= [ # Fail on warnings "error", "ignore:unclosed event loop:ResourceWarning", "ignore:There is no current event loop:DeprecationWarning", # When we run ipcluster and then run the tests we get this warning "ignore:Widget.* is deprecated:DeprecationWarning", ]